Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
};