diff options
author | Werner Koch <[email protected]> | 2018-11-26 19:22:24 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2018-11-26 19:22:24 +0000 |
commit | bd8668c120ac0f725edb092b2c4ca49ffdb78ed2 (patch) | |
tree | ffeea782e9dc6435822f3b3f1c950c7222ff93b9 | |
parent | core: Add a limited version of gpgrt_ftruncate. (diff) | |
download | libgpg-error-bd8668c120ac0f725edb092b2c4ca49ffdb78ed2.tar.gz libgpg-error-bd8668c120ac0f725edb092b2c4ca49ffdb78ed2.zip |
core: New functions gpgrt_fprintf_sf anf gpgrt_fprintf_sf_unlocked.
* src/gpg-error.h.in (gpgrt_string_filter_t): New type.
(gpgrt_fprintf_sf, gpgrt_fprintf_sf_unlocked): New.
* src/gpg-error.vers, src/gpg-error.def.in: Add them.
* src/visibility.c (gpgrt_fprintf_sf): New.
(gpgrt_fprintf_sf_unlocked): New.
* src/estream-printf.c (pr_string): Add and use args sf, sfvalue and
string_no.
(do_format): Add args sf and sfvalue. Keep a string format counter.
(_gpgrt_estream_format): Add args sf and sfvalue. Change all callers
to provide NULL for them.
* src/estream.c (_gpgrt_vfprintf_unlocked, _gpgrt_vfprintf): Add sf
and sfvalue and adjust all callers.
(do_print_stream): Ditto.
* tests/t-printf.c (stream_to_string): New.
(struct sfstate_s): New.
(string_filter): New.
(check_fprintf_sf): New.
(main): Call new test.
--
The actual reason to implement these functions is to enhance the
internal logging function with a filter to sanitized strings so that
control values or other things can be quoted.
Signed-off-by: Werner Koch <[email protected]>
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | src/estream-printf.c | 67 | ||||
-rw-r--r-- | src/estream-printf.h | 4 | ||||
-rw-r--r-- | src/estream.c | 13 | ||||
-rw-r--r-- | src/gpg-error.def.in | 3 | ||||
-rw-r--r-- | src/gpg-error.h.in | 14 | ||||
-rw-r--r-- | src/gpg-error.vers | 3 | ||||
-rw-r--r-- | src/gpgrt-int.h | 6 | ||||
-rw-r--r-- | src/logging.c | 2 | ||||
-rw-r--r-- | src/visibility.c | 42 | ||||
-rw-r--r-- | src/visibility.h | 4 | ||||
-rw-r--r-- | tests/t-printf.c | 112 |
12 files changed, 239 insertions, 35 deletions
@@ -5,6 +5,10 @@ Noteworthy changes in version 1.33 (unreleased) [C24/A24/R_] * Interface changes relative to the 1.28 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgrt_cmp_version New. + gpgrt_ftruncate New but limited functionality. + gpgrt_string_filter_t New. + gpgrt_fprintf_sf New. + gpgrt_fprintf_sf_unlocked New. Noteworthy changes in version 1.32 (2018-07-12) [C24/A24/R3] diff --git a/src/estream-printf.c b/src/estream-printf.c index eb6fa3a..b9775a6 100644 --- a/src/estream-printf.c +++ b/src/estream-printf.c @@ -1196,7 +1196,8 @@ pr_char (estream_printf_out_t outfnc, void *outfncarg, /* "s" formatting. */ static int pr_string (estream_printf_out_t outfnc, void *outfncarg, - argspec_t arg, value_t value, size_t *nbytes) + argspec_t arg, value_t value, size_t *nbytes, + gpgrt_string_filter_t sf, void *sfvalue, int string_no) { int rc; size_t n; @@ -1205,6 +1206,11 @@ pr_string (estream_printf_out_t outfnc, void *outfncarg, if (arg->vt != VALTYPE_STRING) return -1; string = value.a_string; + if (sf) + string = sf (value.a_string, string_no, sfvalue); + else + string = value.a_string; + if (!string) string = "(null)"; if (arg->precision >= 0) @@ -1222,12 +1228,12 @@ pr_string (estream_printf_out_t outfnc, void *outfncarg, { rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes); if (rc) - return rc; + goto leave; } rc = outfnc (outfncarg, string, n); if (rc) - return rc; + goto leave; *nbytes += n; if ((arg->flags & FLAG_LEFT_JUST) @@ -1235,10 +1241,16 @@ pr_string (estream_printf_out_t outfnc, void *outfncarg, { rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes); if (rc) - return rc; + goto leave; } - return 0; + rc = 0; + + leave: + if (sf) /* Tell the filter to release resources. */ + sf (value.a_string, -1, sfvalue); + + return rc; } @@ -1337,14 +1349,18 @@ pr_bytes_so_far (estream_printf_out_t outfnc, void *outfncarg, /* Run the actual formatting. OUTFNC and OUTFNCARG are the output - functions. FORMAT is format string ARGSPECS is the parsed format - string, ARGSPECS_LEN the number of items in ARGSPECS. VALUETABLE - holds the values and may be directly addressed using the position - arguments given by ARGSPECS. MYERRNO is used for the "%m" - conversion. NBYTES well be updated to reflect the number of bytes - send to the output function. */ + * functions. FORMAT is format string ARGSPECS is the parsed format + * string, ARGSPECS_LEN the number of items in ARGSPECS. + * STRING_FILTER is an optional function to filter string (%s) args; + * it is called with the original string and the count of already + * processed %s arguments. Its return value will be used instead of + * the original string. VALUETABLE holds the values and may be + * directly addressed using the position arguments given by ARGSPECS. + * MYERRNO is used for the "%m" conversion. NBYTES well be updated to + * reflect the number of bytes send to the output function. */ static int do_format (estream_printf_out_t outfnc, void *outfncarg, + gpgrt_string_filter_t sf, void *sfvalue, const char *format, argspec_t argspecs, size_t argspecs_len, valueitem_t valuetable, int myerrno, size_t *nbytes) { @@ -1354,6 +1370,7 @@ do_format (estream_printf_out_t outfnc, void *outfncarg, int argidx = 0; /* Only used for assertion. */ size_t n; value_t value; + int string_no = 0; /* Number of processed "%s" args. */ s = format; while ( *s ) @@ -1443,8 +1460,12 @@ do_format (estream_printf_out_t outfnc, void *outfncarg, rc = pr_char (outfnc, outfncarg, arg, value, nbytes); break; case CONSPEC_STRING: + rc = pr_string (outfnc, outfncarg, arg, value, nbytes, + sf, sfvalue, string_no++); + break; case CONSPEC_STRERROR: - rc = pr_string (outfnc, outfncarg, arg, value, nbytes); + rc = pr_string (outfnc, outfncarg, arg, value, nbytes, + NULL, NULL, 0); break; case CONSPEC_POINTER: rc = pr_pointer (outfnc, outfncarg, arg, value, nbytes); @@ -1478,6 +1499,7 @@ do_format (estream_printf_out_t outfnc, void *outfncarg, int _gpgrt_estream_format (estream_printf_out_t outfnc, void *outfncarg, + gpgrt_string_filter_t sf, void *sfvalue, const char *format, va_list vaargs) { /* Buffer to hold the argspecs and a pointer to it.*/ @@ -1489,10 +1511,10 @@ _gpgrt_estream_format (estream_printf_out_t outfnc, struct valueitem_s valuetable_buffer[DEFAULT_MAX_VALUES]; valueitem_t valuetable = valuetable_buffer; - int rc; /* Return code. */ + int rc; /* Return code. */ size_t argidx; /* Used to index the argspecs array. */ size_t validx; /* Used to index the valuetable. */ - int max_pos;/* Highest argument position. */ + int max_pos; /* Highest argument position. */ size_t nbytes = 0; /* Keep track of the number of bytes passed to the output function. */ @@ -1606,7 +1628,7 @@ _gpgrt_estream_format (estream_printf_out_t outfnc, /* fprintf (stderr, "%2d: vt=%d\n", validx, valuetable[validx].vt); */ /* Everything has been collected, go ahead with the formatting. */ - rc = do_format (outfnc, outfncarg, format, + rc = do_format (outfnc, outfncarg, sf, sfvalue, format, argspecs, argspecs_len, valuetable, myerrno, &nbytes); goto leave; @@ -1646,7 +1668,8 @@ _gpgrt_estream_printf (const char *format, ...) va_list arg_ptr; va_start (arg_ptr, format); - rc = _gpgrt_estream_format (plain_stdio_out, stderr, format, arg_ptr); + rc = _gpgrt_estream_format (plain_stdio_out, stderr, NULL, NULL, + format, arg_ptr); va_end (arg_ptr); return rc; @@ -1660,7 +1683,8 @@ _gpgrt_estream_fprintf (FILE *fp, const char *format, ...) va_list arg_ptr; va_start (arg_ptr, format); - rc = _gpgrt_estream_format (plain_stdio_out, fp, format, arg_ptr); + rc = _gpgrt_estream_format (plain_stdio_out, fp, NULL, NULL, + format, arg_ptr); va_end (arg_ptr); return rc; @@ -1670,7 +1694,8 @@ _gpgrt_estream_fprintf (FILE *fp, const char *format, ...) int _gpgrt_estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr) { - return _gpgrt_estream_format (plain_stdio_out, fp, format, arg_ptr); + return _gpgrt_estream_format (plain_stdio_out, fp, NULL, NULL, + format, arg_ptr); } @@ -1725,7 +1750,8 @@ _gpgrt_estream_vsnprintf (char *buf, size_t bufsize, parm.count = 0; parm.used = 0; parm.buffer = bufsize?buf:NULL; - rc = _gpgrt_estream_format (fixed_buffer_out, &parm, format, arg_ptr); + rc = _gpgrt_estream_format (fixed_buffer_out, &parm, NULL, NULL, + format, arg_ptr); if (!rc) rc = fixed_buffer_out (&parm, "", 1); /* Print terminating Nul. */ if (rc == -1) @@ -1820,7 +1846,8 @@ _gpgrt_estream_vasprintf (char **bufp, const char *format, va_list arg_ptr) return -1; } - rc = _gpgrt_estream_format (dynamic_buffer_out, &parm, format, arg_ptr); + rc = _gpgrt_estream_format (dynamic_buffer_out, &parm, NULL, NULL, + format, arg_ptr); if (!rc) rc = dynamic_buffer_out (&parm, "", 1); /* Print terminating Nul. */ /* Fixme: Should we shrink the resulting buffer? */ diff --git a/src/estream-printf.h b/src/estream-printf.h index ae303a7..69c7052 100644 --- a/src/estream-printf.h +++ b/src/estream-printf.h @@ -124,8 +124,10 @@ typedef int (*estream_printf_out_t) (void *outfncarg, const char *buf, size_t buflen); int _gpgrt_estream_format (estream_printf_out_t outfnc, void *outfncarg, + char *(*string_filter)(const char *s,int n,void*st), + void *string_filter_state, const char *format, va_list vaargs) - _ESTREAM_GCC_A_PRINTF(3,0); + _ESTREAM_GCC_A_PRINTF(5,0); int _gpgrt_estream_printf (const char *format, ...) _ESTREAM_GCC_A_PRINTF(1,2); int _gpgrt_estream_fprintf (FILE *fp, const char *format, ... ) diff --git a/src/estream.c b/src/estream.c index 72e93e0..3645dfe 100644 --- a/src/estream.c +++ b/src/estream.c @@ -2982,12 +2982,13 @@ print_writer (void *outfncarg, const char *buf, size_t buflen) /* The core of our printf function. This is called in locked state. */ static int do_print_stream (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, const char *_GPGRT__RESTRICT format, va_list ap) { int rc; stream->intern->print_ntotal = 0; - rc = _gpgrt_estream_format (print_writer, stream, format, ap); + rc = _gpgrt_estream_format (print_writer, stream, sf, sfvalue, format, ap); if (rc) return -1; return (int)stream->intern->print_ntotal; @@ -4444,22 +4445,24 @@ _gpgrt_read_line (estream_t stream, int _gpgrt_vfprintf_unlocked (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, const char *_GPGRT__RESTRICT format, va_list ap) { - return do_print_stream (stream, format, ap); + return do_print_stream (stream, sf, sfvalue, format, ap); } int _gpgrt_vfprintf (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, const char *_GPGRT__RESTRICT format, va_list ap) { int ret; lock_stream (stream); - ret = do_print_stream (stream, format, ap); + ret = do_print_stream (stream, sf, sfvalue, format, ap); unlock_stream (stream); return ret; @@ -4474,7 +4477,7 @@ _gpgrt_fprintf_unlocked (estream_t _GPGRT__RESTRICT stream, va_list ap; va_start (ap, format); - ret = do_print_stream (stream, format, ap); + ret = do_print_stream (stream, NULL, NULL, format, ap); va_end (ap); return ret; @@ -4490,7 +4493,7 @@ _gpgrt_fprintf (estream_t _GPGRT__RESTRICT stream, va_list ap; va_start (ap, format); lock_stream (stream); - ret = do_print_stream (stream, format, ap); + ret = do_print_stream (stream, NULL, NULL, format, ap); unlock_stream (stream); va_end (ap); diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in index 9b522ea..f03a7e3 100644 --- a/src/gpg-error.def.in +++ b/src/gpg-error.def.in @@ -221,5 +221,8 @@ EXPORTS gpgrt_cmp_version @169 gpgrt_ftruncate @170 + gpgrt_fprintf_sf @171 + gpgrt_fprintf_sf_unlocked @172 + ;; end of file with public symbols for Windows. diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in index c0ac0eb..cb32c48 100644 --- a/src/gpg-error.h.in +++ b/src/gpg-error.h.in @@ -644,6 +644,11 @@ typedef struct _gpgrt_poll_s gpgrt_poll_t; typedef struct _gpgrt_poll_s es_poll_t; #endif +/* The type of the string filter function as used by fprintf_sf et al. */ +typedef char *(*gpgrt_string_filter_t) (const char *s, int n, void *opaque); + + + gpgrt_stream_t gpgrt_fopen (const char *_GPGRT__RESTRICT path, const char *_GPGRT__RESTRICT mode); gpgrt_stream_t gpgrt_mopen (void *_GPGRT__RESTRICT data, @@ -783,6 +788,15 @@ int gpgrt_fprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, const char *_GPGRT__RESTRICT format, ...) GPGRT_ATTR_PRINTF(2,3); +int gpgrt_fprintf_sf (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, + ...) GPGRT_ATTR_PRINTF(4,5); +int gpgrt_fprintf_sf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, + ...) GPGRT_ATTR_PRINTF(4,5); + int gpgrt_printf (const char *_GPGRT__RESTRICT format, ...) GPGRT_ATTR_PRINTF(1,2); int gpgrt_printf_unlocked (const char *_GPGRT__RESTRICT format, ...) diff --git a/src/gpg-error.vers b/src/gpg-error.vers index f9524d7..105e3bb 100644 --- a/src/gpg-error.vers +++ b/src/gpg-error.vers @@ -193,6 +193,9 @@ GPG_ERROR_1.0 { gpgrt_cmp_version; gpgrt_ftruncate; + gpgrt_fprintf_sf; + gpgrt_fprintf_sf_unlocked; + local: *; }; diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h index 09aad11..e326400 100644 --- a/src/gpgrt-int.h +++ b/src/gpgrt-int.h @@ -435,11 +435,13 @@ int _gpgrt_fprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, GPGRT_ATTR_PRINTF(2,3); int _gpgrt_vfprintf (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, const char *_GPGRT__RESTRICT format, va_list ap) - GPGRT_ATTR_PRINTF(2,0); + GPGRT_ATTR_PRINTF(4,0); int _gpgrt_vfprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, const char *_GPGRT__RESTRICT format, va_list ap) - GPGRT_ATTR_PRINTF(2,0); + GPGRT_ATTR_PRINTF(4,0); int _gpgrt_setvbuf (gpgrt_stream_t _GPGRT__RESTRICT stream, char *_GPGRT__RESTRICT buf, int mode, size_t size); diff --git a/src/logging.c b/src/logging.c index d01f974..51e1362 100644 --- a/src/logging.c +++ b/src/logging.c @@ -839,7 +839,7 @@ _gpgrt_logv_internal (int level, int ignore_arg_ptr, const char *extrastring, } else { - rc = _gpgrt_vfprintf_unlocked (logstream, fmt, arg_ptr); + rc = _gpgrt_vfprintf_unlocked (logstream, NULL, NULL, fmt, arg_ptr); if (rc > 0) length += rc; } diff --git a/src/visibility.c b/src/visibility.c index 1947111..573a5a4 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -515,7 +515,7 @@ gpgrt_vfprintf (estream_t _GPGRT__RESTRICT stream, const char *_GPGRT__RESTRICT format, va_list ap) { - return _gpgrt_vfprintf (stream, format, ap); + return _gpgrt_vfprintf (stream, NULL, NULL, format, ap); } int @@ -523,7 +523,7 @@ gpgrt_vfprintf_unlocked (estream_t _GPGRT__RESTRICT stream, const char *_GPGRT__RESTRICT format, va_list ap) { - return _gpgrt_vfprintf_unlocked (stream, format, ap); + return _gpgrt_vfprintf_unlocked (stream, NULL, NULL, format, ap); } int @@ -533,7 +533,7 @@ gpgrt_printf (const char *_GPGRT__RESTRICT format, ...) int rc; va_start (ap, format); - rc = _gpgrt_vfprintf (es_stdout, format, ap); + rc = _gpgrt_vfprintf (es_stdout, NULL, NULL, format, ap); va_end (ap); return rc; @@ -546,7 +546,7 @@ gpgrt_printf_unlocked (const char *_GPGRT__RESTRICT format, ...) int rc; va_start (ap, format); - rc = _gpgrt_vfprintf_unlocked (es_stdout, format, ap); + rc = _gpgrt_vfprintf_unlocked (es_stdout, NULL, NULL, format, ap); va_end (ap); return rc; @@ -560,7 +560,7 @@ gpgrt_fprintf (estream_t _GPGRT__RESTRICT stream, int rc; va_start (ap, format); - rc = _gpgrt_vfprintf (stream, format, ap); + rc = _gpgrt_vfprintf (stream, NULL, NULL, format, ap); va_end (ap); return rc; @@ -574,7 +574,37 @@ gpgrt_fprintf_unlocked (estream_t _GPGRT__RESTRICT stream, int rc; va_start (ap, format); - rc = _gpgrt_vfprintf_unlocked (stream, format, ap); + rc = _gpgrt_vfprintf_unlocked (stream, NULL, NULL, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_fprintf_sf (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf (stream, sf, sfvalue, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_fprintf_sf_unlocked (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf_unlocked (stream, sf, sfvalue, format, ap); va_end (ap); return rc; diff --git a/src/visibility.h b/src/visibility.h index 46383c7..2dde522 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -121,6 +121,8 @@ MARK_VISIBLE (gpgrt_getline) MARK_VISIBLE (gpgrt_read_line) MARK_VISIBLE (gpgrt_fprintf) MARK_VISIBLE (gpgrt_fprintf_unlocked) +MARK_VISIBLE (gpgrt_fprintf_sf) +MARK_VISIBLE (gpgrt_fprintf_sf_unlocked) MARK_VISIBLE (gpgrt_printf) MARK_VISIBLE (gpgrt_printf_unlocked) MARK_VISIBLE (gpgrt_vfprintf) @@ -296,6 +298,8 @@ MARK_VISIBLE (gpgrt_cmp_version); #define gpgrt_read_line _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_fprintf _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_fprintf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fprintf_sf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fprintf_sf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_printf _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_printf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_vfprintf _gpgrt_USE_UNDERSCORED_FUNCTION diff --git a/tests/t-printf.c b/tests/t-printf.c index 7fba012..1e4d393 100644 --- a/tests/t-printf.c +++ b/tests/t-printf.c @@ -40,6 +40,49 @@ static char *one_test_buf1; static int one_test_rc1; + + + +/* Read all data from STREAM into a new malloced buffer and return + * that buffer. The buffer is always 0 terminated. Either returns a + * string or dies. The stream will be trunctaed to zero. */ +static char * +stream_to_string (gpgrt_stream_t stream) +{ +#define NCHUNK 1024 + char *buffer; + size_t bufsize, buflen; + size_t nread; + + gpgrt_rewind (stream); + + buffer = NULL; + buflen = bufsize = 0; + do + { + bufsize += NCHUNK; + buffer = realloc (buffer, bufsize+1); + if (!buffer) + die ("malloc failed at line %d\n", __LINE__); + + nread = gpgrt_fread (buffer + buflen, 1, NCHUNK, stream); + if (nread < NCHUNK && gpgrt_ferror (stream)) + die ("fread failed at line %d: %s\n", __LINE__, strerror (errno)); + buflen += nread; + } + while (nread == NCHUNK); + buffer[nread] = 0; + + if (strlen (buffer) != buflen) + fail ("stream_to_string detected an embedded nul"); + + gpgrt_ftruncate (stream, 0); + return buffer; +#undef NCHUNK +} + + + static void one_test_x0 (const char *format, ...) { @@ -375,6 +418,74 @@ check_snprintf (void) } +struct sfstate_s +{ + char *last_result; +}; + +static char * +string_filter (const char *string, int no, void *opaque) +{ + struct sfstate_s *state = opaque; + + free (state->last_result); + if (no == -1) + { + state->last_result = NULL; + return NULL; + } + if (no == 3) + state->last_result = NULL; + else + state->last_result = strdup (string? string : "[==>Niente<==]"); + + return state->last_result; +} + + +static void +check_fprintf_sf (void) +{ + volatile char *nullptr = NULL; /* Avoid compiler warning. */ + struct sfstate_s sfstate = {NULL}; + gpgrt_stream_t stream; + const char *expect; + char *result; + + stream = gpgrt_fopenmem (0, "w+b"); + if (!stream) + die ("fopenmem failed at line %d\n", __LINE__); + + gpgrt_fprintf_sf (stream, string_filter, &sfstate, + "%s a=%d b=%s c=%d d=%.8s null=%s\n", + nullptr, 1, "foo\x01 bar", 2, + "a longer string", nullptr); + expect = "[==>Niente<==] a=1 b=foo\x01 bar c=2 d=a longer null=(null)\n"; + result = stream_to_string (stream); + if (strcmp (result, expect)) + { + show ("expect: '%s'\n", expect); + show ("result: '%s'\n", result); + fail ("fprintf_sf failed at %d\n", __LINE__); + } + free (result); + + gpgrt_fprintf_sf (stream, string_filter, &sfstate, + "a=%d b=%s c=%d d=%.8s e=%s\n", + 1, "foo\n bar", 2, nullptr, ""); + expect = "a=1 b=foo\n bar c=2 d=[==>Nien e=\n"; + result = stream_to_string (stream); + if (strcmp (result, expect)) + { + show ("expect: '%s'\n", expect); + show ("result: '%s'\n", result); + fail ("fprintf_sf failed at %d\n", __LINE__); + } + free (result); + + gpgrt_fclose (stream); +} + int main (int argc, char **argv) @@ -420,6 +531,7 @@ main (int argc, char **argv) run_tests (); check_snprintf (); + check_fprintf_sf (); #ifdef __GLIBC__ return !!errorcount; |