[BACK]Return to es.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari-2.2 / src / language

Annotation of OpenXM_contrib/pari-2.2/src/language/es.c, Revision 1.2

1.2     ! noro        1: /* $Id: es.c,v 1.91 2002/09/10 18:40:48 karim Exp $
1.1       noro        2:
                      3: Copyright (C) 2000  The PARI group.
                      4:
                      5: This file is part of the PARI/GP package.
                      6:
                      7: PARI/GP is free software; you can redistribute it and/or modify it under the
                      8: terms of the GNU General Public License as published by the Free Software
                      9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
                     10: ANY WARRANTY WHATSOEVER.
                     11:
                     12: Check the License for details. You should have received a copy of it, along
                     13: with the package; see the file 'COPYING'. If not, write to the Free Software
                     14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
                     15:
                     16: /*******************************************************************/
                     17: /**                                                               **/
                     18: /**                 INPUT/OUTPUT SUBROUTINES                      **/
                     19: /**                                                               **/
                     20: /*******************************************************************/
                     21: #include "pari.h"
                     22: #include "anal.h"
                     23: extern GEN confrac(GEN x); /* should be static here, but use hiremainder */
                     24: extern GEN convi(GEN x);
                     25: char * type_name(long t);
                     26:
                     27: void
1.2     ! noro       28: hit_return(void)
1.1       noro       29: {
                     30:   int c;
1.2     ! noro       31:   if (GP_DATA && (GP_DATA->flags & (EMACS|TEXMACS))) return;
1.1       noro       32:   pariputs("---- (type RETURN to continue) ----");
                     33:   /* if called from a readline callback, may be in a funny TTY mode,  */
                     34:   do c = fgetc(stdin); while (c >= 0 && c != '\n' && c != '\r' && c != ' ');
                     35:   pariputc('\n');
                     36: }
                     37:
                     38: /********************************************************************/
                     39: /**                                                                **/
                     40: /**                        INPUT FILTER                            **/
                     41: /**                                                                **/
                     42: /********************************************************************/
                     43: #define ONE_LINE_COMMENT   2
                     44: #define MULTI_LINE_COMMENT 1
1.2     ! noro       45: /* Filter F->s into F->t */
1.1       noro       46: char *
1.2     ! noro       47: filtre0(filtre_t *F)
1.1       noro       48: {
1.2     ! noro       49:   const int downcase = F->downcase;
        !            50:   char c, *s = F->s, *t;
1.1       noro       51:
1.2     ! noro       52:   if (!F->t) F->t = gpmalloc(strlen(s)+1);
        !            53:   t = F->t;
        !            54:
        !            55:   if (F->more_input == 1) F->more_input = 0;
        !            56:
        !            57:   if (! F->in_comment)
1.1       noro       58:   {
1.2     ! noro       59:     while (isspace((int)*s)) s++; /* Skip space */
        !            60:     if (*s == LBRACE) { s++; F->more_input = 2; F->wait_for_brace = 1; }
1.1       noro       61:   }
                     62:
                     63:   while ((c = *s++))
                     64:   {
1.2     ! noro       65:     if (F->in_string)
1.1       noro       66:     {
1.2     ! noro       67:       *t++ = c; /* copy verbatim */
        !            68:       switch(c)
        !            69:       {
        !            70:         case '\\': /* in strings, \ is the escape character */
        !            71:           if (*s) *t++ = *s++;
        !            72:           break;
        !            73:
        !            74:         case '"': F->in_string = 0;
        !            75:       }
        !            76:       continue;
        !            77:     }
        !            78:
        !            79:     if (F->in_comment)
        !            80:     { /* look for comment's end */
        !            81:       if (F->in_comment == MULTI_LINE_COMMENT)
1.1       noro       82:       {
                     83:         while (c != '*' || *s != '/')
                     84:         {
1.2     ! noro       85:           if (!*s)
        !            86:           {
        !            87:             if (!F->more_input) F->more_input = 1;
        !            88:             goto END;
        !            89:           }
1.1       noro       90:           c = *s++;
                     91:         }
                     92:         s++;
                     93:       }
                     94:       else
1.2     ! noro       95:         while (c != '\n' && *s) c = *s++;
        !            96:       F->in_comment = 0;
        !            97:       continue;
1.1       noro       98:     }
1.2     ! noro       99:
        !           100:     /* weed out comments and spaces */
        !           101:     if (c=='\\' && *s=='\\') { F->in_comment = ONE_LINE_COMMENT; continue; }
        !           102:     if (isspace((int)c)) continue;
        !           103:     *t++ = downcase? tolower(c): c;
        !           104:
1.1       noro      105:     switch(c)
                    106:     {
                    107:       case '/':
1.2     ! noro      108:         if (*s == '*') { t--; F->in_comment = MULTI_LINE_COMMENT; }
        !           109:         break;
1.1       noro      110:
                    111:       case '\\':
1.2     ! noro      112:         if (!*s) {
        !           113:           if (t[-2] == '?') break; /* '?\' */
        !           114:           t--;
        !           115:           if (!F->more_input) F->more_input = 1;
        !           116:           goto END;
        !           117:         }
        !           118:         if (*s == '\n') {
        !           119:           if (t[-2] == '?') break; /* '?\' */
        !           120:           t--; s++;
        !           121:           if (!*s)
        !           122:           {
        !           123:             if (!F->more_input) F->more_input = 1;
        !           124:             goto END;
        !           125:           }
        !           126:         } /* skip \<CR> */
        !           127:         break;
1.1       noro      128:
1.2     ! noro      129:       case '"': F->in_string = 1;
1.1       noro      130:     }
                    131:   }
1.2     ! noro      132:
        !           133:   if (t != F->t) /* non empty input */
        !           134:   {
        !           135:     c = t[-1]; /* = last input char */
        !           136:     if (c == '=')                 F->more_input = 2;
        !           137:     else if (! F->wait_for_brace) F->more_input = 0;
        !           138:     else if (c == RBRACE)       { F->more_input = 0; t--; }
        !           139:   }
        !           140:
1.1       noro      141: END:
1.2     ! noro      142:   F->end = t; *t = 0; return F->t;
1.1       noro      143: }
                    144: #undef ONE_LINE_COMMENT
                    145: #undef MULTI_LINE_COMMENT
                    146:
1.2     ! noro      147: char *
        !           148: filtre(char *s, int downcase)
        !           149: {
        !           150:   filtre_t T;
        !           151:   T.s = s;    T.in_string = 0; T.more_input = 0;
        !           152:   T.t = NULL; T.in_comment= 0; T.wait_for_brace = 0;
        !           153:   T.downcase = downcase;
        !           154:   return filtre0(&T);
        !           155: }
        !           156:
1.1       noro      157: GEN
                    158: lisGEN(FILE *fi)
                    159: {
                    160:   long size = 512, n = size;
                    161:   char *buf = gpmalloc(n), *s = buf;
                    162:
                    163:   while (fgets(s, n, fi))
                    164:   {
                    165:     if (s[strlen(s)-1] == '\n')
                    166:     {
                    167:       GEN x = flisexpr(buf);
                    168:       free(buf); return x;
                    169:     }
1.2     ! noro      170:     buf = gprealloc(buf, size<<1);
1.1       noro      171:     s = buf + (size-1); n = size+1; size <<= 1;
                    172:   }
                    173: #if defined(UNIX) || defined(__EMX__)
                    174:   if (!feof(fi))
                    175: #endif
                    176:     err(talker, "failed read from file");
                    177:   return NULL;
                    178: }
                    179:
                    180: /********************************************************************/
                    181: /**                                                                **/
                    182: /**                  GENERAL PURPOSE PRINTING                      **/
                    183: /**                                                                **/
                    184: /********************************************************************/
                    185: PariOUT *pariOut, *pariErr;
                    186:
                    187: static void
                    188: normalOutC(char c)
                    189: {
                    190:   putc(c, pari_outfile);
                    191:   if (logfile) putc(c, logfile);
                    192: }
                    193: static void
                    194: normalOutS(char *s)
                    195: {
                    196:   fputs(s, pari_outfile);
                    197:   if (logfile) { fputs(s, logfile); }
                    198: }
                    199: static void
                    200: normalOutF(void)
                    201: {
                    202:   fflush(pari_outfile);
                    203:   if (logfile) fflush(logfile);
                    204: }
                    205: PariOUT defaultOut = {normalOutC, normalOutS, normalOutF, NULL};
                    206:
                    207: static void
                    208: normalErrC(char c)
                    209: {
                    210:   putc(c, errfile);
                    211:   if (logfile) putc(c, logfile);
                    212: }
                    213: static void
                    214: normalErrS(char *s)
                    215: {
                    216:   fputs(s, errfile);
                    217:   if (logfile) fputs(s, logfile);
                    218: }
                    219: static void
                    220: normalErrF(void)
                    221: {
                    222:   fflush(errfile);
                    223:   if (logfile) fflush(logfile);
                    224: }
                    225: PariOUT defaultErr = {normalErrC, normalErrS, normalErrF, NULL};
                    226:
                    227: /**                         GENERIC PRINTING                       **/
                    228: void
                    229: initout(int initerr)
                    230: {
                    231:   infile = stdin; pari_outfile = stdout; errfile = stderr;
                    232:   pariOut = &defaultOut;
                    233:   if (initerr) pariErr = &defaultErr;
                    234: }
                    235:
                    236: void
                    237: pariputc(char c) { pariOut->putch(c); }
                    238:
                    239: void
                    240: pariputs(char *s) { pariOut->puts(s); }
                    241:
                    242: void
                    243: pariflush(void) { pariOut->flush(); }
                    244:
                    245: void
                    246: flusherr(void) { pariErr->flush(); }
                    247:
1.2     ! noro      248: /* format is standard printf format, except %Z is a GEN */
1.1       noro      249: void
                    250: vpariputs(char* format, va_list args)
                    251: {
1.2     ! noro      252:   long nb = 0, bufsize = 1023;
        !           253:   char *buf, *str, *s, *f = format;
        !           254:
        !           255:   /* replace each %Z (2 chars) by braced address format (8 chars) */
        !           256:   s = str = gpmalloc(strlen(format)*4 + 1);
1.1       noro      257:   while (*f)
                    258:   {
                    259:     if (*f != '%') *s++ = *f++;
                    260:     else
                    261:     {
                    262:       if (f[1] != 'Z') { *s++ = *f++; *s++ = *f++; }
                    263:       else
                    264:       {
                    265:         strcpy(s,"\003%020ld\003"); /* brace with unprobable characters */
                    266:         nb++; s += 8; f += 2; /* skip %Z */
                    267:       }
                    268:     }
                    269:   }
1.2     ! noro      270:   *s = 0;
        !           271: #ifdef HAS_VSNPRINTF
        !           272:   for(;;)
        !           273:   {
        !           274:     int l;
        !           275:     buf = gpmalloc(bufsize);
        !           276:     l = vsnprintf(buf,bufsize,str,args);
        !           277:     if (l < 0) l = bufsize<<1; else if (l < bufsize) break;
        !           278:     free(buf); bufsize++;
        !           279:   }
        !           280:   buf[bufsize] = 0; /* just in case */
        !           281: #else
        !           282:   buf = gpmalloc(bufsize);
        !           283:   (void)vsprintf(buf,str,args); /* pray it does fit */
        !           284: #endif
        !           285:   f = s = buf;
1.1       noro      286:   if (nb)
1.2     ! noro      287:     while ( *f )
        !           288:     {
1.1       noro      289:       if (*f == '\003' && f[21] == '\003')
                    290:       {
                    291:         *f = 0; f[21] = 0; /* remove the bracing chars */
                    292:         pariOut->puts(s); bruteall((GEN)atol(f+1),'g',-1,1);
                    293:         f += 22; s = f;
1.2     ! noro      294:         if (!--nb) break;
1.1       noro      295:       }
1.2     ! noro      296:       else
        !           297:         f++;
        !           298:     }
        !           299:   pariOut->puts(s); free(buf); free(str);
1.1       noro      300: }
                    301:
                    302: void
                    303: pariputsf(char *format, ...)
                    304: {
                    305:   va_list args;
                    306:
                    307:   va_start(args,format); vpariputs(format,args);
                    308:   va_end(args);
                    309: }
                    310:
                    311: /* start printing in "color" c */
                    312: /* terminal has to support ANSI color escape sequences */
                    313: #ifdef ESC
                    314: #  undef ESC
                    315: #endif
                    316: #define ESC  (0x1f & '[') /* C-[ = escape */
                    317:
                    318: void
                    319: term_color(int c)
                    320: {
                    321:   pariputs(term_get_color(c));
                    322: }
                    323:
                    324: void
                    325: decode_color(int n, int *c)
                    326: {
                    327:   c[1] = n & 0xf; n >>= 4; /* foreground */
                    328:   c[2] = n & 0xf; n >>= 4; /* background */
                    329:   c[0] = n & 0xf; /* attribute */
                    330: }
                    331:
                    332: char *
                    333: term_get_color(int n)
                    334: {
                    335:   static char s[16];
                    336:   int c[3], a;
                    337:
                    338:   if (disable_color) return "";
                    339:   if (n == c_NONE || (a = gp_colors[n]) == c_NONE)
                    340:     sprintf(s, "%c[0m",ESC); /* reset */
                    341:   else
                    342:   {
                    343:     decode_color(a,c);
                    344:     if (c[1]<8) c[1] += 30; else c[1] += 82;
                    345:     if (a & (1<<12)) /* transparent background */
                    346:       sprintf(s, "%c[%d;%dm", ESC, c[0], c[1]);
                    347:     else
                    348:     {
                    349:       if (c[2]<8) c[2] += 40; else c[2] += 92;
                    350:       sprintf(s, "%c[%d;%d;%dm", ESC, c[0], c[1], c[2]);
                    351:     }
                    352:   }
                    353:   return s;
                    354: }
                    355:
                    356: /********************************************************************/
                    357: /**                                                                **/
                    358: /**                  PRINTING BASED ON SCREEN WIDTH                **/
                    359: /**                                                                **/
                    360: /********************************************************************/
                    361: static int col_index, lin_index, max_width, max_lin;
                    362: #ifdef HAS_TIOCGWINSZ
                    363: #  include <sys/termios.h>
                    364: #  include <sys/ioctl.h>
                    365: #endif
                    366:
                    367: static int
