/* - exit - */ static int zexit(i_ctx_t *i_ctx_p) { os_ptr op = osp; ref_stack_enum_t rsenum; uint scanned = 0; ref_stack_enum_begin(&rsenum, &e_stack); do { uint used = rsenum.size; es_ptr ep = rsenum.ptr + used - 1; uint count = used; for (; count; count--, ep--) if (r_is_estack_mark(ep)) switch (estack_mark_index(ep)) { case es_for: pop_estack(i_ctx_p, scanned + (used - count + 1)); return o_pop_estack; case es_stopped: return_error(e_invalidexit); /* not a loop */ } scanned += used; } while (ref_stack_enum_next(&rsenum)); /* No mark, quit. (per Adobe documentation) */ push(2); return unmatched_exit(op, zexit); }
/* <key> where false */ int zwhere(i_ctx_t *i_ctx_p) { os_ptr op = osp; ref_stack_enum_t rsenum; check_op(1); ref_stack_enum_begin(&rsenum, &d_stack); do { const ref *const bot = rsenum.ptr; const ref *pdref = bot + rsenum.size; ref *pvalue; int code; while (pdref-- > bot) { check_dict_read(*pdref); code = dict_find(pdref, op, &pvalue); if (code < 0 && code != e_dictfull) return code; if (code > 0) { push(1); ref_assign(op - 1, pdref); make_true(op); return 0; } } } while (ref_stack_enum_next(&rsenum)); make_false(op); return 0; }
/* Get the current file from which the interpreter is reading. */ static ref * zget_current_file(i_ctx_t *i_ctx_p) { ref_stack_enum_t rsenum; ref_stack_enum_begin(&rsenum, &e_stack); do { uint count = rsenum.size; es_ptr ep = rsenum.ptr + count - 1; for (; count; count--, ep--) if (r_has_type_attrs(ep, t_file, a_executable)) return ep; } while (ref_stack_enum_next(&rsenum)); return 0; }
/* Return 0 if we can't find the mark. */ static uint op_show_find_index(i_ctx_t *i_ctx_p) { ref_stack_enum_t rsenum; uint count = 0; ref_stack_enum_begin(&rsenum, &e_stack); do { es_ptr ep = rsenum.ptr; uint size = rsenum.size; for (ep += size - 1; size != 0; size--, ep--, count++) if (r_is_estack_mark(ep) && estack_mark_index(ep) == es_show) return count; } while (ref_stack_enum_next(&rsenum)); return 0; /* no mark */ }
/* * If the new save level is zero, fix up the contents of a stack * by clearing the l_new bit in all the entries (since we can't tolerate * values with l_new set if the save level is zero). * Also, in any case, fix up the e-stack by replacing empty executable * strings and closed executable files that are newer than the save * with canonical ones that aren't. * * Note that this procedure is only called if restore_check_stack succeeded. */ static void restore_fix_stack(ref_stack_t * pstack, const alloc_save_t * asave, bool is_estack) { ref_stack_enum_t rsenum; ref_stack_enum_begin(&rsenum, pstack); do { ref *stkp = rsenum.ptr; uint size = rsenum.size; for (; size; stkp++, size--) { r_clear_attrs(stkp, l_new); /* always do it, no harm */ if (is_estack) { ref ofile; ref_assign(&ofile, stkp); switch (r_type(stkp)) { case t_string: if (r_size(stkp) == 0 && alloc_is_since_save(stkp->value.bytes, asave) ) { make_empty_const_string(stkp, avm_foreign); break; } continue; case t_file: if (alloc_is_since_save(stkp->value.pfile, asave) ) { make_invalid_file(stkp); break; } continue; default: continue; } r_copy_attrs(stkp, a_all | a_executable, &ofile); } } } while (ref_stack_enum_next(&rsenum)); }
/* * Count the number of elements down to and including the first 'stopped' * mark on the e-stack with a given mask. Return 0 if there is no 'stopped' * mark. */ static uint count_to_stopped(i_ctx_t *i_ctx_p, long mask) { ref_stack_enum_t rsenum; uint scanned = 0; ref_stack_enum_begin(&rsenum, &e_stack); do { uint used = rsenum.size; es_ptr ep = rsenum.ptr + used - 1; uint count = used; for (; count; count--, ep--) { if (r_is_estack_mark(ep)) { if (estack_mark_index(ep) == es_stopped && (ep[2].value.intval & mask) != 0) return scanned + (used - count + 1); } } scanned += used; } while (ref_stack_enum_next(&rsenum)); return 0; }
/* Check a stack to make sure all its elements are older than a save. */ static int restore_check_stack(const i_ctx_t *i_ctx_p, const ref_stack_t * pstack, const alloc_save_t * asave, bool is_estack) { ref_stack_enum_t rsenum; ref_stack_enum_begin(&rsenum, pstack); do { const ref *stkp = rsenum.ptr; uint size = rsenum.size; for (; size; stkp++, size--) { const void *ptr; switch (r_type(stkp)) { case t_array: /* * Zero-length arrays are a special case: see the * t_*array case (label rr:) in igc.c:gc_trace. */ if (r_size(stkp) == 0) { /*stkp->value.refs = (void *)0;*/ continue; } ptr = stkp->value.refs; break; case t_dictionary: ptr = stkp->value.pdict; break; case t_file: /* Don't check executable or closed literal */ /* files on the e-stack. */ { stream *s; if (is_estack && (r_has_attr(stkp, a_executable) || file_is_invalid(s, stkp)) ) continue; } ptr = stkp->value.pfile; break; case t_name: /* Names are special because of how they are allocated. */ if (alloc_name_is_since_save((const gs_memory_t *)pstack->memory, stkp, asave)) return_error(e_invalidrestore); continue; case t_string: /* Don't check empty executable strings */ /* on the e-stack. */ if (r_size(stkp) == 0 && r_has_attr(stkp, a_executable) && is_estack ) continue; ptr = stkp->value.bytes; break; case t_mixedarray: case t_shortarray: /* See the t_array case above. */ if (r_size(stkp) == 0) { /*stkp->value.packed = (void *)0;*/ continue; } ptr = stkp->value.packed; break; case t_device: ptr = stkp->value.pdevice; break; case t_fontID: case t_struct: case t_astruct: ptr = stkp->value.pstruct; break; case t_save: /* See the comment in isave.h regarding the following. */ if (i_ctx_p->language_level <= 2) continue; ptr = alloc_find_save(&gs_imemory, stkp->value.saveid); /* * Invalid save objects aren't supposed to be possible * in LL3, but just in case.... */ if (ptr == 0) return_error(e_invalidrestore); if (ptr == asave) continue; break; default: continue; } if (alloc_is_since_save(ptr, asave)) return_error(e_invalidrestore); } } while (ref_stack_enum_next(&rsenum)); return 0; /* OK */ }