jbr0@cbnews.att.com (joseph.a.brownlee) (03/14/91)
#!/bin/sh # This is part 04 of a multipart archive # ============= pcalinit.c ============== if test -f 'pcalinit.c' -a X"$1" != X"-c"; then echo 'x - skipping pcalinit.c (File already exists)' else echo 'x - extracting pcalinit.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pcalinit.c' && /* X * Create a .h file from a .ps file. Strips out leading and trailing X * whitespace, blank lines, and lines consisting solely of comments, X * except for the very first block of comments/blanklines, which are X * turned into C comments at the top of the file. X * X * 14-sep-90 Jamie Zawinski created. X * X * Revision history: X * X * 4.0 AWR 02/25/91 added optional third argument for X * name of array X * X * AWR 02/19/91 added function prototypes; documented X * X * AWR 01/16/91 Escape " and \ in quoted strings; X * strip trailing comments; skip FF X * X * 2.6 JAB 10/18/90 Add exit(0). X * X * 2.3 JWZ 09/14/90 Author X */ X #include <stdio.h> #include <ctype.h> #include <string.h> X #if defined(__STDC__) || defined(AMIGA) #define PROTOS #endif X #define FALSE 0 #define TRUE 1 X #define ARRAY_NAME "header" /* default name of array in .h file */ X #define IS_WHITESPACE(c) \ X ((c) == ' ' || (c) == '\t' || (c) == '\n' || c == '\f') X #define IS_POSTSCRIPT(s) ((s)[0] != '%' && (s)[0] != '\0') X X /* X * strip_white: strip leading and trailing whitespace from 'string'; return X * pointer to first non-whitespace character X */ #ifdef PROTOS char *strip_white (char *string) #else char *strip_white (string) X char *string; #endif { X int n; X for (; IS_WHITESPACE(*string); string++) X ; X n = strlen(string)-1; X for (; IS_WHITESPACE(string[n]); n--) X string[n] = '\0'; X return string; } X X /* X * strip_comment: strip comment and any preceding whitespace from 'string'; X * return pointer to 'string' X */ #ifdef PROTOS char *strip_comment (char *string) #else char *strip_comment (string) X char *string; #endif { X char *p; X if ((p = strchr(string, '%')) != NULL) { X *p = '\0'; X string = strip_white(string); X } X return string; } X X /* X * escape: copy string 'in' to string 'out', escaping the characters \ and "; X * return pointer to 'out' X */ #ifdef PROTOS char *escape(char *out, char *in) #else char *escape(out, in) X char *out, *in; #endif { X char c, *sv_out = out; X X for (; c = *in; *out++ = *in++) X if (c == '\\' || c == '"') X *out++ = '\\'; X X *out = '\0'; X return sv_out; } X X #ifdef PROTOS int main(int argc, char *argv[]) #else int main (argc, argv) X int argc; char *argv[]; #endif { X FILE *in, *out; X char line[256], line2[512], *L, *array; X int in_initial_comments = TRUE; X X /* retrieve arguments and attempt to open input and output files */ X X if (argc < 3 || argc > 4) { X fprintf(stderr, "usage: %s <infile>.ps <outfile>.h [<arrayname>]\n", X argv[0]); X exit(-1); } X X in = fopen(argv[1], "r"); X if (NULL == in) { X fprintf(stderr, "%s: couldn't open %s\n", argv[0], argv[1]); X exit(-1); } X X out = fopen(argv[2], "w"); X if (NULL == out) { X fprintf(stderr, "%s: couldn't open %s\n", argv[0], argv[2]); X exit(-1); } X X array = argc == 4 ? argv[3] : ARRAY_NAME; X X /* print topline comment on output file */ X X fprintf (out, "/*\n * %s: automatically generated by %s from %s\n", X argv[2], argv[0], argv[1]); X fprintf (out, " *\n *\tDO NOT EDIT THIS FILE!\n *\n"); X X /* main loop - copy lines from input file, to output file, preserving X * only initial block of comments and blank lines X */ X X while ( fgets(line, 255, in) != NULL ) { X L = strip_white(line); /* strip whitespace */ X X if ( IS_POSTSCRIPT(L) ) { /* PostScript source? */ X if ( in_initial_comments ) { /* first PS line? */ X in_initial_comments = FALSE; X fprintf(out, " */\n\nchar *%s[] = {\n", array); X } X L = strip_comment(L); /* copy string to output */ X L = escape(line2, L); X fprintf(out, " \"%s\",\n", L); X } else /* blank or comment line */ X if ( in_initial_comments ) /* copy only initial block */ X fprintf(out, " * %s\n", L); X } X X fprintf(out, " (char *)0,\n};\n"); /* terminate array decl */ X X fclose(out); /* close files and exit */ X fclose(in); X exit (0); } SHAR_EOF chmod 0644 pcalinit.c || echo 'restore of pcalinit.c failed' Wc_c="`wc -c < 'pcalinit.c'`" test 3975 -eq "$Wc_c" || echo 'pcalinit.c: original size 3975, current size' "$Wc_c" fi # ============= pcalinit.ps ============== if test -f 'pcalinit.ps' -a X"$1" != X"-c"; then echo 'x - skipping pcalinit.ps (File already exists)' else echo 'x - extracting pcalinit.ps (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pcalinit.ps' && % pcalinit.ps - provides the PostScript routines for pcal.c % % 4.0 modified by Andrew Rogers: % % support -w ("whole year") option - cf. printmonth_[pl], startpage % moved all the calendar calculations to pcal.c and moonphas.c (q.v.) % % support -B option (leave unused boxes blank) % % support -O option (print "gray" numbers as outlines) % % revised several of the basic routines and added some others; dates, % moons, text, Julian days are now relative to upper-left corner of box % % enlarged title and dates in small calendars % % 3.0 modified by Andrew Rogers: % % added xsval, ysval, xtval, ytval for scaling and translation % as per Ed Hand % % added day-of-year support (-j, -J flags) % % 2.6 * no modifications * % % 2.5 modified by Joe Brownlee: % % made day numbers smaller, providing more room for event text % repositioned event text and moons accordingly % added support for variable first day of week % % 2.4 * no modifications * % % 2.3 modified by Jamie Zawinski <jwz@lucid.com>: % % merged in moon routines (originally by Mark Hanson) % % 2.2 modified by Joe Brownlee: % % add "notetext" to print notes in unused calendar box % % 2.1 modified by Mark Kantrowitz: % % use symbolic names instead of magic numbers throughout % support -L, -C, -R, -n options (all new) % print holiday text in otherwise-wasted space next to date % use larger text for dates in large calendars % % 2.0 modified by Andrew W. Rogers: % % skip printing days of week on small calendars % center month and year at top of calendar % use correct algorithm for leap year calculation % get month and day names from main program % use table to determine color (black/gray) of weekdays and holidays % use hanging indent to print continued text lines X /SM 0 def % definitions for calendar sizes /MED 1 def /LG 2 def X /titlefontsize [ 60 48 48 ] def % font sizes for SM/MED/LG calendars /datefontsize [ 54 40 25 ] def /weekdayfontsize [ 0 24 12 ] def /footfontsize 12 def /notesfontsize 6 def X /titlepos [ 19 40 25 ] def % Y-offset (SM/MED/LG) of month/year title /Y0 35 def % Y-coordinate of calendar grid origin X /daywidth 100 def % dimensions of grid boxes /dayheight 80 def /gridwidth daywidth 7 mul def /gridheight dayheight 6 mul def /negdaywidth daywidth neg def /negdayheight dayheight neg def /neggridwidth gridwidth neg def /neggridheight gridheight neg def X /gridlinewidth 1.0 def % width of grid lines /charlinewidth 0.1 def % width of outline characters /moonlinewidth 0.1 def % width of moon icon line /dategray 0.8 def % density of gray for dates /fillgray 0.9 def % density of gray for fill squares X /hangingindent ( ) def % for indenting continued text lines X X % % Utility functions: % X X /center { % print string centered in given width X /width exch def X /str exch def X width str stringwidth pop sub 2 div 0 rmoveto str show } def X X /strcat { % concatenate two strings X 2 copy X length exch length X dup 3 -1 roll add X string X dup 0 6 -1 roll putinterval X dup 3 -1 roll 4 -1 roll putinterval } def X X /prtday { % print the date in black, gray, or outline X day 3 string cvs % convert to string X color (outline) eq { X true charpath stroke % print as outline X } X { X color (gray) eq { dategray setgray } if % print in gray X show X } ifelse } def X X /nextbox { % go to next column or start of next row X day startday add 7 mod 0 eq % end of week? X { neggridwidth daywidth add negdayheight rmoveto } % next row X { daywidth 0 rmoveto } % next col X ifelse } def X X /datepos { % push coords of upper-left corner of box for day <arg> X startday add 1 sub dup 7 mod daywidth mul % x-coord X exch 7 idiv negdayheight mul Y0 add % y-coord } def X X % % Functions for drawing parts of calendar: % X X /drawtitle { % draw month and year title X titlefont findfont titlefontsize calsize get scalefont setfont X /month_name month_names month 1 sub get def X /yearstring year 10 string cvs def X 0 Y0 titlepos calsize get add moveto X month_name ( ) strcat yearstring strcat gridwidth center } def X X /drawdaynames { % draw day names above respective columns X dayfont findfont weekdayfontsize calsize get scalefont setfont X 0 1 6 { X /i exch def X i daywidth mul Y0 5 add moveto X day_names i get X daywidth center X } for } def X X /drawgrid { % draw the grid for the calendar X gridlinewidth setlinewidth X 0 daywidth gridwidth { % vertical lines X Y0 moveto X 0 neggridheight rlineto X stroke X } for X 0 negdayheight neggridheight { % horizontal lines X 0 exch Y0 add moveto X gridwidth 0 rlineto X stroke X } for } def X X /drawnums { % place day numbers on calendar X dayfont findfont datefontsize calsize get scalefont setfont X /fontdiff datefontsize calsize get datefontsize LG get sub def X charlinewidth setlinewidth X 1 datepos 20 fontdiff add sub exch 5 add exch moveto X X 1 1 ndays { X /day exch def X /color (black) def X calsize SM ne { % select alternate color X /gray day_gray day startday add 1 sub 7 mod get def X holidays { day eq { /gray holiday_gray def } if } forall X gray { X /color outline {(outline)} {(gray)} ifelse def X } if X } if X gsave X prtday X grestore X nextbox X } for } def X X /drawjnums { % place day-of-year numbers on calendar X notesfont findfont notesfontsize scalefont setfont X 1 datepos dayheight 3 sub sub exch daywidth 3 sub add exch moveto X X 1 1 ndays { X /day exch def X /jday jdstart day add 1 sub def X /str jday 3 string cvs def X julian-dates true eq { % print days left in year? X /str str ( \050) strcat yearlen jday sub 3 string cvs X strcat (\051) strcat def X } if X gsave X str dup stringwidth pop 0 exch sub 0 rmoveto show X grestore X nextbox X } for } def X X /fillboxes { % used by drawfill to generate row of fill squares X /last exch def % last box to fill (0 = Sun) X /first exch def % first box to fill (0 = Sun) X /width last first sub 1 add daywidth mul def X X width 0 gt { X gsave X first daywidth mul 0 rmoveto X fillgray setgray X width 0 rlineto X 0 negdayheight rlineto X width neg 0 rlineto X closepath fill X grestore X } if } def X X /drawfill { % generate fill squares where necessary X /firstbox startday ndays add def X /lastbox calsize LG ne {41} { note_block {38} {39} ifelse } ifelse def X X 0 Y0 moveto % boxes (if any) at start of first row X 0 startday 1 sub fillboxes X X 0 4 negdayheight mul rmoveto % boxes (if any) at end of fifth row X firstbox 35 lt { X firstbox 7 mod 6 fillboxes X /firstbox 35 def X } if X X 0 negdayheight rmoveto % boxes at end of bottom row X firstbox 7 mod lastbox 7 mod fillboxes } def X X /footstrings { % print foot strings at bottom of page X titlefont findfont footfontsize scalefont setfont X /bottomrow { neggridheight 20 add } def X 0 bottomrow moveto X Lfootstring show X gridwidth Rfootstring stringwidth pop sub bottomrow moveto X Rfootstring show X 0 bottomrow moveto X Cfootstring gridwidth center } def X X % % Functions for printing text inside boxes: % X X /daytext { X notesfont findfont notesfontsize scalefont setfont X /mytext exch def /day exch def X day datepos 29 sub dup /ypos exch def exch 2 add exch moveto X currentpoint pop /LM exch def /RM LM 95 add def X showtext } def X X /holidaytext { % print text for holiday (next to date) X notesfont findfont notesfontsize scalefont setfont X /mytext exch def /day exch def X /dwidth day 10 lt {20} {33} ifelse def % width of date X /mwidth do-moon-p {16} {0} ifelse def % width of moon icon X day datepos 8 sub dup /ypos exch def exch dwidth add exch moveto X currentpoint pop /LM exch def /RM LM 97 dwidth mwidth add sub add def X showtext } def X X /notetext { % print text in notes box X dayfont findfont 12 scalefont setfont X /day 40 startday sub def % "date" of notes box X day datepos 11 sub exch 4 add exch moveto X notesheading show X X notesfont findfont notesfontsize scalefont setfont X /mytext exch def X day datepos 19 sub dup /ypos exch def exch 4 add exch moveto X /LM currentpoint pop def /RM LM 93 add def X showtext } def X X /crlf { % simulate CR/LF sequence X ypos notesfontsize sub /ypos exch def LM ypos moveto } def X X /prstr { % print string on current or next line X dup stringwidth pop currentpoint pop X add RM gt { crlf hangingindent show } if show } def X X /showtext { % print words in "mytext", splitting into lines X mytext { X dup linesep eq % force new line? X { crlf pop } % yes - discard text X { prstr ( ) show } % no - print string + space X ifelse X } forall } def X X % % Functions for printing months of various sizes and orientations: % X X /startpage { % initialize new physical page X rval rotate X xsval ysval scale X xtval ytval translate } def X X /calendar % draw calendar for month/year { X drawtitle % month/year heading X X calsize SM ne { % day names X drawdaynames X } if X X calsize LG eq { % foot strings X footstrings X } if X X drawnums % calendar dates X X julian-dates false ne calsize LG eq and { % julian dates X drawjnums X } if X X fill-boxes { % fill unused boxes X drawfill X } if X X drawgrid % calendar grid X X draw-moons false ne calsize LG eq and { % moon icons X drawmoons X } if X X 0 0 moveto % return to origin } def X X /printmonth_l { % print month on landscape page ("posn" = 0..11) X /calsize MED def X X posn 0 eq { % assume first month printed on page is posn 0 X startpage X footstrings X } if X X gsave % draw medium calendar at selected position X .226 .25 scale % landscape mode - 3 rows, 4 cols X posn 4 mod 800 mul X posn 4 idiv -700 mul 150 add X translate X calendar X grestore } def X X /printmonth_p { % print month on portrait page ("posn" = 0..11) X /calsize MED def X /footfontsize 15 def % compensate for scaling X X posn 0 eq { % assume first month printed on page is posn 0 X gsave % print foot strings at original scale X startpage X 0 20 translate % move foot strings up slightly X footstrings X grestore % re-scale Y axis for portrait mode X /sv_ysval ysval def X /ysval ysval 1.675 mul def X startpage X /ysval sv_ysval def X } if X X gsave % draw medium calendar at selected position X .304 .194 scale % portrait mode - 4 rows, 3 cols X posn 3 mod 800 mul X posn 3 idiv -700 mul 300 add X translate X calendar X grestore } def X X /printmonth { % print single month on page X startpage X X /calsize LG def % main (large) calendar X calendar X X gsave % small calendars X /calsize SM def X /sv_startday startday def X X % calculate previous and next month, year, and starting day X X /lmonth month 1 eq { 12 } { month 1 sub } ifelse def X /lyear month 1 eq { year 1 sub } { year } ifelse def X /lstartday startday 35 add lndays sub 7 mod def X /nmonth month 12 eq { 1 } { month 1 add } ifelse def X /nyear month 12 eq { year 1 add } { year } ifelse def X /nstartday startday ndays add 7 mod def X X /year lyear def % prev month/year X /month lmonth def X /startday lstartday def X /ndays lndays def X 5 daywidth mul 5 negdayheight mul Y0 add translate X gsave X .138 .138 scale X 12 -120 translate X calendar X grestore X X /year nyear def % next month/year X /month nmonth def X /startday nstartday def X /ndays nndays def X daywidth 0 translate X gsave X .138 .138 scale X 12 -120 translate X calendar X grestore X X /startday sv_startday def % restore starting day (for text boxes) X grestore } def X X % % Moon drawing functions: % X X /domoon { % draw moon at phase (0 = new; .25 = 1q; .5 = full; .75 = 3q) X /phase exch def X X gsave X currentpoint translate X newpath X X % if moon is full, just draw unfilled circle X X phase halfperiod .01 sub ge phase halfperiod .01 add le and { X 0 0 radius X 0 360 arc stroke X } X { X % draw the line arc now; prepare (but don't draw) the fill arc X X 0 0 radius % for line and fill arcs X 0 0 radius X phase halfperiod lt { % phase between new and full X 270 90 arc stroke % (line on right, fill on left) X 0 radius neg moveto X 270 90 arcn X } X { % phase between full and new X 90 270 arc stroke % (line on left, fill on right) X 0 radius neg moveto X 270 90 arc X /phase phase halfperiod sub def X } ifelse X X % curveto uses (x0,y0) (current point), (x1,y1), (x2,y2), X % and (x3,y3) as the control points for drawing a Bezier X % cubic section, used here as the curve dividing the moon X % icon into dark and light sections. x1 is in the range X % -R*sqrt(2) <= x1 <= R*sqrt(2) and y1 is in the range X % 0 <= y1 <= R; note that except in the degenerate case X % where x1 = y1 = x2 = y2 = 0, the curve does not actually X % pass through (x1,y1) or (x2,y2). X X /x1 quartperiod phase sub rect mul def X /y1 x1 abs 2 sqrt div def X X % push control points for curveto X X % x0 = 0 (current X % y0 = R point) X x1 % x1 X y1 % y1 X x1 % x2 = x1 X y1 neg % y2 = -y1 X 0 % x3 = 0 X radius neg % y3 = -R X X % draw Bezier curve; fill area between curve and fill arc X X curveto X fill X } ifelse X X grestore } def X X /do-moon-p { % draw a moon on "day"? X draw-moons (some) eq { % printing quarter moons? look up day X /p false def X quarter_moons { day eq { /p true def } if } forall X p X } X { X draw-moons % all moons or no moons X } ifelse } def X X /drawmoons { % main routine to draw moons on calendar X /halfperiod 0.5 def X /quartperiod 0.25 def X /radius 6 def X /offset radius 3 add def X /rect radius 2 sqrt mul quartperiod div def % domoon{} scale factor X /n 0 def X X gsave X moonlinewidth setlinewidth X 1 datepos offset sub exch daywidth add offset sub exch moveto X 1 1 ndays { X /day exch def X do-moon-p { % draw a moon today? X moon_phases n get domoon X /n n 1 add def X } if X nextbox X } for X grestore } def SHAR_EOF chmod 0666 pcalinit.ps || echo 'restore of pcalinit.ps failed' Wc_c="`wc -c < 'pcalinit.ps'`" test 13415 -eq "$Wc_c" || echo 'pcalinit.ps: original size 13415, current size' "$Wc_c" fi # ============= pcallang.h ============== if test -f 'pcallang.h' -a X"$1" != X"-c"; then echo 'x - skipping pcallang.h (File already exists)' else echo 'x - extracting pcallang.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pcallang.h' && /* X * pcallang.h - language-dependent strings (month and day names, option file X * keywords, preprocessor tokens, prepositions, etc.): X * X * Revision history: X * X * 4.0 AWR 03/01/91 expand parameter message to explain X * parameter meaning when -w specified X * X * AWR 02/19/91 revise ordinal definitions for X * support of negative ordinals X * X * AWR 02/06/91 add text describing expression syntax X * X * AWR 02/04/91 support "odd" and "even" ordinals X * X * AWR 01/28/91 support -B (blank fill squares) flag X * and -O (outline "gray" dates) flag X * X * 01/16/91 added moon file support (tokens, help X * file text, error messages); define X * note block heading here X * X * 01/07/91 added support for -w (whole year) flag X * X * 3.0 AWR 12/10/90 added support for "workday", "weekday", X * "holiday", et. al. X * X * AWR 11/15/90 extracted from pcal.c; revised X * to contain all language-dependent X * strings X */ X #define ALL "all" /* command-line or date file keyword */ X #ifdef MAIN_MODULE X char *months[12] = { X "January", "February", "March", "April", "May", "June", X "July", "August", "September", "October", "November", "December" X }; X /* Must be a 2-D array so address within may be used as an initializer; X * wildcard names must be in same order as symbolic names in pcaldefs.h X */ char days[14][12] = { X "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", X "Saturday", /* weekday names */ X "day", "weekday", "workday", "holiday", "nonweekday", "nonworkday", X "nonholiday" /* wildcards */ X }; X /* preprocessor tokens: token name, token code, dispatch routine */ X KWD_F pp_info[] = { X "define", PP_DEFINE, do_define, X "else", PP_ELSE, NULL, X "endif", PP_ENDIF, NULL, X "ifdef", PP_IFDEF, do_ifdef, X "ifndef", PP_IFNDEF, do_ifndef, X "include", PP_INCLUDE, NULL, /* do_include */ X "undef", PP_UNDEF, do_undef, X NULL, PP_OTHER, NULL }; /* must be last */ X /* ordinal numbers - e.g. "first Monday in September": ordinal name, X * ordinal code, ordinal value; note that "all" is parsed as a keyword X * and (depending on context) may be subsequently treated as an ordinal X */ X KWD_O ordinals[] = { X "first", ORD_POSNUM, 1, X "second", ORD_POSNUM, 2, X "third", ORD_POSNUM, 3, X "fourth", ORD_POSNUM, 4, X "fifth", ORD_POSNUM, 5, X "last", ORD_NEGNUM, -1, X "odd", ORD_ODD, 0, X "even", ORD_EVEN, 0, X NULL, ORD_OTHER, 0 }; /* must be last */ X /* allowable suffixes for ordinal numbers */ X char *ord_suffix[] = { "st", "nd", "rd", "th", NULL }; X /* prepositions - e.g., "Friday after fourth Thursday in November" */ X KWD preps[] = { X "before", PR_BEFORE, X "preceding", PR_BEFORE, X "on_or_before", PR_ON_BEFORE, X "oob", PR_ON_BEFORE, X "after", PR_AFTER, X "following", PR_AFTER, X "on_or_after", PR_ON_AFTER, X "ooa", PR_ON_AFTER, X NULL, PR_OTHER }; /* must be last */ X /* other keywords */ X KWD keywds[] = { X ALL, DT_ALL, X "each", DT_ALL, X "every", DT_ALL, X "note", DT_NOTE, X "opt", DT_OPT, X "year", DT_YEAR, X NULL, DT_OTHER }; /* must be last */ X /* moon phases (for moon file) */ X KWD phases[] = { X "NM", MOON_NM, /* new moon */ X "1Q", MOON_1Q, /* first quarter */ X "FQ", MOON_1Q, X "FM", MOON_FM, /* full moon */ X "3Q", MOON_3Q, /* third (last) quarter */ X "LQ", MOON_3Q, X NULL, MOON_OTHER }; /* must be last */ X #else extern char *months[]; extern char days[14][12]; extern KWD_F pp_info[]; extern KWD preps[]; extern KWD_O ordinals[]; extern char *ord_suffix[]; extern KWD keywds[]; extern KWD phases[]; #endif X /* minimum size of abbreviations */ X #define MIN_DAY_LEN 3 #define MIN_MONTH_LEN 3 #define MIN_PPTOK_LEN 3 #define MIN_PREP_LEN 7 /* distinguish "on_or_before", "on_or_after" */ #define MIN_ORD_LEN 3 /* distinguish "Thursday" from "third" */ X X /* X * Symbolic names for command-line flags. These may be changed X * as desired in order to be meaningful in languages other than X * English. X */ X #define F_INITIALIZE 'I' /* re-initialize program defaults */ #define F_BLACK_DAY 'b' /* print day in black */ #define F_GRAY_DAY 'g' /* print day in gray */ X #define F_DAY_FONT 'd' /* select alternate day font */ #define F_NOTES_FONT 'n' /* select alternate notes font */ #define F_TITLE_FONT 't' /* select alternate title font */ X #define F_EMPTY_CAL 'e' /* print empty calendar */ #define F_DATE_FILE 'f' /* select alternate date file */ #define F_OUT_FILE 'o' /* select alternate output file */ X #define F_LANDSCAPE 'l' /* landscape mode */ #define F_PORTRAIT 'p' /* portrait mode */ X #define F_HELP 'h' /* generate help message */ X #define F_MOON_4 'm' /* print new/half/full moons */ #define F_MOON_ALL 'M' /* print all moons */ X #define F_DEFINE 'D' /* define preprocessor symbol */ #define F_UNDEF 'U' /* undefine preprocessor symbol */ X #define F_L_FOOT 'L' /* define left foot string */ #define F_C_FOOT 'C' /* define center foot string */ #define F_R_FOOT 'R' /* define right foot string */ X #define F_FIRST_DAY 'F' /* define alternate starting day */ X #define F_USA_DATES 'A' /* parse American date format */ #define F_EUR_DATES 'E' /* parse European date format */ X #define F_X_TRANS 'X' /* X-axis transformation */ #define F_Y_TRANS 'Y' /* Y-axis transformation */ #define F_X_SCALE 'x' /* X-axis scale factor */ #define F_Y_SCALE 'y' /* Y-axis scale factor */ X #define F_JULIAN 'j' /* print Julian day (day of year) */ #define F_JULIAN_ALL 'J' /* print Julian day and days left */ X #define F_WHOLE_YEAR 'w' /* print whole year per page */ X /* (cf. W_WYFLAG below) */ X #define F_BLANK_BOXES 'B' /* don't fill unused boxes */ X #define F_OUTLINE 'O' /* draw "gray" dates as outlines */ X /* X * Flag usage information - not strictly language-dependent, but here anyway X * (N.B.: all flags must be represented by an entry in this table!) X * X * Flags may appear in any of three places: in environment variable X * PCAL_OPTS, on the command line, or in "opt" lines in the date file. X * The command line is actually parsed twice: once before reading the date X * file to get the flags needed in processing it (-e, -f, -b, -g, -D, -U, -A, X * -E), and again after reading the date file to give the user one last X * chance to override any of the other flags set earlier. (Note, however, X * that the only way to turn off -J|-j [Julian dates], -M|-m [moons], -w X * [whole year], or -O [outline "gray" dates] once selected is to use -I X * to reinitialize all program defaults.) X * X * The table below supplies the following information about each flag: X * X * - Its name (cf. symbolic definitions above) X * X * - Whether or not it can take an (optional) argument X * X * - Which passes parse it: P_ENV (environment variable), P_CMD1 X * (first command line pass), P_OPT ("opt" lines in date file), X * and P_CMD2 (second command line pass) X * X */ X #ifdef MAIN_MODULE X FLAG_USAGE flag_tbl[] = { X /* flag name arg? passes where parsed */ X X F_INITIALIZE, FALSE, P_ENV | P_CMD1 | P_OPT | P_CMD2 , X X F_BLACK_DAY, TRUE, P_ENV | P_CMD1 | P_OPT , X F_GRAY_DAY, TRUE, P_ENV | P_CMD1 | P_OPT , X X F_DAY_FONT, TRUE, P_ENV | P_OPT | P_CMD2 , X F_NOTES_FONT, TRUE, P_ENV | P_OPT | P_CMD2 , X F_TITLE_FONT, TRUE, P_ENV | P_OPT | P_CMD2 , X X F_EMPTY_CAL, FALSE, P_ENV | P_CMD1 , X F_DATE_FILE, TRUE, P_ENV | P_CMD1 , X F_OUT_FILE, TRUE, P_ENV | P_OPT | P_CMD2 , X X F_LANDSCAPE, FALSE, P_ENV | P_OPT | P_CMD2 , X F_PORTRAIT, FALSE, P_ENV | P_OPT | P_CMD2 , X X F_HELP, FALSE, P_CMD1 , X X F_MOON_4, FALSE, P_ENV | P_OPT | P_CMD2 , X F_MOON_ALL, FALSE, P_ENV | P_OPT | P_CMD2 , X X F_DEFINE, TRUE, P_ENV | P_CMD1 , X F_UNDEF, TRUE, P_ENV | P_CMD1 , X X F_L_FOOT, TRUE, P_ENV | P_OPT | P_CMD2 , X F_C_FOOT, TRUE, P_ENV | P_OPT | P_CMD2 , X F_R_FOOT, TRUE, P_ENV | P_OPT | P_CMD2 , X X F_FIRST_DAY, TRUE, P_ENV | P_OPT | P_CMD2 , X X F_USA_DATES, FALSE, P_ENV | P_CMD1 | P_OPT , X F_EUR_DATES, FALSE, P_ENV | P_CMD1 | P_OPT , X X F_X_TRANS, TRUE, P_ENV | P_OPT | P_CMD2 , X F_Y_TRANS, TRUE, P_ENV | P_OPT | P_CMD2 , X F_X_SCALE, TRUE, P_ENV | P_OPT | P_CMD2 , X F_Y_SCALE, TRUE, P_ENV | P_OPT | P_CMD2 , X X F_JULIAN, FALSE, P_ENV | P_OPT | P_CMD2 , X F_JULIAN_ALL, FALSE, P_ENV | P_OPT | P_CMD2 , X X F_WHOLE_YEAR, FALSE, P_ENV | P_CMD1 | P_OPT , X X F_BLANK_BOXES, FALSE, P_ENV | P_OPT | P_CMD2 , X X F_OUTLINE, FALSE, P_ENV | P_OPT | P_CMD2 , X X '-', FALSE, P_ENV | P_CMD1 | P_OPT | P_CMD2 , X '\0', FALSE, P_ENV | P_CMD1 | P_OPT | P_CMD2 /* must be last */ X }; X #else extern FLAG_USAGE flag_tbl[]; #endif X /* X * Words used in usage() message - translate as necessary X */ X #define W_DEFAULT "default" /* translate as required */ #define W_USAGE "Usage" X #define W_FONT "FONT" /* names of metavariables */ #define W_DAY "DAY" #define W_STRING "STRING" #define W_FILE "FILE" #define W_SYMBOL "SYMBOL" #define W_VALUE "VALUE" X #define W_MM "MM" /* abbrev. for month, year */ #define W_YY "YY" X #define W_WYFLAG "-w" /* must conform to F_WHOLE_YEAR */ X #define W_BLACK "black" /* cf. color_msg() */ #define W_GRAY "gray" X X /* special flag_msg[] entries for end of option group, etc. */ X #define END_GROUP '\n', NULL, NULL, NULL /* end of option group */ #define END_LIST '\0', NULL, NULL, NULL /* end of list */ #define GROUP_DEFAULT ' ', NULL, " " /* group default */ X /* X * Message strings to be printed by usage() - translate as necessary X */ #ifdef MAIN_MODULE X FLAG_MSG flag_msg[] = { X /* flag name metasyntax description default */ X X F_INITIALIZE, NULL, "initialize all parameters to program defaults", NULL, X END_GROUP, X X F_BLACK_DAY, W_DAY, "print weekday in black", NULL, X F_GRAY_DAY, W_DAY, "print weekday in gray (see below)", NULL, X END_GROUP, X X F_OUTLINE, NULL, "print \"gray\" dates as outlined characters", NULL, X X END_GROUP, X X F_DAY_FONT, W_FONT, "specify alternate day name font", DAYFONT, X F_NOTES_FONT, W_FONT, "specify alternate notes font", NOTESFONT, X F_TITLE_FONT, W_FONT, "specify alternate title font", TITLEFONT, X END_GROUP, X X F_EMPTY_CAL, NULL, "generate empty calendar (ignore date file)", NULL, X END_GROUP, X X F_DATE_FILE, W_FILE, "specify alternate date file", DATEFILE, X END_GROUP, X #ifdef DEFAULT_OUTFILE X F_OUT_FILE, W_FILE, "specify alternate output file", DEFAULT_OUTFILE, #else X F_OUT_FILE, W_FILE, "specify alternate output file", "stdout", #endif X END_GROUP, X X F_LANDSCAPE, NULL, "generate landscape-style calendar", NULL, X F_PORTRAIT, NULL, "generate portrait-style calendar", NULL, #if ROTATE == LANDSCAPE X GROUP_DEFAULT, "landscape", #else X GROUP_DEFAULT, "portrait", #endif X END_GROUP, X X F_HELP, NULL, "print this help message", NULL, X END_GROUP, X X F_MOON_4, NULL, "draw a \"moon\" icon at full/new/half moons", NULL, X F_MOON_ALL, NULL, "draw a \"moon\" icon every day", NULL, #if DRAW_MOONS == NO_MOONS X GROUP_DEFAULT, "no moons", #else #if DRAW_MOONS == SOME_MOONS X GROUP_DEFAULT, "full/new/half moons", #else X GROUP_DEFAULT, "every day", #endif #endif X END_GROUP, X X F_DEFINE, W_SYMBOL, "define preprocessor symbol", NULL, X F_UNDEF, W_SYMBOL, "undefine preprocessor symbol", NULL, X END_GROUP, X X F_L_FOOT, W_STRING, "specify left foot string", LFOOT, X F_C_FOOT, W_STRING, "specify center foot string", CFOOT, X F_R_FOOT, W_STRING, "specify right foot string", RFOOT, X END_GROUP, X X F_FIRST_DAY, W_DAY, "specify starting day of week", days[FIRST_DAY], X END_GROUP, X X F_USA_DATES, NULL, "parse American dates (\"mm/dd{/yy}\" and \"month dd\")", NULL, X F_EUR_DATES, NULL, "parse European dates (\"dd/mm{/yy}\" and \"dd month\")", NULL, #if DATE_STYLE == USA_DATES X GROUP_DEFAULT, "American", #else X GROUP_DEFAULT, "European", #endif X END_GROUP, X X F_X_TRANS, W_VALUE, "specify x-axis translation", XTVAL, X F_Y_TRANS, W_VALUE, "specify y-axis translation", YTVAL, X F_X_SCALE, W_VALUE, "specify x-axis scale factor", XSVAL, X F_Y_SCALE, W_VALUE, "specify y-axis scale factor", YSVAL, X END_GROUP, X X F_JULIAN, NULL, "print Julian day (day of year)", NULL, X F_JULIAN_ALL, NULL, "print Julian day and days left in year", NULL, #if JULIAN_DATES == NO_JULIANS X GROUP_DEFAULT, "neither", #else #if JULIAN_DATES == SOME_JULIANS X GROUP_DEFAULT, "Julian day", #else X GROUP_DEFAULT, "both", #endif #endif X END_GROUP, X X F_WHOLE_YEAR, NULL, "print whole year (12 consecutive months) per page", NULL, X END_GROUP, X X F_BLANK_BOXES, NULL, "leave unused boxes blank", NULL, X X END_GROUP, /* must precede END_LIST */ X X END_LIST /* must be last */ }; X #else extern FLAG_MSG flag_msg[]; #endif X /* Numeric parameter descriptions and text */ X #ifdef MAIN_MODULE X #if __STDC__ PARAM_MSG param_msg[] = { X W_YY, "generate calendar for year " W_YY " (19" W_YY " if " W_YY " < 100)", X W_MM " " W_YY, "generate calendar for month " W_MM " (Jan = 1), year " W_YY, X W_MM " " W_YY " N", "generate calendars for N months, starting at " W_MM "/" W_YY, X "(" W_DEFAULT ")", "generate calendar for current month and/or year", X "", "", X "if " W_WYFLAG " specified:", "", X "", "", X W_YY, "generate calendar for year " W_YY " (19" W_YY " if " W_YY " < 100)", X W_MM " " W_YY, "generate calendars for 12 months, starting at " W_MM "/" W_YY, X W_MM " " W_YY " N", "generate calendars for N months, starting at " W_MM "/" W_YY, X "", " (N rounded up to next multiple of 12)", X "(" W_DEFAULT ")", "generate calendar for current year", X NULL, NULL /* must be last */ }; #else PARAM_MSG param_msg[] = { X "YY", "generate calendar for year YY (19YY if YY < 100)", X "MM YY", "generate calendar for month MM (Jan = 1), year YY", X "MM YY N", "generate calendars for N months, starting at MM/YY", X "(default)", "generate calendar for current month and year", X "", "", X "if -w specified:", "", X "", "", X "YY", "generate calendar for year YY (19YY if YY < 100)", X "MM YY", "generate calendar for 12 months, starting at MM/YY", X "MM YY N", "generate calendars for N months, starting at MM/YY", X "", " (N rounded up to next multiple of 12)", X "(default)", "generate calendar for current year", X NULL, NULL /* must be last */ }; #endif X #else extern PARAM_MSG param_msg[]; #endif X #define PARAM_MSGS 3 /* number of above to print in command-line syntax message */ X /* Date file syntax message - lines are copied intact */ X #ifdef MAIN_MODULE X char *date_msg[] = { X "", X "Date file syntax:", X "", X "The following rules describe the syntax of date file entries:", X "", X " year <year>", X "", X " opt <options>", X "", X " note <month_spec> <text>", X " note <month> <text>", X "", X " if -A flag (American date formats) specified:", X " <month_name> <day>{*} {<text>}", X " <month><sep><day>{<sep><year>}{*} {<text>}", X "", X " if -E flag (European date formats) specified:", X " <day> <month_name>{*} {<text>}", X " <day><sep><month>{<sep><year>}{*} {<text>}", X "", X " <ordinal> <day_spec> in <month_spec>{*} {<text>}", X " <day_spec> <prep> <date_spec>", X "", X "where", X "", X " {x} means x is optional", X "", X " <date_spec> := any of the above date specs (not year, note, or opt)", X " <month_name> := first 3+ characters of name of month, or \"all\"", X " <month_spec> := <month_name>, or \"year\"", X " <day_name> := first 3+ characters of name of weekday, \"day\",", X " \"weekday\", \"workday\", \"holiday\", \"nonweekday\",", X " \"nonworkday\", or \"nonholiday\"", X " <ordinal> := ordinal number (\"1st\", \"2nd\", etc.), \"first\" .. \"fifth\",", X " \"last\", \"even\", \"odd\", or \"all\"", X " <prep> := \"before\", \"preceding\", \"after\", \"following\", \"on_or_before\",", X " or \"on_or_after\"", X " <sep> := one or more non-numeric, non-space, non-'*' characters", X " <month>, <day>, <year> are the numeric forms", X "", X " <options> := any command-line option except -e, -f, -h, -D, -U", X "", X "Comments start with '#' and run through end-of-line.", X "", X "Holidays may be flagged by specifying '*' as the last character of", X "the date field(s), e.g. \"10/12* Columbus Day\", \"July 4* Independence", X "Day\", etc. Any dates flagged as holidays will be printed in gray, and", X "any associated text will appear adjacent to the date.", X "", X "Note that the numeric date formats (mm/dd{/yy}, dd.mm{.yy}) support", X "an optional year, which will become the subsequent default year. The", X "alphabetic date formats (month dd, dd month) do not support a year", X "field; the \"year yy\" command is provided to reset the default year.", X "", X "\"Floating\" days may be specified in the date file as \"first Mon in ", X "Sep\", \"last Mon in May\", \"4th Thu in Nov\", etc.; any word may be", X "used in place of \"in\". \"Relative floating\" days (e.g. \"Fri after 4th ", X "Thu in Nov\") are also accepted; they may span month/year bounds.", X "Pcal also accepts date specs such as \"all Friday{s} in October\", \"last", X "Thursday in all\", etc., and produces the expected results; \"each\" and", X "\"every\" are accepted as synonyms for \"all\". Negative ordinals are", X "allowed; \"-2nd\" means \"next to last\".", X "", X "The words \"day\", \"weekday\", \"workday\", and \"holiday\" may be used as", X "wildcards: \"day\" matches any day, \"weekday\" matches any day normally", X "printed in black, \"workday\" matches any day normally printed in black", X "and not explicitly flagged as a holiday, and \"holiday\" matches any", X "day explicitly flagged as a holiday. \"Nonweekday\", \"nonworkday\",", X "and \"nonholiday\" are also supported and have the obvious meanings.", X "", X "\"Odd\" and \"even\" do not refer to the actual date; instead, \"odd\"", X "means \"alternate, starting with the first\"; \"even\" means \"alternate,", X "starting with the second\". Thus, \"odd Fridays in March\" refers to", X "the first, third, and (if present) fifth Fridays in March - not to", X "those Fridays falling on odd dates.", X "", X "\"All\" refers to each individual month; \"year\" refers to the year", X "as an entity. Thus \"odd Fridays in all\" refers to the first/third/", X "fifth Friday of each month, while \"odd Fridays in year\" refers to", X "the first Friday of January and every other Friday thereafter.", X "", X "Additional notes may be propagated to an empty calendar box by the", X "inclusion of one or more lines of the form \"note <month> <text>\",", X "where <month> may be numeric or alphabetic; \"note all <text>\"", X "propagates <text> to each month in the current year.", X "", X "Simple cpp-like functionality is provided. The date file may include", X "the following commands, which work like their cpp counterparts:", X "", X " define <sym>", X " undef <sym>", X "", X " if{n}def <expr>", X " ...", X " { else", X " ... }", X " endif", X "", X " include <file>", X "", X "Note that these do not start with '#', which is reserved as a comment", X "character.", X "", X "<sym> is a symbol name consisting of a letter followed by zero or", X "more letters, digits, or underscores ('_'). Symbol names are always", X "treated in a case-insensitive manner.", X "", X "<expr> is an expression consisting of symbol names joined by the logical", X "operators (in order of precedence, high to low) '!' (unary negate), '&'", X "(and), '^' (exclusive or), and '|' (inclusive or). '&&' and '||' are", X "accepted as synonyms for '&' and '|' respectively; the order of", X "evaluation may be altered by the use of parentheses. A symbol whose", X "name is currently defined evaluates to TRUE; one whose name is not", X "currently defined evaluates to FALSE. Thus \"ifdef A | B | C\" is TRUE", X "if any of the symbols A, B, and C is currently defined, and", X "\"ifdef A & B & C\" is TRUE if all of them are.", X "", X "\"ifndef A | B | C\" is equivalent to \"ifdef !(A | B | C)\" (or, using", X "DeMorgan's Law, \"ifdef !A & !B & !C\") - in other words, TRUE if none of", X "the symbols A, B, and C is currently defined.", X "", X "\"define\" alone deletes all the current definitions; \"ifdef\" alone is", X "always false; \"ifndef\" alone is always true.", X "", X "The file name in the \"include\" directive may optionally be surrounded", X "by \"\" or <>. In any case, path names are taken to be relative to", X "the location of the file containing the \"include\" directive.", X "", X "", X "Moon file syntax:", X "", X "Pcal normally calculates the approximate phase of the moon using", X "a simple algorithm which assumes (among other things) that the", X "length of the lunar month is constant and that the quarter moons", X "will occur on the same day worldwide. For most users, that is", X "adequate; however, moon-phase freaks may enter the dates and", X "(optionally) times of quarter moons (from a reliable source such", X "as an almanac or astronomical table) into a file called .moonXX ", X "(moonXX.dat on VMS), where XX is the last two digits of the year.", X "If such a file exists (in the same directory as the date file),", X "pcal will interpolate the phase of the moon from the information", X "in this file instead of using the default algorithm.", X "", X "Entries in the moon file must conform to the following syntax:", X "", X " if -A flag (American date formats) specified:", X " <quarter> <month><sep><day> {<hour><sep><min>}", X "", X " if -E flag (European date formats) specified:", X " <quarter> <day><sep><month> {<hour><sep><min>}", X "", X "where", X "", X " <quarter> := \"nm\", \"fq\" or \"1q\", \"fm\", \"3q\" or \"lq\" (new", X " moon, first quarter, full moon, last quarter)", X " <hour> := number 0-23 (24-hour clock)", X " <min> := number 0-59", X "", X "This file must contain entries for all quarter moons in the year,", X "in chronological order; if any errors are encountered, pcal will", X "revert to using its default algorithm.", X "", X "As in the date file, comments start with '#' and run through", X "end-of-line. ", X NULL X }; #else extern char *date_msg[]; #endif X /* format strings for color_msg() - translate as necessary */ #define COLOR_MSG_1 "all days in %s" #define COLOR_MSG_2 "in %s; others in %s" X /* format string for short usage() message */ #define USAGE_MSG "enter \"%s -%c\" for full description of parameters\n" X /* format strings for comment in PostScript output file */ #define VERSION_MSG "Generated by %s %s" #define DATEFILE_MSG " from %s" X #define NOTES_HDR "Notes" /* title of "notes" box */ #define LINE_SEP ".p" /* text line separator */ X /* strings used in error messages */ #define ENV_VAR "environment variable " #define DATE_FILE "date file " X /* Error and information messages - translate as necessary */ X /* program error messages */ #define E_ALLOC_ERR "%s: calloc() failed - out of memory\n" #define E_FOPEN_ERR "%s: can't open file %s\n" #define E_ILL_LINE "%s: %s in file %s, line %d\n" #define E_ILL_MONTH "%s: month %d not in range %d .. %d\n" #define E_ILL_OPT "%s: unrecognized flag %s" #define E_ILL_OPT2 " (%s\"%s\")" #define E_ILL_YEAR "%s: year %d not in range %d .. %d\n" #define E_SYMFULL "%s: symbol table full - can't define %s\n" #define E_UNT_IFDEF "%s: unterminated if{n}def..{else..}endif in file %s\n" #define E_FLAG_IGNORED "%s: -%c flag ignored (%s\"%s\")\n" X /* preprocessor error strings */ #define E_ELSE_ERR "unmatched \"else\"" #define E_END_ERR "unmatched \"endif\"" #define E_GARBAGE "extraneous data on \"%s\" line" #define E_INV_DATE "invalid date (or no match for wildcard)" #define E_INV_LINE "unrecognized line" #define E_NESTING "maximum file nesting level exceeded" #define E_EXPR_SYNTAX "syntax error in expression" X /* moon file error strings */ #define E_DATE_SEQ "date or phase out of sequence" #define E_PREM_EOF "premature EOF" X /* information message (VMS, Amiga only) */ #define I_OUT_NAME "%s: output is in file %s\n" X SHAR_EOF chmod 0666 pcallang.h || echo 'restore of pcallang.h failed' Wc_c="`wc -c < 'pcallang.h'`" test 23965 -eq "$Wc_c" || echo 'pcallang.h: original size 23965, current size' "$Wc_c" fi # ============= pcalutil.c ============== if test -f 'pcalutil.c' -a X"$1" != X"-c"; then echo 'x - skipping pcalutil.c (File already exists)' else echo 'x - extracting pcalutil.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pcalutil.c' && /* X * pcalutil.c - utility routines for Pcal X * X * Contents: X * X * alloc X * calc_day X * calc_weekday X * calc_year_day X * ci_strcmp X * ci_strncmp X * copy_text X * getline X * is_valid X * loadwords X * mk_filespec X * mk_path X * normalize X * split_date X * trnlog X * X * Revision history: X * X * 4.0 AWR 02/24/91 Revised getline() and copy_text() to X * handle C-style escapes of characters X * and octal/hex numbers X * X * AWR 02/19/91 Added support for negative ordinals X * in calc_day(), calc_year_day() X * X * AWR 02/04/91 Added calc_year_day() X * X * AWR 01/15/91 Extracted from pcal.c X * X */ X X /* X * Standard headers: X */ X #include <stdio.h> #include <ctype.h> #include <string.h> X /* X * Pcal-specific definitions: X */ X #include "pcaldefs.h" #include "pcalglob.h" #include "pcallang.h" X /* X * Macros: X */ X /* skip over numeric field and subsequent non-numeric characters */ #define SKIP_FIELD(p) \ X do { while (*p && isdigit(*p)) p++; \ X while (*p && !isdigit(*p)) p++; } while (0) X X /* X * General-purpose utility routines X */ X X /* X * alloc - interface to calloc(); terminates if unsuccessful X */ #ifdef PROTOS char *alloc(int size) #else char *alloc(size) X int size; #endif { X char *p; X X if (size == 0) /* not all calloc()s like null requests */ X size = 1; X X if ((p = calloc(1, size)) == NULL) { X FPR(stderr, E_ALLOC_ERR, progname); X exit(EXIT_FAILURE); X } X X return p; } X X /* X * ci_str{n}cmp - case-insensitive flavors of strcmp(), strncmp() X */ #ifdef PROTOS int ci_strcmp(register char *s1, X register char *s2) #else int ci_strcmp(s1, s2) register char *s1, *s2; #endif { X register char c1, c2; X X for ( ; (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++) X if (c1 == '\0') X return 0; X X return c1 - c2; } X X #ifdef PROTOS int ci_strncmp(register char *s1, X register char *s2, X int n) #else int ci_strncmp(s1, s2, n) register char *s1, *s2; int n; #endif { X register char c1, c2; X X for ( ; --n >= 0 && (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++) X if (c1 == '\0') X return 0; X X return n < 0 ? 0 : c1 - c2; } X X /* X * Date calculation routines (see also macros in pcaldefs.h) X */ X X /* X * normalize - adjust day in case it has crossed month (or year) bounds X */ #ifdef PROTOS void normalize(DATE *pd) #else void normalize(pd) X DATE *pd; /* pointer to date */ #endif { X int len; X X /* adjust if day is in previous or following month */ X X while (pd->dd < 1) { X pd->yy = PREV_YEAR(pd->mm, pd->yy); X pd->mm = PREV_MONTH(pd->mm, pd->yy); X pd->dd += LENGTH_OF(pd->mm, pd->yy); X } X X while (pd->dd > (len = LENGTH_OF(pd->mm, pd->yy))) { X pd->dd -= len; X pd->yy = NEXT_YEAR(pd->mm, pd->yy); X pd->mm = NEXT_MONTH(pd->mm, pd->yy); X } } X X /* X * calc_day - calculate calendar date from ordinal date (e.g., "first Friday X * in November", "last day in October"); return calendar date if it exists, X * 0 if it does not X */ #ifdef PROTOS int calc_day(int ord, X int wkd, X int mm) #else int calc_day(ord, wkd, mm) X int ord; X int wkd; X int mm; #endif { #ifdef PROTOS X int first, last, day, (*pfcn)(int, int, int); #else X int first, last, day, (*pfcn)(); #endif X X if (IS_WILD(wkd)) { /* "day", "weekday", "workday", or "holiday" */ X pfcn = pdatefcn[wkd - WILD_FIRST]; X last = LENGTH_OF(mm, curr_year); X X if (ord < 0) { /* search backwards */ X for (day = last; X day >= 1 && X !((*pfcn)(mm, day, curr_year) && ++ord == 0); X day--) X ; X } else { /* search forwards */ X for (day = 1; X day <= last && X !((*pfcn)(mm, day, curr_year) && --ord == 0); X day++) X ; X } X return is_valid(mm, day, curr_year) ? day : 0; X X } else { /* fixed weekday - calculate it */ X first = (wkd - FIRST_OF(mm, curr_year) + 7) % 7 + 1; X if (ord < 0) { /* get last (try 5th, then 4th) */ X if (!is_valid(mm, last = first + 28, curr_year)) X last -= 7; X if (!is_valid(mm, day = last + 7 * (ord + 1), X curr_year)) X day = 0; X } X else X if (!is_valid(mm, day = first + 7 * (ord - 1), X curr_year)) X day = 0; X X return day; X } X } X X /* X * calc_year_day - calculate calendar date from ordinal date within year X * (e.g., "last Friday in year", "10th holiday in year"); if date exists, X * fill in pdate and return TRUE; else return FALSE X */ #ifdef PROTOS int calc_year_day(int ord, X int wkd, X DATE *pdate) #else int calc_year_day(ord, wkd, pdate) X int ord; X int wkd; X DATE *pdate; #endif { #ifdef PROTOS X int incr, (*pfcn)(int, int, int); #else X int incr, (*pfcn)(); #endif X DATE date; X X if (IS_WILD(wkd)) { /* "day", "weekday", "workday", or "holiday" */ X pfcn = pdatefcn[wkd - WILD_FIRST]; X X if (ord < 0) { /* nth occurrence backwards */ X MAKE_DATE(date, DEC, 31, curr_year); X ord = -ord; X incr = -1; X } else { /* nth occurrence forwards */ X MAKE_DATE(date, JAN, 1, curr_year); X incr = 1; X } X X /* search for selected occurrence of specified wildcard */ X X while (date.yy == curr_year && X !((*pfcn)(date.mm, date.dd, date.yy) && --ord == 0)) { X date.dd += incr; X normalize(&date); X } X X } else { /* fixed weekday - calculate it */ X if (ord < 0) X MAKE_DATE(date, DEC, X calc_day(-1, wkd, DEC) + 7 * (ord + 1), X curr_year); X else X MAKE_DATE(date, JAN, X calc_day(1, wkd, JAN) + 7 * (ord - 1), X curr_year); X normalize(&date); X } X X return date.yy == curr_year ? (*pdate = date, TRUE) : FALSE; } X X /* X * calc_weekday - return the weekday (0-6) of mm/dd/yy (mm: 1-12) X */ #ifdef PROTOS int calc_weekday(int mm, X int dd, X int yy) #else int calc_weekday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X return (yy + (yy-1)/4 - (yy-1)/100 + (yy-1)/400 + OFFSET_OF(mm, yy) + X (dd-1)) % 7; } X X /* X * is_valid - return TRUE if m/d/y is a valid date X */ #ifdef PROTOS int is_valid(register int m, X register int d, X register int y) #else int is_valid(m, d, y) X register int m, d, y; #endif { X return m >= JAN && m <= DEC && X d >= 1 && d <= LENGTH_OF(m, y); } X X X /* X * Token parsing/remerging routines: X */ X X /* X * loadwords - tokenize line buffer into word array, return word count. X * differs from old loadwords() in that it handles quoted (" or ') strings X * and removes escaped quotes X */ #ifdef PROTOS int loadwords(void) #else int loadwords() #endif { X register char *ptok; X char *delim, **ap, *p1, *p2, c; X int nwords; X X for (ptok = lbuf, ap = words; TRUE; ap++) { X X ptok += strspn(ptok, WHITESPACE); /* find next token */ X X if (! *ptok) { /* end of lbuf? */ X *ap = NULL; /* add null ptr at end */ X nwords = ap - words; /* number of non-null ptrs */ X break; /* exit loop */ X } X X delim = *ptok == '"' ? "\"" : /* set closing delimiter */ X *ptok == '\'' ? "'" : X WHITESPACE; X X if (*ptok == *delim) /* skip opening quote */ X ptok++; X X *ap = ptok; /* save token ptr */ X X do { /* find unescaped delimiter */ X ptok += strcspn(ptok, delim); X if ((c = ptok[-1]) == '\\') X ptok++; X } while (c == '\\'); X X if (*ptok) /* terminate token */ X *ptok++ = '\0'; X } X X /* now reprocess the word list, removing escapes from quotes */ X X for (ap = words; *ap; *ap++) X for (p1 = p2 = *ap; c = *p2 = *p1++; *p2++) X if (c == '\\') X *p2 = *p1++; X X return nwords; /* return word count */ X } X X /* X * copy_text - retrieve remaining text in lbuf and copy to output string, X * separating tokens by a single blank and condensing runs of blanks (all X * other whitespace has been converted to blanks by now) to one blank X */ #ifdef PROTOS void copy_text(char *pbuf, X char **ptext) #else void copy_text(pbuf, ptext) X char *pbuf; /* output buffer - can be lbuf itself */ X char **ptext; /* pointer to first text word in "words" */ #endif { X char *p, *pb; X X /* copy words to pbuf, separating by one blank */ X X for (*(pb = pbuf) = '\0'; p = *ptext; *pb++ = *++ptext ? ' ' : '\0') { X for ( ; *p; *p++) X if (! (*p == ' ' && (pb == pbuf || pb[-1] == ' '))) X *pb++ = *p; X if (pb > pbuf && pb[-1] == ' ') X pb--; X } } X X /* X * split_date - extract 1-3 numeric fields (separated by one or more X * non-numeric characters) from date string; return number of fields X */ #ifdef PROTOS int split_date(char *pstr, X int *pn1, X int *pn2, X int *pn3) #else int split_date(pstr, pn1, pn2, pn3) X char *pstr; /* input string */ X int *pn1, *pn2, *pn3; /* output numbers */ #endif { X int i, n, *pn; X X /* attempt to extract up to three numeric fields */ X for (n = 0, i = 1; i <= 3; i++) { X pn = i == 1 ? pn1 : i == 2 ? pn2 : pn3; /* crude but portable */ X if (pn) X *pn = *pstr ? (n++, atoi(pstr)) : 0; X SKIP_FIELD(pstr); /* go to next field */ X } X X return n; } X X X /* X * File input routines: X */ X X /* X * octal_esc - read up to 3 octal digits from file; return value of octal X * constant and leave file pointer at last character X */ #ifdef PROTOS static int octal_esc(FILE *fp) #else static int octal_esc(fp) X FILE *fp; #endif { X int i, n, c; X X for (n = 0, i = 0; i < 3; i++) { X c = getc(fp); X if (c == EOF) X return EOF; X if (!isodigit(c)) { X ungetc(c, fp); X break; X } X n = n * 8 + (c - '0'); X } X X return n & 0377; /* truncate to 8 bits */ } X X /* X * hex_esc - read 'x' or 'X' followed by 1 or 2 hex digits from file; return X * value of hexadecimal constant (or letter if no hex digits follow) and X * leave file pointer at last character X */ #ifdef PROTOS static int hex_esc(FILE *fp) #else static int hex_esc(fp) X FILE *fp; #endif { X int i, n, c, sv_c; X X sv_c = c = getc(fp); /* read leading 'x' or 'X' */ X if (TOLOWER(c) != 'x') X return c; /* something else - just return it */ X X for (n = 0, i = 0; i < 2; i++) { X c = getc(fp); X if (c == EOF) X return EOF; X if (!isxdigit(c)) { X ungetc(c, fp); X break; X } X n = n * 16 + (isupper(c) ? c - 'A' + 10 : X islower(c) ? c - 'a' + 10 : X c - '0'); X } X X return i > 0 ? n & 0377 : sv_c; /* truncate to 8 bits */ } X X /* X * getline - read next non-null line of input file into lbuf; return 0 on EOF X * strip leading whitespace, translate other whitespace to blanks, and handle X * all escapes except \' and \", (cf. loadwords()) X */ #ifdef PROTOS int getline(FILE *fp, X int *pline) #else int getline(fp, pline) X FILE *fp; X int *pline; #endif { X register char *cp; X register int c, c2; X static char escape[] = "abfnrtv"; /* cf. ANSI spec, 2.2.2 */ X int in_comment; /* comments: from '#' to end-of-line */ X X cp = lbuf; X do { X in_comment = FALSE; X while ((c = getc(fp)) != '\n' && c != EOF) { X if (c == '#') X in_comment = TRUE; X X if (isspace(c)) /* whitespace => blank */ X c = ' '; X X /* ignore comments and leading white space */ X if (in_comment || (cp == lbuf && c == ' ')) X continue; X X /* handle escape sequences here: escaped whitespace X * and ANSI escapes are all converted to a space; X * octal and hex constants are converted in place X */ X if (c == '\\') { X if ((c2 = getc(fp)) == EOF) X return FALSE; X X if (isspace(c2) || strchr(escape, c2)) { X c = ' '; X if (c2 == '\n') X (*pline)++; X } X else if (isodigit(c2)) { /* octal */ X ungetc(c2, fp); X if((c = octal_esc(fp)) == EOF) X return FALSE; X } X else if (TOLOWER(c2) == 'x') { /* hex */ X ungetc(c2, fp); X if((c = hex_esc(fp)) == EOF) X return FALSE; X } X else if (c2 == '\'' || c2 == '"') X ungetc(c2, fp); X else X c = c2; X X } X *cp++ = c; X } X X if (c == EOF) /* no more input lines */ X return FALSE; X X (*pline)++; /* bump line number */ X X } while (cp == lbuf); /* ignore empty lines */ X X *cp = '\0'; X return TRUE; } X X /* X * Routines dealing with translation of file specifications (VMS, Un*x) X */ X #ifdef VMS /* X * mk_path - extract the path component from VMS file spec X */ #ifdef PROTOS char *mk_path(char *path, X char *filespec) #else char *mk_path(path, filespec) X char *path; /* output path */ X char *filespec; /* input filespec */ #endif { X char *p; X X strcpy(path, filespec); X if (!(p = strchr(path, ']')) && !(p = strchr(path, ':'))) X p = path - 1; /* return null string if no path */ X *++p = '\0'; X X return path; } X X /* X * mk_filespec - merge VMS path and file names, where latter can be relative X */ #ifdef PROTOS char *mk_filespec(char *filespec, X char *path, X char *name) #else char *mk_filespec(filespec, path, name) X char *filespec; /* output filespec */ X char *path; /* input path */ X char *name; /* input file name */ #endif { X char *p; X X *filespec = '\0'; X X /* copy name intact if absolute; else merge path and relative name */ X if (!strchr(name, ':')) { X strcpy(filespec, path); X if ((p = P_LASTCHAR(filespec)) && *p == END_PATH && X name[0] == START_PATH && strchr(".-", name[1])) X *p = *++name == '-' ? '.' : '\0'; X } X X return strcat(filespec, name); } X X /* X * trnlog - return translation of VMS logical name (null if missing) X */ #ifdef PROTOS char *trnlog(char *logname) #else char *trnlog(logname) /* look up logical name */ X char *logname; #endif { X static char trnbuf[STRSIZ]; X X $DESCRIPTOR(src, logname); X $DESCRIPTOR(dst, trnbuf); X short len; X int ret; X X src.dsc$w_length = strlen(logname); X ret = LIB$SYS_TRNLOG(&src, &len, &dst); X return ret == SS$_NORMAL ? (trnbuf[len] = '\0', trnbuf) : NULL; } X #else /* apparently DOS and Amiga can use the Un*x flavors */ X /* X * mk_path - extract the path component from a Un*x file spec X */ #ifdef PROTOS char *mk_path(char *path, X char *filespec) #else char *mk_path(path, filespec) X char *path; /* output path */ X char *filespec; /* input filespec */ #endif { X char *p; X X strcpy(path, filespec); X if (! (p = strrchr(path, END_PATH)) ) X p = path - 1; /* return null string if no path */ X X *++p = '\0'; X return path; } X X /* X * mk_filespec - merge Un*x path and file names, where latter can be relative X */ #ifdef PROTOS char *mk_filespec(char *filespec, X char *path, X char *name) #else char *mk_filespec(filespec, path, name) X char *filespec; /* output filespec */ X char *path; /* input path */ X char *name; /* input file name */ #endif { X char *p; X X *filespec = '\0'; X X /* copy name intact if absolute; else merge path and relative name */ X X /* if path starts with "~/", translate it for user */ X if (strncmp(name, "~/", 2) == 0 && (p = trnlog(HOME_DIR)) != NULL) { X strcpy(filespec, p); X if ((p = P_LASTCHAR(filespec)) && *p != END_PATH) X *++p = END_PATH, *++p = '\0'; X name += 2; /* skip "~/" */ X } X else if (*name != START_PATH) { /* relative path */ X strcpy(filespec, path); X if ((p = P_LASTCHAR(filespec)) && *p != END_PATH) X *++p = END_PATH, *++p = '\0'; X } X X return strcat(filespec, name); } X X /* X * trnlog - return translation of Un*x environment variable X */ #ifdef PROTOS char *trnlog(char *logname) #else char *trnlog(logname) /* look up logical name */ X char *logname; #endif { X return getenv(logname); } X #endif SHAR_EOF chmod 0644 pcalutil.c || echo 'restore of pcalutil.c failed' Wc_c="`wc -c < 'pcalutil.c'`" test 14737 -eq "$Wc_c" || echo 'pcalutil.c: original size 14737, current size' "$Wc_c" fi true || echo 'restore of protos.h failed' echo End of part 4, continue with part 5 exit 0