Completely remove the use of TIME_WITH_SYS_TIME (I removed the autoconf
[mmh] / sbr / fmt_scan.c
1
2 /*
3  * fmt_scan.c -- format string interpretation
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9
10 #include <h/mh.h>
11 #include <h/addrsbr.h>
12 #include <h/fmt_scan.h>
13 #include <h/tws.h>
14 #include <h/fmt_compile.h>
15
16 #ifdef HAVE_SYS_TIME_H
17 # include <sys/time.h>
18 #endif
19 #include <time.h>
20 #ifdef MULTIBYTE_SUPPORT
21 #  include <wctype.h>
22 #  include <wchar.h>
23 #endif
24
25 #define NFMTS MAXARGS
26
27 extern char *formataddr ();     /* hook for custom address formatting */
28
29 #ifdef LBL
30 struct msgs *fmt_current_folder; /* current folder (set by main program) */
31 #endif
32
33 extern int fmt_norm;            /* defined in sbr/fmt_def.c = AD_NAME */
34 struct mailname fmt_mnull;
35
36 /*
37  * static prototypes
38  */
39 static int match (char *, char *);
40 static char *get_x400_friendly (char *, char *, int);
41 static int get_x400_comp (char *, char *, char *, int);
42
43
44 /*
45  * test if string "sub" appears anywhere in
46  * string "str" (case insensitive).
47  */
48
49 static int
50 match (char *str, char *sub)
51 {
52     int c1, c2;
53     char *s1, *s2;
54
55 #ifdef LOCALE
56     while ((c1 = *sub)) {
57         c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1;
58         while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2))
59             ;
60         if (! c2)
61             return 0;
62         s1 = sub + 1; s2 = str;
63         while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2))
64             ;
65         if (! c1)
66             return 1;
67     }
68 #else
69     while ((c1 = *sub)) {
70         while ((c2 = *str++) && (c1 | 040) != (c2 | 040))
71             ;
72         if (! c2)
73             return 0;
74         s1 = sub + 1; s2 = str;
75         while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040))
76             ;
77         if (! c1)
78             return 1;
79     }
80 #endif
81     return 1;
82 }
83
84 /*
85  * copy a number to the destination subject to a maximum width
86  */
87 static void
88 cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) {
89     int i, c;
90     char *sp;
91     char *cp = *dest;
92     char *ep = cp + n;
93
94     if (cp + wid < ep) {
95         if ((i = (num)) < 0)
96             i = -(num);
97         if ((c = (wid)) < 0)
98             c = -c;
99         sp = cp + c;
100         do {
101             *--sp = (i % 10) + '0';
102             i /= 10;
103         } while (i > 0 && sp > cp);
104         if (i > 0)
105             *sp = '?';
106         else if ((num) < 0 && sp > cp)
107             *--sp = '-';
108         while (sp > cp)
109             *--sp = fill;
110         cp += c;
111     }
112     *dest = cp;
113 }
114
115 /*
116  * copy string from str to dest padding with the fill character to a size
117  * of wid characters. if wid is negative, the string is right aligned
118  * no more than n bytes are copied
119  */
120 static void
121 cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) {
122     int remaining;     /* remaining output width available */
123     int c, ljust;
124     int end;           /* number of input bytes remaining in str */
125 #ifdef MULTIBYTE_SUPPORT
126     int char_len;      /* bytes in current character */
127     int w;
128     wchar_t wide_char;
129 #endif
130     char *sp;          /* current position in source string */
131     char *cp = *dest;  /* current position in destination string */
132     char *ep = cp + n; /* end of destination buffer */
133     int prevCtrl = 1;
134
135     /* get alignment */
136     ljust = 0;
137     if ((remaining = (wid)) < 0) {
138         remaining = -remaining;
139         ljust++;
140     }
141     if ((sp = (str))) {
142         mbtowc(NULL, NULL, 0); /* reset shift state */
143         end = strlen(str);
144         while (*sp && remaining > 0 && end > 0) {
145 #ifdef MULTIBYTE_SUPPORT
146             char_len = mbtowc(&wide_char, sp, end);
147             if (char_len <= 0 || (cp + char_len > ep))
148                 break;
149
150             end -= char_len;
151
152             if (iswcntrl(wide_char) || iswspace(wide_char)) {
153                 sp += char_len;
154 #else
155             end--;
156             if (iscntrl(*sp) || isspace(*sp)) {
157                 sp++;
158 #endif
159                 if (!prevCtrl) {
160                     *cp++ = ' ';
161                     remaining--;
162                 }
163
164                 prevCtrl = 1;
165                 continue;
166             }
167             prevCtrl = 0;
168
169 #ifdef MULTIBYTE_SUPPORT
170             w = wcwidth(wide_char);
171             if (w >= 0 && remaining >= w) {
172                 strncpy(cp, sp, char_len);
173                 cp += char_len;
174                 remaining -= w;
175             }
176             sp += char_len;
177 #else
178             *cp++ = *sp++;
179             remaining--;
180 #endif
181         }
182     }
183
184     if (ljust) {
185         if (cp + remaining > ep)
186             remaining = ep - cp;
187         ep = cp + remaining;
188         if (remaining > 0) {
189             /* copy string to the right */
190             while (--cp >= *dest)
191                 *(cp + remaining) = *cp;
192             /* add padding at the beginning */
193             cp += remaining;
194             for (c=remaining; c>0; c--)
195                 *cp-- = fill;
196         }
197         *dest = ep;
198     } else {
199         /* pad remaining space */
200         while (remaining-- > 0 && cp < ep)
201                 *cp++ = fill;
202         *dest = cp;
203     }
204 }
205
206 static void
207 cpstripped (char **start, char *end, char *str)
208 {
209     int c;
210     char *s = str;
211
212     if (!s)
213         return;
214
215     /* skip any initial control characters or spaces */
216     while ((c = (unsigned char) *s) &&
217 #ifdef LOCALE
218             (iscntrl(c) || isspace(c)))
219 #else
220             (c <= 32))
221 #endif
222         s++;
223
224     /* compact repeated control characters and spaces into a single space */
225     while((c = (unsigned char) *s++) && *start < end)
226         if (!iscntrl(c) && !isspace(c))
227             *(*start)++ = c;
228         else {
229             while ((c = (unsigned char) *s) &&
230 #ifdef LOCALE
231                     (iscntrl(c) || isspace(c)))
232 #else
233                     (c <= 32))
234 #endif
235                 s++;
236             *(*start)++ = ' ';
237         }
238 }
239
240 static char *lmonth[] = { "January",  "February","March",   "April",
241                           "May",      "June",    "July",    "August",
242                           "September","October", "November","December" };
243
244 static char *
245 get_x400_friendly (char *mbox, char *buffer, int buffer_len)
246 {
247     char given[BUFSIZ], surname[BUFSIZ];
248
249     if (mbox == NULL)
250         return NULL;
251     if (*mbox == '"')
252         mbox++;
253     if (*mbox != '/')
254         return NULL;
255
256     if (get_x400_comp (mbox, "/PN=", buffer, buffer_len)) {
257         for (mbox = buffer; (mbox = strchr(mbox, '.')); )
258             *mbox++ = ' ';
259
260         return buffer;
261     }
262
263     if (!get_x400_comp (mbox, "/S=", surname, sizeof(surname)))
264         return NULL;
265
266     if (get_x400_comp (mbox, "/G=", given, sizeof(given)))
267         snprintf (buffer, buffer_len, "%s %s", given, surname);
268     else
269         snprintf (buffer, buffer_len, "%s", surname);
270
271     return buffer;
272 }
273
274 static int
275 get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len)
276 {
277     int idx;
278     char *cp;
279
280     if ((idx = stringdex (key, mbox)) < 0
281             || !(cp = strchr(mbox += idx + strlen (key), '/')))
282         return 0;
283
284     snprintf (buffer, buffer_len, "%*.*s", (int)(cp - mbox), (int)(cp - mbox), mbox);
285     return 1;
286 }
287
288 struct format *
289 fmt_scan (struct format *format, char *scanl, int width, int *dat)
290 {
291     char *cp, *ep;
292     unsigned char *sp;
293     char *savestr = NULL;
294     unsigned char *str = NULL;
295     char buffer[BUFSIZ], buffer2[BUFSIZ];
296     int i, c, ljust, n;
297     int value = 0;
298     time_t t;
299     struct format *fmt;
300     struct comp *comp;
301     struct tws *tws;
302     struct mailname *mn;
303
304     cp = scanl;
305     ep = scanl + width - 1;
306
307     for (fmt = format; fmt->f_type != FT_DONE; fmt++)
308         switch (fmt->f_type) {
309         case FT_PARSEADDR:
310         case FT_PARSEDATE:
311             fmt->f_comp->c_flags &= ~CF_PARSED;
312             break;
313         }
314
315     fmt = format;
316
317     while (cp < ep) {
318         switch (fmt->f_type) {
319
320         case FT_COMP:
321             cpstripped (&cp, ep, fmt->f_comp->c_text);
322             break;
323         case FT_COMPF:
324             cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, ep - cp);
325             break;
326
327         case FT_LIT:
328             sp = fmt->f_text;
329             while( (c = *sp++) && cp < ep)
330                 *cp++ = c;
331             break;
332         case FT_LITF:
333             sp = fmt->f_text;
334             ljust = 0;
335             i = fmt->f_width;
336             if (i < 0) {
337                 i = -i;
338                 ljust++;                /* XXX should do something with this */
339             }
340             while( (c = *sp++) && --i >= 0 && cp < ep)
341                 *cp++ = c;
342             while( --i >= 0 && cp < ep)
343                 *cp++ = fmt->f_fill;
344             break;
345
346         case FT_STR:
347             cpstripped (&cp, ep, str);
348             break;
349         case FT_STRF:
350             cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp);
351             break;
352         case FT_STRFW:
353             adios (NULL, "internal error (FT_STRFW)");
354
355         case FT_NUM:
356             n = snprintf(cp, ep - cp + 1, "%d", value);
357             if (n >= 0) {
358                 if (n >= ep - cp) {
359                     cp = ep;
360                 } else
361                     cp += n;
362             }
363             break;
364         case FT_NUMF:
365             cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp);
366             break;
367
368         case FT_CHAR:
369             *cp++ = fmt->f_char;
370             break;
371
372         case FT_DONE:
373             goto finished;
374
375         case FT_IF_S:
376             if (!(value = (str && *str))) {
377                 fmt += fmt->f_skip;
378                 continue;
379             }
380             break;
381
382         case FT_IF_S_NULL:
383             if (!(value = (str == NULL || *str == 0))) {
384                 fmt += fmt->f_skip;
385                 continue;
386             }
387             break;
388
389         case FT_IF_V_EQ:
390             if (value != fmt->f_value) {
391                 fmt += fmt->f_skip;
392                 continue;
393             }
394             break;
395
396         case FT_IF_V_NE:
397             if (value == fmt->f_value) {
398                 fmt += fmt->f_skip;
399                 continue;
400             }
401             break;
402
403         case FT_IF_V_GT:
404             if (value <= fmt->f_value) {
405                 fmt += fmt->f_skip;
406                 continue;
407             }
408             break;
409
410         case FT_IF_MATCH:
411             if (!(value = (str && match (str, fmt->f_text)))) {
412                 fmt += fmt->f_skip;
413                 continue;
414             }
415             break;
416
417         case FT_V_MATCH:
418             if (str)
419                 value = match (str, fmt->f_text);
420             else
421                 value = 0;
422             break;
423
424         case FT_IF_AMATCH:
425             if (!(value = (str && uprf (str, fmt->f_text)))) {
426                 fmt += fmt->f_skip;
427                 continue;
428             }
429             break;
430
431         case FT_V_AMATCH:
432             value = uprf (str, fmt->f_text);
433             break;
434
435         case FT_S_NONNULL:
436             value = (str != NULL && *str != 0);
437             break;
438
439         case FT_S_NULL:
440             value = (str == NULL || *str == 0);
441             break;
442
443         case FT_V_EQ:
444             value = (fmt->f_value == value);
445             break;
446
447         case FT_V_NE:
448             value = (fmt->f_value != value);
449             break;
450
451         case FT_V_GT:
452             value = (fmt->f_value > value);
453             break;
454
455         case FT_GOTO:
456             fmt += fmt->f_skip;
457             continue;
458
459         case FT_NOP:
460             break;
461
462         case FT_LS_COMP:
463             str = fmt->f_comp->c_text;
464             break;
465         case FT_LS_LIT:
466             str = fmt->f_text;
467             break;
468         case FT_LS_GETENV:
469             if (!(str = getenv (fmt->f_text)))
470                 str = "";
471             break;
472         case FT_LS_CFIND:
473             if (!(str = context_find (fmt->f_text)))
474                 str = "";
475             break;
476
477         case FT_LS_DECODECOMP:
478             if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2)))
479                 str = buffer2;
480             else
481                 str = fmt->f_comp->c_text;
482             break;
483
484         case FT_LS_DECODE:
485             if (str && decode_rfc2047(str, buffer2, sizeof(buffer2)))
486                 str = buffer2;
487             break;
488
489         case FT_LS_TRIM:
490             if (str) {
491                     unsigned char *xp;
492
493                     strncpy(buffer, str, sizeof(buffer));
494                     buffer[sizeof(buffer)-1] = '\0';
495                     str = buffer;
496                     while (isspace(*str))
497                             str++;
498                     ljust = 0;
499                     if ((i = fmt->f_width) < 0) {
500                             i = -i;
501                             ljust++;
502                     }
503
504                     if (!ljust && i > 0 && strlen(str) > i)
505                             str[i] = '\0';
506                     xp = str;
507                     xp += strlen(str) - 1;
508                     while (xp > str && isspace(*xp))
509                             *xp-- = '\0';
510                     if (ljust && i > 0 && strlen(str) > i)
511                         str += strlen(str) - i;
512             }
513             break;
514
515         case FT_LV_COMPFLAG:
516             value = (fmt->f_comp->c_flags & CF_TRUE) != 0;
517             break;
518         case FT_LV_COMP:
519             value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
520             break;
521         case FT_LV_LIT:
522             value = fmt->f_value;
523             break;
524         case FT_LV_DAT:
525             value = dat[fmt->f_value];
526             break;
527         case FT_LV_STRLEN:
528             if (str != NULL)
529                     value = strlen(str);
530             else
531                     value = 0;
532             break;
533         case FT_LV_CHAR_LEFT:
534             value = width - (cp - scanl);
535             break;
536         case FT_LV_PLUS_L:
537             value += fmt->f_value;
538             break;
539         case FT_LV_MINUS_L:
540             value = fmt->f_value - value;
541             break;
542         case FT_LV_DIVIDE_L:
543             if (fmt->f_value)
544                 value = value / fmt->f_value;
545             else
546                 value = 0;
547             break;
548         case FT_LV_MODULO_L:
549             if (fmt->f_value)
550                 value = value % fmt->f_value;
551             else
552                 value = 0;
553             break;
554         case FT_SAVESTR:
555             savestr = str;
556             break;
557
558         case FT_LV_SEC:
559             value = fmt->f_comp->c_tws->tw_sec;
560             break;
561         case FT_LV_MIN:
562             value = fmt->f_comp->c_tws->tw_min;
563             break;
564         case FT_LV_HOUR:
565             value = fmt->f_comp->c_tws->tw_hour;
566             break;
567         case FT_LV_MDAY:
568             value = fmt->f_comp->c_tws->tw_mday;
569             break;
570         case FT_LV_MON:
571             value = fmt->f_comp->c_tws->tw_mon + 1;
572             break;
573         case FT_LS_MONTH:
574             str = tw_moty[fmt->f_comp->c_tws->tw_mon];
575             break;
576         case FT_LS_LMONTH:
577             str = lmonth[fmt->f_comp->c_tws->tw_mon];
578             break;
579         case FT_LS_ZONE:
580             str = dtwszone (fmt->f_comp->c_tws);
581             break;
582         case FT_LV_YEAR:
583             value = fmt->f_comp->c_tws->tw_year;
584             break;
585         case FT_LV_WDAY:
586             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
587                 set_dotw (tws);
588             value = tws->tw_wday;
589             break;
590         case FT_LS_DAY:
591             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
592                 set_dotw (tws);
593             str = tw_dotw[tws->tw_wday];
594             break;
595         case FT_LS_WEEKDAY:
596             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
597                 set_dotw (tws);
598             str = tw_ldotw[tws->tw_wday];
599             break;
600         case FT_LV_YDAY:
601             value = fmt->f_comp->c_tws->tw_yday;
602             break;
603         case FT_LV_ZONE:
604             value = fmt->f_comp->c_tws->tw_zone;
605             break;
606         case FT_LV_CLOCK:
607             if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
608                 value = dmktime(fmt->f_comp->c_tws);
609             break;
610         case FT_LV_RCLOCK:
611             if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
612                 value = dmktime(fmt->f_comp->c_tws);
613             value = time((time_t *) 0) - value;
614             break;
615         case FT_LV_DAYF:
616             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
617                 set_dotw (tws);
618             switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
619                 case TW_SEXP:
620                     value = 1; break;
621                 case TW_SIMP:
622                     value = 0; break;
623                 default:
624                     value = -1; break;
625             }
626         case FT_LV_ZONEF:
627             if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP)
628                     value = 1;
629             else
630                     value = -1;
631             break;
632         case FT_LV_DST:
633             value = fmt->f_comp->c_tws->tw_flags & TW_DST;
634             break;
635         case FT_LS_822DATE:
636             str = dasctime (fmt->f_comp->c_tws , TW_ZONE);
637             break;
638         case FT_LS_PRETTY:
639             str = dasctime (fmt->f_comp->c_tws, TW_NULL);
640             break;
641
642         case FT_LS_PERS:
643             str = fmt->f_comp->c_mn->m_pers;
644             break;
645         case FT_LS_MBOX:
646             str = fmt->f_comp->c_mn->m_mbox;
647             break;
648         case FT_LS_HOST:
649             str = fmt->f_comp->c_mn->m_host;
650             break;
651         case FT_LS_PATH:
652             str = fmt->f_comp->c_mn->m_path;
653             break;
654         case FT_LS_GNAME:
655             str = fmt->f_comp->c_mn->m_gname;
656             break;
657         case FT_LS_NOTE:
658             str = fmt->f_comp->c_mn->m_note;
659             break;
660         case FT_LS_822ADDR:
661             str = adrformat( fmt->f_comp->c_mn );
662             break;
663         case FT_LV_HOSTTYPE:
664             value = fmt->f_comp->c_mn->m_type;
665             break;
666         case FT_LV_INGRPF:
667             value = fmt->f_comp->c_mn->m_ingrp;
668             break;
669         case FT_LV_NOHOSTF:
670             value = fmt->f_comp->c_mn->m_nohost;
671             break;
672         case FT_LS_ADDR:
673         case FT_LS_FRIENDLY:
674             if ((mn = fmt->f_comp->c_mn) == &fmt_mnull) {
675                 str = fmt->f_comp->c_text;
676                 break;
677             }
678             if (fmt->f_type == FT_LS_ADDR)
679                 goto unfriendly;
680             if ((str = mn->m_pers) == NULL) {
681                 if ((str = mn->m_note)) {
682                     strncpy (buffer, str, sizeof(buffer));
683                     buffer[sizeof(buffer)-1] = '\0';
684                     str = buffer;
685                     if (*str == '(')
686                         str++;
687                     sp = str + strlen(str) - 1;
688                     if (*sp == ')') {
689                         *sp-- = '\0';
690                         while (sp >= str)
691                             if (*sp == ' ')
692                                 *sp-- = '\0';
693                             else
694                                 break;
695                     }
696                 } else if (!(str = get_x400_friendly (mn->m_mbox,
697                                 buffer, sizeof(buffer)))) {
698         unfriendly: ;
699                   switch (mn->m_type) {
700                     case LOCALHOST:
701                         str = mn->m_mbox;
702                         break;
703                     case UUCPHOST:
704                         snprintf (buffer, sizeof(buffer), "%s!%s",
705                                 mn->m_host, mn->m_mbox);
706                         str = buffer;
707                         break;
708                     default:
709                         if (mn->m_mbox) {
710                             snprintf (buffer, sizeof(buffer), "%s@%s",
711                                 mn->m_mbox, mn->m_host);
712                             str= buffer;
713                         }
714                         else
715                             str = mn->m_text;
716                         break;
717                   }
718                 }
719             }
720             break;
721
722
723                 /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
724         case FT_LS_UNQUOTE:
725             if (str) {          
726                 int m;
727                 strncpy(buffer, str, sizeof(buffer));
728                 /* strncpy doesn't NUL-terminate if it fills the buffer */
729                 buffer[sizeof(buffer)-1] = '\0';
730                 str = buffer;
731         
732                 /* we will parse from buffer to buffer2 */
733                 n = 0; /* n is the input position in str */
734                 m = 0; /* m is the ouput position in buffer2 */
735
736                 while ( str[n] != '\0') {
737                     switch ( str[n] ) {
738                         case '\\':
739                             n++;
740                             if ( str[n] != '\0')
741                                 buffer2[m++] = str[n++];
742                             break;
743                         case '"':
744                             n++;
745                             break;
746                         default:
747                             buffer2[m++] = str[n++];
748                             break;
749                         }
750                 }
751                 buffer2[m] = '\0';
752                 str = buffer2;
753             }
754             break;
755
756         case FT_LOCALDATE:
757             comp = fmt->f_comp;
758             if ((t = comp->c_tws->tw_clock) == 0)
759                 t = dmktime(comp->c_tws);
760             tws = dlocaltime(&t);
761             *comp->c_tws = *tws;
762             break;
763
764         case FT_GMTDATE:
765             comp = fmt->f_comp;
766             if ((t = comp->c_tws->tw_clock) == 0)
767                 t = dmktime(comp->c_tws);
768             tws = dgmtime(&t);
769             *comp->c_tws = *tws;
770             break;
771
772         case FT_PARSEDATE:
773             comp = fmt->f_comp;
774             if (comp->c_flags & CF_PARSED)
775                 break;
776             if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
777                 *comp->c_tws = *tws;
778                 comp->c_flags &= ~CF_TRUE;
779             } else if ((comp->c_flags & CF_DATEFAB) == 0) {
780                 memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws);
781                 comp->c_flags = CF_TRUE;
782             }
783             comp->c_flags |= CF_PARSED;
784             break;
785
786         case FT_FORMATADDR:
787             /* hook for custom address list formatting (see replsbr.c) */
788             str = formataddr (savestr, str);
789             break;
790
791         case FT_PUTADDR:
792             /* output the str register as an address component,
793              * splitting it into multiple lines if necessary.  The
794              * value reg. contains the max line length.  The lit.
795              * field may contain a string to prepend to the result
796              * (e.g., "To: ")
797              */
798             {
799             unsigned char *lp;
800             char *lastb;
801             int indent, wid, len;
802
803             lp = str;
804             wid = value;
805             len = strlen (str);
806             sp = fmt->f_text;
807             indent = strlen (sp);
808             wid -= indent;
809             while( (c = *sp++) && cp < ep)
810                 *cp++ = c;
811             while (len > wid) {
812                 /* try to break at a comma; failing that, break at a
813                  * space.
814                  */
815                 lastb = 0; sp = lp + wid;
816                 while (sp > lp && (c = *--sp) != ',') {
817                     if (! lastb && isspace(c))
818                         lastb = sp - 1;
819                 }
820                 if (sp == lp) {
821                     if (! (sp = lastb)) {
822                         sp = lp + wid - 1;
823                         while (*sp && *sp != ',' && !isspace(*sp))
824                             sp++;
825                         if (*sp != ',')
826                             sp--;
827                     }
828                 }
829                 len -= sp - lp + 1;
830                 while (cp < ep && lp <= sp)
831                     *cp++ = *lp++;
832                 while (isspace(*lp))
833                     lp++, len--;
834                 if (*lp) {
835                     if (cp < ep)
836                         *cp++ = '\n';
837                     for (i=indent; cp < ep && i > 0; i--)
838                         *cp++ = ' ';
839                 }
840             }
841             cpstripped (&cp, ep, lp);
842             }
843             break;
844
845         case FT_PARSEADDR:
846             comp = fmt->f_comp;
847             if (comp->c_flags & CF_PARSED)
848                 break;
849             if (comp->c_mn != &fmt_mnull)
850                 mnfree (comp->c_mn);
851             if ((sp = comp->c_text) && (sp = getname(sp)) &&
852                 (mn = getm (sp, NULL, 0, fmt_norm, NULL))) {
853                 comp->c_mn = mn;
854                 while (getname(""))
855                     ;
856                 comp->c_flags |= CF_PARSED;
857             } else {
858                 while (getname(""))             /* XXX */
859                     ;
860                 comp->c_mn = &fmt_mnull;
861             }
862             break;
863
864         case FT_MYMBOX:
865             /*
866              * if there's no component, we say true.  Otherwise we
867              * say "true" only if we can parse the address and it
868              * matches one of our addresses.
869              */
870             comp = fmt->f_comp;
871             if (comp->c_mn != &fmt_mnull)
872                 mnfree (comp->c_mn);
873             if ((sp = comp->c_text) && (sp = getname(sp)) &&
874                 (mn = getm (sp, NULL, 0, AD_NAME, NULL))) {
875                 comp->c_mn = mn;
876                 if (ismymbox(mn))
877                     comp->c_flags |= CF_TRUE;
878                 else
879                     comp->c_flags &= ~CF_TRUE;
880                 while ((sp = getname(sp)))
881                     if ((comp->c_flags & CF_TRUE) == 0 &&
882                         (mn = getm (sp, NULL, 0, AD_NAME, NULL)))
883                         if (ismymbox(mn))
884                             comp->c_flags |= CF_TRUE;
885             } else {
886                 while (getname(""))             /* XXX */
887                     ;
888                 if (comp->c_text == 0)
889                     comp->c_flags |= CF_TRUE;
890                 else
891                     comp->c_flags &= ~CF_TRUE;
892                 comp->c_mn = &fmt_mnull;
893             }
894             break;
895
896         case FT_ADDTOSEQ:
897 #ifdef LBL
898             /* If we're working on a folder (as opposed to a file), add the
899              * current msg to sequence given in literal field.  Don't
900              * disturb string or value registers.
901              */
902             if (fmt_current_folder)
903                     seq_addmsg(fmt_current_folder, fmt->f_text, dat[0], -1);
904 #endif
905             break;
906         }
907         fmt++;
908     }
909 #ifndef JLR
910     finished:;
911     if (cp[-1] != '\n')
912         *cp++ = '\n';
913     *cp   = 0;
914     return ((struct format *)0);
915 #else /* JLR */
916     if (cp[-1] != '\n')
917         *cp++ = '\n';
918     while (fmt->f_type != FT_DONE)
919         fmt++;
920
921     finished:;
922     *cp = '\0';
923     return (fmt->f_value ? ++fmt : (struct format *) 0);
924
925 #endif /* JLR */
926 }