2 ** scansbr.c -- routines to help scan along...
4 ** This code is Copyright (c) 2002, by the authors of nmh. See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
10 #include <h/addrsbr.h>
11 #include <h/fmt_scan.h>
12 #include <h/scansbr.h>
17 # define _ptr _p /* Gag */
18 # define _cnt _w /* Wretch */
25 # define _filbuf(fp) ((fp)->__cnt = 0, __filbuf(fp))
28 #define MAXSCANL 256 /* longest possible scan line */
31 ** Buffer size for content part of header fields. We want this
32 ** to be large enough so that we don't do a lot of extra FLDPLUS
33 ** calls on m_getfld but small enough so that we don't snarf
34 ** the entire message body when we're only going to display 30
39 static struct format *fmt;
41 static struct format *fmt_top;
44 static struct comp *datecomp; /* pntr to "date" comp */
45 static struct comp *bodycomp; /* pntr to "body" pseudo-comp (if referenced) */
46 static int ncomps = 0; /* # of interesting components */
47 static char **compbuffers = 0; /* buffers for component text */
48 static struct comp **used_buf = 0; /* stack for comp that use buffers */
50 static int dat[5]; /* aux. data for format routine */
52 char *scanl = 0; /* text of most recent scanline */
54 #define DIEWRERR() adios (scnmsg, "write error on")
57 if (mh_fputs(buf,scnout) == EOF)\
64 int sc_width (void); /* from termsbr.c */
65 static int mh_fputs(char *, FILE *);
67 #ifdef MULTIBYTE_SUPPORT
68 #define SCAN_CHARWIDTH MB_CUR_MAX
70 #define SCAN_CHARWIDTH 1
74 scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg,
75 int unseen, char *folder, long size, int noisy)
77 int i, compnum, encrypted, state;
78 unsigned char *cp, *tmpbuf;
80 char *saved_c_text = NULL;
82 struct comp **savecomp;
86 static int rlwidth, slwidth;
89 char returnpath[BUFSIZ];
90 char deliverydate[BUFSIZ];
93 /* first-time only initialization */
96 if ((width = sc_width ()) < WIDTH/2)
98 else if (width > MAXSCANL)
101 dat[3] = slwidth = width;
102 scanl = (char *) mh_xmalloc((size_t) SCAN_CHARWIDTH *
107 /* Compile format string */
108 ncomps = fmt_compile (nfs, &fmt) + 1;
113 FINDCOMP(bodycomp, "body");
114 FINDCOMP(datecomp, "date");
115 FINDCOMP(cptr, "folder");
117 cptr->c_text = folder;
118 FINDCOMP(cptr, "encrypted");
120 if ((cptr = (struct comp *) calloc (1,
122 cptr->c_name = "encrypted";
123 cptr->c_next = wantcomp[i = CHASH (cptr->c_name)];
127 FINDCOMP (cptr, "dtimenow");
129 cptr->c_text = getcpy(dtimenow (0));
130 nxtbuf = compbuffers = (char **) calloc((size_t) ncomps,
133 adios (NULL, "unable to allocate component buffers");
134 used_buf = (struct comp **) calloc((size_t) (ncomps+1),
135 sizeof(struct comp *));
136 if (used_buf == NULL)
137 adios (NULL, "unable to allocate component buffer stack");
138 used_buf += ncomps+1; *--used_buf = 0;
139 rlwidth = bodycomp && (width > SBUFSIZ) ? width : SBUFSIZ;
140 for (i = ncomps; i--; )
141 *nxtbuf++ = mh_xmalloc(rlwidth);
145 ** each-message initialization
147 nxtbuf = compbuffers;
150 dat[0] = innum ? innum : outnum;
155 ** Get the first field. If the message is non-empty
156 ** and we're doing an "inc", open the output file.
158 if ((state = m_getfld (FLD, name, tmpbuf, rlwidth, inb)) == FILEEOF) {
160 advise("read", "unable to"); /* "read error" */
169 scnmsg = m_name (outnum);
170 if (*scnmsg == '?') /* msg num out of range */
173 scnmsg = "/dev/null";
175 if ((scnout = fopen (scnmsg, "w")) == NULL)
176 adios (scnmsg, "unable to write");
179 ** Add the Return-Path and Delivery-Date
180 ** header fields to message.
182 if (get_returnpath (returnpath, sizeof(returnpath),
183 deliverydate, sizeof(deliverydate))) {
184 FPUTS ("Return-Path: ");
186 FPUTS ("Delivery-Date: ");
187 FPUTS (deliverydate);
192 /* scan - main loop */
194 state = m_getfld (state, name, tmpbuf, rlwidth, inb)) {
201 if ( putc (':', scnout) == EOF)
206 ** if we're interested in this component,
207 ** save a pointer to the component text,
208 ** then start using our next free buffer
209 ** as the component temp buffer (buffer
210 ** switching saves an extra copy of the
213 if ((cptr = wantcomp[CHASH(name)])) {
215 if (!mh_strcasecmp(name, cptr->c_name)) {
216 if (! cptr->c_text) {
217 cptr->c_text = tmpbuf;
218 for (cp = tmpbuf + strlen (tmpbuf) - 1;
229 } while ((cptr = cptr->c_next));
232 while (state == FLDPLUS) {
233 state = m_getfld (state, name, tmpbuf, rlwidth, inb);
242 state = FILEEOF; /* stop now if scan cmd */
245 if (putc ('\n', scnout) == EOF) DIEWRERR();
248 ** performance hack: some people like to
249 ** run "inc" on things like net.sources or
250 ** large digests. We do a copy directly
251 ** into the output buffer rather than
252 ** going through an intermediate buffer.
254 ** We need the amount of data m_getfld
255 ** found & don't want to do a strlen on
256 ** the long buffer so there's a hack in
257 ** m_getfld to save the amount of data it
258 ** returned in the global "msg_count".
261 while (state == BODY) {
263 if (scnout->_IO_write_ptr == scnout->_IO_write_end) {
264 #elif defined(__DragonFly__)
265 if (((struct __FILE_public *)scnout)->_w <= 0) {
267 if (scnout->_cnt <= 0) {
269 if (fflush(scnout) == EOF)
273 state = m_getfld(state, name, scnout->_IO_write_ptr,
274 (long)scnout->_IO_write_ptr-(long)scnout->_IO_write_end , inb);
275 scnout->_IO_write_ptr += msg_count;
276 #elif defined(__DragonFly__)
277 state = m_getfld( state, name, ((struct __FILE_public *)scnout)->_p, -(((struct __FILE_public *)scnout)->_w), inb );
278 ((struct __FILE_public *)scnout)->_w -= msg_count;
279 ((struct __FILE_public *)scnout)->_p += msg_count;
281 state = m_getfld( state, name, scnout->_ptr, -(scnout->_cnt), inb );
282 scnout->_cnt -= msg_count;
283 scnout->_ptr += msg_count;
290 fprintf (stderr, innum ? "??Format error (message %d) in " : "??Format error in ", outnum ? outnum : innum);
291 fprintf (stderr, "component %d\n", compnum);
294 FPUTS ("\n\nBAD MSG:\n");
296 if (putc ('\n', scnout) == EOF) DIEWRERR();
306 adios (NULL, "getfld() returned %d", state);
311 ** format and output the scan line.
315 advise("read", "unable to"); /* "read error" */
319 /* Save and restore buffer so we don't trash our dynamic pool! */
321 saved_c_text = bodycomp->c_text;
322 bodycomp->c_text = tmpbuf;
327 else if (outnum > 0) {
328 dat[2] = ftell(scnout);
329 if (dat[2] == EOF) DIEWRERR();
332 if ((datecomp && !datecomp->c_text) || (!size && !outnum)) {
335 fstat (fileno(inb), &st);
336 if (!size && !outnum)
339 if (! datecomp->c_text) {
340 if (datecomp->c_tws == NULL)
341 datecomp->c_tws = (struct tws *)
342 calloc((size_t) 1, sizeof(*datecomp->c_tws));
343 if (datecomp->c_tws == NULL)
344 adios (NULL, "unable to allocate tws buffer");
345 *datecomp->c_tws = *dlocaltime ((time_t *) &st.st_mtime);
346 datecomp->c_flags |= CF_DATEFAB|CF_TRUE;
348 datecomp->c_flags &= ~CF_DATEFAB;
353 fmt_scan (fmt, scanl, slwidth, dat);
356 fmt = fmt_scan (fmt, scanl, slwidth, dat);
358 fmt = fmt_top; /* reset for old format files */
362 bodycomp->c_text = saved_c_text;
365 fputs (scanl, stdout);
367 FINDCOMP (cptr, "encrypted");
368 encrypted = cptr && cptr->c_text;
370 /* return dynamically allocated buffers to pool */
371 while ((cptr = *savecomp++)) {
372 *--nxtbuf = cptr->c_text;
377 if (outnum && (ferror(scnout) || fclose (scnout) == EOF))
380 return (state != FILEEOF ? SCNERR : encrypted ? SCNENC : SCNMSG);
384 mh_fputs(char *s, FILE *stream)
389 if (putc (c,stream) == EOF )