1.2     ! noro      368: term_width_intern(void)
1.1       noro      369: {
                    370: #ifdef HAS_TIOCGWINSZ
                    371:   {
                    372:     struct winsize s;
1.2     ! noro      373:     if (!(GP_DATA && (GP_DATA->flags & (EMACS|TEXMACS)))
        !           374:      && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_col;
1.1       noro      375:   }
                    376: #endif
                    377: #ifdef UNIX
                    378:   {
                    379:     char *str;
                    380:     if ((str = getenv("COLUMNS"))) return atoi(str);
                    381:   }
                    382: #endif
                    383: #ifdef __EMX__
                    384:   {
                    385:     int scrsize[2];
                    386:     _scrsize(scrsize); return scrsize[0];
                    387:   }
                    388: #endif
                    389:   return 0;
                    390: }
                    391:
                    392: static int
1.2     ! noro      393: term_height_intern(void)
1.1       noro      394: {
                    395: #ifdef HAS_TIOCGWINSZ
                    396:   {
                    397:     struct winsize s;
1.2     ! noro      398:     if (!(GP_DATA && (GP_DATA->flags & (EMACS|TEXMACS)))
        !           399:      && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_row;
1.1       noro      400:   }
                    401: #endif
                    402: #ifdef UNIX
                    403:   {
                    404:     char *str;
                    405:     if ((str = getenv("LINES"))) return atoi(str);
                    406:   }
                    407: #endif
                    408: #ifdef __EMX__
                    409:   {
                    410:     int scrsize[2];
                    411:     _scrsize(scrsize); return scrsize[1];
                    412:   }
                    413: #endif
                    414:   return 0;
                    415: }
                    416:
                    417: #define DFT_TERM_WIDTH  80
                    418: #define DFT_TERM_HEIGHT 20
                    419:
                    420: int
1.2     ! noro      421: term_width(void)
1.1       noro      422: {
                    423:   int n = term_width_intern();
                    424:   return (n>1)? n: DFT_TERM_WIDTH;
                    425: }
                    426:
                    427: int
1.2     ! noro      428: term_height(void)
1.1       noro      429: {
                    430:   int n = term_height_intern();
                    431:   return (n>1)? n: DFT_TERM_HEIGHT;
                    432: }
                    433:
                    434: #define MAX_WIDTH 76
                    435: /* output string wrapped after MAX_WIDTH characters (for gp -test) */
                    436: static void
                    437: putc80(char c)
                    438: {
                    439:   if (c == '\n') col_index = -1;
                    440:   else if (col_index == MAX_WIDTH)
                    441:     { putc('\n',pari_outfile); col_index = 0; }
                    442:   putc(c, pari_outfile); col_index++;
                    443: }
                    444: #undef MAX_WIDTH
                    445: static void
                    446: puts80(char *s)
                    447: {
                    448:   while (*s) putc80(*s++);
                    449: }
                    450: PariOUT pariOut80= {putc80, puts80, normalOutF, NULL};
                    451:
1.2     ! noro      452: static void
1.1       noro      453: init80(long n)
                    454: {
                    455:   col_index = n; pariOut = &pariOut80;
                    456: }
                    457:
                    458: /* output stopped after max_line have been printed (for default(lines,)) */
                    459: static void
                    460: putc_lim_lines(char c)
                    461: {
                    462:   if (lin_index > max_lin) return;
                    463:   if (lin_index == max_lin)
                    464:     if (c == '\n' || col_index >= max_width-5)
                    465:     {
                    466:       normalOutS(term_get_color(c_ERR));
                    467:       normalOutS("[+++]"); lin_index++; return;
                    468:     }
                    469:   if (c == '\n')
                    470:   {
                    471:     col_index = -1; lin_index++;
                    472:   }
                    473:   else if (col_index == max_width)
                    474:   {
                    475:     col_index =  0; lin_index++;
                    476:   }
                    477:   col_index++; normalOutC(c);
                    478: }
                    479: static void
                    480: puts_lim_lines(char *s)
                    481: {
                    482:   long i,len;
                    483:   if (lin_index > max_lin) return;
                    484:   len = strlen(s);
                    485:   for(i=0; i<len; i++) putc_lim_lines(s[i]);
                    486: }
                    487:
                    488: PariOUT pariOut_lim_lines= {putc_lim_lines, puts_lim_lines, normalOutF, NULL};
                    489:
1.2     ! noro      490: /* n = length of prefix already printed (print up to max lines) */
1.1       noro      491: void
1.2     ! noro      492: lim_lines_output(GEN z, pariout_t *fmt, long n, long max)
1.1       noro      493: {
1.2     ! noro      494:   PariOUT *tmp = pariOut;
1.1       noro      495:   max_width = term_width();
                    496:   max_lin = max;
1.2     ! noro      497:   lin_index = 1;
        !           498:   col_index = n;
1.1       noro      499:   pariOut = &pariOut_lim_lines;
1.2     ! noro      500:   gen_output(z, fmt);
        !           501:   pariOut = tmp;
1.1       noro      502: }
                    503:
                    504: #define is_blank_or_null(c) (!(c) || is_blank(c))
                    505: #define is_blank(c) ((c) == ' ' || (c) == '\n')
                    506: #define MAX_WORD_LEN 255
                    507:
                    508: static void
                    509: _new_line(char *prefix)
                    510: {
                    511:   pariputc('\n'); if (prefix) pariputs(prefix);
                    512: }
                    513:
                    514: static long
                    515: strlen_real(char *s)
                    516: {
                    517:   char *t = s, *t0;
                    518:   long ctrl_len = 0;
                    519:   while (*t)
                    520:   {
                    521:     t0 = t;
                    522:     if (*t++ == ESC && *t++ == '[')
                    523:     {
                    524:       while (*t && *t++ != 'm') /* empty */;
                    525:       ctrl_len += t - t0;
                    526:     }
                    527:   }
                    528:   return strlen(s) - ctrl_len;
                    529: }
                    530:
                    531: /* output: <prefix>< s wrapped at EOL >
                    532:  *         <prefix>< ... > <str>
                    533:  *                         ^---  (no \n at the end)
                    534:  * If str is NULL, omit the arrow, assume the text doesn't contain ASCII
                    535:  * escape sequences and end the text with '\n'. If prefix is NULL, use ""
                    536:  */
                    537: void
                    538: print_prefixed_text(char *s, char *prefix, char *str)
                    539: {
                    540:   long prelen = prefix? strlen_real(prefix): 0;
                    541:   long oldwlen=0, linelen=prelen, w = term_width();
                    542:   char word[MAX_WORD_LEN+1], oldword[MAX_WORD_LEN+1], *u=word;
                    543:
                    544:   if (prefix) pariputs(prefix);
                    545:   oldword[0]='\0';
                    546:   while ((*u++ = *s++))
                    547:   {
                    548:     if (is_blank_or_null(*s))
                    549:     {
                    550:       while (is_blank(*s)) s++;
                    551:       linelen += oldwlen;
                    552:       if (linelen >= w)
                    553:       {
                    554:         _new_line(prefix);
                    555:         linelen = oldwlen + prelen;
                    556:       }
                    557:       pariputs(oldword); *u++ = ' '; *u = 0;
                    558:       /* u-word = strlen(word) */
                    559:       oldwlen = str ? strlen_real(word): u - word;
                    560:       if (*s) { strcpy(oldword,word);  u = word; }
                    561:     }
                    562:   }
                    563:   if (!str)
                    564:   { /* add final period if needed */
                    565:     u--; while (u > word && is_blank_or_null(*u)) u--;
                    566:     if (u >= word && isalnum((int)*u)) { u[1] = '.'; u[2] = 0; }
                    567:   }
                    568:   else
                    569:     { *(u-2) = 0; oldwlen--; }
                    570:   linelen += oldwlen;
                    571:   if (linelen >= w) { _new_line(prefix); linelen = prelen + oldwlen; }
                    572:   pariputs(word);
                    573:   if (str)
                    574:   {
                    575:     long i,len = strlen_real(str);
                    576:     int space = (*str == ' ' && str[1]);
                    577:     if (linelen + len >= w)
                    578:     {
                    579:       _new_line(prefix); linelen = prelen;
                    580:       if (space) { str++; len--; space = 0; }
                    581:     }
                    582:     term_color(c_OUTPUT);
                    583:     pariputs(str); if (!len || str[len-1] != '\n') pariputc('\n');
                    584:     if (space) { linelen++; len--; }
                    585:     term_color(c_ERR);
                    586:     for (i=0; i<linelen; i++) pariputc(' ');
                    587:     pariputc('^');
                    588:     for (i=0; i<len; i++) pariputc('-');
                    589:   }
                    590:   else
                    591:     pariputc('\n');
                    592: }
                    593:
                    594: /********************************************************************/
                    595: /**                                                                **/
                    596: /**                    GEN <---> CHARACTER STRINGS                 **/
                    597: /**                                                                **/
                    598: /********************************************************************/
                    599:
                    600: typedef struct outString {
                    601:   char *string;
                    602:   ulong len,size;
                    603: } outString;
                    604: static outString *OutStr, *ErrStr = NULL;
                    605:
                    606: #define STEPSIZE 1024
                    607: #define check_output_length(str,l) { \
                    608:   const ulong s = str->size; \
                    609:   if (str->len + l >= s) { \
1.2     ! noro      610:     str->size = s + l + STEPSIZE; \
        !           611:     str->string = gprealloc(str->string, str->size); \
1.1       noro      612:   } \
                    613: }
                    614:
                    615: #define str_putc(str, c) { \
                    616:   check_output_length(str,1); \
                    617:   str->string[str->len++] = c; \
                    618: }
                    619: static void
                    620: outstr_putc(char c) { str_putc(OutStr, c); }
                    621: static void
                    622: errstr_putc(char c) { str_putc(ErrStr, c); }
                    623:
                    624: #define str_puts(str, s) {\
                    625:   const long len=strlen(s); \
                    626:   check_output_length(str,len); \
                    627:   strcpy(str->string+str->len,s); \
                    628:   str->len += len; \
                    629: }
                    630: static void
                    631: outstr_puts(char *s) { str_puts(OutStr, s); }
                    632: static void
                    633: errstr_puts(char *s) { str_puts(ErrStr, s); }
                    634:
                    635: static void
                    636: outstr_flush(void) { /* empty */ }
                    637: PariOUT pariOut2Str = {outstr_putc, outstr_puts, outstr_flush, NULL};
                    638: PariOUT pariErr2Str = {errstr_putc, errstr_puts, outstr_flush, NULL};
                    639: #undef STEPSIZE
                    640:
                    641: char *
                    642: pari_strdup(char *s)
                    643: {
                    644:   int n = strlen(s)+1;
                    645:   char *t = gpmalloc(n);
                    646:   memcpy(t,s,n); return t;
                    647: }
                    648:
                    649: /* returns a malloc-ed string, which should be freed after usage */
                    650: char *
1.2     ! noro      651: GENtostr0(GEN x, pariout_t *T, void (*do_out)(GEN, pariout_t*))
1.1       noro      652: {
                    653:   PariOUT *tmp = pariOut;
                    654:   outString *tmps = OutStr, newStr;
                    655:
                    656:   if (typ(x) == t_STR) return pari_strdup(GSTR(x));
1.2     ! noro      657:   pariOut = &pariOut2Str;
        !           658:   newStr.len   = 0;
        !           659:   newStr.size  = 0;
        !           660:   newStr.string= NULL; OutStr = &newStr;
        !           661:   do_out(x, T);
        !           662:   OutStr->string[OutStr->len] = 0;
1.1       noro      663:
                    664:   pariOut = tmp; OutStr = tmps; return newStr.string;
                    665: }
                    666:
                    667: char *
1.2     ! noro      668: GENtostr(GEN x) { return GENtostr0(x, NULL, &gen_output); }
1.1       noro      669:
                    670: /********************************************************************/
                    671: /**                                                                **/
                    672: /**                         WRITE AN INTEGER                       **/
                    673: /**                                                                **/
                    674: /********************************************************************/
1.2     ! noro      675: #define putsigne_nosp(x) pariputc((x>0)? '+' : '-')
1.1       noro      676: #define putsigne(x) pariputs((x>0)? " + " : " - ")
1.2     ! noro      677: #define sp_sign_sp(T,x) ((T)->sp? putsigne(x): putsigne_nosp(x))
        !           678: #define sp(T) do { if ((T)->sp) pariputc(' '); } while(0);
        !           679: #define comma_sp(T)     ((T)->sp? pariputs(", "): pariputc(','))
1.1       noro      680:
                    681: static void
                    682: blancs(long nb) { while (nb-- > 0) pariputc(' '); }
                    683:
                    684: static void
                    685: zeros(long nb)  { while (nb-- > 0) pariputc('0'); }
                    686:
                    687: static long
                    688: coinit(long x)
                    689: {
                    690:   char cha[10], *p = cha + 9;
                    691:
                    692:   *p = 0;
                    693:   do { *--p = x%10 + '0'; x /= 10; } while (x);
                    694:   pariputs(p); return 9 - (p - cha);
                    695: }
                    696:
1.2     ! noro      697: /* as above, printing leading 0s, return # significant digits printed
        !           698:  * print at most dec significant digits */
1.1       noro      699: static long
1.2     ! noro      700: coinit2(long x, long dec)
1.1       noro      701: {
                    702:   char cha[10], *p = cha + 9;
                    703:   int i = 0;
                    704:
                    705:   for (*p = 0; p > cha; x /= 10) *--p = x%10 + '0';
                    706:   while (cha[i] == '0') i++;
1.2     ! noro      707:   i = 9-i; /* # significant digits to print */
        !           708:   if (i > dec) { i = dec; cha[dec] = 0; }
        !           709:   pariputs(cha); return i;
1.1       noro      710: }
                    711:
                    712: static void
                    713: comilieu(long x)
                    714: {
                    715:   char cha[10], *p = cha + 9;
                    716:
                    717:   for (*p = 0; p > cha; x /= 10) *--p = x%10 + '0';
                    718:   pariputs(cha);
                    719: }
                    720:
                    721: static void
                    722: cofin(long x, long decim)
                    723: {
                    724:   char cha[10], *p = cha + 9;
                    725:
                    726:   for (; p > cha; x /= 10) *--p = x%10 + '0';
                    727:   cha[decim] = 0; pariputs(cha);
                    728: }
                    729:
                    730: static long
                    731: nbdch(long l)
                    732: {
                    733:   if (l<100000)
                    734:   {
                    735:     if (l<10) return 1;
                    736:     if (l<100) return 2;
                    737:     if (l<1000) return 3;
                    738:     if (l<10000) return 4;
                    739:     return 5;
                    740:   }
                    741:   if (l<1000000) return 6;
                    742:   if (l<10000000) return 7;
                    743:   if (l<100000000) return 8;
                    744:   if (l<1000000000) return 9;
                    745:   return 10; /* not reached */
                    746: }
                    747:
1.2     ! noro      748: /* write int x > 0 */
        !           749: static void
        !           750: wr_intpos(GEN x)
        !           751: {
        !           752:   long *res = convi(x);
        !           753:   (void)coinit(*--res); while (*--res >= 0) comilieu(*res);
        !           754: }
        !           755:
        !           756: /* write int. T->fieldw: field width (pad with ' ') */
1.1       noro      757: static void
1.2     ! noro      758: wr_int(pariout_t *T, GEN x, int nosign)
1.1       noro      759: {
1.2     ! noro      760:   long *res,*re,i, sx = signe(x);
        !           761:   int minus;
1.1       noro      762:
1.2     ! noro      763:   if (!sx) { blancs(T->fieldw - 1); pariputc('0'); return; }
        !           764:   re = res = convi(x);
1.1       noro      765:   i = nbdch(*--re); while (*--re >= 0) i+=9;
1.2     ! noro      766:   minus = (sx < 0 && !nosign);
        !           767:   if (minus) i++;
        !           768:
        !           769:   blancs(T->fieldw - i);
        !           770:   if (minus) pariputc('-');
        !           771:   (void)coinit(*--res); while (*--res >= 0) comilieu(*res);
1.1       noro      772: }
                    773:
                    774: static void
1.2     ! noro      775: wr_vecsmall(pariout_t *T, GEN g)
1.1       noro      776: {
                    777:   long i,l;
1.2     ! noro      778:   pariputs("Vecsmall(["); l = lg(g);
1.1       noro      779:   for (i=1; i<l; i++)
                    780:   {
                    781:     pariputsf("%ld", g[i]);
1.2     ! noro      782:     if (i<l-1) comma_sp(T);
1.1       noro      783:   }
1.2     ! noro      784:   pariputs("])");
1.1       noro      785: }
                    786: /********************************************************************/
                    787: /**                                                                **/
                    788: /**                        WRITE A REAL NUMBER                     **/
                    789: /**                                                                **/
                    790: /********************************************************************/
1.2     ! noro      791: static void wr_exp(pariout_t *T, GEN x);
1.1       noro      792:
                    793: /* assume x != 0 and print |x| in floating point format */
                    794: static void
1.2     ! noro      795: wr_float(pariout_t *T, GEN x)
1.1       noro      796: {
1.2     ! noro      797:   long *res, ex,s,d,e,decmax, dec = T->sigd;
1.1       noro      798:   GEN p1;
                    799:
                    800:   if (dec>0) /* round if needed */
                    801:   {
                    802:     GEN arrondi = cgetr(3);
1.2     ! noro      803:     ex = expo(x) - (long)((((double)BITS_IN_LONG)/pariK)*dec+2);
        !           804:     arrondi[1] = evalsigne(1)|evalexpo(ex);
1.1       noro      805:     arrondi[2] = x[2]; x = addrr(x,arrondi);
                    806:   }
                    807:   ex = expo(x); e = bit_accuracy(lg(x)); /* significant bits */
1.2     ! noro      808:   if (ex >= e) { wr_exp(T,x); return; }
1.1       noro      809:   decmax = (long) (e * L2SL10); /* significant digits */
                    810:   if ((ulong)decmax < (ulong)dec) dec = decmax; /* Hack: includes dec < 0 */
                    811:
                    812: /* integer part */
                    813:   p1 = gcvtoi(x,&e); s = signe(p1);
                    814:   if (e > 0) err(bugparier,"wr_float");
                    815:   if (!s) { pariputc('0'); d=0; }
                    816:   else
                    817:   {
                    818:     x = subri(x,p1); setsigne(p1,1);
                    819:     res = convi(p1); d = coinit(*--res);
                    820:     while (*(--res) >= 0) { d += 9; comilieu(*res); }
                    821:   }
                    822:   pariputc('.');
                    823:
                    824: /* fractional part: 0 < x < 1 */
                    825:   if (!signe(x))
                    826:   {
                    827:     dec -= d; if (dec>0) zeros(dec);
                    828:     return;
                    829:   }
                    830:
                    831:   res = confrac(x);
                    832:   if (!s)
                    833:   {
                    834:     while (!*res) { res++; pariputs("000000000"); }
1.2     ! noro      835:     d = coinit2(*res++, dec);
1.1       noro      836:   }
                    837:
                    838:   /* d = # significant digits already printed */
                    839:   dec -= d;
                    840:   while (dec>8) { comilieu(*res++); dec -= 9; }
                    841:   if (dec>0) cofin(*res,dec);
                    842: }
                    843:
                    844: /* as above in exponential format */
                    845: static void
1.2     ! noro      846: wr_exp(pariout_t *T, GEN x)
1.1       noro      847: {
1.2     ! noro      848:   GEN dix = stor(10, lg(x)+1);
        !           849:   long e = expo(x);
1.1       noro      850:
1.2     ! noro      851:   e = (e>=0)? (long)(e*L2SL10): (long)(-(-e*L2SL10)-1);
        !           852:   if (e) x = mulrr(x, gpowgs(dix,-e));
        !           853:   if (absr_cmp(x, dix) >= 0) { x = divrr(x,dix); e++; }
        !           854:   wr_float(T,x); sp(T); pariputsf("E%ld",e);
1.1       noro      855: }
                    856:
                    857: /* Write real number x.
                    858:  * format: e (exponential), f (floating point), g (as f unless x too small)
                    859:  *   if format isn't correct (one of the above) act as e.
1.2     ! noro      860:  * sigd: number of sigd to print (all if <0).
1.1       noro      861:  */
                    862: static void
