diff options
author | Lukas Fleischer <calcurse@cryptocrack.de> | 2011-08-26 11:26:51 +0200 |
---|---|---|
committer | Lukas Fleischer <calcurse@cryptocrack.de> | 2011-08-26 11:57:30 +0200 |
commit | 806a13ed8a23eeda97f50e4a9e0dd0fc5988efa7 (patch) | |
tree | 08c1071fcc8af4bc038b8d91460ceb4c799cdfca /src/io.c | |
parent | de85010edc4ba228313f730473258743a1063652 (diff) | |
download | calcurse-806a13ed8a23eeda97f50e4a9e0dd0fc5988efa7.zip |
src/io.c: iCal content line folding correctness
This is a rather invasive change that introduces correct line folding to
our iCal parser.
From now on, ical_readline() should be used instead of fgets() to read
lines from an iCal file as it unfolds lines automatically. We also need
to use shared buffers as each ical_readline() invocation eats up the
first part of the next line and stores it in the "lstore" buffer.
Subsequent ical_readline() invocations copy the contents of this buffer
and append continuation lines. We currently use a single buffer pair
that is allocated in io_import_data() and pass it to all subroutines.
ical_readline_init() needs to be called once for every buffer pair. It
reads the first part of the current line and writes to "lstore",
clearing the target buffer at the same time.
Signed-off-by: Lukas Fleischer <calcurse@cryptocrack.de>
Diffstat (limited to 'src/io.c')
-rw-r--r-- | src/io.c | 181 |
1 files changed, 69 insertions, 112 deletions
@@ -1813,7 +1813,7 @@ ical_store_apoint (char *mesg, char *note, long start, long dur, /* * Returns an allocated string representing the string given in argument once - * unformatted. See ical_unfold_content () below. + * unformatted. * * Note: * Even if the RFC2445 recommends not to have more than 75 octets on one line of @@ -1827,8 +1827,6 @@ ical_store_apoint (char *mesg, char *note, long start, long dur, static char * ical_unformat_line (char *line) { -#define LINE_FEED 0x0a -#define CARRIAGE_RETURN 0x0d char *p, uline[BUFSIZ]; int len; @@ -1840,10 +1838,6 @@ ical_unformat_line (char *line) { switch (*p) { - case LINE_FEED: - return mem_strdup (uline); - case CARRIAGE_RETURN: - break; case '\\': switch (*(p + 1)) { @@ -1871,106 +1865,69 @@ ical_unformat_line (char *line) break; } } -#undef LINE_FEED -#undef CARRIAGE_RETURN - return NULL; + + return mem_strdup (uline); } -/* - * Extract from RFC2445: - * - * When parsing a content line, folded lines MUST first be - * unfolded [..] The content information associated with an iCalendar - * object is formatted using a syntax similar to that defined by [RFC 2425]. - */ -static char * -ical_unfold_content (FILE *fd, char *line, unsigned *lineno) +static void +ical_readline_init (FILE *fdi, char *buf, char *lstore, unsigned *ln) { - char *content; - int c; + char *eol; - content = ical_unformat_line (line); - if (!content) - return NULL; + *buf = *lstore = '\0'; + fgets (lstore, BUFSIZ, fdi); + if ((eol = strchr(lstore, '\n')) != NULL) + *eol = '\0'; + (*ln)++; +} - for (;;) - { - c = getc (fd); - if (c == SPACE || c == TAB) - { - char buf[BUFSIZ]; +static int +ical_readline (FILE *fdi, char *buf, char *lstore, unsigned *ln) +{ + char *eol; - if (fgets (buf, BUFSIZ, fd) != NULL) - { - char *tmpline, *rline; - int newsize; + strncpy (buf, lstore, BUFSIZ); + (*ln)++; - (*lineno)++; - tmpline = ical_unformat_line (buf); - if (!tmpline) - { - mem_free (content); - return NULL; - } - newsize = strlen (content) + strlen (tmpline) + 1; - if ((rline = mem_realloc (content, newsize, 1)) == NULL) - { - mem_free (content); - mem_free (tmpline); - return NULL; - } - content = rline; - (void)strncat (content, tmpline, BUFSIZ); - mem_free (tmpline); - } - else - { - mem_free (content); - return NULL; - /* Could not get entire item description. */ - } - } - else - { - (void)ungetc (c, fd); - return content; - } + while (fgets (lstore, BUFSIZ, fdi) != NULL) + { + if ((eol = strchr(lstore, '\n')) != NULL) + *eol = '\0'; + if (*lstore != SPACE && *lstore != TAB) + break; + strncat (buf, lstore + 1, BUFSIZ); + (*ln)++; + } + + if (feof (fdi)) + { + *lstore = '\0'; + if (*buf == '\0') + return 0; } + + return 1; } static float -ical_chk_header (FILE *fd, unsigned *lineno) +ical_chk_header (FILE *fd, char *buf, char *lstore, unsigned *lineno) { const int HEADER_MALFORMED = -1; const struct string icalheader = STRING_BUILD ("BEGIN:VCALENDAR"); - char buf[BUFSIZ]; - - (void)fgets (buf, BUFSIZ, fd); - (*lineno)++; + float version; - if (buf == NULL) return HEADER_MALFORMED; + if (!ical_readline (fd, buf, lstore, lineno)) + return HEADER_MALFORMED; str_toupper (buf); if (strncmp (buf, icalheader.str, icalheader.len) != 0) return HEADER_MALFORMED; - const int AWAITED = 1; - float version = HEADER_MALFORMED; - int read; - - do + while (!sscanf (buf, "VERSION:%f", &version)) { - if (fgets (buf, BUFSIZ, fd) == NULL) - { - return HEADER_MALFORMED; - } - else - { - (*lineno)++; - read = sscanf (buf, "VERSION:%f", &version); - } + if (!ical_readline (fd, buf, lstore, lineno)) + return HEADER_MALFORMED; } - while (read != AWAITED); return version; } @@ -2354,14 +2311,13 @@ ical_read_exdate (llist_t *exc, FILE *log, char *exstr, unsigned *noskipped, /* Return an allocated string containing the name of the newly created note. */ static char * -ical_read_note (char *first_line, FILE *fdi, unsigned *noskipped, - unsigned *lineno, ical_vevent_e item_type, const int itemline, - FILE *log) +ical_read_note (char *line, unsigned *noskipped, ical_vevent_e item_type, + const int itemline, FILE *log) { char *p, *notestr, *notename, fullnotename[BUFSIZ]; FILE *fdo; - if ((p = strchr (first_line, ':')) != NULL) + if ((p = strchr (line, ':')) != NULL) { notename = new_tempfile (path_notes, NOTESIZ); EXIT_IF (notename == NULL, @@ -2372,7 +2328,7 @@ ical_read_note (char *first_line, FILE *fdi, unsigned *noskipped, EXIT_IF (fdo == NULL, _("Warning: could not open %s, Aborting..."), fullnotename); p++; - notestr = ical_unfold_content (fdi, p, lineno); + notestr = ical_unformat_line (p); if (notestr == NULL) { ical_log (log, item_type, itemline, @@ -2407,14 +2363,14 @@ ical_read_note (char *first_line, FILE *fdi, unsigned *noskipped, /* Returns an allocated string containing the ical item summary. */ static char * -ical_read_summary (char *first_line, FILE *fdi, unsigned *lineno) +ical_read_summary (char *line) { char *p, *summary; - if ((p = strchr (first_line, ':')) != NULL) + if ((p = strchr (line, ':')) != NULL) { p++; - summary = ical_unfold_content (fdi, p, lineno); + summary = ical_unformat_line (p); return summary; } else @@ -2423,7 +2379,8 @@ ical_read_summary (char *first_line, FILE *fdi, unsigned *lineno) static void ical_read_event (FILE *fdi, FILE *log, unsigned *noevents, unsigned *noapoints, - unsigned *noskipped, unsigned *lineno) + unsigned *noskipped, char *buf, char *lstore, + unsigned *lineno) { const int ITEMLINE = *lineno; const struct string endevent = STRING_BUILD ("END:VEVENT"); @@ -2437,7 +2394,7 @@ ical_read_event (FILE *fdi, FILE *log, unsigned *noevents, unsigned *noapoints, const struct string endalarm = STRING_BUILD ("END:VALARM"); const struct string desc = STRING_BUILD ("DESCRIPTION"); ical_vevent_e vevent_type; - char *p, buf[BUFSIZ], buf_upper[BUFSIZ]; + char *p, buf_upper[BUFSIZ]; struct { llist_t exc; ical_rpt_t *rpt; @@ -2450,11 +2407,11 @@ ical_read_event (FILE *fdi, FILE *log, unsigned *noevents, unsigned *noapoints, vevent_type = UNDEFINED; bzero (&vevent, sizeof vevent); skip_alarm = 0; - while (fgets (buf, BUFSIZ, fdi) != NULL) + while (ical_readline (fdi, buf, lstore, lineno)) { - (*lineno)++; memcpy (buf_upper, buf, strlen (buf)); str_toupper (buf_upper); + if (skip_alarm) { /* Need to skip VALARM properties because some keywords could @@ -2584,7 +2541,7 @@ ical_read_event (FILE *fdi, FILE *log, unsigned *noevents, unsigned *noapoints, } else if (strncmp (buf_upper, summary.str, summary.len) == 0) { - vevent.mesg = ical_read_summary (buf, fdi, lineno); + vevent.mesg = ical_read_summary (buf); } else if (strncmp (buf_upper, alarm.str, alarm.len) == 0) { @@ -2593,8 +2550,8 @@ ical_read_event (FILE *fdi, FILE *log, unsigned *noevents, unsigned *noapoints, } else if (strncmp (buf_upper, desc.str, desc.len) == 0) { - vevent.note = ical_read_note (buf, fdi, noskipped, lineno, - ICAL_VEVENT, ITEMLINE, log); + vevent.note = ical_read_note (buf, noskipped, ICAL_VEVENT, + ITEMLINE, log); } } } @@ -2616,7 +2573,7 @@ cleanup: static void ical_read_todo (FILE *fdi, FILE *log, unsigned *notodos, unsigned *noskipped, - unsigned *lineno) + char *buf, char *lstore, unsigned *lineno) { const struct string endtodo = STRING_BUILD ("END:VTODO"); const struct string summary = STRING_BUILD ("SUMMARY"); @@ -2625,7 +2582,7 @@ ical_read_todo (FILE *fdi, FILE *log, unsigned *notodos, unsigned *noskipped, const struct string desc = STRING_BUILD ("DESCRIPTION"); const int LOWEST = 9; const int ITEMLINE = *lineno; - char buf[BUFSIZ], buf_upper[BUFSIZ]; + char buf_upper[BUFSIZ]; struct { char *mesg, *note; int has_priority, priority; @@ -2634,9 +2591,8 @@ ical_read_todo (FILE *fdi, FILE *log, unsigned *notodos, unsigned *noskipped, bzero (&vtodo, sizeof vtodo); skip_alarm = 0; - while (fgets (buf, BUFSIZ, fdi) != NULL) + while (ical_readline (fdi, buf, lstore, lineno)) { - (*lineno)++; memcpy (buf_upper, buf, strlen (buf)); str_toupper (buf_upper); if (skip_alarm) @@ -2685,7 +2641,7 @@ ical_read_todo (FILE *fdi, FILE *log, unsigned *notodos, unsigned *noskipped, } else if (strncmp (buf_upper, summary.str, summary.len) == 0) { - vtodo.mesg = ical_read_summary (buf, fdi, lineno); + vtodo.mesg = ical_read_summary (buf); } else if (strncmp (buf_upper, alarm.str, alarm.len) == 0) { @@ -2693,8 +2649,8 @@ ical_read_todo (FILE *fdi, FILE *log, unsigned *notodos, unsigned *noskipped, } else if (strncmp (buf_upper, desc.str, desc.len) == 0) { - vtodo.note = ical_read_note (buf, fdi, noskipped, lineno, - ICAL_VTODO, ITEMLINE, log); + vtodo.note = ical_read_note (buf, noskipped, ICAL_VTODO, + ITEMLINE, log); } } } @@ -2762,7 +2718,7 @@ io_import_data (enum import_type type, struct conf *conf, char *stream_name) _("%d apps / %d events / %d todos / %d skipped "); char *lines_stats_interactive = _("%d apps / %d events / %d todos / %d skipped ([ENTER] to continue)"); - char buf[BUFSIZ]; + char buf[BUFSIZ], lstore[BUFSIZ]; FILE *stream = NULL; struct io_file *log; float ical_version; @@ -2791,7 +2747,8 @@ io_import_data (enum import_type type, struct conf *conf, char *stream_name) return; bzero (&stats, sizeof stats); - ical_version = ical_chk_header (stream, &stats.lines); + ical_readline_init (stream, buf, lstore, &stats.lines); + ical_version = ical_chk_header (stream, buf, lstore, &stats.lines); RETURN_IF (ical_version < 0, _("Warning: ical header malformed or wrong version number. " "Aborting...")); @@ -2805,19 +2762,19 @@ io_import_data (enum import_type type, struct conf *conf, char *stream_name) } ical_log_init (log->fd, ical_version); - while (fgets (buf, BUFSIZ, stream) != NULL) + while (ical_readline (stream, buf, lstore, &stats.lines)) { stats.lines++; str_toupper (buf); if (strncmp (buf, vevent.str, vevent.len) == 0) { ical_read_event (stream, log->fd, &stats.events, &stats.apoints, - &stats.skipped, &stats.lines); + &stats.skipped, buf, lstore, &stats.lines); } else if (strncmp (buf, vtodo.str, vtodo.len) == 0) { ical_read_todo (stream, log->fd, &stats.todos, &stats.skipped, - &stats.lines); + buf, lstore, &stats.lines); } } if (stream != stdin) |