#include "assert.h" #include "errors/errors.h" #include "errors/exceptions.h" #include "files/files.h" #include "interpreter/contexts.h" #include "interpreter/parameters/parameters.h" #include "interpreter/serverloop.h" #include "memory/virtualmemory.h" #include "object.h" #include "operators/operands.h" #include "stacks.h" #include "types/boolean.h" #include "types/composites/composites.h" #include "types/composites/postscript.h" #include "types/equality.h" #include "types/operator.h" enum job {filename, fileobject, encapsulation, administrator, values}; static void start(const object job) { assert(job.type == arraytype); assert(job.length == values); assert(job.array); job.array[fileobject] = namedfile(job.array[filename], string("r")); push(literal(job), executionstack); push(jobcontext, executionstack); push(postscript( "systemdict begin {" " (%stderr) (w) file [(%%[ Server: ) version ( ]%%) (\\n)] {1 index exch writestring} forall pop" " cvx executeonly stopped {" " handleerror" " (%stderr) (w) file" " (%%[ Flushing: rest of job (to end-of-file) will be ignored ]%%\\n)" " writestring" " //true" " } executeonly {" " //false" " } executeonly ifelse" "} bind executeonly end exec" ), executionstack); push(literal(job.array[fileobject]), executionstack); if (job.array[encapsulation].type == savetype) { push(postscript( "systemdict begin " "errordict /timeout {stop} bind executeonly put " "userdict /quit /stop load put " "end" ), executionstack); } } static object end(const object job) { if (job.type != arraytype) throw (typecheck); if (job.access != none) throw (invalidaccess); if (job.length != values) throw (rangecheck); assert(job.array); flushfile(stdout); clear(operandstack); clear(dictionarystack); if (job.array[filename].type != stringtype) throw (typecheck); if (job.array[fileobject].type != filetype) throw (typecheck); switch (job.array[encapsulation].type) { case savetype: { restore(job.array[encapsulation].state); break; } case nulltype: { switch (job.array[administrator].type) { case stringtype: { if (checkpassword(string(""), string("SystemParamsPassword"))) setpassword(readonly(job.array[administrator]), string("SystemParamsPassword")); } case nulltype: { break; } default: { throw (typecheck); } } break; } default: { throw (typecheck); } } job.array[fileobject] = null; job.array[encapsulation] = null; job.array[administrator] = null; return job; } static void serverloop(void) { const object environment = pop(executionstack); if (environment.type != arraytype) throw (typecheck); if (environment.access != none) throw (invalidaccess); if (environment.length != values) throw (rangecheck); assert(environment.array); const object flushing = pop(operandstack); if (flushing.type == booleantype) { if (flushing.boolean && environment.array[fileobject].type == filetype) flushfile(environment.array[fileobject]); } else { throw (typecheck); } const object job = end(environment); if (eq(job.array[filename], string("%stdin")) && terminal(stdin) == false) return; job.array[encapsulation] = (object){.type = savetype, .state = save()}; start(job); } const object jobcontext = staticoperator("@job", serverloop); void enterserverloop(const object input) { assert(input.type == stringtype); if (input.length) assert(input.string); if (enclosing(jobcontext, executionstack) == false) { if (vmlevel()) throw (VMerror); const object job = noaccess(copy[arraytype]((object){ .type = arraytype, .array = (object [values]){ [filename] = input, [encapsulation] = (object){.type = savetype, .state = save()} }, .length = values }, create[arraytype](values))); clear(operandstack); clear(dictionarystack); start(job); } } boolean encapsulated(const object job) { if (job.type != arraytype) throw (typecheck); if (job.access != none) throw (invalidaccess); if (job.length != values) throw (rangecheck); assert(job.array); switch (job.array[encapsulation].type) { case savetype: return true; case nulltype: return false; default: throw (typecheck); } } boolean startjob(const boolean persistent, const object password) { const enum access {denied, SetSystemParams, StartJob} permission = ( checkpassword(password, string("SystemParamsPassword")) ? SetSystemParams : checkpassword(password, string("StartJobPassword")) ? StartJob : denied ); if (permission == denied) { return false; } else { const object *context = 0; for (const object *operand = 0; operand = enclosingcontext(operand, executionstack);) { if (eq(*operand, jobcontext)) context = operand; } if (context && vmlevel() == (encapsulated(context[-1]) ? 1 : 0)) { const object *leaving = 0; while (leaving = enclosingcontext(leaving, executionstack)) { if (eq(*leaving, runcontext)) closefile(leaving[-1]); else if (leaving == context) break; } assert(leaving == context); clearto(executionstack, context); const object job = end(pop(executionstack)); if (persistent) { if (permission == SetSystemParams) { const object password = secret(string("SystemParamsPassword")); setpassword(string(""), string("SystemParamsPassword")); job.array[administrator] = noaccess(password); } job.array[encapsulation] = null; } else { job.array[encapsulation] = (object){.type = savetype, .state = save()}; } start(job); return true; } else { return false; } } }