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(vp, fp)
10/*	VSTRING	*vp;
11/*	VSTREAM	*fp;
12/*
13/*	int	vstring_get_nonl(vp, fp)
14/*	VSTRING	*vp;
15/*	VSTREAM	*fp;
16/*
17/*	int	vstring_get_null(vp, fp)
18/*	VSTRING	*vp;
19/*	VSTREAM	*fp;
20/*
21/*	int	vstring_get_bound(vp, fp, bound)
22/*	VSTRING	*vp;
23/*	VSTREAM	*fp;
24/*	ssize_t	bound;
25/*
26/*	int	vstring_get_nonl_bound(vp, fp, bound)
27/*	VSTRING	*vp;
28/*	VSTREAM	*fp;
29/*	ssize_t	bound;
30/*
31/*	int	vstring_get_null_bound(vp, fp, bound)
32/*	VSTRING	*vp;
33/*	VSTREAM	*fp;
34/*	ssize_t	bound;
35/* DESCRIPTION
36/*	The routines in this module each read one newline or null-terminated
37/*	string from an input stream. In all cases the result is either the
38/*	last character read, typically the record terminator, or VSTREAM_EOF.
39/*
40/*	vstring_get() reads one line from the named stream, including the
41/*	terminating newline character if present.
42/*
43/*	vstring_get_nonl() reads a line from the named stream and strips
44/*	the trailing newline character.
45/*
46/*	vstring_get_null() reads a null-terminated string from the named
47/*	stream.
48/*
49/*	the vstring_get<whatever>_bound() routines read no more
50/*	than \fIbound\fR characters.  Otherwise they behave like the
51/*	unbounded versions documented above.
52/* DIAGNOSTICS
53/*	Fatal errors: memory allocation failure.
54/*	Panic: improper string bound.
55/* LICENSE
56/* .ad
57/* .fi
58/*	The Secure Mailer license must be distributed with this software.
59/* AUTHOR(S)
60/*	Wietse Venema
61/*	IBM T.J. Watson Research
62/*	P.O. Box 704
63/*	Yorktown Heights, NY 10598, USA
64/*--*/
65
66/* System library. */
67
68#include "sys_defs.h"
69#include <stdio.h>
70#include <string.h>
71
72/* Application-specific. */
73
74#include "msg.h"
75#include "vstring.h"
76#include "vstream.h"
77#include "vstring_vstream.h"
78
79 /*
80  * Macro to return the last character added to a VSTRING, for consistency.
81  */
82#define VSTRING_GET_RESULT(vp) \
83    (VSTRING_LEN(vp) > 0 ? vstring_end(vp)[-1] : VSTREAM_EOF)
84
85/* vstring_get - read line from file, keep newline */
86
87int     vstring_get(VSTRING *vp, VSTREAM *fp)
88{
89    int     c;
90
91    VSTRING_RESET(vp);
92    while ((c = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
93	VSTRING_ADDCH(vp, c);
94	if (c == '\n')
95	    break;
96    }
97    VSTRING_TERMINATE(vp);
98    return (VSTRING_GET_RESULT(vp));
99}
100
101/* vstring_get_nonl - read line from file, strip newline */
102
103int     vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
104{
105    int     c;
106
107    VSTRING_RESET(vp);
108    while ((c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != '\n')
109	VSTRING_ADDCH(vp, c);
110    VSTRING_TERMINATE(vp);
111    return (c == '\n' ? c : VSTRING_GET_RESULT(vp));
112}
113
114/* vstring_get_null - read null-terminated string from file */
115
116int     vstring_get_null(VSTRING *vp, VSTREAM *fp)
117{
118    int     c;
119
120    VSTRING_RESET(vp);
121    while ((c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0)
122	VSTRING_ADDCH(vp, c);
123    VSTRING_TERMINATE(vp);
124    return (c == 0 ? c : VSTRING_GET_RESULT(vp));
125}
126
127/* vstring_get_bound - read line from file, keep newline, up to bound */
128
129int     vstring_get_bound(VSTRING *vp, VSTREAM *fp, ssize_t bound)
130{
131    int     c;
132
133    if (bound <= 0)
134	msg_panic("vstring_get_bound: invalid bound %ld", (long) bound);
135
136    VSTRING_RESET(vp);
137    while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
138	VSTRING_ADDCH(vp, c);
139	if (c == '\n')
140	    break;
141    }
142    VSTRING_TERMINATE(vp);
143    return (VSTRING_GET_RESULT(vp));
144}
145
146/* vstring_get_nonl_bound - read line from file, strip newline, up to bound */
147
148int     vstring_get_nonl_bound(VSTRING *vp, VSTREAM *fp, ssize_t bound)
149{
150    int     c;
151
152    if (bound <= 0)
153	msg_panic("vstring_get_nonl_bound: invalid bound %ld", (long) bound);
154
155    VSTRING_RESET(vp);
156    while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != '\n')
157	VSTRING_ADDCH(vp, c);
158    VSTRING_TERMINATE(vp);
159    return (c == '\n' ? c : VSTRING_GET_RESULT(vp));
160}
161
162/* vstring_get_null_bound - read null-terminated string from file */
163
164int     vstring_get_null_bound(VSTRING *vp, VSTREAM *fp, ssize_t bound)
165{
166    int     c;
167
168    if (bound <= 0)
169	msg_panic("vstring_get_null_bound: invalid bound %ld", (long) bound);
170
171    VSTRING_RESET(vp);
172    while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0)
173	VSTRING_ADDCH(vp, c);
174    VSTRING_TERMINATE(vp);
175    return (c == 0 ? c : VSTRING_GET_RESULT(vp));
176}
177
178#ifdef TEST
179
180 /*
181  * Proof-of-concept test program: copy the source to this module to stdout.
182  */
183#include <fcntl.h>
184
185#define TEXT_VSTREAM    "vstring_vstream.c"
186
187int     main(void)
188{
189    VSTRING *vp = vstring_alloc(1);
190    VSTREAM *fp;
191
192    if ((fp = vstream_fopen(TEXT_VSTREAM, O_RDONLY, 0)) == 0)
193	msg_fatal("open %s: %m", TEXT_VSTREAM);
194    while (vstring_fgets(vp, fp))
195	vstream_fprintf(VSTREAM_OUT, "%s", vstring_str(vp));
196    vstream_fclose(fp);
197    vstream_fflush(VSTREAM_OUT);
198    vstring_free(vp);
199    return (0);
200}
201
202#endif
203