+/*
+** This replaces the old approach, which included direct access to
+** stdio internals. It uses one fread() to load a buffer that we
+** manage.
+*/
+#define MSG_INPUT_SIZE 8192
+static struct m_getfld_buffer {
+ unsigned char msg_buf[2 * MSG_INPUT_SIZE];
+ unsigned char *readpos;
+ unsigned char *end; /* One past the last character read in. */
+} m;
+
+static void
+setup_buffer(FILE *iob, struct m_getfld_buffer *m)
+{
+ /*
+ ** Rely on Restrictions that m_getfld() calls on different file
+ ** streams are not interleaved, and no other file stream read
+ ** methods are used. And, the first call to m_getfld (), etc., on
+ ** a stream always reads at least 1 byte.
+ ** I don't think it's necessary to use ftello() because we just
+ ** need to determine whether the current offset is 0 or not.
+ */
+ if (ftell(iob) == 0) {
+ /* A new file stream, so reset the buffer state. */
+ m->readpos = m->end = m->msg_buf;
+ }
+}
+
+static size_t
+read_more(struct m_getfld_buffer *m, FILE *iob)
+{
+ size_t num_read;
+
+ /* Move any leftover at the end of buf to the beginning. */
+ if (m->end > m->readpos) {
+ memmove(m->msg_buf, m->readpos, m->end - m->readpos);
+ }
+ m->readpos = m->msg_buf + (m->end - m->readpos);
+ num_read = fread(m->readpos, 1, MSG_INPUT_SIZE, iob);
+ m->end = m->readpos + num_read;
+
+ return num_read;
+}
+
+static int
+Getc(FILE *iob)
+{
+ if (m.end - m.readpos < 1) {
+ if (read_more(&m, iob) == 0) {
+ /*
+ ** Pretend that we read a character.
+ ** That's what stdio does.
+ */
+ ++m.readpos;
+ return EOF;
+ }
+ }
+ return (m.readpos < m.end) ? *m.readpos++ : EOF;
+}
+
+static int
+Ungetc(int c, FILE *iob)
+{
+ return (m.readpos == m.msg_buf) ? EOF : (*--m.readpos = c);
+}