1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: zmisc.c 8727 2008-05-13 03:58:10Z alexcher $ */
15
/* Miscellaneous operators */
21
#include "gscdefs.h" /* for gs_serialnumber */
26
#include "dstack.h" /* for name lookup in bind */
32
/**********************************************************************/
34
/* <proc> bind <proc> */
36
r_is_ex_oper(const ref *rp)
38
return (r_has_attr(rp, a_executable) &&
39
(r_btype(rp) == t_operator || r_type(rp) == t_oparray));
42
zbind(i_ctx_t *i_ctx_p)
51
if (!r_has_attr(op, a_write)) {
52
return 0; /* per PLRM3 */
59
defn = *op->value.const_refs;
62
return_op_typecheck(op);
68
* We must not make the top-level procedure read-only,
69
* but we must bind it even if it is read-only already.
71
* Here are the invariants for the following loop:
72
* `depth' elements have been pushed on the ostack;
73
* For i < depth, p = ref_stack_index(&o_stack, i):
74
* *p is an array (or packedarray) ref.
78
ref_packed *const tpp = (ref_packed *)bsp->value.packed; /* break const */
81
if (r_is_packed(tpp)) {
82
/* Check for a packed executable name */
85
if (r_packed_is_exec_name(&elt)) {
89
name_index_ref(imemory, packed_name_index(&elt),
91
if ((pvalue = dict_find_name(&nref)) != 0 &&
94
store_check_dest(bsp, pvalue);
96
* Always save the change, since this can only
99
ref_do_save(bsp, tpp, "bind");
100
*tpp = pt_tag(pt_executable_operator) +
104
bsp->value.packed = tpp + 1;
106
ref *const tp = bsp->value.refs++;
108
switch (r_type(tp)) {
109
case t_name: /* bind the name if an operator */
110
if (r_has_attr(tp, a_executable)) {
113
if ((pvalue = dict_find_name(tp)) != 0 &&
116
store_check_dest(bsp, pvalue);
117
ref_assign_old(bsp, tp, pvalue, "bind");
121
case t_array: /* push into array if writable */
122
if (!r_has_attr(tp, a_write))
126
if (r_has_attr(tp, a_executable)) {
127
/* Make reference read-only */
128
r_clear_attrs(tp, a_write);
130
/* Push a new stack block. */
136
code = ref_stack_push(&o_stack, 1);
138
ref_stack_pop(&o_stack, depth);
152
if (bsp < osbot) { /* Pop back to the previous stack block. */
154
ref_stack_pop_block(&o_stack);
162
/* - serialnumber <int> */
164
zserialnumber(i_ctx_t *i_ctx_p)
169
make_int(op, gs_serialnumber);
173
/* some FTS tests work better if realtime starts from 0 at boot time */
174
static long real_time_0[2];
177
zmisc_init_realtime(i_ctx_t * i_ctx_p)
179
gp_get_realtime(real_time_0);
183
/* - realtime <int> */
185
zrealtime(i_ctx_t *i_ctx_p)
190
gp_get_realtime(secs_ns);
191
secs_ns[1] -= real_time_0[1];
192
secs_ns[0] -= real_time_0[0];
194
make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
198
/* - usertime <int> */
200
zusertime(i_ctx_t *i_ctx_p)
205
gp_get_usertime(secs_ns);
207
make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
211
/* ---------------- Non-standard operators ---------------- */
213
/* <string> getenv <value_string> true */
214
/* <string> getenv false */
216
zgetenv(i_ctx_t *i_ctx_p)
223
check_read_type(*op, t_string);
224
str = ref_to_string(op, imemory, "getenv key");
226
return_error(e_VMerror);
227
if (gp_getenv(str, (char *)0, &len) > 0) { /* key missing */
228
ifree_string((byte *) str, r_size(op) + 1, "getenv key");
232
value = ialloc_string(len, "getenv value");
234
ifree_string((byte *) str, r_size(op) + 1, "getenv key");
235
return_error(e_VMerror);
237
DISCARD(gp_getenv(str, (char *)value, &len)); /* can't fail */
238
ifree_string((byte *) str, r_size(op) + 1, "getenv key");
239
/* Delete the stupid C string terminator. */
240
value = iresize_string(value, len, len - 1,
241
"getenv value"); /* can't fail */
243
make_string(op - 1, a_all | icurrent_space, len - 1, value);
248
/* <name> <proc> .makeoperator <oper> */
250
zmakeoperator(i_ctx_t *i_ctx_p)
257
check_type(op[-1], t_name);
259
switch (r_space(op)) {
261
opt = &op_array_table_global;
264
opt = &op_array_table_local;
267
return_error(e_invalidaccess);
270
tab = opt->table.value.refs;
272
* restore doesn't reset op_array_table.count, but it does
273
* remove entries from op_array_table.table. Since we fill
274
* the table in order, we can detect that a restore has occurred
275
* by checking whether what should be the most recent entry
276
* is occupied. If not, we scan backwards over the vacated entries
277
* to find the true end of the table.
279
while (count > 0 && r_has_type(&tab[count - 1], t_null))
281
if (count == r_size(&opt->table))
282
return_error(e_limitcheck);
283
ref_assign_old(&opt->table, &tab[count], op, "makeoperator");
284
opt->nx_table[count] = name_index(imemory, op - 1);
285
op_index_ref(opt->base_index + count, op - 1);
286
opt->count = count + 1;
291
/* - .oserrno <int> */
293
zoserrno(i_ctx_t *i_ctx_p)
302
/* <int> .setoserrno - */
304
zsetoserrno(i_ctx_t *i_ctx_p)
308
check_type(*op, t_integer);
309
errno = op->value.intval;
314
/* <int> .oserrorstring <string> true */
315
/* <int> .oserrorstring false */
317
zoserrorstring(i_ctx_t *i_ctx_p)
325
check_type(*op, t_integer);
326
str = gp_strerror((int)op->value.intval);
327
if (str == 0 || (len = strlen(str)) == 0) {
332
code = string_to_ref(str, op, iimemory, ".oserrorstring");
335
/* Strip trailing end-of-line characters. */
336
while ((len = r_size(op)) != 0 &&
337
((ch = op->value.bytes[--len]) == '\r' || ch == '\n')
345
/* <string> <bool> .setdebug - */
347
zsetdebug(i_ctx_t *i_ctx_p)
350
check_read_type(op[-1], t_string);
351
check_type(*op, t_boolean);
355
for (i = 0; i < r_size(op - 1); i++)
356
gs_debug[op[-1].value.bytes[i] & 127] =
363
/* There are a few cases where a customer/user might want CPSI behavior
364
* instead of the GS default behavior. cmyk_to_rgb and Type 1 char fill
365
* method are two that have come up so far. This operator allows a PS
366
* program to control the behavior without needing to recompile
368
* While this would better if it were in some context 'state', we use
369
* a global, which we don't really like, but at least it is better
370
* than a compile time #define, as in #USE_ADOBE_CMYK_RGB and allows
371
* us to easily test with/without and not require recompilation.
373
extern bool CPSI_mode; /* not worth polluting a header file */
375
/* <bool> .setCPSImode - */
377
zsetCPSImode(i_ctx_t *i_ctx_p)
380
check_type(*op, t_boolean);
381
CPSI_mode = op->value.boolval;
386
/* - .getCPSImode <bool> */
388
zgetCPSImode(i_ctx_t *i_ctx_p)
393
make_bool(op, CPSI_mode);
397
/* ------ gs persistent cache operators ------ */
398
/* these are for testing only. they're disabled in the normal build
399
* to prevent access to the cache by malicious postscript files
401
* use something like this:
402
* (value) (key) .pcacheinsert
403
* (key) .pcachequery { (\n) concatstrings print } if
408
/* <string> <string> .pcacheinsert */
410
zpcacheinsert(i_ctx_t *i_ctx_p)
417
check_read_type(*op, t_string);
419
key = op->value.bytes;
420
check_read_type(*(op - 1), t_string);
421
buflen = r_size(op - 1);
422
buffer = (op - 1)->value.bytes;
424
code = gp_cache_insert(0, key, keylen, buffer, buflen);
433
/* allocation callback for query result */
435
pcache_alloc_callback(void *userdata, int bytes)
437
i_ctx_t *i_ctx_p = (i_ctx_t*)userdata;
438
return ialloc_string(bytes, "pcache buffer");
441
/* <string> .pcachequery <string> true */
442
/* <string> .pcachequery false */
444
zpcachequery(i_ctx_t *i_ctx_p)
452
check_read_type(*op, t_string);
454
key = op->value.bytes;
455
len = gp_cache_query(GP_CACHE_TYPE_TEST, key, len, (void**)&string, &pcache_alloc_callback, i_ctx_p);
461
return_error(e_VMerror);
462
make_string(op, a_all | icurrent_space, len, string);
470
#endif /* DEBUG_CACHE */
472
/* ------ Initialization procedure ------ */
474
const op_def zmisc_op_defs[] =
477
{"1getenv", zgetenv},
478
{"2.makeoperator", zmakeoperator},
479
{"0.oserrno", zoserrno},
480
{"1.oserrorstring", zoserrorstring},
481
{"0realtime", zrealtime},
482
{"1serialnumber", zserialnumber},
483
{"2.setdebug", zsetdebug},
484
{"1.setoserrno", zsetoserrno},
485
{"0usertime", zusertime},
486
{"1.setCPSImode", zsetCPSImode},
487
{"0.getCPSImode", zgetCPSImode},
490
{"2.pcacheinsert", zpcacheinsert},
491
{"1.pcachequery", zpcachequery},
493
op_def_end(zmisc_init_realtime)