1.2     ! noro      863: wr_real(pariout_t *T, GEN x, int nosign)
1.1       noro      864: {
1.2     ! noro      865:   gpmem_t ltop;
        !           866:   long sx = signe(x), ex = expo(x);
1.1       noro      867:
                    868:   if (!sx) /* real 0 */
                    869:   {
1.2     ! noro      870:     if (T->format == 'f')
1.1       noro      871:     {
1.2     ! noro      872:       long d, dec = T->sigd;
        !           873:       if (dec < 0)
1.1       noro      874:       {
1.2     ! noro      875:         d = 1+((-ex)>>TWOPOTBITS_IN_LONG);
1.1       noro      876:         if (d < 0) d = 0;
1.2     ! noro      877:         dec = (long)(pariK*d);
1.1       noro      878:       }
1.2     ! noro      879:       pariputs("0."); zeros(dec);
1.1       noro      880:     }
                    881:     else
                    882:     {
                    883:       ex = (ex>=0)? (long)(ex*L2SL10): (long)(-(-ex*L2SL10)-1);
                    884:       pariputsf("0.E%ld", ex+1);
                    885:     }
                    886:     return;
                    887:   }
                    888:   if (!nosign && sx < 0) pariputc('-'); /* print sign if needed */
                    889:   ltop = avma;
1.2     ! noro      890:   if ((T->format == 'g' && ex>=-32)
        !           891:     || T->format == 'f') wr_float(T,x); else wr_exp(T,x);
1.1       noro      892:   avma = ltop;
                    893: }
                    894:
                    895: /********************************************************************/
                    896: /**                                                                **/
                    897: /**                       HEXADECIMAL OUTPUT                       **/
                    898: /**                                                                **/
                    899: /********************************************************************/
                    900:
                    901: static void
                    902: sorstring(char* b, long x)
                    903: {
                    904: #ifdef LONG_IS_64BIT
                    905:   pariputsf(b,(ulong)x>>32,x & MAXHALFULONG);
                    906: #else
                    907:   pariputsf(b,x);
                    908: #endif
                    909: }
                    910:
                    911: /* English ordinal numbers -- GN1998Apr17 */
                    912: static const char *ordsuff[4] = {"st","nd","rd","th"};
                    913:
                    914: const char*
                    915: eng_ord(long i)                        /* i > 0 assumed */
                    916: {
                    917:   switch (i%10)
                    918:   {
                    919:     case 1:
                    920:       if (i%100==11) return ordsuff[3]; /* xxx11-th */
                    921:       return ordsuff[0];         /* xxx01-st, xxx21-st,... */
                    922:     case 2:
                    923:       if (i%100==12) return ordsuff[3]; /* xxx12-th */
                    924:       return ordsuff[1];         /* xxx02-nd, xxx22-nd,... */
                    925:     case 3:
                    926:       if (i%100==13) return ordsuff[3]; /* xxx13-th */
                    927:       return ordsuff[2];         /* xxx03-rd, xxx23-rd,... */
                    928:     default:
                    929:       return ordsuff[3];         /* xxxx4-th,... */
                    930:   }
                    931: }
                    932:
                    933: static char
                    934: vsigne(GEN x)
                    935: {
                    936:   long s = signe(x);
                    937:   if (!s) return '0';
                    938:   return (s > 0) ? '+' : '-';
                    939: }
                    940:
                    941: static void
                    942: voir2(GEN x, long nb, long bl)
                    943: {
1.2     ! noro      944:   long tx,i,j,e,dx,lx;
1.1       noro      945:
1.2     ! noro      946:   if (!x) { pariputs("NULL\n"); return; }
        !           947:   tx = typ(x);
1.1       noro      948:   if (tx == t_INT && x == gzero) { pariputs("gzero\n"); return; }
                    949:   if (tx == t_SMALL) {
                    950:     pariputs("[SMALL ");
                    951:     sorstring(VOIR_STRING2,(long)x);
                    952:     pariputs("]\n"); return;
                    953:   }
                    954:   sorstring(VOIR_STRING1,(ulong)x);
                    955:
1.2     ! noro      956:   lx = lg(x);
1.1       noro      957:   pariputsf("%s(lg=%ld%s):",type_name(tx)+2,lx,isclone(x)? ",CLONE" : "");
                    958:   sorstring(VOIR_STRING2,x[0]);
                    959:   if (! is_recursive_t(tx)) /* t_SMALL, t_INT, t_REAL, t_STR, t_VECSMALL */
                    960:   {
1.2     ! noro      961:     if (tx == t_STR)
        !           962:       pariputs("chars:");
1.1       noro      963:     else if (tx == t_INT)
1.2     ! noro      964:       pariputsf("(%c,lgef=%ld):", vsigne(x), lgefint(x));
1.1       noro      965:     else if (tx == t_REAL)
1.2     ! noro      966:       pariputsf("(%c,expo=%ld):", vsigne(x), expo(x));
1.1       noro      967:     if (nb<0) nb = (tx==t_INT)? lgefint(x): lx;
                    968:     if (tx == t_VECSMALL) nb = lx;
                    969:     for (i=1; i < nb; i++) sorstring(VOIR_STRING2,x[i]);
                    970:     pariputc('\n'); return;
                    971:   }
                    972:
                    973:   if (tx == t_PADIC)
                    974:     pariputsf("(precp=%ld,valp=%ld):", precp(x), valp(x));
                    975:   else if (tx == t_POL)
                    976:     pariputsf("(%c,varn=%ld,lgef=%ld):", vsigne(x), varn(x), lgef(x));
                    977:   else if (tx == t_SER)
                    978:     pariputsf("(%c,varn=%ld,prec=%ld,valp=%ld):",
                    979:                vsigne(x), varn(x),lg(x)-2, valp(x));
                    980:   else if (tx == t_LIST)
                    981:     pariputsf("(lgef=%ld):", lgef(x));
                    982:
                    983:   if (tx == t_POL || tx == t_LIST) lx = lgef(x);
                    984:   for (i=1; i<lx; i++) sorstring(VOIR_STRING2,x[i]);
                    985:   bl+=2; pariputc('\n');
                    986:   switch(tx)
                    987:   {
                    988:     case t_INTMOD: case t_POLMOD:
                    989:     {
                    990:       char *s = (tx==t_INTMOD)? "int = ": "pol = ";
                    991:       if (isonstack(x[1])) blancs(bl); else { blancs(bl-2); pariputs("* "); }
                    992:       pariputs("mod = "); voir2((GEN)x[1],nb,bl);
                    993:       blancs(bl); pariputs(s);        voir2((GEN)x[2],nb,bl);
                    994:       break;
                    995:     }
                    996:     case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
                    997:       blancs(bl); pariputs("num = "); voir2((GEN)x[1],nb,bl);
                    998:       blancs(bl); pariputs("den = "); voir2((GEN)x[2],nb,bl);
                    999:       break;
                   1000:
                   1001:     case t_COMPLEX:
                   1002:       blancs(bl); pariputs("real = "); voir2((GEN)x[1],nb,bl);
                   1003:       blancs(bl); pariputs("imag = "); voir2((GEN)x[2],nb,bl);
                   1004:       break;
                   1005:
                   1006:     case t_PADIC:
                   1007:       if (isonstack(x[2])) blancs(bl); else { blancs(bl-2); pariputs("* "); }
                   1008:                   pariputs("  p : "); voir2((GEN)x[2],nb,bl);
                   1009:       blancs(bl); pariputs("p^l : "); voir2((GEN)x[3],nb,bl);
                   1010:       blancs(bl); pariputs("  I : "); voir2((GEN)x[4],nb,bl);
                   1011:       break;
                   1012:
                   1013:     case t_QUAD:
                   1014:       blancs(bl); pariputs("pol = ");  voir2((GEN)x[1],nb,bl);
                   1015:       blancs(bl); pariputs("real = "); voir2((GEN)x[2],nb,bl);
                   1016:       blancs(bl); pariputs("imag = "); voir2((GEN)x[3],nb,bl);
                   1017:       break;
                   1018:
                   1019:     case t_POL: case t_SER:
                   1020:       e = (tx==t_SER)? valp(x): 0;
                   1021:       for (i=2; i<lx; i++)
                   1022:       {
                   1023:        blancs(bl); pariputsf("coef of degree %ld = ",e);
                   1024:        e++; voir2((GEN)x[i],nb,bl);
                   1025:       }
                   1026:       break;
                   1027:
                   1028:     case t_LIST: case t_QFR: case t_QFI: case t_VEC: case t_COL:
                   1029:       i = (tx==t_LIST)? 2: 1;
                   1030:       for (   ; i<lx; i++)
                   1031:       {
                   1032:         blancs(bl); pariputsf("%ld%s component = ",i,eng_ord(i));
                   1033:        voir2((GEN)x[i],nb,bl);
                   1034:       }
                   1035:       break;
                   1036:
                   1037:     case t_MAT:
                   1038:       if (lx==1) return;
                   1039:       dx=lg((GEN)x[1]);
                   1040:       for (i=1; i<dx; i++)
                   1041:        for (j=1; j<lx; j++)
                   1042:        {
                   1043:          blancs(bl); pariputsf("mat(%ld,%ld) = ",i,j);
                   1044:          voir2(gcoeff(x,i,j),nb,bl);
                   1045:        }
                   1046:   }
                   1047: }
                   1048:
                   1049: void
                   1050: voir(GEN x, long nb)
                   1051: {
                   1052:   voir2(x,nb,0);
                   1053: }
                   1054:
                   1055: char *
                   1056: type_name(long t)
                   1057: {
                   1058:   char *s;
                   1059:   switch(t)
                   1060:   {
                   1061:     case t_SMALL  : s="t_SMALL";   break;
                   1062:     case t_INT    : s="t_INT";     break;
                   1063:     case t_REAL   : s="t_REAL";    break;
                   1064:     case t_INTMOD : s="t_INTMOD";  break;
                   1065:     case t_FRAC   : s="t_FRAC";    break;
                   1066:     case t_FRACN  : s="t_FRACN";   break;
                   1067:     case t_COMPLEX: s="t_COMPLEX"; break;
                   1068:     case t_PADIC  : s="t_PADIC";   break;
                   1069:     case t_QUAD   : s="t_QUAD";    break;
                   1070:     case t_POLMOD : s="t_POLMOD";  break;
                   1071:     case t_POL    : s="t_POL";     break;
                   1072:     case t_SER    : s="t_SER";     break;
                   1073:     case t_RFRAC  : s="t_RFRAC";   break;
                   1074:     case t_RFRACN : s="t_RFRACN";  break;
                   1075:     case t_QFR    : s="t_QFR";     break;
                   1076:     case t_QFI    : s="t_QFI";     break;
                   1077:     case t_VEC    : s="t_VEC";     break;
                   1078:     case t_COL    : s="t_COL";     break;
                   1079:     case t_MAT    : s="t_MAT";     break;
                   1080:     case t_LIST   : s="t_LIST";    break;
                   1081:     case t_STR    : s="t_STR";     break;
                   1082:     case t_VECSMALL:s="t_VECSMALL";break;
                   1083:     default: err(talker,"unknown type %ld",t);
                   1084:       s = NULL; /* not reached */
                   1085:   }
                   1086:   return s;
                   1087: }
                   1088:
                   1089: /********************************************************************/
                   1090: /**                                                                **/
                   1091: /**                        FORMATTED OUTPUT                        **/
                   1092: /**                                                                **/
                   1093: /********************************************************************/
                   1094: static char *
                   1095: get_var(long v, char *buf)
                   1096: {
                   1097:   entree *ep = varentries[v];
                   1098:
                   1099:   if (ep) return ep->name;
                   1100:   if (v==MAXVARN) return "#";
                   1101:   sprintf(buf,"#<%d>",(int)v); return buf;
                   1102: }
                   1103:
                   1104: static char *
                   1105: get_texvar(long v, char *buf)
                   1106: {
                   1107:   entree *ep = varentries[v];
                   1108:   char *s, *t = buf;
                   1109:
                   1110:   if (!ep) err(talker, "this object uses debugging variables");
                   1111:   s = ep->name;
                   1112:   if (strlen(s)>=64) err(talker, "TeX variable name too long");
                   1113:   while(isalpha((int)*s)) *t++ = *s++;
                   1114:   *t = 0; if (isdigit((int)*s) || *s++ == '_') sprintf(t,"_{%s}",s);
                   1115:   return buf;
                   1116: }
                   1117:
                   1118: static void
                   1119: monome(char *v, long deg)
                   1120: {
                   1121:   if (deg)
                   1122:   {
                   1123:     pariputs(v);
                   1124:     if (deg!=1) pariputsf("^%ld",deg);
                   1125:   }
                   1126:   else pariputc('1');
                   1127: }
                   1128:
                   1129: static void
                   1130: texnome(char *v, long deg)
                   1131: {
                   1132:   if (deg)
                   1133:   {
                   1134:     pariputs(v);
                   1135:     if (deg!=1) pariputsf("^{%ld}",deg);
                   1136:   }
                   1137:   else pariputc('1');
                   1138: }
                   1139:
                   1140: #define padic_nome(p,e) {pariputs(p); if (e != 1) pariputsf("^%ld",e);}
                   1141: #define padic_texnome(p,e) {pariputs(p); if (e != 1) pariputsf("^{%ld}",e);}
                   1142:
                   1143: void
                   1144: etatpile(unsigned int n)
                   1145: {
1.2     ! noro     1146:   long nu, i, l, m;
        !          1147:   gpmem_t av=avma;
1.1       noro     1148:   GEN adr,adr1;
                   1149:   double r;
                   1150:
                   1151:   nu = (top-avma)/BYTES_IN_LONG;
                   1152:   l = (top-bot)/BYTES_IN_LONG;
                   1153:   r = 100.0*nu/l;
                   1154:   pariputsf("\n Top : %lx   Bottom : %lx   Current stack : %lx\n",
                   1155:           top, bot, avma);
                   1156:
                   1157:   pariputsf(" Used :                         %ld  long words  (%ld K)\n",
                   1158:            nu, nu/1024*BYTES_IN_LONG);
                   1159:
                   1160:   pariputsf(" Available :                    %ld  long words  (%ld K)\n",
                   1161:            (l-nu), (l-nu)/1024*BYTES_IN_LONG);
                   1162:
                   1163:   pariputsf(" Occupation of the PARI stack : %6.2f percent\n",r);
                   1164:
                   1165:   adr=getheap();
                   1166:   pariputsf(" %ld objects on heap occupy %ld long words\n\n",
                   1167:                  itos((GEN)adr[1]), itos((GEN)adr[2]));
                   1168:   avma=av;
                   1169:
                   1170:   pariputsf(" %ld variable names used out of %d\n\n",manage_var(3,NULL),MAXVARN);
                   1171:   if (!n) return;
                   1172:
                   1173:   if (n > (ulong)nu) n = nu;
                   1174:   adr = (GEN)avma; adr1 = adr+n;
                   1175:   while (adr<adr1)
                   1176:   {
                   1177:     sorstring(VOIR_STRING3,(ulong)adr);
                   1178:     l=lg(adr); m = (adr==polvar) ? MAXVARN : 0;
                   1179:     for (i=0; i<l && adr<adr1; i++,adr++) sorstring(VOIR_STRING2,*adr);
                   1180:     pariputc('\n'); adr=polvar+m;
                   1181:   }
                   1182:   pariputc('\n');
                   1183: }
                   1184:
                   1185: /********************************************************************/
                   1186: /**                                                                **/
                   1187: /**                           RAW OUTPUT                           **/
                   1188: /**                                                                **/
                   1189: /********************************************************************/
                   1190: #define isnull_for_pol(g)  ((typ(g)==t_INTMOD)? !signe(g[2]): isnull(g))
                   1191:
                   1192: /* is to be printed as '0' */
                   1193: static long
                   1194: isnull(GEN g)
                   1195: {
                   1196:   long i;
                   1197:   switch (typ(g))
                   1198:   {
                   1199:     case t_SMALL:
                   1200:       return !smalltos(g);
                   1201:     case t_INT:
                   1202:       return !signe(g);
                   1203:     case t_COMPLEX:
                   1204:       return isnull((GEN)g[1]) && isnull((GEN)g[2]);
                   1205:     case t_QUAD:
                   1206:       return isnull((GEN)g[2]) && isnull((GEN)g[3]);
                   1207:     case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
                   1208:       return isnull((GEN)g[1]);
                   1209:     case t_POLMOD:
                   1210:       return isnull((GEN)g[2]);
                   1211:     case t_POL:
                   1212:       for (i=lgef(g)-1; i>1; i--)
                   1213:        if (!isnull((GEN)g[i])) return 0;
                   1214:       return 1;
                   1215:   }
                   1216:   return 0;
                   1217: }
                   1218:
                   1219: /* return 1 or -1 if g is 1 or -1, 0 otherwise*/
                   1220: static long
                   1221: isone(GEN g)
                   1222: {
                   1223:   long i;
                   1224:   switch (typ(g))
                   1225:   {
                   1226:     case t_SMALL:
                   1227:       switch(smalltos(g))
                   1228:       {
                   1229:         case  1: return  1;
                   1230:         case -1: return -1;
                   1231:       }
                   1232:       break;
                   1233:     case t_INT:
                   1234:       return (signe(g) && is_pm1(g))? signe(g): 0;
                   1235:     case t_COMPLEX:
                   1236:       return isnull((GEN)g[2])? isone((GEN)g[1]): 0;
                   1237:     case t_QUAD:
                   1238:       return isnull((GEN)g[3])? isone((GEN)g[2]): 0;
                   1239:     case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
                   1240:       return isone((GEN)g[1]) * isone((GEN)g[2]);
                   1241:     case t_POL:
                   1242:       if (!signe(g)) return 0;
                   1243:       for (i=lgef(g)-1; i>2; i--)
                   1244:        if (!isnull((GEN)g[i])) return 0;
                   1245:       return isone((GEN)g[2]);
                   1246:   }
                   1247:   return 0;
                   1248: }
                   1249:
                   1250: /* if g is a "monomial", return its sign, 0 otherwise */
                   1251: static long
                   1252: isfactor(GEN g)
                   1253: {
                   1254:   long i,deja,sig;
                   1255:   switch(typ(g))
                   1256:   {
                   1257:     case t_INT: case t_REAL:
                   1258:       return (signe(g)<0)? -1: 1;
                   1259:     case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
                   1260:       return isfactor((GEN)g[1]);
                   1261:     case t_COMPLEX:
                   1262:       if (isnull((GEN)g[1])) return isfactor((GEN)g[2]);
                   1263:       if (isnull((GEN)g[2])) return isfactor((GEN)g[1]);
                   1264:       return 0;
                   1265:     case t_PADIC:
                   1266:       return !signe((GEN)g[4]);
                   1267:     case t_QUAD:
                   1268:       if (isnull((GEN)g[2])) return isfactor((GEN)g[3]);
                   1269:       if (isnull((GEN)g[3])) return isfactor((GEN)g[2]);
                   1270:       return 0;
                   1271:     case t_POL: deja = 0; sig = 1;
                   1272:       for (i=lgef(g)-1; i>1; i--)
                   1273:         if (!isnull((GEN)g[i]))
                   1274:        {
                   1275:          if (deja) return 0;
                   1276:          sig=isfactor((GEN)g[i]); deja=1;
                   1277:        }
                   1278:       return sig? sig: 1;
                   1279:     case t_SER:
                   1280:       for (i=lg(g)-1; i>1; i--)
                   1281:         if (!isnull((GEN)g[i])) return 0;
                   1282:   }
                   1283:   return 1;
                   1284: }
                   1285:
                   1286: /* return 1 if g is a "truc" (see anal.c) */
                   1287: static long
                   1288: isdenom(GEN g)
                   1289: {
                   1290:   long i,deja;
                   1291:   switch(typ(g))
                   1292:   {
                   1293:     case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
                   1294:       return 0;
                   1295:     case t_COMPLEX: return isnull((GEN)g[2]);
                   1296:     case t_PADIC: return !signe((GEN)g[4]);
                   1297:     case t_QUAD: return isnull((GEN)g[3]);
                   1298:
                   1299:     case t_POL: deja = 0;
                   1300:       for (i=lgef(g)-1; i>1; i--)
                   1301:         if (!isnull((GEN)g[i]))
                   1302:        {
                   1303:          if (deja) return 0;
                   1304:          if (i==2) return isdenom((GEN)g[2]);
                   1305:          if (!isone((GEN)g[i])) return 0;
                   1306:          deja=1;
                   1307:        }
                   1308:       return 1;
                   1309:     case t_SER:
                   1310:       for (i=lg(g)-1; i>1; i--)
                   1311:        if (!isnull((GEN)g[i])) return 0;
                   1312:   }
                   1313:   return 1;
                   1314: }
                   1315:
                   1316: /* write a * v^d */
                   1317: static void
