]> diplodocus.org Git - nmh/blob - sbr/fmt_scan.c
Removed temporary probes added in commit
[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 (char_len > 1 && epmax - *ep >= char_len - w) {
179 *ep += char_len - w;
180 }
181
182 if (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 (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 sp = str;
471 while ((c = *sp++) && cp < ep)
472 *cp++ = c;
473 break;
474 case FT_STRLITZ: {
475 size_t len = strlen (str);
476
477 /* Don't want to emit part of an escape sequence. So if
478 there isn't enough room in the buffer for the entire
479 string, skip it completely. */
480 if (cp - scanl + len + 1 < max) {
481 for (sp = str; *sp; *cp++ = *sp++) continue;
482
483 /* This string doesn't count against the width. So
484 increase ep the same amount as cp, only if the
485 scan buffer will always be large enough. */
486 if (ep - scanl + len + 1 < max) {
487 ep += len;
488 }
489 }
490
491 break;
492 }
493 case FT_STRFW:
494 adios (NULL, "internal error (FT_STRFW)");
495
496 case FT_NUM:
497 n = snprintf(cp, ep - cp + 1, "%d", value);
498 if (n >= 0) {
499 if (n >= ep - cp) {
500 cp = ep;
501 } else
502 cp += n;
503 }
504 break;
505 case FT_NUMF:
506 cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp);
507 break;
508
509 case FT_CHAR:
510 *cp++ = fmt->f_char;
511 break;
512
513 case FT_DONE:
514 if (callbacks && callbacks->trace_func)
515 callbacks->trace_func(callbacks->trace_context, fmt, value,
516 str, scanl);
517 goto finished;
518
519 case FT_IF_S:
520 if (!(value = (str && *str))) {
521 fmt += fmt->f_skip;
522 continue;
523 }
524 break;
525
526 case FT_IF_S_NULL:
527 if (!(value = (str == NULL || *str == 0))) {
528 fmt += fmt->f_skip;
529 continue;
530 }
531 break;
532
533 case FT_IF_V_EQ:
534 if (value != fmt->f_value) {
535 fmt += fmt->f_skip;
536 continue;
537 }
538 break;
539
540 case FT_IF_V_NE:
541 if (value == fmt->f_value) {
542 fmt += fmt->f_skip;
543 continue;
544 }
545 break;
546
547 case FT_IF_V_GT:
548 if (value <= fmt->f_value) {
549 fmt += fmt->f_skip;
550 continue;
551 }
552 break;
553
554 case FT_IF_MATCH:
555 if (!(value = (str && match (str, fmt->f_text)))) {
556 fmt += fmt->f_skip;
557 continue;
558 }
559 break;
560
561 case FT_V_MATCH:
562 if (str)
563 value = match (str, fmt->f_text);
564 else
565 value = 0;
566 break;
567
568 case FT_IF_AMATCH:
569 if (!(value = (str && uprf (str, fmt->f_text)))) {
570 fmt += fmt->f_skip;
571 continue;
572 }
573 break;
574
575 case FT_V_AMATCH:
576 value = uprf (str, fmt->f_text);
577 break;
578
579 case FT_S_NONNULL:
580 value = (str != NULL && *str != 0);
581 break;
582
583 case FT_S_NULL:
584 value = (str == NULL || *str == 0);
585 break;
586
587 case FT_V_EQ:
588 value = (fmt->f_value == value);
589 break;
590
591 case FT_V_NE:
592 value = (fmt->f_value != value);
593 break;
594
595 case FT_V_GT:
596 value = (fmt->f_value > value);
597 break;
598
599 case FT_GOTO:
600 fmt += fmt->f_skip;
601 continue;
602
603 case FT_NOP:
604 break;
605
606 case FT_LS_COMP:
607 str = fmt->f_comp->c_text;
608 break;
609 case FT_LS_LIT:
610 str = fmt->f_text;
611 break;
612 case FT_LS_GETENV:
613 if (!(str = getenv (fmt->f_text)))
614 str = "";
615 break;
616 case FT_LS_CFIND:
617 if (!(str = context_find (fmt->f_text)))
618 str = "";
619 break;
620
621 case FT_LS_DECODECOMP:
622 if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2)))
623 str = buffer2;
624 else
625 str = fmt->f_comp->c_text;
626 break;
627
628 case FT_LS_DECODE:
629 if (str && decode_rfc2047(str, buffer2, sizeof(buffer2)))
630 str = buffer2;
631 break;
632
633 case FT_LS_TRIM:
634 if (str) {
635 char *xp;
636
637 strncpy(buffer, str, sizeof(buffer));
638 buffer[sizeof(buffer)-1] = '\0';
639 str = buffer;
640 while (isspace((unsigned char) *str))
641 str++;
642 ljust = 0;
643 if ((i = fmt->f_width) < 0) {
644 i = -i;
645 ljust++;
646 }
647
648 if (!ljust && i > 0 && (int) strlen(str) > i)
649 str[i] = '\0';
650 xp = str;
651 xp += strlen(str) - 1;
652 while (xp > str && isspace((unsigned char) *xp))
653 *xp-- = '\0';
654 if (ljust && i > 0 && (int) strlen(str) > i)
655 str += strlen(str) - i;
656 }
657 break;
658
659 case FT_LV_COMPFLAG:
660 value = (fmt->f_comp->c_flags & CF_TRUE) != 0;
661 break;
662 case FT_LV_COMP:
663 value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
664 break;
665 case FT_LV_LIT:
666 value = fmt->f_value;
667 break;
668 case FT_LV_DAT:
669 value = dat[fmt->f_value];
670 break;
671 case FT_LV_STRLEN:
672 if (str != NULL)
673 value = strlen(str);
674 else
675 value = 0;
676 break;
677 case FT_LV_CHAR_LEFT:
678 value = width - (cp - scanl);
679 break;
680 case FT_LV_PLUS_L:
681 value += fmt->f_value;
682 break;
683 case FT_LV_MINUS_L:
684 value = fmt->f_value - value;
685 break;
686 case FT_LV_DIVIDE_L:
687 if (fmt->f_value)
688 value = value / fmt->f_value;
689 else
690 value = 0;
691 break;
692 case FT_LV_MODULO_L:
693 if (fmt->f_value)
694 value = value % fmt->f_value;
695 else
696 value = 0;
697 break;
698 case FT_SAVESTR:
699 savestr = str;
700 break;
701
702 case FT_LV_SEC:
703 value = fmt->f_comp->c_tws->tw_sec;
704 break;
705 case FT_LV_MIN:
706 value = fmt->f_comp->c_tws->tw_min;
707 break;
708 case FT_LV_HOUR:
709 value = fmt->f_comp->c_tws->tw_hour;
710 break;
711 case FT_LV_MDAY:
712 value = fmt->f_comp->c_tws->tw_mday;
713 break;
714 case FT_LV_MON:
715 value = fmt->f_comp->c_tws->tw_mon + 1;
716 break;
717 case FT_LS_MONTH:
718 str = tw_moty[fmt->f_comp->c_tws->tw_mon];
719 break;
720 case FT_LS_LMONTH:
721 str = lmonth[fmt->f_comp->c_tws->tw_mon];
722 break;
723 case FT_LS_ZONE:
724 str = dtwszone (fmt->f_comp->c_tws);
725 break;
726 case FT_LV_YEAR:
727 value = fmt->f_comp->c_tws->tw_year;
728 break;
729 case FT_LV_WDAY:
730 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
731 set_dotw (tws);
732 value = tws->tw_wday;
733 break;
734 case FT_LS_DAY:
735 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
736 set_dotw (tws);
737 str = tw_dotw[tws->tw_wday];
738 break;
739 case FT_LS_WEEKDAY:
740 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
741 set_dotw (tws);
742 str = tw_ldotw[tws->tw_wday];
743 break;
744 case FT_LV_YDAY:
745 value = fmt->f_comp->c_tws->tw_yday;
746 break;
747 case FT_LV_ZONE:
748 value = fmt->f_comp->c_tws->tw_zone;
749 break;
750 case FT_LV_CLOCK:
751 if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
752 value = dmktime(fmt->f_comp->c_tws);
753 break;
754 case FT_LV_RCLOCK:
755 if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
756 value = dmktime(fmt->f_comp->c_tws);
757 value = time((time_t *) 0) - value;
758 break;
759 case FT_LV_DAYF:
760 if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
761 set_dotw (tws);
762 switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
763 case TW_SEXP:
764 value = 1; break;
765 case TW_SIMP:
766 value = 0; break;
767 default:
768 value = -1; break;
769 }
770 case FT_LV_ZONEF:
771 if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP)
772 value = 1;
773 else
774 value = -1;
775 break;
776 case FT_LV_DST:
777 value = fmt->f_comp->c_tws->tw_flags & TW_DST;
778 break;
779 case FT_LS_822DATE:
780 str = dasctime (fmt->f_comp->c_tws , TW_ZONE);
781 break;
782 case FT_LS_PRETTY:
783 str = dasctime (fmt->f_comp->c_tws, TW_NULL);
784 break;
785
786 case FT_LS_PERS:
787 str = fmt->f_comp->c_mn->m_pers;
788 break;
789 case FT_LS_MBOX:
790 str = fmt->f_comp->c_mn->m_mbox;
791 break;
792 case FT_LS_HOST:
793 str = fmt->f_comp->c_mn->m_host;
794 break;
795 case FT_LS_PATH:
796 str = fmt->f_comp->c_mn->m_path;
797 break;
798 case FT_LS_GNAME:
799 str = fmt->f_comp->c_mn->m_gname;
800 break;
801 case FT_LS_NOTE:
802 str = fmt->f_comp->c_mn->m_note;
803 break;
804 case FT_LS_822ADDR:
805 str = adrformat( fmt->f_comp->c_mn );
806 break;
807 case FT_LV_HOSTTYPE:
808 value = fmt->f_comp->c_mn->m_type;
809 break;
810 case FT_LV_INGRPF:
811 value = fmt->f_comp->c_mn->m_ingrp;
812 break;
813 case FT_LV_NOHOSTF:
814 value = fmt->f_comp->c_mn->m_nohost;
815 break;
816 case FT_LS_ADDR:
817 case FT_LS_FRIENDLY:
818 if ((mn = fmt->f_comp->c_mn) == &fmt_mnull) {
819 str = fmt->f_comp->c_text;
820 break;
821 }
822 if (fmt->f_type == FT_LS_ADDR)
823 goto unfriendly;
824 if ((str = mn->m_pers) == NULL) {
825 if ((str = mn->m_note)) {
826 strncpy (buffer, str, sizeof(buffer));
827 buffer[sizeof(buffer)-1] = '\0';
828 str = buffer;
829 if (*str == '(')
830 str++;
831 sp = str + strlen(str) - 1;
832 if (*sp == ')') {
833 *sp-- = '\0';
834 while (sp >= str)
835 if (*sp == ' ')
836 *sp-- = '\0';
837 else
838 break;
839 }
840 } else if (!(str = get_x400_friendly (mn->m_mbox,
841 buffer, sizeof(buffer)))) {
842 unfriendly: ;
843 switch (mn->m_type) {
844 case LOCALHOST:
845 str = mn->m_mbox;
846 break;
847 case UUCPHOST:
848 snprintf (buffer, sizeof(buffer), "%s!%s",
849 mn->m_host, mn->m_mbox);
850 str = buffer;
851 break;
852 default:
853 if (mn->m_mbox) {
854 snprintf (buffer, sizeof(buffer), "%s@%s",
855 mn->m_mbox, mn->m_host);
856 str= buffer;
857 }
858 else
859 str = mn->m_text;
860 break;
861 }
862 }
863 }
864 break;
865
866
867 /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
868 case FT_LS_UNQUOTE:
869 if (str) {
870 strncpy(buffer, str, sizeof(buffer));
871 /* strncpy doesn't NUL-terminate if it fills the buffer */
872 buffer[sizeof(buffer)-1] = '\0';
873 unquote_string(buffer, buffer2);
874 str = buffer2;
875 }
876 break;
877
878 case FT_LOCALDATE:
879 comp = fmt->f_comp;
880 if ((t = comp->c_tws->tw_clock) == 0)
881 t = dmktime(comp->c_tws);
882 tws = dlocaltime(&t);
883 *comp->c_tws = *tws;
884 break;
885
886 case FT_GMTDATE:
887 comp = fmt->f_comp;
888 if ((t = comp->c_tws->tw_clock) == 0)
889 t = dmktime(comp->c_tws);
890 tws = dgmtime(&t);
891 *comp->c_tws = *tws;
892 break;
893
894 case FT_PARSEDATE:
895 comp = fmt->f_comp;
896 if (comp->c_flags & CF_PARSED)
897 break;
898 if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
899 *comp->c_tws = *tws;
900 comp->c_flags &= ~CF_TRUE;
901 } else if ((comp->c_flags & CF_DATEFAB) == 0) {
902 memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws);
903 comp->c_flags = CF_TRUE;
904 }
905 comp->c_flags |= CF_PARSED;
906 break;
907
908 case FT_FORMATADDR:
909 /* hook for custom address list formatting (see replsbr.c) */
910 if (callbacks && callbacks->formataddr)
911 str = callbacks->formataddr (savestr, str);
912 else
913 str = formataddr (savestr, str);
914 break;
915
916 case FT_CONCATADDR:
917 /* The same as formataddr, but doesn't do duplicate suppression */
918 if (callbacks && callbacks->concataddr)
919 str = callbacks->concataddr (savestr, str);
920 else
921 str = concataddr (savestr, str);
922 break;
923
924 case FT_PUTADDR:
925 /* output the str register as an address component,
926 * splitting it into multiple lines if necessary. The
927 * value reg. contains the max line length. The lit.
928 * field may contain a string to prepend to the result
929 * (e.g., "To: ")
930 */
931 {
932 char *lp, *lastb;
933 int indent, wid, len;
934
935 lp = str;
936 wid = value;
937 len = strlen (str);
938 sp = fmt->f_text;
939 indent = strlen (sp);
940 wid -= indent;
941 if (wid <= 0) {
942 adios(NULL, "putaddr -- num register (%d) must be greater "
943 "than label width (%d)", value, indent);
944 }
945 while( (c = (unsigned char) *sp++) && cp < ep)
946 *cp++ = (char) c;
947 while (len > wid) {
948 /* try to break at a comma; failing that, break at a
949 * space.
950 */
951 lastb = 0; sp = lp + wid;
952 while (sp > lp && (c = (unsigned char) *--sp) != ',') {
953 if (! lastb && isspace(c))
954 lastb = sp - 1;
955 }
956 if (sp == lp) {
957 if (! (sp = lastb)) {
958 sp = lp + wid - 1;
959 while (*sp && *sp != ',' &&
960 !isspace((unsigned char) *sp))
961 sp++;
962 if (*sp != ',')
963 sp--;
964 }
965 }
966 len -= sp - lp + 1;
967 while (cp < ep && lp <= sp)
968 *cp++ = *lp++;
969 while (isspace((unsigned char) *lp))
970 lp++, len--;
971 if (*lp) {
972 if (cp < ep)
973 *cp++ = '\n';
974 for (i=indent; cp < ep && i > 0; i--)
975 *cp++ = ' ';
976 }
977 }
978 cpstripped (&cp, &ep, scanl + max - 1, lp);
979 }
980 break;
981
982 case FT_PARSEADDR:
983 comp = fmt->f_comp;
984 if (comp->c_flags & CF_PARSED)
985 break;
986 if (comp->c_mn != &fmt_mnull)
987 mnfree (comp->c_mn);
988 if ((sp = comp->c_text) && (sp = getname(sp)) &&
989 (mn = getm (sp, NULL, 0, NULL, 0))) {
990 comp->c_mn = mn;
991 while (getname(""))
992 ;
993 comp->c_flags |= CF_PARSED;
994 } else {
995 while (getname("")) /* XXX */
996 ;
997 comp->c_mn = &fmt_mnull;
998 }
999 break;
1000
1001 case FT_MYMBOX:
1002 /*
1003 * if there's no component, we say true. Otherwise we
1004 * say "true" only if we can parse the address and it
1005 * matches one of our addresses.
1006 */
1007 comp = fmt->f_comp;
1008 if (comp->c_mn != &fmt_mnull)
1009 mnfree (comp->c_mn);
1010 if ((sp = comp->c_text) && (sp = getname(sp)) &&
1011 (mn = getm (sp, NULL, 0, NULL, 0))) {
1012 comp->c_mn = mn;
1013 if (ismymbox(mn))
1014 comp->c_flags |= CF_TRUE;
1015 else
1016 comp->c_flags &= ~CF_TRUE;
1017 while ((sp = getname(sp)))
1018 if ((comp->c_flags & CF_TRUE) == 0 &&
1019 (mn = getm (sp, NULL, 0, NULL, 0)))
1020 if (ismymbox(mn))
1021 comp->c_flags |= CF_TRUE;
1022 } else {
1023 while (getname("")) /* XXX */
1024 ;
1025 if (comp->c_text == 0)
1026 comp->c_flags |= CF_TRUE;
1027 else
1028 comp->c_flags &= ~CF_TRUE;
1029 comp->c_mn = &fmt_mnull;
1030 }
1031 break;
1032 }
1033
1034 /*
1035 * Call our tracing callback function, if one was supplied
1036 */
1037
1038 if (callbacks && callbacks->trace_func)
1039 callbacks->trace_func(callbacks->trace_context, fmt, value,
1040 str, scanl);
1041 fmt++;
1042 }
1043
1044 /* Emit any trailing sequences of zero display length. */
1045 while (fmt->f_type != FT_DONE) {
1046 if (fmt->f_type == FT_LS_LIT) {
1047 str = fmt->f_text;
1048 if (callbacks && callbacks->trace_func)
1049 callbacks->trace_func(callbacks->trace_context, fmt, value,
1050 str, scanl);
1051 } else if (fmt->f_type == FT_STRLITZ) {
1052 /* Don't want to emit part of an escape sequence. So if
1053 there isn't enough room in the buffer for the entire
1054 string, skip it completely. Need room for null
1055 terminator, and maybe trailing newline (added below). */
1056 if (cp - scanl + strlen (str) + 1 < max) {
1057 for (sp = str; *sp; *cp++ = *sp++) continue;
1058 }
1059 if (callbacks && callbacks->trace_func)
1060 callbacks->trace_func(callbacks->trace_context, fmt, value,
1061 str, scanl);
1062 }
1063 fmt++;
1064 }
1065
1066 finished:;
1067 if (cp > scanl && cp[-1] != '\n') {
1068 if (cp - scanl < (int) max - 1) {
1069 *cp++ = '\n';
1070 } else {
1071 cp[-1] = '\n';
1072 }
1073 }
1074 *cp = '\0';
1075 return ((struct format *)0);
1076 }