]>
diplodocus.org Git - nmh/blob - sbr/fmt_scan.c
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).
12 #include <h/addrsbr.h>
13 #include <h/fmt_scan.h>
15 #include <h/fmt_compile.h>
19 #ifdef HAVE_SYS_TIME_H
20 # include <sys/time.h>
23 #ifdef MULTIBYTE_SUPPORT
28 struct mailname fmt_mnull
= { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, 0, 0, 0, 0,
34 static int match (char *, char *) PURE
;
35 static char *get_x400_friendly (char *, char *, int);
36 static int get_x400_comp (char *, char *, char *, int);
40 * test if string "sub" appears anywhere in
41 * string "str" (case insensitive).
45 match (char *str
, char *sub
)
51 c1
= tolower((unsigned char)c1
);
52 while ((c2
= *str
++) && c1
!= tolower((unsigned char)c2
))
56 s1
= sub
+ 1; s2
= str
;
57 while ((c1
= *s1
++) &&
58 tolower((unsigned char)c1
) == tolower((unsigned char)(c2
= *s2
++)))
67 * copy a number to the destination subject to a maximum width
70 cpnumber(charstring_t dest
, int num
, int wid
, char fill
, size_t max
)
72 /* Maybe we should handle left padding at some point? */
76 wid
= -wid
; /* OK because wid originally a short. */
77 if ((size_t)wid
< (num
>= 0 ? max
: max
-1)) {
78 /* Build up the string representation of num in reverse. */
79 charstring_t rev
= charstring_create (0);
80 int i
= num
>= 0 ? num
: -num
;
83 charstring_push_back (rev
, i
% 10 + '0');
85 } while (--wid
> 0 && i
> 0);
87 /* Overflowed the field (wid). */
88 charstring_push_back (rev
, '?');
89 } else if (num
< 0 && wid
> 0) {
90 /* Shouldn't need the wid > 0 check, that's why the condition
91 at the top checks wid < max-1 when num < 0. */
94 charstring_push_back (rev
, '-');
97 while (wid
-- > 0 && fill
!= 0) {
98 charstring_push_back (rev
, fill
);
100 if (num
< 0 && fill
== '0') {
101 charstring_push_back (rev
, '-');
105 /* Output the string in reverse. */
106 size_t b
= charstring_bytes (rev
);
107 const char *cp
= b
? &charstring_buffer (rev
)[b
] : NULL
;
110 charstring_push_back (dest
, *--cp
);
114 charstring_free (rev
);
119 * copy string from str to dest padding with the fill character to a
120 * size of wid characters. if wid is negative, the string is right
121 * aligned no more than max characters are copied
124 cptrimmed(charstring_t dest
, char *str
, int wid
, char fill
, size_t max
)
126 int remaining
; /* remaining output width available */
128 struct charstring
*trimmed
;
129 size_t end
; /* number of input bytes remaining in str */
130 #ifdef MULTIBYTE_SUPPORT
131 int char_len
; /* bytes in current character */
136 char *sp
; /* current position in source string */
140 if ((remaining
= wid
) < 0) {
141 remaining
= -remaining
;
144 if (remaining
> (int) max
) { remaining
= max
; }
146 trimmed
= rjust
? charstring_create(remaining
) : dest
;
148 bool prevCtrl
= true;
150 #ifdef MULTIBYTE_SUPPORT
151 if (mbtowc(NULL
, NULL
, 0)) {} /* reset shift state */
154 while (*sp
&& remaining
> 0 && end
> 0) {
155 #ifdef MULTIBYTE_SUPPORT
156 char_len
= mbtowc(&wide_char
, sp
, end
);
159 * See the relevant comments in cpstripped() to explain what's
160 * going on here; we want to handle the case where we get
161 * characters that mbtowc() cannot handle
166 char_len
= mbtowc(&wide_char
, altstr
, 1);
173 w
= wcwidth(wide_char
);
175 /* If w > remaining, w must be positive. */
182 if (iswcntrl(wide_char
) || iswspace(wide_char
)) {
187 /* isnctrl(), etc., take an int argument. Cygwin's ctype.h
188 intentionally warns if they are passed a char. */
189 c
= (unsigned char) *sp
;
190 if (iscntrl(c
) || isspace(c
)) {
194 charstring_push_back (trimmed
, ' ');
203 #ifdef MULTIBYTE_SUPPORT
204 if (w
>= 0 && remaining
>= w
) {
205 charstring_push_back_chars (trimmed
, altstr
? altstr
: sp
,
212 charstring_push_back (trimmed
, *sp
++);
218 while (remaining
-- > 0) {
219 charstring_push_back(dest
, fill
);
223 charstring_append(dest
, trimmed
);
224 charstring_free(trimmed
);
228 #ifdef MULTIBYTE_SUPPORT
230 cpstripped (charstring_t dest
, size_t max
, char *str
)
233 static char *oddchar
;
234 static size_t oddlen
;
235 static char *spacechar
;
236 static size_t spacelen
;
249 two
= MB_CUR_MAX
* 2; /* Varies at run-time. */
251 oddchar
= mh_xmalloc(two
);
252 oddlen
= wcstombs(oddchar
, L
"?", two
);
255 assert(wcwidth(L
' ') == 1); /* Need to pad in ones. */
256 spacechar
= mh_xmalloc(two
);
257 spacelen
= wcstombs(spacechar
, L
" ", two
);
258 assert(spacelen
> 0);
262 return; /* It's unclear why no padding in this case. */
263 end
= str
+ strlen(str
);
265 if (mbtowc(NULL
, NULL
, 0))
266 {} /* Reset shift state. */
268 squash
= true; /* Trim `space' or `cntrl' from the start. */
271 return; /* It's unclear why no padding in this case. */
273 srclen
= mbtowc(&rune
, str
, end
- str
);
275 /* Invalid rune, or not enough bytes to finish it. */
279 str
++; /* Skip one byte. */
285 if (iswspace(rune
) || iswcntrl(rune
)) {
287 continue; /* Amidst a run of these. */
304 if ((size_t)w
> max
) {
305 /* No room for rune; pad. */
307 charstring_push_back_chars(dest
, spacechar
, spacelen
, 1);
311 charstring_push_back_chars(dest
, src
, srclen
, w
);
317 #ifndef MULTIBYTE_SUPPORT
319 cpstripped (charstring_t dest
, size_t max
, char *str
)
327 squash
= true; /* Strip leading cases. */
329 c
= (unsigned char)*str
++;
333 if (isspace(c
) || iscntrl(c
)) {
341 charstring_push_back(dest
, (char)c
);
346 static char *lmonth
[] = { "January", "February","March", "April",
347 "May", "June", "July", "August",
348 "September","October", "November","December" };
351 get_x400_friendly (char *mbox
, char *buffer
, int buffer_len
)
353 char given
[BUFSIZ
], surname
[BUFSIZ
];
362 if (get_x400_comp (mbox
, "/PN=", buffer
, buffer_len
)) {
363 for (mbox
= buffer
; (mbox
= strchr(mbox
, '.')); )
369 if (!get_x400_comp (mbox
, "/S=", surname
, sizeof(surname
)))
372 if (get_x400_comp (mbox
, "/G=", given
, sizeof(given
)))
373 snprintf (buffer
, buffer_len
, "%s %s", given
, surname
);
375 snprintf (buffer
, buffer_len
, "%s", surname
);
381 get_x400_comp (char *mbox
, char *key
, char *buffer
, int buffer_len
)
386 if ((idx
= stringdex (key
, mbox
)) < 0
387 || !(cp
= strchr(mbox
+= idx
+ strlen (key
), '/')))
390 snprintf (buffer
, buffer_len
, "%*.*s", (int)(cp
- mbox
), (int)(cp
- mbox
), mbox
);
395 fmt_scan (struct format
*format
, charstring_t scanlp
, int width
, int *dat
,
396 struct fmt_callbacks
*callbacks
)
400 char buffer
[NMH_BUFSIZ
], buffer2
[NMH_BUFSIZ
];
412 * max is the same as width, but unsigned so comparisons
413 * with charstring_chars() won't raise compile warnings.
416 savestr
= str
= NULL
;
419 for (fmt
= format
; fmt
->f_type
!= FT_DONE
; fmt
++)
420 switch (fmt
->f_type
) {
423 fmt
->f_comp
->c_flags
&= ~CF_PARSED
;
428 case FT_LS_DECODECOMP
:
430 * Trim these components of any newlines.
432 * But don't trim the "body" and "text" components.
437 if (! (comp
->c_flags
& CF_TRIMMED
) && comp
->c_text
&&
438 (i
= strlen(comp
->c_text
)) > 0) {
439 if (comp
->c_text
[i
- 1] == '\n' &&
440 strcmp(comp
->c_name
, "body") != 0 &&
441 strcmp(comp
->c_name
, "text") != 0)
442 comp
->c_text
[i
- 1] = '\0';
443 comp
->c_flags
|= CF_TRIMMED
;
450 for ( ; charstring_chars (scanlp
) < max
; ) {
451 switch (fmt
->f_type
) {
454 cpstripped (scanlp
, max
- charstring_chars (scanlp
),
455 fmt
->f_comp
->c_text
);
458 cptrimmed (scanlp
, fmt
->f_comp
->c_text
, fmt
->f_width
,
459 fmt
->f_fill
, max
- charstring_chars (scanlp
));
464 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
465 charstring_push_back (scanlp
, c
);
474 rjust
= true; /* XXX should do something with this */
476 while ((c
= *sp
++) && --i
>= 0 && charstring_chars (scanlp
) < max
) {
477 charstring_push_back (scanlp
, c
);
479 while (--i
>= 0 && charstring_chars (scanlp
) < max
) {
480 charstring_push_back (scanlp
, fmt
->f_fill
);
485 cpstripped (scanlp
, max
- charstring_chars (scanlp
), str
);
488 cptrimmed (scanlp
, str
, fmt
->f_width
, fmt
->f_fill
,
489 max
- charstring_chars (scanlp
));
494 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
495 charstring_push_back (scanlp
, c
);
500 if (str
) charstring_push_back_chars (scanlp
, str
, strlen (str
), 0);
503 die("internal error (FT_STRFW)");
509 for (wid
= num
<= 0; num
; ++wid
, num
/= 10) {}
510 cpnumber (scanlp
, value
, wid
, ' ',
511 max
- charstring_chars (scanlp
));
518 unsigned int whole
, tenths
;
519 unsigned int scale
= 0;
520 unsigned int val
= (unsigned int)value
;
521 char *kibisuff
= NULL
;
523 switch (fmt
->f_type
) {
524 case FT_LS_KILO
: scale
= 1000; kibisuff
= ""; break;
525 case FT_LS_KIBI
: scale
= 1024; kibisuff
= "i"; break;
529 snprintf(buffer
, sizeof(buffer
), "%u", val
);
531 /* To prevent divide by 0, found by clang static
533 if (scale
== 0) { scale
= 1; }
535 /* find correct scale for size (Kilo/Mega/Giga/Tera) */
536 for (unitcp
= "KMGT"; val
> (scale
* scale
); val
/= scale
) {
542 strcpy(buffer
, "huge");
544 /* val is scale times too big. we want tenths */
552 tenths
= val
- (whole
* 10);
555 snprintf(buffer
, sizeof(buffer
), "%u.%u%c%s",
556 whole
, tenths
, *unitcp
, kibisuff
);
558 snprintf(buffer
, sizeof(buffer
), "%u%c%s",
559 whole
, *unitcp
, kibisuff
);
567 cpnumber (scanlp
, value
, fmt
->f_width
, fmt
->f_fill
,
568 max
- charstring_chars (scanlp
));
572 charstring_push_back (scanlp
, fmt
->f_char
);
576 if (callbacks
&& callbacks
->trace_func
)
577 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
578 str
, charstring_buffer (scanlp
));
582 if (!(value
= (str
&& *str
))) {
583 if (callbacks
&& callbacks
->trace_func
)
584 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
585 str
, charstring_buffer (scanlp
));
592 if (!(value
= (str
== NULL
|| *str
== 0))) {
593 if (callbacks
&& callbacks
->trace_func
)
594 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
595 str
, charstring_buffer (scanlp
));
602 if (value
!= fmt
->f_value
) {
603 if (callbacks
&& callbacks
->trace_func
)
604 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
605 str
, charstring_buffer (scanlp
));
612 if (value
== fmt
->f_value
) {
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
= (str
&& match (str
, fmt
->f_text
)))) {
633 if (callbacks
&& callbacks
->trace_func
)
634 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
635 str
, charstring_buffer (scanlp
));
643 value
= match (str
, fmt
->f_text
);
649 if (!(value
= (str
&& uprf (str
, fmt
->f_text
)))) {
650 if (callbacks
&& callbacks
->trace_func
)
651 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
652 str
, charstring_buffer (scanlp
));
659 value
= uprf (str
, fmt
->f_text
);
663 value
= (str
!= NULL
&& *str
!= 0);
667 value
= (str
== NULL
|| *str
== 0);
671 value
= (fmt
->f_value
== value
);
675 value
= (fmt
->f_value
!= value
);
679 value
= (fmt
->f_value
> value
);
683 if (callbacks
&& callbacks
->trace_func
)
684 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
685 str
, charstring_buffer (scanlp
));
693 str
= fmt
->f_comp
->c_text
;
699 if (!(str
= getenv (fmt
->f_text
)))
703 if (!(str
= context_find (fmt
->f_text
)))
707 case FT_LS_DECODECOMP
:
708 if (decode_rfc2047(fmt
->f_comp
->c_text
, buffer2
, sizeof(buffer2
)))
711 str
= fmt
->f_comp
->c_text
;
715 if (str
&& decode_rfc2047(str
, buffer2
, sizeof(buffer2
)))
724 strncpy(buffer
, str
, sizeof(buffer
));
725 buffer
[sizeof(buffer
)-1] = '\0';
727 while (isspace((unsigned char) *str
))
730 if ((i
= fmt
->f_width
) < 0) {
735 if (!rjust
&& i
> 0 && (int) strlen(str
) > i
)
738 xp
+= strlen(str
) - 1;
739 while (xp
> str
&& isspace((unsigned char) *xp
))
741 if (rjust
&& i
> 0 && (int) strlen(str
) > i
)
742 str
+= strlen(str
) - i
;
747 value
= (fmt
->f_comp
->c_flags
& CF_TRUE
) != 0;
750 value
= (comp
= fmt
->f_comp
)->c_text
? atoi(comp
->c_text
) : 0;
753 value
= fmt
->f_value
;
756 value
= dat
[fmt
->f_value
];
764 case FT_LV_CHAR_LEFT
:
765 value
= max
- charstring_bytes (scanlp
);
768 value
+= fmt
->f_value
;
771 value
= fmt
->f_value
- value
;
773 case FT_LV_MULTIPLY_L
:
774 value
*= fmt
->f_value
;
778 value
/= fmt
->f_value
;
784 value
%= fmt
->f_value
;
793 value
= fmt
->f_comp
->c_tws
->tw_sec
;
796 value
= fmt
->f_comp
->c_tws
->tw_min
;
799 value
= fmt
->f_comp
->c_tws
->tw_hour
;
802 value
= fmt
->f_comp
->c_tws
->tw_mday
;
805 value
= fmt
->f_comp
->c_tws
->tw_mon
+ 1;
808 str
= tw_moty
[fmt
->f_comp
->c_tws
->tw_mon
];
811 str
= lmonth
[fmt
->f_comp
->c_tws
->tw_mon
];
814 str
= dtwszone (fmt
->f_comp
->c_tws
);
817 value
= fmt
->f_comp
->c_tws
->tw_year
;
820 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
822 value
= tws
->tw_wday
;
825 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
827 str
= tw_dotw
[tws
->tw_wday
];
830 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
832 str
= tw_ldotw
[tws
->tw_wday
];
835 value
= fmt
->f_comp
->c_tws
->tw_yday
;
838 value
= fmt
->f_comp
->c_tws
->tw_zone
;
841 if ((value
= fmt
->f_comp
->c_tws
->tw_clock
) == 0)
842 value
= dmktime(fmt
->f_comp
->c_tws
);
845 if ((value
= fmt
->f_comp
->c_tws
->tw_clock
) == 0)
846 value
= dmktime(fmt
->f_comp
->c_tws
);
847 value
= time(NULL
) - value
;
850 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
852 switch (fmt
->f_comp
->c_tws
->tw_flags
& TW_SDAY
) {
862 if (fmt
->f_comp
->c_tws
->tw_flags
& TW_SZEXP
)
868 value
= fmt
->f_comp
->c_tws
->tw_flags
& TW_DST
? 1 : 0;
871 str
= dasctime (fmt
->f_comp
->c_tws
, TW_ZONE
);
874 str
= dasctime (fmt
->f_comp
->c_tws
, TW_NULL
);
878 str
= fmt
->f_comp
->c_mn
->m_pers
;
881 str
= fmt
->f_comp
->c_mn
->m_mbox
;
884 str
= fmt
->f_comp
->c_mn
->m_host
;
887 str
= fmt
->f_comp
->c_mn
->m_path
;
890 str
= fmt
->f_comp
->c_mn
->m_gname
;
893 str
= fmt
->f_comp
->c_mn
->m_note
;
896 str
= adrformat( fmt
->f_comp
->c_mn
);
899 value
= fmt
->f_comp
->c_mn
->m_type
;
902 value
= fmt
->f_comp
->c_mn
->m_ingrp
;
905 value
= fmt
->f_comp
->c_mn
->m_nohost
;
909 if ((mn
= fmt
->f_comp
->c_mn
) == &fmt_mnull
) {
910 str
= fmt
->f_comp
->c_text
;
913 if (fmt
->f_type
== FT_LS_ADDR
)
915 if ((str
= mn
->m_pers
) == NULL
) {
916 if ((str
= mn
->m_note
)) {
918 strncpy (buffer
, str
, sizeof(buffer
));
919 buffer
[sizeof(buffer
)-1] = '\0';
923 sp
= str
+ strlen(str
) - 1;
932 } else if (!(str
= get_x400_friendly (mn
->m_mbox
,
933 buffer
, sizeof(buffer
)))) {
935 switch (mn
->m_type
) {
940 snprintf (buffer
, sizeof(buffer
), "%s!%s",
941 mn
->m_host
, mn
->m_mbox
);
946 snprintf (buffer
, sizeof(buffer
), "%s@%s",
947 mn
->m_mbox
, mn
->m_host
);
959 /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
963 strncpy(buffer
, str
, sizeof(buffer
));
964 /* strncpy doesn't NUL-terminate if it fills the buffer */
965 buffer
[sizeof(buffer
)-1] = '\0';
966 unquote_string(buffer
, buffer2
);
973 if ((t
= comp
->c_tws
->tw_clock
) == 0)
974 t
= dmktime(comp
->c_tws
);
975 tws
= dlocaltime(&t
);
981 if ((t
= comp
->c_tws
->tw_clock
) == 0)
982 t
= dmktime(comp
->c_tws
);
989 if (comp
->c_flags
& CF_PARSED
)
991 if ((sp
= comp
->c_text
) && (tws
= dparsetime(sp
))) {
993 comp
->c_flags
&= ~CF_TRUE
;
994 } else if ((comp
->c_flags
& CF_DATEFAB
) == 0) {
996 comp
->c_flags
= CF_TRUE
;
998 comp
->c_flags
|= CF_PARSED
;
1002 /* hook for custom address list formatting (see replsbr.c) */
1003 if (callbacks
&& callbacks
->formataddr
)
1004 str
= callbacks
->formataddr (savestr
, str
);
1006 str
= formataddr (savestr
, str
);
1010 /* The same as formataddr, but doesn't do duplicate suppression */
1011 if (callbacks
&& callbacks
->concataddr
)
1012 str
= callbacks
->concataddr (savestr
, str
);
1014 str
= concataddr (savestr
, str
);
1018 /* output the str register as an address component,
1019 * splitting it into multiple lines if necessary. The
1020 * value reg. contains the max line length. The lit.
1021 * field may contain a string to prepend to the result
1026 int indent
, wid
, len
;
1030 len
= str
? strlen (str
) : 0;
1032 indent
= strlen (sp
);
1035 die("putaddr -- num register (%d) must be greater "
1036 "than label width (%d)", value
, indent
);
1038 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
1039 charstring_push_back (scanlp
, c
);
1042 /* try to break at a comma; failing that, break at a
1045 lastb
= 0; sp
= lp
+ wid
;
1046 while (sp
> lp
&& (c
= (unsigned char) *--sp
) != ',') {
1047 if (! lastb
&& isspace(c
))
1051 if (! (sp
= lastb
)) {
1053 while (*sp
&& *sp
!= ',' &&
1054 !isspace((unsigned char) *sp
))
1061 while (lp
<= sp
&& charstring_chars (scanlp
) < max
) {
1062 charstring_push_back (scanlp
, *lp
++);
1064 while (isspace((unsigned char) *lp
))
1067 if (charstring_chars (scanlp
) < max
) {
1068 charstring_push_back (scanlp
, '\n');
1071 charstring_chars (scanlp
) < max
&& i
> 0;
1073 charstring_push_back (scanlp
, ' ');
1076 cpstripped (scanlp
, max
- charstring_chars (scanlp
), lp
);
1082 if (comp
->c_flags
& CF_PARSED
)
1084 if (comp
->c_mn
!= &fmt_mnull
)
1085 mnfree (comp
->c_mn
);
1086 if ((sp
= comp
->c_text
) && (sp
= getname(sp
)) &&
1087 (mn
= getm (sp
, NULL
, 0, NULL
, 0))) {
1091 comp
->c_flags
|= CF_PARSED
;
1093 while (getname("")) /* XXX */
1095 comp
->c_mn
= &fmt_mnull
;
1103 * if there's no component, we say true. Otherwise we
1104 * say "true" only if we can parse the address and it
1105 * matches one of our addresses.
1108 if (comp
->c_mn
!= &fmt_mnull
)
1109 mnfree (comp
->c_mn
);
1110 if ((sp
= comp
->c_text
) && (sp
= getname(sp
)) &&
1111 (mn
= getm (sp
, NULL
, 0, NULL
, 0))) {
1114 comp
->c_flags
|= CF_TRUE
;
1115 /* Set str for use with FT_GETMYMBOX. With
1116 FT_GETMYADDR, comp->c_mn will be run through
1117 FT_LS_ADDR, which will strip off any pers
1121 comp
->c_flags
&= ~CF_TRUE
;
1123 while ((sp
= getname(sp
)))
1124 if ((comp
->c_flags
& CF_TRUE
) == 0 &&
1125 (mn
= getm (sp
, NULL
, 0, NULL
, 0)))
1127 comp
->c_flags
|= CF_TRUE
;
1128 /* Set str and comp->c_text for use with
1129 FT_GETMYMBOX. With FT_GETMYADDR,
1130 comp->c_mn will be run through
1131 FT_LS_ADDR, which will strip off any
1133 free (comp
->c_text
);
1134 comp
->c_text
= str
= strdup (mn
->m_text
);
1137 comp
->c_flags
|= CF_PARSED
;
1139 while (getname("")) /* XXX */
1141 if (comp
->c_text
== 0)
1142 comp
->c_flags
|= CF_TRUE
;
1144 comp
->c_flags
&= ~CF_TRUE
;
1146 comp
->c_mn
= &fmt_mnull
;
1148 if ((comp
->c_flags
& CF_TRUE
) == 0 &&
1149 (fmt
->f_type
== FT_GETMYMBOX
|| fmt
->f_type
== FT_GETMYADDR
)) {
1150 /* Fool FT_LS_ADDR into not producing an address. */
1151 comp
->c_mn
= &fmt_mnull
; comp
->c_text
= NULL
;
1157 * Call our tracing callback function, if one was supplied
1160 if (callbacks
&& callbacks
->trace_func
)
1161 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1162 str
, charstring_buffer (scanlp
));
1166 /* Emit any trailing sequences of zero display length. */
1167 while (fmt
->f_type
!= FT_DONE
) {
1168 if (fmt
->f_type
== FT_LS_LIT
) {
1170 if (callbacks
&& callbacks
->trace_func
)
1171 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1172 str
, charstring_buffer (scanlp
));
1173 } else if (fmt
->f_type
== FT_STRLITZ
) {
1174 /* Don't want to emit part of an escape sequence. So if
1175 there isn't enough room in the buffer for the entire
1176 string, skip it completely. Need room for null
1177 terminator, and maybe trailing newline (added below). */
1179 for (sp
= str
; *sp
; ++sp
) {
1180 charstring_push_back (scanlp
, *sp
);
1183 if (callbacks
&& callbacks
->trace_func
)
1184 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1185 str
, charstring_buffer (scanlp
));
1191 if (charstring_bytes (scanlp
) > 0) {
1193 * Append a newline if the last character wasn't.
1195 #ifdef MULTIBYTE_SUPPORT
1197 * It's a little tricky because the last byte might be part of
1198 * a multibyte character, in which case we assume that wasn't
1201 size_t last_char_len
= charstring_last_char_len (scanlp
);
1202 #else /* ! MULTIBYTE_SUPPORT */
1203 size_t last_char_len
= 1;
1204 #endif /* ! MULTIBYTE_SUPPORT */
1206 if (last_char_len
> 1 ||
1207 charstring_buffer (scanlp
)[charstring_bytes (scanlp
) - 1] != '\n') {
1208 charstring_push_back (scanlp
, '\n');