Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

Testing latest pari + WASM + node.js... and it works?! Wow.

28485 views
License: GPL3
ubuntu2004
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
/** LIBRARY ROUTINES FOR PARI CALCULATOR **/
18
/** **/
19
/*******************************************************************/
20
#ifdef _WIN32
21
# include "../systems/mingw/pwinver.h"
22
# include <windows.h>
23
# include "../systems/mingw/mingw.h"
24
# include <process.h>
25
#endif
26
27
#include "pari.h"
28
#include "paripriv.h"
29
#ifdef __EMSCRIPTEN__
30
#include "../systems/emscripten/emscripten.h"
31
#endif
32
33
/********************************************************************/
34
/** **/
35
/** STRINGS **/
36
/** **/
37
/********************************************************************/
38
39
void
40
pari_skip_space(char **s) {
41
char *t = *s;
42
while (isspace((int)*t)) t++;
43
*s = t;
44
}
45
void
46
pari_skip_alpha(char **s) {
47
char *t = *s;
48
while (isalpha((int)*t)) t++;
49
*s = t;
50
}
51
52
/*******************************************************************/
53
/** **/
54
/** BUFFERS **/
55
/** **/
56
/*******************************************************************/
57
static Buffer **bufstack;
58
static pari_stack s_bufstack;
59
void
60
pari_init_buffers(void)
61
{ pari_stack_init(&s_bufstack, sizeof(Buffer*), (void**)&bufstack); }
62
63
void
64
pop_buffer(void)
65
{
66
if (s_bufstack.n)
67
delete_buffer( bufstack[ --s_bufstack.n ] );
68
}
69
70
/* kill all buffers until B is met or nothing is left */
71
void
72
kill_buffers_upto(Buffer *B)
73
{
74
while (s_bufstack.n) {
75
if (bufstack[ s_bufstack.n-1 ] == B) break;
76
pop_buffer();
77
}
78
}
79
void
80
kill_buffers_upto_including(Buffer *B)
81
{
82
while (s_bufstack.n) {
83
if (bufstack[ s_bufstack.n-1 ] == B) { pop_buffer(); break; }
84
pop_buffer();
85
}
86
}
87
88
static int disable_exception_handler = 0;
89
#define BLOCK_EH_START \
90
{ \
91
int block=disable_exception_handler;\
92
disable_exception_handler = 1;
93
94
#define BLOCK_EH_END \
95
disable_exception_handler = block;\
96
}
97
/* numerr < 0: from SIGINT */
98
int
99
gp_handle_exception(long numerr)
100
{
101
if (disable_exception_handler)
102
disable_exception_handler = 0;
103
else if (GP_DATA->breakloop && cb_pari_break_loop
104
&& cb_pari_break_loop(numerr))
105
return 1;
106
return 0;
107
}
108
109
/********************************************************************/
110
/** **/
111
/** HELP **/
112
/** **/
113
/********************************************************************/
114
void
115
pari_hit_return(void)
116
{
117
int c;
118
if (GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS)) return;
119
BLOCK_EH_START
120
pari_puts("/*-- (type RETURN to continue) --*/");
121
pari_flush();
122
/* if called from a readline callback, may be in a funny TTY mode */
123
do c = fgetc(stdin); while (c >= 0 && c != '\n' && c != '\r');
124
pari_putc('\n');
125
BLOCK_EH_END
126
}
127
128
static int
129
has_ext_help(void) { return (GP_DATA->help && *GP_DATA->help); }
130
131
static int
132
compare_str(char **s1, char **s2) { return strcmp(*s1, *s2); }
133
134
/* Print all elements of list in columns, pausing every nbli lines
135
* if nbli is nonzero. list is a NULL terminated list of function names */
136
void
137
print_fun_list(char **list, long nbli)
138
{
139
long i=0, j=0, maxlen=0, nbcol,len, w = term_width();
140
char **l;
141
142
while (list[i]) i++;
143
qsort (list, i, sizeof(char *), (QSCOMP)compare_str);
144
145
for (l=list; *l; l++)
146
{
147
len = strlen(*l);
148
if (len > maxlen) maxlen=len;
149
}
150
maxlen++; nbcol= w / maxlen;
151
if (nbcol * maxlen == w) nbcol--;
152
if (!nbcol) nbcol = 1;
153
154
pari_putc('\n'); i=0;
155
for (l=list; *l; l++)
156
{
157
pari_puts(*l); i++;
158
if (i >= nbcol)
159
{
160
i=0; pari_putc('\n');
161
if (nbli && j++ > nbli) { j = 0; pari_hit_return(); }
162
continue;
163
}
164
len = maxlen - strlen(*l);
165
while (len--) pari_putc(' ');
166
}
167
if (i) pari_putc('\n');
168
}
169
170
static const long MAX_SECTION = 16;
171
static void
172
commands(long n)
173
{
174
long i;
175
entree *ep;
176
char **t_L;
177
pari_stack s_L;
178
179
pari_stack_init(&s_L, sizeof(*t_L), (void**)&t_L);
180
for (i = 0; i < functions_tblsz; i++)
181
for (ep = functions_hash[i]; ep; ep = ep->next)
182
{
183
long m;
184
switch (EpVALENCE(ep))
185
{
186
case EpVAR:
187
if (typ((GEN)ep->value) == t_CLOSURE) break;
188
/* fall through */
189
case EpNEW: continue;
190
}
191
m = ep->menu;
192
if (m == n || (n < 0 && m && m <= MAX_SECTION))
193
pari_stack_pushp(&s_L, (void*)ep->name);
194
}
195
pari_stack_pushp(&s_L, NULL);
196
print_fun_list(t_L, term_height()-4);
197
pari_stack_delete(&s_L);
198
}
199
200
void
201
pari_center(const char *s)
202
{
203
pari_sp av = avma;
204
long i, l = strlen(s), pad = term_width() - l;
205
char *buf, *u;
206
207
if (pad<0) pad=0; else pad >>= 1;
208
u = buf = stack_malloc(l + pad + 2);
209
for (i=0; i<pad; i++) *u++ = ' ';
210
while (*s) *u++ = *s++;
211
*u++ = '\n'; *u = 0;
212
pari_puts(buf); set_avma(av);
213
}
214
215
static void
216
community(void)
217
{
218
print_text("The PARI/GP distribution includes a reference manual, a \
219
tutorial, a reference card and quite a few examples. They have been installed \
220
in the directory ");
221
pari_puts(" ");
222
pari_puts(pari_datadir);
223
pari_puts("\nYou can also download them from http://pari.math.u-bordeaux.fr/.\
224
\n\nThree mailing lists are devoted to PARI:\n\
225
- pari-announce (moderated) to announce major version changes.\n\
226
- pari-dev for everything related to the development of PARI, including\n\
227
suggestions, technical questions, bug reports and patch submissions.\n\
228
- pari-users for everything else!\n\
229
To subscribe, send an empty message to\n\
230
<pari_list_name>[email protected]\n\
231
with a Subject: field containing the word 'subscribe'.\n\n");
232
print_text("An archive is kept at the WWW site mentioned above. You can also \
233
reach the authors at [email protected] (answer not guaranteed)."); }
234
235
static void
236
gentypes(void)
237
{
238
pari_puts("List of the PARI types:\n\
239
t_INT : long integers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
240
t_REAL : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
241
t_INTMOD : integermods [ code ] [ mod ] [ integer ]\n\
242
t_FRAC : irred. rationals [ code ] [ num. ] [ den. ]\n\
243
t_FFELT : finite field elt. [ code ] [ cod2 ] [ elt ] [ mod ] [ p ]\n\
244
t_COMPLEX: complex numbers [ code ] [ real ] [ imag ]\n\
245
t_PADIC : p-adic numbers [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ]\n\
246
t_QUAD : quadratic numbers [ cod1 ] [ mod ] [ real ] [ imag ]\n\
247
t_POLMOD : poly mod [ code ] [ mod ] [ polynomial ]\n\
248
-------------------------------------------------------------\n\
249
t_POL : polynomials [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
250
t_SER : power series [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
251
t_RFRAC : irred. rat. func. [ code ] [ num. ] [ den. ]\n\
252
t_QFB : qfb [ code ] [ a ] [ b ] [ c ] [ disc ]\n\
253
t_VEC : row vector [ code ] [ x_1 ] ... [ x_k ]\n\
254
t_COL : column vector [ code ] [ x_1 ] ... [ x_k ]\n\
255
t_MAT : matrix [ code ] [ col_1 ] ... [ col_k ]\n\
256
t_LIST : list [ cod1 ] [ cod2 ][ vec ]\n\
257
t_STR : string [ code ] [ man_1 ] ... [ man_k ]\n\
258
t_VECSMALL: vec. small ints [ code ] [ x_1 ] ... [ x_k ]\n\
259
t_CLOSURE: functions [ code ] [ arity ] [ code ] [ operand ] [ data ] [ text ]\n\
260
t_ERROR : error context [ code ] [ errnum ] [ dat_1 ] ... [ dat_k ]\n\
261
t_INFINITY: a*infinity [ code ] [ a ]\n\
262
\n");
263
}
264
265
static void
266
menu_commands(void)
267
{
268
ulong i;
269
const char *s[] = {
270
"user-defined functions (aliases, installed and user functions)",
271
"PROGRAMMING under GP",
272
"Standard monadic or dyadic OPERATORS",
273
"CONVERSIONS and similar elementary functions",
274
"functions related to COMBINATORICS",
275
"NUMBER THEORETICAL functions",
276
"POLYNOMIALS and power series",
277
"Vectors, matrices, LINEAR ALGEBRA and sets",
278
"TRANSCENDENTAL functions",
279
"SUMS, products, integrals and similar functions",
280
"General NUMBER FIELDS",
281
"Associative and central simple ALGEBRAS",
282
"ELLIPTIC CURVES",
283
"L-FUNCTIONS",
284
"MODULAR FORMS",
285
"MODULAR SYMBOLS",
286
"GRAPHIC functions",
287
"The PARI community"
288
};
289
pari_puts("Help topics: for a list of relevant subtopics, type ?n for n in\n");
290
for (i = 0; i < numberof(s); i++) pari_printf(" %2lu: %s\n", i, s[i]);
291
pari_puts("Also:\n\
292
? functionname (short on-line help)\n\
293
?\\ (keyboard shortcuts)\n\
294
?. (member functions)\n");
295
if (has_ext_help()) pari_puts("\
296
Extended help (if available):\n\
297
?? (opens the full user's manual in a dvi previewer)\n\
298
?? tutorial / refcard / libpari (tutorial/reference card/libpari manual)\n\
299
?? refcard-ell (or -lfun/-mf/-nf: specialized reference card)\n\
300
?? keyword (long help text about \"keyword\" from the user's manual)\n\
301
??? keyword (a propos: list of related functions).");
302
}
303
304
static void
305
slash_commands(void)
306
{
307
pari_puts("# : enable/disable timer\n\
308
## : print time for last result\n\
309
\\\\ : comment up to end of line\n\
310
\\a {n} : print result in raw format (readable by PARI)\n\
311
\\B {n} : print result in beautified format\n\
312
\\c : list all commands (same effect as ?*)\n\
313
\\d : print all defaults\n\
314
\\e {n} : enable/disable echo (set echo=n)\n\
315
\\g {n} : set debugging level\n\
316
\\gf{n} : set file debugging level\n\
317
\\gm{n} : set memory debugging level\n\
318
\\h {m-n}: hashtable information\n\
319
\\l {f} : enable/disable logfile (set logfile=f)\n\
320
\\m {n} : print result in prettymatrix format\n\
321
\\o {n} : set output method (0=raw, 1=prettymatrix, 2=prettyprint, 3=2-dim)\n\
322
\\p {n} : change real precision\n\
323
\\pb{n} : change real bit precision\n\
324
\\ps{n} : change series precision\n\
325
\\q : quit completely this GP session\n\
326
\\r {f} : read in a file\n\
327
\\s : print stack information\n\
328
\\t : print the list of PARI types\n\
329
\\u : print the list of user-defined functions\n\
330
\\um : print the list of user-defined member functions\n\
331
\\v : print current version of GP\n\
332
\\w {nf} : write to a file\n\
333
\\x {n} : print complete inner structure of result\n\
334
\\y {n} : disable/enable automatic simplification (set simplify=n)\n\
335
\n\
336
{f}=optional filename. {n}=optional integer\n");
337
}
338
339
static void
340
member_commands(void)
341
{
342
pari_puts("\
343
Member functions, followed by relevant objects\n\n\
344
a1-a6, b2-b8, c4-c6 : coeff. of the curve. ell\n\
345
area : area ell\n\
346
bid : big ideal bid, bnr\n\
347
bnf : big number field bnf,bnr\n\
348
clgp : class group bid, bnf,bnr\n\
349
cyc : cyclic decomposition (SNF) bid, clgp,ell, bnf,bnr\n\
350
diff, codiff: different and codifferent nf,bnf,bnr\n\
351
disc : discriminant ell,nf,bnf,bnr,rnf\n\
352
e, f : inertia/residue degree prid\n\
353
fu : fundamental units bnf\n\
354
gen : generators bid,prid,clgp,ell, bnf,bnr, gal\n\
355
group: group ell, gal\n\
356
index: index nf,bnf,bnr\n\
357
j : j-invariant ell\n");
358
/* split: some compilers can't handle long constant strings */
359
pari_puts("\
360
mod : modulus bid, bnr, gal\n\
361
nf : number field nf,bnf,bnr,rnf\n\
362
no : number of elements bid, clgp,ell, bnf,bnr\n\
363
omega, eta: [w1,w2] and [eta1, eta2] ell\n\
364
orders: relative orders of generators gal\n\
365
p : rational prime prid, ell,nf,bnr,bnr,rnf,gal\n\
366
pol : defining polynomial nf,bnf,bnr, gal\n\
367
polabs: defining polynomial over Q rnf\n\
368
reg : regulator bnf\n\
369
roots: roots ell,nf,bnf,bnr, gal\n\
370
sign,r1,r2 : signature nf,bnf,bnr\n\
371
t2 : t2 matrix nf,bnf,bnr\n\
372
tate : Tate's [u^2, u, q, [a,b], L, Ei] ell\n\
373
tu : torsion unit and its order bnf\n\
374
zk : integral basis nf,bnf,bnr,rnf\n\
375
zkst : structure of (Z_K/m)* bid, bnr\n");
376
}
377
378
#define QUOTE "_QUOTE"
379
#define DOUBQUOTE "_DOUBQUOTE"
380
#define BACKQUOTE "_BACKQUOTE"
381
382
static char *
383
_cat(char *s, const char *t)
384
{
385
*s = 0; strcat(s,t); return s + strlen(t);
386
}
387
388
static char *
389
filter_quotes(const char *s)
390
{
391
int i, l = strlen(s);
392
int quote = 0;
393
int backquote = 0;
394
int doubquote = 0;
395
char *str, *t;
396
397
for (i=0; i < l; i++)
398
switch(s[i])
399
{
400
case '\'': quote++; break;
401
case '`' : backquote++; break;
402
case '"' : doubquote++;
403
}
404
str = (char*)pari_malloc(l + quote * (strlen(QUOTE)-1)
405
+ doubquote * (strlen(DOUBQUOTE)-1)
406
+ backquote * (strlen(BACKQUOTE)-1) + 1);
407
t = str;
408
for (i=0; i < l; i++)
409
switch(s[i])
410
{
411
case '\'': t = _cat(t, QUOTE); break;
412
case '`' : t = _cat(t, BACKQUOTE); break;
413
case '"' : t = _cat(t, DOUBQUOTE); break;
414
default: *t++ = s[i];
415
}
416
*t = 0; return str;
417
}
418
419
static int
420
nl_read(char *s) { size_t l = strlen(s); return s[l-1] == '\n'; }
421
422
/* query external help program for s. num < 0 [keyword] or chapter number */
423
static void
424
external_help(const char *s, int num)
425
{
426
long nbli = term_height()-3, li = 0;
427
char buf[256], *str;
428
const char *opt = "", *ar = "";
429
char *t, *help = GP_DATA->help;
430
pariFILE *z;
431
FILE *f;
432
#ifdef __EMSCRIPTEN__
433
pari_emscripten_help(s);
434
#endif
435
436
if (!has_ext_help()) pari_err(e_MISC,"no external help program");
437
t = filter_quotes(s);
438
if (num < 0)
439
opt = "-k";
440
else if (t[strlen(t)-1] != '@')
441
ar = stack_sprintf("@%d",num);
442
#ifdef _WIN32
443
if (*help == '@')
444
{
445
const char *basedir = win32_basedir();
446
help = stack_sprintf("%c:& cd %s & %s", *basedir, basedir, help+1);
447
}
448
#endif
449
str = stack_sprintf("%s -fromgp %s %c%s%s%c",
450
help, opt, SHELL_Q, t, ar, SHELL_Q);
451
z = try_pipe(str,0); f = z->file;
452
pari_free(t);
453
while (fgets(buf, numberof(buf), f))
454
{
455
if (!strncmp("ugly_kludge_done",buf,16)) break;
456
pari_puts(buf);
457
if (nl_read(buf) && ++li > nbli) { pari_hit_return(); li = 0; }
458
}
459
pari_fclose(z);
460
}
461
462
const char **
463
gphelp_keyword_list(void)
464
{
465
static const char *L[]={
466
"operator",
467
"libpari",
468
"member",
469
"integer",
470
"real",
471
"readline",
472
"refcard",
473
"refcard-nf",
474
"refcard-ell",
475
"refcard-mf",
476
"refcard-lfun",
477
"tutorial",
478
"tutorial-mf",
479
"mf",
480
"nf",
481
"bnf",
482
"bnr",
483
"ell",
484
"rnf",
485
"bid",
486
"modulus",
487
"prototype",
488
"Lmath",
489
"Ldata",
490
"Linit",
491
NULL};
492
return L;
493
}
494
495
static int
496
ok_external_help(char **s)
497
{
498
const char **L;
499
long n;
500
if (!**s) return 1;
501
if (!isalpha((int)**s)) return 3; /* operator or section number */
502
if (!strncmp(*s,"t_",2)) { *s += 2; return 2; } /* type name */
503
504
L = gphelp_keyword_list();
505
for (n=0; L[n]; n++)
506
if (!strcmp(*s,L[n])) return 3;
507
return 0;
508
}
509
510
static void
511
cut_trailing_garbage(char *s)
512
{
513
char c;
514
while ( (c = *s++) )
515
{
516
if (c == '\\' && ! *s++) return; /* gobble next char, return if none. */
517
if (!is_keyword_char(c) && c != '@') { s[-1] = 0; return; }
518
}
519
}
520
521
static void
522
digit_help(char *s, long flag)
523
{
524
long n = atoi(s);
525
if (n < 0 || n > MAX_SECTION+4)
526
pari_err(e_SYNTAX,"no such section in help: ?",s,s);
527
if (n == MAX_SECTION+1)
528
community();
529
else if (flag & h_LONG)
530
external_help(s,3);
531
else
532
commands(n);
533
return;
534
}
535
536
long
537
pari_community(void)
538
{
539
return MAX_SECTION+1;
540
}
541
542
static void
543
simple_help(const char *s1, const char *s2) { pari_printf("%s: %s\n", s1, s2); }
544
545
static void
546
default_help(char *s, long flag)
547
{
548
if (flag & h_LONG)
549
external_help(stack_strcat("se:def,",s),3);
550
else
551
simple_help(s,"default");
552
}
553
554
static void
555
help(const char *s0, int flag)
556
{
557
const long long_help = flag & h_LONG;
558
long n;
559
entree *ep;
560
char *s = get_sep(s0);
561
562
if (isdigit((int)*s)) { digit_help(s,flag); return; }
563
if (flag & h_APROPOS) { external_help(s,-1); return; }
564
/* Get meaningful answer on '\ps 5' (e.g. from <F1>) */
565
if (*s == '\\' && isalpha((int)*(s+1)))
566
{ char *t = s+1; pari_skip_alpha(&t); *t = '\0'; }
567
if (isalpha((int)*s))
568
{
569
char *t = s;
570
if (!strncmp(s, "default", 7))
571
{ /* special-case ?default(dft_name), e.g. default(log) */
572
t += 7; pari_skip_space(&t);
573
if (*t == '(')
574
{
575
t++; pari_skip_space(&t);
576
cut_trailing_garbage(t);
577
if (pari_is_default(t)) { default_help(t,flag); return; }
578
}
579
}
580
if (!strncmp(s, "refcard-", 8)) t += 8;
581
else if (!strncmp(s, "tutorial-", 9)) t += 9;
582
cut_trailing_garbage(t);
583
}
584
585
if (long_help && (n = ok_external_help(&s))) { external_help(s,n); return; }
586
switch (*s)
587
{
588
case '*' : commands(-1); return;
589
case '\0': menu_commands(); return;
590
case '\\': slash_commands(); return;
591
case '.' : member_commands(); return;
592
}
593
ep = is_entry(s);
594
if (!ep)
595
{
596
if (pari_is_default(s))
597
default_help(s,flag);
598
else if (long_help)
599
external_help(s,3);
600
else if (!cb_pari_whatnow || !cb_pari_whatnow(pariOut, s,1))
601
simple_help(s,"unknown identifier");
602
return;
603
}
604
605
if (EpVALENCE(ep) == EpALIAS)
606
{
607
pari_printf("%s is aliased to:\n\n",s);
608
ep = do_alias(ep);
609
}
610
switch(EpVALENCE(ep))
611
{
612
case EpVAR:
613
if (!ep->help)
614
{
615
if (typ((GEN)ep->value)!=t_CLOSURE)
616
simple_help(s, "user defined variable");
617
else
618
{
619
GEN str = closure_get_text((GEN)ep->value);
620
if (typ(str) == t_VEC)
621
pari_printf("%s =\n %Ps\n", ep->name, ep->value);
622
}
623
return;
624
}
625
break;
626
627
case EpINSTALL:
628
if (!ep->help) { simple_help(s, "installed function"); return; }
629
break;
630
631
case EpNEW:
632
if (!ep->help) { simple_help(s, "new identifier"); return; };
633
break;
634
635
default: /* built-in function */
636
if (!ep->help) pari_err_BUG("gp_help (no help found)"); /*paranoia*/
637
if (long_help) { external_help(ep->name,3); return; }
638
}
639
print_text(ep->help);
640
}
641
642
void
643
gp_help(const char *s, long flag)
644
{
645
pari_sp av = avma;
646
if ((flag & h_RL) == 0)
647
{
648
if (*s == '?') { flag |= h_LONG; s++; }
649
if (*s == '?') { flag |= h_APROPOS; s++; }
650
}
651
term_color(c_HELP); help(s,flag); term_color(c_NONE);
652
if ((flag & h_RL) == 0) pari_putc('\n');
653
set_avma(av);
654
}
655
656
/********************************************************************/
657
/** **/
658
/** GP HEADER **/
659
/** **/
660
/********************************************************************/
661
static char *
662
what_readline(void)
663
{
664
#ifdef READLINE
665
const char *v = READLINE;
666
char *s = stack_malloc(3 + strlen(v) + 8);
667
(void)sprintf(s, "v%s %s", v, GP_DATA->use_readline? "enabled": "disabled");
668
return s;
669
#else
670
return (char*)"not compiled in";
671
#endif
672
}
673
674
static char *
675
what_cc(void)
676
{
677
char *s;
678
#ifdef GCC_VERSION
679
# ifdef __cplusplus
680
s = stack_malloc(6 + strlen(GCC_VERSION) + 1);
681
(void)sprintf(s, "(C++) %s", GCC_VERSION);
682
# else
683
s = stack_strdup(GCC_VERSION);
684
# endif
685
#else
686
# ifdef _MSC_VER
687
s = stack_malloc(32);
688
(void)sprintf(s, "MSVC-%i", _MSC_VER);
689
# else
690
s = NULL;
691
# endif
692
#endif
693
return s;
694
}
695
696
static char *
697
convert_time(char *s, long delay)
698
{
699
if (delay >= 3600000)
700
{
701
sprintf(s, "%ldh, ", delay / 3600000); s+=strlen(s);
702
delay %= 3600000;
703
}
704
if (delay >= 60000)
705
{
706
sprintf(s, "%ldmin, ", delay / 60000); s+=strlen(s);
707
delay %= 60000;
708
}
709
if (delay >= 1000)
710
{
711
sprintf(s, "%ld,", delay / 1000); s+=strlen(s);
712
delay %= 1000;
713
if (delay < 100)
714
{
715
sprintf(s, "%s", (delay<10)? "00": "0");
716
s+=strlen(s);
717
}
718
}
719
sprintf(s, "%ld ms", delay); s+=strlen(s);
720
return s;
721
}
722
723
/* Format a time of 'delay' ms */
724
const char *
725
gp_format_time(long delay)
726
{
727
char *buf = stack_malloc(64), *s = buf;
728
term_get_color(s, c_TIME);
729
s = convert_time(s + strlen(s), delay);
730
term_get_color(s, c_NONE); return buf;
731
}
732
733
GEN
734
strtime(long delay)
735
{
736
long n = nchar2nlong(64);
737
GEN x = cgetg(n+1, t_STR);
738
char *buf = GSTR(x), *t = buf + 64, *s = convert_time(buf, delay);
739
s++; while (s < t) *s++ = 0; /* pacify valgrind */
740
return x;
741
}
742
743
/********************************************************************/
744
/* */
745
/* GPRC */
746
/* */
747
/********************************************************************/
748
/* LOCATE GPRC */
749
static void
750
err_gprc(const char *s, char *t, char *u)
751
{
752
err_printf("\n");
753
pari_err(e_SYNTAX,s,t,u);
754
}
755
756
/* return $HOME or the closest we can find */
757
static const char *
758
get_home(int *free_it)
759
{
760
char *drv, *pth = os_getenv("HOME");
761
if (pth) return pth;
762
if ((drv = os_getenv("HOMEDRIVE"))
763
&& (pth = os_getenv("HOMEPATH")))
764
{ /* looks like WinNT */
765
char *buf = (char*)pari_malloc(strlen(pth) + strlen(drv) + 1);
766
sprintf(buf, "%s%s",drv,pth);
767
*free_it = 1; return buf;
768
}
769
pth = pari_get_homedir("");
770
return pth? pth: ".";
771
}
772
773
static FILE *
774
gprc_chk(const char *s)
775
{
776
FILE *f = fopen(s, "r");
777
if (f && !(GP_DATA->flags & gpd_QUIET)) err_printf("Reading GPRC: %s\n", s);
778
return f;
779
}
780
781
/* Look for [._]gprc: $GPRC, then in $HOME, ., /etc, pari_datadir */
782
static FILE *
783
gprc_get(void)
784
{
785
FILE *f = NULL;
786
const char *gprc = os_getenv("GPRC");
787
if (gprc) f = gprc_chk(gprc);
788
if (!f)
789
{
790
int free_it = 0;
791
const char *home = get_home(&free_it);
792
char *str, *s, c;
793
long l;
794
l = strlen(home); c = home[l-1];
795
/* + "/gprc.txt" + \0*/
796
str = strcpy((char*)pari_malloc(l+10), home);
797
if (free_it) pari_free((void*)home);
798
s = str + l;
799
if (c != '/' && c != '\\') *s++ = '/';
800
#ifndef _WIN32
801
strcpy(s, ".gprc");
802
#else
803
strcpy(s, "gprc.txt");
804
#endif
805
f = gprc_chk(str); /* in $HOME */
806
if (!f) f = gprc_chk(s); /* in . */
807
#ifndef _WIN32
808
if (!f) f = gprc_chk("/etc/gprc");
809
#else
810
if (!f) /* in basedir */
811
{
812
const char *basedir = win32_basedir();
813
char *t = (char *) pari_malloc(strlen(basedir)+strlen(s)+2);
814
sprintf(t, "%s/%s", basedir, s);
815
f = gprc_chk(t); free(t);
816
}
817
#endif
818
pari_free(str);
819
}
820
return f;
821
}
822
823
/* PREPROCESSOR */
824
825
static ulong
826
read_uint(char **s)
827
{
828
long v = atol(*s);
829
if (!isdigit((int)**s)) err_gprc("not an integer", *s, *s);
830
while (isdigit((int)**s)) (*s)++;
831
return v;
832
}
833
static ulong
834
read_dot_uint(char **s)
835
{
836
if (**s != '.') return 0;
837
(*s)++; return read_uint(s);
838
}
839
/* read a.b.c */
840
static long
841
read_version(char **s)
842
{
843
long a, b, c;
844
a = read_uint(s);
845
b = read_dot_uint(s);
846
c = read_dot_uint(s);
847
return PARI_VERSION(a,b,c);
848
}
849
850
static int
851
get_preproc_value(char **s)
852
{
853
if (!strncmp(*s,"EMACS",5)) {
854
*s += 5;
855
return GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS);
856
}
857
if (!strncmp(*s,"READL",5)) {
858
*s += 5;
859
return GP_DATA->use_readline;
860
}
861
if (!strncmp(*s,"VERSION",7)) {
862
int less = 0, orequal = 0;
863
long d;
864
*s += 7;
865
switch(**s)
866
{
867
case '<': (*s)++; less = 1; break;
868
case '>': (*s)++; less = 0; break;
869
default: return -1;
870
}
871
if (**s == '=') { (*s)++; orequal = 1; }
872
d = paricfg_version_code - read_version(s);
873
if (!d) return orequal;
874
return less? (d < 0): (d > 0);
875
}
876
if (!strncmp(*s,"BITS_IN_LONG",12)) {
877
*s += 12;
878
if ((*s)[0] == '=' && (*s)[1] == '=')
879
{
880
*s += 2;
881
return BITS_IN_LONG == read_uint(s);
882
}
883
}
884
return -1;
885
}
886
887
/* PARSE GPRC */
888
889
/* 1) replace next separator by '\0' (t must be writable)
890
* 2) return the next expression ("" if none)
891
* see get_sep() */
892
static char *
893
next_expr(char *t)
894
{
895
int outer = 1;
896
char *s = t;
897
898
for(;;)
899
{
900
char c;
901
switch ((c = *s++))
902
{
903
case '"':
904
if (outer || (s >= t+2 && s[-2] != '\\')) outer = !outer;
905
break;
906
case '\0':
907
return (char*)"";
908
default:
909
if (outer && c == ';') { s[-1] = 0; return s; }
910
}
911
}
912
}
913
914
Buffer *
915
filtered_buffer(filtre_t *F)
916
{
917
Buffer *b = new_buffer();
918
init_filtre(F, b);
919
pari_stack_pushp(&s_bufstack, (void*)b);
920
return b;
921
}
922
923
/* parse src of the form s=t (or s="t"), set *ps to s, and *pt to t.
924
* modifies src (replaces = by \0) */
925
void
926
parse_key_val(char *src, char **ps, char **pt)
927
{
928
char *s_end, *t;
929
t = src; while (*t && *t != '=') t++;
930
if (*t != '=') err_gprc("missing '='",t,src);
931
s_end = t;
932
t++;
933
if (*t == '"') (void)pari_translate_string(t, t, src);
934
*s_end = 0; *ps = src; *pt = t;
935
}
936
937
void
938
gp_initrc(pari_stack *p_A)
939
{
940
FILE *file = gprc_get();
941
Buffer *b;
942
filtre_t F;
943
VOLATILE long c = 0;
944
jmp_buf *env;
945
pari_stack s_env;
946
947
if (!file) return;
948
b = filtered_buffer(&F);
949
pari_stack_init(&s_env, sizeof(*env), (void**)&env);
950
(void)pari_stack_new(&s_env);
951
for(;;)
952
{
953
char *nexts, *s, *t;
954
if (setjmp(env[s_env.n-1])) err_printf("...skipping line %ld.\n", c);
955
c++;
956
if (!get_line_from_file(NULL,&F,file)) break;
957
s = b->buf;
958
if (*s == '#')
959
{ /* preprocessor directive */
960
int z, NOT = 0;
961
s++;
962
if (strncmp(s,"if",2)) err_gprc("unknown directive",s,b->buf);
963
s += 2;
964
if (!strncmp(s,"not",3)) { NOT = !NOT; s += 3; }
965
if (*s == '!') { NOT = !NOT; s++; }
966
t = s;
967
z = get_preproc_value(&s);
968
if (z < 0) err_gprc("unknown preprocessor variable",t,b->buf);
969
if (NOT) z = !z;
970
if (!*s)
971
{ /* make sure at least an expr follows the directive */
972
if (!get_line_from_file(NULL,&F,file)) break;
973
s = b->buf;
974
}
975
if (!z) continue; /* dump current line */
976
}
977
/* parse line */
978
for ( ; *s; s = nexts)
979
{
980
nexts = next_expr(s);
981
if (!strncmp(s,"read",4) && (s[4] == ' ' || s[4] == '\t' || s[4] == '"'))
982
{ /* read file */
983
s += 4;
984
t = (char*)pari_malloc(strlen(s) + 1);
985
if (*s == '"') (void)pari_translate_string(s, t, s-4); else strcpy(t,s);
986
pari_stack_pushp(p_A,t);
987
}
988
else
989
{ /* set default */
990
parse_key_val(s, &s,&t);
991
(void)setdefault(s,t,d_INITRC);
992
}
993
}
994
}
995
pari_stack_delete(&s_env);
996
pop_buffer();
997
if (!(GP_DATA->flags & gpd_QUIET)) err_printf("GPRC Done.\n\n");
998
fclose(file);
999
}
1000
1001
void
1002
gp_load_gprc(void)
1003
{
1004
pari_stack sA;
1005
char **A;
1006
long i;
1007
pari_stack_init(&sA,sizeof(*A),(void**)&A);
1008
gp_initrc(&sA);
1009
for (i = 0; i < sA.n; pari_free(A[i]),i++)
1010
{
1011
pari_CATCH(CATCH_ALL) { err_printf("... skipping file '%s'\n", A[i]); }
1012
pari_TRY { gp_read_file(A[i]); } pari_ENDCATCH;
1013
}
1014
pari_stack_delete(&sA);
1015
}
1016
1017
/********************************************************************/
1018
/* */
1019
/* PROMPTS */
1020
/* */
1021
/********************************************************************/
1022
/* if prompt is coloured, tell readline to ignore the ANSI escape sequences */
1023
/* s must be able to store 14 chars (including final \0) */
1024
#ifdef READLINE
1025
static void
1026
readline_prompt_color(char *s, int c)
1027
{
1028
#ifdef _WIN32
1029
(void)s; (void)c;
1030
#else
1031
*s++ = '\001'; /*RL_PROMPT_START_IGNORE*/
1032
term_get_color(s, c);
1033
s += strlen(s);
1034
*s++ = '\002'; /*RL_PROMPT_END_IGNORE*/
1035
*s = 0;
1036
#endif
1037
}
1038
#endif
1039
/* s must be able to store 14 chars (including final \0) */
1040
static void
1041
brace_color(char *s, int c, int force)
1042
{
1043
if (disable_color || (gp_colors[c] == c_NONE && !force)) return;
1044
#ifdef READLINE
1045
if (GP_DATA->use_readline)
1046
readline_prompt_color(s, c);
1047
else
1048
#endif
1049
term_get_color(s, c);
1050
}
1051
1052
/* strlen(prompt) + 28 chars */
1053
static const char *
1054
color_prompt(const char *prompt)
1055
{
1056
long n = strlen(prompt);
1057
char *t = stack_malloc(n + 28), *s = t;
1058
*s = 0;
1059
/* escape sequences bug readline, so use special bracing (if available) */
1060
brace_color(s, c_PROMPT, 0);
1061
s += strlen(s); memcpy(s, prompt, n);
1062
s += n; *s = 0;
1063
brace_color(s, c_INPUT, 1);
1064
return t;
1065
}
1066
1067
const char *
1068
gp_format_prompt(const char *prompt)
1069
{
1070
if (GP_DATA->flags & gpd_TEST)
1071
return prompt;
1072
else
1073
{
1074
char b[256]; /* longer is truncated */
1075
strftime_expand(prompt, b, sizeof(b));
1076
return color_prompt(b);
1077
}
1078
}
1079
1080
/********************************************************************/
1081
/* */
1082
/* GP MAIN LOOP */
1083
/* */
1084
/********************************************************************/
1085
static int
1086
is_interactive(void)
1087
{ return cb_pari_is_interactive? cb_pari_is_interactive(): 0; }
1088
1089
static char *
1090
strip_prompt(const char *s)
1091
{
1092
long l = strlen(s);
1093
char *t, *t0 = stack_malloc(l+1);
1094
t = t0;
1095
for (; *s; s++)
1096
{
1097
/* RL_PROMPT_START_IGNORE / RL_PROMPT_END_IGNORE */
1098
if (*s == 1 || *s == 2) continue;
1099
if (*s == '\x1b') /* skip ANSI color escape sequence */
1100
{
1101
while (*++s != 'm')
1102
if (!*s) goto end;
1103
continue;
1104
}
1105
*t = *s; t++;
1106
}
1107
end:
1108
*t = 0; return t0;
1109
}
1110
static void
1111
update_logfile(const char *prompt, const char *s)
1112
{
1113
pari_sp av;
1114
const char *p;
1115
if (!pari_logfile) return;
1116
av = avma;
1117
p = strip_prompt(prompt); /* raw prompt */
1118
1119
switch (pari_logstyle) {
1120
case logstyle_TeX:
1121
fprintf(pari_logfile,
1122
"\\PARIpromptSTART|%s\\PARIpromptEND|%s\\PARIinputEND|%%\n",
1123
p, s);
1124
break;
1125
case logstyle_plain:
1126
fprintf(pari_logfile,"%s%s\n",p, s);
1127
break;
1128
case logstyle_color:
1129
fprintf(pari_logfile,"%s%s%s%s%s\n",term_get_color(NULL,c_PROMPT), p,
1130
term_get_color(NULL,c_INPUT), s,
1131
term_get_color(NULL,c_NONE));
1132
break;
1133
}
1134
set_avma(av);
1135
}
1136
1137
void
1138
gp_echo_and_log(const char *prompt, const char *s)
1139
{
1140
if (!is_interactive())
1141
{
1142
if (!GP_DATA->echo) return;
1143
/* not pari_puts(): would duplicate in logfile */
1144
fputs(prompt, pari_outfile);
1145
fputs(s, pari_outfile);
1146
fputc('\n', pari_outfile);
1147
pari_set_last_newline(1);
1148
}
1149
update_logfile(prompt, s);
1150
pari_flush();
1151
}
1152
1153
/* prompt = NULL --> from gprc. Return 1 if new input, and 0 if EOF */
1154
int
1155
get_line_from_file(const char *prompt, filtre_t *F, FILE *file)
1156
{
1157
char *s;
1158
input_method IM;
1159
1160
IM.file = (void*)file;
1161
if (file==stdin && cb_pari_fgets_interactive)
1162
IM.myfgets = (fgets_t)cb_pari_fgets_interactive;
1163
else
1164
IM.myfgets = (fgets_t)&fgets;
1165
IM.getline = &file_input;
1166
IM.free = 0;
1167
if (! input_loop(F,&IM))
1168
{
1169
if (file==stdin && cb_pari_start_output) cb_pari_start_output();
1170
return 0;
1171
}
1172
s = F->buf->buf;
1173
/* don't log if from gprc or empty input */
1174
if (*s && prompt && GP_DATA->echo != 2) gp_echo_and_log(prompt, s);
1175
return 1;
1176
}
1177
1178
/* return 0 if no line could be read (EOF). If PROMPT = NULL, expand and
1179
* color default prompt; otherwise, use PROMPT as-is. */
1180
int
1181
gp_read_line(filtre_t *F, const char *PROMPT)
1182
{
1183
static const char *DFT_PROMPT = "? ";
1184
Buffer *b = (Buffer*)F->buf;
1185
const char *p;
1186
int res, interactive;
1187
if (b->len > 100000) fix_buffer(b, 100000);
1188
interactive = is_interactive();
1189
if (interactive || pari_logfile || GP_DATA->echo)
1190
{
1191
p = PROMPT;
1192
if (!p) {
1193
p = F->in_comment? GP_DATA->prompt_comment: GP_DATA->prompt;
1194
p = gp_format_prompt(p);
1195
}
1196
}
1197
else
1198
p = DFT_PROMPT;
1199
1200
if (interactive)
1201
{
1202
BLOCK_EH_START
1203
if (!pari_last_was_newline()) pari_putc('\n');
1204
if (cb_pari_get_line_interactive)
1205
res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F);
1206
else {
1207
pari_puts(p); pari_flush();
1208
res = get_line_from_file(p, F, pari_infile);
1209
}
1210
BLOCK_EH_END
1211
}
1212
else
1213
{ /* in case UI fakes noninteractivity, e.g. TeXmacs */
1214
if (cb_pari_start_output && cb_pari_get_line_interactive)
1215
res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F);
1216
else
1217
res = get_line_from_file(p, F, pari_infile);
1218
}
1219
1220
if (!disable_color && p != DFT_PROMPT &&
1221
(gp_colors[c_PROMPT] != c_NONE || gp_colors[c_INPUT] != c_NONE))
1222
{
1223
term_color(c_NONE); pari_flush();
1224
}
1225
return res;
1226
}
1227
1228
/********************************************************************/
1229
/* */
1230
/* EXCEPTION HANDLER */
1231
/* */
1232
/********************************************************************/
1233
static THREAD pari_timer ti_alarm;
1234
1235
#if defined(_WIN32) || defined(SIGALRM)
1236
static void
1237
gp_alarm_fun(void) {
1238
char buf[64];
1239
if (cb_pari_start_output) cb_pari_start_output();
1240
convert_time(buf, timer_get(&ti_alarm));
1241
pari_err(e_ALARM, buf);
1242
}
1243
#endif /* SIGALRM */
1244
1245
void
1246
gp_sigint_fun(void) {
1247
char buf[150];
1248
#if defined(_WIN32)
1249
if (win32alrm) { win32alrm = 0; gp_alarm_fun(); return;}
1250
#endif
1251
if (cb_pari_start_output) cb_pari_start_output();
1252
convert_time(buf, timer_get(GP_DATA->T));
1253
if (pari_mt_nbthreads > 1)
1254
{
1255
sprintf(buf + strlen(buf), " cpu time, ");
1256
convert_time(buf + strlen(buf), walltimer_get(GP_DATA->Tw));
1257
sprintf(buf + strlen(buf), " real time");
1258
}
1259
pari_sigint(buf);
1260
}
1261
1262
#ifdef SIGALRM
1263
void
1264
gp_alarm_handler(int sig)
1265
{
1266
#ifndef HAS_SIGACTION
1267
/*SYSV reset the signal handler in the handler*/
1268
(void)os_signal(sig,gp_alarm_handler);
1269
#endif
1270
if (PARI_SIGINT_block) PARI_SIGINT_pending=sig;
1271
else gp_alarm_fun();
1272
return;
1273
}
1274
#endif /* SIGALRM */
1275
1276
/********************************************************************/
1277
/* */
1278
/* GP-SPECIFIC ROUTINES */
1279
/* */
1280
/********************************************************************/
1281
void
1282
gp_allocatemem(GEN z)
1283
{
1284
ulong newsize;
1285
if (!z) newsize = 0;
1286
else {
1287
if (typ(z) != t_INT) pari_err_TYPE("allocatemem",z);
1288
newsize = itou(z);
1289
if (signe(z) < 0) pari_err_DOMAIN("allocatemem","size","<",gen_0,z);
1290
}
1291
if (pari_mainstack->vsize)
1292
paristack_resize(newsize);
1293
else
1294
paristack_newrsize(newsize);
1295
}
1296
1297
GEN
1298
gp_input(void)
1299
{
1300
filtre_t F;
1301
Buffer *b = filtered_buffer(&F);
1302
GEN x;
1303
1304
while (! get_line_from_file("",&F,pari_infile))
1305
if (popinfile()) { err_printf("no input ???"); cb_pari_quit(1); }
1306
x = readseq(b->buf);
1307
pop_buffer(); return x;
1308
}
1309
1310
static GEN
1311
closure_alarmer(GEN C, long s)
1312
{
1313
struct pari_evalstate state;
1314
VOLATILE GEN x;
1315
if (!s) { pari_alarm(0); return closure_evalgen(C); }
1316
evalstate_save(&state);
1317
#if !defined(HAS_ALARM) && !defined(_WIN32)
1318
pari_err(e_ARCH,"alarm");
1319
#endif
1320
pari_CATCH(CATCH_ALL) /* We need to stop the timer after any error */
1321
{
1322
GEN E = pari_err_last();
1323
if (err_get_num(E) != e_ALARM) { pari_alarm(0); pari_err(0, E); }
1324
x = evalstate_restore_err(&state);
1325
}
1326
pari_TRY { pari_alarm(s); x = closure_evalgen(C); pari_alarm(0); } pari_ENDCATCH;
1327
return x;
1328
}
1329
1330
void
1331
pari_alarm(long s)
1332
{
1333
if (s < 0) pari_err_DOMAIN("alarm","delay","<",gen_0,stoi(s));
1334
if (s) timer_start(&ti_alarm);
1335
#ifdef _WIN32
1336
win32_alarm(s);
1337
#elif defined(HAS_ALARM)
1338
alarm(s);
1339
#else
1340
if (s) pari_err(e_ARCH,"alarm");
1341
#endif
1342
}
1343
1344
GEN
1345
gp_alarm(long s, GEN code)
1346
{
1347
if (!code) { pari_alarm(s); return gnil; }
1348
return closure_alarmer(code,s);
1349
}
1350
1351
/*******************************************************************/
1352
/** **/
1353
/** EXTERNAL PRETTYPRINTER **/
1354
/** **/
1355
/*******************************************************************/
1356
/* Wait for prettinprinter to finish, to prevent new prompt from overwriting
1357
* the output. Fill the output buffer, wait until it is read.
1358
* Better than sleep(2): give possibility to print */
1359
static void
1360
prettyp_wait(FILE *out)
1361
{
1362
const char *s = " \n";
1363
long i = 2000;
1364
1365
fputs("\n\n", out); fflush(out); /* start translation */
1366
while (--i) fputs(s, out);
1367
fputs("\n", out); fflush(out);
1368
}
1369
1370
/* initialise external prettyprinter (tex2mail) */
1371
static int
1372
prettyp_init(void)
1373
{
1374
gp_pp *pp = GP_DATA->pp;
1375
if (!pp->cmd) return 0;
1376
if (pp->file || (pp->file = try_pipe(pp->cmd, mf_OUT))) return 1;
1377
1378
pari_warn(warner,"broken prettyprinter: '%s'",pp->cmd);
1379
pari_free(pp->cmd); pp->cmd = NULL;
1380
sd_output("1", d_SILENT);
1381
return 0;
1382
}
1383
1384
/* n = history number. if n = 0 no history */
1385
int
1386
tex2mail_output(GEN z, long n)
1387
{
1388
pariout_t T = *(GP_DATA->fmt); /* copy */
1389
FILE *log = pari_logfile, *out;
1390
1391
if (!prettyp_init()) return 0;
1392
out = GP_DATA->pp->file->file;
1393
/* Emit first: there may be lines before the prompt */
1394
if (n) term_color(c_OUTPUT);
1395
pari_flush();
1396
T.prettyp = f_TEX;
1397
/* history number */
1398
if (n)
1399
{
1400
pari_sp av = avma;
1401
const char *c_hist = term_get_color(NULL, c_HIST);
1402
const char *c_out = term_get_color(NULL, c_OUTPUT);
1403
if (!(GP_DATA->flags & gpd_QUIET))
1404
{
1405
if (*c_hist || *c_out)
1406
fprintf(out, "\\LITERALnoLENGTH{%s}\\%%%ld =\\LITERALnoLENGTH{%s} ",
1407
c_hist, n, c_out);
1408
else
1409
fprintf(out, "\\%%%ld = ", n);
1410
}
1411
if (log) {
1412
switch (pari_logstyle) {
1413
case logstyle_plain:
1414
fprintf(log, "%%%ld = ", n);
1415
break;
1416
case logstyle_color:
1417
fprintf(log, "%s%%%ld = %s", c_hist, n, c_out);
1418
break;
1419
case logstyle_TeX:
1420
fprintf(log, "\\PARIout{%ld}", n);
1421
break;
1422
}
1423
}
1424
set_avma(av);
1425
}
1426
/* output */
1427
fputGEN_pariout(z, &T, out);
1428
/* flush and restore, output to logfile */
1429
prettyp_wait(out);
1430
if (log) {
1431
if (pari_logstyle == logstyle_TeX) {
1432
T.TeXstyle |= TEXSTYLE_BREAK;
1433
fputGEN_pariout(z, &T, log);
1434
fputc('%', log);
1435
} else {
1436
T.prettyp = f_RAW;
1437
fputGEN_pariout(z, &T, log);
1438
}
1439
fputc('\n', log); fflush(log);
1440
}
1441
if (n) term_color(c_NONE);
1442
pari_flush(); return 1;
1443
}
1444
1445
/*******************************************************************/
1446
/** **/
1447
/** GP-SPECIFIC DEFAULTS **/
1448
/** **/
1449
/*******************************************************************/
1450
1451
static long
1452
atocolor(const char *s)
1453
{
1454
long l = atol(s);
1455
if (l & ~0xff) pari_err(e_MISC, "invalid 8bit RGB code: %ld", l);
1456
return l;
1457
}
1458
1459
GEN
1460
sd_graphcolormap(const char *v, long flag)
1461
{
1462
char *p, *q;
1463
long i, j, l, a, s, *lp;
1464
1465
if (v)
1466
{
1467
pari_sp av = avma;
1468
char *t = gp_filter(v);
1469
if (*t != '[' || t[strlen(t)-1] != ']')
1470
pari_err(e_SYNTAX, "incorrect value for graphcolormap", t, t);
1471
for (s = 0, p = t+1, l = 2, a=0; *p; p++)
1472
if (*p == '[')
1473
{
1474
a++;
1475
while (*++p != ']')
1476
if (!*p || *p == '[')
1477
pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
1478
}
1479
else if (*p == '"')
1480
{
1481
s += sizeof(long)+1;
1482
while (*p && *++p != '"') s++;
1483
if (!*p) pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
1484
s = (s+sizeof(long)-1) & ~(sizeof(long)-1);
1485
}
1486
else if (*p == ',')
1487
l++;
1488
if (l < 4)
1489
pari_err(e_MISC, "too few colors (< 4) in graphcolormap");
1490
if (GP_DATA->colormap) pari_free(GP_DATA->colormap);
1491
GP_DATA->colormap = (GEN)pari_malloc((l+4*a)*sizeof(long) + s);
1492
GP_DATA->colormap[0] = evaltyp(t_VEC)|evallg(l);
1493
for (p = t+1, i = 1, lp = GP_DATA->colormap+l; i < l; p++)
1494
switch(*p)
1495
{
1496
case '"':
1497
gel(GP_DATA->colormap, i) = lp;
1498
q = ++p; while (*q != '"') q++;
1499
*q = 0;
1500
j = 1 + nchar2nlong(q-p+1);
1501
lp[0] = evaltyp(t_STR)|evallg(j);
1502
strncpy(GSTR(lp), p, q-p+1);
1503
lp += j; p = q;
1504
break;
1505
case '[': {
1506
const char *ap[3];
1507
gel(GP_DATA->colormap, i) = lp;
1508
lp[0] = evaltyp(t_VECSMALL)|_evallg(4);
1509
for (ap[0] = ++p, j=0; *p && *p != ']'; p++)
1510
if (*p == ',' && j<2) { *p++ = 0; ap[++j] = p; }
1511
while (j<2) ap[++j] = "0";
1512
if (j>2 || *p != ']')
1513
{
1514
char buf[100];
1515
sprintf(buf, "incorrect value for graphcolormap[%ld]: ", i);
1516
pari_err(e_SYNTAX, buf, p, t);
1517
}
1518
*p = '\0';
1519
lp[1] = atocolor(ap[0]);
1520
lp[2] = atocolor(ap[1]);
1521
lp[3] = atocolor(ap[2]);
1522
lp += 4;
1523
break;
1524
}
1525
case ',':
1526
case ']':
1527
i++;
1528
break;
1529
default:
1530
pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
1531
}
1532
set_avma(av);
1533
}
1534
if (flag == d_RETURN || flag == d_ACKNOWLEDGE)
1535
{
1536
GEN C = cgetg(lg(GP_DATA->colormap), t_VEC);
1537
long i, l = lg(C);
1538
for (i = 1; i < l; i++)
1539
{
1540
GEN c = gel(GP_DATA->colormap, i);
1541
gel(C, i) = (typ(c) == t_STR)? gcopy(c): zv_to_ZV(c);
1542
}
1543
if (flag == d_RETURN) return C;
1544
pari_printf(" graphcolormap = %Ps\n", C);
1545
}
1546
return gnil;
1547
}
1548
1549
GEN
1550
sd_graphcolors(const char *v, long flag)
1551
{ return sd_intarray(v, flag, &(GP_DATA->graphcolors), "graphcolors"); }
1552
GEN
1553
sd_plothsizes(const char *v, long flag)
1554
{ return sd_intarray(v, flag, &(GP_DATA->plothsizes), "plothsizes"); }
1555
1556
GEN
1557
sd_help(const char *v, long flag)
1558
{
1559
const char *str;
1560
if (v)
1561
{
1562
if (GP_DATA->secure)
1563
pari_err(e_MISC,"[secure mode]: can't modify 'help' default (to %s)",v);
1564
if (GP_DATA->help) pari_free((void*)GP_DATA->help);
1565
#ifndef _WIN32
1566
GP_DATA->help = path_expand(v);
1567
#else
1568
GP_DATA->help = pari_strdup(v);
1569
#endif
1570
}
1571
str = GP_DATA->help? GP_DATA->help: "none";
1572
if (flag == d_RETURN) return strtoGENstr(str);
1573
if (flag == d_ACKNOWLEDGE)
1574
pari_printf(" help = \"%s\"\n", str);
1575
return gnil;
1576
}
1577
1578
static GEN
1579
sd_prompt_set(const char *v, long flag, const char *how, char **p)
1580
{
1581
if (v) {
1582
if (*p) free(*p);
1583
*p = pari_strdup(v);
1584
}
1585
if (flag == d_RETURN) return strtoGENstr(*p);
1586
if (flag == d_ACKNOWLEDGE)
1587
pari_printf(" prompt%s = \"%s\"\n", how, *p);
1588
return gnil;
1589
}
1590
GEN
1591
sd_prompt(const char *v, long flag)
1592
{ return sd_prompt_set(v, flag, "", &(GP_DATA->prompt)); }
1593
GEN
1594
sd_prompt_cont(const char *v, long flag)
1595
{ return sd_prompt_set(v, flag, "_cont", &(GP_DATA->prompt_cont)); }
1596
1597
GEN
1598
sd_breakloop(const char *v, long flag)
1599
{ return sd_toggle(v,flag,"breakloop", &(GP_DATA->breakloop)); }
1600
GEN
1601
sd_echo(const char *v, long flag)
1602
{ return sd_ulong(v,flag,"echo", &(GP_DATA->echo), 0,2,NULL); }
1603
GEN
1604
sd_timer(const char *v, long flag)
1605
{ return sd_toggle(v,flag,"timer", &(GP_DATA->chrono)); }
1606
GEN
1607
sd_recover(const char *v, long flag)
1608
{ return sd_toggle(v,flag,"recover", &(GP_DATA->recover)); }
1609
1610
GEN
1611
sd_psfile(const char *v, long flag)
1612
{ return sd_string(v, flag, "psfile", &current_psfile); }
1613
1614
GEN
1615
sd_lines(const char *v, long flag)
1616
{ return sd_ulong(v,flag,"lines",&(GP_DATA->lim_lines), 0,LONG_MAX,NULL); }
1617
GEN
1618
sd_linewrap(const char *v, long flag)
1619
{
1620
ulong old = GP_DATA->linewrap, n = GP_DATA->linewrap;
1621
GEN z = sd_ulong(v,flag,"linewrap",&n, 0,LONG_MAX,NULL);
1622
if (old)
1623
{ if (!n) resetout(1); }
1624
else
1625
{ if (n) init_linewrap(n); }
1626
GP_DATA->linewrap = n; return z;
1627
}
1628
1629
/* readline-specific defaults */
1630
GEN
1631
sd_readline(const char *v, long flag)
1632
{
1633
const char *msg[] = {
1634
"(bits 0x2/0x4 control matched-insert/arg-complete)", NULL};
1635
ulong state = GP_DATA->readline_state;
1636
GEN res = sd_ulong(v,flag,"readline", &GP_DATA->readline_state, 0, 7, msg);
1637
1638
if (state != GP_DATA->readline_state)
1639
(void)sd_toggle(GP_DATA->readline_state? "1": "0", d_SILENT, "readline", &(GP_DATA->use_readline));
1640
return res;
1641
}
1642
GEN
1643
sd_histfile(const char *v, long flag)
1644
{
1645
char *old = GP_DATA->histfile;
1646
GEN r = sd_string(v, flag, "histfile", &GP_DATA->histfile);
1647
if (v && !*v)
1648
{
1649
free(GP_DATA->histfile);
1650
GP_DATA->histfile = NULL;
1651
}
1652
else if (GP_DATA->histfile != old && (!old || strcmp(old,GP_DATA->histfile)))
1653
{
1654
if (cb_pari_init_histfile) cb_pari_init_histfile();
1655
}
1656
return r;
1657
}
1658
1659
/********************************************************************/
1660
/** **/
1661
/** METACOMMANDS **/
1662
/** **/
1663
/********************************************************************/
1664
void
1665
pari_print_version(void)
1666
{
1667
pari_sp av = avma;
1668
char *buf, *ver = what_cc();
1669
const char *kver = pari_kernel_version();
1670
const char *date = paricfg_compiledate;
1671
1672
pari_center(paricfg_version);
1673
buf = stack_malloc(strlen(paricfg_buildinfo) + 2 + strlen(kver));
1674
(void)sprintf(buf, paricfg_buildinfo, kver);
1675
pari_center(buf);
1676
buf = stack_malloc(strlen(date) + 32 + (ver? strlen(ver): 0));
1677
if (ver) (void)sprintf(buf, "compiled: %s, %s", date, ver);
1678
else (void)sprintf(buf, "compiled: %s", date);
1679
pari_center(buf);
1680
sprintf(buf, "threading engine: %s",paricfg_mt_engine);
1681
pari_center(buf);
1682
ver = what_readline();
1683
buf = stack_malloc(strlen(ver) + 64);
1684
(void)sprintf(buf, "(readline %s, extended help%s enabled)", ver,
1685
has_ext_help()? "": " not");
1686
pari_center(buf); set_avma(av);
1687
}
1688
1689
static int
1690
cmp_epname(void *E, GEN e, GEN f)
1691
{
1692
(void)E;
1693
return strcmp(((entree*)e)->name, ((entree*)f)->name);
1694
}
1695
static void
1696
print_all_user_fun(int member)
1697
{
1698
pari_sp av = avma;
1699
long iL = 0, lL = 1024;
1700
GEN L = cgetg(lL+1, t_VECSMALL);
1701
entree *ep;
1702
int i;
1703
for (i = 0; i < functions_tblsz; i++)
1704
for (ep = functions_hash[i]; ep; ep = ep->next)
1705
{
1706
const char *f;
1707
int is_member;
1708
if (EpVALENCE(ep) != EpVAR || typ((GEN)ep->value)!=t_CLOSURE) continue;
1709
f = ep->name;
1710
is_member = (f[0] == '_' && f[1] == '.');
1711
if (member != is_member) continue;
1712
1713
if (iL >= lL)
1714
{
1715
GEN oL = L;
1716
long j;
1717
lL *= 2; L = cgetg(lL+1, t_VECSMALL);
1718
for (j = 1; j <= iL; j++) gel(L,j) = gel(oL,j);
1719
}
1720
L[++iL] = (long)ep;
1721
}
1722
if (iL)
1723
{
1724
setlg(L, iL+1);
1725
gen_sort_inplace(L, NULL, &cmp_epname, NULL);
1726
for (i = 1; i <= iL; i++)
1727
{
1728
ep = (entree*)L[i];
1729
pari_printf("%s =\n %Ps\n\n", ep->name, ep->value);
1730
}
1731
}
1732
set_avma(av);
1733
}
1734
1735
static char *
1736
get_name(const char *s)
1737
{
1738
char *t = get_sep(s);
1739
if (*t == '"')
1740
{
1741
long n = strlen(t)-1;
1742
if (t[n] == '"') { t[n] = 0; t++; }
1743
}
1744
return t;
1745
}
1746
1747
static void
1748
escape(const char *tch, int ismain)
1749
{
1750
const char *s = tch;
1751
char c;
1752
switch ((c = *s++))
1753
{
1754
case 'w': case 'x': case 'a': case 'b': case 'B': case 'm':
1755
{ /* history things */
1756
long d;
1757
GEN x;
1758
if (c != 'w' && c != 'x') d = get_int(s,0);
1759
else
1760
{
1761
d = atol(s); if (*s == '-') s++;
1762
while (isdigit((int)*s)) s++;
1763
}
1764
x = pari_get_hist(d);
1765
switch (c)
1766
{
1767
case 'B': /* prettyprinter */
1768
if (tex2mail_output(x,0)) break;
1769
case 'b': /* fall through */
1770
case 'm': matbrute(x, GP_DATA->fmt->format, -1); break;
1771
case 'a': brute(x, GP_DATA->fmt->format, -1); break;
1772
case 'x': dbgGEN(x, get_int(s, -1)); break;
1773
case 'w':
1774
s = get_name(s); if (!*s) s = current_logfile;
1775
write0(s, mkvec(x)); return;
1776
}
1777
pari_putc('\n'); return;
1778
}
1779
1780
case 'c': commands(-1); break;
1781
case 'd': (void)setdefault(NULL,NULL,d_SILENT); break;
1782
case 'e':
1783
s = get_sep(s);
1784
if (!*s) s = (GP_DATA->echo)? "0": "1";
1785
(void)sd_echo(s,d_ACKNOWLEDGE); break;
1786
case 'g':
1787
switch (*s)
1788
{
1789
case 'm': s++; (void)sd_debugmem(*s? s: NULL,d_ACKNOWLEDGE); break;
1790
case 'f': s++; (void)sd_debugfiles(*s? s: NULL,d_ACKNOWLEDGE); break;
1791
default : (void)sd_debug(*s? s: NULL,d_ACKNOWLEDGE); break;
1792
}
1793
break;
1794
case 'h': print_functions_hash(s); break;
1795
case 'l':
1796
s = get_name(s);
1797
if (*s)
1798
{
1799
if (pari_logfile) { (void)sd_logfile(s,d_ACKNOWLEDGE);break; }
1800
(void)sd_logfile(s,d_SILENT);
1801
}
1802
(void)sd_log(pari_logfile?"0":"1",d_ACKNOWLEDGE);
1803
break;
1804
case 'o': (void)sd_output(*s? s: NULL,d_ACKNOWLEDGE); break;
1805
case 'p':
1806
switch (*s)
1807
{
1808
case 's': s++;
1809
(void)sd_seriesprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
1810
case 'b' : s++;
1811
(void)sd_realbitprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
1812
default :
1813
(void)sd_realprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
1814
}
1815
break;
1816
case 'q': cb_pari_quit(0); break;
1817
case 'r':
1818
s = get_name(s);
1819
if (!ismain) { (void)gp_read_file(s); break; }
1820
switchin(s);
1821
if (file_is_binary(pari_infile))
1822
{
1823
pari_sp av = avma;
1824
int vector;
1825
GEN x = readbin(s,pari_infile, &vector);
1826
popinfile();
1827
if (!x) pari_err_FILE("input file",s);
1828
if (vector) /* many BIN_GEN */
1829
{
1830
long i, l = lg(x);
1831
pari_warn(warner,"setting %ld history entries", l-1);
1832
for (i=1; i<l; i++) pari_add_hist(gel(x,i), 0, 0);
1833
}
1834
set_avma(av);
1835
}
1836
break;
1837
case 's': dbg_pari_heap(); break;
1838
case 't': gentypes(); break;
1839
case 'u':
1840
print_all_user_fun((*s == 'm')? 1: 0);
1841
break;
1842
case 'v': pari_print_version(); break;
1843
case 'y':
1844
s = get_sep(s);
1845
if (!*s) s = (GP_DATA->simplify)? "0": "1";
1846
(void)sd_simplify(s,d_ACKNOWLEDGE); break;
1847
default: pari_err(e_SYNTAX,"unexpected character", tch,tch-1);
1848
}
1849
}
1850
1851
static int
1852
chron(const char *s)
1853
{
1854
if (*s)
1855
{ /* if "#" or "##" timer metacommand. Otherwise let the parser get it */
1856
const char *t;
1857
if (*s == '#') s++;
1858
if (*s) return 0;
1859
t = gp_format_time(pari_get_histtime(0));
1860
if (pari_mt_nbthreads==1)
1861
pari_printf(" *** last result computed in %s.\n", t);
1862
else
1863
{
1864
const char *r = gp_format_time(pari_get_histrtime(0));
1865
pari_printf(" *** last result: cpu time %s, real time %s.\n", t,r);
1866
}
1867
}
1868
else { GP_DATA->chrono ^= 1; (void)sd_timer(NULL,d_ACKNOWLEDGE); }
1869
return 1;
1870
}
1871
1872
/* return 0: can't interpret *buf as a metacommand
1873
* 1: did interpret *buf as a metacommand or empty command */
1874
int
1875
gp_meta(const char *buf, int ismain)
1876
{
1877
switch(*buf++)
1878
{
1879
case '?': gp_help(buf, h_REGULAR); break;
1880
case '#': return chron(buf);
1881
case '\\': escape(buf, ismain); break;
1882
case '\0': break;
1883
default: return 0;
1884
}
1885
return 1;
1886
}
1887
1888