+struct m_getfld_state;
+static int m_Eom (m_getfld_state_t, int);
+static char *matchc(int, char *, int, char *);
+
+#define eom(c,s) (s->msg_style != MS_DEFAULT && \
+ (((c) == *s->msg_delim && m_Eom(s,c)) || \
+ (s->eom_action && (*s->eom_action)(c))))
+
+/* This replaces the old approach, with its direct access to stdio
+ * internals. It uses one fread() to load a buffer that we manage.
+ *
+ * MSG_INPUT_SIZE is the size of the buffer.
+ * MAX_DELIMITER_SIZE is the maximum size of the delimiter used to
+ * separate messages in a maildrop, such as mbox "From ".
+ *
+ * Some of the tests in the test suite assume a MSG_INPUT_SIZE
+ * of 4096.
+ */
+#define MSG_INPUT_SIZE 4096
+#define MAX_DELIMITER_SIZE 5
+
+struct m_getfld_state {
+ char msg_buf[2 * MSG_INPUT_SIZE + MAX_DELIMITER_SIZE];
+ char *readpos;
+ char *end; /* One past the last character read in. */
+ /* The following support tracking of the read position in the
+ input file stream so that callers can interleave m_getfld()
+ calls with ftell() and fseek(). ytes_read replaces the old
+ m_getfld() msg_count global. last_caller_pos is stored when
+ leaving m_getfld()/m_unknown(), then checked on the next entry.
+ last_internal_pos is used to remember the position used
+ internally by m_getfld() (read_more(), actually). */
+ off_t bytes_read;
+ off_t total_bytes_read; /* by caller, not necessarily from input file */
+ off_t last_caller_pos;
+ off_t last_internal_pos;
+ FILE *iob;
+
+ char **pat_map;
+ int msg_style;
+ /*
+ * The "full" delimiter string for a packed maildrop consists
+ * of a newline followed by the actual delimiter. E.g., the
+ * full string for a Unix maildrop would be: "\n\nFrom ".
+ * "Fdelim" points to the start of the full string and is used
+ * in the BODY case of the main routine to search the buffer for
+ * a possible eom. Msg_delim points to the first character of
+ * the actual delim. string (i.e., fdelim+1). Edelim
+ * points to the 2nd character of actual delimiter string. It
+ * is used in m_Eom because the first character of the string
+ * has been read and matched before m_Eom is called.
+ */
+ char *msg_delim;
+ char *fdelim;
+ char *delimend;
+ int fdelimlen;
+ char *edelim;
+ int edelimlen;
+ int (*eom_action)(int);
+ int state;
+ int track_filepos;
+};
+
+static
+void
+m_getfld_state_init (m_getfld_state_t *gstate, FILE *iob) {
+ m_getfld_state_t s;
+
+ s = *gstate = (m_getfld_state_t) mh_xmalloc(sizeof (struct m_getfld_state));
+ s->readpos = s->end = s->msg_buf;
+ s->bytes_read = s->total_bytes_read = 0;
+ s->last_caller_pos = s->last_internal_pos = 0;
+ s->iob = iob;
+ s->pat_map = NULL;
+ s->msg_style = MS_DEFAULT;
+ s->msg_delim = "";
+ s->fdelim = s->delimend = s->edelim = NULL;
+ s->fdelimlen = s->edelimlen = 0;
+ s->eom_action = NULL;
+ s->state = FLD;
+ s->track_filepos = 0;
+}
+
+/* scan() needs to force a state an initial state of FLD for each message. */
+void
+m_getfld_state_reset (m_getfld_state_t *gstate) {
+ if (*gstate) {
+ (*gstate)->state = FLD;
+ }
+}