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