Guest User

Untitled

a guest
Jun 13th, 2018
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 51.80 KB | None | 0 0
  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. }
Add Comment
Please, Sign In to add comment