Line data Source code
1 : /* Copyright (C) 2000 The PARI group.
2 :
3 : This file is part of the PARI/GP package.
4 :
5 : PARI/GP is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 2 of the License, or (at your option) any later
8 : version. It is distributed in the hope that it will be useful, but WITHOUT
9 : ANY WARRANTY WHATSOEVER.
10 :
11 : Check the License for details. You should have received a copy of it, along
12 : with the package; see the file 'COPYING'. If not, write to the Free Software
13 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 :
15 : /*******************************************************************/
16 : /** **/
17 : /** PARI CALCULATOR **/
18 : /** **/
19 : /*******************************************************************/
20 : #ifdef _WIN32
21 : # include "../systems/mingw/pwinver.h"
22 : # include <windows.h>
23 : # include "../systems/mingw/mingw.h"
24 : #endif
25 : #ifdef DEBUG_FLOATS
26 : # undef _GNU_SOURCE
27 : # define _GNU_SOURCE
28 : # include <fenv.h>
29 : #endif
30 : #include "pari.h"
31 : #include "paripriv.h"
32 : #include "gp.h"
33 :
34 : static jmp_buf *env;
35 : static pari_stack s_env;
36 : void (*cb_pari_end_output)(void) = NULL;
37 :
38 : static void
39 0 : gp_ask_confirm(const char *s)
40 : {
41 0 : err_printf(s);
42 0 : err_printf(". OK ? (^C if not)\n");
43 0 : pari_hit_return();
44 0 : }
45 :
46 : /* numerr < 0: after changing PARI stack size
47 : * numerr > 0: normal error, including SIGINT */
48 : static void
49 12738 : gp_err_recover(long numerr)
50 : {
51 12738 : longjmp(env[s_env.n-1], numerr);
52 : }
53 :
54 : /* numerr >= 0 */
55 : static void
56 12286 : gp_pre_recover(long numerr)
57 : {
58 12286 : out_puts(pariErr, "\n"); pariErr->flush();
59 12286 : gp_err_recover(numerr);
60 0 : }
61 :
62 : static void
63 134565 : reset_ctrlc(void)
64 : {
65 : #if defined(_WIN32) || defined(__CYGWIN32__)
66 : win32ctrlc = 0;
67 : #endif
68 134565 : }
69 :
70 : static int
71 86536 : is_silent(char *s) { return s[strlen(s) - 1] == ';'; }
72 :
73 : static int stdin_isatty = 0;
74 : static int
75 1954 : is_interactive(void)
76 1954 : { return pari_infile == stdin && stdin_isatty; }
77 :
78 : /*******************************************************************/
79 : /** **/
80 : /** INITIALIZATION **/
81 : /** **/
82 : /*******************************************************************/
83 : static void
84 2 : print_shortversion(void)
85 : {
86 2 : const ulong mask = (1UL<<PARI_VERSION_SHIFT) - 1;
87 2 : ulong n = paricfg_version_code, major, minor, patch;
88 :
89 2 : patch = n & mask; n >>= PARI_VERSION_SHIFT;
90 2 : minor = n & mask; n >>= PARI_VERSION_SHIFT;
91 2 : major = n;
92 2 : printf("%lu.%lu.%lu\n", major,minor,patch); exit(0);
93 : }
94 :
95 : static void
96 2 : usage(char *s)
97 : {
98 2 : printf("### Usage: %s [options] [GP files]\n", s);
99 2 : printf("Available options:\n");
100 2 : printf(" [-f,--fast]\t\tFast start: do not read .gprc\n");
101 2 : printf(" [-q,--quiet]\t\tQuiet mode: do not print banner and history numbers\n");
102 2 : printf(" [-s stacksize]\tStart with the PARI stack of given size (in bytes)\n");
103 2 : printf(" [--default key=val]\tExecute default(key,val) on startup\n");
104 2 : printf(" [--emacs]\t\tRun as if in Emacs shell\n");
105 2 : printf(" [--help]\t\tPrint this message\n");
106 2 : printf(" [--test]\t\tTest mode. No history, wrap long lines (bench only)\n");
107 2 : printf(" [--texmacs]\t\tRun as if using TeXmacs frontend\n");
108 2 : printf(" [--version]\t\tOutput version info and exit\n");
109 2 : printf(" [--version-short]\tOutput version number and exit\n\n");
110 2 : exit(0);
111 : }
112 :
113 : static void
114 2 : gp_head(void)
115 : {
116 : ulong p, f;
117 2 : pari_print_version();
118 2 : pari_putc('\n');
119 2 : pari_center("Copyright (C) 2000-2024 The PARI Group");
120 2 : pari_putc('\n');
121 2 : print_text("PARI/GP is free software, covered by the GNU General Public \
122 : License, and comes WITHOUT ANY WARRANTY WHATSOEVER.");
123 2 : pari_puts("\nType ? for help, \\q to quit.\n");
124 2 : pari_printf("Type ?%d for how to get moral"
125 : " (and possibly technical) support.\n", pari_community());
126 2 : p = GP_DATA->primelimit;
127 2 : f = GP_DATA->factorlimit;
128 2 : if (pari_mainstack->vsize)
129 0 : pari_printf("\nparisizemax = %lu, primelimit = %lu, factorlimit = %lu",
130 0 : pari_mainstack->vsize, p, f);
131 : else
132 2 : pari_printf("\nparisize = %lu, primelimit = %lu, factorlimit = %lu",
133 2 : pari_mainstack->rsize, p, f);
134 2 : pari_putc('\n');
135 2 : }
136 :
137 : static char *
138 0 : read_arg(long *nread, char *t, long argc, char **argv)
139 : {
140 0 : long i = *nread;
141 0 : if (isdigit((unsigned char)*t)) return t;
142 0 : if (*t || i==argc) usage(argv[0]);
143 0 : *nread = i+1; return argv[i];
144 : }
145 :
146 : static char *
147 0 : read_arg_equal(long *nread, char *t, long argc, char **argv)
148 : {
149 0 : long i = *nread;
150 0 : if (*t=='=' && isdigit((unsigned char)t[1])) return t+1;
151 0 : if (*t || i==argc) usage(argv[0]);
152 0 : *nread = i+1; return argv[i];
153 : }
154 :
155 : static void
156 4 : init_trivial_stack(void)
157 : {
158 4 : const size_t s = 2048;
159 4 : pari_mainstack->size = s;
160 4 : pari_mainstack->bot = (pari_sp)pari_malloc(s);
161 4 : avma = pari_mainstack->top = pari_mainstack->bot + s;
162 4 : }
163 :
164 : static void
165 4 : free_trivial_stack(void)
166 : {
167 4 : free((void*)pari_mainstack->bot);
168 4 : }
169 :
170 : typedef struct { char *key, *val; } pair_t;
171 : /* If ab of the form key=val, record pair in new stack entry
172 : * P[n].key must be freed by caller to avoid memory leak */
173 : static void
174 6 : record_default(pari_stack *s_P, char *ab)
175 : {
176 6 : pair_t *P = (pair_t*)*pari_stack_base(s_P);
177 : char *k, *v;
178 : long n;
179 6 : ab = pari_strdup(ab);
180 6 : parse_key_val(ab, &k, &v);
181 6 : n = pari_stack_new(s_P);
182 6 : P[n].key = k;
183 6 : P[n].val = v;
184 6 : }
185 : static void
186 1851 : read_opt(pari_stack *p_A, long argc, char **argv)
187 : {
188 : pair_t *P;
189 : pari_stack s_P; /* key / value to record default() settings */
190 1851 : char *b = NULL, *p = NULL, *s = NULL;
191 1851 : ulong f = GP_DATA->flags;
192 1851 : long i = 1, initrc = 1;
193 :
194 : (void)&p; (void)&b; (void)&s; /* -Wall gcc-2.95 */
195 :
196 1851 : pari_stack_init(&s_P,sizeof(*P),(void**)&P);
197 1851 : pari_stack_alloc(&s_P, 64);
198 1851 : pari_outfile = stderr;
199 5535 : while (i < argc)
200 : {
201 3692 : char *t = argv[i];
202 :
203 3692 : if (*t++ != '-') break;
204 3692 : i++;
205 3692 : START:
206 3692 : switch(*t++)
207 : {
208 0 : case 'p': p = read_arg(&i,t,argc,argv); break;
209 0 : case 's': s = read_arg(&i,t,argc,argv); break;
210 0 : case 'e':
211 0 : f |= gpd_EMACS; if (*t) goto START;
212 0 : break;
213 1837 : case 'q':
214 1837 : f |= gpd_QUIET; if (*t) goto START;
215 1837 : break;
216 0 : case 't':
217 0 : f |= gpd_TEST; if (*t) goto START;
218 0 : break;
219 33 : case 'f':
220 33 : initrc = 0; if (*t) goto START;
221 33 : break;
222 4 : case 'D':
223 4 : if (*t || i == argc) usage(argv[0]);
224 4 : record_default(&s_P, argv[i++]);
225 4 : break;
226 1818 : case '-':
227 1818 : if (strcmp(t, "version-short") == 0) { print_shortversion(); exit(0); }
228 1816 : if (strcmp(t, "version") == 0) {
229 4 : init_trivial_stack(); pari_print_version();
230 4 : free_trivial_stack(); exit(0);
231 : }
232 1812 : if (strcmp(t, "default") == 0) {
233 2 : if (i == argc) usage(argv[0]);
234 2 : record_default(&s_P, argv[i++]);
235 2 : break;
236 : }
237 1810 : if (strcmp(t, "texmacs") == 0) { f |= gpd_TEXMACS; break; }
238 1810 : if (strcmp(t, "emacs") == 0) { f |= gpd_EMACS; break; }
239 1810 : if (strcmp(t, "test") == 0) { f |= gpd_TEST; initrc = 0; break; }
240 6 : if (strcmp(t, "quiet") == 0) { f |= gpd_QUIET; break; }
241 4 : if (strcmp(t, "fast") == 0) { initrc = 0; break; }
242 2 : if (strncmp(t, "primelimit",10) == 0) {p = read_arg_equal(&i,t+10,argc,argv); break; }
243 2 : if (strncmp(t, "stacksize",9) == 0) {s = read_arg_equal(&i,t+9,argc,argv); break; }
244 : /* fall through */
245 : default:
246 2 : usage(argv[0]);
247 : }
248 : }
249 1843 : if (f & gpd_TEST) stdin_isatty = 0;
250 1843 : GP_DATA->flags = f;
251 : #ifdef READLINE
252 1843 : GP_DATA->use_readline = stdin_isatty;
253 : #endif
254 1843 : if (!is_interactive()) GP_DATA->breakloop = 0;
255 1843 : if (initrc) gp_initrc(p_A);
256 1843 : for ( ; i < argc; i++) pari_stack_pushp(p_A, pari_strdup(argv[i]));
257 :
258 : /* override the values from gprc */
259 1843 : if (p) (void)sd_primelimit(p, d_INITRC);
260 1843 : if (s) (void)sd_parisize(s, d_INITRC);
261 1847 : for (i = 0; i < s_P.n; i++) {
262 6 : setdefault(P[i].key, P[i].val, d_INITRC);
263 4 : free((void*)P[i].key);
264 : }
265 1841 : pari_stack_delete(&s_P);
266 1841 : pari_outfile = stdout;
267 1841 : }
268 :
269 : /*******************************************************************/
270 : /** **/
271 : /** TEST MODE **/
272 : /** **/
273 : /*******************************************************************/
274 : static int
275 250687 : test_is_interactive(void) { return 0; }
276 :
277 : static void
278 58472 : test_output(long n) { init_linewrap(76); gen_output(pari_get_hist(n)); }
279 : void
280 1804 : init_test(void)
281 : {
282 1804 : disable_color = 1;
283 1804 : init_linewrap(76);
284 1804 : pari_errfile = stdout;
285 1804 : cb_pari_display_hist = test_output;
286 1804 : cb_pari_is_interactive = test_is_interactive;
287 1804 : }
288 :
289 : static GEN
290 1841 : gp_main_loop(long ismain)
291 : {
292 1841 : VOLATILE GEN z = gnil;
293 1841 : VOLATILE long t = 0, r = 0;
294 1841 : VOLATILE pari_sp av = avma;
295 : filtre_t F;
296 1841 : Buffer *b = filtered_buffer(&F);
297 : struct gp_context rec;
298 : long er;
299 1841 : if ((er = setjmp(env[s_env.n-1])))
300 : { /* recover: jump from error [ > 0 ] or allocatemem [ -1 ] */
301 12708 : if (er > 0) { /* true error */
302 12277 : if (!(GP_DATA->recover)) exit(1);
303 12277 : gp_context_restore(&rec);
304 : /* true error not from main instance, let caller sort it out */
305 12277 : if (!ismain) { kill_buffers_upto_including(b); return NULL; }
306 : } else { /* allocatemem */
307 431 : tmp_restore(rec.file.file);
308 431 : gp_context_save(&rec);
309 : }
310 12708 : set_avma(av = pari_mainstack->top);
311 12708 : parivstack_reset();
312 12708 : kill_buffers_upto(b);
313 12708 : pari_alarm(0);
314 : }
315 : for(;;)
316 : {
317 136231 : gp_context_save(&rec);
318 136231 : if (! gp_read_line(&F, NULL))
319 : {
320 1841 : if (popinfile()) gp_quit(0);
321 0 : if (ismain) continue;
322 0 : pop_buffer(); return z;
323 : }
324 134390 : if (ismain)
325 : {
326 134390 : reset_ctrlc();
327 134390 : timer_start(GP_DATA->T);
328 134390 : walltimer_start(GP_DATA->Tw);
329 134390 : pari_set_last_newline(1);
330 : }
331 134390 : if (gp_meta(b->buf,ismain)) continue;
332 113578 : z = pari_compile_str(b->buf);
333 113501 : z = closure_evalres(z);
334 100891 : if (!ismain) continue;
335 :
336 100891 : t = timer_delay(GP_DATA->T);
337 100891 : r = walltimer_delay(GP_DATA->Tw);
338 100891 : if (!pari_last_was_newline()) pari_putc('\n');
339 100891 : pari_alarm(0);
340 100891 : if (t && GP_DATA->chrono)
341 : {
342 0 : if (pari_mt_nbthreads==1)
343 : {
344 0 : pari_puts("time = ");
345 0 : pari_puts(gp_format_time(t));
346 : }
347 : else
348 : {
349 0 : pari_puts("cpu time = ");
350 0 : pari_puts(gp_format_time(t));
351 0 : pari_puts(", real time = ");
352 0 : pari_puts(gp_format_time(r));
353 : }
354 0 : pari_puts(".\n");
355 : }
356 100891 : if (GP_DATA->simplify) z = simplify_shallow(z);
357 100891 : pari_add_hist(z, t, r);
358 100891 : if (z != gnil && ! is_silent(b->buf) )
359 58476 : gp_display_hist(GP_DATA->hist->total);
360 100891 : set_avma(av);
361 100891 : parivstack_reset();
362 : }
363 : }
364 :
365 : /* as gp_read_file, before running the main gp instance */
366 : static void
367 0 : read_main(const char *s)
368 : {
369 : GEN z;
370 0 : if (setjmp(env[s_env.n-1]))
371 0 : z = NULL;
372 : else {
373 0 : FILE *f = switchin(s);
374 0 : if (file_is_binary(f)) {
375 0 : z = readbin(s,f, NULL);
376 0 : popinfile();
377 : }
378 0 : else z = gp_main_loop(0);
379 : }
380 0 : if (!z) err_printf("... skipping file '%s'\n", s);
381 0 : set_avma(pari_mainstack->top);
382 0 : }
383 :
384 : static const char *
385 126 : break_loop_prompt(long n)
386 : {
387 126 : return n==0 ? "GP prompt" : n==1? "break> ": stack_sprintf("break[%ld]> ", n);
388 : }
389 :
390 : static long frame_level=0, dbg_level = 0;
391 :
392 : static int
393 63 : break_loop(int numerr)
394 : {
395 : filtre_t F;
396 : Buffer *b;
397 63 : int sigint = numerr<0, go_on = sigint;
398 : struct gp_context rec1, rec2;
399 : const char *prompt, *msg;
400 63 : long nenv, oldframe_level = frame_level;
401 : pari_sp av;
402 :
403 63 : if (numerr == e_SYNTAX) return 0;
404 63 : if (numerr == e_STACK) { evalstate_clone(); set_avma(pari_mainstack->top); }
405 63 : gp_context_save(&rec1);
406 :
407 63 : b = filtered_buffer(&F);
408 63 : nenv=pari_stack_new(&s_env);
409 63 : prompt = gp_format_prompt(break_loop_prompt(nenv));
410 63 : iferr_env = NULL;
411 63 : dbg_level = 0;
412 63 : frame_level = closure_context(oldframe_level, dbg_level);
413 63 : pari_infile = newfile(stdin, "stdin", mf_IN)->file;
414 63 : term_color(c_ERR); pari_putc('\n');
415 63 : if (sigint)
416 7 : msg = "Break loop: <Return> to continue; 'break' to go back to %s";
417 : else
418 56 : msg = "Break loop: type 'break' to go back to %s";
419 63 : msg = stack_sprintf(msg, break_loop_prompt(nenv-1));
420 63 : print_errcontext(pariOut, msg, NULL, NULL);
421 63 : term_color(c_NONE);
422 63 : av = avma;
423 : for(;;)
424 91 : {
425 : GEN x;
426 : long er, br_status;
427 154 : set_avma(av);
428 154 : gp_context_save(&rec2);
429 154 : if ((er=setjmp(env[nenv])))
430 : {
431 35 : if (er < 0)
432 : {
433 7 : s_env.n = 1;
434 7 : frame_level = oldframe_level;
435 7 : longjmp(env[s_env.n-1], er);
436 : }
437 28 : gp_context_restore(&rec2);
438 28 : iferr_env = NULL;
439 28 : closure_err(dbg_level);
440 28 : compilestate_restore(&rec1.eval.comp);
441 28 : (void) closure_context(oldframe_level, dbg_level);
442 28 : pari_infile = newfile(stdin, "stdin", mf_IN)->file;
443 : }
444 182 : term_color(c_NONE);
445 182 : if (!gp_read_line(&F, prompt))
446 0 : br_status = br_BREAK; /* EOF */
447 : else
448 : {
449 : /* Empty input ? Continue if entry on sigint (exit debugger frame) */
450 182 : if (! *(b->buf) && sigint) break;
451 175 : reset_ctrlc();
452 175 : if (gp_meta(b->buf,0)) continue;
453 175 : x = pari_compile_str(b->buf);
454 175 : x = closure_evalbrk(x, &br_status);
455 : }
456 140 : switch (br_status)
457 : {
458 0 : case br_NEXT: case br_MULTINEXT:
459 0 : popinfile(); /* exit frame. Don't exit debugger if s_env.n > 2 */
460 49 : go_on = 0; goto BR_EXIT;
461 49 : case br_BREAK: case br_RETURN:
462 49 : killallfiles(); /* completely exit the debugger */
463 49 : go_on = 0; goto BR_EXIT;
464 : }
465 91 : if (x!=gnil && !is_silent(b->buf)) { term_color(c_OUTPUT); gen_output(x); }
466 : }
467 56 : BR_EXIT:
468 56 : s_env.n=nenv;
469 56 : frame_level = oldframe_level;
470 56 : gp_context_restore(&rec1);
471 56 : pop_buffer(); return go_on;
472 : }
473 :
474 : #ifdef __CYGWIN32__
475 : void
476 : cyg_environment(int argc, char ** argv)
477 : {
478 : char *ti_dirs = getenv("TERMINFO_DIRS");
479 : char *argv0, *p;
480 : char *newdir;
481 : long n;
482 :
483 : if (!argc || !argv) return;
484 : argv0 = *argv;
485 : if (!argv0 || !*argv0) return;
486 : p = strrchr(argv0, '/');
487 : if (!p)
488 : p = argv0 = "";
489 : else
490 : p++;
491 : n = p - argv0;
492 : if (ti_dirs)
493 : {
494 : n += 14 + strlen(ti_dirs) + 1 + 8 + 1;
495 : newdir = malloc(n);
496 : if (!newdir) return;
497 : snprintf(newdir, n-8, "TERMINFO_DIRS=%s:%s", ti_dirs, argv0);
498 : }
499 : else
500 : {
501 : n += 14 + 8 + 1;
502 : newdir = malloc(n);
503 : if (!newdir) return;
504 : snprintf(newdir, n-8, "TERMINFO_DIRS=%s", argv0);
505 : }
506 : strcpy(newdir+n-9,"terminfo");
507 : putenv(newdir);
508 : }
509 : #endif
510 :
511 : int
512 1851 : main(int argc, char **argv)
513 : {
514 : char **A;
515 : pari_stack s_A;
516 :
517 1851 : GP_DATA = default_gp_data();
518 1851 : pari_stack_init(&s_env, sizeof(*env), (void**)&env);
519 1851 : (void)pari_stack_new(&s_env);
520 :
521 1851 : if (setjmp(env[s_env.n-1]))
522 : {
523 2 : puts("### Errors on startup, exiting...\n\n");
524 2 : exit(1);
525 : }
526 : #ifdef DEBUG_FLOATS
527 : feenableexcept(FE_INVALID);
528 : #endif
529 : #ifdef __CYGWIN32__
530 : cyg_environment(argc, argv);
531 : #endif
532 1851 : stdin_isatty = pari_stdin_isatty();
533 1851 : pari_init_defaults();
534 1851 : pari_library_path = DL_DFLT_NAME;
535 1851 : pari_stack_init(&s_A,sizeof(*A),(void**)&A);
536 : /* must be defined here in case an error is raised in pari_init_opts, e.g.
537 : * when parsing function prototypes */
538 1851 : cb_pari_err_recover = gp_err_recover;
539 1851 : pari_init_opts(8000000, 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm);
540 1851 : cb_pari_pre_recover = gp_pre_recover;
541 1851 : cb_pari_break_loop = break_loop;
542 1851 : cb_pari_is_interactive = is_interactive;
543 :
544 1851 : read_opt(&s_A, argc,argv);
545 1841 : pari_init_primes(GP_DATA->primelimit);
546 : #ifdef SIGALRM
547 1841 : (void)os_signal(SIGALRM,gp_alarm_handler);
548 : #endif
549 1841 : pari_add_module(functions_gp);
550 :
551 1841 : pari_set_plot_engine(gp_get_plot);
552 1841 : cb_pari_quit = gp_quit;
553 1841 : cb_pari_whatnow = whatnow;
554 1841 : cb_pari_sigint = gp_sigint_fun;
555 1841 : cb_pari_handle_exception = gp_handle_exception;
556 1841 : cb_pari_ask_confirm = gp_ask_confirm;
557 1841 : pari_init_paths();
558 1841 : pari_mt_init(); /* MPI: will not return on slaves (pari_MPI_rank = 0) */
559 : #ifdef _WIN32
560 : if (stdin_isatty) win32_set_codepage();
561 : #endif
562 : #ifdef READLINE
563 1841 : init_readline();
564 : #endif
565 1841 : if (GP_DATA->flags & gpd_EMACS) init_emacs();
566 1841 : if (GP_DATA->flags & gpd_TEXMACS) init_texmacs();
567 :
568 1841 : timer_start(GP_DATA->T);
569 1841 : walltimer_start(GP_DATA->Tw);
570 1841 : if (!(GP_DATA->flags & gpd_QUIET)) gp_head();
571 1841 : if (GP_DATA->flags & gpd_TEST) init_test();
572 1841 : if (s_A.n)
573 : {
574 0 : FILE *l = pari_logfile;
575 : long i;
576 0 : pari_logfile = NULL;
577 0 : for (i = 0; i < s_A.n; pari_free(A[i]),i++) read_main(A[i]);
578 : /* Reading one of the input files above can set pari_logfile.
579 : * Don't restore in that case. */
580 0 : if (!pari_logfile) pari_logfile = l;
581 : }
582 1841 : pari_stack_delete(&s_A);
583 1841 : (void)gp_main_loop(1);
584 0 : gp_quit(0);
585 : return 0; /* LCOV_EXCL_LINE */
586 : }
587 :
588 : void
589 7 : dbg_down(long k)
590 : {
591 7 : if (k<0) k=0;
592 7 : dbg_level -= k;
593 7 : if (dbg_level<0) dbg_level=0;
594 7 : gp_err_recover(e_NONE);
595 0 : }
596 :
597 : GEN
598 7 : dbg_err(void) { GEN E = pari_err_last(); return E? gcopy(E):gnil; }
599 :
600 : void
601 14 : dbg_up(long k)
602 : {
603 14 : if (k<0) k=0;
604 14 : dbg_level += k;
605 14 : if (dbg_level>frame_level) dbg_level=frame_level;
606 14 : gp_err_recover(e_NONE);
607 0 : }
608 :
609 : void
610 1841 : gp_quit(long code)
611 : {
612 1841 : pari_kill_plot_engine();
613 1841 : pari_close();
614 1841 : kill_buffers_upto(NULL);
615 1841 : if (!(GP_DATA->flags & gpd_QUIET)) pari_puts("Goodbye!\n");
616 1841 : if (cb_pari_end_output) cb_pari_end_output();
617 1841 : exit(code);
618 : }
619 :
620 : void
621 35 : whatnow0(char *s) { whatnow(pariOut, s,0); }
622 :
623 : #include "gp_init.h"
|