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