1/*	$NetBSD: vstring_vstream.c,v 1.2 2020/03/18 19:05:22 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, baselen) \
129    (VSTRING_LEN(vp) > (base_len) ? vstring_end(vp)[-1] : VSTREAM_EOF)
130
131/* vstring_get_flags - read line from file, keep newline */
132
133int     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, baselen));
148}
149
150/* vstring_get_flags_nonl - read line from file, strip newline */
151
152int     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, baselen));
164}
165
166/* vstring_get_flags_null - read null-terminated string from file */
167
168int     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, baselen));
180}
181
182/* vstring_get_flags_bound - read line from file, keep newline, up to bound */
183
184int     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, baselen));
203}
204
205/* vstring_get_flags_nonl_bound - read line from file, strip newline, up to bound */
206
207int     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, baselen));
223}
224
225/* vstring_get_flags_null_bound - read null-terminated string from file */
226
227int     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, baselen));
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
254int     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