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