Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28495 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
/** INPUT/OUTPUT SUBROUTINES **/
18
/** **/
19
/*******************************************************************/
20
#ifdef _WIN32
21
#include "../systems/mingw/pwinver.h"
22
#include <windows.h>
23
#include <process.h> /* for getpid */
24
#include <fcntl.h>
25
#include <io.h> /* for setmode */
26
#include "../systems/mingw/mingw.h"
27
#endif
28
#include "paricfg.h"
29
#ifdef HAS_STAT
30
#include <sys/stat.h>
31
#endif
32
#ifdef HAS_OPENDIR
33
#include <dirent.h>
34
#endif
35
36
#include "pari.h"
37
#include "paripriv.h"
38
#include "anal.h"
39
#ifdef __EMSCRIPTEN__
40
#include "../systems/emscripten/emscripten.h"
41
#endif
42
43
#define DEBUGLEVEL DEBUGLEVEL_io
44
45
typedef void (*OUT_FUN)(GEN, pariout_t *, pari_str *);
46
47
static void bruti_sign(GEN g, pariout_t *T, pari_str *S, int addsign);
48
static void matbruti(GEN g, pariout_t *T, pari_str *S);
49
static void texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign);
50
51
static void bruti(GEN g, pariout_t *T, pari_str *S)
52
{ bruti_sign(g,T,S,1); }
53
static void texi(GEN g, pariout_t *T, pari_str *S)
54
{ texi_sign(g,T,S,1); }
55
56
void
57
pari_ask_confirm(const char *s)
58
{
59
if (!cb_pari_ask_confirm)
60
pari_err(e_MISC,"Can't ask for confirmation. Please define cb_pari_ask_confirm()");
61
cb_pari_ask_confirm(s);
62
}
63
64
static char *
65
strip_last_nl(char *s)
66
{
67
ulong l = strlen(s);
68
char *t;
69
if (l && s[l-1] != '\n') return s;
70
if (l>1 && s[l-2] == '\r') l--;
71
t = stack_malloc(l); memcpy(t, s, l-1); t[l-1] = 0;
72
return t;
73
}
74
75
/********************************************************************/
76
/** **/
77
/** INPUT FILTER **/
78
/** **/
79
/********************************************************************/
80
#define ONE_LINE_COMMENT 2
81
#define MULTI_LINE_COMMENT 1
82
#define LBRACE '{'
83
#define RBRACE '}'
84
85
static int
86
in_help(filtre_t *F)
87
{
88
char c;
89
if (!F->buf) return (*F->s == '?');
90
c = *F->buf->buf;
91
return c? (c == '?'): (*F->s == '?');
92
}
93
/* Filter F->s into F->t */
94
static char *
95
filtre0(filtre_t *F)
96
{
97
const char *s = F->s;
98
char c, *t = F->t;
99
100
if (F->more_input == 1) F->more_input = 0;
101
while ((c = *s++))
102
{
103
if (F->in_string)
104
{
105
*t++ = c; /* copy verbatim */
106
switch(c)
107
{
108
case '\\': /* in strings, \ is the escape character */
109
if (*s) *t++ = *s++;
110
break;
111
112
case '"': F->in_string = 0;
113
}
114
continue;
115
}
116
117
if (F->in_comment)
118
{ /* look for comment's end */
119
if (F->in_comment == MULTI_LINE_COMMENT)
120
{
121
while (c != '*' || *s != '/')
122
{
123
if (!*s)
124
{
125
if (!F->more_input) F->more_input = 1;
126
goto END;
127
}
128
c = *s++;
129
}
130
s++;
131
}
132
else
133
while (c != '\n' && *s) c = *s++;
134
F->in_comment = 0;
135
continue;
136
}
137
138
/* weed out comments and spaces */
139
if (c=='\\' && *s=='\\') { F->in_comment = ONE_LINE_COMMENT; continue; }
140
if (isspace((int)c)) continue;
141
*t++ = c;
142
switch(c)
143
{
144
case '/':
145
if (*s == '*') { t--; F->in_comment = MULTI_LINE_COMMENT; }
146
break;
147
148
case '\\':
149
if (!*s) {
150
if (in_help(F)) break; /* '?...\' */
151
t--;
152
if (!F->more_input) F->more_input = 1;
153
goto END;
154
}
155
if (*s == '\r') s++; /* DOS */
156
if (*s == '\n') {
157
if (in_help(F)) break; /* '?...\' */
158
t--; s++;
159
if (!*s)
160
{
161
if (!F->more_input) F->more_input = 1;
162
goto END;
163
}
164
} /* skip \<CR> */
165
break;
166
167
case '"': F->in_string = 1;
168
break;
169
170
case LBRACE:
171
t--;
172
if (F->wait_for_brace) pari_err_IMPL("embedded braces (in parser)");
173
F->more_input = 2;
174
F->wait_for_brace = 1;
175
break;
176
177
case RBRACE:
178
if (!F->wait_for_brace) pari_err(e_MISC,"unexpected closing brace");
179
F->more_input = 0; t--;
180
F->wait_for_brace = 0;
181
break;
182
}
183
}
184
185
if (t != F->t) /* non empty input */
186
{
187
c = t[-1]; /* last char */
188
if (c == '=') { if (!in_help(F)) F->more_input = 2; }
189
else if (! F->wait_for_brace) F->more_input = 0;
190
else if (c == RBRACE) { F->more_input = 0; t--; F->wait_for_brace--;}
191
}
192
193
END:
194
F->end = t; *t = 0; return F->t;
195
}
196
#undef ONE_LINE_COMMENT
197
#undef MULTI_LINE_COMMENT
198
199
char *
200
gp_filter(const char *s)
201
{
202
filtre_t T;
203
T.buf = NULL;
204
T.s = s;
205
T.t = (char*)stack_malloc(strlen(s)+1);
206
T.in_string = 0; T.more_input = 0;
207
T.in_comment= 0; T.wait_for_brace = 0;
208
return filtre0(&T);
209
}
210
211
void
212
init_filtre(filtre_t *F, Buffer *buf)
213
{
214
F->buf = buf;
215
F->in_string = 0;
216
F->in_comment = 0;
217
}
218
219
/********************************************************************/
220
/** **/
221
/** INPUT METHODS **/
222
/** **/
223
/********************************************************************/
224
/* create */
225
Buffer *
226
new_buffer(void)
227
{
228
Buffer *b = (Buffer*) pari_malloc(sizeof(Buffer));
229
b->len = 1024;
230
b->buf = (char*)pari_malloc(b->len);
231
return b;
232
}
233
/* delete */
234
void
235
delete_buffer(Buffer *b)
236
{
237
if (!b) return;
238
pari_free((void*)b->buf); pari_free((void*)b);
239
}
240
/* resize */
241
void
242
fix_buffer(Buffer *b, long newlbuf)
243
{
244
b->len = newlbuf;
245
pari_realloc_ip((void**)&b->buf, b->len);
246
}
247
248
static int
249
gp_read_stream_buf(FILE *fi, Buffer *b)
250
{
251
input_method IM;
252
filtre_t F;
253
254
init_filtre(&F, b);
255
256
IM.file = (void*)fi;
257
IM.myfgets = (fgets_t)&fgets;
258
IM.getline = &file_input;
259
IM.free = 0;
260
return input_loop(&F,&IM);
261
}
262
263
GEN
264
gp_read_stream(FILE *fi)
265
{
266
Buffer *b = new_buffer();
267
GEN x = NULL;
268
while (gp_read_stream_buf(fi, b))
269
{
270
if (*(b->buf)) { x = readseq(b->buf); break; }
271
}
272
delete_buffer(b); return x;
273
}
274
275
static GEN
276
gp_read_from_input(input_method* IM, int loop, char *last)
277
{
278
Buffer *b = new_buffer();
279
GEN x = gnil;
280
filtre_t F;
281
if (last) *last = 0;
282
do {
283
char *s;
284
init_filtre(&F, b);
285
if (!input_loop(&F, IM)) break;
286
s = b->buf;
287
if (s[0])
288
{
289
x = readseq(s);
290
if (last) *last = s[strlen(s) - 1];
291
}
292
} while (loop);
293
delete_buffer(b);
294
return x;
295
}
296
297
GEN
298
gp_read_file(const char *s)
299
{
300
GEN x = gnil;
301
FILE *f = switchin(s);
302
if (file_is_binary(f))
303
{
304
x = readbin(s,f, NULL);
305
if (!x) pari_err_FILE("input file",s);
306
}
307
else {
308
pari_sp av = avma;
309
Buffer *b = new_buffer();
310
x = gnil;
311
for (;;) {
312
if (!gp_read_stream_buf(f, b)) break;
313
if (*(b->buf)) { set_avma(av); x = readseq(b->buf); }
314
}
315
delete_buffer(b);
316
}
317
popinfile(); return x;
318
}
319
320
static char*
321
string_gets(char *s, int size, const char **ptr)
322
{
323
/* f is actually a const char** */
324
const char *in = *ptr;
325
int i;
326
char c;
327
328
/* Copy from in to s */
329
for (i = 0; i+1 < size && in[i] != 0;)
330
{
331
s[i] = c = in[i]; i++;
332
if (c == '\n') break;
333
}
334
s[i] = 0; /* Terminating 0 byte */
335
if (i == 0) return NULL;
336
337
*ptr += i;
338
return s;
339
}
340
341
GEN
342
gp_read_str_multiline(const char *s, char *last)
343
{
344
input_method IM;
345
const char *ptr = s;
346
347
IM.file = (void*)(&ptr);
348
IM.myfgets = (fgets_t)&string_gets;
349
IM.getline = &file_input;
350
IM.free = 0;
351
352
return gp_read_from_input(&IM, 1, last);
353
}
354
355
void
356
gp_embedded_init(long rsize, long vsize)
357
{
358
pari_init(rsize, 500000);
359
paristack_setsize(rsize, vsize);
360
}
361
362
char *
363
gp_embedded(const char *s)
364
{
365
char last, *res;
366
struct gp_context state;
367
VOLATILE long t = 0, r = 0;
368
gp_context_save(&state);
369
timer_start(GP_DATA->T);
370
timer_start(GP_DATA->Tw);
371
pari_set_last_newline(1);
372
pari_CATCH(CATCH_ALL)
373
{
374
GENbin* err = copy_bin(pari_err_last());
375
gp_context_restore(&state);
376
res = pari_err2str(bin_copy(err));
377
} pari_TRY {
378
GEN z = gp_read_str_multiline(s, &last);
379
ulong n;
380
t = timer_delay(GP_DATA->T);
381
r = walltimer_delay(GP_DATA->Tw);
382
if (GP_DATA->simplify) z = simplify_shallow(z);
383
pari_add_hist(z, t, r);
384
n = pari_nb_hist();
385
set_avma(pari_mainstack->top);
386
parivstack_reset();
387
res = (z==gnil || last==';') ? stack_strdup("\n"):
388
stack_sprintf("%%%lu = %Ps\n", n, pari_get_hist(n));
389
if (t && GP_DATA->chrono)
390
res = stack_sprintf("%stime = %s.\n", res, gp_format_time(t));
391
} pari_ENDCATCH;
392
if (!pari_last_was_newline()) pari_putc('\n');
393
set_avma(pari_mainstack->top);
394
return res;
395
}
396
397
GEN
398
gp_readvec_stream(FILE *fi)
399
{
400
pari_sp ltop = avma;
401
Buffer *b = new_buffer();
402
long i = 1, n = 16;
403
GEN z = cgetg(n+1,t_VEC);
404
for(;;)
405
{
406
if (!gp_read_stream_buf(fi, b)) break;
407
if (!*(b->buf)) continue;
408
if (i>n)
409
{
410
if (DEBUGLEVEL) err_printf("gp_readvec_stream: reaching %ld entries\n",n);
411
n <<= 1;
412
z = vec_lengthen(z,n);
413
}
414
gel(z,i++) = readseq(b->buf);
415
}
416
if (DEBUGLEVEL) err_printf("gp_readvec_stream: found %ld entries\n",i-1);
417
setlg(z,i); delete_buffer(b);
418
return gerepilecopy(ltop,z);
419
}
420
421
GEN
422
gp_readvec_file(char *s)
423
{
424
GEN x = NULL;
425
FILE *f = switchin(s);
426
if (file_is_binary(f)) {
427
int junk;
428
x = readbin(s,f,&junk);
429
if (!x) pari_err_FILE("input file",s);
430
} else
431
x = gp_readvec_stream(f);
432
popinfile(); return x;
433
}
434
435
char *
436
file_getline(Buffer *b, char **s0, input_method *IM)
437
{
438
const ulong MAX = (1UL << 31) - 1;
439
ulong used0, used;
440
441
**s0 = 0; /* paranoia */
442
used0 = used = *s0 - b->buf;
443
for(;;)
444
{
445
ulong left = b->len - used, l, read;
446
char *s;
447
448
/* If little space left, double the buffer size before next read. */
449
if (left < 512)
450
{
451
fix_buffer(b, b->len << 1);
452
left = b->len - used;
453
*s0 = b->buf + used0;
454
}
455
/* # of chars read by fgets is an int; be careful */
456
read = minuu(left, MAX);
457
s = b->buf + used;
458
if (! IM->myfgets(s, (int)read, IM->file)) return **s0? *s0: NULL; /* EOF */
459
460
l = strlen(s);
461
if (l+1 < read || s[l-1] == '\n') return *s0; /* \n */
462
used += l;
463
}
464
}
465
466
/* Read from file (up to '\n' or EOF) and copy at s0 (points in b->buf) */
467
char *
468
file_input(char **s0, int junk, input_method *IM, filtre_t *F)
469
{
470
(void)junk;
471
return file_getline(F->buf, s0, IM);
472
}
473
474
/* Read a "complete line" and filter it. Return: 0 if EOF, 1 otherwise */
475
int
476
input_loop(filtre_t *F, input_method *IM)
477
{
478
Buffer *b = (Buffer*)F->buf;
479
char *to_read, *s = b->buf;
480
481
/* read first line */
482
if (! (to_read = IM->getline(&s,1, IM, F)) )
483
{
484
if (F->in_string)
485
{
486
pari_warn(warner,"run-away string. Closing it");
487
F->in_string = 0;
488
}
489
if (F->in_comment)
490
{
491
pari_warn(warner,"run-away comment. Closing it");
492
F->in_comment = 0;
493
}
494
return 0;
495
}
496
497
/* buffer is not empty, init filter */
498
F->in_string = 0;
499
F->more_input= 0;
500
F->wait_for_brace = 0;
501
for(;;)
502
{
503
if (GP_DATA->echo == 2) gp_echo_and_log("", strip_last_nl(to_read));
504
F->s = to_read;
505
F->t = s;
506
(void)filtre0(F); /* pre-processing of line, read by previous call to IM->getline */
507
if (IM->free) pari_free(to_read);
508
if (! F->more_input) break;
509
510
/* read continuation line */
511
s = F->end;
512
to_read = IM->getline(&s,0, IM, F);
513
if (!to_read) break;
514
}
515
return 1;
516
}
517
518
/********************************************************************/
519
/** **/
520
/** GENERAL PURPOSE PRINTING **/
521
/** **/
522
/********************************************************************/
523
PariOUT *pariOut, *pariErr;
524
static void
525
_fputs(const char *s, FILE *f ) {
526
#ifdef _WIN32
527
win32_ansi_fputs(s, f);
528
#else
529
fputs(s, f);
530
#endif
531
}
532
static void
533
_putc_log(char c) { if (pari_logfile) (void)putc(c, pari_logfile); }
534
static void
535
_puts_log(const char *s)
536
{
537
FILE *f = pari_logfile;
538
const char *p;
539
if (!f) return;
540
if (pari_logstyle != logstyle_color)
541
while ( (p = strchr(s, '\x1b')) )
542
{ /* skip ANSI color escape sequence */
543
if ( p!=s ) fwrite(s, 1, p-s, f);
544
s = strchr(p, 'm');
545
if (!s) return;
546
s++;
547
}
548
fputs(s, f);
549
}
550
static void
551
_flush_log(void)
552
{ if (pari_logfile != NULL) (void)fflush(pari_logfile); }
553
554
static void
555
normalOutC(char c) { putc(c, pari_outfile); _putc_log(c); }
556
static void
557
normalOutS(const char *s) { _fputs(s, pari_outfile); _puts_log(s); }
558
static void
559
normalOutF(void) { fflush(pari_outfile); _flush_log(); }
560
static PariOUT defaultOut = {normalOutC, normalOutS, normalOutF};
561
562
static void
563
normalErrC(char c) { putc(c, pari_errfile); _putc_log(c); }
564
static void
565
normalErrS(const char *s) { _fputs(s, pari_errfile); _puts_log(s); }
566
static void
567
normalErrF(void) { fflush(pari_errfile); _flush_log(); }
568
static PariOUT defaultErr = {normalErrC, normalErrS, normalErrF};
569
570
/** GENERIC PRINTING **/
571
void
572
resetout(int initerr)
573
{
574
pariOut = &defaultOut;
575
if (initerr) pariErr = &defaultErr;
576
}
577
void
578
initout(int initerr)
579
{
580
pari_infile = stdin;
581
pari_outfile = stdout;
582
pari_errfile = stderr;
583
resetout(initerr);
584
}
585
586
static int last_was_newline = 1;
587
588
static void
589
set_last_newline(char c) { last_was_newline = (c == '\n'); }
590
591
void
592
out_putc(PariOUT *out, char c) { set_last_newline(c); out->putch(c); }
593
void
594
pari_putc(char c) { out_putc(pariOut, c); }
595
596
void
597
out_puts(PariOUT *out, const char *s) {
598
if (*s) { set_last_newline(s[strlen(s)-1]); out->puts(s); }
599
}
600
void
601
pari_puts(const char *s) { out_puts(pariOut, s); }
602
603
int
604
pari_last_was_newline(void) { return last_was_newline; }
605
void
606
pari_set_last_newline(int last) { last_was_newline = last; }
607
608
void
609
pari_flush(void) { pariOut->flush(); }
610
611
void
612
err_flush(void) { pariErr->flush(); }
613
614
static GEN
615
log10_2(void)
616
{ return divrr(mplog2(LOWDEFAULTPREC), mplog(utor(10,LOWDEFAULTPREC))); }
617
618
/* e binary exponent, return exponent in base ten */
619
static long
620
ex10(long e) {
621
pari_sp av;
622
GEN z;
623
if (e >= 0) {
624
if (e < 1e15) return (long)(e*LOG10_2);
625
av = avma; z = mulur(e, log10_2());
626
z = floorr(z); e = itos(z);
627
}
628
else /* e < 0 */
629
{
630
if (e > -1e15) return (long)(-(-e*LOG10_2)-1);
631
av = avma; z = mulsr(e, log10_2());
632
z = floorr(z); e = itos(z) - 1;
633
}
634
set_avma(av); return e;
635
}
636
637
static char *
638
zeros(char *b, long nb) { while (nb-- > 0) *b++ = '0'; *b = 0; return b; }
639
640
/* # of decimal digits, assume l > 0 */
641
static long
642
numdig(ulong l)
643
{
644
if (l < 100000)
645
{
646
if (l < 100) return (l < 10)? 1: 2;
647
if (l < 10000) return (l < 1000)? 3: 4;
648
return 5;
649
}
650
if (l < 10000000) return (l < 1000000)? 6: 7;
651
if (l < 1000000000) return (l < 100000000)? 8: 9;
652
return 10;
653
}
654
655
/* let ndig <= 9, x < 10^ndig, write in p[-ndig..-1] the decimal digits of x */
656
static void
657
utodec(char *p, ulong x, long ndig)
658
{
659
switch(ndig)
660
{
661
case 9: *--p = x % 10 + '0'; x = x/10;
662
case 8: *--p = x % 10 + '0'; x = x/10;
663
case 7: *--p = x % 10 + '0'; x = x/10;
664
case 6: *--p = x % 10 + '0'; x = x/10;
665
case 5: *--p = x % 10 + '0'; x = x/10;
666
case 4: *--p = x % 10 + '0'; x = x/10;
667
case 3: *--p = x % 10 + '0'; x = x/10;
668
case 2: *--p = x % 10 + '0'; x = x/10;
669
case 1: *--p = x % 10 + '0'; x = x/10;
670
}
671
}
672
673
/* convert abs(x) != 0 to str. Prepend '-' if (sx < 0) */
674
static char *
675
itostr_sign(GEN x, int sx, long *len)
676
{
677
long l, d;
678
ulong *res = convi(x, &l);
679
/* l 9-digits words (< 10^9) + (optional) sign + \0 */
680
char *s = (char*)new_chunk(nchar2nlong(l*9 + 1 + 1)), *t = s;
681
682
if (sx < 0) *t++ = '-';
683
d = numdig(*--res); t += d; utodec(t, *res, d);
684
while (--l > 0) { t += 9; utodec(t, *--res, 9); }
685
*t = 0; *len = t - s; return s;
686
}
687
688
/********************************************************************/
689
/** **/
690
/** WRITE A REAL NUMBER **/
691
/** **/
692
/********************************************************************/
693
/* 19 digits (if 64 bits, at most 2^60-1) + 1 sign */
694
static const long MAX_EXPO_LEN = 20;
695
696
/* write z to buf, inserting '.' at 'point', 0 < point < strlen(z) */
697
static void
698
wr_dec(char *buf, char *z, long point)
699
{
700
char *s = buf + point;
701
strncpy(buf, z, point); /* integer part */
702
*s++ = '.'; z += point;
703
while ( (*s++ = *z++) ) /* empty */;
704
}
705
706
static char *
707
zerotostr(void)
708
{
709
char *s = (char*)new_chunk(1);
710
s[0] = '0';
711
s[1] = 0; return s;
712
}
713
714
/* write a real 0 of exponent ex in format f */
715
static char *
716
real0tostr_width_frac(long width_frac)
717
{
718
char *buf, *s;
719
if (width_frac == 0) return zerotostr();
720
buf = s = stack_malloc(width_frac + 3);
721
*s++ = '0';
722
*s++ = '.';
723
(void)zeros(s, width_frac);
724
return buf;
725
}
726
727
/* write a real 0 of exponent ex */
728
static char *
729
real0tostr(long ex, char format, char exp_char, long wanted_dec)
730
{
731
char *buf, *buf0;
732
733
if (format == 'f') {
734
long width_frac = wanted_dec;
735
if (width_frac < 0) width_frac = (ex >= 0)? 0: (long)(-ex * LOG10_2);
736
return real0tostr_width_frac(width_frac);
737
} else {
738
buf0 = buf = stack_malloc(3 + MAX_EXPO_LEN + 1);
739
*buf++ = '0';
740
*buf++ = '.';
741
*buf++ = exp_char;
742
sprintf(buf, "%ld", ex10(ex) + 1);
743
}
744
return buf0;
745
}
746
747
/* format f, width_frac >= 0: number of digits in fractional part, */
748
static char *
749
absrtostr_width_frac(GEN x, int width_frac)
750
{
751
long beta, ls, point, lx, sx = signe(x);
752
char *s, *buf;
753
GEN z;
754
755
if (!sx) return real0tostr_width_frac(width_frac);
756
757
/* x != 0 */
758
lx = realprec(x);
759
beta = width_frac;
760
if (beta) /* >= 0 */
761
{ /* z = |x| 10^beta, 10^b = 5^b * 2^b, 2^b goes into exponent */
762
if (beta > 4e9) lx++;
763
z = mulrr(x, rpowuu(5UL, (ulong)beta, lx+1));
764
setsigne(z, 1);
765
shiftr_inplace(z, beta);
766
}
767
else
768
z = mpabs(x);
769
z = roundr_safe(z);
770
if (!signe(z)) return real0tostr_width_frac(width_frac);
771
772
s = itostr_sign(z, 1, &ls); /* ls > 0, number of digits in s */
773
point = ls - beta; /* position of . in s; <= ls, may be < 0 */
774
if (point > 0) /* write integer_part.fractional_part */
775
{
776
/* '.', trailing \0 */
777
buf = stack_malloc( ls + 1+1 );
778
if (ls == point)
779
strcpy(buf, s); /* no '.' */
780
else
781
wr_dec(buf, s, point);
782
} else { /* point <= 0, fractional part must be written */
783
char *t;
784
/* '0', '.', zeroes, trailing \0 */
785
buf = t = stack_malloc( 1 + 1 - point + ls + 1 );
786
*t++ = '0';
787
*t++ = '.';
788
t = zeros(t, -point);
789
strcpy(t, s);
790
}
791
return buf;
792
}
793
794
/* Return t_REAL |x| in floating point format.
795
* Allocate freely, the caller must clean the stack.
796
* FORMAT: E/e (exponential), F/f (floating point), G/g
797
* wanted_dec: number of significant digits to print (all if < 0).
798
*/
799
static char *
800
absrtostr(GEN x, int sp, char FORMAT, long wanted_dec)
801
{
802
const char format = (char)tolower((int)FORMAT), exp_char = (format == FORMAT)? 'e': 'E';
803
long beta, ls, point, lx, sx = signe(x), ex = expo(x);
804
char *s, *buf, *buf0;
805
GEN z;
806
807
if (!sx) return real0tostr(ex, format, exp_char, wanted_dec);
808
809
/* x != 0 */
810
lx = realprec(x);
811
if (wanted_dec >= 0)
812
{ /* reduce precision if possible */
813
long w = ndec2prec(wanted_dec); /* digits -> pari precision in words */
814
if (lx > w) lx = w; /* truncature with guard, no rounding */
815
}
816
beta = ex10(prec2nbits(lx) - ex);
817
if (beta)
818
{ /* z = |x| 10^beta, 10^b = 5^b * 2^b, 2^b goes into exponent */
819
if (beta > 0)
820
{
821
if (beta > 18) { lx++; x = rtor(x, lx); }
822
z = mulrr(x, rpowuu(5UL, (ulong)beta, lx+1));
823
}
824
else
825
{
826
if (beta < -18) { lx++; x = rtor(x, lx); }
827
z = divrr(x, rpowuu(5UL, (ulong)-beta, lx+1));
828
}
829
setsigne(z, 1);
830
shiftr_inplace(z, beta);
831
}
832
else
833
z = x;
834
z = roundr_safe(z);
835
if (!signe(z)) return real0tostr(ex, format, exp_char, wanted_dec);
836
837
s = itostr_sign(z, 1, &ls); /* ls > 0, number of digits in s */
838
if (wanted_dec < 0)
839
wanted_dec = ls;
840
else if (ls > wanted_dec)
841
{
842
beta -= ls - wanted_dec;
843
ls = wanted_dec;
844
if (s[ls] >= '5') /* round up */
845
{
846
long i;
847
for (i = ls-1; i >= 0; s[i--] = '0')
848
if (++s[i] <= '9') break;
849
if (i < 0) { s[0] = '1'; beta--; }
850
}
851
s[ls] = 0;
852
}
853
854
/* '.', " E", exponent, trailing \0 */
855
point = ls - beta; /* position of . in s; < 0 or > 0 */
856
if (beta <= 0 || format == 'e' || (format == 'g' && point-1 < -4))
857
{ /* e format */
858
buf0 = buf = stack_malloc(ls+1+2+MAX_EXPO_LEN + 1);
859
wr_dec(buf, s, 1); buf += ls + 1;
860
if (sp) *buf++ = ' ';
861
*buf++ = exp_char;
862
sprintf(buf, "%ld", point-1);
863
}
864
else if (point > 0) /* f format, write integer_part.fractional_part */
865
{
866
buf0 = buf = stack_malloc(ls+1 + 1);
867
wr_dec(buf, s, point); /* point < ls since beta > 0 */
868
}
869
else /* f format, point <= 0, write fractional part */
870
{
871
buf0 = buf = stack_malloc(2-point+ls + 1);
872
*buf++ = '0';
873
*buf++ = '.';
874
buf = zeros(buf, -point);
875
strcpy(buf, s);
876
}
877
return buf0;
878
}
879
880
/* vsnprintf implementation rewritten from snprintf.c to be found at
881
*
882
* http://www.nersc.gov/~scottc/misc/docs/snort-2.1.1-RC1/snprintf_8c-source.html
883
* The original code was
884
* Copyright (C) 1998-2002 Martin Roesch <[email protected]>
885
* available under the terms of the GNU GPL version 2 or later. It
886
* was itself adapted from an original version by Patrick Powell. */
887
888
/* Modifications for format %Ps: R.Butel IMB/CNRS 2007/12/03 */
889
890
/* l = old len, L = new len */
891
static void
892
str_alloc0(pari_str *S, long l, long L)
893
{
894
if (S->use_stack)
895
S->string = (char*) memcpy(stack_malloc(L), S->string, l);
896
else
897
pari_realloc_ip((void**)&S->string, L);
898
S->cur = S->string + l;
899
S->end = S->string + L;
900
S->size = L;
901
}
902
/* make sure S is large enough to write l further words (<= l * 20 chars).
903
* To avoid automatic extension in between av = avma / set_avma(av) pairs
904
* [ would destroy S->string if (S->use_stack) ] */
905
static void
906
str_alloc(pari_str *S, long l)
907
{
908
l *= 20;
909
if (S->end - S->cur <= l)
910
str_alloc0(S, S->cur - S->string, S->size + maxss(S->size, l));
911
}
912
void
913
str_putc(pari_str *S, char c)
914
{
915
*S->cur++ = c;
916
if (S->cur == S->end) str_alloc0(S, S->size, S->size << 1);
917
}
918
919
void
920
str_init(pari_str *S, int use_stack)
921
{
922
char *s;
923
S->size = 1024;
924
S->use_stack = use_stack;
925
if (S->use_stack)
926
s = (char*)stack_malloc(S->size);
927
else
928
s = (char*)pari_malloc(S->size);
929
*s = 0;
930
S->string = S->cur = s;
931
S->end = S->string + S->size;
932
}
933
void
934
str_puts(pari_str *S, const char *s) { while (*s) str_putc(S, *s++); }
935
936
static void
937
str_putscut(pari_str *S, const char *s, int cut)
938
{
939
if (cut < 0) str_puts(S, s);
940
else {
941
while (*s && cut-- > 0) str_putc(S, *s++);
942
}
943
}
944
945
/* lbuf = strlen(buf), len < 0: unset */
946
static void
947
outpad(pari_str *S, const char *buf, long lbuf, int sign, long ljust, long len, long zpad)
948
{
949
long padlen = len - lbuf;
950
if (padlen < 0) padlen = 0;
951
if (ljust) padlen = -padlen;
952
if (padlen > 0)
953
{
954
if (zpad) {
955
if (sign) { str_putc(S, sign); --padlen; }
956
while (padlen > 0) { str_putc(S, '0'); --padlen; }
957
}
958
else
959
{
960
if (sign) --padlen;
961
while (padlen > 0) { str_putc(S, ' '); --padlen; }
962
if (sign) str_putc(S, sign);
963
}
964
} else
965
if (sign) str_putc(S, sign);
966
str_puts(S, buf);
967
while (padlen < 0) { str_putc(S, ' '); ++padlen; }
968
}
969
970
/* len < 0 or maxwidth < 0: unset */
971
static void
972
fmtstr(pari_str *S, const char *buf, int ljust, int len, int maxwidth)
973
{
974
int padlen, lbuf = strlen(buf);
975
976
if (maxwidth >= 0 && lbuf > maxwidth) lbuf = maxwidth;
977
978
padlen = len - lbuf;
979
if (padlen < 0) padlen = 0;
980
if (ljust) padlen = -padlen;
981
while (padlen > 0) { str_putc(S, ' '); --padlen; }
982
str_putscut(S, buf, maxwidth);
983
while (padlen < 0) { str_putc(S, ' '); ++padlen; }
984
}
985
986
/* abs(base) is 8, 10, 16. If base < 0, some "alternate" form
987
* -- print hex in uppercase
988
* -- prefix octal with 0
989
* signvalue = -1: unsigned, otherwise ' ' or '+'. Leaves a messy stack if
990
* S->use_stack */
991
static void
992
fmtnum(pari_str *S, long lvalue, GEN gvalue, int base, int signvalue,
993
int ljust, int len, int zpad)
994
{
995
int caps;
996
char *buf0, *buf;
997
long lbuf, mxl;
998
GEN uvalue = NULL;
999
ulong ulvalue = 0;
1000
pari_sp av = avma;
1001
1002
if (gvalue)
1003
{
1004
long s, l;
1005
if (typ(gvalue) != t_INT) {
1006
long i, j, h;
1007
l = lg(gvalue);
1008
switch(typ(gvalue))
1009
{
1010
case t_VEC:
1011
str_putc(S, '[');
1012
for (i = 1; i < l; i++)
1013
{
1014
fmtnum(S, 0, gel(gvalue,i), base, signvalue, ljust,len,zpad);
1015
if (i < l-1) str_putc(S, ',');
1016
}
1017
str_putc(S, ']');
1018
return;
1019
case t_COL:
1020
str_putc(S, '[');
1021
for (i = 1; i < l; i++)
1022
{
1023
fmtnum(S, 0, gel(gvalue,i), base, signvalue, ljust,len,zpad);
1024
if (i < l-1) str_putc(S, ',');
1025
}
1026
str_putc(S, ']');
1027
str_putc(S, '~');
1028
return;
1029
case t_MAT:
1030
if (l == 1)
1031
str_puts(S, "[;]");
1032
else
1033
{
1034
h = lgcols(gvalue);
1035
for (i=1; i<h; i++)
1036
{
1037
str_putc(S, '[');
1038
for (j=1; j<l; j++)
1039
{
1040
fmtnum(S, 0, gcoeff(gvalue,i,j), base, signvalue, ljust,len,zpad);
1041
if (j<l-1) str_putc(S, ' ');
1042
}
1043
str_putc(S, ']');
1044
str_putc(S, '\n');
1045
if (i<h-1) str_putc(S, '\n');
1046
}
1047
}
1048
return;
1049
}
1050
gvalue = gfloor( simplify_shallow(gvalue) );
1051
if (typ(gvalue) != t_INT)
1052
pari_err(e_MISC,"not a t_INT in integer format conversion: %Ps", gvalue);
1053
}
1054
s = signe(gvalue);
1055
if (!s) { lbuf = 1; buf = zerotostr(); signvalue = 0; goto END; }
1056
1057
l = lgefint(gvalue);
1058
uvalue = gvalue;
1059
if (signvalue < 0)
1060
{
1061
if (s < 0) uvalue = addii(int2n(bit_accuracy(l)), gvalue);
1062
signvalue = 0;
1063
}
1064
else
1065
{
1066
if (s < 0) { signvalue = '-'; uvalue = absi(uvalue); }
1067
}
1068
mxl = (l-2)* 22 + 1; /* octal at worst; 22 octal chars per 64bit word */
1069
} else {
1070
ulvalue = lvalue;
1071
if (signvalue < 0)
1072
signvalue = 0;
1073
else
1074
if (lvalue < 0) { signvalue = '-'; ulvalue = - lvalue; }
1075
mxl = 22 + 1; /* octal at worst; 22 octal chars to write down 2^64 - 1 */
1076
}
1077
if (base > 0) caps = 0; else { caps = 1; base = -base; }
1078
1079
buf0 = buf = stack_malloc(mxl) + mxl; /* fill from the right */
1080
*--buf = 0; /* trailing \0 */
1081
if (gvalue) {
1082
if (base == 10) {
1083
long i, l, cnt;
1084
ulong *larray = convi(uvalue, &l);
1085
larray -= l;
1086
for (i = 0; i < l; i++) {
1087
cnt = 0;
1088
ulvalue = larray[i];
1089
do {
1090
*--buf = '0' + ulvalue%10;
1091
ulvalue = ulvalue / 10;
1092
cnt++;
1093
} while (ulvalue);
1094
if (i + 1 < l)
1095
for (;cnt<9;cnt++) *--buf = '0';
1096
}
1097
} else if (base == 16) {
1098
long i, l = lgefint(uvalue);
1099
GEN up = int_LSW(uvalue);
1100
for (i = 2; i < l; i++, up = int_nextW(up)) {
1101
ulong ucp = (ulong)*up;
1102
long j;
1103
for (j=0; j < BITS_IN_LONG/4; j++) {
1104
unsigned char cv = ucp & 0xF;
1105
*--buf = (caps? "0123456789ABCDEF":"0123456789abcdef")[cv];
1106
ucp >>= 4;
1107
if (ucp == 0 && i+1 == l) break;
1108
}
1109
} /* loop on hex digits in word */
1110
} else if (base == 8) {
1111
long i, l = lgefint(uvalue);
1112
GEN up = int_LSW(uvalue);
1113
ulong rem = 0;
1114
int shift = 0;
1115
int mask[3] = {0, 1, 3};
1116
for (i = 2; i < l; i++, up = int_nextW(up)) {
1117
ulong ucp = (ulong)*up;
1118
long j, ldispo = BITS_IN_LONG;
1119
if (shift) { /* 0, 1 or 2 */
1120
unsigned char cv = ((ucp & mask[shift]) <<(3-shift)) + rem;
1121
*--buf = "01234567"[cv];
1122
ucp >>= shift;
1123
ldispo -= shift;
1124
};
1125
shift = (shift + 3 - BITS_IN_LONG % 3) % 3;
1126
for (j=0; j < BITS_IN_LONG/3; j++) {
1127
unsigned char cv = ucp & 0x7;
1128
if (ucp == 0 && i+1 == l) { rem = 0; break; };
1129
*--buf = "01234567"[cv];
1130
ucp >>= 3;
1131
ldispo -= 3;
1132
rem = ucp;
1133
if (ldispo < 3) break;
1134
}
1135
} /* loop on hex digits in word */
1136
if (rem) *--buf = "01234567"[rem];
1137
}
1138
} else { /* not a gvalue, thus a standard integer */
1139
do {
1140
*--buf = (caps? "0123456789ABCDEF":"0123456789abcdef")[ulvalue % (unsigned)base ];
1141
ulvalue /= (unsigned)base;
1142
} while (ulvalue);
1143
}
1144
/* leading 0 if octal and alternate # form */
1145
if (caps && base == 8) *--buf = '0';
1146
lbuf = (buf0 - buf) - 1;
1147
END:
1148
outpad(S, buf, lbuf, signvalue, ljust, len, zpad);
1149
if (!S->use_stack) set_avma(av);
1150
}
1151
1152
static GEN
1153
v_get_arg(pari_str *S, GEN arg_vector, int *index, const char *save_fmt)
1154
{
1155
if (*index >= lg(arg_vector))
1156
{
1157
if (!S->use_stack) pari_free(S->string);
1158
pari_err(e_MISC, "missing arg %d for printf format '%s'", *index, save_fmt); }
1159
return gel(arg_vector, (*index)++);
1160
}
1161
1162
static int
1163
dosign(int blank, int plus)
1164
{
1165
if (plus) return('+');
1166
if (blank) return(' ');
1167
return 0;
1168
}
1169
1170
/* x * 10 + 'digit whose char value is ch'. Do not check for overflow */
1171
static int
1172
shift_add(int x, int ch)
1173
{
1174
if (x < 0) /* was unset */
1175
x = ch - '0';
1176
else
1177
x = x*10 + ch - '0';
1178
return x;
1179
}
1180
1181
static long
1182
get_sigd(GEN gvalue, char ch, int maxwidth)
1183
{
1184
long e;
1185
if (maxwidth < 0) return nbits2ndec(precreal);
1186
switch(ch)
1187
{
1188
case 'E': case 'e': return maxwidth+1;
1189
case 'F': case 'f':
1190
e = gexpo(gvalue);
1191
return (e == -(long)HIGHEXPOBIT)? 0: ex10(e) + 1 + maxwidth;
1192
}
1193
return maxwidth? maxwidth: 1; /* 'g', 'G' */
1194
}
1195
1196
static void
1197
fmtreal(pari_str *S, GEN gvalue, int space, int signvalue, int FORMAT,
1198
int maxwidth, int ljust, int len, int zpad)
1199
{
1200
pari_sp av = avma;
1201
long sigd;
1202
char *buf;
1203
1204
if (typ(gvalue) == t_REAL)
1205
sigd = get_sigd(gvalue, FORMAT, maxwidth);
1206
else
1207
{
1208
long i, j, h, l = lg(gvalue);
1209
switch(typ(gvalue))
1210
{
1211
case t_VEC:
1212
str_putc(S, '[');
1213
for (i = 1; i < l; i++)
1214
{
1215
fmtreal(S, gel(gvalue,i), space, signvalue, FORMAT, maxwidth,
1216
ljust,len,zpad);
1217
if (i < l-1) str_putc(S, ',');
1218
}
1219
str_putc(S, ']');
1220
return;
1221
case t_COL:
1222
str_putc(S, '[');
1223
for (i = 1; i < l; i++)
1224
{
1225
fmtreal(S, gel(gvalue,i), space, signvalue, FORMAT, maxwidth,
1226
ljust,len,zpad);
1227
if (i < l-1) str_putc(S, ',');
1228
}
1229
str_putc(S, ']');
1230
str_putc(S, '~');
1231
return;
1232
case t_MAT:
1233
if (l == 1)
1234
str_puts(S, "[;]");
1235
else
1236
{
1237
h = lgcols(gvalue);
1238
for (j=1; j<h; j++)
1239
{
1240
str_putc(S, '[');
1241
for (i=1; i<l; i++)
1242
{
1243
fmtreal(S, gcoeff(gvalue,j,i), space, signvalue, FORMAT, maxwidth,
1244
ljust,len,zpad);
1245
if (i<l-1) str_putc(S, ' ');
1246
}
1247
str_putc(S, ']');
1248
str_putc(S, '\n');
1249
if (j<h-1) str_putc(S, '\n');
1250
}
1251
}
1252
return;
1253
}
1254
sigd = get_sigd(gvalue, FORMAT, maxwidth);
1255
gvalue = gtofp(gvalue, maxss(ndec2prec(sigd), LOWDEFAULTPREC));
1256
if (typ(gvalue) != t_REAL)
1257
{
1258
if (!S->use_stack) free(S->string);
1259
pari_err(e_MISC,"impossible conversion to t_REAL: %Ps",gvalue);
1260
}
1261
}
1262
if ((FORMAT == 'f' || FORMAT == 'F') && maxwidth >= 0)
1263
buf = absrtostr_width_frac(gvalue, maxwidth);
1264
else
1265
buf = absrtostr(gvalue, space, FORMAT, sigd);
1266
if (signe(gvalue) < 0) signvalue = '-';
1267
outpad(S, buf, strlen(buf), signvalue, ljust, len, zpad);
1268
if (!S->use_stack) set_avma(av);
1269
}
1270
static long
1271
gtolong_OK(GEN x)
1272
{
1273
switch(typ(x))
1274
{
1275
case t_INT: case t_REAL: case t_FRAC: return 1;
1276
case t_COMPLEX: return gequal0(gel(x,2)) && gtolong_OK(gel(x,1));
1277
case t_QUAD: return gequal0(gel(x,3)) && gtolong_OK(gel(x,2));
1278
}
1279
return 0;
1280
}
1281
/* Format handling "inspired" by the standard draft at
1282
-- http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf pages 274ff
1283
* fmt is a standard printf format, except 'P' is a "length modifier"
1284
* allowing GEN arguments. Use either the arg_vector or (if NULL) the va_list.
1285
* Appent output to the pari_str S, which must be initialized; clean if
1286
* !S->use_stack, else leaves objects of stack. */
1287
static void
1288
str_arg_vprintf(pari_str *S, const char *fmt, GEN arg_vector, va_list args)
1289
{
1290
int GENflag = 0, longflag = 0, pointflag = 0;
1291
int print_plus, print_blank, with_sharp, ch, ljust, len, maxwidth, zpad;
1292
long lvalue;
1293
int index = 1;
1294
GEN gvalue;
1295
const char *save_fmt = fmt;
1296
1297
while ((ch = *fmt++) != '\0') {
1298
switch(ch) {
1299
case '%':
1300
ljust = zpad = 0;
1301
len = maxwidth = -1;
1302
GENflag = longflag = pointflag = 0;
1303
print_plus = print_blank = with_sharp = 0;
1304
nextch:
1305
ch = *fmt++;
1306
switch(ch) {
1307
case 0:
1308
pari_err(e_MISC, "printf: end of format");
1309
/*------------------------------------------------------------------------
1310
-- flags
1311
------------------------------------------------------------------------*/
1312
case '-':
1313
ljust = 1;
1314
goto nextch;
1315
case '+':
1316
print_plus = 1;
1317
goto nextch;
1318
case '#':
1319
with_sharp = 1;
1320
goto nextch;
1321
case ' ':
1322
print_blank = 1;
1323
goto nextch;
1324
case '0':
1325
/* appears as a flag: set zero padding */
1326
if (len < 0 && !pointflag) { zpad = '0'; goto nextch; }
1327
1328
/* else part of a field width or precision */
1329
/* fall through */
1330
/*------------------------------------------------------------------------
1331
-- maxwidth or precision
1332
------------------------------------------------------------------------*/
1333
case '1':
1334
case '2':
1335
case '3':
1336
case '4':
1337
case '5':
1338
case '6':
1339
case '7':
1340
case '8':
1341
case '9':
1342
if (pointflag)
1343
maxwidth = shift_add(maxwidth, ch);
1344
else
1345
len = shift_add(len, ch);
1346
goto nextch;
1347
1348
case '*':
1349
{
1350
int *t = pointflag? &maxwidth: &len;
1351
if (arg_vector)
1352
{
1353
gvalue = v_get_arg(S, arg_vector, &index, save_fmt);
1354
if (!gtolong_OK(gvalue) && !S->use_stack) pari_free(S->string);
1355
*t = (int)gtolong(gvalue);
1356
}
1357
else
1358
*t = va_arg(args, int);
1359
goto nextch;
1360
}
1361
case '.':
1362
if (pointflag)
1363
pari_err(e_MISC, "two '.' in conversion specification");
1364
pointflag = 1;
1365
goto nextch;
1366
/*------------------------------------------------------------------------
1367
-- length modifiers
1368
------------------------------------------------------------------------*/
1369
case 'l':
1370
if (GENflag)
1371
pari_err(e_MISC, "P/l length modifiers in the same conversion");
1372
#if !defined(_WIN64)
1373
if (longflag)
1374
pari_err_IMPL( "ll length modifier in printf");
1375
#endif
1376
longflag = 1;
1377
goto nextch;
1378
case 'P':
1379
if (longflag)
1380
pari_err(e_MISC, "P/l length modifiers in the same conversion");
1381
if (GENflag)
1382
pari_err(e_MISC, "'P' length modifier appears twice");
1383
GENflag = 1;
1384
goto nextch;
1385
case 'h': /* dummy: va_arg promotes short into int */
1386
goto nextch;
1387
/*------------------------------------------------------------------------
1388
-- conversions
1389
------------------------------------------------------------------------*/
1390
case 'u': /* not a signed conversion: print_(blank|plus) ignored */
1391
#define get_num_arg() \
1392
if (arg_vector) { \
1393
lvalue = 0; \
1394
gvalue = v_get_arg(S, arg_vector, &index, save_fmt); \
1395
} else { \
1396
if (GENflag) { \
1397
lvalue = 0; \
1398
gvalue = va_arg(args, GEN); \
1399
} else { \
1400
lvalue = longflag? va_arg(args, long): va_arg(args, int); \
1401
gvalue = NULL; \
1402
} \
1403
}
1404
get_num_arg();
1405
fmtnum(S, lvalue, gvalue, 10, -1, ljust, len, zpad);
1406
break;
1407
case 'o': /* not a signed conversion: print_(blank|plus) ignored */
1408
get_num_arg();
1409
fmtnum(S, lvalue, gvalue, with_sharp? -8: 8, -1, ljust, len, zpad);
1410
break;
1411
case 'd':
1412
case 'i':
1413
get_num_arg();
1414
fmtnum(S, lvalue, gvalue, 10,
1415
dosign(print_blank, print_plus), ljust, len, zpad);
1416
break;
1417
case 'p':
1418
str_putc(S, '0'); str_putc(S, 'x');
1419
if (arg_vector)
1420
lvalue = (long)v_get_arg(S, arg_vector, &index, save_fmt);
1421
else
1422
lvalue = (long)va_arg(args, void*);
1423
fmtnum(S, lvalue, NULL, 16, -1, ljust, len, zpad);
1424
break;
1425
case 'x': /* not a signed conversion: print_(blank|plus) ignored */
1426
if (with_sharp) { str_putc(S, '0'); str_putc(S, 'x'); }
1427
get_num_arg();
1428
fmtnum(S, lvalue, gvalue, 16, -1, ljust, len, zpad);
1429
break;
1430
case 'X': /* not a signed conversion: print_(blank|plus) ignored */
1431
if (with_sharp) { str_putc(S, '0'); str_putc(S, 'X'); }
1432
get_num_arg();
1433
fmtnum(S, lvalue, gvalue,-16, -1, ljust, len, zpad);
1434
break;
1435
case 's':
1436
{
1437
char *strvalue;
1438
pari_sp av = avma;
1439
1440
if (arg_vector) {
1441
gvalue = v_get_arg(S, arg_vector, &index, save_fmt);
1442
strvalue = NULL;
1443
} else {
1444
if (GENflag) {
1445
gvalue = va_arg(args, GEN);
1446
strvalue = NULL;
1447
} else {
1448
gvalue = NULL;
1449
strvalue = va_arg(args, char *);
1450
}
1451
}
1452
if (gvalue) strvalue = GENtostr_unquoted(gvalue);
1453
fmtstr(S, strvalue, ljust, len, maxwidth);
1454
if (!S->use_stack) set_avma(av);
1455
break;
1456
}
1457
case 'c':
1458
gvalue = NULL;
1459
if (arg_vector)
1460
gvalue = v_get_arg(S, arg_vector, &index, save_fmt);
1461
else if (GENflag)
1462
gvalue = va_arg(args,GEN);
1463
else
1464
{
1465
ch = va_arg(args, int);
1466
str_putc(S, ch); break;
1467
}
1468
if (!gtolong_OK(gvalue) && !S->use_stack) free(S->string);
1469
str_putc(S, (int)gtolong(gvalue));
1470
break;
1471
1472
case '%':
1473
str_putc(S, ch);
1474
continue;
1475
case 'g':
1476
case 'G':
1477
case 'e':
1478
case 'E':
1479
case 'f':
1480
case 'F':
1481
{
1482
pari_sp av = avma;
1483
if (arg_vector)
1484
gvalue = simplify_shallow(v_get_arg(S, arg_vector, &index, save_fmt));
1485
else {
1486
if (GENflag)
1487
gvalue = simplify_shallow( va_arg(args, GEN) );
1488
else
1489
gvalue = dbltor( va_arg(args, double) );
1490
}
1491
fmtreal(S, gvalue, GP_DATA->fmt->sp, dosign(print_blank,print_plus),
1492
ch, maxwidth, ljust, len, zpad);
1493
if (!S->use_stack) set_avma(av);
1494
break;
1495
}
1496
default:
1497
if (!S->use_stack) free(S->string);
1498
pari_err(e_MISC, "invalid conversion or specification %c in format `%s'", ch, save_fmt);
1499
} /* second switch on ch */
1500
break;
1501
default:
1502
str_putc(S, ch);
1503
break;
1504
} /* first switch on ch */
1505
} /* while loop on ch */
1506
*S->cur = 0;
1507
}
1508
1509
void
1510
decode_color(long n, long *c)
1511
{
1512
c[1] = n & 0xf; n >>= 4; /* foreground */
1513
c[2] = n & 0xf; n >>= 4; /* background */
1514
c[0] = n & 0xf; /* attribute */
1515
}
1516
1517
#define COLOR_LEN 16
1518
/* start printing in "color" c */
1519
/* terminal has to support ANSI color escape sequences */
1520
void
1521
out_term_color(PariOUT *out, long c)
1522
{
1523
static char s[COLOR_LEN];
1524
out->puts(term_get_color(s, c));
1525
}
1526
void
1527
term_color(long c) { out_term_color(pariOut, c); }
1528
1529
/* s must be able to store 12 chars (including final \0) */
1530
char *
1531
term_get_color(char *s, long n)
1532
{
1533
long c[3], a;
1534
if (!s) s = stack_malloc(COLOR_LEN);
1535
1536
if (disable_color) { *s = 0; return s; }
1537
if (n == c_NONE || (a = gp_colors[n]) == c_NONE)
1538
strcpy(s, "\x1b[0m"); /* reset */
1539
else
1540
{
1541
decode_color(a,c);
1542
if (c[1]<8) c[1] += 30; else c[1] += 82;
1543
if (a & (1L<<12)) /* transparent background */
1544
sprintf(s, "\x1b[%ld;%ldm", c[0], c[1]);
1545
else
1546
{
1547
if (c[2]<8) c[2] += 40; else c[2] += 92;
1548
sprintf(s, "\x1b[%ld;%ld;%ldm", c[0], c[1], c[2]);
1549
}
1550
}
1551
return s;
1552
}
1553
1554
static long
1555
strlen_real(const char *s)
1556
{
1557
const char *t = s;
1558
long len = 0;
1559
while (*t)
1560
{
1561
if (t[0] == '\x1b' && t[1] == '[')
1562
{ /* skip ANSI escape sequence */
1563
t += 2;
1564
while (*t && *t++ != 'm') /* empty */;
1565
continue;
1566
}
1567
t++; len++;
1568
}
1569
return len;
1570
}
1571
1572
#undef COLOR_LEN
1573
1574
/********************************************************************/
1575
/** **/
1576
/** PRINTING BASED ON SCREEN WIDTH **/
1577
/** **/
1578
/********************************************************************/
1579
#undef larg /* problems with SCO Unix headers (ioctl_arg) */
1580
#ifdef HAS_TIOCGWINSZ
1581
# ifdef __sun
1582
# include <sys/termios.h>
1583
# endif
1584
# include <sys/ioctl.h>
1585
#endif
1586
1587
static int
1588
term_width_intern(void)
1589
{
1590
#ifdef _WIN32
1591
return win32_terminal_width();
1592
#endif
1593
#ifdef HAS_TIOCGWINSZ
1594
{
1595
struct winsize s;
1596
if (!(GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS))
1597
&& !ioctl(0, TIOCGWINSZ, &s)) return s.ws_col;
1598
}
1599
#endif
1600
{
1601
char *str;
1602
if ((str = os_getenv("COLUMNS"))) return atoi(str);
1603
}
1604
#ifdef __EMX__
1605
{
1606
int scrsize[2];
1607
_scrsize(scrsize); return scrsize[0];
1608
}
1609
#endif
1610
return 0;
1611
}
1612
1613
static int
1614
term_height_intern(void)
1615
{
1616
#ifdef _WIN32
1617
return win32_terminal_height();
1618
#endif
1619
#ifdef HAS_TIOCGWINSZ
1620
{
1621
struct winsize s;
1622
if (!(GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS))
1623
&& !ioctl(0, TIOCGWINSZ, &s)) return s.ws_row;
1624
}
1625
#endif
1626
{
1627
char *str;
1628
if ((str = os_getenv("LINES"))) return atoi(str);
1629
}
1630
#ifdef __EMX__
1631
{
1632
int scrsize[2];
1633
_scrsize(scrsize); return scrsize[1];
1634
}
1635
#endif
1636
return 0;
1637
}
1638
1639
#define DFT_TERM_WIDTH 80
1640
#define DFT_TERM_HEIGHT 20
1641
1642
int
1643
term_width(void)
1644
{
1645
int n = term_width_intern();
1646
return (n>1)? n: DFT_TERM_WIDTH;
1647
}
1648
1649
int
1650
term_height(void)
1651
{
1652
int n = term_height_intern();
1653
return (n>1)? n: DFT_TERM_HEIGHT;
1654
}
1655
1656
static ulong col_index;
1657
1658
/* output string wrapped after MAX_WIDTH characters (for gp -test) */
1659
static void
1660
putc_lw(char c)
1661
{
1662
if (c == '\n') col_index = 0;
1663
else if (col_index >= GP_DATA->linewrap) { normalOutC('\n'); col_index = 1; }
1664
else col_index++;
1665
normalOutC(c);
1666
}
1667
static void
1668
puts_lw(const char *s) { while (*s) putc_lw(*s++); }
1669
1670
static PariOUT pariOut_lw= {putc_lw, puts_lw, normalOutF};
1671
1672
void
1673
init_linewrap(long w) { col_index=0; GP_DATA->linewrap=w; pariOut=&pariOut_lw; }
1674
1675
/* output stopped after max_line have been printed, for default(lines,).
1676
* n = length of prefix already printed (print up to max_lin lines) */
1677
void
1678
lim_lines_output(char *s, long n, long max_lin)
1679
{
1680
long lin, col, width;
1681
char c;
1682
if (!*s) return;
1683
width = term_width();
1684
lin = 1;
1685
col = n;
1686
1687
if (lin > max_lin) return;
1688
while ( (c = *s++) )
1689
{
1690
if (lin >= max_lin)
1691
if (c == '\n' || col >= width-5)
1692
{
1693
pari_sp av = avma;
1694
pari_puts(term_get_color(NULL, c_ERR)); set_avma(av);
1695
pari_puts("[+++]"); return;
1696
}
1697
if (c == '\n') { col = -1; lin++; }
1698
else if (col == width) { col = 0; lin++; }
1699
set_last_newline(c);
1700
col++; pari_putc(c);
1701
}
1702
}
1703
1704
static void
1705
new_line(PariOUT *out, const char *prefix)
1706
{
1707
out_putc(out, '\n'); if (prefix) out_puts(out, prefix);
1708
}
1709
1710
#define is_blank(c) ((c) == ' ' || (c) == '\n' || (c) == '\t')
1711
/* output: <prefix>< s wrapped at EOL >
1712
* <prefix>< ... > <str>
1713
* ^--- (no \n at the end)
1714
* If str is NULL, omit the arrow, end the text with '\n'.
1715
* If prefix is NULL, use "" */
1716
void
1717
print_prefixed_text(PariOUT *out, const char *s, const char *prefix,
1718
const char *str)
1719
{
1720
const long prelen = prefix? strlen_real(prefix): 0;
1721
const long W = term_width(), ls = strlen(s);
1722
long linelen = prelen;
1723
char *word = (char*)pari_malloc(ls + 3);
1724
1725
if (prefix) out_puts(out, prefix);
1726
for(;;)
1727
{
1728
long len;
1729
int blank = 0;
1730
char *u = word;
1731
while (*s && !is_blank(*s)) *u++ = *s++;
1732
*u = 0; /* finish "word" */
1733
len = strlen_real(word);
1734
linelen += len;
1735
if (linelen >= W) { new_line(out, prefix); linelen = prelen + len; }
1736
out_puts(out, word);
1737
while (is_blank(*s)) {
1738
switch (*s) {
1739
case ' ': break;
1740
case '\t':
1741
linelen = (linelen & ~7UL) + 8; out_putc(out, '\t');
1742
blank = 1; break;
1743
case '\n':
1744
linelen = W;
1745
blank = 1; break;
1746
}
1747
if (linelen >= W) { new_line(out, prefix); linelen = prelen; }
1748
s++;
1749
}
1750
if (!*s) break;
1751
if (!blank) { out_putc(out, ' '); linelen++; }
1752
}
1753
if (!str)
1754
out_putc(out, '\n');
1755
else
1756
{
1757
long i,len = strlen_real(str);
1758
int space = (*str == ' ' && str[1]);
1759
if (linelen + len >= W)
1760
{
1761
new_line(out, prefix); linelen = prelen;
1762
if (space) { str++; len--; space = 0; }
1763
}
1764
out_term_color(out, c_OUTPUT);
1765
out_puts(out, str);
1766
if (!len || str[len-1] != '\n') out_putc(out, '\n');
1767
if (space) { linelen++; len--; }
1768
out_term_color(out, c_ERR);
1769
if (prefix) { out_puts(out, prefix); linelen -= prelen; }
1770
for (i=0; i<linelen; i++) out_putc(out, ' ');
1771
out_putc(out, '^');
1772
for (i=0; i<len; i++) out_putc(out, '-');
1773
}
1774
pari_free(word);
1775
}
1776
1777
#define CONTEXT_LEN 46
1778
#define MAX_TERM_COLOR 16
1779
/* Outputs a beautiful error message (not \n terminated)
1780
* msg is errmessage to print.
1781
* s points to the offending chars.
1782
* entry tells how much we can go back from s[0] */
1783
void
1784
print_errcontext(PariOUT *out,
1785
const char *msg, const char *s, const char *entry)
1786
{
1787
const long MAX_PAST = 25;
1788
long past = s - entry, future, lmsg;
1789
char str[CONTEXT_LEN + 1 + 1], pre[MAX_TERM_COLOR + 8 + 1];
1790
char *buf, *t;
1791
1792
if (!s || !entry) { print_prefixed_text(out, msg," *** ",NULL); return; }
1793
1794
/* message + context */
1795
lmsg = strlen(msg);
1796
/* msg + past + ': ' + '...' + term_get_color + \0 */
1797
t = buf = (char*)pari_malloc(lmsg + MAX_PAST + 2 + 3 + MAX_TERM_COLOR + 1);
1798
memcpy(t, msg, lmsg); t += lmsg;
1799
strcpy(t, ": "); t += 2;
1800
if (past <= 0) past = 0;
1801
else
1802
{
1803
if (past > MAX_PAST) { past = MAX_PAST; strcpy(t, "..."); t += 3; }
1804
term_get_color(t, c_OUTPUT);
1805
t += strlen(t);
1806
memcpy(t, s - past, past); t[past] = 0;
1807
}
1808
1809
/* suffix (past arrow) */
1810
t = str; if (!past) *t++ = ' ';
1811
future = CONTEXT_LEN - past;
1812
strncpy(t, s, future); t[future] = 0;
1813
/* prefix '***' */
1814
term_get_color(pre, c_ERR);
1815
strcat(pre, " *** ");
1816
/* now print */
1817
print_prefixed_text(out, buf, pre, str);
1818
pari_free(buf);
1819
}
1820
1821
/********************************************************************/
1822
/** **/
1823
/** GEN <---> CHARACTER STRINGS **/
1824
/** **/
1825
/********************************************************************/
1826
static OUT_FUN
1827
get_fun(long flag)
1828
{
1829
switch(flag) {
1830
case f_RAW : return bruti;
1831
case f_TEX : return texi;
1832
default: return matbruti;
1833
}
1834
}
1835
1836
/* not stack clean */
1837
static char *
1838
stack_GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out)
1839
{
1840
pari_str S; str_init(&S, 1);
1841
out(x, T, &S); *S.cur = 0;
1842
return S.string;
1843
}
1844
/* same but remove quotes "" around t_STR */
1845
static char *
1846
stack_GENtostr_fun_unquoted(GEN x, pariout_t *T, OUT_FUN out)
1847
{ return (typ(x)==t_STR)? GSTR(x): stack_GENtostr_fun(x, T, out); }
1848
1849
/* stack-clean: pari-malloc'ed */
1850
static char *
1851
GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out)
1852
{
1853
pari_sp av = avma;
1854
pari_str S; str_init(&S, 0);
1855
out(x, T, &S); *S.cur = 0;
1856
set_avma(av); return S.string;
1857
}
1858
/* returns a malloc-ed string, which should be freed after usage */
1859
/* Returns pari_malloc()ed string */
1860
char *
1861
GENtostr(GEN x)
1862
{ return GENtostr_fun(x, GP_DATA->fmt, get_fun(GP_DATA->fmt->prettyp)); }
1863
char *
1864
GENtoTeXstr(GEN x) { return GENtostr_fun(x, GP_DATA->fmt, &texi); }
1865
char *
1866
GENtostr_unquoted(GEN x)
1867
{ return stack_GENtostr_fun_unquoted(x, GP_DATA->fmt, &bruti); }
1868
/* alloc-ed on PARI stack */
1869
char *
1870
GENtostr_raw(GEN x) { return stack_GENtostr_fun(x,GP_DATA->fmt,&bruti); }
1871
1872
GEN
1873
GENtoGENstr(GEN x)
1874
{
1875
char *s = GENtostr_fun(x, GP_DATA->fmt, &bruti);
1876
GEN z = strtoGENstr(s); pari_free(s); return z;
1877
}
1878
GEN
1879
GENtoGENstr_nospace(GEN x)
1880
{
1881
pariout_t T = *(GP_DATA->fmt);
1882
char *s;
1883
GEN z;
1884
T.sp = 0;
1885
s = GENtostr_fun(x, &T, &bruti);
1886
z = strtoGENstr(s); pari_free(s); return z;
1887
}
1888
1889
/********************************************************************/
1890
/** **/
1891
/** WRITE AN INTEGER **/
1892
/** **/
1893
/********************************************************************/
1894
char *
1895
itostr(GEN x) {
1896
long sx = signe(x), l;
1897
return sx? itostr_sign(x, sx, &l): zerotostr();
1898
}
1899
1900
/* x != 0 t_INT, write abs(x) to S */
1901
static void
1902
str_absint(pari_str *S, GEN x)
1903
{
1904
pari_sp av;
1905
long l;
1906
str_alloc(S, lgefint(x)); /* careful ! */
1907
av = avma;
1908
str_puts(S, itostr_sign(x, 1, &l)); set_avma(av);
1909
}
1910
1911
#define putsigne_nosp(S, x) str_putc(S, (x>0)? '+' : '-')
1912
#define putsigne(S, x) str_puts(S, (x>0)? " + " : " - ")
1913
#define sp_sign_sp(T,S, x) ((T)->sp? putsigne(S,x): putsigne_nosp(S,x))
1914
#define semicolon_sp(T,S) ((T)->sp? str_puts(S, "; "): str_putc(S, ';'))
1915
#define comma_sp(T,S) ((T)->sp? str_puts(S, ", "): str_putc(S, ','))
1916
1917
/* print e to S (more efficient than sprintf) */
1918
static void
1919
str_ulong(pari_str *S, ulong e)
1920
{
1921
if (e == 0) str_putc(S, '0');
1922
else
1923
{
1924
char buf[21], *p = buf + numberof(buf);
1925
*--p = 0;
1926
if (e > 9) {
1927
do
1928
*--p = "0123456789"[e % 10];
1929
while ((e /= 10) > 9);
1930
}
1931
*--p = "0123456789"[e];
1932
str_puts(S, p);
1933
}
1934
}
1935
static void
1936
str_long(pari_str *S, long e)
1937
{
1938
if (e >= 0) str_ulong(S, (ulong)e);
1939
else { str_putc(S, '-'); str_ulong(S, -(ulong)e); }
1940
}
1941
1942
static void
1943
wr_vecsmall(pariout_t *T, pari_str *S, GEN g)
1944
{
1945
long i, l;
1946
str_puts(S, "Vecsmall(["); l = lg(g);
1947
for (i=1; i<l; i++)
1948
{
1949
str_long(S, g[i]);
1950
if (i<l-1) comma_sp(T,S);
1951
}
1952
str_puts(S, "])");
1953
}
1954
1955
/********************************************************************/
1956
/** **/
1957
/** HEXADECIMAL OUTPUT **/
1958
/** **/
1959
/********************************************************************/
1960
/* English ordinal numbers */
1961
char *
1962
uordinal(ulong i)
1963
{
1964
const char *suff[] = {"st","nd","rd","th"};
1965
char *s = stack_malloc(23);
1966
long k = 3;
1967
switch (i%10)
1968
{
1969
case 1: if (i%100!=11) k = 0;
1970
break;
1971
case 2: if (i%100!=12) k = 1;
1972
break;
1973
case 3: if (i%100!=13) k = 2;
1974
break;
1975
}
1976
sprintf(s, "%lu%s", i, suff[k]); return s;
1977
}
1978
1979
static char
1980
vsigne(GEN x)
1981
{
1982
long s = signe(x);
1983
if (!s) return '0';
1984
return (s > 0) ? '+' : '-';
1985
}
1986
1987
static void
1988
blancs(long nb) { while (nb-- > 0) pari_putc(' '); }
1989
1990
/* write an "address" */
1991
static void
1992
str_addr(pari_str *S, ulong x)
1993
{ char s[128]; sprintf(s,"%0*lx", BITS_IN_LONG/4, x); str_puts(S, s); }
1994
static void
1995
dbg_addr(ulong x) { pari_printf("[&=%0*lx] ", BITS_IN_LONG/4, x); }
1996
/* write a "word" */
1997
static void
1998
dbg_word(ulong x) { pari_printf("%0*lx ", BITS_IN_LONG/4, x); }
1999
2000
/* bl: indent level */
2001
static void
2002
dbg(GEN x, long nb, long bl)
2003
{
2004
long tx,i,j,e,dx,lx;
2005
2006
if (!x) { pari_puts("NULL\n"); return; }
2007
tx = typ(x);
2008
if (tx == t_INT && x == gen_0) { pari_puts("gen_0\n"); return; }
2009
dbg_addr((ulong)x);
2010
2011
lx = lg(x);
2012
pari_printf("%s(lg=%ld%s):",type_name(tx)+2,lx,isclone(x)? ",CLONE" : "");
2013
dbg_word(x[0]);
2014
if (! is_recursive_t(tx)) /* t_INT, t_REAL, t_STR, t_VECSMALL */
2015
{
2016
if (tx == t_STR)
2017
pari_puts("chars:");
2018
else if (tx == t_INT)
2019
{
2020
lx = lgefint(x);
2021
pari_printf("(%c,lgefint=%ld):", vsigne(x), lx);
2022
}
2023
else if (tx == t_REAL)
2024
pari_printf("(%c,expo=%ld):", vsigne(x), expo(x));
2025
if (nb < 0) nb = lx;
2026
for (i=1; i < nb; i++) dbg_word(x[i]);
2027
pari_putc('\n'); return;
2028
}
2029
2030
if (tx == t_PADIC)
2031
pari_printf("(precp=%ld,valp=%ld):", precp(x), valp(x));
2032
else if (tx == t_POL)
2033
pari_printf("(%c,varn=%ld):", vsigne(x), varn(x));
2034
else if (tx == t_SER)
2035
pari_printf("(%c,varn=%ld,prec=%ld,valp=%ld):",
2036
vsigne(x), varn(x), lg(x)-2, valp(x));
2037
else if (tx == t_LIST)
2038
{
2039
pari_printf("(subtyp=%ld,lmax=%ld):", list_typ(x), list_nmax(x));
2040
x = list_data(x); lx = x? lg(x): 1;
2041
tx = t_VEC; /* print list_data as vec */
2042
} else if (tx == t_CLOSURE)
2043
pari_printf("(arity=%ld%s):", closure_arity(x),
2044
closure_is_variadic(x)?"+":"");
2045
for (i=1; i<lx; i++) dbg_word(x[i]);
2046
bl+=2; pari_putc('\n');
2047
switch(tx)
2048
{
2049
case t_INTMOD: case t_POLMOD:
2050
{
2051
const char *s = (tx==t_INTMOD)? "int = ": "pol = ";
2052
blancs(bl); pari_puts("mod = "); dbg(gel(x,1),nb,bl);
2053
blancs(bl); pari_puts(s); dbg(gel(x,2),nb,bl);
2054
break;
2055
}
2056
case t_FRAC: case t_RFRAC:
2057
blancs(bl); pari_puts("num = "); dbg(gel(x,1),nb,bl);
2058
blancs(bl); pari_puts("den = "); dbg(gel(x,2),nb,bl);
2059
break;
2060
2061
case t_FFELT:
2062
blancs(bl); pari_puts("pol = "); dbg(gel(x,2),nb,bl);
2063
blancs(bl); pari_puts("mod = "); dbg(gel(x,3),nb,bl);
2064
blancs(bl); pari_puts("p = "); dbg(gel(x,4),nb,bl);
2065
break;
2066
2067
case t_COMPLEX:
2068
blancs(bl); pari_puts("real = "); dbg(gel(x,1),nb,bl);
2069
blancs(bl); pari_puts("imag = "); dbg(gel(x,2),nb,bl);
2070
break;
2071
2072
case t_PADIC:
2073
blancs(bl); pari_puts(" p : "); dbg(gel(x,2),nb,bl);
2074
blancs(bl); pari_puts("p^l : "); dbg(gel(x,3),nb,bl);
2075
blancs(bl); pari_puts(" I : "); dbg(gel(x,4),nb,bl);
2076
break;
2077
2078
case t_QUAD:
2079
blancs(bl); pari_puts("pol = "); dbg(gel(x,1),nb,bl);
2080
blancs(bl); pari_puts("real = "); dbg(gel(x,2),nb,bl);
2081
blancs(bl); pari_puts("imag = "); dbg(gel(x,3),nb,bl);
2082
break;
2083
2084
case t_POL: case t_SER:
2085
e = (tx==t_SER)? valp(x): 0;
2086
for (i=2; i<lx; i++)
2087
{
2088
blancs(bl); pari_printf("coef of degree %ld = ",e);
2089
e++; dbg(gel(x,i),nb,bl);
2090
}
2091
break;
2092
2093
case t_QFB: case t_VEC: case t_COL:
2094
for (i=1; i<lx; i++)
2095
{
2096
blancs(bl); pari_printf("%s component = ",uordinal(i));
2097
dbg(gel(x,i),nb,bl);
2098
}
2099
break;
2100
2101
case t_CLOSURE:
2102
blancs(bl); pari_puts("code = "); dbg(closure_get_code(x),nb,bl);
2103
blancs(bl); pari_puts("operand = "); dbg(closure_get_oper(x),nb,bl);
2104
blancs(bl); pari_puts("data = "); dbg(closure_get_data(x),nb,bl);
2105
blancs(bl); pari_puts("dbg/frpc/fram = "); dbg(closure_get_dbg(x),nb,bl);
2106
if (lg(x)>=7)
2107
{
2108
blancs(bl); pari_puts("text = "); dbg(closure_get_text(x),nb,bl);
2109
if (lg(x)>=8)
2110
{
2111
blancs(bl); pari_puts("frame = "); dbg(closure_get_frame(x),nb,bl);
2112
}
2113
}
2114
break;
2115
2116
case t_ERROR:
2117
blancs(bl);
2118
pari_printf("error type = %s\n", numerr_name(err_get_num(x)));
2119
for (i=2; i<lx; i++)
2120
{
2121
blancs(bl); pari_printf("%s component = ",uordinal(i-1));
2122
dbg(gel(x,i),nb,bl);
2123
}
2124
break;
2125
2126
case t_INFINITY:
2127
blancs(bl); pari_printf("1st component = ");
2128
dbg(gel(x,1),nb,bl);
2129
break;
2130
2131
case t_MAT:
2132
{
2133
GEN c = gel(x,1);
2134
if (lx == 1) return;
2135
if (typ(c) == t_VECSMALL)
2136
{
2137
for (i = 1; i < lx; i++)
2138
{
2139
blancs(bl); pari_printf("%s column = ",uordinal(i));
2140
dbg(gel(x,i),nb,bl);
2141
}
2142
}
2143
else
2144
{
2145
dx = lg(c);
2146
for (i=1; i<dx; i++)
2147
for (j=1; j<lx; j++)
2148
{
2149
blancs(bl); pari_printf("mat(%ld,%ld) = ",i,j);
2150
dbg(gcoeff(x,i,j),nb,bl);
2151
}
2152
}
2153
}
2154
}
2155
}
2156
2157
void
2158
dbgGEN(GEN x, long nb) { dbg(x,nb,0); }
2159
2160
static void
2161
print_entree(entree *ep)
2162
{
2163
pari_printf(" %s ",ep->name); dbg_addr((ulong)ep);
2164
pari_printf(": hash = %ld [%ld]\n", ep->hash % functions_tblsz, ep->hash);
2165
pari_printf(" menu = %2ld, code = %-10s",
2166
ep->menu, ep->code? ep->code: "NULL");
2167
if (ep->next)
2168
{
2169
pari_printf("next = %s ",(ep->next)->name);
2170
dbg_addr((ulong)ep->next);
2171
}
2172
pari_puts("\n");
2173
}
2174
2175
/* s = digit n : list of entrees in functions_hash[n] (s = $: last entry)
2176
* = range m-n: functions_hash[m..n]
2177
* = identifier: entree for that identifier */
2178
void
2179
print_functions_hash(const char *s)
2180
{
2181
long m, n, Max, Total;
2182
entree *ep;
2183
2184
if (isdigit((int)*s) || *s == '$')
2185
{
2186
m = functions_tblsz-1; n = atol(s);
2187
if (*s=='$') n = m;
2188
if (m<n) pari_err(e_MISC,"invalid range in print_functions_hash");
2189
while (isdigit((int)*s)) s++;
2190
2191
if (*s++ != '-') m = n;
2192
else
2193
{
2194
if (*s !='$') m = minss(atol(s),m);
2195
if (m<n) pari_err(e_MISC,"invalid range in print_functions_hash");
2196
}
2197
2198
for(; n<=m; n++)
2199
{
2200
pari_printf("*** hashcode = %lu\n",n);
2201
for (ep=functions_hash[n]; ep; ep=ep->next) print_entree(ep);
2202
}
2203
return;
2204
}
2205
if (is_keyword_char((int)*s))
2206
{
2207
ep = is_entry(s);
2208
if (!ep) pari_err(e_MISC,"no such function");
2209
print_entree(ep); return;
2210
}
2211
if (*s=='-')
2212
{
2213
for (n=0; n<functions_tblsz; n++)
2214
{
2215
m=0;
2216
for (ep=functions_hash[n]; ep; ep=ep->next) m++;
2217
pari_printf("%3ld:%3ld ",n,m);
2218
if (n%9 == 8) pari_putc('\n');
2219
}
2220
pari_putc('\n'); return;
2221
}
2222
Max = Total = 0;
2223
for (n=0; n<functions_tblsz; n++)
2224
{
2225
long cnt = 0;
2226
for (ep=functions_hash[n]; ep; ep=ep->next) { print_entree(ep); cnt++; }
2227
Total += cnt;
2228
if (cnt > Max) Max = cnt;
2229
}
2230
pari_printf("Total: %ld, Max: %ld\n", Total, Max);
2231
}
2232
2233
/********************************************************************/
2234
/** **/
2235
/** FORMATTED OUTPUT **/
2236
/** **/
2237
/********************************************************************/
2238
static const char *
2239
get_var(long v, char *buf)
2240
{
2241
entree *ep = varentries[v];
2242
if (ep) return (char*)ep->name;
2243
sprintf(buf,"t%d",(int)v); return buf;
2244
}
2245
2246
static void
2247
do_append(char **sp, char c, char *last, int count)
2248
{
2249
if (*sp + count > last)
2250
pari_err(e_MISC, "TeX variable name too long");
2251
while (count--)
2252
*(*sp)++ = c;
2253
}
2254
2255
static char *
2256
get_texvar(long v, char *buf, unsigned int len)
2257
{
2258
entree *ep = varentries[v];
2259
char *t = buf, *e = buf + len - 1;
2260
const char *s;
2261
2262
if (!ep) pari_err(e_MISC, "this object uses debugging variables");
2263
s = ep->name;
2264
if (strlen(s) >= len) pari_err(e_MISC, "TeX variable name too long");
2265
while (isalpha((int)*s)) *t++ = *s++;
2266
*t = 0;
2267
if (isdigit((int)*s) || *s == '_') {
2268
int seen1 = 0, seen = 0;
2269
2270
/* Skip until the first non-underscore */
2271
while (*s == '_') s++, seen++;
2272
2273
/* Special-case integers and empty subscript */
2274
if (*s == 0 || isdigit((unsigned char)*s))
2275
seen++;
2276
2277
do_append(&t, '_', e, 1);
2278
do_append(&t, '{', e, 1);
2279
do_append(&t, '[', e, seen - 1);
2280
while (1) {
2281
if (*s == '_')
2282
seen1++, s++;
2283
else {
2284
if (seen1) {
2285
do_append(&t, ']', e, (seen >= seen1 ? seen1 : seen) - 1);
2286
do_append(&t, ',', e, 1);
2287
do_append(&t, '[', e, seen1 - 1);
2288
if (seen1 > seen)
2289
seen = seen1;
2290
seen1 = 0;
2291
}
2292
if (*s == 0)
2293
break;
2294
do_append(&t, *s++, e, 1);
2295
}
2296
}
2297
do_append(&t, ']', e, seen - 1);
2298
do_append(&t, '}', e, 1);
2299
*t = 0;
2300
}
2301
return buf;
2302
}
2303
2304
void
2305
dbg_pari_heap(void)
2306
{
2307
long nu, l, u, s;
2308
pari_sp av = avma;
2309
GEN adr = getheap();
2310
pari_sp top = pari_mainstack->top, bot = pari_mainstack->bot;
2311
2312
nu = (top-avma)/sizeof(long);
2313
l = pari_mainstack->size/sizeof(long);
2314
pari_printf("\n Top : %lx Bottom : %lx Current stack : %lx\n",
2315
top, bot, avma);
2316
pari_printf(" Used : %ld long words (%ld K)\n",
2317
nu, nu/1024*sizeof(long));
2318
pari_printf(" Available : %ld long words (%ld K)\n",
2319
(l-nu), (l-nu)/1024*sizeof(long));
2320
pari_printf(" Occupation of the PARI stack : %6.2f percent\n", 100.0*nu/l);
2321
pari_printf(" %ld objects on heap occupy %ld long words\n\n",
2322
itos(gel(adr,1)), itos(gel(adr,2)));
2323
u = pari_var_next();
2324
s = MAXVARN - pari_var_next_temp();
2325
pari_printf(" %ld variable names used (%ld user + %ld private) out of %d\n\n",
2326
u+s, u, s, MAXVARN);
2327
set_avma(av);
2328
}
2329
2330
/* is to be printed as '0' */
2331
static long
2332
isnull(GEN g)
2333
{
2334
long i;
2335
switch (typ(g))
2336
{
2337
case t_INT:
2338
return !signe(g);
2339
case t_COMPLEX:
2340
return isnull(gel(g,1)) && isnull(gel(g,2));
2341
case t_FFELT:
2342
return FF_equal0(g);
2343
case t_QUAD:
2344
return isnull(gel(g,2)) && isnull(gel(g,3));
2345
case t_FRAC: case t_RFRAC:
2346
return isnull(gel(g,1));
2347
case t_POL:
2348
for (i=lg(g)-1; i>1; i--)
2349
if (!isnull(gel(g,i))) return 0;
2350
return 1;
2351
}
2352
return 0;
2353
}
2354
/* 0 coeff to be omitted in t_POL ? */
2355
static int
2356
isnull_for_pol(GEN g)
2357
{
2358
switch(typ(g))
2359
{
2360
case t_INTMOD: return !signe(gel(g,2));
2361
case t_POLMOD: return isnull(gel(g,2));
2362
default: return isnull(g);
2363
}
2364
}
2365
2366
/* return 1 or -1 if g is 1 or -1, 0 otherwise*/
2367
static long
2368
isone(GEN g)
2369
{
2370
long i;
2371
switch (typ(g))
2372
{
2373
case t_INT:
2374
return (signe(g) && is_pm1(g))? signe(g): 0;
2375
case t_FFELT:
2376
return FF_equal1(g);
2377
case t_COMPLEX:
2378
return isnull(gel(g,2))? isone(gel(g,1)): 0;
2379
case t_QUAD:
2380
return isnull(gel(g,3))? isone(gel(g,2)): 0;
2381
case t_FRAC: case t_RFRAC:
2382
return isone(gel(g,1)) * isone(gel(g,2));
2383
case t_POL:
2384
if (!signe(g)) return 0;
2385
for (i=lg(g)-1; i>2; i--)
2386
if (!isnull(gel(g,i))) return 0;
2387
return isone(gel(g,2));
2388
}
2389
return 0;
2390
}
2391
2392
/* if g is a "monomial", return its sign, 0 otherwise */
2393
static long
2394
isfactor(GEN g)
2395
{
2396
long i,deja,sig;
2397
switch(typ(g))
2398
{
2399
case t_INT: case t_REAL:
2400
return (signe(g)<0)? -1: 1;
2401
case t_FRAC: case t_RFRAC:
2402
return isfactor(gel(g,1));
2403
case t_FFELT:
2404
return isfactor(FF_to_FpXQ_i(g));
2405
case t_COMPLEX:
2406
if (isnull(gel(g,1))) return isfactor(gel(g,2));
2407
if (isnull(gel(g,2))) return isfactor(gel(g,1));
2408
return 0;
2409
case t_PADIC:
2410
return !signe(gel(g,4));
2411
case t_QUAD:
2412
if (isnull(gel(g,2))) return isfactor(gel(g,3));
2413
if (isnull(gel(g,3))) return isfactor(gel(g,2));
2414
return 0;
2415
case t_POL: deja = 0; sig = 1;
2416
for (i=lg(g)-1; i>1; i--)
2417
if (!isnull_for_pol(gel(g,i)))
2418
{
2419
if (deja) return 0;
2420
sig=isfactor(gel(g,i)); deja=1;
2421
}
2422
return sig? sig: 1;
2423
case t_SER:
2424
for (i=lg(g)-1; i>1; i--)
2425
if (!isnull(gel(g,i))) return 0;
2426
return 1;
2427
case t_CLOSURE:
2428
return 0;
2429
}
2430
return 1;
2431
}
2432
2433
/* return 1 if g is a "truc" (see anal.c) */
2434
static long
2435
isdenom(GEN g)
2436
{
2437
long i,deja;
2438
switch(typ(g))
2439
{
2440
case t_FRAC: case t_RFRAC:
2441
return 0;
2442
case t_COMPLEX: return isnull(gel(g,2));
2443
case t_PADIC: return !signe(gel(g,4));
2444
case t_QUAD: return isnull(gel(g,3));
2445
2446
case t_POL: deja = 0;
2447
for (i=lg(g)-1; i>1; i--)
2448
if (!isnull(gel(g,i)))
2449
{
2450
if (deja) return 0;
2451
if (i==2) return isdenom(gel(g,2));
2452
if (!isone(gel(g,i))) return 0;
2453
deja=1;
2454
}
2455
return 1;
2456
case t_SER:
2457
for (i=lg(g)-1; i>1; i--)
2458
if (!isnull(gel(g,i))) return 0;
2459
}
2460
return 1;
2461
}
2462
2463
/********************************************************************/
2464
/** **/
2465
/** RAW OUTPUT **/
2466
/** **/
2467
/********************************************************************/
2468
/* ^e */
2469
static void
2470
texexpo(pari_str *S, long e)
2471
{
2472
if (e != 1) {
2473
str_putc(S, '^');
2474
if (e >= 0 && e < 10)
2475
{ str_putc(S, '0' + e); }
2476
else
2477
{
2478
str_putc(S, '{'); str_long(S, e); str_putc(S, '}');
2479
}
2480
}
2481
}
2482
static void
2483
wrexpo(pari_str *S, long e)
2484
{ if (e != 1) { str_putc(S, '^'); str_long(S, e); } }
2485
2486
/* v^e */
2487
static void
2488
VpowE(pari_str *S, const char *v, long e) { str_puts(S, v); wrexpo(S,e); }
2489
static void
2490
texVpowE(pari_str *S, const char *v, long e) { str_puts(S, v); texexpo(S,e); }
2491
static void
2492
monome(pari_str *S, const char *v, long e)
2493
{ if (e) VpowE(S, v, e); else str_putc(S, '1'); }
2494
static void
2495
texnome(pari_str *S, const char *v, long e)
2496
{ if (e) texVpowE(S, v, e); else str_putc(S, '1'); }
2497
2498
/* ( a ) */
2499
static void
2500
paren(pariout_t *T, pari_str *S, GEN a)
2501
{ str_putc(S, '('); bruti(a,T,S); str_putc(S, ')'); }
2502
static void
2503
texparen(pariout_t *T, pari_str *S, GEN a)
2504
{
2505
if (T->TeXstyle & TEXSTYLE_PAREN)
2506
str_puts(S, " (");
2507
else
2508
str_puts(S, " \\left(");
2509
texi(a,T,S);
2510
if (T->TeXstyle & TEXSTYLE_PAREN)
2511
str_puts(S, ") ");
2512
else
2513
str_puts(S, "\\right) ");
2514
}
2515
2516
/* * v^d */
2517
static void
2518
times_texnome(pari_str *S, const char *v, long d)
2519
{ if (d) { str_puts(S, "\\*"); texnome(S,v,d); } }
2520
static void
2521
times_monome(pari_str *S, const char *v, long d)
2522
{ if (d) { str_putc(S, '*'); monome(S,v,d); } }
2523
2524
/* write a * v^d */
2525
static void
2526
wr_monome(pariout_t *T, pari_str *S, GEN a, const char *v, long d)
2527
{
2528
long sig = isone(a);
2529
2530
if (sig) {
2531
sp_sign_sp(T,S,sig); monome(S,v,d);
2532
} else {
2533
sig = isfactor(a);
2534
if (sig) { sp_sign_sp(T,S,sig); bruti_sign(a,T,S,0); }
2535
else { sp_sign_sp(T,S,1); paren(T,S, a); }
2536
times_monome(S, v, d);
2537
}
2538
}
2539
static void
2540
wr_texnome(pariout_t *T, pari_str *S, GEN a, const char *v, long d)
2541
{
2542
long sig = isone(a);
2543
2544
str_putc(S, '\n'); /* Avoid TeX buffer overflow */
2545
if (T->TeXstyle & TEXSTYLE_BREAK) str_puts(S, "\\PARIbreak ");
2546
2547
if (sig) {
2548
putsigne(S,sig); texnome(S,v,d);
2549
} else {
2550
sig = isfactor(a);
2551
if (sig) { putsigne(S,sig); texi_sign(a,T,S,0); }
2552
else { str_puts(S, " +"); texparen(T,S, a); }
2553
times_texnome(S, v, d);
2554
}
2555
}
2556
2557
static void
2558
wr_lead_monome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign)
2559
{
2560
long sig = isone(a);
2561
if (sig) {
2562
if (addsign && sig<0) str_putc(S, '-');
2563
monome(S,v,d);
2564
} else {
2565
if (isfactor(a)) bruti_sign(a,T,S,addsign);
2566
else paren(T,S, a);
2567
times_monome(S, v, d);
2568
}
2569
}
2570
static void
2571
wr_lead_texnome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign)
2572
{
2573
long sig = isone(a);
2574
if (sig) {
2575
if (addsign && sig<0) str_putc(S, '-');
2576
texnome(S,v,d);
2577
} else {
2578
if (isfactor(a)) texi_sign(a,T,S,addsign);
2579
else texparen(T,S, a);
2580
times_texnome(S, v, d);
2581
}
2582
}
2583
2584
static void
2585
prints(GEN g, pariout_t *T, pari_str *S)
2586
{ (void)T; str_long(S, (long)g); }
2587
2588
static void
2589
quote_string(pari_str *S, char *s)
2590
{
2591
str_putc(S, '"');
2592
while (*s)
2593
{
2594
char c=*s++;
2595
if (c=='\\' || c=='"' || c=='\033' || c=='\n' || c=='\t')
2596
{
2597
str_putc(S, '\\');
2598
switch(c)
2599
{
2600
case '\\': case '"': break;
2601
case '\n': c='n'; break;
2602
case '\033': c='e'; break;
2603
case '\t': c='t'; break;
2604
}
2605
}
2606
str_putc(S, c);
2607
}
2608
str_putc(S, '"');
2609
}
2610
2611
static int
2612
print_0_or_pm1(GEN g, pari_str *S, int addsign)
2613
{
2614
long r;
2615
if (!g) { str_puts(S, "NULL"); return 1; }
2616
if (isnull(g)) { str_putc(S, '0'); return 1; }
2617
r = isone(g);
2618
if (r)
2619
{
2620
if (addsign && r<0) str_putc(S, '-');
2621
str_putc(S, '1'); return 1;
2622
}
2623
return 0;
2624
}
2625
2626
static void
2627
print_precontext(GEN g, pari_str *S, long tex)
2628
{
2629
if (lg(g)<8 || lg(gel(g,7))==1) return;
2630
else
2631
{
2632
long i, n = closure_arity(g);
2633
str_puts(S,"(");
2634
for(i=1; i<=n; i++)
2635
{
2636
str_puts(S,"v");
2637
if (tex) str_puts(S,"_{");
2638
str_ulong(S,i);
2639
if (tex) str_puts(S,"}");
2640
if (i < n) str_puts(S,",");
2641
}
2642
str_puts(S,")->");
2643
}
2644
}
2645
2646
static void
2647
print_context(GEN g, pariout_t *T, pari_str *S, long tex)
2648
{
2649
GEN str = closure_get_text(g);
2650
if (lg(g)<8 || lg(gel(g,7))==1) return;
2651
if (typ(str)==t_VEC && lg(gel(closure_get_dbg(g),3)) >= 2)
2652
{
2653
GEN v = closure_get_frame(g), d = gmael(closure_get_dbg(g),3,1);
2654
long i, l = lg(v), n=0;
2655
for(i=1; i<l; i++)
2656
if (gel(d,i))
2657
n++;
2658
if (n==0) return;
2659
str_puts(S,"my(");
2660
for(i=1; i<l; i++)
2661
if (gel(d,i))
2662
{
2663
entree *ep = (entree*) gel(d,i);
2664
GEN vi = gel(v,l-i);
2665
str_puts(S,ep->name);
2666
if (!isintzero(vi))
2667
{
2668
str_putc(S,'=');
2669
if (tex) texi(gel(v,l-i),T,S); else bruti(gel(v,l-i),T,S);
2670
}
2671
if (--n)
2672
str_putc(S,',');
2673
}
2674
str_puts(S,");");
2675
}
2676
else
2677
{
2678
GEN v = closure_get_frame(g);
2679
long i, l = lg(v), n = closure_arity(g);
2680
str_puts(S,"(");
2681
for(i=1; i<=n; i++)
2682
{
2683
str_puts(S,"v");
2684
if (tex) str_puts(S,"_{");
2685
str_ulong(S,i);
2686
if (tex) str_puts(S,"}");
2687
str_puts(S,",");
2688
}
2689
for(i=1; i<l; i++)
2690
{
2691
if (tex) texi(gel(v,i),T,S); else bruti(gel(v,i),T,S);
2692
if (i<l-1)
2693
str_putc(S,',');
2694
}
2695
str_puts(S,")");
2696
}
2697
}
2698
static void
2699
mat0n(pari_str *S, long n)
2700
{ str_puts(S, "matrix(0,"); str_long(S, n); str_putc(S, ')'); }
2701
2702
static const char *
2703
cxq_init(GEN g, long tg, GEN *a, GEN *b, char *buf)
2704
{
2705
int r = (tg==t_QUAD);
2706
*a = gel(g,r+1);
2707
*b = gel(g,r+2); return r? get_var(varn(gel(g,1)), buf): "I";
2708
}
2709
2710
static void
2711
print_coef(GEN g, long i, long j, pariout_t *T, pari_str *S)
2712
{ (void)T; str_long(S, coeff(g,i,j)); }
2713
static void
2714
print_gcoef(GEN g, long i, long j, pariout_t *T, pari_str *S)
2715
{
2716
GEN gij = gcoeff(g, i, j);
2717
if (typ(gij)==t_CLOSURE)
2718
{ str_putc(S, '('); bruti(gij, T, S); str_putc(S, ')'); }
2719
else
2720
bruti(gij, T, S);
2721
}
2722
2723
static void
2724
bruti_intern(GEN g, pariout_t *T, pari_str *S, int addsign)
2725
{
2726
long l,i,j,r, tg = typ(g);
2727
GEN a,b;
2728
const char *v;
2729
char buf[32];
2730
2731
switch(tg)
2732
{
2733
case t_INT:
2734
if (addsign && signe(g) < 0) str_putc(S, '-');
2735
str_absint(S, g); break;
2736
case t_REAL:
2737
{
2738
pari_sp av;
2739
str_alloc(S, lg(g)); /* careful! */
2740
av = avma;
2741
if (addsign && signe(g) < 0) str_putc(S, '-');
2742
str_puts(S, absrtostr(g, T->sp, (char)toupper((int)T->format), T->sigd) );
2743
set_avma(av); break;
2744
}
2745
2746
case t_INTMOD: case t_POLMOD:
2747
str_puts(S, "Mod(");
2748
bruti(gel(g,2),T,S); comma_sp(T,S);
2749
bruti(gel(g,1),T,S); str_putc(S, ')'); break;
2750
2751
case t_FFELT:
2752
bruti_sign(FF_to_FpXQ_i(g),T,S,addsign);
2753
break;
2754
2755
case t_FRAC: case t_RFRAC:
2756
r = isfactor(gel(g,1)); if (!r) str_putc(S, '(');
2757
bruti_sign(gel(g,1),T,S,addsign);
2758
if (!r) str_putc(S, ')');
2759
str_putc(S, '/');
2760
r = isdenom(gel(g,2)); if (!r) str_putc(S, '(');
2761
bruti(gel(g,2),T,S);
2762
if (!r) str_putc(S, ')');
2763
break;
2764
2765
case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
2766
v = cxq_init(g, tg, &a, &b, buf);
2767
if (isnull(a))
2768
{
2769
wr_lead_monome(T,S,b,v,1,addsign);
2770
return;
2771
}
2772
bruti_sign(a,T,S,addsign);
2773
if (!isnull(b)) wr_monome(T,S,b,v,1);
2774
break;
2775
2776
case t_POL: v = get_var(varn(g), buf);
2777
/* hack: we want g[i] = coeff of degree i. */
2778
i = degpol(g); g += 2; while (isnull(gel(g,i))) i--;
2779
wr_lead_monome(T,S,gel(g,i),v,i,addsign);
2780
while (i--)
2781
{
2782
a = gel(g,i);
2783
if (!isnull_for_pol(a)) wr_monome(T,S,a,v,i);
2784
}
2785
break;
2786
2787
case t_SER: v = get_var(varn(g), buf);
2788
i = valp(g);
2789
l = lg(g)-2;
2790
if (l)
2791
{
2792
/* See normalize(): Mod(0,2)*x^i*(1+O(x)), has valp = i+1 */
2793
if (l == 1 && !signe(g) && isexactzero(gel(g,2))) i--;
2794
/* hack: we want g[i] = coeff of degree i */
2795
l += i; g -= i-2;
2796
wr_lead_monome(T,S,gel(g,i),v,i,addsign);
2797
while (++i < l)
2798
{
2799
a = gel(g,i);
2800
if (!isnull_for_pol(a)) wr_monome(T,S,a,v,i);
2801
}
2802
sp_sign_sp(T,S,1);
2803
}
2804
str_puts(S, "O("); VpowE(S, v, i); str_putc(S, ')'); break;
2805
2806
case t_PADIC:
2807
{
2808
GEN p = gel(g,2);
2809
pari_sp av, av0;
2810
char *ev;
2811
str_alloc(S, (precp(g)+1) * lgefint(p)); /* careful! */
2812
av0 = avma;
2813
ev = itostr(p);
2814
av = avma;
2815
i = valp(g); l = precp(g)+i;
2816
g = gel(g,4);
2817
for (; i<l; i++)
2818
{
2819
g = dvmdii(g,p,&a);
2820
if (signe(a))
2821
{
2822
if (!i || !is_pm1(a))
2823
{
2824
str_absint(S, a); if (i) str_putc(S, '*');
2825
}
2826
if (i) VpowE(S, ev,i);
2827
sp_sign_sp(T,S,1);
2828
}
2829
if ((i & 0xff) == 0) g = gerepileuptoint(av,g);
2830
}
2831
str_puts(S, "O("); VpowE(S, ev,i); str_putc(S, ')');
2832
set_avma(av0); break;
2833
}
2834
2835
case t_QFB:
2836
str_puts(S, "Qfb(");
2837
bruti(gel(g,1),T,S); comma_sp(T,S);
2838
bruti(gel(g,2),T,S); comma_sp(T,S);
2839
bruti(gel(g,3),T,S);
2840
str_putc(S, ')'); break;
2841
2842
case t_VEC: case t_COL:
2843
str_putc(S, '['); l = lg(g);
2844
for (i=1; i<l; i++)
2845
{
2846
bruti(gel(g,i),T,S);
2847
if (i<l-1) comma_sp(T,S);
2848
}
2849
str_putc(S, ']'); if (tg==t_COL) str_putc(S, '~');
2850
break;
2851
case t_VECSMALL: wr_vecsmall(T,S,g); break;
2852
2853
case t_LIST:
2854
switch (list_typ(g))
2855
{
2856
case t_LIST_RAW:
2857
str_puts(S, "List([");
2858
g = list_data(g);
2859
l = g? lg(g): 1;
2860
for (i=1; i<l; i++)
2861
{
2862
bruti(gel(g,i),T,S);
2863
if (i<l-1) comma_sp(T,S);
2864
}
2865
str_puts(S, "])"); break;
2866
case t_LIST_MAP:
2867
str_puts(S, "Map(");
2868
bruti(maptomat_shallow(g),T,S);
2869
str_puts(S, ")"); break;
2870
}
2871
break;
2872
case t_STR:
2873
quote_string(S, GSTR(g)); break;
2874
case t_ERROR:
2875
{
2876
char *s = pari_err2str(g);
2877
str_puts(S, "error(");
2878
quote_string(S, s); pari_free(s);
2879
str_puts(S, ")"); break;
2880
}
2881
case t_CLOSURE:
2882
if (lg(g)>=7)
2883
{
2884
GEN str = closure_get_text(g);
2885
if (typ(str)==t_STR)
2886
{
2887
print_precontext(g, S, 0);
2888
str_puts(S, GSTR(str));
2889
print_context(g, T, S, 0);
2890
}
2891
else
2892
{
2893
str_putc(S,'('); str_puts(S,GSTR(gel(str,1)));
2894
str_puts(S,")->");
2895
print_context(g, T, S, 0);
2896
str_puts(S,GSTR(gel(str,2)));
2897
}
2898
}
2899
else
2900
{
2901
str_puts(S,"{\""); str_puts(S,GSTR(closure_get_code(g)));
2902
str_puts(S,"\","); wr_vecsmall(T,S,closure_get_oper(g));
2903
str_putc(S,','); bruti(gel(g,4),T,S);
2904
str_putc(S,','); bruti(gel(g,5),T,S);
2905
str_putc(S,'}');
2906
}
2907
break;
2908
case t_INFINITY: str_puts(S, inf_get_sign(g) == 1? "+oo": "-oo");
2909
break;
2910
2911
case t_MAT:
2912
{
2913
void (*print)(GEN,long,long,pariout_t *,pari_str *);
2914
2915
r = lg(g); if (r==1) { str_puts(S, "[;]"); return; }
2916
l = lgcols(g); if (l==1) { mat0n(S, r-1); return; }
2917
print = (typ(gel(g,1)) == t_VECSMALL)? print_coef: print_gcoef;
2918
if (l==2)
2919
{
2920
str_puts(S, "Mat(");
2921
if (r == 2) { print(g, 1, 1,T, S); str_putc(S, ')'); return; }
2922
}
2923
str_putc(S, '[');
2924
for (i=1; i<l; i++)
2925
{
2926
for (j=1; j<r; j++)
2927
{
2928
print(g, i, j, T, S);
2929
if (j<r-1) comma_sp(T,S);
2930
}
2931
if (i<l-1) semicolon_sp(T,S);
2932
}
2933
str_putc(S, ']'); if (l==2) str_putc(S, ')');
2934
break;
2935
}
2936
2937
default: str_addr(S, *g);
2938
}
2939
}
2940
2941
static void
2942
bruti_sign(GEN g, pariout_t *T, pari_str *S, int addsign)
2943
{
2944
if (!print_0_or_pm1(g, S, addsign))
2945
bruti_intern(g, T, S, addsign);
2946
}
2947
2948
static void
2949
matbruti(GEN g, pariout_t *T, pari_str *S)
2950
{
2951
long i, j, r, w, l, *pad = NULL;
2952
pari_sp av;
2953
OUT_FUN print;
2954
2955
if (typ(g) != t_MAT) { bruti(g,T,S); return; }
2956
2957
r=lg(g); if (r==1) { str_puts(S, "[;]"); return; }
2958
l = lgcols(g); if (l==1) { mat0n(S, r-1); return; }
2959
str_putc(S, '\n');
2960
print = (typ(gel(g,1)) == t_VECSMALL)? prints: bruti;
2961
av = avma;
2962
w = term_width();
2963
if (2*r < w)
2964
{
2965
long lgall = 2; /* opening [ and closing ] */
2966
pari_sp av2;
2967
pari_str str;
2968
pad = cgetg(l*r+1, t_VECSMALL); /* left on stack if (S->use_stack)*/
2969
av2 = avma;
2970
str_init(&str, 1);
2971
for (j=1; j<r; j++)
2972
{
2973
GEN col = gel(g,j);
2974
long maxc = 0;
2975
for (i=1; i<l; i++)
2976
{
2977
long lgs;
2978
str.cur = str.string;
2979
print(gel(col,i),T,&str);
2980
lgs = str.cur - str.string;
2981
pad[j*l+i] = -lgs;
2982
if (maxc < lgs) maxc = lgs;
2983
}
2984
for (i=1; i<l; i++) pad[j*l+i] += maxc;
2985
lgall += maxc + 1; /* column width, including separating space */
2986
if (lgall > w) { pad = NULL; break; } /* doesn't fit, abort padding */
2987
}
2988
set_avma(av2);
2989
}
2990
for (i=1; i<l; i++)
2991
{
2992
str_putc(S, '[');
2993
for (j=1; j<r; j++)
2994
{
2995
if (pad) {
2996
long white = pad[j*l+i];
2997
while (white-- > 0) str_putc(S, ' ');
2998
}
2999
print(gcoeff(g,i,j),T,S); if (j<r-1) str_putc(S, ' ');
3000
}
3001
if (i<l-1) str_puts(S, "]\n\n"); else str_puts(S, "]\n");
3002
}
3003
if (!S->use_stack) set_avma(av);
3004
}
3005
3006
/********************************************************************/
3007
/** **/
3008
/** TeX OUTPUT **/
3009
/** **/
3010
/********************************************************************/
3011
/* this follows bruti_sign */
3012
static void
3013
texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign)
3014
{
3015
long tg,i,j,l,r;
3016
GEN a,b;
3017
const char *v;
3018
char buf[67];
3019
3020
if (print_0_or_pm1(g, S, addsign)) return;
3021
3022
tg = typ(g);
3023
switch(tg)
3024
{
3025
case t_INT: case t_REAL: case t_QFB:
3026
bruti_intern(g, T, S, addsign); break;
3027
3028
case t_INTMOD: case t_POLMOD:
3029
texi(gel(g,2),T,S); str_puts(S, " mod ");
3030
texi(gel(g,1),T,S); break;
3031
3032
case t_FRAC:
3033
if (addsign && isfactor(gel(g,1)) < 0) str_putc(S, '-');
3034
str_puts(S, "\\frac{");
3035
texi_sign(gel(g,1),T,S,0);
3036
str_puts(S, "}{");
3037
texi_sign(gel(g,2),T,S,0);
3038
str_puts(S, "}"); break;
3039
3040
case t_RFRAC:
3041
str_puts(S, "\\frac{");
3042
texi(gel(g,1),T,S); /* too complicated otherwise */
3043
str_puts(S, "}{");
3044
texi(gel(g,2),T,S);
3045
str_puts(S, "}"); break;
3046
3047
case t_FFELT:
3048
bruti_sign(FF_to_FpXQ_i(g),T,S,addsign);
3049
break;
3050
3051
case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
3052
v = cxq_init(g, tg, &a, &b, buf);
3053
if (isnull(a))
3054
{
3055
wr_lead_texnome(T,S,b,v,1,addsign);
3056
break;
3057
}
3058
texi_sign(a,T,S,addsign);
3059
if (!isnull(b)) wr_texnome(T,S,b,v,1);
3060
break;
3061
3062
case t_POL: v = get_texvar(varn(g), buf, sizeof(buf));
3063
/* hack: we want g[i] = coeff of degree i. */
3064
i = degpol(g); g += 2; while (isnull(gel(g,i))) i--;
3065
wr_lead_texnome(T,S,gel(g,i),v,i,addsign);
3066
while (i--)
3067
{
3068
a = gel(g,i);
3069
if (!isnull_for_pol(a)) wr_texnome(T,S,a,v,i);
3070
}
3071
break;
3072
3073
case t_SER: v = get_texvar(varn(g), buf, sizeof(buf));
3074
i = valp(g);
3075
if (lg(g)-2)
3076
{ /* hack: we want g[i] = coeff of degree i. */
3077
l = i + lg(g)-2; g -= i-2;
3078
wr_lead_texnome(T,S,gel(g,i),v,i,addsign);
3079
while (++i < l)
3080
{
3081
a = gel(g,i);
3082
if (!isnull_for_pol(a)) wr_texnome(T,S,a,v,i);
3083
}
3084
str_puts(S, "+ ");
3085
}
3086
str_puts(S, "O("); texnome(S,v,i); str_putc(S, ')'); break;
3087
3088
case t_PADIC:
3089
{
3090
GEN p = gel(g,2);
3091
pari_sp av;
3092
char *ev;
3093
str_alloc(S, (precp(g)+1) * lgefint(p)); /* careful! */
3094
av = avma;
3095
i = valp(g); l = precp(g)+i;
3096
g = gel(g,4); ev = itostr(p);
3097
for (; i<l; i++)
3098
{
3099
g = dvmdii(g,p,&a);
3100
if (signe(a))
3101
{
3102
if (!i || !is_pm1(a))
3103
{
3104
str_absint(S, a); if (i) str_puts(S, "\\cdot");
3105
}
3106
if (i) texVpowE(S, ev,i);
3107
str_putc(S, '+');
3108
}
3109
}
3110
str_puts(S, "O("); texVpowE(S, ev,i); str_putc(S, ')');
3111
set_avma(av); break;
3112
}
3113
3114
case t_VEC:
3115
str_puts(S, "\\pmatrix{ "); l = lg(g);
3116
for (i=1; i<l; i++)
3117
{
3118
texi(gel(g,i),T,S); if (i < l-1) str_putc(S, '&');
3119
}
3120
str_puts(S, "\\cr}\n"); break;
3121
3122
case t_LIST:
3123
switch(list_typ(g))
3124
{
3125
case t_LIST_RAW:
3126
str_puts(S, "\\pmatrix{ ");
3127
g = list_data(g);
3128
l = g? lg(g): 1;
3129
for (i=1; i<l; i++)
3130
{
3131
texi(gel(g,i),T,S); if (i < l-1) str_putc(S, '&');
3132
}
3133
str_puts(S, "\\cr}\n"); break;
3134
case t_LIST_MAP:
3135
{
3136
pari_sp av = avma;
3137
texi(maptomat_shallow(g),T,S);
3138
set_avma(av);
3139
break;
3140
}
3141
}
3142
break;
3143
case t_COL:
3144
str_puts(S, "\\pmatrix{ "); l = lg(g);
3145
for (i=1; i<l; i++)
3146
{
3147
texi(gel(g,i),T,S); str_puts(S, "\\cr\n");
3148
}
3149
str_putc(S, '}'); break;
3150
3151
case t_VECSMALL:
3152
str_puts(S, "\\pmatrix{ "); l = lg(g);
3153
for (i=1; i<l; i++)
3154
{
3155
str_long(S, g[i]);
3156
if (i < l-1) str_putc(S, '&');
3157
}
3158
str_puts(S, "\\cr}\n"); break;
3159
3160
case t_STR:
3161
str_puts(S, GSTR(g)); break;
3162
3163
case t_CLOSURE:
3164
if (lg(g)>=6)
3165
{
3166
GEN str = closure_get_text(g);
3167
if (typ(str)==t_STR)
3168
{
3169
print_precontext(g, S, 1);
3170
str_puts(S, GSTR(str));
3171
print_context(g, T, S ,1);
3172
}
3173
else
3174
{
3175
str_putc(S,'('); str_puts(S,GSTR(gel(str,1)));
3176
str_puts(S,")\\mapsto ");
3177
print_context(g, T, S ,1); str_puts(S,GSTR(gel(str,2)));
3178
}
3179
}
3180
else
3181
{
3182
str_puts(S,"\\{\""); str_puts(S,GSTR(closure_get_code(g)));
3183
str_puts(S,"\","); texi(gel(g,3),T,S);
3184
str_putc(S,','); texi(gel(g,4),T,S);
3185
str_putc(S,','); texi(gel(g,5),T,S); str_puts(S,"\\}");
3186
}
3187
break;
3188
case t_INFINITY: str_puts(S, inf_get_sign(g) == 1? "+\\infty": "-\\infty");
3189
break;
3190
3191
case t_MAT:
3192
{
3193
str_puts(S, "\\pmatrix{\n "); r = lg(g);
3194
if (r>1)
3195
{
3196
OUT_FUN print = (typ(gel(g,1)) == t_VECSMALL)? prints: texi;
3197
3198
l = lgcols(g);
3199
for (i=1; i<l; i++)
3200
{
3201
for (j=1; j<r; j++)
3202
{
3203
print(gcoeff(g,i,j),T,S); if (j<r-1) str_putc(S, '&');
3204
}
3205
str_puts(S, "\\cr\n ");
3206
}
3207
}
3208
str_putc(S, '}'); break;
3209
}
3210
}
3211
}
3212
3213
/*******************************************************************/
3214
/** **/
3215
/** USER OUTPUT FUNCTIONS **/
3216
/** **/
3217
/*******************************************************************/
3218
static void
3219
_initout(pariout_t *T, char f, long sigd, long sp)
3220
{
3221
T->format = f;
3222
T->sigd = sigd;
3223
T->sp = sp;
3224
}
3225
3226
static void
3227
gen_output_fun(GEN x, pariout_t *T, OUT_FUN out)
3228
{ pari_sp av = avma; pari_puts( stack_GENtostr_fun(x,T,out) ); set_avma(av); }
3229
3230
void
3231
fputGEN_pariout(GEN x, pariout_t *T, FILE *out)
3232
{
3233
pari_sp av = avma;
3234
char *s = stack_GENtostr_fun(x, T, get_fun(T->prettyp));
3235
if (*s) { set_last_newline(s[strlen(s)-1]); fputs(s, out); }
3236
set_avma(av);
3237
}
3238
3239
void
3240
brute(GEN g, char f, long d)
3241
{
3242
pariout_t T; _initout(&T,f,d,0);
3243
gen_output_fun(g, &T, &bruti);
3244
}
3245
void
3246
matbrute(GEN g, char f, long d)
3247
{
3248
pariout_t T; _initout(&T,f,d,1);
3249
gen_output_fun(g, &T, &matbruti);
3250
}
3251
void
3252
texe(GEN g, char f, long d)
3253
{
3254
pariout_t T; _initout(&T,f,d,0);
3255
gen_output_fun(g, &T, &texi);
3256
}
3257
3258
void
3259
gen_output(GEN x)
3260
{
3261
gen_output_fun(x, GP_DATA->fmt, get_fun(GP_DATA->fmt->prettyp));
3262
pari_putc('\n'); pari_flush();
3263
}
3264
void
3265
output(GEN x)
3266
{ brute(x,'g',-1); pari_putc('\n'); pari_flush(); }
3267
void
3268
outmat(GEN x)
3269
{ matbrute(x,'g',-1); pari_putc('\n'); pari_flush(); }
3270
3271
/*******************************************************************/
3272
/** FILES **/
3273
/*******************************************************************/
3274
/* to cache '~' expansion */
3275
static char *homedir;
3276
/* last file read successfully from try_name() */
3277
static THREAD char *last_filename;
3278
/* stack of temporary files (includes all infiles + some output) */
3279
static THREAD pariFILE *last_tmp_file;
3280
/* stack of "permanent" (output) files */
3281
static THREAD pariFILE *last_file;
3282
3283
typedef struct gpfile
3284
{
3285
const char *name;
3286
FILE *fp;
3287
int type;
3288
long serial;
3289
} gpfile;
3290
3291
static THREAD gpfile *gp_file;
3292
static THREAD pari_stack s_gp_file;
3293
static THREAD long gp_file_serial;
3294
3295
#if defined(UNIX) || defined(__EMX__)
3296
# include <fcntl.h>
3297
# include <sys/stat.h> /* for open */
3298
# ifdef __EMX__
3299
# include <process.h>
3300
# endif
3301
# define HAVE_PIPES
3302
#endif
3303
#if defined(_WIN32)
3304
# define HAVE_PIPES
3305
#endif
3306
#ifndef O_RDONLY
3307
# define O_RDONLY 0
3308
#endif
3309
3310
pariFILE *
3311
newfile(FILE *f, const char *name, int type)
3312
{
3313
pariFILE *file = (pariFILE*) pari_malloc(strlen(name) + 1 + sizeof(pariFILE));
3314
file->type = type;
3315
file->name = strcpy((char*)(file+1), name);
3316
file->file = f;
3317
file->next = NULL;
3318
if (type & mf_PERM)
3319
{
3320
file->prev = last_file;
3321
last_file = file;
3322
}
3323
else
3324
{
3325
file->prev = last_tmp_file;
3326
last_tmp_file = file;
3327
}
3328
if (file->prev) (file->prev)->next = file;
3329
if (DEBUGFILES)
3330
err_printf("I/O: new pariFILE %s (code %d) \n",name,type);
3331
return file;
3332
}
3333
3334
static void
3335
pari_kill_file(pariFILE *f)
3336
{
3337
if ((f->type & mf_PIPE) == 0)
3338
{
3339
if (f->file != stdin && fclose(f->file))
3340
pari_warn(warnfile, "close", f->name);
3341
}
3342
#ifdef HAVE_PIPES
3343
else
3344
{
3345
if (f->type & mf_FALSE)
3346
{
3347
if (f->file != stdin && fclose(f->file))
3348
pari_warn(warnfile, "close", f->name);
3349
if (unlink(f->name)) pari_warn(warnfile, "delete", f->name);
3350
}
3351
else
3352
if (pclose(f->file) < 0) pari_warn(warnfile, "close pipe", f->name);
3353
}
3354
#endif
3355
if (DEBUGFILES)
3356
err_printf("I/O: closing file %s (code %d) \n",f->name,f->type);
3357
pari_free(f);
3358
}
3359
3360
void
3361
pari_fclose(pariFILE *f)
3362
{
3363
if (f->next) (f->next)->prev = f->prev;
3364
else if (f == last_tmp_file) last_tmp_file = f->prev;
3365
else if (f == last_file) last_file = f->prev;
3366
if (f->prev) (f->prev)->next = f->next;
3367
pari_kill_file(f);
3368
}
3369
3370
static pariFILE *
3371
pari_open_file(FILE *f, const char *s, const char *mode)
3372
{
3373
if (!f) pari_err_FILE("requested file", s);
3374
if (DEBUGFILES)
3375
err_printf("I/O: opening file %s (mode %s)\n", s, mode);
3376
return newfile(f,s,0);
3377
}
3378
3379
pariFILE *
3380
pari_fopen_or_fail(const char *s, const char *mode)
3381
{
3382
return pari_open_file(fopen(s, mode), s, mode);
3383
}
3384
pariFILE *
3385
pari_fopen(const char *s, const char *mode)
3386
{
3387
FILE *f = fopen(s, mode);
3388
return f? pari_open_file(f, s, mode): NULL;
3389
}
3390
3391
void
3392
pari_fread_chars(void *b, size_t n, FILE *f)
3393
{
3394
if (fread(b, sizeof(char), n, f) < n)
3395
pari_err_FILE("input file [fread]", "FILE*");
3396
}
3397
3398
/* FIXME: HAS_FDOPEN & allow standard open() flags */
3399
#ifdef UNIX
3400
/* open tmpfile s (a priori for writing) avoiding symlink attacks */
3401
pariFILE *
3402
pari_safefopen(const char *s, const char *mode)
3403
{
3404
long fd = open(s, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
3405
3406
if (fd == -1) pari_err(e_MISC,"tempfile %s already exists",s);
3407
return pari_open_file(fdopen(fd, mode), s, mode);
3408
}
3409
#else
3410
pariFILE *
3411
pari_safefopen(const char *s, const char *mode)
3412
{
3413
return pari_fopen_or_fail(s, mode);
3414
}
3415
#endif
3416
3417
void
3418
pari_unlink(const char *s)
3419
{
3420
if (unlink(s)) pari_warn(warner, "I/O: can\'t remove file %s", s);
3421
else if (DEBUGFILES)
3422
err_printf("I/O: removed file %s\n", s);
3423
}
3424
3425
/* Remove one INFILE from the stack. Reset pari_infile (to the most recent
3426
* infile)
3427
* Return -1, if we're trying to pop out stdin itself; 0 otherwise
3428
* Check for leaked file handlers (temporary files) */
3429
int
3430
popinfile(void)
3431
{
3432
pariFILE *f = last_tmp_file, *g;
3433
while (f)
3434
{
3435
if (f->type & mf_IN) break;
3436
pari_warn(warner, "I/O: leaked file descriptor (%d): %s", f->type, f->name);
3437
g = f; f = f->prev; pari_fclose(g);
3438
}
3439
last_tmp_file = f; if (!f) return -1;
3440
pari_fclose(last_tmp_file);
3441
for (f = last_tmp_file; f; f = f->prev)
3442
if (f->type & mf_IN) { pari_infile = f->file; return 0; }
3443
pari_infile = stdin; return 0;
3444
}
3445
3446
/* delete all "temp" files open since last reference point F */
3447
void
3448
tmp_restore(pariFILE *F)
3449
{
3450
pariFILE *f = last_tmp_file;
3451
if (DEBUGFILES>1) err_printf("gp_context_restore: deleting open files...\n");
3452
while (f)
3453
{
3454
pariFILE *g = f->prev;
3455
if (f == F) break;
3456
pari_fclose(f); f = g;
3457
}
3458
for (; f; f = f->prev) {
3459
if (f->type & mf_IN) {
3460
pari_infile = f->file;
3461
if (DEBUGFILES>1)
3462
err_printf("restoring pari_infile to %s\n", f->name);
3463
break;
3464
}
3465
}
3466
if (!f) {
3467
pari_infile = stdin;
3468
if (DEBUGFILES>1)
3469
err_printf("gp_context_restore: restoring pari_infile to stdin\n");
3470
}
3471
if (DEBUGFILES>1) err_printf("done\n");
3472
}
3473
3474
void
3475
filestate_save(struct pari_filestate *file)
3476
{
3477
file->file = last_tmp_file;
3478
file->serial = gp_file_serial;
3479
}
3480
3481
static void
3482
filestate_close(long serial)
3483
{
3484
long i;
3485
for (i = 0; i < s_gp_file.n; i++)
3486
if (gp_file[i].fp && gp_file[i].serial >= serial)
3487
gp_fileclose(i);
3488
gp_file_serial = serial;
3489
}
3490
3491
void
3492
filestate_restore(struct pari_filestate *file)
3493
{
3494
tmp_restore(file->file);
3495
filestate_close(file->serial);
3496
}
3497
3498
static void
3499
kill_file_stack(pariFILE **s)
3500
{
3501
pariFILE *f = *s;
3502
while (f)
3503
{
3504
pariFILE *t = f->prev;
3505
pari_kill_file(f);
3506
*s = f = t; /* have to update *s in case of ^C */
3507
}
3508
}
3509
3510
void
3511
killallfiles(void)
3512
{
3513
kill_file_stack(&last_tmp_file);
3514
pari_infile = stdin;
3515
}
3516
3517
void
3518
pari_init_homedir(void)
3519
{
3520
homedir = NULL;
3521
}
3522
3523
void
3524
pari_close_homedir(void)
3525
{
3526
if (homedir) pari_free(homedir);
3527
}
3528
3529
void
3530
pari_init_files(void)
3531
{
3532
last_filename = NULL;
3533
last_tmp_file = NULL;
3534
last_file=NULL;
3535
pari_stack_init(&s_gp_file, sizeof(*gp_file), (void**)&gp_file);
3536
gp_file_serial = 0;
3537
}
3538
3539
void
3540
pari_thread_close_files(void)
3541
{
3542
popinfile(); /* look for leaks */
3543
kill_file_stack(&last_file);
3544
if (last_filename) pari_free(last_filename);
3545
kill_file_stack(&last_tmp_file);
3546
filestate_close(-1);
3547
pari_stack_delete(&s_gp_file);
3548
}
3549
3550
void
3551
pari_close_files(void)
3552
{
3553
if (pari_logfile) { fclose(pari_logfile); pari_logfile = NULL; }
3554
pari_infile = stdin;
3555
}
3556
3557
static int
3558
ok_pipe(FILE *f)
3559
{
3560
if (DEBUGFILES) err_printf("I/O: checking output pipe...\n");
3561
pari_CATCH(CATCH_ALL) {
3562
return 0;
3563
}
3564
pari_TRY {
3565
int i;
3566
fprintf(f,"\n\n"); fflush(f);
3567
for (i=1; i<1000; i++) fprintf(f," \n");
3568
fprintf(f,"\n"); fflush(f);
3569
} pari_ENDCATCH;
3570
return 1;
3571
}
3572
3573
pariFILE *
3574
try_pipe(const char *cmd, int fl)
3575
{
3576
#ifndef HAVE_PIPES
3577
pari_err(e_ARCH,"pipes");
3578
return NULL;/*LCOV_EXCL_LINE*/
3579
#else
3580
FILE *file;
3581
const char *f;
3582
VOLATILE int flag = fl;
3583
3584
# ifdef __EMX__
3585
if (_osmode == DOS_MODE) /* no pipes under DOS */
3586
{
3587
pari_sp av = avma;
3588
char *s;
3589
if (flag & mf_OUT) pari_err(e_ARCH,"pipes");
3590
f = pari_unique_filename("pipe");
3591
s = stack_malloc(strlen(cmd)+strlen(f)+4);
3592
sprintf(s,"%s > %s",cmd,f);
3593
file = system(s)? NULL: fopen(f,"r");
3594
flag |= mf_FALSE; pari_free(f); set_avma(av);
3595
}
3596
else
3597
# endif
3598
{
3599
file = (FILE *) popen(cmd, (flag & mf_OUT)? "w": "r");
3600
if (flag & mf_OUT) {
3601
if (!ok_pipe(file)) return NULL;
3602
flag |= mf_PERM;
3603
}
3604
f = cmd;
3605
}
3606
if (!file) pari_err(e_MISC,"[pipe:] '%s' failed",cmd);
3607
return newfile(file, f, mf_PIPE|flag);
3608
#endif
3609
}
3610
3611
char *
3612
os_getenv(const char *s)
3613
{
3614
#ifdef HAS_GETENV
3615
return getenv(s);
3616
#else
3617
(void) s; return NULL;
3618
#endif
3619
}
3620
3621
GEN
3622
gp_getenv(const char *s)
3623
{
3624
char *t = os_getenv(s);
3625
return t?strtoGENstr(t):gen_0;
3626
}
3627
3628
/* FIXME: HAS_GETPWUID */
3629
#if defined(UNIX) || defined(__EMX__)
3630
#include <pwd.h>
3631
#include <sys/types.h>
3632
/* user = "": use current uid */
3633
char *
3634
pari_get_homedir(const char *user)
3635
{
3636
struct passwd *p;
3637
char *dir = NULL;
3638
3639
if (!*user)
3640
{
3641
if (homedir) dir = homedir;
3642
else
3643
{
3644
p = getpwuid(geteuid());
3645
if (p)
3646
{
3647
dir = p->pw_dir;
3648
homedir = pari_strdup(dir); /* cache result */
3649
}
3650
}
3651
}
3652
else
3653
{
3654
p = getpwnam(user);
3655
if (p) dir = p->pw_dir;
3656
/* warn, but don't kill session on startup (when expanding path) */
3657
if (!dir) pari_warn(warner,"can't expand ~%s", user? user: "");
3658
}
3659
return dir;
3660
}
3661
#else
3662
char *
3663
pari_get_homedir(const char *user) { (void) user; return NULL; }
3664
#endif
3665
3666
/*******************************************************************/
3667
/** **/
3668
/** GP STANDARD INPUT AND OUTPUT **/
3669
/** **/
3670
/*******************************************************************/
3671
#ifdef HAS_OPENDIR
3672
/* slow, but more portable than stat + S_ISDIR */
3673
static int
3674
is_dir_opendir(const char *name)
3675
{
3676
DIR *d = opendir(name);
3677
if (d) { (void)closedir(d); return 1; }
3678
return 0;
3679
}
3680
#endif
3681
3682
#ifdef HAS_STAT
3683
static int
3684
is_dir_stat(const char *name)
3685
{
3686
struct stat buf;
3687
if (stat(name, &buf)) return 0;
3688
return S_ISDIR(buf.st_mode);
3689
}
3690
#endif
3691
3692
/* Does name point to a directory? */
3693
int
3694
pari_is_dir(const char *name)
3695
{
3696
#ifdef HAS_STAT
3697
return is_dir_stat(name);
3698
#else
3699
# ifdef HAS_OPENDIR
3700
return is_dir_opendir(name);
3701
# else
3702
(void) name; return 0;
3703
# endif
3704
#endif
3705
}
3706
3707
/* Does name point to a regular file? */
3708
/* If unknown, assume that it is indeed regular. */
3709
int
3710
pari_is_file(const char *name)
3711
{
3712
#ifdef HAS_STAT
3713
struct stat buf;
3714
if (stat(name, &buf)) return 1;
3715
return S_ISREG(buf.st_mode);
3716
#else
3717
(void) name; return 1;
3718
#endif
3719
}
3720
3721
int
3722
pari_stdin_isatty(void)
3723
{
3724
#ifdef HAS_ISATTY
3725
return isatty( fileno(stdin) );
3726
#else
3727
return 1;
3728
#endif
3729
}
3730
3731
/* expand tildes in filenames, return a malloc'ed buffer */
3732
static char *
3733
_path_expand(const char *s)
3734
{
3735
const char *t;
3736
char *ret, *dir = NULL;
3737
3738
if (*s != '~') return pari_strdup(s);
3739
s++; /* skip ~ */
3740
t = s; while (*t && *t != '/') t++;
3741
if (t == s)
3742
dir = pari_get_homedir("");
3743
else
3744
{
3745
char *user = pari_strndup(s, t - s);
3746
dir = pari_get_homedir(user);
3747
pari_free(user);
3748
}
3749
if (!dir) return pari_strdup(s);
3750
ret = (char*)pari_malloc(strlen(dir) + strlen(t) + 1);
3751
sprintf(ret,"%s%s",dir,t); return ret;
3752
}
3753
3754
/* expand environment variables in str, return a malloc'ed buffer
3755
* assume no \ remain and str can be freed */
3756
static char *
3757
_expand_env(char *str)
3758
{
3759
long i, l, len = 0, xlen = 16, xnum = 0;
3760
char *s = str, *s0 = s;
3761
char **x = (char **)pari_malloc(xlen * sizeof(char*));
3762
3763
while (*s)
3764
{
3765
char *env;
3766
if (*s != '$') { s++; continue; }
3767
l = s - s0;
3768
if (l) { x[xnum++] = pari_strndup(s0, l); len += l; }
3769
if (xnum > xlen - 3) /* need room for possibly two more elts */
3770
{
3771
xlen <<= 1;
3772
pari_realloc_ip((void**)&x, xlen * sizeof(char*));
3773
}
3774
3775
s0 = ++s; /* skip $ */
3776
while (is_keyword_char(*s)) s++;
3777
l = s - s0; env = pari_strndup(s0, l);
3778
s0 = os_getenv(env);
3779
if (!s0) pari_warn(warner,"undefined environment variable: %s",env);
3780
else
3781
{
3782
l = strlen(s0);
3783
if (l) { x[xnum++] = pari_strndup(s0,l); len += l; }
3784
}
3785
pari_free(env); s0 = s;
3786
}
3787
l = s - s0;
3788
if (l) { x[xnum++] = pari_strndup(s0,l); len += l; }
3789
3790
s = (char*)pari_malloc(len+1); *s = 0;
3791
for (i = 0; i < xnum; i++) { (void)strcat(s, x[i]); pari_free(x[i]); }
3792
pari_free(str); pari_free(x); return s;
3793
}
3794
3795
char *
3796
path_expand(const char *s)
3797
{
3798
#ifdef _WIN32
3799
char *ss, *p;
3800
ss = pari_strdup(s);
3801
for (p = ss; *p != 0; ++p)
3802
if (*p == '\\') *p = '/';
3803
p = _expand_env(_path_expand(ss));
3804
pari_free(ss);
3805
return p;
3806
#else
3807
return _expand_env(_path_expand(s));
3808
#endif
3809
}
3810
3811
#ifdef HAS_STRFTIME
3812
# include <time.h>
3813
void
3814
strftime_expand(const char *s, char *buf, long max)
3815
{
3816
time_t t;
3817
BLOCK_SIGINT_START
3818
t = time(NULL);
3819
(void)strftime(buf,max,s,localtime(&t));
3820
BLOCK_SIGINT_END
3821
}
3822
#else
3823
void
3824
strftime_expand(const char *s, char *buf, long max)
3825
{ strcpy(buf,s); }
3826
#endif
3827
3828
/* name is a malloc'ed (existing) filename. Accept it as new pari_infile
3829
* (unzip if needed). */
3830
static pariFILE *
3831
pari_get_infile(const char *name, FILE *file)
3832
{
3833
#ifdef ZCAT
3834
long l = strlen(name);
3835
const char *end = name + l-1;
3836
3837
if (l > 2 && (!strncmp(end-1,".Z",2)
3838
#ifdef GNUZCAT
3839
|| !strncmp(end-2,".gz",3)
3840
#endif
3841
))
3842
{ /* compressed file (compress or gzip) */
3843
char *cmd = stack_malloc(strlen(ZCAT) + l + 4);
3844
sprintf(cmd,"%s \"%s\"",ZCAT,name);
3845
fclose(file);
3846
return try_pipe(cmd, mf_IN);
3847
}
3848
#endif
3849
return newfile(file, name, mf_IN);
3850
}
3851
3852
pariFILE *
3853
pari_fopengz(const char *s)
3854
{
3855
pari_sp av = avma;
3856
char *name;
3857
long l;
3858
FILE *f = fopen(s, "r");
3859
pariFILE *pf;
3860
3861
if (f) return pari_get_infile(s, f);
3862
3863
#ifdef __EMSCRIPTEN__
3864
if (pari_is_dir(pari_datadir)) pari_emscripten_wget(s);
3865
#endif
3866
l = strlen(s);
3867
name = stack_malloc(l + 3 + 1);
3868
strcpy(name, s); (void)sprintf(name + l, ".gz");
3869
f = fopen(name, "r");
3870
pf = f ? pari_get_infile(name, f): NULL;
3871
set_avma(av); return pf;
3872
}
3873
3874
static FILE*
3875
try_open(char *s)
3876
{
3877
if (!pari_is_dir(s)) return fopen(s, "r");
3878
pari_warn(warner,"skipping directory %s",s);
3879
return NULL;
3880
}
3881
3882
void
3883
forpath_init(forpath_t *T, gp_path *path, const char *s)
3884
{
3885
T->s = s;
3886
T->ls = strlen(s);
3887
T->dir = path->dirs;
3888
}
3889
char *
3890
forpath_next(forpath_t *T)
3891
{
3892
char *t, *dir = T->dir[0];
3893
3894
if (!dir) return NULL; /* done */
3895
/* room for dir + '/' + s + '\0' */
3896
t = (char*)pari_malloc(strlen(dir) + T->ls + 2);
3897
if (!t) return NULL; /* can't happen but kills a warning */
3898
sprintf(t,"%s/%s", dir, T->s);
3899
T->dir++; return t;
3900
}
3901
3902
/* If a file called "name" exists (possibly after appending ".gp")
3903
* record it in the file_stack (as a pipe if compressed).
3904
* name is malloc'ed, we free it before returning
3905
*/
3906
static FILE *
3907
try_name(char *name)
3908
{
3909
pari_sp av = avma;
3910
char *s = name;
3911
FILE *file = try_open(name);
3912
3913
if (!file)
3914
{ /* try appending ".gp" to name */
3915
s = stack_malloc(strlen(name)+4);
3916
sprintf(s, "%s.gp", name);
3917
file = try_open(s);
3918
}
3919
if (file)
3920
{
3921
if (! last_tmp_file)
3922
{ /* empty file stack, record this name */
3923
if (last_filename) pari_free(last_filename);
3924
last_filename = pari_strdup(s);
3925
}
3926
file = pari_infile = pari_get_infile(s,file)->file;
3927
}
3928
pari_free(name); set_avma(av);
3929
return file;
3930
}
3931
static FILE *
3932
switchin_last(void)
3933
{
3934
char *s = last_filename;
3935
FILE *file;
3936
if (!s) pari_err(e_MISC,"You never gave me anything to read!");
3937
file = try_open(s);
3938
if (!file) pari_err_FILE("input file",s);
3939
return pari_infile = pari_get_infile(s,file)->file;
3940
}
3941
3942
/* return 1 if s starts by '/' or './' or '../' */
3943
static int
3944
path_is_absolute(char *s)
3945
{
3946
#ifdef _WIN32
3947
if( (*s >= 'A' && *s <= 'Z') ||
3948
(*s >= 'a' && *s <= 'z') )
3949
{
3950
return *(s+1) == ':';
3951
}
3952
#endif
3953
if (*s == '/') return 1;
3954
if (*s++ != '.') return 0;
3955
if (*s == '/') return 1;
3956
if (*s++ != '.') return 0;
3957
return *s == '/';
3958
}
3959
3960
/* If name = "", re-read last file */
3961
FILE *
3962
switchin(const char *name)
3963
{
3964
FILE *f;
3965
char *s;
3966
3967
if (!*name) return switchin_last();
3968
s = path_expand(name);
3969
/* if s is an absolute path, don't use dir_list */
3970
if (path_is_absolute(s)) { if ((f = try_name(s))) return f; }
3971
else
3972
{
3973
char *t;
3974
forpath_t T;
3975
forpath_init(&T, GP_DATA->path, s);
3976
while ( (t = forpath_next(&T)) )
3977
if ((f = try_name(t))) { pari_free(s); return f; }
3978
pari_free(s);
3979
}
3980
pari_err_FILE("input file",name);
3981
return NULL; /*LCOV_EXCL_LINE*/
3982
}
3983
3984
static int is_magic_ok(FILE *f);
3985
3986
static FILE *
3987
switchout_get_FILE(const char *name)
3988
{
3989
FILE* f;
3990
/* only for ordinary files (to avoid blocking on pipes). */
3991
if (pari_is_file(name))
3992
{
3993
f = fopen(name, "r");
3994
if (f)
3995
{
3996
int magic = is_magic_ok(f);
3997
fclose(f);
3998
if (magic) pari_err_FILE("binary output file [ use writebin ! ]", name);
3999
}
4000
}
4001
f = fopen(name, "a");
4002
if (!f) pari_err_FILE("output file",name);
4003
return f;
4004
}
4005
4006
void
4007
switchout(const char *name)
4008
{
4009
if (name)
4010
pari_outfile = switchout_get_FILE(name);
4011
else if (pari_outfile != stdout)
4012
{
4013
fclose(pari_outfile);
4014
pari_outfile = stdout;
4015
}
4016
}
4017
4018
/*******************************************************************/
4019
/** **/
4020
/** SYSTEM, READSTR/EXTERNSTR/EXTERN **/
4021
/** **/
4022
/*******************************************************************/
4023
static void
4024
check_secure(const char *s)
4025
{
4026
if (GP_DATA->secure)
4027
pari_err(e_MISC, "[secure mode]: system commands not allowed\nTried to run '%s'",s);
4028
}
4029
4030
void
4031
gpsystem(const char *s)
4032
{
4033
#ifdef HAS_SYSTEM
4034
check_secure(s);
4035
if (system(s) < 0)
4036
pari_err(e_MISC, "system(\"%s\") failed", s);
4037
#else
4038
pari_err(e_ARCH,"system");
4039
#endif
4040
}
4041
4042
static GEN
4043
get_lines(FILE *F)
4044
{
4045
pari_sp av = avma;
4046
long i, nz = 16;
4047
GEN z = cgetg(nz + 1, t_VEC);
4048
Buffer *b = new_buffer();
4049
input_method IM;
4050
IM.myfgets = (fgets_t)&fgets;
4051
IM.file = (void*)F;
4052
for(i = 1;;)
4053
{
4054
char *s = b->buf, *e;
4055
if (!file_getline(b, &s, &IM)) break;
4056
if (i > nz) { nz <<= 1; z = vec_lengthen(z, nz); }
4057
e = s + strlen(s)-1;
4058
if (*e == '\n') *e = 0;
4059
gel(z,i++) = strtoGENstr(s);
4060
}
4061
delete_buffer(b); setlg(z, i);
4062
return gerepilecopy(av, z);
4063
}
4064
4065
GEN
4066
externstr(const char *s)
4067
{
4068
pariFILE *F;
4069
GEN z;
4070
check_secure(s);
4071
F = try_pipe(s, mf_IN);
4072
z = get_lines(F->file);
4073
pari_fclose(F); return z;
4074
}
4075
GEN
4076
gpextern(const char *s)
4077
{
4078
pariFILE *F;
4079
GEN z;
4080
check_secure(s);
4081
F = try_pipe(s, mf_IN);
4082
z = gp_read_stream(F->file);
4083
pari_fclose(F); return z ? z : gnil;
4084
}
4085
4086
GEN
4087
readstr(const char *s)
4088
{
4089
GEN z = get_lines(switchin(s));
4090
popinfile(); return z;
4091
}
4092
4093
/*******************************************************************/
4094
/** **/
4095
/** I/O IN BINARY FORM **/
4096
/** **/
4097
/*******************************************************************/
4098
static void
4099
pari_fread_longs(void *a, size_t c, FILE *d)
4100
{ if (fread(a,sizeof(long),c,d) < c)
4101
pari_err_FILE("input file [fread]", "FILE*"); }
4102
4103
static void
4104
_fwrite(const void *a, size_t b, size_t c, FILE *d)
4105
{ if (fwrite(a,b,c,d) < c) pari_err_FILE("output file [fwrite]", "FILE*"); }
4106
static void
4107
_lfwrite(const void *a, size_t b, FILE *c) { _fwrite(a,sizeof(long),b,c); }
4108
static void
4109
_cfwrite(const void *a, size_t b, FILE *c) { _fwrite(a,sizeof(char),b,c); }
4110
4111
enum { BIN_GEN, NAM_GEN, VAR_GEN, RELINK_TABLE };
4112
4113
static long
4114
rd_long(FILE *f) { long L; pari_fread_longs(&L, 1UL, f); return L; }
4115
static void
4116
wr_long(long L, FILE *f) { _lfwrite(&L, 1UL, f); }
4117
4118
/* append x to file f */
4119
static void
4120
wrGEN(GEN x, FILE *f)
4121
{
4122
GENbin *p = copy_bin_canon(x);
4123
size_t L = p->len;
4124
4125
wr_long(L,f);
4126
if (L)
4127
{
4128
wr_long((long)p->x,f);
4129
wr_long((long)p->base,f);
4130
_lfwrite(GENbinbase(p), L,f);
4131
}
4132
pari_free((void*)p);
4133
}
4134
4135
static void
4136
wrstr(const char *s, FILE *f)
4137
{
4138
size_t L = strlen(s)+1;
4139
wr_long(L,f);
4140
_cfwrite(s, L, f);
4141
}
4142
4143
static char *
4144
rdstr(FILE *f)
4145
{
4146
size_t L = (size_t)rd_long(f);
4147
char *s;
4148
if (!L) return NULL;
4149
s = (char*)pari_malloc(L);
4150
pari_fread_chars(s, L, f); return s;
4151
}
4152
4153
static void
4154
writeGEN(GEN x, FILE *f)
4155
{
4156
fputc(BIN_GEN,f);
4157
wrGEN(x, f);
4158
}
4159
4160
static void
4161
writenamedGEN(GEN x, const char *s, FILE *f)
4162
{
4163
fputc(x ? NAM_GEN : VAR_GEN,f);
4164
wrstr(s, f);
4165
if (x) wrGEN(x, f);
4166
}
4167
4168
/* read a GEN from file f */
4169
static GEN
4170
rdGEN(FILE *f)
4171
{
4172
size_t L = (size_t)rd_long(f);
4173
GENbin *p;
4174
4175
if (!L) return gen_0;
4176
p = (GENbin*)pari_malloc(sizeof(GENbin) + L*sizeof(long));
4177
p->len = L;
4178
p->x = (GEN)rd_long(f);
4179
p->base = (GEN)rd_long(f);
4180
p->rebase = &shiftaddress_canon;
4181
pari_fread_longs(GENbinbase(p), L,f);
4182
return bin_copy(p);
4183
}
4184
4185
/* read a binary object in file f. Set *ptc to the object "type":
4186
* BIN_GEN: an anonymous GEN x; return x.
4187
* NAM_GEN: a named GEN x, with name v; set 'v to x (changevalue) and return x
4188
* VAR_GEN: a name v; create the (unassigned) variable v and return gnil
4189
* RELINK_TABLE: a relinking table for gen_relink(), to replace old adresses
4190
* in * the original session by new incarnations in the current session.
4191
* H is the current relinking table
4192
* */
4193
static GEN
4194
readobj(FILE *f, int *ptc, hashtable *H)
4195
{
4196
int c = fgetc(f);
4197
GEN x = NULL;
4198
switch(c)
4199
{
4200
case BIN_GEN:
4201
x = rdGEN(f);
4202
if (H) gen_relink(x, H);
4203
break;
4204
case NAM_GEN:
4205
case VAR_GEN:
4206
{
4207
char *s = rdstr(f);
4208
if (!s) pari_err(e_MISC,"malformed binary file (no name)");
4209
if (c == NAM_GEN)
4210
{
4211
x = rdGEN(f);
4212
if (H) gen_relink(x, H);
4213
err_printf("setting %s\n",s);
4214
changevalue(varentries[fetch_user_var(s)], x);
4215
}
4216
else
4217
{
4218
pari_var_create(fetch_entry(s));
4219
x = gnil;
4220
}
4221
break;
4222
}
4223
case RELINK_TABLE:
4224
x = rdGEN(f); break;
4225
case EOF: break;
4226
default: pari_err(e_MISC,"unknown code in readobj");
4227
}
4228
*ptc = c; return x;
4229
}
4230
4231
#define MAGIC "\020\001\022\011-\007\020" /* ^P^A^R^I-^G^P */
4232
#ifdef LONG_IS_64BIT
4233
# define ENDIAN_CHECK 0x0102030405060708L
4234
#else
4235
# define ENDIAN_CHECK 0x01020304L
4236
#endif
4237
static const long BINARY_VERSION = 1; /* since 2.2.9 */
4238
4239
static int
4240
is_magic_ok(FILE *f)
4241
{
4242
pari_sp av = avma;
4243
size_t L = strlen(MAGIC);
4244
char *s = stack_malloc(L);
4245
int r = (fread(s,1,L, f) == L && strncmp(s,MAGIC,L) == 0);
4246
set_avma(av); return r;
4247
}
4248
4249
static int
4250
is_sizeoflong_ok(FILE *f)
4251
{
4252
char c;
4253
return (fread(&c,1,1, f) == 1 && c == (char)sizeof(long));
4254
}
4255
4256
static int
4257
is_long_ok(FILE *f, long L)
4258
{
4259
long c;
4260
return (fread(&c,sizeof(long),1, f) == 1 && c == L);
4261
}
4262
4263
/* return 1 if valid binary file */
4264
static int
4265
check_magic(const char *name, FILE *f)
4266
{
4267
if (!is_magic_ok(f))
4268
pari_warn(warner, "%s is not a GP binary file",name);
4269
else if (!is_sizeoflong_ok(f))
4270
pari_warn(warner, "%s not written for a %ld bit architecture",
4271
name, sizeof(long)*8);
4272
else if (!is_long_ok(f, ENDIAN_CHECK))
4273
pari_warn(warner, "unexpected endianness in %s",name);
4274
else if (!is_long_ok(f, BINARY_VERSION))
4275
pari_warn(warner, "%s written by an incompatible version of GP",name);
4276
else return 1;
4277
return 0;
4278
}
4279
4280
static void
4281
write_magic(FILE *f)
4282
{
4283
fprintf(f, MAGIC);
4284
fprintf(f, "%c", (char)sizeof(long));
4285
wr_long(ENDIAN_CHECK, f);
4286
wr_long(BINARY_VERSION, f);
4287
}
4288
4289
int
4290
file_is_binary(FILE *f)
4291
{
4292
int r, c = fgetc(f);
4293
ungetc(c,f);
4294
r = (c != EOF && isprint(c) == 0 && isspace(c) == 0);
4295
#ifdef _WIN32
4296
if (r) { setmode(fileno(f), _O_BINARY); rewind(f); }
4297
#endif
4298
return r;
4299
}
4300
4301
void
4302
writebin(const char *name, GEN x)
4303
{
4304
FILE *f = fopen(name,"rb");
4305
pari_sp av = avma;
4306
GEN V;
4307
int already = f? 1: 0;
4308
4309
if (f) {
4310
int ok = check_magic(name,f);
4311
fclose(f);
4312
if (!ok) pari_err_FILE("binary output file",name);
4313
}
4314
f = fopen(name,"ab");
4315
if (!f) pari_err_FILE("binary output file",name);
4316
if (!already) write_magic(f);
4317
4318
V = copybin_unlink(x);
4319
if (lg(gel(V,1)) > 1)
4320
{
4321
fputc(RELINK_TABLE,f);
4322
wrGEN(V, f);
4323
}
4324
if (x) writeGEN(x,f);
4325
else
4326
{
4327
long v, maxv = pari_var_next();
4328
for (v=0; v<maxv; v++)
4329
{
4330
entree *ep = varentries[v];
4331
if (!ep) continue;
4332
writenamedGEN((GEN)ep->value,ep->name,f);
4333
}
4334
}
4335
set_avma(av); fclose(f);
4336
}
4337
4338
/* read all objects in f. If f contains BIN_GEN that would be silently ignored
4339
* [i.e f contains more than one objet, not all of them 'named GENs'], return
4340
* them all in a vector and set 'vector'. */
4341
GEN
4342
readbin(const char *name, FILE *f, int *vector)
4343
{
4344
pari_sp av = avma;
4345
hashtable *H = NULL;
4346
pari_stack s_obj;
4347
GEN obj, x, y;
4348
int cy;
4349
if (vector) *vector = 0;
4350
if (!check_magic(name,f)) return NULL;
4351
pari_stack_init(&s_obj, sizeof(GEN), (void**)&obj);
4352
/* HACK: push codeword so as to be able to treat s_obj.data as a t_VEC */
4353
pari_stack_pushp(&s_obj, (void*) (evaltyp(t_VEC)|evallg(1)));
4354
x = gnil;
4355
while ((y = readobj(f, &cy, H)))
4356
{
4357
x = y;
4358
switch(cy)
4359
{
4360
case BIN_GEN:
4361
pari_stack_pushp(&s_obj, (void*)y); break;
4362
case RELINK_TABLE:
4363
if (H) hash_destroy(H);
4364
H = hash_from_link(gel(y,1),gel(y,2), 0);
4365
}
4366
}
4367
if (H) hash_destroy(H);
4368
switch(s_obj.n) /* >= 1 */
4369
{
4370
case 1: break; /* nothing but the codeword */
4371
case 2: x = gel(obj,1); break; /* read a single BIN_GEN */
4372
default: /* more than one BIN_GEN */
4373
setlg(obj, s_obj.n);
4374
if (DEBUGLEVEL)
4375
pari_warn(warner,"%ld unnamed objects read. Returning then in a vector",
4376
s_obj.n - 1);
4377
x = gerepilecopy(av, obj);
4378
if (vector) *vector = 1;
4379
}
4380
pari_stack_delete(&s_obj);
4381
return x;
4382
}
4383
4384
/*******************************************************************/
4385
/** **/
4386
/** GP I/O **/
4387
/** **/
4388
/*******************************************************************/
4389
/* print a vector of GENs, in output context 'out', using 'sep' as a
4390
* separator between sucessive entries [ NULL = no separator ]*/
4391
void
4392
out_print0(PariOUT *out, const char *sep, GEN g, long flag)
4393
{
4394
pari_sp av = avma;
4395
OUT_FUN f = get_fun(flag);
4396
long i, l = lg(g);
4397
for (i = 1; i < l; i++, set_avma(av))
4398
{
4399
out_puts(out, stack_GENtostr_fun_unquoted(gel(g,i), GP_DATA->fmt, f));
4400
if (sep && i+1 < l) out_puts(out, sep);
4401
}
4402
}
4403
static void
4404
str_print0(pari_str *S, GEN g, long flag)
4405
{
4406
pari_sp av = avma;
4407
OUT_FUN f = get_fun(flag);
4408
long i, l = lg(g);
4409
for (i = 1; i < l; i++)
4410
{
4411
GEN x = gel(g,i);
4412
if (typ(x) == t_STR) str_puts(S, GSTR(x)); else f(x, GP_DATA->fmt, S);
4413
if (!S->use_stack) set_avma(av);
4414
}
4415
*(S->cur) = 0;
4416
}
4417
4418
/* see print0(). Returns pari_malloc()ed string */
4419
char *
4420
RgV_to_str(GEN g, long flag)
4421
{
4422
pari_str S; str_init(&S,0);
4423
str_print0(&S, g, flag);
4424
return S.string;
4425
}
4426
4427
static GEN
4428
Str_fun(GEN g, long flag) {
4429
char *t = RgV_to_str(g, flag);
4430
GEN z = strtoGENstr(t);
4431
pari_free(t); return z;
4432
}
4433
GEN Str(GEN g) { return Str_fun(g, f_RAW); }
4434
GEN strtex(GEN g) { return Str_fun(g, f_TEX); }
4435
GEN
4436
strexpand(GEN g) {
4437
char *s = RgV_to_str(g, f_RAW), *t = path_expand(s);
4438
GEN z = strtoGENstr(t);
4439
pari_free(t); pari_free(s); return z;
4440
}
4441
4442
/* display s, followed by the element of g */
4443
char *
4444
pari_sprint0(const char *s, GEN g, long flag)
4445
{
4446
pari_str S; str_init(&S, 0);
4447
str_puts(&S, s);
4448
str_print0(&S, g, flag);
4449
return S.string;
4450
}
4451
4452
static void
4453
print0_file(FILE *out, GEN g, long flag)
4454
{
4455
pari_sp av = avma;
4456
pari_str S; str_init(&S, 1);
4457
str_print0(&S, g, flag);
4458
fputs(S.string, out);
4459
set_avma(av);
4460
}
4461
4462
void
4463
print0(GEN g, long flag) { out_print0(pariOut, NULL, g, flag); }
4464
void
4465
printsep(const char *s, GEN g)
4466
{ out_print0(pariOut, s, g, f_RAW); pari_putc('\n'); pari_flush(); }
4467
void
4468
printsep1(const char *s, GEN g)
4469
{ out_print0(pariOut, s, g, f_RAW); pari_flush(); }
4470
4471
static char *
4472
sm_dopr(const char *fmt, GEN arg_vector, va_list args)
4473
{
4474
pari_str s; str_init(&s, 0);
4475
str_arg_vprintf(&s, fmt, arg_vector, args);
4476
return s.string;
4477
}
4478
char *
4479
pari_vsprintf(const char *fmt, va_list ap)
4480
{ return sm_dopr(fmt, NULL, ap); }
4481
4482
/* dummy needed to pass an empty va_list to sm_dopr */
4483
static char *
4484
dopr_arg_vector(GEN arg_vector, const char* fmt, ...)
4485
{
4486
va_list ap;
4487
char *s;
4488
va_start(ap, fmt);
4489
s = sm_dopr(fmt, arg_vector, ap);
4490
va_end(ap); return s;
4491
}
4492
/* GP only */
4493
void
4494
printf0(const char *fmt, GEN args)
4495
{ char *s = dopr_arg_vector(args, fmt);
4496
pari_puts(s); pari_free(s); pari_flush(); }
4497
/* GP only */
4498
GEN
4499
strprintf(const char *fmt, GEN args)
4500
{ char *s = dopr_arg_vector(args, fmt);
4501
GEN z = strtoGENstr(s); pari_free(s); return z; }
4502
4503
void
4504
out_vprintf(PariOUT *out, const char *fmt, va_list ap)
4505
{
4506
char *s = pari_vsprintf(fmt, ap);
4507
out_puts(out, s); pari_free(s);
4508
}
4509
void
4510
pari_vprintf(const char *fmt, va_list ap) { out_vprintf(pariOut, fmt, ap); }
4511
4512
void
4513
err_printf(const char* fmt, ...)
4514
{
4515
va_list args; va_start(args, fmt);
4516
out_vprintf(pariErr,fmt,args); va_end(args);
4517
}
4518
4519
/* variadic version of printf0 */
4520
void
4521
out_printf(PariOUT *out, const char *fmt, ...)
4522
{
4523
va_list args; va_start(args,fmt);
4524
out_vprintf(out,fmt,args); va_end(args);
4525
}
4526
void
4527
pari_printf(const char *fmt, ...) /* variadic version of printf0 */
4528
{
4529
va_list args; va_start(args,fmt);
4530
pari_vprintf(fmt,args); va_end(args);
4531
}
4532
4533
GEN
4534
gvsprintf(const char *fmt, va_list ap)
4535
{
4536
char *s = pari_vsprintf(fmt, ap);
4537
GEN z = strtoGENstr(s);
4538
pari_free(s); return z;
4539
}
4540
4541
char *
4542
pari_sprintf(const char *fmt, ...) /* variadic version of strprintf */
4543
{
4544
char *s;
4545
va_list ap;
4546
va_start(ap, fmt);
4547
s = pari_vsprintf(fmt, ap);
4548
va_end(ap); return s;
4549
}
4550
4551
void
4552
str_printf(pari_str *S, const char *fmt, ...)
4553
{
4554
va_list ap; va_start(ap, fmt);
4555
str_arg_vprintf(S, fmt, NULL, ap);
4556
va_end(ap);
4557
}
4558
4559
char *
4560
stack_sprintf(const char *fmt, ...)
4561
{
4562
char *s, *t;
4563
va_list ap;
4564
va_start(ap, fmt);
4565
s = pari_vsprintf(fmt, ap);
4566
va_end(ap);
4567
t = stack_strdup(s);
4568
pari_free(s); return t;
4569
}
4570
4571
GEN
4572
gsprintf(const char *fmt, ...) /* variadic version of gvsprintf */
4573
{
4574
GEN s;
4575
va_list ap;
4576
va_start(ap, fmt);
4577
s = gvsprintf(fmt, ap);
4578
va_end(ap); return s;
4579
}
4580
4581
/* variadic version of fprintf0. FIXME: fprintf0 not yet available */
4582
void
4583
pari_vfprintf(FILE *file, const char *fmt, va_list ap)
4584
{
4585
char *s = pari_vsprintf(fmt, ap);
4586
fputs(s, file); pari_free(s);
4587
}
4588
void
4589
pari_fprintf(FILE *file, const char *fmt, ...)
4590
{
4591
va_list ap; va_start(ap, fmt);
4592
pari_vfprintf(file, fmt, ap); va_end(ap);
4593
}
4594
4595
void print (GEN g) { print0(g, f_RAW); pari_putc('\n'); pari_flush(); }
4596
void printp (GEN g) { print0(g, f_PRETTYMAT); pari_putc('\n'); pari_flush(); }
4597
void printtex(GEN g) { print0(g, f_TEX); pari_putc('\n'); pari_flush(); }
4598
void print1 (GEN g) { print0(g, f_RAW); pari_flush(); }
4599
4600
void
4601
error0(GEN g)
4602
{
4603
if (lg(g)==2 && typ(gel(g,1))==t_ERROR) pari_err(0, gel(g,1));
4604
else pari_err(e_USER, g);
4605
}
4606
4607
void warning0(GEN g) { pari_warn(warnuser, g); }
4608
4609
static void
4610
wr_check(const char *t) {
4611
if (GP_DATA->secure)
4612
{
4613
char *msg = pari_sprintf("[secure mode]: about to write to '%s'",t);
4614
pari_ask_confirm(msg);
4615
pari_free(msg);
4616
}
4617
}
4618
4619
/* write to file s */
4620
static void
4621
wr(const char *s, GEN g, long flag, int addnl)
4622
{
4623
char *t = path_expand(s);
4624
FILE *out;
4625
4626
wr_check(t);
4627
out = switchout_get_FILE(t);
4628
pari_free(t);
4629
print0_file(out, g, flag);
4630
if (addnl) fputc('\n', out);
4631
fflush(out);
4632
if (fclose(out)) pari_warn(warnfile, "close", t);
4633
}
4634
void write0 (const char *s, GEN g) { wr(s, g, f_RAW, 1); }
4635
void writetex(const char *s, GEN g) { wr(s, g, f_TEX, 1); }
4636
void write1 (const char *s, GEN g) { wr(s, g, f_RAW, 0); }
4637
void gpwritebin(const char *s, GEN x)
4638
{
4639
char *t = path_expand(s);
4640
wr_check(t); writebin(t, x); pari_free(t);
4641
}
4642
4643
/*******************************************************************/
4644
/** **/
4645
/** HISTORY HANDLING **/
4646
/** **/
4647
/*******************************************************************/
4648
/* history management function:
4649
* p > 0, called from %p or %#p
4650
* p <= 0, called from %` or %#` (|p| backquotes, possibly 0) */
4651
static gp_hist_cell *
4652
history(long p)
4653
{
4654
gp_hist *H = GP_DATA->hist;
4655
ulong t = H->total, s = H->size;
4656
gp_hist_cell *c;
4657
4658
if (!t) pari_err(e_MISC,"The result history is empty");
4659
4660
if (p <= 0) p += t; /* count |p| entries starting from last */
4661
if (p <= 0 || p <= (long)(t - s) || (ulong)p > t)
4662
{
4663
long pmin = (long)(t - s) + 1;
4664
if (pmin <= 0) pmin = 1;
4665
pari_err(e_MISC,"History result %%%ld not available [%%%ld-%%%lu]",
4666
p,pmin,t);
4667
}
4668
c = H->v + ((p-1) % s);
4669
if (!c->z)
4670
pari_err(e_MISC,"History result %%%ld has been deleted (histsize changed)", p);
4671
return c;
4672
}
4673
GEN
4674
pari_get_hist(long p) { return history(p)->z; }
4675
long
4676
pari_get_histtime(long p) { return history(p)->t; }
4677
long
4678
pari_get_histrtime(long p) { return history(p)->r; }
4679
GEN
4680
pari_histtime(long p) { return mkvec2s(history(p)->t, history(p)->r); }
4681
4682
void
4683
pari_add_hist(GEN x, long time, long rtime)
4684
{
4685
gp_hist *H = GP_DATA->hist;
4686
ulong i = H->total % H->size;
4687
H->total++;
4688
guncloneNULL(H->v[i].z);
4689
H->v[i].t = time;
4690
H->v[i].r = rtime;
4691
H->v[i].z = gclone(x);
4692
}
4693
4694
ulong
4695
pari_nb_hist(void)
4696
{
4697
return GP_DATA->hist->total;
4698
}
4699
4700
/*******************************************************************/
4701
/** **/
4702
/** TEMPORARY FILES **/
4703
/** **/
4704
/*******************************************************************/
4705
4706
#ifndef R_OK
4707
# define R_OK 4
4708
# define W_OK 2
4709
# define X_OK 1
4710
# define F_OK 0
4711
#endif
4712
4713
#ifdef __EMX__
4714
#include <io.h>
4715
static int
4716
unix_shell(void)
4717
{
4718
char *base, *sh = getenv("EMXSHELL");
4719
if (!sh) {
4720
sh = getenv("COMSPEC");
4721
if (!sh) return 0;
4722
}
4723
base = _getname(sh);
4724
return (stricmp (base, "cmd.exe") && stricmp (base, "4os2.exe")
4725
&& stricmp (base, "command.com") && stricmp (base, "4dos.com"));
4726
}
4727
#endif
4728
4729
/* check if s has rwx permissions for us */
4730
static int
4731
pari_is_rwx(const char *s)
4732
{
4733
/* FIXME: HAS_ACCESS */
4734
#if defined(UNIX) || defined (__EMX__)
4735
return access(s, R_OK | W_OK | X_OK) == 0;
4736
#else
4737
(void) s; return 1;
4738
#endif
4739
}
4740
4741
#if defined(UNIX) || defined (__EMX__)
4742
#include <sys/types.h>
4743
#include <sys/stat.h>
4744
static int
4745
pari_file_exists(const char *s)
4746
{
4747
int id = open(s, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
4748
return id < 0 || close(id);
4749
}
4750
static int
4751
pari_dir_exists(const char *s) { return mkdir(s, 0777); }
4752
#elif defined(_WIN32)
4753
static int
4754
pari_file_exists(const char *s) { return GetFileAttributesA(s) != ~0UL; }
4755
static int
4756
pari_dir_exists(const char *s) { return mkdir(s); }
4757
#else
4758
static int
4759
pari_file_exists(const char *s) { return 0; }
4760
static int
4761
pari_dir_exists(const char *s) { return 0; }
4762
#endif
4763
4764
static char *
4765
env_ok(const char *s)
4766
{
4767
char *t = os_getenv(s);
4768
if (t && !pari_is_rwx(t))
4769
{
4770
pari_warn(warner,"%s is set (%s), but is not writable", s,t);
4771
t = NULL;
4772
}
4773
if (t && !pari_is_dir(t))
4774
{
4775
pari_warn(warner,"%s is set (%s), but is not a directory", s,t);
4776
t = NULL;
4777
}
4778
return t;
4779
}
4780
4781
static const char*
4782
pari_tmp_dir(void)
4783
{
4784
char *s;
4785
s = env_ok("GPTMPDIR"); if (s) return s;
4786
s = env_ok("TMPDIR"); if (s) return s;
4787
#if defined(_WIN32) || defined(__EMX__)
4788
s = env_ok("TMP"); if (s) return s;
4789
s = env_ok("TEMP"); if (s) return s;
4790
#endif
4791
#if defined(UNIX) || defined(__EMX__)
4792
if (pari_is_rwx("/tmp")) return "/tmp";
4793
if (pari_is_rwx("/var/tmp")) return "/var/tmp";
4794
#endif
4795
return ".";
4796
}
4797
4798
/* loop through 26^2 variants [suffix 'aa' to 'zz'] */
4799
static int
4800
get_file(char *buf, int test(const char *), const char *suf)
4801
{
4802
char c, d, *end = buf + strlen(buf) - 1;
4803
if (suf) end -= strlen(suf);
4804
for (d = 'a'; d <= 'z'; d++)
4805
{
4806
end[-1] = d;
4807
for (c = 'a'; c <= 'z'; c++)
4808
{
4809
*end = c;
4810
if (! test(buf)) return 1;
4811
if (DEBUGFILES) err_printf("I/O: file %s exists!\n", buf);
4812
}
4813
}
4814
return 0;
4815
}
4816
4817
#if defined(__EMX__) || defined(_WIN32)
4818
static void
4819
swap_slash(char *s)
4820
{
4821
#ifdef __EMX__
4822
if (!unix_shell())
4823
#endif
4824
{
4825
char *t;
4826
for (t=s; *t; t++)
4827
if (*t == '/') *t = '\\';
4828
}
4829
}
4830
#endif
4831
4832
/* s truncated to 8 chars, suf possibly NULL */
4833
static char *
4834
init_unique(const char *s, const char *suf)
4835
{
4836
const char *pre = pari_tmp_dir();
4837
char *buf, salt[64];
4838
size_t lpre, lsalt, lsuf;
4839
#ifdef UNIX
4840
sprintf(salt,"-%ld-%ld", (long)getuid(), (long)getpid());
4841
#else
4842
sprintf(salt,"-%ld", (long)time(NULL));
4843
#endif
4844
lsuf = suf? strlen(suf): 0;
4845
lsalt = strlen(salt);
4846
lpre = strlen(pre);
4847
/* room for prefix + '/' + s + salt + suf + '\0' */
4848
buf = (char*) pari_malloc(lpre + 1 + 8 + lsalt + lsuf + 1);
4849
strcpy(buf, pre);
4850
if (buf[lpre-1] != '/') { (void)strcat(buf, "/"); lpre++; }
4851
#if defined(__EMX__) || defined(_WIN32)
4852
swap_slash(buf);
4853
#endif
4854
sprintf(buf + lpre, "%.8s%s", s, salt);
4855
if (lsuf) strcat(buf, suf);
4856
if (DEBUGFILES) err_printf("I/O: prefix for unique file/dir = %s\n", buf);
4857
return buf;
4858
}
4859
4860
/* Return a "unique filename" built from the string s, possibly the user id
4861
* and the process pid (on Unix systems). A "temporary" directory name is
4862
* prepended. The name returned is pari_malloc'ed. It is DOS-safe
4863
* (s truncated to 8 chars) */
4864
char*
4865
pari_unique_filename_suffix(const char *s, const char *suf)
4866
{
4867
char *buf = init_unique(s, suf);
4868
if (pari_file_exists(buf) && !get_file(buf, pari_file_exists, suf))
4869
pari_err(e_MISC,"couldn't find a suitable name for a tempfile (%s)",s);
4870
return buf;
4871
}
4872
char*
4873
pari_unique_filename(const char *s)
4874
{ return pari_unique_filename_suffix(s, NULL); }
4875
4876
/* Create a "unique directory" and return its name built from the string
4877
* s, the user id and process pid (on Unix systems). A "temporary"
4878
* directory name is prepended. The name returned is pari_malloc'ed.
4879
* It is DOS-safe (truncated to 8 chars) */
4880
char*
4881
pari_unique_dir(const char *s)
4882
{
4883
char *buf = init_unique(s, NULL);
4884
if (pari_dir_exists(buf) && !get_file(buf, pari_dir_exists, NULL))
4885
pari_err(e_MISC,"couldn't find a suitable name for a tempdir (%s)",s);
4886
return buf;
4887
}
4888
4889
static long
4890
get_free_gp_file(void)
4891
{
4892
long i, l = s_gp_file.n;
4893
for (i=0; i<l; i++)
4894
if (!gp_file[i].fp)
4895
return i;
4896
return pari_stack_new(&s_gp_file);
4897
}
4898
4899
static void
4900
check_gp_file(const char *s, long n)
4901
{
4902
if (n < 0 || n >= s_gp_file.n || !gp_file[n].fp)
4903
pari_err_FILEDESC(s, n);
4904
}
4905
4906
static long
4907
new_gp_file(const char *s, FILE *f, int t)
4908
{
4909
long n;
4910
n = get_free_gp_file();
4911
gp_file[n].name = pari_strdup(s);
4912
gp_file[n].fp = f;
4913
gp_file[n].type = t;
4914
gp_file[n].serial = gp_file_serial++;
4915
if (DEBUGFILES) err_printf("fileopen:%ld (%ld)\n", n, gp_file[n].serial);
4916
return n;
4917
}
4918
4919
#if defined(ZCAT) && defined(HAVE_PIPES)
4920
static long
4921
check_compress(const char *name)
4922
{
4923
long l = strlen(name);
4924
const char *end = name + l-1;
4925
if (l > 2 && (!strncmp(end-1,".Z",2)
4926
#ifdef GNUZCAT
4927
|| !strncmp(end-2,".gz",3)
4928
#endif
4929
))
4930
{ /* compressed file (compress or gzip) */
4931
char *cmd = stack_malloc(strlen(ZCAT) + l + 4);
4932
sprintf(cmd,"%s \"%s\"",ZCAT,name);
4933
return gp_fileextern(cmd);
4934
}
4935
return -1;
4936
}
4937
#endif
4938
4939
long
4940
gp_fileopen(char *s, char *mode)
4941
{
4942
FILE *f;
4943
if (mode[0]==0 || mode[1]!=0)
4944
pari_err_TYPE("fileopen",strtoGENstr(mode));
4945
switch (mode[0])
4946
{
4947
case 'r':
4948
#if defined(ZCAT) && defined(HAVE_PIPES)
4949
{
4950
long n = check_compress(s);
4951
if (n >= 0) return n;
4952
}
4953
#endif
4954
f = fopen(s, "r");
4955
if (!f) pari_err_FILE("requested file", s);
4956
return new_gp_file(s, f, mf_IN);
4957
case 'w':
4958
case 'a':
4959
wr_check(s);
4960
f = fopen(s, mode[0]=='w' ? "w": "a");
4961
if (!f) pari_err_FILE("requested file", s);
4962
return new_gp_file(s, f, mf_OUT);
4963
default:
4964
pari_err_TYPE("fileopen",strtoGENstr(mode));
4965
return -1; /* LCOV_EXCL_LINE */
4966
}
4967
}
4968
4969
long
4970
gp_fileextern(char *s)
4971
{
4972
#ifndef HAVE_PIPES
4973
pari_err(e_ARCH,"pipes");
4974
return NULL;/*LCOV_EXCL_LINE*/
4975
#else
4976
FILE *f;
4977
check_secure(s);
4978
f = popen(s, "r");
4979
if (!f) pari_err(e_MISC,"[pipe:] '%s' failed",s);
4980
return new_gp_file(s,f, mf_PIPE);
4981
#endif
4982
}
4983
4984
void
4985
gp_fileclose(long n)
4986
{
4987
check_gp_file("fileclose", n);
4988
if (DEBUGFILES) err_printf("fileclose(%ld)\n",n);
4989
if (gp_file[n].type == mf_PIPE)
4990
pclose(gp_file[n].fp);
4991
else
4992
fclose(gp_file[n].fp);
4993
pari_free((void*)gp_file[n].name);
4994
gp_file[n].name = NULL;
4995
gp_file[n].fp = NULL;
4996
gp_file[n].type = mf_FALSE;
4997
gp_file[n].serial = -1;
4998
while (s_gp_file.n > 0 && !gp_file[s_gp_file.n-1].fp)
4999
s_gp_file.n--;
5000
}
5001
5002
void
5003
gp_fileflush(long n)
5004
{
5005
check_gp_file("fileflush", n);
5006
if (DEBUGFILES) err_printf("fileflush(%ld)\n",n);
5007
if (gp_file[n].type == mf_OUT) (void)fflush(gp_file[n].fp);
5008
}
5009
void
5010
gp_fileflush0(GEN gn)
5011
{
5012
long i;
5013
if (gn)
5014
{
5015
if (typ(gn) != t_INT) pari_err_TYPE("fileflush",gn);
5016
gp_fileflush(itos(gn));
5017
}
5018
else for (i = 0; i < s_gp_file.n; i++)
5019
if (gp_file[i].fp && gp_file[i].type == mf_OUT) gp_fileflush(i);
5020
}
5021
5022
GEN
5023
gp_fileread(long n)
5024
{
5025
Buffer *b;
5026
FILE *fp;
5027
GEN z;
5028
int t;
5029
check_gp_file("fileread", n);
5030
t = gp_file[n].type;
5031
if (t!=mf_IN && t!=mf_PIPE)
5032
pari_err_FILEDESC("fileread",n);
5033
fp = gp_file[n].fp;
5034
b = new_buffer();
5035
while(1)
5036
{
5037
if (!gp_read_stream_buf(fp, b)) { delete_buffer(b); return gen_0; }
5038
if (*(b->buf)) break;
5039
}
5040
z = strtoGENstr(b->buf);
5041
delete_buffer(b);
5042
return z;
5043
}
5044
5045
void
5046
gp_filewrite(long n, const char *s)
5047
{
5048
FILE *fp;
5049
check_gp_file("filewrite", n);
5050
if (gp_file[n].type!=mf_OUT)
5051
pari_err_FILEDESC("filewrite",n);
5052
fp = gp_file[n].fp;
5053
fputs(s, fp);
5054
fputc('\n',fp);
5055
}
5056
5057
void
5058
gp_filewrite1(long n, const char *s)
5059
{
5060
FILE *fp;
5061
check_gp_file("filewrite1", n);
5062
if (gp_file[n].type!=mf_OUT)
5063
pari_err_FILEDESC("filewrite1",n);
5064
fp = gp_file[n].fp;
5065
fputs(s, fp);
5066
}
5067
5068
GEN
5069
gp_filereadstr(long n)
5070
{
5071
Buffer *b;
5072
char *s, *e;
5073
GEN z;
5074
int t;
5075
input_method IM;
5076
check_gp_file("filereadstr", n);
5077
t = gp_file[n].type;
5078
if (t!=mf_IN && t!=mf_PIPE)
5079
pari_err_FILEDESC("fileread",n);
5080
b = new_buffer();
5081
IM.myfgets = (fgets_t)&fgets;
5082
IM.file = (void*) gp_file[n].fp;
5083
s = b->buf;
5084
if (!file_getline(b, &s, &IM)) { delete_buffer(b); return gen_0; }
5085
e = s + strlen(s)-1;
5086
if (*e == '\n') *e = 0;
5087
z = strtoGENstr(s);
5088
delete_buffer(b);
5089
return z;
5090
}
5091
5092
/*******************************************************************/
5093
/** **/
5094
/** INSTALL **/
5095
/** **/
5096
/*******************************************************************/
5097
5098
#ifdef HAS_DLOPEN
5099
#include <dlfcn.h>
5100
5101
/* see try_name() */
5102
static void *
5103
try_dlopen(const char *s, int flag)
5104
{ void *h = dlopen(s, flag); pari_free((void*)s); return h; }
5105
5106
/* like dlopen, but using default(sopath) */
5107
static void *
5108
gp_dlopen(const char *name, int flag)
5109
{
5110
void *handle;
5111
char *s;
5112
5113
if (!name) return dlopen(NULL, flag);
5114
s = path_expand(name);
5115
5116
/* if sopath empty or path is absolute, use dlopen */
5117
if (!GP_DATA || *(GP_DATA->sopath->PATH)==0 || path_is_absolute(s))
5118
return try_dlopen(s, flag);
5119
else
5120
{
5121
forpath_t T;
5122
char *t;
5123
forpath_init(&T, GP_DATA->sopath, s);
5124
while ( (t = forpath_next(&T)) )
5125
{
5126
if ( (handle = try_dlopen(t,flag)) ) { pari_free(s); return handle; }
5127
(void)dlerror(); /* clear error message */
5128
}
5129
pari_free(s);
5130
}
5131
return NULL;
5132
}
5133
5134
static void *
5135
install0(const char *name, const char *lib)
5136
{
5137
void *handle;
5138
5139
#ifndef RTLD_GLOBAL /* OSF1 has dlopen but not RTLD_GLOBAL*/
5140
# define RTLD_GLOBAL 0
5141
#endif
5142
handle = gp_dlopen(lib, RTLD_LAZY|RTLD_GLOBAL);
5143
5144
if (!handle)
5145
{
5146
const char *s = dlerror(); if (s) err_printf("%s\n\n",s);
5147
if (lib) pari_err(e_MISC,"couldn't open dynamic library '%s'",lib);
5148
pari_err(e_MISC,"couldn't open dynamic symbol table of process");
5149
}
5150
return dlsym(handle, name);
5151
}
5152
#else
5153
# ifdef _WIN32
5154
static HMODULE
5155
try_LoadLibrary(const char *s)
5156
{ void *h = LoadLibrary(s); pari_free((void*)s); return h; }
5157
5158
/* like LoadLibrary, but using default(sopath) */
5159
static HMODULE
5160
gp_LoadLibrary(const char *name)
5161
{
5162
HMODULE handle;
5163
char *s = path_expand(name);
5164
5165
/* if sopath empty or path is absolute, use LoadLibrary */
5166
if (!GP_DATA || *(GP_DATA->sopath->PATH)==0 || path_is_absolute(s))
5167
return try_LoadLibrary(s);
5168
else
5169
{
5170
forpath_t T;
5171
char *t;
5172
forpath_init(&T, GP_DATA->sopath, s);
5173
while ( (t = forpath_next(&T)) )
5174
if ( (handle = try_LoadLibrary(t)) ) { pari_free(s); return handle; }
5175
pari_free(s);
5176
}
5177
return NULL;
5178
}
5179
static void *
5180
install0(const char *name, const char *lib)
5181
{
5182
HMODULE handle;
5183
if (lib == pari_library_path)
5184
{
5185
handle = GetModuleHandleA(NULL);
5186
void * fun = (void *) GetProcAddress(handle,name);
5187
if (fun) return fun;
5188
}
5189
handle = gp_LoadLibrary(lib);
5190
if (!handle)
5191
{
5192
if (lib) pari_err(e_MISC,"couldn't open dynamic library '%s'",lib);
5193
pari_err(e_MISC,"couldn't open dynamic symbol table of process");
5194
}
5195
return (void *) GetProcAddress(handle,name);
5196
}
5197
# else
5198
static void *
5199
install0(const char *name, const char *lib)
5200
{ pari_err(e_ARCH,"install"); return NULL; }
5201
#endif
5202
#endif
5203
5204
static char *
5205
dft_help(const char *gp, const char *s, const char *code)
5206
{ return stack_sprintf("%s: installed function\nlibrary name: %s\nprototype: %s" , gp, s, code); }
5207
5208
void
5209
gpinstall(const char *s, const char *code, const char *gpname, const char *lib)
5210
{
5211
pari_sp av = avma;
5212
const char *gp = *gpname? gpname: s;
5213
int update_help;
5214
void *f;
5215
entree *ep;
5216
if (GP_DATA->secure)
5217
{
5218
char *msg = pari_sprintf("[secure mode]: about to install '%s'", s);
5219
pari_ask_confirm(msg);
5220
pari_free(msg);
5221
}
5222
f = install0(s, *lib ?lib :pari_library_path);
5223
if (!f)
5224
{
5225
if (*lib) pari_err(e_MISC,"can't find symbol '%s' in library '%s'",s,lib);
5226
pari_err(e_MISC,"can't find symbol '%s' in dynamic symbol table of process",s);
5227
}
5228
ep = is_entry(gp);
5229
/* Delete help if 1) help is the default (don't delete user addhelp)
5230
* and 2) default help changes */
5231
update_help = (ep && ep->valence == EpINSTALL && ep->help
5232
&& strcmp(ep->code, code)
5233
&& !strcmp(ep->help, dft_help(gp,s,ep->code)));
5234
ep = install(f,gp,code);
5235
if (update_help || !ep->help) addhelp(gp, dft_help(gp,s,code));
5236
mt_broadcast(snm_closure(is_entry("install"),
5237
mkvec4(strtoGENstr(s),strtoGENstr(code),
5238
strtoGENstr(gp),strtoGENstr(lib))));
5239
set_avma(av);
5240
}
5241
5242