1 /* Copyright (C) 1989, 1995-2004 artofcode LLC. 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: zmisc.c,v 1.7 2004/08/04 19:36:13 stefan Exp $ */
18 /* Miscellaneous operators */
19
20 #include "errno_.h"
21 #include "memory_.h"
22 #include "string_.h"
23 #include "ghost.h"
24 #include "gscdefs.h" /* for gs_serialnumber */
25 #include "gp.h"
26 #include "oper.h"
27 #include "ialloc.h"
28 #include "idict.h"
29 #include "dstack.h" /* for name lookup in bind */
30 #include "iname.h"
31 #include "ipacked.h"
32 #include "ivmspace.h"
33 #include "store.h"
34
35 /* <proc> bind <proc> */
36 inline private bool
r_is_ex_oper(const ref * rp)37 r_is_ex_oper(const ref *rp)
38 {
39 return (r_has_attr(rp, a_executable) &&
40 (r_btype(rp) == t_operator || r_type(rp) == t_oparray));
41 }
42 private int
zbind(i_ctx_t * i_ctx_p)43 zbind(i_ctx_t *i_ctx_p)
44 {
45 os_ptr op = osp;
46 uint depth = 1;
47 ref defn;
48 register os_ptr bsp;
49
50 switch (r_type(op)) {
51 case t_array:
52 case t_mixedarray:
53 case t_shortarray:
54 defn = *op;
55 break;
56 case t_oparray:
57 defn = *op->value.const_refs;
58 break;
59 default:
60 return_op_typecheck(op);
61 }
62 push(1);
63 *op = defn;
64 bsp = op;
65 /*
66 * We must not make the top-level procedure read-only,
67 * but we must bind it even if it is read-only already.
68 *
69 * Here are the invariants for the following loop:
70 * `depth' elements have been pushed on the ostack;
71 * For i < depth, p = ref_stack_index(&o_stack, i):
72 * *p is an array (or packedarray) ref.
73 */
74 while (depth) {
75 while (r_size(bsp)) {
76 ref_packed *const tpp = (ref_packed *)bsp->value.packed; /* break const */
77
78 r_dec_size(bsp, 1);
79 if (r_is_packed(tpp)) {
80 /* Check for a packed executable name */
81 ushort elt = *tpp;
82
83 if (r_packed_is_exec_name(&elt)) {
84 ref nref;
85 ref *pvalue;
86
87 name_index_ref(imemory, packed_name_index(&elt),
88 &nref);
89 if ((pvalue = dict_find_name(&nref)) != 0 &&
90 r_is_ex_oper(pvalue)
91 ) {
92 store_check_dest(bsp, pvalue);
93 /*
94 * Always save the change, since this can only
95 * happen once.
96 */
97 ref_do_save(bsp, tpp, "bind");
98 *tpp = pt_tag(pt_executable_operator) +
99 op_index(pvalue);
100 }
101 }
102 bsp->value.packed = tpp + 1;
103 } else {
104 ref *const tp = bsp->value.refs++;
105
106 switch (r_type(tp)) {
107 case t_name: /* bind the name if an operator */
108 if (r_has_attr(tp, a_executable)) {
109 ref *pvalue;
110
111 if ((pvalue = dict_find_name(tp)) != 0 &&
112 r_is_ex_oper(pvalue)
113 ) {
114 store_check_dest(bsp, pvalue);
115 ref_assign_old(bsp, tp, pvalue, "bind");
116 }
117 }
118 break;
119 case t_array: /* push into array if writable */
120 if (!r_has_attr(tp, a_write))
121 break;
122 case t_mixedarray:
123 case t_shortarray:
124 if (r_has_attr(tp, a_executable)) {
125 /* Make reference read-only */
126 r_clear_attrs(tp, a_write);
127 if (bsp >= ostop) {
128 /* Push a new stack block. */
129 ref temp;
130 int code;
131
132 temp = *tp;
133 osp = bsp;
134 code = ref_stack_push(&o_stack, 1);
135 if (code < 0) {
136 ref_stack_pop(&o_stack, depth);
137 return_error(code);
138 }
139 bsp = osp;
140 *bsp = temp;
141 } else
142 *++bsp = *tp;
143 depth++;
144 }
145 }
146 }
147 }
148 bsp--;
149 depth--;
150 if (bsp < osbot) { /* Pop back to the previous stack block. */
151 osp = bsp;
152 ref_stack_pop_block(&o_stack);
153 bsp = osp;
154 }
155 }
156 osp = bsp;
157 return 0;
158 }
159
160 /* - serialnumber <int> */
161 private int
zserialnumber(i_ctx_t * i_ctx_p)162 zserialnumber(i_ctx_t *i_ctx_p)
163 {
164 os_ptr op = osp;
165
166 push(1);
167 make_int(op, gs_serialnumber);
168 return 0;
169 }
170
171 /* some FTS tests work better if realtime starts from 0 at boot time */
172 private long real_time_0[2];
173
174 private int
zmisc_init_realtime(i_ctx_t * i_ctx_p)175 zmisc_init_realtime(i_ctx_t * i_ctx_p)
176 {
177 gp_get_realtime(real_time_0);
178 return 0;
179 }
180
181 /* - realtime <int> */
182 private int
zrealtime(i_ctx_t * i_ctx_p)183 zrealtime(i_ctx_t *i_ctx_p)
184 {
185 os_ptr op = osp;
186 long secs_ns[2];
187
188 gp_get_realtime(secs_ns);
189 secs_ns[1] -= real_time_0[1];
190 secs_ns[0] -= real_time_0[0];
191 push(1);
192 make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
193 return 0;
194 }
195
196 /* - usertime <int> */
197 private int
zusertime(i_ctx_t * i_ctx_p)198 zusertime(i_ctx_t *i_ctx_p)
199 {
200 os_ptr op = osp;
201 long secs_ns[2];
202
203 gp_get_usertime(secs_ns);
204 push(1);
205 make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
206 return 0;
207 }
208
209 /* ---------------- Non-standard operators ---------------- */
210
211 /* <string> getenv <value_string> true */
212 /* <string> getenv false */
213 private int
zgetenv(i_ctx_t * i_ctx_p)214 zgetenv(i_ctx_t *i_ctx_p)
215 {
216 os_ptr op = osp;
217 char *str;
218 byte *value;
219 int len = 0;
220
221 check_read_type(*op, t_string);
222 str = ref_to_string(op, imemory, "getenv key");
223 if (str == 0)
224 return_error(e_VMerror);
225 if (gp_getenv(str, (char *)0, &len) > 0) { /* key missing */
226 ifree_string((byte *) str, r_size(op) + 1, "getenv key");
227 make_false(op);
228 return 0;
229 }
230 value = ialloc_string(len, "getenv value");
231 if (value == 0) {
232 ifree_string((byte *) str, r_size(op) + 1, "getenv key");
233 return_error(e_VMerror);
234 }
235 DISCARD(gp_getenv(str, (char *)value, &len)); /* can't fail */
236 ifree_string((byte *) str, r_size(op) + 1, "getenv key");
237 /* Delete the stupid C string terminator. */
238 value = iresize_string(value, len, len - 1,
239 "getenv value"); /* can't fail */
240 push(1);
241 make_string(op - 1, a_all | icurrent_space, len - 1, value);
242 make_true(op);
243 return 0;
244 }
245
246 /* <name> <proc> .makeoperator <oper> */
247 private int
zmakeoperator(i_ctx_t * i_ctx_p)248 zmakeoperator(i_ctx_t *i_ctx_p)
249 {
250 os_ptr op = osp;
251 op_array_table *opt;
252 uint count;
253 ref *tab;
254
255 check_type(op[-1], t_name);
256 check_proc(*op);
257 switch (r_space(op)) {
258 case avm_global:
259 opt = &op_array_table_global;
260 break;
261 case avm_local:
262 opt = &op_array_table_local;
263 break;
264 default:
265 return_error(e_invalidaccess);
266 }
267 count = opt->count;
268 tab = opt->table.value.refs;
269 /*
270 * restore doesn't reset op_array_table.count, but it does
271 * remove entries from op_array_table.table. Since we fill
272 * the table in order, we can detect that a restore has occurred
273 * by checking whether what should be the most recent entry
274 * is occupied. If not, we scan backwards over the vacated entries
275 * to find the true end of the table.
276 */
277 while (count > 0 && r_has_type(&tab[count - 1], t_null))
278 --count;
279 if (count == r_size(&opt->table))
280 return_error(e_limitcheck);
281 ref_assign_old(&opt->table, &tab[count], op, "makeoperator");
282 opt->nx_table[count] = name_index(imemory, op - 1);
283 op_index_ref(opt->base_index + count, op - 1);
284 opt->count = count + 1;
285 pop(1);
286 return 0;
287 }
288
289 /* - .oserrno <int> */
290 private int
zoserrno(i_ctx_t * i_ctx_p)291 zoserrno(i_ctx_t *i_ctx_p)
292 {
293 os_ptr op = osp;
294
295 push(1);
296 make_int(op, errno);
297 return 0;
298 }
299
300 /* <int> .setoserrno - */
301 private int
zsetoserrno(i_ctx_t * i_ctx_p)302 zsetoserrno(i_ctx_t *i_ctx_p)
303 {
304 os_ptr op = osp;
305
306 check_type(*op, t_integer);
307 errno = op->value.intval;
308 pop(1);
309 return 0;
310 }
311
312 /* <int> .oserrorstring <string> true */
313 /* <int> .oserrorstring false */
314 private int
zoserrorstring(i_ctx_t * i_ctx_p)315 zoserrorstring(i_ctx_t *i_ctx_p)
316 {
317 os_ptr op = osp;
318 const char *str;
319 int code;
320 uint len;
321 byte ch;
322
323 check_type(*op, t_integer);
324 str = gp_strerror((int)op->value.intval);
325 if (str == 0 || (len = strlen(str)) == 0) {
326 make_false(op);
327 return 0;
328 }
329 check_ostack(1);
330 code = string_to_ref(str, op, iimemory, ".oserrorstring");
331 if (code < 0)
332 return code;
333 /* Strip trailing end-of-line characters. */
334 while ((len = r_size(op)) != 0 &&
335 ((ch = op->value.bytes[--len]) == '\r' || ch == '\n')
336 )
337 r_dec_size(op, 1);
338 push(1);
339 make_true(op);
340 return 0;
341 }
342
343 /* <string> <bool> .setdebug - */
344 private int
zsetdebug(i_ctx_t * i_ctx_p)345 zsetdebug(i_ctx_t *i_ctx_p)
346 {
347 os_ptr op = osp;
348 check_read_type(op[-1], t_string);
349 check_type(*op, t_boolean);
350 {
351 int i;
352
353 for (i = 0; i < r_size(op - 1); i++)
354 gs_debug[op[-1].value.bytes[i] & 127] =
355 op->value.boolval;
356 }
357 pop(2);
358 return 0;
359 }
360
361 /* ------ gs persistent cache operators ------ */
362 /* these are for testing only. they're disabled in the normal build
363 * to prevent access to the cache by malicious postscript files
364 *
365 * use something like this:
366 * (value) (key) .pcacheinsert
367 * (key) .pcachequery { (\n) concatstrings print } if
368 */
369
370 #ifdef DEBUG_CACHE
371
372 /* <string> <string> .pcacheinsert */
373 private int
zpcacheinsert(i_ctx_t * i_ctx_p)374 zpcacheinsert(i_ctx_t *i_ctx_p)
375 {
376 os_ptr op = osp;
377 char *key, *buffer;
378 int keylen, buflen;
379 int code = 0;
380
381 check_read_type(*op, t_string);
382 keylen = r_size(op);
383 key = op->value.bytes;
384 check_read_type(*(op - 1), t_string);
385 buflen = r_size(op - 1);
386 buffer = (op - 1)->value.bytes;
387
388 code = gp_cache_insert(0, key, keylen, buffer, buflen);
389 if (code < 0)
390 return code;
391
392 pop(2);
393
394 return code;
395 }
396
397 /* allocation callback for query result */
398 private void *
pcache_alloc_callback(void * userdata,int bytes)399 pcache_alloc_callback(void *userdata, int bytes)
400 {
401 i_ctx_t *i_ctx_p = (i_ctx_t*)userdata;
402 return ialloc_string(bytes, "pcache buffer");
403 }
404
405 /* <string> .pcachequery <string> true */
406 /* <string> .pcachequery false */
407 private int
zpcachequery(i_ctx_t * i_ctx_p)408 zpcachequery(i_ctx_t *i_ctx_p)
409 {
410 os_ptr op = osp;
411 int len;
412 char *key;
413 byte *string;
414 int code = 0;
415
416 check_read_type(*op, t_string);
417 len = r_size(op);
418 key = op->value.bytes;
419 len = gp_cache_query(GP_CACHE_TYPE_TEST, key, len, (void**)&string, &pcache_alloc_callback, i_ctx_p);
420 if (len < 0) {
421 make_false(op);
422 return 0;
423 }
424 if (string == NULL)
425 return_error(e_VMerror);
426 make_string(op, a_all | icurrent_space, len, string);
427
428 push(1);
429 make_true(op);
430
431 return code;
432 }
433
434 #endif /* DEBUG_CACHE */
435
436 /* ------ Initialization procedure ------ */
437
438 const op_def zmisc_op_defs[] =
439 {
440 {"1bind", zbind},
441 {"1getenv", zgetenv},
442 {"2.makeoperator", zmakeoperator},
443 {"0.oserrno", zoserrno},
444 {"1.oserrorstring", zoserrorstring},
445 {"0realtime", zrealtime},
446 {"1serialnumber", zserialnumber},
447 {"2.setdebug", zsetdebug},
448 {"1.setoserrno", zsetoserrno},
449 {"0usertime", zusertime},
450 #ifdef DEBUG_CACHE
451 /* pcache test */
452 {"2.pcacheinsert", zpcacheinsert},
453 {"1.pcachequery", zpcachequery},
454 #endif
455 op_def_end(zmisc_init_realtime)
456 };
457