ical.c: Reduce nesting depth

Refactor the iCal parser to reduce nesting depth.

Signed-off-by: Lukas Fleischer <calcurse@cryptocrack.de>
This commit is contained in:
Lukas Fleischer 2015-02-24 11:43:45 +01:00
parent 52779d2ec6
commit 329ef1c22a

View File

@ -569,45 +569,39 @@ static long ical_durtime2long(char *timestr)
*/
static long ical_dur2long(char *durstr)
{
const int NOTFOUND = -1;
long durlong;
char *p;
struct {
unsigned week, day;
} date;
memset(&date, 0, sizeof date);
if ((p = strchr(durstr, 'P')) == NULL) {
durlong = NOTFOUND;
} else {
p++;
if (*p == '-')
return NOTFOUND;
else if (*p == '+')
p = strchr(durstr, 'P');
if (!p)
return -1;
p++;
if (*p == 'T') { /* dur-time */
durlong = ical_durtime2long(p);
} else if (strchr(p, 'W')) { /* dur-week */
if (*p == '-')
return -1;
if (*p == '+')
p++;
if (*p == 'T') {
/* dur-time */
return ical_durtime2long(p);
} else if (strchr(p, 'W')) {
/* dur-week */
if (sscanf(p, "%u", &date.week) == 1)
durlong =
date.week * WEEKINDAYS * DAYINSEC;
else
durlong = NOTFOUND;
} else {
if (strchr(p, 'D')) { /* dur-date */
return date.week * WEEKINDAYS * DAYINSEC;
} else if (strchr(p, 'D')) {
/* dur-date */
if (sscanf(p, "%uD", &date.day) == 1) {
durlong = date.day * DAYINSEC;
durlong += ical_durtime2long(p);
} else {
durlong = NOTFOUND;
}
} else {
durlong = NOTFOUND;
return date.day * DAYINSEC +
ical_durtime2long(p);
}
}
}
return durlong;
return -1;
}
/*
@ -620,35 +614,20 @@ static long ical_dur2long(char *durstr)
*/
static long ical_compute_rpt_until(long start, ical_rpt_t * rpt)
{
long until;
switch (rpt->type) {
case RECUR_DAILY:
until =
date_sec_change(start, 0,
rpt->freq * (rpt->count - 1));
break;
return date_sec_change(start, 0, rpt->freq * (rpt->count - 1));
case RECUR_WEEKLY:
until = date_sec_change(start, 0,
rpt->freq * WEEKINDAYS *
(rpt->count - 1));
break;
return date_sec_change(start, 0,
rpt->freq * WEEKINDAYS * (rpt->count - 1));
case RECUR_MONTHLY:
until =
date_sec_change(start, rpt->freq * (rpt->count - 1),
0);
break;
return date_sec_change(start, rpt->freq * (rpt->count - 1), 0);
case RECUR_YEARLY:
until =
date_sec_change(start,
return date_sec_change(start,
rpt->freq * 12 * (rpt->count - 1), 0);
break;
default:
until = 0;
break;
/* NOTREACHED */
return 0;
}
return until;
}
/*
@ -693,15 +672,20 @@ static ical_rpt_t *ical_read_rrule(FILE * log, char *rrulestr,
{
const char count[] = "COUNT=";
const char interv[] = "INTERVAL=";
char freqstr[BUFSIZ];
unsigned interval;
ical_rpt_t *rpt;
char *p;
rpt = NULL;
if ((p = strchr(rrulestr, ':')) != NULL) {
char freqstr[BUFSIZ];
p = strchr(rrulestr, ':');
if (!p) {
ical_log(log, ICAL_VEVENT, itemline,
_("recurrence rule malformed."));
(*noskipped)++;
return NULL;
}
p++;
rpt = mem_malloc(sizeof(ical_rpt_t));
memset(rpt, 0, sizeof(ical_rpt_t));
if (sscanf(p, "FREQ=%s", freqstr) != 1) {
@ -710,7 +694,8 @@ static ical_rpt_t *ical_read_rrule(FILE * log, char *rrulestr,
(*noskipped)++;
mem_free(rpt);
return NULL;
} else {
}
if (starts_with(freqstr, "DAILY")) {
rpt->type = RECUR_DAILY;
} else if (starts_with(freqstr, "WEEKLY")) {
@ -726,66 +711,50 @@ static ical_rpt_t *ical_read_rrule(FILE * log, char *rrulestr,
mem_free(rpt);
return NULL;
}
}
/*
The UNTIL rule part defines a date-time value which bounds the
recurrence rule in an inclusive manner. If not present, and the
COUNT rule part is also not present, the RRULE is considered to
repeat forever.
The COUNT rule part defines the number of occurrences at which to
range-bound the recurrence. The "DTSTART" property value, if
specified, counts as the first occurrence.
/*
* The UNTIL rule part defines a date-time value which bounds the
* recurrence rule in an inclusive manner. If not present, and the
* COUNT rule part is also not present, the RRULE is considered to
* repeat forever.
* The COUNT rule part defines the number of occurrences at which to
* range-bound the recurrence. The "DTSTART" property value, if
* specified, counts as the first occurrence.
*/
if ((p = strstr(rrulestr, "UNTIL")) != NULL) {
char *untilstr;
untilstr = strchr(p, '=');
rpt->until = ical_datetime2long(++untilstr, NULL);
rpt->until = ical_datetime2long(strchr(p, '=') + 1, NULL);
} else {
unsigned cnt;
char *countstr;
if ((countstr = strstr(rrulestr, count)) != NULL) {
rpt->until = 0;
if ((countstr = strstr(rrulestr, count))) {
countstr += sizeof(count) - 1;
if (sscanf(countstr, "%u", &cnt) != 1) {
rpt->until = 0;
/* endless repetition */
} else {
if (sscanf(countstr, "%u", &cnt) == 1)
rpt->count = cnt;
}
} else {
rpt->until = 0;
}
}
if ((p = strstr(rrulestr, interv)) != NULL) {
p += sizeof(interv) - 1;
if (sscanf(p, "%u", &interval) != 1) {
rpt->freq = 1;
/* default frequence if none specified */
} else {
if ((p = strstr(rrulestr, interv))) {
p += sizeof(interv) - 1;
if (sscanf(p, "%u", &interval) == 1)
rpt->freq = interval;
}
} else {
rpt->freq = 1;
}
} else {
ical_log(log, ICAL_VEVENT, itemline,
_("recurrence rule malformed."));
(*noskipped)++;
}
return rpt;
}
static void ical_add_exc(llist_t * exc_head, long date)
{
if (date != 0) {
if (date == 0)
return;
struct excp *exc = mem_malloc(sizeof(struct excp));
exc->st = date;
LLIST_ADD(exc_head, exc);
}
}
/*
@ -799,8 +768,15 @@ ical_read_exdate(llist_t * exc, FILE * log, char *exstr,
char *p, *q;
long date;
if ((p = strchr(exstr, ':')) != NULL) {
p = strchr(exstr, ':');
if (!p) {
ical_log(log, ICAL_VEVENT, itemline,
_("recurrence exception dates malformed."));
(*noskipped)++;
return;
}
p++;
while ((q = strchr(p, ',')) != NULL) {
char buf[BUFSIZ];
const int buflen = q - p;
@ -813,11 +789,6 @@ ical_read_exdate(llist_t * exc, FILE * log, char *exstr,
}
date = ical_datetime2long(p, NULL);
ical_add_exc(exc, date);
} else {
ical_log(log, ICAL_VEVENT, itemline,
_("recurrence exception dates malformed."));
(*noskipped)++;
}
}
/* Return an allocated string containing the name of the newly created note. */
@ -827,8 +798,15 @@ static char *ical_read_note(char *line, unsigned *noskipped,
{
char *p, *notestr, *note;
if ((p = strchr(line, ':')) != NULL) {
p = strchr(line, ':');
if (!p) {
ical_log(log, item_type, itemline,
_("description malformed."));
(*noskipped)++;
return NULL;
}
p++;
notestr = ical_unformat_line(p);
if (notestr == NULL) {
ical_log(log, item_type, itemline,
@ -843,12 +821,6 @@ static char *ical_read_note(char *line, unsigned *noskipped,
mem_free(notestr);
return note;
}
} else {
ical_log(log, item_type, itemline,
_("description malformed."));
(*noskipped)++;
return NULL;
}
}
/* Returns an allocated string containing the ical item summary. */
@ -902,147 +874,119 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
skip_alarm = 0;
continue;
}
if (starts_with_ci(buf, "END:VEVENT")) {
if (vevent.mesg) {
if (vevent.rpt && vevent.rpt->count)
vevent.rpt->until =
ical_compute_rpt_until(vevent.
start,
vevent.
rpt);
switch (vevent_type) {
case APPOINTMENT:
if (vevent.start == 0) {
ical_log(log, ICAL_VEVENT,
ITEMLINE,
_("appointment has no start time."));
goto cleanup;
}
if (vevent.dur == 0) {
if (vevent.end == 0) {
ical_log(log,
ICAL_VEVENT,
ITEMLINE,
_("could not compute duration "
"(no end time)."));
goto cleanup;
} else if (vevent.start ==
vevent.end) {
vevent_type =
EVENT;
vevent.end = 0L;
ical_store_event
(vevent.mesg,
vevent.note,
vevent.start,
vevent.end,
vevent.rpt,
&vevent.exc);
(*noevents)++;
return;
} else {
vevent.dur =
vevent.end -
vevent.start;
if (vevent.dur < 0) {
ical_log
(log,
ICAL_VEVENT,
ITEMLINE,
_("item has a negative duration."));
goto cleanup;
}
}
}
ical_store_apoint(vevent.mesg,
vevent.note,
vevent.start,
vevent.dur,
vevent.rpt,
&vevent.exc,
vevent.
has_alarm);
(*noapoints)++;
break;
case EVENT:
if (vevent.start == 0) {
ical_log(log, ICAL_VEVENT,
ITEMLINE,
_("event date is not defined."));
goto cleanup;
}
ical_store_event(vevent.mesg,
vevent.note,
vevent.start,
vevent.end,
vevent.rpt,
&vevent.exc);
(*noevents)++;
break;
case UNDEFINED:
ical_log(log, ICAL_VEVENT,
ITEMLINE,
_("item could not be identified."));
goto cleanup;
break;
}
} else {
if (starts_with_ci(buf, "END:VEVENT")) {
if (!vevent.mesg) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("could not retrieve item summary."));
goto cleanup;
}
if (vevent.start == 0) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("item start date is not defined."));
goto cleanup;
}
if (vevent_type == APPOINTMENT && vevent.dur == 0) {
if (vevent.end == 0) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("could not compute duration "
"(no end time)."));
goto cleanup;
}
vevent.dur = vevent.end - vevent.start;
if (vevent.dur == 0) {
vevent_type = EVENT;
vevent.end = 0L;
} else if (vevent.dur < 0) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("item has a negative duration."));
goto cleanup;
}
}
if (vevent.rpt && vevent.rpt->count) {
vevent.rpt->until =
ical_compute_rpt_until(vevent.start,
vevent.rpt);
}
switch (vevent_type) {
case APPOINTMENT:
ical_store_apoint(vevent.mesg, vevent.note,
vevent.start, vevent.dur,
vevent.rpt, &vevent.exc,
vevent.has_alarm);
(*noapoints)++;
break;
case EVENT:
ical_store_event(vevent.mesg, vevent.note,
vevent.start, vevent.end,
vevent.rpt, &vevent.exc);
(*noevents)++;
break;
case UNDEFINED:
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("item could not be identified."));
goto cleanup;
break;
}
return;
} else {
}
if (starts_with_ci(buf, "DTSTART")) {
if ((p = strchr(buf, ':')) != NULL)
vevent.start =
ical_datetime2long(++p,
&vevent_type);
p = strchr(buf, ':');
if (!p) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("event start time malformed."));
goto cleanup;
}
vevent.start = ical_datetime2long(++p, &vevent_type);
if (!vevent.start) {
ical_log(log, ICAL_VEVENT,
ITEMLINE,
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("could not retrieve event start time."));
goto cleanup;
}
} else if (starts_with_ci(buf, "DTEND")) {
if ((p = strchr(buf, ':')) != NULL)
vevent.end =
ical_datetime2long(++p,
&vevent_type);
p = strchr(buf, ':');
if (!p) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("event end time malformed."));
goto cleanup;
}
vevent.end = ical_datetime2long(++p, &vevent_type);
if (!vevent.end) {
ical_log(log, ICAL_VEVENT,
ITEMLINE,
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("could not retrieve event end time."));
goto cleanup;
}
} else if (starts_with_ci(buf, "DURATION")) {
if ((vevent.dur = ical_dur2long(buf)) <= 0) {
ical_log(log, ICAL_VEVENT,
ITEMLINE,
vevent.dur = ical_dur2long(buf);
if (vevent.dur <= 0) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("item duration malformed."));
goto cleanup;
}
} else if (starts_with_ci(buf, "RRULE")) {
vevent.rpt =
ical_read_rrule(log, buf, noskipped,
vevent.rpt = ical_read_rrule(log, buf, noskipped,
ITEMLINE);
} else if (starts_with_ci(buf, "EXDATE")) {
ical_read_exdate(&vevent.exc, log, buf,
noskipped, ITEMLINE);
ical_read_exdate(&vevent.exc, log, buf, noskipped,
ITEMLINE);
} else if (starts_with_ci(buf, "SUMMARY")) {
vevent.mesg = ical_read_summary(buf);
} else if (starts_with_ci(buf, "BEGIN:VALARM")) {
skip_alarm = 1;
vevent.has_alarm = 1;
skip_alarm = vevent.has_alarm = 1;
} else if (starts_with_ci(buf, "DESCRIPTION")) {
vevent.note =
ical_read_note(buf, noskipped,
ICAL_VEVENT, ITEMLINE,
log);
}
vevent.note = ical_read_note(buf, noskipped,
ICAL_VEVENT, ITEMLINE, log);
}
}
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("The ical file seems to be malformed. "
"The end of item was not found."));
@ -1084,51 +1028,46 @@ ical_read_todo(FILE * fdi, FILE * log, unsigned *notodos,
skip_alarm = 0;
continue;
}
if (starts_with_ci(buf, "END:VTODO")) {
if (!vtodo.has_priority)
vtodo.priority = LOWEST;
if (vtodo.mesg) {
ical_store_todo(vtodo.priority, vtodo.mesg,
vtodo.note);
(*notodos)++;
} else {
if (!vtodo.mesg) {
ical_log(log, ICAL_VTODO, ITEMLINE,
_("could not retrieve item summary."));
goto cleanup;
}
ical_store_todo(vtodo.priority, vtodo.mesg,
vtodo.note);
(*notodos)++;
return;
} else {
int tmpint;
}
if (starts_with_ci(buf, "PRIORITY:")) {
sscanf(buf, "%d", &tmpint);
if (tmpint <= 9 && tmpint >= 1) {
vtodo.priority = tmpint;
sscanf(buf, "%d", &vtodo.priority);
if (vtodo.priority >= 1 && vtodo.priority <= 9) {
vtodo.has_priority = 1;
} else {
ical_log(log, ICAL_VTODO, ITEMLINE,
_("item priority is not acceptable "
"(must be between 1 and 9)."));
vtodo.priority = LOWEST;
}
} else if (starts_with_ci(buf, "SUMMARY")) {
vtodo.mesg = ical_read_summary(buf);
} else if (starts_with_ci(buf, "BEGIN:VALARM")) {
skip_alarm = 1;
} else if (starts_with_ci(buf, "DESCRIPTION")) {
vtodo.note =
ical_read_note(buf, noskipped,
ICAL_VTODO, ITEMLINE,
log);
}
vtodo.note = ical_read_note(buf, noskipped, ICAL_VTODO,
ITEMLINE, log);
}
}
ical_log(log, ICAL_VTODO, ITEMLINE,
_("The ical file seems to be malformed. "
"The end of item was not found."));
cleanup:
if (vtodo.note)
mem_free(vtodo.note);
if (vtodo.mesg)