rewrite mutt_read_rfc822_header to have a more consistent API.
[apps/madmutt.git] / lib-mime / rfc822parse.c
index 3d9211c..6a3c164 100644 (file)
  * lines.  ``line'' must point to a dynamically allocated string; it is
  * increased if more space is required to fit the whole line.
  */
-char *mutt_read_rfc822_line (FILE * f, char *line, size_t * linelen)
+ssize_t mutt_read_rfc822_line(FILE *f, char **line, ssize_t *n)
 {
-  char *buf = line;
-  char ch;
-  size_t offset = 0;
-
-  for (;;) {
-    if (fgets (buf, *linelen - offset, f) == NULL ||    /* end of file or */
-        (ISSPACE (*line) && !offset)) { /* end of headers */
-      *line = 0;
-      return (line);
-    }
+    ssize_t pos = 0;
 
-    buf += m_strlen(buf) - 1;
-    if (*buf == '\n') {
-      /* we did get a full line. remove trailing space */
-      while (ISSPACE (*buf))
-        *buf-- = 0;             /* we cannot come beyond line's beginning because
-                                 * it begins with a non-space */
-
-      /* check to see if the next line is a continuation line */
-      if ((ch = fgetc (f)) != ' ' && ch != '\t') {
-        ungetc (ch, f);
-        return (line);          /* next line is a separate header field or EOH */
-      }
+    for (;;) {
+        char *p = *line;
 
-      /* eat tabs and spaces from the beginning of the continuation line */
-      while ((ch = fgetc (f)) == ' ' || ch == '\t');
-      ungetc (ch, f);
-      *++buf = ' ';             /* string is still terminated because we removed
-                                   at least one whitespace char above */
-    }
+        /* end of file or end of headers */
+        if (!fgets(p + pos, *n - pos, f) || (ISSPACE(*p) && pos == 0)) {
+            *p = '\0';
+            return 0;
+        }
+
+        pos += m_strlen(p + pos);
+        if (p[pos - 1] == '\n') {
+            int c;
+
+            /* remove trailing spaces. safe: p[0] is not a space */
+            do {
+                p[--pos] = '\0';
+            } while (ISSPACE(p[pos]));
+
+            /* check to see if the next line is a continuation line */
+            c = fgetc(f);
+            if (c != ' ' && c != '\t') {
+                /* next line is a separate header field or EOH */
+                ungetc(c, f);
+                return pos;
+            }
 
-    buf++;
-    offset = buf - line;
-    if (*linelen < offset + STRING) {
-      /* grow the buffer */
-      *linelen += STRING;
-      p_realloc(&line, *linelen);
-      buf = line + offset;
+            /* eat tabs and spaces from the beginning of the continuation line */
+            do {
+                c = fgetc(f);
+            } while (c == ' ' || c == '\t');
+            ungetc(c, f);
+
+            /* string is still terminated because we removed at least one
+               whitespace char above */
+            p[pos++] = ' ';
+        }
+
+        if (*n < pos + STRING) {
+            /* grow the buffer */
+            *n += STRING;
+            p_realloc(line, *n);
+        }
     }
-  }
-  /* not reached */
 }
 
 LIST *mutt_parse_references (char *s, int in_reply_to)
@@ -408,7 +412,7 @@ BODY *mutt_read_mime_header (FILE * fp, int digest)
   BODY *p = mutt_new_body ();
   char *c;
   char *line = p_new(char, LONG_STRING);
-  size_t linelen = LONG_STRING;
+  ssize_t linelen = LONG_STRING;
 
   p->hdr_offset = ftello (fp);
 
@@ -416,7 +420,7 @@ BODY *mutt_read_mime_header (FILE * fp, int digest)
   p->type = digest ? TYPEMESSAGE : TYPETEXT;
   p->disposition = DISPINLINE;
 
-  while (*(line = mutt_read_rfc822_line (fp, line, &linelen)) != 0) {
+  while (mutt_read_rfc822_line(fp, &line, &linelen)) {
     /* Find the value of the current header */
     if ((c = strchr (line, ':'))) {
       *c++ = 0;
@@ -1253,7 +1257,7 @@ ENVELOPE *mutt_read_rfc822_header (FILE * f, HEADER * hdr, short user_hdrs,
   char *p;
   off_t loc;
   int matched;
-  size_t linelen = LONG_STRING;
+  ssize_t linelen = LONG_STRING;
   char buf[LONG_STRING + 1];
 
   if (hdr) {
@@ -1272,7 +1276,8 @@ ENVELOPE *mutt_read_rfc822_header (FILE * f, HEADER * hdr, short user_hdrs,
   }
 
   while ((loc = ftello (f)),
-         *(line = mutt_read_rfc822_line (f, line, &linelen)) != 0) {
+         mutt_read_rfc822_line (f, &line, &linelen))
+  {
     matched = 0;
 
     if ((p = strpbrk (line, ": \t")) == NULL || *p != ':') {