Annotation of OpenXM_contrib/pari/src/language/es.c, Revision 1.1.1.1
1.1 maekawa 1: /*******************************************************************/
2: /** **/
3: /** INPUT/OUTPUT SUBROUTINES **/
4: /** **/
5: /*******************************************************************/
6: /* $Id: es.c,v 1.2 1999/09/23 17:50:57 karim Exp $ */
7: #include "pari.h"
8: #include "anal.h"
9: GEN confrac(GEN x); /* should be static here, but use hiremainder */
10: GEN convi(GEN x);
11: static void bruti(GEN g, long n);
12: static void texi(GEN g, long nosign);
13: static void sori(GEN g);
14: static char format;
15: static long decimals, chmp, initial;
16:
17: /* output a space or do nothing depending on original caller */
18: static void (*sp)();
19:
20: /********************************************************************/
21: /** **/
22: /** INPUT FILTER **/
23: /** **/
24: /********************************************************************/
25:
26: #define ONE_LINE_COMMENT 2
27: #define MULTI_LINE_COMMENT 1
28: /* filter s in place. If status not a query, return pointer to ending '\0'.
29: * return s / NULL otherwise
30: */
31: char *
32: filtre(char *s, int status)
33: {
34: static int in_string, in_comment = 0;
35: char c, *t;
36: int downcase;
37:
38: if (status & f_INIT) in_string = 0;
39: switch(status)
40: {
41: case f_ENDFILE:
42: if (in_string)
43: {
44: err(warner,"run-away string. Closing it");
45: in_string = 0;
46: }
47: if (in_comment)
48: {
49: err(warner,"run-away comment. Closing it");
50: in_comment = 0;
51: } /* fall through */
52: case f_INIT: case f_COMMENT:
53: return in_comment? s: NULL;
54: }
55: downcase = ((status & f_KEEPCASE) == 0 && compatible == OLDALL);
56: t = s;
57: while ((c = *s++))
58: {
59: if (in_string) *t++ = c; /* copy verbatim */
60: else if (in_comment)
61: {
62: if (in_comment == MULTI_LINE_COMMENT)
63: {
64: while (c != '*' || *s != '/')
65: {
66: if (!*s) { *t=0; return t; }
67: c = *s++;
68: }
69: s++;
70: }
71: else
72: while (c != '\n')
73: {
74: if (!*s)
75: {
76: if (status == f_READL) in_comment=0;
77: *t=0; return t;
78: }
79: c = *s++;
80: }
81: in_comment=0; continue;
82: }
83: else
84: { /* weed out comments and spaces */
85: if (c=='\\' && *s=='\\') { in_comment = ONE_LINE_COMMENT; continue; }
86: if (isspace((int)c)) continue;
87: *t++ = downcase? tolower(c): c;
88: }
89: switch(c)
90: {
91: case '/':
92: if (*s != '*' || in_string) break;
93: /* start multi-line comment */
94: t--; in_comment = MULTI_LINE_COMMENT; break;
95:
96: case '\\':
97: if (!in_string) break;
98: if (!*s) return t; /* this will result in an error */
99: *t++ = *s++; break; /* in strings, \ is the escape character */
100: /* \" does not end a string. But \\" does */
101:
102: case '"':
103: in_string = !in_string;
104: }
105: }
106: *t = 0; return t;
107: }
108: #undef ONE_LINE_COMMENT
109: #undef MULTI_LINE_COMMENT
110:
111: GEN
112: lisGEN(FILE *fi)
113: {
114: long size = 512, n = size;
115: char *buf = gpmalloc(n), *s = buf;
116:
117: for(;;)
118: if (fgets(s, n, fi))
119: {
120: if (s[strlen(s)-1] == '\n')
121: {
122: GEN x = flisexpr(buf);
123: free(buf); return x;
124: }
125: buf = gprealloc(buf, size<<1, size);
126: s = buf + (size-1); n = size+1; size <<= 1;
127: }
128: }
129:
130: /********************************************************************/
131: /** **/
132: /** GENERAL PURPOSE PRINTING **/
133: /** **/
134: /********************************************************************/
135: PariOUT *pariOut, *pariErr;
136:
137: static void
138: normalOutC(char c)
139: {
140: putc(c, pari_outfile);
141: if (logfile) putc(c, logfile);
142: }
143: static void
144: normalOutS(char *s)
145: {
146: fputs(s, pari_outfile);
147: if (logfile) { fputs(s, logfile); }
148: }
149: static void
150: normalOutF(void)
151: {
152: fflush(pari_outfile);
153: if (logfile) fflush(logfile);
154: }
155: PariOUT defaultOut = {normalOutC, normalOutS, normalOutF, NULL};
156:
157: static void
158: normalErrC(char c)
159: {
160: putc(c, errfile);
161: if (logfile) putc(c, logfile);
162: }
163: static void
164: normalErrS(char *s)
165: {
166: fputs(s, errfile);
167: if (logfile) fputs(s, logfile);
168: }
169: static void
170: normalErrF(void)
171: {
172: fflush(errfile);
173: if (logfile) fflush(logfile);
174: }
175: PariOUT defaultErr = {normalErrC, normalErrS, normalErrF, NULL};
176:
177: void
178: initout(void)
179: {
180: pariOut = &defaultOut;
181: pariErr = &defaultErr;
182: }
183:
184: void
185: pariputc(char c) { pariOut->putch(c); }
186:
187: void
188: pariputs(char *s) { pariOut->puts(s); }
189:
190: void
191: pariflush(void) { pariOut->flush(); }
192:
193: void
194: flusherr() { pariErr->flush(); }
195:
196: /* format is standard printf format, except %Z is a GEN (cast to long) */
197: void
198: vpariputs(char* format, va_list args)
199: {
200: char buf[1024], str[1024], *f = format, *s = str;
201: long nb = 0;
202:
203: while (*f)
204: {
205: if (*f != '%') *s++ = *f++;
206: else
207: {
208: if (f[1] != 'Z') { *s++ = *f++; *s++ = *f++; }
209: else
210: {
211: strcpy(s,"\003%016ld\003"); /* brace with unprobable characters */
212: nb++; s += 8; f += 2; /* skip %Z */
213: }
214: }
215: }
216: *s = 0; vsprintf(buf,str,args); s = buf;
217: if (nb)
218: for (f=s; *f; f++)
219: if (*f == '\003' && f[17] == '\003')
220: {
221: *f = 0; f[17] = 0; /* remove the bracing chars */
222: pariOut->puts(s); bruteall((GEN)atol(f+1),'g',-1,1);
223: f += 18; s = f;
224: nb--; if (!nb) break;
225: }
226: pariOut->puts(s);
227: }
228:
229: void
230: pariputsf(char *format, ...)
231: {
232: va_list args;
233:
234: va_start(args,format); vpariputs(format,args);
235: va_end(args);
236: }
237:
238: /* start printing in "color" c */
239: /* terminal has to support ANSI color escape sequences */
240: void
241: term_color(int c)
242: {
243: pariputs(term_get_color(c));
244: }
245:
246: void
247: decode_color(int n, int *c)
248: {
249: if (n < 0) n = -n;
250: c[1] = n & 0xf; n >>= 4; /* foreground */
251: c[2] = n & 0xf; n >>= 4; /* background */
252: c[0] = n & 0xf; /* attribute */
253: }
254:
255: char *
256: term_get_color(int n)
257: {
258: static char s[16];
259: int c[3], a;
260:
261: if (disable_color) return "";
262: if (n == c_NONE || (a = gp_colors[n]) == c_NONE)
263: return "\033[0m"; /* reset */
264:
265: decode_color(a,c);
266: if (c[1]<8) c[1] += 30; else c[1] += 82;
267: if (a < 0)
268: sprintf(s, "\033[%d;%dm", c[0], c[1]);
269: else
270: {
271: if (c[2]<8) c[2] += 40; else c[2] += 92;
272: sprintf(s, "\033[%d;%d;%dm", c[0], c[1], c[2]);
273: }
274: return s;
275: }
276:
277: /********************************************************************/
278: /** **/
279: /** PRINTING BASED ON SCREEN WIDTH **/
280: /** **/
281: /********************************************************************/
282: static int col_index, lin_index, max_width, max_lin;
283: void init_lim_lines(char *s, long max);
284: #ifdef HAS_TIOCGWINSZ
285: # include <sys/termios.h>
286: # include <sys/ioctl.h>
287: #endif
288:
289: static int
290: term_width_intern()
291: {
292: #ifdef WINCE
293: return 0;
294: #endif
295: #ifdef HAS_TIOCGWINSZ
296: {
297: struct winsize s;
298: if (!under_emacs && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_col;
299: }
300: #endif
301: #ifdef UNIX
302: {
303: char *str;
304: if ((str = getenv("COLUMNS"))) return atoi(str);
305: }
306: #endif
307: #ifdef __EMX__
308: {
309: int scrsize[2];
310: _scrsize(scrsize); return scrsize[0];
311: }
312: #endif
313: return 0;
314: }
315:
316: static int
317: term_height_intern()
318: {
319: #ifdef HAS_TIOCGWINSZ
320: {
321: struct winsize s;
322: if (!under_emacs && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_row;
323: }
324: #endif
325: #ifdef UNIX
326: {
327: char *str;
328: if ((str = getenv("LINES"))) return atoi(str);
329: }
330: #endif
331: #ifdef __EMX__
332: {
333: int scrsize[2];
334: _scrsize(scrsize); return scrsize[1];
335: }
336: #endif
337: return 0;
338: }
339:
340: #define DFT_TERM_WIDTH 80
341: #define DFT_TERM_HEIGHT 20
342:
343: int
344: term_width()
345: {
346: int n = term_width_intern();
347: return (n>1)? n: DFT_TERM_WIDTH;
348: }
349:
350: int
351: term_height()
352: {
353: int n = term_height_intern();
354: return (n>1)? n: DFT_TERM_HEIGHT;
355: }
356:
357: #define MAX_WIDTH 76
358: /* output string wrapped after MAX_WIDTH characters (for gp -test) */
359: static void
360: putc80(char c)
361: {
362: if (c == '\n') col_index = -1;
363: else if (col_index == MAX_WIDTH)
364: { putc('\n',pari_outfile); col_index = 0; }
365: putc(c, pari_outfile); col_index++;
366: }
367: #undef MAX_WIDTH
368: static void
369: puts80(char *s)
370: {
371: while (*s) putc80(*s++);
372: }
373: PariOUT pariOut80= {putc80, puts80, normalOutF, NULL};
374:
375: void
376: init80(long n)
377: {
378: col_index = n; pariOut = &pariOut80;
379: }
380:
381: /* output stopped after max_line have been printed (for default(lines,)) */
382: static void
383: putc_lim_lines(char c)
384: {
385: if (lin_index > max_lin) return;
386: if (lin_index == max_lin)
387: if (c == '\n' || col_index >= max_width-5)
388: {
389: normalOutS(term_get_color(c_ERR));
390: normalOutS("[+++]"); lin_index++; return;
391: }
392: if (c == '\n')
393: {
394: col_index = -1; lin_index++;
395: }
396: else if (col_index == max_width)
397: {
398: col_index = 0; lin_index++;
399: }
400: col_index++; normalOutC(c);
401: }
402: static void
403: puts_lim_lines(char *s)
404: {
405: long i,len;
406: if (lin_index > max_lin) return;
407: len = strlen(s);
408: for(i=0; i<len; i++) putc_lim_lines(s[i]);
409: }
410:
411: PariOUT pariOut_lim_lines= {putc_lim_lines, puts_lim_lines, normalOutF, NULL};
412:
413: /* s = prefix already printed (print up to max lines) */
414: void
415: init_lim_lines(char *s, long max)
416: {
417: if (!max) return;
418: max_width = term_width();
419: max_lin = max;
420: lin_index = 1; col_index = strlen(s);
421: pariOut = &pariOut_lim_lines;
422: }
423:
424: #define is_blank_or_null(c) (!(c) || is_blank(c))
425: #define is_blank(c) ((c) == ' ' || (c) == '\n')
426: #define MAX_WORD_LEN 255
427:
428: static void
429: _new_line(char *prefix)
430: {
431: pariputc('\n'); if (prefix) pariputs(prefix);
432: }
433:
434: /* output: <prefix>< s wrapped at EOL >
435: * <prefix>< ... > <str>
436: * ^---
437: * If str is NULL, omit the arrow
438: * If prefix is NULL, use ""
439: */
440: void
441: print_prefixed_text(char *s, char *prefix, char *str)
442: {
443: long prelen = prefix? strlen(prefix): 0;
444: long oldwlen=0, linelen=prelen, w = term_width();
445: char word[MAX_WORD_LEN+1], oldword[MAX_WORD_LEN+1], *u=word;
446:
447: if (prefix) pariputs(prefix);
448: oldword[0]='\0';
449: while ((*u++ = *s++))
450: {
451: if (is_blank_or_null(*s))
452: {
453: while (is_blank(*s)) s++;
454: linelen += oldwlen;
455: if (linelen > w)
456: {
457: _new_line(prefix);
458: linelen = oldwlen + prelen;
459: }
460: pariputs(oldword); *u++ = ' '; *u = '\0'; oldwlen = u-word;
461: if (*s) { strcpy(oldword,word); u = word; }
462: }
463: }
464: if (!str)
465: { if (u[-2] != '.') u[-2] = '.'; }
466: else
467: { *(u-2) = 0; oldwlen--; }
468: linelen += oldwlen;
469: if (linelen > w) { _new_line(prefix); linelen = prelen + oldwlen; }
470: pariputs(word);
471: if (str)
472: {
473: long i,len = strlen(str);
474: int space = (*str == ' ' && str[1]);
475: if (linelen + len > w)
476: {
477: _new_line(prefix); linelen = prelen;
478: if (space) { str++; len--; space = 0; }
479: }
480: pariputs(str); if (str[len-1] != '\n') pariputc('\n');
481: if (space) { linelen++; len--; }
482: for (i=0; i<linelen; i++) pariputc(' ');
483: pariputc('^');
484: for (i=0; i<len; i++) pariputc('-');
485: }
486: pariputc('\n');
487: }
488:
489: /********************************************************************/
490: /** **/
491: /** GEN <---> CHARACTER STRINGS **/
492: /** **/
493: /********************************************************************/
494:
495: typedef struct outString {
496: char *string;
497: ulong len,size;
498: } outString;
499: static outString *OutStr, *ErrStr;
500:
501: #define STEPSIZE 1024
502: #define check_output_length(str,l) { \
503: const ulong s = str->size; \
504: if (str->len + l >= s) { \
505: ulong t = s + l + STEPSIZE; \
506: str->string = gprealloc(str->string, t, s); \
507: str->size = t; \
508: } \
509: }
510:
511: #define str_putc(str, c) { \
512: check_output_length(str,1); \
513: str->string[str->len++] = c; \
514: }
515: static void
516: outstr_putc(char c) { str_putc(OutStr, c); }
517: static void
518: errstr_putc(char c) { str_putc(ErrStr, c); }
519:
520: #define str_puts(str, s) {\
521: const long len=strlen(s); \
522: check_output_length(str,len); \
523: strcpy(str->string+str->len,s); \
524: str->len += len; \
525: }
526: static void
527: outstr_puts(char *s) { str_puts(OutStr, s); }
528: static void
529: errstr_puts(char *s) { str_puts(ErrStr, s); }
530:
531: static void
532: outstr_flush(void) { /* empty */ }
533: PariOUT pariOut2Str = {outstr_putc, outstr_puts, outstr_flush, NULL};
534: PariOUT pariErr2Str = {errstr_putc, errstr_puts, outstr_flush, NULL};
535: #undef STEPSIZE
536:
537: char *
538: pari_strdup(char *s)
539: {
540: int n = strlen(s)+1;
541: char *t = gpmalloc(n);
542: memcpy(t,s,n); return t;
543: }
544:
545: /* returns a malloc-ed string, which should be freed after usage */
546: char *
547: GENtostr0(GEN x, void(*do_out)(GEN))
548: {
549: PariOUT *tmp = pariOut;
550: outString *tmps = OutStr, newStr;
551:
552: if (typ(x) == t_STR) return pari_strdup(GSTR(x));
553: pariOut = &pariOut2Str; OutStr = &newStr;
554: OutStr->len = 0; OutStr->size=0; OutStr->string=NULL;
555: do_out(x); OutStr->string[OutStr->len] = 0;
556:
557: pariOut = tmp; OutStr = tmps; return newStr.string;
558: }
559:
560: char *
561: GENtostr(GEN x) { return GENtostr0(x,outbrute); }
562: /********************************************************************/
563: /** **/
564: /** TEXMACS INTERFACE **/
565: /** **/
566: /********************************************************************/
567: extern jmp_buf environnement;
568: #include "TeXmacs.h"
569: static TeXmacs_exports_1 *TeXmacs;
570:
571: static char *
572: pari_evaluate(char *s, char *session, char **fail)
573: {
574: static PariOUT *tmp;
575: static outString *tmps;
576: outString newStr;
577: long av = avma;
578: char *t;
579:
580: tmp = pariErr; pariErr = &pariErr2Str;
581: tmps = ErrStr; ErrStr = &newStr;
582: ErrStr->len = 0; ErrStr->size=0; ErrStr->string=NULL;
583: if (setjmp(environnement)) t = NULL;
584: else
585: {
586: t = GENtostr(flisexpr(s));
587: avma = av;
588: }
589: if (ErrStr->string) ErrStr->string[ErrStr->len] = 0;
590: *fail = ErrStr->string;
591: pariErr = tmp; ErrStr = tmps; return t;
592: }
593:
594: static char *
595: pari_install(TeXmacs_exports_1* _TeXmacs, char *options, char **fail)
596: {
597: *TeXmacs = *_TeXmacs;
598: pari_init(1000000, 500000);
599: if (setjmp(environnement))
600: {
601: *fail = pari_strdup("Pari Error");
602: return NULL;
603: }
604: else
605: {
606: *fail = NULL;
607: return pari_strdup("Pari Ready");
608: }
609: }
610:
611: static char *
612: pari_execute(char *s, char *session, char **fail)
613: {
614: *fail = NULL; return pari_strdup("");
615: }
616:
617: static package_exports_1 PARI_exports_1 = {
618: "TeXmacs communication protocol 1",
619: PARIVERSION,
620: &pari_install,
621: &pari_evaluate,
622: &pari_execute
623: };
624:
625: package_exports_1 *
626: get_my_package(int i)
627: {
628: return &PARI_exports_1;
629: }
630:
631:
632: /********************************************************************/
633: /** **/
634: /** WRITE AN INTEGER **/
635: /** **/
636: /********************************************************************/
637: #define putsigne(x) pariputs((x>0)? " + " : " - ")
638: #define sp_sign_sp(x) sp(), pariputc(x>0? '+': '-'), sp()
639: #define sp_plus_sp() sp(), pariputc('+'), sp()
640: #define comma_sp() pariputc(','), sp()
641:
642: static void wr_space() {pariputc(' ');}
643: static void no_space() {}
644:
645: static void
646: blancs(long nb) { while (nb-- > 0) pariputc(' '); }
647:
648: static void
649: zeros(long nb) { while (nb-- > 0) pariputc('0'); }
650:
651: static long
652: coinit(long x)
653: {
654: char cha[10], *p = cha + 9;
655:
656: *p = 0;
657: do { *--p = x%10 + '0'; x /= 10; } while (x);
658: pariputs(p); return 9 - (p - cha);
659: }
660:
661: static void
662: comilieu(long x)
663: {
664: char cha[10], *p = cha + 9;
665:
666: for (*p = 0; p > cha; x /= 10) *--p = x%10 + '0';
667: pariputs(cha);
668: }
669:
670: static void
671: cofin(long x, long decim)
672: {
673: char cha[10], *p = cha + 9;
674:
675: for (; p > cha; x /= 10) *--p = x%10 + '0';
676: cha[decim] = 0; pariputs(cha);
677: }
678:
679: static long
680: nbdch(long l)
681: {
682: if (l<100000)
683: {
684: if (l<10) return 1;
685: if (l<100) return 2;
686: if (l<1000) return 3;
687: if (l<10000) return 4;
688: return 5;
689: }
690: if (l<1000000) return 6;
691: if (l<10000000) return 7;
692: if (l<100000000) return 8;
693: if (l<1000000000) return 9;
694: return 10; /* not reached */
695: }
696:
697: /* write an int. fw = field width (pad with ' ') */
698: static void
699: wr_int(GEN x, long fw, long nosign)
700: {
701: long *res,*re,i, sx=signe(x);
702:
703: if (!sx) { blancs(fw-1); pariputc('0'); return; }
704: setsigne(x,1); re = res = convi(x);
705: setsigne(x,sx);
706: i = nbdch(*--re); while (*--re >= 0) i+=9;
707: if (nosign || sx>0) blancs(fw-i);
708: else
709: { i++; blancs(fw-i); pariputc('-'); }
710: coinit(*--res); while (*--res >= 0) comilieu(*res);
711: }
712:
713: static void
714: wr_vecsmall(GEN g)
715: {
716: long i,l;
717: pariputc('['); l = lg(g);
718: for (i=1; i<l; i++)
719: {
720: pariputsf("%ld", g[i]);
721: if (i<l-1) comma_sp();
722: }
723: pariputc(']');
724: }
725: /********************************************************************/
726: /** **/
727: /** WRITE A REAL NUMBER **/
728: /** **/
729: /********************************************************************/
730: static void wr_exp(GEN x);
731:
732: /* assume x != 0 and print |x| in floating point format */
733: static void
734: wr_float(GEN x)
735: {
736: long *res, ex,s,d,e,decmax,deceff, dec = decimals;
737: GEN p1;
738:
739: if (dec>0) /* round if needed */
740: {
741: GEN arrondi = cgetr(3);
742: arrondi[1] = (long) (x[1]-((double)BITS_IN_LONG/pariK)*dec-2);
743: arrondi[2] = x[2]; x = addrr(x,arrondi);
744: }
745: ex = expo(x);
746: if (ex >= bit_accuracy(lg(x))) { wr_exp(x); return; }
747:
748: /* integer part */
749: p1 = gcvtoi(x,&e); s = signe(p1);
750: if (e > 0) err(bugparier,"wr_float");
751: if (!s) { pariputc('0'); d=1; }
752: else
753: {
754: setsigne(p1,1); res = convi(p1); d = coinit(*--res);
755: setsigne(p1,s);
756: while (*(--res) >= 0) { d += 9; comilieu(*res); }
757: x = subri(x,p1);
758: }
759: pariputc('.');
760:
761: /* fractional part: 0 < x < 1 */
762: if (!signe(x))
763: {
764: if (dec<0) dec=(long) (-expo(x)*L2SL10+1);
765: dec -= d; if (dec>0) zeros(dec);
766: return;
767: }
768: if (!s)
769: {
770: for(;;)
771: {
772: p1=mulsr(1000000000,x); if (expo(p1)>=0) break;
773: pariputs("000000000"); x=p1;
774: }
775: for(;;)
776: {
777: p1=mulsr(10,x); if (expo(p1)>=0) break;
778: pariputc('0'); x=p1;
779: }
780: d=0;
781: }
782: res = (long *) confrac(x); decmax = d + *res++;
783: if (dec<0) dec=decmax;
784: deceff = dec-decmax; dec -= d;
785: while (dec>8)
786: {
787: if (dec>deceff) comilieu(*res++); else pariputs("000000000");
788: dec -= 9;
789: }
790: if (dec>0)
791: {
792: if (dec>deceff) cofin(*res,dec); else zeros(dec);
793: }
794: }
795:
796: /* as above in exponential format */
797: static void
798: wr_exp(GEN x)
799: {
800: GEN dix = cgetr(lg(x)+1);
801: long ex = expo(x);
802:
803: ex = (ex>=0)? (long)(ex*L2SL10): (long)(-(-ex*L2SL10)-1);
804: affsr(10,dix); if (ex) x = mulrr(x,gpuigs(dix,-ex));
805: if (absr_cmp(x, dix) >= 0) { x=divrr(x,dix); ex++; }
806: wr_float(x); sp(); pariputsf("E%ld",ex);
807: }
808:
809: /* Write real number x.
810: * format: e (exponential), f (floating point), g (as f unless x too small)
811: * if format isn't correct (one of the above) act as e.
812: * decimals: number of decimals to print (all if <0).
813: */
814: #define print_float(fo,ex) ((fo == 'g' && ex >= -32) || fo == 'f')
815: static void
816: wr_real(GEN x, long nosign)
817: {
818: long ltop, sx = signe(x), ex = expo(x);
819:
820: if (!sx) /* real 0 */
821: {
822: if (print_float(format,ex))
823: {
824: if (decimals<0)
825: {
826: long d = 1+((-ex)>>TWOPOTBITS_IN_LONG);
827: if (d < 0) d = 0;
828: decimals=(long)(pariK*d);
829: }
830: pariputs("0."); zeros(decimals);
831: }
832: else
833: {
834: ex = (ex>=0)? (long)(ex*L2SL10): (long)(-(-ex*L2SL10)-1);
835: pariputsf("0.E%ld", ex+1);
836: }
837: return;
838: }
839: if (!nosign && sx < 0) pariputc('-'); /* print sign if needed */
840: ltop = avma;
841: if (print_float(format,ex)) wr_float(x); else wr_exp(x);
842: avma = ltop;
843: }
844: #undef print_float
845:
846: void
847: ecrire(GEN x, char f, long d, long fw)
848: {
849: if (typ(x)==t_INT)
850: wr_int(x,fw,0);
851: else
852: {
853: sp = &wr_space; format = f; decimals = d;
854: wr_real(x,0);
855: }
856: }
857:
858: /********************************************************************/
859: /** **/
860: /** HEXADECIMAL OUTPUT **/
861: /** **/
862: /********************************************************************/
863:
864: static void
865: sorstring(char* b, long x)
866: {
867: #ifdef LONG_IS_64BIT
868: pariputsf(b,(ulong)x>>32,x & MAXHALFULONG);
869: #else
870: pariputsf(b,x);
871: #endif
872: }
873:
874: /* English ordinal numbers -- GN1998Apr17 */
875: static const char *ordsuff[4] = {"st","nd","rd","th"};
876:
877: const char*
878: eng_ord(long i) /* i > 0 assumed */
879: {
880: switch (i%10)
881: {
882: case 1:
883: if (i%100==11) return ordsuff[3]; /* xxx11-th */
884: return ordsuff[0]; /* xxx01-st, xxx21-st,... */
885: case 2:
886: if (i%100==12) return ordsuff[3]; /* xxx12-th */
887: return ordsuff[1]; /* xxx02-nd, xxx22-nd,... */
888: case 3:
889: if (i%100==13) return ordsuff[3]; /* xxx13-th */
890: return ordsuff[2]; /* xxx03-rd, xxx23-rd,... */
891: default:
892: return ordsuff[3]; /* xxxx4-th,... */
893: }
894: }
895:
896: static void
897: voir2(GEN x, long nb, long bl)
898: {
899: long tx=typ(x),i,j,e,dx,lx=lg(x);
900:
901: sorstring(VOIR_STRING1,(ulong)x);
902: if (! is_recursive_t(tx)) /* t_SMALL, t_INT, t_REAL, t_STR, t_VECSMALL */
903: {
904: if (nb<0) nb = (tx==t_INT)? lgefint(x): lx;
905: if (tx == t_SMALL) x = (GEN)&x;
906: for (i=0; i<nb; i++) sorstring(VOIR_STRING2,x[i]);
907: pariputc('\n'); return;
908: }
909:
910: if (tx == t_POL || tx == t_LIST) lx = lgef(x);
911: for (i=0; i<lx; i++) sorstring(VOIR_STRING2,x[i]);
912: bl+=2; pariputc('\n');
913: switch(tx)
914: {
915: case t_INTMOD: case t_POLMOD:
916: {
917: char *s = (tx==t_INTMOD)? "int = ": "pol = ";
918: if (isonstack(x[1])) blancs(bl); else { blancs(bl-2); pariputs("* "); }
919: pariputs("mod = "); voir2((GEN)x[1],nb,bl);
920: blancs(bl); pariputs(s); voir2((GEN)x[2],nb,bl);
921: break;
922: }
923: case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
924: blancs(bl); pariputs("num = "); voir2((GEN)x[1],nb,bl);
925: blancs(bl); pariputs("den = "); voir2((GEN)x[2],nb,bl);
926: break;
927:
928: case t_COMPLEX:
929: blancs(bl); pariputs("real = "); voir2((GEN)x[1],nb,bl);
930: blancs(bl); pariputs("imag = "); voir2((GEN)x[2],nb,bl);
931: break;
932:
933: case t_PADIC:
934: if (isonstack(x[2])) blancs(bl); else { blancs(bl-2); pariputs("* "); }
935: pariputs(" p : "); voir2((GEN)x[2],nb,bl);
936: blancs(bl); pariputs("p^l : "); voir2((GEN)x[3],nb,bl);
937: blancs(bl); pariputs(" I : "); voir2((GEN)x[4],nb,bl);
938: break;
939:
940: case t_QUAD:
941: blancs(bl); pariputs("pol = "); voir2((GEN)x[1],nb,bl);
942: blancs(bl); pariputs("real = "); voir2((GEN)x[2],nb,bl);
943: blancs(bl); pariputs("imag = "); voir2((GEN)x[3],nb,bl);
944: break;
945:
946: case t_POL: case t_SER:
947: e = (tx==t_SER)? valp(x): 0;
948: for (i=2; i<lx; i++)
949: {
950: blancs(bl); pariputsf("coef of degree %ld = ",e);
951: e++; voir2((GEN)x[i],nb,bl);
952: }
953: break;
954:
955: case t_LIST: case t_QFR: case t_QFI: case t_VEC: case t_COL:
956: i = (tx==t_LIST)? 2: 1;
957: for ( ; i<lx; i++)
958: {
959: blancs(bl); pariputsf("%ld%s component = ",i,eng_ord(i));
960: voir2((GEN)x[i],nb,bl);
961: }
962: break;
963:
964: case t_MAT:
965: if (lx==1) return;
966: dx=lg((GEN)x[1]);
967: for (i=1; i<dx; i++)
968: for (j=1; j<lx; j++)
969: {
970: blancs(bl); pariputsf("mat(%ld,%ld) = ",i,j);
971: voir2(gcoeff(x,i,j),nb,bl);
972: }
973: }
974: }
975:
976: void
977: voir(GEN x, long nb)
978: {
979: voir2(x,nb,0);
980: }
981:
982: char *
983: type_name(long t)
984: {
985: char *s;
986: switch(t)
987: {
988: case t_SMALL : s="t_SMALL"; break;
989: case t_INT : s="t_INT"; break;
990: case t_REAL : s="t_REAL"; break;
991: case t_INTMOD : s="t_INTMOD"; break;
992: case t_FRAC : s="t_FRAC"; break;
993: case t_FRACN : s="t_FRACN"; break;
994: case t_COMPLEX: s="t_COMPLEX"; break;
995: case t_PADIC : s="t_PADIC"; break;
996: case t_QUAD : s="t_QUAD"; break;
997: case t_POLMOD : s="t_POLMOD"; break;
998: case t_POL : s="t_POL"; break;
999: case t_SER : s="t_SER"; break;
1000: case t_RFRAC : s="t_RFRAC"; break;
1001: case t_RFRACN : s="t_RFRACN"; break;
1002: case t_QFR : s="t_QFR"; break;
1003: case t_QFI : s="t_QFI"; break;
1004: case t_VEC : s="t_VEC"; break;
1005: case t_COL : s="t_COL"; break;
1006: case t_MAT : s="t_MAT"; break;
1007: case t_LIST : s="t_LIST"; break;
1008: case t_STR : s="t_STR"; break;
1009: case t_VECSMALL:s="t_VECSMALL";break;
1010: }
1011: return s;
1012: }
1013:
1014: /********************************************************************/
1015: /** **/
1016: /** FORMATTED OUTPUT **/
1017: /** **/
1018: /********************************************************************/
1019: static char *
1020: get_var(long v, char *buf)
1021: {
1022: entree *ep = varentries[v];
1023:
1024: if (ep) return ep->name;
1025: if (v==MAXVARN) return "#";
1026: sprintf(buf,"#<%d>",(int)v); return buf;
1027: }
1028:
1029: static char *
1030: get_texvar(long v, char *buf)
1031: {
1032: entree *ep = varentries[v];
1033: char *s, *t = buf;
1034:
1035: if (!ep) err(talker, "this object uses debugging variables");
1036: s = ep->name;
1037: if (strlen(s)>=64) err(talker, "TeX variable name too long");
1038: while(isalpha((int)*s)) *t++ = *s++;
1039: *t = 0; if (isdigit((int)*s) || *s++ == '_') sprintf(t,"_{%s}",s);
1040: return buf;
1041: }
1042:
1043: static void
1044: monome(char *v, long deg)
1045: {
1046: if (deg)
1047: {
1048: pariputs(v);
1049: if (deg!=1) pariputsf("^%ld",deg);
1050: }
1051: else pariputc('1');
1052: }
1053:
1054: static void
1055: texnome(char *v, long deg)
1056: {
1057: if (deg)
1058: {
1059: pariputs(v);
1060: if (deg!=1) pariputsf("^{%ld}",deg);
1061: }
1062: else pariputc('1');
1063: }
1064:
1065: #define padic_nome(p,e) {pariputs(p); if (e != 1) pariputsf("^%ld",e);}
1066: #define padic_texnome(p,e) {pariputs(p); if (e != 1) pariputsf("^{%ld}",e);}
1067:
1068: void
1069: etatpile(unsigned int n)
1070: {
1071: long av=avma,nu,i,l,m;
1072: GEN adr,adr1;
1073: double r;
1074:
1075: nu = (top-avma)/BYTES_IN_LONG;
1076: l = (top-bot)/BYTES_IN_LONG;
1077: r = 100.0*nu/l;
1078: pariputsf("\n Top : %lx Bottom : %lx Current stack : %lx\n",
1079: top, bot, avma);
1080:
1081: pariputsf(" Used : %ld long words (%ld K)\n",
1082: nu, nu/1024*BYTES_IN_LONG);
1083:
1084: pariputsf(" Available : %ld long words (%ld K)\n",
1085: (l-nu), (l-nu)/1024*BYTES_IN_LONG);
1086:
1087: pariputsf(" Occupation of the PARI stack : %6.2f percent\n",r);
1088:
1089: adr=getheap();
1090: pariputsf(" %ld objects on heap occupy %ld long words\n\n",
1091: itos((GEN)adr[1]), itos((GEN)adr[2]));
1092: avma=av;
1093:
1094: pariputsf(" %ld variable names used out of %d\n\n",manage_var(3,NULL),MAXVARN);
1095: if (!n) return;
1096:
1097: if (n>nu) n=nu; adr=(GEN)avma; adr1=adr+n;
1098: while (adr<adr1)
1099: {
1100: sorstring(VOIR_STRING3,(ulong)adr);
1101: l=lg(adr); m = (adr==polvar) ? MAXVARN : 0;
1102: for (i=0; i<l && adr<adr1; i++,adr++) sorstring(VOIR_STRING2,*adr);
1103: pariputc('\n'); adr=polvar+m;
1104: }
1105: pariputc('\n');
1106: }
1107:
1108: /********************************************************************/
1109: /** **/
1110: /** RAW OUTPUT **/
1111: /** **/
1112: /********************************************************************/
1113: #define isnull_for_pol(g) ((typ(g)==t_INTMOD)? !signe(g[2]): isnull(g))
1114:
1115: /* is to be printed as '0' */
1116: static long
1117: isnull(GEN g)
1118: {
1119: long i;
1120: switch (typ(g))
1121: {
1122: case t_SMALL:
1123: return !smalltos(g);
1124: case t_INT:
1125: return !signe(g);
1126: case t_COMPLEX:
1127: return isnull((GEN)g[1]) && isnull((GEN)g[2]);
1128: case t_QUAD:
1129: return isnull((GEN)g[2]) && isnull((GEN)g[3]);
1130: case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
1131: return isnull((GEN)g[1]);
1132: case t_POLMOD:
1133: return isnull((GEN)g[2]);
1134: case t_POL:
1135: for (i=lgef(g)-1; i>1; i--)
1136: if (!isnull((GEN)g[i])) return 0;
1137: return 1;
1138: }
1139: return 0;
1140: }
1141:
1142: /* return 1 or -1 if g is 1 or -1, 0 otherwise*/
1143: static long
1144: isone(GEN g)
1145: {
1146: long i;
1147: switch (typ(g))
1148: {
1149: case t_SMALL:
1150: switch(smalltos(g))
1151: {
1152: case 1: return 1;
1153: case -1: return -1;
1154: }
1155: break;
1156: case t_INT:
1157: return (signe(g) && is_pm1(g))? signe(g): 0;
1158: case t_COMPLEX:
1159: return isnull((GEN)g[2])? isone((GEN)g[1]): 0;
1160: case t_QUAD:
1161: return isnull((GEN)g[3])? isone((GEN)g[2]): 0;
1162: case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
1163: return isone((GEN)g[1]) * isone((GEN)g[2]);
1164: case t_POL:
1165: if (!signe(g)) return 0;
1166: for (i=lgef(g)-1; i>2; i--)
1167: if (!isnull((GEN)g[i])) return 0;
1168: return isone((GEN)g[2]);
1169: }
1170: return 0;
1171: }
1172:
1173: /* if g is a "monomial", return its sign, 0 otherwise */
1174: static long
1175: isfactor(GEN g)
1176: {
1177: long i,deja,sig;
1178: switch(typ(g))
1179: {
1180: case t_INT: case t_REAL:
1181: return (signe(g)<0)? -1: 1;
1182: case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
1183: return isfactor((GEN)g[1]);
1184: case t_COMPLEX:
1185: if (isnull((GEN)g[1])) return isfactor((GEN)g[2]);
1186: if (isnull((GEN)g[2])) return isfactor((GEN)g[1]);
1187: return 0;
1188: case t_PADIC:
1189: return !signe((GEN)g[4]);
1190: case t_QUAD:
1191: if (isnull((GEN)g[2])) return isfactor((GEN)g[3]);
1192: if (isnull((GEN)g[3])) return isfactor((GEN)g[2]);
1193: return 0;
1194: case t_POL: deja = 0; sig = 1;
1195: for (i=lgef(g)-1; i>1; i--)
1196: if (!isnull((GEN)g[i]))
1197: {
1198: if (deja) return 0;
1199: sig=isfactor((GEN)g[i]); deja=1;
1200: }
1201: return sig? sig: 1;
1202: case t_SER:
1203: for (i=lg(g)-1; i>1; i--)
1204: if (!isnull((GEN)g[i])) return 0;
1205: }
1206: return 1;
1207: }
1208:
1209: /* return 1 if g is a "truc" (see anal.c) */
1210: static long
1211: isdenom(GEN g)
1212: {
1213: long i,deja;
1214: switch(typ(g))
1215: {
1216: case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
1217: return 0;
1218: case t_COMPLEX: return isnull((GEN)g[2]);
1219: case t_PADIC: return !signe((GEN)g[4]);
1220: case t_QUAD: return isnull((GEN)g[3]);
1221:
1222: case t_POL: deja = 0;
1223: for (i=lgef(g)-1; i>1; i--)
1224: if (!isnull((GEN)g[i]))
1225: {
1226: if (deja) return 0;
1227: if (i==2) return isdenom((GEN)g[2]);
1228: if (!isone((GEN)g[i])) return 0;
1229: deja=1;
1230: }
1231: return 1;
1232: case t_SER:
1233: for (i=lg(g)-1; i>1; i--)
1234: if (!isnull((GEN)g[i])) return 0;
1235: }
1236: return 1;
1237: }
1238:
1239: /* write a * v^d */
1240: static void
1241: wr_monome(GEN a, char *v, long d)
1242: {
1243: long sig = isone(a);
1244:
1245: if (sig) { sp_sign_sp(sig); monome(v,d); }
1246: else
1247: {
1248: sig = isfactor(a);
1249: if (sig) { sp_sign_sp(sig); bruti(a,sig); }
1250: else
1251: {
1252: sp_plus_sp(); pariputc('('); bruti(a,sig); pariputc(')');
1253: }
1254: if (d) { pariputc('*'); monome(v,d); }
1255: }
1256: }
1257:
1258: static void
1259: wr_texnome(GEN a, char *v, long d)
1260: {
1261: long sig = isone(a);
1262:
1263: if (sig) { putsigne(sig); texnome(v,d); }
1264: else
1265: {
1266: sig = isfactor(a);
1267: if (sig) { putsigne(sig); texi(a,sig); }
1268: else
1269: {
1270: pariputs("+("); texi(a,sig); pariputc(')');
1271: }
1272: if (d) texnome(v,d);
1273: }
1274: }
1275:
1276: static void
1277: wr_lead_monome(GEN a, char *v, long d, long nosign)
1278: {
1279: long sig = isone(a);
1280: if (sig)
1281: {
1282: if (!nosign && sig<0) pariputc('-');
1283: monome(v,d);
1284: }
1285: else
1286: {
1287: if (isfactor(a)) bruti(a,nosign);
1288: else
1289: {
1290: pariputc('('); bruti(a,0); pariputc(')');
1291: }
1292: if (d) { pariputc('*'); monome(v,d); }
1293: }
1294: }
1295:
1296: static void
1297: wr_lead_texnome(GEN a, char *v, long d, long nosign)
1298: {
1299: long sig = isone(a);
1300: if (sig)
1301: {
1302: if (!nosign && sig<0) pariputc('-');
1303: texnome(v,d);
1304: }
1305: else
1306: {
1307: if (isfactor(a)) texi(a,nosign);
1308: else
1309: {
1310: pariputc('('); texi(a,0); pariputc(')');
1311: }
1312: if (d) texnome(v,d);
1313: }
1314: }
1315:
1316: static void
1317: bruti(GEN g, long nosign)
1318: {
1319: long tg,l,i,j,r;
1320: GEN a,b;
1321: char *v, buf[32];
1322:
1323: if (!g) { pariputs("NULL"); return; }
1324: if (isnull(g)) { pariputc('0'); return; }
1325: r = isone(g);
1326: if (r)
1327: {
1328: if (!nosign && r<0) pariputc('-');
1329: pariputc('1'); return;
1330: }
1331:
1332: tg = typ(g);
1333: switch(tg)
1334: {
1335: case t_SMALL: pariputsf("%ld",smalltos(g)); break;
1336: case t_INT: wr_int(g,0,nosign); break;
1337: case t_REAL: wr_real(g,nosign); break;
1338:
1339: case t_INTMOD: case t_POLMOD:
1340: pariputs(new_fun_set? "Mod(": "mod(");
1341: bruti((GEN)g[2],0); comma_sp();
1342: bruti((GEN)g[1],0); pariputc(')'); break;
1343:
1344: case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
1345: r = isfactor((GEN)g[1]); if (!r) pariputc('(');
1346: bruti((GEN)g[1],nosign);
1347: if (!r) pariputc(')');
1348: pariputc('/');
1349: r = isdenom((GEN)g[2]); if (!r) pariputc('(');
1350: bruti((GEN)g[2],0);
1351: if (!r) pariputc(')');
1352: break;
1353:
1354: case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
1355: a = (GEN)g[r+1]; b = (GEN)g[r+2]; v = r? "w": "I";
1356: if (isnull(a))
1357: {
1358: wr_lead_monome(b,v,1,nosign);
1359: return;
1360: }
1361: bruti(a,nosign);
1362: if (!isnull(b)) wr_monome(b,v,1);
1363: break;
1364:
1365: case t_POL: v = get_var(ordvar[varn(g)], buf);
1366: /* hack: we want g[i] = coeff of degree i. */
1367: i = lgef(g)-3; g += 2; while (isnull((GEN)g[i])) i--;
1368: wr_lead_monome((GEN)g[i],v,i,nosign);
1369: while (i--)
1370: {
1371: a = (GEN)g[i];
1372: if (!isnull_for_pol(a)) wr_monome(a,v,i);
1373: }
1374: break;
1375:
1376: case t_SER: v = get_var(ordvar[varn(g)], buf);
1377: i = valp(g);
1378: if (signe(g))
1379: { /* hack: we want g[i] = coeff of degree i. */
1380: l = i + lg(g)-2; g += (2-i);
1381: wr_lead_monome((GEN)g[i],v,i,nosign);
1382: while (++i < l)
1383: {
1384: a = (GEN)g[i];
1385: if (!isnull_for_pol(a)) wr_monome(a,v,i);
1386: }
1387: sp_plus_sp();
1388: }
1389: pariputs("O("); monome(v,i); pariputc(')'); break;
1390:
1391: case t_PADIC:
1392: {
1393: GEN p = (GEN)g[2];
1394: i = valp(g); l = precp(g)+i;
1395: g = (GEN)g[4]; v = GENtostr(p);
1396: for (; i<l; i++)
1397: {
1398: g = dvmdii(g,p,&a);
1399: if (signe(a))
1400: {
1401: if (!i || !is_pm1(a))
1402: {
1403: wr_int(a,0,1); if (i) pariputc('*');
1404: }
1405: if (i) padic_nome(v,i);
1406: sp_plus_sp();
1407: }
1408: }
1409: pariputs("O("); padic_nome(v,i); pariputc(')');
1410: free(v); break;
1411: }
1412:
1413: case t_QFR: case t_QFI: r = (tg == t_QFR);
1414: if (new_fun_set) pariputs("Qfb("); else pariputs(r? "qfr(": "qfi(");
1415: bruti((GEN)g[1],0); comma_sp();
1416: bruti((GEN)g[2],0); comma_sp();
1417: bruti((GEN)g[3],0);
1418: if (r) { comma_sp(); bruti((GEN)g[4],0); }
1419: pariputc(')'); break;
1420:
1421: case t_VEC: case t_COL:
1422: pariputc('['); l = lg(g);
1423: for (i=1; i<l; i++)
1424: {
1425: bruti((GEN)g[i],0);
1426: if (i<l-1) comma_sp();
1427: }
1428: pariputc(']'); if (tg==t_COL) pariputc('~');
1429: break;
1430: case t_VECSMALL: wr_vecsmall(g); break;
1431:
1432: case t_LIST:
1433: pariputs("List(["); l = lgef(g);
1434: for (i=2; i<l; i++)
1435: {
1436: bruti((GEN)g[i],0);
1437: if (i<l-1) comma_sp();
1438: }
1439: pariputs("])"); break;
1440:
1441: case t_STR:
1442: pariputc('"'); pariputs(GSTR(g)); pariputc('"');
1443: return;
1444:
1445: case t_MAT:
1446: r = lg(g); if (r==1) { pariputs("[;]"); return; }
1447: l = lg(g[1]);
1448: if (l==1)
1449: {
1450: pariputsf(new_fun_set? "matrix(0,%ld)":"matrix(0,%ld,j,k,0)", r-1);
1451: return;
1452: }
1453: if (l==2)
1454: {
1455: pariputs(new_fun_set? "Mat(": "mat(");
1456: if (r == 2) { bruti(gcoeff(g,1,1),0); pariputc(')'); return; }
1457: }
1458: pariputc('[');
1459: for (i=1; i<l; i++)
1460: {
1461: for (j=1; j<r; j++)
1462: {
1463: bruti(gcoeff(g,i,j),0);
1464: if (j<r-1) comma_sp();
1465: }
1466: if (i<l-1) { pariputc(';'); sp(); }
1467: }
1468: pariputc(']'); if (l==2) pariputc(')');
1469: break;
1470:
1471: default: sorstring(VOIR_STRING2,*g);
1472: }
1473: }
1474:
1475: static void
1476: matbruti(GEN g, long flag)
1477: {
1478: long i,j,r,l;
1479:
1480: if (typ(g) != t_MAT) { bruti(g,flag); return; }
1481:
1482: r=lg(g); if (r==1 || lg(g[1])==1) { pariputs("[;]\n"); return; }
1483: pariputc('\n'); l = lg(g[1]);
1484: for (i=1; i<l; i++)
1485: {
1486: pariputc('[');
1487: for (j=1; j<r; j++)
1488: {
1489: bruti(gcoeff(g,i,j),0); if (j<r-1) pariputc(' ');
1490: }
1491: if (i<l-1) pariputs("]\n\n"); else pariputs("]\n");
1492: }
1493: }
1494:
1495: static void
1496: sor_monome(GEN a, char *v, long d)
1497: {
1498: long sig = isone(a);
1499: if (sig) { putsigne(sig); monome(v,d); }
1500: else
1501: {
1502: sig = isfactor(a);
1503: if (sig) { putsigne(sig); if (sig < 0) a = gneg(a); }
1504: else pariputs(" + ");
1505: sori(a); if (d) { pariputc(' '); monome(v,d);}
1506: }
1507: }
1508:
1509: static void
1510: sor_lead_monome(GEN a, char *v, long d)
1511: {
1512: long sig = isone(a);
1513: if (sig)
1514: {
1515: if (sig < 0) pariputc('-');
1516: monome(v,d);
1517: }
1518: else
1519: {
1520: sori(a);
1521: if (d) { pariputc(' '); monome(v,d); }
1522: }
1523: }
1524:
1525: static void
1526: sori(GEN g)
1527: {
1528: long tg=typ(g), i,j,r,l,close_paren;
1529: GEN a,b;
1530: char *v, buf[32];
1531:
1532: switch (tg)
1533: {
1534: case t_SMALL: pariputsf("%ld",smalltos(g)); return;
1535: case t_INT: wr_int(g,chmp,0); return;
1536: case t_REAL: wr_real(g,0); return;
1537: case t_STR:
1538: pariputc('"'); pariputs(GSTR(g)); pariputc('"'); return;
1539: case t_LIST:
1540: chmp=0; pariputs("List(");
1541: for (i=2; i<lgef(g); i++)
1542: {
1543: sori((GEN)g[i]); if (i<lgef(g)-1) pariputs(", ");
1544: }
1545: pariputs(")\n"); return;
1546: }
1547: close_paren=0;
1548: if (!is_matvec_t(tg)) chmp = 0;
1549: if (!is_graphicvec_t(tg))
1550: {
1551: if (is_frac_t(tg) && gsigne(g) < 0) pariputc('-');
1552: if (! is_rfrac_t(tg)) { pariputc('('); close_paren=1; }
1553: }
1554: switch(tg)
1555: {
1556: case t_INTMOD: case t_POLMOD:
1557: a = (GEN)g[2]; b = (GEN)g[1];
1558: if (tg == t_INTMOD && signe(a) < 0) a = addii(a,b);
1559: sori(a); pariputs(" mod "); sori(b); break;
1560:
1561: case t_FRAC: case t_FRACN:
1562: a=(GEN)g[1]; wr_int(a,chmp,1); pariputs(" /");
1563: b=(GEN)g[2]; wr_int(b,chmp,1); break;
1564:
1565: case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
1566: a = (GEN)g[r+1]; b = (GEN)g[r+2]; v = r? "w": "I";
1567: if (isnull(a)) { sor_lead_monome(b,v,1); break; }
1568: sori(a); if (!isnull(b)) sor_monome(b,v,1);
1569: break;
1570:
1571: case t_PADIC:
1572: {
1573: GEN p = (GEN)g[2];
1574: i = valp(g); l = precp(g)+i;
1575: g = (GEN)g[4]; v = GENtostr(p);
1576: for (; i<l; i++)
1577: {
1578: g = dvmdii(g,p,&a);
1579: if (signe(a))
1580: {
1581: if (!i || !is_pm1(a))
1582: {
1583: wr_int(a,chmp,1); pariputc(i? '*': ' ');
1584: }
1585: if (i) { padic_nome(v,i); pariputc(' '); }
1586: pariputs("+ ");
1587: }
1588: }
1589: pariputs("O(");
1590: if (!i) pariputs(" 1)"); else padic_nome(v,i);
1591: pariputc(')'); free(v); break;
1592: }
1593:
1594: case t_POL:
1595: if (!signe(g)) { pariputc('0'); break; }
1596: v = get_var(ordvar[varn(g)],buf);
1597: i = lgef(g)-3; g += 2; while (isnull((GEN)g[i])) i--;
1598: sor_lead_monome((GEN)g[i],v,i);
1599: while (i--)
1600: {
1601: a = (GEN)g[i]; if (!isnull_for_pol(a)) sor_monome(a,v,i);
1602: }
1603: break;
1604:
1605: case t_SER: v = get_var(ordvar[varn(g)],buf);
1606: i = valp(g);
1607: if (signe(g))
1608: { /* hack: we want g[i] = coeff of degree i. */
1609: l = i + lg(g)-2; g += (2-i);
1610: sor_lead_monome((GEN)g[i],v,i);
1611: while (++i < l)
1612: {
1613: a = (GEN)g[i]; if (!isnull_for_pol(a)) sor_monome(a,v,i);
1614: }
1615: pariputs(" + ");
1616: }
1617: pariputs("O(");
1618: if (!i) pariputs(" 1)"); else monome(v,i);
1619: pariputc(')'); break;
1620:
1621: case t_RFRAC: case t_RFRACN:
1622: if (initial)
1623: {
1624: char *v1, *v2;
1625: long sd = 0, sn = 0, d,n;
1626: long wd = term_width();
1627:
1628: initial = 0;
1629: v1 = GENtostr0((GEN)g[1], &sori); n = strlen(v1);
1630: v2 = GENtostr0((GEN)g[2], &sori); d = strlen(v2);
1631:
1632: pariputc('\n');
1633: i = max(n,d)+2;
1634: if (i > wd)
1635: {
1636: pariputs(v1); pariputs("\n\n");
1637: for (j=0; j<wd; j++) pariputc('-');
1638: pariputs("\n\n");
1639: pariputs(v2);
1640: pariputc('\n'); return;
1641: }
1642: if (n < d) sn = (d-n) >> 1; else sd = (n-d) >> 1;
1643: blancs(sn+1); pariputs(v1);
1644: pariputs("\n\n"); for (j=0; j<i; j++) pariputc('-');
1645: pariputs("\n\n");
1646: blancs(sd+1); pariputs(v2);
1647: pariputc('\n'); return;
1648: }
1649: pariputc('('); sori((GEN)g[1]); pariputs(" / "); sori((GEN)g[2]);
1650: pariputc(')'); return;
1651:
1652: case t_QFR: case t_QFI: pariputc('{');
1653: sori((GEN)g[1]); pariputs(", ");
1654: sori((GEN)g[2]); pariputs(", ");
1655: sori((GEN)g[3]);
1656: if (tg == t_QFR) { pariputs(", "); sori((GEN)g[4]); }
1657: pariputs("}\n"); break;
1658:
1659: case t_VEC:
1660: chmp=0; pariputc('[');
1661: for (i=1; i<lg(g); i++)
1662: {
1663: sori((GEN)g[i]); if (i<lg(g)-1) pariputs(", ");
1664: }
1665: pariputc(']'); break;
1666: case t_VECSMALL: wr_vecsmall(g); break;
1667:
1668: case t_COL:
1669: if (lg(g)==1) { pariputs("[]\n"); return; }
1670: pariputc('\n');
1671: for (i=1; i<lg(g); i++)
1672: {
1673: pariputc('['); sori((GEN)g[i]); pariputs("]\n");
1674: }
1675: break;
1676:
1677: case t_MAT:
1678: {
1679: long lx = lg(g);
1680:
1681: if (lx==1) { pariputs("[;]\n"); return; }
1682: pariputc('\n'); l=lg((GEN)g[1]);
1683: for (i=1; i<l; i++)
1684: {
1685: pariputc('[');
1686: for (j=1; j<lx; j++)
1687: {
1688: sori(gcoeff(g,i,j)); if (j<lx-1) pariputc(' ');
1689: }
1690: pariputs("]\n"); if (i<l-1) pariputc('\n');
1691: }
1692: break;
1693: }
1694: default: sorstring(VOIR_STRING2,*g);
1695: }
1696: if (close_paren) pariputc(')');
1697: }
1698:
1699: /********************************************************************/
1700: /** **/
1701: /** TeX OUTPUT **/
1702: /** **/
1703: /********************************************************************/
1704:
1705: /* this follows bruti exactly */
1706: static void
1707: texi(GEN g, long nosign)
1708: {
1709: long tg,i,j,l,r;
1710: GEN a,b;
1711: char *v, buf[67];
1712:
1713: if (isnull(g)) { pariputs("{0}"); return; }
1714: r = isone(g); pariputc('{');
1715: if (r)
1716: {
1717: if (!nosign && r<0) pariputc('-');
1718: pariputs("1}"); return;
1719: }
1720:
1721: tg = typ(g);
1722: switch(tg)
1723: {
1724: case t_INT: wr_int(g,0,nosign); break;
1725: case t_REAL: wr_real(g,nosign); break;
1726:
1727: case t_INTMOD: case t_POLMOD:
1728: texi((GEN)g[2],0); pariputs("mod");
1729: texi((GEN)g[1],0); break;
1730:
1731: case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
1732: texi((GEN)g[1],nosign); pariputs("\\over");
1733: texi((GEN)g[2],0); break;
1734:
1735: case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
1736: a = (GEN)g[r+1]; b = (GEN)g[r+2]; v = r? "w": "I";
1737: if (isnull(a))
1738: {
1739: wr_lead_texnome(b,v,1,nosign);
1740: break;
1741: }
1742: texi(a,nosign);
1743: if (!isnull(b)) wr_texnome(b,v,1);
1744: break;
1745:
1746: case t_POL: v = get_texvar(ordvar[varn(g)],buf);
1747: /* hack: we want g[i] = coeff of degree i. */
1748: i = lgef(g)-3; g += 2; while (isnull((GEN)g[i])) i--;
1749: wr_lead_texnome((GEN)g[i],v,i,nosign);
1750: while (i--)
1751: {
1752: a = (GEN)g[i];
1753: if (!isnull_for_pol(a)) wr_texnome(a,v,i);
1754: }
1755: break;
1756:
1757: case t_SER: v = get_texvar(ordvar[varn(g)],buf);
1758: i = valp(g);
1759: if (signe(g))
1760: { /* hack: we want g[i] = coeff of degree i. */
1761: l = i + lg(g)-2; g += (2-i);
1762: wr_lead_texnome((GEN)g[i],v,i,nosign);
1763: while (++i < l)
1764: {
1765: a = (GEN)g[i];
1766: if (!isnull_for_pol(a)) wr_texnome(a,v,i);
1767: }
1768: pariputc('+');
1769: }
1770: pariputs("O("); monome(v,i); pariputc(')'); break;
1771:
1772: case t_PADIC:
1773: {
1774: GEN p = (GEN)g[2];
1775: i = valp(g); l = precp(g)+i;
1776: g = (GEN)g[4]; v = GENtostr(p);
1777: for (; i<l; i++)
1778: {
1779: g = dvmdii(g,p,&a);
1780: if (signe(a))
1781: {
1782: if (!i || !is_pm1(a))
1783: {
1784: wr_int(a,0,1); if (i) pariputs("\\cdot");
1785: }
1786: if (i) padic_texnome(v,i);
1787: pariputc('+');
1788: }
1789: }
1790: pariputs("O("); padic_texnome(v,i); pariputc(')');
1791: free(v); break;
1792: }
1793: case t_QFR: case t_QFI: r = (tg == t_QFR);
1794: if (new_fun_set) pariputs("Qfb("); else pariputs(r? "qfr(": "qfi(");
1795: texi((GEN)g[1],0); pariputs(", ");
1796: texi((GEN)g[2],0); pariputs(", ");
1797: texi((GEN)g[3],0);
1798: if (r) { pariputs(", "); texi((GEN)g[4],0); }
1799: pariputc(')'); break;
1800:
1801: case t_VEC:
1802: pariputs("\\pmatrix{ "); l = lg(g);
1803: for (i=1; i<l; i++)
1804: {
1805: texi((GEN)g[i],0); if (i<lg(g)-1) pariputc('&');
1806: }
1807: pariputs("\\cr}\n"); break;
1808:
1809: case t_LIST:
1810: pariputs("\\pmatrix{ "); l = lgef(g);
1811: for (i=2; i<l; i++)
1812: {
1813: texi((GEN)g[i],0); if (i<lgef(g)-1) pariputc('&');
1814: }
1815: pariputs("\\cr}\n"); break;
1816:
1817: case t_COL:
1818: pariputs("\\pmatrix{ "); l = lg(g);
1819: for (i=1; i<l; i++)
1820: {
1821: texi((GEN)g[i],0); pariputs("\\cr\n");
1822: }
1823: pariputc('}'); break;
1824:
1825: case t_STR:
1826: pariputs("\\mbox{"); pariputs(GSTR(g)); pariputc('}');
1827: return;
1828:
1829: case t_MAT:
1830: pariputs("\\pmatrix{\n "); r = lg(g);
1831: if (r>1)
1832: {
1833: l = lg(g[1]);
1834: for (i=1; i<l; i++)
1835: {
1836: for (j=1; j<r; j++)
1837: {
1838: texi(gcoeff(g,i,j),0); if (j<r-1) pariputc('&');
1839: }
1840: pariputs("\\cr\n ");
1841: }
1842: }
1843: pariputc('}'); break;
1844: }
1845: pariputc('}');
1846: }
1847:
1848: /*******************************************************************/
1849: /** **/
1850: /** USER OUTPUT FUNCTIONS **/
1851: /** **/
1852: /*******************************************************************/
1853:
1854: void
1855: bruteall(GEN g, char f, long d, long flag)
1856: {
1857: long av = avma;
1858: void (*oldsp)() = sp;
1859:
1860: sp = flag? &wr_space: &no_space;
1861: format = f; decimals = d;
1862: bruti(changevar(g,polvar),0);
1863: sp = oldsp; avma = av;
1864: }
1865:
1866: void
1867: matbrute(GEN g, char f, long d)
1868: {
1869: long av=avma; sp = &wr_space;
1870: format = f; decimals = d;
1871: matbruti(changevar(g,polvar),0); avma=av;
1872: }
1873:
1874: void
1875: sor(GEN g, char f, long d, long c)
1876: {
1877: long av=avma; sp = &wr_space;
1878: format = f; decimals = d; chmp = c; initial = 1;
1879: sori(changevar(g,polvar)); avma = av;
1880: }
1881:
1882: void
1883: texe(GEN g, char f, long d)
1884: {
1885: long av=avma; sp = &no_space;
1886: format = f; decimals = d;
1887: texi(changevar(g,polvar),0); avma=av;
1888: }
1889:
1890: void
1891: brute(GEN g, char format, long decimals) { bruteall(g,format,decimals,1); }
1892:
1893: void
1894: outbrute(GEN g) { bruteall(g,'g',-1,1); }
1895:
1896: void
1897: outsor(GEN g) { sor(g,'g',-1,1); }
1898:
1899: void
1900: output(GEN x)
1901: {
1902: outbrute(x); pariputc('\n'); pariflush();
1903: }
1904:
1905: void
1906: outmat(GEN x)
1907: {
1908: matbrute(x,'g',-1); pariputc('\n'); pariflush();
1909: }
1910:
1911: void
1912: outbeaut(GEN x)
1913: {
1914: outsor(x); pariputc('\n'); pariflush();
1915: }
1916:
1917: void
1918: outerr(GEN x)
1919: {
1920: PariOUT *out = pariOut; pariOut = pariErr;
1921: output(x); pariOut = out;
1922: }
1923:
1924: void
1925: outbeauterr(GEN x)
1926: {
1927: PariOUT *out = pariOut; pariOut = pariErr;
1928: outbeaut(x); pariOut = out;
1929: }
1930:
1931: void
1932: bruterr(GEN x,char format,long decimals)
1933: {
1934: PariOUT *out = pariOut; pariOut = pariErr;
1935: bruteall(x,format,decimals,1); pariOut = out;
1936: }
1937:
1938: void
1939: fprintferr(char* format, ...)
1940: {
1941: va_list args;
1942: PariOUT *out = pariOut; pariOut = pariErr;
1943:
1944: va_start(args, format); vpariputs(format,args);
1945: va_end(args); pariOut = out;
1946: }
1947:
1948: /*******************************************************************/
1949: /** FILES **/
1950: /*******************************************************************/
1951: static pariFILE *last_file = NULL;
1952: #if defined(UNIX) || defined(__EMX__)
1953: # include <pwd.h>
1954: # ifdef __EMX__
1955: # include <process.h>
1956: # endif
1957: # define HAVE_PIPES
1958: #endif
1959:
1960: pariFILE *
1961: newfile(FILE *f, char *name, int type)
1962: {
1963: pariFILE *file = (pariFILE*) gpmalloc(strlen(name) + 1 + sizeof(pariFILE));
1964: file->type = type;
1965: file->name = strcpy((char*)(file+1), name);
1966: file->file = f;
1967: file->prev = last_file;
1968: file->next = NULL;
1969: if (last_file) last_file->next = file;
1970: if (DEBUGFILES)
1971: fprintferr("I/O: opening file %s (code %d) \n",name,type);
1972: return last_file = file;
1973: }
1974:
1975: static void
1976: pari_kill_file(pariFILE *f)
1977: {
1978: if ((f->type & mf_PIPE) == 0)
1979: {
1980: if (fclose(f->file)) err(warnfile, "close", f->name);
1981: }
1982: #ifdef HAVE_PIPES
1983: else
1984: {
1985: if (f->type & mf_FALSE)
1986: {
1987: if (fclose(f->file)) err(warnfile, "close", f->name);
1988: if (unlink(f->name)) err(warnfile, "delete", f->name);
1989: }
1990: else
1991: if (pclose(f->file) < 0) err(warnfile, "close pipe", f->name);
1992: }
1993: #endif
1994: if (DEBUGFILES)
1995: fprintferr("I/O: closing file %s (code %d) \n",f->name,f->type);
1996: free(f);
1997: }
1998:
1999: void
2000: pari_fclose(pariFILE *f)
2001: {
2002: if (f->next) (f->next)->prev = f->prev; else last_file = f->prev;
2003: if (f->prev) (f->prev)->next = f->next;
2004: pari_kill_file(f);
2005: }
2006:
2007: pariFILE *
2008: pari_fopen(char *s, char *mode)
2009: {
2010: FILE *f = fopen(s, mode);
2011: if (!f) err(talker, "could not open requested file %s", s);
2012: if (DEBUGFILES)
2013: fprintferr("I/O: opening file %s (mode %s)\n", s, mode);
2014: return newfile(f,s,0);
2015: }
2016:
2017: void
2018: pari_unlink(char *s)
2019: {
2020: if (unlink(s)) err(warner, "I/O: can\'t remove file %s", s);
2021: else if (DEBUGFILES)
2022: fprintferr("I/O: removed file %s\n", s);
2023: }
2024:
2025: /* Remove one INFILE from the stack. Reset infile (to the most recent infile)
2026: * Return -1, if we're trying to pop out stdin itself; 0 otherwise
2027: */
2028: int
2029: popinfile()
2030: {
2031: pariFILE *f;
2032:
2033: filtre(NULL, f_ENDFILE);
2034: for (f = last_file; f; f = f->prev)
2035: {
2036: if (f->type & mf_IN) break;
2037: err(warner, "I/O: leaked file descriptor (%d): %s",
2038: f->type, f->name);
2039: pari_fclose(f);
2040: }
2041: last_file = f; if (!last_file) return -1;
2042: pari_fclose(last_file);
2043: for (f = last_file; f; f = f->prev)
2044: if (f->type & mf_IN) { infile = f->file; return 0; }
2045: infile = stdin; return 0;
2046: }
2047:
2048: void
2049: killallfiles(int check)
2050: {
2051: if (check) popinfile(); /* look for leaks */
2052: while (last_file)
2053: {
2054: pariFILE *f = last_file->prev;
2055: pari_kill_file(last_file);
2056: last_file = f;
2057: }
2058: infile = stdin;
2059: }
2060:
2061: pariFILE *
2062: try_pipe(char *cmd, int flag)
2063: {
2064: #ifndef HAVE_PIPES
2065: err(archer); return NULL;
2066: #else
2067: FILE *file;
2068: char *f;
2069:
2070: # ifdef __EMX__
2071: if (_osmode == DOS_MODE) /* no pipes under DOS */
2072: {
2073: char *s;
2074: f = pari_unique_filename("pipe");
2075: s = gpmalloc(strlen(cmd)+strlen(f)+4);
2076: sprintf(s,"%s > %s",cmd,f);
2077: if (system(s)) file = NULL;
2078: else
2079: {
2080: file = (FILE *) fopen(f,"r");
2081: flag |= mf_FALSE;
2082: }
2083: free(s);
2084: }
2085: else
2086: # endif
2087: {
2088: file = (FILE *) popen(cmd,"r");
2089: f = "";
2090: }
2091: if (!file) err(talker,"%s failed !",cmd);
2092: return newfile(file, f, mf_PIPE|flag);
2093: #endif
2094: }
2095: /*******************************************************************/
2096: /** **/
2097: /** GP STANDARD INPUT AND OUTPUT **/
2098: /** **/
2099: /*******************************************************************/
2100: static char *last_filename = NULL;
2101: static char **dir_list = NULL;
2102:
2103: /* expand tildes in filenames, return a malloc'ed buffer */
2104: static char *
2105: _expand_tilde(char *s)
2106: {
2107: #if !defined(UNIX) && !defined(__EMX__)
2108: return pari_strdup(s);
2109: #else
2110: struct passwd *p;
2111: char *u;
2112: int len;
2113:
2114: if (*s != '~') return pari_strdup(s);
2115: s++; u = s; /* skip ~ */
2116: if (!*s || *s == '/') p = getpwuid(geteuid());
2117: else
2118: {
2119: char *tmp;
2120: while (*u && *u != '/') u++;
2121: len = u-s;
2122: tmp = strncpy(gpmalloc(len+1),s,len);
2123: tmp[len] = 0;
2124: p = getpwnam(tmp); free(tmp);
2125: }
2126: if (!p) err(talker2,"unknown user ",s,s-1);
2127: s = gpmalloc(strlen(p->pw_dir) + strlen(u) + 1);
2128: sprintf(s,"%s%s",p->pw_dir,u); return s;
2129: #endif
2130: }
2131:
2132: /* expand environment variables in str, return a malloc'ed buffer
2133: * assume no \ remain */
2134: static char *
2135: _expand_env(char *str)
2136: {
2137: #ifdef WINCE
2138: return str;
2139: #elif defined(macintosh)
2140: return s;
2141: #else
2142: long i, l, len = 0, xlen = 16, xnum = 0;
2143: char *s = str, *s0 = s, *env;
2144: char **x = (char **)gpmalloc(xlen * sizeof(char*));
2145:
2146: while (*s)
2147: {
2148: if (*s != '$') { s++; continue; }
2149: l = s - s0;
2150: if (l)
2151: {
2152: s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0;
2153: x[xnum++] = s0; len += l;
2154: }
2155: if (xnum > xlen - 3) /* need room for possibly two more elts */
2156: {
2157: long xnew = xlen << 1;
2158: x = (char **)gprealloc((void*)x, xlen * sizeof(char*),
2159: xnew * sizeof(char*));
2160: xlen = xnew;
2161: }
2162:
2163: s0 = ++s; /* skip $ */
2164: while (is_keyword_char(*s)) s++;
2165: l = s - s0;
2166: env = strncpy(gpmalloc(l+1), s0, l); env[l] = 0;
2167: s0 = getenv(env);
2168: if (!s0)
2169: {
2170: err(warner,"undefined environment variable: %s",env);
2171: s0 = "";
2172: }
2173: l = strlen(s0);
2174: if (l)
2175: {
2176: s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0;
2177: x[xnum++] = s0; len += l;
2178: }
2179: free(env); s0 = s;
2180: }
2181: l = s - s0;
2182: if (l)
2183: {
2184: s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0;
2185: x[xnum++] = s0; len += l;
2186: }
2187:
2188: s = gpmalloc(len+1); *s = 0;
2189: for (i = 0; i < xnum; i++) { (void)strcat(s, x[i]); free(x[i]); }
2190: free(str); free(x); return s;
2191: #endif
2192: }
2193:
2194: char *
2195: expand_tilde(char *s)
2196: {
2197: return _expand_env(_expand_tilde(s));
2198: }
2199:
2200: #if defined __EMX__ || defined _WIN32
2201: # define PATH_SEPARATOR ';'
2202: #else
2203: # define PATH_SEPARATOR ':'
2204: #endif
2205:
2206: void
2207: gp_expand_path(char *v)
2208: {
2209: char **path, **old, *s;
2210: int i, n = 0;
2211:
2212: v = pari_strdup(v);
2213: for (s=v; *s; s++)
2214: if (*s == PATH_SEPARATOR) { *s = 0; n++; }
2215: path = (char**) gpmalloc((n + 2)*sizeof(char *));
2216:
2217: for (s=v, i=0; i<=n; i++)
2218: {
2219: char *end = s + strlen(s), *f = end;
2220: while (f > s && *--f == '/') *f = 0;
2221: path[i] = expand_tilde(s);
2222: s = end + 1; /* next path component */
2223: }
2224: path[i] = NULL; old = dir_list; dir_list = path;
2225: if (old)
2226: {
2227: for (path=old; *path; path++) free(*path);
2228: free(old);
2229: }
2230: }
2231:
2232: /* name is a malloc'ed (existing) filename. Accept it (unzip if needed). */
2233: static FILE *
2234: accept_file(char *name, FILE *file)
2235: {
2236: if (! last_file)
2237: { /* empty file stack, record this name */
2238: if (last_filename) free(last_filename);
2239: last_filename = pari_strdup(name);
2240: }
2241: #ifdef ZCAT
2242: {
2243: long l = strlen(name);
2244: char *end = name + l-1;
2245:
2246: if (l > 2 && (!strncmp(end-1,".Z",2)
2247: #ifdef GNUZCAT
2248: || !strncmp(end-2,".gz",3)
2249: #endif
2250: ))
2251: { /* compressed file (compress or gzip) */
2252: char *cmd = gpmalloc(strlen(ZCAT) + l + 2);
2253: sprintf(cmd,"%s %s",ZCAT,name);
2254: fclose(file); infile = try_pipe(cmd, mf_IN)->file;
2255: free(cmd); return infile;
2256: }
2257: }
2258: #endif
2259: return infile = newfile(file, name, mf_IN)->file;
2260: }
2261:
2262: /* If a file called "name" exists (possibly after appending ".gp")
2263: * record it in the file_stack (as a pipe if compressed).
2264: * name is malloc'ed, we free it before returning
2265: */
2266: static FILE *
2267: try_name(char *name)
2268: {
2269: FILE *file = fopen(name, "r");
2270: if (file) return accept_file(name,file);
2271:
2272: { /* try appending ".gp" to name */
2273: char *s = gpmalloc(strlen(name)+4);
2274: sprintf(s, "%s.gp", name);
2275: file = fopen(s, "r");
2276: if (file) file = accept_file(s,file);
2277: free(s);
2278: }
2279: free(name); return file;
2280: }
2281:
2282: /* If name = "", re-read last file */
2283: void
2284: switchin(char *name0)
2285: {
2286: char *s, *name;
2287:
2288: if (*name0)
2289: name = expand_tilde(name0);
2290: else
2291: {
2292: if (last_filename == NULL)
2293: err(talker,"You never gave me anything to read!");
2294: name0 = last_filename;
2295: name = pari_strdup(name0);
2296: }
2297: /* if name contains '/', don't use dir_list */
2298: s=name; while (*s && *s != '/') s++;
2299: if (*s) { if (try_name(name)) return; }
2300: else
2301: {
2302: char **tmp = dir_list;
2303: for ( ; *tmp; tmp++)
2304: { /* make room for '/' and '\0', try_name frees it */
2305: s = gpmalloc(2 + strlen(*tmp) + strlen(name));
2306: sprintf(s,"%s/%s",*tmp,name);
2307: if (try_name(s)) return;
2308: }
2309: }
2310: err(openfiler,"input",name0);
2311: }
2312:
2313: void
2314: switchout(char *name)
2315: {
2316: if (name)
2317: {
2318: FILE *f = fopen(name, "a");
2319: if (!f) err(openfiler,"output",name);
2320: pari_outfile = f;
2321: }
2322: else if (pari_outfile != stdout)
2323: {
2324: fclose(pari_outfile);
2325: pari_outfile = stdout;
2326: }
2327: }
2328:
2329: /*******************************************************************/
2330: /** **/
2331: /** TEMPORARY FILES **/
2332: /** **/
2333: /*******************************************************************/
2334: #ifdef __WIN32
2335: # include <process.h> /* for getpid */
2336: #endif
2337:
2338: #ifndef R_OK
2339: # define R_OK 4
2340: # define W_OK 2
2341: # define X_OK 1
2342: # define F_OK 0
2343: #endif
2344:
2345: #ifdef __EMX__
2346: #include <io.h>
2347: static int
2348: unix_shell()
2349: {
2350: char *base, *sh = getenv ("EMXSHELL");
2351: if (sh == NULL) sh = getenv ("COMSPEC");
2352: if (sh == NULL) return 0;
2353: base = _getname (sh);
2354: if (stricmp (base, "cmd.exe") == 0 || stricmp (base, "4os2.exe") == 0
2355: || stricmp (base, "command.com") == 0
2356: || stricmp (base, "4dos.com") == 0)
2357: return 0;
2358: return 1;
2359: }
2360: #endif
2361:
2362: /* check if s has rwx permissions for us */
2363: static int
2364: pari_is_rwx(char *s)
2365: {
2366: #if defined(UNIX) || defined (__EMX__) /* TODO: ok for macintosh? */
2367: return access(s, R_OK | W_OK | X_OK) == 0;
2368: #else
2369: return 1;
2370: #endif
2371: }
2372:
2373: static int
2374: pari_file_exists(char *s)
2375: {
2376: #if defined(UNIX) || defined (__EMX__)
2377: return access(s, F_OK) == 0;
2378: #else
2379: return 0;
2380: #endif
2381: }
2382:
2383: #ifndef macintosh
2384: char *
2385: env_ok(char *s)
2386: {
2387: #ifdef WINCE
2388: return NULL;
2389: #else
2390: char *t = getenv(s);
2391: if (t && pari_is_rwx(t) == 0)
2392: {
2393: err(warner,"%s is set (%s), but is not writeable", s,t);
2394: t = NULL;
2395: }
2396: return t;
2397: #endif
2398: }
2399: #endif
2400:
2401: static char*
2402: pari_tmp_dir()
2403: {
2404: #ifdef WINCE
2405: char *s;
2406:
2407: s = env_ok("TEMP"); if (s) return s;
2408: return "\\temp";
2409: #else
2410: #ifndef macintosh
2411: char *s;
2412:
2413: s = env_ok("GPTMPDIR"); if (s) return s;
2414: s = env_ok("TMPDIR"); if (s) return s;
2415: #ifdef __EMX__
2416: s = env_ok("TMP"); if (s) return s;
2417: s = env_ok("TEMP"); if (s) return s;
2418: #endif
2419: #endif
2420: #if defined(UNIX) || defined(__EMX__)
2421: if (pari_is_rwx("/var/tmp")) return "/var/tmp";
2422: if (pari_is_rwx("/tmp")) return "/tmp";
2423: #endif
2424: return ".";
2425: #endif
2426: }
2427:
2428: /* Return a "unique filename" built from the string s, possibly the user id
2429: * and the process pid (on Unix systems). A "temporary" directory name is
2430: * prepended. The name returned is stored in a static buffer (gpmalloc'ed
2431: * permanently). It is DOS-safe (s truncated to 8 chars)
2432: */
2433: char*
2434: pari_unique_filename(char *s)
2435: {
2436: static char *buf, *pre, *post = NULL;
2437:
2438: if (!post || !s) /* initialize */
2439: {
2440: char suf[64];
2441: int lpre, lsuf;
2442:
2443: if (post) free(post);
2444: pre = pari_tmp_dir();
2445: #ifdef UNIX
2446: sprintf(suf,".%ld.%ld", (long)getuid(), (long)getpid());
2447: #else
2448: sprintf(suf,".gpa");
2449: #endif
2450: lsuf = strlen(suf);
2451: lpre = strlen(pre);
2452: /* room for suffix + '\0 + prefix + '/' + s + suffix '\0' */
2453: /* ^- post ^- buf ^- pre */
2454: post = (char*) gpmalloc(lpre + 1 + 8 + 2*(lsuf + 1));
2455: strcpy(post, suf);
2456: buf = post + lsuf; *buf = 0; buf++;
2457: strcpy(buf, pre);
2458: if (buf[lpre-1] != '/') { (void)strcat(buf, "/"); lpre++; }
2459: #ifdef __EMX__
2460: if (!unix_shell())
2461: for (pre=buf; *pre; pre++)
2462: if (*pre == '/') *pre = '\\';
2463: #endif
2464: #ifdef WINCE
2465: for (pre=buf; *pre; pre++)
2466: if (*pre == '/') *pre = '\\';
2467: #endif
2468: pre = buf + lpre; if (!s) return s;
2469: }
2470: sprintf(pre, "%.8s%s", s, post);
2471: if (pari_file_exists(buf))
2472: {
2473: char c, *end = buf + strlen(buf) - 1;
2474: for (c='a'; c<='z'; c++)
2475: {
2476: *end = c;
2477: if (! pari_file_exists(buf)) break;
2478: }
2479: if (c > 'z')
2480: err(talker,"couldn't find a suitable name for a tempfile (%s)",s);
2481: }
2482: return buf;
2483: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>