xref: /plan9/sys/src/cmd/gs/src/zmisc.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 /* Copyright (C) 1989, 1995, 1997, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: zmisc.c,v 1.2 2000/09/19 19:00:54 lpd Exp $ */
20 /* Miscellaneous operators */
21 #include "errno_.h"
22 #include "memory_.h"
23 #include "string_.h"
24 #include "ghost.h"
25 #include "gscdefs.h"		/* for gs_serialnumber */
26 #include "gp.h"
27 #include "oper.h"
28 #include "ialloc.h"
29 #include "idict.h"
30 #include "dstack.h"		/* for name lookup in bind */
31 #include "iname.h"
32 #include "ipacked.h"
33 #include "ivmspace.h"
34 #include "store.h"
35 
36 /* <proc> bind <proc> */
37 inline private bool
38 r_is_ex_oper(const ref *rp)
39 {
40     return (r_has_attr(rp, a_executable) &&
41 	    (r_btype(rp) == t_operator || r_type(rp) == t_oparray));
42 }
43 private int
44 zbind(i_ctx_t *i_ctx_p)
45 {
46     os_ptr op = osp;
47     uint depth = 1;
48     ref defn;
49     register os_ptr bsp;
50 
51     switch (r_type(op)) {
52 	case t_array:
53 	case t_mixedarray:
54 	case t_shortarray:
55 	    defn = *op;
56 	    break;
57 	case t_oparray:
58 	    defn = *op->value.const_refs;
59 	    break;
60 	default:
61 	    return_op_typecheck(op);
62     }
63     push(1);
64     *op = defn;
65     bsp = op;
66     /*
67      * We must not make the top-level procedure read-only,
68      * but we must bind it even if it is read-only already.
69      *
70      * Here are the invariants for the following loop:
71      *      `depth' elements have been pushed on the ostack;
72      *      For i < depth, p = ref_stack_index(&o_stack, i):
73      *        *p is an array (or packedarray) ref.
74      */
75     while (depth) {
76 	while (r_size(bsp)) {
77 	    ref_packed *const tpp = (ref_packed *)bsp->value.packed; /* break const */
78 
79 	    r_dec_size(bsp, 1);
80 	    if (r_is_packed(tpp)) {
81 		/* Check for a packed executable name */
82 		ushort elt = *tpp;
83 
84 		if (r_packed_is_exec_name(&elt)) {
85 		    ref nref;
86 		    ref *pvalue;
87 
88 		    name_index_ref(packed_name_index(&elt),
89 				   &nref);
90 		    if ((pvalue = dict_find_name(&nref)) != 0 &&
91 			r_is_ex_oper(pvalue)
92 			) {
93 			store_check_dest(bsp, pvalue);
94 			/*
95 			 * Always save the change, since this can only
96 			 * happen once.
97 			 */
98 			ref_do_save(bsp, tpp, "bind");
99 			*tpp = pt_tag(pt_executable_operator) +
100 			    op_index(pvalue);
101 		    }
102 		}
103 		bsp->value.packed = tpp + 1;
104 	    } else {
105 		ref *const tp = bsp->value.refs++;
106 
107 		switch (r_type(tp)) {
108 		    case t_name:	/* bind the name if an operator */
109 			if (r_has_attr(tp, a_executable)) {
110 			    ref *pvalue;
111 
112 			    if ((pvalue = dict_find_name(tp)) != 0 &&
113 				r_is_ex_oper(pvalue)
114 				) {
115 				store_check_dest(bsp, pvalue);
116 				ref_assign_old(bsp, tp, pvalue, "bind");
117 			    }
118 			}
119 			break;
120 		    case t_array:	/* push into array if writable */
121 			if (!r_has_attr(tp, a_write))
122 			    break;
123 		    case t_mixedarray:
124 		    case t_shortarray:
125 			if (r_has_attr(tp, a_executable)) {
126 			    /* Make reference read-only */
127 			    r_clear_attrs(tp, a_write);
128 			    if (bsp >= ostop) {
129 				/* Push a new stack block. */
130 				ref temp;
131 				int code;
132 
133 				temp = *tp;
134 				osp = bsp;
135 				code = ref_stack_push(&o_stack, 1);
136 				if (code < 0) {
137 				    ref_stack_pop(&o_stack, depth);
138 				    return_error(code);
139 				}
140 				bsp = osp;
141 				*bsp = temp;
142 			    } else
143 				*++bsp = *tp;
144 			    depth++;
145 			}
146 		}
147 	    }
148 	}
149 	bsp--;
150 	depth--;
151 	if (bsp < osbot) {	/* Pop back to the previous stack block. */
152 	    osp = bsp;
153 	    ref_stack_pop_block(&o_stack);
154 	    bsp = osp;
155 	}
156     }
157     osp = bsp;
158     return 0;
159 }
160 
161 /* - serialnumber <int> */
162 private int
163 zserialnumber(i_ctx_t *i_ctx_p)
164 {
165     os_ptr op = osp;
166 
167     push(1);
168     make_int(op, gs_serialnumber);
169     return 0;
170 }
171 
172 /* - realtime <int> */
173 private int
174 zrealtime(i_ctx_t *i_ctx_p)
175 {
176     os_ptr op = osp;
177     long secs_ns[2];
178 
179     gp_get_realtime(secs_ns);
180     push(1);
181     make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
182     return 0;
183 }
184 
185 /* - usertime <int> */
186 private int
187 zusertime(i_ctx_t *i_ctx_p)
188 {
189     os_ptr op = osp;
190     long secs_ns[2];
191 
192     gp_get_usertime(secs_ns);
193     push(1);
194     make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
195     return 0;
196 }
197 
198 /* ---------------- Non-standard operators ---------------- */
199 
200 /* <string> getenv <value_string> true */
201 /* <string> getenv false */
202 private int
203 zgetenv(i_ctx_t *i_ctx_p)
204 {
205     os_ptr op = osp;
206     char *str;
207     byte *value;
208     int len = 0;
209 
210     check_read_type(*op, t_string);
211     str = ref_to_string(op, imemory, "getenv key");
212     if (str == 0)
213 	return_error(e_VMerror);
214     if (gp_getenv(str, (char *)0, &len) > 0) {	/* key missing */
215 	ifree_string((byte *) str, r_size(op) + 1, "getenv key");
216 	make_false(op);
217 	return 0;
218     }
219     value = ialloc_string(len, "getenv value");
220     if (value == 0) {
221 	ifree_string((byte *) str, r_size(op) + 1, "getenv key");
222 	return_error(e_VMerror);
223     }
224     DISCARD(gp_getenv(str, (char *)value, &len));	/* can't fail */
225     ifree_string((byte *) str, r_size(op) + 1, "getenv key");
226     /* Delete the stupid C string terminator. */
227     value = iresize_string(value, len, len - 1,
228 			   "getenv value");	/* can't fail */
229     push(1);
230     make_string(op - 1, a_all | icurrent_space, len - 1, value);
231     make_true(op);
232     return 0;
233 }
234 
235 /* <name> <proc> .makeoperator <oper> */
236 private int
237 zmakeoperator(i_ctx_t *i_ctx_p)
238 {
239     os_ptr op = osp;
240     op_array_table *opt;
241     uint count;
242     ref *tab;
243 
244     check_type(op[-1], t_name);
245     check_proc(*op);
246     switch (r_space(op)) {
247 	case avm_global:
248 	    opt = &op_array_table_global;
249 	    break;
250 	case avm_local:
251 	    opt = &op_array_table_local;
252 	    break;
253 	default:
254 	    return_error(e_invalidaccess);
255     }
256     count = opt->count;
257     tab = opt->table.value.refs;
258     /*
259      * restore doesn't reset op_array_table.count, but it does
260      * remove entries from op_array_table.table.  Since we fill
261      * the table in order, we can detect that a restore has occurred
262      * by checking whether what should be the most recent entry
263      * is occupied.  If not, we scan backwards over the vacated entries
264      * to find the true end of the table.
265      */
266     while (count > 0 && r_has_type(&tab[count - 1], t_null))
267 	--count;
268     if (count == r_size(&opt->table))
269 	return_error(e_limitcheck);
270     ref_assign_old(&opt->table, &tab[count], op, "makeoperator");
271     opt->nx_table[count] = name_index(op - 1);
272     op_index_ref(opt->base_index + count, op - 1);
273     opt->count = count + 1;
274     pop(1);
275     return 0;
276 }
277 
278 /* - .oserrno <int> */
279 private int
280 zoserrno(i_ctx_t *i_ctx_p)
281 {
282     os_ptr op = osp;
283 
284     push(1);
285     make_int(op, errno);
286     return 0;
287 }
288 
289 /* <int> .setoserrno - */
290 private int
291 zsetoserrno(i_ctx_t *i_ctx_p)
292 {
293     os_ptr op = osp;
294 
295     check_type(*op, t_integer);
296     errno = op->value.intval;
297     pop(1);
298     return 0;
299 }
300 
301 /* <int> .oserrorstring <string> true */
302 /* <int> .oserrorstring false */
303 private int
304 zoserrorstring(i_ctx_t *i_ctx_p)
305 {
306     os_ptr op = osp;
307     const char *str;
308     int code;
309     uint len;
310     byte ch;
311 
312     check_type(*op, t_integer);
313     str = gp_strerror((int)op->value.intval);
314     if (str == 0 || (len = strlen(str)) == 0) {
315 	make_false(op);
316 	return 0;
317     }
318     check_ostack(1);
319     code = string_to_ref(str, op, iimemory, ".oserrorstring");
320     if (code < 0)
321 	return code;
322     /* Strip trailing end-of-line characters. */
323     while ((len = r_size(op)) != 0 &&
324 	   ((ch = op->value.bytes[--len]) == '\r' || ch == '\n')
325 	)
326 	r_dec_size(op, 1);
327     push(1);
328     make_true(op);
329     return 0;
330 }
331 
332 /* <string> <bool> .setdebug - */
333 private int
334 zsetdebug(i_ctx_t *i_ctx_p)
335 {
336     os_ptr op = osp;
337     check_read_type(op[-1], t_string);
338     check_type(*op, t_boolean);
339     {
340 	int i;
341 
342 	for (i = 0; i < r_size(op - 1); i++)
343 	    gs_debug[op[-1].value.bytes[i] & 127] =
344 		op->value.boolval;
345     }
346     pop(2);
347     return 0;
348 }
349 
350 /* ------ Initialization procedure ------ */
351 
352 const op_def zmisc_op_defs[] =
353 {
354     {"1bind", zbind},
355     {"1getenv", zgetenv},
356     {"2.makeoperator", zmakeoperator},
357     {"0.oserrno", zoserrno},
358     {"1.oserrorstring", zoserrorstring},
359     {"0realtime", zrealtime},
360     {"1serialnumber", zserialnumber},
361     {"2.setdebug", zsetdebug},
362     {"1.setoserrno", zsetoserrno},
363     {"0usertime", zusertime},
364     op_def_end(0)
365 };
366