This is calendar.c in view mode; [Download] [Up]
/***************************************************************/ /* */ /* CALENDAR.C */ /* */ /* The code for generating a calendar. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992, 1993, 1994 by David F. Skoll. */ /* */ /***************************************************************/ #include "config.h" #include <stdio.h> #include <string.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #ifdef HAVE_MALLOC_H #include <malloc.h> #endif #include <ctype.h> #include "types.h" #include "protos.h" #include "expr.h" #include "globals.h" #include "err.h" /* Data structures used by the calendar */ typedef struct cal_entry { struct cal_entry *next; char *text; char *pos; int time; int priority; } CalEntry; /* Global variables */ static CalEntry *CalColumn[7]; static CalEntry *CalPs[7]; static int ColSpaces; PRIVATE void SortCol ARGS((CalEntry **col)); PRIVATE void DoCalendarOneWeek ARGS ((void)); PRIVATE void DoCalendarOneMonth ARGS ((void)); PRIVATE int WriteCalendarRow ARGS ((void)); PRIVATE void PrintLeft ARGS ((char *s, int width, char pad)); PRIVATE void PrintCentered ARGS ((char *s, int width, char pad)); PRIVATE int WriteOneCalLine ARGS ((void)); PRIVATE int WriteOneColLine ARGS ((int col)); PRIVATE void GenerateCalEntries ARGS ((int col)); PRIVATE void WriteCalHeader ARGS ((void)); PRIVATE void WriteCalTrailer ARGS ((void)); PRIVATE int DoCalRem ARGS ((ParsePtr p, int col)); PRIVATE void WriteSimpleEntries ARGS ((int col, int jul)); PRIVATE void WriteSolidCalLine ARGS ((void)); PRIVATE void WriteIntermediateCalLine ARGS ((void)); PRIVATE void WriteCalDays ARGS ((void)); /***************************************************************/ /* */ /* ProduceCalendar */ /* */ /* Main loop for generating a calendar. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void ProduceCalendar(void) #else void ProduceCalendar() #endif { int y, m, d; ShouldCache = 1; ColSpaces = (CalWidth - 9) / 7; CalWidth = 7*ColSpaces + 8; if (CalMonths) { FromJulian(JulianToday, &y, &m, &d); JulianToday = Julian(y, m, 1); while (CalMonths--) DoCalendarOneMonth(); return; } else { if (MondayFirst) JulianToday -= (JulianToday%7); else JulianToday -= ((JulianToday+1)%7); if (!DoSimpleCalendar) { WriteIntermediateCalLine(); WriteCalDays(); WriteIntermediateCalLine(); } while (CalWeeks--) DoCalendarOneWeek(); return; } } /***************************************************************/ /* */ /* DoCalendarOneWeek */ /* */ /* Write a calendar for a single week */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void DoCalendarOneWeek(void) #else static void DoCalendarOneWeek() #endif { int y, m, d, done, i, l, wd; char buf[81]; int LinesWritten = 0; int OrigJul = JulianToday; /* Fill in the column entries */ for (i=0; i<7; i++) { GenerateCalEntries(i); JulianToday++; } /* Output the entries */ /* If it's "Simple Calendar" format, do it simply... */ if (DoSimpleCalendar) { if (MondayFirst) wd = JulianToday % 7; else wd = (JulianToday + 1) % 7; for (i=0; i<7; i++) { WriteSimpleEntries(i, OrigJul+i-wd); } return; } /* Here come the first few lines... */ putchar('|'); for (i=0; i<7; i++) { FromJulian(OrigJul+i, &y, &m, &d); sprintf(buf, "%d %c%c%c ", d, MonthName[m][0], MonthName[m][1], MonthName[m][2]); if (OrigJul+i == RealToday) PrintLeft(buf, ColSpaces, '*'); else PrintLeft(buf, ColSpaces, ' '); putchar('|'); } putchar('\n'); for (l=0; l<CalPad; l++) { putchar('|'); for (i=0; i<7; i++) { PrintLeft("", ColSpaces, ' '); putchar('|'); } putchar('\n'); } /* Write the body lines */ done = 0; while (!done) { done = WriteOneCalLine(); LinesWritten++; } /* Write any blank lines required */ while (LinesWritten++ < CalLines) { putchar('|'); for (i=0; i<7; i++) { PrintLeft("", ColSpaces, ' '); putchar('|'); } putchar('\n'); } /* Write the final line */ WriteIntermediateCalLine(); } /***************************************************************/ /* */ /* DoCalendarOneMonth */ /* */ /* Produce a calendar for the current month. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void DoCalendarOneMonth(void) #else static void DoCalendarOneMonth() #endif { int y, m, d, mm, yy; if (!DoSimpleCalendar) WriteCalHeader(); if (PsCal) { FromJulian(JulianToday, &y, &m, &d); printf("%s\n", PSBEGIN); printf("%s %d %d %d\n", MonthName[m], y, DaysInMonth(m, y), (JulianToday+1) % 7); mm = m-1; if (mm<0) { mm = 11; yy = y-1; } else yy=y; printf("%s %d\n", MonthName[mm], DaysInMonth(mm,yy)); mm = m+1; if (mm>11) { mm = 0; yy = y+1; } else yy=y; printf("%s %d\n", MonthName[mm], DaysInMonth(mm,yy)); } while (WriteCalendarRow()) continue; if (PsCal) printf("%s\n", PSEND); if (!DoSimpleCalendar) WriteCalTrailer(); } /***************************************************************/ /* */ /* WriteCalendarRow */ /* */ /* Write one row of the calendar */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int WriteCalendarRow(void) #else static int WriteCalendarRow() #endif { int y, m, d, wd, i, l; int done; char buf[81]; int OrigJul = JulianToday; int LinesWritten = 0; /* Get the date of the first day */ FromJulian(JulianToday, &y, &m, &d); if (!MondayFirst) wd = (JulianToday + 1) % 7; else wd = JulianToday % 7; /* Fill in the column entries */ for (i=wd; i<7; i++) { if (d+i-wd > DaysInMonth(m, y)) break; GenerateCalEntries(i); JulianToday++; } /* Output the entries */ /* If it's "Simple Calendar" format, do it simply... */ if (DoSimpleCalendar) { for (i=wd; i<7 && d+i-wd<=DaysInMonth(m, y); i++) { WriteSimpleEntries(i, OrigJul+i-wd); } return (d+7-wd <= DaysInMonth(m, y)); } /* Here come the first few lines... */ putchar('|'); for (i=0; i<7; i++) { if (i < wd || d+i-wd>DaysInMonth(m, y)) PrintLeft("", ColSpaces, ' '); else { sprintf(buf, "%d", d+i-wd); PrintLeft(buf, ColSpaces, ' '); } putchar('|'); } putchar('\n'); for (l=0; l<CalPad; l++) { putchar('|'); for (i=0; i<7; i++) { PrintLeft("", ColSpaces, ' '); putchar('|'); } putchar('\n'); } /* Write the body lines */ done = 0; while (!done) { done = WriteOneCalLine(); LinesWritten++; } /* Write any blank lines required */ while (LinesWritten++ < CalLines) { putchar('|'); for (i=0; i<7; i++) { PrintLeft("", ColSpaces, ' '); putchar('|'); } putchar('\n'); } WriteIntermediateCalLine(); /* Return non-zero if we have not yet finished */ return (d+7-wd <= DaysInMonth(m, y)); } /***************************************************************/ /* */ /* PrintLeft */ /* */ /* Left-justify a piece of text. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void PrintLeft(char *s, int width, char pad) #else static void PrintLeft(s, width, pad) char *s; int width; char pad; #endif { int len = strlen(s); printf("%s", s); while (len++ < width) putchar(pad); } /***************************************************************/ /* */ /* PrintCentered */ /* */ /* Center a piec of text */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void PrintCentered(char *s, int width, char pad) #else static void PrintCentered(s, width, pad) char *s; int width; char pad; #endif { int len = strlen(s); int d = (width - len) / 2; int i; for (i=0; i<d; i++) putchar(pad); for (i=0; i<width; i++) { if (*s) putchar(*s++); else break; } for (i=d+len; i<width; i++) putchar(pad); } /***************************************************************/ /* */ /* WriteOneCalLine */ /* */ /* Write a single line. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int WriteOneCalLine(void) #else static int WriteOneCalLine() #endif { int done = 1, i; putchar('|'); for (i=0; i<7; i++) { if (CalColumn[i]) { if (WriteOneColLine(i)) done = 0; } else { PrintCentered("", ColSpaces, ' '); } putchar('|'); } putchar('\n'); return done; } /***************************************************************/ /* */ /* WriteOneColLine */ /* */ /* Write a single line for a specified column. Return 1 if */ /* the column still has entries; 0 otherwise. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int WriteOneColLine(int col) #else static int WriteOneColLine(col) int col; #endif { CalEntry *e = CalColumn[col]; char *s; char *space; int numwritten = 0; /* Print as many characters as possible within the column */ space = NULL; s = e->pos; /* If we're at the end, and there's another entry, do a blank line and move to next entry. */ if (!*s && e->next) { PrintLeft("", ColSpaces, ' '); CalColumn[col] = e->next; free(e->text); free(e); return 1; } /* Find the last space char within the column. */ while (s - e->pos <= ColSpaces) { if (!*s) {space = s; break;} if (*s == ' ') space = s; s++; } /* If we couldn't find a space char, print what we have. */ if (!space) { for (s = e->pos; s - e->pos < ColSpaces; s++) { if (!*s) break; numwritten++; putchar(*s); } e->pos = s; } else { /* We found a space - print everything before it. */ for (s = e->pos; s<space; s++) { if (!*s) break; numwritten++; putchar(*s); } } /* Flesh out the rest of the column */ while(numwritten++ < ColSpaces) putchar(' '); /* Skip any spaces before next word */ while (*s == ' ') s++; /* If done, free memory if no next entry. */ if (!*s && !e->next) { CalColumn[col] = e->next; free(e->text); free(e); } else { e->pos = s; } if (CalColumn[col]) return 1; else return 0; } /***************************************************************/ /* */ /* GenerateCalEntries */ /* */ /* Generate the calendar entries for the ith column */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void GenerateCalEntries(int col) #else static void GenerateCalEntries(col) int col; #endif { int r; Token tok; char *s; Parser p; /* Do some initialization first... */ ClearGlobalOmits(); DestroyOmitContexts(); DestroyVars(0); NumTriggered = 0; r=OpenFile(InitialFile); if (r) { fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING], InitialFile, ErrMsg[r]); exit(1); } while(1) { r = ReadLine(); if (r == E_EOF) return; if (r) { Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]); exit(1); } s = FindInitialToken(&tok, CurLine); /* Should we ignore it? */ if (NumIfs && tok.type != T_If && tok.type != T_Else && tok.type != T_EndIf && tok.type != T_IfTrig && ShouldIgnoreLine()) { /* DO NOTHING */ } else { /* Create a parser to parse the line */ CreateParser(s, &p); switch(tok.type) { case T_Empty: case T_Comment: break; case T_ErrMsg: r=DoErrMsg(&p); break; case T_Rem: r=DoCalRem(&p, col); break; case T_If: r=DoIf(&p); break; case T_IfTrig: r=DoIfTrig(&p); break; case T_Else: r=DoElse(&p); break; case T_EndIf: r=DoEndif(&p); break; case T_Include: r=DoInclude(&p); break; case T_Exit: DoExit(&p); break; case T_Set: r=DoSet(&p); break; case T_Fset: r=DoFset(&p); break; case T_UnSet: r=DoUnset(&p); break; case T_Clr: r=DoClear(&p); break; case T_Flush: r=DoFlush(&p); break; case T_Debug: break; /* IGNORE DEBUG CMD */ case T_Dumpvars: break; /* IGNORE DUMPVARS CMD */ case T_Banner: break; /* IGNORE BANNER CMD */ case T_Omit: r=DoOmit(&p); if (r == E_PARSE_AS_REM) { DestroyParser(&p); CreateParser(s, &p); r=DoCalRem(&p, col); } break; case T_Pop: r=PopOmitContext(&p); break; case T_Push: r=PushOmitContext(&p); break; case T_Preserve: r=DoPreserve(&p); break; case T_RemType: if (tok.val == RUN_TYPE) { r=DoRun(&p); break; } else { CreateParser(CurLine, &p); r=DoCalRem(&p, col); break; } /* If we don't recognize the command, do a REM by default */ /* Note: Since the parser hasn't been used yet, we don't */ /* need to destroy it here. */ default: CreateParser(CurLine, &p); r=DoCalRem(&p, col); break; } if (r && (!Hush || r != E_RUN_DISABLED)) Eprint("%s", ErrMsg[r]); /* Destroy the parser - free up resources it may be tying up */ DestroyParser(&p); } } } /***************************************************************/ /* */ /* WriteCalHeader */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void WriteCalHeader(void) #else static void WriteCalHeader() #endif { char buf[80]; int y, m, d; FromJulian(JulianToday, &y, &m, &d); sprintf(buf, "%s %d", MonthName[m], y); WriteSolidCalLine(); putchar('|'); PrintCentered(buf, CalWidth-2, ' '); putchar('|'); putchar('\n'); WriteIntermediateCalLine(); WriteCalDays(); WriteIntermediateCalLine(); } /***************************************************************/ /* */ /* WriteCalTrailer */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void WriteCalTrailer(void) #else static void WriteCalTrailer() #endif { putchar('\f'); } /***************************************************************/ /* */ /* DoCalRem */ /* */ /* Do the REM command in the context of a calendar. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int DoCalRem(ParsePtr p, int col) #else static int DoCalRem(p, col) ParsePtr p; int col; #endif { Trigger trig; TimeTrig tim; Value v; int r; int jul; CalEntry *CurCol = CalColumn[col]; CalEntry *CurPs = CalPs[col]; CalEntry *e; char *s, *s2; static char buf[TOKSIZE]; static char obuf[LINELEN]; Token tok; /* Parse the trigger date and time */ if ( (r=ParseRem(p, &trig, &tim)) ) return r; /* Don't include timed reminders in calendar if -a option supplied. */ #ifdef HAVE_QUEUED if (DontIssueAts && tim.ttime != NO_TIME) return OK; #endif if (trig.typ == NO_TYPE) return E_EOLN; if (trig.typ == SAT_TYPE) { r=DoSatRemind(&trig, &tim, p); if (r) return r; r=ParseToken(p, buf); if (r) return r; FindToken(buf, &tok); if (tok.type == T_Empty || tok.type == T_Comment) return OK; if (tok.type != T_RemType || tok.val == SAT_TYPE) return E_PARSE_ERR; trig.typ = tok.val; jul = LastTriggerDate; if (!LastTrigValid) return OK; } else { /* Calculate the trigger date */ jul = ComputeTrigger(trig.scanfrom, &trig, &r); if (r) return r; } if (!PsCal && (trig.typ == PS_TYPE || trig.typ == PSF_TYPE)) return OK; /* Remove any "at" times from PS or PSFILE reminders */ if (trig.typ == PS_TYPE || trig.typ == PSF_TYPE) tim.ttime = NO_TIME; /* If trigger date == today, add it to the current entry */ if (jul == JulianToday) { NumTriggered++; s = obuf; *s = 0; if (DoSimpleCalendar || tim.ttime != NO_TIME) s += strlen(SimpleTime(tim.ttime, s)); if (trig.typ != PS_TYPE && trig.typ != PSF_TYPE && UserFuncExists("calprefix")==1) { sprintf(buf, "calprefix(%d)", trig.priority); s2 = buf; r = EvalExpr(&s2, &v); if (!r) { if (!DoCoerce(STR_TYPE, &v)) { strcat(s, v.v.str); s += strlen(s); } DestroyValue(v); } } if ( (r=DoSubst(p, s, &trig, &tim, jul, CAL_MODE)) ) return r; if (!*s) return OK; if (trig.typ != PS_TYPE && trig.typ != PSF_TYPE && UserFuncExists("calsuffix")==1) { sprintf(buf, "calsuffix(%d)", trig.priority); s2 = buf; r = EvalExpr(&s2, &v); if (!r) { if (!DoCoerce(STR_TYPE, &v)) { strcat(s, v.v.str); s += strlen(s); } DestroyValue(v); } } s = obuf; if (!DoSimpleCalendar) while (isspace(*s)) s++; e = NEW(CalEntry); if (!e) return E_NO_MEM; e->text = StrDup(s); if (!e->text) { free(e); return E_NO_MEM; } e->priority = trig.priority; if (trig.typ == PS_TYPE || trig.typ == PSF_TYPE) { e->pos = (trig.typ == PS_TYPE) ? "P" : "F"; e->time = NO_TIME; e->next = CurPs; CalPs[col] = e; SortCol(&CalPs[col]); } else { e->pos = e->text; e->time = tim.ttime; e->next = CurCol; CalColumn[col] = e; SortCol(&CalColumn[col]); } } return OK; } /***************************************************************/ /* */ /* WriteSimpleEntries */ /* */ /* Write entries in 'simple calendar' format. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void WriteSimpleEntries(int col, int jul) #else static void WriteSimpleEntries(col, jul) int col, jul; #endif { CalEntry *e = CalPs[col]; CalEntry *n; int y, m, d; /* Do all the PostScript entries first, if any */ FromJulian(jul, &y, &m, &d); while(e) { printf("%c%c%c%c%c%02d%c%02d ", *(e->pos), *(e->pos), *(e->pos), *(e->pos), DATESEP, m+1, DATESEP, d); printf("%s\n", e->text); free(e->text); n = e->next; free(e); e = n; } CalPs[col] = NULL; e = CalColumn[col]; while(e) { printf("%04d%c%02d%c%02d ", y, DATESEP, m+1, DATESEP, d); printf("%s\n", e->text); free(e->text); n = e->next; free(e); e = n; } CalColumn[col] = NULL; } /***************************************************************/ /* */ /* Various functions for writing different types of lines. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void WriteSolidCalLine(void) #else static void WriteSolidCalLine() #endif { putchar('+'); PrintCentered("", CalWidth-2, '-'); putchar('+'); putchar('\n'); } #ifdef HAVE_PROTOS PRIVATE void WriteIntermediateCalLine(void) #else static void WriteIntermediateCalLine() #endif { int i; putchar('+'); for (i=0; i<7; i++) { PrintCentered("", ColSpaces, '-'); putchar('+'); } putchar('\n'); } #ifdef HAVE_PROTOS PRIVATE void WriteCalDays(void) #else static void WriteCalDays() #endif { int i; putchar('|'); for (i=0; i<7; i++) { if (!MondayFirst) PrintCentered(DayName[(i+6)%7], ColSpaces, ' '); else PrintCentered(DayName[i%7], ColSpaces, ' '); putchar('|'); } putchar('\n'); } /***************************************************************/ /* */ /* SimpleTime */ /* */ /* Format the time according to simple time format. */ /* If out is NULL, result placed in internal static buffer. */ /* A trailing space is always added. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC char *SimpleTime(int tim, char *out) #else char *SimpleTime(tim, out) int tim; char *out; #endif { static buf[9]; int h, min, hh; if (!out) out = (char *) buf; *out = 0; switch(ScFormat) { case SC_AMPM: if (tim == NO_TIME) sprintf(out, " "); else { h = tim / 60; min = tim % 60; if (h == 0) hh=12; else if (h > 12) hh=h-12; else hh=h; sprintf(out, "%2d%c%02d%s ", hh, TIMESEP, min, (h>=12) ? L_PM : L_AM); } break; case SC_MIL: if (tim == NO_TIME) sprintf(out, " "); else { h = tim / 60; min = tim % 60; sprintf(out, "%02d%c%02d ", h, TIMESEP, min); } break; } return out; } /***************************************************************/ /* */ /* SortCol */ /* */ /* Sort the calendar entries in a column by time and priority */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void SortCol(CalEntry **col) #else static void SortCol(col) CalEntry **col; #endif { CalEntry *cur, *prev, *next; cur = *col; prev = NULL; /* Note that we use <= comparison rather than > comparison to preserve the file order of reminders which have the same time and priority */ while (cur->next && CompareRems(0, cur->time, cur->priority, 0, cur->next->time, cur->next->priority, SortByDate, SortByTime, SortByPrio) <= 0) { next = cur->next; /* Swap cur and next */ if (!prev) { *col = next; cur->next = next->next; next->next = cur; prev = next; } else { prev->next = next; cur->next = next->next; next->next = cur; prev = next; } } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.