home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3866 < prev    next >
Text File  |  1991-08-22  |  48KB  |  2,052 lines

  1. Path: wupost!uwm.edu!linac!att!cbnews!jbr0
  2. From: jbr0@cbnews.cb.att.com (joseph.a.brownlee)
  3. Newsgroups: alt.sources
  4. Subject: Pcal v4.1, part 6 of 6
  5. Keywords: pcal calendar postscript
  6. Message-ID: <1991Aug19.122056.1164@cbnews.cb.att.com>
  7. Date: 19 Aug 91 12:20:56 GMT
  8. Followup-To: alt.sources.d
  9. Organization: AT&T Bell Laboratories
  10. Lines: 2040
  11.  
  12. #!/bin/sh
  13. # This is part 06 of a multipart archive
  14. # ============= readfile.c ==============
  15. if test -f 'readfile.c' -a X"$1" != X"-c"; then
  16.     echo 'x - skipping readfile.c (File already exists)'
  17. else
  18. echo 'x - extracting readfile.c (Text)'
  19. sed 's/^X//' << 'SHAR_EOF' > 'readfile.c' &&
  20. /*
  21. X * readfile.c - Pcal routines concerned with reading and parsing the datefile
  22. X *
  23. X * Contents:
  24. X *
  25. X *        cleanup
  26. X *        clear_syms
  27. X *        date_type
  28. X *        do_define
  29. X *        do_ifdef
  30. X *        do_ifndef
  31. X *        do_include
  32. X *        do_undef
  33. X *        enter_day_info
  34. X *        find_sym
  35. X *        find_year
  36. X *        get_keywd
  37. X *        get_month
  38. X *        get_ordinal
  39. X *        get_prep
  40. X *        get_token
  41. X *        get_weekday
  42. X *        is_anyday
  43. X *        is_holiday
  44. X *        is_weekday
  45. X *        is_workday
  46. X *        not_holiday
  47. X *        not_weekday
  48. X *        not_workday
  49. X *        parse
  50. X *        parse_date
  51. X *        parse_ord
  52. X *        parse_rel
  53. X *        read_datefile
  54. X *
  55. X * Revision history:
  56. X *
  57. X *    4.0    AWR    02/19/91    Support negative ordinals
  58. X *
  59. X *        AWR    02/06/91    Support expressions in "if{n}def"
  60. X *
  61. X *        AWR    02/04/91    Support "even" and "odd" ordinals
  62. X *                    and ordinals > 5th; support "year"
  63. X *
  64. X *        AWR    01/15/91    Extracted from pcal.c
  65. X *
  66. X */
  67. X
  68. /*
  69. X * Standard headers:
  70. X */
  71. X
  72. #include <stdio.h>
  73. #include <string.h>
  74. #include <ctype.h>
  75. X
  76. /*
  77. X * Pcal-specific definitions:
  78. X */
  79. X
  80. #include "pcaldefs.h"
  81. #include "pcalglob.h"
  82. #include "pcallang.h"
  83. X
  84. /*
  85. X * Macros:
  86. X */
  87. X
  88. /* status codes returned by parse(), enter_day_info() */
  89. #define PARSE_OK    0    /* successful date parse */
  90. #define PARSE_INVDATE    1    /* nonexistent date */
  91. #define PARSE_INVLINE    2    /* syntax error */
  92. X
  93. /* append date to list; terminate list */
  94. #define ADD_DATE(m, d, y)    pdate->mm = m, pdate->dd = d, pdate++->yy = y
  95. #define TERM_DATES        pdate->mm = pdate->dd = pdate->yy = 0
  96. X
  97. /*
  98. X * Globals:
  99. X */
  100. X
  101. static DATE dates[MAX_DATES+1];        /* array of date structures */
  102. static char *pp_sym[MAX_PP_SYMS];    /* preprocessor defined symbols */
  103. X
  104. X
  105. /*
  106. X * read_datefile - read and parse date file, handling preprocessor lines
  107. X *
  108. X * This is the main routine of this module.  It calls getline() to read each
  109. X * non-null line (stripped of leading blanks and trailing comments), loadwords()
  110. X * to "tokenize" it, and get_token() to classify it as a preprocessor directive
  111. X * or "other".  A switch{} statement takes the appropriate action for each
  112. X * token type; "other" lines are further classified by parse() (q.v.) which
  113. X * calls parse_date() (q.v.) to parse date entries and enter them in the data
  114. X * structure (as described in pcaldefs.h).
  115. X *
  116. X */
  117. #ifdef PROTOS
  118. void read_datefile(FILE *fp,
  119. X           char *filename)
  120. #else
  121. void read_datefile(fp, filename)
  122. X    FILE *fp;        /* file pointer (assumed open) */
  123. X    char *filename;        /* file name (for error messages) */
  124. #endif
  125. {
  126. X    static int file_level = 0;
  127. X    int if_level = 0;
  128. X    int restart_level = 0;
  129. X    int line = 0;
  130. X    int processing = TRUE;
  131. X
  132. X    int pptype, extra, ntokens, save_year, expr;
  133. X    int (*pfcn)();
  134. X    char *ptok;
  135. X    char **pword;
  136. X    char msg[STRSIZ], incpath[STRSIZ];
  137. X
  138. X    if (fp == NULL)                /* whoops, no date file */
  139. X        return;
  140. X
  141. X    if (++file_level > MAX_NESTING) {    /* nesting too deep? */
  142. X        ERR(E_NESTING);
  143. X        exit(EXIT_FAILURE);
  144. X    }
  145. X
  146. X    save_year = curr_year;            /* save default year */
  147. X
  148. X    /* read lines until EOF */
  149. X
  150. X    while (getline(fp, &line)) {
  151. X
  152. X        ntokens = loadwords();        /* split line into tokens */
  153. X        pword = words;            /* point to the first */
  154. X
  155. X        /* get token type and pointers to function and name */
  156. X
  157. X        pptype = get_token(*pword++);
  158. X        pfcn = pp_info[pptype].pfcn;
  159. X        ptok = pp_info[pptype].name;
  160. X
  161. X        switch (pptype) {
  162. X
  163. X        case PP_DEFINE:
  164. X        case PP_UNDEF:
  165. X            if (processing)
  166. X                (void) (*pfcn)(*pword);
  167. X            extra = ntokens > 2;
  168. X            break;
  169. X
  170. X        case PP_ELSE:
  171. X            if (if_level < 1) {
  172. X                ERR(E_ELSE_ERR);
  173. X                break;
  174. X            }
  175. X
  176. X            if (processing) {
  177. X                processing = FALSE;    /* disable processing */
  178. X                restart_level = if_level;
  179. X            }
  180. X            else
  181. X            if (if_level == restart_level) {
  182. X                processing = TRUE;    /* re-enable processing */
  183. X                restart_level = 0;
  184. X            }
  185. X            extra = ntokens > 1;
  186. X            break;
  187. X
  188. X        case PP_ENDIF:
  189. X            if (if_level < 1) {
  190. X                ERR(E_END_ERR);
  191. X                break;
  192. X            }
  193. X
  194. X            if (! processing && if_level == restart_level) {
  195. X                processing = TRUE;    /* re-enable processing */
  196. X                restart_level = 0;
  197. X            }
  198. X            if_level--;
  199. X            extra = ntokens > 1;
  200. X            break;
  201. X
  202. X        case PP_IFDEF:
  203. X        case PP_IFNDEF:
  204. X            if_level++;
  205. X            if (processing) {
  206. X                copy_text(lbuf, pword);    /* reconstruct string */
  207. X                if ((expr = (*pfcn)(lbuf)) == EXPR_ERR) {
  208. X                    ERR(E_EXPR_SYNTAX);
  209. X                    expr = FALSE;
  210. X                }
  211. X                if (! expr) {        /* disable processing */
  212. X                    processing = FALSE;
  213. X                    restart_level = if_level;
  214. X                }
  215. X            }
  216. X            extra = FALSE;
  217. X            break;
  218. X
  219. X        case PP_INCLUDE:
  220. X            if (processing)
  221. X                do_include(mk_path(incpath, filename), *pword);
  222. X            extra = ntokens > 2;
  223. X            break;
  224. X
  225. X        case PP_OTHER:    /* none of the above - parse as date */
  226. X            if (processing) {
  227. X                switch (parse(words, filename)) {
  228. X
  229. X                case PARSE_INVDATE:
  230. X                    ERR(E_INV_DATE);
  231. X                    break;
  232. X
  233. X                case PARSE_INVLINE:
  234. X                    ERR(E_INV_LINE);
  235. X                    break;
  236. X
  237. X                }
  238. X            }
  239. X            extra = FALSE;
  240. X            break;
  241. X
  242. X        } /* end switch */
  243. X
  244. X        if (extra) {        /* extraneous data? */
  245. X            sprintf(msg, E_GARBAGE, ptok);
  246. X            ERR(msg);
  247. X        }
  248. X
  249. X    } /* end while */
  250. X
  251. X    if (if_level > 0)
  252. X        FPR(stderr, E_UNT_IFDEF, progname, filename);
  253. X
  254. X    file_level--;
  255. X    curr_year = save_year;        /* restore default year */
  256. }
  257. X
  258. X
  259. /*
  260. X * Routines to free allocated data (symbol table and data structure) 
  261. X */
  262. X
  263. X
  264. /*
  265. X * clear_syms - clear and deallocate the symbol table
  266. X */
  267. #ifdef PROTOS
  268. void clear_syms(void)
  269. #else
  270. void clear_syms()
  271. #endif
  272. {
  273. X    int i;
  274. X
  275. X    for (i = 0; i < MAX_PP_SYMS; i++)
  276. X        if (pp_sym[i]) {
  277. X            free(pp_sym[i]);
  278. X            pp_sym[i] = NULL;
  279. X        }
  280. }
  281. X
  282. X
  283. /*
  284. X * cleanup - free all allocated data
  285. X */
  286. #ifdef PROTOS
  287. void cleanup(void)
  288. #else
  289. void cleanup()
  290. #endif
  291. {
  292. X    int i, j;
  293. X    year_info *py, *pny;
  294. X    month_info *pm;
  295. X    day_info *pd, *pnd;
  296. X
  297. X    for (py = head; py; py = pny) {        /* main data structure */
  298. X        pny = py->next;
  299. X        for (i = 0; i < 12; i++) {
  300. X            if ((pm = py->month[i]) == NULL)
  301. X                continue;
  302. X            for (j = 0; j < NOTE_DAY; j++)
  303. X                for (pd = pm->day[j]; pd; pd = pnd) {
  304. X                    pnd = pd->next;
  305. X                    free(pd->text);
  306. X                    free(pd);
  307. X                }
  308. X            free(pm);
  309. X        }
  310. X    free(py);
  311. X    }
  312. X
  313. X    clear_syms();                /* symbol table */
  314. X
  315. }
  316. X
  317. X
  318. /*
  319. X * Preprocessor token and symbol table routines
  320. X */
  321. X
  322. X
  323. /*
  324. X * find_sym - look up symbol; return symbol table index if found, PP_SYM_UNDEF
  325. X * if not found
  326. X */
  327. #ifdef PROTOS
  328. int find_sym(char *sym)
  329. #else
  330. int find_sym(sym)
  331. X    char *sym;
  332. #endif
  333. {
  334. X    int i;
  335. X
  336. X    if (!sym)
  337. X        return PP_SYM_UNDEF;
  338. X
  339. X    for (i = 0; i < MAX_PP_SYMS; i++)
  340. X        if (pp_sym[i] && ci_strcmp(pp_sym[i], sym) == 0)
  341. X            return i;
  342. X
  343. X    return PP_SYM_UNDEF;
  344. }
  345. X
  346. X
  347. /*
  348. X * do_ifdef - return TRUE if 'expr' is true; FALSE if not; EXPR_ERR if invalid
  349. X */
  350. #ifdef PROTOS
  351. int do_ifdef(char *expr)
  352. #else
  353. int do_ifdef(expr)
  354. X    char *expr;
  355. #endif
  356. {
  357. X    return parse_expr(expr);
  358. }
  359. X
  360. X
  361. /*
  362. X * do_ifndef - return FALSE if 'expr' is true; TRUE if not; EXPR_ERR if invalid
  363. X */
  364. #ifdef PROTOS
  365. int do_ifndef(char *expr)
  366. #else
  367. int do_ifndef(expr)
  368. X    char *expr;
  369. #endif
  370. {
  371. X    int val;
  372. X
  373. X    return (val = parse_expr(expr)) == EXPR_ERR ? EXPR_ERR : ! val;
  374. }
  375. X
  376. X
  377. /*
  378. X * do_define - enter 'sym' into symbol table; if 'sym' NULL, clear symbol table.
  379. X * Always returns 0 (for compatibility with other dispatch functions).
  380. X */
  381. #ifdef PROTOS
  382. int do_define(char *sym)
  383. #else
  384. int do_define(sym)
  385. X    char *sym;
  386. #endif
  387. {
  388. X    int i;
  389. X
  390. X    if (! sym) {        /* null argument - clear all definitions */
  391. X        clear_syms();
  392. X        return 0;
  393. X    }
  394. X
  395. X    if (do_ifdef(sym))    /* already defined? */
  396. X        return 0;
  397. X
  398. X    for (i = 0; i < MAX_PP_SYMS; i++)    /* find room for it */
  399. X        if (! pp_sym[i]) {
  400. X            strcpy(pp_sym[i] = alloc(strlen(sym)+1), sym);
  401. X            return 0;
  402. X        }
  403. X
  404. X    FPR(stderr, E_SYMFULL, progname, sym);
  405. X    return 0;
  406. }
  407. X
  408. X
  409. /*
  410. X * do_undef - undefine 'sym' and free its space; no error if not defined.
  411. X * Always return 0 (for compatibility with other dispatch fcns).
  412. X */
  413. #ifdef PROTOS
  414. int do_undef(char *sym)
  415. #else
  416. int do_undef(sym)
  417. X    char *sym;
  418. #endif
  419. {
  420. X    int i;
  421. X
  422. X    if (! sym) 
  423. X        return 0;
  424. X
  425. X    if ((i = find_sym(sym)) != PP_SYM_UNDEF) {
  426. X        free(pp_sym[i]);
  427. X        pp_sym[i] = NULL;
  428. X    }
  429. X
  430. X    return 0;
  431. }
  432. X
  433. X
  434. /*
  435. X * do_include - include specified file (optionally in "" or <>); always
  436. X * returns 0 (for compatibility with related functions returning int)
  437. X */
  438. #ifdef PROTOS
  439. int do_include(char *path,
  440. X           char *name)
  441. #else
  442. int do_include(path, name)
  443. X    char *path;        /* path to file */
  444. X    char *name;        /* file name */
  445. #endif
  446. {
  447. X    FILE *fp;
  448. X    char *p, incfile[STRSIZ], tmpnam[STRSIZ];
  449. X
  450. X    if (! name)        /* whoops, no date file */
  451. X        return 0;
  452. X
  453. X    /* copy name, stripping "" or <> */
  454. X    strcpy(tmpnam, name + (*name == '"' || *name == '<'));
  455. X    if ((p = P_LASTCHAR(tmpnam)) && *p == '"' || *p == '>')
  456. X        *p = '\0';
  457. X
  458. X    if ((fp = fopen(mk_filespec(incfile, path, tmpnam), "r")) == NULL) {
  459. X        FPR(stderr, E_FOPEN_ERR, progname, incfile);
  460. X        exit(EXIT_FAILURE);
  461. X    }
  462. X
  463. X    read_datefile(fp, incfile);    /* recursive call */
  464. X    fclose(fp);
  465. X
  466. X    return 0;
  467. }
  468. X
  469. X
  470. X
  471. /*
  472. X * Dispatch functions for wildcard matching
  473. X */
  474. X
  475. X
  476. /*
  477. X * is_anyday - dummy function which always returns TRUE
  478. X */
  479. #ifdef PROTOS
  480. int is_anyday(int mm,
  481. X          int dd,
  482. X          int yy)
  483. #else
  484. int is_anyday(mm, dd, yy)
  485. X    int mm;
  486. X    int dd;
  487. X    int yy;
  488. #endif
  489. {
  490. X    return TRUE;
  491. }
  492. X
  493. X
  494. /*
  495. X * is_weekday - determine whether or not mm/dd/yy is a weekday (i.e., the
  496. X * day of the week normally prints in black)
  497. X */
  498. #ifdef PROTOS
  499. int is_weekday(int mm,
  500. X           int dd,
  501. X           int yy)
  502. #else
  503. int is_weekday(mm, dd, yy)
  504. X    int mm;
  505. X    int dd;
  506. X    int yy;
  507. #endif
  508. {
  509. X    return day_color[calc_weekday(mm, dd, yy)] == BLACK;
  510. }
  511. X
  512. X
  513. /*
  514. X * is_workday - determine whether or not mm/dd/yy is a workday (i.e., the
  515. X * day of the week normally prints in black and the date is not a holiday)
  516. X */
  517. #ifdef PROTOS
  518. int is_workday(int mm,
  519. X           int dd,
  520. X           int yy)
  521. #else
  522. int is_workday(mm, dd, yy)
  523. X    int mm;
  524. X    int dd;
  525. X    int yy;
  526. #endif
  527. {
  528. X    return is_weekday(mm, dd, yy) && ! is_holiday(mm, dd, yy);
  529. }
  530. X
  531. X
  532. /*
  533. X * is_holiday - determine whether or not mm/dd/yy is a holiday
  534. X */
  535. #ifdef PROTOS
  536. int is_holiday(int mm,
  537. X           int dd,
  538. X           int yy)
  539. #else
  540. int is_holiday(mm, dd, yy)
  541. X    int mm;
  542. X    int dd;
  543. X    int yy;
  544. #endif
  545. {
  546. X    year_info *py;
  547. X    month_info *pm;
  548. X
  549. X    pm = (py = find_year(yy, FALSE)) ? py->month[mm-1] : NULL;
  550. X    return pm ? (pm->holidays & (1L << (dd-1))) != 0 : FALSE;
  551. }
  552. X
  553. X
  554. /*
  555. X * not_XXXXX - converses of is_XXXXX above
  556. X */
  557. #ifdef PROTOS
  558. int not_weekday(int mm,
  559. X        int dd,
  560. X        int yy)
  561. #else
  562. int not_weekday(mm, dd, yy)
  563. X    int mm;
  564. X    int dd;
  565. X    int yy;
  566. #endif
  567. {
  568. X    return !is_weekday(mm, dd, yy);
  569. }
  570. X
  571. X
  572. #ifdef PROTOS
  573. int not_workday(int mm,
  574. X        int dd,
  575. X        int yy)
  576. #else
  577. int not_workday(mm, dd, yy)
  578. X    int mm;
  579. X    int dd;
  580. X    int yy;
  581. #endif
  582. {
  583. X    return !is_workday(mm, dd, yy);
  584. }
  585. X
  586. X
  587. #ifdef PROTOS
  588. int not_holiday(int mm,
  589. X        int dd,
  590. X        int yy)
  591. #else
  592. int not_holiday(mm, dd, yy)
  593. X    int mm;
  594. X    int dd;
  595. X    int yy;
  596. #endif
  597. {
  598. X    return !is_holiday(mm, dd, yy);
  599. }
  600. X
  601. X
  602. X
  603. /*
  604. X * Keyword classification routines
  605. X */
  606. X
  607. /*
  608. X * get_month - convert alpha (or, optionally, numeric) string to month; return 
  609. X * 1..12 if valid, NOT_MONTH if not, ALL_MONTHS if "all", ENTIRE_YEAR if "year"
  610. X */
  611. #ifdef PROTOS
  612. int get_month(char *cp,
  613. X          int numeric_ok,
  614. X          int year_ok)
  615. #else
  616. int get_month(cp, numeric_ok, year_ok)
  617. X    char *cp;        /* string to convert */
  618. X    int numeric_ok;        /* accept numeric string ? */
  619. X    int year_ok;        /* accept "year"? */
  620. #endif
  621. {
  622. X    int mm;
  623. X
  624. X    if (! cp)
  625. X        return NOT_MONTH;
  626. X
  627. X    if (get_keywd(cp) == DT_ALL)
  628. X        return ALL_MONTHS;
  629. X
  630. X    if (year_ok && get_keywd(cp) == DT_YEAR)
  631. X        return ENTIRE_YEAR;
  632. X
  633. X    if (numeric_ok && isdigit(*cp))
  634. X        mm = atoi(cp);
  635. X    else
  636. X        for (mm = JAN;
  637. X             mm <= DEC && ci_strncmp(cp, months[mm-1], MIN_MONTH_LEN);
  638. X             mm++)
  639. X            ;
  640. X
  641. X    return mm >= JAN && mm <= DEC ? mm : NOT_MONTH;
  642. }
  643. X
  644. X
  645. /*
  646. X * get_weekday - look up string in weekday list; return 0-6 if valid,
  647. X * NOT_WEEKDAY if not.  If wild_ok flag is set, accept "day", "weekday",
  648. X * "workday", or "holiday" and return appropriate value.
  649. X */
  650. #ifdef PROTOS
  651. int get_weekday(char *cp,
  652. X        int wild_ok)
  653. #else
  654. int get_weekday(cp, wild_ok)
  655. X    char *cp;
  656. X    int wild_ok;
  657. #endif
  658. {
  659. X    int w;
  660. X
  661. X    if (!cp)
  662. X        return NOT_WEEKDAY;
  663. X
  664. X    if (wild_ok) {        /* try wildcards first */
  665. X        for (w = WILD_FIRST; w <= WILD_LAST; w++)
  666. X            if (ci_strncmp(cp, days[w], strlen(days[w])) == 0)
  667. X                return w;
  668. X    }
  669. X
  670. X    for (w = SUN; w <= SAT; w++)
  671. X        if (ci_strncmp(cp, days[w], MIN_DAY_LEN) == 0)
  672. X            return w;
  673. X
  674. X    return NOT_WEEKDAY;
  675. }
  676. X
  677. X
  678. /*
  679. X * get_keywd - look up string in misc. keyword list; return keyword code
  680. X * if valid, DT_OTHER if not
  681. X */
  682. #ifdef PROTOS
  683. int get_keywd(char *cp)
  684. #else
  685. int get_keywd(cp)
  686. X    char *cp;
  687. #endif
  688. {
  689. X    KWD *k;
  690. X
  691. X    if (!cp)
  692. X        return DT_OTHER;
  693. X
  694. X    for (k = keywds;
  695. X         k->name && ci_strncmp(cp, k->name, strlen(k->name));
  696. X         k++)
  697. X        ;
  698. X
  699. X    return k->code;
  700. }
  701. X
  702. X
  703. /*
  704. X * get_ordinal - look up string in ordinal list; return ordinal code (and
  705. X * fill in ordinal value) if valid, return ORD_OTHER if not
  706. X */
  707. #ifdef PROTOS
  708. int get_ordinal(char *cp,
  709. X        int *pval)
  710. #else
  711. int get_ordinal(cp, pval)
  712. X    char *cp;
  713. X    int *pval;
  714. #endif
  715. {
  716. X    KWD_O *o;
  717. X    int val;
  718. X    char **psuf;
  719. X
  720. X    if (!cp)
  721. X        return ORD_OTHER;
  722. X
  723. X    if (isdigit(*cp) || *cp == '-') {        /* numeric? */
  724. X        if ((val = atoi(cp)) == 0)
  725. X            return ORD_OTHER;
  726. X
  727. X        if (*cp == '-')                /* skip over number */
  728. X            cp++;
  729. X        cp += strspn(cp, DIGITS);
  730. X
  731. X        for (psuf = ord_suffix; *psuf; psuf++)    /* find suffix */
  732. X            if (ci_strcmp(cp, *psuf) == 0) {
  733. X                *pval = val;
  734. X                return val < 0 ? ORD_NEGNUM : ORD_POSNUM;
  735. X            }
  736. X
  737. X        return ORD_OTHER;
  738. X    }
  739. X
  740. X    /* look for word in ordinals list */
  741. X
  742. X    for (o = ordinals; o->name && ci_strncmp(cp, o->name, MIN_ORD_LEN); o++)
  743. X        ;
  744. X
  745. X    *pval = o->value;
  746. X    return o->code;
  747. }
  748. X
  749. X
  750. /*
  751. X * get_prep - look up string in preposition list; return preposition code if 
  752. X * valid, PR_OTHER if not
  753. X */
  754. #ifdef PROTOS
  755. int get_prep(char *cp)
  756. #else
  757. int get_prep(cp)
  758. X    char *cp;
  759. #endif
  760. {
  761. X    KWD *p;
  762. X
  763. X    if (!cp)
  764. X        return PR_OTHER;
  765. X
  766. X    for (p = preps; p->name && ci_strncmp(cp, p->name, MIN_PREP_LEN); p++)
  767. X        ;
  768. X
  769. X    return p->code;
  770. }
  771. X
  772. X
  773. /*
  774. X * get_token - look up 'token' in list of preprocessor tokens; return its
  775. X * index if found, PP_OTHER if not
  776. X */
  777. #ifdef PROTOS
  778. int get_token(char *token)
  779. #else
  780. int get_token(token)
  781. X    char *token;
  782. #endif
  783. {
  784. X    KWD_F *p;
  785. X
  786. X    for (p = pp_info;
  787. X             p->name && ci_strncmp(token, p->name, MIN_PPTOK_LEN);
  788. X         p++)
  789. X        ;
  790. X
  791. X    return p->code;
  792. }
  793. X
  794. X
  795. /*
  796. X * date_type - examine token and return date type code; if DT_MONTH, DT_ORDINAL,
  797. X * or DT_WEEKDAY, fill in appropriate code (and value if DT_ORDINAL)
  798. X */
  799. #ifdef PROTOS
  800. int date_type(char *cp,
  801. X          int *pn,
  802. X          int *pv)
  803. #else
  804. int date_type(cp, pn, pv)
  805. X    char *cp;    /* pointer to start of token  */
  806. X    int *pn;    /* token type code (returned) */
  807. X    int *pv;    /* ordinal value (returned)   */
  808. #endif
  809. {
  810. X    int n, v;
  811. X
  812. X    if ((n = get_ordinal(cp, &v)) != ORD_OTHER)    /* ordinal? */
  813. X        return (*pn = n, *pv = v, DT_ORDINAL);
  814. X
  815. X    if (isdigit(*cp))                /* other digit? */
  816. X        return IS_NUMERIC(cp) ? DT_EURDATE : DT_DATE;
  817. X
  818. X    if ((n = get_weekday(cp, TRUE)) != NOT_WEEKDAY)    /* weekday name? */
  819. X        return (*pn = n, DT_WEEKDAY);
  820. X
  821. X    /* "all" can be either a keyword or a month wildcard - look for
  822. X       the former usage first */
  823. X
  824. X    if ((n = get_keywd(cp)) != DT_OTHER)
  825. X        return n;
  826. X
  827. X    if ((n = get_month(cp, FALSE, FALSE)) != NOT_MONTH)  /* month name? */
  828. X        return (*pn = n, DT_MONTH);
  829. X
  830. X    return DT_OTHER;        /* unrecognized keyword - give up */
  831. X
  832. }
  833. X
  834. X
  835. X
  836. /*
  837. X * Routines for entering data in the data structure (described in pcaldefs.h)
  838. X */
  839. X
  840. X
  841. /*
  842. X * find_year - find record in year list; optionally create if not present 
  843. X */
  844. #ifdef PROTOS
  845. year_info *find_year(int year,
  846. X             int insert)
  847. #else
  848. year_info *find_year(year, insert)    /* find record in year list */
  849. X    int year;
  850. X    int insert;            /* insert if missing */
  851. #endif
  852. {
  853. X    year_info *pyear, *plast, *p;
  854. X
  855. X    for (plast = NULL, pyear = head;        /* search linked list */
  856. X         pyear && pyear->year < year;
  857. X         plast = pyear, pyear = pyear->next)
  858. X        ;
  859. X
  860. X    if (pyear && pyear->year == year)        /* found - return it */
  861. X        return pyear;
  862. X
  863. X    if (insert) {        /* not found - insert it if requested */
  864. X        p = (year_info *) alloc((int) sizeof(year_info));    /* create new record */
  865. X        p->year = year;
  866. X
  867. X        p->next = pyear;                /* link it in */
  868. X        return *(plast ? &plast->next : &head) = p;
  869. X    }
  870. X    else
  871. X        return NULL;
  872. }
  873. X
  874. X
  875. /*
  876. X * enter_day_info - enter text for specified day; avoid entering duplicates.
  877. X * Returns PARSE_INVDATE if date invalid, PARSE_OK if OK; if symbol FEB_29_OK
  878. X * is non-zero (cf. pcaldefs.h), will silently ignore Feb 29 of common year.
  879. X */
  880. #ifdef PROTOS
  881. int enter_day_info(int m,
  882. X           int d,
  883. X           int y,
  884. X           int text_type,
  885. X           char **pword)
  886. #else
  887. int enter_day_info(m, d, y, text_type, pword)    /* fill in information for given day */
  888. X    int m, d, y;
  889. X    int text_type;
  890. X    char **pword;
  891. #endif
  892. {
  893. X    static year_info *pyear;
  894. X    static int prev_year = 0;
  895. X    month_info *pmonth;
  896. X    day_info *pday, *plast;
  897. X    int is_holiday = text_type == HOLIDAY_TEXT;
  898. X    char text[LINSIZ];
  899. X
  900. X    if (! is_valid(m, d == NOTE_DAY && text_type == NOTE_TEXT ? 1 : d, y))
  901. X        return (m == FEB && d == 29 && FEB_29_OK) ? PARSE_OK : PARSE_INVDATE;
  902. X
  903. X    if (y != prev_year)        /* avoid unnecessary year lookup */
  904. X        pyear = find_year(y, 1);
  905. X
  906. X    --m, --d;            /* adjust for use as subscripts */
  907. X
  908. X    if ((pmonth = pyear->month[m]) == NULL)    /* find/create month record */
  909. X        pyear->month[m] = pmonth = (month_info *) alloc((int) sizeof(month_info));
  910. X
  911. X    if (is_holiday)
  912. X        pmonth->holidays |= (1L << d);
  913. X
  914. X    /* insert text for day at end of list (preserving the order of entry
  915. X     * for multiple lines on same day); eliminate those differing only
  916. X     * in spacing and capitalization from existing entries
  917. X         */
  918. X
  919. X    copy_text(text, pword);    /* consolidate text from lbuf into text */
  920. X
  921. #ifdef DATE_DEBUG
  922. X    {
  923. X    char *p;
  924. X    fprintf(stderr, "%02d/%02d/%d%c '", m+1, d+1, y, is_holiday ? '*' : ' ');
  925. X    for (p = text; *p; p++)
  926. X        fprintf(stderr, isprint(*p) ? "%c" : "\\%03o", *p & 0377);
  927. X    fprintf(stderr, "'\n");
  928. X    }
  929. #endif
  930. X
  931. X    if (*text) {
  932. X        for (plast = NULL, pday = pmonth->day[d];
  933. X             pday;
  934. X             plast = pday, pday = pday->next)
  935. X            if (ci_strcmp(pday->text, text) == 0) {
  936. X                pday->is_holiday |= is_holiday;
  937. X                return PARSE_OK;
  938. X            }
  939. X
  940. X        /* unique - add to end of list */
  941. X
  942. X        pday = (day_info *) alloc(sizeof(day_info));
  943. X        pday->is_holiday = is_holiday;
  944. X        strcpy(pday->text = (char *) alloc(strlen(text)+1), text);
  945. X        pday->next = NULL;
  946. X        *(plast ? &plast->next : &pmonth->day[d]) = pday;
  947. X    }
  948. X
  949. X    return PARSE_OK;
  950. }
  951. X
  952. X
  953. X
  954. /*
  955. X * Date parsing routines:
  956. X */
  957. X
  958. X
  959. /*
  960. X * parse_ord - parse an ordinal date spec (e.g. "first Monday in September",
  961. X * "every Sunday in October", "last workday in all"); return PARSE_OK if line
  962. X * syntax valid, PARSE_INVLINE if not.  Write all matching dates (if any) to
  963. X * global array dates[]; terminate date list with null entry.
  964. X */
  965. #ifdef PROTOS
  966. int parse_ord(int ord,
  967. X          int val,
  968. X          char **pword)
  969. #else
  970. int parse_ord(ord, val, pword)
  971. X    int ord;        /* valid ordinal code - from get_ordinal() */
  972. X    int val;        /* ordinal value - also from get_ordinal() */
  973. X    char **pword;        /* pointer to word after ordinal */
  974. #endif
  975. {
  976. X    int wkd, mon, mm, dd, len, (*pfcn)(), doit;
  977. X    int val_first, val_last, val_incr, mon_first, mon_last;
  978. X    DATE *pdate, date;
  979. X
  980. X    if ((wkd = get_weekday(*pword, TRUE)) == NOT_WEEKDAY ||    /* weekday */
  981. X        *++pword == NULL ||                    /* any word */
  982. X        (mon = get_month(*++pword, FALSE, TRUE)) == NOT_MONTH) /* month */
  983. X        return PARSE_INVLINE;
  984. X
  985. X    /* set up loop boundaries for month loop */
  986. X
  987. X    mon_first = mon == ALL_MONTHS || mon == ENTIRE_YEAR ? JAN : mon;
  988. X    mon_last  = mon == ALL_MONTHS || mon == ENTIRE_YEAR ? DEC : mon;
  989. X
  990. X    pdate = dates;            /* start of date array */
  991. X
  992. X    /* special case of "all|odd|even <wildcard> in <month>|all|year" */
  993. X
  994. X    if ((ord == ORD_ALL || ord == ORD_EVEN || ord == ORD_ODD) &&
  995. X        IS_WILD(wkd)) {
  996. X        pfcn = pdatefcn[wkd - ANY_DAY];
  997. X        doit = ord != ORD_EVEN;
  998. X        for (mm = mon_first; mm <= mon_last; mm++) {
  999. X            len = LENGTH_OF(mm, curr_year);
  1000. X            if (mon != ENTIRE_YEAR)
  1001. X                doit = ord != ORD_EVEN;
  1002. X            for (dd = 1; dd <= len; dd++)
  1003. X                if ((*pfcn)(mm, dd, curr_year)) {
  1004. X                    if (doit)
  1005. X                        ADD_DATE(mm, dd, curr_year);
  1006. X                    if (ord != ORD_ALL)
  1007. X                        doit = ! doit;
  1008. X                }
  1009. X        }
  1010. X    }
  1011. X
  1012. X    /* special case of "odd|even <weekday> in year" */
  1013. X
  1014. X    else if ((ord == ORD_EVEN || ord == ORD_ODD) && mon == ENTIRE_YEAR) {
  1015. X        date.mm = JAN;            /* starting date */
  1016. X        date.dd = calc_day(ord == ORD_EVEN ? 2 : 1, wkd, JAN);
  1017. X        date.yy = curr_year;
  1018. X        do {                /* alternates throughout year */
  1019. X            ADD_DATE(date.mm, date.dd, date.yy);
  1020. X            date.dd += 14;
  1021. X            normalize(&date);
  1022. X        } while (date.yy == curr_year);
  1023. X    }
  1024. X
  1025. X    /* special case of "<ordinal>|last <weekday>|<wildcard> in year" */
  1026. X
  1027. X    else if ((ord == ORD_NEGNUM || ord == ORD_POSNUM) &&
  1028. X             mon == ENTIRE_YEAR) {
  1029. X        if (calc_year_day(val, wkd, &date))
  1030. X            ADD_DATE(date.mm, date.dd, date.yy);
  1031. X    }
  1032. X
  1033. X    /* all other combinations of ordinal and day */
  1034. X
  1035. X    else {
  1036. X        /* set up loop boundaries for "wildcard" ordinals */
  1037. X
  1038. X        val_first = ord == ORD_ALL || ord == ORD_ODD ? 1 :
  1039. X                ord == ORD_EVEN ? 2 : val;
  1040. X        val_last  = ord == ORD_ALL || ord == ORD_ODD ? 5 :
  1041. X                ord == ORD_EVEN ? 4 : val;
  1042. X        val_incr  = ord == ORD_ODD || ord == ORD_EVEN ? 2 : 1;
  1043. X
  1044. X        for (mm = mon_first; mm <= mon_last; mm++)
  1045. X            for (val = val_first; val <= val_last; val += val_incr)
  1046. X                if ((dd = calc_day(val, wkd, mm)) != 0)
  1047. X                    ADD_DATE(mm, dd, curr_year);
  1048. X    }
  1049. X
  1050. X    TERM_DATES;        /* terminate array with null entry */
  1051. X    return PARSE_OK;
  1052. X
  1053. }
  1054. X
  1055. X
  1056. /*
  1057. X * parse_rel - parse a relative date spec (e.g. "Friday after fourth Thursday
  1058. X * in November", "Saturday after first Friday in all"; return PARSE_OK if
  1059. X * line syntax valid, PARSE_INVLINE if not.  Transform all dates that match
  1060. X * the base date to the appropriate day, month, and year.
  1061. X *
  1062. X * This calls parse_date() recursively in order to handle cases such as
  1063. X * "Friday after Tuesday before last day in all".
  1064. X */
  1065. #ifdef PROTOS
  1066. int parse_rel(int wkd,
  1067. X          char **pword,
  1068. X          int *ptype,
  1069. X          char ***pptext)
  1070. #else
  1071. int parse_rel(wkd, pword, ptype, pptext)
  1072. X    int wkd;        /* valid weekday code - from get_weekday() */
  1073. X    char **pword;        /* pointer to word after weekday */
  1074. X    int *ptype;        /* return text type (holiday/non-holiday) */
  1075. X    char ***pptext;        /* return pointer to first word of text */
  1076. #endif
  1077. {
  1078. X    int prep, rtn, base_wkd, incr, (*pfcn)();
  1079. X    DATE *pd;
  1080. X
  1081. X    /* we have the weekday - now look for the preposition */
  1082. X    if ((prep = get_prep(*pword++)) == PR_OTHER)
  1083. X        return PARSE_INVLINE;
  1084. X
  1085. X    /* get the base date */
  1086. X    if ((rtn = parse_date(pword, ptype, pptext)) != PARSE_OK)
  1087. X        return rtn;
  1088. X
  1089. X    /* transform date array in place - note that the relative date may
  1090. X       not be in the same month or even year */
  1091. X
  1092. X    if (IS_WILD(wkd)) {        /* wildcard for weekday name? */
  1093. X        pfcn = pdatefcn[wkd - ANY_DAY];
  1094. X        incr = prep == PR_BEFORE || prep == PR_ON_BEFORE ? -1 : 1;
  1095. X
  1096. X        for (pd = dates; pd->mm; pd++) {
  1097. X            /* search for nearest matching date */
  1098. X
  1099. X            if (prep == PR_BEFORE || prep == PR_AFTER) {
  1100. X                pd->dd += incr;
  1101. X                normalize(pd);
  1102. X            }
  1103. X            while (!(*pfcn)(pd->mm, pd->dd, pd->yy)) {
  1104. X                pd->dd += incr;
  1105. X                normalize(pd);
  1106. X            }
  1107. X        }
  1108. X
  1109. X    } else  {            /* explicit weekday name */
  1110. X        for (pd = dates; pd->mm; pd++) {
  1111. X            /* calculate nearest matching date */
  1112. X
  1113. X            base_wkd = calc_weekday(pd->mm, pd->dd, pd->yy);
  1114. X
  1115. X            if (prep == PR_BEFORE ||
  1116. X                (prep == PR_ON_BEFORE && wkd != base_wkd))
  1117. X                pd->dd -= 7 - (wkd - base_wkd + 7) % 7;
  1118. X
  1119. X            if (prep == PR_AFTER ||
  1120. X                (prep == PR_ON_AFTER && wkd != base_wkd))
  1121. X                pd->dd += (wkd - base_wkd + 6) % 7 + 1;
  1122. X
  1123. X            normalize(pd);    /* adjust for month/year crossing */
  1124. X        }
  1125. X    }
  1126. X
  1127. X    return PARSE_OK;
  1128. }
  1129. X
  1130. X
  1131. /*
  1132. X * parse_date - parse a date specification in any of its myriad forms; upon
  1133. X * return, array dates[] will contain a list of all the dates that matched,
  1134. X * terminated by a null entry.  Also fill in the date type (holiday/non-
  1135. X * holiday) code and the pointer to the first word of text.
  1136. X */
  1137. #ifdef PROTOS
  1138. int parse_date(char **pword,
  1139. X           int *ptype,
  1140. X           char ***pptext)
  1141. #else
  1142. int parse_date(pword, ptype, pptext)
  1143. X    char **pword;        /* first word to parse */
  1144. X    int *ptype;        /* return date type (holiday/non-holiday) */
  1145. X    char ***pptext;        /* return pointer to first word of text */
  1146. #endif
  1147. {
  1148. X    int mm, dd, yy;
  1149. X    int token, n, v, ord, val, wkd, rtn;
  1150. X    DATE *pdate;
  1151. X    char *cp;
  1152. X
  1153. X    pdate = dates;
  1154. X
  1155. X    switch (token = date_type(*pword, &n, &v)) {
  1156. X
  1157. X    case DT_MONTH:        /* <month> dd */
  1158. X        if (date_style != USA_DATES)
  1159. X            return PARSE_INVLINE;
  1160. X
  1161. X        if ((cp = *++pword) == NULL)
  1162. X            return PARSE_INVLINE;
  1163. X
  1164. X        ADD_DATE(n, atoi(cp), curr_year);
  1165. X        TERM_DATES;
  1166. X
  1167. X        break;
  1168. X
  1169. X    case DT_DATE:        /* mm/dd{/yy} | dd/mm{/yy} */
  1170. X        n = split_date(*pword,
  1171. X                   date_style == USA_DATES ? &mm : &dd,
  1172. X                   date_style == USA_DATES ? &dd : &mm,
  1173. X                   &yy);
  1174. X
  1175. X        if (n > 2) {            /* year present? */
  1176. X            if (yy < 100)
  1177. X                yy += CENTURY;
  1178. X            curr_year = yy;        /* reset current year */
  1179. X        }
  1180. X
  1181. X        ADD_DATE(mm, dd, curr_year);
  1182. X        TERM_DATES;
  1183. X
  1184. X        break;
  1185. X
  1186. X    case DT_EURDATE:    /* dd [ <month> | "all" ] */
  1187. X        if (date_style != EUR_DATES)
  1188. X            return PARSE_INVLINE;
  1189. X
  1190. X        dd = atoi(*pword);
  1191. X
  1192. X        if (get_keywd(*++pword) == DT_ALL) {
  1193. X            for (mm = JAN; mm <= DEC; mm++)        /* wildcard */
  1194. X                ADD_DATE(mm, dd, curr_year);
  1195. X        }
  1196. X        else {                        /* one month */
  1197. X            if ((mm = get_month(*pword, FALSE, FALSE)) == NOT_MONTH)
  1198. X                return PARSE_INVLINE;
  1199. X
  1200. X            ADD_DATE(mm, dd, curr_year);
  1201. X        }
  1202. X
  1203. X        TERM_DATES;
  1204. X        break;
  1205. X
  1206. X    case DT_ALL:        /* "all" <weekday> "in" [ <month> | "all" ] */
  1207. X                /* or "all" <day>" */
  1208. X
  1209. X        if ((cp = *(pword+1)) && (*(cp += strspn(cp, DIGITS)) == '\0' ||
  1210. X            *cp == '*')) {
  1211. X            dd = atoi(*++pword);        /* "all" <day> */
  1212. X            for (mm = JAN; mm <= DEC; mm++)
  1213. X                ADD_DATE(mm, dd, curr_year);
  1214. X            TERM_DATES;
  1215. X            break;        /* leave switch */
  1216. X        }
  1217. X
  1218. X        n = ORD_ALL;    /* "all" <weekday> ... */
  1219. X        v = 0;
  1220. X         /* fall through */
  1221. X
  1222. X    case DT_ORDINAL:    /* <ordinal> <weekday> in [ <month> | "all" ] */
  1223. X        ord = n;
  1224. X        val = v;
  1225. X        if ((rtn = parse_ord(ord, val, pword + 1)) != PARSE_OK)
  1226. X            return rtn;
  1227. X
  1228. X        pword += 3;        /* last word of date */
  1229. X        break;
  1230. X
  1231. X    case DT_WEEKDAY:    /* <weekday> <prep> <date> */
  1232. X        wkd = n;
  1233. X
  1234. X        /* parse_rel() calls parse_date() recursively */
  1235. X        return parse_rel(wkd, ++pword, ptype, pptext);
  1236. X        break;
  1237. X
  1238. X    default:
  1239. X        return PARSE_INVLINE;
  1240. X        break;
  1241. X    }
  1242. X
  1243. X    /* at this point, pword points to the last component of the date;
  1244. X     * fill in type code and pointer to following word (start of text)
  1245. X     */
  1246. X    *ptype = LASTCHAR(*pword) == '*' ? HOLIDAY_TEXT : DAY_TEXT;
  1247. X    *pptext = ++pword;
  1248. X
  1249. X    return PARSE_OK;
  1250. }
  1251. X
  1252. /*
  1253. X * parse - parse non-preprocessor lines in date file
  1254. X *
  1255. X * This routine parses "year", "opt", "note", and date entries in the date
  1256. X * file.  It calls parse_date() to parse date entries (and enter the date(s)
  1257. X * matched in global array "dates"), and then calls enter_day_info() to
  1258. X * enter each date found (and its associated text) in the date file.
  1259. X *
  1260. X * N.B.: "inc" and other cpp-like lines are handled in read_datefile().
  1261. X *
  1262. X */
  1263. #ifdef PROTOS
  1264. int parse(char **pword,
  1265. X      char *filename)
  1266. #else
  1267. int parse(pword, filename)
  1268. X    char **pword;        /* pointer to first word to parse */
  1269. X    char *filename;        /* name of file (for error messages) */
  1270. #endif
  1271. {
  1272. X    register char *cp;
  1273. X    char **ptext;
  1274. X    int mm, yy;
  1275. X    int text_type, n, v, rtn, match;
  1276. X    int token;
  1277. X    DATE *pd;
  1278. X
  1279. X    /*
  1280. X     * Get first field and call date_type() to decode it
  1281. X         */
  1282. X    cp = *pword;
  1283. X
  1284. X    switch (token = date_type(cp, &n, &v)) {
  1285. X
  1286. X    case DT_YEAR:
  1287. X        if ((cp = *++pword) != NULL && (yy = atoi(cp)) > 0) {
  1288. X            if (yy < 100)
  1289. X                yy += CENTURY;
  1290. X            curr_year = yy;
  1291. X            return PARSE_OK;
  1292. X        }
  1293. X        return PARSE_INVLINE;    /* year missing or non-numeric */
  1294. X        break;
  1295. X
  1296. X    case DT_OPT:
  1297. X         if (!get_args(pword, P_OPT, filename)) {
  1298. X            usage(stderr, FALSE);
  1299. X            exit(EXIT_FAILURE);
  1300. X        }
  1301. X        return PARSE_OK;
  1302. X        break;
  1303. X
  1304. X    case DT_NOTE:
  1305. X        if ((mm = get_month(*++pword, TRUE, TRUE)) == NOT_MONTH)
  1306. X            return PARSE_INVLINE;
  1307. X
  1308. X        if (mm == ALL_MONTHS || mm == ENTIRE_YEAR)    /* "note all"? */
  1309. X            for (mm = JAN; mm <= DEC; mm++)
  1310. X                enter_day_info(mm, NOTE_DAY, curr_year,
  1311. X                    NOTE_TEXT, pword+1);
  1312. X        else
  1313. X            enter_day_info(mm, NOTE_DAY, curr_year, NOTE_TEXT,
  1314. X                pword+1);
  1315. X
  1316. X        return PARSE_OK;
  1317. X        break;
  1318. X
  1319. X    case DT_OTHER:        /* unrecognized token */
  1320. X        return PARSE_INVLINE;
  1321. X        break;
  1322. X
  1323. X    /* assume anything else is a date */
  1324. X
  1325. X    default:
  1326. X        if ((rtn = parse_date(pword, &text_type, &ptext)) == PARSE_OK) {
  1327. X            match = FALSE;    /* is at least one date valid? */
  1328. X            for (pd = dates; pd->mm; pd++)
  1329. X                match |= enter_day_info(pd->mm, pd->dd, pd->yy,
  1330. X                           text_type, ptext) == PARSE_OK;
  1331. X            rtn = match ? PARSE_OK : PARSE_INVDATE;
  1332. X        }
  1333. X        return rtn;
  1334. X        break;
  1335. X
  1336. X    }
  1337. }
  1338. SHAR_EOF
  1339. chmod 0644 readfile.c ||
  1340. echo 'restore of readfile.c failed'
  1341. Wc_c="`wc -c < 'readfile.c'`"
  1342. test 27599 -eq "$Wc_c" ||
  1343.     echo 'readfile.c: original size 27599, current size' "$Wc_c"
  1344. fi
  1345. # ============= troffman.sty ==============
  1346. if test -f 'troffman.sty' -a X"$1" != X"-c"; then
  1347.     echo 'x - skipping troffman.sty (File already exists)'
  1348. else
  1349. echo 'x - extracting troffman.sty (Text)'
  1350. sed 's/^X//' << 'SHAR_EOF' > 'troffman.sty' &&
  1351. % -*-LaTeX-*-
  1352. % <BEEBE.TR2TEX>TROFFMAN.STY.6, 24-Feb-87 09:53:53, Edit by BEEBE
  1353. % These macros are intended to be referenced by a LaTeX
  1354. % \documentstyle[troffman]{article}
  1355. % command.  You can insert an 11pt or 12pt option if you like larger
  1356. % type--sizes set here are computed from the LaTeX point size setting.
  1357. % Size values have been chosen to closely match Unix manual page
  1358. % documents, which are actually too wide and too high for good
  1359. % typographic taste and readability.
  1360. %
  1361. \hbadness=10000                 % do not want underfull box messages--there are
  1362. X                                % usually lots in man pages
  1363. \hfuzz=\maxdimen                % no overfull box messages either
  1364. \voffset=-0.8in                 % man pages start high on page
  1365. \textheight=9in                 % and are long
  1366. \textwidth=6.5in                % troff man pages have very wide text
  1367. \parindent=0pt
  1368. \oddsidemargin=-.2in
  1369. \newdimen\singlespacing
  1370. \singlespacing=10pt                     % LaTeX has (10+\@ptsize)pt
  1371. \addtolength{\singlespacing}{\@ptsize pt} % get size from \documentstyle[??pt]{}
  1372. X
  1373. % Use conventional typesetting baselineskip spacing for 10pt type
  1374. \normalbaselineskip=1.2\singlespacing
  1375. \newlength{\parmargin}  % whole paragraphs indented this much on man pages
  1376. \parmargin=3\normalbaselineskip 
  1377. \baselineskip=\normalbaselineskip
  1378. X
  1379. % page heading/footing
  1380. % NB: we need \hfill, not \hfil, here; otherwise box is filled only to current
  1381. %     paragraph width
  1382. \newcommand{\phead}[3]{%
  1383. X   \renewcommand{\@oddhead}{%\@setpar{\hangindent=0pt\hangafter=0\@@par}
  1384. X     {\makebox[\textwidth]{#1(#2) \hfill \rm UNIX Programmer's Manual%
  1385. X         \hfill #1(#2)}}}%
  1386. X   \renewcommand{\@oddfoot}{%\@setpar{\hangindent=0pt\hangafter=0\@@par}
  1387. X      {\makebox[\textwidth]{4th Berkeley distribution \hfill #3%
  1388. X         \hfill \rm\thepage}}}%
  1389. X   \renewcommand{\@evenfoot}{\@oddfoot}%
  1390. X   \renewcommand{\@evenhead}{\@oddhead}%
  1391. }
  1392. % multi-line left-justified subheading
  1393. \def\shead#1{
  1394. X        \par % force out previous paragraph with its \hangindent values
  1395. X        \@setpar{\hangindent=0pt\hangafter=0\@@par}
  1396. X        \typeout{[#1]}  % maybe temporary, but nice for progress report
  1397. X        \subsubsection*{#1}
  1398. X        \@setpar{\hangindent=\parmargin\hangafter=0\@@par}
  1399. }
  1400. X
  1401. \newcommand{\bs}{$\backslash$}
  1402. \def\under{\underline}
  1403. \def\dotdot{\ddot}
  1404. \def\nwl{\hfill\break}          % similar to LaTex's \newline but does not
  1405. X                                % complain if there is no line to break
  1406. \def\ind#1{\par\everypar{\hangindent=#1\hangafter=0\hskip-\parindent}}
  1407. \def\tmpind#1{\par\hskip#1}
  1408. \newenvironment{SEPcntr}{\begin{center}}{\end{center}}
  1409. \def\cntr#1{\begin{SEPcntr} #1 \end{SEPcntr}}
  1410. % displayed text, indented, justification off
  1411. \def\displaybegin{\par\begingroup\medskip\narrower\narrower\noindent
  1412. X                  \obeylines\obeyspaces}
  1413. \def\displayend{\endgroup\smallskip\noindent}
  1414. % fill and nofill
  1415. \def\nofill{\par\begingroup\noindent\obeylines
  1416. X    \frenchspacing\@vobeyspaces\linepenalty10000}
  1417. {\catcode`\ =\active\gdef\@vobeyspaces{\catcode`\ \active \let \@xobeysp}}
  1418. \def\@xobeysp{\leavevmode{} }
  1419. \def\fill{\endgroup\noindent}
  1420. X
  1421. % define a boxing macro
  1422. \def\boxit#1{\vbox{\hrule\hbox{\vrule\kern10pt\vbox{\medskip\kern5pt#1\bigskip
  1423. \kern5pt}\kern10pt\vrule}\hrule}}
  1424. X
  1425. % try this TPlist environment
  1426. \newcommand{\TPlistlabel}[1]{\mbox{#1}\hfil}
  1427. \newenvironment{TPlist}[1]{
  1428. \begin{list}{}
  1429. X    {
  1430. X      \let\makelabel\TPlistlabel
  1431. X      \settowidth{\labelwidth}{#1mm}
  1432. X      \setlength{\leftmargin}{\parmargin}       % all paragraphs have this much
  1433. X      \addtolength{\leftmargin}{\labelwidth}    % space for label
  1434. X    }
  1435. X  }{
  1436. \end{list}}
  1437. SHAR_EOF
  1438. chmod 0644 troffman.sty ||
  1439. echo 'restore of troffman.sty failed'
  1440. Wc_c="`wc -c < 'troffman.sty'`"
  1441. test 3609 -eq "$Wc_c" ||
  1442.     echo 'troffman.sty: original size 3609, current size' "$Wc_c"
  1443. fi
  1444. # ============= writefil.c ==============
  1445. if test -f 'writefil.c' -a X"$1" != X"-c"; then
  1446.     echo 'x - skipping writefil.c (File already exists)'
  1447. else
  1448. echo 'x - extracting writefil.c (Text)'
  1449. sed 's/^X//' << 'SHAR_EOF' > 'writefil.c' &&
  1450. /*
  1451. X * writefil.c - Pcal routines concerned with writing the PostScript output
  1452. X *
  1453. X * Contents:
  1454. X *
  1455. X *        def_footstring
  1456. X *        expand_fmt
  1457. X *        find_daytext
  1458. X *        find_holidays
  1459. X *        print_julian_info
  1460. X *        print_month
  1461. X *        print_moon_info
  1462. X *        print_text
  1463. X *        print_word
  1464. X *        write_psfile
  1465. X *
  1466. X * Revision history:
  1467. X *
  1468. X *    4.1    AWR    08/16/91    Support -G flag (outlined gray dates)
  1469. X *
  1470. X *    4.02    AWR    07/02/91    Added "%" expansions in text strings
  1471. X *                    (cf. expand_fmt())
  1472. X *
  1473. X *    4.0    AWR    01/28/91    Support -B, -w flags and moon file
  1474. X *
  1475. X *            01/15/91    Extracted from pcal.c
  1476. X *
  1477. X */
  1478. X
  1479. /*
  1480. X * Standard headers:
  1481. X */
  1482. X
  1483. #include <stdio.h>
  1484. #include <ctype.h>
  1485. X
  1486. /*
  1487. X * Pcal-specific definitions:
  1488. X */
  1489. X
  1490. #include "pcaldefs.h"
  1491. #include "pcalglob.h"
  1492. #define  WRITEFIL        /* to get ordinal_suffix() from pcallang.h */
  1493. #include "pcallang.h"
  1494. #include "pcalinit.h"        /* PostScript boilerplate */
  1495. X
  1496. /*
  1497. X * Macros:
  1498. X */
  1499. X
  1500. /* convert "ph" (approximate quarter moon) to exact quarter moon */
  1501. #define EXACT_QUARTER(ph)    ((((int) (((ph) + .05) * 4.0)) % 4) / 4.0)
  1502. X
  1503. /* make sure printf() doesn't round "ph" up to 1.0 when printing it */
  1504. #define PRT_TWEAK(ph)        ((ph) >= 0.9995 ? 0.0 : (ph))
  1505. X
  1506. /*
  1507. X * Globals:
  1508. X */
  1509. X
  1510. /* order of following strings must conform to #define's in pcaldefs.h (q.v.) */
  1511. static char *cond[3] = {"false", "true", "(some)"};
  1512. static char *gray[3] = {"(gray)", "(outline)", "(outline_gray)"};
  1513. X
  1514. static int this_day, this_month, this_year;
  1515. X
  1516. X
  1517. /*
  1518. X * write_psfile - write PostScript code to stdout
  1519. X *
  1520. X * The actual output of the PostScript code is straightforward.  This routine
  1521. X * writes a PostScript header followed by declarations of all the PostScript
  1522. X * variables affected by command-line flags and/or language dependencies.  It
  1523. X * the generates the PostScript boilerplate generated from pcalinit.ps, and
  1524. X * finally calls print_month() to generate the PostScript code for each
  1525. X * requested month.
  1526. X */
  1527. #ifdef PROTOS
  1528. void write_psfile(int month,
  1529. X          int year,
  1530. X          int nmonths)
  1531. #else
  1532. void write_psfile(month, year, nmonths)
  1533. X    int month;            /* starting month   */
  1534. X    int year;            /* starting year    */
  1535. X    int nmonths;            /* number of months */
  1536. #endif
  1537. {
  1538. X    int i, ngray;
  1539. X    char **ap, tmp[20];
  1540. X
  1541. X    /*
  1542. X     * Write out PostScript prolog
  1543. X     */
  1544. X
  1545. X     PRT("%%!\n%%\t");
  1546. X    PRT(VERSION_MSG, progname, version);
  1547. X    if (*datefile)
  1548. X        PRT(DATEFILE_MSG, datefile);
  1549. X    PRT("\n%%\n");
  1550. X
  1551. X    /* font names */
  1552. X
  1553. X    PRT("/titlefont /%s def\n/dayfont /%s def\n/notesfont /%s def\n",
  1554. X        titlefont, dayfont, notesfont);
  1555. X
  1556. X    /* month names */
  1557. X
  1558. X    PRT("/month_names [");
  1559. X    for (i = JAN; i <= DEC; i++) {
  1560. X        PRT(i % 6 == 1 ? "\n\t" : " ");
  1561. X        (void) print_word(months[i-1]);
  1562. X    }
  1563. X    PRT(" ] def\n");
  1564. X
  1565. X    /* day names - abbreviate if printing entire year on page */
  1566. X
  1567. X    PRT("/day_names [");
  1568. X    for (i = SUN; i <= SAT; i++) {
  1569. X        PRT(i % 6 == 0 && ! do_whole_year ? "\n\t" : " ");
  1570. X        strcpy(tmp, days[(i + first_day_of_week) % 7]);
  1571. X        if (do_whole_year)
  1572. X            tmp[MIN_DAY_LEN] = '\0';
  1573. X        (void) print_word(tmp);
  1574. X        }
  1575. X    PRT(" ] def\n");
  1576. X
  1577. X    /* title for "notes" box */
  1578. X
  1579. X    PRT("/notesheading (");
  1580. X    PUTSTR(NOTES_HDR);
  1581. X    PRT(") def\n");
  1582. X
  1583. X    /* line separator */
  1584. X
  1585. X    PRT("/linesep ");
  1586. X    print_word(LINE_SEP);
  1587. X    PRT(" def\n");
  1588. X
  1589. X    /* colors (black/gray) to print weekdays and holidays */
  1590. X
  1591. X    PRT("/day_gray [");
  1592. X    for (ngray = 0, i = SUN; i <= SAT; ngray += day_color[i++] == GRAY)
  1593. X        PRT(" %s", cond[day_color[(i + first_day_of_week) % 7]]);
  1594. X    PRT(" ] def\n");
  1595. X    PRT("/holiday_gray %s def\n", cond[ngray <= 3]);
  1596. X
  1597. X     /* rotation, scale, and translate values. */
  1598. X     PRT("/rval %d def\n", rotate);
  1599. X     PRT("/xsval %s def\n/ysval %s def\n", xsval, ysval);
  1600. X     PRT("/xtval %s def\n/ytval %s def\n", xtval, ytval);
  1601. X
  1602. X    /* moon, Julian date, box fill, and outline flags */
  1603. X
  1604. X    PRT("/draw-moons %s def\n", cond[draw_moons]);
  1605. X    PRT("/julian-dates %s def\n", cond[julian_dates]);
  1606. X    PRT("/fill-boxes %s def\n", cond[! blank_boxes]);
  1607. X    PRT("/logical_gray %s def\n", gray[num_style]);
  1608. X
  1609. X    /* PostScript boilerplate (part 1 of 1) */
  1610. X
  1611. X    for (ap = header; *ap; ap++)
  1612. X        PRT("%s\n", *ap);
  1613. X    PRT("\n");
  1614. X
  1615. X    /*
  1616. X     * Write out PostScript code to print calendars
  1617. X     */
  1618. X
  1619. X    if (do_whole_year)    /* round up to multiple of 12 months */
  1620. X        nmonths = ((nmonths + 11) / 12) * 12;
  1621. X
  1622. X    for (this_month = month, this_year = year; nmonths--; ) {
  1623. X        print_month(this_month, this_year);
  1624. X        this_year = NEXT_YEAR(this_month, this_year);
  1625. X        this_month = NEXT_MONTH(this_month, this_year);
  1626. X    }
  1627. X
  1628. }
  1629. X
  1630. X
  1631. /*
  1632. X * low-level utilities for PostScript generation
  1633. X */
  1634. X
  1635. /*
  1636. X * expand_fmt - expand a strftime-like date format string; pcal supports
  1637. X * %[aAbBdjmUWyY] from strftime() plus %l and prefixes [0o+-] (see below);
  1638. X * returns pointer to character following end of string
  1639. X */
  1640. #ifdef PROTOS
  1641. char *expand_fmt(char *p)
  1642. #else
  1643. char *expand_fmt(p)
  1644. X    char *p;        /* character following percent sign */
  1645. #endif
  1646. {
  1647. X    char c, tmp[20];
  1648. X    static char *prefixes = "0o+-";
  1649. X    int firstday, wkday;
  1650. X    int adjust = 0, strip_lz = TRUE, ordinal = FALSE, prev_num = 0;
  1651. X
  1652. X    do {
  1653. X        switch (c = *p++) {
  1654. X        case 'a':    /* %a : abbreviated weekday */
  1655. X        case 'A':    /* %A : full weekday */
  1656. X            wkday = calc_weekday(this_month, this_day, this_year);
  1657. X            strcpy(tmp, days[wkday]);
  1658. X            if (c == 'a')
  1659. X                tmp[MIN_DAY_LEN] = '\0';
  1660. X            printf("%s", tmp);
  1661. X            break;
  1662. X
  1663. X        case 'b':    /* %b : abbreviated month name */
  1664. X        case 'B':    /* %B : full month name */
  1665. X            strcpy(tmp, months[(this_month + adjust + 11) % 12]);
  1666. X            if (c == 'b')
  1667. X                tmp[MIN_MONTH_LEN] = '\0';
  1668. X            printf("%s", tmp);
  1669. X            break;
  1670. X
  1671. X        case 'd':    /* %d : day of month (01-31) */
  1672. X            printf(strip_lz ? "%d" : "%02d", prev_num = this_day);
  1673. X            break;
  1674. X
  1675. X        case 'j':    /* %j : day of year (001-366) */
  1676. X            prev_num = DAY_OF_YEAR(this_month, this_day, this_year);
  1677. X            printf(strip_lz ? "%d" : "%03d", prev_num);
  1678. X            break;
  1679. X
  1680. X        case 'l':    /* %l : days left in year (000-365) (NEW) */
  1681. X            prev_num = YEAR_LEN(this_year) - DAY_OF_YEAR(this_month,                    this_day, this_year);
  1682. X            printf(strip_lz ? "%d" : "%03d", prev_num);
  1683. X            break;
  1684. X
  1685. X        case 'm':    /* %m : month (01-12) */
  1686. X            prev_num = (this_month + adjust + 11) % 12 + 1;
  1687. X            printf(strip_lz ? "%d" : "%02d", prev_num);
  1688. X            break;
  1689. X
  1690. X        /* %U considers the first "logical Sunday" (the first day
  1691. X         * of the week as printed - cf. the -F option) of the year
  1692. X         * to be the start of week 1; %W uses the first "logical
  1693. X         * Monday" instead.
  1694. X         */
  1695. X        case 'U':    /* %U : week number (00-53) */
  1696. X        case 'W':    /* %W : week number (00-53) */
  1697. X            firstday = ((c == 'W' ? 15 : 14) -
  1698. X                    START_DAY(JAN, this_year)) % 7 + 1;
  1699. X            prev_num = (DAY_OF_YEAR(this_month, this_day,
  1700. X                    this_year) - firstday + 7) / 7;
  1701. X            printf(strip_lz ? "%d" : "%02d", prev_num);
  1702. X            break;
  1703. X
  1704. X        case 'y':    /* %y : year w/o century (00-99) */
  1705. X            printf("%02d", prev_num = (this_year + adjust) % 100);
  1706. X            break;
  1707. X
  1708. X        case 'Y':    /* %Y : year w/century */
  1709. X            printf("%d", prev_num = this_year + adjust);
  1710. X            break;
  1711. X
  1712. X        /* prefix flags [o0+-] : set flags for next pass */
  1713. X
  1714. X        case 'o':    /* %o : ordinal suffix (NEW) */
  1715. X            ordinal = TRUE;
  1716. X            break;
  1717. X
  1718. X        case '0':    /* %0 : add leading zeroes (NEW) */
  1719. X            strip_lz = FALSE;
  1720. X            break;
  1721. X
  1722. X        case '+':    /* %+ : increment next month/year (NEW) */
  1723. X        case '-':    /* %- : decrement next month/year (NEW) */
  1724. X            adjust = c == '-' ? -1 : 1;
  1725. X            break;
  1726. X
  1727. X        case '\0':    /* accidental end-of-string */
  1728. X        case ' ':
  1729. X            return p - 1;
  1730. X
  1731. X        default:    /* other - just print it */
  1732. X            PUTCHAR(c);
  1733. X            break;
  1734. X        };
  1735. X
  1736. X    } while (strchr(prefixes, c) != NULL);
  1737. X
  1738. X    if (ordinal && prev_num)
  1739. X        printf("%s", ordinal_suffix(prev_num));
  1740. X    return p;
  1741. X
  1742. }
  1743. X
  1744. X
  1745. /*
  1746. X * print_word - print a single word, representing parentheses and non-ASCII
  1747. X * characters as octal literals and expanding format specifiers; return pointer
  1748. X * to character following word (NULL if no word follows)
  1749. X */
  1750. #ifdef PROTOS
  1751. char *print_word(char *p)
  1752. #else
  1753. char *print_word(p)
  1754. X    char *p;
  1755. #endif
  1756. {
  1757. X    char c;
  1758. X
  1759. X    if (*p == '\0' || *(p += strspn(p, WHITESPACE)) == '\0')
  1760. X        return NULL;
  1761. X
  1762. X    PRT("(");
  1763. X    while ((c = *p) && !isspace(c)) {
  1764. X        if (c == '%' && p[1] != '\0')
  1765. X            p = expand_fmt(p + 1);
  1766. X        else {
  1767. X            PUTCHAR(c);
  1768. X            p++;
  1769. X        }
  1770. X    }
  1771. X    PRT(")");
  1772. X
  1773. X    return p;
  1774. }
  1775. X
  1776. X
  1777. /*
  1778. X * print_text - print tokens in text (assumed separated by single blank)
  1779. X * in PostScript format
  1780. X */
  1781. #ifdef PROTOS
  1782. void print_text(char *p)
  1783. #else
  1784. void print_text(p)
  1785. X    char *p;
  1786. #endif
  1787. {
  1788. X    while (p = print_word(p))
  1789. X        PRT(" ");
  1790. }
  1791. X
  1792. X
  1793. /*
  1794. X * def_footstring - print definition for foot string, again converting 
  1795. X * all characters other than letters, digits, or space to octal escape
  1796. X * and expanding format specifiers
  1797. X */
  1798. #ifdef PROTOS
  1799. void def_footstring(char *p,
  1800. X            char lcr)
  1801. #else
  1802. void def_footstring(p, lcr)
  1803. X    char *p;            /* definition */
  1804. X    char lcr;            /* L, C, or R */
  1805. #endif
  1806. {
  1807. X    char c;
  1808. X
  1809. X    this_day = 1;            /* set default day in foot string */
  1810. X    PRT("/%cfootstring (", lcr);
  1811. X    while (c = *p)
  1812. X        if (c == '%' && p[1] != '\0')
  1813. X            p = expand_fmt(p + 1);
  1814. X        else
  1815. X            PUTCHAR(c), p++;
  1816. X    PRT(") def\n");
  1817. }
  1818. X
  1819. X
  1820. /*
  1821. X * Routines to extract and print data
  1822. X */
  1823. X
  1824. X
  1825. /*
  1826. X * find_daytext - find and print the day (including notes) or holiday text
  1827. X * for the specified month/year
  1828. X */
  1829. #ifdef PROTOS
  1830. void find_daytext(int month,
  1831. X          int year,
  1832. X          int is_holiday)
  1833. #else
  1834. void find_daytext(month, year, is_holiday)
  1835. X    int month, year;
  1836. X    int is_holiday;        /* TRUE: print holiday text */
  1837. #endif
  1838. {
  1839. X    register int day;
  1840. X    year_info *py;
  1841. X    month_info *pm;
  1842. X    register day_info *pd;
  1843. X    int first;
  1844. X    char *fcn = is_holiday ? "holidaytext" : "daytext";
  1845. X
  1846. X    /* if no text for this year and month, return */
  1847. X
  1848. X    if ((py = find_year(year, FALSE)) == NULL ||
  1849. X        (pm = py->month[month-1]) == NULL)
  1850. X        return;
  1851. X
  1852. X    /* walk array of day text pointers and linked lists of text */
  1853. X
  1854. X    for (day = 1; day <= NOTE_DAY; day++) {
  1855. X        for (pd = pm->day[day-1], first = TRUE;
  1856. X             pd;
  1857. X             pd = pd->next) {
  1858. X            if (pd->is_holiday != is_holiday)
  1859. X                continue;
  1860. X            if (first) {
  1861. X                if (day != NOTE_DAY)    /* set up call */
  1862. X                    PRT("%d ", day);
  1863. X                printf("[ \n");
  1864. X            }
  1865. X            else {
  1866. X                PRT("\n");
  1867. X                print_word(LINE_SEP);    /* separate lines */
  1868. X                PRT("\n");
  1869. X            }
  1870. X            this_day = day == NOTE_DAY ? 1 : day;
  1871. X            print_text(pd->text);
  1872. X            first = FALSE;
  1873. X        }
  1874. X        if (! first)        /* wrap up call (if one made) */
  1875. X            PRT("\n] %s\n", day == NOTE_DAY ? "notetext" : fcn);
  1876. X    }
  1877. }
  1878. X
  1879. X
  1880. /*
  1881. X * find_holidays - find and print the note block flag and holidays for
  1882. X * specified month/year
  1883. X */
  1884. #ifdef PROTOS
  1885. void find_holidays(int month,
  1886. X           int year)
  1887. #else
  1888. void find_holidays(month, year)
  1889. X    int month, year;
  1890. #endif
  1891. {
  1892. X    register int day;
  1893. X    register unsigned long holidays;
  1894. X    year_info *py;
  1895. X    month_info *pm;
  1896. X
  1897. X    pm = (py = find_year(year, FALSE)) ? py->month[month-1] : NULL;
  1898. X
  1899. X    if (! do_whole_year)
  1900. X         PRT("/note_block %s def\n", cond[pm && pm->day[NOTE_DAY-1]]);
  1901. X
  1902. X    PRT("/holidays [");    /* start definition of list */
  1903. X
  1904. X    for (holidays = pm ? pm->holidays : 0, day = 1;
  1905. X         holidays;
  1906. X         holidays >>= 1, day++)
  1907. X        if (holidays & 01)
  1908. X            PRT(" %d", day);
  1909. X
  1910. X    PRT(" ] def\n");
  1911. X
  1912. }
  1913. X
  1914. X
  1915. /*
  1916. X * print_moon_info - print the information necessary to draw moons.  If
  1917. X * printing moons on all days, print the phase for each day; if printing
  1918. X * only quarter moons, tweak the phase to an exact quarter (so the icon
  1919. X * is printed correctly) and generate a list of the quarter-moon dates
  1920. X */
  1921. #ifdef PROTOS
  1922. void print_moon_info(int month,
  1923. X             int year)
  1924. #else
  1925. void print_moon_info(month, year)
  1926. X    int month, year;
  1927. #endif
  1928. {
  1929. X    int n, ndays, day, is_q;
  1930. X    char *p;
  1931. X    unsigned long qdays;
  1932. X    double phase;
  1933. X
  1934. X    if (draw_moons == NO_MOONS)
  1935. X        return;
  1936. X
  1937. X    /* print the phase of the moon for each day of the month */
  1938. X
  1939. X    PRT("/moon_phases [\t\t%% from %s\n\t",
  1940. X        (p = find_moonfile(year)) ? p : "algorithm");
  1941. X
  1942. X    for (n = 0, qdays = 0L, day = 1, ndays = LENGTH_OF(month, year);
  1943. X         day <= ndays;
  1944. X         day++) {
  1945. X        phase = find_phase(month, day, year, &is_q);
  1946. X        if (draw_moons == SOME_MOONS && is_q)
  1947. X            phase = EXACT_QUARTER(phase);
  1948. X        if (draw_moons == ALL_MOONS || is_q)
  1949. X            PRT("%.3f%s", PRT_TWEAK(phase), ++n % 10 == 0 ?
  1950. X                "\n\t" : " ");
  1951. X        if (is_q)
  1952. X            qdays |= 1L << (day - 1);
  1953. X        }
  1954. X    PRT("] def\n");
  1955. X
  1956. X    /* if drawing only quarter moons, print days when they occur */
  1957. X
  1958. X    if (draw_moons == SOME_MOONS) {
  1959. X        PRT("/quarter_moons [ ");
  1960. X        for (day = 1; qdays; day++, qdays >>= 1)
  1961. X            if (qdays & 01)
  1962. X                PRT("%d ", day);
  1963. X        PRT("] def\n");
  1964. X    }
  1965. }
  1966. X
  1967. X
  1968. /*
  1969. X * print_julian_info - print the information necessary to print Julian dates
  1970. X */
  1971. #ifdef PROTOS
  1972. void print_julian_info(int month,
  1973. X               int year)
  1974. #else
  1975. void print_julian_info(month, year)
  1976. X    int month, year;
  1977. #endif
  1978. {
  1979. X
  1980. X    if (julian_dates != NO_JULIANS)
  1981. X        PRT("/jdstart %d def\n", DAY_OF_YEAR(month, 1, year));
  1982. X    if (julian_dates == ALL_JULIANS)
  1983. X        PRT("/yearlen %d def\n", YEAR_LEN(year));
  1984. }
  1985. X
  1986. X
  1987. /*
  1988. X * print_month - generate calendar for specified month/year
  1989. X */
  1990. #ifdef PROTOS
  1991. void print_month(int month,
  1992. X         int year)
  1993. #else
  1994. void print_month(month, year)
  1995. X    int month, year;
  1996. #endif
  1997. {
  1998. X    static int nmonths = 0;
  1999. X
  2000. X    PRT("/year %d def\n", year);        /* set up year and month */
  2001. X    PRT("/month %d def\n", month);
  2002. X    PRT("/startday %d def\n", START_DAY(month, year));
  2003. X    PRT("/ndays %d def\n", LENGTH_OF(month, year));
  2004. X
  2005. X    find_holidays(month, year);        /* make list of holidays */
  2006. X
  2007. X    /* are we printing 12 months per page or only one? */
  2008. X
  2009. X    if (do_whole_year) {
  2010. X        /* reset foot strings at start of each page */
  2011. X        if (nmonths % 12 == 0) {
  2012. X            def_footstring(lfoot, 'L');
  2013. X            def_footstring(cfoot, 'C');
  2014. X            def_footstring(rfoot, 'R');
  2015. X        }
  2016. X
  2017. X        PRT("/posn %d def\n", nmonths % 12);    /* location on page */
  2018. X        PRT("printmonth_%c\n", rotate == LANDSCAPE ? 'l' : 'p');
  2019. X        if (++nmonths % 12 == 0)
  2020. X            PRT("showpage\n");
  2021. X    }
  2022. X    else {
  2023. X        /* reset foot strings each month (may change) */
  2024. X        def_footstring(lfoot, 'L');
  2025. X        def_footstring(cfoot, 'C');
  2026. X        def_footstring(rfoot, 'R');
  2027. X
  2028. X        /* generate lengths of previous and next months */
  2029. X        PRT("/lndays %d def\n", LENGTH_OF(PREV_MONTH(month, year),
  2030. X                    PREV_YEAR(month, year)));
  2031. X        PRT("/nndays %d def\n", LENGTH_OF(NEXT_MONTH(month, year),
  2032. X                    NEXT_YEAR(month, year)));
  2033. X
  2034. X        print_julian_info(month, year);        /* Julian date info */
  2035. X        print_moon_info(month, year);        /* moon info */
  2036. X
  2037. X        PRT("printmonth\n");
  2038. X        find_daytext(month, year, TRUE);    /* holiday text */
  2039. X        find_daytext(month, year, FALSE);    /* day and note text */
  2040. X        PRT("showpage\n");
  2041. X    }
  2042. }
  2043. SHAR_EOF
  2044. chmod 0644 writefil.c ||
  2045. echo 'restore of writefil.c failed'
  2046. Wc_c="`wc -c < 'writefil.c'`"
  2047. test 13864 -eq "$Wc_c" ||
  2048.     echo 'writefil.c: original size 13864, current size' "$Wc_c"
  2049. fi
  2050. exit 0
  2051.