From 806a13ed8a23eeda97f50e4a9e0dd0fc5988efa7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 26 Aug 2011 11:26:51 +0200 Subject: 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 --- src/io.c | 181 ++++++++++++++++++++++++--------------------------------------- 1 file changed, 69 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/io.c b/src/io.c index de46cce..12c9494 100644 --- a/src/io.c +++ b/src/io.c @@ -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) -- cgit v1.2.3-70-g09d2 From b59070a49e292746edeb781733db25931a6a6e50 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 26 Aug 2011 12:07:11 +0200 Subject: Rework indentation code in print_notefile() Do not use snprintf() here as printf() behaviour is undefined if the destination pointer is used as a parameter. Signed-off-by: Lukas Fleischer --- src/args.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/args.c b/src/args.c index e447997..a3a22fe 100644 --- a/src/args.c +++ b/src/args.c @@ -199,13 +199,19 @@ print_notefile (FILE *out, char *filename, int nbtab) { char path_to_notefile[BUFSIZ]; FILE *notefile; - char linestarter[BUFSIZ] = ""; + char linestarter[BUFSIZ]; char buffer[BUFSIZ]; int i; int printlinestarter = 1; - for (i = 0; i < nbtab; i++) - (void)snprintf(linestarter, BUFSIZ, "%s\t", linestarter); + if (nbtab < BUFSIZ) + { + for (i = 0; i < nbtab; i++) + linestarter[i] = '\t'; + linestarter[nbtab] = '\0'; + } + else + linestarter[0] = '\0'; (void)snprintf (path_to_notefile, BUFSIZ, "%s/%s", path_notes, filename); notefile = fopen (path_to_notefile, "r"); -- cgit v1.2.3-70-g09d2