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 }; 457