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