1.2     ! noro     1318: wr_monome(pariout_t *T, GEN a, char *v, long d)
1.1       noro     1319: {
                   1320:   long sig = isone(a);
                   1321:
1.2     ! noro     1322:   if (sig) { sp_sign_sp(T,sig); monome(v,d); }
1.1       noro     1323:   else
                   1324:   {
                   1325:     sig = isfactor(a);
1.2     ! noro     1326:     if (sig) { sp_sign_sp(T,sig); bruti(a,T,sig); }
1.1       noro     1327:     else
                   1328:     {
1.2     ! noro     1329:       sp_sign_sp(T,1); pariputc('('); bruti(a,T,sig); pariputc(')');
1.1       noro     1330:     }
                   1331:     if (d) { pariputc('*'); monome(v,d); }
                   1332:   }
                   1333: }
                   1334:
                   1335: static void
1.2     ! noro     1336: wr_texnome(pariout_t *T, GEN a, char *v, long d)
1.1       noro     1337: {
                   1338:   long sig = isone(a);
                   1339:
                   1340:   if (sig) { putsigne(sig); texnome(v,d); }
                   1341:   else
                   1342:   {
                   1343:     sig = isfactor(a);
1.2     ! noro     1344:     if (sig) { putsigne(sig); texi(a,T,sig); }
1.1       noro     1345:     else
                   1346:     {
1.2     ! noro     1347:       pariputs(" + \\left("); texi(a,T,sig); pariputs("\\right) ");
1.1       noro     1348:     }
                   1349:     if (d)
                   1350:     {
1.2     ! noro     1351:       if (GP_DATA && (GP_DATA->flags & TEXMACS)) pariputs("\\*");
1.1       noro     1352:       texnome(v,d);
                   1353:     }
                   1354:   }
                   1355: }
                   1356:
                   1357: static void
1.2     ! noro     1358: wr_lead_monome(pariout_t *T, GEN a, char *v, long d, int nosign)
1.1       noro     1359: {
                   1360:   long sig = isone(a);
                   1361:   if (sig)
                   1362:   {
                   1363:     if (!nosign && sig<0) pariputc('-');
                   1364:     monome(v,d);
                   1365:   }
                   1366:   else
                   1367:   {
1.2     ! noro     1368:     if (isfactor(a)) bruti(a,T,nosign);
1.1       noro     1369:     else
                   1370:     {
1.2     ! noro     1371:       pariputc('('); bruti(a,T,0); pariputc(')');
1.1       noro     1372:     }
                   1373:     if (d) { pariputc('*'); monome(v,d); }
                   1374:   }
                   1375: }
                   1376:
                   1377: static void
1.2     ! noro     1378: wr_lead_texnome(pariout_t *T, GEN a, char *v, long d, int nosign)
1.1       noro     1379: {
                   1380:   long sig = isone(a);
                   1381:   if (sig)
                   1382:   {
                   1383:     if (!nosign && sig<0) pariputc('-');
                   1384:     texnome(v,d);
                   1385:   }
                   1386:   else
                   1387:   {
1.2     ! noro     1388:     if (isfactor(a)) texi(a,T,nosign);
1.1       noro     1389:     else
                   1390:     {
1.2     ! noro     1391:       pariputs(" \\left("); texi(a,T,0); pariputs("\\right) ");
1.1       noro     1392:     }
                   1393:     if (d)
                   1394:     {
1.2     ! noro     1395:       if (GP_DATA && (GP_DATA->flags & TEXMACS)) pariputs("\\*");
1.1       noro     1396:       texnome(v,d);
                   1397:     }
                   1398:   }
                   1399: }
                   1400:
1.2     ! noro     1401: void
        !          1402: bruti(GEN g, pariout_t *T, int nosign)
1.1       noro     1403: {
                   1404:   long tg,l,i,j,r;
                   1405:   GEN a,b;
                   1406:   char *v, buf[32];
                   1407:
                   1408:   if (!g) { pariputs("NULL"); return; }
                   1409:   if (isnull(g)) { pariputc('0'); return; }
                   1410:   r = isone(g);
                   1411:   if (r)
                   1412:   {
                   1413:     if (!nosign && r<0) pariputc('-');
                   1414:     pariputc('1'); return;
                   1415:   }
                   1416:
                   1417:   tg = typ(g);
                   1418:   switch(tg)
                   1419:   {
                   1420:     case t_SMALL: pariputsf("%ld",smalltos(g)); break;
1.2     ! noro     1421:     case t_INT:
        !          1422:       if (!nosign && signe(g) < 0) pariputc('-');
        !          1423:       wr_intpos(g); break;
        !          1424:     case t_REAL: wr_real(T,g,nosign); break;
1.1       noro     1425:
                   1426:     case t_INTMOD: case t_POLMOD:
                   1427:       pariputs(new_fun_set? "Mod(": "mod(");
1.2     ! noro     1428:       bruti((GEN)g[2],T,0); comma_sp(T);
        !          1429:       bruti((GEN)g[1],T,0); pariputc(')'); break;
1.1       noro     1430:
                   1431:     case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
                   1432:       r = isfactor((GEN)g[1]); if (!r) pariputc('(');
1.2     ! noro     1433:       bruti((GEN)g[1],T,nosign);
1.1       noro     1434:       if (!r) pariputc(')');
                   1435:       pariputc('/');
                   1436:       r = isdenom((GEN)g[2]); if (!r) pariputc('(');
1.2     ! noro     1437:       bruti((GEN)g[2],T,0);
1.1       noro     1438:       if (!r) pariputc(')');
                   1439:       break;
                   1440:
                   1441:     case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
                   1442:       a = (GEN)g[r+1]; b = (GEN)g[r+2]; v = r? "w": "I";
                   1443:       if (isnull(a))
                   1444:       {
1.2     ! noro     1445:         wr_lead_monome(T,b,v,1,nosign);
1.1       noro     1446:         return;
                   1447:       }
1.2     ! noro     1448:       bruti(a,T,nosign);
        !          1449:       if (!isnull(b)) wr_monome(T,b,v,1);
1.1       noro     1450:       break;
                   1451:
                   1452:     case t_POL: v = get_var(ordvar[varn(g)], buf);
                   1453:       /* hack: we want g[i] = coeff of degree i. */
                   1454:       i = degpol(g); g += 2; while (isnull((GEN)g[i])) i--;
1.2     ! noro     1455:       wr_lead_monome(T,(GEN)g[i],v,i,nosign);
1.1       noro     1456:       while (i--)
                   1457:       {
                   1458:         a = (GEN)g[i];
1.2     ! noro     1459:         if (!isnull_for_pol(a)) wr_monome(T,a,v,i);
1.1       noro     1460:       }
                   1461:       break;
                   1462:
                   1463:     case t_SER: v = get_var(ordvar[varn(g)], buf);
                   1464:       i = valp(g);
                   1465:       if (signe(g))
                   1466:       { /* hack: we want g[i] = coeff of degree i. */
                   1467:         l = i + lg(g)-2; g += (2-i);
1.2     ! noro     1468:         wr_lead_monome(T,(GEN)g[i],v,i,nosign);
1.1       noro     1469:         while (++i < l)
                   1470:         {
                   1471:           a = (GEN)g[i];
1.2     ! noro     1472:           if (!isnull_for_pol(a)) wr_monome(T,a,v,i);
1.1       noro     1473:         }
1.2     ! noro     1474:         sp_sign_sp(T,1);
1.1       noro     1475:       }
                   1476:       pariputs("O("); monome(v,i); pariputc(')'); break;
                   1477:
                   1478:     case t_PADIC:
                   1479:     {
                   1480:       GEN p = (GEN)g[2];
1.2     ! noro     1481:       gpmem_t av = avma;
1.1       noro     1482:       i = valp(g); l = precp(g)+i;
                   1483:       g = (GEN)g[4]; v = GENtostr(p);
                   1484:       for (; i<l; i++)
                   1485:       {
                   1486:        g = dvmdii(g,p,&a);
                   1487:        if (signe(a))
                   1488:        {
                   1489:          if (!i || !is_pm1(a))
                   1490:          {
1.2     ! noro     1491:            wr_intpos(a); if (i) pariputc('*');
1.1       noro     1492:          }
                   1493:          if (i) padic_nome(v,i);
1.2     ! noro     1494:           sp_sign_sp(T,1);
1.1       noro     1495:        }
1.2     ! noro     1496:         if ((i & 0xff) == 0) g = gerepileuptoint(av,g);
1.1       noro     1497:       }
                   1498:       pariputs("O("); padic_nome(v,i); pariputc(')');
                   1499:       free(v); break;
                   1500:     }
                   1501:
                   1502:     case t_QFR: case t_QFI: r = (tg == t_QFR);
                   1503:       if (new_fun_set) pariputs("Qfb("); else pariputs(r? "qfr(": "qfi(");
1.2     ! noro     1504:       bruti((GEN)g[1],T,0); comma_sp(T);
        !          1505:       bruti((GEN)g[2],T,0); comma_sp(T);
        !          1506:       bruti((GEN)g[3],T,0);
        !          1507:       if (r) { comma_sp(T); bruti((GEN)g[4],T,0); }
1.1       noro     1508:       pariputc(')'); break;
                   1509:
                   1510:     case t_VEC: case t_COL:
                   1511:       pariputc('['); l = lg(g);
                   1512:       for (i=1; i<l; i++)
                   1513:       {
1.2     ! noro     1514:         bruti((GEN)g[i],T,0);
        !          1515:         if (i<l-1) comma_sp(T);
1.1       noro     1516:       }
                   1517:       pariputc(']'); if (tg==t_COL) pariputc('~');
                   1518:       break;
1.2     ! noro     1519:     case t_VECSMALL: wr_vecsmall(T,g); break;
1.1       noro     1520:
                   1521:     case t_LIST:
                   1522:       pariputs("List(["); l = lgef(g);
                   1523:       for (i=2; i<l; i++)
                   1524:       {
1.2     ! noro     1525:         bruti((GEN)g[i],T,0);
        !          1526:         if (i<l-1) comma_sp(T);
1.1       noro     1527:       }
                   1528:       pariputs("])"); break;
                   1529:
                   1530:     case t_STR:
                   1531:       pariputc('"'); pariputs(GSTR(g)); pariputc('"');
                   1532:       return;
                   1533:
                   1534:     case t_MAT:
                   1535:       r = lg(g); if (r==1) { pariputs("[;]"); return; }
                   1536:       l = lg(g[1]);
                   1537:       if (l==1)
                   1538:       {
                   1539:         pariputsf(new_fun_set? "matrix(0,%ld)":"matrix(0,%ld,j,k,0)", r-1);
                   1540:         return;
                   1541:       }
                   1542:       if (l==2)
                   1543:       {
                   1544:         pariputs(new_fun_set? "Mat(": "mat(");
1.2     ! noro     1545:         if (r == 2) { bruti(gcoeff(g,1,1),T,0); pariputc(')'); return; }
1.1       noro     1546:       }
                   1547:       pariputc('[');
                   1548:       for (i=1; i<l; i++)
                   1549:       {
                   1550:        for (j=1; j<r; j++)
                   1551:        {
1.2     ! noro     1552:          bruti(gcoeff(g,i,j),T,0);
        !          1553:           if (j<r-1) comma_sp(T);
1.1       noro     1554:        }
1.2     ! noro     1555:        if (i<l-1) { pariputc(';'); sp(T); }
1.1       noro     1556:       }
                   1557:       pariputc(']'); if (l==2) pariputc(')');
                   1558:       break;
                   1559:
                   1560:     default: sorstring(VOIR_STRING2,*g);
                   1561:   }
                   1562: }
                   1563:
1.2     ! noro     1564: void
        !          1565: matbruti(GEN g, pariout_t *T)
1.1       noro     1566: {
                   1567:   long i,j,r,l;
                   1568:
1.2     ! noro     1569:   if (typ(g) != t_MAT) { bruti(g,T,0); return; }
1.1       noro     1570:
                   1571:   r=lg(g); if (r==1 || lg(g[1])==1) { pariputs("[;]\n"); return; }
                   1572:   pariputc('\n'); l = lg(g[1]);
                   1573:   for (i=1; i<l; i++)
                   1574:   {
                   1575:     pariputc('[');
                   1576:     for (j=1; j<r; j++)
                   1577:     {
1.2     ! noro     1578:       bruti(gcoeff(g,i,j),T,0); if (j<r-1) pariputc(' ');
1.1       noro     1579:     }
                   1580:     if (i<l-1) pariputs("]\n\n"); else pariputs("]\n");
                   1581:   }
                   1582: }
                   1583:
                   1584: static void
1.2     ! noro     1585: sor_monome(pariout_t *T, GEN a, char *v, long d)
1.1       noro     1586: {
                   1587:   long sig = isone(a);
                   1588:   if (sig) { putsigne(sig); monome(v,d); }
                   1589:   else
                   1590:   {
                   1591:     sig = isfactor(a);
                   1592:     if (sig) { putsigne(sig); if (sig < 0) a = gneg(a); }
                   1593:     else pariputs(" + ");
1.2     ! noro     1594:     sori(a,T); if (d) { pariputc(' '); monome(v,d);}
1.1       noro     1595:   }
                   1596: }
                   1597:
                   1598: static void
1.2     ! noro     1599: sor_lead_monome(pariout_t *T, GEN a, char *v, long d)
1.1       noro     1600: {
                   1601:   long sig = isone(a);
                   1602:   if (sig)
                   1603:   {
                   1604:     if (sig < 0) pariputc('-');
                   1605:     monome(v,d);
                   1606:   }
                   1607:   else
                   1608:   {
1.2     ! noro     1609:     sori(a,T);
1.1       noro     1610:     if (d) { pariputc(' '); monome(v,d); }
                   1611:   }
                   1612: }
                   1613:
