xref: /plan9/sys/src/cmd/gs/src/stream.h (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: stream.h,v 1.11 2002/06/16 05:00:54 lpd Exp $ */
18 /* Definitions for Ghostscript stream package */
19 /* Requires stdio.h */
20 
21 #ifndef stream_INCLUDED
22 #  define stream_INCLUDED
23 
24 #include "scommon.h"
25 #include "srdline.h"
26 
27 /* See scommon.h for documentation on the design of streams. */
28 
29 /* ------ Stream structure definition ------ */
30 
31 /*
32  * We expose the stream structure definition to clients so that
33  * they can get reasonable performance out of the basic operations.
34  */
35 
36 /* Define the "virtual" stream procedures. */
37 
38 typedef struct {
39 
40     /* Store # available for reading. */
41     /* Return 0 if OK, ERRC if error or not implemented. */
42 #define stream_proc_available(proc)\
43   int proc(stream *, long *)
44     stream_proc_available((*available));
45 
46     /* Set position. */
47     /* Return 0 if OK, ERRC if error or not implemented. */
48 #define stream_proc_seek(proc)\
49   int proc(stream *, long)
50     stream_proc_seek((*seek));
51 
52     /* Clear buffer and, if relevant, unblock channel. */
53     /* Cannot cause an error. */
54 #define stream_proc_reset(proc)\
55   void proc(stream *)
56     stream_proc_reset((*reset));
57 
58     /* Flush buffered data to output, or drain input. */
59     /* Return 0 if OK, ERRC if error. */
60 #define stream_proc_flush(proc)\
61   int proc(stream *)
62     stream_proc_flush((*flush));
63 
64     /* Flush data (if writing) & close stream. */
65     /* Return 0 if OK, ERRC if error. */
66 #define stream_proc_close(proc)\
67   int proc(stream *)
68     stream_proc_close((*close));
69 
70     /* Process a buffer, updating the cursor pointers. */
71     /* See strimpl.h for details. */
72     stream_proc_process((*process));
73 
74     /* Switch the stream to read or write mode. */
75     /* false = read, true = write. */
76     /* If the procedure is 0, switching is not allowed. */
77 #define stream_proc_switch_mode(proc)\
78   int proc(stream *, bool)
79     stream_proc_switch_mode((*switch_mode));
80 
81 } stream_procs;
82 
83 /* ------ The actual stream structure ------ */
84 
85 struct stream_s {
86     /*
87      * To allow the stream itself to serve as the "state"
88      * of a couple of heavily used types, we start its
89      * definition with the common stream state.
90      */
91     stream_state_common;
92     /*
93      * The following invariants apply at all times for read streams:
94      *
95      *    s->cbuf - 1 <= s->srptr <= s->srlimit.
96      *
97      *    The amount of data in the buffer is s->srlimit + 1 - s->cbuf.
98      *
99      *    s->position represents the stream position as of the beginning
100      *      of the buffer, so the current position is s->position +
101      *      (s->srptr + 1 - s->cbuf).
102      *
103      * Analogous invariants apply for write streams:
104      *
105      *    s->cbuf - 1 <= s->swptr <= s->swlimit.
106      *
107      *    The amount of data in the buffer is s->swptr + 1 - s->cbuf.
108      *
109      *    s->position represents the stream position as of the beginning
110      *      of the buffer, so the current position is s->position +
111      *      (s->swptr + 1 - s->cbuf).
112      */
113     stream_cursor cursor;	/* cursor for reading/writing data */
114     byte *cbuf;			/* base of buffer */
115     uint bsize;			/* size of buffer, 0 if closed */
116     uint cbsize;		/* size of buffer */
117     /*
118      * end_status indicates what should happen when the client
119      * reaches the end of the buffer:
120      *      0 in the normal case;
121      *      EOFC if a read stream has reached EOD or a write
122      *        stream has written the EOD marker;
123      *      ERRC if an error terminated the last read or write
124      *        operation from or to the underlying data source
125      *        or sink;
126      *      INTC if the last transfer was interrupted (NOT
127      *        USED YET);
128      *      CALLC if a callout is required.
129      */
130     short end_status;		/* status at end of buffer (when */
131 				/* reading) or now (when writing) */
132     byte foreign;		/* true if buffer is outside heap */
133     byte modes;			/* access modes allowed for this stream */
134 #define s_mode_read 1
135 #define s_mode_write 2
136 #define s_mode_seek 4
137 #define s_mode_append 8		/* (s_mode_write also set) */
138 #define s_is_valid(s) ((s)->modes != 0)
139 #define s_is_reading(s) (((s)->modes & s_mode_read) != 0)
140 #define s_is_writing(s) (((s)->modes & s_mode_write) != 0)
141 #define s_can_seek(s) (((s)->modes & s_mode_seek) != 0)
142     gs_string cbuf_string;	/* cbuf/cbsize if cbuf is a string, */
143 				/* 0/? if not */
144     long position;		/* file position of beginning of */
145 				/* buffer */
146     stream_procs procs;
147     stream *strm;		/* the underlying stream, non-zero */
148 				/* iff this is a filter stream */
149     int is_temp;		/* if >0, this is a temporary */
150 				/* stream and should be freed */
151 				/* when its source/sink is closed; */
152 				/* if >1, the buffer is also */
153 				/* temporary */
154     int inline_temp;		/* temporary for inline access */
155 				/* (see spgetc_inline below) */
156     stream_state *state;	/* state of process */
157     /*
158      * The following are for the use of the interpreter.
159      * See files.h for more information on read_id and write_id,
160      * zfile.c for more information on prev and next,
161      * zfilter.c for more information on close_strm.
162      */
163     ushort read_id;		/* "unique" serial # for detecting */
164 				/* references to closed streams */
165 				/* and for validating read access */
166     ushort write_id;		/* ditto to validate write access */
167     stream *prev, *next;	/* keep track of all files */
168     bool close_strm;		/* CloseSource/CloseTarget */
169     bool close_at_eod;		/*(default is true, only false if "reusable")*/
170     int (*save_close)(stream *);	/* save original close proc */
171     /*
172      * In order to avoid allocating a separate stream_state for
173      * file streams, which are the most heavily used stream type,
174      * we put their state here.
175      */
176     FILE *file;			/* file handle for C library */
177     gs_const_string file_name;	/* file name (optional) -- clients must */
178 				/* access only through procedures */
179     uint file_modes;		/* access modes for the file, */
180 				/* may be a superset of modes */
181     /* Clients must only set the following through sread_subfile. */
182     long file_offset;		/* starting point in file (reading) */
183     long file_limit;		/* ending point in file (reading) */
184 };
185 
186 /* The descriptor is only public for subclassing. */
187 extern_st(st_stream);
188 #define public_st_stream()	/* in stream.c */\
189   gs_public_st_composite_final(st_stream, stream, "stream",\
190     stream_enum_ptrs, stream_reloc_ptrs, stream_finalize)
191 #define STREAM_NUM_PTRS 6
192 
193 /* Initialize the checking IDs of a stream. */
194 #define s_init_ids(s) ((s)->read_id = (s)->write_id = 1)
195 #define s_init_read_id(s) ((s)->read_id = 1, (s)->write_id = 0)
196 #define s_init_write_id(s) ((s)->read_id = 0, (s)->write_id = 1)
197 #define s_init_no_id(s) ((s)->read_id = (s)->write_id = 0)
198 
199 /* ------ Stream functions ------ */
200 
201 #define srptr cursor.r.ptr
202 #define srlimit cursor.r.limit
203 #define swptr cursor.w.ptr
204 #define swlimit cursor.w.limit
205 
206 /* Some of these are macros -- beware. */
207 /* Note that unlike the C stream library, */
208 /* ALL stream procedures take the stream as the first argument. */
209 #define sendrp(s) ((s)->srptr >= (s)->srlimit)	/* NOT FOR CLIENTS */
210 #define sendwp(s) ((s)->swptr >= (s)->swlimit)	/* NOT FOR CLIENTS */
211 
212 /*
213  * Following are valid for all streams.
214  */
215 /* flush is NOT a no-op for read streams -- it discards data until EOF. */
216 /* close is NOT a no-op for non-file streams -- */
217 /* it actively disables them. */
218 /* The close routine must do a flush if needed. */
219 #define sseekable(s) s_can_seek(s)
220 int savailable(stream *, long *);
221 
222 #define sreset(s) (*(s)->procs.reset)(s)
223 #define sflush(s) (*(s)->procs.flush)(s)
224 int sclose(stream *);
225 int sswitch(stream *, bool);
226 
227 /*
228  * Following are only valid for read streams.
229  */
230 int spgetcc(stream *, bool);	/* bool indicates close at EOD */
231 #define spgetc(s) spgetcc(s, true)	/* a procedure equivalent of sgetc */
232 /*
233  * Note that sgetc must call spgetc one byte early, because filter must read
234  * ahead to detect EOD.
235  *
236  * In the definition of sgetc, the first alternative should read
237  *      (int)(*++((s)->srptr))
238  * but the Borland compiler generates truly atrocious code for this.
239  * The SCO ODT compiler requires the first, pointless cast to int.
240  */
241 #define sgetc(s)\
242   ((int)((s)->srlimit - (s)->srptr > 1 ? (++((s)->srptr), (int)*(s)->srptr) : spgetc(s)))
243 int sgets(stream *, byte *, uint, uint *);
244 int sungetc(stream *, byte);	/* ERRC on error, 0 if OK */
245 
246 #define sputback(s) ((s)->srptr--)	/* can only do this once! */
247 #define seofp(s) (sendrp(s) && (s)->end_status == EOFC)
248 #define serrorp(s) (sendrp(s) && (s)->end_status == ERRC)
249 int spskip(stream *, long, long *);
250 
251 #define sskip(s,nskip,pskipped) spskip(s, (long)(nskip), pskipped)
252 /*
253  * Attempt to refill the buffer of a read stream.
254  * Only call this if the end_status is not EOFC,
255  * and if the buffer is (nearly) empty.
256  */
257 int s_process_read_buf(stream *);
258 
259 /*
260  * Following are only valid for write streams.
261  */
262 int spputc(stream *, byte);	/* a procedure equivalent of sputc */
263 
264 /*
265  * The first alternative should read
266  *      ((int)(*++((s)->swptr)=(c)))
267  * but the Borland compiler generates truly atrocious code for this.
268  */
269 #define sputc(s,c)\
270   (!sendwp(s) ? (++((s)->swptr), *(s)->swptr=(c), 0) : spputc((s),(c)))
271 int sputs(stream *, const byte *, uint, uint *);
272 
273 /*
274  * Attempt to empty the buffer of a write stream.
275  * Only call this if the end_status is not EOFC.
276  */
277 int s_process_write_buf(stream *, bool);
278 
279 /* Following are only valid for positionable streams. */
280 long stell(stream *);
281 int spseek(stream *, long);
282 
283 #define sseek(s,pos) spseek(s, (long)(pos))
284 
285 /* Following are for high-performance reading clients. */
286 /* bufptr points to the next item. */
287 #define sbufptr(s) ((s)->srptr + 1)
288 #define sbufavailable(s) ((s)->srlimit - (s)->srptr)
289 #define sbufskip(s, n) ((s)->srptr += (n), 0)
290 /*
291  * Define the minimum amount of data that must be left in an input buffer
292  * after a read operation to handle filter read-ahead, either 0 or 1
293  * byte(s).
294  */
295 #define max_min_left 1
296 /*
297  * The stream.state min_left value is the minimum amount of data that must
298  * be left in an input buffer after a read operation to handle filter
299  * read-ahead. Once filters reach EOD, return 0 since read-ahead is
300  * no longer relevant.
301  */
302 #define sbuf_min_left(s) \
303       ((s->end_status == EOFC || s->end_status == ERRC ? 0 : s->state->min_left))
304 
305 /* The following are for very high-performance clients of read streams, */
306 /* who unpack the stream state into local variables. */
307 /* Note that any non-inline operations must do a s_end_inline before, */
308 /* and a s_begin_inline after. */
309 #define s_declare_inline(s, cp, ep)\
310   register const byte *cp;\
311   const byte *ep
312 #define s_begin_inline(s, cp, ep)\
313   cp = (s)->srptr, ep = (s)->srlimit
314 #define s_end_inline(s, cp, ep)\
315   (s)->srptr = cp
316 #define sbufavailable_inline(s, cp, ep)\
317   (ep - cp)
318 #define sendbufp_inline(s, cp, ep)\
319   (cp >= ep)
320 /* The (int) is needed to pacify the SCO ODT compiler. */
321 #define sgetc_inline(s, cp, ep)\
322   ((int)(sendbufp_inline(s, cp, ep) ? spgetc_inline(s, cp, ep) : *++cp))
323 #define spgetc_inline(s, cp, ep)\
324   (s_end_inline(s, cp, ep), (s)->inline_temp = spgetc(s),\
325    s_begin_inline(s, cp, ep), (s)->inline_temp)
326 #define sputback_inline(s, cp, ep)\
327   --cp
328 
329 /* Allocate a stream or a stream state. */
330 stream *s_alloc(gs_memory_t *, client_name_t);
331 stream_state *s_alloc_state(gs_memory_t *, gs_memory_type_ptr_t, client_name_t);
332 /*
333  * Initialize a separately allocated stream or stream state, as if allocated
334  * by s_alloc[_state].
335  */
336 void s_init(stream *, gs_memory_t *);
337 void s_init_state(stream_state *, const stream_template *, gs_memory_t *);
338 
339 /* Create a stream on a string or a file. */
340 void sread_string(stream *, const byte *, uint),
341     sread_string_reusable(stream *, const byte *, uint),
342     swrite_string(stream *, byte *, uint);
343 void sread_file(stream *, FILE *, byte *, uint),
344     swrite_file(stream *, FILE *, byte *, uint),
345     sappend_file(stream *, FILE *, byte *, uint);
346 
347 /* Confine reading to a subfile.  This is primarily for reusable streams. */
348 int sread_subfile(stream *s, long start, long length);
349 
350 /* Set the file name of a stream, copying the name. */
351 /* Return <0 if the copy could not be allocated. */
352 int ssetfilename(stream *, const byte *, uint);
353 
354 /* Return the file name of a stream, if any. */
355 /* There is a guaranteed 0 byte after the string. */
356 int sfilename(stream *, gs_const_string *);
357 
358 /* Create a stream that tracks the position, */
359 /* for calculating how much space to allocate when actually writing. */
360 void swrite_position_only(stream *);
361 
362 /* Standard stream initialization */
363 void s_std_init(stream *, byte *, uint, const stream_procs *, int /*mode */ );
364 
365 /* Standard stream finalization */
366 void s_disable(stream *);
367 
368 /* Generic stream procedures exported for templates */
369 int s_std_null(stream *);
370 void s_std_read_reset(stream *), s_std_write_reset(stream *);
371 int s_std_read_flush(stream *), s_std_write_flush(stream *), s_std_noavailable(stream *, long *),
372      s_std_noseek(stream *, long), s_std_close(stream *), s_std_switch_mode(stream *, bool);
373 
374 /* Generic procedures for filters. */
375 int s_filter_write_flush(stream *), s_filter_close(stream *);
376 
377 /* Generic procedure structures for filters. */
378 extern const stream_procs s_filter_read_procs, s_filter_write_procs;
379 
380 /*
381  * Add a filter to an output pipeline.  The client must have allocated the
382  * stream state, if any, using the given allocator.  For s_init_filter, the
383  * client must have called s_init and s_init_state.
384  *
385  * Note that if additional buffering is needed, s_add_filter may add
386  * an additional filter to provide it.
387  */
388 int s_init_filter(stream *fs, stream_state *fss, byte *buf, uint bsize,
389 		  stream *target);
390 stream *s_add_filter(stream **ps, const stream_template *template,
391 		     stream_state *ss, gs_memory_t *mem);
392 
393 /*
394  * Close the filters in a pipeline, up to a given target stream, freeing
395  * their buffers and state structures.
396  */
397 int s_close_filters(stream **ps, stream *target);
398 
399 /* Define templates for the NullEncode/Decode filters. */
400 /* They have no state. */
401 extern const stream_template s_NullE_template;
402 extern const stream_template s_NullD_template;
403 
404 #endif /* stream_INCLUDED */
405