[BACK]Return to gp.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari / src / gp

Annotation of OpenXM_contrib/pari/src/gp/gp.c, Revision 1.1.1.1

1.1       maekawa     1: /*******************************************************************/
                      2: /**                                                               **/
                      3: /**                        PARI CALCULATOR                        **/
                      4: /**                                                               **/
                      5: /*******************************************************************/
                      6: /* $Id: gp.c,v 1.1.1.1 1999/09/16 13:47:41 karim Exp $ */
                      7: #include "pari.h"
                      8: #ifdef _WIN32
                      9: #  include <windows.h>
                     10: #  ifndef WINCE
                     11: #    include <process.h>
                     12: #  endif
                     13: #endif
                     14: #ifdef HAS_STRFTIME
                     15: #  include <time.h>
                     16: #endif
                     17: #include "../language/anal.h"
                     18: #include "gp.h"
                     19:
                     20: #ifdef READLINE
                     21:   void init_readline();
                     22: BEGINEXTERN
                     23: #  if defined(__cplusplus) && defined(__SUNPRO_CC)
                     24:   /* readline.h gives a bad definition of readline() */
                     25:   extern char*readline(char*);
                     26: #  else
                     27: #   ifdef READLINE_LIBRARY
                     28: #     include <readline.h>
                     29: #   else
                     30: #     include <readline/readline.h>
                     31: #   endif
                     32: #  endif
                     33:   extern int isatty(int);
                     34:   extern void add_history(char*);
                     35: ENDEXTERN
                     36: #endif
                     37:
                     38: char*  _analyseur(void);
                     39: void   err_recover(long numerr);
                     40: void   free_graph(void);
                     41: void   gp_expand_path(char *v);
                     42: int    gp_init_entrees(module *modlist, entree **hash, int force);
                     43: long   gptimer(void);
                     44: void   init80(long n);
                     45: void   init_defaults(int force);
                     46: void   init_graph(void);
                     47: void   init_lim_lines(char *s, long max);
                     48: void   pari_sig_init(void (*f)(int));
                     49: int    whatnow(char *s, int flag);
                     50:
                     51: #define MAX_PROMPT_LEN 128
                     52: #define DFT_PROMPT "? "
                     53: #define COMMENTPROMPT "comment> "
                     54: #define DFT_INPROMPT ""
                     55: static GEN *hist;
                     56: static jmp_buf local_environnement[MAX_BUFFER];
                     57: static char *help_prg,*path,*buflist[MAX_BUFFER];
                     58: static char prompt[MAX_PROMPT_LEN];
                     59: static char thestring[256];
                     60: static long prettyp, test_mode, quiet_mode, gpsilent, simplifyflag;
                     61: static long secure;
                     62: static long chrono, pariecho, primelimit, parisize, strictmatch;
                     63: static long bufindex, tglobal, histsize, paribufsize, lim_lines;
                     64: static gp_format fmt;
                     65:
                     66: #define LBRACE '{'
                     67: #define RBRACE '}'
                     68: #define pariputs_opt(s) if (!quiet_mode) pariputs(s)
                     69:
                     70: void
                     71: hit_return()
                     72: {
                     73:   char tmp[16];
                     74:   pariputs("---- (type return to continue) ----");
                     75:   do fgets(tmp,16,stdin); while (tmp[strlen(tmp)-1] != '\n');
                     76:   /* \n has to be echoed later if we are under emacs (E. Kowalski) */
                     77:   pariputc('\n');
                     78: }
                     79:
                     80: static void
                     81: usage(char *s)
                     82: {
                     83:   printf("### Usage: %s [options]\n", s);
                     84:   printf("Options are:\n");
                     85:   printf("\t[-b buffersize]\tDeprecated\n");
                     86:   printf("\t[-emacs]\tRun as if in Emacs shell\n");
                     87:   printf("\t[-f]\t\tFaststart: do not read .gprc\n");
                     88:   printf("\t[--help]\tPrint this message\n");
                     89:   printf("\t[-q]\t\tQuiet mode: do not print banner and history numbers\n");
                     90:   printf("\t[-p primelimit]\tPrecalculate primes up to the limit\n");
                     91:   printf("\t[-s stacksize]\tStart with the PARI stack of given size (in bytes)\n");
                     92:   printf("\t[-test]\t\tTest mode.  As -q, plus wrap long lines\n");
                     93:   printf("\t[--version]\tOutput version info and exit\n\n");
                     94:   exit(0);
                     95: }
                     96:
                     97: /* must be called BEFORE pari_init() */
                     98: static void
                     99: gp_preinit(int force)
                    100: {
                    101:   static char *dflt;
                    102:   char *help;
                    103:   long i;
                    104:
                    105:   if (force)
                    106:   {
                    107: #if !defined(macintosh) || defined(__MWERKS__)
                    108:     primelimit = 500000; parisize = 1000000*sizeof(long);
                    109:     dflt = DFT_PROMPT;
                    110: #else
                    111:     primelimit = 200000; parisize = 1000000;
                    112:     dflt = "?\n";
                    113: #endif
                    114:   }
                    115:   strcpy(prompt, dflt);
                    116:
                    117: #if defined(UNIX) || defined(__EMX__)
                    118: #  ifdef __EMX__
                    119:   path = pari_strdup(".;C:/;C:/gp");
                    120: #  else
                    121:   path = pari_strdup(".:~:~/gp");
                    122: #  endif
                    123:   help = getenv("GPHELP");
                    124: # ifdef GPHELP
                    125:     if (!help) help = GPHELP;
                    126: # endif
                    127: #else
                    128:   path = pari_strdup(".");
                    129:   help = NULL;
                    130: #endif
                    131:   help_prg = help? pari_strdup(help): NULL;
                    132:   prettyp = f_PRETTYMAT;
                    133:   strictmatch = simplifyflag = 1;
                    134:   tglobal = 0;
                    135:   bufindex = -1;
                    136:   secure = test_mode = under_emacs = chrono = pariecho = 0;
                    137:   fmt.format = 'g'; fmt.field = 0;
                    138: #ifdef LONG_IS_64BIT
                    139:   fmt.nb = 38;
                    140: #else
                    141:   fmt.nb = 28;
                    142: #endif
                    143:   lim_lines = 0;
                    144:   histsize = 5000; paribufsize = 1024;
                    145:   i = histsize*sizeof(GEN);
                    146:   hist = (GEN *) gpmalloc(i); memset(hist,0,i);
                    147:   for (i=0; i<c_LAST; i++) gp_colors[i] = c_NONE;
                    148: }
                    149:
                    150: #define GET_SEP_SIZE 128
                    151: #define separe(c)  ((c)==';' || (c)==':')
                    152:
                    153: /* Return all chars, up to next separator */
                    154: static char*
                    155: get_sep(char *t)
                    156: {
                    157:   static char buf[GET_SEP_SIZE], *lim = buf + GET_SEP_SIZE-1;
                    158:   char *s = buf;
                    159:   int outer=1;
                    160:
                    161:   for(;;)
                    162:   {
                    163:     switch(*s++ = *t++)
                    164:     {
                    165:       case '"':
                    166:         if (outer || s[-2] != '\\') outer = !outer;
                    167:         break;
                    168:       case '\0':
                    169:         return buf;
                    170:       default:
                    171:         if (outer && separe(*t)) { *s=0; return buf; }
                    172:     }
                    173:     if (s == lim) err(talker,"buffer overflow in get_sep");
                    174:   }
                    175: }
                    176:
                    177: /* as above, t must be writeable, return 1 if we modified t */
                    178: static int
                    179: get_sep2(char *t)
                    180: {
                    181:   int outer=1;
                    182:   char *s = t;
                    183:
                    184:   for(;;)
                    185:   {
                    186:     switch (*s++)
                    187:     {
                    188:       case '"':
                    189:         if (outer || s[-2] != '\\') outer = !outer;
                    190:         break;
                    191:       case '\0':
                    192:         return 0;
                    193:       default:
                    194:         if (outer && separe(*s)) { *s=0; return 1; }
                    195:     }
                    196:   }
                    197: }
                    198:
                    199: static long
                    200: get_int(char *s, long dflt)
                    201: {
                    202:   char *p=get_sep(s);
                    203:   long n=atol(p);
                    204:
                    205:   if (*p == '-') p++;
                    206:   while(isdigit((int)*p)) { p++; dflt=n; }
                    207:   if (*p) err(talker2,"I was expecting an integer here", s, s);
                    208:   return dflt;
                    209: }
                    210:
                    211: static void
                    212: gp_output(GEN x)
                    213: {
                    214:   long tx=typ(x);
                    215:
                    216:   if (fmt.nb >= 0 && is_intreal_t(tx))
                    217:     ecrire(x, fmt.format, fmt.nb, fmt.field);
                    218:   else
                    219:     switch(prettyp)
                    220:     {
                    221:       case f_PRETTYMAT: matbrute(x, fmt.format, fmt.nb); break;
                    222:       case f_PRETTY   : sor(x, fmt.format, fmt.nb, fmt.field); break;
                    223:       case f_RAW      : brute(x, fmt.format, fmt.nb); break;
                    224:       case f_TEX      : texe(x, fmt.format, fmt.nb); break;
                    225:     }
                    226: }
                    227:
                    228: /* print a sequence of (NULL terminated) GEN */
                    229: void
                    230: print0(GEN *g, long flag)
                    231: {
                    232:   int old=prettyp;
                    233:
                    234:   if (flag < NBFORMATS) added_newline=1;
                    235:   else
                    236:     { flag -= NBFORMATS; added_newline=0; }
                    237:   prettyp=flag;
                    238:
                    239:   for( ; *g; g++)
                    240:     if (typ(*g)==t_STR)
                    241:       pariputs(GSTR(*g)); /* otherwise it's surrounded by "" */
                    242:     else
                    243:       gp_output(*g);
                    244:
                    245:   if (added_newline) pariputc('\n');
                    246:   prettyp=old; pariflush();
                    247: }
                    248:
                    249: /* write a sequence of (NULL terminated) GEN, to file s */
                    250: void
                    251: write0(char *s, GEN *g, long flag)
                    252: {
                    253:   int i = added_newline;
                    254:   s = expand_tilde(s); switchout(s); free(s);
                    255:   print0(g,flag); added_newline = i;
                    256:   switchout(NULL);
                    257: }
                    258:
                    259: /********************************************************************/
                    260: /*                                                                  */
                    261: /*                            DEFAULTS                              */
                    262: /*                                                                  */
                    263: /********************************************************************/
                    264: static void
                    265: do_strftime(char *s, char *buf)
                    266: {
                    267: #ifdef HAS_STRFTIME
                    268:   time_t t = time(NULL);
                    269:   strftime(buf,MAX_PROMPT_LEN-1,s,localtime(&t));
                    270: #else
                    271:   strcpy(buf,s);
                    272: #endif
                    273: }
                    274:
                    275: static GEN
                    276: sd_numeric(char *v, int flag, char *s, long *ptn, long Min, long Max,
                    277:            char **msg)
                    278: {
                    279:   long n;
                    280:   if (*v == 0) n = *ptn;
                    281:   else
                    282:   {
                    283:     n = get_int(v,0);
                    284:     if (*ptn == n) return gnil;
                    285:     if (n > Max || n < Min)
                    286:     {
                    287:       sprintf(thestring, "default: incorrect value for %s [%ld-%ld]",
                    288:              s, Min, Max);
                    289:       err(talker2, thestring, v,v);
                    290:     }
                    291:     *ptn = n;
                    292:   }
                    293:   switch(flag)
                    294:   {
                    295:     case d_RETURN: return stoi(n);
                    296:     case d_ACKNOWLEDGE:
                    297:       if (msg)
                    298:       {
                    299:        if (!*msg)
                    300:          msg++; /* single msg, always printed */
                    301:        else
                    302:          msg += n; /* one per possible value */
                    303:        pariputsf("   %s = %ld %s\n", s, n, *msg);
                    304:       }
                    305:       else if (Max != 1 || Min != 0)
                    306:        pariputsf("   %s = %ld\n", s, n);
                    307:       else /* toggle */
                    308:       {
                    309:        if (n==1) pariputsf("   %s = 1 (on)\n", s);
                    310:        else      pariputsf("   %s = 0 (off)\n", s);
                    311:       } /* fall through */
                    312:     default: return gnil;
                    313:   }
                    314: }
                    315:
                    316: #define PRECDIGIT (long)((prec-2.)*pariK)
                    317: static GEN
                    318: sd_realprecision(char *v, int flag)
                    319: {
                    320:   if (*v)
                    321:   {
                    322:     long newnb = get_int(v, fmt.nb);
                    323:     long newprec = (long) (newnb*pariK1 + 3);
                    324:
                    325:     if (fmt.nb == newnb && prec == newprec) return gnil;
                    326:     if (newnb < 0) err(talker,"default: negative real precision");
                    327:     fmt.nb = newnb; prec = newprec;
                    328:   }
                    329:   if (flag == d_RETURN) return stoi(fmt.nb);
                    330:   if (flag == d_ACKNOWLEDGE)
                    331:   {
                    332:     long n = PRECDIGIT;
                    333:     pariputsf("   realprecision = %ld significant digits", n);
                    334:     if (n != fmt.nb) pariputsf(" (%ld digits displayed)", fmt.nb);
                    335:     pariputc('\n');
                    336:   }
                    337:   return gnil;
                    338: }
                    339: #undef PRECDIGIT
                    340:
                    341: static GEN
                    342: sd_seriesprecision(char *v, int flag)
                    343: {
                    344:   char *msg[] = {NULL, "significant terms"};
                    345:   return sd_numeric(v,flag,"seriesprecision",&precdl, 0,LGBITS,msg);
                    346: }
                    347:
                    348: static GEN
                    349: sd_format(char *v, int flag)
                    350: {
                    351:   if (*v)
                    352:   {
                    353:     char c = *v;
                    354:     if (c!='e' && c!='f' && c!='g')
                    355:       err(talker2,"default: inexistent format",v,v);
                    356:     fmt.format = c; v++;
                    357:
                    358:     if (isdigit((int)*v))
                    359:       { fmt.field=atol(v); while (isdigit((int)*v)) v++; }
                    360:     if (*v++ == '.')
                    361:     {
                    362:       if (*v == '-') fmt.nb = -1;
                    363:       else
                    364:        if (isdigit((int)*v)) fmt.nb=atol(v);
                    365:     }
                    366:   }
                    367:   if (flag == d_RETURN)
                    368:   {
                    369:     sprintf(thestring, "%c%ld.%ld", fmt.format, fmt.field, fmt.nb);
                    370:     return strtoGENstr(thestring,0);
                    371:   }
                    372:   if (flag == d_ACKNOWLEDGE)
                    373:     pariputsf("   format = %c%ld.%ld\n", fmt.format, fmt.field, fmt.nb);
                    374:   return gnil;
                    375: }
                    376:
                    377: static long
                    378: gp_get_color(char **st)
                    379: {
                    380:   char *s, *v = *st;
                    381:   int c, trans = 1;
                    382:   if (!isdigit((int)*v))
                    383:   {
                    384:     if (*v == '[')
                    385:     {
                    386:       char *a[3];
                    387:       int i = 0;
                    388:       for (a[0] = s = ++v; *s && *s != ']'; s++)
                    389:         if (*s == ',') { *s = 0; a[++i] = s+1; }
                    390:       if (*s != ']') err(talker2,"expected character: ']'",s, *st);
                    391:       *s = 0; for (i++; i<3; i++) a[i] = "";
                    392:       /*    properties    |   color    | background */
                    393:       c = (atoi(a[2])<<8) | atoi(a[0]) | (atoi(a[1])<<4);
                    394:       trans = (*(a[1]) == 0);
                    395:       v = s + 1;
                    396:     }
                    397:     else { c = c_NONE; trans = 0; }
                    398:   }
                    399:   else c = atol(v); /* color on transparent background */
                    400:   if (trans) c = -c;
                    401:   while (*v && *v++ != ',') /* empty */;
                    402:   if (c != c_NONE) disable_color=0;
                    403:   *st = v; return c;
                    404: }
                    405:
                    406: static GEN
                    407: sd_colors(char *v, int flag)
                    408: {
                    409:   long c,l;
                    410:   if (*v && !under_emacs)
                    411:   {
                    412:     char *tmp;
                    413:     disable_color=1;
                    414:     l = strlen(v);
                    415:     if (l <= 2 && strncmp(v, "no", l) == 0)
                    416:       v = "";
                    417:     if (l <= 3 && strncmp(v, "yes", l) == 0)
                    418:       v = "1, 5, 3, 7, 6, 2, 3";       /* Assume recent ReadLine. */
                    419:     tmp = v = pari_strdup(v); filtre(v, f_INIT|f_REG);
                    420:     for (c=c_ERR; c < c_LAST; c++)
                    421:       gp_colors[c] = gp_get_color(&v);
                    422:     free(tmp);
                    423:   }
                    424:   if (flag == d_ACKNOWLEDGE || flag == d_RETURN)
                    425:   {
                    426:     char *s = thestring;
                    427:     int col[3], n;
                    428:     for (*s=0,c=c_ERR; c < c_LAST; c++)
                    429:     {
                    430:       n = gp_colors[c];
                    431:       if (n == c_NONE)
                    432:         sprintf(s,"no");
                    433:       else
                    434:       {
                    435:         decode_color(abs(n),col);
                    436:         if (n < 0)
                    437:         {
                    438:           if (col[0])
                    439:             sprintf(s,"[%d,,%d]",col[1],col[0]);
                    440:           else
                    441:             sprintf(s,"%d",col[1]);
                    442:         }
                    443:         else
                    444:           sprintf(s,"[%d,%d,%d]",col[1],col[2],col[0]);
                    445:       }
                    446:       s += strlen(s);
                    447:       if (c < c_LAST - 1) { *s++=','; *s++=' '; }
                    448:     }
                    449:     if (flag==d_RETURN) return strtoGENstr(thestring,0);
                    450:     pariputsf("   colors = \"%s\"\n",thestring);
                    451:   }
                    452:   return gnil;
                    453: }
                    454:
                    455: static GEN
                    456: sd_compatible(char *v, int flag)
                    457: {
                    458:   char *msg[] = {
                    459:     "(no backward compatibility)",
                    460:     "(warn when using obsolete functions)",
                    461:     "(use old functions, don't ignore case)",
                    462:     "(use old functions, ignore case)", NULL
                    463:   };
                    464:   long old = compatible;
                    465:   GEN r = sd_numeric(v,flag,"compatible",&compatible, 0,3,msg);
                    466:
                    467:   if (old != compatible && flag != d_INITRC)
                    468:   {
                    469:     int res = gp_init_entrees(new_fun_set? pari_modules: pari_oldmodules,
                    470:                              functions_hash, 0);
                    471:     if (res) err(warner,"user functions re-initialized");
                    472:   }
                    473:   return r;
                    474: }
                    475:
                    476: static GEN
                    477: sd_secure(char *v, int flag)
                    478: {
                    479:   if (secure)
                    480:   {
                    481:     fprintferr("Do you want to modify the 'secure' flag? (^C if not)\n");
                    482:     hit_return();
                    483:   }
                    484:   return sd_numeric(v,flag,"secure",&secure, 0,1,NULL);
                    485: }
                    486:
                    487: static GEN
                    488: sd_buffersize(char *v, int flag)
                    489: { return sd_numeric(v,flag,"buffersize",&paribufsize, 0,
                    490:                     (VERYBIGINT / sizeof(long)) - 1,NULL); }
                    491: static GEN
                    492: sd_debug(char *v, int flag)
                    493: { return sd_numeric(v,flag,"debug",&DEBUGLEVEL, 0,20,NULL); }
                    494:
                    495: static GEN
                    496: sd_debugfiles(char *v, int flag)
                    497: { return sd_numeric(v,flag,"debugfiles",&DEBUGFILES, 0,20,NULL); }
                    498:
                    499: static GEN
                    500: sd_debugmem(char *v, int flag)
                    501: { return sd_numeric(v,flag,"debugmem",&DEBUGMEM, 0,20,NULL); }
                    502:
                    503: static GEN
                    504: sd_echo(char *v, int flag)
                    505: { return sd_numeric(v,flag,"echo",&pariecho, 0,1,NULL); }
                    506:
                    507: static GEN
                    508: sd_lines(char *v, int flag)
                    509: { return sd_numeric(v,flag,"lines",&lim_lines, 0,VERYBIGINT,NULL); }
                    510:
                    511: static GEN
                    512: sd_histsize(char *v, int flag)
                    513: {
                    514:   long n = histsize;
                    515:   GEN r = sd_numeric(v,flag,"histsize",&n, 1,
                    516:                      (VERYBIGINT / sizeof(long)) - 1,NULL);
                    517:   if (n != histsize)
                    518:   {
                    519:     long i = n*sizeof(GEN);
                    520:     GEN *gg = (GEN *) gpmalloc(i); memset(gg,0,i);
                    521:
                    522:     if (tglobal)
                    523:     {
                    524:       long k = (tglobal-1) % n;
                    525:       long kmin = k - min(n,histsize), j = k;
                    526:
                    527:       i = (tglobal-1) % histsize;
                    528:       while (k > kmin)
                    529:       {
                    530:        gg[j] = hist[i];
                    531:        hist[i] = NULL;
                    532:        if (!i) i = histsize;
                    533:        if (!j) j = n;
                    534:        i--; j--; k--;
                    535:       }
                    536:       while (hist[i])
                    537:       {
                    538:        gunclone(hist[i]);
                    539:        if (!i) i = histsize;
                    540:        i--;
                    541:       }
                    542:     }
                    543:     free((void*)hist); hist=gg; histsize=n;
                    544:   }
                    545:   return r;
                    546: }
                    547:
                    548: static GEN
                    549: sd_log(char *v, int flag)
                    550: {
                    551:   long vlog = logfile? 1: 0, old = vlog;
                    552:   GEN r = sd_numeric(v,flag,"log",&vlog, 0,1,NULL);
                    553:   if (vlog != old)
                    554:   {
                    555:     if (vlog)
                    556:     {
                    557:       logfile = fopen(current_logfile, "a");
                    558:       if (!logfile) err(openfiler,"logfile",current_logfile);
                    559: #ifndef WINCE
                    560:       setbuf(logfile,(char *)NULL);
                    561: #endif
                    562:     }
                    563:     else
                    564:     {
                    565:       if (flag == d_ACKNOWLEDGE)
                    566:         pariputsf("   [logfile was \"%s\"]\n", current_logfile);
                    567:       fclose(logfile); logfile=NULL;
                    568:     }
                    569:   }
                    570:   return r;
                    571: }
                    572:
                    573: static GEN
                    574: sd_output(char *v, int flag)
                    575: {
                    576:   char *msg[] = {"(raw)", "(prettymatrix)", "(prettyprint)", NULL};
                    577:   return sd_numeric(v,flag,"output",&prettyp, 0,2,msg);
                    578: }
                    579:
                    580: static GEN
                    581: sd_parisize(char *v, int flag)
                    582: {
                    583:   long n = parisize;
                    584:   GEN r = sd_numeric(v,flag,"parisize",&n, 10000,VERYBIGINT,NULL);
                    585:   if (n != parisize)
                    586:   {
                    587:     if (flag != d_INITRC)
                    588:     {
                    589:       parisize = allocatemoremem(n);
                    590:       longjmp(local_environnement[bufindex], 0);
                    591:     }
                    592:     parisize = n;
                    593:   }
                    594:   return r;
                    595: }
                    596:
                    597: static GEN
                    598: sd_primelimit(char *v, int flag)
                    599: {
                    600:   long n = primelimit;
                    601:   GEN r = sd_numeric(v,flag,"primelimit",&n, 0,VERYBIGINT,NULL);
                    602:   if (n != primelimit)
                    603:   {
                    604:     if (flag != d_INITRC)
                    605:     {
                    606:       byteptr ptr = initprimes(n);
                    607:       free(diffptr); diffptr = ptr;
                    608:     }
                    609:     primelimit = n;
                    610:   }
                    611:   return r;
                    612: }
                    613:
                    614: static GEN
                    615: sd_simplify(char *v, int flag)
                    616: { return sd_numeric(v,flag,"simplify",&simplifyflag, 0,1,NULL); }
                    617:
                    618: static GEN
                    619: sd_strictmatch(char *v, int flag)
                    620: { return sd_numeric(v,flag,"strictmatch",&strictmatch, 0,1,NULL); }
                    621:
                    622: static GEN
                    623: sd_timer(char *v, int flag)
                    624: { return sd_numeric(v,flag,"timer",&chrono, 0,1,NULL); }
                    625:
                    626: static GEN
                    627: sd_filename(char *v, int flag, char *s, char **f)
                    628: {
                    629:   if (*v)
                    630:   {
                    631:     char *old = *f;
                    632:     v = expand_tilde(v);
                    633:     do_strftime(v,thestring); free(v);
                    634:     *f = pari_strdup(thestring); free(old);
                    635:   }
                    636:   if (flag == d_RETURN) return strtoGENstr(*f,0);
                    637:   if (flag == d_ACKNOWLEDGE) pariputsf("   %s = \"%s\"\n",s,*f);
                    638:   return gnil;
                    639: }
                    640:
                    641: static GEN
                    642: sd_logfile(char *v, int flag)
                    643: {
                    644:   GEN r = sd_filename(v, flag, "logfile", &current_logfile);
                    645:   if (*v && logfile)
                    646:   {
                    647:     fclose(logfile);
                    648:     logfile = fopen(current_logfile, "a");
                    649:     if (!logfile) err(openfiler,"logfile",current_logfile);
                    650: #ifndef WINCE
                    651:     setbuf(logfile,(char *)NULL);
                    652: #endif
                    653:   }
                    654:   return r;
                    655: }
                    656:
                    657: static GEN
                    658: sd_psfile(char *v, int flag)
                    659: { return sd_filename(v, flag, "psfile", &current_psfile); }
                    660:
                    661: static GEN
                    662: sd_help(char *v, int flag)
                    663: {
                    664:   char *str;
                    665:   if (*v)
                    666:   {
                    667:     if (help_prg) free(help_prg);
                    668:     help_prg = expand_tilde(v);
                    669:   }
                    670:   str = help_prg? help_prg: "none";
                    671:   if (flag == d_RETURN) return strtoGENstr(str,0);
                    672:   if (flag == d_ACKNOWLEDGE)
                    673:     pariputsf("   help = \"%s\"\n", str);
                    674:   return gnil;
                    675: }
                    676:
                    677: static GEN
                    678: sd_path(char *v, int flag)
                    679: {
                    680:   if (*v)
                    681:   {
                    682:     char *old = path;
                    683:     path = pari_strdup(v); free(old);
                    684:     if (flag == d_INITRC) return gnil;
                    685:     gp_expand_path(path);
                    686:   }
                    687:   if (flag == d_RETURN) return strtoGENstr(path,0);
                    688:   if (flag == d_ACKNOWLEDGE)
                    689:     pariputsf("   path = \"%s\"\n",path);
                    690:   return gnil;
                    691: }
                    692:
                    693: static GEN
                    694: sd_prompt(char *v, int flag)
                    695: {
                    696:   if (*v)
                    697:   {
                    698:     strncpy(prompt,v,MAX_PROMPT_LEN);
                    699: #ifdef macintosh
                    700:     strcat(prompt,"\n");
                    701: #endif
                    702:   }
                    703:   if (flag == d_RETURN) return strtoGENstr(prompt,0);
                    704:   if (flag == d_ACKNOWLEDGE)
                    705:     pariputsf("   prompt = \"%s\"\n",prompt);
                    706:   return gnil;
                    707: }
                    708:
                    709: default_type gp_default_list[] =
                    710: {
                    711:   {"buffersize",(void*)sd_buffersize},
                    712:   {"colors",(void*)sd_colors},
                    713:   {"compatible",(void*)sd_compatible},
                    714:   {"debug",(void*)sd_debug},
                    715:   {"debugfiles",(void*)sd_debugfiles},
                    716:   {"debugmem",(void*)sd_debugmem},
                    717:   {"echo",(void*)sd_echo},
                    718:   {"format",(void*)sd_format},
                    719:   {"help",(void*)sd_help},
                    720:   {"histsize",(void*)sd_histsize},
                    721:   {"lines",(void*)sd_lines},
                    722:   {"log",(void*)sd_log},
                    723:   {"logfile",(void*)sd_logfile},
                    724:   {"output",(void*)sd_output},
                    725:   {"parisize",(void*)sd_parisize},
                    726:   {"path",(void*)sd_path},
                    727:   {"primelimit",(void*)sd_primelimit},
                    728:   {"prompt",(void*)sd_prompt},
                    729:   {"psfile",(void*)sd_psfile},
                    730:   {"realprecision",(void*)sd_realprecision},
                    731:   {"secure",(void*)sd_secure},
                    732:   {"seriesprecision",(void*)sd_seriesprecision},
                    733:   {"simplify",(void*)sd_simplify},
                    734:   {"strictmatch",(void*)sd_strictmatch},
                    735:   {"timer",(void *)sd_timer},
                    736:   {NULL,NULL} /* sentinel */
                    737: };
                    738:
                    739: static void
                    740: help_default()
                    741: {
                    742:   default_type *dft;
                    743:
                    744:   for (dft=gp_default_list; dft->fun; dft++)
                    745:     ((void (*)(ANYARG)) dft->fun)("", d_ACKNOWLEDGE);
                    746: }
                    747:
                    748: static GEN
                    749: setdefault(char *s,char *v, int flag)
                    750: {
                    751:   default_type *dft;
                    752:
                    753:   if (!*s) { help_default(); return gnil; }
                    754:   for (dft=gp_default_list; dft->fun; dft++)
                    755:     if (!strcmp(s,dft->name))
                    756:     {
                    757:       if (flag == d_EXISTS) return gun;
                    758:       return ((GEN (*)(ANYARG)) dft->fun)(v,flag);
                    759:     }
                    760:   if (flag == d_EXISTS) return gzero;
                    761:   err(talker,"unknown default: %s",s);
                    762:   return NULL; /* not reached */
                    763: }
                    764:
                    765: /********************************************************************/
                    766: /**                                                                **/
                    767: /**                             HELP                               **/
                    768: /**                                                                **/
                    769: /********************************************************************/
                    770: static int
                    771: has_ext_help()
                    772: {
                    773:   if (help_prg)
                    774:   {
                    775:     char *buf = pari_strdup(help_prg), *s = buf;
                    776:     FILE *file;
                    777:
                    778:     while (*s && *s != ' ') s++;
                    779:     *s = 0; file = (FILE *) fopen(buf,"r");
                    780:     if (file) { fclose(file); return 1; }
                    781:     free(buf);
                    782:   }
                    783:   return 0;
                    784: }
                    785:
                    786: static int
                    787: compare_str(char **s1, char **s2) { return strcmp(*s1, *s2); }
                    788:
                    789: /* Print all elements of list in columns, pausing every nbli lines
                    790:  * if nbli is non-zero.
                    791:  * list is a NULL terminated list of function names
                    792:  */
                    793: void
                    794: print_fun_list(char **list, int nbli)
                    795: {
                    796:   long i=0, j=0, maxlen=0, nbcol,len, w = term_width();
                    797:   char **l;
                    798:
                    799:   while (list[i]) i++;
                    800:   qsort (list, i, sizeof(char *), (QSCOMP)compare_str);
                    801:
                    802:   for (l=list; *l; l++)
                    803:   {
                    804:     len = strlen(*l);
                    805:     if (len > maxlen) maxlen=len;
                    806:   }
                    807:   maxlen++; nbcol= w / maxlen;
                    808:   if (nbcol * maxlen == w) nbcol--;
                    809:   if (!nbcol) nbcol = 1;
                    810:
                    811:   pariputc('\n'); i=0;
                    812:   for (l=list; *l; l++)
                    813:   {
                    814:     pariputs(*l); i++;
                    815:     if (i >= nbcol)
                    816:     {
                    817:       i=0; pariputc('\n');
                    818:       if (nbli && j++ > nbli) { j = 0; hit_return(); }
                    819:       continue;
                    820:     }
                    821:     len = maxlen - strlen(*l);
                    822:     while (len--) pariputc(' ');
                    823:   }
                    824:   if (i) pariputc('\n');
                    825: }
                    826:
                    827: #define LIST_LEN 1023
                    828: static void
                    829: commands(int n)
                    830: {
                    831:   int hashpos, s = 0, olds = LIST_LEN;
                    832:   entree *ep;
                    833:   char **list = (char **) gpmalloc((olds+1)*sizeof(char *));
                    834:
                    835:   for (hashpos = 0; hashpos < functions_tblsz; hashpos++)
                    836:     for (ep = functions_hash[hashpos]; ep; ep = ep->next)
                    837:       if ((n<0 && ep->menu) || ep->menu == n)
                    838:       {
                    839:         list[s++] = ep->name;
                    840:         if (s >= olds)
                    841:         {
                    842:          int news = olds + (LIST_LEN + 1)*sizeof(char *);
                    843:           list = (char**) gprealloc(list,news,olds);
                    844:          olds = news;
                    845:         }
                    846:       }
                    847:   list[s]=NULL; print_fun_list(list,term_height()-4); free(list);
                    848: }
                    849:
                    850: static void
                    851: print_user_fun(entree *ep)
                    852: {
                    853:   gp_args *f= (gp_args*)ep->args;
                    854:   GEN q = (GEN)ep->value, *arg = f->arg;
                    855:   int i, narg;
                    856:
                    857:
                    858:   q++; /* skip initial NULL */
                    859:   pariputs(ep->name); pariputc('(');
                    860:   narg = f->narg;
                    861:   for (i=1; i<=narg; i++, arg++)
                    862:   {
                    863:     entree *ep = varentries[*q++];
                    864:     pariputs(ep? ep->name:"#");
                    865:     if (!gcmp0(*arg)) { pariputc('='); bruteall(*arg,'g',-1,1); }
                    866:     if (i == narg) { arg++; break; }
                    867:     pariputs(", ");
                    868:   }
                    869:   pariputs(") = ");
                    870:   narg = f->nloc;
                    871:   if (narg)
                    872:   {
                    873:     pariputs("local(");
                    874:     for (i=1; i<=narg; i++, arg++)
                    875:     {
                    876:       entree *ep = varentries[*q++];
                    877:       pariputs(ep? ep->name:"#");
                    878:       if (!gcmp0(*arg)) { pariputc('='); bruteall(*arg,'g',-1,1); }
                    879:       if (i == narg) break;
                    880:       pariputs(", ");
                    881:     }
                    882:     pariputs("); ");
                    883:   }
                    884:   pariputs((char*)q);
                    885: }
                    886:
                    887: static void
                    888: print_user_member(entree *ep)
                    889: {
                    890:   GEN q = (GEN)ep->value;
                    891:   entree *ep2;
                    892:
                    893:   q++; /* skip initial NULL */
                    894:   ep2 = varentries[*q++];
                    895:   pariputs(ep2? ep2->name:"#");
                    896:   pariputsf(".%s = ", ep->name);
                    897:   pariputs((char*)q);
                    898: }
                    899:
                    900: static void
                    901: user_fun()
                    902: {
                    903:   entree *ep;
                    904:   int hash;
                    905:
                    906:   for (hash = 0; hash < functions_tblsz; hash++)
                    907:     for (ep = functions_hash[hash]; ep; ep = ep->next)
                    908:       if (EpVALENCE(ep) == EpUSER)
                    909:       {
                    910:        pariputc(LBRACE); print_user_fun(ep);
                    911:        pariputc(RBRACE); pariputs("\n\n");
                    912:       }
                    913: }
                    914:
                    915: static void
                    916: user_member()
                    917: {
                    918:   entree *ep;
                    919:   int hash;
                    920:
                    921:   for (hash = 0; hash < functions_tblsz; hash++)
                    922:     for (ep = members_hash[hash]; ep; ep = ep->next)
                    923:       if (EpVALENCE(ep) == EpMEMBER)
                    924:       {
                    925:        pariputc(LBRACE); print_user_member(ep);
                    926:        pariputc(RBRACE); pariputs("\n\n");
                    927:       }
                    928: }
                    929:
                    930: static void
                    931: community()
                    932: {
                    933:   pariputs("The standard distribution of GP/PARI includes a reference manual, a tutorial\n\
                    934: and a reference card and you should ask the person who installed PARI on\n\
                    935: your system where they can be found. You can also download them\n\
                    936: from the PARI WWW site http://hasse.mathematik.tu-muenchen.de/ntsw/pari/\n\
                    937: \n\
                    938: Three mailing lists are devoted to PARI:\n\
                    939:   - pari-announce (moderated) to announce major version changes.\n\
                    940:   - pari-dev for everything related to the development of PARI, including\n\
                    941:     suggestions, technical questions, bug reports and patch submissions.\n\
                    942:   - pari-users for everything else !\n\
                    943: To subscribe, send an empty message to <list name>-subscribe@list.cr.yp.to\n\
                    944: You can only send messages to these lists if you have subscribed !\n\
                    945: An archive is kept at the address\n\
                    946:   http://hasse.mathematik.tu-muenchen.de/ntsw/pari/lists/archive\n\n\
                    947: In case you don't want to subscribe, you can reach the authors directly by\n\
                    948: email: pari@math.u-bordeaux.fr (answer not guaranteed).");
                    949: }
                    950:
                    951: static void
                    952: gentypes(void)
                    953: {
                    954:   pariputs("List of the PARI types:\n\
                    955:   t_INT    : long integers     [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                    956:   t_REAL   : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                    957:   t_INTMOD : integermods       [ code ] [ mod  ] [ integer ]\n\
                    958:   t_FRAC   : irred. rationals  [ code ] [ num. ] [ den. ]\n\
                    959:   t_FRACN  : rational numbers  [ code ] [ num. ] [ den. ]\n\
                    960:   t_COMPLEX: complex numbers   [ code ] [ real ] [ imag ]\n\
                    961:   t_PADIC  : p-adic numbers    [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ]\n\
                    962:   t_QUAD   : quadratic numbers [ cod1 ] [ mod  ] [ real ] [ imag ]\n\
                    963:   t_POLMOD : poly mod          [ code ] [ mod  ] [ polynomial ]\n\
                    964:   -------------------------------------------------------------\n\
                    965:   t_POL    : polynomials       [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                    966:   t_SER    : power series      [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                    967:   t_RFRAC  : irred. rat. func. [ code ] [ num. ] [ den. ]\n\
                    968:   t_RFRACN : rational function [ code ] [ num. ] [ den. ]\n\
                    969:   t_QFR    : real qfb          [ code ] [ a ] [ b ] [ c ] [ del ]\n\
                    970:   t_QFI    : imaginary qfb     [ code ] [ a ] [ b ] [ c ]\n\
                    971:   t_VEC    : row vector        [ code ] [  x_1  ] ... [  x_k  ]\n\
                    972:   t_COL    : column vector     [ code ] [  x_1  ] ... [  x_k  ]\n\
                    973:   t_MAT    : matrix            [ code ] [ col_1 ] ... [ col_k ]\n\
                    974:   t_LIST   : list              [ code ] [ cod2 ] [ x_1 ] ... [ x_k ]\n\
                    975:   t_STR    : string            [ code ] [ man_1 ] ... [ man_k ]\n\
                    976: \n");
                    977: }
                    978:
                    979: static void
                    980: menu_commands(void)
                    981: {
                    982:   pariputs("Help topics:\n\
                    983:   0: list of user-defined identifiers (variable, alias, function)\n\
                    984:   1: Standard monadic or dyadic OPERATORS\n\
                    985:   2: CONVERSIONS and similar elementary functions\n\
                    986:   3: TRANSCENDENTAL functions\n\
                    987:   4: NUMBER THEORETICAL functions\n\
                    988:   5: Functions related to ELLIPTIC CURVES\n\
                    989:   6: Functions related to general NUMBER FIELDS\n\
                    990:   7: POLYNOMIALS and power series\n\
                    991:   8: Vectors, matrices, LINEAR ALGEBRA and sets\n\
                    992:   9: SUMS, products, integrals and similar functions\n\
                    993:  10: GRAPHIC functions\n\
                    994:  11: PROGRAMMING under GP\n\
                    995:  12: The PARI community\n\
                    996: \n\
                    997: Further help (list of relevant functions): ?n (1<=n<=11).\n\
                    998: Also:\n\
                    999:   ? functionname (short on-line help)\n\
                   1000:   ?\\             (keyboard shortcuts)\n\
                   1001:   ?.             (member functions)\n");
                   1002:   if (has_ext_help()) pariputs("\
                   1003: Extended help looks available:\n\
                   1004:   ??             (opens the full user's manual in a dvi previewer)\n\
                   1005:   ??  tutorial   (same with the GP tutorial)\n\
                   1006:   ??  refcard    (same with the GP reference card)\n\
                   1007: \n\
                   1008:   ??  keyword    (long help text about \"keyword\" from the user's manual)\n\
                   1009:   ??? keyword    (a propos: list of related functions).");
                   1010: }
                   1011:
                   1012: static void
                   1013: slash_commands(void)
                   1014: {
                   1015:   pariputs("#       : enable/disable timer\n\
                   1016: ##      : print time for last result\n\
                   1017: \\\\      : comment up to end of line\n\
                   1018: \\a {n}  : print result in raw format (readable by PARI)\n\
                   1019: \\b {n}  : print result in beautified format\n\
                   1020: \\c      : list all commands (same effect as ?*)\n\
                   1021: \\d      : print all defaults\n\
                   1022: \\e {n}  : enable/disable echo (set echo=n)\n\
                   1023: \\g {n}  : set debugging level\n\
                   1024: \\gf{n}  : set file debugging level\n\
                   1025: \\gm{n}  : set memory debugging level\n\
                   1026: \\h {m-n}: hashtable information\n\
                   1027: \\l {f}  : enable/disable logfile (set logfile=f)\n\
                   1028: \\m {n}  : print result in prettymatrix format\n\
                   1029: \\p {n}  : change real precision\n\
                   1030: \\ps{n}  : change series precision\n\
                   1031: \\q      : quit completely this GP session\n\
                   1032: \\r {f}  : read in a file\n\
                   1033: \\s {n}  : print stack information\n\
                   1034: \\t      : print the list of PARI types\n\
                   1035: \\u      : print the list of user-defined functions\n\
                   1036: \\um     : print the list of user-defined member functions\n\
                   1037: \\v      : print current version of GP\n\
                   1038: \\w {nf} : write to a file\n\
                   1039: \\x {n}  : print complete inner structure of result\n\
                   1040: \\y {n}  : disable/enable automatic simplification (set simplify=n)\n\
                   1041: \n\
                   1042: {f}=optional filename. {n}=optional integer\n");
                   1043: }
                   1044:
                   1045: static void
                   1046: member_commands(void)
                   1047: {
                   1048:   pariputs("Member functions, followed by relevant objects\n\n\
                   1049: a1-a6, b2-b8, c4-c6 : coeff. of the curve.            ell\n\
                   1050: area : area                                           ell\n\
                   1051: bnf  : big number field                                        bnf, bnr\n\
                   1052: clgp : class group                                             bnf, bnr\n\
                   1053: cyc  : cyclic decomposition (SNF)               clgp           bnf, bnr\n\
                   1054: diff, codiff: different and codifferent                    nf, bnf, bnr\n\
                   1055: disc : discriminant                                   ell, nf, bnf, bnr\n\
                   1056: e, f : inertia/residues degree            prid\n\
                   1057: fu   : fundamental units                                       bnf, bnr\n\
                   1058: futu : [u,w] where u=unit group, w=torsion                     bnf, bnr\n\
                   1059: gen  : generators                         prid, clgp           bnf, bnr\n\
                   1060: j    : j-invariant                                    ell\n\
                   1061: mod  : modulus\n\
                   1062: nf   : number field                                            bnf, bnr\n\
                   1063: no   : number of elements                       clgp           bnf, bnr\n\
                   1064: omega, eta: [omega1,omega2] and [eta1, eta2]          ell\n\
                   1065: p    : rational prime contained in prid   prid\n\
                   1066: pol  : defining polynomial                                 nf, bnf, bnr\n\
                   1067: reg  : regulator                                               bnf, bnr\n\
                   1068: roots: roots                                          ell  nf, bnf, bnr\n\
                   1069: sign : signature                                           nf, bnf, bnr\n\
                   1070: t2   : t2 matrix                                           nf, bnf, bnr\n\
                   1071: tate : Tate's [u^2,u,q]                               ell\n\
                   1072: tu   : torsion unit and its order                              bnf, bnr\n\
                   1073: tufu : [w,u] where u=unit group, w=torsion                     bnf, bnr\n\
                   1074: w    : Mestre's w                                     ell\n\
                   1075: zk   : integral basis                                      nf, bnf, bnr\n\
                   1076: zkst : structure of (Z_K/m)^* (valid for idealstar also)            bnr\n");
                   1077: }
                   1078:
                   1079: #define MAX_LINE_LEN 255
                   1080: static void
                   1081: external_help(char *s, int num)
                   1082: {
                   1083:   long nbli = term_height()-3, li = 0;
                   1084:   char buf[MAX_LINE_LEN+1], *str, *opt = "", *ar = "";
                   1085:   pariFILE *z;
                   1086:   FILE *f;
                   1087:
                   1088:   if (!help_prg) err(talker,"no external help program");
                   1089:   str = gpmalloc(strlen(help_prg) + strlen(s) + 64);
                   1090:   if (num < 0)
                   1091:     opt = "-k";
                   1092:   else if (s[strlen(s)-1] != '@')
                   1093:     { ar = thestring; sprintf(ar,"@%d",num); }
                   1094:   sprintf(str,"%s -fromgp %s %c%s%s%c",help_prg,opt, SHELL_Q,s,ar,SHELL_Q);
                   1095:   z = try_pipe(str,0); f = z->file;
                   1096:   free(str);
                   1097:   while (fgets(buf,MAX_LINE_LEN,f))
                   1098:   {
                   1099:     if (!strncmp("ugly_kludge_done",buf,16)) break;
                   1100:     buf[MAX_LINE_LEN]=0; pariputs(buf);
                   1101:     if (++li > nbli) { hit_return(); li = 0; }
                   1102:   }
                   1103:   pari_fclose(z);
                   1104: }
                   1105:
                   1106: char *keyword_list[]={
                   1107:   "operator",
                   1108:   "user",
                   1109:   "member",
                   1110:   "integer",
                   1111:   "real",
                   1112:   "readline",
                   1113:   "refcard",
                   1114:   "tutorial",
                   1115:   "nf",
                   1116:   "bnf",
                   1117:   "bnr",
                   1118:   "ell",
                   1119:   NULL
                   1120: };
                   1121:
                   1122: static int
                   1123: ok_external_help(char *s)
                   1124: {
                   1125:   long n;
                   1126:   if (!*s) return 1;
                   1127:   if (!isalpha((int)*s)) return 3; /* operator or section number */
                   1128:   if (!strncmp(s,"t_",2)) return 2; /* type name */
                   1129:
                   1130:   for (n=0; keyword_list[n]; n++)
                   1131:     if (!strcmp(s,keyword_list[n])) return 3;
                   1132:   return 0;
                   1133: }
                   1134:
                   1135: /* don't mess readline display */
                   1136: static void
                   1137: aide_err(char *s1, char *s2, int flag)
                   1138: {
                   1139:   if ((flag & h_RL) == 0) err(talker, "%s: %s", s1, s2);
                   1140:   pariputsf("%s: %s\n", s1, s2);
                   1141: }
                   1142:
                   1143: static void
                   1144: aide0(char *s, int flag)
                   1145: {
                   1146:   long n, long_help = flag & h_LONG;
                   1147:   entree *ep,*ep1;
                   1148:
                   1149:   s = get_sep(s);
                   1150:   if (isdigit((int)*s))
                   1151:   {
                   1152:     n=atoi(s);
                   1153:     if (n == 12) { community(); return; }
                   1154:     if (n<0 || n > 12)
                   1155:       err(talker2,"no such section in help: ?",s,s);
                   1156:     if (long_help) external_help(s,3); else commands(n);
                   1157:     return;
                   1158:   }
                   1159:   if (flag & h_APROPOS) { external_help(s,-1); return; }
                   1160:   if (long_help && (n = ok_external_help(s))) { external_help(s,n); return; }
                   1161:   switch (*s)
                   1162:   {
                   1163:     case '*' : commands(-1); return;
                   1164:     case '\0': menu_commands(); return;
                   1165:     case '\\': slash_commands(); return;
                   1166:     case '.' : member_commands(); return;
                   1167:   }
                   1168:   ep = is_entry(s);
                   1169:   if (!ep)
                   1170:   {
                   1171:     n = whatnow(s,1);
                   1172:     if (n) err(obsoler,s,s, s,n);
                   1173:     if (long_help)
                   1174:     {
                   1175:       n = setdefault(s,"",d_EXISTS) == gun? 2: 3;
                   1176:       external_help(s,n);
                   1177:     }
                   1178:     else
                   1179:       aide_err(s,"unknown identifier",flag);
                   1180:     return;
                   1181:   }
                   1182:
                   1183:   ep1 = ep;  ep = do_alias(ep);
                   1184:   if (ep1 != ep) pariputsf("%s is aliased to:\n\n",s);
                   1185:
                   1186:   switch(EpVALENCE(ep))
                   1187:   {
                   1188:     case EpUSER:
                   1189:       print_user_fun(ep); if (!ep->help) return;
                   1190:       pariputs("\n\n"); long_help=0; break;
                   1191:
                   1192:     case EpGVAR:
                   1193:     case EpVAR:
                   1194:       if (!ep->help) { aide_err(s, "user defined variable",flag); return; }
                   1195:       long_help=0; break;
                   1196:
                   1197:     case EpINSTALL:
                   1198:       if (!ep->help) { aide_err(s, "installed function",flag); return; }
                   1199:       long_help=0; break;
                   1200:   }
                   1201:   if (long_help) { external_help(ep->name,3); return; }
                   1202:   if (ep->help) { print_text(ep->help); return; }
                   1203:
                   1204:   err(bugparier,"aide (no help found)");
                   1205: }
                   1206:
                   1207: void
                   1208: aide(char *s, int flag)
                   1209: {
                   1210:   if ((flag & h_RL) == 0)
                   1211:   {
                   1212:     if (*s == '?') { flag |= h_LONG; s++; }
                   1213:     if (*s == '?') { flag |= h_APROPOS; s++; }
                   1214:   }
                   1215:   term_color(c_HELP); aide0(s,flag); term_color(c_NONE);
                   1216:   if ((flag & h_RL) == 0) pariputc('\n');
                   1217: }
                   1218:
                   1219: /********************************************************************/
                   1220: /**                                                                **/
                   1221: /**                         METACOMMANDS                           **/
                   1222: /**                                                                **/
                   1223: /********************************************************************/
                   1224:
                   1225: static void
                   1226: print_entree(entree *ep, long hash)
                   1227: {
                   1228:   pariputsf(" %s ",ep->name); pariputsf(VOIR_STRING1,(ulong)ep);
                   1229:   pariputsf(":\n   hash = %3ld, valence = %3ld, menu = %2ld, code = %s\n",
                   1230:             hash, ep->valence, ep->menu, ep->code? ep->code: "NULL");
                   1231:   if (ep->next)
                   1232:   {
                   1233:     pariputsf("   next = %s ",(ep->next)->name);
                   1234:     pariputsf(VOIR_STRING1,(ulong)(ep->next));
                   1235:   }
                   1236:   pariputs("\n");
                   1237: }
                   1238:
                   1239: static void
                   1240: print_hash_list(char *s)
                   1241: {
                   1242:   long m,n;
                   1243:   entree *ep;
                   1244:
                   1245:   if (isalpha((int)*s))
                   1246:   {
                   1247:     ep = is_entry_intern(s,functions_hash,&n);
                   1248:     if (!ep) err(talker,"no such function");
                   1249:     print_entree(ep,n); return;
                   1250:   }
                   1251:   if (isdigit((int)*s) || *s == '$')
                   1252:   {
                   1253:     m = functions_tblsz-1; n = atol(s);
                   1254:     if (*s=='$') n = m;
                   1255:     if (m<n) err(talker,"invalid range in print_entree");
                   1256:     while (isdigit((int)*s)) s++;
                   1257:
                   1258:     if (*s++ != '-') m = n;
                   1259:     else
                   1260:     {
                   1261:       if (*s !='$') m = min(atol(s),m);
                   1262:       if (m<n) err(talker,"invalid range in print_entree");
                   1263:     }
                   1264:
                   1265:     for(; n<=m; n++)
                   1266:     {
                   1267:       pariputsf("*** hashcode = %ld\n",n);
                   1268:       for (ep=functions_hash[n]; ep; ep=ep->next)
                   1269:        print_entree(ep,n);
                   1270:     }
                   1271:     return;
                   1272:   }
                   1273:   if (*s=='-')
                   1274:   {
                   1275:     for (n=0; n<functions_tblsz; n++)
                   1276:     {
                   1277:       m=0;
                   1278:       for (ep=functions_hash[n]; ep; ep=ep->next) m++;
                   1279:       pariputsf("%3ld:%3ld ",n,m);
                   1280:       if (n%9 == 8) pariputc('\n');
                   1281:     }
                   1282:     pariputc('\n'); return;
                   1283:   }
                   1284:   for (n=0; n<functions_tblsz; n++)
                   1285:     for (ep=functions_hash[n]; ep; ep=ep->next)
                   1286:       print_entree(ep,n);
                   1287: }
                   1288:
                   1289:
                   1290: static void
                   1291: center(char *s)
                   1292: {
                   1293:   long i, pad = term_width() - strlen(s);
                   1294:   char *u = thestring;
                   1295:
                   1296:   if (pad<0) pad=0; else pad >>= 1;
                   1297:   for (i=0; i<pad; i++) *u++ = ' ';
                   1298:   while (*s) *u++ = *s++;
                   1299:   *u++='\n'; *u=0; pariputs(thestring);
                   1300: }
                   1301:
                   1302: static char *
                   1303: what_readline()
                   1304: {
                   1305: #ifdef READLINE
                   1306:  return "v"READLINE" enabled";
                   1307: #else
                   1308:   return "disabled";
                   1309: #endif
                   1310: }
                   1311:
                   1312: static void
                   1313: print_version()
                   1314: {
                   1315:   char buf[64];
                   1316:
                   1317:   center(PARIVERSION); center(PARIINFO);
                   1318:   sprintf(buf,"(readline %s, extended help%s available)", what_readline(),
                   1319:           has_ext_help()? "": " not");
                   1320:   center(buf);
                   1321: }
                   1322:
                   1323: static void
                   1324: gp_head()
                   1325: {
                   1326:   print_version(); pariputs("\n");
                   1327:   center("Copyright (C) 1989-1999 by");
                   1328:   center("C. Batut, K. Belabas, D. Bernardi, H. Cohen and M. Olivier.");
                   1329:   pariputs("\n\
                   1330: Type ? for help, \\q to quit.\n\
                   1331: Type ?12 for how to get moral (and possibly technical) support.\n\n");
                   1332:   sd_realprecision  ("",d_ACKNOWLEDGE);
                   1333:   sd_seriesprecision("",d_ACKNOWLEDGE);
                   1334:   sd_format         ("",d_ACKNOWLEDGE);
                   1335:   pariputsf("\nparisize = %ld, primelimit = %ld\n", parisize, primelimit);
                   1336: }
                   1337:
                   1338: void
                   1339: gp_quit()
                   1340: {
                   1341:   free_graph(); freeall();
                   1342:   while (bufindex) free((void *)buflist[bufindex--]);
                   1343: #ifdef WINCE
                   1344: #else
                   1345:   if (INIT_SIG)
                   1346:   {
                   1347: #ifdef SIGBUS
                   1348:     signal(SIGBUS,SIG_DFL);
                   1349: #endif
                   1350:     signal(SIGSEGV,SIG_DFL);
                   1351:     signal(SIGINT,SIG_DFL);
                   1352: #ifdef SIGBREAK
                   1353:     signal(SIGBREAK,SIG_DFL);
                   1354: #endif
                   1355:   }
                   1356: #endif
                   1357:   term_color(c_NONE);
                   1358:   pariputs_opt("Good bye!\n"); exit(0);
                   1359: }
                   1360:
                   1361: /* history management function:
                   1362:  *   flag < 0, called from freeall()
                   1363:  *   flag = 0, called from %num in anal.c:truc()
                   1364:  *   flag > 0, called from %` in anal.c:truc(), p > 0
                   1365:  */
                   1366: static GEN
                   1367: gp_history(long p, long flag, char *old, char *entrypoint)
                   1368: {
                   1369:   int er1 = 0;
                   1370:   if (flag < 0) { free((void *)hist); return NULL; }
                   1371:   if (!tglobal) er1 = 1;
                   1372:   if (flag)
                   1373:   {
                   1374:     p = tglobal - p;
                   1375:     if (p <= 0) er1 = 1;
                   1376:   }
                   1377:   else if (p > tglobal)
                   1378:     err(talker2,"I can't see into the future",old,entrypoint);
                   1379:   if (!p) p = tglobal;
                   1380:   if (tglobal - p >= histsize) er1 = 1;
                   1381:   p = (p-1) % histsize;
                   1382:   if (er1 || !hist[p])
                   1383:     err(talker2,"I can't remember before the big bang",old,entrypoint);
                   1384:   return hist[p];
                   1385: }
                   1386:
                   1387: static void
                   1388: escape(char *tch)
                   1389: {
                   1390:   char *s, c;
                   1391:
                   1392:   if (compatible != NONE)
                   1393:   {
                   1394:     s = tch;
                   1395:     while (*s)
                   1396:       if (*s++ == '=')
                   1397:       {
                   1398:        GEN (*f)(char*, int) = NULL;
                   1399:        int len = (s-tch) - 1;
                   1400:
                   1401:        if (!strncmp(tch,"precision",len))         f = sd_realprecision;
                   1402:        else if (!strncmp(tch,"serieslength",len)) f = sd_seriesprecision;
                   1403:        else if (!strncmp(tch,"format",len))       f = sd_format;
                   1404:        else if (!strncmp(tch,"prompt",len))       f = sd_prompt;
                   1405:        if (f) { f(get_sep(s), d_ACKNOWLEDGE); return; }
                   1406:        break;
                   1407:       }
                   1408:   }
                   1409:   s = tch;
                   1410:   switch ((c = *s++))
                   1411:   {
                   1412:     case 'w': case 'x': case 'a': case 'b': case 'm': /* history things */
                   1413:     {
                   1414:       long d;
                   1415:       GEN x;
                   1416:       if (c != 'w' && c != 'x') d = get_int(s,0);
                   1417:       else
                   1418:       {
                   1419:        d = atol(s); if (*s == '-') s++;
                   1420:        while (isdigit((int)*s)) s++;
                   1421:       }
                   1422:       x = gp_history(d, 0, tch+1,tch-1);
                   1423:       switch (c)
                   1424:       {
                   1425:        case 'a': brute   (x, fmt.format, -1); break;
                   1426:        case 'm': matbrute(x, fmt.format, -1); break;
                   1427:        case 'b': sor     (x, fmt.format, -1, fmt.field); break;
                   1428:        case 'x': voir(x, get_int(s, -1)); return;
                   1429:         case 'w':
                   1430:        {
                   1431:          GEN g[2]; g[0] = x; g[1] = NULL;
                   1432:          s = get_sep(s); if (!*s) s = current_logfile;
                   1433:          write0(s, g, f_RAW); return;
                   1434:        }
                   1435:       }
                   1436:       pariputc('\n'); return;
                   1437:     }
                   1438:
                   1439:     case 'c': commands(-1); break;
                   1440:     case 'd': help_default(); break;
                   1441:     case 'e':
                   1442:       s = get_sep(s);
                   1443:       if (!*s) s = pariecho?"0":"1";
                   1444:       sd_echo(s,d_ACKNOWLEDGE); break;
                   1445:     case 'g':
                   1446:       switch (*s)
                   1447:       {
                   1448:         case 'm': sd_debugmem(++s,d_ACKNOWLEDGE); break;
                   1449:         case 'f': sd_debugfiles(++s,d_ACKNOWLEDGE); break;
                   1450:         default : sd_debug(s,d_ACKNOWLEDGE); break;
                   1451:       }
                   1452:       break;
                   1453:     case 'h': print_hash_list(s); break;
                   1454:     case 'l':
                   1455:       s = get_sep(s);
                   1456:       if (*s)
                   1457:       {
                   1458:         sd_logfile(s,d_ACKNOWLEDGE);
                   1459:         if (logfile) break;
                   1460:       }
                   1461:       sd_log(logfile?"0":"1",d_ACKNOWLEDGE);
                   1462:       break;
                   1463:     case 'p':
                   1464:       switch (*s)
                   1465:       {
                   1466:         case 's': sd_seriesprecision(++s,d_ACKNOWLEDGE); break;
                   1467:         default : sd_realprecision(s,d_ACKNOWLEDGE); break;
                   1468:       }
                   1469:       break;
                   1470:     case 'q': gp_quit(); break;
                   1471:     case 'r': switchin(get_sep(s)); break;
                   1472:     case 's': etatpile(0); break;
                   1473:     case 't': gentypes(); break;
                   1474:     case 'u':
                   1475:       switch (*s)
                   1476:       {
                   1477:         case 'm': user_member(); break;
                   1478:         default: user_fun();
                   1479:       }
                   1480:       break;
                   1481:     case 'v': print_version(); break;
                   1482:     case 'y':
                   1483:       s = get_sep(s);
                   1484:       if (!*s) s = simplifyflag?"0":"1";
                   1485:       sd_simplify(s,d_ACKNOWLEDGE); break;
                   1486:     default: err(caracer1,tch-1,tch-2);
                   1487:   }
                   1488: }
                   1489:
                   1490: /********************************************************************/
                   1491: /*                                                                  */
                   1492: /*                              GPRC                                */
                   1493: /*                                                                  */
                   1494: /********************************************************************/
                   1495: #if defined(UNIX) || defined(__EMX__)
                   1496: #  include <pwd.h>
                   1497: #endif
                   1498:
                   1499: static int
                   1500: get_preproc_value(char *s)
                   1501: {
                   1502:   if (!strncmp(s,"EMACS",5)) return under_emacs;
                   1503:   if (!strncmp(s,"READL",5))
                   1504:   {
                   1505: #ifdef READLINE
                   1506:     return 1;
                   1507: #else
                   1508:     return 0;
                   1509: #endif
                   1510:   }
                   1511:   return -1;
                   1512: }
                   1513:
                   1514: /* return $HOME or the closest we can find */
                   1515: static char *
                   1516: get_home(int *free_it)
                   1517: {
                   1518: #ifdef WINCE
                   1519:        return ".";
                   1520: #else
                   1521: #ifndef macintosh /* getenv() for Mac ? */
                   1522:   char *drv, *pth = getenv("HOME");
                   1523:   if (pth) return pth;
                   1524:   if ((drv = getenv("HOMEDRIVE"))
                   1525:    && (pth = getenv("HOMEPATH")))
                   1526:   { /* looks like WinNT */
                   1527:     char *buf = gpmalloc(strlen(pth) + strlen(drv) + 1);
                   1528:     sprintf(buf, "%s%s",drv,pth);
                   1529:     *free_it = 1; return buf;
                   1530:   }
                   1531: #endif
                   1532: #endif
                   1533: #if defined(__EMX__) || defined(UNIX)
                   1534:   {
                   1535:     struct passwd *p = getpwuid(geteuid());
                   1536:     if (p) return p->pw_dir;
                   1537:   }
                   1538: #endif
                   1539:   return ".";
                   1540: }
                   1541:
                   1542: static FILE *
                   1543: gprc_chk(char *s)
                   1544: {
                   1545:   FILE *f = fopen(s, "r");
                   1546:   if (f && !quiet_mode) fprintferr("Reading GPRC: %s ...", s);
                   1547:   return f;
                   1548: }
                   1549:
                   1550: /* Look for [._]gprc: $GPRC, then in $HOME, /, C:/ */
                   1551: static FILE *
                   1552: gprc_get()
                   1553: {
                   1554:   FILE *f = NULL;
                   1555:   char *str, *s, c;
                   1556:   long l;
                   1557: #ifdef macintosh
                   1558:   f = gprc_chk("gprc");
                   1559: #else
                   1560: #ifdef WINCE
                   1561:   s = NULL;
                   1562: #else
                   1563:   s = getenv("GPRC");
                   1564: #endif
                   1565:   if (s) f = gprc_chk(s);
                   1566:   if (!f)
                   1567:   {
                   1568:     int free_it = 0;
                   1569:     s = get_home(&free_it); l = strlen(s); c = s[l-1];
                   1570:     str = strcpy(gpmalloc(l+7), s);
                   1571:     if (free_it) free(s);
                   1572:     s = str + l;
                   1573:     if (c != '/' && c != '\\') *s++ = '/';
                   1574: #ifdef UNIX
                   1575:     *s = '.'; /* .gprc */
                   1576: #else
                   1577:     *s = '_'; /* _gprc */
                   1578: #endif
                   1579:     strcpy(s+1, "gprc");
                   1580:     f = gprc_chk(str); /* in $HOME */
                   1581:     if (!f) f = gprc_chk(s); /* in . */
                   1582:     if (!f) f = gprc_chk("/etc/gprc");
                   1583:     if (!f) f = gprc_chk("C:/_gprc");
                   1584:     free(str);
                   1585:   }
                   1586: #endif
                   1587:   return f;
                   1588: }
                   1589:
                   1590: static int
                   1591: init_brace(char *s)
                   1592: {
                   1593:   while (isspace((int)*s)) s++;
                   1594:   if (*s == LBRACE) { *s=' '; return 1; }
                   1595:   return 0;
                   1596: }
                   1597:
                   1598: /* return 1 if we deleted a '{' */
                   1599: static int
                   1600: init_filtre(char *s)
                   1601: {
                   1602:   if (filtre(s, f_INIT)) return 0; /* in comment */
                   1603:   return init_brace(s);
                   1604: }
                   1605:
                   1606: static void
                   1607: fix_buffer(long newlbuf, char **ptbuf, long *ptlbuf)
                   1608: {
                   1609:   buflist[bufindex] = *ptbuf = gprealloc(*ptbuf,newlbuf,*ptlbuf);
                   1610:   *ptlbuf = paribufsize = newlbuf;
                   1611: }
                   1612:
                   1613: /* prompt = NULL --> from gprc */
                   1614: static int
                   1615: get_line_from_file(FILE *file, char **ptbuf, long *ptlbuf, char *prompt)
                   1616: {
                   1617:   int f_flag = prompt? f_REG | f_KEEPCASE: f_REG;
                   1618:   int wait_for_brace;
                   1619:   long len = *ptlbuf;
                   1620:   char *s = *ptbuf;
                   1621:
                   1622:   if (!fgets(s, len, file)) return 0;
                   1623:   wait_for_brace = init_filtre(s);
                   1624:   for(;;)
                   1625:   {
                   1626:     int read_more = (s[strlen(s)-1] != '\n');
                   1627:     char *end = filtre(s, f_flag);
                   1628:     if (*s)
                   1629:     {
                   1630:       if (read_more) s = end;
                   1631:       else if (end[-1] == '\\')
                   1632:       {
                   1633:         if (*s=='?') break;
                   1634:         s = end-1;
                   1635:       }
                   1636:       else if (end[-1] == '='&& *s != '?')
                   1637:       {
                   1638:         s = end;
                   1639:       }
                   1640:       else
                   1641:       {
                   1642:        if (!wait_for_brace) break;
                   1643:        if (end[-1] == RBRACE) {end[-1]=0; break;}
                   1644:        s = end;
                   1645:       }
                   1646:       len = *ptlbuf - (s - *ptbuf);
                   1647:       if (len < 512)
                   1648:       {
                   1649:        long n = *ptlbuf << 1, l = s - *ptbuf;
                   1650:        len += *ptlbuf;
                   1651:        fix_buffer(n, ptbuf, ptlbuf);
                   1652:        s = *ptbuf + l;
                   1653:       }
                   1654:     }
                   1655:     if (!fgets(s, len, file)) break;
                   1656:     if (!read_more && !wait_for_brace)
                   1657:       wait_for_brace = init_filtre(s);
                   1658:   }
                   1659:   if (prompt && *ptbuf)
                   1660:   {
                   1661:     if (pariecho) { pariputs(prompt); pariputs(*ptbuf); pariputc('\n'); }
                   1662:     else if (logfile) fprintf(logfile, "%s%s\n",prompt,*ptbuf);
                   1663:     pariflush();
                   1664:   }
                   1665:   return 1;
                   1666: }
                   1667:
                   1668: #define err_gprc(s,t,u) { fprintferr("\n"); err(talker2,s,t,u); }
                   1669:
                   1670: static char **
                   1671: gp_initrc()
                   1672: {
                   1673:   char **flist, *buf, *s,*s1,*s2;
                   1674:   FILE *file = gprc_get();
                   1675:   long fnum = 4, find = 0, *ptlbuf = &paribufsize;
                   1676:
                   1677:   if (!file) return NULL;
                   1678:   flist = (char **) gpmalloc(fnum * sizeof(char*));
                   1679:   buflist[++bufindex] = buf = gpmalloc(*ptlbuf);
                   1680:   for(;;)
                   1681:   {
                   1682:     if (! get_line_from_file(file, &buf, ptlbuf, NULL))
                   1683:     {
                   1684:       if (!quiet_mode) fprintferr("Done.\n\n");
                   1685:       fclose(file); free(buflist[bufindex--]);
                   1686:       flist[find] = NULL; return flist;
                   1687:     }
                   1688:     for (s = buf; *s; )
                   1689:     {
                   1690:       s1 = s; if (get_sep2(s)) s++;
                   1691:       s += strlen(s1); /* point to next expr */
                   1692:       if (*s1 == '#')
                   1693:       { /* preprocessor directive */
                   1694:         int z, NOT = 0;
                   1695:         s1++;
                   1696:         if (strncmp(s1,"if",2)) err_gprc("unknown directive",s1,buf);
                   1697:         s1 += 2;
                   1698:         if (!strncmp(s1,"not",3)) { NOT = !NOT; s1 += 3; }
                   1699:         if (*s1 == '!')           { NOT = !NOT; s1++; }
                   1700:         z = get_preproc_value(s1);
                   1701:        if (z < 0) err_gprc("unknown preprocessor variable",s1,buf);
                   1702:        if (NOT) z = !z;
                   1703:         if (!z) continue;
                   1704:         s1 += 5;
                   1705:       }
                   1706:       if (!strncmp(s1,"read",4))
                   1707:       { /* read file */
                   1708:        s1 += 4;
                   1709:        if (find == fnum-1)
                   1710:        {
                   1711:          long n = fnum << 1;
                   1712:          flist = (char**)gprealloc(flist, n*sizeof(char*),
                   1713:                                           fnum*sizeof(char*));
                   1714:          fnum = n;
                   1715:        }
                   1716:        flist[find++] = s2 = gpmalloc(strlen(s1) + 1);
                   1717:        if (*s1 == '"') (void)readstring(s1, s2);
                   1718:        else strcpy(s2,s1);
                   1719:       }
                   1720:       else
                   1721:       { /* set default */
                   1722:        s2 = s1; while (*s2 && *s2 != '=') s2++;
                   1723:        if (*s2 != '=') err_gprc("missing '='",s2,buf);
                   1724:        *s2++ = 0;
                   1725:        if (*s2 == '"') (void)readstring(s2, s2);
                   1726:        setdefault(s1,s2,d_INITRC);
                   1727:       }
                   1728:     }
                   1729:   }
                   1730: }
                   1731:
                   1732: /********************************************************************/
                   1733: /*                                                                  */
                   1734: /*                           GP MAIN LOOP                           */
                   1735: /*                                                                  */
                   1736: /********************************************************************/
                   1737: /* flag:
                   1738:  *   ti_NOPRINT   don't print
                   1739:  *   ti_REGULAR   print elapsed time (chrono = 1)
                   1740:  *   ti_LAST      print last elapsed time (##)
                   1741:  *   ti_INTERRUPT received a SIGINT
                   1742:  */
                   1743: static char *
                   1744: do_time(long flag)
                   1745: {
                   1746:   static long last = 0;
                   1747:   long delay = (flag == ti_LAST)? last: gptimer();
                   1748:   char *s;
                   1749:
                   1750:   last = delay;
                   1751:   switch(flag)
                   1752:   {
                   1753:     case ti_NOPRINT: return NULL;
                   1754:     case ti_REGULAR:   s = "time = "; break;
                   1755:     case ti_INTERRUPT: s = "user interrupt after "; break;
                   1756:     case ti_LAST:      s = "  ***   last result computed in "; break;
                   1757:   }
                   1758:   strcpy(thestring,s); s=thestring+strlen(s);
                   1759:   strcpy(s, term_get_color(c_TIME)); s+=strlen(s);
                   1760:   if (delay >= 3600000)
                   1761:   {
                   1762:     sprintf(s, "%ldh, ", delay / 3600000); s+=strlen(s);
                   1763:     delay %= 3600000;
                   1764:   }
                   1765:   if (delay >= 60000)
                   1766:   {
                   1767:     sprintf(s, "%ldmn, ", delay / 60000); s+=strlen(s);
                   1768:     delay %= 60000;
                   1769:   }
                   1770:   if (delay >= 1000)
                   1771:   {
                   1772:     sprintf(s, "%ld,", delay / 1000); s+=strlen(s);
                   1773:     delay %= 1000;
                   1774:     if (delay < 100)
                   1775:     {
                   1776:       sprintf(s, "%s", (delay<10)? "00": "0");
                   1777:       s+=strlen(s);
                   1778:     }
                   1779:   }
                   1780:   sprintf(s, "%ld ms", delay); s+=strlen(s);
                   1781:   strcpy(s, term_get_color(c_NONE));
                   1782:   if (flag != ti_INTERRUPT) { s+=strlen(s); *s++='.'; *s++='\n'; *s=0; }
                   1783:   return thestring;
                   1784: }
                   1785:
                   1786: #ifndef WINCE
                   1787: static void
                   1788: gp_sighandler(int sig)
                   1789: {
                   1790:   char *msg;
                   1791:   switch(sig)
                   1792:   {
                   1793:     case SIGINT:
                   1794: #ifdef _WIN32
                   1795: # ifdef SIGBREAK
                   1796:     case SIGBREAK:
                   1797: # endif
                   1798:       if (++win32ctrlc >= 5) _exit(3);
                   1799:       signal(sig,gp_sighandler);
                   1800:       return;
                   1801: #endif
                   1802:       msg = do_time(ti_INTERRUPT);
                   1803:       break;
                   1804:
                   1805:     case SIGSEGV:
                   1806:       msg="segmentation fault: bug in GP (please report)";
                   1807:       break;
                   1808:
                   1809: #ifdef SIGBUS
                   1810:     case SIGBUS:
                   1811:       msg="bus error: bug in GP (please report)";
                   1812:       break;
                   1813: #endif
                   1814:     default:
                   1815:       msg="bug in signal handling (please report)";
                   1816:   }
                   1817:   signal(sig,gp_sighandler);
                   1818:   err(talker,msg);
                   1819: }
                   1820: #endif
                   1821: static void
                   1822: brace_color(char *s, int c)
                   1823: {
                   1824:   if (gp_colors[c] == c_NONE) return;
                   1825: #ifdef RL_PROMPT_START_IGNORE
                   1826:   *s++ = RL_PROMPT_START_IGNORE;
                   1827: #endif
                   1828:   strcpy(s, term_get_color(c));
                   1829: #ifdef RL_PROMPT_START_IGNORE
                   1830:   s+=strlen(s);
                   1831:   *s++ = RL_PROMPT_END_IGNORE; *s = 0;
                   1832: #endif
                   1833: }
                   1834:
                   1835: static char *
                   1836: do_prompt()
                   1837: {
                   1838:   static char buf[MAX_PROMPT_LEN + 24]; /* + room for color codes */
                   1839:   char *s = buf;
                   1840:
                   1841:   *s = 0;
                   1842:   /* escape sequences bug readline, so use special bracing (if available) */
                   1843:   brace_color(s, c_PROMPT);
                   1844:   s += strlen(s);
                   1845:   if (filtre(s, f_COMMENT))
                   1846:     strcpy(s, COMMENTPROMPT);
                   1847:   else
                   1848:     do_strftime(prompt,s);
                   1849:   s += strlen(s);
                   1850:   brace_color(s, c_INPUT); return buf;
                   1851: }
                   1852:
                   1853: static int
                   1854: read_line(char *promptbuf, char **ptbuf, long *ptlbuf)
                   1855: {
                   1856:   if (infile == stdin /* interactive use */
                   1857: #if defined(UNIX) || defined(__EMX__)
                   1858:      && (under_emacs || isatty(fileno(stdin)))
                   1859: #endif
                   1860:   )
                   1861:   {
                   1862: #ifdef READLINE
                   1863:     static char *previous_hist = NULL;
                   1864:     char *rlbuffer = readline(promptbuf), *s = *ptbuf;
                   1865:     int wait_for_brace, wait_for_input;
                   1866:
                   1867:     if (!rlbuffer) { pariputs("\n"); return 0; } /* EOF */
                   1868:     wait_for_input = wait_for_brace = init_filtre(rlbuffer);
                   1869:     for(;;)
                   1870:     {
                   1871:       long len = s - *ptbuf;
                   1872:       char *end = filtre(rlbuffer, f_READL);
                   1873:       long l = end - rlbuffer;
                   1874:
                   1875:       if (len + l > *ptlbuf)
                   1876:       {
                   1877:        fix_buffer(len+l+1, ptbuf, ptlbuf);
                   1878:        s = *ptbuf + len;
                   1879:       }
                   1880:       strcpy(s,rlbuffer); free(rlbuffer);
                   1881:       if (!*s) { if (!wait_for_input) break; }
                   1882:       else
                   1883:       {
                   1884:        s += l-1; /* *s = last input char */
                   1885:        if (wait_for_brace && *s == RBRACE) {*s=0; break;}
                   1886:        if (*s == '\\')
                   1887:         {
                   1888:           if (*rlbuffer == '?') break;
                   1889:         }
                   1890:         else if (*s == '=' && s[1-l] != '?')
                   1891:         {
                   1892:           wait_for_input = 1; s++;
                   1893:         }
                   1894:         else
                   1895:        {
                   1896:          if (!wait_for_brace) break;
                   1897:          s++;
                   1898:        }
                   1899:       }
                   1900:       /* read continuation line */
                   1901:       if (!(rlbuffer = readline(""))) break;
                   1902:       if (wait_for_input && !wait_for_brace)
                   1903:         wait_for_brace = init_brace(rlbuffer);
                   1904:     }
                   1905:     /* bug in readline 2.0: need to unblock ^C */
                   1906: # ifdef USE_SIGRELSE
                   1907:     sigrelse(SIGINT);
                   1908: # elif USE_SIGSETMASK
                   1909:     sigsetmask(0);
                   1910: # endif
                   1911:     s = *ptbuf;
                   1912:     if (*s)
                   1913:     {
                   1914:       /* update history (don't add the same entry twice) */
                   1915:       if (!previous_hist || strcmp(s,previous_hist))
                   1916:       {
                   1917:        if (previous_hist) free(previous_hist);
                   1918:        previous_hist = pari_strdup(s); add_history(s);
                   1919:       }
                   1920:       /* update logfile */
                   1921:       if (logfile) fprintf(logfile, "%s%s\n",promptbuf,s);
                   1922:     }
                   1923:     return 1;
                   1924: #else
                   1925:     pariputs(promptbuf);
                   1926: #endif /* defined(READLINE) */
                   1927:   }
                   1928:   else promptbuf = DFT_PROMPT;
                   1929:   return get_line_from_file(infile, ptbuf, ptlbuf, promptbuf);
                   1930: }
                   1931:
                   1932: static void
                   1933: chron(char *s)
                   1934: {
                   1935:   if (*s)
                   1936:   {
                   1937:     char *old = s-1;
                   1938:     if (*s == '#') { pariputs(do_time(ti_LAST)); s++; }
                   1939:     if (*s) err(caracer1,s,old);
                   1940:   }
                   1941:   else { chrono = 1-chrono; sd_timer("",d_ACKNOWLEDGE); }
                   1942: }
                   1943:
                   1944: /* bufindex != 0: we are doing an immediate read (with read, extern...) */
                   1945: static GEN
                   1946: gp_main_loop()
                   1947: {
                   1948:   long av, i,j, lbuf = paribufsize;
                   1949:   char *buf, *promptbuf = prompt;
                   1950:   GEN z = gnil;
                   1951:
                   1952:   if (bufindex == MAX_BUFFER) err(talker,"too many nested files");
                   1953:   buflist[++bufindex] = buf = (char *) gpmalloc(lbuf);
                   1954:   for(;;)
                   1955:   {
                   1956:     if (! bufindex)
                   1957:     {
                   1958:       static long tloc, outtyp;
                   1959:       tloc = tglobal; outtyp = prettyp; recover(0);
                   1960:       if (setjmp(environnement))
                   1961:       {
                   1962:        avma = top; parisize = top - bot;
                   1963:        j = tglobal - tloc; i = (tglobal-1)%histsize;
                   1964:        while (j)
                   1965:        {
                   1966:          gunclone(hist[i]); hist[i]=NULL;
                   1967:          if (!i) i = histsize;
                   1968:          i--; j--;
                   1969:        }
                   1970:         tglobal = tloc; prettyp = outtyp;
                   1971:        while (bufindex) free((void *)buflist[bufindex--]);
                   1972:        killallfiles(0);
                   1973:       }
                   1974:     }
                   1975:     setjmp(local_environnement[bufindex]);
                   1976:     added_newline = 1;
                   1977:     if (paribufsize != lbuf)
                   1978:       fix_buffer(paribufsize, &buf, &lbuf);
                   1979:
                   1980:     for(;;)
                   1981:     {
                   1982:       if (! test_mode) promptbuf = do_prompt();
                   1983:       if (! read_line(promptbuf, &buf, &lbuf))
                   1984:       {
                   1985: #ifdef _WIN32
                   1986:        Sleep(10); if (win32ctrlc) dowin32ctrlc();
                   1987: #endif
                   1988:        if (popinfile()) gp_quit();
                   1989:        if (bufindex) { free(buflist[bufindex--]); return z; }
                   1990:       }
                   1991:       else switch(*buf)
                   1992:       {
                   1993:        case '?': aide(buf+1, h_REGULAR); break;
                   1994:         case '#': chron(buf+1); break;
                   1995:         case '\\': escape(buf+1); break;
                   1996:        case '\0': break;
                   1997:        default: goto WORK;
                   1998:       }
                   1999:     }
                   2000: WORK:
                   2001:     if (! bufindex)
                   2002:     {
                   2003:       char c = buf[strlen(buf) - 1];
                   2004:       gpsilent = separe(c);
                   2005:     }
                   2006:     if (bufindex == 0) (void)gptimer();
                   2007:     av = avma;
                   2008:     z = readseq(buf, strictmatch);
                   2009:     if (!added_newline) pariputc('\n'); /* last output was print1() */
                   2010:     if (bufindex) continue;
                   2011:     if (chrono) pariputs(do_time(ti_REGULAR)); else do_time(ti_NOPRINT);
                   2012:     if (z == gnil) continue;
                   2013:
                   2014:     if (simplifyflag) z = simplify(z);
                   2015:     i = tglobal % histsize; tglobal++;
                   2016:     if (hist[i]) gunclone(hist[i]);
                   2017:     hist[i] = z = gclone(z); avma = av;
                   2018:     if (gpsilent) continue;
                   2019:
                   2020:     if (test_mode) { init80(0); gp_output(z); }
                   2021:     else
                   2022:     {
                   2023:       PariOUT *old = pariOut;
                   2024:       if (DEBUGLEVEL > 4) fprintferr("prec = [%ld, %ld]\n", prec,precdl);
                   2025:       term_color(c_HIST);
                   2026:       sprintf(thestring, "%%%ld = ",tglobal);
                   2027:       pariputs_opt(thestring);
                   2028:       term_color(c_OUTPUT);
                   2029:       init_lim_lines(thestring,lim_lines);
                   2030:       gp_output(z); pariOut=old;
                   2031:       term_color(c_NONE);
                   2032:     }
                   2033:     pariputc('\n'); pariflush();
                   2034:   }
                   2035: }
                   2036:
                   2037: GEN
                   2038: read0(char *s)
                   2039: {
                   2040:   switchin(s);
                   2041:   return gp_main_loop();
                   2042: }
                   2043:
                   2044: static void
                   2045: check_secure(char *s)
                   2046: {
                   2047:   if (secure)
                   2048:     err(talker, "secure mode: system commands not allowed\nTried to run '%s'",s);
                   2049: }
                   2050:
                   2051: GEN
                   2052: extern0(char *s)
                   2053: {
                   2054:   check_secure(s);
                   2055:   infile = try_pipe(s, mf_IN)->file;
                   2056:   return gp_main_loop();
                   2057: }
                   2058:
                   2059: static int
                   2060: silent()
                   2061: {
                   2062:   if (gpsilent) return 1;
                   2063:   { char c = _analyseur()[1]; return separe(c); }
                   2064: }
                   2065:
                   2066: GEN
                   2067: default0(char *a, char *b, long flag)
                   2068: {
                   2069:   if (flag) flag=d_RETURN;
                   2070:   else
                   2071:     flag = silent()? d_SILENT: d_ACKNOWLEDGE;
                   2072:   return setdefault(a,b,flag);
                   2073: }
                   2074:
                   2075: void
                   2076: allocatemem0(unsigned long newsize)
                   2077: {
                   2078:   parisize = allocatemoremem(newsize);
                   2079:   longjmp(local_environnement[bufindex], 0);
                   2080: }
                   2081:
                   2082: GEN
                   2083: input0()
                   2084: {
                   2085:   long *ptlbuf = &paribufsize;
                   2086:   char *buf;
                   2087:   GEN x;
                   2088:
                   2089:   if (bufindex == MAX_BUFFER) err(talker,"too many nested files");
                   2090:   buflist[++bufindex] = buf = gpmalloc(*ptlbuf);
                   2091:   while (! get_line_from_file(infile, &buf, ptlbuf, DFT_INPROMPT))
                   2092:     if (popinfile()) { fprintferr("no input ???"); gp_quit(); }
                   2093:   x = lisseq(buf);
                   2094:   free(buflist[bufindex--]);
                   2095:   return x;
                   2096: }
                   2097:
                   2098: void
                   2099: system0(char *s)
                   2100: {
                   2101: #if defined(UNIX) || defined(__EMX__)
                   2102:   check_secure(s);
                   2103:   system(s);
                   2104: #else
                   2105:   err(archer);
                   2106: #endif
                   2107: }
                   2108:
                   2109: void
                   2110: error0(GEN *g)
                   2111: {
                   2112:   term_color(c_ERR);
                   2113:   if (!added_newline) pariputc('\n');
                   2114:   pariputs("###   User error:\n\n   ");
                   2115:   print0(g,f_RAW); term_color(c_NONE);
                   2116:   err_recover(talker);
                   2117: }
                   2118:
                   2119: long
                   2120: setprecr(long n)
                   2121: {
                   2122:   long m = fmt.nb;
                   2123:
                   2124:   if (n>0) {fmt.nb = n; prec = (long)(n*pariK1 + 3);}
                   2125:   return m;
                   2126: }
                   2127:
                   2128: static void
                   2129: testint(char *s, long *d)
                   2130: {
                   2131:   if (!s) return;
                   2132:   *d = atol(s);
                   2133:   if (*d <= 0) err(talker,"arguments must be positive integers");
                   2134: }
                   2135:
                   2136: static char *
                   2137: read_arg(int *nread, char *t, long argc, char **argv)
                   2138: {
                   2139:   int i = *nread;
                   2140:   if (isdigit((int)*t)) return t;
                   2141:   if (*t || i==argc) usage(argv[0]);
                   2142:   *nread = i+1; return argv[i];
                   2143: }
                   2144:
                   2145: static char**
                   2146: read_opt(long argc, char **argv)
                   2147: {
                   2148:   char *b=NULL, *p=NULL, *s=NULL, **pre=(char**)1;
                   2149:   int i=1;
                   2150:
                   2151:   pari_outfile=stderr;
                   2152:   while (i<argc)
                   2153:   {
                   2154:     char *t = argv[i++];
                   2155:
                   2156:     if (*t++ != '-') usage(argv[0]);
                   2157:     switch(*t++)
                   2158:     {
                   2159:       case 'b': b = read_arg(&i,t,argc,argv); break;
                   2160:       case 'p': p = read_arg(&i,t,argc,argv); break;
                   2161:       case 's': s = read_arg(&i,t,argc,argv); break;
                   2162:
                   2163:       case 'e':
                   2164:        if (strncmp(t,"macs",4)) usage(argv[0]);
                   2165:         under_emacs = 1; break;
                   2166:       case 'q':
                   2167:         quiet_mode = 1; break;
                   2168:       case 't':
                   2169:        if (strncmp(t,"est",3)) usage(argv[0]);
                   2170:         disable_color = 1; test_mode = 1; /* fall through */
                   2171:       case 'f':
                   2172:        pre = NULL; break;
                   2173:       case '-':
                   2174:         if (strcmp(t, "version") == 0) {
                   2175:            print_version();
                   2176:            exit(0);
                   2177:         }
                   2178:        /* fall through */
                   2179:       default:
                   2180:        usage(argv[0]);
                   2181:     }
                   2182:   }
                   2183:   if (pre) pre = gp_initrc();
                   2184:
                   2185:   /* override the values from gprc */
                   2186:   testint(b, &paribufsize); if (paribufsize < 10) paribufsize = 10;
                   2187:   testint(p, &primelimit);
                   2188:   testint(s, &parisize);
                   2189:   if (under_emacs) disable_color=1;
                   2190:   pari_outfile=stdout; return pre;
                   2191: }
                   2192:
                   2193: #ifdef WINCE
                   2194: int
                   2195: WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   2196:         LPWSTR lpCmdLine, int nShowCmd)
                   2197: {
                   2198:   char **argv = NULL;
                   2199:   int argc = 1;
                   2200: #else
                   2201: int
                   2202: main(int argc, char **argv)
                   2203: {
                   2204: #endif
                   2205:   char **flist;
                   2206:
                   2207:   init_defaults(1); gp_preinit(1);
                   2208:   if (setjmp(environnement))
                   2209:   {
                   2210:     pariputs("### Errors on startup, exiting...\n\n");
                   2211:     exit(1);
                   2212:   }
                   2213: #ifdef __MWERKS__
                   2214:   argc = ccommand(&argv);
                   2215: #endif
                   2216:   flist = read_opt(argc,argv);
                   2217:   pari_addfunctions(&pari_modules, functions_gp,helpmessages_gp);
                   2218:   pari_addfunctions(&pari_modules, functions_highlevel,helpmessages_highlevel);
                   2219:   pari_addfunctions(&pari_oldmodules, functions_oldgp,helpmessages_oldgp);
                   2220:
                   2221:   init_graph(); INIT_SIG_off;
                   2222:   pari_init(parisize, primelimit);
                   2223: #ifndef WINCE
                   2224:   pari_sig_init(gp_sighandler);
                   2225: #endif
                   2226: #ifdef READLINE
                   2227:   init_readline();
                   2228: #endif
                   2229:   gp_history_fun = gp_history;
                   2230:   whatnow_fun = whatnow;
                   2231:   gp_expand_path(path);
                   2232:
                   2233:   if (!quiet_mode) gp_head();
                   2234:   if (flist)
                   2235:   {
                   2236:     long c=chrono, b=bufindex, e=pariecho;
                   2237:     FILE *l=logfile;
                   2238:     char **s = flist;
                   2239:     bufindex = 0; chrono=0; pariecho=0; logfile=NULL;
                   2240:     for ( ; *s; s++) { read0(*s); free(*s); }
                   2241:     bufindex = b; chrono=c; pariecho=e; logfile=l; free(flist);
                   2242:   }
                   2243:   gptimer(); timer2();
                   2244:   (void)gp_main_loop();
                   2245:   gp_quit(); return 0; /* not reached */
                   2246: }

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