home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume17 / calentool / part04 / pcaldw.c
C/C++ Source or Header  |  1991-04-06  |  14KB  |  551 lines

  1. /*
  2.  * $Header: pcaldw.c,v 1.2 91/03/27 16:46:17 billr Exp $
  3.  */
  4. /*
  5.  * pcaldw - print pretty PostScript image of a day or week calendar
  6.  *
  7.  * Pieces extracted from the pcal program by Ken Keirnan and modified
  8.  * heavily by Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>.
  9.  * Support for non-English characters by Hakan Kallberg <hk@simulina.se>.
  10.  * 
  11.  * This program is Copyright (C) 1991 Tektronix, Inc.
  12.  *    All Rights Reserved
  13.  * Permission is hereby granted to use and modify the modifications in source
  14.  * or binary form as long as they are not sold for profit and this copyright
  15.  * notice remains intact.
  16.  *
  17.  */
  18. #include "ct.h"        /* for NO_PRINTER define */
  19.  
  20. #ifndef NO_PRINTER
  21. #ifndef RASTER_ONLY
  22. #include <stdio.h>
  23. #include <time.h>
  24.  
  25. extern struct tm current, First;
  26. extern struct dayslot *slots;
  27. extern struct weekrect week_boxes[];
  28. extern char *daynames[], *monthnames[];
  29. extern int day_first, hour24, n_tslots, nr_weekdays, n_slots;
  30. extern int start_hour;
  31. extern int day_of_year(), days_remaining_in_year();
  32. int weekday;
  33.  
  34. #define DAY_FORMAT    1
  35. #define WEEK_FORMAT    2
  36. #define MAX_SLOTS 64
  37.  
  38. /*
  39.  * natural language support for non-English characters
  40.  */
  41. #ifdef LANGUAGE
  42. /** Note: Only SWEDISH is currently supported **/
  43. /** send your local encodings to billr@saab.CNA.TEK.COM **/
  44. #define SWEDISH
  45. /* #define ISO_LATIN_1 */
  46. /* #define GERMAN */
  47. /* #define FRENCH */
  48.  
  49. /*
  50.  *  p_lang_header - provides national language support
  51.  */
  52. char *p_lang_header[] = {
  53.     "/ReEncodeSmall",
  54.     "  { 0 begin",
  55.     "    /newcodesandnames exch def",
  56.     "    /basefontname exch def",
  57.     "    /basefontdict basefontname findfont def",
  58.     "    /newfont basefontdict maxlength dict def",
  59.     "    basefontdict",
  60.     "      { exch dup /FID ne",
  61.     "        { dup /Encoding eq",
  62.     "          { exch dup length array copy",
  63.     "            newfont 3 1 roll put }",
  64.     "          { exch newfont 3 1 roll put }",
  65.     "          ifelse }",
  66.     "        { pop pop }",
  67.     "        ifelse",
  68.     "      } forall",
  69.     "    newcodesandnames aload pop",
  70.     "    newcodesandnames length 2 idiv",
  71.     "      { newfont /Encoding get 3 1 roll put}",
  72.     "      repeat",
  73.     "    basefontname newfont definefont pop",
  74.     "    end",
  75.     "  } def",
  76.     "/ReEncodeSmall load 0 12 dict put",
  77.     "/codevec [",
  78. #ifdef  SWEDISH
  79.       "  8#140 /eacute        % `",
  80.       "  8#176 /udieresis    % ~",
  81.       "  8#175 /aring        % }",
  82.       "  8#173 /adieresis    % {",
  83.       "  8#174 /odieresis    % |",
  84.       "  8#100 /Eacute        % @",
  85.       "  8#136 /Udieresis    % ^",
  86.       "  8#135 /Aring        % ]",
  87.       "  8#133 /Adieresis    % [",
  88.       "  8#134 /Odieresis    % \\",
  89. #endif  SWEDISH
  90. #ifdef  ISO_LATIN_1
  91. #endif  ISO_LATIN_1
  92. #ifdef  GERMAN
  93. #endif  GERMAN
  94. #ifdef  FRENCH
  95. #endif  FRENCH
  96.       "  ] def",
  97.     "daytextfont dup codevec ReEncodeSmall",
  98.     (char *)0
  99. };
  100. #endif
  101.  
  102.  
  103. /*
  104.  * pheader - provides the PostScript routines
  105.  */
  106. static char *prolog[] = {
  107.     "%!",
  108.     "%%Creator: Bill Randle, Tektronix, Inc.",
  109.     "%%Title: calentool's day-or-week-at-a-glance",
  110.     "%%For: calentool",
  111.     "%%DocumentFonts: Times-Bold Helvetica Times",
  112.     "%%Bounding Box: 0 0 500 700",
  113.     "%%Pages: 1",
  114.     "%%EndComments",
  115.     "/titlefont /Times-Bold def",
  116.     "/dayfont /Helvetica def",
  117.     "/daytextfont /Times def",
  118.     (char *)0
  119. };
  120.  
  121. static char *pheader[] = {
  122.     "/prtnum { 3 string cvs show} def",
  123.  
  124.     /*
  125.      * Draw the day name and the grid for the current day
  126.      */
  127.     "/drawgrid {",
  128.     "  1.0 setlinewidth",
  129.     "  0 1 nslots 1 sub {",
  130.     "    gsave",
  131.     "      400 0 rlineto",
  132.     "      0 slotHeight neg rlineto",
  133.     "      -400 0 rlineto",
  134.     "      closepath stroke",
  135.     "    grestore",
  136.     "    0 slotHeight neg rmoveto",
  137.     "  } for",
  138.     "} def",
  139.  
  140.     "/drawtimes {",
  141.     "  /timex exch def",
  142.     "  dayfont findfont 12 scalefont setfont",
  143.     "  0 1 nslots 1 sub {",
  144.     "    /slot exch def",
  145.     "    slot slotHeight mul slotHeight 0.75 mul add neg timex exch moveto",
  146.     "    slot ntslots eq {",
  147.     "      (Notes) show",
  148.     "    } { slot ntslots lt {",
  149.     "        hour24 0 eq {",
  150.     "          shour slot 2 idiv add 12 mod dup 0 eq { pop (12) show",
  151.     "            } { prtnum } ifelse (:) show slot 2 mod 0 eq {",
  152.     "              (00) } { (30) } ifelse show",
  153.     "          shour slot 2 idiv add 12 lt { (am) } { (pm) } ifelse show",
  154.     "        } {",
  155.     "          shour slot 2 idiv add prtnum",
  156.     "          slot 2 mod 0 eq { (00) } { (30) } ifelse show",
  157.     "        } ifelse",
  158.     "      } if",
  159.     "    } ifelse",
  160.     "  } for",
  161.     "} def",
  162.  
  163.     /*
  164.      * define clipping region for the text
  165.      */
  166.     "/pageclip {",
  167.     "  newpath",
  168.     "    100 0 moveto",
  169.     "    400 0 rlineto",
  170.     "    0 slotHeight nslots mul neg rlineto",
  171.     "    -400 0 rlineto",
  172.     "  closepath",
  173.     "} def",
  174.  
  175.     /*
  176.      * string width center
  177.      * centers <string> in the width given by <width>
  178.      */
  179.     "/center {",
  180.     "  /width exch def",
  181.     "  /str exch def width str ",
  182.     "  stringwidth pop sub 2 div 0 rmoveto str show",
  183.     "} def",
  184.  
  185.     /*
  186.      * print the string for a given slot s
  187.      *   str x s slotstr
  188.      */
  189.     "/slotstr {",
  190.     "  slotHeight mul slotHeight 0.75 mul add neg moveto show",
  191.     "} def",
  192.  
  193.     /*
  194.      * draw an arrow shaft from point x1, slot s1 to slot s2.
  195.      *   x1 s1 s2 arrowshaft
  196.      */    
  197.     "/arrowshaft {",
  198.     "  3 1 roll 3 copy 1.0 setlinewidth",
  199.     "  dup slotHeight mul neg exch 3 1 roll moveto",
  200.     "  sub 1 add slotHeight mul neg 0 exch rlineto",
  201.     "  dup slotHeight mul neg exch 3 1 roll exch 7 add exch moveto",
  202.     "  sub 1 add slotHeight mul neg 0 exch rlineto",
  203.     "} def",
  204.  
  205.     /*
  206.      * draw an arrowhead at point x, slot s.
  207.      *   x s arrowhead
  208.      */
  209.     "/arrowhead {",
  210.     "  2 copy 2 setlinejoin 1.0 setlinewidth",
  211.     "  slotHeight mul neg moveto 0 slotHeight neg rlineto",
  212.     "  -5 slotHeight 0.4 mul rlineto stroke",
  213.     "  slotHeight mul neg exch 7 add exch moveto 0 slotHeight neg rlineto",
  214.     "  5 slotHeight 0.4 mul rlineto stroke",
  215.     "} def",
  216.  
  217.     /*
  218.      * draw a vertical bar to seperate multiple appts in the same slot
  219.      *   x s apptbar
  220.      */
  221.     "/apptbar {",
  222.     "  2.0 setlinewidth\n",
  223.     "  slotHeight mul neg moveto 0 slotHeight neg rlineto",
  224.     "} def",
  225.  
  226.     /*
  227.      * do one day page
  228.      */
  229.     "/daypage",
  230.     "{",
  231.     "  100 0 moveto",
  232.     "  drawgrid",
  233.     "  gsave",
  234.     "    pageclip clip",
  235.     "    daytext",
  236.     "  grestore",
  237.     "} def",
  238.  
  239.     /*
  240.      * printweek - Draw an entire week calendar by printing
  241.      * scaled versions of individual day pages.
  242.      */
  243.     "/printweek",
  244.     "{",
  245.     "  90 rotate",
  246.     "  40 -50 translate",
  247.     "  /offset -405 def",
  248.     "  /xscale 8.75 nweekd div 5.625 div def",
  249.     "  dayfont findfont 10 scalefont setfont",
  250.     "  gsave",
  251.     "    0 1 nweekd 1 sub {",
  252.     "      /daynum exch def",
  253.     "      /offset offset 405 add def",
  254.     "      gsave",
  255.     "        xscale .73 scale",
  256.     "        offset 0 translate",
  257.     "        daytextfont findfont 12 scalefont setfont",
  258.     "        daytextindex daynum get cvn cvx /daytext exch def",
  259.     "        daypage",
  260.     "      grestore",
  261.     "      gsave",
  262.     "        offset xscale mul 0 translate",
  263.     "        100 xscale mul 20 .73 mul moveto",
  264.     "        weekday daynum get",
  265.     "        400 xscale mul center",
  266.     "        100 xscale mul -620 .73 mul moveto",
  267.     "        weekdate daynum get",
  268.     "        400 xscale mul center",
  269.     "      grestore",
  270.     "    } for",
  271.     "    gsave",
  272.     "      1 .73 scale",
  273.     "      -20 drawtimes",
  274.     "      405 nweekd mul xscale mul 40 add drawtimes",
  275.     "    grestore",
  276.     "  grestore",
  277.     "  120 -500 moveto",
  278.     "  yearweek show",
  279.     "} def",
  280.  
  281.     /*
  282.      * printday - print a single day page
  283.      */
  284.     "/printday {",
  285.     "  40 700 translate",
  286.     "  titlefont findfont 24 scalefont setfont",
  287.     "  100 40 moveto",
  288.     "  title 400 center",
  289.     "  dayfont findfont 10 scalefont setfont",
  290.     "  daytextfont findfont 10 scalefont setfont",
  291.     "  daypage",
  292.     "  drawtimes",
  293.     "  dayfont findfont 10 scalefont setfont",
  294.     "  100 -660 moveto",
  295.     "  yearday 400 center",
  296.     "} def",
  297.  
  298.     "/daytextindex [ (day0) (day1) (day2) (day3) (day4) (day5) (day6) ] def",
  299.   (char *)0,
  300. };
  301.  
  302. print_psday(fp, noteflag)
  303. FILE *fp;
  304. int noteflag;
  305. {
  306.     char daystring[128];
  307.  
  308.     /*
  309.      * write out headers and prologs
  310.      */
  311.     do_ps_header(fp);
  312.     /*
  313.      * Do the calendar
  314.      */
  315.     First = current;
  316.     if (day_first)
  317.         sprintf(daystring, "%s %d %s %d",
  318.             daynames[current.tm_wday], current.tm_mday,
  319.             monthnames[current.tm_mon], 1900 + current.tm_year);
  320.     else
  321.         sprintf(daystring, "%s %s %d, %d",
  322.             daynames[current.tm_wday], monthnames[current.tm_mon],
  323.             current.tm_mday, 1900 + current.tm_year);
  324.     fprintf(fp, "/title (%s) def\n", daystring);
  325.     sprintf(daystring,
  326.         "Day of year: %d  --  %d days remaining.      Week number: %d",
  327.         day_of_year((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900),
  328.         days_remaining_in_year((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900),
  329.         week_number());
  330.     fprintf(fp, "/yearday (%s) def\n", daystring);
  331.  
  332.     /*
  333.      * printout the text for this day
  334.      */
  335.     fprintf(fp, "/daytext {\n");
  336.     do_ps_day(fp, noteflag, DAY_FORMAT);
  337.     fprintf(fp, "} def\n");
  338.     fprintf(fp, "printday\n");
  339.  
  340.     /*
  341.      * Write out PostScript postlog
  342.      */
  343.     fprintf(fp, "showpage\n");
  344. }
  345.  
  346. print_psweek(fp, noteflag)
  347. FILE *fp;
  348. int noteflag;
  349. {
  350.     /*
  351.      * write out headers and prologs
  352.      */
  353.     do_ps_header(fp);
  354.     /*
  355.      * Do the calendar
  356.      */
  357.     First = current;
  358.     fprintf(fp, "/weekday [ ");
  359.     for (weekday=0; weekday<nr_weekdays; weekday++)
  360.         fprintf(fp, "(%3.3s) ", daynames[(First.tm_wday+weekday) % 7]);
  361.     fprintf(fp, "] def\n");
  362.     fprintf(fp, "/weekdate [ ");
  363.     for (weekday=0; weekday<nr_weekdays; weekday++) {
  364.     if (day_first)
  365.         fprintf(fp, "(%d %3.3s) ", current.tm_mday,
  366.             monthnames[current.tm_mon]);
  367.     else
  368.         fprintf(fp, "(%3.3s %d) ", monthnames[current.tm_mon],
  369.             current.tm_mday);
  370.     current.tm_mday++;
  371.     fix_current_day();
  372.     }
  373.     fprintf(fp, "] def\n");
  374.     current = First;
  375.     fprintf(fp, "/yearweek (%d         Week number: %d) def\n",
  376.         current.tm_year+1900, week_number());
  377.  
  378.     /*
  379.      * get list of appts for this week
  380.      */
  381.     get_week_appts();
  382.  
  383.     /*
  384.      * printout the text for each weekday
  385.      */
  386.     for (weekday=0; weekday<nr_weekdays; weekday++) {
  387.     fprintf(fp, "/day%d\n{\n", weekday);
  388.     do_ps_day(fp, noteflag, WEEK_FORMAT);
  389.     fprintf(fp, "} def\n");
  390.     }
  391.     fprintf(fp, "printweek\n");
  392.  
  393.     /*
  394.      * Write out PostScript postlog
  395.      */
  396.     fprintf(fp, "showpage\n");
  397.  
  398.     /*
  399.      * free up memory
  400.      */
  401.     free_week_appts();
  402. }
  403.  
  404. do_ps_header(fp)
  405. FILE *fp;
  406. {
  407.     char **ap;
  408.  
  409.     /*
  410.      * Write out PostScript header
  411.      */
  412.     for (ap = prolog; *ap; ap++)
  413.     fprintf(fp, "%s\n", *ap);
  414.  
  415. #ifdef LANGUAGE
  416.     /*
  417.      * Write out PS prolog for local languages
  418.      */
  419.     for (ap = p_lang_header; *ap; ap++)
  420.     fprintf(fp, "%s\n", *ap);
  421. #endif
  422.  
  423.     fprintf(fp, "%%EndProlog\n");
  424.  
  425.     /*
  426.      * Write out common PostScript
  427.      */
  428.     for (ap = pheader; *ap; ap++)
  429.     fprintf(fp, "%s\n", *ap);
  430.  
  431.     fprintf(fp, "/shour %d def\n", start_hour);
  432.     fprintf(fp, "/nslots %d def\n", n_slots);
  433.     fprintf(fp, "/ntslots %d def\n", n_tslots);
  434.     fprintf(fp, "/hour24 %d def\n", hour24);
  435.     fprintf(fp, "/nweekd %d def\n", nr_weekdays);
  436.     fprintf(fp, "/slotHeight %.2f def\n", (double)600/n_slots);
  437. }
  438.  
  439. /*
  440.  * printout text for appts and the continuation arrows
  441.  */
  442. do_ps_day(fp, noteflag, format)
  443. FILE *fp;
  444. int noteflag;
  445. int format;
  446. {
  447.     char      *p, *q;
  448.     int        i, offset, narrows;
  449.     int     slotno, xpos=105;
  450.     struct appt_entry    *aptr;
  451.     char strbuf[MAX_STRLEN+MAX_STRLEN/4];
  452.     int arrow_loc[MAX_SLOTS];
  453.     struct dayslot *slptr;
  454.  
  455.     for (slotno=0; slotno<n_slots; slotno++)
  456.     arrow_loc[slotno] = 0;
  457.  
  458.     for (slotno=0; slotno<n_slots; slotno++) {
  459.     /* any appts in this timeslot? */
  460.     slptr = (format==WEEK_FORMAT ? &week_boxes[weekday].weekslots[slotno] :
  461.         &slots[slotno]);
  462.     if (slptr->active) {
  463.         fprintf(fp, "  /xpos %d def\n", xpos);
  464.         if (slptr->count > slptr->active) {
  465.         /*
  466.          * there are arrows here from above. offset our start
  467.          * of text so they won't be on top of each other.
  468.          */
  469.         offset = 0;
  470.         while (arrow_loc[slotno] & 1<<offset)
  471.             offset++;
  472.         fprintf(fp, "  xpos 30 %d mul add /xpos exch def\n",
  473.             offset+1);
  474.         }
  475.         i = 0;
  476.         for (aptr=slptr->first; aptr; aptr=aptr->next) {
  477.         /* get printable string from each appt */
  478.         if (!deleted(aptr, slptr) &&
  479.             (!noteflag || ((aptr->flags & MARKED_NOTE) != MARKED_NOTE))) {
  480.             if (i) {
  481.             /* not the first time thru the loop */
  482.             /* move over, print a bar then next appt */
  483.             fprintf(fp, "  xpos %d apptbar\n", slotno);
  484.             fprintf(fp, "  xpos 5 add /xpos exch def\n");
  485.             }
  486.             /* cleanup the strings */
  487.             p = aptr->str;
  488.             q = strbuf;
  489.             while (*p) {
  490.             switch (*p) {
  491.                 /* ignore these */
  492.                 case '\b':
  493.                 case '\f':
  494.                 case '\n':
  495.                 case '\r':
  496.                 case '\t':
  497.                     break;
  498.                 /* escape these for PostScript */
  499.                 case '\\':
  500.                 case '(':
  501.                 case ')':
  502.                     *q++ = '\\';
  503.                     break;
  504.             }
  505.             *q++ = *p++;
  506.             }
  507.             *q = '\0';
  508.             /* print the string and any arrows */
  509.             fprintf(fp, "  (%s) xpos %d slotstr\n", strbuf, slotno);
  510.             if ((narrows = aptr->arrows) > 0) {
  511.             while (narrows)
  512.                 arrow_loc[slotno+narrows--] |= 1<<offset;
  513.             if (aptr->arrows > 1)
  514.                 fprintf(fp, "    xpos 20 add %d %d arrowshaft\n",
  515.                 slotno+1, slotno+aptr->arrows-1);
  516.             fprintf(fp, "    xpos 20 add %d arrowhead\n",
  517.                 slotno+aptr->arrows);
  518.             }
  519.             fprintf(fp, "    (%s) stringwidth pop xpos add 5 add /xpos exch def\n", strbuf);
  520.             i++;
  521.         }
  522.         }
  523.     }
  524.     }
  525. }
  526.  
  527. /* check to see if appt pointed to by ap has been deleted */
  528. int
  529. deleted(ap, slptr)
  530. struct appt_entry *ap;
  531. struct dayslot *slptr;
  532. {
  533.     struct appt_entry *a;
  534.  
  535.     if (ap->flags & DELETED)
  536.     return(1);
  537.  
  538.     if (Repeating(ap->flags))
  539.     /* run through the list to see if there are any deleted */
  540.     for (a=slptr->first; a; a=a->next)
  541.         if (a->flags & DELETED) {
  542.         /* now see if the current one matches */
  543.         if (!strcmp(a->str, ap->str))
  544.             return(1);
  545.         }
  546.  
  547.     return(0);
  548. }
  549. #endif /* RASTER_ONLY */
  550. #endif /* NO_PRINTER */
  551.