1 /* @(#)fstream.c 1.35 19/01/16 Copyright 1985-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)fstream.c 1.35 19/01/16 Copyright 1985-2019 J. Schilling";
6 #endif
7 /*
8 * Stream filter module
9 *
10 * Copyright (c) 1985-2019 J. Schilling
11 *
12 * Exported functions:
13 * mkfstream(f, fun, rfun, efun) Construct new fstream
14 * fsclose(fsp) Close a fstream
15 * fssetfile(fsp, f) Replace file pointer in fstream
16 * fsgetc(fsp) Get one character from fstream
17 * fspushcha(fsp, c) Push one character on fstream
18 * fspushstr(fsp, str) Push a string on fstream
19 */
20 /*
21 * The contents of this file are subject to the terms of the
22 * Common Development and Distribution License, Version 1.0 only
23 * (the "License"). You may not use this file except in compliance
24 * with the License.
25 *
26 * See the file CDDL.Schily.txt in this distribution for details.
27 * A copy of the CDDL is also available via the Internet at
28 * http://www.opensource.org/licenses/cddl1.txt
29 *
30 * When distributing Covered Code, include this CDDL HEADER in each
31 * file and include the License file CDDL.Schily.txt from this distribution.
32 */
33
34 #define WSTRINGS
35 #include <schily/stdio.h>
36 #include <schily/standard.h>
37 #include <schily/schily.h>
38 #include <schily/string.h>
39 #include <schily/stdlib.h>
40 #include <schily/fstream.h>
41
42 EXPORT fstream *mkfstream __PR((FILE *f, fstr_fun sfun, fstr_rfun rfun,
43 fstr_efun efun));
44 EXPORT fstream *fspush __PR((fstream *fsp, fstr_efun efun));
45 EXPORT fstream *fspop __PR((fstream *fsp));
46 EXPORT fstream *fspushed __PR((fstream *fsp));
47 EXPORT void fsclose __PR((fstream *fsp));
48 EXPORT FILE *fssetfile __PR((fstream *fsp, FILE *f));
49 EXPORT int fsgetc __PR((fstream *fsp));
50 EXPORT void fspushstr __PR((fstream *fsp, char *ss));
51 EXPORT void fspushcha __PR((fstream *fsp, int c));
52 LOCAL void s_ccpy __PR((CHAR *ts, unsigned char *ss));
53 LOCAL void s_scpy __PR((CHAR *ts, CHAR *ss));
54 LOCAL void s_scat __PR((CHAR *ts, CHAR *ss));
55
56 /*
57 * Set up a new stream
58 */
59 EXPORT fstream *
mkfstream(f,sfun,rfun,efun)60 mkfstream(f, sfun, rfun, efun)
61 FILE *f; /* The "file" parameter may be a fstream * */
62 fstr_fun sfun; /* The fstream transfer/filter function */
63 fstr_rfun rfun; /* The read/input function */
64 fstr_efun efun; /* The error function used by this func */
65 {
66 register fstream *fsp;
67
68 if ((fsp = (fstream *)malloc(sizeof (fstream))) == (fstream *)NULL) {
69 if (efun)
70 efun("no memory for new fstream");
71 return ((fstream *)NULL);
72 }
73 fsp->fstr_bp = fsp->fstr_buf = fsp->fstr_sbuf;
74 *fsp->fstr_bp = '\0';
75 fsp->fstr_file = f;
76 fsp->fstr_flags = 0;
77 fsp->fstr_pushed = (fstream *)0;
78 fsp->fstr_func = sfun;
79 fsp->fstr_rfunc = rfun;
80 fsp->fstr_auxp = 0;
81 return (fsp);
82 }
83
84 /*
85 * Push a new stream
86 */
87 EXPORT fstream *
fspush(fsp,efun)88 fspush(fsp, efun)
89 fstream *fsp;
90 fstr_efun efun; /* The error function used by this func */
91 {
92 fstream *new = mkfstream((FILE *)0, (fstr_fun)0, (fstr_rfun)0, efun);
93
94 if (new == (fstream *)NULL)
95 return (new);
96
97 new->fstr_pushed = fsp->fstr_pushed;
98 fsp->fstr_pushed = new;
99 return (new);
100 }
101
102 /*
103 * Pop a stream
104 */
105 EXPORT fstream *
fspop(fsp)106 fspop(fsp)
107 fstream *fsp;
108 {
109 fstream *prev = fsp->fstr_pushed;
110
111 if (prev == (fstream *)NULL)
112 return (prev);
113
114 fsp->fstr_pushed = prev->fstr_pushed;
115 fsclose(prev);
116
117 return (fsp);
118 }
119
120 /*
121 * Return pushed stream
122 */
123 EXPORT fstream *
fspushed(fsp)124 fspushed(fsp)
125 fstream *fsp;
126 {
127 return (fsp->fstr_pushed);
128 }
129
130 /*
131 * close the stream
132 * Do not close the file fsp->fstr_file!
133 */
134 EXPORT void
fsclose(fsp)135 fsclose(fsp)
136 fstream *fsp;
137 {
138 if (fsp->fstr_buf != fsp->fstr_sbuf)
139 free(fsp->fstr_buf);
140 free((char *)fsp);
141 }
142
143 /*
144 * Change the FILE * member of the stream.
145 */
146 EXPORT FILE *
fssetfile(fsp,f)147 fssetfile(fsp, f)
148 register fstream *fsp;
149 FILE *f;
150 {
151 FILE *tmp = fsp->fstr_file;
152
153 fsp->fstr_file = f;
154 return (tmp);
155 }
156
157 /*
158 * get next character from stream
159 */
160 EXPORT int
fsgetc(fsp)161 fsgetc(fsp)
162 register fstream *fsp;
163 {
164 /*
165 * If there are pushed streams, refer to the top of pushed streams.
166 */
167 if (fsp->fstr_pushed != NULL)
168 fsp = fsp->fstr_pushed;
169 /*
170 * If our buffer is non-empty, "read" from the buffer.
171 */
172 while (*fsp->fstr_bp == '\0') { /* buffer is empty */
173 if (fsp->fstr_func != (fstr_fun)0) { /* call function */
174 int ret;
175
176 /*
177 * We have a filter function, so call it.
178 */
179 #ifdef DEBUG
180 printf("filter via function %p\n", fsp->fstr_func);
181 #endif
182 if ((ret = (*fsp->fstr_func)(fsp, fsp->fstr_file)) < 0)
183 return (ret);
184 } else if (fsp->fstr_file == (FILE *)NULL) { /* no file */
185 /*
186 * If we have no input, return EOF.
187 */
188 return (EOF);
189 } else { /* read from FILE */
190 #ifdef DEBUG
191 printf("read character from file at %06x\n", fsp->fstr_file);
192 #endif
193 if (fsp->fstr_rfunc != (fstr_rfun)0)
194 return ((*fsp->fstr_rfunc)(fsp));
195 return (EOF);
196 }
197 }
198 #ifdef DEBUG
199 printf("character '%c' from buffer\n", *fsp->fstr_bp);
200 #endif
201 return (*fsp->fstr_bp++); /* char from buffer */
202 }
203
204 /*
205 * get # of characters in stream
206 */
207 EXPORT size_t
fsgetlen(fsp)208 fsgetlen(fsp)
209 register fstream *fsp;
210 {
211 CHAR *bp;
212
213 /*
214 * If there are pushed streams, refer to the top of pushed streams.
215 */
216 if (fsp->fstr_pushed != NULL)
217 fsp = fsp->fstr_pushed;
218
219 bp = fsp->fstr_bp;
220 while (*bp++ != '\0')
221 ;
222 return (--bp - fsp->fstr_bp);
223 }
224
225 /*
226 * Push a null terminated string on the stream
227 */
228 EXPORT void
fspushstr(fsp,ss)229 fspushstr(fsp, ss)
230 register fstream *fsp;
231 register char *ss;
232 {
233 register CHAR *tp;
234 CHAR *ts;
235 CHAR tbuf[STR_SBUF_SIZE + 1];
236 unsigned len;
237
238 /*
239 * If there are pushed streams, refer to the top of pushed streams.
240 */
241 if (fsp->fstr_pushed != NULL)
242 fsp = fsp->fstr_pushed;
243
244 for (tp = fsp->fstr_bp; *tp; tp++); /* Wide char strlen() */
245 len = tp - fsp->fstr_bp + strlen(ss);
246 if (len > STR_SBUF_SIZE) { /* realloc !!! */
247 if ((ts = (CHAR *)malloc(sizeof (*ts)*(len+1))) == NULL) {
248 raisecond("fspushstr", (long)NULL);
249 /* NOTREACHED */
250 }
251 #ifdef WSTRINGS
252 s_ccpy(ts, (unsigned char *)ss);
253 s_scat(ts, fsp->fstr_bp);
254 #else
255 strcatl(ts, ss, fsp->fstr_bp, (char *)NULL);
256 #endif
257 if (fsp->fstr_buf != fsp->fstr_sbuf)
258 free(fsp->fstr_buf);
259 fsp->fstr_buf = fsp->fstr_bp = ts;
260 } else {
261 #ifdef WSTRINGS
262 s_scpy(tbuf, fsp->fstr_bp);
263 #else
264 strcatl(tbuf, fsp->fstr_bp, (char *)NULL);
265 #endif
266 if (fsp->fstr_buf != fsp->fstr_sbuf) {
267 free(fsp->fstr_buf);
268 fsp->fstr_buf = fsp->fstr_sbuf;
269 }
270 #ifdef WSTRINGS
271 s_ccpy(fsp->fstr_buf, (unsigned char *)ss);
272 s_scat(fsp->fstr_buf, tbuf);
273 #else
274 strcatl(fsp->fstr_buf, ss, tbuf, (char *)NULL);
275 #endif
276 fsp->fstr_bp = fsp->fstr_buf;
277 }
278 }
279
280 /*
281 * Push a character on the stream
282 */
283 EXPORT void
fspushcha(fsp,c)284 fspushcha(fsp, c)
285 fstream *fsp;
286 int c;
287 {
288 char t[2];
289
290 #ifdef WSTRINGS
291 t[0] = (char)1; /* Nonzero placeholder */
292 #else
293 t[0] = (char)c;
294 #endif
295 t[1] = 0;
296 fspushstr(fsp, t);
297 #ifdef WSTRINGS
298 /*
299 * Solange es kein fspushstr mit SHORT * gibt, wird zuerst Platz
300 * geschafft und dann der korrekte Buchstabe eingetragen.
301 */
302 if (fsp->fstr_pushed != NULL)
303 fsp = fsp->fstr_pushed;
304 *fsp->fstr_bp = c;
305 #endif
306 }
307
308 /*
309 * Copy from narrow char string to wide char string
310 */
311 LOCAL void
s_ccpy(ts,ss)312 s_ccpy(ts, ss)
313 register CHAR *ts;
314 register unsigned char *ss;
315 {
316 while (*ss)
317 *ts++ = *ss++;
318 *ts = 0;
319 }
320
321 /*
322 * Copy from wide char string to wide char string
323 */
324 LOCAL void
s_scpy(ts,ss)325 s_scpy(ts, ss)
326 register CHAR *ts;
327 register CHAR *ss;
328 {
329 while (*ss)
330 *ts++ = *ss++;
331 *ts = 0;
332 }
333
334 #ifdef __needed__
335 LOCAL void
s_ccat(ts,ss)336 s_ccat(ts, ss)
337 register string ts;
338 register unsigned char *ss;
339 {
340 while (*ts)
341 ts++;
342 while (*ss)
343 *ts++ = *ss++;
344 *ts = 0;
345 }
346 #endif
347
348 LOCAL void
s_scat(ts,ss)349 s_scat(ts, ss)
350 register CHAR *ts;
351 register CHAR *ss;
352 {
353 while (*ts)
354 ts++;
355 while (*ss)
356 *ts++ = *ss++;
357 *ts = 0;
358 }
359