home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / remind / src / calendar.c next >
Encoding:
C/C++ Source or Header  |  1993-10-12  |  25.6 KB  |  922 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  CALENDAR.C                                                 */
  4. /*                                                             */
  5. /*  The code for generating a calendar.                        */
  6. /*                                                             */
  7. /*  This file is part of REMIND.                               */
  8. /*  Copyright (C) 1992, 1993 by David F. Skoll.                */
  9. /*                                                             */
  10. /***************************************************************/
  11. #include "config.h"
  12. #include <stdio.h>
  13. #include <string.h>
  14. #ifdef HAVE_STDLIB_H
  15. #include <stdlib.h>
  16. #endif
  17. #ifdef HAVE_MALLOC_H
  18. #include <malloc.h>
  19. #endif
  20. #include <ctype.h>
  21. #include "types.h"
  22. #include "protos.h"
  23. #include "expr.h"
  24. #include "globals.h"
  25. #include "err.h"
  26.  
  27. /* Data structures used by the calendar */
  28. typedef struct cal_entry {
  29.    struct cal_entry *next;
  30.    char *text;
  31.    char *pos;
  32.    int time;
  33.    int priority;
  34. } CalEntry;
  35.  
  36. /* Global variables */
  37. static CalEntry *CalColumn[7];
  38. static CalEntry *CalPs[7];
  39.  
  40. static int ColSpaces;
  41.  
  42. PRIVATE void SortCol ARGS((CalEntry **col));
  43. PRIVATE void DoCalendarOneWeek ARGS ((void));
  44. PRIVATE void DoCalendarOneMonth ARGS ((void));
  45. PRIVATE int WriteCalendarRow ARGS ((void));
  46. PRIVATE void PrintLeft ARGS ((char *s, int width, char pad));
  47. PRIVATE void PrintCentered ARGS ((char *s, int width, char pad));
  48. PRIVATE int WriteOneCalLine ARGS ((void));
  49. PRIVATE int WriteOneColLine ARGS ((int col));
  50. PRIVATE void GenerateCalEntries ARGS ((int col));
  51. PRIVATE void WriteCalHeader ARGS ((void));
  52. PRIVATE void WriteCalTrailer ARGS ((void));
  53. PRIVATE int DoCalRem ARGS ((ParsePtr p, int col));
  54. PRIVATE void WriteSimpleEntries ARGS ((int col, int jul));
  55. PRIVATE void WriteSolidCalLine ARGS ((void));
  56. PRIVATE void WriteIntermediateCalLine ARGS ((void));
  57. PRIVATE void WriteCalDays ARGS ((void));
  58.  
  59. /***************************************************************/
  60. /*                                                             */
  61. /*  ProduceCalendar                                            */
  62. /*                                                             */
  63. /*  Main loop for generating a calendar.                       */
  64. /*                                                             */
  65. /***************************************************************/
  66. #ifdef HAVE_PROTOS
  67. PUBLIC void ProduceCalendar(void)
  68. #else
  69. void ProduceCalendar()
  70. #endif
  71. {
  72.    int y, m, d;
  73.  
  74.    ShouldCache = 1;
  75.  
  76.    ColSpaces = (CalWidth - 9) / 7;
  77.    CalWidth = 7*ColSpaces + 8;
  78.  
  79.    if (CalMonths) {
  80.       FromJulian(JulianToday, &y, &m, &d);
  81.       JulianToday = Julian(y, m, 1);   
  82.       while (CalMonths--)
  83.          DoCalendarOneMonth();
  84.       return;
  85.    } else {
  86.       if (MondayFirst) JulianToday -= (JulianToday%7);
  87.       else             JulianToday -= ((JulianToday+1)%7);
  88.  
  89.       if (!DoSimpleCalendar) {
  90.          WriteIntermediateCalLine();
  91.          WriteCalDays();
  92.          WriteIntermediateCalLine();
  93.       }
  94.  
  95.       while (CalWeeks--)
  96.          DoCalendarOneWeek();
  97.       return;
  98.    }
  99. }
  100.  
  101. /***************************************************************/
  102. /*                                                             */
  103. /*  DoCalendarOneWeek                                          */
  104. /*                                                             */
  105. /*  Write a calendar for a single week                         */
  106. /*                                                             */
  107. /***************************************************************/
  108. #ifdef HAVE_PROTOS
  109. PRIVATE void DoCalendarOneWeek(void)
  110. #else
  111. static void DoCalendarOneWeek()
  112. #endif
  113. {
  114.    int y, m, d, done, i, l, wd;
  115.    char buf[81];
  116.    int LinesWritten = 0;
  117.    int OrigJul = JulianToday;
  118.  
  119. /* Fill in the column entries */
  120.    for (i=0; i<7; i++) {
  121.       GenerateCalEntries(i);
  122.       JulianToday++;
  123.    }
  124.  
  125. /* Output the entries */
  126.  
  127. /* If it's "Simple Calendar" format, do it simply... */
  128.    if (DoSimpleCalendar) {
  129.       if (MondayFirst) wd = JulianToday % 7;
  130.       else             wd = (JulianToday + 1) % 7;
  131.       for (i=0; i<7; i++) {
  132.          WriteSimpleEntries(i, OrigJul+i-wd);
  133.       }
  134.       return;
  135.    }
  136.  
  137. /* Here come the first few lines... */
  138.    putchar('|');
  139.    for (i=0; i<7; i++) {
  140.       FromJulian(OrigJul+i, &y, &m, &d);
  141.       sprintf(buf, "%d %c%c%c ", d, MonthName[m][0], MonthName[m][1], 
  142.                                    MonthName[m][2]);
  143.       if (OrigJul+i == RealToday)                  
  144.          PrintLeft(buf, ColSpaces, '*');
  145.       else
  146.          PrintLeft(buf, ColSpaces, ' ');
  147.       putchar('|');
  148.    }
  149.    putchar('\n');
  150.    for (l=0; l<CalPad; l++) {
  151.       putchar('|');
  152.       for (i=0; i<7; i++) {
  153.          PrintLeft("", ColSpaces, ' ');
  154.          putchar('|');
  155.       }
  156.       putchar('\n');
  157.    }
  158.  
  159. /* Write the body lines */
  160.    done = 0;
  161.    while (!done) {
  162.       done = WriteOneCalLine();
  163.       LinesWritten++;
  164.    }
  165.  
  166. /* Write any blank lines required */
  167.    while (LinesWritten++ < CalLines) {
  168.       putchar('|');
  169.       for (i=0; i<7; i++) {
  170.          PrintLeft("", ColSpaces, ' ');
  171.          putchar('|');
  172.       }
  173.       putchar('\n');
  174.    }
  175.  
  176. /* Write the final line */   
  177.    WriteIntermediateCalLine();
  178. }
  179.  
  180. /***************************************************************/
  181. /*                                                             */
  182. /*  DoCalendarOneMonth                                         */
  183. /*                                                             */
  184. /*  Produce a calendar for the current month.                  */
  185. /*                                                             */
  186. /***************************************************************/
  187. #ifdef HAVE_PROTOS
  188. PRIVATE void DoCalendarOneMonth(void)
  189. #else
  190. static void DoCalendarOneMonth()
  191. #endif
  192. {
  193.    int y, m, d, mm, yy;
  194.  
  195.    if (!DoSimpleCalendar) WriteCalHeader();
  196.  
  197.    if (PsCal) {
  198.       FromJulian(JulianToday, &y, &m, &d);
  199.       printf("%s\n", PSBEGIN);
  200.       printf("%s %d %d %d\n",
  201.               MonthName[m], y, DaysInMonth(m, y), (JulianToday+1) % 7);
  202.       mm = m-1;
  203.       if (mm<0) {
  204.          mm = 11; yy = y-1;
  205.       } else yy=y;
  206.  
  207.       printf("%s %d\n", MonthName[mm], DaysInMonth(mm,yy));
  208.       mm = m+1;
  209.       if (mm>11) {
  210.          mm = 0; yy = y+1;
  211.       } else yy=y;
  212.       printf("%s %d\n", MonthName[mm], DaysInMonth(mm,yy));
  213.    }
  214.    while (WriteCalendarRow()) continue;
  215.  
  216.    if (PsCal) printf("%s\n", PSEND);
  217.    if (!DoSimpleCalendar) WriteCalTrailer();
  218. }   
  219.  
  220. /***************************************************************/
  221. /*                                                             */
  222. /*  WriteCalendarRow                                           */
  223. /*                                                             */
  224. /*  Write one row of the calendar                              */
  225. /*                                                             */
  226. /***************************************************************/
  227. #ifdef HAVE_PROTOS
  228. PRIVATE int WriteCalendarRow(void)
  229. #else
  230. static int WriteCalendarRow()
  231. #endif
  232. {
  233.    int y, m, d, wd, i, l;
  234.    int done;
  235.    char buf[81];
  236.    int OrigJul = JulianToday;
  237.    int LinesWritten = 0;
  238.  
  239. /* Get the date of the first day */
  240.    FromJulian(JulianToday, &y, &m, &d);
  241.    if (!MondayFirst) wd = (JulianToday + 1) % 7;
  242.    else             wd = JulianToday % 7;
  243.  
  244. /* Fill in the column entries */
  245.    for (i=wd; i<7; i++) {
  246.       if (d+i-wd > DaysInMonth(m, y)) break;
  247.       GenerateCalEntries(i);
  248.       JulianToday++;
  249.    }
  250.  
  251. /* Output the entries */
  252.  
  253. /* If it's "Simple Calendar" format, do it simply... */
  254.    if (DoSimpleCalendar) {
  255.       for (i=wd; i<7 && d+i-wd<=DaysInMonth(m, y); i++) {
  256.          WriteSimpleEntries(i, OrigJul+i-wd);
  257.       }
  258.       return (d+7-wd <= DaysInMonth(m, y));
  259.    }
  260.  
  261.  
  262. /* Here come the first few lines... */
  263.    putchar('|');
  264.    for (i=0; i<7; i++) {
  265.       if (i < wd || d+i-wd>DaysInMonth(m, y))
  266.          PrintLeft("", ColSpaces, ' ');
  267.       else {
  268.          sprintf(buf, "%d", d+i-wd);
  269.      PrintLeft(buf, ColSpaces, ' ');
  270.       }
  271.       putchar('|');
  272.    }
  273.    putchar('\n');
  274.    for (l=0; l<CalPad; l++) {
  275.       putchar('|');
  276.       for (i=0; i<7; i++) {
  277.          PrintLeft("", ColSpaces, ' ');
  278.          putchar('|');
  279.       }
  280.       putchar('\n');
  281.    }
  282.  
  283. /* Write the body lines */
  284.    done = 0;
  285.    while (!done) {
  286.       done = WriteOneCalLine();
  287.       LinesWritten++;
  288.    }
  289.  
  290. /* Write any blank lines required */
  291.    while (LinesWritten++ < CalLines) {
  292.       putchar('|');
  293.       for (i=0; i<7; i++) {
  294.          PrintLeft("", ColSpaces, ' ');
  295.          putchar('|');
  296.       }
  297.       putchar('\n');
  298.    }
  299.  
  300.    WriteIntermediateCalLine();
  301.  
  302. /* Return non-zero if we have not yet finished */
  303.    return (d+7-wd <= DaysInMonth(m, y));
  304. }
  305.  
  306. /***************************************************************/
  307. /*                                                             */
  308. /*  PrintLeft                                                  */
  309. /*                                                             */
  310. /*  Left-justify a piece of text.                              */
  311. /*                                                             */
  312. /***************************************************************/
  313. #ifdef HAVE_PROTOS
  314. PRIVATE void PrintLeft(char *s, int width, char pad)
  315. #else
  316. static void PrintLeft(s, width, pad)
  317. char *s;
  318. int width;
  319. char pad;
  320. #endif
  321. {
  322.    int len = strlen(s);
  323.    printf("%s", s);
  324.    while (len++ < width) putchar(pad);
  325. }
  326.  
  327. /***************************************************************/
  328. /*                                                             */
  329. /*  PrintCentered                                              */
  330. /*                                                             */
  331. /*  Center a piec of text                                      */
  332. /*                                                             */
  333. /***************************************************************/
  334. #ifdef HAVE_PROTOS
  335. PRIVATE void PrintCentered(char *s, int width, char pad)
  336. #else
  337. static void PrintCentered(s, width, pad)
  338. char *s;
  339. int width;
  340. char pad;
  341. #endif
  342. {
  343.    int len = strlen(s);
  344.    int d = (width - len) / 2;
  345.    int i;
  346.  
  347.    for (i=0; i<d; i++) putchar(pad);
  348.    for (i=0; i<width; i++) {
  349.       if (*s) putchar(*s++); else break;
  350.    }
  351.    for (i=d+len; i<width; i++) putchar(pad);
  352. }
  353.  
  354. /***************************************************************/
  355. /*                                                             */
  356. /*  WriteOneCalLine                                            */
  357. /*                                                             */
  358. /*  Write a single line.                                       */
  359. /*                                                             */
  360. /***************************************************************/
  361. #ifdef HAVE_PROTOS
  362. PRIVATE int WriteOneCalLine(void)
  363. #else
  364. static int WriteOneCalLine()
  365. #endif
  366. {
  367.    int done = 1, i;
  368.  
  369.    putchar('|');
  370.    for (i=0; i<7; i++) {
  371.       if (CalColumn[i]) {
  372.          if (WriteOneColLine(i)) done = 0;
  373.       } else {
  374.          PrintCentered("", ColSpaces, ' ');
  375.       }
  376.       putchar('|');
  377.    }
  378.    putchar('\n');
  379.  
  380.    return done;
  381. }
  382.  
  383.      
  384. /***************************************************************/
  385. /*                                                             */
  386. /*  WriteOneColLine                                            */
  387. /*                                                             */
  388. /*  Write a single line for a specified column.  Return 1 if   */
  389. /*  the column still has entries; 0 otherwise.                 */
  390. /*                                                             */
  391. /***************************************************************/
  392. #ifdef HAVE_PROTOS
  393. PRIVATE int WriteOneColLine(int col)
  394. #else
  395. static int WriteOneColLine(col)
  396. int col;
  397. #endif
  398. {
  399.    CalEntry *e = CalColumn[col];
  400.    char *s;
  401.    char *space;
  402.    int numwritten = 0;
  403.  
  404. /* Print as many characters as possible within the column */
  405.    space = NULL;
  406.    s = e->pos;
  407.  
  408. /* If we're at the end, and there's another entry, do a blank line and move
  409.    to next entry. */
  410.    if (!*s && e->next) {
  411.       PrintLeft("", ColSpaces, ' ');
  412.       CalColumn[col] = e->next;
  413.       free(e->text);
  414.       free(e);
  415.       return 1;
  416.    }
  417.  
  418. /* Find the last space char within the column. */
  419.    while (s - e->pos <= ColSpaces) {
  420.       if (!*s) {space = s; break;}
  421.       if (*s == ' ') space = s;
  422.       s++;
  423.    }
  424.  
  425. /* If we couldn't find a space char, print what we have. */
  426.    if (!space) {
  427.       for (s = e->pos; s - e->pos < ColSpaces; s++) {
  428.          if (!*s) break;
  429.      numwritten++;
  430.          putchar(*s);
  431.       }
  432.       e->pos = s;
  433.    } else {
  434.  
  435. /* We found a space - print everything before it. */
  436.       for (s = e->pos; s<space; s++) {
  437.          if (!*s) break;
  438.      numwritten++;
  439.      putchar(*s);
  440.       }
  441.    }
  442.  
  443. /* Flesh out the rest of the column */
  444.    while(numwritten++ < ColSpaces) putchar(' ');
  445.  
  446. /* Skip any spaces before next word */
  447.    while (*s == ' ') s++;
  448.  
  449. /* If done, free memory if no next entry. */
  450.    if (!*s && !e->next) {
  451.       CalColumn[col] = e->next;
  452.       free(e->text);
  453.       free(e);
  454.    } else {
  455.       e->pos = s;
  456.    }
  457.    if (CalColumn[col]) return 1; else return 0;
  458. }
  459.  
  460. /***************************************************************/
  461. /*                                                             */
  462. /*  GenerateCalEntries                                         */
  463. /*                                                             */
  464. /*  Generate the calendar entries for the ith column           */
  465. /*                                                             */
  466. /***************************************************************/
  467. #ifdef HAVE_PROTOS
  468. PRIVATE void GenerateCalEntries(int col)
  469. #else
  470. static void GenerateCalEntries(col)
  471. int col;
  472. #endif
  473. {
  474.    int r;
  475.    Token tok;
  476.    char *s;
  477.    Parser p;
  478.  
  479. /* Do some initialization first... */
  480.    ClearGlobalOmits();
  481.    DestroyOmitContexts();
  482.    DestroyVars(0);
  483.    NumTriggered = 0;
  484.  
  485.    r=OpenFile(InitialFile);
  486.    if (r) {
  487.       fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING], InitialFile, ErrMsg[r]);
  488.       exit(1);
  489.    }
  490.  
  491.    while(1) {
  492.       r = ReadLine();
  493.       if (r == E_EOF) return;
  494.       if (r) {
  495.      Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]);
  496.      exit(1);
  497.       }
  498.       s = FindInitialToken(&tok, CurLine);
  499.  
  500.       /* Should we ignore it? */
  501.       if (NumIfs &&
  502.           tok.type != T_If &&
  503.           tok.type != T_Else &&
  504.           tok.type != T_EndIf &&
  505.           tok.type != T_IfTrig &&
  506.           ShouldIgnoreLine())
  507.       {
  508.       /* DO NOTHING */
  509.       }
  510.       else {
  511.          /* Create a parser to parse the line */
  512.          CreateParser(s, &p);
  513.  
  514.          switch(tok.type) {
  515.  
  516.             case T_Empty:
  517.         case T_Comment:
  518.            break;
  519.  
  520.         case T_ErrMsg:  r=DoErrMsg(&p);  break;
  521.         case T_Rem:     r=DoCalRem(&p, col); break;
  522.         case T_If:      r=DoIf(&p);      break;
  523.         case T_IfTrig:  r=DoIfTrig(&p);  break;
  524.         case T_Else:    r=DoElse(&p);    break;
  525.         case T_EndIf:   r=DoEndif(&p);   break;
  526.         case T_Include: r=DoInclude(&p); break;
  527.         case T_Exit:    DoExit(&p);         break;
  528.         case T_Set:     r=DoSet(&p);     break;
  529.         case T_Fset:    r=DoFset(&p);    break;
  530.         case T_UnSet:   r=DoUnset(&p);   break;
  531.         case T_Clr:     r=DoClear(&p);   break;
  532.         case T_Flush:   r=DoFlush(&p);   break;
  533.             case T_Debug:   break;  /* IGNORE DEBUG CMD */
  534.         case T_Dumpvars: break; /* IGNORE DUMPVARS CMD */
  535.         case T_Banner:  break;  /* IGNORE BANNER CMD */
  536.         case T_Omit:    r=DoOmit(&p);
  537.                        if (r == E_PARSE_AS_REM) {
  538.                    DestroyParser(&p);
  539.                    CreateParser(s, &p);
  540.                    r=DoCalRem(&p, col);
  541.                 }
  542.                             break;
  543.         case T_Pop:     r=PopOmitContext(&p);     break;
  544.         case T_Push:    r=PushOmitContext(&p);    break;
  545.             case T_Preserve: r=DoPreserve(&p);        break;
  546.         case T_RemType: if (tok.val == RUN_TYPE) {
  547.                                r=DoRun(&p);
  548.                                break;
  549.                  } else {
  550.                     CreateParser(CurLine, &p);
  551.                 r=DoCalRem(&p, col);
  552.                 break;
  553.                  }
  554.  
  555.      /* If we don't recognize the command, do a REM by default */
  556.      /* Note:  Since the parser hasn't been used yet, we don't */
  557.      /* need to destroy it here. */
  558.  
  559.         default:        CreateParser(CurLine, &p);
  560.                 r=DoCalRem(&p, col);
  561.                 break;
  562.          }
  563.          if (r && (!Hush || r != E_RUN_DISABLED)) Eprint("%s", ErrMsg[r]);
  564.  
  565.          /* Destroy the parser - free up resources it may be tying up */
  566.          DestroyParser(&p);
  567.       }
  568.    }
  569. }
  570.  
  571.  
  572. /***************************************************************/
  573. /*                                                             */
  574. /*  WriteCalHeader                                             */
  575. /*                                                             */
  576. /***************************************************************/
  577. #ifdef HAVE_PROTOS
  578. PRIVATE void WriteCalHeader(void)
  579. #else
  580. static void WriteCalHeader()
  581. #endif
  582. {
  583.    char buf[80];
  584.    int y, m, d;
  585.  
  586.    FromJulian(JulianToday, &y, &m, &d);
  587.    sprintf(buf, "%s %d", MonthName[m], y);
  588.  
  589.    WriteSolidCalLine();
  590.  
  591.    putchar('|');
  592.    PrintCentered(buf, CalWidth-2, ' ');
  593.    putchar('|');
  594.    putchar('\n');
  595.  
  596.    WriteIntermediateCalLine();
  597.    WriteCalDays();
  598.    WriteIntermediateCalLine();
  599. }
  600.  
  601. /***************************************************************/
  602. /*                                                             */
  603. /*  WriteCalTrailer                                            */
  604. /*                                                             */
  605. /***************************************************************/
  606. #ifdef HAVE_PROTOS
  607. PRIVATE void WriteCalTrailer(void)
  608. #else
  609. static void WriteCalTrailer()
  610. #endif
  611. {
  612.    putchar('\f');
  613. }
  614.  
  615. /***************************************************************/
  616. /*                                                             */
  617. /*  DoCalRem                                                   */
  618. /*                                                             */
  619. /*  Do the REM command in the context of a calendar.           */
  620. /*                                                             */
  621. /***************************************************************/
  622. #ifdef HAVE_PROTOS
  623. PRIVATE int DoCalRem(ParsePtr p, int col)
  624. #else
  625. static int DoCalRem(p, col)
  626. ParsePtr p;
  627. int col;
  628. #endif
  629. {
  630.  
  631.    Trigger trig;
  632.    TimeTrig tim;
  633.    Value v;
  634.    int r;
  635.    int jul;
  636.    CalEntry *CurCol = CalColumn[col];
  637.    CalEntry *CurPs = CalPs[col];
  638.    CalEntry *e;
  639.    char *s, *s2;
  640.    static char buf[TOKSIZE];
  641.    static char obuf[LINELEN];
  642.    Token tok;
  643.  
  644.    /* Parse the trigger date and time */
  645.    if ( (r=ParseRem(p, &trig, &tim)) ) return r;
  646.  
  647. /* Don't include timed reminders in calendar if -a option supplied. */
  648. #ifdef HAVE_QUEUED
  649.    if (DontIssueAts && tim.ttime != NO_TIME) return OK;
  650. #endif
  651.    if (trig.typ == NO_TYPE) return E_EOLN;
  652.    if (trig.typ == SAT_TYPE) {
  653.       r=DoSatRemind(&trig, &tim, p);
  654.       if (r) return r;
  655.       r=ParseToken(p, buf);
  656.       if (r) return r;
  657.       FindToken(buf, &tok);
  658.       if (tok.type == T_Empty || tok.type == T_Comment) return OK;
  659.       if (tok.type != T_RemType || tok.val == SAT_TYPE) return E_PARSE_ERR;
  660.       trig.typ = tok.val;
  661.       jul = LastTriggerDate;
  662.       if (!LastTrigValid) return OK;
  663.    } else {
  664.    /* Calculate the trigger date */
  665.       jul = ComputeTrigger(trig.scanfrom, &trig, &r);
  666.       if (r) return r;
  667.    }
  668.  
  669.    if (!PsCal && (trig.typ == PS_TYPE || trig.typ == PSF_TYPE)) return OK;
  670.  
  671.    /* Remove any "at" times from PS or PSFILE reminders */
  672.    if (trig.typ == PS_TYPE || trig.typ == PSF_TYPE) tim.ttime = NO_TIME;
  673.  
  674.    /* If trigger date == today, add it to the current entry */   
  675.    if (jul == JulianToday) {
  676.       NumTriggered++;
  677.       s = obuf;
  678.       *s = 0;
  679.       if (DoSimpleCalendar || tim.ttime != NO_TIME)
  680.          s += strlen(SimpleTime(tim.ttime, s));
  681.       if (trig.typ != PS_TYPE && trig.typ != PSF_TYPE &&
  682.           UserFuncExists("calprefix")==1) {
  683.          sprintf(buf, "calprefix(%d)", trig.priority);
  684.      s2 = buf;
  685.      r = EvalExpr(&s2, &v);
  686.      if (!r) {
  687.         if (!DoCoerce(STR_TYPE, &v)) {
  688.            strcat(s, v.v.str);
  689.            s += strlen(s);
  690.             }
  691.         DestroyValue(&v);
  692.          }
  693.       }
  694.       if ( (r=DoSubst(p, s, &trig, &tim, jul, CAL_MODE)) ) return r;
  695.       if (!*s) return OK;
  696.       if (trig.typ != PS_TYPE && trig.typ != PSF_TYPE &&
  697.           UserFuncExists("calsuffix")==1) {
  698.          sprintf(buf, "calsuffix(%d)", trig.priority);
  699.      s2 = buf;
  700.      r = EvalExpr(&s2, &v);
  701.      if (!r) {
  702.         if (!DoCoerce(STR_TYPE, &v)) {
  703.            strcat(s, v.v.str);
  704.            s += strlen(s);
  705.             }
  706.         DestroyValue(&v);
  707.          }
  708.       }
  709.       s = obuf;
  710.       if (!DoSimpleCalendar) while (isspace(*s)) s++;
  711.       e = NEW(CalEntry);
  712.       if (!e) return E_NO_MEM;
  713.       e->text = StrDup(s);
  714.       if (!e->text) {
  715.          free(e);
  716.      return E_NO_MEM;
  717.       }
  718.       e->priority = trig.priority;
  719.       if (trig.typ == PS_TYPE || trig.typ == PSF_TYPE) {
  720.          e->pos = (trig.typ == PS_TYPE) ? "P" : "F";
  721.      e->time = NO_TIME;
  722.      e->next = CurPs;
  723.      CalPs[col] = e;
  724.      SortCol(&CalPs[col]);
  725.       } else {
  726.          e->pos = e->text;
  727.          e->time = tim.ttime;
  728.          e->next = CurCol;
  729.          CalColumn[col] = e;
  730.          SortCol(&CalColumn[col]);
  731.       }
  732.    }
  733.    return OK;
  734. }
  735.  
  736. /***************************************************************/
  737. /*                                                             */
  738. /*  WriteSimpleEntries                                         */
  739. /*                                                             */
  740. /*  Write entries in 'simple calendar' format.                 */
  741. /*                                                             */
  742. /***************************************************************/
  743. #ifdef HAVE_PROTOS
  744. PRIVATE void WriteSimpleEntries(int col, int jul)
  745. #else
  746. static void WriteSimpleEntries(col, jul)
  747. int col, jul;
  748. #endif
  749. {
  750.    CalEntry *e = CalPs[col];
  751.    CalEntry *n;
  752.    int y, m, d;
  753.  
  754. /* Do all the PostScript entries first, if any */
  755.    FromJulian(jul, &y, &m, &d);
  756.    while(e) {
  757.       printf("%c%c%c%c%c%02d%c%02d ", *(e->pos), *(e->pos),
  758.                                      *(e->pos), *(e->pos), DATESEP,
  759.                      m+1, DATESEP, d);
  760.       printf("%s\n", e->text);
  761.       free(e->text);
  762.       n = e->next;
  763.       free(e);
  764.       e = n;
  765.    }
  766.    CalPs[col] = NULL;
  767.  
  768.    e = CalColumn[col];                     
  769.    while(e) {
  770.       printf("%04d%c%02d%c%02d ", y, DATESEP, m+1, DATESEP, d);
  771.       printf("%s\n", e->text);
  772.       free(e->text);
  773.       n = e->next;
  774.       free(e);
  775.       e = n;
  776.    }
  777.    CalColumn[col] = NULL;
  778. }
  779.  
  780. /***************************************************************/
  781. /*                                                             */
  782. /*  Various functions for writing different types of lines.    */
  783. /*                                                             */
  784. /***************************************************************/
  785. #ifdef HAVE_PROTOS
  786. PRIVATE void WriteSolidCalLine(void)
  787. #else
  788. static void WriteSolidCalLine()
  789. #endif
  790. {
  791.    putchar('+');
  792.    PrintCentered("", CalWidth-2, '-');
  793.    putchar('+');
  794.    putchar('\n');
  795. }
  796.  
  797. #ifdef HAVE_PROTOS
  798. PRIVATE void WriteIntermediateCalLine(void)
  799. #else
  800. static void WriteIntermediateCalLine()
  801. #endif
  802. {
  803.    int i;
  804.  
  805.    putchar('+');
  806.    for (i=0; i<7; i++) {
  807.       PrintCentered("", ColSpaces, '-');
  808.       putchar('+');
  809.    }
  810.    putchar('\n');
  811. }
  812.  
  813. #ifdef HAVE_PROTOS
  814. PRIVATE void WriteCalDays(void)
  815. #else
  816. static void WriteCalDays()
  817. #endif
  818. {
  819.    int i;
  820.    putchar('|');
  821.    for (i=0; i<7; i++) {
  822.       if (!MondayFirst)
  823.          PrintCentered(DayName[(i+6)%7], ColSpaces, ' ');
  824.       else
  825.          PrintCentered(DayName[i%7], ColSpaces, ' ');
  826.       putchar('|');
  827.    }
  828.    putchar('\n');
  829. }
  830.  
  831. /***************************************************************/
  832. /*                                                             */
  833. /*  SimpleTime                                                 */
  834. /*                                                             */
  835. /*  Format the time according to simple time format.           */
  836. /*  If out is NULL, result placed in internal static buffer.   */
  837. /*  A trailing space is always added.                          */
  838. /*                                                             */
  839. /***************************************************************/
  840. #ifdef HAVE_PROTOS
  841. PUBLIC char *SimpleTime(int tim, char *out)
  842. #else
  843. char *SimpleTime(tim, out)
  844. int tim;
  845. char *out;
  846. #endif
  847. {
  848.    static buf[9];
  849.    int h, min, hh;
  850.    
  851.    if (!out) out = (char *) buf;
  852.  
  853.    *out = 0;
  854.    
  855.    switch(ScFormat) {
  856.  
  857.       case SC_AMPM:
  858.      if (tim == NO_TIME) sprintf(out, "        ");
  859.      else {
  860.         h = tim / 60;
  861.         min = tim % 60;
  862.         if (h == 0) hh=12;
  863.         else if (h > 12) hh=h-12;
  864.         else hh=h;
  865.         sprintf(out, "%2d%c%02d%s ", hh, TIMESEP, min, (h>=12) ? L_PM : L_AM);
  866.          }
  867.      break;
  868.  
  869.       case SC_MIL:
  870.      if (tim == NO_TIME) sprintf(out, "      ");
  871.      else {
  872.         h = tim / 60;
  873.         min = tim % 60;
  874.         sprintf(out, "%02d%c%02d ", h, TIMESEP, min);
  875.          }
  876.      break;
  877.    }
  878.    return out;
  879. }
  880.  
  881. /***************************************************************/
  882. /*                                                             */
  883. /*  SortCol                                                    */
  884. /*                                                             */
  885. /*  Sort the calendar entries in a column by time and priority */
  886. /*                                                             */
  887. /***************************************************************/
  888. #ifdef HAVE_PROTOS
  889. PRIVATE void SortCol(CalEntry **col)
  890. #else
  891. static void SortCol(col)
  892. CalEntry **col;
  893. #endif
  894. {
  895.    CalEntry *cur, *prev, *next;
  896.  
  897.    cur = *col;
  898.    prev = NULL;
  899.  
  900. /* Note that we use <= comparison rather than > comparison to preserve the
  901.    file order of reminders which have the same time and priority */
  902.  
  903.    while (cur->next &&
  904.           CompareRems(0, cur->time, cur->priority,
  905.                   0, cur->next->time, cur->next->priority,
  906.               SortByDate, SortByTime, SortByPrio) <= 0) {
  907.       next = cur->next;
  908.    /* Swap cur and next */
  909.       if (!prev) {
  910.          *col = next;
  911.      cur->next = next->next;
  912.      next->next = cur;
  913.      prev = next;
  914.       } else {
  915.          prev->next = next;
  916.      cur->next = next->next;
  917.      next->next = cur;
  918.      prev = next;
  919.       }
  920.    }
  921. }
  922.