/* template proc scratch filenameforall - execute proc for all filenames matching template using scratch string */ static int xpost_op_filenameforall (Xpost_Context *ctx, Xpost_Object Tmp, Xpost_Object Proc, Xpost_Object Scr) { char *tmpbuf; glob_t *globbuf; Xpost_Object oglob; int ret; tmpbuf = alloca(Tmp.comp_.sz + 1); memcpy(tmpbuf, xpost_string_get_pointer(ctx, Tmp), Tmp.comp_.sz); tmpbuf[Tmp.comp_.sz] = '\0'; globbuf = malloc(sizeof *globbuf); if (!globbuf) return unregistered; ret = xpost_glob(tmpbuf, globbuf); if (ret != 0) { free(globbuf); return ioerror; } oglob.glob_.tag = globtype; oglob.glob_.off = 0; oglob.glob_.ptr = globbuf; xpost_op_contfilenameforall(ctx, oglob, Proc, xpost_object_cvlit(Scr)); return 0; }
/* obj cvlit obj set executable attribute in obj to literal (quoted) */ static int Acvlit(Xpost_Context *ctx, Xpost_Object o) { xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(o)); return 0; }
/* internal continuation operator for filenameforall */ static int xpost_op_contfilenameforall (Xpost_Context *ctx, Xpost_Object oglob, Xpost_Object Proc, Xpost_Object Scr) { glob_t *globbuf; char *str; char *src; int len; Xpost_Object interval; globbuf = oglob.glob_.ptr; if (oglob.glob_.off < globbuf->gl_pathc) { /* xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons(ctx, "contfilenameforall", NULL,0,0)); */ xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(ctx->opcode_shortcuts.contfilenameforall)); xpost_stack_push(ctx->lo, ctx->es, Scr); /* xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons(ctx, "cvx", NULL,0,0)); */ xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(ctx->opcode_shortcuts.cvx)); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvlit(Proc)); ++oglob.glob_.off; xpost_stack_push(ctx->lo, ctx->es, oglob); str = xpost_string_get_pointer(ctx, Scr); src = globbuf->gl_pathv[ oglob.glob_.off-1 ]; len = strlen(src); if (len > Scr.comp_.sz) return rangecheck; memcpy(str, src, len); interval = xpost_object_get_interval(Scr, 0, len); if (xpost_object_get_type(interval) == invalidtype) return rangecheck; xpost_stack_push(ctx->lo, ctx->os, interval); xpost_stack_push(ctx->lo, ctx->es, Proc); } else { xpost_glob_free(globbuf); /* reference has already been popped */ } return 0; }
static int packedarray (Xpost_Context *ctx, Xpost_Object n) { int i; Xpost_Object a, v; a = xpost_array_cons(ctx, n.int_.val); if (xpost_object_get_type(a) == nulltype) return VMerror; for (i=n.int_.val; i > 0; i--) { v = xpost_stack_pop(ctx->lo, ctx->os); if (xpost_object_get_type(v) == invalidtype) return stackunderflow; xpost_array_put(ctx, a, i-1, v); } a = xpost_object_set_access(ctx, xpost_object_cvlit(a), XPOST_OBJECT_TAG_ACCESS_READ_ONLY); xpost_stack_push(ctx->lo, ctx->os, a); return 0; }
/* string cvn name convert string to name */ static int Scvn(Xpost_Context *ctx, Xpost_Object s) { char *t; Xpost_Object name; t = alloca(s.comp_.sz+1); memcpy(t, xpost_string_get_pointer(ctx, s), s.comp_.sz); t[s.comp_.sz] = '\0'; name = xpost_name_cons(ctx, t); if (xpost_object_get_type(name) == invalidtype) return VMerror; if (xpost_object_is_exe(s)) name = xpost_object_cvx(name); else name = xpost_object_cvlit(name); xpost_stack_push(ctx->lo, ctx->os, name); return 0; }
/* filename mode file file create file object for filename with access mode */ static int xpost_op_string_mode_file (Xpost_Context *ctx, Xpost_Object fn, Xpost_Object mode) { Xpost_Object f; char *cfn, *cmode; int ret; cfn = alloca(fn.comp_.sz + 1); memcpy(cfn, xpost_string_get_pointer(ctx, fn), fn.comp_.sz); cfn[fn.comp_.sz] = '\0'; cmode = alloca(mode.comp_.sz + 1); memcpy(cmode, xpost_string_get_pointer(ctx, mode), mode.comp_.sz); cmode[mode.comp_.sz] = '\0'; ret = xpost_file_open(ctx->lo, cfn, cmode, &f); if (ret) return ret; xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(f)); return 0; }
/* set global pagesize, initialize eval's jump-tabl allocate global itpdata interpreter instance call xpost_interpreter_init which initializes the first context */ static int initalldata(const char *device) { int ret; initevaltype(); xpost_object_install_dict_get_access(xpost_dict_get_access); xpost_object_install_dict_set_access(xpost_dict_set_access); /* allocate the top-level itpdata data structure. */ null = xpost_object_cvlit(null); itpdata = malloc(sizeof*itpdata); if (!itpdata) { XPOST_LOG_ERR("itpdata=malloc failed"); return 0; } memset(itpdata, 0, sizeof*itpdata); /* allocate and initialize the first context structure and associated memory structures. populate OPTAB and systemdict with operators. push systemdict, globaldict, and userdict on dict stack */ ret = xpost_interpreter_init(itpdata, device); if (!ret) { return 0; } /* set global shortcut to context_0 (the only context in a single-threaded interpreter) TODO remove this variable */ xpost_ctx = &itpdata->ctab[0]; return 1; }
/* FIXME remove duplication of effort here and in bin/xpost_main.c (ie. there should be 1 table, not 2) Generates postscript code to initialize the selected device currentglobal false setglobal % allocate in local memory device_requires_loading? { loadXXXdevice } if % load if necessary userdict /DEVICE 612 792 newXXXdevice put % instantiate the device setglobal % reset previous allocation mode initialization of the device is deferred until the start procedure has initialized graphics (importantly, the ppmimage base class). the loadXXXdevice operators all specialize the ppmimage base class and so must wait until it is available. also creates the definitions PACKAGE_DATA_DIR PACKAGE_INSTALL_DIR and EXE_DIR */ static void setlocalconfig(Xpost_Context *ctx, Xpost_Object sd, const char *device, const char *outfile, const char *bufferin, char **bufferout, Xpost_Showpage_Semantics semantics, Xpost_Set_Size set_size, int width, int height) { const char *device_strings[][3] = { { "pgm", "", "newPGMIMAGEdevice" }, { "ppm", "", "newPPMIMAGEdevice" }, { "null", "", "newnulldevice" }, { "xcb", "loadxcbdevice", "newxcbdevice" }, { "gdi", "loadwin32device", "newwin32device" }, { "gl", "loadwin32device", "newwin32device" }, { "bgr", "loadbgrdevice", "newbgrdevice" }, { "raster", "loadrasterdevice", "newrasterdevice" }, { "png", "loadpngdevice", "newpngdevice" }, { "jpeg", "loadjpegdevice", "newjpegdevice" }, { NULL, NULL, NULL } }; const char *strtemplate = "currentglobal false setglobal " "%s userdict /DEVICE %s %s put " "setglobal"; Xpost_Object namenewdev; Xpost_Object newdevstr; int i; char *devstr; char *subdevice; char *dimensions; ctx->vmmode = GLOBAL; #ifdef _WIN32 xpost_dict_put(ctx, sd, xpost_name_cons(ctx, "WIN32"), xpost_bool_cons(1)); #endif devstr = strdup(device); /* Parse device string for mode selector "dev:mode" */ if ((subdevice=strchr(devstr, ':'))) { *subdevice++ = '\0'; xpost_dict_put(ctx, sd, xpost_name_cons(ctx, "SUBDEVICE"), xpost_object_cvlit(xpost_string_cons(ctx, strlen(subdevice), subdevice))); } /* define the /newdefaultdevice name called by /start */ for (i = 0; device_strings[i][0]; i++) { if (strcmp(devstr, device_strings[i][0]) == 0) { break; } } if (set_size == XPOST_USE_SIZE){ dimensions = malloc(2 + (int)ceil(log10(width)) + (int)ceil(log10(height))); sprintf(dimensions, "%d %d", width, height); } else { static char x[] = "612 792"; dimensions = x; } newdevstr = xpost_string_cons(ctx, strlen(strtemplate) - 6 + strlen(device_strings[i][1]) + strlen(dimensions) + strlen(device_strings[i][2]) + 1, NULL); sprintf(xpost_string_get_pointer(ctx, newdevstr), strtemplate, device_strings[i][1], dimensions, device_strings[i][2]); --newdevstr.comp_.sz; /* trim the '\0' */ namenewdev = xpost_name_cons(ctx, "newdefaultdevice"); xpost_dict_put(ctx, sd, namenewdev, xpost_object_cvx(newdevstr)); xpost_dict_put(ctx, sd, xpost_name_cons(ctx, "ShowpageSemantics"), xpost_int_cons(semantics)); if (outfile) { xpost_dict_put(ctx, sd, xpost_name_cons(ctx, "OutputFileName"), xpost_object_cvlit(xpost_string_cons(ctx, strlen(outfile), outfile))); } if (bufferin) { Xpost_Object s = xpost_object_cvlit(xpost_string_cons(ctx, sizeof(bufferin), NULL)); xpost_object_set_access(ctx, s, XPOST_OBJECT_TAG_ACCESS_NONE); memcpy(xpost_string_get_pointer(ctx, s), &bufferin, sizeof(bufferin)); xpost_dict_put(ctx, sd, xpost_name_cons(ctx, "OutputBufferIn"), s); } if (bufferout) { Xpost_Object s = xpost_object_cvlit(xpost_string_cons(ctx, sizeof(bufferout), NULL)); xpost_object_set_access(ctx, s, XPOST_OBJECT_TAG_ACCESS_NONE); memcpy(xpost_string_get_pointer(ctx, s), &bufferout, sizeof(bufferout)); xpost_dict_put(ctx, sd, xpost_name_cons(ctx, "OutputBufferOut"), s); } ctx->vmmode = LOCAL; free(devstr); }
/* called by mainloop() after propagated error codes. pushes postscript-level error procedures and resumes normal execution. */ static void _onerror(Xpost_Context *ctx, unsigned int err) { Xpost_Object sd; Xpost_Object ed; Xpost_Object dollarerror; if (err > unknownerror) err = unknownerror; if (!validate_context(ctx)) XPOST_LOG_ERR("context not valid"); if (itpdata->in_onerror > 5) { fprintf(stderr, "LOOP in error handler\nabort\n"); ++ctx->quit; /*exit(undefinedresult); */ } ++itpdata->in_onerror; #ifdef EMITONERROR fprintf(stderr, "err: %s\n", errorname[err]); #endif /* reset stack */ if ((xpost_object_get_type(ctx->currentobject) == operatortype) && (ctx->currentobject.tag & XPOST_OBJECT_TAG_DATA_FLAG_OPARGSINHOLD)) { int n = ctx->currentobject.mark_.pad0; int i; for (i = 0; i < n; i++) { xpost_stack_push(ctx->lo, ctx->os, xpost_stack_bottomup_fetch(ctx->lo, ctx->hold, i)); } } /* printf("1\n"); */ sd = xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 0); /* printf("2\n"); */ dollarerror = xpost_dict_get(ctx, sd, namedollarerror); if (xpost_object_get_type(dollarerror) == invalidtype) { XPOST_LOG_ERR("cannot load $error dict for error: %s", errorname[err]); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "stop"))); /*itpdata->in_onerror = 0; */ return; } /* printf("3\n"); */ /* printf("4\n"); */ /* printf("5\n"); */ xpost_stack_push(ctx->lo, ctx->os, ctx->currentobject); #if 0 /* printf("6\n"); */ xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(xpost_name_cons(ctx, errorname[err]))); /* printf("7\n"); */ xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "signalerror"))); #endif ed = xpost_dict_get(ctx, sd, nameerrordict); xpost_stack_push(ctx->lo, ctx->es, xpost_dict_get(ctx, ed, xpost_name_cons(ctx, errorname[err]))); /* printf("8\n"); */ itpdata->in_onerror = 0; }
/* execute ps program until quit, fall-through to quit, SHOWPAGE_RETURN semantic, or error (default action: message, purge and quit). */ XPAPI int xpost_run(Xpost_Context *ctx, Xpost_Input_Type input_type, const void *inputptr, size_t set_size) { Xpost_Object lsav = null; int llev = 0; unsigned int vs; const char *ps_str = NULL; const char *ps_file = NULL; const FILE *ps_file_ptr = NULL; int ret; Xpost_Object device; Xpost_Object semantic; switch(input_type) { case XPOST_INPUT_FILENAME: ps_file = inputptr; break; case XPOST_INPUT_STRING: ps_str = inputptr; ps_file_ptr = tmpfile(); if (set_size) fwrite(ps_str, 1, set_size, (FILE*)ps_file_ptr); else fwrite(ps_str, 1, strlen(ps_str), (FILE*)ps_file_ptr); rewind((FILE*)ps_file_ptr); break; case XPOST_INPUT_FILEPTR: ps_file_ptr = inputptr; break; case XPOST_INPUT_RESUME: /* resuming a returned session, skip startup */ goto run; } /* prime the exec stack so it starts with a 'start*' procedure, and if it ever gets to the bottom, it quits. These procedures are all defined in data/init.ps */ xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons(ctx, "quit", NULL,0,0)); /* if ps_file is NULL: if stdin is a tty `start` proc defined in init.ps runs `executive` which prompts for user input else 'startstdin' executes stdin but does not prompt if ps_file is not NULL: 'startfile' executes a named file wrapped in a stopped context with handleerror */ if (ps_file) { /*printf("ps_file\n"); */ xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(xpost_string_cons(ctx, strlen(ps_file), ps_file))); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "startfilename"))); } else if (ps_file_ptr) { xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(xpost_file_cons(ctx->lo, ps_file_ptr))); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "startfile"))); } else { if (xpost_isatty(fileno(stdin))) xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "start"))); else xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "startstdin"))); } (void) xpost_save_create_snapshot_object(ctx->gl); lsav = xpost_save_create_snapshot_object(ctx->lo); /* Run! */ run: ctx->quit = 0; ctx->state = C_RUN; ret = mainloop(ctx); semantic = xpost_dict_get(ctx, xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 0), xpost_name_cons(ctx, "ShowpageSemantics")); if (semantic.int_.val == XPOST_SHOWPAGE_RETURN) return ret == 1 ? yieldtocaller : 0; XPOST_LOG_INFO("destroying device"); device = xpost_dict_get(ctx, xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 2), xpost_name_cons(ctx, "DEVICE")); XPOST_LOG_INFO("device type=%s", xpost_object_type_names[xpost_object_get_type(device)]); /*xpost_operator_dump(ctx, 1); // is this pointer value constant? */ if (xpost_object_get_type(device) == arraytype){ XPOST_LOG_INFO("running proc"); xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons(ctx, "quit", NULL,0,0)); xpost_stack_push(ctx->lo, ctx->es, device); ctx->quit = 0; mainloop(ctx); device = xpost_stack_pop(ctx->lo, ctx->os); } if (xpost_object_get_type(device) == dicttype) { Xpost_Object Destroy; XPOST_LOG_INFO("destroying device dict"); Destroy = xpost_dict_get(ctx, device, xpost_name_cons(ctx, "Destroy")); if (xpost_object_get_type(Destroy) == operatortype) { int res; xpost_stack_push(ctx->lo, ctx->os, device); res = xpost_operator_exec(ctx, Destroy.mark_.padw); if (res) XPOST_LOG_ERR("%s error destroying device", errorname[res]); else XPOST_LOG_INFO("destroyed device"); } } xpost_save_restore_snapshot(ctx->gl); xpost_memory_table_get_addr(ctx->lo, XPOST_MEMORY_TABLE_SPECIAL_SAVE_STACK, &vs); if (xpost_object_get_type(lsav) == savetype) { for ( llev = xpost_stack_count(ctx->lo, vs); llev > lsav.save_.lev; llev-- ) { xpost_save_restore_snapshot(ctx->lo); } } return noerror; }