home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1876 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  18.4 KB

  1. From: rogers@sud509.ed.ray.com (Andrew Rogers)
  2. Newsgroups: alt.sources
  3. Subject: Calendar program for non-PostScript sites
  4. Message-ID: <2587@sud509.ed.ray.com>
  5. Date: 27 Sep 90 18:25:00 GMT
  6.  
  7.  
  8. I've gotten a few requests for this from people who do not have PostScript at
  9. their sites and (consequently) can't use Pcal.  This program generates a
  10. calendar which may be printed on any line printer using standard 132x66
  11. fan-fold paper.  Unfortunately, it lacks Pcal's most important capability -
  12. to import text from a date file - but it's useful nonetheless.  Have fun!
  13.  
  14. Andrew
  15.  
  16. -------------------------------- cut here --------------------------------
  17. /*
  18.  *    Calendar program - one month per page
  19.  *
  20.  *    Author: AW Rogers
  21.  *
  22.  *    Parameters:
  23.  *
  24.  *        calen        generate calendar for current month/year
  25.  *
  26.  *        calen yy    generate calendar for entire year yy
  27.  *
  28.  *        calen mm yy    generate calendar for month mm (1 = January),
  29.  *                    year yy (19yy if yy < 100)
  30.  *
  31.  *        calen mm yy n    as above, for n consecutive months
  32.  *
  33.  *    Options:
  34.  *
  35.  *        -b<N>        add N blank lines at top of each page
  36.  *
  37.  *        -f<FILE>    write output to file FILE (calen.lst if -f alone)
  38.  *
  39.  *        -l        left-justify dates within boxes (default)
  40.  *
  41.  *        -r        right-justify dates within boxes
  42.  *
  43.  *        -o<STR>        use characters in STR as overstrike sequence for
  44.  *                    printing large month/year (default: HIX)
  45.  *        
  46.  *        -t        print trailing dates (30, 31 in 23/30 and 24/31)
  47.  *                    in vacant box on first line
  48.  *
  49.  *    Output:
  50.  *
  51.  *        Full-page calendar for each of the specified months; written to
  52.  *        stdout unless -f option used.
  53.  *
  54.  */
  55.  
  56. #include <stdio.h>
  57. #include <ctype.h>
  58. #include <time.h>
  59. #include <string.h>
  60.  
  61. #define FALSE    0
  62. #define TRUE    1
  63.  
  64. #define JAN    1            /* significant months/years */
  65. #define FEB    2
  66. #define DEC    12
  67. #define MINYR    1753
  68. #define MAXYR    9999
  69.  
  70. #define SOLID    0            /* line styles (cf. box_line()) */
  71. #define OPEN    1
  72.  
  73. #define LEFT    0            /* date justification within boxes */
  74. #define RIGHT    1
  75. #define DEFAULT_JUST    LEFT
  76.  
  77. #define TOP        0        /* trailing date position */
  78. #define BOTTOM        1
  79. #define DEFAULT_TRAIL    BOTTOM
  80.  
  81. #define TOP_ROW        0        /* top and bottom rows of calendar */
  82. #define BOTTOM_ROW    5
  83.  
  84. #define OVERSTRIKE    "HIX"        /* overstrike sequence for heading */
  85. #define MAX_OVERSTR    3
  86.  
  87. #define OUTFILE        "calen.lst"    /* default output file if -f option used */
  88.  
  89. #define NUM_BLANKS    0        /* default blank lines after <FF> */
  90. #define NUM_MONTHS    1        /* default number of months */
  91.  
  92. #define MAXARGS        3        /* maximum non-flag command-line args */
  93.  
  94.  
  95. #ifdef VMS        
  96. #define EXIT_FAILURE    3
  97. #define END_PATH    ']'
  98. #else
  99. #define EXIT_FAILURE    1
  100. #define END_PATH    '/'
  101. #endif
  102.  
  103. #define is_leap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
  104.  
  105. typedef struct                /* information about a single month */
  106.     {
  107.     int     mm;
  108.     int        yy;
  109.     char    *mmname;
  110.     char    dates[6][7][3];
  111.     } month_rec;
  112.  
  113. typedef month_rec *p_month;        /* pointer to above structure */
  114.  
  115. /* globals for defaultable command-line parameters, and their defaults */
  116.  
  117. int just = DEFAULT_JUST;        /* justification of dates */
  118. int trail = DEFAULT_TRAIL;        /* format for 23/30, 24/31 */
  119. int nblank = NUM_BLANKS;        /* blank lines after <FF> */
  120. char *seq = OVERSTRIKE;            /* overstrike sequence for heading */
  121. int nmonths = NUM_MONTHS;        /* number of months to print */
  122.  
  123. char *fname = "";            /* output file name */
  124.  
  125. main(argc, argv)
  126.     int  argc;
  127.     char *argv[];
  128. {
  129. month_rec mRec[3];            /* space for main and small calendars */
  130. p_month prev = mRec, curr = mRec+1, next = mRec+2, temp;
  131.  
  132. /* Get and validate command-line parameters and flags */
  133.  
  134. get_params(argc, argv, curr);
  135.  
  136. /* Fill in calendars for previous and current month */
  137.  
  138. prev->mm = curr->mm == JAN ? DEC : curr->mm - 1;
  139. prev->yy = curr->mm == JAN ? curr-> yy - 1 : curr->yy;
  140.  
  141. fill_calendar(prev);
  142. fill_calendar(curr);
  143.  
  144. /*
  145.  * Main loop: print each month of the calendar (with small calendars for the
  146.  * previous and next months in the upper corners).  The current and next
  147.  * months' calendars can be reused as the previous and current calendars for
  148.  * the following month; only the 'next' calendar need be calculated each
  149.  * time through the loop.
  150.  */
  151.  
  152. while (nmonths-- > 0 && curr->yy <= MAXYR)
  153.     {
  154.     next->mm = curr->mm == DEC ? JAN : curr->mm + 1;
  155.     next->yy = curr->mm == DEC ? curr->yy + 1 : curr->yy;
  156.     fill_calendar(next);            /* fill in following month */
  157.     
  158.     print_calendar(prev, curr, next);
  159.     
  160.     temp = prev;                /* swap pointers to months */
  161.     prev = curr;
  162.     curr = next;
  163.     next = temp;
  164.     }
  165.  
  166. if (*fname)                    /* report output file name */
  167.     fprintf(stderr, "Output is in file %s\n", fname);
  168. }
  169.  
  170.  
  171. /*
  172.  * Get and validate command-line parameters and flags.  If month/year not
  173.  * specified on command line, generate calendar for current month/year.
  174.  * Exit program if month or year out of range; forgive illegal flags.
  175.  */
  176.  
  177. get_params(argc, argv, curr)
  178.     int  argc;        /* argument count, vector passed in from main() */
  179.     char *argv[];
  180.     p_month curr;    /* current month record (fill in month/year) */
  181. {
  182. int  badopt = FALSE;        /* flag set if bad option  */
  183. int  badpar = FALSE;        /* flag set if bad param   */
  184. int  nargs = 0;            /* count of non-flag args  */
  185. int  numargs[MAXARGS];        /* non-flag (numeric) args */
  186. char *parg;            /* generic argument ptr    */
  187. long tmp;            /* temp for system clock   */
  188. struct tm *p_tm;        /* ptr to date/time struct */
  189. char *progname, *p;        /* program name (argv[0))  */
  190. extern int atoi();
  191.  
  192. /* Isolate root program name (for use in error messages) */
  193.  
  194. progname = **argv ? *argv : "calen";
  195. if ((p = strrchr(progname, END_PATH)) != NULL)
  196.     progname = ++p;
  197. if ((p = strchr(progname, '.')) != NULL)
  198.     *p = '\0';
  199.  
  200. /* Walk command-line argument list */
  201.  
  202. while (--argc)
  203.     {
  204.     parg = *++argv;
  205.     if (*parg == '-')
  206.         {
  207.         switch (*++parg)
  208.             {
  209.         case 'b':
  210.             nblank = atoi(++parg);
  211.             break;
  212.     case 'f':
  213.         fname = *++parg ? parg : OUTFILE;
  214.         if (freopen(fname, "w", stdout) == (FILE *) NULL)
  215.         {
  216.         fprintf(stderr, "%s: error opening output file %s\n",
  217.             progname, fname);
  218.         exit (EXIT_FAILURE);
  219.         }
  220.             break;
  221.     case 'l':
  222.             just = LEFT;
  223.             break;
  224.         case 'r':
  225.             just = RIGHT;
  226.             break;
  227.         case 'o':
  228.         if (*++parg)
  229.             seq = parg;
  230.         break;
  231.     case 't':
  232.         trail = TOP;
  233.         break;
  234.     default:
  235.         fprintf(stderr, "%s: invalid flag: %s\n", progname, *argv);
  236.         badopt = TRUE;
  237.         break;
  238.         }
  239.     }
  240.     else            /* non-flag argument - add to list */
  241.         {
  242.         if (nargs < MAXARGS)
  243.             numargs[nargs++] = atoi(parg);
  244.     }
  245.     }
  246.  
  247. /* Get and validate non-flag (numeric) parameters */
  248.  
  249. switch (nargs)
  250.     {
  251.  
  252. case 0:        /* no arguments - print current month/year */
  253.     time(&tmp);
  254.     p_tm = localtime(&tmp);
  255.     curr->mm = p_tm->tm_mon + 1;
  256.     curr->yy = p_tm->tm_year;
  257.     break;            
  258.  
  259. case 1:        /* one argument - print entire year */
  260.     curr->mm = JAN;
  261.     curr->yy = numargs[0];
  262.     nmonths = 12;
  263.     break;
  264.  
  265. default:    /* two or three arguments - print one or more months */
  266.     curr->mm = numargs[0];
  267.     curr->yy = numargs[1];
  268.     nmonths = nargs > 2 ? numargs[2] : NUM_MONTHS;
  269.     break;
  270.     }
  271.  
  272. if (curr->yy > 0 && curr->yy < 100)    /* treat nn as 19nn */
  273.     curr->yy += 1900;
  274.     
  275. if (nmonths < 1)            /* ensure at least one month */
  276.     nmonths = 1;
  277.     
  278. if (curr->mm < JAN || curr->mm > DEC)    /* check range of month and year */
  279.     {
  280.     fprintf(stderr, "%s: month %d not in range %d .. %d\n", progname, 
  281.         curr->mm, JAN, DEC);
  282.     badpar = TRUE;
  283.     }
  284.     
  285. if (curr->yy < MINYR || curr->yy > MAXYR)
  286.     {
  287.     fprintf(stderr, "%s: year %d not in range %d .. %d\n", progname, 
  288.         curr->yy, MINYR, MAXYR);
  289.     badpar = TRUE;
  290.     }
  291.        
  292. if (badpar || badopt)
  293.     usage(progname);
  294.  
  295. if (badpar)
  296.     exit(EXIT_FAILURE);
  297. }
  298.  
  299. /*
  300.  *    Print message explaining correct usage of the command-line
  301.  *    arguments and flags
  302.  */
  303.  
  304. usage(prog)
  305.     char *prog;
  306. {
  307. fprintf(stderr, "\nUsage:\n\n");
  308. fprintf(stderr, "\t%s [-bN] [-fFILE] [-l | -r] [-oSTR] [-t]\n", prog);
  309. fprintf(stderr, "\t\t[ [ [mm] yy ] | [mm yy n] ]\n\n");
  310. fprintf(stderr, "\nValid flags are:\n\n");
  311. fprintf(stderr, "\t-bN\t\tadd N blank lines after each <FF> (default: %d)\n\n",
  312.     NUM_BLANKS);
  313. fprintf(stderr, "\t-fFILE\t\twrite output to file FILE (%s if -f alone)\n\n",
  314.     OUTFILE);
  315. fprintf(stderr, "\t-l\t\tleft-justify dates within boxes");
  316. fprintf(stderr, "%s\n\n", DEFAULT_JUST == LEFT ? " (default)" : "");
  317. fprintf(stderr, "\t-r\t\tright-justify dates within boxes");
  318. fprintf(stderr, "%s\n\n", DEFAULT_JUST == RIGHT ? " (default)" : "");
  319. fprintf(stderr, "\t-oSTR\t\tuse characters in STR as overstrike sequence for\n");
  320. fprintf(stderr, "\t\t\tprinting large month/year (default: %s)\n\n",
  321.     OVERSTRIKE);
  322. fprintf(stderr, "\t-t\t\tmove trailing 30 and 31 to vacant box on top line\n");
  323. fprintf(stderr, "\n");
  324. fprintf(stderr, "\t%s [opts]\t\tgenerate calendar for current month/year\n",
  325.     prog);
  326. fprintf(stderr, "\n");
  327. fprintf(stderr, "\t%s [opts] yy\t\tgenerate calendar for entire year yy\n",
  328.     prog);
  329. fprintf(stderr, "\n");
  330. fprintf(stderr, "\t%s [opts] mm yy\tgenerate calendar for month mm\n", prog);
  331. fprintf(stderr, "\t\t\t\t(Jan = 1), year yy (19yy if yy < 100)\n");
  332. fprintf(stderr, "\n");
  333. fprintf(stderr, "\t%s [opts] mm yy n\tas above, for n consecutive months\n",
  334.     prog);
  335. fprintf(stderr, "\n");
  336. }
  337.  
  338.  
  339. /*
  340.  *    Print the calendar for the current month, generating small calendars
  341.  *    for the previous and following months in the upper corners and the
  342.  *    month/year (in 5x9 dot-matrix characters) centered at the top.
  343.  */
  344.  
  345. print_calendar(prev, curr, next)
  346.     p_month prev;        /* previous month (upper-left corner)    */
  347.     p_month curr;        /* current month (main calendar)    */
  348.     p_month next;        /* following month (upper-right corner)    */
  349. {
  350. static char *wkday[] =
  351.     { 
  352.     " Sunday  ", " Monday  ", " Tuesday ", "Wednesday", "Thursday",
  353.     " Friday  ", "Saturday "
  354.     };
  355.           
  356. int nchars, line, week, day;
  357. char *blanks = "                     ";        /* 21 blanks for centering */
  358. char *padding;                    /* pointer into 'blanks'   */
  359. char month_and_year[20];            /* work area           */
  360. char *ovr;                    /* overstrike sequence       */
  361.  
  362. /* Set up month and year heading and appropriate padding to center it */
  363.  
  364. nchars = strlen(curr->mmname);
  365. padding = blanks + (3 * (nchars - 3));
  366. sprintf(month_and_year, "%s%5d", curr->mmname, curr->yy);
  367.  
  368. /* Print top-of-form and leading blank lines, if any */
  369.  
  370. printf("\f\n");
  371. for (line = 0; line < nblank; line++)
  372.     printf("\n");
  373.  
  374. /* Print month and year in large letters, with small calendars on each side */
  375.     
  376. for (line = 0; line < 9; line++)
  377.     {
  378.     for (ovr = seq; ovr < seq + MAX_OVERSTR - 1 && *(ovr+1); ovr++)
  379.         {
  380.         printf("%20s%s", " ", padding);        /* overstruck lines first */
  381.         header_line(month_and_year, line, *ovr);
  382.         printf(" %s", padding);
  383.         printf("\r");
  384.     }  
  385.     small_cal_line(prev, line);        /* calendars and non-overstruck line */
  386.     printf("%s", padding);
  387.     header_line(month_and_year, line, *ovr);
  388.     printf(" %s", padding);
  389.     small_cal_line(next, line);
  390.     printf("\n");
  391.     }
  392.  
  393. printf("\n");                /* print the weekday names */
  394. box_line(1, SOLID);
  395. box_line(1, OPEN);
  396. printf("  ");
  397. for (day = 0; day < 7; day++)
  398.     printf("|%13.9s    ", wkday[day]);
  399. printf("|\n");
  400. box_line(1, OPEN);
  401.  
  402. for (week = TOP_ROW; week < BOTTOM_ROW - 1; week++)    /* first four weeks */
  403.     {
  404.     box_line(1, SOLID);
  405.     date_line(curr, week, just);
  406.     box_line(7, OPEN);
  407.     }
  408.  
  409. box_line(1, SOLID);            /* fifth week */
  410. date_line(curr, BOTTOM_ROW - 1, just);
  411. box_line(2, OPEN);
  412.  
  413. divider_line(curr->dates[BOTTOM_ROW]);    /* divider for 23/30 and/or 24/31 */
  414. box_line(3, OPEN);
  415.  
  416. date_line(curr, BOTTOM_ROW, !just);    /* sixth week (trailing 31 or 30 31) */
  417. box_line(1, SOLID);
  418.  
  419. }
  420.  
  421.  
  422.  
  423. /*
  424.  *    Fill in the month name and date fields of a calendar record according
  425.  *    to its month and year fields.
  426.  */
  427.  
  428. fill_calendar(month)
  429.     p_month month;        /* record to be filled in */
  430. {
  431. typedef struct            /* local info about months of year */
  432.     {
  433.     char *name;            /* month name                    */
  434.     int offset[2];        /* offset of m/1 from 1/1 (non-leap, leap) */
  435.     int length[2];        /* length of month (non-leap, leap)        */
  436.     } month_info;
  437.  
  438. static month_info info[12] = {
  439.     { "January",   {0, 0}, {31, 31} }, { "February",  {3, 3}, {28, 29} },
  440.     { "March",     {3, 4}, {31, 31} }, { "April",     {6, 0}, {30, 30} },
  441.     { "May",       {1, 2}, {31, 31} }, { "June",      {4, 5}, {30, 30} },
  442.     { "July",      {6, 0}, {31, 31} }, { "August",    {2, 3}, {31, 31} },
  443.     { "September", {5, 6}, {30, 30} }, { "October",   {0, 1}, {31, 31} },
  444.     { "November",  {3, 4}, {30, 30} }, { "December",  {5, 6}, {31, 31} }
  445.     } ;
  446.  
  447. int i, first, last, date = 0, y = month->yy, m = month->mm - 1;
  448. int leap = is_leap(y);
  449.  
  450. /* Determine when month starts and ends */
  451.  
  452. first = (y + (y-1)/4 - (y-1)/100 + (y-1)/400 + info[m].offset[leap]) % 7; 
  453. last = first + info[m].length[leap] - 1;
  454.  
  455. for (i = 0; i < 42; i++)        /* fill in 7x6 matrix of dates */
  456.     if (i < first || i > last)
  457.     month->dates[i/7][i%7][0] = '\0';
  458.     else
  459.     sprintf(month->dates[i/7][i%7], "%2d", ++date);
  460.  
  461. if (trail == TOP)    /* move trailing 30/31 to top row if requested */
  462.     for (i = 0; month->dates[BOTTOM_ROW][i][0]; i++)
  463.     {
  464.     strcpy(month->dates[TOP_ROW][i], month->dates[BOTTOM_ROW][i]);
  465.     month->dates[BOTTOM_ROW][i][0] = '\0';
  466.     }
  467.  
  468. month->mmname = info[m].name;        /* fill in month name */
  469. }
  470.  
  471.  
  472. /*
  473.  *    Print one line of a small calendar (for upper left and right corners);
  474.  *    always prints exactly 20 characters.
  475.  */
  476.  
  477. small_cal_line(month, line)
  478.     p_month month;        /* information for month to print */
  479.     int line;            /* line to print (0-8; see below) */
  480. {
  481. int day;
  482. char tmp1[10], tmp2[30];
  483.  
  484. switch (line)
  485.     {
  486. case 0:                /* month and year (centered) */
  487.     strcpy(tmp1, "      ");
  488.     tmp1[(15 - strlen(month->mmname)) / 2] = '\0';
  489.     sprintf(tmp2, "%s%s %4d      ", tmp1, month->mmname, month->yy);
  490.     printf("%-20.20s", tmp2);
  491.     break;
  492. case 1:                /* blank line */
  493.     printf("%20s", " ");
  494.     break;
  495. case 2:                /* weekdays */
  496.     printf("Su Mo Tu We Th Fr Sa");
  497.     break;
  498. default:            /* line of calendar (3 = first) */
  499.     for (day = 0; day < 6; day++)
  500.     printf("%2s ", month->dates[line-3][day]);
  501.     printf("%2s", month->dates[line-3][day]);
  502.     break;
  503.     }
  504. }
  505.  
  506.  
  507. /*
  508.  *    Print n calendar box lines in selected style
  509.  */
  510.  
  511. box_line(n, style)
  512.     int n;            /* number of lines to print */
  513.     int style;            /* SOLID or OPEN        */
  514. {
  515. int day;
  516. char *fmt = style == SOLID ? "+-----------------" :
  517.                  "|                 " ;
  518.  
  519. for (; n > 0; n--)
  520.     {
  521.     printf("  ");
  522.     for (day = 0; day < 7; day++)
  523.     printf(fmt);
  524.     printf("%c\n", *fmt);
  525.     }
  526. }
  527.  
  528.  
  529. /*
  530.  *    Print one week of dates, left- or right-justified
  531.  */
  532.  
  533. date_line(month, week, just)
  534.     p_month month;        /* pointer to month data      */
  535.     int week;            /* week to print (0 = first)      */
  536.     int just;            /* justification (LEFT or RIGHT) */
  537. {
  538. int day;
  539. char *fmt = just == LEFT ? "| %-16s" : "|%16s " ;
  540.  
  541. printf("  ");
  542. for (day = 0; day < 7; day++)
  543.     printf(fmt, month->dates[week][day]);
  544. printf("|\n");
  545. }
  546.  
  547.  
  548. /*
  549.  *    Print the divider separating 23/30 and/or 24/31 as needed
  550.  */
  551.  
  552. divider_line(last_row)
  553.     char last_row[7][3];    /* row containing any trailing 30 and/or 31 */
  554. {
  555. int day;
  556.  
  557. printf("  ");
  558. for (day = 0; day < 7; day++)
  559.     printf(last_row[day][0] ? "|_________________" : "|                 ");
  560. printf("|\n");
  561. }
  562.  
  563.  
  564. /*
  565.  *    Print least-significant 6 bits of n (0 = ' '; 1 = other char)
  566.  */
  567.  
  568. decode(n, c)
  569.     int n;        /* number to decode (row of 5x9 character) */
  570.     char c;        /* character to print for each 1 bit       */
  571. {
  572. int msk = 1 << 5;
  573.  
  574. for (; msk; msk >>= 1)
  575.     printf("%c", n & msk ? c : ' ');
  576. }
  577.  
  578.  
  579. /*
  580.  *    Print one line of string in large (5x9) characters
  581.  */
  582.  
  583. header_line(str, line, c)
  584.     char *str;        /* string to print     */
  585.     int line;        /* line (0 - 8)        */
  586.     char c;        /* output character    */
  587. {
  588.  
  589. /* 5x7 representations of A-Z, 0-9; 5x9 representation of a-z */
  590.  
  591. static char uppers[26][7] = {
  592.     {14, 17, 17, 31, 17, 17, 17},  {30, 17, 17, 30, 17, 17, 30},  /* AB */
  593.     {14, 17, 16, 16, 16, 17, 14},  {30, 17, 17, 17, 17, 17, 30},  /* CD */
  594.     {31, 16, 16, 30, 16, 16, 31},  {31, 16, 16, 30, 16, 16, 16},  /* EF */
  595.     {14, 17, 16, 23, 17, 17, 14},  {17, 17, 17, 31, 17, 17, 17},  /* GH */
  596.     {31,  4,  4,  4,  4,  4, 31},  { 1,  1,  1,  1,  1, 17, 14},  /* IJ */
  597.     {17, 18, 20, 24, 20, 18, 17},  {16, 16, 16, 16, 16, 16, 31},  /* KL */
  598.     {17, 27, 21, 21, 17, 17, 17},  {17, 17, 25, 21, 19, 17, 17},  /* MN */
  599.     {14, 17, 17, 17, 17, 17, 14},  {30, 17, 17, 30, 16, 16, 16},  /* OP */
  600.     {14, 17, 17, 17, 21, 18, 13},  {30, 17, 17, 30, 20, 18, 17},  /* QR */
  601.     {14, 17, 16, 14,  1, 17, 14},  {31,  4,  4,  4,  4,  4,  4},  /* ST */
  602.     {17, 17, 17, 17, 17, 17, 14},  {17, 17, 17, 17, 17, 10,  4},  /* UV */
  603.     {17, 17, 17, 21, 21, 21, 10},  {17, 17, 10,  4, 10, 17, 17},  /* WX */
  604.     {17, 17, 17, 14,  4,  4,  4},  {31,  1,  2,  4,  8, 16, 31}   /* YZ */
  605.     };
  606.  
  607. static char lowers[26][9] = {
  608.     { 0,  0, 14,  1, 15, 17, 15,  0,  0},  {16, 16, 30, 17, 17, 17, 30,  0,  0},  /* ab */
  609.     { 0,  0, 15, 16, 16, 16, 15,  0,  0},  { 1,  1, 15, 17, 17, 17, 15,  0,  0},  /* cd */
  610.     { 0,  0, 14, 17, 31, 16, 14,  0,  0},  { 6,  9, 28,  8,  8,  8,  8,  0,  0},  /* ef */
  611.     { 0,  0, 14, 17, 17, 17, 15,  1, 14},  {16, 16, 30, 17, 17, 17, 17,  0,  0},  /* gh */
  612.     { 4,  0, 12,  4,  4,  4, 31,  0,  0},  { 1,  0,  3,  1,  1,  1,  1, 17, 14},  /* ij */
  613.     {16, 16, 17, 18, 28, 18, 17,  0,  0},  {12,  4,  4,  4,  4,  4, 31,  0,  0},  /* kl */
  614.     { 0,  0, 30, 21, 21, 21, 21,  0,  0},  { 0,  0, 30, 17, 17, 17, 17,  0,  0},  /* mn */
  615.     { 0,  0, 14, 17, 17, 17, 14,  0,  0},  { 0,  0, 30, 17, 17, 17, 30, 16, 16},  /* op */
  616.     { 0,  0, 15, 17, 17, 17, 15,  1,  1},  { 0,  0, 30, 17, 16, 16, 16,  0,  0},  /* qr */
  617.     { 0,  0, 15, 16, 14,  1, 30,  0,  0},  { 8,  8, 30,  8,  8,  9,  6,  0,  0},  /* st */
  618.     { 0,  0, 17, 17, 17, 17, 15,  0,  0},  { 0,  0, 17, 17, 17, 10,  4,  0,  0},  /* uv */
  619.     { 0,  0, 17, 21, 21, 21, 10,  0,  0},  { 0,  0, 17, 10,  4, 10, 17,  0,  0},  /* wx */
  620.     { 0,  0, 17, 17, 17, 17, 15,  1, 14},  { 0,  0, 31,  2,  4,  8, 31,  0,  0},  /* yz */
  621.     };
  622.  
  623. static char digits[10][7] = {
  624.     {14, 17, 17, 17, 17, 17, 14},  { 2,  6, 10,  2,  2,  2, 31},  /* 01 */
  625.     {14, 17,  2,  4,  8, 16, 31},  {14, 17,  1, 14,  1, 17, 14},  /* 23 */
  626.     { 2,  6, 10, 31,  2,  2,  2},  {31, 16, 16, 30,  1, 17, 14},  /* 45 */
  627.     {14, 17, 16, 30, 17, 17, 14},  {31,  1,  2,  4,  8, 16, 16},  /* 67 */
  628.     {14, 17, 17, 14, 17, 17, 14},  {14, 17, 17, 15,  1, 17, 14}   /* 89 */
  629.     };
  630.  
  631. char ch;
  632.  
  633. /* convert each character of str to dot-matrix representation for line */
  634.  
  635. for ( ; ch = *str; str++)
  636.     {
  637.     if (isupper(ch))
  638.     decode(line < 7 ? uppers[ch-'A'][line] : 0, c);
  639.     else if (islower(ch))
  640.     decode(lowers[ch-'a'][line], c);
  641.     else if (isdigit(ch))
  642.     decode(line < 7 ? digits[ch-'0'][line] : 0, c);
  643.     else
  644.     decode(0, c);
  645.     }
  646.  
  647. }
  648.