#ifndef lint static char sccsid[] = "@(#) PostScript.c 9.8 88/01/19"; #endif /*- * The PostScript interpreter. PostScript.c, Mon Dec 3 17:23:44 1984 * * Copyright (c) 1987 by Sun Microsystems, Inc. */ #ifdef GPROF_HOOKS /* * these labels are used to break up large functions into smaller pieces * for profiling with gprof or pm */ asm(".globl gP_LoopTop, gP_GetArray, gP_GetFile, gP_GetStopped"); asm(".globl gP_GetFixed, gP_GetReal, gP_GetForAll, gP_GetPathForAll"); asm(".globl gP_GetUndet, gP_GetMonitor, gP_ErrorBase, gP_Suspend"); asm(".globl gP_GetBuildI, gP_ExecTop, gP_ExecDefault, gP_ExecOp"); asm(".globl gP_ExecMagic, gP_ExecString, gP_ExecFile, gP_ExecKeyword"); asm(".globl gP_ExecArray, gP_ParseEncoded, gP_ParseDefault"); asm(".globl gP_TypeCaseBottom, gP_PopEstack, gP_ParseLoopTop"); asm(".globl gP_ExecCall, gP_ParseCloseBrace, gP_ParseSlash"); asm(".globl gP_ParseOpenParen, gP_ParseHexOpen, gP_ParseOpenBrace"); asm(".globl gP_ParseCloseBracket, gP_EndBuildI, gP_ExecArrayB, gP_ExecArrayC"); asm(".globl gP_ParseCommon, gP_ParseNumber, gP_ParseIdent, gP_ParseExecutable"); asm(".globl gP_ParseEncodedInt, gP_ParseEncodedIEEE, gP_ParseEncodedShStr"); asm(".globl gP_ParseEncodedStr, gP_ReadEncodedStr, gP_ParseEncodedSysCom"); asm(".globl gP_ParseEncodedUserCom, gP_DoEncodedUserCom, gP_ParseEnd"); #endif #include #include #ifdef REF #include #include #endif #include "PostScript.h" #include "primitives.h" #include "encoding.h" #include #ifndef pr_width /* #include */ #endif #include #ifdef PREVIEW #include #endif #ifdef PERFORMANCE extern int count_primitive_calls; extern int collect_lookup_data; extern unsigned long total_lookups; extern int high_dict_count; extern int low_dict_count; extern unsigned long total_dict_count; extern int dict_count; extern int high_compare_count; extern int low_compare_count; extern unsigned long total_compare_count; extern int compare_count; #endif extern int errno; int verbose; /* true iff PostScript should print out various tidbits about what it is currently up to */ struct execution_environment *current_process; /* The currently executing process */ struct object magic_variable_obj; struct object *free_cons; /* Free list of cons cells */ struct pixrect *empty_pixrect; struct body *system_dictionary; struct body *stdio_file; struct body *dict_table[32]; /* Maps types to corresponding "magic" dictionaries */ struct body *type_table[32]; /* type to name mapping table */ char delim[256]; /* A table indicating which characters are delimiters */ char translate_digit[256]; /* A table which maps characters to their value as a digit */ struct body *hash_table[hash_table_size]; short fract_overflows; /* Incremented by vfract primitives whenever an operation overflows */ #define binary_primitive(op,frop) \ switch (object_type_pair (optop[-2], optop[-1])) { \ case tp (fixed, fixed): \ fract_overflows = 0; \ { register fract temp = frop (optop[-2].value.fixed, optop[-1].value.fixed); \ if (fract_overflows==0) { \ optop[-2].value.fixed = temp; \ optop--; \ break; \ } \ } \ optop[-1].value.real = floatfr(optop[-1].value.fixed); \ case tp (fixed, real): \ optop[-2].value.real = floatfr(optop[-2].value.fixed) op optop[-1].value.real; \ optop[-2].type = real_type; \ optop--; \ break; \ case tp (real, fixed): \ optop[-2].value.real = optop[-2].value.real op floatfr(optop[-1].value.fixed); \ optop--; \ break; \ case tp (real, real): \ optop[-2].value.real = optop[-2].value.real op optop[-1].value.real; \ optop--; \ break; \ default: \ goto typecheck_error; \ } \ break; #define boolean_binary_primitive(op) \ switch (object_type_pair (optop[-2], optop[-1])) { \ case tp (fixed, fixed): \ case tp (boolean,boolean): \ optop[-2].value.fixed = optop[-2].value.fixed op optop[-1].value.fixed; \ optop--; \ break; \ default: \ goto typecheck_error; \ } \ break; #define compare_primitive(op) { \ register ret; \ if ((ret = PerformCompare (optop[-2], optop[-1])) < 0) \ goto typecheck_error; \ else { \ if (op&ret) new.value.fixed = fracti(1); \ goto boolean_result; \ } \ } PerformCompare(o1, o2) struct object o1, o2; { register ret; switch (object_type_pair(o1, o2)) { case tp(real, fixed): o2.value.real = floatfr(o2.value.fixed); goto docomp; case tp(fixed, real): o1.value.real = floatfr(o1.value.fixed); docomp: case tp(real, real): return o1.value.real < o2.value.real ? 4 : o1.value.real == o2.value.real ? 2 : 1; case tp(fixed, fixed): fract_overflows = 0; ret = vfrsub(o1.value.fixed, o2.value.fixed); if (fract_overflows) { o1.value.real = floatfr(o1.value.fixed); o2.value.real = floatfr(o2.value.fixed); goto docomp; } break; case tp(string, keyword) : return get_name(body_of(&o1)->body.string.chars + o1.value.substring.start, o1.value.substring.length) == body_of(&o2) ? 2 : 8; case tp(keyword, string) : return get_name(body_of(&o2)->body.string.chars + o2.value.substring.start, o2.value.substring.length) == body_of(&o1) ? 2 : 8; case tp(string, string):{ register char *p1, *p2; register l, tr; p1 = body_of(&o1)->body.string.chars + o1.value.substring.start; p2 = body_of(&o2)->body.string.chars + o2.value.substring.start; l = o1.value.substring.length; if ((ret = l - o2.value.substring.length) > 0) l = o2.value.substring.length; while (--l >= 0) if (tr = *p1++ - *p2++) { ret = tr; break; } } break; default: return -1; } return ret < 0 ? 4 : ret == 0 ? 2 : 1; } #define error(t) {ee->error_code = EXPAND(t)_error_code; goto handle_error;} #define overflow_check(n) \ if (optop + ((n)-1) >= ee->overflow) { \ ee->optop = optop; \ if (grow_stack(ee, n) < 0) \ goto stack_overflow; \ optop = ee->optop; \ } #ifdef PREVIEW int preview_verbose; static preview_depth; #endif #ifdef PROCEDURIZE_HASH hash_object_proc(obj) register struct object *obj; { register hash; hash = (object_word0(obj) & ValidObjectBits) ^ object_word1(obj); hash = hash ^ (hash >> 16); return(hash); } hash_index(hash, mod) register hash, mod; { return((((unsigned short) hash) % ((unsigned short) mod))*2); } #endif /* * This is the PostScript interpreter. Its implementation breaks almost every * rule of structured programming. This is a result of needing to support * multiple PostScript processes and a paranoia about performance. There are a * couple of #includes that you should think of as procedure calls. Life is * tough in the trenches. * */ /* * The PostScript interpreter has a fairly simple basic structure: * * while (1) { 1. Pick up an object to interpret 2. Execute it } * * Part 1, picking up an object to interpret is handled by the statement that * starts "switch (es->type)". es points to the top of the execution stack: a * stack of sources of executable objects. The switch determines what kind of * thing the object is being fetched from: an array, a string, ... * * Part 2, executing an object, is handled by the code that starts with the label * "execute_top". It does some tests and switches on the type of the object * being executed. * * All of this is complicated by the mechanism for blocking. If the process * needs to block, say by needing to read a new buffer from a socket or by * needing to wait for a message, then the interpreter needs to stop working * on this process and leave information around that lets it restart. This is * the "restart_state" variable: it is used as the index to a switch statement * that is executed when the interpreter starts up, so it won't necessarily be * intering the main loop of the interpreter at the top. There are cleaner * ways of doing this, but they can't be written in C! */ PostScript(ee) register struct execution_environment *ee; { register struct object *optop; register struct execution_stack *es = ee->pos; struct dictstack_ent *magic_target; /* The target object being accessed by * a magic variable */ struct execution_environment *outer_process = current_process; current_process = ee; optop = ee->optop; #ifdef FULLDEBUG { register struct object *p = optop; while (--p >= ee->underflow) assert(!object_has_body(p) || body_of(p)->refcnt > 0); assert(!cv_is_canvas(ee->gontext.canvas) || ((struct canvas *) ee->gontext.canvas)->refcnt > 0); } #endif if (ee->error_code) goto handle_error; #if QLOGFLAG qlog_chain_check(); #endif /* * Restart the interpreter where it left off last */ switch (ee->restart_state) { case 1: goto read_1; case 2: goto read_2; case 3: goto read_3; case 4: goto read_4; case 5: goto read_5; case 6: goto read_6; case 7: goto read_7; case 8: goto read_8; case 9: goto read_9; case 10: goto read_10; case 11: goto read_11; case 12: goto read_12; case 13: goto read_13; case 14: goto read_14; case 15: goto read_15; case 16: goto read_16; case 17: goto read_17; case 18: goto read_18; case 19: goto read_19; case 20: goto read_20; case 21: goto read_21; case 22: goto read_22; case 23: goto read_23; case 24: goto read_24; } /* The main loop of the interpreter */ while (1) { struct object new; #ifdef GPROF_HOOKS asm("gP_LoopTop:"); #endif retry_estack: #ifdef FULLDEBUG { register struct object *p = optop; while (--p >= ee->underflow) assert(!object_has_body(p) || body_of(p)->refcnt > 0); } #endif assert(ee->gontext.font == 0 || (int) ee->gontext.font->family != 0x4000000); #if QLOGFLAG qlog_chain_check(); #endif #ifdef QALLOC_SMASH_SIZE #include "qalloc.h" { struct QuickFreeblock **QuickFreeblock; int dsize = QALLOC_SMASH_SIZE; if ((QALLOC_SMASH_SIZE) > LargestBucketedChunk || *(QuickFreeblock = &QuickSlot(QALLOC_SMASH_SIZE)) == 0) { } else { if (QAllocDebug && &QuickSlot((*QuickFreeblock)->size)!=QuickFreeblock) AllocCorruption(0); } } #endif /* Pick up an object to execute */ switch (es->type) { case array_body_execution: #ifdef GPROF_HOOKS asm("gP_GetArray:"); #endif if (--es->env.array.left >= 0) { ee->execee = *es->env.array.ip++; object_incref(&ee->execee); } else { #ifdef PREVIEW preview_depth--; #endif pop_estack: #ifdef GPROF_HOOKS asm("gP_PopEstack:"); #endif object_decref(&es->executed); switch (es->type) { case forall_execution: object_decref(&es->env.forall); break; case monitor_execution: disentangle_monitor(ee, body_of(&es->env.monitor)); break; } if (--es < ee->execution_stack) goto suspend_process; goto retry_estack; } break; case file_execution:{ register PSFILE *f = es->env.file.file; /* be charitable and think of this as a procedure call */ #ifdef GPROF_HOOKS /* gP_GetFile defined in parse_file.h */ #endif #include "parse_file.h" break; } case stopped_execution: #ifdef GPROF_HOOKS asm("gP_GetStopped:"); #endif overflow_check(1); clear_object(optop); optop->type = boolean_type; optop->value.fixed = 0; optop++; goto pop_estack; case pathforall_execution: #ifdef GPROF_HOOKS asm("gP_GetPathForAll:"); #endif if (es->env.pathforall.pos >= es->env.pathforall.end) { ee->gontext.path.bottompos = es->env.pathforall.bottom; goto pop_estack; } { register struct path_element *patel; register i; register fract nlastop; patel = &ee->gontext.path.element[es->env.pathforall.pos++]; nlastop = patel->variation; if (patel->variation != CLOSEPATH_FLAG) { overflow_check(2); cs_fritransform(&ee->gontext, patel->pos.x, patel->pos.y, &optop[0].value.fixed, &optop[1].value.fixed); set_typed_object(optop, fixed_type); set_typed_object(optop + 1, fixed_type); optop += 2; } switch (patel->variation) { case MOVE_TO_FLAG: i = 0; break; case CLOSEPATH_FLAG: i = 3; break; case 0: if (es->env.pathforall.lastop == CLOSEPATH_FLAG) { i = 0; nlastop = MOVE_TO_FLAG; } else i = 1; break; default: if (es->env.pathforall.lastop == CLOSEPATH_FLAG) { i = 0; nlastop = MOVE_TO_FLAG; } else if (es->env.pathforall.lastop != MOVE_TO_FLAG && es->env.pathforall.lastop != 0) { i = 1; cs_fritransform(&ee->gontext, (patel->pos.x >> 1) + (patel[-1].pos.x >> 1), (patel->pos.y >> 1) + (patel[-1].pos.y >> 1), &optop[-2].value.fixed, &optop[-1].value.fixed); es->env.pathforall.pos--; nlastop = 0; } else if (es->executed.value.substring.length > 4) { overflow_check(1); set_fixed_object(optop, patel->variation); optop++; i = 4; } else { /* make curve! */ i = 1; } } es->env.pathforall.lastop = nlastop; ee->execee = body_of(&es->executed)->body.array.objects [es->executed.value.substring.start + i]; object_incref(&ee->execee); } goto execute_top; case fixed_for_execution: #ifdef GPROF_HOOKS asm("gP_GetFixed:"); #endif fract_overflows = 0; es->env.ifor.initial = vfradd(es->env.ifor.initial, es->env.ifor.increment); if (fract_overflows) goto pop_estack; if (es->env.ifor.increment >= 0) { if (es->env.ifor.initial > es->env.ifor.limit) goto pop_estack; } else if (es->env.ifor.initial < es->env.ifor.limit) goto pop_estack; clear_object(optop); if (es->env.ifor.stackpos) { overflow_check(1); optop->type = fixed_type; optop->value.fixed = es->env.ifor.initial; optop++; } ee->execee = es->executed; object_incref(&ee->execee); goto execute_top; case real_for_execution: #ifdef GPROF_HOOKS asm("gP_GetReal:"); #endif es->env.rfor.initial += es->env.rfor.increment; if (es->env.rfor.increment >= 0) { if (es->env.rfor.initial > es->env.rfor.limit) goto pop_estack; } else if (es->env.rfor.initial < es->env.rfor.limit) goto pop_estack; clear_object(optop); overflow_check(1); optop->type = real_type; optop->value.real = es->env.rfor.initial; optop++; ee->execee = es->executed; object_incref(&ee->execee); goto execute_top; case forall_execution: #ifdef GPROF_HOOKS asm("gP_GetForAll:"); #endif if (es->env.forall.value.substring.length <= 0) goto pop_estack; clear_object(optop); overflow_check(2); switch (es->env.forall.type) { case string_type: optop->type = fixed_type; optop->value.fixed = fracti((unsigned char) body_of(&es->env.forall)->body.string.chars[ es->env.forall.value.substring.start]); es->env.forall.value.substring.start++; es->env.forall.value.substring.length--; optop++; break; case array_type: *optop = body_of(&es->env.forall)->body.array.objects[ es->env.forall.value.substring.start]; object_incref(optop); es->env.forall.value.substring.start++; es->env.forall.value.substring.length--; optop++; break; default: { register struct object *p; register struct body *fbod; int found = 0; if (es->env.forall.type == dictionary_type) fbod = body_of(&es->env.forall); else fbod = dict_table[(int) es->env.forall.type]; p = &fbod->body.dict.objects[ es->env.forall.value.substring.start]; while (es->env.forall.value.substring.start < fbod->body.dict.size) { es->env.forall.value.substring.start += 2; if (p->type != null_type) { found = 1; break; } p += 2; } if (!found) goto pop_estack; optop[0] = *p++; object_incref(optop); optop++; if (p->type == magic_variable_type) { ee->optop = optop; ee->pos = es; (*p->value.def->function) (body_of(&es->env.forall), GET_MAGIC(p->value.def->index)); if (ee->error_code) goto handle_error; optop = ee->optop; } else { optop[0] = *p++; object_incref(optop); optop++; } } break; } ee->execee = es->executed; object_incref(&ee->execee); goto execute_top; case undetermined_execution: #ifdef GPROF_HOOKS asm("gP_GetUndet:"); #endif ee->execee = es->executed; es--; goto execute_top; case monitor_execution: { register struct body *b = body_of(&es->env.monitor); #ifdef GPROF_HOOKS asm("gP_GetMonitor:"); #endif if (es->env.monitor.executable) goto pop_estack; if (b->body.monitor.holder == 0 || b->body.monitor.holder == ee) { b->body.monitor.holder = ee; b->body.monitor.reentry_depth++; ee->execee = es->executed; object_incref(&es->executed); es->env.monitor.executable = 1; goto execute_top; } if (b->body.monitor.first == 0) b->body.monitor.first = ee; else b->body.monitor.last->next = ee; b->body.monitor.last = ee; ee->next = 0; ee->event = monitor_wait; ee->restart_state = 0; goto suspend_process; } case buildimage_execution: #ifdef GPROF_HOOKS asm("gP_GetBuildI:"); #endif if (!es->env.image.first) { if (optop[-1].type != string_type) goto typecheck_error; optop--; if (!buildmore(es, optop)) { create_object_from_image(optop, es->env.image.image); optop++; goto pop_estack; } } ee->execee = es->executed; object_incref(&es->executed); es->env.image.first = 0; goto execute_top; #ifdef GPROF_HOOKS asm("gP_EndBuildI:"); #endif case token_execution: if (!ee->seeking_token) { if (es->executed.type == string_type) { *optop++ = es->executed; object_incref(optop - 1); } *optop++ = ee->execee; } set_boolean_object(optop, fracti(!ee->seeking_token)); optop++; ee->seeking_token = 0; ee->fill = 0; goto pop_estack; case send_execution: ee->pos = es; complete_send(ee); es = ee->pos; goto pop_estack; default: goto pop_estack; } #ifdef GPROF_HOOKS asm("gP_TypeCaseBottom:"); #endif /* Execute the object */ if (ee->execee.type == array_type) { overflow_check(1); *optop++ = ee->execee; } else { execute_top: #ifdef GPROF_HOOKS asm("gP_ExecTop:"); #endif if (!ee->execee.executable) { overflow_check(1); *optop++ = ee->execee; } else { switch (ee->execee.type) { default: #ifdef GPROF_HOOKS asm("gP_ExecDefault:"); #endif overflow_check(1); *optop++ = ee->execee; break; case operator_type: #ifdef GPROF_HOOKS asm("gP_ExecOp:"); #endif if (optop - ee->execee.value.def->args_used < ee->underflow) goto stack_underflow; overflow_check(ee->execee.value.def->growth); clear_object(&new); #ifdef PERFORMANCE if (count_primitive_calls) primitive_called(ee->execee.value.def->pname); #endif /* * operators.c contains a big switch statement that implements * all of the primitive operators */ #include "operators.h" break; case called_operator_type: #ifdef GPROF_HOOKS asm("gP_ExecCall:"); #endif ee->optop = optop; ee->pos = es; if (optop - ee->execee.value.def->args_used < ee->underflow) goto stack_underflow; #ifdef PERFORMANCE if (count_primitive_calls) primitive_called(ee->execee.value.def->pname); #endif overflow_check(ee->execee.value.def->growth) (*ee->execee.value.def->function) (ee); optop = ee->optop; if ((es = ee->pos) == 0) goto suspend_process; if (ee->error_code) goto handle_error; break; case magic_variable_type: #ifdef GPROF_HOOKS asm("gP_ExecMagic:"); #endif ee->optop = optop; ee->pos = es; if (optop - ee->execee.value.def->args_used < ee->underflow) goto stack_underflow; overflow_check(ee->execee.value.def->growth); if (magic_target && magic_target->obj) (*ee->execee.value.def->function) (magic_target->obj, GET_MAGIC(ee->execee.value.def->index)); else ee->error_code = typecheck_error_code; magic_target = 0; optop = ee->optop; if ((es = ee->pos) == 0) goto suspend_process; if (ee->error_code) goto handle_error; break; case string_type: #ifdef GPROF_HOOKS asm("gP_ExecString:"); #endif if (es >= ee->limit) goto stack_overflow; es++; es->executed = ee->execee; es->type = file_execution; es->env.file.file = psio_sopen( (char *) body_of(&ee->execee)->body.string.chars + ee->execee.value.substring.start, ee->execee.value.substring.length, "r"); break; case file_type: { register struct body *f = body_of(&ee->execee); #ifdef GPROF_HOOKS asm("gP_ExecFile:"); #endif if (f->body.file.inbuf == 0 || psio_error(f->body.file.inbuf)) goto ioerror_error; if (es >= ee->limit) goto stack_overflow; es++; es->executed = ee->execee; es->type = file_execution; es->env.file.file = f->body.file.inbuf; if (f->body.file.outbuf) { incref(f); decref(ee->stdprnt); ee->stdprnt = f; psio_setneverblock(f->body.file.outbuf); /* See comment in objects.c.initialize_objects() */ } } break; case keyword_type: { register struct dictstack_ent *stackent = ee->dict_top; register hash; #ifdef GPROF_HOOKS asm("gP_ExecKeyword:"); #endif #ifdef PERFORMANCE /* * performance note: * the following increment is useful only if * collect_lookup_data is true; however, since a * compare and an increment take about the same * amount of time, I decided to dispense with * the compare */ total_lookups++; #endif hash_object(hash, &ee->execee); while (--stackent >= ee->dictionary_stack) { register struct object *ret = &stackent->body->body.array.objects[ hash_index(hash, stackent->body->body.array.size >> 1)]; #ifdef PERFORMANCE dict_count++; #endif while (ret->type != null_type) { #ifdef PERFORMANCE compare_count++; #endif if (equal_object(ret, &ee->execee)) { #ifdef PERFORMANCE if (collect_lookup_data) { if (dict_count > high_dict_count) high_dict_count = dict_count; if (dict_count < low_dict_count) low_dict_count = dict_count; total_dict_count += dict_count; dict_count = 0; if (compare_count > high_compare_count) high_compare_count = compare_count; if (compare_count < low_compare_count) low_compare_count = compare_count; total_compare_count += compare_count; compare_count = 0; } #endif #ifdef PREVIEW if (preview_verbose) { { int i; i = preview_depth; while (i--) printf(" "); } printf("%.*s ", (body_of(&ee->execee))->body.keyword.namelen, (body_of(&ee->execee))->body.keyword.name); /* XXX use decode_body() */ switch (ret[1].type) { case array_type: printf("(array)\n"); break; case operator_type: printf("(operator)\n"); break; case magic_variable_type: printf("(magic_variable)\n"); break; case string_type: printf("(string)\n"); break; case keyword_type: printf("(keyword)\n"); break; case file_type: printf("(file)\n"); break; case called_operator_type: printf("(called_operator)\n"); break; default: printf("(other)\n"); } } #endif /* PREVIEW */ object_incref(&ret[1]); ee->execee = ret[1]; magic_target = stackent; goto execute_top; } ret -= 2; if (ret < stackent->body->body.array.objects) ret = &stackent->body->body.array.objects[stackent->body->body.array.size - 2]; } } } goto undefined_error; case array_type: #ifdef GPROF_HOOKS asm("gP_ExecArray:"); #endif if (ee->error_code) goto handle_error; if (es >= ee->limit) goto stack_overflow; es++; #ifdef PREVIEW preview_depth++; #endif #ifdef GPROF_HOOKS asm("gP_ExecArrayB:"); #endif es->executed = ee->execee; es->type = array_body_execution; es->env.array.ip = body_of(&ee->execee)->body.array.objects + ee->execee.value.substring.start; es->env.array.left = ee->execee.value.substring.length; #ifdef PERFORMANCE body_of(&ee->execee)->body.array.exec_count++; #endif #ifdef GPROF_HOOKS asm("gP_ExecArrayC:"); #endif break; } /* end switch */ } /* end else */ } /* end else just before execute_top */ #ifdef QALLOC_SMASH_SIZE #include "qalloc.h" { struct QuickFreeblock **QuickFreeblock; int dsize = QALLOC_SMASH_SIZE; if ((QALLOC_SMASH_SIZE) > LargestBucketedChunk || *(QuickFreeblock = &QuickSlot(QALLOC_SMASH_SIZE)) == 0) { } else { if (QAllocDebug && &QuickSlot((*QuickFreeblock)->size)!=QuickFreeblock) AllocCorruption(0); } } #endif continue; #ifdef GPROF_HOOKS asm("gP_ErrorBase:"); #endif undefinedfilename_error: error(undefinedfilename); undefined_error: error(undefined); undefinedresult_error: error(undefinedresult); accept_error: error(accept); invalidexit_error: error(invalidexit); rangecheck_error: error(rangecheck); syntax_error: error(syntaxerror); stack_overflow: error(stackoverflow); stack_underflow: error(stackunderflow); nocurrentpoint_error: error(nocurrentpoint); ioerror_error: error(ioerror); handle_error: ee->pos = es; ee->operand_stack->body.array.used = optop - ee->operand_stack->body.array.objects; object_decref(&ee->last_executed); ee->last_executed = ee->execee; object_incref(&ee->last_executed); ee->optop = optop; ee->pos = es; really_handle_error(ee); es = ee->pos; optop = ee->optop; if (es < ee->execution_stack) goto suspend_process; goto execute_top; } suspend_process: { register PSFILE *psf; #ifdef GPROF_HOOKS asm("gP_Suspend:"); #endif psf = ee->stdprnt->body.file.outbuf; if (psf && psio_needsflush(psf)) { if (!psio_error(psf)) psio_flush(psf); if (psio_error(psf) && ee->error_code == no_error_code) ee->error_code = ioerror_error_code; } psf = ee->stddiag->body.file.outbuf; if (psf && psio_needsflush(psf)) { if (!psio_error(psf)) psio_flush(psf); if (psio_error(psf) && ee->error_code == no_error_code) ee->error_code = ioerror_error_code; } } #ifdef DEBUG if (psio_needsflush(psio_stdout)) psio_flush(psio_stdout); #endif ee->pos = es; ee->optop = optop; current_process = outer_process; #ifdef PREVIEW return (0); #endif } set_stop_primitive(ee) register struct execution_environment *ee; { /* The only reason that this procedure is here * is that the symbol "stop_primitive" is only * defined in this module */ set_typed_object(&ee->execee, operator_type); ee->execee.value.def = &operator_def[stop_primitive]; } #undef error #define type_keyword(t,k) type_table[(int) EXPAND(t)_type] = get_name(k, sizeof k - 1); initialize_0_PostScript() { register i; empty_pixrect = (struct pixrect *) cv_create_canvas(0, 0, 0); for (i = 0; i < 256; i++) translate_digit[i] = 99; for (i = '0'; i <= '9'; i++) translate_digit[i] = i - '0'; for (i = 'a'; i <= 'z'; i++) translate_digit[i] = translate_digit[i + ('A' - 'a')] = i - 'a' + 10; delim['('] = 1; delim[')'] = 1; delim['['] = 1; delim[']'] = 1; delim['{'] = 1; delim['}'] = 1; delim['<'] = 1; delim['>'] = 1; delim['/'] = 1; delim['%'] = 1; delim[' '] = 1; delim['\t'] = 1; delim['\n'] = 1; for (i = 128; i < 256; i++) delim[i] = 1; system_dictionary = new_dict(2000); for (i = 0; i < sizeof operator_def / sizeof operator_def[0]; i++) { register struct operator_def *p = &operator_def[i]; struct object no; struct object oo; set_typed_bodied_object(&no, keyword_type, get_name(p->pname, strlen(p->pname))); oo.value.def = p; set_typed_object(&oo, p->function ? called_operator_type : operator_type); oo.executable = 1; define_object_in_dictionary(no, oo, system_dictionary, 0); } type_keyword(null, "nulltype"); type_keyword(fixed, "integertype"); type_keyword(real, "realtype"); type_keyword(boolean, "booleantype"); type_keyword(color, "colortype"); type_keyword(cons, "constype"); /* type_keyword(save, "savetype"); */ type_keyword(marker, "marktype"); type_keyword(operator, "operatortype"); type_table[(int) called_operator_type] = type_table[(int) operator_type]; type_table[(int) magic_variable_type] = type_table[(int) operator_type]; /* type_keyword(called_operator, "operatortype"); */ type_keyword(keyword, "nametype"); type_keyword(string, "stringtype"); type_keyword(array, "arraytype"); type_keyword(dictionary, "dicttype"); type_keyword(font_id, "fonttype"); type_keyword(file, "filetype"); type_keyword(canvas, "canvastype"); type_keyword(process, "processtype"); type_keyword(event, "eventtype"); type_keyword(shape, "shapetype"); type_keyword(monitor, "monitortype"); type_keyword(graphicsstate, "graphicsstatetype"); type_keyword(cursor, "cursortype"); } char **Xargv; #ifndef PREVIEW main(argc, argv) char **argv; { register struct execution_environment *ee; char *initstr = argc > 1 ? argv[1] : "(NeWS/init.ps) (r) file cvx exec &main "; runPostScript(argv, initstr); RunScheduler(); } #endif #ifdef PREVIEW struct execution_environment * #endif runPostScript(argv, initstr) char **argv; char *initstr; { register struct execution_environment *ee; #ifdef PREVIEW bzero(&cv_cursor, sizeof(cv_cursor)); #endif Xargv = argv; define_operator_name.type = keyword_type; magic_variable_obj.type = magic_variable_type; magic_variable_obj.executable = 1; define_operator_obj.type = called_operator_type; define_operator_obj.executable = 1; apply_initialization(); ee = create_process(); ee->execution_stack[0].type = file_execution; ee->execution_stack[0].env.file.file = psio_sopen(initstr, strlen(initstr), "r"); ee->execution_stack[0].executed.type = null_type; ee->autobind = 1; #ifdef PREVIEW return (ee); #endif } error(s) char *s; { fprintf(stderr, "Error: %s\n", s); restore_keyboard(); exit(-1); }