diff --git a/src/calendar.c b/src/calendar.c index 40ccca7c..d584ed21 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -42,7 +42,7 @@ typedef struct cal_entry { int r, g, b; int time; int priority; - char tag[TAG_LEN+1]; + Tag *tags; char passthru[PASSTHRU_LEN+1]; int duration; char const *filename; @@ -941,29 +941,52 @@ static int DoCalRem(ParsePtr p, int col) DBufInit(&pre_buf); /* Parse the trigger date and time */ - if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r; + if ( (r=ParseRem(p, &trig, &tim, 1)) ) { + FreeTrig(&trig); + return r; + } /* Don't include timed reminders in calendar if -a option supplied. */ - if (DontIssueAts && tim.ttime != NO_TIME) return OK; - if (trig.typ == NO_TYPE) return E_EOLN; + if (DontIssueAts && tim.ttime != NO_TIME) { + FreeTrig(&trig); + return OK; + } + if (trig.typ == NO_TYPE) { + FreeTrig(&trig); + return E_EOLN; + } if (trig.typ == SAT_TYPE) { r=DoSatRemind(&trig, &tim, p); if (r) { + FreeTrig(&trig); if (r == E_EXPIRED) return OK; return r; } - if (!LastTrigValid) return OK; + if (!LastTrigValid) { + FreeTrig(&trig); + return OK; + } r=ParseToken(p, &buf); - if (r) return r; + if (r) { + FreeTrig(&trig); + return r; + } FindToken(DBufValue(&buf), &tok); DBufFree(&buf); - if (tok.type == T_Empty || tok.type == T_Comment) return OK; - if (tok.type != T_RemType || tok.val == SAT_TYPE) return E_PARSE_ERR; + if (tok.type == T_Empty || tok.type == T_Comment) { + FreeTrig(&trig); + return OK; + } + if (tok.type != T_RemType || tok.val == SAT_TYPE) { + FreeTrig(&trig); + return E_PARSE_ERR; + } if (tok.val == PASSTHRU_TYPE) { r=ParseToken(p, &buf); if (r) return r; if (!DBufLen(&buf)) { DBufFree(&buf); + FreeTrig(&trig); return E_EOLN; } StrnCpy(trig.passthru, DBufValue(&buf), PASSTHRU_LEN); @@ -971,11 +994,17 @@ static int DoCalRem(ParsePtr p, int col) } trig.typ = tok.val; jul = LastTriggerDate; - if (!LastTrigValid) return OK; + if (!LastTrigValid) { + FreeTrig(&trig); + return OK; + } } else { /* Calculate the trigger date */ jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1); - if (r) return r; + if (r) { + FreeTrig(&trig); + return r; + } } /* Convert PS and PSF to PASSTHRU */ @@ -987,39 +1016,50 @@ static int DoCalRem(ParsePtr p, int col) trig.typ = PASSTHRU_TYPE; } if (trig.typ == PASSTHRU_TYPE) { - if (!PsCal && strcmp(trig.passthru, "COLOR")) return OK; - if (!strcmp(trig.passthru, "COLOR")) { - is_color = 1; - /* Strip off the three color numbers */ - DBufFree(&buf); - r=ParseToken(p, &buf); - DBufPuts(&pre_buf, DBufValue(&buf)); - DBufPutc(&pre_buf, ' '); - DBufFree(&buf); - if (r) return r; - r=ParseToken(p, &buf); - DBufPuts(&pre_buf, DBufValue(&buf)); - DBufPutc(&pre_buf, ' '); - DBufFree(&buf); - if (r) return r; - r=ParseToken(p, &buf); - DBufPuts(&pre_buf, DBufValue(&buf)); - DBufPutc(&pre_buf, ' '); - DBufFree(&buf); - if (r) return r; - (void) sscanf(DBufValue(&pre_buf), "%d %d %d", - &col_r, &col_g, &col_b); - if (col_r < 0) col_r = 0; - else if (col_r > 255) col_r = 255; - if (col_g < 0) col_g = 0; - else if (col_g > 255) col_g = 255; - if (col_b < 0) col_b = 0; - else if (col_b > 255) col_b = 255; - - if (!PsCal && !DoSimpleCalendar) { - DBufFree(&pre_buf); - } - } + if (!PsCal && strcmp(trig.passthru, "COLOR")) { + FreeTrig(&trig); + return OK; + } + if (!strcmp(trig.passthru, "COLOR")) { + is_color = 1; + /* Strip off the three color numbers */ + DBufFree(&buf); + r=ParseToken(p, &buf); + DBufPuts(&pre_buf, DBufValue(&buf)); + DBufPutc(&pre_buf, ' '); + DBufFree(&buf); + if (r) { + FreeTrig(&trig); + return r; + } + r=ParseToken(p, &buf); + DBufPuts(&pre_buf, DBufValue(&buf)); + DBufPutc(&pre_buf, ' '); + DBufFree(&buf); + if (r) { + FreeTrig(&trig); + return r; + } + r=ParseToken(p, &buf); + DBufPuts(&pre_buf, DBufValue(&buf)); + DBufPutc(&pre_buf, ' '); + DBufFree(&buf); + if (r) { + FreeTrig(&trig); + return r; + } + (void) sscanf(DBufValue(&pre_buf), "%d %d %d", + &col_r, &col_g, &col_b); + if (col_r < 0) col_r = 0; + else if (col_r > 255) col_r = 255; + if (col_g < 0) col_g = 0; + else if (col_g > 255) col_g = 255; + if (col_b < 0) col_b = 0; + else if (col_b > 255) col_b = 255; + if (!PsCal && !DoSimpleCalendar) { + DBufFree(&pre_buf); + } + } } /* If trigger date == today, add it to the current entry */ @@ -1037,12 +1077,14 @@ static int DoCalRem(ParsePtr p, int col) if (DBufPuts(&obuf, SimpleTime(NO_TIME)) != OK) { DBufFree(&obuf); DBufFree(&pre_buf); + FreeTrig(&trig); return E_NO_MEM; } } else { if (DBufPuts(&obuf, CalendarTime(tim.ttime, tim.duration)) != OK) { DBufFree(&obuf); DBufFree(&pre_buf); + FreeTrig(&trig); return E_NO_MEM; } } @@ -1059,6 +1101,7 @@ static int DoCalRem(ParsePtr p, int col) DestroyValue(v); DBufFree(&obuf); DBufFree(&pre_buf); + FreeTrig(&trig); return E_NO_MEM; } } @@ -1077,11 +1120,13 @@ static int DoCalRem(ParsePtr p, int col) if (r) { DBufFree(&pre_buf); DBufFree(&obuf); + FreeTrig(&trig); return r; } if (DBufLen(&obuf) <= oldLen) { DBufFree(&obuf); DBufFree(&pre_buf); + FreeTrig(&trig); return OK; } if (trig.typ != PASSTHRU_TYPE && @@ -1096,6 +1141,7 @@ static int DoCalRem(ParsePtr p, int col) DestroyValue(v); DBufFree(&obuf); DBufFree(&pre_buf); + FreeTrig(&trig); return E_NO_MEM; } } @@ -1110,6 +1156,7 @@ static int DoCalRem(ParsePtr p, int col) if (!e) { DBufFree(&obuf); DBufFree(&pre_buf); + FreeTrig(&trig); return E_NO_MEM; } #ifdef REM_USE_WCHAR @@ -1125,17 +1172,18 @@ static int DoCalRem(ParsePtr p, int col) DBufFree(&pre_buf); if (!e->text) { free(e); + FreeTrig(&trig); return E_NO_MEM; } make_wchar_versions(e); - StrnCpy(e->tag, trig.tag, TAG_LEN); - if (!e->tag[0]) { + e->tags = CloneTags(trig.tags); + if (!e->tags) { if (SynthesizeTags) { - SynthesizeTag(e->tag); - } else { - strcpy(e->tag, "*"); + e->tags = SynthesizeTag(); } } + /* Don't need tags any more */ + FreeTrig(&trig); e->duration = tim.duration; e->priority = trig.priority; e->filename = StrDup(FileName); @@ -1185,7 +1233,13 @@ static void WriteSimpleEntries(int col, int jul) } else { printf(" *"); } - printf(" %s ", e->tag); + if (e->tags) { + printf(" "); + PrintTagChain(stdout, e->tags); + printf(" "); + } else { + printf(" * "); + } if (e->duration != NO_TIME) { printf("%d ", e->duration); } else { @@ -1471,10 +1525,11 @@ static void SortCol(CalEntry **col) } } -void SynthesizeTag(char *out) +Tag *SynthesizeTag(void) { struct MD5Context ctx; unsigned char buf[16]; + char out[128]; MD5Init(&ctx); MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine)); MD5Final(buf, &ctx); @@ -1487,5 +1542,6 @@ void SynthesizeTag(char *out) (unsigned int) buf[10], (unsigned int) buf[11], (unsigned int) buf[12], (unsigned int) buf[13], (unsigned int) buf[14], (unsigned int) buf[15]); + return MakeTag(out); } diff --git a/src/dorem.c b/src/dorem.c index 86f6dee1..3a1fd487 100644 --- a/src/dorem.c +++ b/src/dorem.c @@ -56,10 +56,14 @@ int DoRem(ParsePtr p) DBufInit(&buf); /* Parse the trigger date and time */ - if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r; + if ( (r=ParseRem(p, &trig, &tim, 1)) ) { + FreeTrig(&trig); + return r; + } if (trig.typ == NO_TYPE) { PurgeEchoLine("%s\n%s\n", "#!P! Cannot parse next line", CurLine); + FreeTrig(&trig); return E_EOLN; } if (trig.typ == SAT_TYPE) { @@ -67,26 +71,39 @@ int DoRem(ParsePtr p) PurgeEchoLine("%s\n", CurLine); r=DoSatRemind(&trig, &tim, p); if (r) { + FreeTrig(&trig); if (r == E_EXPIRED) return OK; return r; } - if (!LastTrigValid) return OK; + if (!LastTrigValid) { + FreeTrig(&trig); + return OK; + } r=ParseToken(p, &buf); - if (r) return r; + if (r) { + FreeTrig(&trig); + return r; + } FindToken(DBufValue(&buf), &tok); DBufFree(&buf); if (tok.type == T_Empty || tok.type == T_Comment) { DBufFree(&buf); + FreeTrig(&trig); return OK; } if (tok.type != T_RemType || tok.val == SAT_TYPE) { DBufFree(&buf); + FreeTrig(&trig); return E_PARSE_ERR; } if (tok.val == PASSTHRU_TYPE) { r=ParseToken(p, &buf); - if (r) return r; + if (r) { + FreeTrig(&trig); + return r; + } if (!DBufLen(&buf)) { + FreeTrig(&trig); DBufFree(&buf); return E_EOLN; } @@ -95,8 +112,10 @@ int DoRem(ParsePtr p) } trig.typ = tok.val; jul = LastTriggerDate; - if (!LastTrigValid) return OK; - if (PurgeMode) return OK; + if (!LastTrigValid || PurgeMode) { + FreeTrig(&trig); + return OK; + } } else { /* Calculate the trigger date */ jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1); @@ -105,6 +124,7 @@ int DoRem(ParsePtr p) PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", ErrMsg[r]); PurgeEchoLine("%s\n", CurLine); } + FreeTrig(&trig); return r; } } @@ -125,6 +145,7 @@ int DoRem(ParsePtr p) } else { PurgeEchoLine("%s\n", CurLine); } + FreeTrig(&trig); return OK; } /* Queue the reminder, if necessary */ @@ -134,17 +155,21 @@ int DoRem(ParsePtr p) FileAccessDate == JulianToday)) QueueReminder(p, &trig, &tim, trig.sched); /* If we're in daemon mode, do nothing over here */ - if (Daemon) return OK; - - if (ShouldTriggerReminder(&trig, &tim, jul, &err)) { - if ( (r=TriggerReminder(p, &trig, &tim, jul)) ) - { - return r; - } + if (Daemon) { + FreeTrig(&trig); + return OK; } + if (ShouldTriggerReminder(&trig, &tim, jul, &err)) { + if ( (r=TriggerReminder(p, &trig, &tim, jul)) ) { + FreeTrig(&trig); + return r; + } + } + + FreeTrig(&trig); return OK; -} +} /***************************************************************/ /* */ @@ -159,7 +184,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals) register int r; DynamicBuffer buf; Token tok; - + Tag *newtag; int y, m, d; DBufInit(&buf); @@ -181,7 +206,8 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals) trig->sched[0] = 0; trig->warn[0] = 0; trig->omitfunc[0] = 0; - trig->tag[0] = 0; + trig->tags = NULL; + trig->last_tag = NULL; trig->passthru[0] = 0; tim->ttime = NO_TIME; tim->delta = NO_DELTA; @@ -362,7 +388,17 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals) case T_Tag: r = ParseToken(s, &buf); if (r) return r; - StrnCpy(trig->tag, DBufValue(&buf), TAG_LEN); + newtag = MakeTag(DBufValue(&buf)); + if (newtag) { + if (trig->last_tag) { + trig->last_tag->next = newtag; + trig->last_tag = newtag; + } else { + trig->tags = newtag; + trig->last_tag = newtag; + } + newtag->next = NULL; + } break; case T_Duration: @@ -751,16 +787,12 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul) DBufFree(&pre_buf); return E_NO_MEM; } - if (t->tag[0]) { - sprintf(tmpBuf, "%s ", t->tag); - } else { - sprintf(tmpBuf, "* "); - } - if (DBufPuts(&calRow, tmpBuf) != OK) { - DBufFree(&calRow); - DBufFree(&pre_buf); - return E_NO_MEM; - } + if (t->tags) { + AppendTagChain(&calRow, t->tags); + DBufPuts(&calRow, " "); + } else { + DBufPuts(&calRow, "* "); + } if (tim->duration != NO_TIME) { sprintf(tmpBuf, "%d ", tim->duration); } else { diff --git a/src/funcs.c b/src/funcs.c index f1b13435..9403be08 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -2660,7 +2660,10 @@ FEvalTrig(func_info *info) p.allownested = 0; r = ParseRem(&p, &trig, &tim, 0); if (r) return r; - if (trig.typ != NO_TYPE) return E_PARSE_ERR; + if (trig.typ != NO_TYPE) { + FreeTrig(&trig); + return E_PARSE_ERR; + } if (scanfrom == NO_DATE) { jul = ComputeTrigger(trig.scanfrom, &trig, &r, 0); } else { @@ -2670,6 +2673,7 @@ FEvalTrig(func_info *info) } jul = ComputeTrigger(scanfrom, &trig, &r, 0); } + FreeTrig(&trig); if (r) return r; if (jul < 0) { RetVal.type = INT_TYPE; diff --git a/src/main.c b/src/main.c index 356b2aa7..31e9ba0f 100644 --- a/src/main.c +++ b/src/main.c @@ -813,6 +813,7 @@ int DoIfTrig(ParsePtr p) } } } + FreeTrig(&trig); } NumIfs++; IfFlags &= ~(IF_MASK << (2*NumIfs - 2)); @@ -1306,3 +1307,99 @@ void SigIntHandler(int d) GotSigInt(); exit(0); } + +Tag * +CloneTag(Tag const *t) +{ + return MakeTag(t->tag); +} + +Tag * +MakeTag(char const *s) +{ + Tag *u = malloc(sizeof(Tag)); + if (!u) return NULL; + StrnCpy(u->tag, s, TAG_LEN); + u->next = NULL; + return u; +} + +void +FreeTags (Tag *chain) +{ + Tag *next; + + if (!chain) return; + while(chain) { + next = chain->next; + free(chain); + chain = next; + } +} + +Tag * +CloneTags(Tag const *chain) +{ + Tag *head, *tail, *t; + + if (!chain) return NULL; + + head = NULL; + tail = NULL; + + while(chain) { + t = CloneTag(chain); + if (!t) { + FreeTags(head); + return NULL; + } + if (!head) { + head = t; + tail = t; + } else { + tail->next = t; + tail = t; + } + t->next = NULL; + chain = chain->next; + } + return head; +} + +void +PrintTagChain(FILE *fp, Tag *chain) +{ + if (!chain) return; + int done_one = 0; + while(chain) { + if (done_one) { + fprintf(fp, ","); + } + done_one = 1; + fprintf(fp, "%s", chain->tag); + chain = chain->next; + } +} + +void +AppendTagChain(DynamicBuffer *buf, Tag *chain) +{ + if (!chain) return; + int done_one = 0; + while(chain) { + if (done_one) { + DBufPuts(buf, ","); + } + done_one = 1; + DBufPuts(buf, chain->tag); + chain = chain->next; + } +} + +void +FreeTrig(Trigger *t) +{ + FreeTags(t->tags); + t->tags = NULL; + t->last_tag = NULL; +} diff --git a/src/protos.h b/src/protos.h index 06b056b5..858d7a59 100644 --- a/src/protos.h +++ b/src/protos.h @@ -136,5 +136,11 @@ void HuntPhase (int startdate, int starttim, int phas, int *date, int *time); int CompareRems (int dat1, int tim1, int prio1, int dat2, int tim2, int prio2, int bydate, int bytime, int byprio, int untimed_first); void SigIntHandler (int d); void GotSigInt (void); -void SynthesizeTag(char *); +Tag *SynthesizeTag(void); +Tag *CloneTags(Tag const *t); +Tag *MakeTag(char const *s); +void FreeTags(Tag *chain); +void PrintTagChain(FILE *fp, Tag *chain); void PurgeEchoLine(char const *fmt, ...); +void AppendTagChain(DynamicBuffer *buf, Tag *chain); +void FreeTrig(Trigger *t); diff --git a/src/queue.c b/src/queue.c index e442e1e9..070a7f95 100644 --- a/src/queue.c +++ b/src/queue.c @@ -43,7 +43,7 @@ typedef struct queuedrem { char const *text; char passthru[PASSTHRU_LEN+1]; char sched[VAR_NAME_LEN+1]; - char tag[TAG_LEN+1]; + Tag *tags; TimeTrig tt; } QueuedRem; @@ -96,9 +96,9 @@ int QueueReminder(ParsePtr p, Trigger *trig, qelem->RunDisabled = RunDisabled; qelem->ntrig = 0; strcpy(qelem->sched, sched); - strcpy(qelem->tag, trig->tag); - if (! *qelem->tag && SynthesizeTags) { - SynthesizeTag(qelem->tag); + qelem->tags = CloneTags(trig->tags); + if (!qelem->tags && SynthesizeTags) { + qelem->tags = SynthesizeTag(); } QueueHead = qelem; return OK; @@ -235,11 +235,7 @@ void HandleQueuedReminders(void) printf("NOTE reminder %s", SimpleTime(q->tt.ttime)); printf("%s", SimpleTime(SystemTime(0)/60)); - if (!*q->tag) { - printf("*"); - } else { - printf("%s", q->tag); - } + PrintTagChain(stdout, q->tags); printf("\n"); } diff --git a/src/types.h b/src/types.h index 5eda3983..c5a5af6b 100644 --- a/src/types.h +++ b/src/types.h @@ -53,6 +53,12 @@ typedef struct var { Value v; } Var; +/* A tag */ +typedef struct tag_t { + struct tag_t *next; + char tag[TAG_LEN+1]; +} Tag; + /* A trigger */ typedef struct { int expired; @@ -73,7 +79,8 @@ typedef struct { char sched[VAR_NAME_LEN+1]; /* Scheduling function */ char warn[VAR_NAME_LEN+1]; /* Warning function */ char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */ - char tag[TAG_LEN+1]; + Tag *tags; + Tag *last_tag; char passthru[PASSTHRU_LEN+1]; } Trigger;