]>
diplodocus.org Git - nmh/blob - sbr/m_getfld.c
1 /* m_getfld.c -- read/parse a message
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
15 Reads an Internet message (RFC 5322), or one or more messages
16 stored in a maildrop in mbox (RFC 4155) or MMDF format, from a file
17 stream. Each call to m_getfld() reads one header field, or a
18 portion of the body, in sequence.
22 gstate: opaque parse state
23 bufsz: maximum number of characters to load into buf
24 iob: input file stream
28 name: header field name (array of size NAMESZ=999)
29 buf: either a header field body or message body
30 bufsz: number of characters loaded into buf
31 (return value): message parse state on return from function
35 void m_getfld_state_destroy (m_getfld_state_t *gstate): destroys
36 the parse state pointed to by the gstate argument.
38 m_getfld_state_reset (m_getfld_state_t *gstate): resets the parse
41 void m_unknown(FILE *iob): Determines the message delimiter string
42 for the maildrop. Called by inc and scan when reading from a
47 m_getfld() retains state internally between calls in the
48 m_getfld_state_t variable. These are used for detecting the end of
49 each message when reading maildrops:
62 m_getfld_state_t gstate = 0;
64 int state = m_getfld (&gstate, ...);
66 m_getfld_state_destroy (&gstate);
68 The state is retained internally by gstate. To reset its state to FLD:
69 m_getfld_state_reset (&gstate);
72 /* The following described the old implementation. The high-level
73 structure hasn't changed, but some of the details have. I'm
74 leaving this as-is, though, for posterity.
77 /* This module has a long and checkered history. First, it didn't burst
78 maildrops correctly because it considered two CTRL-A:s in a row to be
79 an inter-message delimiter. It really is four CTRL-A:s followed by a
80 newline. Unfortunately, MMDF will convert this delimiter *inside* a
81 message to a CTRL-B followed by three CTRL-A:s and a newline. This
82 caused the old version of m_getfld() to declare eom prematurely. The
83 fix was a lot slower than
85 c == '\001' && peekc (iob) == '\001'
87 but it worked, and to increase generality, MBOX style maildrops could
88 be parsed as well. Unfortunately the speed issue finally caught up with
89 us since this routine is at the very heart of MH.
91 To speed things up considerably, the routine Eom() was made an auxiliary
92 function called by the macro eom(). Unless we are bursting a maildrop,
93 the eom() macro returns FALSE saying we aren't at the end of the
96 The next thing to do is to read the mts.conf file and initialize
97 delimiter[] and delimlen accordingly...
99 After mhl was made a built-in in msh, m_getfld() worked just fine
100 (using m_unknown() at startup). Until one day: a message which was
101 the result of a bursting was shown. Then, since the burst boundaries
102 aren't CTRL-A:s, m_getfld() would blinding plunge on past the boundary.
103 Very sad. The solution: introduce m_eomsbr(). This hook gets called
104 after the end of each line (since testing for eom involves an fseek()).
105 This worked fine, until one day: a message with no body portion arrived.
108 while (eom (c = Getc (iob), iob))
111 loop caused m_getfld() to return FMTERR. So, that logic was changed to
112 check for (*eom_action) and act accordingly.
114 This worked fine, until one day: someone didn't use four CTRL:A's as
115 their delimiters. So, the bullet got bit and we read mts.h and
116 continue to struggle on. It's not that bad though, since the only time
117 the code gets executed is when inc (or msh) calls it, and both of these
118 have already called mts_init().
120 ------------------------
121 (Written by Van Jacobson for the mh6 m_getfld, January, 1986):
123 This routine was accounting for 60% of the cpu time used by most mh
124 programs. I spent a bit of time tuning and it now accounts for <10%
125 of the time used. Like any heavily tuned routine, it's a bit
126 complex and you want to be sure you understand everything that it's
127 doing before you start hacking on it. Let me try to emphasize
128 that: every line in this atrocity depends on every other line,
129 sometimes in subtle ways. You should understand it all, in detail,
130 before trying to change any part. If you do change it, test the
131 result thoroughly (I use a hand-constructed test file that exercises
132 all the ways a header name, header body, header continuation,
133 header-body separator, body line and body eom can align themselves
134 with respect to a buffer boundary). "Minor" bugs in this routine
135 result in garbaged or lost mail.
137 If you hack on this and slow it down, I, my children and my
138 children's children will curse you.
140 This routine gets used on three different types of files: normal,
141 single msg files, "packed" unix or mmdf mailboxs (when used by inc)
142 and packed, directoried bulletin board files (when used by msh).
143 The biggest impact of different file types is in "eom" testing. The
144 code has been carefully organized to test for eom at appropriate
145 times and at no other times (since the check is quite expensive).
146 I have tried to arrange things so that the eom check need only be
147 done on entry to this routine. Since an eom can only occur after a
148 newline, this is easy to manage for header fields. For the msg
149 body, we try to efficiently search the input buffer to see if
150 contains the eom delimiter. If it does, we take up to the
151 delimiter, otherwise we take everything in the buffer. (The change
152 to the body eom/copy processing produced the most noticeable
153 performance difference, particularly for "inc" and "show".)
155 There are three qualitatively different things this routine busts
156 out of a message: field names, field text and msg bodies. Field
157 names are typically short (~8 char) and the loop that extracts them
158 might terminate on a colon, newline or max width. I considered
159 using a Vax "scanc" to locate the end of the field followed by a
160 "memmove" but the routine call overhead on a Vax is too large for this
161 to work on short names. If Berkeley ever makes "inline" part of the
162 C optimiser (so things like "scanc" turn into inline instructions) a
163 change here would be worthwhile.
165 Field text is typically 60 - 100 characters so there's (barely)
166 a win in doing a routine call to something that does a "locc"
167 followed by a "bmove". About 30% of the fields have continuations
168 (usually the 822 "received:" lines) and each continuation generates
169 another routine call. "Inline" would be a big win here, as well.
171 Messages, as of this writing, seem to come in two flavors: small
172 (~1K) and long (>2K). Most messages have 400 - 600 bytes of headers
173 so message bodies average at least a few hundred characters.
174 Assuming your system uses reasonably sized stdio buffers (1K or
175 more), this routine should be able to remove the body in large
176 (>500 byte) chunks. The makes the cost of a call to "memmove"
177 small but there is a premium on checking for the eom in packed
178 maildrops. The eom pattern is always a simple string so we can
179 construct an efficient pattern matcher for it (e.g., a Vax "matchc"
180 instruction). Some thought went into recognizing the start of
181 an eom that has been split across two buffers.
183 This routine wants to deal with large chunks of data so, rather
184 than "getc" into a local buffer, it uses stdio's buffer. If
185 you try to use it on a non-buffered file, you'll get what you
186 deserve. This routine "knows" that struct FILEs have a _ptr
187 and a _cnt to describe the current state of the buffer and
188 it knows that _filbuf ignores the _ptr & _cnt and simply fills
189 the buffer. If stdio on your system doesn't work this way, you
190 may have to make small changes in this routine.
192 This routine also "knows" that an EOF indication on a stream is
193 "sticky" (i.e., you will keep getting EOF until you reposition the
194 stream). If your system doesn't work this way it is broken and you
195 should complain to the vendor. As a consequence of the sticky
196 EOF, this routine will never return any kind of EOF status when
197 there is data in "name" or "buf").
203 static int m_Eom (m_getfld_state_t
);
205 #define eom(c,s) (s->msg_style != MS_DEFAULT && \
206 ((c) == *s->msg_delim && m_Eom(s)))
208 /* This replaces the old approach, with its direct access to stdio
209 * internals. It uses one fread() to load a buffer that we manage.
211 * MSG_INPUT_SIZE is the size of the buffer.
212 * MAX_DELIMITER_SIZE is the maximum size of the delimiter used to
213 * separate messages in a maildrop, such as mbox "From ".
215 * Some of the tests in the test suite assume a MSG_INPUT_SIZE
218 #define MSG_INPUT_SIZE NMH_BUFSIZ
219 #define MAX_DELIMITER_SIZE 5
221 struct m_getfld_state
{
222 char msg_buf
[2 * MSG_INPUT_SIZE
+ MAX_DELIMITER_SIZE
];
224 char *end
; /* One past the last character read in. */
225 /* The following support tracking of the read position in the
226 input file stream so that callers can interleave m_getfld()
227 calls with ftell() and fseek(). bytes_read replaces the old
228 m_getfld() msg_count global. last_caller_pos is stored when
229 leaving m_getfld()/m_unknown(), then checked on the next entry.
230 last_internal_pos is used to remember the position used
231 internally by m_getfld() (read_more(), actually). */
233 off_t total_bytes_read
; /* by caller, not necessarily from input file */
234 off_t last_caller_pos
;
235 off_t last_internal_pos
;
241 * The "full" delimiter string for a packed maildrop consists
242 * of a newline followed by the actual delimiter. E.g., the
243 * full string for a Unix maildrop would be: "\n\nFrom ".
244 * "fdelim" points to the start of the full string and is used
245 * in the BODY case of the main routine to search the buffer for
246 * a possible eom. Msg_delim points to the first character of
247 * the actual delim. string (i.e., fdelim+1). edelim
248 * points to the 2nd character of actual delimiter string. It
249 * is used in m_Eom because the first character of the string
250 * has been read and matched before m_Eom is called.
264 m_getfld_state_init (m_getfld_state_t
*gstate
, FILE *iob
) {
269 s
->readpos
= s
->end
= s
->msg_buf
;
270 s
->bytes_read
= s
->total_bytes_read
= 0;
271 s
->last_caller_pos
= s
->last_internal_pos
= 0;
274 s
->msg_style
= MS_DEFAULT
;
276 s
->fdelim
= s
->delimend
= s
->edelim
= NULL
;
277 s
->fdelimlen
= s
->edelimlen
= 0;
279 s
->track_filepos
= 0;
282 /* scan() needs to force a state an initial state of FLD for each message. */
284 m_getfld_state_reset (m_getfld_state_t
*gstate
) {
286 (*gstate
)->state
= FLD
;
290 /* If the caller interleaves ftell*()/fseek*() calls with m_getfld()
291 calls, m_getfld() must keep track of the file position. The caller
292 must use this function to inform m_getfld(). */
294 m_getfld_track_filepos (m_getfld_state_t
*gstate
, FILE *iob
) {
296 m_getfld_state_init (gstate
, iob
);
299 (*gstate
)->track_filepos
= 1;
302 void m_getfld_state_destroy (m_getfld_state_t
*gstate
) {
303 m_getfld_state_t s
= *gstate
;
316 Summary of file and message input buffer positions:
318 input file -------------------------------------------EOF
320 last_caller_pos last_internal_pos
323 msg_buf --------------------EOF
327 |<>|=retained characters, difference
328 between last_internal_pos and
329 first readpos value after reading
330 in new chunk in read_more()
332 When returning from m_getfld()/m_unknown():
333 1) Save the internal file position in last_internal_pos. That's the
334 m_getfld() position reference in the input file.
335 2) Set file stream position so that callers can use ftell().
337 When entering m_getfld()/m_unknown():
338 Check to see if the call had changed the file position. If so,
339 adjust the internal position reference accordingly. If not, restore
340 the internal file position from last_internal_pos.
345 enter_getfld (m_getfld_state_t
*gstate
, FILE *iob
) {
351 m_getfld_state_init (gstate
, iob
);
356 /* This is ugly and no longer necessary, but is retained just in
357 case it's needed again. The parser used to open the input file
358 multiple times, so we had to always use the FILE * that's
359 passed to m_getfld(). Now the parser inits a new
360 m_getfld_state for each file. See comment below about the
361 readpos shift code being currently unused. */
364 if (!s
->track_filepos
)
368 if (pos
== 0 && s
->last_internal_pos
== 0)
371 if (s
->last_internal_pos
== 0) {
372 s
->total_bytes_read
= pos
;
376 pos_movement
= pos
- s
->last_caller_pos
; /* Can be < 0. */
377 if (pos_movement
== 0) {
378 pos
= s
->last_internal_pos
;
380 /* The current file stream position differs from the
381 last one, so caller must have called ftell/o().
382 Or, this is the first call and the file position
385 if (s
->readpos
+ pos_movement
>= s
->msg_buf
&&
386 s
->readpos
+ pos_movement
< s
->end
) {
387 /* This is currently unused. It could be used by
388 parse_mime() if it was changed to use a global
390 /* We can shift readpos and remain within the
391 bounds of msg_buf. */
392 s
->readpos
+= pos_movement
;
393 s
->total_bytes_read
+= pos_movement
;
394 pos
= s
->last_internal_pos
;
398 /* This seek skips past an integral number of
399 chunks of size MSG_INPUT_SIZE. */
400 fseeko (iob
, pos
/MSG_INPUT_SIZE
* MSG_INPUT_SIZE
, SEEK_SET
);
401 num_read
= fread (s
->msg_buf
, 1, MSG_INPUT_SIZE
, iob
);
402 s
->readpos
= s
->msg_buf
+ pos
% MSG_INPUT_SIZE
;
403 s
->end
= s
->msg_buf
+ num_read
;
404 s
->total_bytes_read
= pos
;
408 fseeko (iob
, pos
, SEEK_SET
);
412 leave_getfld (m_getfld_state_t s
) {
413 s
->total_bytes_read
+= s
->bytes_read
;
415 if (s
->track_filepos
) {
416 /* Save the internal file position that we use for the input buffer. */
417 s
->last_internal_pos
= ftello (s
->iob
);
419 /* Set file stream position so that callers can use ftell(). */
420 fseeko (s
->iob
, s
->total_bytes_read
, SEEK_SET
);
421 s
->last_caller_pos
= ftello (s
->iob
);
426 read_more (m_getfld_state_t s
) {
427 /* Retain at least edelimlen characters that have already been
428 read so that we can back up to them in m_Eom(). */
429 ssize_t retain
= s
->edelimlen
;
432 if (retain
< s
->end
- s
->readpos
)
433 retain
= s
->end
- s
->readpos
;
434 assert (retain
<= s
->readpos
- s
->msg_buf
);
436 /* Move what we want to retain at end of the buffer to the beginning. */
437 memmove (s
->msg_buf
, s
->readpos
- retain
, retain
);
439 s
->readpos
= s
->msg_buf
+ retain
;
440 num_read
= fread (s
->readpos
, 1, MSG_INPUT_SIZE
, s
->iob
);
441 s
->end
= s
->readpos
+ num_read
;
446 /* The return values of the following functions are a bit
447 subtle. They can return 0x00 - 0xff as a valid character,
448 but EOF is typically 0xffffffff. */
450 Getc (m_getfld_state_t s
) {
451 if ((s
->end
- s
->readpos
< 1 && read_more (s
) == 0) ||
452 s
->readpos
>= s
->end
)
456 return (unsigned char)*s
->readpos
++;
460 Peek (m_getfld_state_t s
) {
461 if (s
->end
- s
->readpos
< 1 && read_more (s
) == 0) {
464 return s
->readpos
< s
->end
? (unsigned char) *s
->readpos
: EOF
;
468 Ungetc (int c
, m_getfld_state_t s
) {
469 if (s
->readpos
== s
->msg_buf
) {
473 return *--s
->readpos
= (unsigned char) c
;
478 m_getfld (m_getfld_state_t
*gstate
, char name
[NAMESZ
], char *buf
, int *bufsz
,
485 enter_getfld (gstate
, iob
);
488 if ((c
= Getc(s
)) == EOF
) {
491 return s
->state
= FILEEOF
;
494 /* flush null messages */
495 while ((c
= Getc(s
)) != EOF
&& eom (c
, s
))
502 return s
->state
= FILEEOF
;
507 if (c
== '\n' || c
== '-') {
508 /* we hit the header/body separator */
509 while (c
!= '\n' && (c
= Getc(s
)) != EOF
)
512 if (c
== EOF
|| (c
= Getc(s
)) == EOF
|| eom (c
, s
)) {
513 /* flush null messages */
514 while ((c
= Getc(s
)) != EOF
&& eom (c
, s
))
520 return s
->state
= FILEEOF
;
526 * get the name of this component. take characters up
527 * to a ':', a newline or NAMESZ-1 characters, whichever
532 /* Get the field name. The first time through the loop,
533 this copies out the first character, which was loaded
534 into c prior to loop entry. Initialize n to 1 to
537 c
!= ':' && c
!= '\n' && c
!= EOF
&& n
< max
;
542 /* Check for next character, which is either the space after
543 the ':' or the first folded whitespace. */
546 if (c
== EOF
|| (next_char
= Peek (s
)) == EOF
) {
547 *bufsz
= *cp
= *buf
= 0;
548 inform("eof encountered in field \"%s\"", name
);
550 return s
->state
= FMTERR
;
554 /* If c isn't ':' here, something went wrong. Possibilities are:
555 * . hit a newline (error)
556 * . got more than namesz chars. (error)
559 /* Finished header name, fall through to FLDPLUS below. */
560 } else if (c
== '\n') {
561 /* We hit the end of the line without seeing ':' to
562 * terminate the field name. This is usually (always?)
563 * spam. But, blowing up is lame, especially when
564 * scan(1)ing a folder with such messages. Pretend such
565 * lines are the first of the body (at least mutt also
566 * handles it this way). */
568 /* See if buf can hold this line, since we were assuming
569 * we had a buffer of NAMESZ, not bufsz. */
570 /* + 1 for the newline */
571 if (*bufsz
< n
+ 1) {
572 /* No, it can't. Oh well, guess we'll blow up. */
573 *bufsz
= *cp
= *buf
= 0;
574 inform("eol encountered in field \"%s\"", name
);
578 memcpy (buf
, name
, n
- 1);
581 /* Indicate this wasn't a header field using a character
582 that can't appear in a header field. */
584 /* The last character read was '\n'. s->bytes_read
585 (and n) include that, but it was not put into the
586 name array in the for loop above. So subtract 1. */
587 *bufsz
= --s
->bytes_read
; /* == n - 1 */
589 return s
->state
= BODY
;
592 /* By design, the loop above discards the last character
593 it had read. It's in c, use it. */
595 *bufsz
= *cp
= *buf
= 0;
596 inform("field name \"%s\" exceeds %d bytes", name
,
602 /* Trim any trailing spaces from the end of name. */
603 while (isspace ((unsigned char) *--cp
) && cp
>= name
) continue;
605 /* readpos points to the first character of the field body. */
610 * get (more of) the text of a field. Take
611 * characters up to the end of this field (newline
612 * followed by non-blank) or bufsz-1 characters.
619 for (finished
= 0; ! finished
; ) {
620 while (c
!= '\n' && c
!= EOF
&& n
++ < max
) {
621 if ((c
= Getc (s
)) != EOF
)
628 /* The dest buffer is full. Need to back the read
629 pointer up by one because when m_getfld() is
630 reentered, it will read a character. Then
631 we'll jump right to the FLDPLUS handling code,
632 which will not store that character, but
633 instead move on to the next one. */
634 if (s
->readpos
> s
->msg_buf
) {
640 } else if (c
!= ' ' && c
!= '\t') {
641 /* The next character is not folded whitespace, so
642 prepare to move on to the next field. It's OK
643 if c is EOF, it will be handled on the next
644 call to m_getfld (). */
648 /* Folded header field, continues on the next line. */
651 *bufsz
= s
->bytes_read
;
658 * get the message body up to bufsz characters or the
659 * end of the message.
665 /* Back up and store the current position. */
667 c
= min(s
->end
- s
->readpos
, max
);
668 if (s
->msg_style
!= MS_DEFAULT
&& c
> 1) {
670 * packed maildrop - only take up to the (possible)
671 * start of the next message. This "matchc" should
672 * probably be a Boyer-Moore matcher for non-vaxen,
673 * particularly since we have the alignment table
674 * all built for the end-of-buffer test (next).
675 * But our vax timings indicate that the "matchc"
676 * instruction is 50% faster than a carefully coded
677 * B.M. matcher for most strings. (So much for elegant
678 * algorithms vs. brute force.) Since I (currently)
679 * run MH on a vax, we use the matchc instruction. --vj
683 if ((ep
= memmem(bp
, c
, s
->fdelim
, s
->fdelimlen
)))
687 * There's no delim in the buffer but there may be
688 * a partial one at the end. If so, we want to leave
689 * it so the "eom" check on the next call picks it up.
690 * Use a modified Boyer-Moore matcher to make this
691 * check relatively cheap. The first "if" figures
692 * out what position in the pattern matches the last
693 * character in the buffer. The inner "while" matches
694 * the pattern against the buffer, backwards starting
695 * at that position. Note that unless the buffer
696 * ends with one of the characters in the pattern
697 * (excluding the first and last), we do only one test.
702 if ((sp
= s
->pat_map
[(unsigned char) *ep
])) {
704 /* This if() is true unless (a) the buffer is too
705 * small to contain this delimiter prefix, or
706 * (b) it contains exactly enough chars for the
708 * For case (a) obviously we aren't going to match.
709 * For case (b), if the buffer really contained exactly
710 * a delim prefix, then the m_eom call at entry
711 * should have found it. Thus it's not a delim
712 * and we know we won't get a match.
714 if (((sp
- s
->fdelim
) + 2) <= c
) {
716 /* Unfortunately although fdelim has a preceding NUL
717 * we can't use this as a sentinel in case the buffer
718 * contains a NUL in exactly the wrong place (this
719 * would cause us to run off the front of fdelim).
721 while (*--ep
== *--cp
)
724 if (cp
< s
->fdelim
) {
725 /* we matched the entire delim prefix,
726 * so only take the buffer up to there.
727 * we know ep >= bp -- check above prevents underrun
733 /* try matching one less char of delim string */
735 } while (--sp
> s
->fdelim
);
739 memcpy( buf
, bp
, c
);
740 /* Advance the current position to reflect the copy out.
741 c is less than or equal to the number of bytes remaining
742 in the read buffer, so will not overrun it. */
745 /* Subtract 1 from c because the first character was read by
746 Getc(), and therefore already accounted for in s->bytes_read. */
747 s
->bytes_read
+= c
- 1;
748 *bufsz
= s
->bytes_read
;
753 adios (NULL
, "m_getfld() called with bogus state of %d", s
->state
);
764 m_unknown(m_getfld_state_t
*gstate
, FILE *iob
)
768 char text
[MAX_DELIMITER_SIZE
];
769 char from
[] = "From ";
774 enter_getfld (gstate
, iob
);
778 * Figure out what the message delimiter string is for this
779 * maildrop. (This used to be part of m_Eom but I didn't like
780 * the idea of an "if" statement that could only succeed on the
781 * first call to m_Eom getting executed on each call, i.e., at
782 * every newline in the message).
784 * If the first line of the maildrop is a Unix "From " line, we
785 * say the style is MBOX and eat the rest of the line. Otherwise
786 * we say the style is MMDF and look for the delimiter string
787 * specified when nmh was built (or from the mts.conf file).
790 s
->msg_style
= MS_UNKNOWN
;
792 for (i
= 0, cp
= text
; i
< sizeof text
; ++i
, ++cp
) {
793 if ((c
= Getc (s
)) == EOF
) {
800 if (i
== sizeof from
-1 && strncmp (text
, "From ", sizeof from
-1) == 0) {
801 s
->msg_style
= MS_MBOX
;
802 delimstr
= "\nFrom ";
803 while ((c
= Getc(s
)) != EOF
&& c
!= '\n')
806 /* not a Unix style maildrop */
807 s
->readpos
-= s
->bytes_read
;
810 s
->msg_style
= MS_MMDF
;
813 c
= strlen (delimstr
);
814 s
->fdelim
= mh_xmalloc (c
+ 3); /* \0, \n, delimstr, \0 */
817 s
->fdelimlen
= c
+ 1;
818 s
->msg_delim
= s
->fdelim
+1;
819 strcpy (s
->msg_delim
, delimstr
);
820 s
->edelim
= s
->msg_delim
+1;
821 s
->edelimlen
= c
- 1;
822 s
->delimend
= s
->msg_delim
+ s
->edelimlen
;
823 if (s
->edelimlen
<= 1)
824 adios (NULL
, "maildrop delimiter must be at least 2 bytes");
826 /* Now malloc'd memory at s->fdelim-1 is referenced several times,
827 * containing a copy of the string constant from delimstr.
829 * "\nFrom \0" 7 "\001\001\001\001\n\0" 6
831 * delimstr c=6 delimstr c=5
833 * "\0\n\nFrom \0" 9 "\0\n\001\001\001\001\n\0" 8
835 * | || s->delimend | | | s->delimend
837 * | |s->edelim s->edelimlen=5 | | s->edelim s->edelimlen=4
839 * | s->msg_delim | s->msg_delim
841 * s->fdelim s->fdelimlen=7 s->fdelim s->fdelimlen=6
845 * build a Boyer-Moore end-position map for the matcher in m_getfld.
846 * N.B. - we don't match just the first char (since it's the newline
847 * separator) or the last char (since the matchc would have found it
848 * if it was a real delim).
850 s
->pat_map
= (char **) mh_xcalloc (256, sizeof(char *));
852 for (cp
= s
->fdelim
+ 1; cp
< s
->delimend
; cp
++ )
853 s
->pat_map
[(unsigned char)*cp
] = cp
;
855 if (s
->msg_style
== MS_MMDF
) {
856 /* flush extra msg hdrs */
857 while ((c
= Getc(s
)) != EOF
&& eom (c
, s
))
868 * test for msg delimiter string
872 m_Eom (m_getfld_state_t s
)
875 char text
[MAX_DELIMITER_SIZE
];
878 for (i
= 0, cp
= text
; i
< s
->edelimlen
; ++i
, ++cp
) {
881 if ((c2
= Getc (s
)) == EOF
) {
888 if (i
!= s
->edelimlen
||
889 strncmp (text
, (char *)s
->edelim
, s
->edelimlen
)) {
890 if (i
== 0 && s
->msg_style
== MS_MBOX
)
891 /* the final newline in the (brain damaged) unix-format
892 * maildrop is part of the delimiter - delete it.
896 /* Did not find delimiter, so restore the read position.
897 Note that on input, a character had already been read
898 with Getc(). It will be unget by m_getfld () on return. */
899 s
->readpos
-= s
->bytes_read
- 1;
904 if (s
->msg_style
== MS_MBOX
) {
906 while ((c
= Getc(s
)) != EOF
&& c
!= '\n')