home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3076 < prev    next >
Internet Message Format  |  1991-03-14  |  60KB

  1. From: jbr0@cbnews.att.com (joseph.a.brownlee)
  2. Newsgroups: alt.sources
  3. Subject: Pcal v4.0, part 4 of 5
  4. Message-ID: <1991Mar14.125134.9708@cbnews.att.com>
  5. Date: 14 Mar 91 12:51:34 GMT
  6.  
  7. #!/bin/sh
  8. # This is part 04 of a multipart archive
  9. # ============= pcalinit.c ==============
  10. if test -f 'pcalinit.c' -a X"$1" != X"-c"; then
  11.     echo 'x - skipping pcalinit.c (File already exists)'
  12. else
  13. echo 'x - extracting pcalinit.c (Text)'
  14. sed 's/^X//' << 'SHAR_EOF' > 'pcalinit.c' &&
  15. /*
  16. X * Create a .h file from a .ps file.  Strips out leading and trailing 
  17. X * whitespace, blank lines, and lines consisting solely of comments,
  18. X * except for the very first block of comments/blanklines, which are
  19. X * turned into C comments at the top of the file.
  20. X * 
  21. X *   14-sep-90  Jamie Zawinski  created.
  22. X *
  23. X * Revision history:
  24. X *
  25. X *    4.0    AWR    02/25/91    added optional third argument for
  26. X *                    name of array
  27. X *
  28. X *        AWR    02/19/91    added function prototypes; documented
  29. X *
  30. X *        AWR    01/16/91    Escape " and \ in quoted strings;
  31. X *                    strip trailing comments; skip FF
  32. X *
  33. X *    2.6    JAB    10/18/90    Add exit(0).
  34. X *
  35. X *    2.3    JWZ    09/14/90    Author
  36. X */
  37. X
  38. #include <stdio.h>
  39. #include <ctype.h>
  40. #include <string.h>
  41. X
  42. #if defined(__STDC__) || defined(AMIGA)
  43. #define PROTOS
  44. #endif
  45. X
  46. #define FALSE    0
  47. #define TRUE    1
  48. X
  49. #define ARRAY_NAME    "header"    /* default name of array in .h file */
  50. X
  51. #define IS_WHITESPACE(c) \
  52. X    ((c) == ' ' || (c) == '\t' || (c) == '\n' || c == '\f')
  53. X
  54. #define IS_POSTSCRIPT(s)    ((s)[0] != '%' && (s)[0] != '\0')
  55. X
  56. X
  57. /*
  58. X * strip_white: strip leading and trailing whitespace from 'string'; return
  59. X * pointer to first non-whitespace character
  60. X */
  61. #ifdef PROTOS
  62. char *strip_white (char *string)
  63. #else
  64. char *strip_white (string)
  65. X     char *string;
  66. #endif
  67. {
  68. X    int n;
  69. X    for (; IS_WHITESPACE(*string); string++)
  70. X    ;
  71. X    n = strlen(string)-1;
  72. X    for (; IS_WHITESPACE(string[n]); n--)
  73. X    string[n] = '\0';
  74. X    return string;
  75. }
  76. X
  77. X
  78. /*
  79. X * strip_comment: strip comment and any preceding whitespace from 'string';
  80. X * return pointer to 'string'
  81. X */
  82. #ifdef PROTOS
  83. char *strip_comment (char *string)
  84. #else
  85. char *strip_comment (string)
  86. X     char *string;
  87. #endif
  88. {
  89. X    char *p;
  90. X    if ((p = strchr(string, '%')) != NULL) {
  91. X    *p = '\0';
  92. X    string = strip_white(string);
  93. X    }
  94. X    return string;
  95. }
  96. X
  97. /*
  98. X * escape: copy string 'in' to string 'out', escaping the characters \ and ";
  99. X * return pointer to 'out'
  100. X */
  101. #ifdef PROTOS
  102. char *escape(char *out, char *in)
  103. #else
  104. char *escape(out, in)
  105. X     char *out, *in;
  106. #endif
  107. {
  108. X   char c, *sv_out = out;
  109. X
  110. X   for (; c = *in; *out++ = *in++)
  111. X       if (c == '\\' || c == '"')
  112. X      *out++ = '\\';
  113. X
  114. X   *out = '\0';
  115. X   return sv_out;
  116. }
  117. X
  118. X
  119. #ifdef PROTOS
  120. int main(int argc, char *argv[])
  121. #else
  122. int main (argc, argv)
  123. X     int argc; char *argv[];
  124. #endif
  125. {
  126. X    FILE *in, *out;
  127. X    char line[256], line2[512], *L, *array;
  128. X    int in_initial_comments = TRUE;
  129. X
  130. X    /* retrieve arguments and attempt to open input and output files */
  131. X
  132. X    if (argc < 3 || argc > 4) {
  133. X       fprintf(stderr, "usage: %s <infile>.ps <outfile>.h [<arrayname>]\n",
  134. X        argv[0]);
  135. X       exit(-1); }
  136. X    
  137. X    in = fopen(argv[1], "r");
  138. X    if (NULL == in) {
  139. X       fprintf(stderr, "%s: couldn't open %s\n", argv[0], argv[1]);
  140. X       exit(-1); }
  141. X    
  142. X    out = fopen(argv[2], "w");
  143. X    if (NULL == out) {
  144. X       fprintf(stderr, "%s: couldn't open %s\n", argv[0], argv[2]);
  145. X       exit(-1); }
  146. X    
  147. X    array = argc == 4 ? argv[3] : ARRAY_NAME;
  148. X
  149. X    /* print topline comment on output file */
  150. X
  151. X    fprintf (out, "/*\n * %s: automatically generated by %s from %s\n",
  152. X       argv[2], argv[0], argv[1]);
  153. X    fprintf (out, " *\n *\tDO NOT EDIT THIS FILE!\n *\n");
  154. X
  155. X    /* main loop - copy lines from input file, to output file, preserving
  156. X     * only initial block of comments and blank lines
  157. X     */
  158. X
  159. X    while ( fgets(line, 255, in) != NULL ) {
  160. X       L = strip_white(line);            /* strip whitespace */
  161. X
  162. X       if ( IS_POSTSCRIPT(L) ) {        /* PostScript source? */
  163. X      if ( in_initial_comments ) {        /* first PS line? */
  164. X         in_initial_comments = FALSE;
  165. X         fprintf(out, " */\n\nchar *%s[] = {\n", array);
  166. X      }
  167. X      L = strip_comment(L);            /* copy string to output */
  168. X      L = escape(line2, L);
  169. X      fprintf(out, "  \"%s\",\n", L);
  170. X       } else                    /* blank or comment line */
  171. X      if ( in_initial_comments )        /* copy only initial block */
  172. X         fprintf(out, " * %s\n", L);
  173. X    }
  174. X
  175. X    fprintf(out, "  (char *)0,\n};\n");        /* terminate array decl */
  176. X
  177. X    fclose(out);            /* close files and exit */
  178. X    fclose(in);
  179. X    exit (0);
  180. }
  181. SHAR_EOF
  182. chmod 0644 pcalinit.c ||
  183. echo 'restore of pcalinit.c failed'
  184. Wc_c="`wc -c < 'pcalinit.c'`"
  185. test 3975 -eq "$Wc_c" ||
  186.     echo 'pcalinit.c: original size 3975, current size' "$Wc_c"
  187. fi
  188. # ============= pcalinit.ps ==============
  189. if test -f 'pcalinit.ps' -a X"$1" != X"-c"; then
  190.     echo 'x - skipping pcalinit.ps (File already exists)'
  191. else
  192. echo 'x - extracting pcalinit.ps (Text)'
  193. sed 's/^X//' << 'SHAR_EOF' > 'pcalinit.ps' &&
  194. % pcalinit.ps - provides the PostScript routines for pcal.c
  195. %
  196. % 4.0    modified by Andrew Rogers:
  197. %
  198. %    support -w ("whole year") option - cf. printmonth_[pl], startpage
  199. %    moved all the calendar calculations to pcal.c and moonphas.c (q.v.)
  200. %
  201. %    support -B option (leave unused boxes blank)
  202. %
  203. %    support -O option (print "gray" numbers as outlines)
  204. %
  205. %    revised several of the basic routines and added some others; dates,
  206. %    moons, text, Julian days are now relative to upper-left corner of box
  207. %
  208. %    enlarged title and dates in small calendars
  209. %
  210. % 3.0    modified by Andrew Rogers:
  211. %
  212. %    added xsval, ysval, xtval, ytval for scaling and translation
  213. %    as per Ed Hand
  214. %
  215. %    added day-of-year support (-j, -J flags)
  216. %
  217. % 2.6    * no modifications *
  218. %
  219. % 2.5    modified by Joe Brownlee:
  220. %
  221. %    made day numbers smaller, providing more room for event text
  222. %    repositioned event text and moons accordingly
  223. %    added support for variable first day of week
  224. %
  225. % 2.4    * no modifications *
  226. %
  227. % 2.3    modified by Jamie Zawinski <jwz@lucid.com>:
  228. %
  229. %    merged in moon routines (originally by Mark Hanson)
  230. %
  231. % 2.2    modified by Joe Brownlee:
  232. %
  233. %    add "notetext" to print notes in unused calendar box
  234. %
  235. % 2.1    modified by Mark Kantrowitz:
  236. %
  237. %    use symbolic names instead of magic numbers throughout
  238. %    support -L, -C, -R, -n options (all new)
  239. %    print holiday text in otherwise-wasted space next to date
  240. %    use larger text for dates in large calendars
  241. %
  242. % 2.0    modified by Andrew W. Rogers:
  243. %
  244. %    skip printing days of week on small calendars
  245. %    center month and year at top of calendar
  246. %    use correct algorithm for leap year calculation
  247. %    get month and day names from main program
  248. %    use table to determine color (black/gray) of weekdays and holidays
  249. %    use hanging indent to print continued text lines
  250. X
  251. /SM 0 def                % definitions for calendar sizes
  252. /MED 1 def
  253. /LG 2 def
  254. X
  255. /titlefontsize   [ 60 48 48 ] def    % font sizes for SM/MED/LG calendars
  256. /datefontsize    [ 54 40 25 ] def
  257. /weekdayfontsize [  0 24 12 ] def
  258. /footfontsize 12 def
  259. /notesfontsize 6 def
  260. X
  261. /titlepos [ 19 40 25 ] def        % Y-offset (SM/MED/LG) of month/year title
  262. /Y0 35 def                % Y-coordinate of calendar grid origin
  263. X
  264. /daywidth 100 def            % dimensions of grid boxes
  265. /dayheight 80 def
  266. /gridwidth daywidth 7 mul def
  267. /gridheight dayheight 6 mul def
  268. /negdaywidth daywidth neg def
  269. /negdayheight dayheight neg def
  270. /neggridwidth gridwidth neg def
  271. /neggridheight gridheight neg def
  272. X
  273. /gridlinewidth 1.0 def            % width of grid lines
  274. /charlinewidth 0.1 def            % width of outline characters
  275. /moonlinewidth 0.1 def            % width of moon icon line
  276. /dategray 0.8 def            % density of gray for dates
  277. /fillgray 0.9 def            % density of gray for fill squares
  278. X
  279. /hangingindent (   ) def        % for indenting continued text lines
  280. X
  281. X
  282. %
  283. % Utility functions:
  284. %
  285. X
  286. X
  287. /center {        % print string centered in given width
  288. X    /width exch def
  289. X    /str exch def
  290. X    width str stringwidth pop sub 2 div 0 rmoveto str show
  291. } def
  292. X
  293. X
  294. /strcat {        % concatenate two strings
  295. X    2 copy
  296. X    length exch length
  297. X    dup 3 -1 roll add
  298. X    string
  299. X    dup 0 6 -1 roll putinterval
  300. X    dup 3 -1 roll 4 -1 roll putinterval
  301. } def
  302. X
  303. X
  304. /prtday {        % print the date in black, gray, or outline
  305. X    day 3 string cvs                % convert to string
  306. X    color (outline) eq {
  307. X        true charpath stroke            % print as outline
  308. X    }
  309. X    {
  310. X        color (gray) eq { dategray setgray } if    % print in gray
  311. X        show
  312. X    } ifelse
  313. } def
  314. X
  315. X
  316. /nextbox {        % go to next column or start of next row
  317. X    day startday add 7 mod 0 eq                % end of week?
  318. X        { neggridwidth daywidth add negdayheight rmoveto }  % next row
  319. X        { daywidth 0 rmoveto }                    % next col
  320. X    ifelse
  321. } def
  322. X
  323. X
  324. /datepos {        % push coords of upper-left corner of box for day <arg>
  325. X    startday add 1 sub dup 7 mod daywidth mul        % x-coord
  326. X    exch 7 idiv negdayheight mul Y0 add            % y-coord
  327. } def
  328. X    
  329. X
  330. %
  331. % Functions for drawing parts of calendar:
  332. %
  333. X
  334. X
  335. /drawtitle {        % draw month and year title
  336. X    titlefont findfont titlefontsize calsize get scalefont setfont
  337. X    /month_name month_names month 1 sub get def
  338. X    /yearstring year 10 string cvs def
  339. X    0 Y0 titlepos calsize get add moveto
  340. X    month_name (  ) strcat yearstring strcat gridwidth center
  341. } def
  342. X
  343. X
  344. /drawdaynames {        % draw day names above respective columns
  345. X    dayfont findfont weekdayfontsize calsize get scalefont setfont
  346. X    0 1 6 {
  347. X        /i exch def
  348. X        i daywidth mul Y0 5 add moveto
  349. X        day_names i get
  350. X        daywidth center
  351. X    } for
  352. } def
  353. X
  354. X
  355. /drawgrid {        % draw the grid for the calendar
  356. X    gridlinewidth setlinewidth
  357. X    0 daywidth gridwidth {            % vertical lines
  358. X        Y0 moveto
  359. X        0 neggridheight rlineto
  360. X        stroke
  361. X    } for
  362. X    0 negdayheight neggridheight {        % horizontal lines
  363. X        0 exch Y0 add moveto
  364. X        gridwidth 0 rlineto
  365. X        stroke
  366. X    } for
  367. } def
  368. X
  369. X
  370. /drawnums {        % place day numbers on calendar
  371. X    dayfont findfont datefontsize calsize get scalefont setfont
  372. X    /fontdiff datefontsize calsize get datefontsize LG get sub def
  373. X    charlinewidth setlinewidth
  374. X    1 datepos 20 fontdiff add sub exch 5 add exch moveto
  375. X
  376. X    1 1 ndays {
  377. X        /day exch def
  378. X        /color (black) def
  379. X        calsize SM ne {        % select alternate color
  380. X            /gray day_gray day startday add 1 sub 7 mod get def
  381. X            holidays { day eq { /gray holiday_gray def } if } forall
  382. X            gray {
  383. X                /color outline {(outline)} {(gray)} ifelse def
  384. X            } if
  385. X        } if
  386. X        gsave
  387. X        prtday
  388. X        grestore
  389. X        nextbox
  390. X    } for
  391. } def
  392. X
  393. X
  394. /drawjnums {        % place day-of-year numbers on calendar
  395. X    notesfont findfont notesfontsize scalefont setfont
  396. X    1 datepos dayheight 3 sub sub exch daywidth 3 sub add exch moveto
  397. X
  398. X    1 1 ndays {
  399. X        /day exch def
  400. X        /jday jdstart day add 1 sub def
  401. X        /str jday 3 string cvs def
  402. X        julian-dates true eq {        % print days left in year?
  403. X            /str str ( \050) strcat yearlen jday sub 3 string cvs
  404. X                strcat (\051) strcat def
  405. X        } if
  406. X        gsave
  407. X        str dup stringwidth pop 0 exch sub 0 rmoveto show
  408. X        grestore
  409. X        nextbox
  410. X    } for
  411. } def
  412. X
  413. X
  414. /fillboxes {        % used by drawfill to generate row of fill squares
  415. X    /last exch def        % last box to fill (0 = Sun)
  416. X    /first exch def        % first box to fill (0 = Sun)
  417. X    /width last first sub 1 add daywidth mul def
  418. X
  419. X    width 0 gt {
  420. X        gsave
  421. X        first daywidth mul 0 rmoveto
  422. X        fillgray setgray
  423. X        width 0 rlineto
  424. X        0 negdayheight rlineto
  425. X        width neg 0 rlineto
  426. X        closepath fill
  427. X        grestore
  428. X    } if
  429. } def
  430. X
  431. X
  432. /drawfill {        % generate fill squares where necessary
  433. X    /firstbox startday ndays add def
  434. X    /lastbox calsize LG ne {41} { note_block {38} {39} ifelse } ifelse def
  435. X
  436. X    0 Y0 moveto            % boxes (if any) at start of first row
  437. X    0 startday 1 sub fillboxes
  438. X
  439. X    0 4 negdayheight mul rmoveto    % boxes (if any) at end of fifth row
  440. X    firstbox 35 lt {
  441. X        firstbox 7 mod 6 fillboxes
  442. X        /firstbox 35 def
  443. X    } if
  444. X
  445. X    0 negdayheight rmoveto        % boxes at end of bottom row
  446. X    firstbox 7 mod lastbox 7 mod fillboxes
  447. } def
  448. X
  449. X
  450. /footstrings {        % print foot strings at bottom of page
  451. X    titlefont findfont footfontsize scalefont setfont
  452. X    /bottomrow { neggridheight 20 add } def
  453. X    0 bottomrow moveto
  454. X    Lfootstring show
  455. X    gridwidth Rfootstring stringwidth pop sub bottomrow moveto
  456. X    Rfootstring show
  457. X    0 bottomrow moveto
  458. X    Cfootstring gridwidth center
  459. } def
  460. X
  461. X
  462. %
  463. % Functions for printing text inside boxes:
  464. %
  465. X
  466. X
  467. /daytext {
  468. X    notesfont findfont notesfontsize scalefont setfont
  469. X    /mytext    exch def /day exch def
  470. X    day datepos 29 sub dup /ypos exch def exch 2 add exch moveto
  471. X    currentpoint pop /LM exch def /RM LM 95 add def
  472. X    showtext
  473. } def
  474. X    
  475. X
  476. /holidaytext {        % print text for holiday (next to date)
  477. X    notesfont findfont notesfontsize scalefont setfont
  478. X    /mytext    exch def /day exch def
  479. X    /dwidth day 10 lt {20} {33} ifelse def        % width of date
  480. X    /mwidth do-moon-p {16} {0} ifelse def        % width of moon icon
  481. X    day datepos 8 sub dup /ypos exch def exch dwidth add exch moveto
  482. X    currentpoint pop /LM exch def /RM LM 97 dwidth mwidth add sub add def
  483. X    showtext
  484. } def
  485. X
  486. X
  487. /notetext {        % print text in notes box
  488. X    dayfont findfont 12 scalefont setfont
  489. X    /day 40 startday sub def        % "date" of notes box
  490. X    day datepos 11 sub exch 4 add exch moveto
  491. X    notesheading show
  492. X
  493. X    notesfont findfont notesfontsize scalefont setfont
  494. X    /mytext    exch def
  495. X    day datepos 19 sub dup /ypos exch def exch 4 add exch moveto
  496. X    /LM currentpoint pop def /RM LM 93 add def
  497. X    showtext
  498. } def
  499. X
  500. X
  501. /crlf {            % simulate CR/LF sequence
  502. X    ypos notesfontsize sub /ypos exch def LM ypos moveto
  503. } def
  504. X
  505. X
  506. /prstr {        % print string on current or next line
  507. X    dup stringwidth pop currentpoint pop
  508. X    add RM gt { crlf hangingindent show } if show
  509. } def
  510. X
  511. X
  512. /showtext {        % print words in "mytext", splitting into lines
  513. X    mytext {
  514. X        dup linesep eq            % force new line?
  515. X            { crlf pop }        % yes - discard text
  516. X            { prstr ( ) show }    % no - print string + space
  517. X        ifelse
  518. X    } forall
  519. } def
  520. X
  521. X
  522. %
  523. % Functions for printing months of various sizes and orientations:
  524. %
  525. X
  526. X
  527. /startpage {        % initialize new physical page
  528. X    rval rotate
  529. X    xsval ysval scale
  530. X    xtval ytval translate
  531. } def
  532. X
  533. X
  534. /calendar        % draw calendar for month/year
  535. {
  536. X    drawtitle                    % month/year heading
  537. X
  538. X    calsize SM ne {                    % day names
  539. X        drawdaynames
  540. X    } if
  541. X
  542. X    calsize LG eq {                    % foot strings
  543. X        footstrings
  544. X    } if
  545. X
  546. X    drawnums                    % calendar dates
  547. X
  548. X    julian-dates false ne calsize LG eq and {    % julian dates
  549. X        drawjnums
  550. X    } if
  551. X
  552. X    fill-boxes {                    % fill unused boxes
  553. X        drawfill
  554. X    } if
  555. X
  556. X    drawgrid                    % calendar grid
  557. X
  558. X    draw-moons false ne calsize LG eq and {        % moon icons
  559. X        drawmoons
  560. X    } if
  561. X
  562. X    0 0 moveto                    % return to origin
  563. } def
  564. X
  565. X
  566. /printmonth_l {        % print month on landscape page ("posn" = 0..11)
  567. X    /calsize MED def
  568. X
  569. X    posn 0 eq {        % assume first month printed on page is posn 0
  570. X        startpage
  571. X        footstrings
  572. X    } if
  573. X
  574. X    gsave            % draw medium calendar at selected position
  575. X    .226 .25 scale        % landscape mode - 3 rows, 4 cols
  576. X    posn 4 mod 800 mul
  577. X    posn 4 idiv -700 mul 150 add
  578. X    translate
  579. X    calendar
  580. X    grestore
  581. } def
  582. X
  583. X
  584. /printmonth_p {        % print month on portrait page ("posn" = 0..11)
  585. X    /calsize MED def
  586. X    /footfontsize 15 def    % compensate for scaling
  587. X
  588. X    posn 0 eq {        % assume first month printed on page is posn 0
  589. X        gsave        % print foot strings at original scale
  590. X        startpage
  591. X        0 20 translate  % move foot strings up slightly 
  592. X        footstrings
  593. X        grestore    % re-scale Y axis for portrait mode
  594. X        /sv_ysval ysval def
  595. X        /ysval ysval 1.675 mul def
  596. X        startpage
  597. X        /ysval sv_ysval def
  598. X    } if
  599. X
  600. X    gsave            % draw medium calendar at selected position
  601. X    .304 .194 scale        % portrait mode - 4 rows, 3 cols
  602. X    posn 3 mod 800 mul
  603. X    posn 3 idiv -700 mul 300 add
  604. X    translate
  605. X    calendar
  606. X    grestore
  607. } def
  608. X
  609. X
  610. /printmonth {        % print single month on page
  611. X    startpage
  612. X
  613. X    /calsize LG def            % main (large) calendar
  614. X    calendar
  615. X    
  616. X    gsave                % small calendars
  617. X    /calsize SM def
  618. X    /sv_startday startday def
  619. X
  620. X    % calculate previous and next month, year, and starting day
  621. X
  622. X    /lmonth month 1 eq { 12 } { month 1 sub } ifelse def
  623. X    /lyear  month 1 eq { year 1 sub } { year } ifelse def
  624. X    /lstartday startday 35 add lndays sub 7 mod def
  625. X    /nmonth month 12 eq { 1 } { month 1 add } ifelse def
  626. X    /nyear  month 12 eq { year 1 add } { year } ifelse def
  627. X    /nstartday startday ndays add 7 mod def
  628. X
  629. X    /year lyear def            % prev month/year
  630. X    /month lmonth def
  631. X    /startday lstartday def
  632. X    /ndays lndays def
  633. X    5 daywidth mul 5 negdayheight mul Y0 add translate
  634. X    gsave
  635. X    .138 .138 scale
  636. X    12 -120 translate
  637. X    calendar
  638. X    grestore
  639. X
  640. X    /year nyear def            % next month/year
  641. X    /month nmonth def
  642. X    /startday nstartday def
  643. X    /ndays nndays def
  644. X    daywidth 0 translate
  645. X    gsave
  646. X    .138 .138 scale
  647. X    12 -120 translate
  648. X    calendar
  649. X    grestore
  650. X
  651. X    /startday sv_startday def    % restore starting day (for text boxes)
  652. X    grestore
  653. } def
  654. X
  655. X
  656. %
  657. % Moon drawing functions:
  658. %
  659. X
  660. X
  661. /domoon {    % draw moon at phase (0 = new; .25 = 1q; .5 = full; .75 = 3q)
  662. X    /phase exch def
  663. X
  664. X    gsave
  665. X    currentpoint translate
  666. X    newpath
  667. X
  668. X    % if moon is full, just draw unfilled circle
  669. X
  670. X    phase halfperiod .01 sub ge phase halfperiod .01 add le and {
  671. X        0 0 radius
  672. X        0 360 arc stroke
  673. X    }
  674. X    {
  675. X        % draw the line arc now; prepare (but don't draw) the fill arc
  676. X
  677. X        0 0 radius            % for line and fill arcs
  678. X        0 0 radius 
  679. X        phase halfperiod lt {        % phase between new and full
  680. X            270 90 arc stroke    % (line on right, fill on left)
  681. X            0 radius neg moveto
  682. X            270 90 arcn 
  683. X        }
  684. X        {                % phase between full and new
  685. X            90 270 arc stroke    % (line on left, fill on right)
  686. X            0 radius neg moveto
  687. X            270 90 arc 
  688. X            /phase phase halfperiod sub def
  689. X        } ifelse
  690. X
  691. X        % curveto uses (x0,y0) (current point), (x1,y1), (x2,y2),
  692. X        % and (x3,y3) as the control points for drawing a Bezier
  693. X        % cubic section, used here as the curve dividing the moon
  694. X        % icon into dark and light sections.  x1 is in the range
  695. X        % -R*sqrt(2) <= x1 <= R*sqrt(2) and y1 is in the range
  696. X        % 0 <= y1 <= R; note that except in the degenerate case
  697. X        % where x1 = y1 = x2 = y2 = 0, the curve does not actually
  698. X        % pass through (x1,y1) or (x2,y2).
  699. X
  700. X        /x1 quartperiod phase sub rect mul def
  701. X        /y1 x1 abs 2 sqrt div def
  702. X
  703. X        % push control points for curveto
  704. X
  705. X                    % x0 = 0   (current
  706. X                    % y0 = R    point)
  707. X        x1            % x1
  708. X        y1            % y1
  709. X        x1            % x2 = x1
  710. X        y1 neg            % y2 = -y1
  711. X        0            % x3 = 0
  712. X        radius neg        % y3 = -R
  713. X
  714. X        % draw Bezier curve; fill area between curve and fill arc
  715. X
  716. X        curveto
  717. X        fill
  718. X    } ifelse
  719. X
  720. X    grestore
  721. } def
  722. X
  723. X
  724. /do-moon-p {        % draw a moon on "day"?
  725. X    draw-moons (some) eq {        % printing quarter moons?  look up day
  726. X        /p false def
  727. X        quarter_moons { day eq { /p true def } if } forall
  728. X        p
  729. X    }
  730. X    {
  731. X        draw-moons        % all moons or no moons
  732. X    } ifelse
  733. } def
  734. X
  735. X
  736. /drawmoons {        % main routine to draw moons on calendar
  737. X    /halfperiod 0.5 def
  738. X    /quartperiod 0.25 def
  739. X    /radius 6 def
  740. X    /offset radius 3 add def
  741. X    /rect radius 2 sqrt mul quartperiod div def    % domoon{} scale factor
  742. X    /n 0 def
  743. X
  744. X    gsave
  745. X    moonlinewidth setlinewidth
  746. X    1 datepos offset sub exch daywidth add offset sub exch moveto
  747. X    1 1 ndays {
  748. X        /day exch def
  749. X        do-moon-p {            % draw a moon today?
  750. X            moon_phases n get domoon
  751. X            /n n 1 add def
  752. X        } if
  753. X    nextbox
  754. X    } for
  755. X    grestore
  756. } def
  757. SHAR_EOF
  758. chmod 0666 pcalinit.ps ||
  759. echo 'restore of pcalinit.ps failed'
  760. Wc_c="`wc -c < 'pcalinit.ps'`"
  761. test 13415 -eq "$Wc_c" ||
  762.     echo 'pcalinit.ps: original size 13415, current size' "$Wc_c"
  763. fi
  764. # ============= pcallang.h ==============
  765. if test -f 'pcallang.h' -a X"$1" != X"-c"; then
  766.     echo 'x - skipping pcallang.h (File already exists)'
  767. else
  768. echo 'x - extracting pcallang.h (Text)'
  769. sed 's/^X//' << 'SHAR_EOF' > 'pcallang.h' &&
  770. /*
  771. X * pcallang.h - language-dependent strings (month and day names, option file 
  772. X * keywords, preprocessor tokens, prepositions, etc.):
  773. X *
  774. X * Revision history:
  775. X *
  776. X *    4.0    AWR    03/01/91    expand parameter message to explain
  777. X *                    parameter meaning when -w specified
  778. X *
  779. X *        AWR    02/19/91    revise ordinal definitions for
  780. X *                    support of negative ordinals
  781. X *
  782. X *        AWR    02/06/91    add text describing expression syntax
  783. X *
  784. X *        AWR    02/04/91    support "odd" and "even" ordinals
  785. X *
  786. X *        AWR    01/28/91    support -B (blank fill squares) flag
  787. X *                    and -O (outline "gray" dates) flag
  788. X *
  789. X *            01/16/91    added moon file support (tokens, help
  790. X *                    file text, error messages); define
  791. X *                    note block heading here
  792. X *
  793. X *            01/07/91    added support for -w (whole year) flag
  794. X *
  795. X *    3.0    AWR    12/10/90    added support for "workday", "weekday",
  796. X *                    "holiday", et. al.
  797. X *
  798. X *        AWR    11/15/90    extracted from pcal.c; revised
  799. X *                    to contain all language-dependent
  800. X *                    strings
  801. X */
  802. X
  803. #define ALL    "all"        /* command-line or date file keyword */
  804. X
  805. #ifdef MAIN_MODULE
  806. X
  807. char *months[12] = {
  808. X    "January", "February", "March", "April", "May", "June",
  809. X    "July", "August", "September", "October", "November", "December"
  810. X    };
  811. X
  812. /* Must be a 2-D array so address within may be used as an initializer;
  813. X * wildcard names must be in same order as symbolic names in pcaldefs.h
  814. X */
  815. char days[14][12] = {
  816. X        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  817. X        "Saturday",         /* weekday names */
  818. X    "day", "weekday", "workday", "holiday", "nonweekday", "nonworkday",
  819. X    "nonholiday"        /* wildcards */
  820. X    };
  821. X
  822. /* preprocessor tokens: token name, token code, dispatch routine */
  823. X
  824. KWD_F pp_info[] = {
  825. X    "define",    PP_DEFINE,    do_define,
  826. X    "else",        PP_ELSE,    NULL,
  827. X    "endif",    PP_ENDIF,    NULL,
  828. X    "ifdef",    PP_IFDEF,    do_ifdef,
  829. X    "ifndef",    PP_IFNDEF,    do_ifndef,
  830. X    "include",    PP_INCLUDE,    NULL,        /* do_include */
  831. X    "undef",    PP_UNDEF,    do_undef,
  832. X    NULL,        PP_OTHER,    NULL };        /* must be last */
  833. X
  834. /* ordinal numbers - e.g. "first Monday in September": ordinal name,
  835. X * ordinal code, ordinal value; note that "all" is parsed as a keyword
  836. X * and (depending on context) may be subsequently treated as an ordinal
  837. X */
  838. X
  839. KWD_O ordinals[] = {
  840. X    "first",    ORD_POSNUM,     1,
  841. X    "second",    ORD_POSNUM,     2,
  842. X    "third",    ORD_POSNUM,     3,
  843. X    "fourth",    ORD_POSNUM,     4,
  844. X    "fifth",    ORD_POSNUM,     5,
  845. X    "last",        ORD_NEGNUM,    -1,
  846. X    "odd",        ORD_ODD,     0,
  847. X    "even",        ORD_EVEN,     0,
  848. X    NULL,        ORD_OTHER,     0 };        /* must be last */
  849. X
  850. /* allowable suffixes for ordinal numbers */
  851. X
  852. char *ord_suffix[] = { "st", "nd", "rd", "th", NULL };
  853. X
  854. /* prepositions - e.g., "Friday after fourth Thursday in November" */
  855. X
  856. KWD preps[] = {
  857. X    "before",    PR_BEFORE,
  858. X    "preceding",    PR_BEFORE,
  859. X    "on_or_before",    PR_ON_BEFORE,
  860. X    "oob",        PR_ON_BEFORE,
  861. X    "after",    PR_AFTER,
  862. X    "following",    PR_AFTER,
  863. X    "on_or_after",    PR_ON_AFTER,
  864. X    "ooa",        PR_ON_AFTER,
  865. X    NULL,        PR_OTHER };    /* must be last */
  866. X
  867. /* other keywords */
  868. X
  869. KWD keywds[] = {
  870. X    ALL,         DT_ALL,
  871. X    "each",        DT_ALL,
  872. X    "every",    DT_ALL,
  873. X    "note",        DT_NOTE,
  874. X    "opt",        DT_OPT,
  875. X    "year",        DT_YEAR,
  876. X    NULL,        DT_OTHER };    /* must be last */
  877. X
  878. /* moon phases (for moon file) */
  879. X
  880. KWD phases[] = {
  881. X    "NM",        MOON_NM,    /* new moon */
  882. X    "1Q",        MOON_1Q,    /* first quarter */
  883. X    "FQ",        MOON_1Q,    
  884. X    "FM",        MOON_FM,    /* full moon */
  885. X    "3Q",        MOON_3Q,    /* third (last) quarter */
  886. X    "LQ",        MOON_3Q,
  887. X    NULL,        MOON_OTHER };    /* must be last */
  888. X
  889. #else
  890. extern char *months[];
  891. extern char days[14][12];
  892. extern KWD_F pp_info[];
  893. extern KWD preps[];
  894. extern KWD_O ordinals[];
  895. extern char *ord_suffix[];
  896. extern KWD keywds[];
  897. extern KWD phases[];
  898. #endif
  899. X
  900. /* minimum size of abbreviations  */
  901. X
  902. #define MIN_DAY_LEN    3
  903. #define MIN_MONTH_LEN    3
  904. #define MIN_PPTOK_LEN    3
  905. #define MIN_PREP_LEN    7    /* distinguish "on_or_before", "on_or_after" */
  906. #define MIN_ORD_LEN    3    /* distinguish "Thursday" from "third" */
  907. X
  908. X
  909. /*
  910. X * Symbolic names for command-line flags.  These may be changed
  911. X * as desired in order to be meaningful in languages other than
  912. X * English.
  913. X */
  914. X
  915. #define F_INITIALIZE    'I'        /* re-initialize program defaults */
  916. #define    F_BLACK_DAY    'b'        /* print day in black */
  917. #define F_GRAY_DAY    'g'        /* print day in gray */
  918. X
  919. #define F_DAY_FONT    'd'        /* select alternate day font */
  920. #define F_NOTES_FONT    'n'        /* select alternate notes font */
  921. #define F_TITLE_FONT    't'        /* select alternate title font */
  922. X
  923. #define F_EMPTY_CAL    'e'        /* print empty calendar */
  924. #define F_DATE_FILE    'f'        /* select alternate date file */
  925. #define F_OUT_FILE    'o'        /* select alternate output file */
  926. X
  927. #define F_LANDSCAPE    'l'        /* landscape mode */
  928. #define F_PORTRAIT    'p'        /* portrait mode */
  929. X
  930. #define F_HELP        'h'        /* generate help message */
  931. X
  932. #define F_MOON_4    'm'        /* print new/half/full moons */
  933. #define F_MOON_ALL    'M'        /* print all moons */
  934. X
  935. #define F_DEFINE    'D'        /* define preprocessor symbol */
  936. #define F_UNDEF        'U'        /* undefine preprocessor symbol */
  937. X
  938. #define F_L_FOOT    'L'        /* define left foot string */
  939. #define F_C_FOOT    'C'        /* define center foot string */
  940. #define F_R_FOOT    'R'        /* define right foot string */
  941. X
  942. #define F_FIRST_DAY    'F'        /* define alternate starting day */
  943. X
  944. #define F_USA_DATES    'A'        /* parse American date format */
  945. #define F_EUR_DATES    'E'        /* parse European date format */
  946. X
  947. #define F_X_TRANS    'X'        /* X-axis transformation */
  948. #define F_Y_TRANS    'Y'        /* Y-axis transformation */
  949. #define F_X_SCALE    'x'        /* X-axis scale factor */
  950. #define F_Y_SCALE    'y'        /* Y-axis scale factor */
  951. X
  952. #define F_JULIAN    'j'        /* print Julian day (day of year) */
  953. #define F_JULIAN_ALL    'J'        /* print Julian day and days left */
  954. X
  955. #define F_WHOLE_YEAR    'w'        /* print whole year per page */
  956. X                    /* (cf. W_WYFLAG below) */
  957. X
  958. #define F_BLANK_BOXES    'B'        /* don't fill unused boxes */
  959. X
  960. #define F_OUTLINE    'O'        /* draw "gray" dates as outlines */
  961. X
  962. /*
  963. X * Flag usage information - not strictly language-dependent, but here anyway
  964. X * (N.B.: all flags must be represented by an entry in this table!)
  965. X *
  966. X * Flags may appear in any of three places: in environment variable
  967. X * PCAL_OPTS, on the command line, or in "opt" lines in the date file.
  968. X * The command line is actually parsed twice: once before reading the date
  969. X * file to get the flags needed in processing it (-e, -f, -b, -g, -D, -U, -A,
  970. X * -E), and again after reading the date file to give the user one last
  971. X * chance to override any of the other flags set earlier.  (Note, however,
  972. X * that the only way to turn off -J|-j [Julian dates], -M|-m [moons], -w
  973. X * [whole year], or -O [outline "gray" dates] once selected is to use -I
  974. X * to reinitialize all program defaults.)
  975. X *
  976. X * The table below supplies the following information about each flag:
  977. X *
  978. X *    - Its name (cf. symbolic definitions above)
  979. X *
  980. X *    - Whether or not it can take an (optional) argument
  981. X *
  982. X *    - Which passes parse it: P_ENV (environment variable), P_CMD1
  983. X *      (first command line pass), P_OPT ("opt" lines in date file), 
  984. X *      and P_CMD2 (second command line pass)
  985. X *
  986. X */
  987. X
  988. #ifdef MAIN_MODULE
  989. X
  990. FLAG_USAGE flag_tbl[] = {
  991. X
  992. /*    flag name    arg?    passes where parsed        */
  993. X
  994. X    F_INITIALIZE,    FALSE,    P_ENV | P_CMD1 | P_OPT | P_CMD2 ,
  995. X
  996. X    F_BLACK_DAY,    TRUE,    P_ENV | P_CMD1 | P_OPT          ,
  997. X    F_GRAY_DAY,    TRUE,    P_ENV | P_CMD1 | P_OPT          ,
  998. X
  999. X    F_DAY_FONT,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1000. X    F_NOTES_FONT,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1001. X    F_TITLE_FONT,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1002. X
  1003. X    F_EMPTY_CAL,    FALSE,    P_ENV | P_CMD1                  ,
  1004. X    F_DATE_FILE,    TRUE,    P_ENV | P_CMD1                  ,
  1005. X    F_OUT_FILE,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1006. X
  1007. X    F_LANDSCAPE,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1008. X    F_PORTRAIT,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1009. X
  1010. X    F_HELP,        FALSE,            P_CMD1                  ,
  1011. X
  1012. X    F_MOON_4,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1013. X    F_MOON_ALL,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1014. X
  1015. X    F_DEFINE,    TRUE,    P_ENV | P_CMD1                  ,
  1016. X    F_UNDEF,    TRUE,    P_ENV | P_CMD1                  ,
  1017. X
  1018. X    F_L_FOOT,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1019. X    F_C_FOOT,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1020. X    F_R_FOOT,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1021. X
  1022. X    F_FIRST_DAY,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1023. X
  1024. X    F_USA_DATES,    FALSE,    P_ENV | P_CMD1 | P_OPT          ,
  1025. X    F_EUR_DATES,    FALSE,    P_ENV | P_CMD1 | P_OPT          ,
  1026. X
  1027. X    F_X_TRANS,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1028. X    F_Y_TRANS,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1029. X    F_X_SCALE,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1030. X    F_Y_SCALE,    TRUE,    P_ENV          | P_OPT | P_CMD2 ,
  1031. X
  1032. X    F_JULIAN,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1033. X    F_JULIAN_ALL,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1034. X
  1035. X    F_WHOLE_YEAR,    FALSE,    P_ENV | P_CMD1 | P_OPT          ,
  1036. X
  1037. X    F_BLANK_BOXES,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1038. X
  1039. X    F_OUTLINE,    FALSE,    P_ENV          | P_OPT | P_CMD2 ,
  1040. X
  1041. X    '-',        FALSE,    P_ENV | P_CMD1 | P_OPT | P_CMD2 ,
  1042. X    '\0',        FALSE,    P_ENV | P_CMD1 | P_OPT | P_CMD2        /* must be last */
  1043. X    };
  1044. X
  1045. #else
  1046. extern FLAG_USAGE flag_tbl[];
  1047. #endif
  1048. X
  1049. /*
  1050. X * Words used in usage() message - translate as necessary
  1051. X */
  1052. X
  1053. #define W_DEFAULT    "default"        /* translate as required */
  1054. #define W_USAGE        "Usage"
  1055. X
  1056. #define W_FONT        "FONT"            /* names of metavariables */
  1057. #define W_DAY        "DAY"
  1058. #define W_STRING    "STRING"
  1059. #define W_FILE        "FILE"
  1060. #define W_SYMBOL    "SYMBOL"
  1061. #define W_VALUE        "VALUE"
  1062. X
  1063. #define W_MM        "MM"            /* abbrev. for month, year */
  1064. #define W_YY        "YY"
  1065. X
  1066. #define W_WYFLAG    "-w"            /* must conform to F_WHOLE_YEAR */
  1067. X
  1068. #define W_BLACK        "black"            /* cf. color_msg() */
  1069. #define W_GRAY        "gray"
  1070. X
  1071. X
  1072. /* special flag_msg[] entries for end of option group, etc. */
  1073. X
  1074. #define END_GROUP    '\n', NULL, NULL, NULL        /* end of option group */
  1075. #define END_LIST    '\0', NULL, NULL, NULL        /* end of list */
  1076. #define GROUP_DEFAULT    ' ', NULL, " "            /* group default */
  1077. X
  1078. /*
  1079. X * Message strings to be printed by usage() - translate as necessary
  1080. X */
  1081. #ifdef MAIN_MODULE
  1082. X
  1083. FLAG_MSG flag_msg[] = {
  1084. X
  1085. /*    flag name    metasyntax    description                        default */
  1086. X
  1087. X    F_INITIALIZE,    NULL,        "initialize all parameters to program defaults",    NULL,
  1088. X    END_GROUP,
  1089. X
  1090. X    F_BLACK_DAY,    W_DAY,        "print weekday in black",                NULL,
  1091. X    F_GRAY_DAY,    W_DAY,        "print weekday in gray (see below)",                NULL,
  1092. X    END_GROUP,
  1093. X
  1094. X    F_OUTLINE,    NULL,        "print \"gray\" dates as outlined characters",            NULL,
  1095. X
  1096. X    END_GROUP,
  1097. X
  1098. X    F_DAY_FONT,    W_FONT,        "specify alternate day name font",            DAYFONT,
  1099. X    F_NOTES_FONT,    W_FONT,        "specify alternate notes font",                NOTESFONT,
  1100. X    F_TITLE_FONT,    W_FONT,        "specify alternate title font",                TITLEFONT,
  1101. X    END_GROUP,
  1102. X
  1103. X    F_EMPTY_CAL,    NULL,        "generate empty calendar (ignore date file)",        NULL,
  1104. X    END_GROUP,
  1105. X
  1106. X    F_DATE_FILE,    W_FILE,        "specify alternate date file",                DATEFILE,
  1107. X    END_GROUP,
  1108. X
  1109. #ifdef DEFAULT_OUTFILE
  1110. X    F_OUT_FILE,    W_FILE,        "specify alternate output file",            DEFAULT_OUTFILE,
  1111. #else
  1112. X    F_OUT_FILE,    W_FILE,        "specify alternate output file",            "stdout",
  1113. #endif
  1114. X    END_GROUP,
  1115. X
  1116. X    F_LANDSCAPE,    NULL,        "generate landscape-style calendar",            NULL,
  1117. X    F_PORTRAIT,    NULL,        "generate portrait-style calendar",            NULL,
  1118. #if ROTATE == LANDSCAPE
  1119. X    GROUP_DEFAULT,                                        "landscape",
  1120. #else    
  1121. X    GROUP_DEFAULT,                                        "portrait",
  1122. #endif
  1123. X    END_GROUP,
  1124. X
  1125. X    F_HELP,        NULL,        "print this help message",                NULL,
  1126. X    END_GROUP,
  1127. X
  1128. X    F_MOON_4,    NULL,        "draw a \"moon\" icon at full/new/half moons",        NULL,
  1129. X    F_MOON_ALL,    NULL,        "draw a \"moon\" icon every day",            NULL,
  1130. #if DRAW_MOONS == NO_MOONS
  1131. X    GROUP_DEFAULT,                                        "no moons",
  1132. #else
  1133. #if DRAW_MOONS == SOME_MOONS
  1134. X    GROUP_DEFAULT,                                        "full/new/half moons",
  1135. #else
  1136. X    GROUP_DEFAULT,                                        "every day",
  1137. #endif
  1138. #endif
  1139. X    END_GROUP,
  1140. X
  1141. X    F_DEFINE,    W_SYMBOL,    "define preprocessor symbol",                NULL,
  1142. X    F_UNDEF,    W_SYMBOL,    "undefine preprocessor symbol",                NULL,
  1143. X    END_GROUP,
  1144. X
  1145. X    F_L_FOOT,    W_STRING,    "specify left foot string",                LFOOT,
  1146. X    F_C_FOOT,    W_STRING,    "specify center foot string",                CFOOT,
  1147. X    F_R_FOOT,    W_STRING,    "specify right foot string",                RFOOT,
  1148. X    END_GROUP,
  1149. X
  1150. X    F_FIRST_DAY,    W_DAY,        "specify starting day of week",                days[FIRST_DAY],
  1151. X    END_GROUP,
  1152. X
  1153. X    F_USA_DATES,    NULL,        "parse American dates (\"mm/dd{/yy}\" and \"month dd\")", NULL,
  1154. X    F_EUR_DATES,    NULL,        "parse European dates (\"dd/mm{/yy}\" and \"dd month\")", NULL,
  1155. #if DATE_STYLE == USA_DATES
  1156. X    GROUP_DEFAULT,                                        "American",
  1157. #else
  1158. X    GROUP_DEFAULT,                                        "European",
  1159. #endif
  1160. X    END_GROUP,
  1161. X
  1162. X    F_X_TRANS,    W_VALUE,    "specify x-axis translation",                XTVAL,
  1163. X    F_Y_TRANS,    W_VALUE,    "specify y-axis translation",                YTVAL,
  1164. X    F_X_SCALE,    W_VALUE,    "specify x-axis scale factor",                XSVAL,
  1165. X    F_Y_SCALE,    W_VALUE,    "specify y-axis scale factor",                YSVAL,
  1166. X    END_GROUP,
  1167. X
  1168. X    F_JULIAN,    NULL,        "print Julian day (day of year)",            NULL,
  1169. X    F_JULIAN_ALL,    NULL,        "print Julian day and days left in year",        NULL,
  1170. #if JULIAN_DATES == NO_JULIANS
  1171. X    GROUP_DEFAULT,                                        "neither",
  1172. #else
  1173. #if JULIAN_DATES == SOME_JULIANS
  1174. X    GROUP_DEFAULT,                                        "Julian day",
  1175. #else
  1176. X    GROUP_DEFAULT,                                        "both",
  1177. #endif
  1178. #endif
  1179. X    END_GROUP,
  1180. X
  1181. X    F_WHOLE_YEAR,    NULL,        "print whole year (12 consecutive months) per page",    NULL,
  1182. X    END_GROUP,
  1183. X
  1184. X    F_BLANK_BOXES,    NULL,        "leave unused boxes blank",                NULL,
  1185. X
  1186. X    END_GROUP,            /* must precede END_LIST */
  1187. X
  1188. X    END_LIST            /* must be last */
  1189. };
  1190. X
  1191. #else
  1192. extern FLAG_MSG flag_msg[];
  1193. #endif
  1194. X
  1195. /* Numeric parameter descriptions and text */
  1196. X
  1197. #ifdef MAIN_MODULE
  1198. X
  1199. #if __STDC__
  1200. PARAM_MSG param_msg[] = {
  1201. X    W_YY,            "generate calendar for year " W_YY " (19" W_YY " if " W_YY " < 100)",
  1202. X    W_MM " " W_YY,        "generate calendar for month " W_MM " (Jan = 1), year " W_YY,
  1203. X    W_MM " " W_YY " N",    "generate calendars for N months, starting at " W_MM "/" W_YY,
  1204. X    "(" W_DEFAULT ")",    "generate calendar for current month and/or year",
  1205. X    "",            "",
  1206. X    "if " W_WYFLAG " specified:",    "",
  1207. X    "",            "",
  1208. X    W_YY,            "generate calendar for year " W_YY " (19" W_YY " if " W_YY " < 100)",
  1209. X    W_MM " " W_YY,        "generate calendars for 12 months, starting at " W_MM "/" W_YY,
  1210. X    W_MM " " W_YY " N",    "generate calendars for N months, starting at " W_MM "/" W_YY,
  1211. X    "",            "  (N rounded up to next multiple of 12)",
  1212. X    "(" W_DEFAULT ")",    "generate calendar for current year",
  1213. X    NULL,        NULL        /* must be last */
  1214. };
  1215. #else
  1216. PARAM_MSG param_msg[] = {
  1217. X    "YY",        "generate calendar for year YY (19YY if YY < 100)",
  1218. X    "MM YY",    "generate calendar for month MM (Jan = 1), year YY",
  1219. X    "MM YY N",    "generate calendars for N months, starting at MM/YY",
  1220. X    "(default)",    "generate calendar for current month and year",
  1221. X    "",        "",
  1222. X    "if -w specified:",    "",
  1223. X    "",        "",
  1224. X    "YY",        "generate calendar for year YY (19YY if YY < 100)",
  1225. X    "MM YY",    "generate calendar for 12 months, starting at MM/YY",
  1226. X    "MM YY N",    "generate calendars for N months, starting at MM/YY",
  1227. X    "",        "  (N rounded up to next multiple of 12)",
  1228. X    "(default)",    "generate calendar for current year",
  1229. X    NULL,        NULL        /* must be last */
  1230. };
  1231. #endif
  1232. X
  1233. #else
  1234. extern PARAM_MSG param_msg[];
  1235. #endif
  1236. X
  1237. #define PARAM_MSGS    3    /* number of above to print in command-line syntax message */
  1238. X
  1239. /* Date file syntax message - lines are copied intact */
  1240. X
  1241. #ifdef MAIN_MODULE
  1242. X
  1243. char *date_msg[] = {
  1244. X    "",
  1245. X    "Date file syntax:",
  1246. X    "",
  1247. X    "The following rules describe the syntax of date file entries:",
  1248. X    "",
  1249. X    "  year <year>",
  1250. X    "",
  1251. X    "  opt <options>",
  1252. X    "",
  1253. X    "  note <month_spec> <text>",
  1254. X    "  note <month> <text>",
  1255. X    "",
  1256. X    "  if -A flag (American date formats) specified:",
  1257. X    "    <month_name> <day>{*} {<text>}",
  1258. X    "    <month><sep><day>{<sep><year>}{*} {<text>}",
  1259. X    "",
  1260. X    "  if -E flag (European date formats) specified:",
  1261. X    "    <day> <month_name>{*} {<text>}",
  1262. X    "    <day><sep><month>{<sep><year>}{*} {<text>}",
  1263. X    "",
  1264. X    "  <ordinal> <day_spec> in <month_spec>{*} {<text>}",
  1265. X    "  <day_spec> <prep> <date_spec>",
  1266. X    "",
  1267. X    "where",
  1268. X    "",
  1269. X    "  {x}          means x is optional",
  1270. X    "",
  1271. X    "  <date_spec> := any of the above date specs (not year, note, or opt)",
  1272. X    "  <month_name> := first 3+ characters of name of month, or \"all\"",
  1273. X    "  <month_spec> := <month_name>, or \"year\"",
  1274. X    "  <day_name> := first 3+ characters of name of weekday, \"day\",",
  1275. X    "                \"weekday\", \"workday\", \"holiday\", \"nonweekday\",",
  1276. X    "                \"nonworkday\", or \"nonholiday\"",
  1277. X    "  <ordinal> := ordinal number (\"1st\", \"2nd\", etc.), \"first\" .. \"fifth\",",
  1278. X    "                \"last\", \"even\", \"odd\", or \"all\"",
  1279. X    "  <prep> := \"before\", \"preceding\", \"after\", \"following\", \"on_or_before\",",
  1280. X    "                or \"on_or_after\"",
  1281. X    "  <sep> := one or more non-numeric, non-space, non-'*' characters",
  1282. X    "  <month>, <day>, <year> are the numeric forms",
  1283. X    "",
  1284. X    "  <options> := any command-line option except -e, -f, -h, -D, -U",
  1285. X    "",
  1286. X    "Comments start with '#' and run through end-of-line.",
  1287. X    "",
  1288. X    "Holidays may be flagged by specifying '*' as the last character of",
  1289. X    "the date field(s), e.g. \"10/12* Columbus Day\", \"July 4* Independence",
  1290. X    "Day\", etc.  Any dates flagged as holidays will be printed in gray, and",
  1291. X    "any associated text will appear adjacent to the date.",
  1292. X    "",
  1293. X    "Note that the numeric date formats (mm/dd{/yy}, dd.mm{.yy}) support",
  1294. X    "an optional year, which will become the subsequent default year.  The",
  1295. X    "alphabetic date formats (month dd, dd month) do not support a year",
  1296. X    "field; the \"year yy\" command is provided to reset the default year.",
  1297. X    "",
  1298. X    "\"Floating\" days may be specified in the date file as \"first Mon in ",
  1299. X    "Sep\", \"last Mon in May\", \"4th Thu in Nov\", etc.; any word may be",
  1300. X    "used in place of \"in\".  \"Relative floating\" days (e.g. \"Fri after 4th ",
  1301. X    "Thu in Nov\") are also accepted; they may span month/year bounds.",
  1302. X    "Pcal also accepts date specs such as \"all Friday{s} in October\", \"last",
  1303. X    "Thursday in all\", etc., and produces the expected results; \"each\" and",
  1304. X    "\"every\" are accepted as synonyms for \"all\".  Negative ordinals are",
  1305. X    "allowed; \"-2nd\" means \"next to last\".",
  1306. X    "",
  1307. X    "The words \"day\", \"weekday\", \"workday\", and \"holiday\" may be used as",
  1308. X    "wildcards: \"day\" matches any day, \"weekday\" matches any day normally",
  1309. X    "printed in black, \"workday\" matches any day normally printed in black",
  1310. X    "and not explicitly flagged as a holiday, and \"holiday\" matches any",
  1311. X    "day explicitly flagged as a holiday.  \"Nonweekday\", \"nonworkday\",",
  1312. X    "and \"nonholiday\" are also supported and have the obvious meanings.",
  1313. X    "",
  1314. X    "\"Odd\" and \"even\" do not refer to the actual date; instead, \"odd\"",
  1315. X    "means \"alternate, starting with the first\"; \"even\" means \"alternate,",
  1316. X    "starting with the second\".  Thus, \"odd Fridays in March\" refers to",
  1317. X    "the first, third, and (if present) fifth Fridays in March - not to",
  1318. X    "those Fridays falling on odd dates.",
  1319. X    "",
  1320. X    "\"All\" refers to each individual month; \"year\" refers to the year",
  1321. X    "as an entity.  Thus \"odd Fridays in all\" refers to the first/third/",
  1322. X    "fifth Friday of each month, while \"odd Fridays in year\" refers to",
  1323. X    "the first Friday of January and every other Friday thereafter.",
  1324. X    "",
  1325. X    "Additional notes may be propagated to an empty calendar box by the",
  1326. X    "inclusion of one or more lines of the form \"note <month> <text>\",",
  1327. X    "where <month> may be numeric or alphabetic; \"note all <text>\"",
  1328. X    "propagates <text> to each month in the current year.",
  1329. X    "",
  1330. X    "Simple cpp-like functionality is provided.  The date file may include",
  1331. X    "the following commands, which work like their cpp counterparts:",
  1332. X    "",
  1333. X    "        define <sym>",
  1334. X    "        undef <sym>",
  1335. X    "",
  1336. X    "        if{n}def <expr>",
  1337. X    "           ...",
  1338. X    "        { else",
  1339. X    "           ... }",
  1340. X    "        endif",
  1341. X    "",
  1342. X    "        include <file>",
  1343. X    "",
  1344. X    "Note that these do not start with '#', which is reserved as a comment",
  1345. X    "character.",
  1346. X    "",
  1347. X    "<sym> is a symbol name consisting of a letter followed by zero or",
  1348. X    "more letters, digits, or underscores ('_').  Symbol names are always",
  1349. X    "treated in a case-insensitive manner.",
  1350. X    "",
  1351. X    "<expr> is an expression consisting of symbol names joined by the logical",
  1352. X    "operators (in order of precedence, high to low) '!' (unary negate), '&'",
  1353. X    "(and), '^' (exclusive or), and '|' (inclusive or).  '&&' and '||' are",
  1354. X    "accepted as synonyms for '&' and '|' respectively; the order of",
  1355. X    "evaluation may be altered by the use of parentheses.  A symbol whose",
  1356. X    "name is currently defined evaluates to TRUE; one whose name is not",
  1357. X    "currently defined evaluates to FALSE.  Thus \"ifdef A | B | C\" is TRUE",
  1358. X    "if any of the symbols A, B, and C is currently defined, and",
  1359. X    "\"ifdef A & B & C\" is TRUE if all of them are.",
  1360. X    "",
  1361. X    "\"ifndef A | B | C\" is equivalent to \"ifdef !(A | B | C)\" (or, using",
  1362. X    "DeMorgan's Law, \"ifdef !A & !B & !C\") - in other words, TRUE if none of",
  1363. X    "the symbols A, B, and C is currently defined.",
  1364. X    "",
  1365. X    "\"define\" alone deletes all the current definitions; \"ifdef\" alone is",
  1366. X    "always false; \"ifndef\" alone is always true.",
  1367. X    "",
  1368. X    "The file name in the \"include\" directive may optionally be surrounded",
  1369. X    "by \"\" or <>.  In any case, path names are taken to be relative to",
  1370. X    "the location of the file containing the \"include\" directive.",
  1371. X    "",
  1372. X    "",
  1373. X    "Moon file syntax:",
  1374. X    "",
  1375. X    "Pcal normally calculates the approximate phase of the moon using",
  1376. X    "a simple algorithm which assumes (among other things) that the",
  1377. X    "length of the lunar month is constant and that the quarter moons",
  1378. X    "will occur on the same day worldwide.  For most users, that is",
  1379. X    "adequate; however, moon-phase freaks may enter the dates and",
  1380. X    "(optionally) times of quarter moons (from a reliable source such",
  1381. X    "as an almanac or astronomical table) into a file called .moonXX ",
  1382. X    "(moonXX.dat on VMS), where XX is the last two digits of the year.",
  1383. X    "If such a file exists (in the same directory as the date file),",
  1384. X    "pcal will interpolate the phase of the moon from the information",
  1385. X    "in this file instead of using the default algorithm.",
  1386. X    "",
  1387. X    "Entries in the moon file must conform to the following syntax:",
  1388. X    "",
  1389. X    "  if -A flag (American date formats) specified:",
  1390. X    "    <quarter> <month><sep><day> {<hour><sep><min>}",
  1391. X    "",
  1392. X    "  if -E flag (European date formats) specified:",
  1393. X    "    <quarter> <day><sep><month> {<hour><sep><min>}",
  1394. X    "",
  1395. X    "where",
  1396. X    "",
  1397. X    "  <quarter> := \"nm\", \"fq\" or \"1q\", \"fm\", \"3q\" or \"lq\" (new",
  1398. X    "                moon, first quarter, full moon, last quarter)",
  1399. X    "  <hour>    := number 0-23 (24-hour clock)",
  1400. X    "  <min>     := number 0-59",
  1401. X    "",
  1402. X    "This file must contain entries for all quarter moons in the year,",
  1403. X    "in chronological order; if any errors are encountered, pcal will",
  1404. X    "revert to using its default algorithm.",
  1405. X    "",
  1406. X    "As in the date file, comments start with '#' and run through",
  1407. X    "end-of-line.  ",
  1408. X    NULL
  1409. X    };
  1410. #else
  1411. extern char *date_msg[];
  1412. #endif
  1413. X
  1414. /* format strings for color_msg() - translate as necessary */
  1415. #define COLOR_MSG_1    "all days in %s"
  1416. #define COLOR_MSG_2    "in %s; others in %s"
  1417. X
  1418. /* format string for short usage() message */
  1419. #define USAGE_MSG    "enter \"%s -%c\" for full description of parameters\n"
  1420. X
  1421. /* format strings for comment in PostScript output file */
  1422. #define VERSION_MSG    "Generated by %s %s"
  1423. #define DATEFILE_MSG    " from %s"
  1424. X
  1425. #define NOTES_HDR    "Notes"        /* title of "notes" box */
  1426. #define LINE_SEP    ".p"        /* text line separator */
  1427. X
  1428. /* strings used in error messages */
  1429. #define ENV_VAR        "environment variable "
  1430. #define DATE_FILE    "date file "
  1431. X
  1432. /* Error and information messages - translate as necessary */
  1433. X
  1434. /* program error messages */
  1435. #define    E_ALLOC_ERR    "%s: calloc() failed - out of memory\n"
  1436. #define    E_FOPEN_ERR    "%s: can't open file %s\n"
  1437. #define    E_ILL_LINE    "%s: %s in file %s, line %d\n"
  1438. #define    E_ILL_MONTH    "%s: month %d not in range %d .. %d\n"
  1439. #define    E_ILL_OPT    "%s: unrecognized flag %s"
  1440. #define E_ILL_OPT2    " (%s\"%s\")"
  1441. #define    E_ILL_YEAR    "%s: year %d not in range %d .. %d\n"
  1442. #define    E_SYMFULL    "%s: symbol table full - can't define %s\n"
  1443. #define    E_UNT_IFDEF    "%s: unterminated if{n}def..{else..}endif in file %s\n"
  1444. #define E_FLAG_IGNORED    "%s: -%c flag ignored (%s\"%s\")\n"
  1445. X
  1446. /* preprocessor error strings */
  1447. #define E_ELSE_ERR    "unmatched \"else\""
  1448. #define E_END_ERR    "unmatched \"endif\""
  1449. #define E_GARBAGE    "extraneous data on \"%s\" line"
  1450. #define E_INV_DATE    "invalid date (or no match for wildcard)"
  1451. #define E_INV_LINE    "unrecognized line"
  1452. #define E_NESTING    "maximum file nesting level exceeded"
  1453. #define E_EXPR_SYNTAX    "syntax error in expression"
  1454. X
  1455. /* moon file error strings */
  1456. #define E_DATE_SEQ    "date or phase out of sequence"
  1457. #define E_PREM_EOF    "premature EOF"
  1458. X
  1459. /* information message (VMS, Amiga only) */
  1460. #define    I_OUT_NAME    "%s: output is in file %s\n"
  1461. X
  1462. SHAR_EOF
  1463. chmod 0666 pcallang.h ||
  1464. echo 'restore of pcallang.h failed'
  1465. Wc_c="`wc -c < 'pcallang.h'`"
  1466. test 23965 -eq "$Wc_c" ||
  1467.     echo 'pcallang.h: original size 23965, current size' "$Wc_c"
  1468. fi
  1469. # ============= pcalutil.c ==============
  1470. if test -f 'pcalutil.c' -a X"$1" != X"-c"; then
  1471.     echo 'x - skipping pcalutil.c (File already exists)'
  1472. else
  1473. echo 'x - extracting pcalutil.c (Text)'
  1474. sed 's/^X//' << 'SHAR_EOF' > 'pcalutil.c' &&
  1475. /*
  1476. X * pcalutil.c - utility routines for Pcal
  1477. X *
  1478. X * Contents:
  1479. X *
  1480. X *        alloc
  1481. X *        calc_day
  1482. X *        calc_weekday
  1483. X *        calc_year_day
  1484. X *        ci_strcmp
  1485. X *        ci_strncmp
  1486. X *        copy_text
  1487. X *        getline
  1488. X *        is_valid
  1489. X *        loadwords
  1490. X *        mk_filespec
  1491. X *        mk_path
  1492. X *        normalize
  1493. X *        split_date
  1494. X *        trnlog
  1495. X *
  1496. X * Revision history:
  1497. X *
  1498. X *    4.0    AWR    02/24/91    Revised getline() and copy_text() to
  1499. X *                    handle C-style escapes of characters
  1500. X *                    and octal/hex numbers
  1501. X *
  1502. X *        AWR    02/19/91    Added support for negative ordinals
  1503. X *                    in calc_day(), calc_year_day()
  1504. X *
  1505. X *        AWR    02/04/91    Added calc_year_day()
  1506. X *
  1507. X *        AWR    01/15/91    Extracted from pcal.c
  1508. X *
  1509. X */
  1510. X
  1511. X
  1512. /*
  1513. X * Standard headers:
  1514. X */
  1515. X
  1516. #include <stdio.h>
  1517. #include <ctype.h>
  1518. #include <string.h>
  1519. X
  1520. /*
  1521. X * Pcal-specific definitions:
  1522. X */
  1523. X
  1524. #include "pcaldefs.h"
  1525. #include "pcalglob.h"
  1526. #include "pcallang.h"
  1527. X
  1528. /*
  1529. X * Macros:
  1530. X */
  1531. X
  1532. /* skip over numeric field and subsequent non-numeric characters */
  1533. #define SKIP_FIELD(p) \
  1534. X    do { while (*p && isdigit(*p)) p++; \
  1535. X         while (*p && !isdigit(*p)) p++; } while (0)
  1536. X
  1537. X
  1538. /*
  1539. X * General-purpose utility routines
  1540. X */
  1541. X
  1542. X
  1543. /*
  1544. X * alloc - interface to calloc(); terminates if unsuccessful
  1545. X */
  1546. #ifdef PROTOS
  1547. char *alloc(int size)
  1548. #else
  1549. char *alloc(size)
  1550. X    int size;
  1551. #endif
  1552. {
  1553. X    char *p;
  1554. X
  1555. X    if (size == 0)        /* not all calloc()s like null requests */
  1556. X        size = 1;
  1557. X
  1558. X    if ((p = calloc(1, size)) == NULL) {
  1559. X        FPR(stderr, E_ALLOC_ERR, progname);
  1560. X        exit(EXIT_FAILURE);
  1561. X    }
  1562. X
  1563. X    return p;
  1564. }
  1565. X
  1566. X
  1567. /*
  1568. X * ci_str{n}cmp - case-insensitive flavors of strcmp(), strncmp()
  1569. X */
  1570. #ifdef PROTOS
  1571. int ci_strcmp(register char *s1,
  1572. X          register char *s2)
  1573. #else
  1574. int ci_strcmp(s1, s2)
  1575. register char *s1, *s2;
  1576. #endif
  1577. {
  1578. X    register char c1, c2;
  1579. X
  1580. X    for ( ; (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
  1581. X        if (c1 == '\0')
  1582. X            return 0;
  1583. X
  1584. X    return c1 - c2;
  1585. }
  1586. X
  1587. X
  1588. #ifdef PROTOS
  1589. int ci_strncmp(register char *s1,
  1590. X           register char *s2,
  1591. X           int n)
  1592. #else
  1593. int ci_strncmp(s1, s2, n)
  1594. register char *s1, *s2;
  1595. int n;
  1596. #endif
  1597. {
  1598. X    register char c1, c2;
  1599. X
  1600. X    for ( ; --n >= 0 && (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
  1601. X        if (c1 == '\0')
  1602. X            return 0;
  1603. X
  1604. X    return n < 0 ? 0 : c1 - c2;
  1605. }
  1606. X
  1607. X
  1608. /*
  1609. X * Date calculation routines (see also macros in pcaldefs.h)
  1610. X */
  1611. X
  1612. X
  1613. /*
  1614. X * normalize - adjust day in case it has crossed month (or year) bounds 
  1615. X */
  1616. #ifdef PROTOS
  1617. void normalize(DATE *pd)
  1618. #else
  1619. void normalize(pd)
  1620. X    DATE *pd;        /* pointer to date */
  1621. #endif
  1622. {
  1623. X    int len;
  1624. X
  1625. X    /* adjust if day is in previous or following month */
  1626. X
  1627. X    while (pd->dd < 1) {
  1628. X        pd->yy = PREV_YEAR(pd->mm, pd->yy);
  1629. X        pd->mm = PREV_MONTH(pd->mm, pd->yy);
  1630. X        pd->dd += LENGTH_OF(pd->mm, pd->yy);
  1631. X    }
  1632. X
  1633. X    while (pd->dd > (len = LENGTH_OF(pd->mm, pd->yy))) {
  1634. X        pd->dd -= len;
  1635. X        pd->yy = NEXT_YEAR(pd->mm, pd->yy);
  1636. X        pd->mm = NEXT_MONTH(pd->mm, pd->yy);
  1637. X    }
  1638. }
  1639. X
  1640. X
  1641. /*
  1642. X * calc_day - calculate calendar date from ordinal date (e.g., "first Friday
  1643. X * in November", "last day in October"); return calendar date if it exists, 
  1644. X * 0 if it does not
  1645. X */
  1646. #ifdef PROTOS
  1647. int calc_day(int ord,
  1648. X         int wkd,
  1649. X         int mm)
  1650. #else
  1651. int calc_day(ord, wkd, mm)
  1652. X    int ord;
  1653. X    int wkd;
  1654. X    int mm;
  1655. #endif
  1656. {
  1657. #ifdef PROTOS
  1658. X    int first, last, day, (*pfcn)(int, int, int);
  1659. #else
  1660. X    int first, last, day, (*pfcn)();
  1661. #endif
  1662. X
  1663. X    if (IS_WILD(wkd)) {    /* "day", "weekday", "workday", or "holiday" */
  1664. X        pfcn = pdatefcn[wkd - WILD_FIRST];
  1665. X        last = LENGTH_OF(mm, curr_year);
  1666. X
  1667. X        if (ord < 0) {            /* search backwards */
  1668. X            for (day = last; 
  1669. X                 day >= 1 &&
  1670. X                !((*pfcn)(mm, day, curr_year) && ++ord == 0);
  1671. X                 day--)
  1672. X                ;
  1673. X        } else {            /* search forwards */
  1674. X            for (day = 1; 
  1675. X                 day <= last && 
  1676. X                !((*pfcn)(mm, day, curr_year) && --ord == 0);
  1677. X                 day++)    
  1678. X                ;
  1679. X        }
  1680. X        return is_valid(mm, day, curr_year) ? day : 0; 
  1681. X
  1682. X    } else {        /* fixed weekday - calculate it */
  1683. X        first = (wkd - FIRST_OF(mm, curr_year) + 7) % 7 + 1;
  1684. X        if (ord < 0) {        /* get last (try 5th, then 4th) */
  1685. X            if (!is_valid(mm, last = first + 28, curr_year))
  1686. X                last -= 7;
  1687. X            if (!is_valid(mm, day = last + 7 * (ord + 1),
  1688. X                curr_year))
  1689. X                day = 0;    
  1690. X        }
  1691. X        else 
  1692. X            if (!is_valid(mm, day = first + 7 * (ord - 1),
  1693. X                curr_year))
  1694. X                day = 0;
  1695. X
  1696. X        return day;
  1697. X    }
  1698. X
  1699. }
  1700. X
  1701. X
  1702. /*
  1703. X * calc_year_day - calculate calendar date from ordinal date within year
  1704. X * (e.g., "last Friday in year", "10th holiday in year"); if date exists,
  1705. X * fill in pdate and return TRUE; else return FALSE
  1706. X */
  1707. #ifdef PROTOS
  1708. int calc_year_day(int ord,
  1709. X          int wkd,
  1710. X          DATE *pdate)
  1711. #else
  1712. int calc_year_day(ord, wkd, pdate)
  1713. X    int ord;
  1714. X    int wkd;
  1715. X    DATE *pdate;
  1716. #endif
  1717. {
  1718. #ifdef PROTOS
  1719. X    int incr, (*pfcn)(int, int, int);
  1720. #else
  1721. X    int incr, (*pfcn)();
  1722. #endif
  1723. X    DATE date;
  1724. X
  1725. X    if (IS_WILD(wkd)) {    /* "day", "weekday", "workday", or "holiday" */
  1726. X        pfcn = pdatefcn[wkd - WILD_FIRST];
  1727. X
  1728. X        if (ord < 0) {            /* nth occurrence backwards */
  1729. X            MAKE_DATE(date, DEC, 31, curr_year);
  1730. X            ord = -ord;
  1731. X            incr = -1;
  1732. X        } else {            /* nth occurrence forwards */
  1733. X            MAKE_DATE(date, JAN, 1, curr_year);
  1734. X            incr = 1;
  1735. X        }
  1736. X
  1737. X        /* search for selected occurrence of specified wildcard */
  1738. X
  1739. X        while (date.yy == curr_year &&
  1740. X               !((*pfcn)(date.mm, date.dd, date.yy) && --ord == 0)) {
  1741. X            date.dd += incr;
  1742. X            normalize(&date);
  1743. X        }
  1744. X
  1745. X    } else {        /* fixed weekday - calculate it */
  1746. X        if (ord < 0)
  1747. X            MAKE_DATE(date, DEC,
  1748. X                  calc_day(-1, wkd, DEC) + 7 * (ord + 1),
  1749. X                  curr_year);
  1750. X        else
  1751. X            MAKE_DATE(date, JAN,
  1752. X                  calc_day(1, wkd, JAN) + 7 * (ord - 1),
  1753. X                  curr_year);
  1754. X        normalize(&date);
  1755. X    }
  1756. X
  1757. X    return date.yy == curr_year ? (*pdate = date, TRUE) : FALSE;
  1758. }
  1759. X
  1760. X
  1761. /*
  1762. X * calc_weekday - return the weekday (0-6) of mm/dd/yy (mm: 1-12)
  1763. X */
  1764. #ifdef PROTOS
  1765. int calc_weekday(int mm,
  1766. X         int dd,
  1767. X         int yy)
  1768. #else
  1769. int calc_weekday(mm, dd, yy)
  1770. X    int mm;
  1771. X    int dd;
  1772. X    int yy;
  1773. #endif
  1774. {
  1775. X    return (yy + (yy-1)/4 - (yy-1)/100 + (yy-1)/400 + OFFSET_OF(mm, yy) +
  1776. X        (dd-1)) % 7;
  1777. }
  1778. X
  1779. X
  1780. /*
  1781. X * is_valid - return TRUE if m/d/y is a valid date
  1782. X */
  1783. #ifdef PROTOS
  1784. int is_valid(register int m,
  1785. X         register int d,
  1786. X         register int y)
  1787. #else
  1788. int is_valid(m, d, y)
  1789. X    register int m, d, y;
  1790. #endif
  1791. {
  1792. X    return m >= JAN && m <= DEC && 
  1793. X        d >= 1 && d <= LENGTH_OF(m, y);
  1794. }
  1795. X
  1796. X
  1797. X
  1798. /*
  1799. X * Token parsing/remerging routines:
  1800. X */
  1801. X
  1802. X
  1803. /*
  1804. X * loadwords - tokenize line buffer into word array, return word count.
  1805. X * differs from old loadwords() in that it handles quoted (" or ') strings
  1806. X * and removes escaped quotes
  1807. X */
  1808. #ifdef PROTOS
  1809. int loadwords(void)
  1810. #else
  1811. int loadwords()
  1812. #endif
  1813. {
  1814. X    register char *ptok;
  1815. X    char *delim, **ap, *p1, *p2, c;
  1816. X    int nwords;
  1817. X
  1818. X    for (ptok = lbuf, ap = words; TRUE; ap++) {
  1819. X
  1820. X        ptok += strspn(ptok, WHITESPACE); /* find next token */
  1821. X
  1822. X        if (! *ptok) {            /* end of lbuf? */
  1823. X            *ap = NULL;        /* add null ptr at end */
  1824. X            nwords = ap - words;    /* number of non-null ptrs */
  1825. X            break;            /* exit loop */
  1826. X            }
  1827. X
  1828. X        delim =    *ptok == '"'  ? "\"" :    /* set closing delimiter */
  1829. X            *ptok == '\'' ? "'"  :
  1830. X            WHITESPACE;
  1831. X
  1832. X        if (*ptok == *delim)        /* skip opening quote */
  1833. X            ptok++;
  1834. X
  1835. X        *ap = ptok;            /* save token ptr */
  1836. X
  1837. X        do {                /* find unescaped delimiter */
  1838. X            ptok += strcspn(ptok, delim);
  1839. X            if ((c = ptok[-1]) == '\\')
  1840. X                ptok++;
  1841. X        } while (c == '\\');
  1842. X
  1843. X        if (*ptok)            /* terminate token */
  1844. X            *ptok++ = '\0';
  1845. X    }
  1846. X
  1847. X    /* now reprocess the word list, removing escapes from quotes */
  1848. X
  1849. X    for (ap = words; *ap; *ap++)
  1850. X        for (p1 = p2 = *ap; c = *p2 = *p1++; *p2++)
  1851. X            if (c == '\\')
  1852. X                *p2 = *p1++;
  1853. X
  1854. X    return nwords;                /* return word count */
  1855. X
  1856. }
  1857. X
  1858. X
  1859. /*
  1860. X * copy_text - retrieve remaining text in lbuf and copy to output string,
  1861. X * separating tokens by a single blank and condensing runs of blanks (all
  1862. X * other whitespace has been converted to blanks by now) to one blank
  1863. X */
  1864. #ifdef PROTOS
  1865. void copy_text(char *pbuf,
  1866. X           char **ptext)
  1867. #else
  1868. void copy_text(pbuf, ptext)
  1869. X    char *pbuf;        /* output buffer - can be lbuf itself */
  1870. X    char **ptext;        /* pointer to first text word in "words" */
  1871. #endif
  1872. {
  1873. X    char *p, *pb;
  1874. X
  1875. X    /* copy words to pbuf, separating by one blank */
  1876. X
  1877. X    for (*(pb = pbuf) = '\0'; p = *ptext; *pb++ = *++ptext ? ' ' : '\0') {
  1878. X        for ( ; *p; *p++)
  1879. X            if (! (*p == ' ' && (pb == pbuf || pb[-1] == ' ')))
  1880. X                *pb++ = *p;
  1881. X        if (pb > pbuf && pb[-1] == ' ')
  1882. X            pb--;
  1883. X    }
  1884. }
  1885. X
  1886. X
  1887. /*
  1888. X * split_date - extract 1-3 numeric fields (separated by one or more
  1889. X * non-numeric characters) from date string; return number of fields
  1890. X */
  1891. #ifdef PROTOS
  1892. int split_date(char *pstr,
  1893. X           int *pn1,
  1894. X           int *pn2,
  1895. X           int *pn3)
  1896. #else
  1897. int split_date(pstr, pn1, pn2, pn3)
  1898. X    char *pstr;            /* input string */
  1899. X    int *pn1, *pn2, *pn3;        /* output numbers */
  1900. #endif
  1901. {
  1902. X    int i, n, *pn;
  1903. X
  1904. X    /* attempt to extract up to three numeric fields */
  1905. X    for (n = 0, i = 1; i <= 3; i++) {
  1906. X        pn = i == 1 ? pn1 : i == 2 ? pn2 : pn3;    /* crude but portable */
  1907. X        if (pn)
  1908. X            *pn = *pstr ? (n++, atoi(pstr)) : 0;
  1909. X        SKIP_FIELD(pstr);        /* go to next field */
  1910. X    }
  1911. X
  1912. X    return n;
  1913. }
  1914. X
  1915. X
  1916. X
  1917. /*
  1918. X * File input routines:
  1919. X */
  1920. X
  1921. X
  1922. /*
  1923. X * octal_esc - read up to 3 octal digits from file; return value of octal
  1924. X * constant and leave file pointer at last character
  1925. X */
  1926. #ifdef PROTOS
  1927. static int octal_esc(FILE *fp)
  1928. #else
  1929. static int octal_esc(fp)
  1930. X    FILE *fp;
  1931. #endif
  1932. {
  1933. X    int i, n, c;
  1934. X
  1935. X    for (n = 0, i = 0; i < 3; i++) {
  1936. X        c = getc(fp);
  1937. X        if (c == EOF)
  1938. X            return EOF;
  1939. X        if (!isodigit(c)) {
  1940. X            ungetc(c, fp);
  1941. X            break;
  1942. X        }
  1943. X        n = n * 8 + (c - '0');
  1944. X    }
  1945. X
  1946. X    return n & 0377;        /* truncate to 8 bits */
  1947. }
  1948. X
  1949. X
  1950. /*
  1951. X * hex_esc - read 'x' or 'X' followed by 1 or 2 hex digits from file; return
  1952. X * value of hexadecimal constant (or letter if no hex digits follow) and
  1953. X * leave file pointer at last character
  1954. X */
  1955. #ifdef PROTOS
  1956. static int hex_esc(FILE *fp)
  1957. #else
  1958. static int hex_esc(fp)
  1959. X    FILE *fp;
  1960. #endif
  1961. {
  1962. X    int i, n, c, sv_c;
  1963. X
  1964. X    sv_c = c = getc(fp);        /* read leading 'x' or 'X' */
  1965. X    if (TOLOWER(c) != 'x')
  1966. X        return c;        /* something else - just return it */
  1967. X
  1968. X    for (n = 0, i = 0; i < 2; i++) {
  1969. X        c = getc(fp);
  1970. X        if (c == EOF)
  1971. X            return EOF;
  1972. X        if (!isxdigit(c)) {
  1973. X            ungetc(c, fp);
  1974. X            break;
  1975. X        }
  1976. X        n = n * 16 + (isupper(c) ? c - 'A' + 10 :
  1977. X                  islower(c) ? c - 'a' + 10 :
  1978. X                  c - '0');
  1979. X    }
  1980. X
  1981. X    return i > 0 ? n & 0377 : sv_c;        /* truncate to 8 bits */
  1982. }
  1983. X
  1984. X
  1985. /*
  1986. X * getline - read next non-null line of input file into lbuf; return 0 on EOF
  1987. X * strip leading whitespace, translate other whitespace to blanks, and handle
  1988. X * all escapes except \' and \", (cf. loadwords())
  1989. X */
  1990. #ifdef PROTOS
  1991. int getline(FILE *fp,
  1992. X        int *pline)
  1993. #else
  1994. int getline(fp, pline)
  1995. X    FILE *fp;
  1996. X    int *pline;
  1997. #endif
  1998. {
  1999. X    register char *cp;
  2000. X    register int c, c2;
  2001. X    static char escape[] = "abfnrtv";    /* cf. ANSI spec, 2.2.2 */
  2002. X    int in_comment;        /* comments: from '#' to end-of-line */
  2003. X
  2004. X    cp = lbuf;
  2005. X    do {
  2006. X        in_comment = FALSE;
  2007. X        while ((c = getc(fp)) != '\n' && c != EOF) {
  2008. X            if (c == '#')
  2009. X                in_comment = TRUE;
  2010. X
  2011. X            if (isspace(c))        /* whitespace => blank */
  2012. X                c = ' ';
  2013. X
  2014. X            /* ignore comments and leading white space */
  2015. X            if (in_comment || (cp == lbuf && c == ' '))
  2016. X                continue;
  2017. X
  2018. X            /* handle escape sequences here: escaped whitespace
  2019. X             * and ANSI escapes are all converted to a space;
  2020. X             * octal and hex constants are converted in place
  2021. X             */
  2022. X            if (c == '\\') {
  2023. X                if ((c2 = getc(fp)) == EOF)
  2024. X                    return FALSE;
  2025. X
  2026. X                if (isspace(c2) || strchr(escape, c2)) {
  2027. X                    c = ' ';
  2028. X                    if (c2 == '\n')
  2029. X                        (*pline)++;
  2030. X                }
  2031. X                else if (isodigit(c2)) {    /* octal */    
  2032. X                    ungetc(c2, fp);
  2033. X                    if((c = octal_esc(fp)) == EOF)
  2034. X                        return FALSE;
  2035. X                }
  2036. X                else if (TOLOWER(c2) == 'x') {    /* hex */
  2037. X                    ungetc(c2, fp);
  2038. X                    if((c = hex_esc(fp)) == EOF)
  2039. X                        return FALSE;
  2040. X                }
  2041. X                else if (c2 == '\'' || c2 == '"')
  2042. X                    ungetc(c2, fp);
  2043. X                else
  2044. X                    c = c2;
  2045. X
  2046. X            }
  2047. X            *cp++ = c;
  2048. X        }
  2049. X
  2050. X        if (c == EOF)            /* no more input lines */
  2051. X            return FALSE;
  2052. X
  2053. X        (*pline)++;            /* bump line number */
  2054. X
  2055. X    } while (cp == lbuf);            /* ignore empty lines */
  2056. X
  2057. X    *cp = '\0';
  2058. X    return TRUE;
  2059. }
  2060. X
  2061. X
  2062. /*
  2063. X * Routines dealing with translation of file specifications (VMS, Un*x)
  2064. X */
  2065. X
  2066. #ifdef VMS
  2067. /*
  2068. X * mk_path - extract the path component from VMS file spec
  2069. X */
  2070. #ifdef PROTOS
  2071. char *mk_path(char *path,
  2072. X          char *filespec)
  2073. #else
  2074. char *mk_path(path, filespec)
  2075. X    char *path;        /* output path */
  2076. X    char *filespec;        /* input filespec */
  2077. #endif
  2078. {
  2079. X    char *p;
  2080. X
  2081. X    strcpy(path, filespec);
  2082. X    if (!(p = strchr(path, ']')) && !(p = strchr(path, ':')))
  2083. X        p = path - 1;    /* return null string if no path */
  2084. X    *++p = '\0';
  2085. X
  2086. X    return path;
  2087. }
  2088. X
  2089. X
  2090. /*
  2091. X * mk_filespec - merge VMS path and file names, where latter can be relative
  2092. X */
  2093. #ifdef PROTOS
  2094. char *mk_filespec(char *filespec,
  2095. X          char *path,
  2096. X          char *name)
  2097. #else
  2098. char *mk_filespec(filespec, path, name)
  2099. X    char *filespec;        /* output filespec */
  2100. X    char *path;        /* input path */
  2101. X    char *name;        /* input file name */
  2102. #endif
  2103. {
  2104. X    char *p;
  2105. X
  2106. X    *filespec = '\0';
  2107. X
  2108. X    /* copy name intact if absolute; else merge path and relative name */
  2109. X    if (!strchr(name, ':')) {
  2110. X        strcpy(filespec, path);
  2111. X        if ((p = P_LASTCHAR(filespec)) && *p == END_PATH &&
  2112. X            name[0] == START_PATH && strchr(".-", name[1]))
  2113. X            *p = *++name == '-' ? '.' : '\0';
  2114. X    }
  2115. X
  2116. X    return strcat(filespec, name);
  2117. }
  2118. X
  2119. X
  2120. /*
  2121. X * trnlog - return translation of VMS logical name (null if missing)
  2122. X */
  2123. #ifdef PROTOS
  2124. char *trnlog(char *logname)
  2125. #else
  2126. char *trnlog(logname)    /* look up logical name */
  2127. X    char *logname;
  2128. #endif
  2129. {
  2130. X    static char trnbuf[STRSIZ];
  2131. X    
  2132. X    $DESCRIPTOR(src, logname);
  2133. X    $DESCRIPTOR(dst, trnbuf);
  2134. X    short len;
  2135. X    int ret;
  2136. X    
  2137. X    src.dsc$w_length  = strlen(logname);
  2138. X    ret = LIB$SYS_TRNLOG(&src, &len, &dst);
  2139. X    return ret == SS$_NORMAL ? (trnbuf[len] = '\0', trnbuf) : NULL;
  2140. }
  2141. X
  2142. #else        /* apparently DOS and Amiga can use the Un*x flavors */
  2143. X
  2144. /*
  2145. X * mk_path - extract the path component from a Un*x file spec
  2146. X */
  2147. #ifdef PROTOS
  2148. char *mk_path(char *path,
  2149. X          char *filespec)
  2150. #else
  2151. char *mk_path(path, filespec)
  2152. X    char *path;        /* output path */
  2153. X    char *filespec;        /* input filespec */
  2154. #endif
  2155. {
  2156. X    char *p;
  2157. X
  2158. X    strcpy(path, filespec);
  2159. X    if (! (p = strrchr(path, END_PATH)) )
  2160. X        p = path - 1;    /* return null string if no path */
  2161. X
  2162. X    *++p = '\0';
  2163. X    return path;
  2164. }
  2165. X
  2166. X
  2167. /*
  2168. X * mk_filespec - merge Un*x path and file names, where latter can be relative
  2169. X */
  2170. #ifdef PROTOS
  2171. char *mk_filespec(char *filespec,
  2172. X          char *path,
  2173. X          char *name)
  2174. #else
  2175. char *mk_filespec(filespec, path, name)
  2176. X    char *filespec;        /* output filespec */
  2177. X    char *path;        /* input path */
  2178. X    char *name;        /* input file name */
  2179. #endif
  2180. {
  2181. X    char *p;
  2182. X
  2183. X    *filespec = '\0';
  2184. X
  2185. X    /* copy name intact if absolute; else merge path and relative name */
  2186. X
  2187. X    /* if path starts with "~/", translate it for user */
  2188. X    if (strncmp(name, "~/", 2) == 0 && (p = trnlog(HOME_DIR)) != NULL) {
  2189. X        strcpy(filespec, p);
  2190. X        if ((p = P_LASTCHAR(filespec)) && *p != END_PATH)
  2191. X            *++p = END_PATH, *++p = '\0';
  2192. X        name += 2;        /* skip "~/" */
  2193. X    }
  2194. X    else if (*name != START_PATH) {        /* relative path */
  2195. X        strcpy(filespec, path);
  2196. X        if ((p = P_LASTCHAR(filespec)) && *p != END_PATH)
  2197. X            *++p = END_PATH, *++p = '\0';
  2198. X    }
  2199. X
  2200. X    return strcat(filespec, name);
  2201. }
  2202. X
  2203. X
  2204. /*
  2205. X * trnlog - return translation of Un*x environment variable
  2206. X */
  2207. #ifdef PROTOS
  2208. char *trnlog(char *logname)
  2209. #else
  2210. char *trnlog(logname)    /* look up logical name */
  2211. X    char *logname;
  2212. #endif
  2213. {
  2214. X    return getenv(logname);
  2215. }
  2216. X
  2217. #endif
  2218. SHAR_EOF
  2219. chmod 0644 pcalutil.c ||
  2220. echo 'restore of pcalutil.c failed'
  2221. Wc_c="`wc -c < 'pcalutil.c'`"
  2222. test 14737 -eq "$Wc_c" ||
  2223.     echo 'pcalutil.c: original size 14737, current size' "$Wc_c"
  2224. fi
  2225. true || echo 'restore of protos.h failed'
  2226. echo End of part 4, continue with part 5
  2227. exit 0
  2228.