Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: vstring_vstream.c,v 1.3 2026/05/09 18:49:23 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	vstring_vstream 3
      6 /* SUMMARY
      7 /*	auto-resizing string library, standard I/O interface
      8 /* SYNOPSIS
      9 /*	#include <vstring_vstream.h>
     10 /*
     11 /*	int	vstring_get_flags(vp, fp, flags)
     12 /*	VSTRING	*vp;
     13 /*	VSTREAM	*fp;
     14 /*	int	flags
     15 /*
     16 /*	int	vstring_get_flags_nonl(vp, fp, flags)
     17 /*	VSTRING	*vp;
     18 /*	VSTREAM	*fp;
     19 /*	int	flags
     20 /*
     21 /*	int	vstring_get_flags_null(vp, fp, flags)
     22 /*	VSTRING	*vp;
     23 /*	VSTREAM	*fp;
     24 /*	int	flags
     25 /*
     26 /*	int	vstring_get_flags_bound(vp, fp, flags, bound)
     27 /*	VSTRING	*vp;
     28 /*	VSTREAM	*fp;
     29 /*	ssize_t	bound;
     30 /*	int	flags
     31 /*
     32 /*	int	vstring_get_flags_nonl_bound(vp, fp, flags, bound)
     33 /*	VSTRING	*vp;
     34 /*	VSTREAM	*fp;
     35 /*	ssize_t	bound;
     36 /*	int	flags
     37 /*
     38 /*	int	vstring_get_flags_null_bound(vp, fp, flags, bound)
     39 /*	VSTRING	*vp;
     40 /*	VSTREAM	*fp;
     41 /*	ssize_t	bound;
     42 /*	int	flags
     43 /* CONVENIENCE API
     44 /*	int	vstring_get(vp, fp)
     45 /*	VSTRING	*vp;
     46 /*	VSTREAM	*fp;
     47 /*
     48 /*	int	vstring_get_nonl(vp, fp)
     49 /*	VSTRING	*vp;
     50 /*	VSTREAM	*fp;
     51 /*
     52 /*	int	vstring_get_null(vp, fp)
     53 /*	VSTRING	*vp;
     54 /*	VSTREAM	*fp;
     55 /*
     56 /*	int	vstring_get_bound(vp, fp, bound)
     57 /*	VSTRING	*vp;
     58 /*	VSTREAM	*fp;
     59 /*	ssize_t	bound;
     60 /*
     61 /*	int	vstring_get_nonl_bound(vp, fp, bound)
     62 /*	VSTRING	*vp;
     63 /*	VSTREAM	*fp;
     64 /*	ssize_t	bound;
     65 /*
     66 /*	int	vstring_get_null_bound(vp, fp, bound)
     67 /*	VSTRING	*vp;
     68 /*	VSTREAM	*fp;
     69 /*	ssize_t	bound;
     70 /* DESCRIPTION
     71 /*	The routines in this module each read one newline or null-terminated
     72 /*	string from an input stream. In all cases the result is either the
     73 /*	last character read, typically the record terminator, or VSTREAM_EOF.
     74 /*	The flags argument is VSTRING_GET_FLAG_NONE (default) or
     75 /*	VSTRING_GET_FLAG_APPEND (append instead of overwrite).
     76 /*
     77 /*	vstring_get_flags() reads one line from the named stream, including the
     78 /*	terminating newline character if present.
     79 /*
     80 /*	vstring_get_flags_nonl() reads a line from the named stream and strips
     81 /*	the trailing newline character.
     82 /*
     83 /*	vstring_get_flags_null() reads a null-terminated string from the named
     84 /*	stream.
     85 /*
     86 /*	the vstring_get_flags<whatever>_bound() routines read no more
     87 /*	than \fIbound\fR characters.  Otherwise they behave like the
     88 /*	unbounded versions documented above.
     89 /*
     90 /*	The functions without _flags in their name accept the same
     91 /*	arguments except flags. These functions use the default
     92 /*	flags value.
     93 /* DIAGNOSTICS
     94 /*	Fatal errors: memory allocation failure.
     95 /*	Panic: improper string bound.
     96 /* LICENSE
     97 /* .ad
     98 /* .fi
     99 /*	The Secure Mailer license must be distributed with this software.
    100 /* AUTHOR(S)
    101 /*	Wietse Venema
    102 /*	IBM T.J. Watson Research
    103 /*	P.O. Box 704
    104 /*	Yorktown Heights, NY 10598, USA
    105 /*
    106 /*	Wietse Venema
    107 /*	Google, Inc.
    108 /*	111 8th Avenue
    109 /*	New York, NY 10011, USA
    110 /*--*/
    111 
    112 /* System library. */
    113 
    114 #include "sys_defs.h"
    115 #include <stdio.h>
    116 #include <string.h>
    117 
    118 /* Application-specific. */
    119 
    120 #include "msg.h"
    121 #include "vstring.h"
    122 #include "vstream.h"
    123 #include "vstring_vstream.h"
    124 
    125  /*
    126   * Macro to return the last character added to a VSTRING, for consistency.
    127   */
    128 #define VSTRING_GET_RESULT(vp, base_len) \
    129     (VSTRING_LEN(vp) > (base_len) ? vstring_end(vp)[-1] : VSTREAM_EOF)
    130 
    131 /* vstring_get_flags - read line from file, keep newline */
    132 
    133 int     vstring_get_flags(VSTRING *vp, VSTREAM *fp, int flags)
    134 {
    135     int     c;
    136     ssize_t base_len;
    137 
    138     if ((flags & VSTRING_GET_FLAG_APPEND) == 0)
    139 	VSTRING_RESET(vp);
    140     base_len = VSTRING_LEN(vp);
    141     while ((c = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
    142 	VSTRING_ADDCH(vp, c);
    143 	if (c == '\n')
    144 	    break;
    145     }
    146     VSTRING_TERMINATE(vp);
    147     return (VSTRING_GET_RESULT(vp, base_len));
    148 }
    149 
    150 /* vstring_get_flags_nonl - read line from file, strip newline */
    151 
    152 int     vstring_get_flags_nonl(VSTRING *vp, VSTREAM *fp, int flags)
    153 {
    154     int     c;
    155     ssize_t base_len;
    156 
    157     if ((flags & VSTRING_GET_FLAG_APPEND) == 0)
    158 	VSTRING_RESET(vp);
    159     base_len = VSTRING_LEN(vp);
    160     while ((c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != '\n')
    161 	VSTRING_ADDCH(vp, c);
    162     VSTRING_TERMINATE(vp);
    163     return (c == '\n' ? c : VSTRING_GET_RESULT(vp, base_len));
    164 }
    165 
    166 /* vstring_get_flags_null - read null-terminated string from file */
    167 
    168 int     vstring_get_flags_null(VSTRING *vp, VSTREAM *fp, int flags)
    169 {
    170     int     c;
    171     ssize_t base_len;
    172 
    173     if ((flags & VSTRING_GET_FLAG_APPEND) == 0)
    174 	VSTRING_RESET(vp);
    175     base_len = VSTRING_LEN(vp);
    176     while ((c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0)
    177 	VSTRING_ADDCH(vp, c);
    178     VSTRING_TERMINATE(vp);
    179     return (c == 0 ? c : VSTRING_GET_RESULT(vp, base_len));
    180 }
    181 
    182 /* vstring_get_flags_bound - read line from file, keep newline, up to bound */
    183 
    184 int     vstring_get_flags_bound(VSTRING *vp, VSTREAM *fp, int flags,
    185 				        ssize_t bound)
    186 {
    187     int     c;
    188     ssize_t base_len;
    189 
    190     if (bound <= 0)
    191 	msg_panic("vstring_get_bound: invalid bound %ld", (long) bound);
    192 
    193     if ((flags & VSTRING_GET_FLAG_APPEND) == 0)
    194 	VSTRING_RESET(vp);
    195     base_len = VSTRING_LEN(vp);
    196     while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
    197 	VSTRING_ADDCH(vp, c);
    198 	if (c == '\n')
    199 	    break;
    200     }
    201     VSTRING_TERMINATE(vp);
    202     return (VSTRING_GET_RESULT(vp, base_len));
    203 }
    204 
    205 /* vstring_get_flags_nonl_bound - read line from file, strip newline, up to bound */
    206 
    207 int     vstring_get_flags_nonl_bound(VSTRING *vp, VSTREAM *fp, int flags,
    208 				             ssize_t bound)
    209 {
    210     int     c;
    211     ssize_t base_len;
    212 
    213     if (bound <= 0)
    214 	msg_panic("vstring_get_nonl_bound: invalid bound %ld", (long) bound);
    215 
    216     if ((flags & VSTRING_GET_FLAG_APPEND) == 0)
    217 	VSTRING_RESET(vp);
    218     base_len = VSTRING_LEN(vp);
    219     while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != '\n')
    220 	VSTRING_ADDCH(vp, c);
    221     VSTRING_TERMINATE(vp);
    222     return (c == '\n' ? c : VSTRING_GET_RESULT(vp, base_len));
    223 }
    224 
    225 /* vstring_get_flags_null_bound - read null-terminated string from file */
    226 
    227 int     vstring_get_flags_null_bound(VSTRING *vp, VSTREAM *fp, int flags,
    228 				             ssize_t bound)
    229 {
    230     int     c;
    231     ssize_t base_len;
    232 
    233     if (bound <= 0)
    234 	msg_panic("vstring_get_null_bound: invalid bound %ld", (long) bound);
    235 
    236     if ((flags & VSTRING_GET_FLAG_APPEND) == 0)
    237 	VSTRING_RESET(vp);
    238     base_len = VSTRING_LEN(vp);
    239     while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0)
    240 	VSTRING_ADDCH(vp, c);
    241     VSTRING_TERMINATE(vp);
    242     return (c == 0 ? c : VSTRING_GET_RESULT(vp, base_len));
    243 }
    244 
    245 #ifdef TEST
    246 
    247  /*
    248   * Proof-of-concept test program: copy the source to this module to stdout.
    249   */
    250 #include <fcntl.h>
    251 
    252 #define TEXT_VSTREAM    "vstring_vstream.c"
    253 
    254 int     main(void)
    255 {
    256     VSTRING *vp = vstring_alloc(1);
    257     VSTREAM *fp;
    258 
    259     if ((fp = vstream_fopen(TEXT_VSTREAM, O_RDONLY, 0)) == 0)
    260 	msg_fatal("open %s: %m", TEXT_VSTREAM);
    261     while (vstring_fgets(vp, fp))
    262 	vstream_fprintf(VSTREAM_OUT, "%s", vstring_str(vp));
    263     vstream_fclose(fp);
    264     vstream_fflush(VSTREAM_OUT);
    265     vstring_free(vp);
    266     return (0);
    267 }
    268 
    269 #endif
    270