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