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