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