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