xref: /plan9/sys/src/cmd/gs/src/imain.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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