1.2     ! noro     1614: void
        !          1615: sori(GEN g, pariout_t *T)
1.1       noro     1616: {
                   1617:   long tg=typ(g), i,j,r,l,close_paren;
                   1618:   GEN a,b;
                   1619:   char *v, buf[32];
                   1620:
1.2     ! noro     1621:   if (tg == t_INT) { wr_int(T,g,0); return; }
        !          1622:   if (tg != t_MAT && tg != t_COL) T->fieldw = 0;
1.1       noro     1623:   switch (tg)
                   1624:   {
                   1625:     case t_SMALL: pariputsf("%ld",smalltos(g)); return;
1.2     ! noro     1626:     case t_REAL: wr_real(T,g,0); return;
1.1       noro     1627:     case t_STR:
                   1628:       pariputc('"'); pariputs(GSTR(g)); pariputc('"'); return;
                   1629:     case t_LIST:
1.2     ! noro     1630:       pariputs("List(");
1.1       noro     1631:       for (i=2; i<lgef(g); i++)
                   1632:       {
1.2     ! noro     1633:        sori((GEN)g[i], T); if (i<lgef(g)-1) pariputs(", ");
1.1       noro     1634:       }
                   1635:       pariputs(")\n"); return;
                   1636:   }
                   1637:   close_paren=0;
                   1638:   if (!is_graphicvec_t(tg))
                   1639:   {
                   1640:     if (is_frac_t(tg) && gsigne(g) < 0) pariputc('-');
                   1641:     if (! is_rfrac_t(tg)) { pariputc('('); close_paren=1; }
                   1642:   }
                   1643:   switch(tg)
                   1644:   {
                   1645:     case t_INTMOD: case t_POLMOD:
                   1646:       a = (GEN)g[2]; b = (GEN)g[1];
                   1647:       if (tg == t_INTMOD && signe(a) < 0) a = addii(a,b);
1.2     ! noro     1648:       sori(a,T); pariputs(" mod "); sori(b,T); break;
1.1       noro     1649:
                   1650:     case t_FRAC: case t_FRACN:
1.2     ! noro     1651:       a=(GEN)g[1]; wr_int(T,a,1); pariputs(" /");
        !          1652:       b=(GEN)g[2]; wr_int(T,b,1); break;
1.1       noro     1653:
                   1654:     case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
                   1655:       a = (GEN)g[r+1]; b = (GEN)g[r+2]; v = r? "w": "I";
1.2     ! noro     1656:       if (isnull(a)) { sor_lead_monome(T,b,v,1); break; }
        !          1657:       sori(a,T); if (!isnull(b)) sor_monome(T,b,v,1);
1.1       noro     1658:       break;
                   1659:
                   1660:     case t_PADIC:
                   1661:     {
                   1662:       GEN p = (GEN)g[2];
                   1663:       i = valp(g); l = precp(g)+i;
                   1664:       g = (GEN)g[4]; v = GENtostr(p);
                   1665:       for (; i<l; i++)
                   1666:       {
                   1667:        g = dvmdii(g,p,&a);
                   1668:        if (signe(a))
                   1669:        {
                   1670:          if (!i || !is_pm1(a))
                   1671:          {
1.2     ! noro     1672:            wr_int(T,a,1); pariputc(i? '*': ' ');
1.1       noro     1673:          }
                   1674:          if (i) { padic_nome(v,i); pariputc(' '); }
                   1675:           pariputs("+ ");
                   1676:        }
                   1677:       }
                   1678:       pariputs("O(");
                   1679:       if (!i) pariputs(" 1)"); else padic_nome(v,i);
                   1680:       pariputc(')'); free(v); break;
                   1681:     }
                   1682:
                   1683:     case t_POL:
                   1684:       if (!signe(g)) { pariputc('0'); break; }
                   1685:       v = get_var(ordvar[varn(g)],buf);
                   1686:       i = degpol(g); g += 2; while (isnull((GEN)g[i])) i--;
1.2     ! noro     1687:       sor_lead_monome(T,(GEN)g[i],v,i);
1.1       noro     1688:       while (i--)
                   1689:       {
1.2     ! noro     1690:         a = (GEN)g[i]; if (!isnull_for_pol(a)) sor_monome(T,a,v,i);
1.1       noro     1691:       }
                   1692:       break;
                   1693:
                   1694:     case t_SER: v = get_var(ordvar[varn(g)],buf);
                   1695:       i = valp(g);
                   1696:       if (signe(g))
                   1697:       { /* hack: we want g[i] = coeff of degree i. */
                   1698:         l = i + lg(g)-2; g += (2-i);
1.2     ! noro     1699:         sor_lead_monome(T,(GEN)g[i],v,i);
1.1       noro     1700:         while (++i < l)
                   1701:         {
1.2     ! noro     1702:           a = (GEN)g[i]; if (!isnull_for_pol(a)) sor_monome(T,a,v,i);
1.1       noro     1703:         }
                   1704:         pariputs(" + ");
                   1705:       }
                   1706:       pariputs("O(");
                   1707:       if (!i) pariputs(" 1)"); else monome(v,i);
                   1708:       pariputc(')'); break;
                   1709:
                   1710:     case t_RFRAC: case t_RFRACN:
1.2     ! noro     1711:     if (T->initial)
1.1       noro     1712:     {
                   1713:       char *v1, *v2;
                   1714:       long sd = 0, sn = 0, d,n;
                   1715:       long wd = term_width();
                   1716:
1.2     ! noro     1717:       T->initial = 0;
        !          1718:       v1 = GENtostr0((GEN)g[1], T, &sori); n = strlen(v1);
        !          1719:       v2 = GENtostr0((GEN)g[2], T, &sori); d = strlen(v2);
1.1       noro     1720:
                   1721:       pariputc('\n');
                   1722:       i = max(n,d)+2;
                   1723:       if (i > wd)
                   1724:       {
                   1725:         pariputs(v1); pariputs("\n\n");
                   1726:         for (j=0; j<wd; j++) pariputc('-');
                   1727:         pariputs("\n\n");
                   1728:         pariputs(v2);
                   1729:         pariputc('\n'); return;
                   1730:       }
                   1731:       if (n < d) sn = (d-n) >> 1; else sd = (n-d) >> 1;
                   1732:       blancs(sn+1); pariputs(v1);
                   1733:       pariputs("\n\n"); for (j=0; j<i; j++) pariputc('-');
                   1734:       pariputs("\n\n");
                   1735:       blancs(sd+1); pariputs(v2);
                   1736:       pariputc('\n'); return;
                   1737:     }
1.2     ! noro     1738:     pariputc('('); sori((GEN)g[1],T); pariputs(" / "); sori((GEN)g[2],T);
1.1       noro     1739:     pariputc(')'); return;
                   1740:
                   1741:     case t_QFR: case t_QFI: pariputc('{');
1.2     ! noro     1742:       sori((GEN)g[1],T); pariputs(", ");
        !          1743:       sori((GEN)g[2],T); pariputs(", ");
        !          1744:       sori((GEN)g[3],T);
        !          1745:       if (tg == t_QFR) { pariputs(", "); sori((GEN)g[4],T); }
1.1       noro     1746:       pariputs("}\n"); break;
                   1747:
1.2     ! noro     1748:     case t_VEC: pariputc('[');
1.1       noro     1749:       for (i=1; i<lg(g); i++)
                   1750:       {
1.2     ! noro     1751:        sori((GEN)g[i],T); if (i<lg(g)-1) pariputs(", ");
1.1       noro     1752:       }
                   1753:       pariputc(']'); break;
1.2     ! noro     1754:     case t_VECSMALL: wr_vecsmall(T,g); break;
1.1       noro     1755:
                   1756:     case t_COL:
                   1757:       if (lg(g)==1) { pariputs("[]\n"); return; }
                   1758:       pariputc('\n');
                   1759:       for (i=1; i<lg(g); i++)
                   1760:       {
1.2     ! noro     1761:         pariputc('['); sori((GEN)g[i],T); pariputs("]\n");
1.1       noro     1762:       }
                   1763:       break;
                   1764:
                   1765:     case t_MAT:
                   1766:     {
                   1767:       long lx = lg(g);
                   1768:
                   1769:       if (lx==1) { pariputs("[;]\n"); return; }
                   1770:       pariputc('\n'); l=lg((GEN)g[1]);
                   1771:       for (i=1; i<l; i++)
                   1772:       {
                   1773:        pariputc('[');
                   1774:        for (j=1; j<lx; j++)
                   1775:        {
1.2     ! noro     1776:          sori(gcoeff(g,i,j),T); if (j<lx-1) pariputc(' ');
1.1       noro     1777:        }
                   1778:        pariputs("]\n"); if (i<l-1) pariputc('\n');
                   1779:       }
                   1780:       break;
                   1781:     }
                   1782:     default: sorstring(VOIR_STRING2,*g);
                   1783:   }
                   1784:   if (close_paren) pariputc(')');
                   1785: }
                   1786:
                   1787: /********************************************************************/
                   1788: /**                                                                **/
                   1789: /**                           TeX OUTPUT                           **/
                   1790: /**                                                                **/
                   1791: /********************************************************************/
                   1792:
                   1793: /* this follows bruti exactly */
1.2     ! noro     1794: void
        !          1795: texi(GEN g, pariout_t *T, int nosign)
1.1       noro     1796: {
                   1797:   long tg,i,j,l,r;
                   1798:   GEN a,b;
                   1799:   char *v, buf[67];
                   1800:
                   1801:   if (isnull(g)) { pariputs("{0}"); return; }
                   1802:   r = isone(g); pariputc('{');
                   1803:   if (r)
                   1804:   {
                   1805:     if (!nosign && r<0) pariputc('-');
                   1806:     pariputs("1}"); return;
                   1807:   }
                   1808:
                   1809:   tg = typ(g);
                   1810:   switch(tg)
                   1811:   {
1.2     ! noro     1812:     case t_SMALL: pariputsf("%ld",smalltos(g)); break;
        !          1813:     case t_INT:
        !          1814:       if (!nosign && signe(g) < 0) pariputc('-');
        !          1815:       wr_intpos(g); break;
        !          1816:     case t_REAL: wr_real(T,g,nosign); break;
1.1       noro     1817:
                   1818:     case t_INTMOD: case t_POLMOD:
1.2     ! noro     1819:       texi((GEN)g[2],T,0); pariputs(" mod ");
        !          1820:       texi((GEN)g[1],T,0); break;
1.1       noro     1821:
                   1822:     case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN:
1.2     ! noro     1823:       texi((GEN)g[1],T,nosign); pariputs("\\over");
        !          1824:       texi((GEN)g[2],T,0); break;
1.1       noro     1825:
                   1826:     case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD);
                   1827:       a = (GEN)g[r+1]; b = (GEN)g[r+2]; v = r? "w": "I";
                   1828:       if (isnull(a))
                   1829:       {
1.2     ! noro     1830:         wr_lead_texnome(T,b,v,1,nosign);
1.1       noro     1831:         break;
                   1832:       }
1.2     ! noro     1833:       texi(a,T,nosign);
        !          1834:       if (!isnull(b)) wr_texnome(T,b,v,1);
1.1       noro     1835:       break;
                   1836:
                   1837:     case t_POL: v = get_texvar(ordvar[varn(g)],buf);
                   1838:       /* hack: we want g[i] = coeff of degree i. */
                   1839:       i = degpol(g); g += 2; while (isnull((GEN)g[i])) i--;
1.2     ! noro     1840:       wr_lead_texnome(T,(GEN)g[i],v,i,nosign);
1.1       noro     1841:       while (i--)
                   1842:       {
                   1843:         a = (GEN)g[i];
1.2     ! noro     1844:         if (!isnull_for_pol(a)) wr_texnome(T,a,v,i);
1.1       noro     1845:       }
                   1846:       break;
                   1847:
                   1848:     case t_SER: v = get_texvar(ordvar[varn(g)],buf);
                   1849:       i = valp(g);
                   1850:       if (signe(g))
                   1851:       { /* hack: we want g[i] = coeff of degree i. */
                   1852:         l = i + lg(g)-2; g += (2-i);
1.2     ! noro     1853:         wr_lead_texnome(T,(GEN)g[i],v,i,nosign);
1.1       noro     1854:         while (++i < l)
                   1855:         {
                   1856:           a = (GEN)g[i];
1.2     ! noro     1857:           if (!isnull_for_pol(a)) wr_texnome(T,a,v,i);
1.1       noro     1858:         }
                   1859:         pariputs("+ ");
                   1860:       }
                   1861:       pariputs("O("); texnome(v,i); pariputc(')'); break;
                   1862:
                   1863:     case t_PADIC:
                   1864:     {
                   1865:       GEN p = (GEN)g[2];
                   1866:       i = valp(g); l = precp(g)+i;
                   1867:       g = (GEN)g[4]; v = GENtostr(p);
                   1868:       for (; i<l; i++)
                   1869:       {
                   1870:        g = dvmdii(g,p,&a);
                   1871:        if (signe(a))
                   1872:        {
                   1873:          if (!i || !is_pm1(a))
                   1874:          {
1.2     ! noro     1875:            wr_intpos(a); if (i) pariputs("\\cdot");
1.1       noro     1876:          }
                   1877:          if (i) padic_texnome(v,i);
                   1878:          pariputc('+');
                   1879:        }
                   1880:       }
                   1881:       pariputs("O("); padic_texnome(v,i); pariputc(')');
                   1882:       free(v); break;
                   1883:     }
                   1884:     case t_QFR: case t_QFI: r = (tg == t_QFR);
                   1885:       if (new_fun_set) pariputs("Qfb("); else pariputs(r? "qfr(": "qfi(");
1.2     ! noro     1886:       texi((GEN)g[1],T,0); pariputs(", ");
        !          1887:       texi((GEN)g[2],T,0); pariputs(", ");
        !          1888:       texi((GEN)g[3],T,0);
        !          1889:       if (r) { pariputs(", "); texi((GEN)g[4],T,0); }
1.1       noro     1890:       pariputc(')'); break;
                   1891:
                   1892:     case t_VEC:
                   1893:       pariputs("\\pmatrix{ "); l = lg(g);
                   1894:       for (i=1; i<l; i++)
                   1895:       {
1.2     ! noro     1896:        texi((GEN)g[i],T,0); if (i<lg(g)-1) pariputc('&');
1.1       noro     1897:       }
                   1898:       pariputs("\\cr}\n"); break;
                   1899:
                   1900:     case t_LIST:
                   1901:       pariputs("\\pmatrix{ "); l = lgef(g);
                   1902:       for (i=2; i<l; i++)
                   1903:       {
1.2     ! noro     1904:        texi((GEN)g[i],T,0); if (i<lgef(g)-1) pariputc('&');
1.1       noro     1905:       }
                   1906:       pariputs("\\cr}\n"); break;
                   1907:
                   1908:     case t_COL:
                   1909:       pariputs("\\pmatrix{ "); l = lg(g);
                   1910:       for (i=1; i<l; i++)
                   1911:       {
1.2     ! noro     1912:        texi((GEN)g[i],T,0); pariputs("\\cr\n");
1.1       noro     1913:       }
                   1914:       pariputc('}'); break;
                   1915:
                   1916:     case t_STR:
                   1917:       pariputs("\\mbox{"); pariputs(GSTR(g));
                   1918:       pariputc('}'); break;
                   1919:
                   1920:     case t_MAT:
                   1921:       pariputs("\\pmatrix{\n "); r = lg(g);
                   1922:       if (r>1)
                   1923:       {
                   1924:         l = lg(g[1]);
                   1925:         for (i=1; i<l; i++)
                   1926:         {
                   1927:           for (j=1; j<r; j++)
                   1928:           {
1.2     ! noro     1929:             texi(gcoeff(g,i,j),T,0); if (j<r-1) pariputc('&');
1.1       noro     1930:           }
                   1931:           pariputs("\\cr\n ");
                   1932:         }
                   1933:       }
                   1934:       pariputc('}'); break;
                   1935:   }
                   1936:   pariputc('}');
                   1937: }
                   1938:
                   1939: /*******************************************************************/
                   1940: /**                                                               **/
