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
vstring_get_flags(VSTRING * vp,VSTREAM * fp,int flags)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, baselen));
148 }
149
150 /* vstring_get_flags_nonl - read line from file, strip newline */
151
vstring_get_flags_nonl(VSTRING * vp,VSTREAM * fp,int flags)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, baselen));
164 }
165
166 /* vstring_get_flags_null - read null-terminated string from file */
167
vstring_get_flags_null(VSTRING * vp,VSTREAM * fp,int flags)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, baselen));
180 }
181
182 /* vstring_get_flags_bound - read line from file, keep newline, up to bound */
183
vstring_get_flags_bound(VSTRING * vp,VSTREAM * fp,int flags,ssize_t bound)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, baselen));
203 }
204
205 /* vstring_get_flags_nonl_bound - read line from file, strip newline, up to bound */
206
vstring_get_flags_nonl_bound(VSTRING * vp,VSTREAM * fp,int flags,ssize_t bound)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, baselen));
223 }
224
225 /* vstring_get_flags_null_bound - read null-terminated string from file */
226
vstring_get_flags_null_bound(VSTRING * vp,VSTREAM * fp,int flags,ssize_t bound)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, 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
main(void)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