xref: /plan9/sys/src/cmd/gs/src/zfileio.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 2000, 2001 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: zfileio.c,v 1.18 2005/08/30 23:19:01 ray Exp $ */
18 /* File I/O operators */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "gp.h"
22 #include "oper.h"
23 #include "stream.h"
24 #include "files.h"
25 #include "store.h"
26 #include "strimpl.h"		/* for ifilter.h */
27 #include "ifilter.h"		/* for procedure streams */
28 #include "interp.h"		/* for gs_errorinfo_put_string */
29 #include "gsmatrix.h"		/* for gxdevice.h */
30 #include "gxdevice.h"
31 #include "gxdevmem.h"
32 #include "estack.h"
33 
34 /* Forward references */
35 private int write_string(ref *, stream *);
36 private int handle_read_status(i_ctx_t *, int, const ref *, const uint *,
37 			       op_proc_t);
38 private int handle_write_status(i_ctx_t *, int, const ref *, const uint *,
39 				op_proc_t);
40 
41 /* ------ Operators ------ */
42 
43 /* <file> closefile - */
44 int
zclosefile(i_ctx_t * i_ctx_p)45 zclosefile(i_ctx_t *i_ctx_p)
46 {
47     os_ptr op = osp;
48     stream *s;
49 
50     check_type(*op, t_file);
51     if (file_is_valid(s, op)) {	/* closing a closed file is a no-op */
52 	int status = sclose(s);
53 
54 	if (status != 0 && status != EOFC) {
55 	    if (s_is_writing(s))
56 		return handle_write_status(i_ctx_p, status, op, NULL,
57 					   zclosefile);
58 	    else
59 		return handle_read_status(i_ctx_p, status, op, NULL,
60 					  zclosefile);
61 	}
62     }
63     pop(1);
64     return 0;
65 }
66 
67 /* <file> read <int> -true- */
68 /* <file> read -false- */
69 private int
zread(i_ctx_t * i_ctx_p)70 zread(i_ctx_t *i_ctx_p)
71 {
72     os_ptr op = osp;
73     stream *s;
74     int ch;
75 
76     check_read_file(s, op);
77     /* We 'push' first in case of ostack block overflow and the */
78     /* usual case is we will need to push anyway. If we get EOF */
79     /* we will need to 'pop' and decrement the 'op' pointer.    */
80     /* This is required since the 'push' macro might return with*/
81     /* stackoverflow which will result in another stack block   */
82     /* added on, then the operator being retried. We can't read */
83     /* (sgetc) prior to having a place on the ostack to return  */
84     /* the character.						*/
85     push(1);
86     ch = sgetc(s);
87     if (ch >= 0) {
88 	make_int(op - 1, ch);
89 	make_bool(op, 1);
90     } else {
91 	pop(1);		/* Adjust ostack back from preparatory 'pop' */
92 	op--;
93 	if (ch == EOFC)
94 	make_bool(op, 0);
95     else
96 	return handle_read_status(i_ctx_p, ch, op, NULL, zread);
97     }
98     return 0;
99 }
100 
101 /* <file> <int> write - */
102 int
zwrite(i_ctx_t * i_ctx_p)103 zwrite(i_ctx_t *i_ctx_p)
104 {
105     os_ptr op = osp;
106     stream *s;
107     byte ch;
108     int status;
109 
110     check_write_file(s, op - 1);
111     check_type(*op, t_integer);
112     ch = (byte) op->value.intval;
113     status = sputc(s, (byte) ch);
114     if (status >= 0) {
115 	pop(2);
116 	return 0;
117     }
118     return handle_write_status(i_ctx_p, status, op - 1, NULL, zwrite);
119 }
120 
121 /* <file> <string> readhexstring <substring> <filled_bool> */
122 private int zreadhexstring_continue(i_ctx_t *);
123 
124 /* We keep track of the odd digit in the next byte of the string */
125 /* beyond the bytes already used.  (This is just for convenience; */
126 /* we could do the same thing by passing 2 state parameters to the */
127 /* continuation procedure instead of 1.) */
128 private int
zreadhexstring_at(i_ctx_t * i_ctx_p,os_ptr op,uint start)129 zreadhexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start)
130 {
131     stream *s;
132     uint len, nread;
133     byte *str;
134     int odd;
135     stream_cursor_write cw;
136     int status;
137 
138     check_read_file(s, op - 1);
139     /*check_write_type(*op, t_string); *//* done by caller */
140     str = op->value.bytes;
141     len = r_size(op);
142     if (start < len) {
143 	odd = str[start];
144 	if (odd > 0xf)
145 	    odd = -1;
146     } else
147 	odd = -1;
148     cw.ptr = str + start - 1;
149     cw.limit = str + len - 1;
150     for (;;) {
151 	status = s_hex_process(&s->cursor.r, &cw, &odd,
152 			       hex_ignore_garbage);
153 	if (status == 1) {	/* filled the string */
154 	    ref_assign_inline(op - 1, op);
155 	    make_true(op);
156 	    return 0;
157 	} else if (status != 0)	/* error or EOF */
158 	    break;
159 	/* Didn't fill, keep going. */
160 	status = spgetc(s);
161 	if (status < 0)
162 	    break;
163 	sputback(s);
164     }
165     nread = cw.ptr + 1 - str;
166     if (status != EOFC) {	/* Error */
167 	if (nread < len)
168 	    str[nread] = (odd < 0 ? 0x10 : odd);
169 	return handle_read_status(i_ctx_p, status, op - 1, &nread,
170 				  zreadhexstring_continue);
171     }
172     /* Reached end-of-file before filling the string. */
173     /* Return an appropriate substring. */
174     ref_assign_inline(op - 1, op);
175     r_set_size(op - 1, nread);
176     make_false(op);
177     return 0;
178 }
179 private int
zreadhexstring(i_ctx_t * i_ctx_p)180 zreadhexstring(i_ctx_t *i_ctx_p)
181 {
182     os_ptr op = osp;
183 
184     check_write_type(*op, t_string);
185     if (r_size(op) > 0)
186 	*op->value.bytes = 0x10;
187     return zreadhexstring_at(i_ctx_p, op, 0);
188 }
189 /* Continue a readhexstring operation after a callout. */
190 /* *op is the index within the string. */
191 private int
zreadhexstring_continue(i_ctx_t * i_ctx_p)192 zreadhexstring_continue(i_ctx_t *i_ctx_p)
193 {
194     os_ptr op = osp;
195     int code;
196 
197     check_type(*op, t_integer);
198     if (op->value.intval < 0 || op->value.intval > r_size(op - 1))
199 	return_error(e_rangecheck);
200     check_write_type(op[-1], t_string);
201     code = zreadhexstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
202     if (code >= 0)
203 	pop(1);
204     return code;
205 }
206 
207 /* <file> <string> writehexstring - */
208 private int zwritehexstring_continue(i_ctx_t *);
209 private int
zwritehexstring_at(i_ctx_t * i_ctx_p,os_ptr op,uint odd)210 zwritehexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint odd)
211 {
212     register stream *s;
213     register byte ch;
214     register const byte *p;
215     register const char *const hex_digits = "0123456789abcdef";
216     register uint len;
217     int status;
218 
219 #define MAX_HEX 128
220     byte buf[MAX_HEX];
221 
222     check_write_file(s, op - 1);
223     check_read_type(*op, t_string);
224     p = op->value.bytes;
225     len = r_size(op);
226     while (len) {
227 	uint len1 = min(len, MAX_HEX / 2);
228 	register byte *q = buf;
229 	uint count = len1;
230 	ref rbuf;
231 
232 	do {
233 	    ch = *p++;
234 	    *q++ = hex_digits[ch >> 4];
235 	    *q++ = hex_digits[ch & 0xf];
236 	}
237 	while (--count);
238 	r_set_size(&rbuf, (len1 << 1) - odd);
239 	rbuf.value.bytes = buf + odd;
240 	status = write_string(&rbuf, s);
241 	switch (status) {
242 	    default:
243 		return_error(e_ioerror);
244 	    case 0:
245 		len -= len1;
246 		odd = 0;
247 		continue;
248 	    case INTC:
249 	    case CALLC:
250 		count = rbuf.value.bytes - buf;
251 		op->value.bytes += count >> 1;
252 		r_set_size(op, len - (count >> 1));
253 		count &= 1;
254 		return handle_write_status(i_ctx_p, status, op - 1, &count,
255 					   zwritehexstring_continue);
256 	}
257     }
258     pop(2);
259     return 0;
260 #undef MAX_HEX
261 }
262 private int
zwritehexstring(i_ctx_t * i_ctx_p)263 zwritehexstring(i_ctx_t *i_ctx_p)
264 {
265     os_ptr op = osp;
266 
267     return zwritehexstring_at(i_ctx_p, op, 0);
268 }
269 /* Continue a writehexstring operation after a callout. */
270 /* *op is the odd/even hex digit flag for the first byte. */
271 private int
zwritehexstring_continue(i_ctx_t * i_ctx_p)272 zwritehexstring_continue(i_ctx_t *i_ctx_p)
273 {
274     os_ptr op = osp;
275     int code;
276 
277     check_type(*op, t_integer);
278     if ((op->value.intval & ~1) != 0)
279 	return_error(e_rangecheck);
280     code = zwritehexstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
281     if (code >= 0)
282 	pop(1);
283     return code;
284 }
285 
286 /* <file> <string> readstring <substring> <filled_bool> */
287 private int zreadstring_continue(i_ctx_t *);
288 private int
zreadstring_at(i_ctx_t * i_ctx_p,os_ptr op,uint start)289 zreadstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start)
290 {
291     stream *s;
292     uint len, rlen;
293     int status;
294 
295     check_read_file(s, op - 1);
296     check_write_type(*op, t_string);
297     len = r_size(op);
298     status = sgets(s, op->value.bytes + start, len - start, &rlen);
299     rlen += start;
300     switch (status) {
301 	case EOFC:
302 	case 0:
303 	    break;
304 	default:
305 	    return handle_read_status(i_ctx_p, status, op - 1, &rlen,
306 				      zreadstring_continue);
307     }
308     /*
309      * The most recent Adobe specification says that readstring
310      * must signal a rangecheck if the string length is zero.
311      * I can't imagine the motivation for this, but we emulate it.
312      * It's safe to check it here, rather than earlier, because if
313      * len is zero, sgets will return 0 immediately with rlen = 0.
314      */
315     if (len == 0)
316 	return_error(e_rangecheck);
317     r_set_size(op, rlen);
318     op[-1] = *op;
319     make_bool(op, (rlen == len ? 1 : 0));
320     return 0;
321 }
322 private int
zreadstring(i_ctx_t * i_ctx_p)323 zreadstring(i_ctx_t *i_ctx_p)
324 {
325     os_ptr op = osp;
326 
327     return zreadstring_at(i_ctx_p, op, 0);
328 }
329 /* Continue a readstring operation after a callout. */
330 /* *op is the index within the string. */
331 private int
zreadstring_continue(i_ctx_t * i_ctx_p)332 zreadstring_continue(i_ctx_t *i_ctx_p)
333 {
334     os_ptr op = osp;
335     int code;
336 
337     check_type(*op, t_integer);
338     if (op->value.intval < 0 || op->value.intval > r_size(op - 1))
339 	return_error(e_rangecheck);
340     code = zreadstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
341     if (code >= 0)
342 	pop(1);
343     return code;
344 }
345 
346 /* <file> <string> writestring - */
347 private int
zwritestring(i_ctx_t * i_ctx_p)348 zwritestring(i_ctx_t *i_ctx_p)
349 {
350     os_ptr op = osp;
351     stream *s;
352     int status;
353 
354     check_write_file(s, op - 1);
355     check_read_type(*op, t_string);
356     status = write_string(op, s);
357     if (status >= 0) {
358 	pop(2);
359 	return 0;
360     }
361     return handle_write_status(i_ctx_p, status, op - 1, NULL, zwritestring);
362 }
363 
364 /* <file> <string> readline <substring> <bool> */
365 private int zreadline(i_ctx_t *);
366 private int zreadline_continue(i_ctx_t *);
367 
368 /*
369  * We could handle readline the same way as readstring,
370  * except for the anomalous situation where we get interrupted
371  * between the CR and the LF of an end-of-line marker.
372  * We hack around this in the following way: if we get interrupted
373  * before we've read any characters, we just restart the readline;
374  * if we get interrupted at any other time, we use readline_continue;
375  * we use start=0 (which we have just ruled out as a possible start value
376  * for readline_continue) to indicate interruption after the CR.
377  */
378 private int
zreadline_at(i_ctx_t * i_ctx_p,os_ptr op,uint count,bool in_eol)379 zreadline_at(i_ctx_t *i_ctx_p, os_ptr op, uint count, bool in_eol)
380 {
381     stream *s;
382     int status;
383     gs_string str;
384 
385     check_read_file(s, op - 1);
386     check_write_type(*op, t_string);
387     str.data = op->value.bytes;
388     str.size = r_size(op);
389     status = zreadline_from(s, &str, NULL, &count, &in_eol);
390     switch (status) {
391 	case 0:
392 	case EOFC:
393 	    break;
394 	case 1:
395 	    return_error(e_rangecheck);
396 	default:
397 	    if (count == 0 && !in_eol)
398 		return handle_read_status(i_ctx_p, status, op - 1, NULL,
399 					  zreadline);
400 	    else {
401 		if (in_eol) {
402 		    r_set_size(op, count);
403 		    count = 0;
404 		}
405 		return handle_read_status(i_ctx_p, status, op - 1, &count,
406 					  zreadline_continue);
407 	    }
408     }
409     r_set_size(op, count);
410     op[-1] = *op;
411     make_bool(op, status == 0);
412     return 0;
413 }
414 private int
zreadline(i_ctx_t * i_ctx_p)415 zreadline(i_ctx_t *i_ctx_p)
416 {
417     os_ptr op = osp;
418 
419     return zreadline_at(i_ctx_p, op, 0, false);
420 }
421 /* Continue a readline operation after a callout. */
422 /* *op is the index within the string, or 0 for an interrupt after a CR. */
423 private int
zreadline_continue(i_ctx_t * i_ctx_p)424 zreadline_continue(i_ctx_t *i_ctx_p)
425 {
426     os_ptr op = osp;
427     uint size = r_size(op - 1);
428     uint start;
429     int code;
430 
431     check_type(*op, t_integer);
432     if (op->value.intval < 0 || op->value.intval > size)
433 	return_error(e_rangecheck);
434     start = (uint) op->value.intval;
435     code = (start == 0 ? zreadline_at(i_ctx_p, op - 1, size, true) :
436 	    zreadline_at(i_ctx_p, op - 1, start, false));
437     if (code >= 0)
438 	pop(1);
439     return code;
440 }
441 
442 /* Internal readline routine. */
443 /* Returns a stream status value, or 1 if we overflowed the string. */
444 /* This is exported for %lineedit. */
445 int
zreadline_from(stream * s,gs_string * buf,gs_memory_t * bufmem,uint * pcount,bool * pin_eol)446 zreadline_from(stream *s, gs_string *buf, gs_memory_t *bufmem,
447 	       uint *pcount, bool *pin_eol)
448 {
449     sreadline_proc((*readline));
450 
451     if (zis_stdin(s))
452 	readline = gp_readline;
453     else
454 	readline = sreadline;
455     return readline(s, NULL, NULL /*WRONG*/, NULL, buf, bufmem,
456 		    pcount, pin_eol, zis_stdin);
457 }
458 
459 /* <file> bytesavailable <int> */
460 private int
zbytesavailable(i_ctx_t * i_ctx_p)461 zbytesavailable(i_ctx_t *i_ctx_p)
462 {
463     os_ptr op = osp;
464     stream *s;
465     long avail;
466 
467     check_read_file(s, op);
468     switch (savailable(s, &avail)) {
469 	default:
470 	    return_error(e_ioerror);
471 	case EOFC:
472 	    avail = -1;
473 	case 0:
474 	    ;
475     }
476     make_int(op, avail);
477     return 0;
478 }
479 
480 /* - flush - */
481 int
zflush(i_ctx_t * i_ctx_p)482 zflush(i_ctx_t *i_ctx_p)
483 {
484     stream *s;
485     int status;
486     ref rstdout;
487     int code = zget_stdout(i_ctx_p, &s);
488 
489     if (code < 0)
490 	return code;
491 
492     make_stream_file(&rstdout, s, "w");
493     status = sflush(s);
494     if (status == 0 || status == EOFC) {
495 	return 0;
496     }
497     return
498 	(s_is_writing(s) ?
499 	 handle_write_status(i_ctx_p, status, &rstdout, NULL, zflush) :
500 	 handle_read_status(i_ctx_p, status, &rstdout, NULL, zflush));
501 }
502 
503 /* <file> flushfile - */
504 private int
zflushfile(i_ctx_t * i_ctx_p)505 zflushfile(i_ctx_t *i_ctx_p)
506 {
507     os_ptr op = osp;
508     stream *s;
509     int status;
510 
511     check_type(*op, t_file);
512     /*
513      * We think flushfile is a no-op on closed input files, but causes an
514      * error on closed output files.
515      */
516     if (file_is_invalid(s, op)) {
517 	if (r_has_attr(op, a_write))
518 	    return_error(e_invalidaccess);
519 	pop(1);
520 	return 0;
521     }
522     status = sflush(s);
523     if (status == 0 || status == EOFC) {
524 	pop(1);
525 	return 0;
526     }
527     return
528 	(s_is_writing(s) ?
529 	 handle_write_status(i_ctx_p, status, op, NULL, zflushfile) :
530 	 handle_read_status(i_ctx_p, status, op, NULL, zflushfile));
531 }
532 
533 /* <file> resetfile - */
534 private int
zresetfile(i_ctx_t * i_ctx_p)535 zresetfile(i_ctx_t *i_ctx_p)
536 {
537     os_ptr op = osp;
538     stream *s;
539 
540     /* According to Adobe, resetfile is a no-op on closed files. */
541     check_type(*op, t_file);
542     if (file_is_valid(s, op))
543 	sreset(s);
544     pop(1);
545     return 0;
546 }
547 
548 /* <string> print - */
549 private int
zprint(i_ctx_t * i_ctx_p)550 zprint(i_ctx_t *i_ctx_p)
551 {
552     os_ptr op = osp;
553     stream *s;
554     int status;
555     ref rstdout;
556     int code;
557 
558     check_read_type(*op, t_string);
559     code = zget_stdout(i_ctx_p, &s);
560     if (code < 0)
561 	return code;
562     status = write_string(op, s);
563     if (status >= 0) {
564 	pop(1);
565 	return 0;
566     }
567     /* Convert print to writestring on the fly. */
568     make_stream_file(&rstdout, s, "w");
569     code = handle_write_status(i_ctx_p, status, &rstdout, NULL,
570 			       zwritestring);
571     if (code != o_push_estack)
572 	return code;
573     push(1);
574     *op = op[-1];
575     op[-1] = rstdout;
576     return code;
577 }
578 
579 /* <bool> echo - */
580 private int
zecho(i_ctx_t * i_ctx_p)581 zecho(i_ctx_t *i_ctx_p)
582 {
583     os_ptr op = osp;
584 
585     check_type(*op, t_boolean);
586     /****** NOT IMPLEMENTED YET ******/
587     pop(1);
588     return 0;
589 }
590 
591 /* ------ Level 2 extensions ------ */
592 
593 /* <file> fileposition <int> */
594 private int
zfileposition(i_ctx_t * i_ctx_p)595 zfileposition(i_ctx_t *i_ctx_p)
596 {
597     os_ptr op = osp;
598     stream *s;
599 
600     check_file(s, op);
601     /*
602      * The PLRM says fileposition must give an error for non-seekable
603      * streams.
604      */
605     if (!s_can_seek(s))
606 	return_error(e_ioerror);
607     make_int(op, stell(s));
608     return 0;
609 }
610 /* <file> .fileposition <int> */
611 private int
zxfileposition(i_ctx_t * i_ctx_p)612 zxfileposition(i_ctx_t *i_ctx_p)
613 {
614     os_ptr op = osp;
615     stream *s;
616 
617     check_file(s, op);
618     /*
619      * This version of fileposition doesn't give the error, so we can
620      * use it to get the position of string or procedure streams.
621      */
622     make_int(op, stell(s));
623     return 0;
624 }
625 
626 /* <file> <int> setfileposition - */
627 private int
zsetfileposition(i_ctx_t * i_ctx_p)628 zsetfileposition(i_ctx_t *i_ctx_p)
629 {
630     os_ptr op = osp;
631     stream *s;
632 
633     check_file(s, op - 1);
634     check_type(*op, t_integer);
635     if (sseek(s, op->value.intval) < 0)
636 	return_error(e_ioerror);
637     pop(2);
638     return 0;
639 }
640 
641 /* ------ Non-standard extensions ------ */
642 
643 /* <file> .filename <string> true */
644 /* <file> .filename false */
645 private int
zfilename(i_ctx_t * i_ctx_p)646 zfilename(i_ctx_t *i_ctx_p)
647 {
648     os_ptr op = osp;
649     stream *s;
650     gs_const_string fname;
651     byte *str;
652 
653     check_file(s, op);
654     if (sfilename(s, &fname) < 0) {
655 	make_false(op);
656 	return 0;
657     }
658     check_ostack(1);
659     str = ialloc_string(fname.size, "filename");
660     if (str == 0)
661 	return_error(e_VMerror);
662     memcpy(str, fname.data, fname.size);
663     push(1);			/* can't fail */
664     make_const_string( op - 1 ,
665 		      a_all | imemory_space((const struct gs_ref_memory_s*) imemory),
666 		      fname.size,
667 		      str);
668     make_true(op);
669     return 0;
670 }
671 
672 /* <file> .isprocfilter <bool> */
673 private int
zisprocfilter(i_ctx_t * i_ctx_p)674 zisprocfilter(i_ctx_t *i_ctx_p)
675 {
676     os_ptr op = osp;
677     stream *s;
678 
679     check_file(s, op);
680     while (s->strm != 0)
681 	s = s->strm;
682     make_bool(op, s_is_proc(s));
683     return 0;
684 }
685 
686 /* <file> <string> .peekstring <substring> <filled_bool> */
687 private int
zpeekstring(i_ctx_t * i_ctx_p)688 zpeekstring(i_ctx_t *i_ctx_p)
689 {
690     os_ptr op = osp;
691     stream *s;
692     uint len, rlen;
693 
694     check_read_file(s, op - 1);
695     check_write_type(*op, t_string);
696     len = r_size(op);
697     while ((rlen = sbufavailable(s)) < len) {
698 	int status = s->end_status;
699 
700 	switch (status) {
701 	case EOFC:
702 	    break;
703 	case 0:
704 	    /*
705 	     * The following is a HACK.  It should reallocate the buffer to hold
706 	     * at least len bytes.  However, this raises messy problems about
707 	     * which allocator to use and how it should interact with restore.
708 	     */
709 	    if (len >= s->bsize)
710 		return_error(e_rangecheck);
711 	    s_process_read_buf(s);
712 	    continue;
713 	default:
714 	    return handle_read_status(i_ctx_p, status, op - 1, NULL,
715 				      zpeekstring);
716 	}
717 	break;
718     }
719     if (rlen > len)
720 	rlen = len;
721     /* Don't remove the data from the buffer. */
722     memcpy(op->value.bytes, sbufptr(s), rlen);
723     r_set_size(op, rlen);
724     op[-1] = *op;
725     make_bool(op, (rlen == len ? 1 : 0));
726     return 0;
727 }
728 
729 /* <file> <int> .unread - */
730 private int
zunread(i_ctx_t * i_ctx_p)731 zunread(i_ctx_t *i_ctx_p)
732 {
733     os_ptr op = osp;
734     stream *s;
735     ulong ch;
736 
737     check_read_file(s, op - 1);
738     check_type(*op, t_integer);
739     ch = op->value.intval;
740     if (ch > 0xff)
741 	return_error(e_rangecheck);
742     if (sungetc(s, (byte) ch) < 0)
743 	return_error(e_ioerror);
744     pop(2);
745     return 0;
746 }
747 
748 /* <file> <obj> <==flag> .writecvp - */
749 private int zwritecvp_continue(i_ctx_t *);
750 private int
zwritecvp_at(i_ctx_t * i_ctx_p,os_ptr op,uint start,bool first)751 zwritecvp_at(i_ctx_t *i_ctx_p, os_ptr op, uint start, bool first)
752 {
753     stream *s;
754     byte str[100];		/* arbitrary */
755     ref rstr;
756     const byte *data = str;
757     uint len;
758     int code, status;
759 
760     check_write_file(s, op - 2);
761     check_type(*op, t_integer);
762     code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval,
763 		   start, imemory);
764     if (code == e_rangecheck) {
765         code = obj_string_data(imemory, op - 1, &data, &len);
766 	if (len < start)
767 	    return_error(e_rangecheck);
768 	data += start;
769 	len -= start;
770     }
771     if (code < 0)
772 	return code;
773     r_set_size(&rstr, len);
774     rstr.value.const_bytes = data;
775     status = write_string(&rstr, s);
776     switch (status) {
777 	default:
778 	    return_error(e_ioerror);
779 	case 0:
780 	    break;
781 	case INTC:
782 	case CALLC:
783 	    len = start + len - r_size(&rstr);
784 	    if (!first)
785 		--osp;		/* pop(1) without affecting op */
786 	    return handle_write_status(i_ctx_p, status, op - 2, &len,
787 				       zwritecvp_continue);
788     }
789     if (code == 1) {
790 	if (first)
791 	    check_ostack(1);
792 	push_op_estack(zwritecvp_continue);
793 	if (first)
794 	    push(1);
795 	make_int(osp, start + len);
796 	return o_push_estack;
797     }
798     if (first)			/* zwritecvp */
799 	pop(3);
800     else			/* zwritecvp_continue */
801 	pop(4);
802     return 0;
803 }
804 private int
zwritecvp(i_ctx_t * i_ctx_p)805 zwritecvp(i_ctx_t *i_ctx_p)
806 {
807     return zwritecvp_at(i_ctx_p, osp, 0, true);
808 }
809 /* Continue a .writecvp after a callout. */
810 /* *op is the index within the string. */
811 private int
zwritecvp_continue(i_ctx_t * i_ctx_p)812 zwritecvp_continue(i_ctx_t *i_ctx_p)
813 {
814     os_ptr op = osp;
815 
816     check_type(*op, t_integer);
817     if (op->value.intval != (uint) op->value.intval)
818 	return_error(e_rangecheck);
819     return zwritecvp_at(i_ctx_p, op - 1, (uint) op->value.intval, false);
820 }
821 
822 /* Callout for stdin */
823 /* - .needstdin - */
824 int
zneedstdin(i_ctx_t * i_ctx_p)825 zneedstdin(i_ctx_t *i_ctx_p)
826 {
827     return e_NeedStdin;		/* Interpreter will exit to caller. */
828 }
829 
830 /* Callout for stdout */
831 /* - .needstdout - */
832 int
zneedstdout(i_ctx_t * i_ctx_p)833 zneedstdout(i_ctx_t *i_ctx_p)
834 {
835     return e_NeedStdout;	/* Interpreter will exit to caller. */
836 }
837 
838 /* Callout for stderr */
839 /* - .needstderr - */
840 int
zneedstderr(i_ctx_t * i_ctx_p)841 zneedstderr(i_ctx_t *i_ctx_p)
842 {
843     return e_NeedStderr;	/* Interpreter will exit to caller. */
844 }
845 
846 
847 
848 /* ------ Initialization procedure ------ */
849 
850 /* We need to split the table because of the 16-element limit. */
851 const op_def zfileio1_op_defs[] = {
852     {"1bytesavailable", zbytesavailable},
853     {"1closefile", zclosefile},
854 		/* currentfile is in zcontrol.c */
855     {"1echo", zecho},
856     {"1.filename", zfilename},
857     {"1.fileposition", zxfileposition},
858     {"1fileposition", zfileposition},
859     {"0flush", zflush},
860     {"1flushfile", zflushfile},
861     {"1.isprocfilter", zisprocfilter},
862     {"2.peekstring", zpeekstring},
863     {"1print", zprint},
864     {"1read", zread},
865     {"2readhexstring", zreadhexstring},
866     {"2readline", zreadline},
867     {"2readstring", zreadstring},
868     op_def_end(0)
869 };
870 const op_def zfileio2_op_defs[] = {
871     {"1resetfile", zresetfile},
872     {"2setfileposition", zsetfileposition},
873     {"2.unread", zunread},
874     {"2write", zwrite},
875     {"3.writecvp", zwritecvp},
876     {"2writehexstring", zwritehexstring},
877     {"2writestring", zwritestring},
878 		/* Internal operators */
879     {"3%zreadhexstring_continue", zreadhexstring_continue},
880     {"3%zreadline_continue", zreadline_continue},
881     {"3%zreadstring_continue", zreadstring_continue},
882     {"4%zwritecvp_continue", zwritecvp_continue},
883     {"3%zwritehexstring_continue", zwritehexstring_continue},
884     {"0.needstdin", zneedstdin},
885     {"0.needstdout", zneedstdout},
886     {"0.needstderr", zneedstderr},
887     op_def_end(0)
888 };
889 
890 /* ------ Non-operator routines ------ */
891 
892 /* Switch a file open for read/write access but currently in write mode */
893 /* to read mode. */
894 int
file_switch_to_read(const ref * op)895 file_switch_to_read(const ref * op)
896 {
897     stream *s = fptr(op);
898 
899     if (s->write_id != r_size(op) || s->file == 0)	/* not valid */
900 	return_error(e_invalidaccess);
901     if (sswitch(s, false) < 0)
902 	return_error(e_ioerror);
903     s->read_id = s->write_id;	/* enable reading */
904     s->write_id = 0;		/* disable writing */
905     return 0;
906 }
907 
908 /* Switch a file open for read/write access but currently in read mode */
909 /* to write mode. */
910 int
file_switch_to_write(const ref * op)911 file_switch_to_write(const ref * op)
912 {
913     stream *s = fptr(op);
914 
915     if (s->read_id != r_size(op) || s->file == 0)	/* not valid */
916 	return_error(e_invalidaccess);
917     if (sswitch(s, true) < 0)
918 	return_error(e_ioerror);
919     s->write_id = s->read_id;	/* enable writing */
920     s->read_id = 0;		/* disable reading */
921     return 0;
922 }
923 
924 /* ------ Internal routines ------ */
925 
926 /* Write a string on a file.  The file and string have been validated. */
927 /* If the status is INTC or CALLC, updates the string on the o-stack. */
928 private int
write_string(ref * op,stream * s)929 write_string(ref * op, stream * s)
930 {
931     const byte *data = op->value.const_bytes;
932     uint len = r_size(op);
933     uint wlen;
934     int status = sputs(s, data, len, &wlen);
935 
936     switch (status) {
937 	case INTC:
938 	case CALLC:
939 	    op->value.const_bytes = data + wlen;
940 	    r_set_size(op, len - wlen);
941 	    /* falls through */
942 	default:		/* 0, EOFC, ERRC */
943 	    return status;
944     }
945 }
946 
947 /*
948  * Look for a stream error message that needs to be copied to
949  * $error.errorinfo, if any.
950  */
951 private int
copy_error_string(i_ctx_t * i_ctx_p,const ref * fop)952 copy_error_string(i_ctx_t *i_ctx_p, const ref *fop)
953 {
954     stream *s;
955 
956     for (s = fptr(fop); s->strm != 0 && s->state->error_string[0] == 0;)
957 	s = s->strm;
958     if (s->state->error_string[0]) {
959 	int code = gs_errorinfo_put_string(i_ctx_p, s->state->error_string);
960 
961 	if (code < 0)
962 	    return code;
963 	s->state->error_string[0] = 0; /* just do it once */
964     }
965     return_error(e_ioerror);
966 }
967 
968 /* Handle an exceptional status return from a read stream. */
969 /* fop points to the ref for the stream. */
970 /* ch may be any stream exceptional value. */
971 /* Return 0, 1 (EOF), o_push_estack, or an error. */
972 private int
handle_read_status(i_ctx_t * i_ctx_p,int ch,const ref * fop,const uint * pindex,op_proc_t cont)973 handle_read_status(i_ctx_t *i_ctx_p, int ch, const ref * fop,
974 		   const uint * pindex, op_proc_t cont)
975 {
976     switch (ch) {
977 	default:		/* error */
978 	    return copy_error_string(i_ctx_p, fop);
979 	case EOFC:
980 	    return 1;
981 	case INTC:
982 	case CALLC:
983 	    if (pindex) {
984 		ref index;
985 
986 		make_int(&index, *pindex);
987 		return s_handle_read_exception(i_ctx_p, ch, fop, &index, 1,
988 					       cont);
989 	    } else
990 		return s_handle_read_exception(i_ctx_p, ch, fop, NULL, 0,
991 					       cont);
992     }
993 }
994 
995 /* Handle an exceptional status return from a write stream. */
996 /* fop points to the ref for the stream. */
997 /* ch may be any stream exceptional value. */
998 /* Return 0, 1 (EOF), o_push_estack, or an error. */
999 private int
handle_write_status(i_ctx_t * i_ctx_p,int ch,const ref * fop,const uint * pindex,op_proc_t cont)1000 handle_write_status(i_ctx_t *i_ctx_p, int ch, const ref * fop,
1001 		    const uint * pindex, op_proc_t cont)
1002 {
1003     switch (ch) {
1004 	default:		/* error */
1005 	    return copy_error_string(i_ctx_p, fop);
1006 	case EOFC:
1007 	    return 1;
1008 	case INTC:
1009 	case CALLC:
1010 	    if (pindex) {
1011 		ref index;
1012 
1013 		make_int(&index, *pindex);
1014 		return s_handle_write_exception(i_ctx_p, ch, fop, &index, 1,
1015 						cont);
1016 	    } else
1017 		return s_handle_write_exception(i_ctx_p, ch, fop, NULL, 0,
1018 						cont);
1019     }
1020 }
1021