Add new implementation m_getfld2()
[mmh] / sbr / m_getfld2.c
diff --git a/sbr/m_getfld2.c b/sbr/m_getfld2.c
new file mode 100644 (file)
index 0000000..6eb0ef8
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+** m_getfld2 -- replacement for m_getfld()
+**              read an RFC 822 message
+*/
+
+#define _WITH_GETLINE
+#define _POSIX_C_SOURCE 200809L
+
+#include <h/mh.h>
+#include <h/utils.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+enum threestate {
+       B_TRUE = 1,
+       B_FALSE = 0,
+       FAIL = -1,
+};
+
+/*
+** static prototypes
+*/
+static enum threestate is_falted(FILE *);
+static size_t copyname(char *, char *);
+
+
+/*
+** For the states FLD2, BODY2 memory is allocated for f->value.
+** For the states LENERR2, FMTERR2, ERR2 and FILEEOF2 no memory is allocated.
+*/
+enum state
+m_getfld2(enum state s, struct field *f, FILE *msg)
+{
+       char *tmpline = NULL;
+       size_t len = 0;
+       ssize_t nchars;
+       enum threestate falted;
+
+       nchars = getline(&tmpline, &len, msg);
+       if (nchars == -1) {
+               if (feof(msg)) {
+                       return FILEEOF2;
+               } else {
+                       return ERR2;
+               }
+       }
+
+       if (nchars >= NAMESZ) {
+               free(tmpline);
+               return LENERR2;
+       }
+
+       switch (s) {
+       case FLD2:
+               if (*(tmpline + nchars - 1) != '\n') {
+                       free(tmpline);
+                       return FMTERR2;
+               }
+
+               if (nchars > 0 && (*tmpline == '\n' || *tmpline == '-')) {
+                       /* header/body separator found */
+                       free(tmpline);
+                       return m_getfld2(BODY2, f, msg);
+               }
+
+               f->namelen = copyname(f->name, tmpline);
+               if (f->namelen < 1) {
+                       free(tmpline);
+                       return FMTERR2;
+               }
+
+               /* copy the field's value */
+               if (f->alloclen <= nchars - f->namelen) {
+                       f->value = mh_xrealloc(f->value, f->alloclen + len);
+                       f->alloclen += len;
+               }
+               strcpy(f->value, tmpline + f->namelen + 1);
+               f->valuelen = nchars - f->namelen - 1;
+
+               while ((falted = is_falted(msg)) == B_TRUE) {
+                       nchars = getline(&tmpline, &len, msg);
+                       if (nchars <= 0) {
+                               free(tmpline);
+                               return ERR2;
+                       }
+
+                       if (nchars >= NAMESZ) {
+                               free(tmpline);
+                               return LENERR2;
+                       }
+
+                       if (*(tmpline + nchars - 1) != '\n') {
+                               free(tmpline);
+                               return FMTERR2;
+                       }
+
+                       if (f->alloclen - f->valuelen <= nchars) {
+                               f->value = mh_xrealloc(f->value,
+                                               f->alloclen + len);
+                               f->alloclen += len;
+                       }
+                       strcpy(f->value + f->valuelen, tmpline);
+                       f->valuelen += nchars;
+
+               }
+
+               if (falted == FAIL) {
+                       free(tmpline);
+                       return ERR2;
+               }
+
+               free(tmpline);
+               return FLD2;
+
+       case BODY2:
+               *f->name = '\0';
+               f->namelen = 0;
+               if (f->value) {
+                       free(f->value);
+               }
+               f->value = tmpline;
+               f->valuelen = nchars;
+               f->alloclen = len;
+               return BODY2;
+
+       default:
+               /* give error states back as received */
+               return s;
+       }
+}
+
+static enum threestate
+is_falted(FILE *msg)
+{
+       enum threestate ret;
+       int c;
+
+       if ((c = getc(msg)) < 0) {
+               if (feof(msg)) {
+                       clearerr(msg);
+                       return B_FALSE;
+               } else {
+                       return FAIL;
+               }
+       }
+       if (isblank(c)) {
+               ret = B_TRUE;
+       } else {
+               ret = B_FALSE;
+       }
+       if (ungetc(c, msg) != c) {
+               return FAIL;
+       }
+       return ret;
+}
+
+static size_t
+copyname(char *dst, char *src)
+{
+       size_t len;
+       char *sep = strchr(src, ':');
+
+       if (!sep) {
+               return 0;
+       }
+
+       len = sep - src;
+       if (len >= NAMESZ) {
+               return 0;
+       }
+
+       src[len] = '\0';
+       strcpy(dst, src);
+
+       return strlen(dst);
+}