xref: /plan9/sys/src/cmd/gs/src/zmisc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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