Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/gs/src/imain.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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* 
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
 */
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
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
 
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
 
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
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
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
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
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
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