X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/47313b9bc395470311e383b57eb184c830662c4a..d3e11c5e9:/sbr/m_getfld.c?ds=sidebyside diff --git a/sbr/m_getfld.c b/sbr/m_getfld.c index 6d5f04f0..683db175 100644 --- a/sbr/m_getfld.c +++ b/sbr/m_getfld.c @@ -1,6 +1,4 @@ - -/* - * m_getfld.c -- read/parse a message +/* m_getfld.c -- read/parse a message * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -159,7 +157,7 @@ names are typically short (~8 char) and the loop that extracts them might terminate on a colon, newline or max width. I considered using a Vax "scanc" to locate the end of the field followed by a - "bcopy" but the routine call overhead on a Vax is too large for this + "memmove" but the routine call overhead on a Vax is too large for this to work on short names. If Berkeley ever makes "inline" part of the C optimiser (so things like "scanc" turn into inline instructions) a change here would be worthwhile. @@ -175,7 +173,7 @@ so message bodies average at least a few hundred characters. Assuming your system uses reasonably sized stdio buffers (1K or more), this routine should be able to remove the body in large - (>500 byte) chunks. The makes the cost of a call to "bcopy" + (>500 byte) chunks. The makes the cost of a call to "memmove" small but there is a premium on checking for the eom in packed maildrops. The eom pattern is always a simple string so we can construct an efficient pattern matcher for it (e.g., a Vax "matchc" @@ -202,9 +200,7 @@ /* * static prototypes */ -struct m_getfld_state; static int m_Eom (m_getfld_state_t); -static char *matchc(int, char *, int, char *); #define eom(c,s) (s->msg_style != MS_DEFAULT && \ ((c) == *s->msg_delim && m_Eom(s))) @@ -433,7 +429,8 @@ read_more (m_getfld_state_t s) { ssize_t retain = s->edelimlen; size_t num_read; - if (retain < s->end - s->readpos) retain = s->end - s->readpos; + if (retain < s->end - s->readpos) + retain = s->end - s->readpos; assert (retain <= s->readpos - s->msg_buf); /* Move what we want to retain at end of the buffer to the beginning. */ @@ -548,7 +545,7 @@ m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], char *buf, int *bufsz, int next_char; if (c == EOF || (next_char = Peek (s)) == EOF) { *bufsz = *cp = *buf = 0; - advise (NULL, "eof encountered in field \"%s\"", name); + inform("eof encountered in field \"%s\"", name); leave_getfld (s); return s->state = FMTERR; } @@ -574,7 +571,7 @@ m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], char *buf, int *bufsz, if (*bufsz < n + 1) { /* No, it can't. Oh well, guess we'll blow up. */ *bufsz = *cp = *buf = 0; - advise (NULL, "eol encountered in field \"%s\"", name); + inform("eol encountered in field \"%s\"", name); s->state = FMTERR; break; } @@ -596,7 +593,7 @@ m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], char *buf, int *bufsz, it had read. It's in c, use it. */ *cp++ = c; *bufsz = *cp = *buf = 0; - advise (NULL, "field name \"%s\" exceeds %d bytes", name, + inform("field name \"%s\" exceeds %d bytes", name, NAMESZ - 2); s->state = LENERR; break; @@ -606,7 +603,7 @@ m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], char *buf, int *bufsz, while (isspace ((unsigned char) *--cp) && cp >= name) continue; *++cp = 0; /* readpos points to the first character of the field body. */ - /* fall through */ + /* FALLTHRU */ case FLDPLUS: { /* @@ -621,10 +618,12 @@ m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], char *buf, int *bufsz, n = 0; for (finished = 0; ! finished; ) { while (c != '\n' && c != EOF && n++ < max) { - if ((c = Getc (s)) != EOF) { *cp++ = c; } + if ((c = Getc (s)) != EOF) + *cp++ = c; } - if (c != EOF) c = Peek (s); + if (c != EOF) + c = Peek (s); if (max < n) { /* The dest buffer is full. Need to back the read pointer up by one because when m_getfld() is @@ -661,10 +660,11 @@ m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], char *buf, int *bufsz, */ char *bp; + name[0] = '\0'; max = *bufsz-1; /* Back up and store the current position. */ bp = --s->readpos; - c = s->end - s->readpos < max ? s->end - s->readpos : max; + c = min(s->end - s->readpos, max); if (s->msg_style != MS_DEFAULT && c > 1) { /* * packed maildrop - only take up to the (possible) @@ -680,7 +680,7 @@ m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], char *buf, int *bufsz, */ char *ep; - if ((ep = matchc( s->fdelimlen, s->fdelim, c, bp ))) + if ((ep = memmem(bp, c, s->fdelim, s->fdelimlen))) c = ep - bp + 1; else { /* @@ -775,7 +775,7 @@ m_unknown(m_getfld_state_t *gstate, FILE *iob) s = *gstate; /* - * Figure out what the message delimitter string is for this + * Figure out what the message delimiter string is for this * maildrop. (This used to be part of m_Eom but I didn't like * the idea of an "if" statement that could only succeed on the * first call to m_Eom getting executed on each call, i.e., at @@ -793,9 +793,8 @@ m_unknown(m_getfld_state_t *gstate, FILE *iob) if ((c = Getc (s)) == EOF) { *cp = '\0'; break; - } else { - *cp = c; } + *cp = c; } if (i == sizeof from-1 && strncmp (text, "From ", sizeof from-1) == 0) { @@ -807,21 +806,41 @@ m_unknown(m_getfld_state_t *gstate, FILE *iob) /* not a Unix style maildrop */ s->readpos -= s->bytes_read; s->bytes_read = 0; - delimstr = mmdlm2; + delimstr = MMDF_DELIM; s->msg_style = MS_MMDF; } + c = strlen (delimstr); - s->fdelim = mh_xmalloc (c + 3); + s->fdelim = mh_xmalloc (c + 3); /* \0, \n, delimstr, \0 */ *s->fdelim++ = '\0'; *s->fdelim = '\n'; - s->msg_delim = s->fdelim+1; - s->edelim = s->msg_delim+1; s->fdelimlen = c + 1; - s->edelimlen = c - 1; /* == strlen (delimstr) */ + s->msg_delim = s->fdelim+1; strcpy (s->msg_delim, delimstr); + s->edelim = s->msg_delim+1; + s->edelimlen = c - 1; s->delimend = s->msg_delim + s->edelimlen; if (s->edelimlen <= 1) adios (NULL, "maildrop delimiter must be at least 2 bytes"); + + /* Now malloc'd memory at s->fdelim-1 is referenced several times, + * containing a copy of the string constant from delimstr. + * + * "\nFrom \0" 7 "\001\001\001\001\n\0" 6 + * | | + * delimstr c=6 delimstr c=5 + * + * "\0\n\nFrom \0" 9 "\0\n\001\001\001\001\n\0" 8 + * | || | | | | | + * | || s->delimend | | | s->delimend + * | || | | | + * | |s->edelim s->edelimlen=5 | | s->edelim s->edelimlen=4 + * | | | | + * | s->msg_delim | s->msg_delim + * | | + * s->fdelim s->fdelimlen=7 s->fdelim s->fdelimlen=6 + */ + /* * build a Boyer-Moore end-position map for the matcher in m_getfld. * N.B. - we don't match just the first char (since it's the newline @@ -857,23 +876,20 @@ m_Eom (m_getfld_state_t s) char *cp; for (i = 0, cp = text; i < s->edelimlen; ++i, ++cp) { - int c2; - - if ((c2 = Getc (s)) == EOF) { + if ((*cp = Getc (s)) == EOF) { *cp = '\0'; break; - } else { - *cp = c2; } } if (i != s->edelimlen || strncmp (text, (char *)s->edelim, s->edelimlen)) { - if (i == 0 && s->msg_style == MS_MBOX) + if (i == 0 && s->msg_style == MS_MBOX) { /* the final newline in the (brain damaged) unix-format - * maildrop is part of the delimitter - delete it. + * maildrop is part of the delimiter - delete it. */ return 1; + } /* Did not find delimiter, so restore the read position. Note that on input, a character had already been read @@ -891,27 +907,3 @@ m_Eom (m_getfld_state_t s) return 1; } - - -static char * -matchc(int patln, char *pat, int strln, char *str) -{ - char *es = str + strln - patln; - char *sp; - char *pp; - char *ep = pat + patln; - char pc = *pat++; - - for(;;) { - while (pc != *str++) - if (str > es) - return 0; - if (str > es+1) - return 0; - sp = str; pp = pat; - while (pp < ep && *sp++ == *pp) - pp++; - if (pp >= ep) - return --str; - } -}