home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 2: PC / frozenfish_august_1995.bin / bbs / d09xx / d0975.lha / PCal / writefil.c < prev   
C/C++ Source or Header  |  1993-08-11  |  25KB  |  995 lines

  1. /*
  2.  * writefil.c - Pcal routines concerned with writing the PostScript output
  3.  *
  4.  * Contents:
  5.  *
  6.  *        def_footstring
  7.  *        expand_fmt
  8.  *        find_daytext
  9.  *        find_holidays
  10.  *        find_noteboxes
  11.  *        print_db_word
  12.  *        print_julian_info
  13.  *        print_month
  14.  *        print_moon_info
  15.  *        print_dates
  16.  *        print_pstext
  17.  *        print_text
  18.  *        print_word
  19.  *        write_calfile
  20.  *        write_psfile
  21.  *
  22.  * Revision history:
  23.  *
  24.  *    4.3    AWR    12/03/91    add support for -s flag (specify
  25.  *                    alternate date/fill box shading values)
  26.  *
  27.  *    4.2    AWR    10/08/91    add support for -[kK] flags (change
  28.  *                    position of small calendars)
  29.  *
  30.  *            10/03/91    add find_noteboxes(); revise to print
  31.  *                    text in multiple notes boxes
  32.  *
  33.  *                    add support for -S flag
  34.  *
  35.  *            10/02/91    modify def_footstring() to handle all
  36.  *                    types of strings; use it to print notes
  37.  *                    header (-N flag)
  38.  *
  39.  *            09/19/91    add write_calfile(), print_dates(),
  40.  *                    and new print_text() to generate 
  41.  *                    input for Un*x "calendar" utility;
  42.  *                    renamed old print_text() as
  43.  *                    print_pstext() for clarity; revised
  44.  *                    to simplify setting working date
  45.  *
  46.  *    4.11    AWR    08/23/91    revise expand_fmt() to write results
  47.  *                    to string instead of stdout; revise
  48.  *                    print_word() to avoid writing null
  49.  *                    strings
  50.  *
  51.  *        AWR    08/21/91    use ABBR_DAY_LEN and ABBR_MONTH_LEN
  52.  *                    (cf. pcallang.h) to print abbreviated
  53.  *                    day/month names
  54.  *
  55.  *        AWR    08/21/91    add %u and %w (calculate week number
  56.  *                    so that 1/1 is always week 1); support
  57.  *                    %[+-]<n>[DWMY] to adjust working date
  58.  *                    by +|- <n> days/weeks/months/years
  59.  *
  60.  *    4.1    AWR    08/16/91    Support -G flag (outlined gray dates)
  61.  *
  62.  *    4.02    AWR    07/02/91    Added "%" expansions in text strings
  63.  *                    (cf. expand_fmt())
  64.  *
  65.  *    4.0    AWR    01/28/91    Support -B, -w flags and moon file
  66.  *
  67.  *            01/15/91    Extracted from pcal.c
  68.  *
  69.  */
  70.  
  71. /*
  72.  * Standard headers:
  73.  */
  74.  
  75. #include <stdio.h>
  76. #include <ctype.h>
  77. #include <string.h>
  78.  
  79. /*
  80.  * Pcal-specific definitions:
  81.  */
  82.  
  83. #include "pcaldefs.h"
  84. #include "pcalglob.h"
  85. #define  WRITEFIL        /* to get ordinal_suffix() from pcallang.h */
  86. #include "pcallang.h"
  87. #include "pcalinit.h"        /* PostScript boilerplate */
  88.  
  89. /*
  90.  * Macros:
  91.  */
  92.  
  93. /* make sure PRT() doesn't round "ph" up to 1.0 when printing it */
  94. #define PRT_TWEAK(ph)        ((ph) >= 0.9995 ? 0.0 : (ph))
  95.  
  96. /* advance working date by n days */
  97. #define SET_DATE(n)    do {                        \
  98.     MAKE_DATE(date, work_month, work_day + (n), work_year);        \
  99.     normalize(&date);                        \
  100.     work_month = date.mm, work_day = date.dd, work_year = date.yy;    \
  101. } while (0)
  102.  
  103. /* reset working date to original date */
  104. #define RESET_DATE    \
  105. work_month = this_month, work_day = this_day, work_year = this_year
  106.  
  107. /*
  108.  * Globals:
  109.  */
  110.  
  111. /* order of following strings must conform to #define's in pcaldefs.h (q.v.) */
  112. static char *cond[3] = {"false", "true", "(some)"};
  113. static char *gray[3] = {"(gray)", "(outline)", "(outline_gray)"};
  114.  
  115. static int this_day, this_month, this_year;    /* current day */
  116. static int work_day, work_month, work_year;    /* working day (cf. expand_fmt()) */
  117. static char *kw_note, *kw_opt, *kw_year;    /* keywords for -c output */
  118.  
  119. static int debug_text;                /* generate debug output */
  120.  
  121.  
  122. /*
  123.  * write_psfile - write PostScript code
  124.  *
  125.  * The actual output of the PostScript code is straightforward.  This routine
  126.  * writes a PostScript header followed by declarations of all the PostScript
  127.  * variables affected by command-line flags and/or language dependencies.  It
  128.  * the generates the PostScript boilerplate generated from pcalinit.ps, and
  129.  * finally calls print_month() to generate the PostScript code for each
  130.  * requested month.
  131.  */
  132. #ifdef PROTOS
  133. void write_psfile(int month,
  134.           int year,
  135.           int nmonths)
  136. #else
  137. void write_psfile(month, year, nmonths)
  138.     int month;            /* starting month   */
  139.     int year;            /* starting year    */
  140.     int nmonths;            /* number of months */
  141. #endif
  142. {
  143.     int i, ngray, nfsize;
  144.     char *p, **ap, tmp[STRSIZ];
  145.  
  146.     debug_text = DEBUG(DEBUG_TEXT);        /* debug text output? */
  147.  
  148.     /*
  149.      * Write out PostScript prolog
  150.      */
  151.  
  152.      PRT("%%!PS-Adobe-1.0\n%%\t");
  153.     PRT(VERSION_MSG, progname, version);
  154.     if (*datefile)
  155.         PRT(DATEFILE_MSG, datefile);
  156.     PRT("\n%%\n");
  157.  
  158.     /* font names and sizes (notes font only in 4.2) */
  159.  
  160.     nfsize = (p = strrchr(notesfont, '/')) ? *p = '\0', atoi(p + 1) :
  161.                 atoi(strrchr(NOTESFONT, '/') + 1);
  162.  
  163.     PRT("/titlefont /%s def\n/dayfont /%s def\n/notesfont /%s def\n",
  164.         titlefont, dayfont, notesfont);
  165.     PRT("/notesfontsize %d def\n", nfsize);
  166.  
  167.     /* month names */
  168.  
  169.     PRT("/month_names [");
  170.     for (i = JAN; i <= DEC; i++) {
  171.         PRT(i % 6 == 1 ? "\n\t" : " ");
  172.         (void) print_word(months[i-1]);
  173.     }
  174.     PRT(" ] def\n");
  175.  
  176.     /* day names - abbreviate if printing entire year on page */
  177.  
  178.     PRT("/day_names [");
  179.     for (i = SUN; i <= SAT; i++) {
  180.         PRT(i % 6 == 0 && ! do_whole_year ? "\n\t" : " ");
  181.         strcpy(tmp, days[(i + first_day_of_week) % 7]);
  182.         if (do_whole_year)
  183.             tmp[ABBR_DAY_LEN] = '\0';
  184.         (void) print_word(tmp);
  185.         }
  186.     PRT(" ] def\n");
  187.  
  188.     /* line separator */
  189.  
  190.     PRT("/linesep ");
  191.     print_word(LINE_SEP);
  192.     PRT(" def\n");
  193.  
  194.     /* colors (black/gray) to print weekdays and holidays */
  195.  
  196.     PRT("/day_gray [");
  197.     for (ngray = 0, i = SUN; i <= SAT; ngray += day_color[i++] == GRAY)
  198.         PRT(" %s", cond[day_color[(i + first_day_of_week) % 7]]);
  199.     PRT(" ] def\n");
  200.     PRT("/holiday_gray %s def\n", cond[ngray <= 3]);
  201.     PRT("/logical_gray %s def\n", gray[num_style]);
  202.  
  203.      /* rotation, scale, and translate values */
  204.  
  205.      PRT("/rval %d def\n", rotate);
  206.      PRT("/xsval %s def\n/ysval %s def\n", xsval, ysval);
  207.      PRT("/xtval %s def\n/ytval %s def\n", xtval, ytval);
  208.  
  209.     /* moon, Julian date, and box fill flags */
  210.  
  211.     PRT("/draw-moons %s def\n", cond[draw_moons]);
  212.     PRT("/julian-dates %s def\n", cond[julian_dates]);
  213.     PRT("/fill-boxes %s def\n", cond[! blank_boxes]);
  214.  
  215.     /* position of small calendars */
  216.  
  217.     PRT("/prev_small_cal %d def\n", prev_cal_box[small_cal_pos]);
  218.     PRT("/next_small_cal %d def\n", next_cal_box[small_cal_pos]);
  219.  
  220.     /* date and fill box shading values */
  221.  
  222.     strcpy(tmp, shading);
  223.     *(p = strchr(tmp, '/')) = '\0';
  224.     PRT("/dategray %s def\n", tmp);
  225.     PRT("/fillgray %s def\n", p + 1);
  226.  
  227.     /* PostScript boilerplate (part 1 of 1) */
  228.  
  229.     for (ap = header; *ap; ap++)
  230.         PRT("%s\n", *ap);
  231.     PRT("\n");
  232.  
  233.     /*
  234.      * Write out PostScript code to print calendars
  235.      */
  236.  
  237.     for (this_month = month, this_year = year; nmonths--; ) {
  238.         print_month(this_month, this_year);
  239.         this_year = NEXT_YEAR(this_month, this_year);
  240.         this_month = NEXT_MONTH(this_month, this_year);
  241.     }
  242.  
  243. }
  244.  
  245.  
  246. /*
  247.  * write_calfile - write dates in format suitable for Un*x "calendar" utility
  248.  * (and subsequent use by Pcal)
  249.  */
  250. #ifdef PROTOS
  251. void write_calfile(int month,
  252.            int year,
  253.            int nmonths)
  254. #else
  255. void write_calfile(month, year, nmonths)
  256.     int month;            /* starting month   */
  257.     int year;            /* starting year    */
  258.     int nmonths;            /* number of months */
  259. #endif
  260. {
  261.     KWD *k;
  262.  
  263.     /* look up the Pcal keywords (assumed present) for the -c output file */
  264.     for (k = keywds; k->name; k++) {
  265.         if (k->code == DT_NOTE) kw_note = k->name;
  266.         if (k->code == DT_OPT)  kw_opt  = k->name;
  267.         if (k->code == DT_YEAR) kw_year = k->name;
  268.     }
  269.  
  270.     /* print the date style for subsequent use by Pcal */
  271.     PRT("%s -%c\n", kw_opt, date_style == USA_DATES ? F_USA_DATES :
  272.                               F_EUR_DATES);
  273.  
  274.     for (this_month = month, this_year = year; nmonths--; ) {
  275.         print_dates(this_month, this_year);
  276.         this_year = NEXT_YEAR(this_month, this_year);
  277.         this_month = NEXT_MONTH(this_month, this_year);
  278.     }
  279. }
  280.  
  281. /*
  282.  * low-level utilities for PostScript generation
  283.  */
  284.  
  285. /*
  286.  * expand_fmt - expand a strftime-like date format specifier; pcal supports
  287.  * %[aAbBdjmUWyY] from strftime() plus %[luwDM] and prefixes [0o+-] (see below);
  288.  * places expanded string in output buffer and returns pointer to character
  289.  * following end of format specifier.  Assumes working date has been initialized
  290.  * (via RESET_DATE macro) prior to first call for a given text string
  291.  */
  292. #ifdef PROTOS
  293. char *expand_fmt(char *buf,
  294.          char *p)
  295. #else
  296. char *expand_fmt(buf, p)
  297.     char *buf;        /* output buffer (filled in)        */
  298.     char *p;        /* character following percent sign */
  299. #endif
  300. {
  301.     char c;
  302.     static char *prefixes = "0o+-";
  303.     int firstday, wkday;
  304.     int adjust = 0, print_lz = FALSE, ordinal = FALSE, prev_num = -1;
  305.     int num_present = FALSE, num_value = 0;
  306.     DATE date;
  307.  
  308.     /* For compatibility with version 4.1, still support %[+-][bBdmY]
  309.      * (print the next/last month-name/day/month/year).  Version 4.11
  310.      * introduces %[+-]<n>[DWMY], which adjusts the working date by
  311.      * [+-]<n> days/weeks/months/years; this method is preferred due
  312.      * to its greater flexibility.
  313.      */
  314.  
  315.     buf[0] = '\0';        /* initialize output to null string */
  316.     
  317.     do {            /* loop until format character found */
  318.         switch (c = *p++) {
  319.         case 'a':    /* %a : abbreviated weekday */
  320.         case 'A':    /* %A : full weekday */
  321.             wkday = calc_weekday(work_month, work_day, work_year);
  322.             strcpy(buf, days[wkday]);
  323.             if (c == 'a')
  324.                 buf[ABBR_DAY_LEN] = '\0';
  325.             break;
  326.  
  327.         case 'b':    /* %b : abbreviated month name */
  328.         case 'B':    /* %B : full month name */
  329.             strcpy(buf, months[(work_month + adjust + 11) % 12]);
  330.             if (c == 'b')
  331.                 buf[ABBR_MONTH_LEN] = '\0';
  332.             break;
  333.  
  334.         case 'd':    /* %d : day of month (01-31) */
  335.             prev_num = work_day;
  336.             sprintf(buf, print_lz ? "%02d" : "%d", prev_num);
  337.             break;
  338.  
  339.         case 'D':    /* %D : adjust working date by <N> days (NEW) */
  340.             if (!num_present || num_value == 0)
  341.                 RESET_DATE;
  342.             else
  343.                 SET_DATE(adjust * num_value);
  344.             break;
  345.  
  346.         case 'j':    /* %j : day of year (001-366) */
  347.             prev_num = DAY_OF_YEAR(work_month, work_day,
  348.                     work_year);
  349.             sprintf(buf, print_lz ? "%03d" : "%d", prev_num);
  350.             break;
  351.  
  352.         case 'l':    /* %l : days left in year (000-365) (NEW) */
  353.             prev_num = YEAR_LEN(work_year) - DAY_OF_YEAR(work_month,
  354.                     work_day, work_year);
  355.             sprintf(buf, print_lz ? "%03d" : "%d", prev_num);
  356.             break;
  357.  
  358.         case 'm':    /* %m : month (01-12) */
  359.             prev_num = (work_month + adjust + 11) % 12 + 1;
  360.             sprintf(buf, print_lz ? "%02d" : "%d", prev_num);
  361.             break;
  362.  
  363.         case 'M':    /* %M : adjust date by <N> months (NEW) */
  364.             if (!num_present || num_value == 0)
  365.                 RESET_DATE;
  366.             else {
  367.                 int len;
  368.  
  369.                 work_month += adjust * num_value;
  370.                 while (work_month > DEC) {
  371.                     work_month -= 12;
  372.                     work_year++;
  373.                 }
  374.                 while (work_month < JAN) {
  375.                     work_month += 12;
  376.                     work_year--;
  377.                 }
  378.  
  379.                 /* make sure day of new month is legal */
  380.                 len = LENGTH_OF(work_month, work_year);
  381.                 if (work_day > len)
  382.                     work_day = len;
  383.             }
  384.             break;
  385.  
  386.         /* %u considers the week containing 1/1 to be week 1 and
  387.          * the next "logical Sunday" (the first day of the week
  388.          * as printed - cf. the -F option) to be the start of week
  389.          * 2; %U considers the first "logical Sunday" of the year to
  390.          * be the start of week 1.  %w and %W behave like %u and %U
  391.          * respectively, but use the first "logical Monday" instead.
  392.          */
  393.         case 'W':    /* %W : week number (00-53)       */
  394.             /* %W, if prefaced by [+-]N, adjusts the date by
  395.              * [+-]N weeks (resets if N == 0); check for this
  396.              * case first
  397.              */
  398.             if (num_present) {
  399.                 if (num_value == 0)    /* N = 0: reset date */
  400.                     RESET_DATE;
  401.                 else
  402.                     SET_DATE(7 * adjust * num_value);
  403.                 break;
  404.             }
  405.             /* fall through */
  406.         case 'u':    /* %u : week number (01-54) (NEW) */
  407.         case 'U':    /* %U : week number (00-53)       */
  408.         case 'w':    /* %w : week number (01-54) (NEW) */
  409.             firstday = ((TOLOWER(c) == 'w' ? 15 : 14) -
  410.                     START_BOX(JAN, work_year)) % 7 + 1;
  411.             prev_num = (DAY_OF_YEAR(work_month, work_day,
  412.                     work_year) - firstday + 7) / 7;
  413.             if (islower(c) && firstday != 1)
  414.                 prev_num++;
  415.             sprintf(buf, print_lz ? "%02d" : "%d", prev_num);
  416.             break;
  417.  
  418.         case 'y':    /* %y : year w/o century (00-99) */
  419.             prev_num = (work_year + adjust) % 100;
  420.             sprintf(buf, "%02d", prev_num);
  421.             break;
  422.  
  423.         case 'Y':    /* %Y : year w/century */
  424.             /* %Y, if prefaced by [+-]N, adjusts the date by
  425.              * [+-]N years (resets if N == 0); check for this
  426.              * case first
  427.              */
  428.             if (num_present) {
  429.                 if (num_value == 0)    /* N = 0: reset date */
  430.                     RESET_DATE;
  431.                 else {
  432.                     int len;
  433.  
  434.                     work_year += adjust * num_value;
  435.  
  436.                     /* make sure day is legal */
  437.                     len = LENGTH_OF(work_month, work_year);
  438.                     if (work_day > len)
  439.                         work_day = len;
  440.                 }
  441.             } else {
  442.                 prev_num = work_year + adjust;
  443.                 sprintf(buf, "%d", prev_num);
  444.             }
  445.             break;
  446.  
  447.         /* prefix flags [o0+-] : set flags for next pass */
  448.  
  449.         case 'o':    /* %o : ordinal suffix (NEW) */
  450.             ordinal = TRUE;
  451.             break;
  452.  
  453.         case '0':    /* %0 : add leading zeroes (NEW) */
  454.             print_lz = TRUE;
  455.             break;
  456.  
  457.         case '+':    /* %+ : increment next value (NEW) */
  458.         case '-':    /* %- : decrement next value (NEW) */
  459.             adjust = c == '-' ? -1 : 1;
  460.             if (isdigit(*p)) {        /* get the number */
  461.                 num_present = TRUE;
  462.                 while (isdigit(*p))
  463.                     num_value = num_value * 10 +
  464.                             (*p++ - '0');
  465.             }
  466.             break;
  467.  
  468.         case '\0':    /* accidental end-of-string */
  469.         case ' ':
  470.             return p - 1;
  471.  
  472.         default:    /* other - just copy it to output */
  473.             sprintf(buf, "%c", c);
  474.             break;
  475.         };
  476.  
  477.     } while (strchr(prefixes, c) != NULL);
  478.  
  479.     /* append ordinal suffix if requested */
  480.     if (ordinal && prev_num >= 0)
  481.         strcat(buf, ordinal_suffix(prev_num));
  482.     return p;
  483.  
  484. }
  485.  
  486.  
  487. /*
  488.  * print_word - print a single word, representing punctuation and non-ASCII
  489.  * characters as octal literals and expanding format specifiers; return pointer
  490.  * to character following word (NULL if no word follows)
  491.  */
  492. #ifdef PROTOS
  493. char *print_word(char *p)
  494. #else
  495. char *print_word(p)
  496.     char *p;
  497. #endif
  498. {
  499.     char c, buf[20];
  500.     int first = TRUE;    /* flag to avoid printing null strings */
  501.  
  502.     if (*p == '\0' || *(p += strspn(p, WHITESPACE)) == '\0')
  503.         return NULL;
  504.  
  505.     while ((c = *p) && !isspace(c)) {
  506.         if (c == '%' && p[1] != '\0') {
  507.             p = expand_fmt(buf, p + 1);
  508.             if (*buf && first) {
  509.                 PRT("(");
  510.                 first = FALSE;
  511.             }    
  512.             PRT("%s", buf);
  513.         } else {
  514.             if (first)
  515.                 PRT("(");
  516.             first = FALSE;
  517.             PUTCHAR(c);
  518.             p++;
  519.         }
  520.     }
  521.  
  522.     if (!first)
  523.         PRT(")");
  524.  
  525.     return p;
  526. }
  527.  
  528.  
  529. /*
  530.  * print_db_word - debug version of print_word; omits parentheses, does not
  531.  * convert punctuation to escape sequences, and writes results to stderr
  532.  * (not stdout)
  533.  */
  534. #ifdef PROTOS
  535. char *print_db_word(char *p)
  536. #else
  537. char *print_db_word(p)
  538.     char *p;
  539. #endif
  540. {
  541.     char c, buf[20];
  542.  
  543.     if (*p == '\0' || *(p += strspn(p, WHITESPACE)) == '\0')
  544.         return NULL;
  545.  
  546.     while ((c = *p) && !isspace(c)) {
  547.         if (c == '%' && p[1] != '\0') {
  548.             p = expand_fmt(buf, p + 1);
  549.             FPR(stderr, "%s", buf);
  550.         } else {
  551.             FPR(stderr, isprint(c) ? "%c" : "\\%03o", c & 0377);
  552.             p++;
  553.         }
  554.     }
  555.  
  556.     return p;
  557. }
  558.  
  559.  
  560. /*
  561.  * print_pstext - print tokens in text (assumed separated by single blank)
  562.  * in PostScript format and as debugging information if requested
  563.  */
  564. #ifdef PROTOS
  565. void print_pstext(char *p)
  566. #else
  567. void print_pstext(p)
  568.     char *p;
  569. #endif
  570. {
  571.     char *s = p;        /* save for possible second pass */
  572.     
  573.     while (p = print_word(p))
  574.         PRT(" ");
  575.  
  576.     /* repeat to generate debugging info if requested */
  577.     if (debug_text)
  578.         while (s = print_db_word(s))
  579.             FPR(stderr, " ");
  580.  
  581. }
  582.  
  583.  
  584. /*
  585.  * print_text - print text as supplied; expand format specifiers but
  586.  * do not tokenize into words or translate punctuation to escape sequences
  587.  */
  588. #ifdef PROTOS
  589. void print_text(char *p)
  590. #else
  591. void print_text(p)
  592.     char *p;
  593. #endif
  594. {
  595.     char c, buf[20];
  596.  
  597.     while (c = *p)
  598.         if (c == '%' && p[1] != '\0') {
  599.             p = expand_fmt(buf, p + 1);
  600.             PRT("%s", buf);
  601.         } else {
  602.             PRT(isprint(c) ? "%c" : "\\%03o" , (c) & 0377);
  603.             p++;
  604.         }
  605. }
  606.  
  607.  
  608. /*
  609.  * def_footstring - print definition for foot string, again converting 
  610.  * all characters other than letters, digits, or space to octal escape
  611.  * and expanding format specifiers
  612.  */
  613. #ifdef PROTOS
  614. void def_footstring(char *p,
  615.             char *str)
  616. #else
  617. void def_footstring(p, str)
  618.     char *p;            /* definition */
  619.     char *str;            /* name of string */
  620. #endif
  621. {
  622.     char c, buf[20];
  623.  
  624.     this_day = 1;            /* set default day in foot string */
  625.     RESET_DATE;            /* reset working date */
  626.  
  627.     PRT("/%s (", str);
  628.     while (c = *p)
  629.         if (c == '%' && p[1] != '\0') {
  630.             p = expand_fmt(buf, p + 1);
  631.             PRT("%s", buf);
  632.         } else {
  633.             PUTCHAR(c);
  634.             p++;
  635.         }
  636.     PRT(") def\n");
  637. }
  638.  
  639.  
  640. /*
  641.  * Routines to extract and print data
  642.  */
  643.  
  644.  
  645. /*
  646.  * find_daytext - find and print the day (including notes) or holiday text
  647.  * for the specified month/year
  648.  */
  649. #ifdef PROTOS
  650. void find_daytext(int month,
  651.           int year,
  652.           int is_holiday)
  653. #else
  654. void find_daytext(month, year, is_holiday)
  655.     int month, year;
  656.     int is_holiday;        /* TRUE: print holiday text */
  657. #endif
  658. {
  659.     register int day;
  660.     year_info *py;
  661.     month_info *pm;
  662.     register day_info *pd;
  663.     int first;
  664.     char *fcn = is_holiday ? "holidaytext" : "daytext";
  665.     char hol = is_holiday ? '*' : ' ';
  666.  
  667.     /* if no text for this year and month, return */
  668.  
  669.     if ((py = find_year(year, FALSE)) == NULL ||
  670.         (pm = py->month[month-1]) == NULL)
  671.         return;
  672.  
  673.     /* walk array of day text pointers and linked lists of text */
  674.  
  675.     for (day = 1; day <= LAST_NOTE_DAY; day++) {
  676.         for (pd = pm->day[day-1], first = TRUE;
  677.              pd;
  678.              pd = pd->next) {
  679.             if (pd->is_holiday != is_holiday)
  680.                 continue;
  681.             if (first) {
  682.                 PRT("%d [ \n", day >= FIRST_NOTE_DAY ?
  683.                     note_box(month, day, year) : day);
  684.             }
  685.             else {
  686.                 PRT("\n");
  687.                 print_word(LINE_SEP);    /* separate lines */
  688.                 PRT("\n");
  689.             }
  690.             this_day = day >= FIRST_NOTE_DAY ? 1 : day;
  691.             RESET_DATE;        /* reset working date */
  692.             if (debug_text)
  693.                 if (day < FIRST_NOTE_DAY)
  694.                     FPR(stderr, "%02d/%02d/%d%c ", month,
  695.                         day, year, hol);
  696.                 else
  697.                     FPR(stderr, "%02d[%02d]%d  ", month,
  698.                         day - FIRST_NOTE_DAY + 1, year);
  699.             print_pstext(pd->text);
  700.             if (debug_text)
  701.                 FPR(stderr, "\n");
  702.             first = FALSE;
  703.         }
  704.         if (! first) {        /* wrap up call (if one made) */
  705.             PRT("\n] %s\n", day >= FIRST_NOTE_DAY ? "notetext" :
  706.                                 fcn);
  707.         }
  708.     }
  709. }
  710.  
  711.  
  712. /*
  713.  * find_holidays - find and print the holidays for specified month/year
  714.  */
  715. #ifdef PROTOS
  716. void find_holidays(int month,
  717.            int year)
  718. #else
  719. void find_holidays(month, year)
  720.     int month, year;
  721. #endif
  722. {
  723.     register int day;
  724.     register unsigned long holidays;
  725.     year_info *py;
  726.     month_info *pm;
  727.  
  728.     pm = (py = find_year(year, FALSE)) ? py->month[month-1] : NULL;
  729.     PRT("/holidays [");    /* start definition of list */
  730.  
  731.     for (holidays = pm ? pm->holidays : 0, day = 1;
  732.          holidays;
  733.          holidays >>= 1, day++)
  734.         if (holidays & 01)
  735.             PRT(" %d", day);
  736.  
  737.     PRT(" ] def\n");
  738.  
  739. }
  740.  
  741.  
  742. /*
  743.  * find_noteboxes - find and print the note box numbers for specified
  744.  * month/year
  745.  */
  746. #ifdef PROTOS
  747. void find_noteboxes(int month,
  748.             int year)
  749. #else
  750. void find_noteboxes(month, year)
  751.     int month, year;
  752. #endif
  753. {
  754.     register int day;
  755.     year_info *py;
  756.     month_info *pm;
  757.  
  758.     /* if no text for this year and month, print empty list and return */
  759.  
  760.     if ((py = find_year(year, FALSE)) == NULL ||
  761.         (pm = py->month[month-1]) == NULL) {
  762.         PRT("/noteboxes [ ] def\n");
  763.         return;
  764.     }
  765.  
  766.     PRT("/noteboxes [");    /* start definition of list */
  767.  
  768.     /* walk array of note text pointers, converting days to box numbers */
  769.  
  770.     for (day = FIRST_NOTE_DAY; day <= LAST_NOTE_DAY; day++)
  771.         if (pm->day[day-1])
  772.             PRT(" %d", note_box(month, day, year));
  773.     PRT(" ] def\n");
  774.  
  775. }
  776.  
  777.  
  778. /*
  779.  * print_dates - print the dates (in "calendar" format) for the specified
  780.  * month and year
  781.  */
  782. #ifdef PROTOS
  783. void print_dates(int month,
  784.          int year)
  785. #else
  786. void print_dates(month, year)
  787.     int month, year;
  788. #endif
  789. {
  790.     register int day;
  791.     year_info *py;
  792.     month_info *pm;
  793.     register day_info *pd;
  794.     unsigned long holidays;
  795.     int has_holiday_text;
  796.     static int first = TRUE;
  797.     static int save_year = 0;
  798.  
  799.     /* if no text for this year and month, return */
  800.  
  801.     if ((py = find_year(year, FALSE)) == NULL ||
  802.         (pm = py->month[month-1]) == NULL)
  803.         return;
  804.  
  805.     /* print the year if it has changed */
  806.  
  807.     if (year != save_year)
  808.         PRT("%s %d\n", kw_year, save_year = year);
  809.  
  810.     /* walk array of day text pointers and linked lists of text */
  811.  
  812.     for (holidays = pm->holidays, day = 1;
  813.          day < FIRST_NOTE_DAY;
  814.          holidays >>= 1, day++) {
  815.         has_holiday_text = FALSE;
  816.         for (pd = pm->day[day-1]; pd; pd = pd->next) {
  817.             if (date_style == USA_DATES)
  818.                 PRT("%02d/%02d", month, day);
  819.             else
  820.                 PRT("%02d/%02d", day, month);
  821.             PRT(pd->is_holiday ? "* " : " ");
  822.             this_day = day;
  823.             RESET_DATE;    /* reset working date */
  824.             print_text(pd->text);
  825.             PRT("\n");
  826.             has_holiday_text |= pd->is_holiday;
  827.         }
  828.         /* was date flagged as holiday w/o associated text? */
  829.         if ((holidays & 01) && !has_holiday_text) {
  830.             if (date_style == USA_DATES)
  831.                 PRT("%02d/%02d*\n", month, day);
  832.             else
  833.                 PRT("%02d/%02d*\n", day, month);
  834.         }
  835.     }
  836. }
  837.  
  838.  
  839.  
  840. /*
  841.  * print_moon_info - print the information necessary to draw moons.  If
  842.  * printing moons on all days, print the phase for each day; if printing
  843.  * only quarter moons, tweak the phase to an exact quarter (so the icon
  844.  * is printed correctly) and generate a list of the quarter-moon dates
  845.  */
  846. #ifdef PROTOS
  847. void print_moon_info(int month,
  848.              int year)
  849. #else
  850. void print_moon_info(month, year)
  851.     int month, year;
  852. #endif
  853. {
  854.     int n, ndays, day, quarter;
  855.     char *p;
  856.     unsigned long qdays;
  857.     double phase;
  858.     static char *q[4] = {"NM", "1Q", "FM", "3Q"};
  859.  
  860.     if (draw_moons == NO_MOONS)
  861.         return;
  862.  
  863.     /* print the phase of the moon for each day of the month */
  864.  
  865.     PRT("/moon_phases [\t\t%% from %s\n\t",
  866.         (p = find_moonfile(year)) ? p : "algorithm");
  867.  
  868.     for (n = 0, qdays = 0L, day = 1, ndays = LENGTH_OF(month, year);
  869.          day <= ndays;
  870.          day++) {
  871.         phase = find_phase(month, day, year, &quarter);
  872.         if (DEBUG(DEBUG_MOON))
  873.             FPR(stderr, "%02d/%02d/%d: %.3f %s\n", month, day,
  874.                 year, phase, quarter != MOON_OTHER ?
  875.                 q[quarter] : "");
  876.         /* adjust phase to exact quarter if printing only quarters */
  877.         if (draw_moons == SOME_MOONS && quarter != MOON_OTHER)
  878.             phase = 0.25 * quarter;
  879.         if (draw_moons == ALL_MOONS || quarter != MOON_OTHER)
  880.             PRT("%.3f%s", PRT_TWEAK(phase), ++n % 10 == 0 ?
  881.                 "\n\t" : " ");
  882.         if (quarter != MOON_OTHER)
  883.             qdays |= 1L << (day - 1);
  884.         }
  885.     PRT("] def\n");
  886.  
  887.     /* if drawing only quarter moons, print days when they occur */
  888.  
  889.     if (draw_moons == SOME_MOONS) {
  890.         PRT("/quarter_moons [ ");
  891.         for (day = 1; qdays; day++, qdays >>= 1)
  892.             if (qdays & 01)
  893.                 PRT("%d ", day);
  894.         PRT("] def\n");
  895.     }
  896. }
  897.  
  898.  
  899. /*
  900.  * print_julian_info - print the information necessary to print Julian dates
  901.  */
  902. #ifdef PROTOS
  903. void print_julian_info(int month,
  904.                int year)
  905. #else
  906. void print_julian_info(month, year)
  907.     int month, year;
  908. #endif
  909. {
  910.  
  911.     if (julian_dates != NO_JULIANS)
  912.         PRT("/jdstart %d def\n", DAY_OF_YEAR(month, 1, year));
  913.     if (julian_dates == ALL_JULIANS)
  914.         PRT("/yearlen %d def\n", YEAR_LEN(year));
  915. }
  916.  
  917.  
  918. /*
  919.  * print_month - generate calendar for specified month/year
  920.  */
  921. #ifdef PROTOS
  922. void print_month(int month,
  923.          int year)
  924. #else
  925. void print_month(month, year)
  926.     int month, year;
  927. #endif
  928. {
  929.     static int nmonths = 0;
  930.     int startbox;
  931.  
  932.     PRT("/year %d def\n", year);        /* set up year and month */
  933.     PRT("/month %d def\n", month);
  934.  
  935.     /* move starting box to second row if conflict with small calendars */
  936.     startbox = START_BOX(month, year);
  937.     if (!do_whole_year &&
  938.         (prev_cal_box[small_cal_pos] == startbox ||
  939.          next_cal_box[small_cal_pos] == startbox) )
  940.         startbox += 7;
  941.     PRT("/startbox %d def\n", startbox);
  942.     PRT("/ndays %d def\n", LENGTH_OF(month, year));
  943.  
  944.     find_noteboxes(month, year);        /* make list of note boxes */
  945.     find_holidays(month, year);        /* make list of holidays */
  946.  
  947.     /* are we printing 12 months per page or only one? */
  948.  
  949.     if (do_whole_year) {
  950.         /* reset foot strings at start of each page */
  951.         if (nmonths % 12 == 0) {
  952.             def_footstring(lfoot, "Lfootstring");
  953.             def_footstring(cfoot, "Cfootstring");
  954.             def_footstring(rfoot, "Rfootstring");
  955.             def_footstring(notes_hdr, "notesheading");
  956.         }
  957.  
  958.         PRT("/posn %d def\n", nmonths % 12);    /* location on page */
  959.         PRT("printmonth_%c\n", rotate == LANDSCAPE ? 'l' : 'p');
  960.         if (++nmonths % 12 == 0)
  961.             PRT("showpage\n");
  962.     }
  963.     else {
  964.         /* reset foot strings each month (may change) */
  965.         def_footstring(lfoot, "Lfootstring");
  966.         def_footstring(cfoot, "Cfootstring");
  967.         def_footstring(rfoot, "Rfootstring");
  968.         def_footstring(notes_hdr, "notesheading");
  969.  
  970.         /* generate information necessary for small calendars */
  971.  
  972.         if (small_cal_pos != SC_NONE) {
  973.             int m, y;
  974.  
  975.             PRT("/p_year %d def\n", y = PREV_YEAR(month, year));
  976.             PRT("/p_month %d def\n", m = PREV_MONTH(month, year));
  977.             PRT("/p_startbox %d def\n", START_BOX(m, y));
  978.             PRT("/p_ndays %d def\n", LENGTH_OF(m, y));
  979.  
  980.             PRT("/n_year %d def\n", y = NEXT_YEAR(month, year));
  981.             PRT("/n_month %d def\n", m = NEXT_MONTH(month, year));
  982.             PRT("/n_startbox %d def\n", START_BOX(m, y));
  983.             PRT("/n_ndays %d def\n", LENGTH_OF(m, y));
  984.         }
  985.  
  986.         print_julian_info(month, year);        /* Julian date info */
  987.         print_moon_info(month, year);        /* moon info */
  988.  
  989.         PRT("printmonth\n");
  990.         find_daytext(month, year, TRUE);    /* holiday text */
  991.         find_daytext(month, year, FALSE);    /* day and note text */
  992.         PRT("showpage\n");
  993.     }
  994. }
  995.