xref: /plan9/sys/src/cmd/gs/src/gp_msio.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999 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: gp_msio.c,v 1.6 2002/06/16 05:48:55 lpd Exp $ */
18 /*
19  * Streams for Windows text window
20  *
21  * Original version by Russell Lang and Maurice Castro with help from
22  * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
23  * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992.
24  */
25 
26 /* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */
27 /* by Friedrich Nowak                                           */
28 
29 /* Factored out from gp_mswin.c by JD 6/25/97 */
30 
31 /*
32  * The MSVC compiler, when invoked with the /MD switch, considers that the
33  * dllimport qualifier on fprintf in stdio.h and the dllexport qualifier
34  * on the definition of fprintf in this file are incompatible.
35  * We use a hack (similar to the one in stdpre.h to deal with sys/types.h)
36  * to work around this.
37  */
38 #define fprintf UNDEFINE_fprintf
39 #include "stdio_.h"
40 #undef fprintf
41 
42 #include <stdlib.h>
43 #include "gx.h"
44 #include "gp.h"
45 #include "windows_.h"
46 #include <shellapi.h>
47 #ifdef __WIN32__
48 #include <winspool.h>
49 #endif
50 #include "gp_mswin.h"
51 #include "gsdll.h"
52 
53 #include "stream.h"
54 #include "gxiodev.h"		/* must come after stream.h */
55 
56 /* Imported from gp_msdos.c */
57 int gp_file_is_console(FILE *);
58 
59 
60 /* ====== Substitute for stdio ====== */
61 
62 /* Forward references */
63 private void win_std_init(void);
64 private stream_proc_process(win_std_read_process);
65 private stream_proc_process(win_std_write_process);
66 private stream_proc_available(win_std_available);
67 
68 /* Use a pseudo IODevice to get win_stdio_init called at the right time. */
69 /* This is bad architecture; we'll fix it later. */
70 private iodev_proc_init(win_stdio_init);
71 const gx_io_device gs_iodev_wstdio = {
72     /* The name is null to keep this from showing up as a resource. */
73     0, "Special",
74     {win_stdio_init, iodev_no_open_device,
75      iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,
76      iodev_no_delete_file, iodev_no_rename_file,
77      iodev_no_file_status, iodev_no_enumerate_files
78     }
79 };
80 
81 /* Do one-time initialization */
82 private int
win_stdio_init(gx_io_device * iodev,gs_memory_t * mem)83 win_stdio_init(gx_io_device * iodev, gs_memory_t * mem)
84 {
85     win_std_init();		/* redefine stdin/out/err to our window routines */
86     return 0;
87 }
88 
89 /* Define alternate 'open' routines for our stdin/out/err streams. */
90 
91 extern const gx_io_device gs_iodev_stdin;
92 private int
win_stdin_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)93 win_stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
94 	       gs_memory_t * mem)
95 {
96     int code = gs_iodev_stdin.procs.open_device(iodev, access, ps, mem);
97     stream *s = *ps;
98 
99     if (code != 1)
100 	return code;
101     s->procs.process = win_std_read_process;
102     s->procs.available = win_std_available;
103     s->file = NULL;
104     return 0;
105 }
106 
107 extern const gx_io_device gs_iodev_stdout;
108 private int
win_stdout_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)109 win_stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
110 		gs_memory_t * mem)
111 {
112     int code = gs_iodev_stdout.procs.open_device(iodev, access, ps, mem);
113     stream *s = *ps;
114 
115     if (code != 1)
116 	return code;
117     s->procs.process = win_std_write_process;
118     s->procs.available = win_std_available;
119     s->procs.flush = s_std_write_flush;
120     s->file = NULL;
121     return 0;
122 }
123 
124 extern const gx_io_device gs_iodev_stderr;
125 private int
win_stderr_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)126 win_stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
127 		gs_memory_t * mem)
128 {
129     int code = gs_iodev_stderr.procs.open_device(iodev, access, ps, mem);
130     stream *s = *ps;
131 
132     if (code != 1)
133 	return code;
134     s->procs.process = win_std_write_process;
135     s->procs.available = win_std_available;
136     s->procs.flush = s_std_write_flush;
137     s->file = NULL;
138     return 0;
139 }
140 
141 /* Patch stdin/out/err to use our windows. */
142 private void
win_std_init(void)143 win_std_init(void)
144 {
145     /* If stdxxx is the console, replace the 'open' routines, */
146     /* which haven't gotten called yet. */
147 
148     if (gp_file_is_console(gs_stdin))
149 	gs_findiodevice((const byte *)"%stdin", 6)->procs.open_device =
150 	    win_stdin_open;
151 
152     if (gp_file_is_console(gs_stdout))
153 	gs_findiodevice((const byte *)"%stdout", 7)->procs.open_device =
154 	    win_stdout_open;
155 
156     if (gp_file_is_console(gs_stderr))
157 	gs_findiodevice((const byte *)"%stderr", 7)->procs.open_device =
158 	    win_stderr_open;
159 }
160 
161 private int
win_std_read_process(stream_state * st,stream_cursor_read * ignore_pr,stream_cursor_write * pw,bool last)162 win_std_read_process(stream_state * st, stream_cursor_read * ignore_pr,
163 		     stream_cursor_write * pw, bool last)
164 {
165     int count = pw->limit - pw->ptr;
166 
167     if (count == 0)		/* empty buffer */
168 	return 1;
169 
170 /* callback to get more input */
171     count = (*pgsdll_callback) (GSDLL_STDIN, pw->ptr + 1, count);
172     if (count == 0) {
173 	/* EOF */
174 	/* what should we do? */
175 	return EOFC;
176     }
177     pw->ptr += count;
178     return 1;
179 }
180 
181 private int
win_std_available(register stream * s,long * pl)182 win_std_available(register stream * s, long *pl)
183 {
184     *pl = -1;		// EOF, since we can't do it
185     return 0;		// OK
186 }
187 
188 
189 private int
win_std_write_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * ignore_pw,bool last)190 win_std_write_process(stream_state * st, stream_cursor_read * pr,
191 		      stream_cursor_write * ignore_pw, bool last)
192 {
193     uint count = pr->limit - pr->ptr;
194 
195     (*pgsdll_callback) (GSDLL_STDOUT, (char *)(pr->ptr + 1), count);
196     pr->ptr = pr->limit;
197     return 0;
198 }
199 
200 /* This is used instead of the stdio version. */
201 /* The declaration must be identical to that in <stdio.h>. */
202 #if defined(_WIN32) && (defined(_MSC_VER) || defined(_WATCOM_))
203 #if defined(_CRTAPI2)
204 int _CRTAPI2
fprintf(FILE * file,const char * fmt,...)205 fprintf(FILE * file, const char *fmt,...)
206 #else
207 _CRTIMP int __cdecl
208 fprintf(FILE * file, const char *fmt,...)
209 #endif
210 #else
211 int _Cdecl _FARFUNC
212 fprintf(FILE _FAR * file, const char *fmt,...)
213 #endif
214 {
215     int count;
216     va_list args;
217 
218     va_start(args, fmt);
219     if (gp_file_is_console(file)) {
220 	char buf[1024];
221 
222 	count = vsprintf(buf, fmt, args);
223 	(*pgsdll_callback) (GSDLL_STDOUT, buf, count);
224     } else
225 	count = vfprintf(file, fmt, args);
226     va_end(args);
227     return count;
228 }
229