1 /* Copyright (C) 1989, 1996, 1997, 1998, 1999, 2001 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: imain.c,v 1.41 2004/11/14 01:41:58 ghostgum Exp $ */
18 /* Common support for interpreter front ends */
19 #include "malloc_.h"
20 #include "memory_.h"
21 #include "string_.h"
22 #include "ghost.h"
23 #include "gp.h"
24 #include "gscdefs.h" /* for gs_init_file */
25 #include "gslib.h"
26 #include "gsmatrix.h" /* for gxdevice.h */
27 #include "gsutil.h" /* for bytes_compare */
28 #include "gxdevice.h"
29 #include "gxalloc.h"
30 #include "gzstate.h"
31 #include "ierrors.h"
32 #include "oper.h"
33 #include "iconf.h" /* for gs_init_* imports */
34 #include "idebug.h"
35 #include "idict.h"
36 #include "iname.h" /* for name_init */
37 #include "dstack.h"
38 #include "estack.h"
39 #include "ostack.h" /* put here for files.h */
40 #include "stream.h" /* for files.h */
41 #include "files.h"
42 #include "ialloc.h"
43 #include "iinit.h"
44 #include "strimpl.h" /* for sfilter.h */
45 #include "sfilter.h" /* for iscan.h */
46 #include "iscan.h"
47 #include "main.h"
48 #include "store.h"
49 #include "isave.h" /* for prototypes */
50 #include "interp.h"
51 #include "ivmspace.h"
52 #include "idisp.h" /* for setting display device callback */
53 #include "iplugin.h"
54
55 /* ------ Exported data ------ */
56
57 /** using backpointers retrieve minst from any memory pointer
58 *
59 */
60 gs_main_instance*
get_minst_from_memory(const gs_memory_t * mem)61 get_minst_from_memory(const gs_memory_t *mem)
62 {
63 #ifdef PSI_INCLUDED
64 extern gs_main_instance *ps_impl_get_minst( const gs_memory_t *mem );
65 return ps_impl_get_minst(mem);
66 #else
67 return (gs_main_instance*)mem->gs_lib_ctx->top_of_system;
68 #endif
69 }
70
71 /** construct main instance caller needs to retain */
72 gs_main_instance *
gs_main_alloc_instance(gs_memory_t * mem)73 gs_main_alloc_instance(gs_memory_t *mem)
74 {
75 gs_main_instance *minst = 0;
76 if (mem) {
77 minst = (gs_main_instance *) gs_alloc_bytes_immovable(mem,
78 sizeof(gs_main_instance),
79 "init_main_instance");
80 memcpy(minst, &gs_main_instance_init_values, sizeof(gs_main_instance_init_values));
81 minst->heap = mem;
82
83 # ifndef PSI_INCLUDED
84 mem->gs_lib_ctx->top_of_system = minst;
85 /* else top of system is pl_universe */
86 # endif
87 }
88 return minst;
89 }
90
91 /* ------ Forward references ------ */
92
93 private int gs_run_init_file(gs_main_instance *, int *, ref *);
94 private void print_resource_usage(const gs_main_instance *,
95 gs_dual_memory_t *, const char *);
96
97 /* ------ Initialization ------ */
98
99 /* Initialization to be done before anything else. */
100 int
gs_main_init0(gs_main_instance * minst,FILE * in,FILE * out,FILE * err,int max_lib_paths)101 gs_main_init0(gs_main_instance * minst, FILE * in, FILE * out, FILE * err,
102 int max_lib_paths)
103 {
104 ref *paths;
105
106 /* Do platform-dependent initialization. */
107 /* We have to do this as the very first thing, */
108 /* because it detects attempts to run 80N86 executables (N>0) */
109 /* on incompatible processors. */
110 gp_init();
111
112 /* Initialize the imager. */
113 # ifndef PSI_INCLUDED
114 /* Reset debugging flags */
115 memset(gs_debug, 0, 128);
116 gs_log_errors = 0; /* gs_debug['#'] = 0 */
117 # else
118 /* plmain settings remain in effect */
119 # endif
120 gp_get_usertime(minst->base_time);
121
122 /* Initialize the file search paths. */
123 paths = (ref *) gs_alloc_byte_array(minst->heap, max_lib_paths, sizeof(ref),
124 "lib_path array");
125 if (paths == 0) {
126 gs_lib_finit(1, e_VMerror, minst->heap);
127 return_error(e_VMerror);
128 }
129 make_array(&minst->lib_path.container, avm_foreign, max_lib_paths,
130 (ref *) gs_alloc_byte_array(minst->heap, max_lib_paths, sizeof(ref),
131 "lib_path array"));
132 make_array(&minst->lib_path.list, avm_foreign | a_readonly, 0,
133 minst->lib_path.container.value.refs);
134 minst->lib_path.env = 0;
135 minst->lib_path.final = 0;
136 minst->lib_path.count = 0;
137 minst->user_errors = 1;
138 minst->init_done = 0;
139 return 0;
140 }
141
142 /* Initialization to be done before constructing any objects. */
143 int
gs_main_init1(gs_main_instance * minst)144 gs_main_init1(gs_main_instance * minst)
145 {
146 if (minst->init_done < 1) {
147 gs_dual_memory_t idmem;
148 int code =
149 ialloc_init(&idmem, minst->heap,
150 minst->memory_chunk_size, gs_have_level2());
151
152 if (code < 0)
153 return code;
154 code = gs_lib_init1((gs_memory_t *)idmem.space_system);
155 if (code < 0)
156 return code;
157 alloc_save_init(&idmem);
158 {
159 gs_memory_t *mem = (gs_memory_t *)idmem.space_system;
160 name_table *nt = names_init(minst->name_table_size,
161 idmem.space_system);
162
163 if (nt == 0)
164 return_error(e_VMerror);
165 mem->gs_lib_ctx->gs_name_table = nt;
166 code = gs_register_struct_root(mem, NULL,
167 (void **)&mem->gs_lib_ctx->gs_name_table,
168 "the_gs_name_table");
169 if (code < 0)
170 return code;
171 }
172 code = obj_init(&minst->i_ctx_p, &idmem); /* requires name_init */
173 if (code < 0)
174 return code;
175 code = i_plugin_init(minst->i_ctx_p);
176 if (code < 0)
177 return code;
178 minst->init_done = 1;
179 }
180 return 0;
181 }
182
183 /* Initialization to be done before running any files. */
184 private void
init2_make_string_array(i_ctx_t * i_ctx_p,const ref * srefs,const char * aname)185 init2_make_string_array(i_ctx_t *i_ctx_p, const ref * srefs, const char *aname)
186 {
187 const ref *ifp = srefs;
188 ref ifa;
189
190 for (; ifp->value.bytes != 0; ifp++);
191 make_tasv(&ifa, t_array, a_readonly | avm_foreign,
192 ifp - srefs, const_refs, srefs);
193 initial_enter_name(aname, &ifa);
194 }
195
196 /*
197 * Invoke the interpreter, handling stdio callouts
198 * e_NeedStdin, e_NeedStdout and e_NeedStderr.
199 * We don't yet pass callouts all the way out because they
200 * occur within gs_main_init2() and swproc().
201 */
202 private int
gs_main_interpret(gs_main_instance * minst,ref * pref,int user_errors,int * pexit_code,ref * perror_object)203 gs_main_interpret(gs_main_instance *minst, ref * pref, int user_errors,
204 int *pexit_code, ref * perror_object)
205 {
206 i_ctx_t *i_ctx_p;
207 ref refnul;
208 ref refpop;
209 int code;
210
211 /* set interpreter pointer to lib_path */
212 minst->i_ctx_p->lib_path = &minst->lib_path;
213
214 code = gs_interpret(&minst->i_ctx_p, pref,
215 user_errors, pexit_code, perror_object);
216 while ((code == e_NeedStdin) || (code == e_NeedStdout) ||
217 (code == e_NeedStderr)) {
218 i_ctx_p = minst->i_ctx_p;
219 if (code == e_NeedStdout) {
220 /*
221 * On entry:
222 * esp[0] = string, data to write to stdout
223 * esp[-1] = bool, EOF (ignored)
224 * esp[-2] = array, procedure (ignored)
225 * esp[-3] = file, stdout stream
226 * We print the string then pop these 4 items.
227 */
228 if (r_type(&esp[0]) == t_string) {
229 const char *str = (const char *)(esp[0].value.const_bytes);
230 int count = esp[0].tas.rsize;
231 int rcode = 0;
232 if (str != NULL)
233 rcode = outwrite(imemory, str, count);
234 if (rcode < 0)
235 return_error(e_ioerror);
236 }
237
238 /* On return, we need to set
239 * osp[-1] = string buffer,
240 * osp[0] = file
241 */
242 gs_push_string(minst, (byte *)minst->stdout_buf,
243 sizeof(minst->stdout_buf), false);
244 gs_push_integer(minst, 0); /* push integer */
245 osp[0] = esp[-3]; /* then replace with file */
246 /* remove items from execution stack */
247 esp -= 4;
248 }
249 else if (code == e_NeedStderr) {
250 if (r_type(&esp[0]) == t_string) {
251 const char *str = (const char *)(esp[0].value.const_bytes);
252 int count = esp[0].tas.rsize;
253 int rcode = 0;
254 if (str != NULL)
255 rcode = errwrite(str, count);
256 if (rcode < 0)
257 return_error(e_ioerror);
258 }
259 gs_push_string(minst, (byte *)minst->stderr_buf,
260 sizeof(minst->stderr_buf), false);
261 gs_push_integer(minst, 0);
262 osp[0] = esp[-3];
263 esp -= 4;
264 }
265 else if (code == e_NeedStdin) {
266 int count = sizeof(minst->stdin_buf);
267 /*
268 * On entry:
269 * esp[0] = array, procedure (ignored)
270 * esp[-1] = file, stdin stream
271 * We read from stdin then pop these 2 items.
272 */
273 if (minst->heap->gs_lib_ctx->stdin_fn)
274 count = (*minst->heap->gs_lib_ctx->stdin_fn)
275 (minst->heap->gs_lib_ctx->caller_handle,
276 minst->stdin_buf, count);
277 else
278 count = gp_stdin_read(minst->stdin_buf, count,
279 minst->heap->gs_lib_ctx->stdin_is_interactive,
280 minst->heap->gs_lib_ctx->fstdin);
281 if (count < 0)
282 return_error(e_ioerror);
283
284 /* On return, we need to set
285 * osp[-1] = string buffer,
286 * osp[0] = file
287 */
288 gs_push_string(minst, (byte *)minst->stdin_buf, count, false);
289 gs_push_integer(minst, 0); /* push integer */
290 osp[0] = esp[-1]; /* then replace with file */
291 /* remove items from execution stack */
292 esp -= 2;
293 }
294 /*
295 * To resume the interpreter, we call gs_interpret with a null ref.
296 * This copies the literal null onto the operand stack.
297 * To remove this we push a zpop onto the execution stack.
298 */
299 make_null(&refnul);
300 make_oper(&refpop, 0, zpop);
301 esp += 1;
302 *esp = refpop;
303 code = gs_interpret(&minst->i_ctx_p, &refnul,
304 user_errors, pexit_code, perror_object);
305 }
306 return code;
307 }
308
309 int
gs_main_init2(gs_main_instance * minst)310 gs_main_init2(gs_main_instance * minst)
311 {
312 i_ctx_t *i_ctx_p;
313 int code = gs_main_init1(minst);
314
315 if (code < 0)
316 return code;
317 i_ctx_p = minst->i_ctx_p;
318 if (minst->init_done < 2) {
319 int code, exit_code;
320 ref error_object;
321
322 code = zop_init(i_ctx_p);
323 if (code < 0)
324 return code;
325 {
326 /*
327 * gs_iodev_init has to be called here (late), rather than
328 * with the rest of the library init procedures, because of
329 * some hacks specific to MS Windows for patching the
330 * stdxxx IODevices.
331 */
332 extern init_proc(gs_iodev_init);
333
334 code = gs_iodev_init(imemory);
335 if (code < 0)
336 return code;
337 }
338 code = op_init(i_ctx_p); /* requires obj_init */
339 if (code < 0)
340 return code;
341
342 /* Set up the array of additional initialization files. */
343 init2_make_string_array(i_ctx_p, gs_init_file_array, "INITFILES");
344 /* Set up the array of emulator names. */
345 init2_make_string_array(i_ctx_p, gs_emulator_name_array, "EMULATORS");
346 /* Pass the search path. */
347 code = initial_enter_name("LIBPATH", &minst->lib_path.list);
348 if (code < 0)
349 return code;
350
351 /* Execute the standard initialization file. */
352 code = gs_run_init_file(minst, &exit_code, &error_object);
353 if (code < 0)
354 return code;
355 minst->init_done = 2;
356 i_ctx_p = minst->i_ctx_p; /* init file may change it */
357 /* NB this is to be done with device parameters
358 * both minst->display and display_set_callback() are going away
359 */
360 if (minst->display)
361 code = display_set_callback(minst, minst->display);
362
363 if (code < 0)
364 return code;
365 }
366 if (gs_debug_c(':'))
367 print_resource_usage(minst, &gs_imemory, "Start");
368 gp_readline_init(&minst->readline_data, imemory_system);
369 return 0;
370 }
371
372 /* ------ Search paths ------ */
373
374 /* Internal routine to add a set of directories to a search list. */
375 /* Returns 0 or an error code. */
376 private int
file_path_add(gs_file_path * pfp,const char * dirs)377 file_path_add(gs_file_path * pfp, const char *dirs)
378 {
379 uint len = r_size(&pfp->list);
380 const char *dpath = dirs;
381
382 if (dirs == 0)
383 return 0;
384 for (;;) { /* Find the end of the next directory name. */
385 const char *npath = dpath;
386
387 while (*npath != 0 && *npath != gp_file_name_list_separator)
388 npath++;
389 if (npath > dpath) {
390 if (len == r_size(&pfp->container))
391 return_error(e_limitcheck);
392 make_const_string(&pfp->container.value.refs[len],
393 avm_foreign | a_readonly,
394 npath - dpath, (const byte *)dpath);
395 ++len;
396 }
397 if (!*npath)
398 break;
399 dpath = npath + 1;
400 }
401 r_set_size(&pfp->list, len);
402 return 0;
403 }
404
405 /* Add a library search path to the list. */
406 int
gs_main_add_lib_path(gs_main_instance * minst,const char * lpath)407 gs_main_add_lib_path(gs_main_instance * minst, const char *lpath)
408 {
409 /* Account for the possibility that the first element */
410 /* is gp_current_directory name added by set_lib_paths. */
411 int first_is_here =
412 (r_size(&minst->lib_path.list) != 0 &&
413 minst->lib_path.container.value.refs[0].value.bytes ==
414 (const byte *)gp_current_directory_name ? 1 : 0);
415 int code;
416
417 r_set_size(&minst->lib_path.list, minst->lib_path.count +
418 first_is_here);
419 code = file_path_add(&minst->lib_path, lpath);
420 minst->lib_path.count = r_size(&minst->lib_path.list) - first_is_here;
421 if (code < 0)
422 return code;
423 return gs_main_set_lib_paths(minst);
424 }
425
426 /* ------ Execution ------ */
427
428 /* Complete the list of library search paths. */
429 /* This may involve adding or removing the current directory */
430 /* as the first element. */
431 int
gs_main_set_lib_paths(gs_main_instance * minst)432 gs_main_set_lib_paths(gs_main_instance * minst)
433 {
434 ref *paths = minst->lib_path.container.value.refs;
435 int first_is_here =
436 (r_size(&minst->lib_path.list) != 0 &&
437 paths[0].value.bytes == (const byte *)gp_current_directory_name ? 1 : 0);
438 int count = minst->lib_path.count;
439 int code = 0;
440
441 if (minst->search_here_first) {
442 if (!(first_is_here ||
443 (r_size(&minst->lib_path.list) != 0 &&
444 !bytes_compare((const byte *)gp_current_directory_name,
445 strlen(gp_current_directory_name),
446 paths[0].value.bytes,
447 r_size(&paths[0]))))
448 ) {
449 memmove(paths + 1, paths, count * sizeof(*paths));
450 make_const_string(paths, avm_foreign | a_readonly,
451 strlen(gp_current_directory_name),
452 (const byte *)gp_current_directory_name);
453 }
454 } else {
455 if (first_is_here)
456 memmove(paths, paths + 1, count * sizeof(*paths));
457 }
458 r_set_size(&minst->lib_path.list,
459 count + (minst->search_here_first ? 1 : 0));
460 if (minst->lib_path.env != 0)
461 code = file_path_add(&minst->lib_path, minst->lib_path.env);
462 if (minst->lib_path.final != 0 && code >= 0)
463 code = file_path_add(&minst->lib_path, minst->lib_path.final);
464 return code;
465 }
466
467 /* Open a file, using the search paths. */
468 int
gs_main_lib_open(gs_main_instance * minst,const char * file_name,ref * pfile)469 gs_main_lib_open(gs_main_instance * minst, const char *file_name, ref * pfile)
470 {
471 /* This is a separate procedure only to avoid tying up */
472 /* extra stack space while running the file. */
473 i_ctx_t *i_ctx_p = minst->i_ctx_p;
474 #define maxfn 200
475 byte fn[maxfn];
476 uint len;
477
478 return lib_file_open( &minst->lib_path,
479 NULL /* Don't check permissions here, because permlist
480 isn't ready running init files. */
481 , file_name, strlen(file_name), fn, maxfn,
482 &len, pfile, imemory);
483 }
484
485 /* Open and execute a file. */
486 int
gs_main_run_file(gs_main_instance * minst,const char * file_name,int user_errors,int * pexit_code,ref * perror_object)487 gs_main_run_file(gs_main_instance * minst, const char *file_name, int user_errors, int *pexit_code, ref * perror_object)
488 {
489 ref initial_file;
490 int code = gs_main_run_file_open(minst, file_name, &initial_file);
491
492 if (code < 0)
493 return code;
494 return gs_main_interpret(minst, &initial_file, user_errors,
495 pexit_code, perror_object);
496 }
497 int
gs_main_run_file_open(gs_main_instance * minst,const char * file_name,ref * pfref)498 gs_main_run_file_open(gs_main_instance * minst, const char *file_name, ref * pfref)
499 {
500 gs_main_set_lib_paths(minst);
501 if (gs_main_lib_open(minst, file_name, pfref) < 0) {
502 eprintf1("Can't find initialization file %s.\n", file_name);
503 return_error(e_Fatal);
504 }
505 r_set_attrs(pfref, a_execute + a_executable);
506 return 0;
507 }
508
509 /* Open and run the very first initialization file. */
510 private int
gs_run_init_file(gs_main_instance * minst,int * pexit_code,ref * perror_object)511 gs_run_init_file(gs_main_instance * minst, int *pexit_code, ref * perror_object)
512 {
513 i_ctx_t *i_ctx_p = minst->i_ctx_p;
514 ref ifile;
515 ref first_token;
516 int code;
517 scanner_state state;
518
519 gs_main_set_lib_paths(minst);
520 if (gs_init_string_sizeof == 0) { /* Read from gs_init_file. */
521 code = gs_main_run_file_open(minst, gs_init_file, &ifile);
522 } else { /* Read from gs_init_string. */
523 code = file_read_string(gs_init_string, gs_init_string_sizeof, &ifile,
524 iimemory);
525 }
526 if (code < 0) {
527 *pexit_code = 255;
528 return code;
529 }
530 /* Check to make sure the first token is an integer */
531 /* (for the version number check.) */
532 scanner_state_init(&state, false);
533 code = scan_token(i_ctx_p, ifile.value.pfile, &first_token,
534 &state);
535 if (code != 0 || !r_has_type(&first_token, t_integer)) {
536 eprintf1("Initialization file %s does not begin with an integer.\n", gs_init_file);
537 *pexit_code = 255;
538 return_error(e_Fatal);
539 }
540 *++osp = first_token;
541 r_set_attrs(&ifile, a_executable);
542 return gs_main_interpret(minst, &ifile, minst->user_errors,
543 pexit_code, perror_object);
544 }
545
546 /* Run a string. */
547 int
gs_main_run_string(gs_main_instance * minst,const char * str,int user_errors,int * pexit_code,ref * perror_object)548 gs_main_run_string(gs_main_instance * minst, const char *str, int user_errors,
549 int *pexit_code, ref * perror_object)
550 {
551 return gs_main_run_string_with_length(minst, str, (uint) strlen(str),
552 user_errors,
553 pexit_code, perror_object);
554 }
555 int
gs_main_run_string_with_length(gs_main_instance * minst,const char * str,uint length,int user_errors,int * pexit_code,ref * perror_object)556 gs_main_run_string_with_length(gs_main_instance * minst, const char *str,
557 uint length, int user_errors, int *pexit_code, ref * perror_object)
558 {
559 int code;
560
561 code = gs_main_run_string_begin(minst, user_errors,
562 pexit_code, perror_object);
563 if (code < 0)
564 return code;
565 code = gs_main_run_string_continue(minst, str, length, user_errors,
566 pexit_code, perror_object);
567 if (code != e_NeedInput)
568 return code;
569 return gs_main_run_string_end(minst, user_errors,
570 pexit_code, perror_object);
571 }
572
573 /* Set up for a suspendable run_string. */
574 int
gs_main_run_string_begin(gs_main_instance * minst,int user_errors,int * pexit_code,ref * perror_object)575 gs_main_run_string_begin(gs_main_instance * minst, int user_errors,
576 int *pexit_code, ref * perror_object)
577 {
578 const char *setup = ".runstringbegin";
579 ref rstr;
580 int code;
581
582 gs_main_set_lib_paths(minst);
583 make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
584 strlen(setup), (const byte *)setup);
585 code = gs_main_interpret(minst, &rstr, user_errors, pexit_code,
586 perror_object);
587 return (code == e_NeedInput ? 0 : code == 0 ? e_Fatal : code);
588 }
589 /* Continue running a string with the option of suspending. */
590 int
gs_main_run_string_continue(gs_main_instance * minst,const char * str,uint length,int user_errors,int * pexit_code,ref * perror_object)591 gs_main_run_string_continue(gs_main_instance * minst, const char *str,
592 uint length, int user_errors, int *pexit_code, ref * perror_object)
593 {
594 ref rstr;
595
596 if (length == 0)
597 return 0; /* empty string signals EOF */
598 make_const_string(&rstr, avm_foreign | a_readonly, length,
599 (const byte *)str);
600 return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
601 perror_object);
602 }
603 /* Signal EOF when suspended. */
604 int
gs_main_run_string_end(gs_main_instance * minst,int user_errors,int * pexit_code,ref * perror_object)605 gs_main_run_string_end(gs_main_instance * minst, int user_errors,
606 int *pexit_code, ref * perror_object)
607 {
608 ref rstr;
609
610 make_empty_const_string(&rstr, avm_foreign | a_readonly);
611 return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
612 perror_object);
613 }
614
615 /* ------ Operand stack access ------ */
616
617 /* These are built for comfort, not for speed. */
618
619 private int
push_value(gs_main_instance * minst,ref * pvalue)620 push_value(gs_main_instance *minst, ref * pvalue)
621 {
622 i_ctx_t *i_ctx_p = minst->i_ctx_p;
623 int code = ref_stack_push(&o_stack, 1);
624
625 if (code < 0)
626 return code;
627 *ref_stack_index(&o_stack, 0L) = *pvalue;
628 return 0;
629 }
630
631 int
gs_push_boolean(gs_main_instance * minst,bool value)632 gs_push_boolean(gs_main_instance * minst, bool value)
633 {
634 ref vref;
635
636 make_bool(&vref, value);
637 return push_value(minst, &vref);
638 }
639
640 int
gs_push_integer(gs_main_instance * minst,long value)641 gs_push_integer(gs_main_instance * minst, long value)
642 {
643 ref vref;
644
645 make_int(&vref, value);
646 return push_value(minst, &vref);
647 }
648
649 int
gs_push_real(gs_main_instance * minst,floatp value)650 gs_push_real(gs_main_instance * minst, floatp value)
651 {
652 ref vref;
653
654 make_real(&vref, value);
655 return push_value(minst, &vref);
656 }
657
658 int
gs_push_string(gs_main_instance * minst,byte * chars,uint length,bool read_only)659 gs_push_string(gs_main_instance * minst, byte * chars, uint length,
660 bool read_only)
661 {
662 ref vref;
663
664 make_string(&vref, avm_foreign | (read_only ? a_readonly : a_all),
665 length, (byte *) chars);
666 return push_value(minst, &vref);
667 }
668
669 private int
pop_value(i_ctx_t * i_ctx_p,ref * pvalue)670 pop_value(i_ctx_t *i_ctx_p, ref * pvalue)
671 {
672 if (!ref_stack_count(&o_stack))
673 return_error(e_stackunderflow);
674 *pvalue = *ref_stack_index(&o_stack, 0L);
675 return 0;
676 }
677
678 int
gs_pop_boolean(gs_main_instance * minst,bool * result)679 gs_pop_boolean(gs_main_instance * minst, bool * result)
680 {
681 i_ctx_t *i_ctx_p = minst->i_ctx_p;
682 ref vref;
683 int code = pop_value(i_ctx_p, &vref);
684
685 if (code < 0)
686 return code;
687 check_type_only(vref, t_boolean);
688 *result = vref.value.boolval;
689 ref_stack_pop(&o_stack, 1);
690 return 0;
691 }
692
693 int
gs_pop_integer(gs_main_instance * minst,long * result)694 gs_pop_integer(gs_main_instance * minst, long *result)
695 {
696 i_ctx_t *i_ctx_p = minst->i_ctx_p;
697 ref vref;
698 int code = pop_value(i_ctx_p, &vref);
699
700 if (code < 0)
701 return code;
702 check_type_only(vref, t_integer);
703 *result = vref.value.intval;
704 ref_stack_pop(&o_stack, 1);
705 return 0;
706 }
707
708 int
gs_pop_real(gs_main_instance * minst,float * result)709 gs_pop_real(gs_main_instance * minst, float *result)
710 {
711 i_ctx_t *i_ctx_p = minst->i_ctx_p;
712 ref vref;
713 int code = pop_value(i_ctx_p, &vref);
714
715 if (code < 0)
716 return code;
717 switch (r_type(&vref)) {
718 case t_real:
719 *result = vref.value.realval;
720 break;
721 case t_integer:
722 *result = (float)(vref.value.intval);
723 break;
724 default:
725 return_error(e_typecheck);
726 }
727 ref_stack_pop(&o_stack, 1);
728 return 0;
729 }
730
731 int
gs_pop_string(gs_main_instance * minst,gs_string * result)732 gs_pop_string(gs_main_instance * minst, gs_string * result)
733 {
734 i_ctx_t *i_ctx_p = minst->i_ctx_p;
735 ref vref;
736 int code = pop_value(i_ctx_p, &vref);
737
738 if (code < 0)
739 return code;
740 switch (r_type(&vref)) {
741 case t_name:
742 name_string_ref(minst->heap, &vref, &vref);
743 code = 1;
744 goto rstr;
745 case t_string:
746 code = (r_has_attr(&vref, a_write) ? 0 : 1);
747 rstr:result->data = vref.value.bytes;
748 result->size = r_size(&vref);
749 break;
750 default:
751 return_error(e_typecheck);
752 }
753 ref_stack_pop(&o_stack, 1);
754 return code;
755 }
756
757 /* ------ Termination ------ */
758
759 /* Get the names of temporary files.
760 * Each name is null terminated, and the last name is
761 * terminated by a double null.
762 * We retrieve the names of temporary files just before
763 * the interpreter finishes, and then delete the files
764 * after the interpreter has closed all files.
765 */
gs_main_tempnames(gs_main_instance * minst)766 private char *gs_main_tempnames(gs_main_instance *minst)
767 {
768 i_ctx_t *i_ctx_p = minst->i_ctx_p;
769 ref *SAFETY;
770 ref *tempfiles;
771 ref keyval[2]; /* for key and value */
772 char *tempnames = NULL;
773 int i;
774 int idict;
775 int len = 0;
776 const byte *data = NULL;
777 uint size;
778 if (minst->init_done >= 2) {
779 if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
780 dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0)
781 return NULL;
782 /* get lengths of temporary filenames */
783 idict = dict_first(tempfiles);
784 while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
785 if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0)
786 len += size + 1;
787 }
788 if (len != 0)
789 tempnames = (char *)malloc(len+1);
790 if (tempnames) {
791 memset(tempnames, 0, len+1);
792 /* copy temporary filenames */
793 idict = dict_first(tempfiles);
794 i = 0;
795 while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
796 if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0) {
797 memcpy(tempnames+i, (const char *)data, size);
798 i+= size;
799 tempnames[i++] = '\0';
800 }
801 }
802 }
803 }
804 return tempnames;
805 }
806
807 /* Free all resources and return. */
808 int
gs_main_finit(gs_main_instance * minst,int exit_status,int code)809 gs_main_finit(gs_main_instance * minst, int exit_status, int code)
810 {
811 i_ctx_t *i_ctx_p = minst->i_ctx_p;
812 int exit_code;
813 ref error_object;
814 char *tempnames;
815
816 /* NB: need to free gs_name_table
817 */
818
819 /*
820 * Previous versions of this code closed the devices in the
821 * device list here. Since these devices are now prototypes,
822 * they cannot be opened, so they do not need to be closed;
823 * alloc_restore_all will close dynamically allocated devices.
824 */
825 tempnames = gs_main_tempnames(minst);
826 /*
827 * Close the "main" device, because it may need to write out
828 * data before destruction. pdfwrite needs so.
829 */
830 if (minst->init_done >= 1) {
831 int code;
832
833 if (idmemory->reclaim != 0) {
834 code = interp_reclaim(&minst->i_ctx_p, avm_global);
835
836 if (code < 0) {
837 eprintf1("ERROR %d reclaiming the memory while the interpreter finalization.\n", code);
838 return e_Fatal;
839 }
840 i_ctx_p = minst->i_ctx_p; /* interp_reclaim could change it. */
841 }
842 if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL) {
843 gx_device *pdev = i_ctx_p->pgs->device;
844
845 /* deactivate the device just before we close it for the last time */
846 gs_main_run_string(minst,
847 ".uninstallpagedevice "
848 "serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemvar exec",
849 0 , &exit_code, &error_object);
850 code = gs_closedevice(pdev);
851 if (code < 0)
852 eprintf2("ERROR %d closing the device. See gs/src/ierrors.h for code explanation.\n", code, i_ctx_p->pgs->device->dname);
853 if (exit_status == 0 || exit_status == e_Quit)
854 exit_status = code;
855 }
856 }
857 /* Flush stdout and stderr */
858 if (minst->init_done >= 2)
859 gs_main_run_string(minst,
860 "(%stdout) (w) file closefile (%stderr) (w) file closefile "
861 "serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemvar exec",
862 0 , &exit_code, &error_object);
863 gp_readline_finit(minst->readline_data);
864 if (gs_debug_c(':'))
865 print_resource_usage(minst, &gs_imemory, "Final");
866 /* Do the equivalent of a restore "past the bottom". */
867 /* This will release all memory, close all open files, etc. */
868 if (minst->init_done >= 1) {
869 gs_memory_t *mem_raw = i_ctx_p->memory.current->non_gc_memory;
870 i_plugin_holder *h = i_ctx_p->plugin_list;
871 alloc_restore_all(idmemory);
872 i_plugin_finit(mem_raw, h);
873 }
874 /* clean up redirected stdout */
875 if (minst->heap->gs_lib_ctx->fstdout2
876 && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstdout)
877 && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstderr)) {
878 fclose(minst->heap->gs_lib_ctx->fstdout2);
879 minst->heap->gs_lib_ctx->fstdout2 = (FILE *)NULL;
880 }
881 minst->heap->gs_lib_ctx->stdout_is_redirected = 0;
882 minst->heap->gs_lib_ctx->stdout_to_stderr = 0;
883 /* remove any temporary files, after ghostscript has closed files */
884 if (tempnames) {
885 char *p = tempnames;
886 while (*p) {
887 unlink(p);
888 p += strlen(p) + 1;
889 }
890 free(tempnames);
891 }
892 gs_lib_finit(exit_status, code, minst->heap);
893 return exit_status;
894 }
895 int
gs_to_exit_with_code(const gs_memory_t * mem,int exit_status,int code)896 gs_to_exit_with_code(const gs_memory_t *mem, int exit_status, int code)
897 {
898 return gs_main_finit(get_minst_from_memory(mem), exit_status, code);
899 }
900 int
gs_to_exit(const gs_memory_t * mem,int exit_status)901 gs_to_exit(const gs_memory_t *mem, int exit_status)
902 {
903 return gs_to_exit_with_code(mem, exit_status, 0);
904 }
905 void
gs_abort(const gs_memory_t * mem)906 gs_abort(const gs_memory_t *mem)
907 {
908 gs_to_exit(mem, 1);
909 /* it's fatal calling OS independent exit() */
910 gp_do_exit(1);
911 }
912
913 /* ------ Debugging ------ */
914
915 /* Print resource usage statistics. */
916 private void
print_resource_usage(const gs_main_instance * minst,gs_dual_memory_t * dmem,const char * msg)917 print_resource_usage(const gs_main_instance * minst, gs_dual_memory_t * dmem,
918 const char *msg)
919 {
920 ulong allocated = 0, used = 0;
921 long utime[2];
922
923 gp_get_usertime(utime);
924 {
925 int i;
926
927 for (i = 0; i < countof(dmem->spaces_indexed); ++i) {
928 gs_ref_memory_t *mem = dmem->spaces_indexed[i];
929
930 if (mem != 0 && (i == 0 || mem != dmem->spaces_indexed[i - 1])) {
931 gs_memory_status_t status;
932 gs_ref_memory_t *mem_stable =
933 (gs_ref_memory_t *)gs_memory_stable((gs_memory_t *)mem);
934
935 gs_memory_status((gs_memory_t *)mem, &status);
936 allocated += status.allocated;
937 used += status.used;
938 if (mem_stable != mem) {
939 gs_memory_status((gs_memory_t *)mem_stable, &status);
940 allocated += status.allocated;
941 used += status.used;
942 }
943 }
944 }
945 }
946 dprintf4("%% %s time = %g, memory allocated = %lu, used = %lu\n",
947 msg, utime[0] - minst->base_time[0] +
948 (utime[1] - minst->base_time[1]) / 1000000000.0,
949 allocated, used);
950 }
951
952 /* Dump the stacks after interpretation */
953 void
gs_main_dump_stack(gs_main_instance * minst,int code,ref * perror_object)954 gs_main_dump_stack(gs_main_instance *minst, int code, ref * perror_object)
955 {
956 i_ctx_t *i_ctx_p = minst->i_ctx_p;
957
958 zflush(i_ctx_p); /* force out buffered output */
959 dprintf1("\nUnexpected interpreter error %d.\n", code);
960 if (perror_object != 0) {
961 dputs("Error object: ");
962 debug_print_ref(minst->heap, perror_object);
963 dputc('\n');
964 }
965 debug_dump_stack(minst->heap, &o_stack, "Operand stack");
966 debug_dump_stack(minst->heap, &e_stack, "Execution stack");
967 debug_dump_stack(minst->heap, &d_stack, "Dictionary stack");
968 }
969
970