home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / sun / volume1 / calentool / patch4c / pcal.c < prev   
Encoding:
C/C++ Source or Header  |  1989-10-26  |  14.6 KB  |  516 lines

  1. /*
  2.  * $Header: pcal.c,v 2.3 89/09/19 05:59:27 billr Exp $
  3.  */
  4. /*
  5.  * pcal - print pretty PostScript image of a month calendar
  6.  *
  7.  * Pieces extracted from the pcal program by Ken Keirnan and modified
  8.  * slightly by Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>.
  9.  * 
  10.  * "Pcal" is a program to print PostScript calendars for any month and year.
  11.  * Pcal is the combined effort of several people, most notably Patrick Wood
  12.  * of Pipeline Associates, Inc. for the original PostScript code and Bill
  13.  * Vogel of AT&T for the calendar file mechanism.  My part was simple
  14.  * translation to a "C" program, the addition of a couple options and a more
  15.  * generalized date searching routine (oh yes, and a manual page :-).
  16.  * 
  17.  * The original calendar PostScript was Copyright (c) 1987 by Patrick Wood
  18.  * and Pipeline Associates, Inc. with permission to modify and redistribute.
  19.  * 
  20.  * Ken Keirnan
  21.  * Pacific Bell
  22.  * San Ramon, CA.
  23.  *
  24.  * Changes and additions Copyright (C) 1989 Tektronix, Inc.
  25.  *    All Rights Reserved
  26.  * Permission is hereby granted to use and modify the modifications in source
  27.  * or binary form as long as they are not sold for profit and this copyright
  28.  * notice remains intact.
  29.  *
  30.  * Modified by PM Lashley, KLA Instruments, Inc.
  31.  * Fixes and extentions:                1..2 June, 1989
  32.  *    1. Notes were extending beyond the right and bottom edges of the day.
  33.  *       They are now line-wrapped with indentation.
  34.  *    3. Bottom justify notes for each day.  Truncate if there are too many
  35.  *       to fit.
  36.  *    3. If month starts on a Wednesday or later, put the previous/next
  37.  *       month inserts in the first two day boxes instead of the last two.
  38.  *    4. Center the month inserts vertically in the day box.
  39.  *    5. When possible, draw the calendar in a 5x7 grid instead of a 6x7
  40.  *       grid.  Each day will be taller, and accomodate more note text.
  41.  *    6. Added various comments to the Postscript code array.
  42.  *    7. If a periodic event was removed for given occurance, that event
  43.  *       would be printed twice when it should not be printed at all.
  44.  *    8. Replaced the constant "Helvetica-Narrow" with PS_NOTE_FONT for
  45.  *       sites which do not have the Helvetica-Narrow font but do have
  46.  *       some preference other than the default.
  47.  *
  48.  * Left to do:
  49.  *    1. If a 31 day month starts on Tuesday, the previous month should
  50.  *       be in the upper left, and the next month in the lower right.
  51.  *       This may be more trouble than it is worth.
  52.  *
  53.  * Notes:
  54.  *    1. The Postscript code layout is a compromise between readability
  55.  *       and compaction.  All comments and vertical spacing are in the
  56.  *       c source only to keep the output file size small.
  57.  *
  58.  * Further changes and additions Copyright (C) 1989 PM Lashley
  59.  *    All Rights Reserved
  60.  * Permission is hereby granted to use and modify the modifications in source
  61.  * or binary form as long as they are not sold for profit and this copyright
  62.  * notice remains intact.
  63.  *
  64.  */
  65. #include "ct.h"
  66.  
  67. #include <stdio.h>
  68. #include <time.h>
  69.  
  70. extern struct tm current, First;
  71. extern struct dayslot slots[];
  72. extern int get_day_appts();
  73.  
  74. /*
  75.  * pheader - provides the PostScript routines
  76.  */
  77. char *pheader[] = {
  78.     "%!",
  79.     "%%Creator: Pipeline Associates",
  80.     "%%Title: calentool's month-at-a-glance",
  81.     "%%Modifed: Ken Keirnan, Bill Randle, PM Lashley and Richard Wolff",
  82.     "%%DocumentFonts: Times-Bold Helvetica-Bold Helvetica-Narrow",
  83.     "%%Pages: 1",
  84.     "%%EndComments",
  85.     "/titlefont /Times-Bold def",
  86.     "/dayfont /Helvetica-Bold def",
  87.     "/month_names [ (January) (February) (March) (April) (May) (June) (July)",
  88.     "  (August) (September) (October) (November) (December) ] def",
  89.     "/prtnum { 3 string cvs show} def",
  90.     /*
  91.      * -  -weeks-  int
  92.      *
  93.      * Pushes the number of week lines (rows) necessary for the current month.
  94.      */
  95.     "/weeks {",
  96.     "  startday ndays add 35 gt { 6 } { 5 } ifelse",
  97.     "} def",
  98.  
  99.     /*
  100.      * -  -monthHeight-  int
  101.      *
  102.      * Pushes the height of an individual day box for the current month.
  103.      */
  104.     "/monthHeight { weeks 5 eq { 96 } { 80 } ifelse } def",
  105.  
  106.     /*
  107.      * Draw the day names and the grid for the current month
  108.      */
  109.     "/drawgrid {",
  110.     "  dayfont findfont 10 scalefont setfont",
  111.     "  0 1 6 {",
  112.     "    dup dup 100 mul 40 moveto",
  113.     "    [  (Sunday) (Monday) (Tuesday) (Wednesday)",
  114.     "      (Thursday) (Friday) (Saturday) ]",
  115.     "    exch get",
  116.     "    100 center",
  117.     "    100 mul 35 moveto",
  118.     "    1.0 setlinewidth",
  119.     "    0 1 weeks 1 sub {",
  120.     "      gsave",
  121.     "        100 0 rlineto",
  122.     "        0 monthHeight neg rlineto",
  123.     "        -100 0 rlineto",
  124.     "        closepath stroke",
  125.     "      grestore",
  126.     "      0 monthHeight neg rmoveto",
  127.     "    } for",
  128.     "  } for",
  129.     "} def",
  130.  
  131.     /*
  132.      * Draw in the day numbers for each day of the current month.
  133.      *
  134.      * Sunday (and possibly Saturday) will be gray.
  135.      */
  136.     "/drawnums {",
  137.     "  dayfont findfont 30 scalefont setfont",
  138.     "  /start startday def",
  139.     "  /days ndays def",
  140.     "  start 100 mul 5 add 10 rmoveto",
  141.     "  1 1 days {",
  142.     "    /day exch def",
  143.     "    gsave",
  144. #ifndef SATBLK
  145.     "      day start add 7 mod 0 eq {",
  146.     "        submonth 0 eq { .8 setgray } if",
  147.     "      } if",
  148. #endif
  149.     "      day start add 7 mod 1 eq {",
  150.     "        submonth 0 eq { .8 setgray } if",
  151.     "      } if",
  152.     "      day prtnum",
  153.     "    grestore",
  154.     "    day start add 7 mod 0 eq",
  155.     "    { currentpoint exch pop monthHeight sub 5 exch moveto }",
  156.     "    { 100 0 rmoveto }",
  157.     "    ifelse",
  158.     "  } for",
  159.     "} def",
  160.  
  161.     /*
  162.      * Gray out the day boxes before the first day of the month and after
  163.      * the last day of the month.  If this is not a submonth, leave two
  164.      * blank for the previous and next month miniature calendars.
  165.      */
  166.     "/drawfill {",
  167.     "  /start startday def",
  168.     "  1.0 setlinewidth",
  169.     "  submonth 1 eq {",
  170.     "   0 35 rmoveto",
  171.     "   /grayWidth start 100 mul def",
  172.     "   /lastday 7 def",
  173.     "  } {",
  174.     "   start 3 ge {",
  175.     "     200 35 rmoveto",
  176.     "     /grayWidth start 2 sub 100 mul def",
  177.     "     /lastday 7 def",
  178.     "   } {",
  179.     "     0 35 rmoveto",
  180.     "     /grayWidth start 100 mul def",
  181.     "     /lastday 5 def",
  182.     "   } ifelse",
  183.     "  } ifelse",
  184.     "  grayWidth 0 gt {",
  185.     "   gsave",
  186.     "     .9 setgray",
  187.     "     grayWidth 0 rlineto",
  188.     "     0 monthHeight neg rlineto",
  189.     "     grayWidth neg 0 rlineto",
  190.     "     closepath fill",
  191.     "   grestore",
  192.     "  } if",
  193.     "  /endday startday ndays add 7 mod def",
  194.     "  endday 0 ne {",
  195.     "   ndays startday add 7 mod 100 mul",
  196.     "   weeks 1 sub neg monthHeight mul 35 add moveto",
  197.     "   /grayWidth lastday 100 mul currentpoint pop sub def",
  198.     "   grayWidth 0 gt {",
  199.     "    gsave",
  200.     "      .9 setgray",
  201.     "      grayWidth 0 rlineto",
  202.     "      0 monthHeight neg rlineto",
  203.     "      grayWidth neg 0 rlineto",
  204.     "      closepath fill",
  205.     "    grestore",
  206.     "   } if",
  207.     "  } if",
  208.     "} def",
  209.  
  210.     "/isleap {",
  211.     "  year 4 mod 0 eq",
  212.     "  year 100 mod 0 ne",
  213.     "  year 1000 mod 0 eq or and",
  214.     "} def",
  215.  
  216.     "/days_month [ 31 28 31 30 31 30 31 31 30 31 30 31 ] def",
  217.  
  218.     /*
  219.      * -  -ndays-  int
  220.      *
  221.      * Push number of days in current month.  Account for leap February.
  222.      */
  223.     "/ndays {",
  224.     "  days_month month 1 sub get",
  225.     "  month 2 eq",
  226.     "  isleap and { 1 add } if",
  227.     "} def",
  228.  
  229.     /*
  230.      * -  -startday-  int
  231.      *
  232.      * Push the day of the week on which the first of the current month falls.
  233.      */
  234.     "/startday {",
  235.     "  /off year 2000 sub def",
  236.     "  off",
  237.     "  off 4 idiv add",
  238.     "  off 100 idiv sub",
  239.     "  off 1000 idiv add",
  240.     "  6 add 7 mod 7 add",
  241.     "  /off exch def",
  242.     "  1 1 month 1 sub {",
  243.     "    /idx exch def",
  244.     "    days_month idx 1 sub get",
  245.     "    idx 2 eq",
  246.     "    isleap and",
  247.     "    { 1 add } if",
  248.     "    /off exch off add def",
  249.     "  } for",
  250.     "  off 7 mod",
  251.     "} def",
  252.  
  253.     "/center {",
  254.     "  /width exch def",
  255.     "  /str exch def width str ",
  256.     "  stringwidth pop sub 2 div 0 rmoveto str show",
  257.     "} def",
  258.  
  259.     /*
  260.      * Draw an entire month calendar.
  261.      * (Without any previous/next subcalendars.)
  262.      */
  263.     "/calendar",
  264.     "{",
  265.     "  titlefont findfont 48 scalefont setfont",
  266.     "  0 60 moveto",
  267.     "  /month_name month_names month 1 sub get def",
  268.     "  month_name show",
  269.     "  /yearstring year 10 string cvs def",
  270.     "  700 yearstring stringwidth pop sub 60 moveto",
  271.     "  yearstring show",
  272.     "  0 0 moveto",
  273.     "  drawnums",
  274.     "  0 0 moveto",
  275.     "  drawfill",
  276.     "  0 0 moveto",
  277.     "  drawgrid",
  278.     "} def",
  279.  
  280.     /*
  281.      * array-of-notes  -daytext-  -
  282.      */
  283.     "/daytext {",
  284.     "  /mytext exch def /myday exch def",
  285.     "  /bottom monthHeight 30 sub def",
  286.     "  startday myday 1 sub add dup",
  287.     "  7 mod 100 mul 5 add /LM exch def",
  288.     "  7 idiv monthHeight neg mul /ylimit exch def",
  289.     "  ylimit bottom sub /ypos exch def",
  290.     "  /RM LM 95 add def /ystart ypos def",
  291.     "  mytext {",
  292.     "    95 90 { pop pop /ystart ystart 8 add def } breakIntoLines",
  293.     "    ystart ylimit le { /ypos ystart def } if",
  294.     "  } forall",
  295.     "  /ylimit ylimit bottom sub def",
  296.     "  mytext { 95 90 { prstr } breakIntoLines } forall",
  297.     "} def",
  298.  
  299.     /*
  300.      * string maxwidth  -prstr-  -
  301.      */
  302.     "/prstr {",
  303.     "  ypos ylimit gt {",
  304.     "    RM exch sub ypos moveto show",
  305.     "    /ypos ypos 8 sub def",
  306.     "  } {",
  307.     "   pop pop",
  308.     "  } ifelse",
  309.     "} def",
  310.  
  311.     /*
  312.      * Word break string for breakIntoLines.
  313.      */
  314.     "/space ( ) def",
  315.  
  316.     /*
  317.      * string  first-width  next-width  proc  -breakIntoLines-  -
  318.      *
  319.      * Break the string into lines.  The first line will fit within
  320.      * first-width.  Later lines will fit within next-width.  For each
  321.      * line, push the string and current width then execute proc.
  322.      *
  323.      * This is a modification of the function listed in the Blue book
  324.      * (Postscript Language Tutorial and Cookbook, Adobe Systems, Inc.).
  325.      * The modifications are:
  326.      *    1.    The addition of the next-width parameter to handle indentation.
  327.      *  2.    The original would not break the line if only the last word
  328.      *        extended beyond the limit.
  329.      */
  330.     "/breakIntoLines {",
  331.     "  /proc exch def",
  332.     "  /nextlinewidth exch def",
  333.     "  /linewidth exch def",
  334.     "  /textstring exch def",
  335.     "  /breakwidth space stringwidth pop def",
  336.     "  /curwidth 0 def",
  337.     "  /lastwordbreak 0 def",
  338.     "  /startchar 0 def",
  339.     "  /restoftext textstring def",
  340.     "  {",
  341.     "   restoftext space search {",
  342.     "     /nextword exch def pop",
  343.     "     /restoftext exch def",
  344.     "      /wordwidth nextword stringwidth pop def",
  345.     "      curwidth wordwidth add linewidth gt {",
  346.     "           textstring startchar",
  347.     "        lastwordbreak startchar sub",
  348.     "        getinterval linewidth proc",
  349.     "        /startchar lastwordbreak def",
  350.     "        /curwidth wordwidth breakwidth add def",
  351.     "           /linewidth nextlinewidth def",
  352.     "      } {",
  353.     "           /curwidth curwidth wordwidth add breakwidth add def",
  354.     "     } ifelse",
  355.     "      /lastwordbreak lastwordbreak nextword length add 1 add def",
  356.     "    } {",
  357.     "     stringwidth pop curwidth add linewidth gt {",
  358.     "           textstring startchar",
  359.     "           lastwordbreak startchar sub",
  360.     "           getinterval linewidth proc",
  361.     "        /startchar lastwordbreak def",
  362.     "           /linewidth nextlinewidth def",
  363.     "     } if",
  364.     "     exit",
  365.     "   }",
  366.     "    ifelse",
  367.     "  } loop",
  368.     "  /lastchar textstring length def",
  369.     "  textstring startchar lastchar startchar sub getinterval linewidth proc",
  370.     "} def",
  371.  
  372.     "/printmonth {",
  373.     "  90 rotate",
  374.     "  50 -120 translate",
  375.     "  /submonth 0 def",
  376.     "  calendar",
  377.     "  month 1 sub 0 eq {",
  378.     "    /lmonth 12 def",
  379.     "    /lyear year 1 sub def",
  380.     "  } {",
  381.     "    /lmonth month 1 sub def",
  382.     "    /lyear year def",
  383.     "  } ifelse",
  384.     "  month 1 add 13 eq {",
  385.     "    /nmonth 1 def",
  386.     "    /nyear year 1 add def",
  387.     "  } {",
  388.     "    /nmonth month 1 add def",
  389.     "    /nyear year def",
  390.     "  } ifelse",
  391.     "  /savemonth month def",
  392.     "  /saveyear year def",
  393.     "  /submonth 1 def",
  394.     "  gsave",
  395.     "    /offset monthHeight 80 sub 2 div neg 35 add def",
  396.     "    startday 3 lt",
  397.     "    { 500 weeks 1 sub neg monthHeight mul offset add translate }",
  398.     "    { 0  offset translate }",
  399.     "    ifelse",
  400.     "   /year lyear def",
  401.     "   /month lmonth def",
  402.     "    gsave",
  403.     "      .138 .138 scale",
  404.     "      10 -120 translate",
  405.     "      calendar",
  406.     "    grestore",
  407.     "    /submonth 1 def",
  408.     "    /year nyear def",
  409.     "    /month nmonth def",
  410.     "    100 0 translate",
  411.     "    gsave",
  412.     "      .138 .138 scale",
  413.     "      10 -120 translate",
  414.     "      calendar",
  415.     "    grestore",
  416.     "    /month savemonth def",
  417.     "    /year saveyear def",
  418.     "    /submonth 0 def",
  419.     "  grestore",
  420.     "} def",
  421.   (char *)0,
  422. };
  423.  
  424. print_month(fp, noteflag)
  425. FILE *fp;
  426. int noteflag;
  427. {
  428.     char      **ap;
  429.     int        i;
  430.  
  431.     
  432.     /*
  433.      * Write out PostScript prolog
  434.      */
  435.     for (ap = pheader; *ap; ap++)
  436.     fprintf(fp, "%s\n", *ap);
  437.  
  438.     /*
  439.      * Do the calendar
  440.      */
  441.     fprintf (fp, "/year %d def\n", current.tm_year+1900);
  442.     fprintf (fp, "/month %d def\n", current.tm_mon+1);
  443.     fprintf (fp, "printmonth\n");
  444.  
  445.     /*
  446.      * Set the font here to reduce the number of complainings if
  447.      * it is not found.
  448.      */
  449.     fprintf (fp, "/%s findfont 6 scalefont setfont\n", PS_NOTE_FONT);
  450.  
  451.     First = current;
  452.     current.tm_mday = 1;
  453.     for (i=0; i<monthlength(current.tm_mon); i++) {
  454.     fix_current_day();
  455.     (void)get_day_appts();
  456.     print_mday(fp, noteflag);
  457.     current.tm_mday++;
  458.     }
  459.     current = First;
  460.  
  461.     /*
  462.      * Write out PostScript postlog
  463.      */
  464.     fprintf(fp, "showpage\n");
  465. }
  466.  
  467. print_mday(fp, noteflag)
  468. FILE *fp;
  469. int noteflag;
  470. {
  471.     int     slotno;
  472.     struct appt_entry    *aptr, *optr;
  473.     
  474.     fprintf(fp, "%d [\n", current.tm_mday);
  475.  
  476.     for (slotno=0; slotno<N_SLOTS; slotno++) {
  477.     /* any appts in this timeslot? */
  478.     if ((slots[slotno].active == ACTIVE) && slots[slotno].first) {
  479.         /* get printable string from each appt */
  480.         for (aptr=slots[slotno].first; aptr;) {
  481.         if (!deleted(aptr, slotno) && 
  482.             (!noteflag || ((aptr->flags & MARKED_NOTE) != MARKED_NOTE)))
  483.             fprintf(fp, "    (%s)\n", format_appt_nd(aptr, TRUE));
  484.         /* free up memory used */
  485.         optr = aptr;
  486.         aptr = aptr->next;
  487.         free(optr);
  488.         }
  489.     }
  490.     }
  491.     fprintf(fp, "] daytext\n");
  492. }
  493.  
  494. /* check to see if appt pointed to by ap has been deleted */
  495. int
  496. deleted(ap, bi)
  497. struct appt_entry *ap;
  498. int bi;
  499. {
  500.     int found = 0;
  501.     struct appt_entry *a;
  502.  
  503.     if (ap->flags & DELETED)
  504.         return(1);
  505.  
  506.     /* run through the list to see if there are any deleted */
  507.     for (a=slots[bi].first; a; a=a->next)
  508.         if (a->flags & DELETED) {
  509.             /* now see if the current one matches */
  510.             if (!strcmp(a->str, ap->str))
  511.                 return(1);
  512.         }
  513.     
  514.     return(0);
  515. }
  516.