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