]>
diplodocus.org Git - nmh/blob - sbr/fmt_scan.c
3 * fmt_scan.c -- format string interpretation
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.
9 * This is the engine that processes the format instructions created by
10 * fmt_compile (found in fmt_compile.c).
14 #include <h/addrsbr.h>
15 #include <h/fmt_scan.h>
17 #include <h/fmt_compile.h>
20 #ifdef HAVE_SYS_TIME_H
21 # include <sys/time.h>
24 #ifdef MULTIBYTE_SUPPORT
29 struct mailname fmt_mnull
= { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, 0, 0, 0, 0,
35 static int match (char *, char *);
36 static char *get_x400_friendly (char *, char *, int);
37 static int get_x400_comp (char *, char *, char *, int);
41 * test if string "sub" appears anywhere in
42 * string "str" (case insensitive).
46 match (char *str
, char *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
))
61 s1
= sub
+ 1; s2
= str
;
62 while ((c1
= *s1
++) && ((isascii((unsigned char) c1
) &&
63 isalpha((unsigned char) c1
) &&
64 isupper((unsigned char) c1
)) ?
66 ((isascii((unsigned char) (c2
=*s2
++)) &&
67 isalpha((unsigned char) c2
) &&
68 isupper((unsigned char) c2
)) ?
69 tolower((unsigned char) c2
) : c2
))
78 * copy a number to the destination subject to a maximum width
81 cpnumber(charstring_t dest
, int num
, unsigned int wid
, char fill
, size_t max
) {
82 if (wid
< (num
>= 0 ? max
: max
-1)) {
83 /* Build up the string representation of num in reverse. */
84 charstring_t rev
= charstring_create (0);
85 int i
= num
>= 0 ? num
: -num
;
88 charstring_push_back (rev
, i
% 10 + '0');
90 } while (--wid
> 0 && i
> 0);
92 /* Overflowed the field (wid). */
93 charstring_push_back (rev
, '?');
94 } else if (num
< 0 && wid
> 0) {
95 /* Shouldn't need the wid > 0 check, that's why the condition
96 at the top checks wid < max-1 when num < 0. */
97 charstring_push_back (rev
, '-');
100 while (wid
-- > 0 && fill
!= 0) {
101 charstring_push_back (rev
, fill
);
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
) {
125 int remaining
; /* remaining output width available */
127 size_t end
; /* number of input bytes remaining in str */
128 #ifdef MULTIBYTE_SUPPORT
129 int char_len
; /* bytes in current character */
134 char *sp
; /* current position in source string */
139 if ((remaining
= wid
) < 0) {
140 remaining
= -remaining
;
143 if (remaining
> (int) max
) { remaining
= max
; }
146 #ifdef MULTIBYTE_SUPPORT
147 if (mbtowc(NULL
, NULL
, 0)) {} /* reset shift state */
150 while (*sp
&& remaining
> 0 && end
> 0) {
151 #ifdef MULTIBYTE_SUPPORT
152 char_len
= mbtowc(&wide_char
, sp
, end
);
155 * See the relevant comments in cpstripped() to explain what's
156 * going on here; we want to handle the case where we get
157 * characters that mbtowc() cannot handle
162 char_len
= mbtowc(&wide_char
, altstr
, 1);
169 w
= wcwidth(wide_char
);
171 /* If w > remaining, w must be positive. */
178 if (iswcntrl(wide_char
) || iswspace(wide_char
)) {
183 /* isnctrl(), etc., take an int argument. Cygwin's ctype.h
184 intentionally warns if they are passed a char. */
185 c
= (unsigned char) *sp
;
186 if (iscntrl(c
) || isspace(c
)) {
190 charstring_push_back (dest
, ' ');
199 #ifdef MULTIBYTE_SUPPORT
200 if (w
>= 0 && remaining
>= w
) {
201 charstring_push_back_chars (dest
, altstr
? altstr
: sp
,
208 charstring_push_back (dest
, *sp
++);
216 /* copy string to the right */
217 charstring_t copy
= charstring_copy (dest
);
219 /* add padding at the beginning */
220 charstring_clear (dest
);
221 for (; remaining
> 0; --remaining
) {
222 charstring_push_back (dest
, fill
);
225 charstring_append (dest
, copy
);
227 charstring_free (copy
);
230 /* pad remaining space */
231 while (remaining
-- > 0) {
232 charstring_push_back (dest
, fill
);
238 cpstripped (charstring_t dest
, size_t max
, char *str
)
240 int prevCtrl
= 1; /* This is 1 so we strip out leading spaces */
242 #ifdef MULTIBYTE_SUPPORT
246 #endif /* MULTIBYTE_SUPPORT */
254 #ifdef MULTIBYTE_SUPPORT
255 if (mbtowc(NULL
, NULL
, 0)) {} /* Reset shift state */
256 #endif /* MULTIBYTE_SUPPORT */
259 * Process each character at a time; if we have multibyte support
260 * then deal with that here.
263 while (*str
!= '\0' && len
> 0 && max
> 0) {
264 #ifdef MULTIBYTE_SUPPORT
265 char_len
= mbtowc(&wide_char
, str
, len
);
266 w
= wcwidth(wide_char
);
269 * If mbrtowc() failed, then we have a character that isn't valid
270 * in the current encoding. Replace it with a '?'. We do that by
271 * setting the alstr variable to the value of the replacement string;
272 * altstr is used below when the bytes are copied into the output
278 char_len
= mbtowc(&wide_char
, altstr
, 1);
287 if (iswcntrl(wide_char
) || iswspace(wide_char
)) {
289 #else /* MULTIBYTE_SUPPORT */
290 int c
= (unsigned char) *str
;
292 if (iscntrl(c
) || isspace(c
)) {
294 #endif /* MULTIBYTE_SUPPORT */
296 charstring_push_back (dest
, ' ');
306 #ifdef MULTIBYTE_SUPPORT
307 charstring_push_back_chars (dest
, altstr
? altstr
: str
, char_len
, w
);
311 #else /* MULTIBYE_SUPPORT */
312 charstring_push_back (dest
, *str
++);
314 #endif /* MULTIBYTE_SUPPORT */
318 static char *lmonth
[] = { "January", "February","March", "April",
319 "May", "June", "July", "August",
320 "September","October", "November","December" };
323 get_x400_friendly (char *mbox
, char *buffer
, int buffer_len
)
325 char given
[BUFSIZ
], surname
[BUFSIZ
];
334 if (get_x400_comp (mbox
, "/PN=", buffer
, buffer_len
)) {
335 for (mbox
= buffer
; (mbox
= strchr(mbox
, '.')); )
341 if (!get_x400_comp (mbox
, "/S=", surname
, sizeof(surname
)))
344 if (get_x400_comp (mbox
, "/G=", given
, sizeof(given
)))
345 snprintf (buffer
, buffer_len
, "%s %s", given
, surname
);
347 snprintf (buffer
, buffer_len
, "%s", surname
);
353 get_x400_comp (char *mbox
, char *key
, char *buffer
, int buffer_len
)
358 if ((idx
= stringdex (key
, mbox
)) < 0
359 || !(cp
= strchr(mbox
+= idx
+ strlen (key
), '/')))
362 snprintf (buffer
, buffer_len
, "%*.*s", (int)(cp
- mbox
), (int)(cp
- mbox
), mbox
);
367 fmt_scan (struct format
*format
, charstring_t scanlp
, int width
, int *dat
,
368 struct fmt_callbacks
*callbacks
)
372 char buffer
[BUFSIZ
], buffer2
[BUFSIZ
];
383 * max is the same as width, but unsigned so comparisons
384 * with charstring_chars() won't raise compile warnings.
387 savestr
= str
= NULL
;
390 for (fmt
= format
; fmt
->f_type
!= FT_DONE
; fmt
++)
391 switch (fmt
->f_type
) {
394 fmt
->f_comp
->c_flags
&= ~CF_PARSED
;
399 case FT_LS_DECODECOMP
:
401 * Trim these components of any newlines.
403 * But don't trim the "body" and "text" components.
408 if (! (comp
->c_flags
& CF_TRIMMED
) && comp
->c_text
&&
409 (i
= strlen(comp
->c_text
)) > 0) {
410 if (comp
->c_text
[i
- 1] == '\n' &&
411 strcmp(comp
->c_name
, "body") != 0 &&
412 strcmp(comp
->c_name
, "text") != 0)
413 comp
->c_text
[i
- 1] = '\0';
414 comp
->c_flags
|= CF_TRIMMED
;
421 for ( ; charstring_chars (scanlp
) < max
; ) {
422 switch (fmt
->f_type
) {
425 cpstripped (scanlp
, max
- charstring_chars (scanlp
),
426 fmt
->f_comp
->c_text
);
429 cptrimmed (scanlp
, fmt
->f_comp
->c_text
, fmt
->f_width
,
430 fmt
->f_fill
, max
- charstring_chars (scanlp
));
435 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
436 charstring_push_back (scanlp
, c
);
445 rjust
++; /* XXX should do something with this */
447 while ((c
= *sp
++) && --i
>= 0 && charstring_chars (scanlp
) < max
) {
448 charstring_push_back (scanlp
, c
);
450 while (--i
>= 0 && charstring_chars (scanlp
) < max
) {
451 charstring_push_back (scanlp
, fmt
->f_fill
);
456 cpstripped (scanlp
, max
- charstring_chars (scanlp
), str
);
459 cptrimmed (scanlp
, str
, fmt
->f_width
, fmt
->f_fill
,
460 max
- charstring_chars (scanlp
));
465 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
466 charstring_push_back (scanlp
, c
);
471 if (str
) charstring_push_back_chars (scanlp
, str
, strlen (str
), 0);
474 adios (NULL
, "internal error (FT_STRFW)");
480 for (wid
= num
<= 0 ? 1 : 0; num
; ++wid
, num
/= 10) {}
481 cpnumber (scanlp
, value
, wid
, ' ',
482 max
- charstring_chars (scanlp
));
489 unsigned int whole
, tenths
;
490 unsigned int scale
= 0;
491 unsigned int val
= (unsigned int)value
;
492 char *kibisuff
= NULL
;
494 switch (fmt
->f_type
) {
495 case FT_LS_KILO
: scale
= 1000; kibisuff
= ""; break;
496 case FT_LS_KIBI
: scale
= 1024; kibisuff
= "i"; break;
500 snprintf(buffer
, sizeof(buffer
), "%u", val
);
503 /* find correct scale for size (Kilo/Mega/Giga/Tera) */
504 for (unitcp
= "KMGT"; val
> (scale
* scale
); val
/= scale
) {
510 strcpy(buffer
, "huge");
512 /* val is scale times too big. we want tenths */
520 tenths
= val
- (whole
* 10);
523 snprintf(buffer
, sizeof(buffer
), "%u.%u%c%s",
524 whole
, tenths
, *unitcp
, kibisuff
);
526 snprintf(buffer
, sizeof(buffer
), "%u%c%s",
527 whole
, *unitcp
, kibisuff
);
535 cpnumber (scanlp
, value
, fmt
->f_width
, fmt
->f_fill
,
536 max
- charstring_chars (scanlp
));
540 charstring_push_back (scanlp
, fmt
->f_char
);
544 if (callbacks
&& callbacks
->trace_func
)
545 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
546 str
, charstring_buffer (scanlp
));
550 if (!(value
= (str
&& *str
))) {
551 if (callbacks
&& callbacks
->trace_func
)
552 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
553 str
, charstring_buffer (scanlp
));
560 if (!(value
= (str
== NULL
|| *str
== 0))) {
561 if (callbacks
&& callbacks
->trace_func
)
562 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
563 str
, charstring_buffer (scanlp
));
570 if (value
!= fmt
->f_value
) {
571 if (callbacks
&& callbacks
->trace_func
)
572 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
573 str
, charstring_buffer (scanlp
));
580 if (value
== fmt
->f_value
) {
581 if (callbacks
&& callbacks
->trace_func
)
582 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
583 str
, charstring_buffer (scanlp
));
590 if (value
<= fmt
->f_value
) {
591 if (callbacks
&& callbacks
->trace_func
)
592 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
593 str
, charstring_buffer (scanlp
));
600 if (!(value
= (str
&& match (str
, fmt
->f_text
)))) {
601 if (callbacks
&& callbacks
->trace_func
)
602 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
603 str
, charstring_buffer (scanlp
));
611 value
= match (str
, fmt
->f_text
);
617 if (!(value
= (str
&& uprf (str
, fmt
->f_text
)))) {
618 if (callbacks
&& callbacks
->trace_func
)
619 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
620 str
, charstring_buffer (scanlp
));
627 value
= uprf (str
, fmt
->f_text
);
631 value
= (str
!= NULL
&& *str
!= 0);
635 value
= (str
== NULL
|| *str
== 0);
639 value
= (fmt
->f_value
== value
);
643 value
= (fmt
->f_value
!= value
);
647 value
= (fmt
->f_value
> value
);
651 if (callbacks
&& callbacks
->trace_func
)
652 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
653 str
, charstring_buffer (scanlp
));
661 str
= fmt
->f_comp
->c_text
;
667 if (!(str
= getenv (fmt
->f_text
)))
671 if (!(str
= context_find (fmt
->f_text
)))
675 case FT_LS_DECODECOMP
:
676 if (decode_rfc2047(fmt
->f_comp
->c_text
, buffer2
, sizeof(buffer2
)))
679 str
= fmt
->f_comp
->c_text
;
683 if (str
&& decode_rfc2047(str
, buffer2
, sizeof(buffer2
)))
691 strncpy(buffer
, str
, sizeof(buffer
));
692 buffer
[sizeof(buffer
)-1] = '\0';
694 while (isspace((unsigned char) *str
))
697 if ((i
= fmt
->f_width
) < 0) {
702 if (!rjust
&& i
> 0 && (int) strlen(str
) > i
)
705 xp
+= strlen(str
) - 1;
706 while (xp
> str
&& isspace((unsigned char) *xp
))
708 if (rjust
&& i
> 0 && (int) strlen(str
) > i
)
709 str
+= strlen(str
) - i
;
714 value
= (fmt
->f_comp
->c_flags
& CF_TRUE
) != 0;
717 value
= (comp
= fmt
->f_comp
)->c_text
? atoi(comp
->c_text
) : 0;
720 value
= fmt
->f_value
;
723 value
= dat
[fmt
->f_value
];
731 case FT_LV_CHAR_LEFT
:
732 value
= max
- charstring_bytes (scanlp
);
735 value
+= fmt
->f_value
;
738 value
= fmt
->f_value
- value
;
742 value
= value
/ fmt
->f_value
;
748 value
= value
% fmt
->f_value
;
757 value
= fmt
->f_comp
->c_tws
->tw_sec
;
760 value
= fmt
->f_comp
->c_tws
->tw_min
;
763 value
= fmt
->f_comp
->c_tws
->tw_hour
;
766 value
= fmt
->f_comp
->c_tws
->tw_mday
;
769 value
= fmt
->f_comp
->c_tws
->tw_mon
+ 1;
772 str
= tw_moty
[fmt
->f_comp
->c_tws
->tw_mon
];
775 str
= lmonth
[fmt
->f_comp
->c_tws
->tw_mon
];
778 str
= dtwszone (fmt
->f_comp
->c_tws
);
781 value
= fmt
->f_comp
->c_tws
->tw_year
;
784 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
786 value
= tws
->tw_wday
;
789 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
791 str
= tw_dotw
[tws
->tw_wday
];
794 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
796 str
= tw_ldotw
[tws
->tw_wday
];
799 value
= fmt
->f_comp
->c_tws
->tw_yday
;
802 value
= fmt
->f_comp
->c_tws
->tw_zone
;
805 if ((value
= fmt
->f_comp
->c_tws
->tw_clock
) == 0)
806 value
= dmktime(fmt
->f_comp
->c_tws
);
809 if ((value
= fmt
->f_comp
->c_tws
->tw_clock
) == 0)
810 value
= dmktime(fmt
->f_comp
->c_tws
);
811 value
= time((time_t *) 0) - value
;
814 if (!(((tws
= fmt
->f_comp
->c_tws
)->tw_flags
) & (TW_SEXP
|TW_SIMP
)))
816 switch (fmt
->f_comp
->c_tws
->tw_flags
& TW_SDAY
) {
825 if ((fmt
->f_comp
->c_tws
->tw_flags
& TW_SZONE
) == TW_SZEXP
)
831 value
= fmt
->f_comp
->c_tws
->tw_flags
& TW_DST
;
834 str
= dasctime (fmt
->f_comp
->c_tws
, TW_ZONE
);
837 str
= dasctime (fmt
->f_comp
->c_tws
, TW_NULL
);
841 str
= fmt
->f_comp
->c_mn
->m_pers
;
844 str
= fmt
->f_comp
->c_mn
->m_mbox
;
847 str
= fmt
->f_comp
->c_mn
->m_host
;
850 str
= fmt
->f_comp
->c_mn
->m_path
;
853 str
= fmt
->f_comp
->c_mn
->m_gname
;
856 str
= fmt
->f_comp
->c_mn
->m_note
;
859 str
= adrformat( fmt
->f_comp
->c_mn
);
862 value
= fmt
->f_comp
->c_mn
->m_type
;
865 value
= fmt
->f_comp
->c_mn
->m_ingrp
;
868 value
= fmt
->f_comp
->c_mn
->m_nohost
;
872 if ((mn
= fmt
->f_comp
->c_mn
) == &fmt_mnull
) {
873 str
= fmt
->f_comp
->c_text
;
876 if (fmt
->f_type
== FT_LS_ADDR
)
878 if ((str
= mn
->m_pers
) == NULL
) {
879 if ((str
= mn
->m_note
)) {
880 strncpy (buffer
, str
, sizeof(buffer
));
881 buffer
[sizeof(buffer
)-1] = '\0';
885 sp
= str
+ strlen(str
) - 1;
894 } else if (!(str
= get_x400_friendly (mn
->m_mbox
,
895 buffer
, sizeof(buffer
)))) {
897 switch (mn
->m_type
) {
902 snprintf (buffer
, sizeof(buffer
), "%s!%s",
903 mn
->m_host
, mn
->m_mbox
);
908 snprintf (buffer
, sizeof(buffer
), "%s@%s",
909 mn
->m_mbox
, mn
->m_host
);
921 /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
924 strncpy(buffer
, str
, sizeof(buffer
));
925 /* strncpy doesn't NUL-terminate if it fills the buffer */
926 buffer
[sizeof(buffer
)-1] = '\0';
927 unquote_string(buffer
, buffer2
);
934 if ((t
= comp
->c_tws
->tw_clock
) == 0)
935 t
= dmktime(comp
->c_tws
);
936 tws
= dlocaltime(&t
);
942 if ((t
= comp
->c_tws
->tw_clock
) == 0)
943 t
= dmktime(comp
->c_tws
);
950 if (comp
->c_flags
& CF_PARSED
)
952 if ((sp
= comp
->c_text
) && (tws
= dparsetime(sp
))) {
954 comp
->c_flags
&= ~CF_TRUE
;
955 } else if ((comp
->c_flags
& CF_DATEFAB
) == 0) {
956 memset (comp
->c_tws
, 0, sizeof *comp
->c_tws
);
957 comp
->c_flags
= CF_TRUE
;
959 comp
->c_flags
|= CF_PARSED
;
963 /* hook for custom address list formatting (see replsbr.c) */
964 if (callbacks
&& callbacks
->formataddr
)
965 str
= callbacks
->formataddr (savestr
, str
);
967 str
= formataddr (savestr
, str
);
971 /* The same as formataddr, but doesn't do duplicate suppression */
972 if (callbacks
&& callbacks
->concataddr
)
973 str
= callbacks
->concataddr (savestr
, str
);
975 str
= concataddr (savestr
, str
);
979 /* output the str register as an address component,
980 * splitting it into multiple lines if necessary. The
981 * value reg. contains the max line length. The lit.
982 * field may contain a string to prepend to the result
987 int indent
, wid
, len
;
993 indent
= strlen (sp
);
996 adios(NULL
, "putaddr -- num register (%d) must be greater "
997 "than label width (%d)", value
, indent
);
999 while ((c
= *sp
++) && charstring_chars (scanlp
) < max
) {
1000 charstring_push_back (scanlp
, c
);
1003 /* try to break at a comma; failing that, break at a
1006 lastb
= 0; sp
= lp
+ wid
;
1007 while (sp
> lp
&& (c
= (unsigned char) *--sp
) != ',') {
1008 if (! lastb
&& isspace(c
))
1012 if (! (sp
= lastb
)) {
1014 while (*sp
&& *sp
!= ',' &&
1015 !isspace((unsigned char) *sp
))
1022 while (lp
<= sp
&& charstring_chars (scanlp
) < max
) {
1023 charstring_push_back (scanlp
, *lp
++);
1025 while (isspace((unsigned char) *lp
))
1028 if (charstring_chars (scanlp
) < max
) {
1029 charstring_push_back (scanlp
, '\n');
1032 charstring_chars (scanlp
) < max
&& i
> 0;
1034 charstring_push_back (scanlp
, ' ');
1037 cpstripped (scanlp
, max
- charstring_chars (scanlp
), lp
);
1043 if (comp
->c_flags
& CF_PARSED
)
1045 if (comp
->c_mn
!= &fmt_mnull
)
1046 mnfree (comp
->c_mn
);
1047 if ((sp
= comp
->c_text
) && (sp
= getname(sp
)) &&
1048 (mn
= getm (sp
, NULL
, 0, NULL
, 0))) {
1052 comp
->c_flags
|= CF_PARSED
;
1054 while (getname("")) /* XXX */
1056 comp
->c_mn
= &fmt_mnull
;
1062 * if there's no component, we say true. Otherwise we
1063 * say "true" only if we can parse the address and it
1064 * matches one of our addresses.
1067 if (comp
->c_mn
!= &fmt_mnull
)
1068 mnfree (comp
->c_mn
);
1069 if ((sp
= comp
->c_text
) && (sp
= getname(sp
)) &&
1070 (mn
= getm (sp
, NULL
, 0, NULL
, 0))) {
1073 comp
->c_flags
|= CF_TRUE
;
1075 comp
->c_flags
&= ~CF_TRUE
;
1076 while ((sp
= getname(sp
)))
1077 if ((comp
->c_flags
& CF_TRUE
) == 0 &&
1078 (mn
= getm (sp
, NULL
, 0, NULL
, 0)))
1080 comp
->c_flags
|= CF_TRUE
;
1082 while (getname("")) /* XXX */
1084 if (comp
->c_text
== 0)
1085 comp
->c_flags
|= CF_TRUE
;
1087 comp
->c_flags
&= ~CF_TRUE
;
1088 comp
->c_mn
= &fmt_mnull
;
1094 * Call our tracing callback function, if one was supplied
1097 if (callbacks
&& callbacks
->trace_func
)
1098 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1099 str
, charstring_buffer (scanlp
));
1103 /* Emit any trailing sequences of zero display length. */
1104 while (fmt
->f_type
!= FT_DONE
) {
1105 if (fmt
->f_type
== FT_LS_LIT
) {
1107 if (callbacks
&& callbacks
->trace_func
)
1108 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1109 str
, charstring_buffer (scanlp
));
1110 } else if (fmt
->f_type
== FT_STRLITZ
) {
1111 /* Don't want to emit part of an escape sequence. So if
1112 there isn't enough room in the buffer for the entire
1113 string, skip it completely. Need room for null
1114 terminator, and maybe trailing newline (added below). */
1116 for (sp
= str
; *sp
; ++sp
) {
1117 charstring_push_back (scanlp
, *sp
);
1120 if (callbacks
&& callbacks
->trace_func
)
1121 callbacks
->trace_func(callbacks
->trace_context
, fmt
, value
,
1122 str
, charstring_buffer (scanlp
));
1128 if (charstring_bytes (scanlp
) > 0) {
1130 * Append a newline if the last character wasn't.
1132 #ifdef MULTIBYTE_SUPPORT
1134 * It's a little tricky because the last byte might be part of
1135 * a multibyte character, in which case we assume that wasn't
1138 size_t last_char_len
= charstring_last_char_len (scanlp
);
1139 #else /* ! MULTIBYTE_SUPPORT */
1140 size_t last_char_len
= 1;
1141 #endif /* ! MULTIBYTE_SUPPORT */
1143 if (last_char_len
> 1 ||
1144 charstring_buffer (scanlp
)[charstring_bytes (scanlp
) - 1] != '\n') {
1145 charstring_push_back (scanlp
, '\n');
1149 return ((struct format
*)0);