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