1.2     ! noro     1941: /**                          GP OUTPUT                            **/
        !          1942: /**                                                               **/
        !          1943: /*******************************************************************/
        !          1944:
        !          1945: /* EXTERNAL PRETTYPRINTER */
        !          1946:
        !          1947: /* Wait for prettinprinter to finish, to prevent new prompt from overwriting
        !          1948:  * the output.  Fill the output buffer, wait until it is read.
        !          1949:  * Better than sleep(2): give possibility to print */
        !          1950: static void
        !          1951: prettyp_wait(void)
        !          1952: {
        !          1953:   char *s = "                                                     \n";
        !          1954:   int i = 400;
        !          1955:
        !          1956:   pariputs("\n\n"); pariflush(); /* start translation */
        !          1957:   while (--i) pariputs(s);
        !          1958:   pariputs("\n"); pariflush();
        !          1959: }
        !          1960:
        !          1961: /* initialise external prettyprinter (tex2mail) */
        !          1962: static int
        !          1963: prettyp_init(void)
        !          1964: {
        !          1965:   gp_pp *pp = GP_DATA->pp;
        !          1966:   if (!pp->cmd) return 0;
        !          1967:   if (!pp->file)
        !          1968:     pp->file = try_pipe(pp->cmd, mf_OUT | mf_TEST);
        !          1969:   if (pp->file) return 1;
        !          1970:
        !          1971:   err(warner,"broken prettyprinter: '%s'",pp->cmd);
        !          1972:   free(pp->cmd); pp->cmd = NULL; return 0;
        !          1973: }
        !          1974:
        !          1975: /* n = history number. if n = 0 no history */
        !          1976: static int
        !          1977: tex2mail_output(GEN z, long n)
        !          1978: {
        !          1979:   pariout_t T = *(GP_DATA->fmt); /* copy */
        !          1980:   FILE *o_out;
        !          1981:
        !          1982:   if (!prettyp_init()) return 0;
        !          1983:   o_out = pari_outfile; /* save state */
        !          1984:
        !          1985:   /* Emit first: there may be lines before the prompt */
        !          1986:   if (n) term_color(c_OUTPUT);
        !          1987:   pariflush();
        !          1988:   pari_outfile = GP_DATA->pp->file->file;
        !          1989:   T.prettyp = f_TEX;
        !          1990:
        !          1991:   /* history number */
        !          1992:   if (n)
        !          1993:   {
        !          1994:     char s[128];
        !          1995:     if (*term_get_color(c_HIST) || *term_get_color(c_OUTPUT))
        !          1996:     {
        !          1997:       char col1[80];
        !          1998:       strcpy(col1, term_get_color(c_HIST));
        !          1999:       sprintf(s, "\\LITERALnoLENGTH{%s}\\%%%ld =\\LITERALnoLENGTH{%s} ",
        !          2000:               col1, n, term_get_color(c_OUTPUT));
        !          2001:     }
        !          2002:     else
        !          2003:       sprintf(s, "\\%%%ld = ", n);
        !          2004:     pariputs_opt(s);
        !          2005:   }
        !          2006:   /* output */
        !          2007:   gen_output(z, &T);
        !          2008:
        !          2009:   /* flush and restore */
        !          2010:   prettyp_wait();
        !          2011:   pari_outfile = o_out;
        !          2012:   if (n) term_color(c_NONE);
        !          2013:   return 1;
        !          2014: }
        !          2015:
        !          2016: /* TEXMACS */
        !          2017:
        !          2018: static void
        !          2019: texmacs_output(GEN z, long n)
        !          2020: {
        !          2021:   pariout_t T = *(GP_DATA->fmt); /* copy */
        !          2022:   char *sz;
        !          2023:
        !          2024:   T.prettyp = f_TEX;
        !          2025:   T.fieldw = 0;
        !          2026:   sz = GENtostr0(z, &T, &gen_output);
        !          2027:   printf("%clatex:", DATA_BEGIN);
        !          2028:   if (n)
        !          2029:     printf("\\magenta\\%%%ld = $\\blue ", n);
        !          2030:   else
        !          2031:     printf("$\\blue ");
        !          2032:   printf("%s$%c", sz,DATA_END); free(sz);
        !          2033:   fflush(stdout);
        !          2034: }
        !          2035:
        !          2036: /* REGULAR */
        !          2037:
        !          2038: static void
        !          2039: normal_output(GEN z, long n)
        !          2040: {
        !          2041:   long l = 0;
        !          2042:   /* history number */
        !          2043:   if (n)
        !          2044:   {
        !          2045:     char s[64];
        !          2046:     term_color(c_HIST);
        !          2047:     sprintf(s, "%%%ld = ", n);
        !          2048:     pariputs_opt(s);
        !          2049:     l = strlen(s);
        !          2050:   }
        !          2051:   /* output */
        !          2052:   term_color(c_OUTPUT);
        !          2053:   if (GP_DATA->lim_lines)
        !          2054:     lim_lines_output(z, GP_DATA->fmt, l, GP_DATA->lim_lines);
        !          2055:   else
        !          2056:     gen_output(z, GP_DATA->fmt);
        !          2057:   term_color(c_NONE); pariputc('\n');
        !          2058: }
        !          2059:
        !          2060: void
        !          2061: gp_output(GEN z, gp_data *G)
        !          2062: {
        !          2063:   if (G->flags & TEST) {
        !          2064:     init80(0);
        !          2065:     gen_output(z, G->fmt); pariputc('\n');
        !          2066:   }
        !          2067:   else if (G->flags & TEXMACS)
        !          2068:     texmacs_output(z, G->hist->total);
        !          2069:   else if (G->fmt->prettyp != f_PRETTY || !tex2mail_output(z, G->hist->total))
        !          2070:     normal_output(z, G->hist->total);
        !          2071:   pariflush();
        !          2072: }
        !          2073:
        !          2074: /*******************************************************************/
        !          2075: /**                                                               **/
1.1       noro     2076: /**                        USER OUTPUT FUNCTIONS                  **/
                   2077: /**                                                               **/
                   2078: /*******************************************************************/
                   2079:
                   2080: void
1.2     ! noro     2081: gen_output(GEN x, pariout_t *T)
1.1       noro     2082: {
1.2     ! noro     2083:   gpmem_t av = avma;
        !          2084:   GEN y = changevar(x, polvar);
        !          2085:   if (!T) T = &DFLT_OUTPUT;
        !          2086:   T->initial = 1;
        !          2087:   switch(T->prettyp)
        !          2088:   {
        !          2089:     case f_PRETTYMAT: matbruti(y, T); break;
        !          2090:     case f_PRETTY:
        !          2091:     case f_PRETTYOLD: sori (y, T); break;
        !          2092:     case f_RAW      : bruti(y, T, 0); break;
        !          2093:     case f_TEX      : texi (y, T, 0); break;
        !          2094:   }
        !          2095:   avma = av;
        !          2096: }
1.1       noro     2097:
1.2     ! noro     2098: static void
        !          2099: _initout(pariout_t *T, char f, long sigd, long sp, long fieldw, int prettyp)
        !          2100: {
        !          2101:   T->format = f;
        !          2102:   T->sigd = sigd;
        !          2103:   T->sp = sp;
        !          2104:   T->fieldw = fieldw;
        !          2105:   T->initial = 1;
        !          2106:   T->prettyp = prettyp;
        !          2107: }
        !          2108:
        !          2109: void
        !          2110: bruteall(GEN g, char f, long d, long sp)
        !          2111: {
        !          2112:   pariout_t T; _initout(&T,f,d,sp,0, f_RAW);
        !          2113:   gen_output(g, &T);
1.1       noro     2114: }
                   2115:
                   2116: void
                   2117: matbrute(GEN g, char f, long d)
                   2118: {
1.2     ! noro     2119:   pariout_t T; _initout(&T,f,d,1,0, f_PRETTYMAT);
        !          2120:   gen_output(g, &T);
1.1       noro     2121: }
                   2122:
                   2123: void
                   2124: sor(GEN g, char f, long d, long c)
                   2125: {
1.2     ! noro     2126:   pariout_t T; _initout(&T,f,d,1,c, f_PRETTYOLD);
        !          2127:   gen_output(g, &T);
1.1       noro     2128: }
                   2129:
                   2130: void
                   2131: texe(GEN g, char f, long d)
                   2132: {
1.2     ! noro     2133:   pariout_t T; _initout(&T,f,d,0,0, f_TEX);
        !          2134:   gen_output(g, &T);
1.1       noro     2135: }
                   2136:
                   2137: void
1.2     ! noro     2138: brute(GEN g, char f, long d) { bruteall(g,f,d,1); }
1.1       noro     2139:
                   2140: void
                   2141: outbrute(GEN g) { bruteall(g,'g',-1,1); }
                   2142:
                   2143: void
                   2144: outsor(GEN g) { sor(g,'g',-1,1); }
                   2145:
                   2146: void
                   2147: outtex(GEN g) { texe(g,'g',-1); }
                   2148:
                   2149: void
                   2150: output(GEN x)
                   2151: {
                   2152:   outbrute(x); pariputc('\n'); pariflush();
                   2153: }
                   2154:
                   2155: void
                   2156: outmat(GEN x)
                   2157: {
                   2158:   matbrute(x,'g',-1); pariputc('\n'); pariflush();
                   2159: }
                   2160:
                   2161: void
                   2162: outbeaut(GEN x)
                   2163: {
                   2164:   outsor(x); pariputc('\n'); pariflush();
                   2165: }
                   2166:
                   2167: void
                   2168: outerr(GEN x)
                   2169: {
                   2170:   PariOUT *out = pariOut; pariOut = pariErr;
                   2171:   output(x); pariOut = out;
                   2172: }
                   2173:
                   2174: void
                   2175: outbeauterr(GEN x)
                   2176: {
                   2177:   PariOUT *out = pariOut; pariOut = pariErr;
                   2178:   outbeaut(x); pariOut = out;
                   2179: }
                   2180:
                   2181: void
