Commit | Line | Data |
---|---|---|
e5bee91e WJ |
1 | /* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zfileio.c */ | |
21 | /* File I/O operators for Ghostscript */ | |
22 | #include "ghost.h" | |
23 | #include "gp.h" | |
24 | #include "errors.h" | |
25 | #include "oper.h" | |
26 | #include "stream.h" | |
27 | #include "estack.h" | |
28 | #include "file.h" | |
29 | #include "store.h" | |
30 | #include "gsmatrix.h" /* for gxdevice.h */ | |
31 | #include "gxdevice.h" | |
32 | #include "gxdevmem.h" | |
33 | ||
34 | /* Forward references */ | |
35 | int zreadline_from(P4(byte *, uint, uint *, stream *)); | |
36 | es_ptr zget_current_file(P0()); | |
37 | private int write_string(P2(os_ptr, stream *)); | |
38 | ||
39 | /* ------ Operators ------ */ | |
40 | ||
41 | /* read */ | |
42 | int | |
43 | zread(register os_ptr op) | |
44 | { stream *s; | |
45 | int ch; | |
46 | check_read_file(s, op); | |
47 | ch = sgetc(s); | |
48 | if ( ch == EOFC ) | |
49 | make_bool(op, 0); | |
50 | else | |
51 | { make_int(op, ch); | |
52 | push(1); | |
53 | make_bool(op, 1); | |
54 | } | |
55 | return 0; | |
56 | } | |
57 | ||
58 | /* write */ | |
59 | int | |
60 | zwrite(register os_ptr op) | |
61 | { stream *s; | |
62 | ulong ch; | |
63 | check_write_file(s, op - 1); | |
64 | check_type(*op, t_integer); | |
65 | ch = op->value.intval; | |
66 | if ( ch > 0xff ) return e_rangecheck; | |
67 | sputc(s, (byte)ch); | |
68 | pop(2); | |
69 | return 0; | |
70 | } | |
71 | ||
72 | /* readhexstring */ | |
73 | int | |
74 | zreadhexstring(register os_ptr op) | |
75 | { stream *s; | |
76 | int code; | |
77 | uint nread; | |
78 | int odd = -1; | |
79 | check_read_file(s, op - 1); | |
80 | check_write_type(*op, t_string); | |
81 | code = sreadhex(s, op->value.bytes, r_size(op), &nread, &odd, 1); | |
82 | switch ( code ) | |
83 | { | |
84 | case EOFC: | |
85 | /* Reached end-of-file before filling the string. */ | |
86 | /* Return an appropriate substring. */ | |
87 | r_set_size(op, nread); | |
88 | code = 1; | |
89 | break; | |
90 | case 0: | |
91 | /* Filled the string. */ | |
92 | break; | |
93 | default: /* Error */ | |
94 | return e_ioerror; | |
95 | } | |
96 | ref_assign(op - 1, op); | |
97 | make_bool(op, 1 - code); | |
98 | return 0; | |
99 | } | |
100 | ||
101 | /* writehexstring */ | |
102 | int | |
103 | zwritehexstring(register os_ptr op) | |
104 | { register stream *s; | |
105 | register byte ch; | |
106 | register byte *p; | |
107 | register const char _ds *hex_digits = "0123456789abcdef"; | |
108 | register uint len; | |
109 | check_write_file(s, op - 1); | |
110 | check_read_type(*op, t_string); | |
111 | p = op->value.bytes; | |
112 | len = r_size(op); | |
113 | while ( len-- ) | |
114 | { ch = *p++; | |
115 | sputc(s, hex_digits[ch >> 4]); | |
116 | sputc(s, hex_digits[ch & 0xf]); | |
117 | } | |
118 | pop(2); | |
119 | return 0; | |
120 | } | |
121 | ||
122 | /* readstring */ | |
123 | int | |
124 | zreadstring(register os_ptr op) | |
125 | { stream *s; | |
126 | uint len, rlen; | |
127 | check_read_file(s, op - 1); | |
128 | check_write_type(*op, t_string); | |
129 | len = r_size(op); | |
130 | rlen = sgets(s, op->value.bytes, len); | |
131 | r_set_size(op, rlen); | |
132 | op[-1] = *op; | |
133 | make_bool(op, (rlen == len ? 1 : 0)); | |
134 | return 0; | |
135 | } | |
136 | ||
137 | /* writestring */ | |
138 | int | |
139 | zwritestring(register os_ptr op) | |
140 | { stream *s; | |
141 | int code; | |
142 | check_write_file(s, op - 1); | |
143 | code = write_string(op, s); | |
144 | if ( code >= 0 ) pop(2); | |
145 | return code; | |
146 | } | |
147 | ||
148 | /* readline */ | |
149 | int | |
150 | zreadline(register os_ptr op) | |
151 | { stream *s; | |
152 | uint count; | |
153 | int code; | |
154 | check_read_file(s, op - 1); | |
155 | check_write_type(*op, t_string); | |
156 | code = zreadline_from(op->value.bytes, r_size(op), &count, s); | |
157 | if ( code < 0 ) return code; | |
158 | r_set_size(op, count); | |
159 | op[-1] = *op; | |
160 | make_bool(op, code); | |
161 | return 0; | |
162 | } | |
163 | ||
164 | /* Read a line from stdin. This is called from gs.c. */ | |
165 | int | |
166 | zreadline_stdin(byte *ptr, uint size, uint *pcount) | |
167 | { return zreadline_from(ptr, size, pcount, &std_files[0]); | |
168 | } | |
169 | ||
170 | /* Internal readline routine. */ | |
171 | /* Returns 1 if OK, 0 if end of file, or an error code. */ | |
172 | int | |
173 | zreadline_from(byte *ptr, uint size, uint *pcount, stream *s) | |
174 | { uint count = 0; | |
175 | int ch; | |
176 | for ( ; ; count++ ) | |
177 | { switch ( ch = sgetc(s) ) | |
178 | { | |
179 | case '\r': | |
180 | ch = sgetc(s); | |
181 | if ( ch != '\n' && ch >= 0 ) sputback(s); | |
182 | /* falls through */ | |
183 | case '\n': | |
184 | *pcount = count; | |
185 | return 1; | |
186 | case EOFC: | |
187 | *pcount = count; | |
188 | return 0; | |
189 | } | |
190 | if ( count >= size ) /* filled the string */ | |
191 | { sputback(s); | |
192 | return e_rangecheck; | |
193 | } | |
194 | *ptr++ = ch; | |
195 | } | |
196 | return 0; | |
197 | } | |
198 | ||
199 | /* token - this is called from zstring.c */ | |
200 | int | |
201 | ztoken_file(register os_ptr op) | |
202 | { stream *s; | |
203 | ref token; | |
204 | int code; | |
205 | check_read_file(s, op); | |
206 | switch ( code = scan_token(s, 0, &token) ) | |
207 | { | |
208 | case 0: /* read a token */ | |
209 | *op = token; | |
210 | push(1); | |
211 | make_bool(op, 1); | |
212 | return 0; | |
213 | case 1: /* no tokens */ | |
214 | make_bool(op, 0); | |
215 | return 0; | |
216 | default: /* error */ | |
217 | return code; | |
218 | } | |
219 | } | |
220 | ||
221 | /* bytesavailable */ | |
222 | int | |
223 | zbytesavailable(register os_ptr op) | |
224 | { stream *s; | |
225 | long avail; | |
226 | check_read_file(s, op); | |
227 | if ( savailable(s, &avail) < 0 ) return e_ioerror; | |
228 | make_int(op, avail); | |
229 | return 0; | |
230 | } | |
231 | ||
232 | /* flush */ | |
233 | int | |
234 | zflush(register os_ptr op) | |
235 | { sflush(&std_files[1]); | |
236 | return 0; | |
237 | } | |
238 | ||
239 | /* flushfile */ | |
240 | int | |
241 | zflushfile(register os_ptr op) | |
242 | { stream *s; | |
243 | check_file(s, op); | |
244 | sflush(s); | |
245 | if ( !s_is_writing(s) ) | |
246 | fseek(s->file, 0L, 2); /* set to end */ | |
247 | pop(1); | |
248 | return 0; | |
249 | } | |
250 | ||
251 | /* resetfile */ | |
252 | int | |
253 | zresetfile(register os_ptr op) | |
254 | { NYI("resetfile"); | |
255 | pop(1); | |
256 | return 0; | |
257 | } | |
258 | ||
259 | /* status */ | |
260 | int | |
261 | zstatus(register os_ptr op) | |
262 | { switch ( r_type(op) ) | |
263 | { | |
264 | case t_file: | |
265 | make_bool(op, (fptr(op)->bsize != 0 ? 1 : 0)); | |
266 | return 0; | |
267 | case t_string: | |
268 | { char *fname = ref_to_string(op, "status"); | |
269 | file_status fstat; | |
270 | if ( fname == 0 ) return e_VMerror; | |
271 | if ( gp_file_status(fname, &fstat) ) | |
272 | { push(4); | |
273 | make_int(op - 4, fstat.size_pages); | |
274 | make_int(op - 3, fstat.size_bytes); | |
275 | make_int(op - 2, fstat.time_referenced); | |
276 | make_int(op - 1, fstat.time_created); | |
277 | make_bool(op, 1); | |
278 | } | |
279 | else | |
280 | make_bool(op, 0); | |
281 | alloc_free(fname, r_size(op) + 1, 1, "status"); | |
282 | } return 0; | |
283 | default: | |
284 | return e_typecheck; | |
285 | } | |
286 | } | |
287 | ||
288 | /* currentfile */ | |
289 | int | |
290 | zcurrentfile(register os_ptr op) | |
291 | { es_ptr fp; | |
292 | push(1); | |
293 | /* Check the cache first */ | |
294 | if ( esfile != 0 ) | |
295 | ref_assign(op, esfile); | |
296 | else if ( (fp = zget_current_file()) == 0 ) | |
297 | { /* Return an invalid file object. */ | |
298 | /* This doesn't make a lot of sense to me, */ | |
299 | /* but it's what the PostScript manual specifies. */ | |
300 | make_file(op, 0, &invalid_file_entry); | |
301 | } | |
302 | else | |
303 | { ref_assign(op, fp); | |
304 | /* Load the cache */ | |
305 | esfile = fp; | |
306 | } | |
307 | /* Make the returned value literal. */ | |
308 | r_clear_attrs(op, a_executable); | |
309 | return 0; | |
310 | } | |
311 | ||
312 | /* print */ | |
313 | int | |
314 | zprint(register os_ptr op) | |
315 | { int code = write_string(op, &std_files[1]); | |
316 | if ( code >= 0 ) pop(1); | |
317 | return code; | |
318 | } | |
319 | ||
320 | /* echo */ | |
321 | int | |
322 | zecho(register os_ptr op) | |
323 | { check_type(*op, t_boolean); | |
324 | /****** NOT IMPLEMENTED YET ******/ | |
325 | pop(1); | |
326 | return 0; | |
327 | } | |
328 | ||
329 | /* ------ Level 2 extensions ------ */ | |
330 | ||
331 | /* fileposition */ | |
332 | int | |
333 | zfileposition(register os_ptr op) | |
334 | { stream *s; | |
335 | check_file(s, op); | |
336 | if ( !sseekable(s) ) return e_ioerror; | |
337 | make_int(op, stell(s)); | |
338 | return 0; | |
339 | } | |
340 | ||
341 | /* setfileposition */ | |
342 | int | |
343 | zsetfileposition(register os_ptr op) | |
344 | { stream *s; | |
345 | check_file(s, op - 1); | |
346 | check_type(*op, t_integer); | |
347 | if ( sseek(s, op->value.intval) < 0 ) return e_ioerror; | |
348 | pop(2); | |
349 | return 0; | |
350 | } | |
351 | ||
352 | /* ------ Ghostscript extensions ------ */ | |
353 | ||
354 | /* unread */ | |
355 | int | |
356 | zunread(register os_ptr op) | |
357 | { stream *s; | |
358 | ulong ch; | |
359 | check_read_file(s, op - 1); | |
360 | check_type(*op, t_integer); | |
361 | ch = op->value.intval; | |
362 | if ( ch > 0xff ) return e_rangecheck; | |
363 | if ( sungetc(s, (byte)ch) < 0 ) return e_ioerror; | |
364 | pop(2); | |
365 | return 0; | |
366 | } | |
367 | ||
368 | /* writeppmfile */ | |
369 | int | |
370 | zwriteppmfile(register os_ptr op) | |
371 | { stream *s; | |
372 | int code; | |
373 | check_write_file(s, op - 1); | |
374 | check_type(*op, t_device); | |
375 | if ( !gs_device_is_memory(op->value.pdevice) ) return e_typecheck; | |
376 | sflush(s); | |
377 | code = gs_writeppmfile((gx_device_memory *)(op->value.pdevice), s->file); | |
378 | if ( code >= 0 ) pop(2); | |
379 | return code; | |
380 | } | |
381 | ||
382 | /* ------ Initialization procedure ------ */ | |
383 | ||
384 | op_def zfileio_op_defs[] = { | |
385 | {"1bytesavailable", zbytesavailable}, | |
386 | {"0currentfile", zcurrentfile}, | |
387 | {"1echo", zecho}, | |
388 | {"1fileposition", zfileposition}, | |
389 | {"0flush", zflush}, | |
390 | {"1flushfile", zflushfile}, | |
391 | {"1print", zprint}, | |
392 | {"1read", zread}, | |
393 | {"2readhexstring", zreadhexstring}, | |
394 | {"2readline", zreadline}, | |
395 | {"2readstring", zreadstring}, | |
396 | {"1resetfile", zresetfile}, | |
397 | {"2setfileposition", zsetfileposition}, | |
398 | {"2unread", zunread}, | |
399 | {"1status", zstatus}, | |
400 | {"2write", zwrite}, | |
401 | {"2writehexstring", zwritehexstring}, | |
402 | {"2writeppmfile", zwriteppmfile}, | |
403 | {"2writestring", zwritestring}, | |
404 | op_def_end(0) | |
405 | }; | |
406 | ||
407 | /* ------ Non-operator routines ------ */ | |
408 | ||
409 | /* Check a file for reading. */ | |
410 | /* The interpreter calls this to check an executable file. */ | |
411 | int | |
412 | file_check_read(ref *op, stream **ps) | |
413 | { if ( !s_is_reading(*ps = fptr(op)) ) return e_invalidaccess; | |
414 | return 0; | |
415 | } | |
416 | ||
417 | /* Get the current file from which the interpreter is reading. */ | |
418 | es_ptr | |
419 | zget_current_file() | |
420 | { register es_ptr ep = esp; | |
421 | while ( ep >= esbot ) | |
422 | { if ( r_has_type_attrs(ep, t_file, a_executable) ) | |
423 | return ep; | |
424 | ep--; | |
425 | } | |
426 | return (es_ptr)0; | |
427 | } | |
428 | ||
429 | /* ------ Internal routines ------ */ | |
430 | ||
431 | /* Write a string on a file. The file has been checked for validity, */ | |
432 | /* but not the string. */ | |
433 | private int | |
434 | write_string(os_ptr op, stream *s) | |
435 | { uint len; | |
436 | check_read_type(*op, t_string); | |
437 | len = r_size(op); | |
438 | if ( sputs(s, op->value.bytes, len) != len ) return e_ioerror; | |
439 | return 0; | |
440 | } |