home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Header: pcal.c,v 2.3 89/09/19 05:59:27 billr Exp $
- */
- /*
- * pcal - print pretty PostScript image of a month calendar
- *
- * Pieces extracted from the pcal program by Ken Keirnan and modified
- * slightly by Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>.
- *
- * "Pcal" is a program to print PostScript calendars for any month and year.
- * Pcal is the combined effort of several people, most notably Patrick Wood
- * of Pipeline Associates, Inc. for the original PostScript code and Bill
- * Vogel of AT&T for the calendar file mechanism. My part was simple
- * translation to a "C" program, the addition of a couple options and a more
- * generalized date searching routine (oh yes, and a manual page :-).
- *
- * The original calendar PostScript was Copyright (c) 1987 by Patrick Wood
- * and Pipeline Associates, Inc. with permission to modify and redistribute.
- *
- * Ken Keirnan
- * Pacific Bell
- * San Ramon, CA.
- *
- * Changes and additions Copyright (C) 1989 Tektronix, Inc.
- * All Rights Reserved
- * Permission is hereby granted to use and modify the modifications in source
- * or binary form as long as they are not sold for profit and this copyright
- * notice remains intact.
- *
- * Modified by PM Lashley, KLA Instruments, Inc.
- * Fixes and extentions: 1..2 June, 1989
- * 1. Notes were extending beyond the right and bottom edges of the day.
- * They are now line-wrapped with indentation.
- * 3. Bottom justify notes for each day. Truncate if there are too many
- * to fit.
- * 3. If month starts on a Wednesday or later, put the previous/next
- * month inserts in the first two day boxes instead of the last two.
- * 4. Center the month inserts vertically in the day box.
- * 5. When possible, draw the calendar in a 5x7 grid instead of a 6x7
- * grid. Each day will be taller, and accomodate more note text.
- * 6. Added various comments to the Postscript code array.
- * 7. If a periodic event was removed for given occurance, that event
- * would be printed twice when it should not be printed at all.
- * 8. Replaced the constant "Helvetica-Narrow" with PS_NOTE_FONT for
- * sites which do not have the Helvetica-Narrow font but do have
- * some preference other than the default.
- *
- * Left to do:
- * 1. If a 31 day month starts on Tuesday, the previous month should
- * be in the upper left, and the next month in the lower right.
- * This may be more trouble than it is worth.
- *
- * Notes:
- * 1. The Postscript code layout is a compromise between readability
- * and compaction. All comments and vertical spacing are in the
- * c source only to keep the output file size small.
- *
- * Further changes and additions Copyright (C) 1989 PM Lashley
- * All Rights Reserved
- * Permission is hereby granted to use and modify the modifications in source
- * or binary form as long as they are not sold for profit and this copyright
- * notice remains intact.
- *
- */
- #include "ct.h"
-
- #include <stdio.h>
- #include <time.h>
-
- extern struct tm current, First;
- extern struct dayslot slots[];
- extern int get_day_appts();
-
- /*
- * pheader - provides the PostScript routines
- */
- char *pheader[] = {
- "%!",
- "%%Creator: Pipeline Associates",
- "%%Title: calentool's month-at-a-glance",
- "%%Modifed: Ken Keirnan, Bill Randle, PM Lashley and Richard Wolff",
- "%%DocumentFonts: Times-Bold Helvetica-Bold Helvetica-Narrow",
- "%%Pages: 1",
- "%%EndComments",
- "/titlefont /Times-Bold def",
- "/dayfont /Helvetica-Bold def",
- "/month_names [ (January) (February) (March) (April) (May) (June) (July)",
- " (August) (September) (October) (November) (December) ] def",
- "/prtnum { 3 string cvs show} def",
- /*
- * - -weeks- int
- *
- * Pushes the number of week lines (rows) necessary for the current month.
- */
- "/weeks {",
- " startday ndays add 35 gt { 6 } { 5 } ifelse",
- "} def",
-
- /*
- * - -monthHeight- int
- *
- * Pushes the height of an individual day box for the current month.
- */
- "/monthHeight { weeks 5 eq { 96 } { 80 } ifelse } def",
-
- /*
- * Draw the day names and the grid for the current month
- */
- "/drawgrid {",
- " dayfont findfont 10 scalefont setfont",
- " 0 1 6 {",
- " dup dup 100 mul 40 moveto",
- " [ (Sunday) (Monday) (Tuesday) (Wednesday)",
- " (Thursday) (Friday) (Saturday) ]",
- " exch get",
- " 100 center",
- " 100 mul 35 moveto",
- " 1.0 setlinewidth",
- " 0 1 weeks 1 sub {",
- " gsave",
- " 100 0 rlineto",
- " 0 monthHeight neg rlineto",
- " -100 0 rlineto",
- " closepath stroke",
- " grestore",
- " 0 monthHeight neg rmoveto",
- " } for",
- " } for",
- "} def",
-
- /*
- * Draw in the day numbers for each day of the current month.
- *
- * Sunday (and possibly Saturday) will be gray.
- */
- "/drawnums {",
- " dayfont findfont 30 scalefont setfont",
- " /start startday def",
- " /days ndays def",
- " start 100 mul 5 add 10 rmoveto",
- " 1 1 days {",
- " /day exch def",
- " gsave",
- #ifndef SATBLK
- " day start add 7 mod 0 eq {",
- " submonth 0 eq { .8 setgray } if",
- " } if",
- #endif
- " day start add 7 mod 1 eq {",
- " submonth 0 eq { .8 setgray } if",
- " } if",
- " day prtnum",
- " grestore",
- " day start add 7 mod 0 eq",
- " { currentpoint exch pop monthHeight sub 5 exch moveto }",
- " { 100 0 rmoveto }",
- " ifelse",
- " } for",
- "} def",
-
- /*
- * Gray out the day boxes before the first day of the month and after
- * the last day of the month. If this is not a submonth, leave two
- * blank for the previous and next month miniature calendars.
- */
- "/drawfill {",
- " /start startday def",
- " 1.0 setlinewidth",
- " submonth 1 eq {",
- " 0 35 rmoveto",
- " /grayWidth start 100 mul def",
- " /lastday 7 def",
- " } {",
- " start 3 ge {",
- " 200 35 rmoveto",
- " /grayWidth start 2 sub 100 mul def",
- " /lastday 7 def",
- " } {",
- " 0 35 rmoveto",
- " /grayWidth start 100 mul def",
- " /lastday 5 def",
- " } ifelse",
- " } ifelse",
- " grayWidth 0 gt {",
- " gsave",
- " .9 setgray",
- " grayWidth 0 rlineto",
- " 0 monthHeight neg rlineto",
- " grayWidth neg 0 rlineto",
- " closepath fill",
- " grestore",
- " } if",
- " /endday startday ndays add 7 mod def",
- " endday 0 ne {",
- " ndays startday add 7 mod 100 mul",
- " weeks 1 sub neg monthHeight mul 35 add moveto",
- " /grayWidth lastday 100 mul currentpoint pop sub def",
- " grayWidth 0 gt {",
- " gsave",
- " .9 setgray",
- " grayWidth 0 rlineto",
- " 0 monthHeight neg rlineto",
- " grayWidth neg 0 rlineto",
- " closepath fill",
- " grestore",
- " } if",
- " } if",
- "} def",
-
- "/isleap {",
- " year 4 mod 0 eq",
- " year 100 mod 0 ne",
- " year 1000 mod 0 eq or and",
- "} def",
-
- "/days_month [ 31 28 31 30 31 30 31 31 30 31 30 31 ] def",
-
- /*
- * - -ndays- int
- *
- * Push number of days in current month. Account for leap February.
- */
- "/ndays {",
- " days_month month 1 sub get",
- " month 2 eq",
- " isleap and { 1 add } if",
- "} def",
-
- /*
- * - -startday- int
- *
- * Push the day of the week on which the first of the current month falls.
- */
- "/startday {",
- " /off year 2000 sub def",
- " off",
- " off 4 idiv add",
- " off 100 idiv sub",
- " off 1000 idiv add",
- " 6 add 7 mod 7 add",
- " /off exch def",
- " 1 1 month 1 sub {",
- " /idx exch def",
- " days_month idx 1 sub get",
- " idx 2 eq",
- " isleap and",
- " { 1 add } if",
- " /off exch off add def",
- " } for",
- " off 7 mod",
- "} def",
-
- "/center {",
- " /width exch def",
- " /str exch def width str ",
- " stringwidth pop sub 2 div 0 rmoveto str show",
- "} def",
-
- /*
- * Draw an entire month calendar.
- * (Without any previous/next subcalendars.)
- */
- "/calendar",
- "{",
- " titlefont findfont 48 scalefont setfont",
- " 0 60 moveto",
- " /month_name month_names month 1 sub get def",
- " month_name show",
- " /yearstring year 10 string cvs def",
- " 700 yearstring stringwidth pop sub 60 moveto",
- " yearstring show",
- " 0 0 moveto",
- " drawnums",
- " 0 0 moveto",
- " drawfill",
- " 0 0 moveto",
- " drawgrid",
- "} def",
-
- /*
- * array-of-notes -daytext- -
- */
- "/daytext {",
- " /mytext exch def /myday exch def",
- " /bottom monthHeight 30 sub def",
- " startday myday 1 sub add dup",
- " 7 mod 100 mul 5 add /LM exch def",
- " 7 idiv monthHeight neg mul /ylimit exch def",
- " ylimit bottom sub /ypos exch def",
- " /RM LM 95 add def /ystart ypos def",
- " mytext {",
- " 95 90 { pop pop /ystart ystart 8 add def } breakIntoLines",
- " ystart ylimit le { /ypos ystart def } if",
- " } forall",
- " /ylimit ylimit bottom sub def",
- " mytext { 95 90 { prstr } breakIntoLines } forall",
- "} def",
-
- /*
- * string maxwidth -prstr- -
- */
- "/prstr {",
- " ypos ylimit gt {",
- " RM exch sub ypos moveto show",
- " /ypos ypos 8 sub def",
- " } {",
- " pop pop",
- " } ifelse",
- "} def",
-
- /*
- * Word break string for breakIntoLines.
- */
- "/space ( ) def",
-
- /*
- * string first-width next-width proc -breakIntoLines- -
- *
- * Break the string into lines. The first line will fit within
- * first-width. Later lines will fit within next-width. For each
- * line, push the string and current width then execute proc.
- *
- * This is a modification of the function listed in the Blue book
- * (Postscript Language Tutorial and Cookbook, Adobe Systems, Inc.).
- * The modifications are:
- * 1. The addition of the next-width parameter to handle indentation.
- * 2. The original would not break the line if only the last word
- * extended beyond the limit.
- */
- "/breakIntoLines {",
- " /proc exch def",
- " /nextlinewidth exch def",
- " /linewidth exch def",
- " /textstring exch def",
- " /breakwidth space stringwidth pop def",
- " /curwidth 0 def",
- " /lastwordbreak 0 def",
- " /startchar 0 def",
- " /restoftext textstring def",
- " {",
- " restoftext space search {",
- " /nextword exch def pop",
- " /restoftext exch def",
- " /wordwidth nextword stringwidth pop def",
- " curwidth wordwidth add linewidth gt {",
- " textstring startchar",
- " lastwordbreak startchar sub",
- " getinterval linewidth proc",
- " /startchar lastwordbreak def",
- " /curwidth wordwidth breakwidth add def",
- " /linewidth nextlinewidth def",
- " } {",
- " /curwidth curwidth wordwidth add breakwidth add def",
- " } ifelse",
- " /lastwordbreak lastwordbreak nextword length add 1 add def",
- " } {",
- " stringwidth pop curwidth add linewidth gt {",
- " textstring startchar",
- " lastwordbreak startchar sub",
- " getinterval linewidth proc",
- " /startchar lastwordbreak def",
- " /linewidth nextlinewidth def",
- " } if",
- " exit",
- " }",
- " ifelse",
- " } loop",
- " /lastchar textstring length def",
- " textstring startchar lastchar startchar sub getinterval linewidth proc",
- "} def",
-
- "/printmonth {",
- " 90 rotate",
- " 50 -120 translate",
- " /submonth 0 def",
- " calendar",
- " month 1 sub 0 eq {",
- " /lmonth 12 def",
- " /lyear year 1 sub def",
- " } {",
- " /lmonth month 1 sub def",
- " /lyear year def",
- " } ifelse",
- " month 1 add 13 eq {",
- " /nmonth 1 def",
- " /nyear year 1 add def",
- " } {",
- " /nmonth month 1 add def",
- " /nyear year def",
- " } ifelse",
- " /savemonth month def",
- " /saveyear year def",
- " /submonth 1 def",
- " gsave",
- " /offset monthHeight 80 sub 2 div neg 35 add def",
- " startday 3 lt",
- " { 500 weeks 1 sub neg monthHeight mul offset add translate }",
- " { 0 offset translate }",
- " ifelse",
- " /year lyear def",
- " /month lmonth def",
- " gsave",
- " .138 .138 scale",
- " 10 -120 translate",
- " calendar",
- " grestore",
- " /submonth 1 def",
- " /year nyear def",
- " /month nmonth def",
- " 100 0 translate",
- " gsave",
- " .138 .138 scale",
- " 10 -120 translate",
- " calendar",
- " grestore",
- " /month savemonth def",
- " /year saveyear def",
- " /submonth 0 def",
- " grestore",
- "} def",
- (char *)0,
- };
-
- print_month(fp, noteflag)
- FILE *fp;
- int noteflag;
- {
- char **ap;
- int i;
-
-
- /*
- * Write out PostScript prolog
- */
- for (ap = pheader; *ap; ap++)
- fprintf(fp, "%s\n", *ap);
-
- /*
- * Do the calendar
- */
- fprintf (fp, "/year %d def\n", current.tm_year+1900);
- fprintf (fp, "/month %d def\n", current.tm_mon+1);
- fprintf (fp, "printmonth\n");
-
- /*
- * Set the font here to reduce the number of complainings if
- * it is not found.
- */
- fprintf (fp, "/%s findfont 6 scalefont setfont\n", PS_NOTE_FONT);
-
- First = current;
- current.tm_mday = 1;
- for (i=0; i<monthlength(current.tm_mon); i++) {
- fix_current_day();
- (void)get_day_appts();
- print_mday(fp, noteflag);
- current.tm_mday++;
- }
- current = First;
-
- /*
- * Write out PostScript postlog
- */
- fprintf(fp, "showpage\n");
- }
-
- print_mday(fp, noteflag)
- FILE *fp;
- int noteflag;
- {
- int slotno;
- struct appt_entry *aptr, *optr;
-
- fprintf(fp, "%d [\n", current.tm_mday);
-
- for (slotno=0; slotno<N_SLOTS; slotno++) {
- /* any appts in this timeslot? */
- if ((slots[slotno].active == ACTIVE) && slots[slotno].first) {
- /* get printable string from each appt */
- for (aptr=slots[slotno].first; aptr;) {
- if (!deleted(aptr, slotno) &&
- (!noteflag || ((aptr->flags & MARKED_NOTE) != MARKED_NOTE)))
- fprintf(fp, " (%s)\n", format_appt_nd(aptr, TRUE));
- /* free up memory used */
- optr = aptr;
- aptr = aptr->next;
- free(optr);
- }
- }
- }
- fprintf(fp, "] daytext\n");
- }
-
- /* check to see if appt pointed to by ap has been deleted */
- int
- deleted(ap, bi)
- struct appt_entry *ap;
- int bi;
- {
- int found = 0;
- struct appt_entry *a;
-
- if (ap->flags & DELETED)
- return(1);
-
- /* run through the list to see if there are any deleted */
- for (a=slots[bi].first; a; a=a->next)
- if (a->flags & DELETED) {
- /* now see if the current one matches */
- if (!strcmp(a->str, ap->str))
- return(1);
- }
-
- return(0);
- }
-