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 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 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 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 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 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 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 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