]> diplodocus.org Git - nmh/blob - sbr/fmt_scan.c
Garbage collect unused code.
[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 * 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 #ifdef MULTIBYTE_SUPPORT
24 # include <wctype.h>
25 # include <wchar.h>
26 #endif
27
28 struct mailname fmt_mnull = { NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0,
29 NULL, NULL };
30
31 /*
32 * static prototypes
33 */
34 static int match (char *, char *);
35 static char *get_x400_friendly (char *, char *, int);
36 static int get_x400_comp (char *, char *, char *, int);
37
38
39 /*
40 * test if string "sub" appears anywhere in
41 * string "str" (case insensitive).
42 */
43
44 static int
45 match (char *str, char *sub)
46 {
47 int c1, c2;
48 char *s1, *s2;
49
50 #ifdef LOCALE
51 while ((c1 = *sub)) {
52 c1 = (isascii((unsigned char) c1) && isalpha((unsigned char) c1) &&
53 isupper((unsigned char) c1)) ? tolower((unsigned char) c1) : c1;
54 while ((c2 = *str++) && c1 != ((isascii((unsigned char) c2) &&
55 isalpha((unsigned char) c2) &&
56 isupper((unsigned char) c2)) ?
57 tolower((unsigned char) c2) : c2))
58 ;
59 if (! c2)
60 return 0;
61 s1 = sub + 1; s2 = str;
62 while ((c1 = *s1++) && ((isascii((unsigned char) c1) &&
63 isalpha((unsigned char) c1) &&
64 isupper((unsigned char) c1)) ?
65 tolower(c1) : c1) ==
66 ((isascii((unsigned char) (c2 =*s2++)) &&
67 isalpha((unsigned char) c2) &&
68 isupper((unsigned char) c2)) ?
69 tolower((unsigned char) 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 **ep, char *str, unsigned int wid, char fill,
128 char *epmax) {
129 int remaining; /* remaining output width available */
130 int c, ljust;
131 int end; /* number of input bytes remaining in str */
132 #ifdef MULTIBYTE_SUPPORT
133 int char_len; /* bytes in current character */
134 int w;
135 wchar_t wide_char;
136 char *altstr = NULL;
137 #endif
138 char *sp; /* current position in source string */
139 char *cp = *dest; /* current position in destination string */
140 int prevCtrl = 1;
141
142 /* get alignment */
143 ljust = 0;
144 if ((remaining = (wid)) < 0) {
145 remaining = -remaining;
146 ljust++;
147 }
148 if ((sp = (str))) {
149 #ifdef MULTIBYTE_SUPPORT
150 mbtowc(NULL, NULL, 0); /* reset shift state */
151 #endif
152 end = strlen(str);
153 while (*sp && remaining > 0 && end > 0) {
154 #ifdef MULTIBYTE_SUPPORT
155 char_len = mbtowc(&wide_char, sp, end);
156
157 /*
158 * See the relevant comments in cpstripped() to explain what's
159 * going on here; we want to handle the case where we get
160 * characters that mbtowc() cannot handle
161 */
162
163 if (char_len < 0) {
164 altstr = "?";
165 char_len = mbtowc(&wide_char, altstr, 1);
166 }
167
168 if (char_len <= 0)
169 break;
170
171 w = wcwidth(wide_char);
172
173 /*
174 * Multibyte characters can have a variable number of column
175 * widths, so use the column width to bump the end pointer when
176 * appropriate.
177 */
178 if (w >= 0 && char_len > 1 && epmax - *ep >= char_len - w) {
179 *ep += char_len - w;
180 }
181
182 if (w >= 0 && cp + w > *ep)
183 break;
184
185 end -= char_len;
186
187 if (iswcntrl(wide_char) || iswspace(wide_char)) {
188 sp += char_len;
189 #else
190 int c;
191 end--;
192 /* isnctrl(), etc., take an int argument. Cygwin's ctype.h
193 intentionally warns if they are passed a char. */
194 c = (unsigned char) *sp;
195 if (iscntrl(c) || isspace(c)) {
196 sp++;
197 #endif
198 if (!prevCtrl) {
199 *cp++ = ' ';
200 remaining--;
201 }
202
203 prevCtrl = 1;
204 continue;
205 }
206 prevCtrl = 0;
207
208 #ifdef MULTIBYTE_SUPPORT
209 if (w >= 0 && remaining >= w) {
210 strncpy(cp, altstr ? altstr : sp, char_len);
211 cp += char_len;
212 remaining -= w;
213 altstr = NULL;
214 }
215 sp += char_len;
216 #else
217 *cp++ = *sp++;
218 remaining--;
219 #endif
220 }
221 }
222
223 if (ljust) {
224 char *endfield;
225 if (cp + remaining > *ep)
226 remaining = *ep - cp;
227 endfield = cp + remaining;
228 if (remaining > 0) {
229 /* copy string to the right */
230 while (--cp >= *dest)
231 *(cp + remaining) = *cp;
232 /* add padding at the beginning */
233 cp += remaining;
234 for (c=remaining; c>0; c--)
235 *cp-- = fill;
236 }
237 *dest = endfield;
238 } else {
239 /* pad remaining space */
240 while (remaining-- > 0 && cp < *ep)
241 *cp++ = fill;
242 *dest = cp;
243 }
244 }
245
246 static void
247 cpstripped (char **dest, char **end, char *max, char *str)
248 {
249 int prevCtrl = 1; /* This is 1 so we strip out leading spaces */
250 int len;
251 #ifdef MULTIBYTE_SUPPORT
252 int char_len, w;
253 wchar_t wide_char;
254 char *altstr = NULL;
255 #endif /* MULTIBYTE_SUPPORT */
256
257 if (!str)
258 return;
259
260 len = strlen(str);
261
262 #ifdef MULTIBYTE_SUPPORT
263 mbtowc(NULL, NULL, 0); /* Reset shift state */
264 #endif /* MULTIBYTE_SUPPORT */
265
266 /*
267 * Process each character at a time; if we have multibyte support
268 * then deal with that here.
269 */
270
271 while (*str != '\0' && len > 0 && *dest < *end) {
272 #ifdef MULTIBYTE_SUPPORT
273 char_len = mbtowc(&wide_char, str, len);
274 w = wcwidth(wide_char);
275
276 /*
277 * Account for multibyte characters, and increment the end pointer
278 * by the number of "extra" bytes in this character. That's the
279 * character length (char_len) minus the column width (w).
280 */
281 if (w >= 0 && char_len > 1 && max - *end >= char_len - w) {
282 *end += char_len - w;
283 }
284
285 /*
286 * If mbrtowc() failed, then we have a character that isn't valid
287 * in the current encoding. Replace it with a '?'. We do that by
288 * setting the alstr variable to the value of the replacement string;
289 * altstr is used below when the bytes are copied into the output
290 * buffer.
291 */
292
293 if (char_len < 0) {
294 altstr = "?";
295 char_len = mbtowc(&wide_char, altstr, 1);
296 }
297
298 if (char_len <= 0 || *dest + char_len > *end)
299 break;
300
301 len -= char_len;
302
303 if (iswcntrl(wide_char) || iswspace(wide_char)) {
304 str += char_len;
305 #else /* MULTIBYTE_SUPPORT */
306 int c = (unsigned char) *str;
307 len--;
308 if (iscntrl(c) || isspace(c)) {
309 str++;
310 #endif /* MULTIBYTE_SUPPORT */
311 if (! prevCtrl) {
312 *(*dest)++ = ' ';
313 }
314
315 prevCtrl = 1;
316 continue;
317 }
318
319 prevCtrl = 0;
320
321 #ifdef MULTIBYTE_SUPPORT
322 memcpy(*dest, altstr ? altstr : str, char_len);
323 str += char_len;
324 *dest += char_len;
325 altstr = NULL;
326 #else /* MULTIBYE_SUPPORT */
327 *(*dest)++ = *str++
328 #endif /* MULTIBYTE_SUPPORT */
329 }
330 }
331
332 static char *lmonth[] = { "January", "February","March", "April",
333 "May", "June", "July", "August",
334 "September","October", "November","December" };
335
336 static char *
337 get_x400_friendly (char *mbox, char *buffer, int buffer_len)
338 {
339 char given[BUFSIZ], surname[BUFSIZ];
340
341 if (mbox == NULL)
342 return NULL;
343 if (*mbox == '"')
344 mbox++;
345 if (*mbox != '/')
346 return NULL;
347
348 if (get_x400_comp (mbox, "/PN=", buffer, buffer_len)) {
349 for (mbox = buffer; (mbox = strchr(mbox, '.')); )
350 *mbox++ = ' ';
351
352 return buffer;
353 }
354
355 if (!get_x400_comp (mbox, "/S=", surname, sizeof(surname)))
356 return NULL;
357
358 if (get_x400_comp (mbox, "/G=", given, sizeof(given)))
359 snprintf (buffer, buffer_len, "%s %s", given, surname);
360 else
361 snprintf (buffer, buffer_len, "%s", surname);
362
363 return buffer;
364 }
365
366 static int
367 get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len)
368 {
369 int idx;
370 char *cp;
371
372 if ((idx = stringdex (key, mbox)) < 0
373 || !(cp = strchr(mbox += idx + strlen (key), '/')))
374 return 0;
375
376 snprintf (buffer, buffer_len, "%*.*s", (int)(cp - mbox), (int)(cp - mbox), mbox);
377 return 1;
378 }
379
380 struct format *
381 fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat,
382 struct fmt_callbacks *callbacks)
383 {
384 char *cp, *ep, *sp;
385 char *savestr = NULL, *str = NULL;
386 char buffer[BUFSIZ], buffer2[BUFSIZ];
387 int i, c, ljust, n;
388 int value = 0;
389 time_t t;
390 struct format *fmt;
391 struct comp *comp;
392 struct tws *tws;
393 struct mailname *mn;
394
395 /* ep keeps track of displayed characters. They're limited by width.
396 The total number of characters, cp - scanl + 1 (for trailing NULL),
397 includes invisible control characters and is limited by max. */
398 cp = scanl;
399 ep = scanl + (width <= (int) max ? width : (int) max) - 1;
400
401 for (fmt = format; fmt->f_type != FT_DONE; fmt++)
402 switch (fmt->f_type) {
403 case FT_PARSEADDR:
404 case FT_PARSEDATE:
405 fmt->f_comp->c_flags &= ~CF_PARSED;
406 break;
407 case FT_COMP:
408 case FT_COMPF:
409 case FT_LS_COMP:
410 case FT_LS_DECODECOMP:
411 /*
412 * Trim these components of any newlines.
413 *
414 * But don't trim the "body" and "text" components.
415 */
416
417 comp = fmt->f_comp;
418
419 if (! (comp->c_flags & CF_TRIMMED) && comp->c_text &&
420 (i = strlen(comp->c_text)) > 0) {
421 if (comp->c_text[i - 1] == '\n' &&
422 strcmp(comp->c_name, "body") != 0 &&
423 strcmp(comp->c_name, "text") != 0)
424 comp->c_text[i - 1] = '\0';
425 comp->c_flags |= CF_TRIMMED;
426 }
427 break;
428 }
429
430 fmt = format;
431
432 while (cp < ep) {
433 switch (fmt->f_type) {
434
435 case FT_COMP:
436 cpstripped (&cp, &ep, scanl + max - 1, fmt->f_comp->c_text);
437 break;
438 case FT_COMPF:
439 cptrimmed (&cp, &ep, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill,
440 scanl + max - 1);
441 break;
442
443 case FT_LIT:
444 sp = fmt->f_text;
445 while( (c = *sp++) && cp < ep)
446 *cp++ = c;
447 break;
448 case FT_LITF:
449 sp = fmt->f_text;
450 ljust = 0;
451 i = fmt->f_width;
452 if (i < 0) {
453 i = -i;
454 ljust++; /* XXX should do something with this */
455 }
456 while( (c = *sp++) && --i >= 0 && cp < ep)
457 *cp++ = c;
458 while( --i >= 0 && cp < ep)
459 *cp++ = fmt->f_fill;
460 break;
461
462 case FT_STR:
463 cpstripped (&cp, &ep, scanl + max - 1, str);
464 break;
465 case FT_STRF:
466 cptrimmed (&cp, &ep, str, fmt->f_width, fmt->f_fill,
467 scanl + max - 1);
468 break;
469 case FT_STRLIT:
470 if (str) {
471 sp = str;
472 while ((c = *sp++) && cp < ep)
473 *cp++ = c;
474 }
475 break;
476 case FT_STRLITZ:
477 if (str) {
478 size_t len = strlen (str);
479
480 /* Don't want to emit part of an escape sequence. So if
481 there isn't enough room in the buffer for the entire
482 string, skip it completely. */
483 if (cp - scanl + len + 1 < max) {
484 for (sp = str; *sp; *cp++ = *sp++) continue;
485
486 /* This string doesn't count against the width.
487 So increase ep the same amount as cp, only if the
488 scan buffer will always be large enough. */
489 if (ep - scanl + len + 1 < max) {
490 ep += len;
491 }
492 }
493 }
494 break;
495 case FT_STRFW:
496 adios (NULL, "internal error (FT_STRFW)");
497
498 case FT_NUM:
499 n = snprintf(cp, ep - cp + 1, "%d", value);
500 if (n >= 0) {
501 if (n >= ep - cp) {
502 cp = ep;
503 } else
504 cp += n;
505 }
506 break;
507 case FT_NUMF:
508 cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp);
509 break;
510
511 case FT_CHAR:
512 *cp++ = fmt->f_char;
513 break;
514
515 case FT_DONE:
516 if (callbacks && callbacks->trace_func)
517 callbacks->trace_func(callbacks->trace_context, fmt, value,
518 str, scanl);
519 goto finished;
520
521 case FT_IF_S:
522 if (!(value = (str && *str))) {
523 if (callbacks && callbacks->trace_func)
524 callbacks->trace_func(callbacks->trace_context, fmt, value,
525 str, scanl);
526 fmt += fmt->f_skip;
527 continue;
528 }
529 break;
530
531 case FT_IF_S_NULL:
532 if (!(value = (str == NULL || *str == 0))) {
533 if (callbacks && callbacks->trace_func)
534 callbacks->trace_func(callbacks->trace_context, fmt, value,
535 str, scanl);
536 fmt += fmt->f_skip;
537 continue;
538 }
539 break;
540
541 case FT_IF_V_EQ:
542 if (value != fmt->f_value) {
543 if (callbacks && callbacks->trace_func)
544 callbacks->trace_func(callbacks->trace_context, fmt, value,
545 str, scanl);
546 fmt += fmt->f_skip;
547 continue;
548 }
549 break;
550
551 case FT_IF_V_NE:
552 if (value == fmt->f_value) {
553 if (callbacks && callbacks->trace_func)
554 callbacks->trace_func(callbacks->trace_context, fmt, value,
555 str, scanl);
556 fmt += fmt->f_skip;
557 continue;
558 }
559 break;
560
561 case FT_IF_V_GT:
562 if (value <= fmt->f_value) {
563 if (callbacks && callbacks->trace_func)
564 callbacks->trace_func(callbacks->trace_context, fmt, value,
565 str, scanl);
566 fmt += fmt->f_skip;
567 continue;
568 }
569 break;
570
571 case FT_IF_MATCH:
572 if (!(value = (str && match (str, fmt->f_text)))) {
573 if (callbacks && callbacks->trace_func)
574 callbacks->trace_func(callbacks->trace_context, fmt, value,
575 str, scanl);
576 fmt += fmt->f_skip;
577 continue;
578 }
579 break;
580
581 case FT_V_MATCH:
582 if (str)
583 value = match (str, fmt->f_text);
584 else
585 value = 0;
586 break;
587
588 case FT_IF_AMATCH:
589 if (!(value = (str && uprf (str, fmt->f_text)))) {
590 if (callbacks && callbacks->trace_func)
591 callbacks->trace_func(callbacks->trace_context, fmt, value,
592 str, scanl);
593 fmt += fmt->f_skip;
594 continue;
595 }
596 break;
597
598 case FT_V_AMATCH:
599 value = uprf (str, fmt->f_text);
600 break;
601
602 case FT_S_NONNULL:
603 value = (str != NULL && *str != 0);
604 break;
605
606 case FT_S_NULL:
607 value = (str == NULL || *str == 0);
608 break;
609
610 case FT_V_EQ:
611 value = (fmt->f_value == value);
612 break;
613
614 case FT_V_NE:
615 value = (fmt->f_value != value);
616 break;
617
618 case FT_V_GT:
619 value = (fmt->f_value > value);
620 break;
621
622 case FT_GOTO:
623 if (callbacks && callbacks->trace_func)
624 callbacks->trace_func(callbacks->trace_context, fmt, value,
625 str, scanl);
626 fmt += fmt->f_skip;
627 continue;
628
629 case FT_NOP:
630 break;
631
632 case FT_LS_COMP:
633 str = fmt->f_comp->c_text;
634 break;
635 case FT_LS_LIT:
636 str = fmt->f_text;
637 break;
638 case FT_LS_GETENV:
639 if (!(str = getenv (fmt->f_text)))
640 str = "";
641 break;
642 case FT_LS_CFIND:
643 if (!(str = context_find (fmt->f_text)))
644 str = "";
645 break;
646
647 case FT_LS_DECODECOMP:
648 if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2)))
649 str = buffer2;
650 else
651 str = fmt->f_comp->c_text;
652 break;
653
654 case FT_LS_DECODE:
655 if (str && decode_rfc2047(str, buffer2, sizeof(buffer2)))
656 str = buffer2;
657 break;
658
659 case FT_LS_TRIM:
660 if (str) {
661 char *xp;
662
663 strncpy(buffer, str, sizeof(buffer));
664 buffer[sizeof(buffer)-1] = '\0';
665 str = buffer;
666 while (isspace((unsigned char) *str))
667 str++;
668 ljust = 0;
669 if ((i = fmt->f_width) < 0) {
670 i = -i;
671 ljust++;
672 }
673
674 if (!ljust && i > 0 && (int) strlen(str) > i)
675 str[i] = '\0';
676 xp = str;
677 xp += strlen(str) - 1;
678 while (xp > str && isspace((unsigned char) *xp))
679 *xp-- = '\0';
680 if (ljust && i > 0 && (int) strlen(str) > i)
681 str += strlen(str) - i;
682 }
683 break;
684
685 case FT_LV_COMPFLAG:
686 value = (fmt->f_comp->c_flags & CF_TRUE) != 0;
687 break;
688 case FT_LV_COMP:
689 value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
690 break;
691 case FT_LV_LIT:
692 value = fmt->f_value;
693 break;
694 case FT_LV_DAT:
695 value = dat[fmt->f_value];
696 break;
697 case FT_LV_STRLEN:
698 if (str != NULL)
699 value = strlen(str);
700 else
701 value = 0;
702 break;
703 case FT_LV_CHAR_LEFT:
704 value = width - (cp - scanl);
705 break;
706 case FT_LV_PLUS_L:
707 value += fmt->f_value;
708 break;
709 case FT_LV_MINUS_L:
710 value = fmt->f_value - value;
711 break;
712 case FT_LV_DIVIDE_L:
713 if (fmt->f_value)
714 value = value / fmt->f_value;
715 else
716 value = 0;
717 break;
718 case FT_LV_MODULO_L:
719 if (fmt->f_value)
720 value = value % fmt->f_value;
721 else
722 value = 0;
723 break;
724 case FT_SAVESTR:
725 savestr = str;
726 break;
727
728 case FT_LV_SEC:
729 value = fmt->f_comp->c_tws->tw_sec;
730 break;
731 case FT_LV_MIN:
732 value = fmt->f_comp->c_tws->tw_min;
733 break;
734 case FT_LV_HOUR:
735 value = fmt->f_comp->c_tws->tw_hour;
736 break;
737 case FT_LV_MDAY:
738 value = fmt->f_comp->c_tws->tw_mday;
739 break;
740 case FT_LV_MON:
741 value = fmt->f_comp->c_tws->tw_mon + 1;
742 break;
743 case FT_LS_MONTH:
744 str = tw_moty[fmt->f_comp->c_tws->tw_mon];
745 break;
746 case FT_LS_LMONTH:
747 str = lmonth[fmt->f_comp->c_tws->tw_mon];
748 break;
749 case FT_LS_ZONE:
750 str = dtwszone (fmt->f_comp->c_tws);
751 break;
752 case FT_LV_YEAR:
753 value = fmt->f_comp->c_tws->tw_year;
754 break;
755 case FT_LV_WDAY:
756 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
757 set_dotw (tws);
758 value = tws->tw_wday;
759 break;
760 case FT_LS_DAY:
761 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
762 set_dotw (tws);
763 str = tw_dotw[tws->tw_wday];
764 break;
765 case FT_LS_WEEKDAY:
766 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
767 set_dotw (tws);
768 str = tw_ldotw[tws->tw_wday];
769 break;
770 case FT_LV_YDAY:
771 value = fmt->f_comp->c_tws->tw_yday;
772 break;
773 case FT_LV_ZONE:
774 value = fmt->f_comp->c_tws->tw_zone;
775 break;
776 case FT_LV_CLOCK:
777 if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
778 value = dmktime(fmt->f_comp->c_tws);
779 break;
780 case FT_LV_RCLOCK:
781 if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
782 value = dmktime(fmt->f_comp->c_tws);
783 value = time((time_t *) 0) - value;
784 break;
785 case FT_LV_DAYF:
786 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
787 set_dotw (tws);
788 switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
789 case TW_SEXP:
790 value = 1; break;
791 case TW_SIMP:
792 value = 0; break;
793 default:
794 value = -1; break;
795 }
796 case FT_LV_ZONEF:
797 if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP)
798 value = 1;
799 else
800 value = -1;
801 break;
802 case FT_LV_DST:
803 value = fmt->f_comp->c_tws->tw_flags & TW_DST;
804 break;
805 case FT_LS_822DATE:
806 str = dasctime (fmt->f_comp->c_tws , TW_ZONE);
807 break;
808 case FT_LS_PRETTY:
809 str = dasctime (fmt->f_comp->c_tws, TW_NULL);
810 break;
811
812 case FT_LS_PERS:
813 str = fmt->f_comp->c_mn->m_pers;
814 break;
815 case FT_LS_MBOX:
816 str = fmt->f_comp->c_mn->m_mbox;
817 break;
818 case FT_LS_HOST:
819 str = fmt->f_comp->c_mn->m_host;
820 break;
821 case FT_LS_PATH:
822 str = fmt->f_comp->c_mn->m_path;
823 break;
824 case FT_LS_GNAME:
825 str = fmt->f_comp->c_mn->m_gname;
826 break;
827 case FT_LS_NOTE:
828 str = fmt->f_comp->c_mn->m_note;
829 break;
830 case FT_LS_822ADDR:
831 str = adrformat( fmt->f_comp->c_mn );
832 break;
833 case FT_LV_HOSTTYPE:
834 value = fmt->f_comp->c_mn->m_type;
835 break;
836 case FT_LV_INGRPF:
837 value = fmt->f_comp->c_mn->m_ingrp;
838 break;
839 case FT_LV_NOHOSTF:
840 value = fmt->f_comp->c_mn->m_nohost;
841 break;
842 case FT_LS_ADDR:
843 case FT_LS_FRIENDLY:
844 if ((mn = fmt->f_comp->c_mn) == &fmt_mnull) {
845 str = fmt->f_comp->c_text;
846 break;
847 }
848 if (fmt->f_type == FT_LS_ADDR)
849 goto unfriendly;
850 if ((str = mn->m_pers) == NULL) {
851 if ((str = mn->m_note)) {
852 strncpy (buffer, str, sizeof(buffer));
853 buffer[sizeof(buffer)-1] = '\0';
854 str = buffer;
855 if (*str == '(')
856 str++;
857 sp = str + strlen(str) - 1;
858 if (*sp == ')') {
859 *sp-- = '\0';
860 while (sp >= str)
861 if (*sp == ' ')
862 *sp-- = '\0';
863 else
864 break;
865 }
866 } else if (!(str = get_x400_friendly (mn->m_mbox,
867 buffer, sizeof(buffer)))) {
868 unfriendly: ;
869 switch (mn->m_type) {
870 case LOCALHOST:
871 str = mn->m_mbox;
872 break;
873 case UUCPHOST:
874 snprintf (buffer, sizeof(buffer), "%s!%s",
875 mn->m_host, mn->m_mbox);
876 str = buffer;
877 break;
878 default:
879 if (mn->m_mbox) {
880 snprintf (buffer, sizeof(buffer), "%s@%s",
881 mn->m_mbox, mn->m_host);
882 str= buffer;
883 }
884 else
885 str = mn->m_text;
886 break;
887 }
888 }
889 }
890 break;
891
892
893 /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
894 case FT_LS_UNQUOTE:
895 if (str) {
896 strncpy(buffer, str, sizeof(buffer));
897 /* strncpy doesn't NUL-terminate if it fills the buffer */
898 buffer[sizeof(buffer)-1] = '\0';
899 unquote_string(buffer, buffer2);
900 str = buffer2;
901 }
902 break;
903
904 case FT_LOCALDATE:
905 comp = fmt->f_comp;
906 if ((t = comp->c_tws->tw_clock) == 0)
907 t = dmktime(comp->c_tws);
908 tws = dlocaltime(&t);
909 *comp->c_tws = *tws;
910 break;
911
912 case FT_GMTDATE:
913 comp = fmt->f_comp;
914 if ((t = comp->c_tws->tw_clock) == 0)
915 t = dmktime(comp->c_tws);
916 tws = dgmtime(&t);
917 *comp->c_tws = *tws;
918 break;
919
920 case FT_PARSEDATE:
921 comp = fmt->f_comp;
922 if (comp->c_flags & CF_PARSED)
923 break;
924 if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
925 *comp->c_tws = *tws;
926 comp->c_flags &= ~CF_TRUE;
927 } else if ((comp->c_flags & CF_DATEFAB) == 0) {
928 memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws);
929 comp->c_flags = CF_TRUE;
930 }
931 comp->c_flags |= CF_PARSED;
932 break;
933
934 case FT_FORMATADDR:
935 /* hook for custom address list formatting (see replsbr.c) */
936 if (callbacks && callbacks->formataddr)
937 str = callbacks->formataddr (savestr, str);
938 else
939 str = formataddr (savestr, str);
940 break;
941
942 case FT_CONCATADDR:
943 /* The same as formataddr, but doesn't do duplicate suppression */
944 if (callbacks && callbacks->concataddr)
945 str = callbacks->concataddr (savestr, str);
946 else
947 str = concataddr (savestr, str);
948 break;
949
950 case FT_PUTADDR:
951 /* output the str register as an address component,
952 * splitting it into multiple lines if necessary. The
953 * value reg. contains the max line length. The lit.
954 * field may contain a string to prepend to the result
955 * (e.g., "To: ")
956 */
957 {
958 char *lp, *lastb;
959 int indent, wid, len;
960
961 lp = str;
962 wid = value;
963 len = strlen (str);
964 sp = fmt->f_text;
965 indent = strlen (sp);
966 wid -= indent;
967 if (wid <= 0) {
968 adios(NULL, "putaddr -- num register (%d) must be greater "
969 "than label width (%d)", value, indent);
970 }
971 while( (c = (unsigned char) *sp++) && cp < ep)
972 *cp++ = (char) c;
973 while (len > wid) {
974 /* try to break at a comma; failing that, break at a
975 * space.
976 */
977 lastb = 0; sp = lp + wid;
978 while (sp > lp && (c = (unsigned char) *--sp) != ',') {
979 if (! lastb && isspace(c))
980 lastb = sp - 1;
981 }
982 if (sp == lp) {
983 if (! (sp = lastb)) {
984 sp = lp + wid - 1;
985 while (*sp && *sp != ',' &&
986 !isspace((unsigned char) *sp))
987 sp++;
988 if (*sp != ',')
989 sp--;
990 }
991 }
992 len -= sp - lp + 1;
993 while (cp < ep && lp <= sp)
994 *cp++ = *lp++;
995 while (isspace((unsigned char) *lp))
996 lp++, len--;
997 if (*lp) {
998 if (cp < ep)
999 *cp++ = '\n';
1000 for (i=indent; cp < ep && i > 0; i--)
1001 *cp++ = ' ';
1002 }
1003 }
1004 cpstripped (&cp, &ep, scanl + max - 1, lp);
1005 }
1006 break;
1007
1008 case FT_PARSEADDR:
1009 comp = fmt->f_comp;
1010 if (comp->c_flags & CF_PARSED)
1011 break;
1012 if (comp->c_mn != &fmt_mnull)
1013 mnfree (comp->c_mn);
1014 if ((sp = comp->c_text) && (sp = getname(sp)) &&
1015 (mn = getm (sp, NULL, 0, NULL, 0))) {
1016 comp->c_mn = mn;
1017 while (getname(""))
1018 ;
1019 comp->c_flags |= CF_PARSED;
1020 } else {
1021 while (getname("")) /* XXX */
1022 ;
1023 comp->c_mn = &fmt_mnull;
1024 }
1025 break;
1026
1027 case FT_MYMBOX:
1028 /*
1029 * if there's no component, we say true. Otherwise we
1030 * say "true" only if we can parse the address and it
1031 * matches one of our addresses.
1032 */
1033 comp = fmt->f_comp;
1034 if (comp->c_mn != &fmt_mnull)
1035 mnfree (comp->c_mn);
1036 if ((sp = comp->c_text) && (sp = getname(sp)) &&
1037 (mn = getm (sp, NULL, 0, NULL, 0))) {
1038 comp->c_mn = mn;
1039 if (ismymbox(mn))
1040 comp->c_flags |= CF_TRUE;
1041 else
1042 comp->c_flags &= ~CF_TRUE;
1043 while ((sp = getname(sp)))
1044 if ((comp->c_flags & CF_TRUE) == 0 &&
1045 (mn = getm (sp, NULL, 0, NULL, 0)))
1046 if (ismymbox(mn))
1047 comp->c_flags |= CF_TRUE;
1048 } else {
1049 while (getname("")) /* XXX */
1050 ;
1051 if (comp->c_text == 0)
1052 comp->c_flags |= CF_TRUE;
1053 else
1054 comp->c_flags &= ~CF_TRUE;
1055 comp->c_mn = &fmt_mnull;
1056 }
1057 break;
1058 }
1059
1060 /*
1061 * Call our tracing callback function, if one was supplied
1062 */
1063
1064 if (callbacks && callbacks->trace_func)
1065 callbacks->trace_func(callbacks->trace_context, fmt, value,
1066 str, scanl);
1067 fmt++;
1068 }
1069
1070 /* Emit any trailing sequences of zero display length. */
1071 while (fmt->f_type != FT_DONE) {
1072 if (fmt->f_type == FT_LS_LIT) {
1073 str = fmt->f_text;
1074 if (callbacks && callbacks->trace_func)
1075 callbacks->trace_func(callbacks->trace_context, fmt, value,
1076 str, scanl);
1077 } else if (fmt->f_type == FT_STRLITZ) {
1078 /* Don't want to emit part of an escape sequence. So if
1079 there isn't enough room in the buffer for the entire
1080 string, skip it completely. Need room for null
1081 terminator, and maybe trailing newline (added below). */
1082 if (str && (cp - scanl + strlen (str) + 1 < max)) {
1083 for (sp = str; *sp; *cp++ = *sp++) continue;
1084 }
1085 if (callbacks && callbacks->trace_func)
1086 callbacks->trace_func(callbacks->trace_context, fmt, value,
1087 str, scanl);
1088 }
1089 fmt++;
1090 }
1091
1092 finished:;
1093 if (cp > scanl && cp[-1] != '\n') {
1094 if (cp - scanl < (int) max - 1) {
1095 *cp++ = '\n';
1096 } else {
1097 cp[-1] = '\n';
1098 }
1099 }
1100 *cp = '\0';
1101 return ((struct format *)0);
1102 }