"Fossies" - the Fresh Open Source Software Archive

Member "remind-03.03.09/src/rem2ps.c" (15 Oct 2021, 39151 Bytes) of package /linux/misc/remind-03.03.09.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rem2ps.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 03.03.03_vs_03.03.04.

    1 /***************************************************************/
    2 /*                                                             */
    3 /*  REM2PS.C                                                   */
    4 /*                                                             */
    5 /*  Print a PostScript calendar.                               */
    6 /*                                                             */
    7 /*  This file is part of REMIND.                               */
    8 /*  Copyright (C) 1992-2021 by Dianne Skoll                    */
    9 /*                                                             */
   10 /***************************************************************/
   11 
   12 #include "version.h"
   13 #include "config.h"
   14 #include "dynbuf.h"
   15 
   16 #include <stdio.h>
   17 #include <string.h>
   18 #include <ctype.h>
   19 
   20 #include <unistd.h>
   21 #include <stdlib.h>
   22 #include "rem2ps.h"
   23 #include "json.h"
   24 
   25 #define NEW(type) (malloc(sizeof(type)))
   26 
   27 #define SPECIAL_NORMAL     0
   28 #define SPECIAL_POSTSCRIPT 1
   29 #define SPECIAL_PSFILE     2
   30 #define SPECIAL_MOON       3
   31 #define SPECIAL_COLOR      4
   32 #define SPECIAL_WEEK       5
   33 #define SPECIAL_SHADE      6
   34 #define SPECIAL_UNKNOWN    7
   35 
   36 /* Array holding how specials sort */
   37 static int SpecialSortOrder[] = {
   38     0, /* NORMAL */
   39     1, /* POSTSCRIPT */
   40     1, /* PSFILE */
   41     2, /* MOON */
   42     0, /* COLOR */
   43     4, /* WEEK */
   44     5  /* SHADE */
   45 };
   46 
   47 typedef struct calentry {
   48     struct calentry *next;
   49     int special;
   50     char *entry;
   51     int daynum;
   52 } CalEntry;
   53 
   54 typedef struct {
   55     char const *name;
   56     int xsize, ysize;
   57 } PageType;
   58 
   59 char DayName[7][33];
   60 
   61 char const *SmallCalLoc[] = {
   62     "",
   63     "bt",
   64     "tb",
   65     "sbt",
   66 };
   67 
   68 #define NUMSMALL ((int) (sizeof(SmallCalLoc)/sizeof(SmallCalLoc[0])))
   69 char const *SmallLocation;
   70 int SmallCol1, SmallCol2;
   71 
   72 PageType Pages[] =
   73 {
   74     {"Letter", 612, 792},     /* 8.5 x 11 in. */
   75     {"Tabloid", 792, 1224},   /* 11 x 17 in. */
   76     {"Ledger", 1224, 792},    /* 17 x 11 in. */
   77     {"Legal", 612, 1008},     /* 8.5 x 14 in. */
   78     {"Statement", 396, 612},  /* 5.5 x 8.5 in. */
   79     {"Executive", 540, 720},  /* 7.5 x 10 in. */
   80     {"A3", 842, 1190},
   81     {"A4", 595, 842},
   82     {"A5", 420, 595},
   83     {"B4", 729, 1032},
   84     {"B5", 519, 729},
   85     {"Folio", 612, 936},
   86     {"Quarto", 612, 780},
   87     {"10x14", 720, 1008},
   88     {"-custom-", 0, 0}
   89 };
   90 
   91 PageType DefaultPage[1] =
   92 {
   93     DEFAULT_PAGE
   94 };
   95 
   96 #define NUMPAGES (sizeof(Pages)/sizeof(Pages[0]))
   97 
   98 CalEntry *CurEntries = NULL;
   99 CalEntry *PsEntries[32];
  100 PageType *CurPage;
  101 char PortraitMode;
  102 char DaynumRight;
  103 char NoSmallCal;
  104 char UseISO;
  105 
  106 char const *HeadFont="Helvetica";
  107 char const *TitleFont="Helvetica";
  108 char const *DayFont="Helvetica-BoldOblique";
  109 char const *EntryFont="Helvetica";
  110 char const *SmallFont="Helvetica";
  111 char const *LineWidth = "1";
  112 
  113 char const *HeadSize="14";
  114 char const *TitleSize="14";
  115 char const *DaySize="14";
  116 char const *EntrySize="8";
  117 char const *BorderSize = "6";
  118 
  119 char const *UserProlog = NULL;
  120 
  121 int validfile = 0;
  122 
  123 int CurDay;
  124 int MaxDay;
  125 int DayNum;
  126 int WkDayNum;
  127 int FirstWkDay;
  128 int MondayFirst;
  129 int LeftMarg, RightMarg, TopMarg, BotMarg;
  130 int FillPage;
  131 int Verbose = 0;
  132 
  133 void Init (int argc, char *argv[]);
  134 void Usage (char const *s);
  135 void DoPsCal (void);
  136 int DoQueuedPs (void);
  137 void DoSmallCal (char const *m, int days, int first, int col, int which);
  138 void WriteProlog (void);
  139 void WriteCalEntry (void);
  140 void WriteOneEntry (CalEntry *c);
  141 void GetSmallLocations (void);
  142 char const *EatToken(char const *in, char *out, int maxlen);
  143 
  144 static void
  145 put_escaped_string(char const *s)
  146 {
  147     while(*s) {
  148         if (*s == '\\' || *s == '(' || *s == ')') {
  149             PutChar('\\');
  150         }
  151         PutChar(*s);
  152         s++;
  153     }
  154 }
  155 
  156 /***************************************************************/
  157 /*                                                             */
  158 /*  StrCmpi                                                    */
  159 /*                                                             */
  160 /*  Compare strings, case insensitive.                         */
  161 /*                                                             */
  162 /***************************************************************/
  163 int StrCmpi(char const *s1, char const *s2)
  164 {
  165     int r;
  166     while (*s1 && *s2) {
  167     r = toupper(*s1) - toupper(*s2);
  168     if (r) return r;
  169     s1++;
  170     s2++;
  171     }
  172     return toupper(*s1) - toupper(*s2);
  173 }
  174 /***************************************************************/
  175 /*                                                             */
  176 /*   Parse the new-style JSON intermediate format              */
  177 /*                                                             */
  178 /***************************************************************/
  179 static CalEntry *
  180 JSONToCalEntry(DynamicBuffer *buf)
  181 {
  182     CalEntry *c;
  183     json_value *val;
  184 
  185     val = json_parse(DBufValue(buf), DBufLen(buf));
  186     if (!val) {
  187     fprintf(stderr, "Unable to parse JSON line `%s'\n", DBufValue(buf));
  188     exit(1);
  189     }
  190 
  191     if (val->type != json_object) {
  192     fprintf(stderr, "Expecting JSON object; found `%s'\n",
  193         DBufValue(buf));
  194     exit(1);
  195     }
  196 
  197     c = NEW(CalEntry);
  198     if (!c) {
  199     fprintf(stderr, "malloc failed - aborting.\n");
  200     exit(1);
  201     }
  202     c->next = NULL;
  203     c->special = SPECIAL_NORMAL;
  204 
  205     int got_date = 0, got_body = 0;
  206     size_t i;
  207     for (i=0; i<val->u.object.length; i++) {
  208     char const *nm = val->u.object.values[i].name;
  209     json_value *v = val->u.object.values[i].value;
  210     char const *s;
  211     if (!strcmp(nm, "date")) {
  212         if (v->type == json_string) {
  213         s = v->u.string.ptr;
  214         c->daynum = (s[8] - '0') * 10 + s[9] - '0';
  215         got_date = 1;
  216         }
  217     } else if (!strcmp(nm, "body")) {
  218         if (v->type == json_string) {
  219         s = v->u.string.ptr;
  220         c->entry = malloc(strlen(s)+1);
  221         if (!c->entry) {
  222             fprintf(stderr, "malloc failed - aborting.\n");
  223             exit(1);
  224         }
  225         strcpy(c->entry, s);
  226         got_body = 1;
  227         }
  228     } else if (!strcmp(nm, "passthru")) {
  229         if (v->type == json_string) {
  230         s = v->u.string.ptr;
  231         if (!StrCmpi(s, "PostScript")) {
  232             c->special = SPECIAL_POSTSCRIPT;
  233         } else if (!StrCmpi(s, "SHADE")) {
  234             c->special = SPECIAL_SHADE;
  235         } else if (!StrCmpi(s, "MOON")) {
  236             c->special = SPECIAL_MOON;
  237         } else if (!StrCmpi(s, "WEEK")) {
  238             c->special = SPECIAL_WEEK;
  239         } else if (!StrCmpi(s, "PSFile")) {
  240             c->special = SPECIAL_PSFILE;
  241         } else if (!StrCmpi(s, "COLOUR") ||
  242                !StrCmpi(s, "COLOR")) {
  243             c->special = SPECIAL_COLOR;
  244         } else {
  245             c->special = SPECIAL_UNKNOWN;
  246         }
  247         }
  248     }
  249     }
  250 
  251     json_value_free(val);
  252 
  253     if (!got_body || !got_date) {
  254     fprintf(stderr, "Could not parse line `%s'\n", DBufValue(buf));
  255     exit(1);
  256     }
  257     return c;
  258 }
  259 
  260 /***************************************************************/
  261 /*                                                             */
  262 /*   Parse the old-style REM2PS intermediate format            */
  263 /*                                                             */
  264 /***************************************************************/
  265 static CalEntry *
  266 TextToCalEntry(DynamicBuffer *buf)
  267 {
  268     char const *startOfBody;
  269     char passthru[PASSTHRU_LEN+1];
  270 
  271     CalEntry *c = NEW(CalEntry);
  272     if (!c) {
  273     fprintf(stderr, "malloc failed - aborting.\n");
  274     exit(1);
  275     }
  276     c->next = NULL;
  277     c->special = SPECIAL_NORMAL;
  278     c->daynum = (DBufValue(buf)[8] - '0') * 10 + DBufValue(buf)[9] - '0';
  279 
  280     /* Skip the tag, duration and time */
  281     startOfBody = DBufValue(buf)+10;
  282 
  283     /* Eat the passthru */
  284     startOfBody = EatToken(startOfBody, passthru, PASSTHRU_LEN);
  285 
  286     /* Eat the tag */
  287     startOfBody = EatToken(startOfBody, NULL, 0);
  288 
  289     /* Eat the duration */
  290     startOfBody = EatToken(startOfBody, NULL, 0);
  291 
  292     /* Eat the time */
  293     startOfBody = EatToken(startOfBody, NULL, 0);
  294 
  295     c->entry = malloc(strlen(startOfBody) + 1);
  296     if (!c->entry) {
  297     fprintf(stderr, "malloc failed - aborting.\n");
  298     exit(1);
  299     }
  300     strcpy(c->entry, startOfBody);
  301 
  302     /* Save the type of SPECIAL */
  303     if (!StrCmpi(passthru, "PostScript")) {
  304     c->special = SPECIAL_POSTSCRIPT;
  305     } else if (!StrCmpi(passthru, "SHADE")) {
  306     c->special = SPECIAL_SHADE;
  307     } else if (!StrCmpi(passthru, "MOON")) {
  308     c->special = SPECIAL_MOON;
  309     } else if (!StrCmpi(passthru, "WEEK")) {
  310     c->special = SPECIAL_WEEK;
  311     } else if (!StrCmpi(passthru, "PSFile")) {
  312     c->special = SPECIAL_PSFILE;
  313     } else if (!StrCmpi(passthru, "COLOUR") ||
  314            !StrCmpi(passthru, "COLOR")) {
  315     c->special = SPECIAL_COLOR;
  316     } else if (StrCmpi(passthru, "*")) {
  317     c->special = SPECIAL_UNKNOWN;
  318     }
  319     return c;
  320 }
  321 
  322 /***************************************************************/
  323 /*                                                             */
  324 /*   MAIN PROGRAM                                              */
  325 /*                                                             */
  326 /***************************************************************/
  327 int main(int argc, char *argv[])
  328 {
  329     /* If stdin is a tty - probably wrong. */
  330 
  331     DynamicBuffer buf;
  332     DBufInit(&buf);
  333     Init(argc, argv);
  334 
  335     if (isatty(0)) {
  336     Usage("Input should not come from a terminal");
  337     }
  338 
  339     int first_line = 1;
  340     /* Search for a valid input file */
  341     while (!feof(stdin)) {
  342     DBufGets(&buf, stdin);
  343     if (first_line && (!strcmp(DBufValue(&buf), "["))) {
  344         fprintf(stderr, "Rem2PS: It appears that you have invoked Remind with the -ppp option.\n        Please use either -p or -pp, but not -ppp.\n");
  345         exit(1);
  346     }
  347     first_line = 0;
  348     if (!strcmp(DBufValue(&buf), PSBEGIN) ||
  349         !strcmp(DBufValue(&buf), PSBEGIN2)) {
  350         if (!validfile) {
  351         if (Verbose) {
  352             fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2021 by Dianne Skoll\n\n", VERSION);
  353             fprintf(stderr, "Generating PostScript calendar\n");
  354         }
  355         }
  356         validfile++;
  357         DoPsCal();
  358     }
  359     }
  360     if (!validfile) {
  361     fprintf(stderr, "Rem2PS: Couldn't find any calendar data - are you\n");
  362     fprintf(stderr, "        sure you fed me input produced by remind -p ...?\n");
  363     exit(1);
  364     }
  365     printf("%%%%Trailer\n");
  366     printf("%%%%Pages: %d\n", validfile);
  367     if (Verbose) fprintf(stderr, "Rem2PS: Done\n");
  368     return 0;
  369 }
  370 
  371 /***************************************************************/
  372 /*                                                             */
  373 /*  DoPsCal - emit PostScript for the calendar.                */
  374 /*                                                             */
  375 /***************************************************************/
  376 void DoPsCal(void)
  377 {
  378     char month[40], year[40];
  379     char prevm[40], nextm[40];
  380     int days, wkday, prevdays, nextdays;
  381     int sfirst;
  382     int i;
  383     int firstcol;
  384     DynamicBuffer buf;
  385     CalEntry *c, *d, *p;
  386 
  387 /* Read the month and year name, followed by # days in month and 1st day of
  388    month */
  389     DBufInit(&buf);
  390     DBufGets(&buf, stdin);
  391     sscanf(DBufValue(&buf), "%s %s %d %d %d", month, year, &days, &wkday,
  392        &MondayFirst);
  393 
  394     /* Get day names */
  395     DBufGets(&buf, stdin);
  396     sscanf(DBufValue(&buf), "%32s %32s %32s %32s %32s %32s %32s",
  397        DayName[0], DayName[1], DayName[2], DayName[3],
  398        DayName[4], DayName[5], DayName[6]);
  399 
  400     /* We write the prolog here because it's only at this point that
  401        MondayFirst is set correctly. */
  402     if (validfile == 1) {
  403     WriteProlog();
  404     }
  405 
  406     DBufGets(&buf, stdin);
  407     sscanf(DBufValue(&buf), "%s %d", prevm, &prevdays);
  408     DBufGets(&buf, stdin);
  409     sscanf(DBufValue(&buf), "%s %d", nextm, &nextdays);
  410     DBufFree(&buf);
  411     MaxDay = days;
  412     FirstWkDay = wkday;
  413 
  414 /* Print a message for the user */
  415     if (Verbose) fprintf(stderr, "        %s %s\n", month, year);
  416 
  417     printf("%%%%Page: %c%c%c%c%c %d\n", month[0], month[1], month[2],
  418        year[2], year[3], validfile);
  419     printf("%%%%PageBoundingBox: 0 0 %d %d\n", CurPage->xsize, CurPage->ysize);
  420 
  421 /* Emit PostScript to do the heading */
  422     if (!PortraitMode) printf("90 rotate 0 XSIZE neg translate\n");
  423     printf("/SAVESTATE save def (%s) (%s) PreCal SAVESTATE restore\n", month, year);
  424     printf("(%s %s) doheading\n", month, year);
  425 
  426 /* Figure out the column of the first day in the calendar */
  427 
  428     if (MondayFirst) {
  429     firstcol = wkday-1;
  430     if (firstcol < 0) firstcol = 6;
  431     } else {
  432     firstcol = wkday;
  433     }
  434 
  435 /* Calculate the minimum box size */
  436     if (!FillPage) {
  437     printf("/MinBoxSize ytop MinY sub 7 div def\n");
  438     } else {
  439     if ((days == 31 && firstcol >= 5) || (days == 30 && firstcol == 6))
  440         printf("/MinBoxSize ytop MinY sub 6 div def\n");
  441     else if (days == 28 && firstcol == 0 && NoSmallCal)
  442         printf("/MinBoxSize ytop MinY sub 4 div def\n");
  443     else
  444         printf("/MinBoxSize ytop MinY sub 5 div def\n");
  445     }
  446 
  447     printf("/ysmalltop ytop def\n");
  448 
  449 /* Do each entry */
  450 
  451     CurEntries = NULL;
  452     CurDay = 1;
  453     WkDayNum = wkday;
  454 
  455     while(1) {
  456     if (feof(stdin)) {
  457         fprintf(stderr, "Input from REMIND is corrupt!\n");
  458         exit(1);
  459     }
  460 
  461     DBufGets(&buf, stdin);
  462     if (!strcmp(DBufValue(&buf), PSEND) ||
  463         !strcmp(DBufValue(&buf), PSEND2)) {
  464         DBufFree(&buf);
  465         break;
  466     }
  467 
  468     /* Ignore lines beginning with '#' */
  469     if (DBufValue(&buf)[0] == '#') {
  470         DBufFree(&buf);
  471         continue;
  472     }
  473 
  474     if (DBufValue(&buf)[0] == '{') {
  475         /* Starts with '{', so assume new-style JSON format */
  476         c = JSONToCalEntry(&buf);
  477     } else {
  478         /* Assume it's the old-style rem2ps intermediate format */
  479         c = TextToCalEntry(&buf);
  480     }
  481 
  482     /* If it's an unknown special, ignore */
  483     if (c->special == SPECIAL_UNKNOWN) {
  484         DBufFree(&buf);
  485         free(c);
  486         c = NULL;
  487         continue;
  488     }
  489     if (c->daynum != CurDay) {
  490         for(; CurDay<c->daynum; CurDay++) {
  491         WriteCalEntry();
  492         WkDayNum = (WkDayNum + 1) % 7;
  493         }
  494     }
  495     if (c->special == SPECIAL_POSTSCRIPT ||
  496         c->special == SPECIAL_SHADE ||
  497         c->special == SPECIAL_MOON ||
  498         c->special == SPECIAL_WEEK ||
  499         c->special == SPECIAL_PSFILE) {
  500         if (!PsEntries[c->daynum]) {
  501         PsEntries[c->daynum] = c;
  502         } else {
  503         d = PsEntries[c->daynum];
  504         p = NULL;
  505         /* Slot it into the right place */
  506         while (d->next && (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special])) {
  507             p = d;
  508             d = d->next;
  509         }
  510         if (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special]) {
  511             c->next = d->next;
  512             d->next = c;
  513         } else {
  514             if (p) {
  515             p->next = c;
  516             } else {
  517             PsEntries[c->daynum] = c;
  518             }
  519             c->next = d;
  520         }
  521         }
  522     } else {
  523         /* Put on linked list */
  524         if (!CurEntries) {
  525         CurEntries = c;
  526         } else {
  527         d = CurEntries;
  528         while(d->next) d = d->next;
  529         d->next = c;
  530         }
  531     }
  532     }
  533     for(; CurDay<=days; CurDay++) {
  534     WriteCalEntry();
  535     WkDayNum = (WkDayNum + 1) % 7;
  536     }
  537 
  538 /* If wkday < 2, set ysmall.  If necessary (only for feb) increase cal size. */
  539     printf("/ysmallbot ylast def\n");
  540 
  541 /* Now draw the vertical lines */
  542     GetSmallLocations();
  543     for (i=0; i<=7; i++) {
  544     printf("%d xincr mul MinX add ymin %d xincr mul MinX add topy L\n",
  545            i, i);
  546     }
  547 
  548 /* print the small calendars */
  549     if (!NoSmallCal) {
  550     sfirst = wkday - (prevdays % 7);
  551     if (sfirst < 0) sfirst += 7;
  552     DoSmallCal(prevm, prevdays, sfirst, SmallCol1, 1);
  553     sfirst = wkday + (days % 7);
  554     if (sfirst >6) sfirst -= 7;
  555     DoSmallCal(nextm, nextdays, sfirst, SmallCol2, 2);
  556     }
  557 /* Do it! */
  558     printf("showpage\n");
  559 }
  560 
  561 /***************************************************************/
  562 /*                                                             */
  563 /*  WriteProlog - write the PostScript prologue                */
  564 /*                                                             */
  565 /***************************************************************/
  566 void WriteProlog(void)
  567 {
  568     int i;
  569     int x = CurPage->xsize;
  570     int y = CurPage->ysize;
  571     char const *isostuff;
  572     FILE *fp;
  573     int nread;
  574     char buffer[512];
  575 
  576     if (!PortraitMode) {
  577     i = x; x = y; y = i;
  578     }
  579 
  580     if (UseISO)
  581     isostuff = "reencodeISO";
  582     else
  583     isostuff = "copyFont";
  584 
  585 /* Write the document structuring stuff */
  586     printf("%%!PS-Adobe-2.0\n");
  587     printf("%%%%DocumentFonts: %s", HeadFont);
  588     if (strcmp(TitleFont, HeadFont)) printf(" %s", TitleFont);
  589     if (strcmp(TitleFont, DayFont) &&
  590     strcmp(HeadFont, DayFont)) printf(" %s", DayFont);
  591     if (strcmp(EntryFont, HeadFont) &&
  592     strcmp(TitleFont, EntryFont) &&
  593     strcmp(EntryFont, DayFont)) printf(" %s", EntryFont);
  594     if (!NoSmallCal && strcmp(SmallFont, HeadFont) &&
  595     strcmp(SmallFont, DayFont)  &&
  596     strcmp(TitleFont, SmallFont) &&
  597     strcmp(SmallFont, EntryFont)) printf(" %s", SmallFont);
  598     PutChar('\n');
  599     printf("%%%%Creator: Rem2PS\n");
  600     printf("%%%%Pages: (atend)\n");
  601     printf("%%%%Orientation: %s\n", PortraitMode ? "Portrait" : "Landscape");
  602     printf("%%%%EndComments\n");
  603     if (PortraitMode) {
  604         printf("<< /PageSize [%d %d] >> setpagedevice\n", x, y);
  605     } else {
  606         /* They were swapped up above, so swap them back or we'll get rotated output */
  607         printf("<< /PageSize [%d %d] >> setpagedevice\n", y, x);
  608     }
  609 
  610     for (i=0; PSProlog1[i]; i++) puts(PSProlog1[i]);
  611     if (!MondayFirst)
  612     printf("[(%s) (%s) (%s) (%s) (%s) (%s) (%s)]\n",
  613            DayName[0], DayName[1], DayName[2], DayName[3],
  614            DayName[4], DayName[5], DayName[6]);
  615     else
  616     printf("[(%s) (%s) (%s) (%s) (%s) (%s) (%s)]\n",
  617            DayName[1], DayName[2], DayName[3],
  618            DayName[4], DayName[5], DayName[6], DayName[0]);
  619     for (i=0; PSProlog2[i]; i++) puts(PSProlog2[i]);
  620 
  621     printf("/HeadFont /%s %s\n", HeadFont, isostuff);
  622     if (!NoSmallCal) printf("/SmallFont /%s %s\n", SmallFont, isostuff);
  623     printf("/DayFont /%s %s\n", DayFont, isostuff);
  624     printf("/EntryFont /%s %s\n", EntryFont, isostuff);
  625     printf("/TitleFont /%s %s\n", TitleFont, isostuff);
  626     printf("/HeadSize %s def\n", HeadSize);
  627     printf("/DaySize %s def\n", DaySize);
  628     printf("/EntrySize %s def\n", EntrySize);
  629     printf("/TitleSize %s def\n", TitleSize);
  630     printf("/XSIZE %d def\n", CurPage->xsize);
  631     printf("/MinX %d def\n", LeftMarg);
  632     printf("/MinY %d def\n", BotMarg);
  633     printf("/MaxX %d def\n", x-RightMarg);
  634     printf("/MaxY %d def\n", y-TopMarg);
  635     printf("/Border %s def\n", BorderSize);
  636     printf("/LineWidth %s def\n", LineWidth);
  637     printf("%s setlinewidth\n", LineWidth);
  638 
  639 /* Check if smallfont is fixed pitch */
  640     if (!NoSmallCal) {
  641     printf("/SmallFont findfont /FontInfo get /isFixedPitch get\n");
  642 
  643 /* Define SmallString used to set smallfont size */
  644     printf("{/SmallString (WW ) def}\n");
  645     printf("{/SmallString (WW) def}\nifelse\n");
  646     }
  647 
  648 /* Do the user-supplied prolog file, if any */
  649     if (UserProlog) {
  650     fp = fopen(UserProlog, "r");
  651     if (!fp) {
  652         fprintf(stderr, "Could not open prologue file `%s'\n", UserProlog);
  653     } else {
  654         while(1) {
  655         nread = fread(buffer, sizeof(char), 512, fp);
  656         if (!nread) break;
  657         fwrite(buffer, sizeof(char), nread, stdout);
  658         }
  659         fclose(fp);
  660     }
  661     }
  662 
  663     printf("%%%%EndProlog\n");
  664 
  665 
  666 }
  667 
  668 /***************************************************************/
  669 /*                                                             */
  670 /*  WriteCalEntry - write all entries for one day              */
  671 /*                                                             */
  672 /***************************************************************/
  673 void WriteCalEntry(void)
  674 {
  675     CalEntry *c = CurEntries;
  676     CalEntry *d;
  677     int begin, end, i, HadQPS;
  678 
  679 /* Move to appropriate location */
  680     printf("/CAL%d {\n", CurDay);
  681     if (!MondayFirst)
  682     printf("Border ytop %d xincr mul MinX add xincr\n", WkDayNum);
  683     else
  684     printf("Border ytop %d xincr mul MinX add xincr\n", (WkDayNum ? WkDayNum-1 : 6));
  685 
  686 /* Set up the text array */
  687     printf("[\n");
  688 
  689     CurEntries = NULL;
  690 
  691     while(c) {
  692     WriteOneEntry(c);
  693     free(c->entry);
  694     d = c->next;
  695     free(c);
  696     c = d;
  697     }
  698     printf("]\n");
  699 
  700 /* Print the day number */
  701     printf("(%d) %d\n", CurDay, (int) DaynumRight);
  702 /* Do it! */
  703     printf("DoCalBox\n");
  704 
  705 /* Update ymin */
  706     printf("/y exch def y ymin lt {/ymin y def} if\n");
  707     printf("} def\n");
  708 
  709 /* If WkDayNum is a Sunday or Monday, depending on MondayFirst,
  710    move to next row.  Also handle the queued PS and PSFILE reminders */
  711     if ((!MondayFirst && WkDayNum == 6) ||
  712     (MondayFirst && WkDayNum == 0) || CurDay == MaxDay) {
  713     HadQPS = 0;
  714     if (MondayFirst) begin =  CurDay - (WkDayNum ? WkDayNum-1 : 6);
  715     else             begin = CurDay - WkDayNum;
  716     if (begin < 1) begin = 1;
  717     end = CurDay;
  718     for (i=begin; i<=end; i++) {
  719         if (PsEntries[i]) {
  720         HadQPS = 1;
  721         break;
  722         }
  723     }
  724     /* Avoid problems with blotching if PS printer has roundoff errors */
  725     if (HadQPS) printf("1 setgray\n");
  726     for (i=begin; i<=end; i++) {
  727         printf("CAL%d\n", i);
  728     }
  729     if (HadQPS) printf("0 setgray\n");
  730     printf("/y ytop MinBoxSize sub def y ymin lt {/ymin y def} if\n");
  731 
  732 /* Draw the line at the bottom of the row */
  733     printf("MinX ymin MaxX ymin L\n");
  734 
  735 /* Update ytop */
  736     printf("/ylast ytop def\n");
  737     printf("/ytop ymin def\n");
  738 
  739     (void) DoQueuedPs();
  740 
  741 /* Re-do the calendar stuff if there was any included PS code */
  742     if (HadQPS) {
  743         printf("/ytop ylast def\n");
  744         for (i=begin; i<=end; i++) {
  745         printf("CAL%d\n", i);
  746         }
  747         printf("/y ytop MinBoxSize sub def y ymin lt {/ymin y def} if\n");
  748         printf("MinX ymin MaxX ymin L\n");
  749         printf("/ylast ytop def\n");
  750         printf("/ytop ymin def\n");
  751     }
  752     }
  753 }
  754 
  755 /***************************************************************/
  756 /*                                                             */
  757 /*  WriteOneEntry - write an entry for one day                 */
  758 /*                                                             */
  759 /***************************************************************/
  760 void WriteOneEntry(CalEntry *c)
  761 {
  762     int ch, i;
  763     char const *s = c->entry;
  764 
  765     printf("  [");
  766 
  767     /* Chew up leading spaces */
  768     while(isspace((unsigned char) *s)) s++;
  769 
  770     /* Skip three decimal numbers for COLOR special */
  771     if (c->special == SPECIAL_COLOR) {
  772     for (i=0; i<3; i++) {
  773         while(*s && !isspace(*s)) s++;
  774         while(*s && isspace(*s)) s++;
  775     }
  776     }
  777 
  778     PutChar('(');
  779     while(*s) {
  780     /* Use the "unsigned char" cast to fix problem on Solaris 2.5 */
  781     /* which treated some latin1 characters as white space.       */
  782     ch = (unsigned char) *s++;
  783     if (ch == '\\' || ch == '(' || ch == ')') PutChar('\\');
  784     if (!isspace(ch)) PutChar(ch);
  785     else {
  786         PutChar(')');
  787         while(isspace((unsigned char)*s)) s++;
  788         if (!*s) {
  789         goto finish;
  790         }
  791         PutChar('(');
  792     }
  793     }
  794     printf(")\n");
  795   finish:
  796     if (c->special == SPECIAL_COLOR) {
  797     int r, g, b;
  798     if (sscanf(c->entry, "%d %d %d", &r, &g, &b) == 3) {
  799         if (r < 0) r = 0;
  800         else if (r > 255) r = 255;
  801         if (g < 0) g = 0;
  802         else if (g > 255) g = 255;
  803         if (b < 0) b = 0;
  804         else if (b > 255) b = 255;
  805         printf("(gsave %f %f %f setrgbcolor)(grestore)",
  806            r / 255.0, g / 255.0, b / 255.0);
  807     } else {
  808         /* Punt... unrecognized color is black */
  809         printf("()()");
  810     }
  811     } else {
  812     printf("()()");
  813     }
  814     printf("]\n");
  815 }
  816 
  817 /***************************************************************/
  818 /*                                                             */
  819 /*  Init - set up parameters                                   */
  820 /*                                                             */
  821 /***************************************************************/
  822 void Init(int argc, char *argv[])
  823 {
  824     char const *s;
  825     char const *t;
  826     int i=1;
  827     size_t j;
  828     int k;
  829     int offset;
  830 
  831     PortraitMode = 1;
  832     NoSmallCal = 0;
  833     LeftMarg = 36;
  834     RightMarg = 36;
  835     TopMarg = 36;
  836     BotMarg = 36;
  837     UseISO = 0;
  838     FillPage = 0;
  839     MondayFirst = 0;
  840     SmallLocation = "bt";
  841     DaynumRight = 1;
  842 
  843     for(j=0; j<32; j++) PsEntries[i] = NULL;
  844 
  845     CurPage = DefaultPage;  /* Letter size by default */
  846 
  847     while (i < argc) {
  848     s = argv[i];
  849     i++;
  850 
  851     if (*s++ != '-') Usage("Options must begin with `-'");
  852 
  853     switch(*s++) {
  854 
  855     case 'p':
  856         if (i == argc) Usage("Prologue filename must be supplied");
  857         UserProlog = argv[i++];
  858         break;
  859 
  860     case 's':
  861         if (i == argc) Usage("Size must be supplied");
  862         t = argv[i++];
  863         while(*s) {
  864         switch(*s++) {
  865         case 'h': HeadSize = t; break;
  866         case 'e': EntrySize = t; break;
  867         case 'd': DaySize = t; break;
  868         case 't': TitleSize = t; break;
  869         default: Usage("Size must specify h, t, e, or d");
  870         }
  871         }
  872         break;
  873 
  874     case 'f':
  875         if (i == argc) Usage("Font must be supplied");
  876         t = argv[i++];
  877         while(*s) {
  878         switch(*s++) {
  879         case 'h': HeadFont = t; break;
  880         case 'e': EntryFont = t; break;
  881         case 'd': DayFont = t; break;
  882         case 's': SmallFont = t; break;
  883         case 't': TitleFont = t; break;
  884         default: Usage("Font must specify s, h, t, e, or d");
  885         }
  886         }
  887         break;
  888 
  889     case 'v':
  890         Verbose = 1;
  891         break;
  892 
  893     case 'm':
  894         if (i == argc) Usage("Media must be supplied");
  895         t = argv[i++];
  896         CurPage = NULL;
  897         for (j=0; j<NUMPAGES-1; j++)
  898         if (!strcmp(t, Pages[j].name)) {
  899             CurPage = &Pages[j];
  900             break;
  901         }
  902 
  903         if (!CurPage) {
  904         double w, h;
  905         if (sscanf(t, "%lfx%lfin", &w, &h) == 2) {
  906             CurPage = &Pages[NUMPAGES-1];
  907             CurPage->xsize = (int) (w * 72.0);
  908             CurPage->ysize = (int) (h * 72.0);
  909         } else if (sscanf(t, "%lfx%lfcm", &w, &h) == 2) {
  910             CurPage = &Pages[NUMPAGES-1];
  911             CurPage->xsize = (int) ((double) w * 28.346457);
  912             CurPage->ysize = (int) ((double) w * 28.346457);
  913         }
  914         }
  915         if (!CurPage) {
  916         fprintf(stderr, "\nUnknown media specified.\n");
  917         fprintf(stderr, "\nAvailable media types:\n");
  918         for (j=0; j<NUMPAGES-1; j++) {
  919             fprintf(stderr, "   %s\n", Pages[j].name);
  920         }
  921         fprintf(stderr, "   WxHin  Specify size in inches (W and H are decimal numbers)\n");
  922         fprintf(stderr, "   WxHcm  Specify size in centimetres (W and H are decimal numbers)\n");
  923         fprintf(stderr, "Default media type is %s\n", DefaultPage[0].name);
  924         exit(1);
  925         }
  926         break;
  927 
  928     case 'o':
  929         if (i == argc) Usage("Offset must be supplied");
  930         offset = atoi(argv[i++]);
  931         if (offset < 0) offset = 0;
  932         if (!*s) Usage("Offset must specify l, r, t or b");
  933         while(*s) {
  934         switch(*s++) {
  935         case 'l': LeftMarg = offset; break;
  936         case 'r': RightMarg = offset ; break;
  937         case 't': TopMarg = offset; break;
  938         case 'b': BotMarg = offset; break;
  939         default: Usage("Offset must specify l, r, t or b");
  940         }
  941         }
  942         break;
  943 
  944     case 'b':
  945         if (i == argc) Usage("Border must be supplied");
  946         BorderSize = argv[i++];
  947         break;
  948 
  949     case 't':
  950         if (i == argc) Usage("Line thickness must be supplied");
  951         LineWidth = argv[i++];
  952         break;
  953 
  954     case 'l': PortraitMode = 0; break;
  955 
  956     case 'i': UseISO = 1; break;
  957 
  958         case 'x': DaynumRight = 0; break;
  959     case 'c': k=(*s);
  960         if (!k) {
  961         SmallLocation = SmallCalLoc[0];
  962         } else {
  963         k -= '0';
  964         if (k>=0 && k<NUMSMALL) {
  965             SmallLocation = SmallCalLoc[k];
  966         } else {
  967             SmallLocation = SmallCalLoc[0];
  968         }
  969         }
  970         break;
  971 
  972     case 'e': FillPage = 1; break;
  973 
  974     default: Usage("Unrecognized option");
  975     }
  976     }
  977 }
  978 
  979 /***************************************************************/
  980 /*                                                             */
  981 /*  Usage - print usage information                            */
  982 /*                                                             */
  983 /***************************************************************/
  984 void Usage(char const *s)
  985 {
  986     if (s) fprintf(stderr, "Rem2PS: %s\n\n", s);
  987 
  988     fprintf(stderr, "Rem2PS: Produce a PostScript calendar from output of Remind.\n\n");
  989     fprintf(stderr, "Usage: rem2ps [options]\n\n");
  990     fprintf(stderr, "Options:\n\n");
  991     fprintf(stderr, "-v            Print progress messages to standard error\n");
  992     fprintf(stderr, "-p file       Include user-supplied PostScript code in prologue\n");
  993     fprintf(stderr, "-l            Do calendar in landscape mode\n");
  994     fprintf(stderr, "-c[n]         Control small calendars: 0=none; 1=bt; 2=tb; 3=sbt\n");
  995     fprintf(stderr, "-i            Use ISO 8859-1 encoding in PostScript output\n");
  996     fprintf(stderr, "-m media      Set page size (eg, Letter, Legal, A4.)  Case sensitive!\n");
  997     fprintf(stderr, "              (Default page size is %s)\n", DefaultPage[0].name);
  998     fprintf(stderr, "-f[shted] font Set font for small cal, hdr, title, cal entries, day numbers\n");
  999     fprintf(stderr, "-s[hted] size Set size for header, title, calendar entries and/or day numbers\n");
 1000     fprintf(stderr, "-b size       Set border size for calendar entries\n");
 1001     fprintf(stderr, "-t size       Set line thickness\n");
 1002     fprintf(stderr, "-e            Make calendar fill entire page\n");
 1003     fprintf(stderr, "-x            Put day numbers on left instead of right\n");
 1004     fprintf(stderr, "-o[lrtb] marg Specify left, right, top and bottom margins\n");
 1005     exit(1);
 1006 }
 1007 
 1008 /***************************************************************/
 1009 /*                                                             */
 1010 /*  DoSmallCal - do the small calendar for previous or next    */
 1011 /*  month.                                                     */
 1012 /*                                                             */
 1013 /***************************************************************/
 1014 void DoSmallCal(char const *m, int days, int first, int col, int which)
 1015 {
 1016     /* Do the small calendar */
 1017     int i, j;
 1018     int row = 2;
 1019 
 1020     if (MondayFirst) {
 1021     first--;
 1022     if (first < 0) first = 6;
 1023     }
 1024     /* Figure out the font size */
 1025 
 1026     printf("/SmallFontSize MinBoxSize Border sub Border sub 8 div 2 sub def\n");
 1027     printf("/SmallFont findfont setfont\n");
 1028     printf("SmallString stringwidth pop /SmallWidth exch def\n");
 1029     printf("SmallWidth 7 mul xincr Border sub Border sub exch div /tmp exch def\n");
 1030     printf("tmp SmallFontSize lt {/SmallFontSize tmp def} if\n");
 1031     printf("/SmallFont findfont SmallFontSize scalefont setfont\n");
 1032 
 1033    /* Recalculate SmallWidth */
 1034     printf("SmallString stringwidth pop /SmallWidth exch def\n");
 1035 
 1036     /* Save graphics state */
 1037     printf("gsave\n");
 1038 
 1039     /* Move origin to upper-left hand corner of appropriate box */
 1040     printf("%d xincr mul MinX add ysmall%d translate\n", col, which);
 1041 
 1042     /* Print the month */
 1043     printf("SmallWidth 7 mul (%s) stringwidth pop sub 2 div Border add Border neg SmallFontSize sub moveto (%s) show\n", m, m);
 1044 
 1045     /* Print the days of the week */
 1046     for (i=0; i<7; i++) {
 1047     if (MondayFirst) j=(i+1)%7;
 1048     else             j=i;
 1049     printf("Border %d SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (%c) show\n", i, DayName[j][0]);
 1050     }
 1051 
 1052     /* Now do the days of the month */
 1053     for (i=1; i<=days; i++) {
 1054     printf("Border %d SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add %d mul sub moveto (%d) show\n", first, row, i);
 1055     first++;
 1056     if (first == 7) { first = 0; row++; }
 1057     }
 1058 
 1059     /* restore graphics state */
 1060     printf("grestore\n");
 1061 }
 1062 
 1063 /***************************************************************/
 1064 /*                                                             */
 1065 /*  DoQueuedPs - do the queued PS and PSFILE reminders.        */
 1066 /*                                                             */
 1067 /***************************************************************/
 1068 int DoQueuedPs(void)
 1069 {
 1070     int i;
 1071     int HadPS = 0;
 1072     int wd;
 1073     int begin, end;
 1074     int nread;
 1075     CalEntry *e, *n;
 1076     FILE *fp;
 1077     int fnoff;
 1078     char buffer[512];
 1079     char fbuffer[512];
 1080     char const *size, *fsize, *extra;
 1081     char const *s;
 1082     int num, r, g, b, phase, fontsize, moonsize;
 1083 
 1084     if (!MondayFirst) begin = CurDay - WkDayNum;
 1085     else             begin = CurDay - (WkDayNum ? WkDayNum-1 : 6);
 1086     wd = 0;
 1087     while (begin < 1) begin++, wd++;
 1088     end = CurDay;
 1089     for (i=begin; i<=end; i++, wd++) {
 1090     e = PsEntries[i];
 1091 
 1092     if (e) {
 1093         HadPS = 1;
 1094         printf("/SAVESTATE save def\n");
 1095 
 1096         /* Translate coordinates to bottom of calendar box */
 1097         printf("%d xincr mul MinX add ytop translate\n", wd);
 1098 
 1099         /* Set up convenient variables */
 1100         printf("/BoxWidth xincr def\n/BoxHeight ylast ytop sub def\n");
 1101         printf("/InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def \n");
 1102     }
 1103 
 1104     while (e) {
 1105 
 1106         /* Now do the PostScript SPECIAL */
 1107         fnoff = 0;
 1108         while (isspace(*(e->entry+fnoff))) fnoff++;
 1109         switch(e->special) {
 1110         case SPECIAL_POSTSCRIPT:        /* Send PostScript through */
 1111         printf("%s\n", e->entry+fnoff);
 1112         break;
 1113         case SPECIAL_PSFILE:        /* PostScript from a file */
 1114         fp = fopen(e->entry+fnoff, "r");
 1115         if (!fp) {
 1116             fprintf(stderr, "Could not open PostScript file `%s'\n", e->entry+1);
 1117         } else {
 1118             while(1) {
 1119             nread = fread(buffer, sizeof(char), 512, fp);
 1120             if (!nread) break;
 1121             fwrite(buffer, sizeof(char), nread, stdout);
 1122             }
 1123             fclose(fp);
 1124         }
 1125         break;
 1126         case SPECIAL_SHADE:     /* Shading */
 1127         num = sscanf(e->entry+fnoff, "%d %d %d", &r, &g, &b);
 1128         if (num == 1) {
 1129             g = r;
 1130             b = r;
 1131         } else if (num != 3) {
 1132             fprintf(stderr, "Rem2PS: Malformed SHADE special\n");
 1133             break;
 1134         }
 1135         if (r < 0 || r > 255 ||
 1136             g < 0 || g > 255 ||
 1137             b < 0 || b > 255) {
 1138             fprintf(stderr, "Rem2PS: Illegal values for SHADE\n");
 1139             break;
 1140         }
 1141         printf("/_A LineWidth 2 div def _A _A moveto\n");
 1142         printf("BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto\n");
 1143         printf("_A BoxHeight _A sub lineto closepath\n");
 1144         printf("%g %g %g setrgbcolor fill 0.0 setgray\n",
 1145                r/255.0, g/255.0, b/255.0);
 1146         break;
 1147 
 1148         case SPECIAL_WEEK:          /* Week number */
 1149         printf("gsave Border Border 2 div moveto /EntryFont findfont EntrySize 1.2 div scalefont setfont (");
 1150         s = e->entry+fnoff;
 1151         while(*s && isspace(*s)) {
 1152             s++;
 1153         }
 1154                 put_escaped_string(s);
 1155         printf(") show grestore\n");
 1156         break;
 1157 
 1158         case SPECIAL_MOON:      /* Moon phase */
 1159         num = sscanf(e->entry+fnoff, "%d %d %d", &phase, &moonsize,
 1160                  &fontsize);
 1161         /* See if we have extra stuff */
 1162         extra = e->entry+fnoff;
 1163 
 1164         /* Skip phase */
 1165         while(*extra && !isspace(*extra)) extra++;
 1166         while(*extra && isspace(*extra)) extra++;
 1167 
 1168         /* Skip moon size */
 1169         while(*extra && !isspace(*extra)) extra++;
 1170         while(*extra && isspace(*extra)) extra++;
 1171 
 1172         /* Skip font size */
 1173         while(*extra && !isspace(*extra)) extra++;
 1174         while(*extra && isspace(*extra)) extra++;
 1175 
 1176         if (num == 1) {
 1177             moonsize = -1;
 1178             fontsize = -1;
 1179         } else if (num == 2) {
 1180             fontsize = -1;
 1181         } else if (num != 3) {
 1182             fprintf(stderr, "Rem2PS: Badly formed MOON special\n");
 1183             break;
 1184         }
 1185         if (phase < 0 || phase > 3) {
 1186             fprintf(stderr, "Rem2PS: Illegal MOON phase %d\n",
 1187                 phase);
 1188             break;
 1189         }
 1190         if (moonsize < 0) {
 1191             size = "DaySize 2 div";
 1192         } else {
 1193             sprintf(buffer, "%d", moonsize);
 1194             size = buffer;
 1195         }
 1196 
 1197                 /* Store the starting X coordinate in "moonstartx" */
 1198                 if (DaynumRight) {
 1199                     printf("Border %s add /moonstartx exch def", size);
 1200                 } else {
 1201                     printf("xincr Border sub %s sub ", size);
 1202                     if (*extra) {
 1203                         if (fontsize < 0) {
 1204                             fsize = "EntrySize";
 1205                         } else {
 1206                             sprintf(fbuffer, "%d", fontsize);
 1207                             fsize = fbuffer;
 1208                         }
 1209                         printf("/EntryFont findfont %s scalefont setfont (",
 1210                                fsize);
 1211                         put_escaped_string(extra);
 1212                         printf(") stringwidth pop sub Border sub ");
 1213                     }
 1214                     printf("/moonstartx exch def\n");
 1215                 }
 1216                 printf(" gsave 0 setgray newpath ");
 1217                 printf("moonstartx BoxHeight Border sub %s sub\n", size);
 1218         printf(" %s 0 360 arc closepath\n", size);
 1219         switch(phase) {
 1220         case 0:
 1221             printf("fill\n");
 1222             break;
 1223         case 2:
 1224             printf("stroke\n");
 1225             break;
 1226 
 1227         case 1:
 1228             printf("stroke\nnewpath ");
 1229                     printf("moonstartx BoxHeight Border sub %s sub\n", size);
 1230             printf("%s 90 270 arc closepath fill\n", size);
 1231             break;
 1232         default:
 1233             printf("stroke\nnewpath ");
 1234                     printf("moonstartx BoxHeight Border sub %s sub\n", size);
 1235             printf("%s 270 90 arc closepath fill\n", size);
 1236             break;
 1237         }
 1238         /* Anything left? */
 1239         if (*extra) {
 1240                     printf("moonstartx %s add Border add BoxHeight border sub %s sub %s sub moveto\n", size, size, size);
 1241             if (fontsize < 0) {
 1242             fsize = "EntrySize";
 1243             } else {
 1244             sprintf(fbuffer, "%d", fontsize);
 1245             fsize = fbuffer;
 1246             }
 1247             printf("/EntryFont findfont %s scalefont setfont (",
 1248                fsize);
 1249                     put_escaped_string(extra);
 1250             printf(") show\n");
 1251 
 1252         }
 1253         printf("grestore\n");
 1254         break;
 1255         }
 1256 
 1257 /* Free the entry */
 1258         free(e->entry);
 1259         n = e->next;
 1260         free(e);
 1261         e = n;
 1262     }
 1263     if (PsEntries[i]) printf("\n SAVESTATE restore\n");
 1264     PsEntries[i] = NULL;
 1265     }
 1266     return HadPS;
 1267 }
 1268 
 1269 /***************************************************************/
 1270 /*                                                             */
 1271 /* GetSmallLocations                                           */
 1272 /*                                                             */
 1273 /* Set up the locations for the small calendars.               */
 1274 /*                                                             */
 1275 /***************************************************************/
 1276 void GetSmallLocations(void)
 1277 {
 1278     char c;
 1279     char const *s = SmallLocation;
 1280     int colfirst, collast;
 1281 
 1282 /* Figure out the first and last columns */
 1283     colfirst = FirstWkDay;
 1284     collast = (FirstWkDay+MaxDay-1) % 7;
 1285     if (MondayFirst) {
 1286     colfirst = colfirst ? colfirst - 1 : 6;
 1287     collast = collast ? collast - 1 : 6;
 1288     }
 1289     NoSmallCal = 0;
 1290 
 1291     while((c = *s++) != 0) {
 1292     switch(c) {
 1293     case 'b':
 1294         /* Adjust Feb. if we want it on the bottom */
 1295         if (MaxDay == 28 && colfirst == 0) {
 1296         printf("/ysmallbot ymin def /ymin ysmallbot MinBoxSize sub def\n");
 1297         printf("MinX ymin MaxX ymin L\n");
 1298         printf("/ysmall1 ysmallbot def /ysmall2 ysmallbot def\n");
 1299         SmallCol1 = 5;
 1300         SmallCol2 = 6;
 1301         return;
 1302         }
 1303         if (collast <= 4) {
 1304         printf("/ysmall1 ysmallbot def /ysmall2 ysmallbot def\n");
 1305         SmallCol1 = 5;
 1306         SmallCol2 = 6;
 1307         return;
 1308         }
 1309         break;
 1310 
 1311     case 't':
 1312         if (colfirst >= 2) {
 1313         printf("/ysmall1 ysmalltop def /ysmall2 ysmalltop def\n");
 1314         SmallCol1 = 0;
 1315         SmallCol2 = 1;
 1316         return;
 1317         }
 1318         break;
 1319 
 1320     case 's':
 1321         if (colfirst >= 1 && collast<=5) {
 1322         printf("/ysmall1 ysmalltop def /ysmall2 ysmallbot def\n");
 1323         SmallCol1 = 0;
 1324         SmallCol2 = 6;
 1325         return;
 1326         }
 1327         break;
 1328     }
 1329     }
 1330     NoSmallCal = 1;
 1331     return;
 1332 }
 1333 
 1334 /***************************************************************/
 1335 /*                                                             */
 1336 /* EatToken                                                    */
 1337 /*                                                             */
 1338 /* Read a space-delimited token into an output buffer.         */
 1339 /*                                                             */
 1340 /***************************************************************/
 1341 char const *EatToken(char const *in, char *out, int maxlen)
 1342 {
 1343     int i = 0;
 1344 
 1345     /* Skip space before token */
 1346     while(*in && isspace(*in)) in++;
 1347 
 1348     /* Eat the token */
 1349     while(*in && !isspace(*in)) {
 1350     if (i < maxlen) {
 1351         if (out) *out++ = *in;
 1352         i++;
 1353     }
 1354     in++;
 1355     }
 1356     if (out) *out = 0;
 1357     return in;
 1358 }