]>
diplodocus.org Git - nmh/blob - sbr/fmt_scan.c
cb29b72cb1460cb669116ccfbc04b3b115e73f69
1 /* fmt_scan.c -- format string interpretation
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
7 * This is the engine that processes the format instructions created by
8 * fmt_compile (found in fmt_compile.c).
15 #include "fmt_rfc2047.h"
17 #include "context_find.h"
19 #include "h/addrsbr.h"
20 #include "h/fmt_scan.h"
22 #include "h/fmt_compile.h"
26 #ifdef HAVE_SYS_TIME_H
27 # include <sys/time.h>
30 #ifdef MULTIBYTE_SUPPORT
35 struct mailname fmt_mnull
= { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, 0, 0, 0, 0,
41 static int match (char *, char *) PURE
;
42 static char *get_x400_friendly (char *, char *, int);
43 static int get_x400_comp (char *, char *, char *, int);
47 * test if string "sub" appears anywhere in
48 * string "str" (case insensitive).
52 match (char *str
, char *sub
)
58 c1
= tolower((unsigned char)c1
);
59 while ((c2
= *str
++) && c1
!= tolower((unsigned char)c2
))
63 s1
= sub
+ 1; s2
= str
;
64 while ((c1
= *s1
++) &&
65 tolower((unsigned char)c1
) == tolower((unsigned char)(c2
= *s2
++)))
73 /* cpnumber formats num as a signed decimal,
74 * appending it to dest if the result doesn't exceed max.
75 * The absolute value of width is the minimum width to produce.
76 * A smaller string is padded;
77 * on the left if width is positive, else the right.
78 * Left-padding uses fill. It is either ' ' or '0'.
79 * Right-padding is always with space. */
81 cpnumber(charstring_t dest
, int num
, int width
, char fill
, size_t max
)
83 if (width
== 0 || width
== INT_MIN
) {
87 bool padright
= width
< 0;
89 width
= -width
; /* Can't overflow after above check. */
93 return; /* The padded result can't fit. */
95 if (num
< 0 && w
== 1) {
96 return; /* No room for `-' and a digit or `?'. */
100 size_t len
= strlen(s
);
102 charstring_append_cstring(dest
, s
);
106 bool neg
= *s
== '-';
109 charstring_append_cstring(dest
, s
);
111 charstring_push_back(dest
, ' ');
116 if (neg
&& fill
== '0') {
117 charstring_push_back(dest
, *s
++);
120 charstring_push_back(dest
, fill
);
122 charstring_append_cstring(dest
, s
);
126 /* Transform 1234567 -> 1234?67 and -1234567 -> 1234-?7. */
127 char *news
= s
+ len
- w
;
132 charstring_append_cstring(dest
, news
);
136 * copy string from str to dest padding with the fill character to a
137 * size of wid characters. if wid is negative, the string is right
138 * aligned no more than max characters are copied
141 cptrimmed(charstring_t dest
, char *str
, int wid
, char fill
, size_t max
)
143 int remaining
; /* remaining output width available */
145 struct charstring
*trimmed
;
146 size_t end
; /* number of input bytes remaining in str */
147 #ifdef MULTIBYTE_SUPPORT
148 int char_len
; /* bytes in current character */
153 char *sp
; /* current position in source string */
157 if ((remaining
= wid
) < 0) {
158 remaining
= -remaining
;
161 if (remaining
> (int) max
) { remaining
= max
; }
163 trimmed
= rjust
? charstring_create(remaining
) : dest
;
165 bool prevCtrl
= true;
167 #ifdef MULTIBYTE_SUPPORT
168 if (mbtowc(NULL
, NULL
, 0)) {} /* reset shift state */
171 while (*sp
&& remaining
> 0 && end
> 0) {
172 #ifdef MULTIBYTE_SUPPORT
173 char_len
= mbtowc(&wide_char
, sp
, end
);
176 * See the relevant comments in cpstripped() to explain what's
177 * going on here; we want to handle the case where we get
178 * characters that mbtowc() cannot handle
183 char_len
= mbtowc(&wide_char
, altstr
, 1);
190 w
= wcwidth(wide_char
);
192 /* If w > remaining, w must be positive. */
199 if (iswcntrl(wide_char
) || iswspace(wide_char
)) {
204 /* isnctrl(), etc., take an int argument. Cygwin's ctype.h
205 intentionally warns if they are passed a char. */
206 c
= (unsigned char) *sp
;
207 if (iscntrl(c
) || isspace(c
)) {
211 charstring_push_back (trimmed
, ' ');
220 #ifdef MULTIBYTE_SUPPORT
221 if (w
>= 0 && remaining
>= w
) {
222 charstring_push_back_chars (trimmed
, altstr
? altstr
: sp
,
229 charstring_push_back (trimmed
, *sp
++);
235 while (remaining
-- > 0) {
236 charstring_push_back(dest
, fill
);
240 charstring_append(dest
, trimmed
);
241 charstring_free(trimmed
);
245 #ifdef MULTIBYTE_SUPPORT
247 cpstripped (charstring_t dest
, size_t max
, char *str
)
250 static char *oddchar
;
251 static size_t oddlen
;
252 static char *spacechar
;
253 static size_t spacelen
;
266 two
= MB_CUR_MAX
* 2; /* Varies at run-time. */
268 oddchar
= mh_xmalloc(two
);
269 oddlen
= wcstombs(oddchar
, L
"?", two
);
272 assert(wcwidth(L
' ') == 1); /* Need to pad in ones. */
273 spacechar
= mh_xmalloc(two
);
274 spacelen
= wcstombs(spacechar
, L
" ", two
);
275 assert(spacelen
> 0);
279 return; /* It's unclear why no padding in this case. */
280 end
= str
+ strlen(str
);
282 if (mbtowc(NULL
, NULL
, 0))
283 {} /* Reset shift state. */
285 squash
= true; /* Trim `space' or `cntrl' from the start. */
288 return; /* It's unclear why no padding in this case. */
290 srclen
= mbtowc(&rune
, str
, end
- str
);
292 /* Invalid rune, or not enough bytes to finish it. */
296 str
++; /* Skip one byte. */
302 if (iswspace(rune
) || iswcntrl(rune
)) {
304 continue; /* Amidst a run of these. */
321 if ((size_t)w
> max
) {
322 /* No room for rune; pad. */
324 charstring_push_back_chars(dest
, spacechar
, spacelen
, 1);
328 charstring_push_back_chars(dest
, src
, srclen
, w
);
334 #ifndef MULTIBYTE_SUPPORT
336 cpstripped (charstring_t dest
, size_t max
, char *str
)
344 squash
= true; /* Strip leading cases. */
346 c
= (unsigned char)*str
++;
350 if (isspace(c
) || iscntrl(c
)) {
358 charstring_push_back(dest
, (char)c
);
363 static char *lmonth
[] = { "January", "February","March", "April",
364 "May", "June", "July", "August",
365 "September","October", "November","December" };
368 get_x400_friendly (char *mbox
, char *buffer
, int buffer_len
)
370 char given
[BUFSIZ
], surname
[BUFSIZ
];
379 if (get_x400_comp (mbox
, "/PN=", buffer
, buffer_len
)) {
380 for (mbox
= buffer
; (mbox
= strchr(mbox
, '.')); )
386 if (!get_x400_comp (mbox
, "/S=", surname
, sizeof(surname
)))
389 if (get_x400_comp (mbox
, "/G=", given
, sizeof(given
)))
390 snprintf (buffer
, buffer_len
, "%s %s", given
, surname
);
392 snprintf (buffer
, buffer_len
, "%s", surname
);
398 get_x400_comp (char *mbox
, char *key
, char *buffer
, int buffer_len
)
403 if ((idx
= stringdex (key
, mbox
)) < 0
404 || !(cp
= strchr(mbox
+= idx
+ strlen (key
), '/')))
407 snprintf (buffer
, buffer_len
, "%*.*s", (int)(cp
- mbox
), (int)(cp
- mbox
), mbox
);
412 fmt_scan (struct format
*format
, charstring_t scanlp
, int width
, int *dat
,
413 struct fmt_callbacks
*callbacks
)
416 /* If str points to part of buffer[] or buffer2[] then it must only
417 * ever point at their first element as otherwise undefined
418 * behaviour from overlapping strncpy(3)s can result. */
420 char buffer
[NMH_BUFSIZ
], buffer2
[NMH_BUFSIZ
];
432 * max is the same as width, but unsigned so comparisons
433 * with charstring_chars() won't raise compile warnings.
436 savestr
= str
= NULL
;
439 for (fmt
= format
; fmt
->f_type
!= FT_DONE
; fmt
++)
440 switch (fmt
->f_type
) {
443 fmt
->f_comp
->c_flags
&= ~CF_PARSED
;
448 case FT_LS_DECODECOMP
:
450 * Trim these components of any newlines.
452 * But don't trim the "body" and "text" components.
457 if (! (comp
->c_flags
& CF_TRIMMED
) && comp
->c_text
&&
458 (i
= strlen(comp
->c_text
)) > 0) {
459 if (comp
->c_text
[i
- 1] == '\n' &&
460 strcmp(comp
->c_name
, "body") != 0 &&
461 strcmp(comp
->c_name
, "text") != 0)
462 comp
->c_text
[i
- 1] = '\0';
463 comp
->c_flags
|= CF_TRIMMED
;
470 for ( ; charstring_chars (scanlp
) < max
; ) {
471 switch (fmt
->f_type
) {
474 cpstripped (scanlp
, max
- charstring_chars (scanlp
),
475 fmt
->f_comp
->c_text
);
478 cptrimmed (scanlp
, fmt
->f_comp
->c_text
, fmt
->f_width
,
479 fmt
->f_fill
, max
- charstring_chars (scanlp
));
484 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
485 charstring_push_back (scanlp
, c
);
494 rjust
= true; /* XXX should do something with this */
496 while ((c
= *sp
++) && --i
>= 0 && charstring_chars (scanlp
) < max
) {
497 charstring_push_back (scanlp
, c
);
499 while (--i
>= 0 && charstring_chars (scanlp
) < max
) {
500 charstring_push_back (scanlp
, fmt
->f_fill
);
505 cpstripped (scanlp
, max
- charstring_chars (scanlp
), str
);
508 cptrimmed (scanlp
, str
, fmt
->f_width
, fmt
->f_fill
,
509 max
- charstring_chars (scanlp
));
514 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
515 charstring_push_back (scanlp
, c
);
520 if (str
) charstring_push_back_chars (scanlp
, str
, strlen (str
), 0);
523 die("internal error (FT_STRFW)");
529 for (wid
= num
<= 0; num
; ++wid
, num
/= 10) {}
530 cpnumber (scanlp
, value
, wid
, ' ',
531 max
- charstring_chars (scanlp
));
538 unsigned int whole
, tenths
;
539 unsigned int scale
= 0;
540 unsigned int val
= (unsigned int)value
;
541 char *kibisuff
= NULL
;
543 switch (fmt
->f_type
) {
544 case FT_LS_KILO
: scale
= 1000; kibisuff
= ""; break;
545 case FT_LS_KIBI
: scale
= 1024; kibisuff
= "i"; break;
549 snprintf(buffer
, sizeof(buffer
), "%u", val
);
551 /* To prevent divide by 0, found by clang static
553 if (scale
== 0) { scale
= 1; }
555 /* find correct scale for size (Kilo/Mega/Giga/Tera) */
556 for (unitcp
= "KMGT"; val
> (scale
* scale
); val
/= scale
) {
562 strcpy(buffer
, "huge");
564 /* val is scale times too big. we want tenths */
572 tenths
= val
- (whole
* 10);
575 snprintf(buffer
, sizeof(buffer
), "%u.%u%c%s",
576 whole
, tenths
, *unitcp
, kibisuff
);
578 snprintf(buffer
, sizeof(buffer
), "%u%c%s",
579 whole
, *unitcp
, kibisuff
);
587 cpnumber (scanlp
, value
, fmt
->f_width
, fmt
->f_fill
,
588 max
- charstring_chars (scanlp
));
592 charstring_push_back (scanlp
, fmt
->f_char
);
596 if (callbacks
&& callbacks
->trace_func
)
597 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
598 str
, charstring_buffer (scanlp
));
602 if (!(value
= (str
&& *str
))) {
603 if (callbacks
&& callbacks
->trace_func
)
604 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
605 str
, charstring_buffer (scanlp
));
612 if (!(value
= (str
== NULL
|| *str
== 0))) {
613 if (callbacks
&& callbacks
->trace_func
)
614 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
615 str
, charstring_buffer (scanlp
));
622 if (value
!= fmt
->f_value
) {
623 if (callbacks
&& callbacks
->trace_func
)
624 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
625 str
, charstring_buffer (scanlp
));
632 if (value
== fmt
->f_value
) {
633 if (callbacks
&& callbacks
->trace_func
)
634 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
635 str
, charstring_buffer (scanlp
));
642 if (value
<= fmt
->f_value
) {
643 if (callbacks
&& callbacks
->trace_func
)
644 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
645 str
, charstring_buffer (scanlp
));
652 if (!(value
= (str
&& match (str
, fmt
->f_text
)))) {
653 if (callbacks
&& callbacks
->trace_func
)
654 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
655 str
, charstring_buffer (scanlp
));
663 value
= match (str
, fmt
->f_text
);
669 if (!(value
= (str
&& uprf (str
, fmt
->f_text
)))) {
670 if (callbacks
&& callbacks
->trace_func
)
671 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
672 str
, charstring_buffer (scanlp
));
679 value
= uprf (str
, fmt
->f_text
);
683 value
= (str
!= NULL
&& *str
!= 0);
687 value
= (str
== NULL
|| *str
== 0);
691 value
= (fmt
->f_value
== value
);
695 value
= (fmt
->f_value
!= value
);
699 value
= (fmt
->f_value
> value
);
703 if (callbacks
&& callbacks
->trace_func
)
704 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
705 str
, charstring_buffer (scanlp
));
713 str
= fmt
->f_comp
->c_text
;
719 if (!(str
= getenv (fmt
->f_text
)))
723 if (!(str
= context_find (fmt
->f_text
)))
727 case FT_LS_DECODECOMP
:
728 if (decode_rfc2047(fmt
->f_comp
->c_text
, buffer2
, sizeof(buffer2
)))
731 str
= fmt
->f_comp
->c_text
;
735 if (str
&& decode_rfc2047(str
, buffer2
, sizeof(buffer2
)))
744 strncpy(buffer
, str
, sizeof(buffer
));
745 buffer
[sizeof(buffer
)-1] = '\0';
747 while (isspace((unsigned char) *str
))
750 if ((i
= fmt
->f_width
) < 0) {
755 if (!rjust
&& i
> 0 && (int) strlen(str
) > i
)
758 xp
+= strlen(str
) - 1;
759 while (xp
> str
&& isspace((unsigned char) *xp
))
761 if (rjust
&& i
> 0 && (int) strlen(str
) > i
)
762 str
+= strlen(str
) - i
;
763 str
= memmove(buffer
, str
, strlen(str
) + 1);
768 value
= (fmt
->f_comp
->c_flags
& CF_TRUE
) != 0;
771 value
= (comp
= fmt
->f_comp
)->c_text
? atoi(comp
->c_text
) : 0;
774 value
= fmt
->f_value
;
777 value
= dat
[fmt
->f_value
];
785 case FT_LV_CHAR_LEFT
:
786 value
= max
- charstring_bytes (scanlp
);
789 value
+= fmt
->f_value
;
792 value
= fmt
->f_value
- value
;
794 case FT_LV_MULTIPLY_L
:
795 value
*= fmt
->f_value
;
798 if (fmt
->f_value
== 0 || (fmt
->f_value
== -1 && value
== INT_MIN
)) {
799 // FIXME: Tell the user, and probably stop.
802 value
/= fmt
->f_value
;
807 value
%= fmt
->f_value
;
809 // FIXME: Tell the user, and probably stop.
817 value
= fmt
->f_comp
->c_tws
->tw_sec
;
820 value
= fmt
->f_comp
->c_tws
->tw_min
;
823 value
= fmt
->f_comp
->c_tws
->tw_hour
;
826 value
= fmt
->f_comp
->c_tws
->tw_mday
;
829 value
= fmt
->f_comp
->c_tws
->tw_mon
+ 1;
832 str
= tw_moty
[fmt
->f_comp
->c_tws
->tw_mon
];
835 str
= lmonth
[fmt
->f_comp
->c_tws
->tw_mon
];
838 str
= dtwszone (fmt
->f_comp
->c_tws
);
841 value
= fmt
->f_comp
->c_tws
->tw_year
;
844 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
846 value
= tws
->tw_wday
;
849 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
851 str
= tw_dotw
[tws
->tw_wday
];
854 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
856 str
= tw_ldotw
[tws
->tw_wday
];
859 value
= fmt
->f_comp
->c_tws
->tw_yday
;
862 value
= fmt
->f_comp
->c_tws
->tw_zone
;
865 if ((value
= fmt
->f_comp
->c_tws
->tw_clock
) == 0)
866 value
= dmktime(fmt
->f_comp
->c_tws
);
869 if ((value
= fmt
->f_comp
->c_tws
->tw_clock
) == 0)
870 value
= dmktime(fmt
->f_comp
->c_tws
);
871 value
= time(NULL
) - value
;
874 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
876 switch (fmt
->f_comp
->c_tws
->tw_flags
& TW_SDAY
) {
886 if (fmt
->f_comp
->c_tws
->tw_flags
& TW_SZEXP
)
892 value
= fmt
->f_comp
->c_tws
->tw_flags
& TW_DST
? 1 : 0;
895 str
= dasctime (fmt
->f_comp
->c_tws
, TW_ZONE
);
898 str
= dasctime (fmt
->f_comp
->c_tws
, TW_NULL
);
902 str
= fmt
->f_comp
->c_mn
->m_pers
;
905 str
= fmt
->f_comp
->c_mn
->m_mbox
;
908 str
= fmt
->f_comp
->c_mn
->m_host
;
911 str
= fmt
->f_comp
->c_mn
->m_path
;
914 str
= fmt
->f_comp
->c_mn
->m_gname
;
917 str
= fmt
->f_comp
->c_mn
->m_note
;
920 str
= adrformat( fmt
->f_comp
->c_mn
);
923 value
= fmt
->f_comp
->c_mn
->m_type
;
926 value
= fmt
->f_comp
->c_mn
->m_ingrp
;
929 value
= fmt
->f_comp
->c_mn
->m_nohost
;
933 if ((mn
= fmt
->f_comp
->c_mn
) == &fmt_mnull
) {
934 str
= fmt
->f_comp
->c_text
;
937 if (fmt
->f_type
== FT_LS_ADDR
)
939 if ((str
= mn
->m_pers
) == NULL
) {
940 if ((str
= mn
->m_note
)) {
942 strncpy (buffer
, str
, sizeof(buffer
));
943 buffer
[sizeof(buffer
)-1] = '\0';
947 sp
= str
+ strlen(str
) - 1;
956 str
= memmove(buffer
, str
, strlen(str
) + 1);
957 } else if (!(str
= get_x400_friendly (mn
->m_mbox
,
958 buffer
, sizeof(buffer
)))) {
960 switch (mn
->m_type
) {
965 snprintf (buffer
, sizeof(buffer
), "%s!%s",
966 mn
->m_host
, mn
->m_mbox
);
971 snprintf (buffer
, sizeof(buffer
), "%s@%s",
972 mn
->m_mbox
, mn
->m_host
);
984 /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
988 strncpy(buffer
, str
, sizeof(buffer
));
989 /* strncpy doesn't NUL-terminate if it fills the buffer */
990 buffer
[sizeof(buffer
)-1] = '\0';
991 unquote_string(buffer
, buffer2
);
998 if ((t
= comp
->c_tws
->tw_clock
) == 0)
999 t
= dmktime(comp
->c_tws
);
1000 tws
= dlocaltime(&t
);
1001 *comp
->c_tws
= *tws
;
1006 if ((t
= comp
->c_tws
->tw_clock
) == 0)
1007 t
= dmktime(comp
->c_tws
);
1009 *comp
->c_tws
= *tws
;
1014 if (comp
->c_flags
& CF_PARSED
)
1016 if ((sp
= comp
->c_text
) && (tws
= dparsetime(sp
))) {
1017 *comp
->c_tws
= *tws
;
1018 comp
->c_flags
&= ~CF_TRUE
;
1019 } else if ((comp
->c_flags
& CF_DATEFAB
) == 0) {
1021 comp
->c_flags
= CF_TRUE
;
1023 comp
->c_flags
|= CF_PARSED
;
1027 /* hook for custom address list formatting (see replsbr.c) */
1028 if (callbacks
&& callbacks
->formataddr
)
1029 str
= callbacks
->formataddr (savestr
, str
);
1031 str
= formataddr (savestr
, str
);
1035 /* The same as formataddr, but doesn't do duplicate suppression */
1036 if (callbacks
&& callbacks
->concataddr
)
1037 str
= callbacks
->concataddr (savestr
, str
);
1039 str
= concataddr (savestr
, str
);
1043 /* output the str register as an address component,
1044 * splitting it into multiple lines if necessary. The
1045 * value reg. contains the max line length. The lit.
1046 * field may contain a string to prepend to the result
1051 int indent
, wid
, len
;
1055 len
= str
? strlen (str
) : 0;
1057 indent
= strlen (sp
);
1060 die("putaddr -- num register (%d) must be greater "
1061 "than label width (%d)", value
, indent
);
1063 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
1064 charstring_push_back (scanlp
, c
);
1067 /* try to break at a comma; failing that, break at a
1070 lastb
= 0; sp
= lp
+ wid
;
1071 while (sp
> lp
&& (c
= (unsigned char) *--sp
) != ',') {
1072 if (! lastb
&& isspace(c
))
1076 if (! (sp
= lastb
)) {
1078 while (*sp
&& *sp
!= ',' &&
1079 !isspace((unsigned char) *sp
))
1086 while (lp
<= sp
&& charstring_chars (scanlp
) < max
) {
1087 charstring_push_back (scanlp
, *lp
++);
1089 while (isspace((unsigned char) *lp
))
1092 if (charstring_chars (scanlp
) < max
) {
1093 charstring_push_back (scanlp
, '\n');
1096 charstring_chars (scanlp
) < max
&& i
> 0;
1098 charstring_push_back (scanlp
, ' ');
1101 cpstripped (scanlp
, max
- charstring_chars (scanlp
), lp
);
1107 if (comp
->c_flags
& CF_PARSED
)
1109 if (comp
->c_mn
!= &fmt_mnull
)
1110 mnfree (comp
->c_mn
);
1111 if ((sp
= comp
->c_text
) && (sp
= getname(sp
)) &&
1112 (mn
= getm (sp
, NULL
, 0, NULL
, 0))) {
1116 comp
->c_flags
|= CF_PARSED
;
1118 while (getname("")) /* XXX */
1120 comp
->c_mn
= &fmt_mnull
;
1128 * if there's no component, we say true. Otherwise we
1129 * say "true" only if we can parse the address and it
1130 * matches one of our addresses.
1133 if (comp
->c_mn
!= &fmt_mnull
)
1134 mnfree (comp
->c_mn
);
1135 if ((sp
= comp
->c_text
) && (sp
= getname(sp
)) &&
1136 (mn
= getm (sp
, NULL
, 0, NULL
, 0))) {
1139 comp
->c_flags
|= CF_TRUE
;
1140 /* Set str for use with FT_GETMYMBOX. With
1141 FT_GETMYADDR, comp->c_mn will be run through
1142 FT_LS_ADDR, which will strip off any pers
1146 comp
->c_flags
&= ~CF_TRUE
;
1148 while ((sp
= getname(sp
)))
1149 if ((comp
->c_flags
& CF_TRUE
) == 0 &&
1150 (mn
= getm (sp
, NULL
, 0, NULL
, 0)))
1152 comp
->c_flags
|= CF_TRUE
;
1153 /* Set str and comp->c_text for use with
1154 FT_GETMYMBOX. With FT_GETMYADDR,
1155 comp->c_mn will be run through
1156 FT_LS_ADDR, which will strip off any
1158 free (comp
->c_text
);
1159 comp
->c_text
= str
= strdup (mn
->m_text
);
1162 comp
->c_flags
|= CF_PARSED
;
1164 while (getname("")) /* XXX */
1166 if (comp
->c_text
== 0)
1167 comp
->c_flags
|= CF_TRUE
;
1169 comp
->c_flags
&= ~CF_TRUE
;
1171 comp
->c_mn
= &fmt_mnull
;
1173 if ((comp
->c_flags
& CF_TRUE
) == 0 &&
1174 (fmt
->f_type
== FT_GETMYMBOX
|| fmt
->f_type
== FT_GETMYADDR
)) {
1175 /* Fool FT_LS_ADDR into not producing an address. */
1176 comp
->c_mn
= &fmt_mnull
; comp
->c_text
= NULL
;
1182 * Call our tracing callback function, if one was supplied
1185 if (callbacks
&& callbacks
->trace_func
)
1186 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1187 str
, charstring_buffer (scanlp
));
1191 /* Emit any trailing sequences of zero display length. */
1192 while (fmt
->f_type
!= FT_DONE
) {
1193 if (fmt
->f_type
== FT_LS_LIT
) {
1195 if (callbacks
&& callbacks
->trace_func
)
1196 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1197 str
, charstring_buffer (scanlp
));
1198 } else if (fmt
->f_type
== FT_STRLITZ
) {
1199 /* Don't want to emit part of an escape sequence. So if
1200 there isn't enough room in the buffer for the entire
1201 string, skip it completely. Need room for null
1202 terminator, and maybe trailing newline (added below). */
1204 for (sp
= str
; *sp
; ++sp
) {
1205 charstring_push_back (scanlp
, *sp
);
1208 if (callbacks
&& callbacks
->trace_func
)
1209 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1210 str
, charstring_buffer (scanlp
));
1216 if (charstring_bytes (scanlp
) > 0) {
1218 * Append a newline if the last character wasn't.
1220 #ifdef MULTIBYTE_SUPPORT
1222 * It's a little tricky because the last byte might be part of
1223 * a multibyte character, in which case we assume that wasn't
1226 size_t last_char_len
= charstring_last_char_len (scanlp
);
1227 #else /* ! MULTIBYTE_SUPPORT */
1228 size_t last_char_len
= 1;
1229 #endif /* ! MULTIBYTE_SUPPORT */
1231 if (last_char_len
> 1 ||
1232 charstring_buffer (scanlp
)[charstring_bytes (scanlp
) - 1] != '\n') {
1233 charstring_push_back (scanlp
, '\n');