xref: /plan9-contrib/sys/src/cmd/gs/src/ziodevs.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 2000 Aladdin Enterprises.  All rights reserved.
23ff48bf5SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
53ff48bf5SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: ziodevs.c,v 1.9 2004/08/04 19:36:13 stefan Exp $ */
183ff48bf5SDavid du Colombier /* %stdxxx IODevice implementation for PostScript interpreter */
193ff48bf5SDavid du Colombier #include "stdio_.h"
203ff48bf5SDavid du Colombier #include "ghost.h"
213ff48bf5SDavid du Colombier #include "gp.h"
223ff48bf5SDavid du Colombier #include "gpcheck.h"
233ff48bf5SDavid du Colombier #include "oper.h"
243ff48bf5SDavid du Colombier #include "stream.h"
253ff48bf5SDavid du Colombier #include "gxiodev.h"		/* must come after stream.h */
263ff48bf5SDavid du Colombier 				/* and before files.h */
273ff48bf5SDavid du Colombier #include "files.h"
283ff48bf5SDavid du Colombier #include "store.h"
293ff48bf5SDavid du Colombier 
303ff48bf5SDavid du Colombier /* Define the special devices. */
313ff48bf5SDavid du Colombier const char iodev_dtype_stdio[] = "Special";
323ff48bf5SDavid du Colombier #define iodev_special(dname, init, open) {\
333ff48bf5SDavid du Colombier     dname, iodev_dtype_stdio,\
343ff48bf5SDavid du Colombier 	{ init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,\
353ff48bf5SDavid du Colombier 	  iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,\
363ff48bf5SDavid du Colombier 	  iodev_no_enumerate_files, NULL, NULL,\
373ff48bf5SDavid du Colombier 	  iodev_no_get_params, iodev_no_put_params\
383ff48bf5SDavid du Colombier 	}\
393ff48bf5SDavid du Colombier }
403ff48bf5SDavid du Colombier 
413ff48bf5SDavid du Colombier /*
423ff48bf5SDavid du Colombier  * We need the current context pointer for accessing / opening the %std
433ff48bf5SDavid du Colombier  * IODevices.  However, this is not available to the open routine.
443ff48bf5SDavid du Colombier  * Therefore, we use the hack of storing this pointer in the IODevice state
453ff48bf5SDavid du Colombier  * pointer just before calling the open routines.  We clear the pointer
463ff48bf5SDavid du Colombier  * immediately afterwards so as not to wind up with dangling references.
473ff48bf5SDavid du Colombier  */
483ff48bf5SDavid du Colombier 
493ff48bf5SDavid du Colombier #define STDIN_BUF_SIZE 128
50*593dc095SDavid du Colombier 
513ff48bf5SDavid du Colombier private iodev_proc_init(stdin_init);
523ff48bf5SDavid du Colombier private iodev_proc_open_device(stdin_open);
533ff48bf5SDavid du Colombier const gx_io_device gs_iodev_stdin =
543ff48bf5SDavid du Colombier     iodev_special("%stdin%", stdin_init, stdin_open);
553ff48bf5SDavid du Colombier 
563ff48bf5SDavid du Colombier #define STDOUT_BUF_SIZE 128
573ff48bf5SDavid du Colombier private iodev_proc_open_device(stdout_open);
583ff48bf5SDavid du Colombier const gx_io_device gs_iodev_stdout =
593ff48bf5SDavid du Colombier     iodev_special("%stdout%", iodev_no_init, stdout_open);
603ff48bf5SDavid du Colombier 
613ff48bf5SDavid du Colombier #define STDERR_BUF_SIZE 128
623ff48bf5SDavid du Colombier private iodev_proc_open_device(stderr_open);
633ff48bf5SDavid du Colombier const gx_io_device gs_iodev_stderr =
643ff48bf5SDavid du Colombier     iodev_special("%stderr%", iodev_no_init, stderr_open);
653ff48bf5SDavid du Colombier 
663ff48bf5SDavid du Colombier /* ------- %stdin, %stdout, and %stderr ------ */
673ff48bf5SDavid du Colombier 
683ff48bf5SDavid du Colombier /*
693ff48bf5SDavid du Colombier  * According to Adobe, it is legal to close the %std... files and then
703ff48bf5SDavid du Colombier  * re-open them later.  However, the re-opened file object is not 'eq' to
713ff48bf5SDavid du Colombier  * the original file object (in our implementation, it has a different
723ff48bf5SDavid du Colombier  * read_id or write_id).
733ff48bf5SDavid du Colombier  */
743ff48bf5SDavid du Colombier 
753ff48bf5SDavid du Colombier private int
76*593dc095SDavid du Colombier     s_stdin_read_process(stream_state *, stream_cursor_read *,
77*593dc095SDavid du Colombier 			 stream_cursor_write *, bool);
783ff48bf5SDavid du Colombier 
793ff48bf5SDavid du Colombier private int
stdin_init(gx_io_device * iodev,gs_memory_t * mem)803ff48bf5SDavid du Colombier stdin_init(gx_io_device * iodev, gs_memory_t * mem)
813ff48bf5SDavid du Colombier {
82*593dc095SDavid du Colombier     mem->gs_lib_ctx->stdin_is_interactive = true;
833ff48bf5SDavid du Colombier     return 0;
843ff48bf5SDavid du Colombier }
853ff48bf5SDavid du Colombier 
863ff48bf5SDavid du Colombier /* Read from stdin into the buffer. */
873ff48bf5SDavid du Colombier /* If interactive, only read one character. */
883ff48bf5SDavid du Colombier private int
s_stdin_read_process(stream_state * st,stream_cursor_read * ignore_pr,stream_cursor_write * pw,bool last)893ff48bf5SDavid du Colombier s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
903ff48bf5SDavid du Colombier 		     stream_cursor_write * pw, bool last)
913ff48bf5SDavid du Colombier {
923ff48bf5SDavid du Colombier     FILE *file = ((stream *) st)->file;		/* hack for file streams */
933ff48bf5SDavid du Colombier     int wcount = (int)(pw->limit - pw->ptr);
943ff48bf5SDavid du Colombier     int count;
953ff48bf5SDavid du Colombier 
963ff48bf5SDavid du Colombier     if (wcount <= 0)
973ff48bf5SDavid du Colombier 	return 0;
983ff48bf5SDavid du Colombier     count = gp_stdin_read( (char*) pw->ptr + 1, wcount,
99*593dc095SDavid du Colombier 			   st->memory->gs_lib_ctx->stdin_is_interactive, file);
1003ff48bf5SDavid du Colombier     pw->ptr += (count < 0) ? 0 : count;
1013ff48bf5SDavid du Colombier     return ((count < 0) ? ERRC : (count == 0) ? EOFC : count);
1023ff48bf5SDavid du Colombier }
1033ff48bf5SDavid du Colombier 
1043ff48bf5SDavid du Colombier private int
stdin_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)1053ff48bf5SDavid du Colombier stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
1063ff48bf5SDavid du Colombier 	   gs_memory_t * mem)
1073ff48bf5SDavid du Colombier {
1083ff48bf5SDavid du Colombier     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
1093ff48bf5SDavid du Colombier     stream *s;
1103ff48bf5SDavid du Colombier 
1113ff48bf5SDavid du Colombier     if (!streq1(access, 'r'))
1123ff48bf5SDavid du Colombier 	return_error(e_invalidfileaccess);
1133ff48bf5SDavid du Colombier     if (file_is_invalid(s, &ref_stdin)) {
1143ff48bf5SDavid du Colombier 	/****** stdin SHOULD NOT LINE-BUFFER ******/
1153ff48bf5SDavid du Colombier 	gs_memory_t *mem = imemory_system;
1163ff48bf5SDavid du Colombier 	byte *buf;
1173ff48bf5SDavid du Colombier 
1183ff48bf5SDavid du Colombier 	s = file_alloc_stream(mem, "stdin_open(stream)");
1193ff48bf5SDavid du Colombier 	/* We want stdin to read only one character at a time, */
1203ff48bf5SDavid du Colombier 	/* but it must have a substantial buffer, in case it is used */
1213ff48bf5SDavid du Colombier 	/* by a stream that requires more than one input byte */
1223ff48bf5SDavid du Colombier 	/* to make progress. */
1233ff48bf5SDavid du Colombier 	buf = gs_alloc_bytes(mem, STDIN_BUF_SIZE, "stdin_open(buffer)");
1243ff48bf5SDavid du Colombier 	if (s == 0 || buf == 0)
1253ff48bf5SDavid du Colombier 	    return_error(e_VMerror);
1263ff48bf5SDavid du Colombier 	sread_file(s, gs_stdin, buf, STDIN_BUF_SIZE);
1273ff48bf5SDavid du Colombier 	s->procs.process = s_stdin_read_process;
1283ff48bf5SDavid du Colombier 	s->save_close = s_std_null;
1293ff48bf5SDavid du Colombier 	s->procs.close = file_close_file;
1303ff48bf5SDavid du Colombier 	make_file(&ref_stdin, a_readonly | avm_system, s->read_id, s);
1313ff48bf5SDavid du Colombier 	*ps = s;
1323ff48bf5SDavid du Colombier 	return 1;
1333ff48bf5SDavid du Colombier     }
1343ff48bf5SDavid du Colombier     *ps = s;
1353ff48bf5SDavid du Colombier     return 0;
1363ff48bf5SDavid du Colombier }
1373ff48bf5SDavid du Colombier /* This is the public routine for getting the stdin stream. */
1383ff48bf5SDavid du Colombier int
zget_stdin(i_ctx_t * i_ctx_p,stream ** ps)1393ff48bf5SDavid du Colombier zget_stdin(i_ctx_t *i_ctx_p, stream ** ps)
1403ff48bf5SDavid du Colombier {
1413ff48bf5SDavid du Colombier     stream *s;
1423ff48bf5SDavid du Colombier     gx_io_device *iodev;
1433ff48bf5SDavid du Colombier     int code;
1443ff48bf5SDavid du Colombier 
1453ff48bf5SDavid du Colombier     if (file_is_valid(s, &ref_stdin)) {
1463ff48bf5SDavid du Colombier 	*ps = s;
1473ff48bf5SDavid du Colombier 	return 0;
1483ff48bf5SDavid du Colombier     }
1493ff48bf5SDavid du Colombier     iodev = gs_findiodevice((const byte *)"%stdin", 6);
1503ff48bf5SDavid du Colombier     iodev->state = i_ctx_p;
1513ff48bf5SDavid du Colombier     code = (*iodev->procs.open_device)(iodev, "r", ps, imemory_system);
1523ff48bf5SDavid du Colombier     iodev->state = NULL;
1533ff48bf5SDavid du Colombier     return min(code, 0);
1543ff48bf5SDavid du Colombier }
1553ff48bf5SDavid du Colombier /* Test whether a stream is stdin. */
1563ff48bf5SDavid du Colombier bool
zis_stdin(const stream * s)1573ff48bf5SDavid du Colombier zis_stdin(const stream *s)
1583ff48bf5SDavid du Colombier {
1593ff48bf5SDavid du Colombier     return (s_is_valid(s) && s->procs.process == s_stdin_read_process);
1603ff48bf5SDavid du Colombier }
1613ff48bf5SDavid du Colombier 
1623ff48bf5SDavid du Colombier private int
stdout_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)1633ff48bf5SDavid du Colombier stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
1643ff48bf5SDavid du Colombier 	    gs_memory_t * mem)
1653ff48bf5SDavid du Colombier {
1663ff48bf5SDavid du Colombier     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
1673ff48bf5SDavid du Colombier     stream *s;
1683ff48bf5SDavid du Colombier 
1693ff48bf5SDavid du Colombier     if (!streq1(access, 'w'))
1703ff48bf5SDavid du Colombier 	return_error(e_invalidfileaccess);
1713ff48bf5SDavid du Colombier     if (file_is_invalid(s, &ref_stdout)) {
1723ff48bf5SDavid du Colombier 	gs_memory_t *mem = imemory_system;
1733ff48bf5SDavid du Colombier 	byte *buf;
1743ff48bf5SDavid du Colombier 
1753ff48bf5SDavid du Colombier 	s = file_alloc_stream(mem, "stdout_open(stream)");
1763ff48bf5SDavid du Colombier 	buf = gs_alloc_bytes(mem, STDOUT_BUF_SIZE, "stdout_open(buffer)");
1773ff48bf5SDavid du Colombier 	if (s == 0 || buf == 0)
1783ff48bf5SDavid du Colombier 	    return_error(e_VMerror);
1793ff48bf5SDavid du Colombier 	swrite_file(s, gs_stdout, buf, STDOUT_BUF_SIZE);
1803ff48bf5SDavid du Colombier 	s->save_close = s->procs.flush;
1813ff48bf5SDavid du Colombier 	s->procs.close = file_close_file;
1823ff48bf5SDavid du Colombier 	make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
1833ff48bf5SDavid du Colombier 	*ps = s;
1843ff48bf5SDavid du Colombier 	return 1;
1853ff48bf5SDavid du Colombier     }
1863ff48bf5SDavid du Colombier     *ps = s;
1873ff48bf5SDavid du Colombier     return 0;
1883ff48bf5SDavid du Colombier }
1893ff48bf5SDavid du Colombier /* This is the public routine for getting the stdout stream. */
1903ff48bf5SDavid du Colombier int
zget_stdout(i_ctx_t * i_ctx_p,stream ** ps)1913ff48bf5SDavid du Colombier zget_stdout(i_ctx_t *i_ctx_p, stream ** ps)
1923ff48bf5SDavid du Colombier {
1933ff48bf5SDavid du Colombier     stream *s;
1943ff48bf5SDavid du Colombier     gx_io_device *iodev;
1953ff48bf5SDavid du Colombier     int code;
1963ff48bf5SDavid du Colombier 
1973ff48bf5SDavid du Colombier     if (file_is_valid(s, &ref_stdout)) {
1983ff48bf5SDavid du Colombier 	*ps = s;
1993ff48bf5SDavid du Colombier 	return 0;
2003ff48bf5SDavid du Colombier     }
2013ff48bf5SDavid du Colombier     iodev = gs_findiodevice((const byte *)"%stdout", 7);
2023ff48bf5SDavid du Colombier     iodev->state = i_ctx_p;
2033ff48bf5SDavid du Colombier     code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
2043ff48bf5SDavid du Colombier     iodev->state = NULL;
2053ff48bf5SDavid du Colombier     return min(code, 0);
2063ff48bf5SDavid du Colombier }
2073ff48bf5SDavid du Colombier 
2083ff48bf5SDavid du Colombier private int
stderr_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)2093ff48bf5SDavid du Colombier stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
2103ff48bf5SDavid du Colombier 	    gs_memory_t * mem)
2113ff48bf5SDavid du Colombier {
2123ff48bf5SDavid du Colombier     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
2133ff48bf5SDavid du Colombier     stream *s;
2143ff48bf5SDavid du Colombier 
2153ff48bf5SDavid du Colombier     if (!streq1(access, 'w'))
2163ff48bf5SDavid du Colombier 	return_error(e_invalidfileaccess);
2173ff48bf5SDavid du Colombier     if (file_is_invalid(s, &ref_stderr)) {
2183ff48bf5SDavid du Colombier 	gs_memory_t *mem = imemory_system;
2193ff48bf5SDavid du Colombier 	byte *buf;
2203ff48bf5SDavid du Colombier 
2213ff48bf5SDavid du Colombier 	s = file_alloc_stream(mem, "stderr_open(stream)");
2223ff48bf5SDavid du Colombier 	buf = gs_alloc_bytes(mem, STDERR_BUF_SIZE, "stderr_open(buffer)");
2233ff48bf5SDavid du Colombier 	if (s == 0 || buf == 0)
2243ff48bf5SDavid du Colombier 	    return_error(e_VMerror);
2253ff48bf5SDavid du Colombier 	swrite_file(s, gs_stderr, buf, STDERR_BUF_SIZE);
2263ff48bf5SDavid du Colombier 	s->save_close = s->procs.flush;
2273ff48bf5SDavid du Colombier 	s->procs.close = file_close_file;
2283ff48bf5SDavid du Colombier 	make_file(&ref_stderr, a_write | avm_system, s->write_id, s);
2293ff48bf5SDavid du Colombier 	*ps = s;
2303ff48bf5SDavid du Colombier 	return 1;
2313ff48bf5SDavid du Colombier     }
2323ff48bf5SDavid du Colombier     *ps = s;
2333ff48bf5SDavid du Colombier     return 0;
2343ff48bf5SDavid du Colombier }
2353ff48bf5SDavid du Colombier /* This is the public routine for getting the stderr stream. */
2363ff48bf5SDavid du Colombier int
zget_stderr(i_ctx_t * i_ctx_p,stream ** ps)2373ff48bf5SDavid du Colombier zget_stderr(i_ctx_t *i_ctx_p, stream ** ps)
2383ff48bf5SDavid du Colombier {
2393ff48bf5SDavid du Colombier     stream *s;
2403ff48bf5SDavid du Colombier     gx_io_device *iodev;
2413ff48bf5SDavid du Colombier     int code;
2423ff48bf5SDavid du Colombier 
2433ff48bf5SDavid du Colombier     if (file_is_valid(s, &ref_stderr)) {
2443ff48bf5SDavid du Colombier 	*ps = s;
2453ff48bf5SDavid du Colombier 	return 0;
2463ff48bf5SDavid du Colombier     }
2473ff48bf5SDavid du Colombier     iodev = gs_findiodevice((const byte *)"%stderr", 7);
2483ff48bf5SDavid du Colombier     iodev->state = i_ctx_p;
2493ff48bf5SDavid du Colombier     code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
2503ff48bf5SDavid du Colombier     iodev->state = NULL;
2513ff48bf5SDavid du Colombier     return min(code, 0);
2523ff48bf5SDavid du Colombier }
253