1.2     ! noro     2182: bruterr(GEN x,char format,long sigd)
1.1       noro     2183: {
                   2184:   PariOUT *out = pariOut; pariOut = pariErr;
1.2     ! noro     2185:   bruteall(x,format,sigd,1); pariOut = out;
1.1       noro     2186: }
                   2187:
                   2188: void
                   2189: fprintferr(char* format, ...)
                   2190: {
                   2191:   va_list args;
                   2192:   PariOUT *out = pariOut; pariOut = pariErr;
                   2193:
                   2194:   va_start(args, format); vpariputs(format,args);
                   2195:   va_end(args); pariOut = out;
                   2196: }
                   2197:
                   2198: /*******************************************************************/
                   2199: /**                            FILES                              **/
                   2200: /*******************************************************************/
                   2201: /* stack of temporary files (includes all infiles + some output) */
                   2202: static pariFILE *last_tmp_file = NULL;
                   2203: /* stack of "permanent" (output) files */
                   2204: static pariFILE *last_file = NULL;
                   2205: #if defined(UNIX) || defined(__EMX__)
                   2206: #  include <fcntl.h>
                   2207: #  include <sys/stat.h>
                   2208: #  include <pwd.h>
                   2209: #  ifdef __EMX__
                   2210: #    include <process.h>
                   2211: #  endif
                   2212: #  define HAVE_PIPES
                   2213: #endif
                   2214: #ifndef O_RDONLY
                   2215: #  define O_RDONLY 0
                   2216: #endif
                   2217:
                   2218: pariFILE *
                   2219: newfile(FILE *f, char *name, int type)
                   2220: {
                   2221:   pariFILE *file = (pariFILE*) gpmalloc(strlen(name) + 1 + sizeof(pariFILE));
                   2222:   file->type = type;
                   2223:   file->name = strcpy((char*)(file+1), name);
                   2224:   file->file = f;
                   2225:   file->next = NULL;
                   2226:   if (type & mf_PERM)
                   2227:   {
                   2228:     file->prev = last_file;
                   2229:     last_file = file;
                   2230:   }
                   2231:   else
                   2232:   {
                   2233:     file->prev = last_tmp_file;
                   2234:     last_tmp_file = file;
                   2235:   }
                   2236:   if (file->prev) (file->prev)->next = file;
                   2237:   if (DEBUGFILES)
                   2238:     fprintferr("I/O: opening file %s (code %d) \n",name,type);
                   2239:   return file;
                   2240: }
                   2241:
                   2242: static void
                   2243: pari_kill_file(pariFILE *f)
                   2244: {
                   2245:   if ((f->type & mf_PIPE) == 0)
                   2246:   {
                   2247:     if (fclose(f->file)) err(warnfile, "close", f->name);
                   2248:   }
                   2249: #ifdef HAVE_PIPES
                   2250:   else
                   2251:   {
                   2252:     if (f->type & mf_FALSE)
                   2253:     {
                   2254:       if (fclose(f->file)) err(warnfile, "close", f->name);
                   2255:       if (unlink(f->name)) err(warnfile, "delete", f->name);
                   2256:     }
                   2257:     else
                   2258:       if (pclose(f->file) < 0) err(warnfile, "close pipe", f->name);
                   2259:   }
                   2260: #endif
                   2261:   if (DEBUGFILES)
                   2262:     fprintferr("I/O: closing file %s (code %d) \n",f->name,f->type);
                   2263:   free(f);
                   2264: }
                   2265:
                   2266: void
                   2267: pari_fclose(pariFILE *f)
                   2268: {
                   2269:   if (f->next) (f->next)->prev = f->prev;
                   2270:   else if (f == last_tmp_file) last_tmp_file = f->prev;
                   2271:   else if (f == last_file) last_file = f->prev;
                   2272:   if (f->prev) (f->prev)->next = f->next;
                   2273:   pari_kill_file(f);
                   2274: }
                   2275:
                   2276: static pariFILE *
                   2277: pari_open_file(FILE *f, char *s, char *mode)
                   2278: {
                   2279:   if (!f) err(talker, "could not open requested file %s", s);
                   2280:   if (DEBUGFILES)
                   2281:     fprintferr("I/O: opening file %s (mode %s)\n", s, mode);
                   2282:   return newfile(f,s,0);
                   2283: }
                   2284:
                   2285: pariFILE *
                   2286: pari_fopen(char *s, char *mode)
                   2287: {
                   2288:   return pari_open_file(fopen(s, mode), s, mode);
                   2289: }
                   2290:
                   2291: #ifdef UNIX
                   2292: /* open tmpfile s (a priori for writing) avoiding symlink attacks */
                   2293: pariFILE *
                   2294: pari_safefopen(char *s, char *mode)
                   2295: {
                   2296:   long fd = open(s, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
                   2297:
                   2298:   if (fd == -1) err(talker,"tempfile %s already exists",s);
                   2299:   return pari_open_file(fdopen(fd, mode), s, mode);
                   2300: }
                   2301: #else
                   2302: pariFILE *
                   2303: pari_safefopen(char *s, char *mode)
                   2304: {
                   2305:   return pari_fopen(s, mode);
                   2306: }
                   2307: #endif
                   2308:
                   2309: void
                   2310: pari_unlink(char *s)
                   2311: {
                   2312:   if (unlink(s)) err(warner, "I/O: can\'t remove file %s", s);
                   2313:   else if (DEBUGFILES)
                   2314:     fprintferr("I/O: removed file %s\n", s);
                   2315: }
                   2316:
1.2     ! noro     2317: void
        !          2318: check_filtre(filtre_t *T)
        !          2319: {
        !          2320:   if (T && T->in_string)
        !          2321:   {
        !          2322:     err(warner,"run-away string. Closing it");
        !          2323:     T->in_string = 0;
        !          2324:   }
        !          2325:   if (T && T->in_comment)
        !          2326:   {
        !          2327:     err(warner,"run-away comment. Closing it");
        !          2328:     T->in_comment = 0;
        !          2329:   }
        !          2330: }
        !          2331:
1.1       noro     2332: /* Remove one INFILE from the stack. Reset infile (to the most recent infile)
                   2333:  * Return -1, if we're trying to pop out stdin itself; 0 otherwise
                   2334:  * Check for leaked file handlers (temporary files)
                   2335:  */
                   2336: int
                   2337: popinfile()
                   2338: {
                   2339:   pariFILE *f;
                   2340:   for (f = last_tmp_file; f; f = f->prev)
                   2341:   {
                   2342:     if (f->type & mf_IN) break;
                   2343:     err(warner, "I/O: leaked file descriptor (%d): %s",
                   2344:                f->type, f->name);
                   2345:     pari_fclose(f);
                   2346:   }
                   2347:   last_tmp_file = f; if (!last_tmp_file) return -1;
                   2348:   pari_fclose(last_tmp_file);
                   2349:   for (f = last_tmp_file; f; f = f->prev)
                   2350:     if (f->type & mf_IN) { infile = f->file; return 0; }
                   2351:   infile = stdin; return 0;
                   2352: }
                   2353:
                   2354: static void
                   2355: kill_file_stack(pariFILE **s)
                   2356: {
                   2357:   pariFILE *f = *s;
                   2358:   while (f)
                   2359:   {
                   2360:     pariFILE *t = f->prev;
                   2361:     pari_kill_file(f);
                   2362:     *s = f = t; /* have to update *s in case of ^C */
                   2363:   }
                   2364: }
                   2365:
                   2366: void
                   2367: killallfiles(int leaving)
                   2368: {
                   2369:   if (leaving)
                   2370:   {
                   2371:     popinfile(); /* look for leaks */
                   2372:     kill_file_stack(&last_file);
                   2373:   }
                   2374:   kill_file_stack(&last_tmp_file);
                   2375:   infile = stdin;
                   2376: }
                   2377:
                   2378: pariFILE *
                   2379: try_pipe(char *cmd, int fl)
                   2380: {
                   2381: #ifndef HAVE_PIPES
                   2382:   err(archer); return NULL;
                   2383: #else
                   2384:   FILE *file;
                   2385:   char *f;
1.2     ! noro     2386:   int flag = fl;
1.1       noro     2387:
                   2388: #  ifdef __EMX__
                   2389:   if (_osmode == DOS_MODE) /* no pipes under DOS */
                   2390:   {
                   2391:     char *s;
                   2392:     if (flag & mf_OUT) err(archer);
                   2393:     f = pari_unique_filename("pipe");
                   2394:     s = gpmalloc(strlen(cmd)+strlen(f)+4);
                   2395:     sprintf(s,"%s > %s",cmd,f);
                   2396:     file = system(s)? NULL: (FILE *) fopen(f,"r");
                   2397:     flag |= mf_FALSE; free(s);
                   2398:   }
                   2399:   else
                   2400: #  endif
                   2401:   {
                   2402:     file = (FILE *) popen(cmd, (flag & mf_OUT)? "w": "r");
                   2403:     if (flag & mf_OUT) flag |= mf_PERM;
                   2404:     if (flag & (mf_TEST | mf_OUT))
                   2405:     {
                   2406:       if (DEBUGFILES) fprintferr("I/O: checking output pipe...\n");
1.2     ! noro     2407:       CATCH(-1) { file = NULL; }
        !          2408:       TRY {
        !          2409:         int i;
        !          2410:         fprintf(file,"\n\n"); fflush(file);
        !          2411:         for (i=1; i<1000; i++) fprintf(file,"                  \n");
        !          2412:         fprintf(file,"\n"); fflush(file);
        !          2413:       } ENDCATCH;
        !          2414:       if (!file) return NULL;
1.1       noro     2415:     }
                   2416:     f = cmd;
                   2417:   }
                   2418:   if (!file) err(talker,"[pipe:] '%s' failed",cmd);
                   2419:   return newfile(file, f, mf_PIPE|flag);
                   2420: #endif
                   2421: }
                   2422:
                   2423: void
                   2424: os_close(long fd)
                   2425: {
                   2426: #ifdef WINCE
                   2427:   CloseHandle((HANDLE)fd);
                   2428: #else
                   2429:   close(fd);
                   2430: #endif
                   2431: }
                   2432:
                   2433: void
                   2434: (*os_signal(int sig, void (*f)(int)))(int)
                   2435: {
                   2436: #ifdef WINCE
                   2437:   return SIG_IGN;
                   2438: #else
                   2439:   return signal(sig,f);
                   2440: #endif
                   2441: }
                   2442:
                   2443: void
                   2444: os_read(long fd, char ch[], long s)
                   2445: {
                   2446: #ifdef WINCE
                   2447:   DWORD chRead;
                   2448:   ReadFile((HANDLE)fd, ch, s, &chRead, NULL);
                   2449: #else
1.2     ! noro     2450:   (void)read(fd,ch,s);
1.1       noro     2451: #endif
                   2452: }
                   2453:
                   2454: long
                   2455: os_open(char *s, int mode)
                   2456: {
                   2457:   long fd;
                   2458: #ifdef WINCE
                   2459:   HANDLE h;
                   2460:   short ws[256];
                   2461:   if (mode != O_RDONLY) err(impl,"generic open for Windows");
                   2462:   MultiByteToWideChar(CP_ACP, 0, s, strlen(s)+1, ws, 256);
                   2463:   h = CreateFile(ws,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
                   2464:   fd = (h == INVALID_HANDLE_VALUE)? (long)-1: (long)h;
                   2465: #else
                   2466:   fd = open(s,mode);
                   2467: #endif
                   2468:   return fd;
                   2469: }
                   2470:
                   2471: char *
                   2472: os_getenv(char *s)
                   2473: {
                   2474: #if defined(WINCE) || defined(macintosh)
                   2475:   return NULL;
                   2476: #else
                   2477:   return getenv(s);
                   2478: #endif
                   2479: }
                   2480:
                   2481: /*******************************************************************/
                   2482: /**                                                               **/
                   2483: /**                   GP STANDARD INPUT AND OUTPUT                **/
                   2484: /**                                                               **/
                   2485: /*******************************************************************/
                   2486: static char *last_filename = NULL;
                   2487:
                   2488: #ifdef HAS_OPENDIR
                   2489: #  include <dirent.h>
                   2490: #endif
                   2491: /* slow, but more portable than stat + S_I[FS]DIR */
                   2492: int
                   2493: pari_is_dir(char *name)
                   2494: {
                   2495: #ifdef HAS_OPENDIR
                   2496:   DIR *d = opendir(name);
                   2497:   if (d) { (void)closedir(d); return 1; }
                   2498: #endif
                   2499:   return 0;
                   2500: }
                   2501:
                   2502: /* expand tildes in filenames, return a malloc'ed buffer */
                   2503: static char *
                   2504: _expand_tilde(char *s)
                   2505: {
                   2506: #if !defined(UNIX) && !defined(__EMX__)
                   2507:   return pari_strdup(s);
                   2508: #else
                   2509:   struct passwd *p;
                   2510:   char *u;
                   2511:   int len;
                   2512:
                   2513:   if (*s != '~') return pari_strdup(s);
                   2514:   s++; u = s; /* skip ~ */
                   2515:   if (!*s || *s == '/')
                   2516:   {
                   2517:     p = getpwuid(geteuid());
                   2518:     if (!p)
                   2519:     { /* host badly configured, don't kill session on startup
                   2520:        * (when expanding path) */
                   2521:       err(warner,"can't expand ~");
                   2522:       return pari_strdup(s);
                   2523:     }
                   2524:   }
                   2525:   else
                   2526:   {
                   2527:     char *tmp;
                   2528:     while (*u && *u != '/') u++;
                   2529:     len = u-s;
                   2530:     tmp = strncpy(gpmalloc(len+1),s,len);
                   2531:     tmp[len] = 0;
                   2532:     p = getpwnam(tmp); free(tmp);
                   2533:   }
                   2534:   if (!p) err(talker2,"unknown user ",s,s-1);
                   2535:   s = gpmalloc(strlen(p->pw_dir) + strlen(u) + 1);
                   2536:   sprintf(s,"%s%s",p->pw_dir,u); return s;
                   2537: #endif
                   2538: }
                   2539:
                   2540: /* expand environment variables in str, return a malloc'ed buffer
                   2541:  * assume no \ remain and str can be freed */
                   2542: static char *
                   2543: _expand_env(char *str)
                   2544: {
                   2545: #if defined(WINCE) || defined(macintosh)
                   2546:   return str;
                   2547: #else
                   2548:   long i, l, len = 0, xlen = 16, xnum = 0;
                   2549:   char *s = str, *s0 = s, *env;
                   2550:   char **x = (char **)gpmalloc(xlen * sizeof(char*));
                   2551:
                   2552:   while (*s)
                   2553:   {
                   2554:     if (*s != '$') { s++; continue; }
                   2555:     l = s - s0;
                   2556:     if (l)
                   2557:     {
                   2558:       s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0;
                   2559:       x[xnum++] = s0; len += l;
                   2560:     }
                   2561:     if (xnum > xlen - 3) /* need room for possibly two more elts */
                   2562:     {
1.2     ! noro     2563:       xlen <<= 1;
        !          2564:       x = (char **)gprealloc((void*)x, xlen * sizeof(char*));
1.1       noro     2565:     }
                   2566:
                   2567:     s0 = ++s; /* skip $ */
                   2568:     while (is_keyword_char(*s)) s++;
                   2569:     l = s - s0;
                   2570:     env = strncpy(gpmalloc(l+1), s0, l); env[l] = 0;
                   2571:     s0 = getenv(env);
                   2572:     if (!s0)
                   2573:     {
                   2574:       err(warner,"undefined environment variable: %s",env);
                   2575:       s0 = "";
                   2576:     }
                   2577:     l = strlen(s0);
                   2578:     if (l)
                   2579:     {
                   2580:       s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0;
                   2581:       x[xnum++] = s0; len += l;
                   2582:     }
                   2583:     free(env); s0 = s;
                   2584:   }
                   2585:   l = s - s0;
                   2586:   if (l)
                   2587:   {
                   2588:     s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0;
                   2589:     x[xnum++] = s0; len += l;
                   2590:   }
                   2591:
                   2592:   s = gpmalloc(len+1); *s = 0;
                   2593:   for (i = 0; i < xnum; i++) { (void)strcat(s, x[i]); free(x[i]); }
                   2594:   free(str); free(x); return s;
                   2595: #endif
                   2596: }
                   2597:
                   2598: char *
                   2599: expand_tilde(char *s)
                   2600: {
                   2601:   return _expand_env(_expand_tilde(s));
                   2602: }
                   2603:
1.2     ! noro     2604: void
        !          2605: delete_dirs(gp_path *p)
        !          2606: {
        !          2607:   char **v = p->dirs, **dirs;
        !          2608:   if (v)
        !          2609:   {
        !          2610:     p->dirs = NULL; /* in case of error */
        !          2611:     for (dirs = v; *dirs; dirs++) free(*dirs);
        !          2612:     free(v);
        !          2613:   }
        !          2614: }
        !          2615:
1.1       noro     2616: #if defined __EMX__ || defined _WIN32
                   2617: #  define PATH_SEPARATOR ';'
                   2618: #else
                   2619: #  define PATH_SEPARATOR ':'
                   2620: #endif
                   2621:
                   2622: void
1.2     ! noro     2623: gp_expand_path(gp_path *p)
1.1       noro     2624: {
1.2     ! noro     2625:   char **dirs, *s, *v = p->PATH;
1.1       noro     2626:   int i, n = 0;
                   2627:
1.2     ! noro     2628:   delete_dirs(p);
1.1       noro     2629:   v = pari_strdup(v);
                   2630:   for (s=v; *s; s++)
                   2631:     if (*s == PATH_SEPARATOR) { *s = 0; n++; }
1.2     ! noro     2632:   dirs = (char**) gpmalloc((n + 2)*sizeof(char *));
1.1       noro     2633:
                   2634:   for (s=v, i=0; i<=n; i++)
                   2635:   {
                   2636:     char *end = s + strlen(s), *f = end;
                   2637:     while (f > s && *--f == '/') *f = 0;
1.2     ! noro     2638:     dirs[i] = expand_tilde(s);
1.1       noro     2639:     s = end + 1; /* next path component */
                   2640:   }
1.2     ! noro     2641:   free((void*)v);
        !          2642:   dirs[i] = NULL; p->dirs = dirs;
1.1       noro     2643: }
                   2644:
                   2645: /* name is a malloc'ed (existing) filename. Accept it as new infile
                   2646:  * (unzip if needed). */
                   2647: static FILE *
                   2648: accept_file(char *name, FILE *file)
                   2649: {
                   2650:   if (pari_is_dir(name))
                   2651:   {
                   2652:     err(warner,"skipping directory %s",name);
                   2653:     return NULL;
                   2654:   }
                   2655:   if (! last_tmp_file)
                   2656:   {  /* empty file stack, record this name */
                   2657:     if (last_filename) free(last_filename);
                   2658:     last_filename = pari_strdup(name);
                   2659:   }
                   2660: #ifdef ZCAT
                   2661:   {
                   2662:     long l = strlen(name);
                   2663:     char *end = name + l-1;
                   2664:
                   2665:     if (l > 2 && (!strncmp(end-1,".Z",2)
                   2666: #ifdef GNUZCAT
                   2667:                || !strncmp(end-2,".gz",3)
                   2668: #endif
                   2669:     ))
                   2670:     { /* compressed file (compress or gzip) */
                   2671:       char *cmd = gpmalloc(strlen(ZCAT) + l + 2);
                   2672:       sprintf(cmd,"%s %s",ZCAT,name);
                   2673:       fclose(file); infile = try_pipe(cmd, mf_IN)->file;
                   2674:       free(cmd); return infile;
                   2675:     }
                   2676:   }
                   2677: #endif
                   2678:   return infile = newfile(file, name, mf_IN)->file;
                   2679: }
                   2680:
                   2681: /* If a file called "name" exists (possibly after appending ".gp")
                   2682:  * record it in the file_stack (as a pipe if compressed).
                   2683:  * name is malloc'ed, we free it before returning
                   2684:  */
                   2685: static FILE *
                   2686: try_name(char *name)
                   2687: {
                   2688:   FILE *file = fopen(name, "r");
                   2689:   if (file) file = accept_file(name,file);
                   2690:   if (!file)
                   2691:   { /* try appending ".gp" to name */
                   2692:     char *s = gpmalloc(strlen(name)+4);
                   2693:     sprintf(s, "%s.gp", name);
                   2694:     file = fopen(s, "r");
                   2695:     if (file) file = accept_file(s,file);
                   2696:     free(s);
                   2697:   }
                   2698:   free(name); return file;
                   2699: }
                   2700:
                   2701: /* If name = "", re-read last file */
                   2702: void
                   2703: switchin(char *name0)
                   2704: {
                   2705:   char *s, *name;
                   2706:
                   2707:   if (*name0)
                   2708:     name = expand_tilde(name0);
                   2709:   else
                   2710:   {
                   2711:     if (last_filename == NULL)
                   2712:       err(talker,"You never gave me anything to read!");
                   2713:     name0 = last_filename;
                   2714:     name = pari_strdup(name0);
                   2715:   }
                   2716:   /* if name contains '/',  don't use dir_list */
                   2717:   s=name; while (*s && *s != '/' && *s != '\\') s++;
                   2718:   if (*s) { if (try_name(name)) return; }
1.2     ! noro     2719:   else if (GP_DATA)
1.1       noro     2720:   {
1.2     ! noro     2721:     char **tmp = GP_DATA->path->dirs;
1.1       noro     2722:     for ( ; *tmp; tmp++)
                   2723:     { /* make room for '/' and '\0', try_name frees it */
                   2724:       s = gpmalloc(2 + strlen(*tmp) + strlen(name));
                   2725:       sprintf(s,"%s/%s",*tmp,name);
                   2726:       if (try_name(s)) return;
                   2727:     }
                   2728:   }
                   2729:   err(openfiler,"input",name0);
                   2730: }
                   2731:
1.2     ! noro     2732: static int is_magic_ok(FILE *f);
        !          2733:
1.1       noro     2734: void
                   2735: switchout(char *name)
                   2736: {
                   2737:   if (name)
                   2738:   {
1.2     ! noro     2739:     FILE *f = fopen(name, "r");
        !          2740:     if (f)
        !          2741:     {
        !          2742:       if (is_magic_ok(f))
        !          2743:         err(talker,"%s is a GP binary file. Please use writebin", name);
        !          2744:       fclose(f);
        !          2745:     }
        !          2746:     f = fopen(name, "a");
1.1       noro     2747:     if (!f) err(openfiler,"output",name);
                   2748:     pari_outfile = f;
                   2749:   }
                   2750:   else if (pari_outfile != stdout)
                   2751:   {
                   2752:     fclose(pari_outfile);
                   2753:     pari_outfile = stdout;
                   2754:   }
                   2755: }
                   2756:
                   2757: /*******************************************************************/
                   2758: /**                                                               **/
                   2759: /**                    I/O IN BINARY FORM                         **/
                   2760: /**                                                               **/
                   2761: /*******************************************************************/
                   2762: #define _fwrite(a,b,c,d) \
                   2763:   if (fwrite((a),(b),(c),(d)) < (c)) err(talker,"write failed")
                   2764: #define _fread(a,b,c,d) \
                   2765:   if (fread((a),(b),(c),(d)) < (c)) err(talker,"read failed")
                   2766: #define _lfread(a,b,c) _fread((a),sizeof(long),(b),(c))
                   2767: #define _cfread(a,b,c) _fread((a),sizeof(char),(b),(c))
                   2768: #define _lfwrite(a,b,c) _fwrite((a),sizeof(long),(b),(c))
                   2769: #define _cfwrite(a,b,c) _fwrite((a),sizeof(char),(b),(c))
                   2770:
                   2771: #define BIN_GEN 0
1.2     ! noro     2772: #define NAM_GEN 1
1.1       noro     2773:
                   2774: static long
                   2775: rd_long(FILE *f)
                   2776: {
                   2777:   long L;
                   2778:   _lfread(&L, 1, f); return L;
                   2779: }
                   2780: static void
                   2781: wr_long(long L, FILE *f)
                   2782: {
                   2783:   _lfwrite(&L, 1, f);
                   2784: }
                   2785:
                   2786: /* append x to file f */
                   2787: static void
                   2788: wrGEN(GEN x, FILE *f)
                   2789: {
                   2790:   GENbin *p = copy_bin(x);
                   2791:   long L = p->len;
                   2792:
                   2793:   wr_long(L,f);
                   2794:   wr_long((long)p->x,f);
                   2795:   wr_long((long)p->base,f);
                   2796:   _lfwrite(GENbase(p), L,f);
                   2797:   free((void*)p);
                   2798: }
                   2799:
                   2800: static void
                   2801: wrstr(char *s, FILE *f)
                   2802: {
                   2803:   long L = strlen(s)+1;
                   2804:   wr_long(L,f);
                   2805:   _cfwrite(s, L, f);
                   2806: }
                   2807:
                   2808: static char *
                   2809: rdstr(FILE *f)
                   2810: {
                   2811:   long L = rd_long(f);
                   2812:   char *s;
                   2813:   if (!L) return NULL;
                   2814:   s = gpmalloc(L);
                   2815:   _cfread(s, L, f); return s;
                   2816: }
                   2817:
                   2818: void
                   2819: writeGEN(GEN x, FILE *f)
                   2820: {
                   2821:   fputc(BIN_GEN,f);
                   2822:   wrGEN(x, f);
                   2823: }
                   2824:
                   2825: void
                   2826: writenamedGEN(GEN x, char *s, FILE *f)
                   2827: {
                   2828:   fputc(NAM_GEN,f);
                   2829:   wrstr(s, f);
                   2830:   wrGEN(x, f);
                   2831: }
                   2832:
                   2833: /* read a GEN from file f */
                   2834: static GEN
                   2835: rdGEN(FILE *f)
                   2836: {
                   2837:   long L = rd_long(f);
                   2838:   GENbin *p;
                   2839:
                   2840:   if (!L) return NULL;
                   2841:   p = (GENbin*)gpmalloc(sizeof(GENbin) + L*sizeof(long));
                   2842:   p->len  = L;
                   2843:   p->x    = (GEN)rd_long(f);
                   2844:   p->base = (GEN)rd_long(f);
                   2845:   _lfread(GENbase(p), L,f);
                   2846:   return bin_copy(p);
                   2847: }
                   2848:
                   2849: GEN
1.2     ! noro     2850: readobj(FILE *f, int *ptc)
1.1       noro     2851: {
                   2852:   int c = fgetc(f);
                   2853:   GEN x = NULL;
                   2854:   switch(c)
                   2855:   {
                   2856:     case BIN_GEN:
                   2857:       x = rdGEN(f);
                   2858:       if (!x) err(talker,"malformed binary file (no GEN)");
                   2859:       break;
                   2860:     case NAM_GEN:
                   2861:     {
                   2862:       char *s = rdstr(f);
                   2863:       if (!s) err(talker,"malformed binary file (no name)");
                   2864:       x = rdGEN(f);
                   2865:       if (!x) err(talker,"malformed binary file (no GEN)");
                   2866:       fprintferr("setting %s\n",s);
                   2867:       changevalue(fetch_named_var(s,0), x);
                   2868:       break;
                   2869:     }
                   2870:     case EOF: break;
                   2871:     default: err(talker,"unknown code in readobj");
                   2872:   }
1.2     ! noro     2873:   *ptc = c; return x;
1.1       noro     2874: }
                   2875:
                   2876: #define MAGIC "\020\001\022\011-\007\020" /* ^P^A^R^I-^G^P */
                   2877: #ifdef LONG_IS_64BIT
                   2878: #  define ENDIAN_CHECK 0x0102030405060708L
                   2879: #else
                   2880: #  define ENDIAN_CHECK 0x01020304L
                   2881: #endif
                   2882: const long BINARY_VERSION = 0;
                   2883:
                   2884: static int
                   2885: is_magic_ok(FILE *f)
                   2886: {
                   2887:   int L = strlen(MAGIC);
                   2888:   char *s = gpmalloc(L);
                   2889:   int r = (fread(s,1,L, f) == L && strncmp(s,MAGIC,L) == 0);
                   2890:   free(s); return r;
                   2891: }
                   2892:
                   2893: static int
                   2894: is_sizeoflong_ok(FILE *f)
                   2895: {
                   2896:   char c;
1.2     ! noro     2897:   return (fread(&c,1,1, f) == 1 && c == (char)sizeof(long));
1.1       noro     2898: }
                   2899:
                   2900: static int
                   2901: is_long_ok(FILE *f, long L)
                   2902: {
                   2903:   long c;
                   2904:   return (fread(&c,sizeof(long),1, f) == 1 && c == L);
                   2905: }
                   2906:
                   2907: static void
                   2908: check_magic(char *name, FILE *f)
                   2909: {
                   2910:   if (!is_magic_ok(f))
                   2911:     err(talker, "%s is not a GP binary file",name);
                   2912:   if (!is_sizeoflong_ok(f))
                   2913:     err(talker, "%s not written for a %ld bit architecture",
                   2914:                name, sizeof(long)*8);
                   2915:   if (!is_long_ok(f, ENDIAN_CHECK))
                   2916:     err(talker, "unexpected endianness in %s",name);
                   2917:   if (!is_long_ok(f, BINARY_VERSION))
                   2918:     err(talker, "%s written by an incompatible version of GP",name);
                   2919: }
                   2920:
                   2921: static void
                   2922: write_magic(FILE *f)
                   2923: {
                   2924:   fprintf(f, MAGIC);
1.2     ! noro     2925:   fprintf(f, "%c", (char)sizeof(long));
1.1       noro     2926:   wr_long(ENDIAN_CHECK, f);
                   2927:   wr_long(BINARY_VERSION, f);
                   2928: }
                   2929:
                   2930: int
                   2931: file_is_binary(FILE *f)
                   2932: {
1.2     ! noro     2933:   int c = fgetc(f); ungetc(c,f);
        !          2934:   return (isprint(c) == 0 && isspace(c) == 0);
1.1       noro     2935: }
                   2936:
                   2937: void
                   2938: writebin(char *name, GEN x)
                   2939: {
                   2940:   FILE *f = fopen(name,"r");
                   2941:   int already = f? 1: 0;
                   2942:
                   2943:   if (f) { check_magic(name,f); fclose(f); }
                   2944:   f = fopen(name,"a");
                   2945:   if (!f) err(openfiler,"binary output",name);
                   2946:   if (!already) write_magic(f);
                   2947:
                   2948:   if (x) writeGEN(x,f);
                   2949:   else
                   2950:   {
                   2951:     long v, maxv = manage_var(3,NULL);
                   2952:     for (v=0; v<maxv; v++)
                   2953:     {
                   2954:       entree *ep = varentries[v];
                   2955:       if (!ep) continue;
1.2     ! noro     2956:       writenamedGEN((GEN)ep->value,ep->name,f);
1.1       noro     2957:     }
                   2958:   }
                   2959:   fclose(f);
                   2960: }
                   2961:
1.2     ! noro     2962: /* read all objects in f. If f contains BIN_GEN that would be silently ignored
        !          2963:  * [i.e f contains more than one objet, not all of them 'named GENs'], return
        !          2964:  * them all in a vector with clone bit set (special marker). */
1.1       noro     2965: GEN
                   2966: readbin(char *name, FILE *f)
                   2967: {
1.2     ! noro     2968:   gpmem_t av = avma;
        !          2969:   GEN x,y,z;
        !          2970:   int cx,cy;
        !          2971:   check_magic(name,f); x = y = z = NULL;
        !          2972:   cx = 0; /* gcc -Wall */
        !          2973:   while ((y = readobj(f, &cy)))
        !          2974:   {
        !          2975:     if (x && cx == BIN_GEN) z = z? concatsp(z, _vec(x)): _vec(x);
        !          2976:     x = y; cx = cy;
        !          2977:   }
        !          2978:   if (z)
        !          2979:   {
        !          2980:     if (x && cx == BIN_GEN) z = z? concatsp(z, _vec(x)): _vec(x);
        !          2981:     if (DEBUGLEVEL)
        !          2982:       err(warner,"%ld unnamed objects read. Returning then in a vector",
        !          2983:           lg(z)-1);
        !          2984:     x = gerepilecopy(av, z);
        !          2985:     setisclone(x); /* HACK */
        !          2986:   }
1.1       noro     2987:   return x;
                   2988: }
                   2989:
                   2990: /*******************************************************************/
                   2991: /**                                                               **/
1.2     ! noro     2992: /**                             GP I/O                            **/
        !          2993: /**                                                               **/
        !          2994: /*******************************************************************/
        !          2995: /* print a sequence of (NULL terminated) GEN */
        !          2996: void
        !          2997: print0(GEN *g, long flag)
        !          2998: {
        !          2999:   pariout_t T = GP_DATA? *(GP_DATA->fmt): DFLT_OUTPUT; /* copy */
        !          3000:   T.prettyp = flag;
        !          3001:   for( ; *g; g++)
        !          3002:     if (typ(*g)==t_STR)
        !          3003:       pariputs(GSTR(*g)); /* text surrounded by "" otherwise */
        !          3004:     else
        !          3005:       gen_output(*g, &T);
        !          3006: }
        !          3007:
        !          3008: #define PR_NL() {added_newline = 1; pariputc('\n'); pariflush(); }
        !          3009: #define PR_NO() {added_newline = 0; pariflush(); }
        !          3010: void print   (GEN *g) { print0(g, f_RAW);       PR_NL(); }
        !          3011: void printp  (GEN *g) { print0(g, f_PRETTYOLD); PR_NL(); }
        !          3012: void printtex(GEN *g) { print0(g, f_TEX);       PR_NL(); }
        !          3013: void print1  (GEN *g) { print0(g, f_RAW);       PR_NO(); }
        !          3014: void printp1 (GEN *g) { print0(g, f_PRETTYOLD); PR_NO(); }
        !          3015:
        !          3016: void error0(GEN *g) { err(user, g); }
        !          3017:
        !          3018: static char *
        !          3019: wr_check(char *s) {
        !          3020:   char *t = expand_tilde(s);
        !          3021:   if (GP_DATA && GP_DATA->flags & SECURE)
        !          3022:   {
        !          3023:     fprintferr("[secure mode]: about to write to '%s'. OK ? (^C if not)\n",t);
        !          3024:     hit_return();
        !          3025:   }
        !          3026:   return t;
        !          3027: }
        !          3028:
        !          3029: static void wr_init(char *s)    { char *t=wr_check(s); switchout(t);   free(t);}
        !          3030: void gpwritebin(char *s, GEN x) { char *t=wr_check(s); writebin(t, x); free(t);}
        !          3031:
        !          3032: #define WR_NL() {pariputc('\n'); pariflush(); switchout(NULL); }
        !          3033: #define WR_NO() {pariflush(); switchout(NULL); }
        !          3034: void write0  (char *s, GEN *g) { wr_init(s); print0(g, f_RAW); WR_NL(); }
        !          3035: void writetex(char *s, GEN *g) { wr_init(s); print0(g, f_TEX); WR_NL(); }
        !          3036: void write1  (char *s, GEN *g) { wr_init(s); print0(g, f_RAW); WR_NO(); }
        !          3037:
        !          3038: /*******************************************************************/
        !          3039: /**                                                               **/
        !          3040: /**                       HISTORY HANDLING                        **/
        !          3041: /**                                                               **/
        !          3042: /*******************************************************************/
        !          3043: /* history management function:
        !          3044:  *   p > 0, called from %p
        !          3045:  *   p <= 0, called from %` (p backquotes, possibly 0) */
        !          3046: GEN
        !          3047: gp_history(gp_hist *H, long p, char *old, char *entry)
        !          3048: {
        !          3049:   GEN z;
        !          3050:
        !          3051:   if (p <= 0) p += H->total; /* count |p| entries starting from last */
        !          3052:   if ((ulong)p > H->total)
        !          3053:     err(talker2, "I can't see into the future", old, entry);
        !          3054:
        !          3055:   z = H->res[ (p-1) % H->size ];
        !          3056:   if (!z || p <= 0 || p <= (long)(H->total - H->size))
        !          3057:     err(talker2, "I can't remember before the big bang", old, entry);
        !          3058:   return z;
        !          3059: }
        !          3060:
        !          3061: GEN
        !          3062: set_hist_entry(gp_hist *H, GEN x)
        !          3063: {
        !          3064:   int i = H->total % H->size;
        !          3065:   H->total++;
        !          3066:   if (H->res[i]) gunclone(H->res[i]);
        !          3067:   return H->res[i] = gclone(x);
        !          3068: }
        !          3069:
        !          3070: /*******************************************************************/
        !          3071: /**                                                               **/
1.1       noro     3072: /**                       TEMPORARY FILES                         **/
                   3073: /**                                                               **/
                   3074: /*******************************************************************/
                   3075: #ifdef __WIN32
                   3076: #  include <process.h> /* for getpid */
                   3077: #endif
                   3078:
                   3079: #ifndef R_OK
                   3080: #  define R_OK 4
                   3081: #  define W_OK 2
                   3082: #  define X_OK 1
                   3083: #  define F_OK 0
                   3084: #endif
                   3085:
                   3086: #ifdef __EMX__
                   3087: #include <io.h>
                   3088: static int
                   3089: unix_shell()
                   3090: {
                   3091:   char *base, *sh = getenv("EMXSHELL");
                   3092:   if (sh == NULL) sh = getenv("COMSPEC");
                   3093:   if (sh == NULL) return 0;
                   3094:   base = _getname (sh);
                   3095:   if (stricmp (base, "cmd.exe") == 0 || stricmp (base, "4os2.exe") == 0
                   3096:       || stricmp (base, "command.com") == 0
                   3097:       || stricmp (base, "4dos.com") == 0)
                   3098:     return 0;
                   3099:   return 1;
                   3100: }
                   3101: #endif
                   3102:
                   3103: /* check if s has rwx permissions for us */
                   3104: static int
                   3105: pari_is_rwx(char *s)
                   3106: {
                   3107: #if defined(UNIX) || defined (__EMX__) /* TODO: ok for macintosh? */
                   3108:   return access(s, R_OK | W_OK | X_OK) == 0;
                   3109: #else
                   3110:   return 1;
                   3111: #endif
                   3112: }
                   3113:
                   3114: static int
                   3115: pari_file_exists(char *s)
                   3116: {
                   3117: #if defined(UNIX) || defined (__EMX__)
                   3118:   return access(s, F_OK) == 0;
                   3119: #else
                   3120:   return 0;
                   3121: #endif
                   3122: }
                   3123:
                   3124: char *
                   3125: env_ok(char *s)
                   3126: {
                   3127:   char *t = os_getenv(s);
                   3128:   if (t && !pari_is_rwx(t))
                   3129:   {
                   3130:     err(warner,"%s is set (%s), but is not writeable", s,t);
                   3131:     t = NULL;
                   3132:   }
                   3133:   if (t && !pari_is_dir(t))
                   3134:   {
                   3135:     err(warner,"%s is set (%s), but is not a directory", s,t);
                   3136:     t = NULL;
                   3137:   }
                   3138:   return t;
                   3139: }
                   3140:
                   3141: static char*
1.2     ! noro     3142: pari_tmp_dir(void)
1.1       noro     3143: {
                   3144:   char *s;
                   3145: #ifdef WINCE
                   3146:   s = env_ok("TEMP"); if (s) return s;
                   3147:   return "\\temp";
                   3148: #endif
                   3149:   s = env_ok("GPTMPDIR"); if (s) return s;
                   3150:   s = env_ok("TMPDIR"); if (s) return s;
                   3151: #ifdef __EMX__
                   3152:   s = env_ok("TMP"); if (s) return s;
                   3153:   s = env_ok("TEMP"); if (s) return s;
                   3154: #endif
                   3155: #if defined(UNIX) || defined(__EMX__)
                   3156:   if (pari_is_rwx("/tmp")) return "/tmp";
                   3157:   if (pari_is_rwx("/var/tmp")) return "/var/tmp";
                   3158: #endif
                   3159:   return ".";
                   3160: }
                   3161:
                   3162: /* Return a "unique filename" built from the string s, possibly the user id
                   3163:  * and the process pid (on Unix systems). A "temporary" directory name is
                   3164:  * prepended. The name returned is stored in a static buffer (gpmalloc'ed
                   3165:  * permanently). It is DOS-safe (s truncated to 8 chars)
                   3166:  */
                   3167: char*
                   3168: pari_unique_filename(char *s)
                   3169: {
                   3170:   static char *buf, *pre, *post = NULL;
                   3171:
                   3172:   if (!post || !s) /* initialize */
                   3173:   {
                   3174:     char suf[64];
                   3175:     int lpre, lsuf;
                   3176:
                   3177:     if (post) free(post);
                   3178:     pre = pari_tmp_dir();
                   3179: #ifdef UNIX
                   3180:     sprintf(suf,".%ld.%ld", (long)getuid(), (long)getpid());
                   3181: #else
                   3182:     sprintf(suf,".gpa");
                   3183: #endif
                   3184:     lsuf = strlen(suf);
                   3185:     lpre = strlen(pre);
                   3186:     /* room for suffix + '\0 + prefix + '/' + s + suffix '\0' */
                   3187:     /*          ^- post        ^- buf         ^- pre          */
                   3188:     post = (char*) gpmalloc(lpre + 1 + 8 + 2*(lsuf + 1));
                   3189:     strcpy(post, suf);
                   3190:     buf = post + lsuf; *buf = 0; buf++;
                   3191:     strcpy(buf, pre);
                   3192:     if (buf[lpre-1] != '/') { (void)strcat(buf, "/"); lpre++; }
                   3193: #ifdef __EMX__
                   3194:     if (!unix_shell())
                   3195: #endif
                   3196: #if defined(__EMX__) || defined(WINCE)
                   3197:       for (pre=buf; *pre; pre++)
                   3198:        if (*pre == '/') *pre = '\\';
                   3199: #endif
                   3200:     pre = buf + lpre; if (!s) return s;
                   3201:   }
                   3202:   sprintf(pre, "%.8s%s", s, post);
                   3203:   if (pari_file_exists(buf))
                   3204:   {
                   3205:     char c, *end = buf + strlen(buf) - 1;
                   3206:     for (c='a'; c<='z'; c++)
                   3207:     {
                   3208:       *end = c;
                   3209:       if (! pari_file_exists(buf)) break;
                   3210:     }
                   3211:     if (c > 'z')
                   3212:       err(talker,"couldn't find a suitable name for a tempfile (%s)",s);
                   3213:   }
                   3214:   return buf;
                   3215: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>