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