daily pastebin goal
77%
SHARE
TWEET

Untitled

a guest Jun 13th, 2018 50 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* Set the three #defines in the section below as appropriate. */
  2. /*--------------------------------------------------------------------------*/
  3. #define MSDOS 1     /* un-define if not MSDOS, use OS2 or UNIX instead.     */
  4.  
  5. #define USE_COLOR   /* un-define if not MSDOS nor OS/2, or not using colors.*/
  6.                     /* USE_COLOR assumes that either OS2 or MSDOS is used.  */
  7.                     /* For colors in unix, #define USE_ANSI instead.        */
  8.  
  9. #define USE_ANSI    /* Will work with DOS, OS/2, or Unix.  This is #undef'd */
  10.                     /* automatically if used with USE_COLOR for MSDOS or    */
  11.                     /* OS/2, because USE_COLOR cannot coexist with USE_ANSI.*/
  12. /*--------------------------------------------------------------------------*/
  13.  
  14. #ifdef OS2
  15. #undef MSDOS
  16. #undef UNIX
  17. #endif
  18.  
  19. /* Some self-defining unix variables */
  20. #if defined(__unix__) || defined(UNIX)
  21. #ifdef MSDOS
  22. #undef MSDOS
  23. #endif /* MSDOS */
  24. #ifdef USE_COLOR
  25. #undef USE_COLOR
  26. #endif /* USE_COLOR */
  27. #ifndef UNIX
  28. #define UNIX 1        /* Delete if not running on UNIX */
  29. #endif
  30. #endif /* __unix__ */
  31.  
  32. /* correct non-coexisting definitions */
  33. #if defined(OS2) || defined(MSDOS)
  34. #if defined(USE_COLOR) && defined(USE_ANSI)
  35. #undef USE_ANSI
  36. #endif
  37. #endif
  38.  
  39. /*===========================================================================
  40.  * cal.c - print calendar for one month or one year
  41.  * compatible with unix cal command
  42.  * version 3.5
  43.  *
  44.  * cal [-options] [[month] year]    (numerical month argument)
  45.  * or
  46.  * cal [-options] [month] [year]    (verbal month argument)
  47.  *
  48.  * cal (C) 1992 by Unicorn Research Corporation
  49.  * Inspired by the unix `cal' command for an Amiga, ported by Gary L. Brant.
  50.  * Compile with MSDOS defined (above) to activate the MSDOS features.
  51.  *
  52.  * Borland users: PLEASE try not to Borland-ize this code.  Use
  53.  * #ifdef __TURBOC__ on any Borland-specific sections you create.
  54.  *===========================================================================
  55.  
  56. 29 March 1993, Darrel Hankerson hankedr@mail.auburn.edu
  57.   Modifications and enhancements for OS/2 (and others).
  58.   New command line options:
  59.     [-nodata] [-data-file=data-file]
  60.   and color options (if compiling with -DUSE_COLOR for OS/2 or MSDOS)
  61.     [-nocolor] [-color-file=color-file]
  62.  
  63. 05 June 1993, Don Retzlaff donr@gab.unt.edu, University of North Texas
  64.   Modifications and enhancements (re-done by Alex Matulich for
  65.   ANSI compatibility):
  66.   Variable-number of events for month display (previously only allowed 8)
  67.   New command line option:
  68.     [--maxappts=num]
  69.   Allow multiple --datafile= command line parameters
  70.  
  71. 31 August 1995, Chris Bagwell cbagwell@aud.alcatel.com
  72.   Added ANSI color support and a few updates for compiling easier under
  73.   Linux and SunOS.
  74.   Added -8bit option for enabling 8-bit characters under unix.
  75.  
  76. 11 January 1996, Dan Fandrich dan@fch.wimsey.bc.ca
  77.   Added `reminder(1)'-style date file.
  78.   Extracted some code into functions for readability.
  79.  
  80. BASIC DATA STRUCTURE:                                          specialdays()
  81.                                                                pointers:
  82.  char *buf ==>  line[0] -> [......LineWid (default 80).......] lln[2]
  83.                 line[1] -> [.................................] lln[3]
  84.                 line[2] -> [.................................] lln[4]
  85.                       ...  [.................................] ...
  86.        line[numappts-3] -> [.................................] lln[numappts-1]
  87.         str (work area) -> [.................................]
  88.             spcldesc[0] -> [....DAY_DESC (56).....]            lln[0]
  89.             spcldesc[1] -> [....DAY_DESC (56).....]            lln[1]
  90.  
  91.            line_attr[0] -> [........LineWid (80).............]
  92.            line_attr[1] -> [.................................] allocated
  93.            line_attr[2] -> [.................................] only if
  94.                       ...  [.................................] colors
  95.   line_attr[numappts-3] -> [.................................] are used
  96.                mon_attr -> [.................................]
  97.                 wk_attr -> [.................................]
  98.                day_attr -> [......YEARWID (72)...........]
  99.            spclday_attr -> [....DAY_DESC (56).....]
  100. */
  101.  
  102. #define MAXFILES 8   /* maximum number of data file paths */
  103. #define MAXAPPTS 50  /* maximum number of appointment description lines */
  104.  
  105. #ifdef USE_COLOR
  106. #ifdef OS2
  107. #define INCL_SUB
  108. #include <os2.h>
  109. #else
  110. #include <dos.h> /* for int86() */
  111. #endif /* OS2 */
  112. #endif /* USE_COLOR */
  113.  
  114. #include <stdio.h>
  115. #ifndef UNIX
  116. #include <io.h>  /* for isatty() */
  117. #else
  118. #include <unistd.h>  /* sun4/linux place for isatty() */
  119. #endif
  120. #include <stdlib.h>
  121. #include <time.h>
  122. #include <ctype.h>
  123. #include <string.h>
  124. #include <sys/types.h>
  125.  
  126. #ifndef max
  127. #define max(a,b) (((a)>(b))?(a):(b))
  128. #endif /* max */
  129.  
  130. /* Note: Other unix systems may require this next re-define to work. */
  131. /* I believe that SCO is one such system.  Please send in any fixes  */
  132. /* needed to get your system running.                                */
  133. #ifdef __linux__          /* Make linux compatible with stricmp() */
  134. #define stricmp(a,b) strcasecmp(a,b) /* case-insensitive string comparison */
  135. #endif
  136.  
  137. #ifdef __ZTC__            /* make Zortech compatible with stricmp() */
  138. #define stricmp(a,b) strcmpl(a,b) /* case-insensitive string comparison */
  139. #endif /* __ZTC__ */
  140.  
  141. #ifdef MSDOS
  142. #ifndef MK_FP
  143. #define MK_FP(seg,off) (void far *)(((unsigned long)(seg)<<16)|(unsigned)(off))
  144. #endif /* MK_FP */
  145. #ifndef USE_ANSI
  146. union REGS reg;
  147. char far *video, far *tmpvideo;
  148. #endif
  149. #endif /* MSDOS */
  150.  
  151. #define FUDGE1  1               /* needed to make day of week come out right */
  152. #define FUDGE2  6               /* for old style (Julian) calendar           */
  153. #define MONWID  24              /* width of month                            */
  154. #define YEARWID (3*MONWID-2)    /* width of yearly calendar                  */
  155. #define DAY_DESC  (LineWid-MONWID)  /* width of special day descriptions     */
  156.  
  157. #if defined(USE_COLOR)  || defined(USE_ANSI)    /* define display attribute */
  158. #define FG_BLACK     0x00                       /* possibilities. */
  159. #define FG_BLUE      0x01
  160. #define FG_GREEN     0x02
  161. #define FG_CYAN      0x03
  162. #define FG_RED       0x04
  163. #define FG_VIOLET    0x05
  164. #define FG_ORANGE    0x06
  165. #define FG_LTGRAY    0x07
  166. #define FG_DKGRAY    0x08
  167. #define FG_BRTBLUE   0x09
  168. #define FG_BRTGREEN  0x0a
  169. #define FG_BRTCYAN   0x0b
  170. #define FG_BRTRED    0x0c
  171. #define FG_BRTVIOLET 0x0d
  172. #define FG_YELLOW    0x0e
  173. #define FG_WHITE     0x0f
  174. #define FG_FLASH     0x80
  175. #define BG_BLACK     0x00
  176. #define BG_BLUE      0x10
  177. #define BG_GREEN     0x20
  178. #define BG_CYAN      0x30
  179. #define BG_RED       0x40
  180. #define BG_VIOLET    0x50
  181. #define BG_ORANGE    0x60
  182. #define BG_WHITE     0x70
  183.  
  184. unsigned
  185. char dfmon_attr   = FG_BLACK|BG_GREEN,   /* video attribute for month name */
  186.      dfwk_attr    = FG_BLUE|BG_CYAN,     /* attribute for weekday header   */
  187.      dfdy_attr    = FG_BLACK|BG_WHITE,   /* attribute for days             */
  188.      dfsun_attr   = FG_VIOLET|BG_WHITE,  /* attribute for sundays          */
  189.      dftoday_attr = FG_YELLOW|BG_BLUE,   /* attribute for current day      */
  190.      dfbk_attr    = FG_LTGRAY|BG_BLACK,  /* year calendar background       */
  191.      dfspday_attr = FG_BRTCYAN|BG_BLACK, /* special day description attr.  */
  192.      dfspdfl_attr = FG_BRTRED|FG_FLASH,  /* special day flasher            */
  193.      dftoday_attr2;                      /* this must be initialized later */
  194.  
  195. char *mon_attr, *wk_attr, *day_attr, *spclday_attr, *line_attr[MAXAPPTS-2];
  196.  
  197. int crt;
  198. int eightbit;
  199. #ifndef UNIX
  200. char *color_file = "cal.col";
  201. #else
  202. char *color_file = "calcol";
  203. #endif /* UNIX */
  204. #endif /* USE_COLOR or USE_ANSI */
  205.  
  206. /* LineWid may change depending on terminal (MSDOS only).             */
  207. /* This variable determines memory allocation size and display width. */
  208. short LineWid = 80;                /* set to 80 for non-MSDOS systems */
  209.  
  210. #ifndef UNIX
  211. char *data_file = "cal.dat";
  212. #else
  213. char *data_file = "caldat";
  214. #endif
  215.  
  216. #define REMINDER_FILE "dates"
  217.  
  218. short days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  219.     mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
  220.     multi = 0, thisday, thismonth, thisyear, discard_old = 0, prog_pause = 0,
  221.     europe = 0, numfiles = 0,
  222.     numappts = 24;  /* default maximum number of appointments to display */
  223.  
  224. char *months[] = {
  225.      "January ", "February ", "March ", "April ", "May ", "June ", "July ",
  226.      "August " , "September ", "October ", "November ", "December " },
  227.      monthline[] = "         ---                     ---                     ---          ",
  228.      *monthpos[] = { monthline+9, monthline+33, monthline+57 },
  229.      USdays[] =     " Su Mo Tu We Th Fr Sa ",
  230.      Europedays[] = " Mo Tu We Th Fr Sa Su ",
  231.      *dayline = USdays,
  232.      *spcldesc[2],
  233.      *filename[MAXFILES],
  234.      *homedir,                  /* home directory from argv[0] or enviornment*/
  235.      *line[MAXAPPTS-2],         /* line buffer for body of calendar          */
  236.      *buf = NULL,       /* workspace memory into which pointers are assigned */
  237.      *str;              /* temporary string workspace (LineWid characters)   */
  238.  
  239. void  addfilename(char *);
  240. void  clearfilenames(void);
  241. void  printmonth (short, short);
  242. short putd(register short);
  243. void  fixtab(register short);
  244. short weekday(register short, register short);
  245. void  putattr(char *, register short);
  246. void  setcolor(char);
  247. void  ansiputs(char *, char *);
  248. short specialdays(short, short);
  249. short reminderdays(short, short);
  250. FILE *efopen(const char *, const char *);
  251. void  usage(void);
  252.  
  253. /* commandline argument list */
  254. static struct arglist {
  255.     char *opt;         /* full argument string */
  256.     short needsvalue;  /* 1=argument needs a value, 0=stand-alone */
  257. } opt[] = {
  258.     { "nodata",     0 },
  259.     { "data-file",  1 },
  260.     { "future",     0 },
  261.     { "today",      0 },
  262.     { "europe",     0 },
  263.     { "maxappts",   1 },
  264.     { "pause",      0 },
  265. #if defined(USE_COLOR) || defined(USE_ANSI)
  266.     { "nocolor",    0 },
  267.     { "color-file", 1 },
  268. #ifdef UNIX
  269.     { "8bit",       0 },
  270. #endif
  271. #endif
  272.     { NULL,         0 }
  273. };
  274.  
  275. /*===========================================================================
  276.  * GETARG
  277.  * Return the index of the argument in the option array.  val is set if the
  278.  * argument needs a value.  The passed arg to test does not have to be
  279.  * exactly like one of the arguments in o; it just has to match one of them
  280.  * enough to be uniquely identified.  Any arg that is passed here should
  281.  * begin with a '-' (or also a '/' if compiling for MSDOS or OS/2).
  282.  *=========================================================================*/
  283. int getarg(struct arglist *o, char *arg, char **val)
  284. {
  285.     int len = -1, i = -1, found = -1;
  286.     *val = NULL;
  287.  
  288.     while (*arg == '-'
  289.            #if (defined(MSDOS) || defined(OS2))
  290.            || *arg == '/'
  291.            #endif
  292.         ) ++arg;
  293.     while (arg[++len]) {
  294.         arg[len] = tolower(arg[len]);
  295.         if (arg[len] == '=') {
  296.             arg[len] = '\0';
  297.             *val = &arg[len+1];
  298.             break;
  299.         }
  300.     }
  301.     while (o[++i].opt) {
  302.         if (!memcmp(o[i].opt, arg, len)) {
  303.             if (found >= 0) return -1;
  304.             found = i;
  305.         }
  306.     }
  307.     if (found < 0) return -1;
  308.     if (o[found].needsvalue && !(*val)) return -1;
  309.     return found;
  310. }
  311.  
  312. /*===========================================================================
  313.  * setopt
  314.  * This function will set a global option based on the value passed in.
  315.  * The value passed in must be a valid index into the options array.
  316.  *=========================================================================*/
  317. void setopt(int c, char *optarg)
  318. {
  319.     switch (c) {
  320.     case 0:
  321.         data_file = NULL; break;
  322.     case 1:
  323.         addfilename(optarg);
  324.         break;
  325.     case 2:
  326.         discard_old = 1; break;   /* show future dates only */
  327.     case 3:
  328.         discard_old = 2; break;   /* show today's dates only */
  329.     case 4:
  330.         dayline = Europedays;  europe = 1;  break;
  331.     case 5:
  332.         numappts = atoi(optarg); break;
  333.     case 6:
  334.         prog_pause = 1; break;
  335. #if defined(USE_COLOR) || defined(USE_ANSI)
  336.     case 7:
  337.         crt = 0; break;
  338.     case 8:
  339.         color_file = optarg; break;
  340. #ifdef UNIX
  341.     case 9:
  342.         eightbit = 1; break;
  343. #endif
  344. #endif /* USE_COLOR || USE_ANSI */
  345.     }
  346. }
  347.  
  348. /*===========================================================================
  349.  * MAIN
  350.  * Process command line, allocate and initialize, etc.
  351.  *=========================================================================*/
  352. int main(int argc, char *argv[])
  353. {
  354.     short       bufsiz, i, m, y;
  355.     time_t      t;
  356.     struct tm  *lt;
  357.     int         c;
  358.     char       *optarg;
  359.     char       *calopt, *s;
  360.     int         status=0;
  361.  
  362. #if defined(USE_COLOR) || defined(USE_ANSI)
  363.     FILE *colorfile;
  364.     short fg[8], bg[8];
  365.     crt = isatty(fileno(stdout));  /* check if stdout is being redirected */
  366. #ifndef UNIX
  367.     eightbit = 1;
  368. #else
  369.     eightbit = 0;
  370. #endif /* UNIX */
  371. #endif /* USE_COLOR || USE_ANSI */
  372.  
  373.     clearfilenames();
  374.  
  375.     /* First, set any options from the Env. Variable CALOPT */
  376.     if ( (calopt = getenv("CALOPT")) != NULL ) {
  377.     s = strtok(calopt," ");
  378.     while (s != NULL) {
  379.         if (*s != '-'
  380.             #if (defined(MSDOS) || defined(OS2))
  381.             && *s != '/'
  382.             #endif
  383.             ) break;
  384.         if ((c = getarg(opt, s, &optarg)) < 0)
  385.         {
  386.             usage();
  387.             status=1;   /* Let user known program didn't run */
  388.             goto freestuff;
  389.         }
  390.         setopt(c, optarg);
  391.         s = strtok(NULL," ");
  392.     }
  393.     }
  394.  
  395.     /* Next, loop through command line options and set parameters */
  396.     for (i = 1; i < argc; ++i) {
  397.         if (*argv[i] != '-'
  398.             #if (defined(MSDOS) || defined(OS2))
  399.             && *argv[i] != '/'
  400.             #endif
  401.             ) break;
  402.         if ((c = getarg(opt, argv[i], &optarg)) < 0)
  403.         {
  404.             usage();
  405.             status=1;   /* Let user know program didn't run */
  406.             goto freestuff;
  407.         }
  408.         setopt(c, optarg);
  409.     }
  410.  
  411.     if (numappts < 8 || numappts > MAXAPPTS) {
  412.         usage();
  413.         status=2;  /* Let user know failed because to many datafiles */
  414.         goto freestuff;
  415.     }
  416.  
  417.     if (!numfiles && data_file)  /* add default data file if none specified */
  418.         addfilename(data_file);
  419.  
  420.     /* make the argument list compatible with unix cal */
  421.     argc = argc - i + 1;
  422.     for (m = 1; m < argc; ++m) argv[m] = argv[i++];
  423.  
  424. #ifdef MSDOS
  425. #ifndef USE_ANSI
  426.     reg.h.ah = 0x0f;       /* function 0x0F of INT 0x10 - get display mode */
  427.     int86(0x10, &reg, &reg);
  428.     LineWid = max(80, reg.h.ah);  /* number of columns returned in AH */
  429.     /* The above should work for all displays.
  430.      * The following can be used instead, but will work in EGA and VGA only:*/
  431.     /* Linewid = *((unsigned far *)0x004004a); */
  432. #endif
  433. #endif /* MSDOS */
  434.  
  435.     /* allocate workspace buffer */
  436.  
  437.     bufsiz = (numappts+1)*LineWid + 2*DAY_DESC;
  438. #if defined(USE_COLOR) || defined(USE_ANSI)
  439.     /* adjust workspace for color enhancements */
  440.     bufsiz += (numappts+3)*LineWid + YEARWID + DAY_DESC;
  441. #endif /* USE_COLOR || USE_ANSI */
  442.     if ((buf = (char *)calloc(bufsiz,1)) == NULL) {
  443.         puts("Memory overflow");
  444.         goto freestuff;
  445.     }
  446.  
  447.     /* assign pointers into buf */
  448.  
  449.     line[0] = buf;
  450.     for (i = 1; i < numappts-2; i++)
  451.         line[i] = line[i-1] + LineWid;               /* calendar body    */
  452.     str = line[i-1] + LineWid;                       /* string workspace */
  453.     *(spcldesc[0] = str + LineWid) = '\0';           /* description 0    */
  454.     *(spcldesc[1] = spcldesc[0] + DAY_DESC) = '\0';  /* description 1    */
  455.     /* descriptions 2,3,... point into line[] */
  456.  
  457.     /* find originating directory */
  458.  
  459. #ifndef UNIX
  460.     homedir = argv[0];
  461.     i = strlen(homedir);
  462.     while (i >= 0 && homedir[i] != '/' && homedir[i] != '\\' &&
  463.            homedir[i] != ':')
  464.         homedir[i--] = '\0';
  465. #else
  466.     homedir = getenv("HOME");
  467. #endif
  468.  
  469. #if defined(USE_COLOR) || defined(USE_ANSI)         /* color attributes */
  470.     line_attr[0] = spcldesc[1] + DAY_DESC;
  471.     for (i = 1; i < numappts-2; i++) line_attr[i] = line_attr[i-1] + LineWid;
  472.     mon_attr = line_attr[i-1] + LineWid;
  473.     wk_attr = mon_attr + LineWid;
  474.     day_attr = wk_attr + LineWid;
  475.     spclday_attr = day_attr + YEARWID;
  476.  
  477.     /* attempt to read in file of colors */
  478.     if (!crt || (colorfile = efopen(color_file, "r")) == NULL) goto contsetup;
  479.     for (i = 0; i < 8; i++) {
  480.         if (fgets(str, LineWid, colorfile) == NULL) break;
  481.         if ((fg[i] = atoi(str)) == (bg[i] = atoi(&str[3]))) break;
  482.         if (fg[i] > 15 || bg[i] > 15) break;
  483.     }
  484.     fclose(colorfile);
  485.     if (i < 8) goto contsetup;
  486.     dfmon_attr   = fg[0] | (bg[0] << 4);
  487.     dfwk_attr    = fg[1] | (bg[1] << 4);
  488.     dfdy_attr    = fg[2] | (bg[2] << 4);
  489.     dfsun_attr   = fg[3] | (bg[3] << 4);
  490.     dftoday_attr = fg[4] | (bg[4] << 4);
  491.     dfbk_attr    = fg[5] | (bg[5] << 4);
  492.     dfspday_attr = fg[6] | (bg[6] << 4);
  493.     dfspdfl_attr = fg[7] | (bg[7] << 4);
  494.  
  495.     /* initialize color attribute strings */
  496. contsetup:
  497.     memset (mon_attr, dfmon_attr, LineWid);
  498.     memset (wk_attr, dfwk_attr, LineWid);
  499.     memset (day_attr, dfdy_attr, YEARWID);
  500.     memset (spclday_attr, dfspday_attr, DAY_DESC);
  501.     spclday_attr[0] = dfspdfl_attr;
  502.     for (i = MONWID-2; i <= MONWID+MONWID; i += MONWID) {
  503.         memset (&mon_attr[i], dfbk_attr, 2);
  504.         memset (&wk_attr[i], dfbk_attr, 2);
  505.         memset (&day_attr[i], dfbk_attr, 2);
  506.         memset (&day_attr[i - MONWID + 3 + (18*europe)], dfsun_attr, 2);
  507.     }
  508.     mon_attr[i] = dfbk_attr;  /* "termination" attr. for ansiputs() */
  509.     memset (&day_attr[i - MONWID + 3 + (18*europe)], dfsun_attr, 2);
  510.     dftoday_attr2 = ((dfdy_attr & '\x70')|(dftoday_attr >> 4));
  511.  
  512. #ifdef MSDOS
  513. #ifndef USE_ANSI
  514.     int86(0x11, &reg, &reg);  /* read the equipment list into reg. */
  515.     video = (char far *)MK_FP((((reg.x.ax & 48) == 48) ? 0xb000 : 0xb800), 0);
  516. #endif
  517. #endif /* MSDOS */
  518.  
  519. #endif /* USE_COLOR || USE_ANSI */
  520.  
  521.     /* now that all the setup is done, we can begin with the program proper */
  522.  
  523.     t = time(NULL);
  524.     lt = localtime(&t);
  525.     thisyear = y = lt->tm_year + 1900;
  526.     thismonth = m = lt->tm_mon + 1;
  527.     thisday = lt->tm_mday;
  528.     puts("");           /* first display a blank line */
  529.  
  530.     switch (argc) {
  531.     case 1:             /* display current month if no arguments */
  532.         fixtab (y);
  533.         printmonth (m, y);
  534.         break;
  535.  
  536.     case 2:
  537.         if (isdigit(argv[1][0]) || (isdigit(argv[1][1]) &&
  538.                                     argv[1][0] == '-')) {
  539.             multi = 1;
  540.             fixtab (y = atoi(argv[1]));
  541.             fputs("\t\t\t\t ", stdout);
  542.             putd(y);         /* put year */
  543.             puts("\n");
  544.             for (m = 1; m < 13; m++) printmonth (m, y);
  545.             break;
  546.         }
  547.         /* drop through to next case */
  548.  
  549.     case 3:
  550.         m = atoi(argv[1]);
  551.         if (strlen(argv[1]) >= 3) {
  552.             for (i = 0; i < 12; i++) {
  553.                 strcpy(str, months[i]);
  554.                 str[3] = argv[1][3] = '\0';
  555.                 if (!stricmp(argv[1], str)) {
  556.                     m = i + 1;
  557.                     break;
  558.                 }
  559.             }
  560.         }
  561.         if (!m) {
  562.             usage();
  563.             status=3;   /* Let user know failed because invalid month */
  564.             break;
  565.         }
  566.         if (argc == 3) {
  567.             if (isdigit(argv[2][0]) || (isdigit(argv[1][1]) &&
  568.                                         argv[2][0] == '-'))
  569.                 y = atoi(argv[2]);
  570.             else {
  571.                 usage();
  572.                 status=4;  /* failed because invalid number parameters */
  573.                 break;
  574.             }
  575.         }
  576.         fixtab(y);
  577.         printmonth(m, y);
  578.         break;
  579.  
  580.     default:
  581.         usage();
  582.         status=4;  /* failed because invalid number parameters */
  583.     }
  584.  
  585.     if (prog_pause) {
  586.         fputs("\nPress the RETURN key to continue.", stderr);
  587.         fflush(stdin);
  588.         fgets(str, 3, stdin);
  589.     }
  590. freestuff:
  591.     free(buf);
  592.     return (status);
  593. }
  594.  
  595.  
  596. /*===========================================================================
  597.  * addfilename()
  598.  * append a file name into the list of files to read
  599.  * name must be a static string
  600.  *=========================================================================*/
  601. void addfilename(char *name)
  602. {
  603.     if (numfiles < MAXFILES && name) filename[numfiles++] = name;
  604. }
  605.  
  606. /*===========================================================================
  607.  * clearfilenames()
  608.  * empty the list of file names
  609.  * NOTE: does not free() any entries
  610.  *=========================================================================*/
  611. void clearfilenames(void)
  612. {
  613.     numfiles = 0;
  614. }
  615.  
  616.  
  617. /*===========================================================================
  618.  * printmonth()
  619.  * either prints an entire month at a time or multiplexes
  620.  * a month into a buffer, dumping the buffer after the third call.
  621.  *=========================================================================*/
  622. void printmonth(short m, short y)
  623. {
  624.     register short first, last;
  625.     register short index, p = 0;
  626.     register char *ll;
  627.     static short q = 0;
  628.     short l, hilite = ((m == thismonth) && (y == thisyear)), num_appts = 0;
  629.  
  630.     --m;
  631.     if (multi) {
  632.         q++;
  633.         if (q > 3) q = 1;
  634.         p = MONWID * (q - 1);        /* character position of line in buffer */
  635.         (void) memcpy(monthpos[q-1], months[m], 3);       /* copy month name */
  636.         if (q == 3) {
  637.             #ifdef USE_ANSI
  638.             ansiputs(monthline,mon_attr);
  639.             #else
  640.             puts(monthline);
  641.             #endif
  642.             #ifdef USE_COLOR
  643.             putattr(mon_attr, YEARWID);
  644.             #endif /* USE_COLOR */
  645.             for (index = 0; index < 2; ++index) {
  646.             #ifdef USE_ANSI
  647.                 setcolor(dfwk_attr);
  648.             #endif
  649.                 fputs(dayline, stdout);
  650.                 #ifdef USE_ANSI
  651.                 setcolor(dfbk_attr);
  652.                 #endif
  653.                 fputs("  ", stdout);
  654.             }
  655.             #ifdef USE_ANSI
  656.             ansiputs(dayline, wk_attr);
  657.             #else
  658.             puts(dayline);
  659.             #endif
  660.             #ifdef USE_COLOR
  661.             putattr(wk_attr, YEARWID);
  662.             #endif /* USE_COLOR */
  663.             #if defined(USE_COLOR) || defined(USE_ANSI)
  664.             for (l = 0; l < 6; l++) memcpy(line_attr[l], day_attr, LineWid);
  665.             #endif /* USE_COLOR || USE_ANSI */
  666.         }
  667.     }
  668.     else {
  669.         q = 1;         /* initialize attribute buffers for month display */
  670. #if defined(USE_COLOR) || defined(USE_ANSI)
  671.         for (l = 0; l < numappts-2; l++) {
  672.             if (l<6)
  673.                 memcpy(line_attr[l], day_attr, MONWID-2);
  674.             else
  675.                 memset(line_attr[l], 0, MONWID-2);
  676.             line_attr[l][MONWID-2] = dfspdfl_attr;
  677.             memcpy(&line_attr[l][MONWID-1], spclday_attr, DAY_DESC);
  678.         }
  679.         memcpy(&mon_attr[MONWID-1], spclday_attr, DAY_DESC);
  680.         memcpy(&wk_attr[MONWID-1], spclday_attr, DAY_DESC);
  681.         mon_attr[MONWID-2] = wk_attr[MONWID-2] = dfspdfl_attr;
  682. #endif /* USE_COLOR || USE_ANSI */
  683.     }
  684.  
  685.     if (!p) memset(line[0], ' ', (numappts-2)*LineWid);
  686.  
  687.     if (y == 1752 && m == 8) {      /* special case Sep. 1752 */
  688.         line[0][p + 8] = '1';
  689.         line[0][p + 11] = '2';
  690.         first = 14;
  691.         last = 16;
  692.         index = 12;
  693.     }
  694.     else {
  695.         short dow = weekday(m, y);   /* day of week for first day of month */
  696.         first = 1;
  697.         last = 7 - dow;
  698.         index = 3 * dow;
  699.     }
  700.  
  701.     for (l = 0; l < 6; ++l) {       /* loop thru month one week per line */
  702.         ll = line[l] + p + 1;
  703.         while (first <= last) {      /* for each day in week encode day of month */
  704.             if (first >= 10) ll[index] = '0' + first / 10;
  705.             ll[index+1] = '0' + first % 10;
  706.             if (!multi && hilite && first == thisday) {  /* hilight today */
  707.                 #if defined(USE_COLOR) || defined(USE_ANSI)
  708.                 line_attr[l][index+1] = line_attr[l][index+2] = dftoday_attr;
  709.                 line_attr[l][index] = line_attr[l][index+3] = dftoday_attr2;
  710.                 ll[index-1] = (crt && eightbit) ? '\xde' : '<';
  711.                 ll[index+2] = (crt && eightbit) ? '\xdd' : '>';
  712.                 #else
  713.                 ll[index-1] = '<';
  714.                 ll[index+2] = '>';
  715.                 #endif /* USE_COLOR || USE_ANSI */
  716.             }
  717.             index += 3;
  718.             ++first;
  719.         }
  720.         last = (last + 7) > days[m] ? days[m] : last + 7;
  721.         index = 0;
  722.     }
  723.  
  724.     if (!multi) {
  725.         short i, yw;
  726.         /* the next 2 lines assume that the shortest-length month name
  727.          * in months[], such as "June ", will be 5 characters long. */
  728.         char mtmp[] = "             ";     /* 13 spaces */
  729.         mtmp[l = (18 - (i = strlen(months[m]))) >> 1] = '\0';
  730.         #ifdef USE_ANSI
  731.         setcolor(dfmon_attr);
  732.         #endif
  733.         fputs(mtmp, stdout);
  734.         fputs(months[m], stdout);          /* put month name */
  735.         yw = putd(y);                      /* put year */
  736.         num_appts = specialdays(m+1, y);
  737.         #ifdef USE_REMINDER
  738.         if (num_appts < 1)
  739.             num_appts = reminderdays(m+1, y);
  740.         #endif
  741.         mtmp[l] = ' ';
  742.         mtmp[MONWID - l - i - yw - 2] = '\0';
  743.         fputs(mtmp, stdout);
  744.         #ifdef USE_ANSI
  745.         setcolor(dfspday_attr);
  746.         #endif
  747.         if (num_appts) {
  748.             fputs(" ", stdout);
  749.             #ifdef USE_ANSI
  750.             ansiputs(spcldesc[0],line_attr[0]+23);
  751.             #else
  752.             puts(spcldesc[0]);              /* put first description */
  753.             #endif
  754.         }
  755.         else puts("");
  756.         #ifdef USE_COLOR
  757.         putattr(mon_attr, LineWid-1);
  758.         #endif /* USE_COLOR */
  759.         #ifdef USE_ANSI
  760.         setcolor(dfwk_attr);
  761.         #endif
  762.         fputs(dayline, stdout);
  763.         #ifdef USE_ANSI
  764.         setcolor(dfspday_attr);
  765.         #endif
  766.         if (num_appts > 1) {
  767.             fputs(" ", stdout);
  768.             #ifdef USE_ANSI
  769.             ansiputs(spcldesc[1],line_attr[1]+23);
  770.             #else
  771.             puts(spcldesc[1]);              /* put second description */
  772.             #endif
  773.         }
  774.         else puts("");
  775.         #ifdef USE_COLOR
  776.         putattr(wk_attr, LineWid-1);
  777.         #endif /* USE_COLOR */
  778.     } /* end of if not multi */
  779.     #ifdef USE_ANSI
  780.     setcolor(dfdy_attr);
  781.     #endif
  782.     num_appts = max(6, num_appts-2);
  783.     for (l = 0; l < num_appts; l++)
  784.         if (!multi || q == 3) {
  785.             index = LineWid-1;
  786.             ll = line[l];
  787.             while (index >= 1 && ll[index] == ' ') --index;
  788.             if (q == 3)
  789.                 index = 69;
  790.             else if (index < 21)  /* leave one space after last day in week */
  791.                 index = 21;
  792.             ll[index+1] = '\0';
  793.             #ifdef USE_ANSI
  794.             ansiputs(line[l],line_attr[l]);
  795.             #else
  796.             puts(ll);
  797.             #endif
  798.             #ifdef USE_COLOR
  799.             putattr(line_attr[l], multi ? YEARWID : LineWid-1);
  800.             #endif /* USE_COLOR */
  801.         }
  802.     #ifdef USE_ANSI
  803.     setcolor(0);
  804.     #endif
  805. }
  806.  
  807.  
  808. /*===========================================================================
  809.  * putd() - put year to standard output.
  810.  *=========================================================================*/
  811. short putd(register short n)
  812. {
  813.     register char *p = str+10;
  814.     short yw = 0, neg = (n < 0);
  815.     *p = '\0';
  816.     if (neg) n = -n;
  817.     do {
  818.         --p;
  819.         ++yw;
  820.         *p = '0' + n % 10;
  821.         n = n / 10;
  822.     } while (n);
  823.     if (neg) *(--p) = '-';
  824.     fputs(p, stdout);
  825.     return yw;
  826. }
  827.  
  828.  
  829. #define isleap(y) (!((y)%4) && (((y)%100) || !((y)%400)))
  830. /*===========================================================================
  831.  * fixtab() - correct for leapyears.
  832.  *=========================================================================*/
  833. void fixtab(register short y)
  834. {
  835.     register short i;
  836.     if (!(y % 4)) {
  837.         if ((y % 100) || !(y % 400) || (y < 1753)) {
  838.             days[1] = 29;
  839.             for (i = 2; i < 13; i++) mdays[i]++;
  840.         }
  841.     }
  842. }
  843.  
  844.  
  845. /*===========================================================================
  846.  * weekday() - return day-of-week for first day of month.
  847.  *=========================================================================*/
  848. short weekday(register short m, register short y)
  849. {
  850.     --y;
  851.     if (y > 1752-1 || (y == 1752-1 && m > 8))
  852.         return (mdays[m]+y+y / 4-y / 100+y / 400+FUDGE1 - europe) % 7;
  853.     else
  854.         return (mdays[m] + y + y / 4           + FUDGE2 - europe) % 7;
  855. }
  856.  
  857.  
  858. #ifdef USE_COLOR
  859. /*===========================================================================
  860.  * putattr() - MSDOS or OS/2 only
  861.  * modify the video memory text attribute areas with the attributes passed
  862.  * in attr of lengh len, starting at the current cursor location.
  863.  *=========================================================================*/
  864. void putattr(char *attr, register short len)  /* write video attr. string */
  865. {
  866. #ifdef OS2
  867.     USHORT row, col;
  868.     int i;
  869. #endif /* OS2 */
  870.  
  871.     if (!crt) return;
  872.  
  873. #ifdef OS2
  874.     VioGetCurPos(&row, &col,0);
  875.     --row;
  876.     while (len) {        /* minimize the number of Vio calls */
  877.         for (i = 1; i < len; i++)
  878.             if (attr[i] != *attr) break;
  879.         VioWrtNAttr((PBYTE) attr, i, row, col, 0);
  880.         attr += i; col += i; len -= i;
  881.     }
  882.  
  883. #else /* if not OS2 */
  884.  
  885.     reg.h.ah = 3;
  886.     reg.h.bh = 0;
  887.     int86(0x10, &reg, &reg);
  888.     tmpvideo = video + ((LineWid << 1) * (reg.h.dh - 1) + reg.h.dl + 1);
  889.     while (len--) {
  890.         *tmpvideo = *(attr++);
  891.         tmpvideo += 2;
  892.     }
  893. #endif /* OS2 */
  894. }
  895. #endif /* USE_COLOR */
  896.  
  897.  
  898. #ifdef USE_ANSI
  899. /*===========================================================================
  900.  * ansiputs()
  901.  * Puts a string to stdio in color as defined by line_attr.
  902.  *=========================================================================*/
  903. void ansiputs(char *l, char *a)
  904. {
  905.     char prev_color;
  906.  
  907.     setcolor(*a);
  908.     while (*l) {
  909.         fputc(*l++,stdout);
  910.         prev_color = *a++;
  911.         if (prev_color != *a) setcolor(*a);
  912.     }
  913.     fputc('\n',stdout);
  914. }
  915.  
  916.  
  917. /*===========================================================================
  918.  * setcolor()
  919.  * Set the color attributes to those passed in.
  920.  *=========================================================================*/
  921. void setcolor(char attr)
  922. {
  923.     char command[256];
  924.     char dos2ansi[] = { 0, 4, 2, 6, 1, 5, 3, 7, 0, 4, 2, 6, 1, 5, 3, 7};
  925.     if (!crt) return;
  926.  
  927.     /* ANSI codes
  928.        0 = normal attributes (white one black)
  929.        1 = high intensity     5 = blinking
  930.        2 = Normal intensity   7 = reverse
  931.        4 = underlined         8 = invisible
  932.      */
  933.     if (attr == 0)
  934.         fputs("\033[0m",stdout);
  935.     else {
  936.         strcpy(command,"\033[0;");
  937.         if (attr&0x80) strcat(command,"5;");
  938.         if (attr&0x08) strcat(command,"1;");
  939.         sprintf(command,"%s3%d;4%dm",command,dos2ansi[attr&0x0F],
  940.                 dos2ansi[(attr&0x70)>>4]);
  941.         fputs(command,stdout);
  942.     }
  943. }
  944. #endif /* USE_ANSI */
  945.  
  946.  
  947. /*============================================================================
  948.  * add_days()
  949.  * function to return year, month, day of dates + n days
  950.  * used in find periodic dates.
  951.  * e.g. 1996 02 06 14 -- Payday! --
  952.  *==========================================================================*/
  953. void add_days(short *y, short *m, short *d, short n)
  954. {
  955.     short tmpfeb = days[1];
  956.     days[1] = isleap(*y) ? 29 : 28;
  957.     --(*m);
  958.     *d += n;
  959.     while (*d > days[*m]) {
  960.         *d -= days[*m];
  961.         if (++(*m) > 11) {
  962.             ++(*y);
  963.             days[1] = isleap(*y) ? 29 : 28;
  964.             *m = 0;
  965.         }
  966.     }
  967.     ++(*m);
  968.     days[1] = tmpfeb;  /* restore original value */
  969. }
  970.  
  971. /* Return day of month corresponding to the weekth week and dayth day of week*/
  972. /* Requires that the line[] structure be filled in with the given month */
  973. int monthweekday(int week, int day)
  974. {
  975.     int j;
  976.  
  977.     if (week == 9)                      /* special case to find last weekday */
  978.         for (j = 5; j > 0; j--)
  979.         { if (line[j][3*day+2] != ' ') break; }
  980.     else {                              /* find dayth weekday                */
  981.         for (j = 0; j < 6; j++)
  982.             if (line[j][3*day+2] != ' ') if (!(--week)) break;
  983.         if (week)
  984.             return -1;                  /* dayth weekday didn't exist        */
  985.         /* could probably change this to return 0 */
  986.     }
  987.     return atoi(&line[j][3*day+1]);     /* date of dayth weekday             */
  988. }
  989.  
  990. /* make space for a new item in the right spot & return pointer to it */
  991. char *insertitem(char **lln, int maxentry, int dy)
  992. {
  993.     short j,k,day;
  994.  
  995.     for (j = 0; j < maxentry; j++)              /* insert in sorted order */
  996.         if (dy < (day = atoi(&lln[j][1]))) {
  997.             k = maxentry;
  998.             if (k == numappts) --k;
  999.             for (; k > j; k--)                  /* move everything up     */
  1000.                 strcpy(lln[k], lln[k-1]);
  1001.             break;
  1002.         }
  1003.         else if (day == 100) dy = dy-100;       /* reached new month      */
  1004.  
  1005.     if (j == numappts) return NULL;
  1006.     return lln[j];
  1007. }
  1008.  
  1009. /*===========================================================================
  1010.  * specialdays()
  1011.  * find the file CAL.DAT and attempt to read in special date descriptions.
  1012.  * e.g. -999 12 25 00 Christmas Day
  1013.  *=========================================================================*/
  1014. short specialdays(short m, short y)
  1015. {
  1016.     FILE   *fp;
  1017.     short  mo, dy, yr, w, n, filenum, wn, weeklyflag, periodflag = 0, k, j,
  1018.            hiappt = 1, hilight = (m == thismonth && y == thisyear);
  1019.     char **lln = NULL, *ll;
  1020.  
  1021.     if ((lln = (char **)calloc(numappts+1, sizeof(char *)))==NULL)
  1022.         goto spcldone;
  1023.  
  1024.     if (m != thismonth) discard_old = 0;
  1025.     lln[0] = spcldesc[0];
  1026.     lln[1] = spcldesc[1];
  1027.     for (j = 2; j < numappts; j++) lln[j] = &line[j-2][MONWID-1];
  1028.  
  1029.     strcpy(lln[0], " 100");             /* last (hiappt) entry */
  1030.  
  1031.     for (filenum = 0; filenum < numfiles; filenum++) {
  1032.         if ((fp = efopen(filename[filenum], "r")) == NULL) continue;
  1033.  
  1034.         while (fgets(str, LineWid, fp) != NULL) {  /* go until EOF is hit */
  1035.             if (!isdigit(*str) && *str != '-') continue; /* a data line? */
  1036.             if ((yr = atoi(str)) == 0) continue;         /* get year */
  1037.             if ((mo = atoi(&str[5])) == 0) continue;     /* get month */
  1038.             wn = atoi(&str[11]);                         /*nth wkdy or period*/
  1039.             if ((dy = atoi(&str[8])) == 0)               /* get day */
  1040.                 if (!wn) continue;
  1041.             if (yr == y && mo > m && dy > 0 && wn > 0)
  1042.                 continue; /* incalculable periodic date */
  1043.             if (!( (yr >= 1970 && mo > 0 && dy > 0 && wn > 0)
  1044.                   || ((yr == -999 || yr == y) &&
  1045.                   (mo == m || mo == m+1)) /* got it all? */
  1046.                   || ((yr == -999 || yr == y+1) &&
  1047.                       (mo == 1 && m == 12)) || mo == -9))
  1048.                 continue;
  1049.             if (dy == -9) {
  1050.                 if (m == thismonth && y == thisyear)
  1051.                     dy = thisday;            /* set daily reminder */
  1052.                 else
  1053.                     continue;
  1054.          }
  1055.  
  1056.         periodduplicate:
  1057.             if (yr >= 1970 && mo > 0 && dy > 0 && wn > 0  /* proper format? */
  1058.                 && !(yr == thisyear && mo == thismonth &&
  1059.                      dy == thisday && !periodflag)        /* not today? */
  1060.                 && yr <= y && !(yr == y && mo > m)) {     /* <= displayed month
  1061.                                                                & year? */
  1062.                 while (yr < y || mo <= m) {   /* find periodic dates */
  1063.                     add_days(&yr, &mo, &dy, wn);
  1064.                     if (yr == y && mo == m) break;
  1065.                 }
  1066.                 if (mo > m) continue;
  1067.                 /* periodic dates left in month */
  1068.                 periodflag = (days[m-1] - dy)/wn;
  1069.                 if (periodflag && ((discard_old && dy<thisday) || (discard_old==2 && dy!=thisday)))
  1070.                     goto periodduplicate;
  1071.             }
  1072.             else periodflag = 0;
  1073.  
  1074.             weeklyflag = 5*(wn<0 && wn!=-9); /* flag to dup. weekly dates */
  1075.             if (wn < 0) wn = 50-wn;
  1076.         weeklyduplicate:
  1077.             w = weeklyflag ? weeklyflag : wn/10;
  1078.             if (!(yr > 0 && mo > 0 && dy > 0) &&
  1079.                 ((wn >= 11 && wn <= 57) || w == 9) && (mo == m || mo == -9)) {
  1080.                 /* find nth weekday */
  1081.                 n = wn%10 - 1;           /* day of week (0=sun, 1=mon, etc.) */
  1082.                 if (n < 0 || n > 6) continue;
  1083.  
  1084.                 if ((dy = monthweekday(w,n)) < 0) {
  1085.                     if (--weeklyflag > 0) goto weeklyduplicate;
  1086.                     else continue;        /* nth weekday didn't exist */
  1087.          }
  1088.             }
  1089.  
  1090.             if (!dy) continue;        /* next loop if wn>57 or wn<11 or dy=0 */
  1091.             if ((mo == m+1 && (yr == y || yr == -999))
  1092.                 || (mo == 1 && m == 12 && (yr == y+1 || yr == -999)))
  1093.                 dy += 100;           /* make sure 'next month' days are last */
  1094.  
  1095.             if ((discard_old && dy<thisday) || (discard_old==2 && dy != thisday))
  1096.                 continue;  /* next loop if old day */
  1097.  
  1098.             if ((ll = insertitem(lln,hiappt,dy)) == NULL) continue;
  1099.             ll[0] = (hilight && dy == thisday && (mo == m || mo == -9))
  1100.                 ? '*' : ' ';  /* 'today' flag */
  1101.             ll[1] = (dy%100 < 10) ? ' ' : '0' + (dy%100)/10;
  1102.             ll[2] = '0' + dy%10;
  1103.             ll[3] = ':';
  1104.             j = strlen(str) - 1;         /* get rid of trailing white space */
  1105.             while (j >= 13 && isspace(str[j])) str[j--] = '\0';
  1106.  
  1107. /**************************************************************************/
  1108. /*             Check for special case of Anniversary/Birthdays             */
  1109. /*   Change added by R. Scott, and generalized a bit by Alex Matulich     */
  1110. /* A field indicated by [] will be displayed with [], but a field using {}*/
  1111. /* will be displayed without the braces.                                  */
  1112. /**************************************************************************/
  1113. /* These changes replace the next two lines: */
  1114. /*    str[j = 14+DAY_DESC-6] = '\0';         */
  1115. /*    strcpy(&ll[4], &str[13]);              */
  1116. /*********************************************/
  1117.  
  1118.             j=13; k=4;  /* init pointers into strings */
  1119.             while (k < DAY_DESC - 1 && str[j]) {
  1120.                 ll[k++] = str[j];
  1121.                 if (str[j] == '\\') { /* Don't treat next char as special */
  1122.                     ll[k-1] = str[++j]; /* Write next char over '\' */
  1123.                     j++;                /* & then advance to next char */
  1124.                 }
  1125.                 /* start of [field] */
  1126.                 else if (str[j] == '[' || str[j] == '{') {
  1127.                     short suffix = -1;   /* <0 indicates no ordinal suffix */
  1128.                     long ipower = 1,
  1129.                         by = atoi(&str[++j]); /* year of aniversary */
  1130.                     if (by <= y) {             /* will year be modified? */
  1131.                         by = y - by + (dy>100 && mo==1); /* years since anniversary */
  1132.                         if (str[j-1] == '{')
  1133.                             suffix = by; /* ordinal suffix will be attached */
  1134.                     }
  1135.                     if (str[j-1] == '{' || str[j-1] == '[')
  1136.                         --k;  /* don't display brace */
  1137.                     while (by / ipower) ipower *= 10L;
  1138.                     ipower /= 10L;      /* ipower is now the magnitude of by */
  1139.                     if (!by) ll[k++] = '0';
  1140.                     else while (ipower && k < DAY_DESC - 1) {
  1141.                         ll[k++] = by / ipower + '0';
  1142.                         by -= (by / ipower) * ipower;/* remove largest digit */
  1143.                         ipower /= 10L;
  1144.                     }
  1145.                     /* optionally add the ordinal suffixes st, nd, rd and th
  1146.                      * to the end of value for better readability (for example,
  1147.                      * 31 will be 31st, 23 will be 23rd, etc.) */
  1148.                     if (suffix >= 0 && k < DAY_DESC - 3) {
  1149.                         suffix %= 100;  /* only use last two digits */
  1150.                         if (suffix >= 11 && suffix <= 13) suffix = 4;
  1151.                         else suffix %= 10; /* last digit */
  1152.                         switch (suffix) {
  1153.                         case 1:  ll[k++]='s'; ll[k++]='t';  break;
  1154.                         case 2:  ll[k++]='n'; ll[k++]='d';  break;
  1155.                         case 3:  ll[k++]='r'; ll[k++]='d';  break;
  1156.                         default: ll[k++]='t'; ll[k++]='h';
  1157.                         }
  1158.                     }
  1159.                     while (isdigit(str[j])) ++j;  /* advance to end of field */
  1160.                     if (str[j] == '}' || str[j] == ']') ++j; /* skip brace*/
  1161.                 }
  1162.                 else
  1163.                     ++j;      /* advance to next char */
  1164.             }
  1165.             ll[k] = '\0';   /* ensure string is terminated */
  1166. /**************************************************************************/
  1167. /* End of anniversary changes                                             */
  1168. /**************************************************************************/
  1169.  
  1170.             if (++hiappt > numappts) hiappt = numappts;
  1171.             if (--weeklyflag > 0) goto weeklyduplicate; /* dup. wkly reminders */
  1172.             if (periodflag > 0) goto periodduplicate; /* dup. periodic reminders */
  1173.         }
  1174.  
  1175.         fclose(fp);
  1176.     }
  1177.  
  1178.     for (j = 0; j < hiappt; j++)
  1179.         if (atoi(&lln[j][1]) == 100) break;     /* find last item */
  1180.     if (j == hiappt-1)
  1181.         lln[--hiappt][0] = '\0';
  1182.     else if (j < hiappt)
  1183.         strcat(strcat(strcpy(lln[j], " "), months[m%12]), "--");
  1184.  
  1185. spcldone:
  1186.     free(lln);
  1187.     return hiappt;
  1188. }
  1189.  
  1190.  
  1191. #ifdef USE_REMINDER
  1192.  
  1193. /* dayofweek()
  1194.  * convert Sun, Mon, Tues, etc. to number (honours europe flag)
  1195.  * returns 0 in case of error
  1196. */
  1197. int dayofweek(const char *day)
  1198. {
  1199.     switch (toupper(day[0])) {
  1200.     case 'S':
  1201.         if (tolower(day[1]) == 'u')
  1202.             return europe ? 7 : 1;
  1203.         else
  1204.             return 7 - europe;
  1205.     case 'M':
  1206.         return 2 - europe;
  1207.     case 'T':
  1208.         if (tolower(day[1]) == 'u')
  1209.             return 3 - europe;
  1210.         else
  1211.             return 5 - europe;
  1212.     case 'W':
  1213.         return 4 - europe;
  1214.     case 'F':
  1215.         return 6 - europe;
  1216.     default:
  1217.         return 0;
  1218.     }
  1219. }
  1220.  
  1221.  
  1222. /*===========================================================================
  1223.  * reminderdays()
  1224.  * find the file DATES and attempt to read in reminder-style date descriptions.
  1225.  * e.g. 12/25:7:Christmas Day::N
  1226.  *=========================================================================*/
  1227. short reminderdays(short m, short y)
  1228. {
  1229.     FILE *fp;
  1230.     short mo, dy, yr, n, wn, weeklyflag, filenum, j, hiappt = 1,
  1231.         hilight = (m == thismonth && y == thisyear);
  1232.     char **lln = NULL, *ll;
  1233.     char *descrip;
  1234.     static char tempstr[256];   /* big enough for a long reminder line */
  1235.  
  1236.     if (!data_file) return 0;   /* don't read any data files */
  1237.     if ((lln = (char **)calloc(numappts+1, sizeof(char *)))==NULL) return 1;
  1238.  
  1239. /* set up pointers array for descriptions */
  1240.     lln[0] = spcldesc[0];
  1241.     lln[1] = spcldesc[1];
  1242.     for (j = 2; j < numappts; j++) lln[j] = &line[j-2][MONWID-1];
  1243.  
  1244.     strcpy(lln[0], " 100");     /* last entry */
  1245.  
  1246.     if (m != thismonth) discard_old = 0;
  1247.  
  1248.     clearfilenames();   /* ignore all the cal native format data files */
  1249.     addfilename(REMINDER_FILE);
  1250.     for (filenum = 0; filenum < numfiles; filenum++) {
  1251.         if ((fp = efopen(filename[filenum], "r")) == NULL) continue;
  1252.  
  1253.         /* go until EOF is hit */
  1254.         while (fgets(tempstr, sizeof(tempstr), fp) != NULL) {
  1255.             if (isspace(tempstr[0]))
  1256.                 continue;  /* ignore blanks and empty lines */
  1257.             else if (strchr(tempstr, ':') &&
  1258.                      (isdigit(tempstr[0]) || (tempstr[1] != ':'))) {
  1259.                 /* assume normal date entry & not include file (which may be
  1260.                    of form C:\NAME)  */
  1261.  
  1262.                 char *field = strtok(tempstr, ":");             /* get date */
  1263.  
  1264.                 if (isdigit(field[0])) {
  1265.                     mo = yr = wn = 0;
  1266.                     /* day of month only? */
  1267.                     dy = atoi(tempstr);
  1268.                     if ((field = strchr(field,'/')) != NULL) {
  1269.                         /* mm/dd or mm/dd/yy format */
  1270.                         mo = dy;
  1271.                         if (mo != m)            /* not this month */
  1272.                             continue;
  1273.                         dy = atoi(field+1);
  1274.                         yr = 0;
  1275.  
  1276.                         if ((field = strchr(field+1,'/')) != NULL) {
  1277.                             /* mm/dd/yy format */
  1278.                             yr = atoi(field+1);
  1279.                             if (yr < 1000) yr = yr + 1900;
  1280.                         }
  1281.                     }
  1282.                     if ((dy > 31))              /* bad day */
  1283.                         continue;
  1284.                     if (yr && (yr != y))        /* not this year */
  1285.                         continue;
  1286.  
  1287.                 } else {
  1288.                     /* day of week */
  1289.                     dy = mo = yr = 0;
  1290.                     wn = dayofweek(field);
  1291.                 }
  1292.  
  1293.                 strtok(NULL, ":");              /* skip days of notice */
  1294.                 descrip = strtok(NULL, ":");    /* get description */
  1295.                 /* get person & status fields */
  1296.                 if ((field = strtok(NULL, "\n")) == NULL)
  1297.                     continue;           /* skip if sanity check fails */
  1298.                 if (field[0] != ':') {          /* person is specified */
  1299.                     char *newdescrip = malloc(LineWid);
  1300.                     field = strtok(field, ":"); /* get person */
  1301.                     strcat(strcat(strcpy(newdescrip, field), "'s "), descrip);
  1302.                     /* BUG: could overwrite end by 1 char */
  1303.                     strcpy(descrip, newdescrip);
  1304.                     field = strtok(NULL, ":");  /* get status */
  1305.                     free(newdescrip);
  1306.                 } else ++field;
  1307.  
  1308.                 if (!field || field[0] == 'D')  /* do not report this event */
  1309.                     continue;
  1310.  
  1311.             } else  {
  1312.                 /* must be an include file--add to the list to check */
  1313.                 /* NOTE: this malloced storage is never freed */
  1314.                 addfilename(strtok(strcpy(malloc(strlen(tempstr)+1),tempstr),"\n"));
  1315.                 continue;
  1316.             }
  1317.  
  1318.             weeklyflag = 5*(wn>0);       /* flag to dup. weekly dates */
  1319.  
  1320.             do {
  1321.                 if (!(yr > 0 && mo > 0 && dy > 0) &&
  1322.                     (wn >= 1) && (mo == m || mo <= 0)) {
  1323.                     n = wn - 1;          /* day of week (0=sun, 1=mon, etc.) */
  1324.                     if ((dy = monthweekday(weeklyflag,n)) < 0) {
  1325.                         if (--weeklyflag > 0) continue;
  1326.                         else continue;        /* nth weekday didn't exist */
  1327.             }
  1328.                 }
  1329.  
  1330.                 if (!dy) continue;             /* ignore if dy=0 */
  1331.                 if (discard_old < 2 && ((mo == m+1 && (yr == y || yr <= 0))
  1332.                     || (mo == 1 && m == 12 && (yr == y+1 || yr <= 0))))
  1333.                     dy += 100;       /* make sure 'next month' days are last */
  1334.  
  1335.                 if ((discard_old && dy<thisday) || (discard_old==2 &&
  1336.                     (dy != thisday || mo != thismonth || yr != thisyear)))
  1337.                     continue;  /* next loop if old day */
  1338.  
  1339.                 if ((ll = insertitem(lln,hiappt,dy)) == NULL) continue;
  1340.                 ll[0] = (hilight && dy == thisday && (mo == m || mo == -9))
  1341.                     ? '*' : ' ';  /* 'today' flag */
  1342.                 ll[1] = (dy%100 < 10) ? ' ' : '0' + (dy%100)/10;
  1343.                 ll[2] = '0' + dy%10;
  1344.                 ll[3] = ':';
  1345.                 j = strlen(descrip) - 1;  /* get rid of trailing white space */
  1346.                 while (j > 0 && isspace(descrip[j])) descrip[j--] = '\0';
  1347.  
  1348.                 descrip[DAY_DESC-5] = '\0';     /* truncate description */
  1349.                 strcpy(&ll[4], descrip);
  1350.  
  1351.                 if (++hiappt > numappts) hiappt = numappts;
  1352.             } while (--weeklyflag > 0); /* dup. weekly reminders */
  1353.         }
  1354.         fclose(fp);
  1355.     }
  1356.  
  1357.     for (j = 0; j < hiappt; j++)
  1358.         if (atoi(&lln[j][1]) == 100) break;     /* find last item */
  1359.     if (j == hiappt-1)
  1360.         lln[--hiappt][0] = '\0';
  1361.     else if (j < hiappt)
  1362.         strcat(strcat(strcpy(lln[j], " "), months[m%12]), "--");
  1363.  
  1364.     free(lln);
  1365.     return hiappt;
  1366. }
  1367. #endif /* USE_REMINDER */
  1368.  
  1369.  
  1370. /*===========================================================================
  1371.  * efopen() - fopen() replacement that does path searches
  1372.  *=========================================================================*/
  1373. FILE *efopen(const char *file, const char *mode)
  1374. {
  1375.     FILE  *fp;
  1376.  
  1377. #ifdef OS2
  1378.     char  path[_MAX_PATH];
  1379. #endif /* OS2 */
  1380.  
  1381.     if ((fp = fopen(file, mode)) == NULL) {
  1382.         if (*homedir) {
  1383.             strcpy(str, homedir);
  1384. #ifdef UNIX
  1385.             if (homedir[strlen(homedir)-1] != '/') strcat(str,"/");
  1386.             if (file[0] != '.') strcat(str, ".");
  1387. #endif
  1388.             strcat(str, file);
  1389.             fp = fopen(str, mode);
  1390.         }
  1391.  
  1392. #ifdef OS2
  1393.         if (fp == NULL) {
  1394.             _searchenv(file, "PATH", path);
  1395.             if (*path == '\0')
  1396.                 _searchenv(file, "DPATH", path);
  1397.             if (*path)
  1398.                 fp = fopen(path, mode);
  1399.         }
  1400. #endif /* OS2 */
  1401.  
  1402. #ifdef UNIX
  1403.         /* If not found in home dir, look in current dir, then /usr/lib */
  1404.         if (fp == NULL) {
  1405.             strcpy(str, ".");
  1406.             strcpy(str, file);
  1407.             if ((fp = fopen(str, mode)) == NULL) {
  1408.                 /* If still not found then look in a lib directory */
  1409.                 strcpy(str, "/usr/lib/");
  1410.                 strcat(str,file);
  1411.                 fp = fopen(str, mode);
  1412.             }
  1413.         }
  1414. #endif
  1415.     }
  1416.     return fp;
  1417. }
  1418.  
  1419.  
  1420. /*===========================================================================
  1421.  * usage() - called from main() - display commandline usage
  1422.  *=========================================================================*/
  1423. void usage()
  1424. {
  1425. fputs("\n\
  1426. CAL 3.5 -- unix-like 'cal' by Unicorn Research Corporation & DTF\n\
  1427. Display a monthly or yearly calendar, with optional appointments\n\n\
  1428. Usages:\tcal [options] [[month (1-12)] year]\n\
  1429. \tcal [options] [month (jan-dec)] [year]\n\n\
  1430. Options:\n\
  1431.   -nod[ata]          Ignore appointment descriptions file\n\
  1432.   -d[ata-file]=file  Load appointments from `file'",stderr);
  1433. #ifndef UNIX
  1434. fputs("(CAL.DAT)\n",stderr);
  1435. #else
  1436. fputs("(caldat)\n",stderr);
  1437. #endif
  1438. fputs("\
  1439.   -f[uture]          Show only future appointments on current month\n\
  1440.   -t[oday]           Show only today's appointments on current month\n\
  1441.   -e[urope]          European format (first day is Monday)\n\
  1442.   -m[axappts]=n      Display maximum of n (8-50) appointments (24)\n\
  1443.   -p[ause]           Pause for keystroke before exiting\n", stderr);
  1444.  
  1445. #if defined(USE_COLOR) || defined(USE_ANSI)
  1446. fputs("\
  1447.   -noc[olor]         Inhibit use of colors\n\
  1448.   -c[olor-file]=file Load color definitions from `file' ",stderr);
  1449. #ifndef UNIX
  1450. fputs("(CAL.COL)\n", stderr);
  1451. #else
  1452. fputs("(calcol)\n\
  1453.   -8[bit]            Display 8-bit ascii characters\n",stderr);
  1454. #endif
  1455. #endif /* USE_COLOR */
  1456. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top