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

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

1.2     ! noro        1: /* $Id: gp.c,v 1.139 2002/09/11 02:30:28 karim Exp $
1.1       noro        2:
                      3: Copyright (C) 2000  The PARI group.
                      4:
                      5: This file is part of the PARI/GP package.
                      6:
                      7: PARI/GP is free software; you can redistribute it and/or modify it under the
                      8: terms of the GNU General Public License as published by the Free Software
                      9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
                     10: ANY WARRANTY WHATSOEVER.
                     11:
                     12: Check the License for details. You should have received a copy of it, along
                     13: with the package; see the file 'COPYING'. If not, write to the Free Software
                     14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
                     15:
                     16: /*******************************************************************/
                     17: /**                                                               **/
                     18: /**                        PARI CALCULATOR                        **/
                     19: /**                                                               **/
                     20: /*******************************************************************/
                     21: #include "pari.h"
                     22: #ifdef _WIN32
                     23: #  include <windows.h>
                     24: #  ifndef WINCE
                     25: #    include <process.h>
                     26: #  endif
                     27: #endif
                     28: #ifdef HAS_STRFTIME
                     29: #  include <time.h>
                     30: #endif
                     31: #include "../language/anal.h"
                     32: #include "gp.h"
                     33:
                     34: #ifdef READLINE
1.2     ! noro       35:   extern void init_readline(void);
1.1       noro       36:   int readline_init = 1;
                     37: BEGINEXTERN
                     38: #  if defined(__cplusplus) && defined(__SUNPRO_CC)
1.2     ! noro       39:   extern char* readline(char*); /* bad prototype for readline() in readline.h */
1.1       noro       40: #  else
                     41: #   ifdef READLINE_LIBRARY
                     42: #     include <readline.h>
                     43: #   else
                     44: #     include <readline/readline.h>
                     45: #   endif
                     46: #  endif
                     47:   extern int isatty(int);
                     48: ENDEXTERN
                     49: #endif
                     50:
1.2     ! noro       51: extern void err_clean(void);
        !            52: extern void gp_output(GEN z, gp_data *G);
        !            53: extern void errcontext(char *msg, char *s, char *entry);
        !            54: extern void free_graph(void);
        !            55: extern void gp_expand_path(gp_path *p);
        !            56: extern int  gp_init_entrees(module *modlist, entree **hash, int force);
        !            57: extern void init_defaults(int force);
        !            58: extern void init_graph(void);
        !            59: extern void pari_sig_init(void (*f)(int));
        !            60: extern int  whatnow(char *s, int flag);
        !            61:
        !            62: static char *DFT_PRETTYPRINTER = "tex2mail -TeX -noindent -ragged -by_par";
1.1       noro       63:
                     64: #define MAX_PROMPT_LEN 128
                     65: #define DFT_PROMPT "? "
1.2     ! noro       66: #define BREAK_LOOP_PROMPT "> "
1.1       noro       67: #define COMMENTPROMPT "comment> "
1.2     ! noro       68: #define CONTPROMPT ""
1.1       noro       69: #define DFT_INPROMPT ""
1.2     ! noro       70: static char prompt[MAX_PROMPT_LEN], prompt_cont[MAX_PROMPT_LEN];
        !            71:
        !            72: static int tm_is_waiting = 0, handle_C_C = 0, gpsilent = 0;
        !            73:
        !            74: static ulong paribufsize, primelimit;
1.1       noro       75:
                     76: #define current_buffer (bufstack?((Buffer*)(bufstack->value)):NULL)
                     77: static stack *bufstack = NULL;
                     78:
                     79: #define skip_space(s) while (isspace((int)*s)) s++
                     80: #define skip_alpha(s) while (isalpha((int)*s)) s++
                     81:
                     82: static void
                     83: usage(char *s)
                     84: {
                     85:   printf("### Usage: %s [options]\n", s);
                     86:   printf("Options are:\n");
                     87:   printf("\t[-b buffersize]\tDeprecated\n");
                     88:   printf("\t[-emacs]\tRun as if in Emacs shell\n");
                     89:   printf("\t[-f]\t\tFaststart: do not read .gprc\n");
                     90:   printf("\t[--help]\tPrint this message\n");
                     91:   printf("\t[-q]\t\tQuiet mode: do not print banner and history numbers\n");
                     92:   printf("\t[-p primelimit]\tPrecalculate primes up to the limit\n");
                     93:   printf("\t[-s stacksize]\tStart with the PARI stack of given size (in bytes)\n");
                     94:   printf("\t[-test]\t\tTest mode.  As -q, plus wrap long lines\n");
                     95:   printf("\t[--version]\tOutput version info and exit\n\n");
                     96:   exit(0);
                     97: }
                     98:
                     99: static void
1.2     ! noro      100: init_hist(gp_hist *H, size_t l, ulong total)
1.1       noro      101: {
1.2     ! noro      102:   H->total = total;
        !           103:   H->size = l;
        !           104:   H->res = (GEN *) gpmalloc(l * sizeof(GEN));
        !           105:   memset(H->res,0, l * sizeof(GEN));
        !           106: }
1.1       noro      107:
1.2     ! noro      108: static void
        !           109: init_path(gp_path *path)
        !           110: {
        !           111:   char *p;
        !           112: #if defined(__EMX__) || defined(__CYGWIN32__)
        !           113:   p = ".;C:;C:/gp";
        !           114: #elif defined(UNIX)
        !           115:   p = ".:~:~/gp";
1.1       noro      116: #else
1.2     ! noro      117:   p = ".";
1.1       noro      118: #endif
1.2     ! noro      119:   path->PATH = pari_strdup(p);
        !           120:   path->dirs = NULL;
        !           121: }
1.1       noro      122:
1.2     ! noro      123: static char *
        !           124: init_help()
        !           125: {
        !           126:   char *h = os_getenv("GPHELP");
1.1       noro      127: # ifdef GPHELP
1.2     ! noro      128:   if (!h) h = GPHELP;
1.1       noro      129: # endif
1.2     ! noro      130:   if (h) h = pari_strdup(h);
        !           131:   return h;
        !           132: }
        !           133:
        !           134: static pariout_t *
        !           135: init_fmt()
        !           136: {
        !           137:   pariout_t *f = &DFLT_OUTPUT;
        !           138:   f->prettyp= f_PRETTYMAT;
        !           139: #ifdef LONG_IS_64BIT
        !           140:   f->sigd     = 38;
1.1       noro      141: #else
1.2     ! noro      142:   f->sigd     = 28;
1.1       noro      143: #endif
1.2     ! noro      144:   return f;
        !           145: }
        !           146:
        !           147: static void
        !           148: init_pp(gp_pp *p)
        !           149: {
        !           150:   p->cmd = pari_strdup(DFT_PRETTYPRINTER);
        !           151:   p->file = NULL;
        !           152: }
        !           153:
        !           154: /* must be called BEFORE pari_init() */
        !           155: static void
        !           156: gp_preinit(void)
        !           157: {
        !           158:   static gp_data __GP_DATA;
        !           159:   static gp_hist __HIST;
        !           160:   static gp_pp   __PP;
        !           161:   static gp_path __PATH;
        !           162:   static pari_timer __T;
        !           163:   long i;
        !           164:
1.1       noro      165:   bufstack = NULL;
1.2     ! noro      166:
        !           167:   primelimit = 500000;
        !           168:   bot = (gpmem_t)0;
        !           169:   top = (gpmem_t)(1000000*sizeof(long));
        !           170:   strcpy(prompt,      DFT_PROMPT);
        !           171:   strcpy(prompt_cont, CONTPROMPT);
        !           172:
        !           173:   paribufsize = 1024;
        !           174:   for (i=0; i<c_LAST; i++) gp_colors[i] = c_NONE;
        !           175:
        !           176:   GP_DATA = &__GP_DATA;
        !           177: #ifdef READLINE
        !           178:   GP_DATA->flags = (STRICTMATCH | SIMPLIFY | USE_READLINE);
1.1       noro      179: #else
1.2     ! noro      180:   GP_DATA->flags = (STRICTMATCH | SIMPLIFY);
1.1       noro      181: #endif
1.2     ! noro      182:   GP_DATA->lim_lines = 0;
        !           183:   GP_DATA->T    = &__T;
        !           184:   GP_DATA->hist = &__HIST;
        !           185:   GP_DATA->pp   = &__PP;
        !           186:   GP_DATA->path = &__PATH;
        !           187:   GP_DATA->help = init_help();
        !           188:   GP_DATA->fmt  = init_fmt();
        !           189:   init_hist(GP_DATA->hist, 5000, 0);
        !           190:   init_path(GP_DATA->path);
        !           191:   init_pp(GP_DATA->pp);
1.1       noro      192: }
                    193:
                    194: #ifdef MAXPATHLEN
                    195: #  define GET_SEP_SIZE MAXPATHLEN
                    196: #else
                    197: #  define GET_SEP_SIZE 128
                    198: #endif
                    199: #define separe(c)  ((c)==';' || (c)==':')
                    200:
1.2     ! noro      201: /* Return all chars, up to next separator
        !           202:  * [as strtok but must handle verbatim character string]
        !           203:  * If 'colon' is set, allow ';' and ':' as separator, only ';' otherwise */
1.1       noro      204: static char*
                    205: get_sep0(char *t, int colon)
                    206: {
1.2     ! noro      207:   static char buf[GET_SEP_SIZE], *lim = buf + (GET_SEP_SIZE-1);
1.1       noro      208:   char *s = buf;
1.2     ! noro      209:   int outer = 1;
1.1       noro      210:
                    211:   for(;;)
                    212:   {
                    213:     switch(*s++ = *t++)
                    214:     {
                    215:       case '"':
                    216:         if (outer || (s >= buf+2 && s[-2] != '\\')) outer = !outer;
                    217:         break;
                    218:       case '\0':
                    219:         return buf;
                    220:       case ';':
1.2     ! noro      221:        if (outer) { s[-1] = 0; return buf; } break;
1.1       noro      222:       case ':':
1.2     ! noro      223:         if (outer && colon) { s[-1] = 0; return buf; } break;
1.1       noro      224:     }
                    225:     if (s == lim) err(talker,"buffer overflow in get_sep");
                    226:   }
                    227: }
                    228:
                    229: static char*
                    230: get_sep(char *t)
                    231: {
                    232:   return get_sep0(t,1);
                    233: }
                    234:
                    235: static char*
                    236: get_sep_colon_ok(char *t)
                    237: {
                    238:   return get_sep0(t,0);
                    239: }
                    240:
1.2     ! noro      241: /* "atoul" + optional [km] suffix */
        !           242: static ulong
        !           243: my_int(char *s)
1.1       noro      244: {
1.2     ! noro      245:   ulong n = 0;
        !           246:   char *p = s;
1.1       noro      247:
1.2     ! noro      248:   while (isdigit((int)*p)) { n = 10*n + (*p++ - '0'); }
        !           249:   switch(*p)
1.1       noro      250:   {
1.2     ! noro      251:     case 'k': case 'K': n *= 1000;    p++; break;
        !           252:     case 'm': case 'M': n *= 1000000; p++; break;
1.1       noro      253:   }
1.2     ! noro      254:   if (*p) err(talker2,"I was expecting an integer here", s, s);
        !           255:   return n;
1.1       noro      256: }
                    257:
                    258: static long
                    259: get_int(char *s, long dflt)
                    260: {
1.2     ! noro      261:   char *p = get_sep(s);
        !           262:   long n;
        !           263:   int minus = 0;
        !           264:
        !           265:   if (*p == '-') { minus = 1; p++; }
        !           266:   if (!isdigit((int)*p)) return dflt;
        !           267:
        !           268:   n = (long)my_int(p);
        !           269:   if (n < 0) err(talker2,"integer too large in get_int",s,s);
        !           270:   return minus? -n: n;
        !           271: }
1.1       noro      272:
1.2     ! noro      273: static ulong
        !           274: get_uint(char *s)
        !           275: {
        !           276:   char *p = get_sep(s);
        !           277:   if (*p == '-') err(talker2,"arguments must be positive integers",s,s);
        !           278:   return my_int(p);
1.1       noro      279: }
                    280:
                    281: /* tell TeXmacs GP will start outputing data */
                    282: static void
1.2     ! noro      283: tm_start_output(void)
1.1       noro      284: {
                    285:   if (!tm_is_waiting) { printf("%cverbatim:",DATA_BEGIN); fflush(stdout); }
                    286:   tm_is_waiting = 1;
                    287: }
                    288:
                    289: /* tell TeXmacs GP is done and is waiting for new data */
                    290: static void
1.2     ! noro      291: tm_end_output(void)
1.1       noro      292: {
1.2     ! noro      293:   if (tm_is_waiting) { printf("%c", DATA_END); fflush(stdout); }
1.1       noro      294:   tm_is_waiting = 0;
                    295: }
                    296:
                    297: Buffer *
1.2     ! noro      298: new_buffer(void)
1.1       noro      299: {
                    300:   Buffer *b = (Buffer*) gpmalloc(sizeof(Buffer));
                    301:   b->len = paribufsize;
                    302:   b->buf = gpmalloc(b->len);
                    303:   b->flenv = 0; return b;
                    304: }
                    305:
                    306: void
                    307: del_buffer(Buffer *b)
                    308: {
                    309:   if (!b) return;
                    310:   free(b->buf); free((void*)b);
                    311: }
                    312:
                    313: static void
1.2     ! noro      314: pop_buffer(void)
1.1       noro      315: {
                    316:   Buffer *b = (Buffer*) pop_stack(&bufstack);
                    317:   del_buffer(b);
                    318: }
                    319:
                    320: /* kill all buffers until B is met or nothing is left */
                    321: static void
                    322: kill_all_buffers(Buffer *B)
                    323: {
                    324:   for(;;) {
                    325:     Buffer *b = current_buffer;
                    326:     if (b == B || !b) break;
                    327:     pop_buffer();
                    328:   }
                    329: }
                    330:
                    331: static void
1.2     ! noro      332: jump_to_buffer(void)
1.1       noro      333: {
                    334:   Buffer *b;
                    335:   while ( (b = current_buffer) )
                    336:   {
                    337:     if (b->flenv) break;
                    338:     pop_buffer();
                    339:   }
                    340:   if (!b) longjmp(environnement, 0);
                    341:   longjmp(b->env, 0);
                    342: }
                    343:
                    344: static void
                    345: jump_to_given_buffer(Buffer *buf)
                    346: {
                    347:   Buffer *b;
                    348:   while ( (b = current_buffer) )
                    349:   {
                    350:     if (b == buf) break;
                    351:     pop_buffer();
                    352:   }
                    353:   if (!b->env) { b = NULL; err(warner,"no environmnent tied to buffer"); }
                    354:   if (!b) longjmp(environnement, 0);
                    355:   longjmp(b->env, 0);
                    356: }
                    357:
                    358: /********************************************************************/
                    359: /*                                                                  */
                    360: /*                            DEFAULTS                              */
                    361: /*                                                                  */
                    362: /********************************************************************/
                    363: static void
1.2     ! noro      364: do_strftime(char *s, char *buf, long max)
1.1       noro      365: {
                    366: #ifdef HAS_STRFTIME
                    367:   time_t t = time(NULL);
1.2     ! noro      368:   strftime(buf,max,s,localtime(&t));
1.1       noro      369: #else
                    370:   strcpy(buf,s);
                    371: #endif
                    372: }
                    373:
                    374: static GEN
1.2     ! noro      375: sd_toggle(char *v, int flag, char *s, int *ptn)
        !           376: {
        !           377:   int state = *ptn;
        !           378:   if (*v)
        !           379:   {
        !           380:     int n = (int)get_int(v,0);
        !           381:     if (n == state) return gnil;
        !           382:     if (n != !state)
        !           383:     {
        !           384:       char s[128];
        !           385:       sprintf(s, "default: incorrect value for %s [0:off / 1:on]", s);
        !           386:       err(talker2, s, v,v);
        !           387:     }
        !           388:     state = *ptn = n;
        !           389:   }
        !           390:   switch(flag)
        !           391:   {
        !           392:     case d_RETURN: return utoi(state);
        !           393:     case d_ACKNOWLEDGE:
        !           394:       if (state) pariputsf("   %s = 1 (on)\n", s);
        !           395:       else       pariputsf("   %s = 0 (off)\n", s);
        !           396:       break;
        !           397:   }
        !           398:   return gnil;
        !           399: }
        !           400:
        !           401: static GEN
        !           402: sd_gptoggle(char *v, int flag, char *s, ulong FLAG)
        !           403: {
        !           404:   int n = (GP_DATA->flags & FLAG)? 1: 0, old = n;
        !           405:   GEN z = sd_toggle(v, flag, s, &n);
        !           406:   if (n != old)
        !           407:   {
        !           408:     if (n) GP_DATA->flags |=  FLAG;
        !           409:     else   GP_DATA->flags &= ~FLAG;
        !           410:   }
        !           411:   return z;
        !           412: }
        !           413:
        !           414: static GEN
        !           415: sd_ulong(char *v, int flag, char *s, ulong *ptn, ulong Min, ulong Max,
1.1       noro      416:            char **msg)
                    417: {
1.2     ! noro      418:   ulong n;
1.1       noro      419:   if (*v == 0) n = *ptn;
                    420:   else
                    421:   {
1.2     ! noro      422:     n = (ulong)get_int(v,0);
1.1       noro      423:     if (*ptn == n) return gnil;
                    424:     if (n > Max || n < Min)
                    425:     {
1.2     ! noro      426:       char s[128];
        !           427:       sprintf(s, "default: incorrect value for %s [%lu-%lu]", s, Min, Max);
        !           428:       err(talker2, s, v,v);
1.1       noro      429:     }
                    430:     *ptn = n;
                    431:   }
                    432:   switch(flag)
                    433:   {
1.2     ! noro      434:     case d_RETURN: return utoi(n);
1.1       noro      435:     case d_ACKNOWLEDGE:
                    436:       if (msg)
                    437:       {
1.2     ! noro      438:        if (!*msg) msg++; /* single msg, always printed */
        !           439:        else       msg += n; /* one per possible value */
        !           440:        pariputsf("   %s = %lu %s\n", s, n, *msg);
        !           441:       }
        !           442:       else
        !           443:        pariputsf("   %s = %lu\n", s, n);
1.1       noro      444:     default: return gnil;
                    445:   }
                    446: }
                    447:
                    448: #define PRECDIGIT (long)((prec-2.)*pariK)
                    449: static GEN
                    450: sd_realprecision(char *v, int flag)
                    451: {
1.2     ! noro      452:   pariout_t *fmt = GP_DATA->fmt;
1.1       noro      453:   if (*v)
                    454:   {
1.2     ! noro      455:     long newnb = get_int(v, fmt->sigd);
1.1       noro      456:     long newprec = (long) (newnb*pariK1 + 3);
                    457:
1.2     ! noro      458:     if (fmt->sigd == newnb && prec == newprec) return gnil;
1.1       noro      459:     if (newnb < 0) err(talker,"default: negative real precision");
1.2     ! noro      460:     fmt->sigd = newnb; prec = newprec;
1.1       noro      461:   }
1.2     ! noro      462:   if (flag == d_RETURN) return stoi(fmt->sigd);
1.1       noro      463:   if (flag == d_ACKNOWLEDGE)
                    464:   {
                    465:     long n = PRECDIGIT;
                    466:     pariputsf("   realprecision = %ld significant digits", n);
1.2     ! noro      467:     if (n != fmt->sigd)
        !           468:       pariputsf(" (%ld digits displayed)", fmt->sigd);
1.1       noro      469:     pariputc('\n');
                    470:   }
                    471:   return gnil;
                    472: }
                    473: #undef PRECDIGIT
                    474:
                    475: static GEN
                    476: sd_seriesprecision(char *v, int flag)
                    477: {
                    478:   char *msg[] = {NULL, "significant terms"};
1.2     ! noro      479:   return sd_ulong(v,flag,"seriesprecision",&precdl, 0,LGBITS,msg);
1.1       noro      480: }
                    481:
                    482: static GEN
                    483: sd_format(char *v, int flag)
                    484: {
1.2     ! noro      485:   pariout_t *fmt = GP_DATA->fmt;
1.1       noro      486:   if (*v)
                    487:   {
                    488:     char c = *v;
                    489:     if (c!='e' && c!='f' && c!='g')
                    490:       err(talker2,"default: inexistent format",v,v);
1.2     ! noro      491:     fmt->format = c; v++;
1.1       noro      492:
                    493:     if (isdigit((int)*v))
1.2     ! noro      494:       { fmt->fieldw=atol(v); while (isdigit((int)*v)) v++; }
1.1       noro      495:     if (*v++ == '.')
                    496:     {
1.2     ! noro      497:       if (*v == '-') fmt->sigd = -1;
1.1       noro      498:       else
1.2     ! noro      499:        if (isdigit((int)*v)) fmt->sigd=atol(v);
1.1       noro      500:     }
                    501:   }
                    502:   if (flag == d_RETURN)
                    503:   {
1.2     ! noro      504:     char s[128];
        !           505:     sprintf(s, "%c%ld.%ld", fmt->format, fmt->fieldw, fmt->sigd);
        !           506:     return strtoGENstr(s,0);
1.1       noro      507:   }
                    508:   if (flag == d_ACKNOWLEDGE)
1.2     ! noro      509:     pariputsf("   format = %c%ld.%ld\n", fmt->format, fmt->fieldw, fmt->sigd);
1.1       noro      510:   return gnil;
                    511: }
                    512:
                    513: static long
                    514: gp_get_color(char **st)
                    515: {
                    516:   char *s, *v = *st;
                    517:   int c, trans;
                    518:   if (isdigit((int)*v))
                    519:     { c = atol(v); trans = 1; } /* color on transparent background */
                    520:   else
                    521:   {
                    522:     if (*v == '[')
                    523:     {
                    524:       char *a[3];
                    525:       int i = 0;
                    526:       for (a[0] = s = ++v; *s && *s != ']'; s++)
                    527:         if (*s == ',') { *s = 0; a[++i] = s+1; }
                    528:       if (*s != ']') err(talker2,"expected character: ']'",s, *st);
                    529:       *s = 0; for (i++; i<3; i++) a[i] = "";
                    530:       /*    properties    |   color    | background */
                    531:       c = (atoi(a[2])<<8) | atoi(a[0]) | (atoi(a[1])<<4);
                    532:       trans = (*(a[1]) == 0);
                    533:       v = s + 1;
1.2     ! noro      534:     }
1.1       noro      535:     else { c = c_NONE; trans = 0; }
                    536:   }
                    537:   if (trans) c = c | (1<<12);
                    538:   while (*v && *v++ != ',') /* empty */;
1.2     ! noro      539:   if (c != c_NONE) disable_color = 0;
1.1       noro      540:   *st = v; return c;
                    541: }
                    542:
                    543: static GEN
                    544: sd_colors(char *v, int flag)
                    545: {
                    546:   long c,l;
1.2     ! noro      547:   if (*v && !(GP_DATA->flags & (EMACS|TEXMACS)))
1.1       noro      548:   {
1.2     ! noro      549:     char *v0;
1.1       noro      550:     disable_color=1;
                    551:     l = strlen(v);
                    552:     if (l <= 2 && strncmp(v, "no", l) == 0)
                    553:       v = "";
                    554:     if (l <= 6 && strncmp(v, "darkbg", l) == 0)
                    555:       v = "1, 5, 3, 7, 6, 2, 3";       /* Assume recent ReadLine. */
                    556:     if (l <= 7 && strncmp(v, "lightbg", l) == 0)
                    557:       v = "1, 6, 3, 4, 5, 2, 3";       /* Assume recent ReadLine. */
                    558:     if (l <= 6 && strncmp(v, "boldfg", l) == 0)        /* Good for darkbg consoles */
                    559:       v = "[1,,1], [5,,1], [3,,1], [7,,1], [6,,1], [2,,1], [3,,1]";
1.2     ! noro      560:     v0 = v = filtre(v, 0);
1.1       noro      561:     for (c=c_ERR; c < c_LAST; c++)
                    562:       gp_colors[c] = gp_get_color(&v);
1.2     ! noro      563:     free(v0);
1.1       noro      564:   }
                    565:   if (flag == d_ACKNOWLEDGE || flag == d_RETURN)
                    566:   {
1.2     ! noro      567:     char s[128], *t = s;
1.1       noro      568:     int col[3], n;
1.2     ! noro      569:     for (*t=0,c=c_ERR; c < c_LAST; c++)
1.1       noro      570:     {
                    571:       n = gp_colors[c];
1.2     ! noro      572:       if (n == c_NONE)
        !           573:         sprintf(t,"no");
1.1       noro      574:       else
                    575:       {
                    576:         decode_color(n,col);
                    577:         if (n & (1<<12))
                    578:         {
                    579:           if (col[0])
1.2     ! noro      580:             sprintf(t,"[%d,,%d]",col[1],col[0]);
1.1       noro      581:           else
1.2     ! noro      582:             sprintf(t,"%d",col[1]);
1.1       noro      583:         }
                    584:         else
1.2     ! noro      585:           sprintf(t,"[%d,%d,%d]",col[1],col[2],col[0]);
1.1       noro      586:       }
1.2     ! noro      587:       t += strlen(t);
        !           588:       if (c < c_LAST - 1) { *t++=','; *t++=' '; }
1.1       noro      589:     }
1.2     ! noro      590:     if (flag==d_RETURN) return strtoGENstr(s,0);
        !           591:     pariputsf("   colors = \"%s\"\n",s);
1.1       noro      592:   }
                    593:   return gnil;
                    594: }
                    595:
                    596: static GEN
                    597: sd_compatible(char *v, int flag)
                    598: {
                    599:   char *msg[] = {
                    600:     "(no backward compatibility)",
                    601:     "(warn when using obsolete functions)",
                    602:     "(use old functions, don't ignore case)",
                    603:     "(use old functions, ignore case)", NULL
                    604:   };
1.2     ! noro      605:   ulong old = compatible;
        !           606:   GEN r = sd_ulong(v,flag,"compatible",&compatible, 0,3,msg);
1.1       noro      607:
                    608:   if (old != compatible && flag != d_INITRC)
                    609:   {
                    610:     int res = gp_init_entrees(new_fun_set? pari_modules: pari_oldmodules,
                    611:                              functions_hash, 0);
                    612:     if (res) err(warner,"user functions re-initialized");
                    613:   }
                    614:   return r;
                    615: }
                    616:
                    617: static GEN
                    618: sd_secure(char *v, int flag)
                    619: {
1.2     ! noro      620:   if (*v && (GP_DATA->flags & SECURE))
1.1       noro      621:   {
                    622:     fprintferr("[secure mode]: Do you want to modify the 'secure' flag? (^C if not)\n");
                    623:     hit_return();
                    624:   }
1.2     ! noro      625:   return sd_gptoggle(v,flag,"secure", SECURE);
1.1       noro      626: }
                    627:
                    628: static GEN
                    629: sd_buffersize(char *v, int flag)
1.2     ! noro      630: { return sd_ulong(v,flag,"buffersize",&paribufsize, 1,
1.1       noro      631:                     (VERYBIGINT / sizeof(long)) - 1,NULL); }
                    632: static GEN
                    633: sd_debug(char *v, int flag)
1.2     ! noro      634: { return sd_ulong(v,flag,"debug",&DEBUGLEVEL, 0,20,NULL); }
1.1       noro      635:
                    636: static GEN
                    637: sd_rl(char *v, int flag)
                    638: {
                    639: #ifdef READLINE
1.2     ! noro      640:   if (!readline_init && *v && *v != '0') {
        !           641:     init_readline();
        !           642:     readline_init = 1;
        !           643:   }
1.1       noro      644: #endif
1.2     ! noro      645:   return sd_gptoggle(v,flag,"readline", USE_READLINE);
1.1       noro      646: }
                    647:
                    648: static GEN
                    649: sd_debugfiles(char *v, int flag)
1.2     ! noro      650: { return sd_ulong(v,flag,"debugfiles",&DEBUGFILES, 0,20,NULL); }
1.1       noro      651:
                    652: static GEN
                    653: sd_debugmem(char *v, int flag)
1.2     ! noro      654: { return sd_ulong(v,flag,"debugmem",&DEBUGMEM, 0,20,NULL); }
1.1       noro      655:
                    656: static GEN
                    657: sd_echo(char *v, int flag)
1.2     ! noro      658: { return sd_gptoggle(v,flag,"echo", ECHO); }
1.1       noro      659:
                    660: static GEN
                    661: sd_lines(char *v, int flag)
1.2     ! noro      662: { return sd_ulong(v,flag,"lines",&(GP_DATA->lim_lines), 0,VERYBIGINT,NULL); }
1.1       noro      663:
                    664: static GEN
                    665: sd_histsize(char *v, int flag)
                    666: {
1.2     ! noro      667:   gp_hist *H = GP_DATA->hist;
        !           668:   ulong n = H->size;
        !           669:   GEN r = sd_ulong(v,flag,"histsize",&n, 1,
1.1       noro      670:                      (VERYBIGINT / sizeof(long)) - 1,NULL);
1.2     ! noro      671:   if (n != H->size)
1.1       noro      672:   {
1.2     ! noro      673:     const ulong total = H->total;
        !           674:     long g, h, k, kmin;
        !           675:     GEN *resG = H->res, *resH; /* G = old data, H = new one */
        !           676:     size_t sG = H->size, sH;
        !           677:
        !           678:     init_hist(H, n, total);
        !           679:     if (!total) return r;
        !           680:
        !           681:     resH = H->res;
        !           682:     sH   = H->size;
        !           683:     /* copy relevant history entries */
        !           684:     g     = (total-1) % sG;
        !           685:     h = k = (total-1) % sH;
        !           686:     kmin = k - min(sH, sG);
        !           687:     for ( ; k > kmin; k--, g--, h--)
        !           688:     {
        !           689:       resH[h] = resG[g];
        !           690:       resG[g] = NULL;
        !           691:       if (!g) g = sG;
        !           692:       if (!h) h = sH;
        !           693:     }
        !           694:     /* clean up */
        !           695:     for ( ; resG[g]; g--)
1.1       noro      696:     {
1.2     ! noro      697:       gunclone(resG[g]);
        !           698:       if (!g) g = sG;
1.1       noro      699:     }
1.2     ! noro      700:     free((void*)resG);
1.1       noro      701:   }
                    702:   return r;
                    703: }
                    704:
                    705: static GEN
                    706: sd_log(char *v, int flag)
                    707: {
1.2     ! noro      708:   int old = GP_DATA->flags;
        !           709:   GEN r = sd_gptoggle(v,flag,"log",LOG);
        !           710:   if (GP_DATA->flags != old)
        !           711:   { /* toggled LOG */
        !           712:     if (old & LOG)
        !           713:     { /* close log */
        !           714:       if (flag == d_ACKNOWLEDGE)
        !           715:         pariputsf("   [logfile was \"%s\"]\n", current_logfile);
        !           716:       fclose(logfile); logfile = NULL;
        !           717:     }
        !           718:     else
        !           719:     { /* open log */
1.1       noro      720:       logfile = fopen(current_logfile, "a");
                    721:       if (!logfile) err(openfiler,"logfile",current_logfile);
                    722: #ifndef WINCE
                    723:       setbuf(logfile,(char *)NULL);
                    724: #endif
                    725:     }
                    726:   }
                    727:   return r;
                    728: }
                    729:
                    730: static GEN
                    731: sd_output(char *v, int flag)
                    732: {
1.2     ! noro      733:   char *msg[] = {"(raw)", "(prettymatrix)", "(prettyprint)",
        !           734:                  "(external prettyprint)", NULL};
        !           735:   ulong n = GP_DATA->fmt->prettyp;
        !           736:   GEN z = sd_ulong(v,flag,"output", &n, 0,3,msg);
        !           737:   GP_DATA->fmt->prettyp = n; return z;
1.1       noro      738: }
                    739:
                    740: void
1.2     ! noro      741: allocatemem0(size_t newsize)
1.1       noro      742: {
1.2     ! noro      743:   (void)allocatemoremem(newsize);
1.1       noro      744:   err_clean();
                    745:   jump_to_buffer();
                    746: }
                    747:
                    748: static GEN
                    749: sd_parisize(char *v, int flag)
                    750: {
1.2     ! noro      751:   ulong n = top-bot;
        !           752:   GEN r = sd_ulong(v,flag,"parisize",&n, 10000,VERYBIGINT,NULL);
        !           753:   if (n != (ulong)top-bot)
1.1       noro      754:   {
1.2     ! noro      755:     if (!bot) top = (gpmem_t)n; /* no stack allocated yet */
1.1       noro      756:     if (flag != d_INITRC) allocatemem0(n);
                    757:   }
                    758:   return r;
                    759: }
                    760:
                    761: static GEN
                    762: sd_primelimit(char *v, int flag)
                    763: {
1.2     ! noro      764:   ulong n = primelimit;
        !           765:   GEN r = sd_ulong(v,flag,"primelimit",&n, 0,VERYBIGINT,NULL);
1.1       noro      766:   if (n != primelimit)
                    767:   {
                    768:     if (flag != d_INITRC)
                    769:     {
                    770:       byteptr ptr = initprimes(n);
                    771:       free(diffptr); diffptr = ptr;
                    772:     }
                    773:     primelimit = n;
                    774:   }
                    775:   return r;
                    776: }
                    777:
                    778: static GEN
                    779: sd_simplify(char *v, int flag)
1.2     ! noro      780: { return sd_gptoggle(v,flag,"simplify", SIMPLIFY); }
1.1       noro      781:
                    782: static GEN
                    783: sd_strictmatch(char *v, int flag)
1.2     ! noro      784: { return sd_gptoggle(v,flag,"strictmatch", STRICTMATCH); }
1.1       noro      785:
                    786: static GEN
                    787: sd_timer(char *v, int flag)
1.2     ! noro      788: { return sd_gptoggle(v,flag,"timer", CHRONO); }
1.1       noro      789:
                    790: static GEN
                    791: sd_filename(char *v, int flag, char *s, char **f)
                    792: {
                    793:   if (*v)
                    794:   {
1.2     ! noro      795:     char *s, *old = *f;
        !           796:     long l;
1.1       noro      797:     v = expand_tilde(v);
1.2     ! noro      798:     l = strlen(v) + 256;
        !           799:     s = malloc(l);
        !           800:     do_strftime(v,s, l-1); free(v);
        !           801:     *f = pari_strdup(s); free(s); free(old);
1.1       noro      802:   }
                    803:   if (flag == d_RETURN) return strtoGENstr(*f,0);
                    804:   if (flag == d_ACKNOWLEDGE) pariputsf("   %s = \"%s\"\n",s,*f);
                    805:   return gnil;
                    806: }
                    807:
                    808: static GEN
                    809: sd_logfile(char *v, int flag)
                    810: {
                    811:   GEN r = sd_filename(v, flag, "logfile", &current_logfile);
                    812:   if (*v && logfile)
                    813:   {
                    814:     fclose(logfile);
                    815:     logfile = fopen(current_logfile, "a");
                    816:     if (!logfile) err(openfiler,"logfile",current_logfile);
                    817: #ifndef WINCE
                    818:     setbuf(logfile,(char *)NULL);
                    819: #endif
                    820:   }
                    821:   return r;
                    822: }
                    823:
                    824: static GEN
1.2     ! noro      825: sd_new_galois_format(char *v, int flag)
        !           826: { return sd_toggle(v,flag,"new_galois_format", &new_galois_format); }
        !           827:
        !           828: static GEN
1.1       noro      829: sd_psfile(char *v, int flag)
                    830: { return sd_filename(v, flag, "psfile", &current_psfile); }
                    831:
                    832: static void
                    833: err_secure(char *d, char *v)
                    834: { err(talker,"[secure mode]: can't modify '%s' default (to %s)",d,v); }
                    835:
                    836: static GEN
                    837: sd_help(char *v, int flag)
                    838: {
                    839:   char *str;
                    840:   if (*v)
                    841:   {
1.2     ! noro      842:     if (GP_DATA->flags & SECURE) err_secure("help",v);
        !           843:     if (GP_DATA->help) free(GP_DATA->help);
        !           844:     GP_DATA->help = expand_tilde(v);
1.1       noro      845:   }
1.2     ! noro      846:   str = GP_DATA->help? GP_DATA->help: "none";
1.1       noro      847:   if (flag == d_RETURN) return strtoGENstr(str,0);
                    848:   if (flag == d_ACKNOWLEDGE)
                    849:     pariputsf("   help = \"%s\"\n", str);
                    850:   return gnil;
                    851: }
                    852:
                    853: static GEN
                    854: sd_path(char *v, int flag)
                    855: {
1.2     ! noro      856:   gp_path *p = GP_DATA->path;
1.1       noro      857:   if (*v)
                    858:   {
1.2     ! noro      859:     free((void*)p->PATH);
        !           860:     p->PATH = pari_strdup(v);
1.1       noro      861:     if (flag == d_INITRC) return gnil;
1.2     ! noro      862:     gp_expand_path(p);
1.1       noro      863:   }
1.2     ! noro      864:   if (flag == d_RETURN) return strtoGENstr(p->PATH,0);
1.1       noro      865:   if (flag == d_ACKNOWLEDGE)
1.2     ! noro      866:     pariputsf("   path = \"%s\"\n",p->PATH);
1.1       noro      867:   return gnil;
                    868: }
                    869:
                    870: static GEN
                    871: sd_prettyprinter(char *v, int flag)
                    872: {
1.2     ! noro      873:   gp_pp *pp = GP_DATA->pp;
        !           874:   if (*v && !(GP_DATA->flags & TEXMACS))
1.1       noro      875:   {
1.2     ! noro      876:     char *old = pp->cmd;
1.1       noro      877:     int cancel = (!strcmp(v,"no"));
                    878:
1.2     ! noro      879:     if (GP_DATA->flags & SECURE) err_secure("prettyprinter",v);
        !           880:     if (!strcmp(v,"yes")) v = DFT_PRETTYPRINTER;
        !           881:     if (old && strcmp(old,v) && pp->file)
1.1       noro      882:     {
                    883:       pariFILE *f;
                    884:       if (cancel) f = NULL;
                    885:       else
                    886:       {
                    887:         f = try_pipe(v, mf_OUT | mf_TEST);
                    888:         if (!f)
                    889:         {
                    890:           err(warner,"broken prettyprinter: '%s'",v);
                    891:           return gnil;
                    892:         }
                    893:       }
1.2     ! noro      894:       pari_fclose(pp->file);
        !           895:       pp->file = f;
1.1       noro      896:     }
1.2     ! noro      897:     pp->cmd = cancel? NULL: pari_strdup(v);
        !           898:     if (old) free(old);
1.1       noro      899:     if (flag == d_INITRC) return gnil;
                    900:   }
1.2     ! noro      901:   if (flag == d_RETURN) return strtoGEN(pp->cmd? pp->cmd: "");
1.1       noro      902:   if (flag == d_ACKNOWLEDGE)
1.2     ! noro      903:     pariputsf("   prettyprinter = \"%s\"\n",pp->cmd? pp->cmd: "");
1.1       noro      904:   return gnil;
                    905: }
                    906:
                    907: static GEN
1.2     ! noro      908: sd_prompt_set(char *v, int flag, char *how, char *p)
1.1       noro      909: {
                    910:   if (*v)
                    911:   {
1.2     ! noro      912:     strncpy(p,v,MAX_PROMPT_LEN);
1.1       noro      913: #ifdef macintosh
1.2     ! noro      914:     strcat(p,"\n");
1.1       noro      915: #endif
                    916:   }
1.2     ! noro      917:   if (flag == d_RETURN) return strtoGENstr(p,0);
1.1       noro      918:   if (flag == d_ACKNOWLEDGE)
1.2     ! noro      919:     pariputsf("   prompt%s = \"%s\"\n", how, p);
1.1       noro      920:   return gnil;
                    921: }
                    922:
1.2     ! noro      923: static GEN
        !           924: sd_prompt(char *v, int flag)
        !           925: {
        !           926:   return sd_prompt_set(v, flag, "", prompt);
        !           927: }
        !           928:
        !           929: static GEN
        !           930: sd_prompt_cont(char *v, int flag)
        !           931: {
        !           932:   return sd_prompt_set(v, flag, "_cont", prompt_cont);
        !           933: }
        !           934:
1.1       noro      935: default_type gp_default_list[] =
                    936: {
                    937:   {"buffersize",(void*)sd_buffersize},
                    938:   {"colors",(void*)sd_colors},
                    939:   {"compatible",(void*)sd_compatible},
                    940:   {"debug",(void*)sd_debug},
                    941:   {"debugfiles",(void*)sd_debugfiles},
                    942:   {"debugmem",(void*)sd_debugmem},
                    943:   {"echo",(void*)sd_echo},
                    944:   {"format",(void*)sd_format},
                    945:   {"help",(void*)sd_help},
                    946:   {"histsize",(void*)sd_histsize},
                    947:   {"lines",(void*)sd_lines},
                    948:   {"log",(void*)sd_log},
                    949:   {"logfile",(void*)sd_logfile},
1.2     ! noro      950:   {"new_galois_format",(void*)sd_new_galois_format},
1.1       noro      951:   {"output",(void*)sd_output},
                    952:   {"parisize",(void*)sd_parisize},
                    953:   {"path",(void*)sd_path},
                    954:   {"primelimit",(void*)sd_primelimit},
                    955:   {"prettyprinter",(void*)sd_prettyprinter},
                    956:   {"prompt",(void*)sd_prompt},
1.2     ! noro      957:   {"prompt_cont",(void*)sd_prompt_cont},
1.1       noro      958:   {"psfile",(void*)sd_psfile},
                    959:   {"realprecision",(void*)sd_realprecision},
                    960:   {"readline",(void*)sd_rl},
                    961:   {"secure",(void*)sd_secure},
                    962:   {"seriesprecision",(void*)sd_seriesprecision},
                    963:   {"simplify",(void*)sd_simplify},
                    964:   {"strictmatch",(void*)sd_strictmatch},
                    965:   {"timer",(void *)sd_timer},
                    966:   {NULL,NULL} /* sentinel */
                    967: };
                    968:
                    969: static void
1.2     ! noro      970: help_default(void)
1.1       noro      971: {
                    972:   default_type *dft;
                    973:
                    974:   for (dft=gp_default_list; dft->fun; dft++)
1.2     ! noro      975:     ((void (*)(char*,int)) dft->fun)("", d_ACKNOWLEDGE);
1.1       noro      976: }
                    977:
                    978: static GEN
                    979: setdefault(char *s,char *v, int flag)
                    980: {
                    981:   default_type *dft;
                    982:
                    983:   if (!*s) { help_default(); return gnil; }
                    984:   for (dft=gp_default_list; dft->fun; dft++)
                    985:     if (!strcmp(s,dft->name))
                    986:     {
                    987:       if (flag == d_EXISTS) return gun;
1.2     ! noro      988:       return ((GEN (*)(char*,int)) dft->fun)(v,flag);
1.1       noro      989:     }
                    990:   if (flag == d_EXISTS) return gzero;
                    991:   err(talker,"unknown default: %s",s);
                    992:   return NULL; /* not reached */
                    993: }
                    994:
                    995: /********************************************************************/
                    996: /**                                                                **/
                    997: /**                             HELP                               **/
                    998: /**                                                                **/
                    999: /********************************************************************/
                   1000: static int
1.2     ! noro     1001: has_ext_help(void)
1.1       noro     1002: {
1.2     ! noro     1003:   if (GP_DATA->help)
1.1       noro     1004:   {
1.2     ! noro     1005:     char *buf = pari_strdup(GP_DATA->help), *s = buf;
1.1       noro     1006:     FILE *file;
                   1007:
                   1008:     while (*s && *s != ' ') s++;
                   1009:     *s = 0; file = fopen(buf,"r");
1.2     ! noro     1010:     free(buf);
1.1       noro     1011:     if (file) { fclose(file); return 1; }
                   1012:   }
                   1013:   return 0;
                   1014: }
1.2     ! noro     1015:
1.1       noro     1016: static int
                   1017: compare_str(char **s1, char **s2) { return strcmp(*s1, *s2); }
                   1018:
                   1019: /* Print all elements of list in columns, pausing every nbli lines
                   1020:  * if nbli is non-zero.
                   1021:  * list is a NULL terminated list of function names
                   1022:  */
                   1023: void
                   1024: print_fun_list(char **list, int nbli)
                   1025: {
                   1026:   long i=0, j=0, maxlen=0, nbcol,len, w = term_width();
                   1027:   char **l;
                   1028:
                   1029:   while (list[i]) i++;
                   1030:   qsort (list, i, sizeof(char *), (QSCOMP)compare_str);
                   1031:
                   1032:   for (l=list; *l; l++)
                   1033:   {
                   1034:     len = strlen(*l);
                   1035:     if (len > maxlen) maxlen=len;
                   1036:   }
                   1037:   maxlen++; nbcol= w / maxlen;
                   1038:   if (nbcol * maxlen == w) nbcol--;
                   1039:   if (!nbcol) nbcol = 1;
                   1040:
                   1041:   pariputc('\n'); i=0;
                   1042:   for (l=list; *l; l++)
                   1043:   {
                   1044:     pariputs(*l); i++;
                   1045:     if (i >= nbcol)
                   1046:     {
                   1047:       i=0; pariputc('\n');
                   1048:       if (nbli && j++ > nbli) { j = 0; hit_return(); }
                   1049:       continue;
                   1050:     }
                   1051:     len = maxlen - strlen(*l);
                   1052:     while (len--) pariputc(' ');
                   1053:   }
                   1054:   if (i) pariputc('\n');
                   1055: }
                   1056:
                   1057: #define LIST_LEN 1023
                   1058: static void
                   1059: commands(int n)
                   1060: {
1.2     ! noro     1061:   int hashpos, s = 0, size = LIST_LEN;
1.1       noro     1062:   entree *ep;
1.2     ! noro     1063:   char **list = (char **) gpmalloc((size+1)*sizeof(char *));
1.1       noro     1064:
                   1065:   for (hashpos = 0; hashpos < functions_tblsz; hashpos++)
                   1066:     for (ep = functions_hash[hashpos]; ep; ep = ep->next)
                   1067:       if ((n<0 && ep->menu) || ep->menu == n)
                   1068:       {
1.2     ! noro     1069:         list[s] = ep->name;
        !          1070:         if (++s >= size)
1.1       noro     1071:         {
1.2     ! noro     1072:          size += (LIST_LEN + 1)*sizeof(char *);
        !          1073:           list = (char**) gprealloc(list,size);
1.1       noro     1074:         }
                   1075:       }
                   1076:   list[s]=NULL; print_fun_list(list,term_height()-4); free(list);
                   1077: }
                   1078:
                   1079: static void
                   1080: print_def_arg(GEN x)
                   1081: {
                   1082:   if (x == gzero) return;
                   1083:   pariputc('=');
                   1084:   if (typ(x)==t_STR)
                   1085:     pariputs(GSTR(x)); /* otherwise it's surrounded by "" */
                   1086:   else
                   1087:     bruteall(x,'g',-1,1);
                   1088: }
                   1089:
                   1090: static void
                   1091: print_user_fun(entree *ep)
                   1092: {
                   1093:   gp_args *f= (gp_args*)ep->args;
                   1094:   GEN q = (GEN)ep->value, *arg = f->arg;
                   1095:   int i, narg;
                   1096:
                   1097:   q++; /* skip initial NULL */
                   1098:   pariputs(ep->name); pariputc('(');
                   1099:   narg = f->narg;
                   1100:   for (i=1; i<=narg; i++, arg++)
                   1101:   {
                   1102:     entree *ep = varentries[*q++];
                   1103:     pariputs(ep? ep->name:"#");
                   1104:     print_def_arg(*arg);
                   1105:     if (i == narg) { arg++; break; }
                   1106:     pariputs(", ");
                   1107:   }
                   1108:   pariputs(") = ");
                   1109:   narg = f->nloc;
                   1110:   if (narg)
                   1111:   {
                   1112:     pariputs("local(");
                   1113:     for (i=1; i<=narg; i++, arg++)
                   1114:     {
                   1115:       entree *ep = varentries[*q++];
                   1116:       pariputs(ep? ep->name:"#");
                   1117:       print_def_arg(*arg);
                   1118:       if (i == narg) break;
                   1119:       pariputs(", ");
                   1120:     }
                   1121:     pariputs("); ");
                   1122:   }
                   1123:   pariputs((char*)q);
                   1124: }
                   1125:
                   1126: static void
                   1127: print_user_member(entree *ep)
                   1128: {
                   1129:   GEN q = (GEN)ep->value;
                   1130:   entree *ep2;
                   1131:
                   1132:   q++; /* skip initial NULL */
                   1133:   ep2 = varentries[*q++];
                   1134:   pariputs(ep2? ep2->name:"#");
                   1135:   pariputsf(".%s = ", ep->name);
                   1136:   pariputs((char*)q);
                   1137: }
                   1138:
                   1139: static void
1.2     ! noro     1140: user_fun(void)
1.1       noro     1141: {
                   1142:   entree *ep;
                   1143:   int hash;
                   1144:
                   1145:   for (hash = 0; hash < functions_tblsz; hash++)
                   1146:     for (ep = functions_hash[hash]; ep; ep = ep->next)
                   1147:       if (EpVALENCE(ep) == EpUSER)
                   1148:       {
                   1149:        pariputc(LBRACE); print_user_fun(ep);
                   1150:        pariputc(RBRACE); pariputs("\n\n");
                   1151:       }
                   1152: }
                   1153:
                   1154: static void
1.2     ! noro     1155: user_member(void)
1.1       noro     1156: {
                   1157:   entree *ep;
                   1158:   int hash;
                   1159:
                   1160:   for (hash = 0; hash < functions_tblsz; hash++)
                   1161:     for (ep = members_hash[hash]; ep; ep = ep->next)
                   1162:       if (EpVALENCE(ep) == EpMEMBER)
                   1163:       {
                   1164:        pariputc(LBRACE); print_user_member(ep);
                   1165:        pariputc(RBRACE); pariputs("\n\n");
                   1166:       }
                   1167: }
                   1168:
                   1169: static void
                   1170: center(char *s)
                   1171: {
1.2     ! noro     1172:   long i, l = strlen(s), pad = term_width() - l;
        !          1173:   char *buf, *u;
1.1       noro     1174:
                   1175:   if (pad<0) pad=0; else pad >>= 1;
1.2     ! noro     1176:   u = buf = (char*)gpmalloc(l + pad + 2);
1.1       noro     1177:   for (i=0; i<pad; i++) *u++ = ' ';
                   1178:   while (*s) *u++ = *s++;
1.2     ! noro     1179:   *u++ = '\n'; *u = 0;
        !          1180:   pariputs(buf); free(buf);
1.1       noro     1181: }
                   1182:
                   1183: static void
1.2     ! noro     1184: community(void)
1.1       noro     1185: {
                   1186:   long len = strlen(GPMISCDIR) + 1024;
1.2     ! noro     1187:   char *s = (char*)gpmalloc(len);
        !          1188:
1.1       noro     1189:   sprintf(s, "The standard distribution of GP/PARI includes a reference \
                   1190: manual, a tutorial, a reference card and quite a few examples. They should \
                   1191: have been installed in the directory '%s'. If not you should ask the person \
                   1192: who installed PARI on your system where they can be found. You can also \
                   1193: download them from the PARI WWW site 'http://www.parigp-home.de/'",
                   1194: GPMISCDIR);
                   1195:   print_text(s); free(s);
                   1196:
                   1197:   pariputs("\nThree mailing lists are devoted to PARI:\n\
                   1198:   - pari-announce (moderated) to announce major version changes.\n\
                   1199:   - pari-dev for everything related to the development of PARI, including\n\
                   1200:     suggestions, technical questions, bug reports and patch submissions.\n\
                   1201:   - pari-users for everything else!\n");
                   1202:   print_text("\
                   1203: To subscribe, send an empty message to <listname>-subscribe@list.cr.yp.to. You \
                   1204: can only send messages to the lists you have subscribed to! An archive is kept \
                   1205: at the WWW site mentioned above. You can also reach the authors directly by \
                   1206: email: pari@math.u-bordeaux.fr (answer not guaranteed)."); }
                   1207:
                   1208: static void
                   1209: gentypes(void)
                   1210: {
                   1211:   pariputs("List of the PARI types:\n\
                   1212:   t_INT    : long integers     [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                   1213:   t_REAL   : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                   1214:   t_INTMOD : integermods       [ code ] [ mod  ] [ integer ]\n\
                   1215:   t_FRAC   : irred. rationals  [ code ] [ num. ] [ den. ]\n\
                   1216:   t_FRACN  : rational numbers  [ code ] [ num. ] [ den. ]\n\
                   1217:   t_COMPLEX: complex numbers   [ code ] [ real ] [ imag ]\n\
                   1218:   t_PADIC  : p-adic numbers    [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ]\n\
                   1219:   t_QUAD   : quadratic numbers [ cod1 ] [ mod  ] [ real ] [ imag ]\n\
                   1220:   t_POLMOD : poly mod          [ code ] [ mod  ] [ polynomial ]\n\
                   1221:   -------------------------------------------------------------\n\
                   1222:   t_POL    : polynomials       [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                   1223:   t_SER    : power series      [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
                   1224:   t_RFRAC  : irred. rat. func. [ code ] [ num. ] [ den. ]\n\
                   1225:   t_RFRACN : rational function [ code ] [ num. ] [ den. ]\n\
                   1226:   t_QFR    : real qfb          [ code ] [ a ] [ b ] [ c ] [ del ]\n\
                   1227:   t_QFI    : imaginary qfb     [ code ] [ a ] [ b ] [ c ]\n\
                   1228:   t_VEC    : row vector        [ code ] [  x_1  ] ... [  x_k  ]\n\
                   1229:   t_COL    : column vector     [ code ] [  x_1  ] ... [  x_k  ]\n\
                   1230:   t_MAT    : matrix            [ code ] [ col_1 ] ... [ col_k ]\n\
                   1231:   t_LIST   : list              [ code ] [ cod2 ] [ x_1 ] ... [ x_k ]\n\
                   1232:   t_STR    : string            [ code ] [ man_1 ] ... [ man_k ]\n\
                   1233: \n");
                   1234: }
                   1235:
                   1236: static void
                   1237: menu_commands(void)
                   1238: {
                   1239:   pariputs("Help topics:\n\
                   1240:   0: list of user-defined identifiers (variable, alias, function)\n\
                   1241:   1: Standard monadic or dyadic OPERATORS\n\
                   1242:   2: CONVERSIONS and similar elementary functions\n\
                   1243:   3: TRANSCENDENTAL functions\n\
                   1244:   4: NUMBER THEORETICAL functions\n\
                   1245:   5: Functions related to ELLIPTIC CURVES\n\
                   1246:   6: Functions related to general NUMBER FIELDS\n\
                   1247:   7: POLYNOMIALS and power series\n\
                   1248:   8: Vectors, matrices, LINEAR ALGEBRA and sets\n\
                   1249:   9: SUMS, products, integrals and similar functions\n\
                   1250:  10: GRAPHIC functions\n\
                   1251:  11: PROGRAMMING under GP\n\
                   1252:  12: The PARI community\n\
                   1253: \n\
                   1254: Further help (list of relevant functions): ?n (1<=n<=11).\n\
                   1255: Also:\n\
                   1256:   ? functionname (short on-line help)\n\
                   1257:   ?\\             (keyboard shortcuts)\n\
                   1258:   ?.             (member functions)\n");
                   1259:   if (has_ext_help()) pariputs("\
                   1260: Extended help looks available:\n\
                   1261:   ??             (opens the full user's manual in a dvi previewer)\n\
                   1262:   ??  tutorial   (same with the GP tutorial)\n\
                   1263:   ??  refcard    (same with the GP reference card)\n\
                   1264: \n\
                   1265:   ??  keyword    (long help text about \"keyword\" from the user's manual)\n\
                   1266:   ??? keyword    (a propos: list of related functions).");
                   1267: }
                   1268:
                   1269: static void
                   1270: slash_commands(void)
                   1271: {
                   1272:   pariputs("#       : enable/disable timer\n\
                   1273: ##      : print time for last result\n\
                   1274: \\\\      : comment up to end of line\n\
                   1275: \\a {n}  : print result in raw format (readable by PARI)\n\
                   1276: \\b {n}  : print result in beautified format\n\
                   1277: \\c      : list all commands (same effect as ?*)\n\
                   1278: \\d      : print all defaults\n\
                   1279: \\e {n}  : enable/disable echo (set echo=n)\n\
                   1280: \\g {n}  : set debugging level\n\
                   1281: \\gf{n}  : set file debugging level\n\
                   1282: \\gm{n}  : set memory debugging level\n\
                   1283: \\h {m-n}: hashtable information\n\
                   1284: \\l {f}  : enable/disable logfile (set logfile=f)\n\
                   1285: \\m {n}  : print result in prettymatrix format\n\
                   1286: \\o {n}  : change output method (0=raw, 1=prettymatrix, 2=prettyprint)\n\
                   1287: \\p {n}  : change real precision\n\
                   1288: \\ps{n}  : change series precision\n\
                   1289: \\q      : quit completely this GP session\n\
                   1290: \\r {f}  : read in a file\n\
                   1291: \\s {n}  : print stack information\n\
                   1292: \\t      : print the list of PARI types\n\
                   1293: \\u      : print the list of user-defined functions\n\
                   1294: \\um     : print the list of user-defined member functions\n\
                   1295: \\v      : print current version of GP\n\
                   1296: \\w {nf} : write to a file\n\
                   1297: \\x {n}  : print complete inner structure of result\n\
                   1298: \\y {n}  : disable/enable automatic simplification (set simplify=n)\n\
                   1299: \n\
                   1300: {f}=optional filename. {n}=optional integer\n");
                   1301: }
                   1302:
                   1303: static void
                   1304: member_commands(void)
                   1305: {
                   1306:   pariputs("Member functions, followed by relevant objects\n\n\
                   1307: a1-a6, b2-b8, c4-c6 : coeff. of the curve.            ell\n\
                   1308: area : area                                           ell\n\
                   1309: bnf  : big number field                                        bnf, bnr\n\
                   1310: clgp : class group                                             bnf, bnr\n\
                   1311: cyc  : cyclic decomposition (SNF)               clgp           bnf, bnr\n\
                   1312: diff, codiff: different and codifferent                    nf, bnf, bnr\n\
                   1313: disc : discriminant                                   ell, nf, bnf, bnr\n\
                   1314: e, f : inertia/residues degree            prid\n\
                   1315: fu   : fundamental units                                       bnf, bnr\n\
                   1316: futu : [u,w] where u=unit group, w=torsion                     bnf, bnr\n\
                   1317: gen  : generators                         prid, clgp           bnf, bnr\n\
                   1318: j    : j-invariant                                    ell\n\
                   1319: mod  : modulus\n\
                   1320: nf   : number field                                            bnf, bnr\n\
                   1321: no   : number of elements                       clgp           bnf, bnr\n\
                   1322: omega, eta: [omega1,omega2] and [eta1, eta2]          ell\n\
                   1323: p    : rational prime contained in prid   prid\n\
                   1324: pol  : defining polynomial                                 nf, bnf, bnr\n\
                   1325: reg  : regulator                                               bnf, bnr\n\
                   1326: roots: roots                                          ell  nf, bnf, bnr\n\
                   1327: sign : signature                                           nf, bnf, bnr\n\
                   1328: t2   : t2 matrix                                           nf, bnf, bnr\n\
                   1329: tate : Tate's [u^2,u,q]                               ell\n\
                   1330: tu   : torsion unit and its order                              bnf, bnr\n\
                   1331: tufu : [w,u] where u=unit group, w=torsion                     bnf, bnr\n\
                   1332: w    : Mestre's w                                     ell\n\
                   1333: zk   : integral basis                                      nf, bnf, bnr\n\
                   1334: zkst : structure of (Z_K/m)^* (valid for idealstar also)            bnr\n");
                   1335: }
                   1336:
                   1337: #define QUOTE "_QUOTE"
                   1338: #define DOUBQUOTE "_DOUBQUOTE"
                   1339: #define BACKQUOTE "_BACKQUOTE"
                   1340:
                   1341: static char *
                   1342: _cat(char *s, char *t)
                   1343: {
                   1344:   *s = 0; strcat(s,t); return s + strlen(t);
                   1345: }
                   1346:
                   1347: static char *
                   1348: filter_quotes(char *s)
                   1349: {
                   1350:   int i, l = strlen(s);
                   1351:   int quote = 0;
                   1352:   int backquote = 0;
                   1353:   int doubquote = 0;
                   1354:   char *str, *t;
                   1355:
1.2     ! noro     1356:   for (i=0; i < l; i++)
1.1       noro     1357:     switch(s[i])
                   1358:     {
                   1359:       case '\'': quote++; break;
                   1360:       case '`' : backquote++; break;
                   1361:       case '"' : doubquote++;
                   1362:     }
                   1363:   str = (char*)gpmalloc(l + quote * (strlen(QUOTE)-1)
                   1364:                           + doubquote * (strlen(DOUBQUOTE)-1)
                   1365:                           + backquote * (strlen(BACKQUOTE)-1) + 1);
                   1366:   t = str;
1.2     ! noro     1367:   for (i=0; i < l; i++)
1.1       noro     1368:     switch(s[i])
                   1369:     {
                   1370:       case '\'': t = _cat(t, QUOTE); break;
                   1371:       case '`' : t = _cat(t, BACKQUOTE); break;
                   1372:       case '"' : t = _cat(t, DOUBQUOTE); break;
                   1373:       default: *t++ = s[i];
                   1374:     }
                   1375:   *t = 0; return str;
                   1376: }
                   1377:
1.2     ! noro     1378: static int
        !          1379: nl_read(char *s) { size_t l = strlen(s); return s[l-1] == '\n'; }
        !          1380:
        !          1381: #define nbof(a) sizeof(a) / sizeof(a[0])
        !          1382: /* query external help program for s. num < 0 [keyword] or chapter number */
1.1       noro     1383: static void
                   1384: external_help(char *s, int num)
                   1385: {
                   1386:   long nbli = term_height()-3, li = 0;
1.2     ! noro     1387:   char buf[256], ar[32], *str, *opt = "";
1.1       noro     1388:   pariFILE *z;
                   1389:   FILE *f;
                   1390:
1.2     ! noro     1391:   if (!GP_DATA->help) err(talker,"no external help program");
1.1       noro     1392:   s = filter_quotes(s);
1.2     ! noro     1393:   str = gpmalloc(strlen(GP_DATA->help) + strlen(s) + 64);
        !          1394:   *ar = 0;
1.1       noro     1395:   if (num < 0)
                   1396:     opt = "-k";
                   1397:   else if (s[strlen(s)-1] != '@')
1.2     ! noro     1398:     sprintf(ar,"@%d",num);
        !          1399:   sprintf(str,"%s -fromgp %s %c%s%s%c",GP_DATA->help,opt, SHELL_Q,s,ar,SHELL_Q);
1.1       noro     1400:   z = try_pipe(str,0); f = z->file;
1.2     ! noro     1401:   free(str);
        !          1402:   free(s);
        !          1403:   while (fgets(buf, nbof(buf), f))
1.1       noro     1404:   {
                   1405:     if (!strncmp("ugly_kludge_done",buf,16)) break;
1.2     ! noro     1406:     pariputs(buf);
        !          1407:     if (nl_read(buf) && ++li > nbli) { hit_return(); li = 0; }
1.1       noro     1408:   }
                   1409:   pari_fclose(z);
                   1410: }
                   1411:
                   1412: char *keyword_list[]={
                   1413:   "operator",
                   1414:   "user",
                   1415:   "member",
                   1416:   "integer",
                   1417:   "real",
                   1418:   "readline",
                   1419:   "refcard",
                   1420:   "tutorial",
                   1421:   "nf",
                   1422:   "bnf",
                   1423:   "bnr",
                   1424:   "ell",
                   1425:   NULL
                   1426: };
                   1427:
                   1428: static int
                   1429: ok_external_help(char *s)
                   1430: {
                   1431:   long n;
                   1432:   if (!*s) return 1;
                   1433:   if (!isalpha((int)*s)) return 3; /* operator or section number */
                   1434:   if (!strncmp(s,"t_",2)) return 2; /* type name */
                   1435:
                   1436:   for (n=0; keyword_list[n]; n++)
                   1437:     if (!strcmp(s,keyword_list[n])) return 3;
                   1438:   return 0;
                   1439: }
                   1440:
                   1441: /* don't mess readline display */
                   1442: static void
                   1443: aide_print(char *s1, char *s2, int flag)
                   1444: {
                   1445:   if ((flag & h_RL) == 0) err(talker, "%s: %s", s1, s2);
                   1446:   pariputsf("%s: %s\n", s1, s2);
                   1447: }
                   1448:
                   1449: static void
                   1450: aide0(char *s, int flag)
                   1451: {
                   1452:   long n, long_help = flag & h_LONG;
                   1453:   entree *ep,*ep1;
                   1454:   char *s1;
                   1455:
                   1456:   s = get_sep(s);
                   1457:   if (isdigit((int)*s))
                   1458:   {
1.2     ! noro     1459:     n = atoi(s);
1.1       noro     1460:     if (n == 12) { community(); return; }
1.2     ! noro     1461:     if (n < 0 || n > 12)
1.1       noro     1462:       err(talker2,"no such section in help: ?",s,s);
                   1463:     if (long_help) external_help(s,3); else commands(n);
                   1464:     return;
                   1465:   }
1.2     ! noro     1466:   /* Get meaningful entry on \ps 5 */
1.1       noro     1467:   if (*s == '\\') { s1 = s+1; skip_alpha(s1); *s1 = '\0';}
                   1468:
                   1469:   if (flag & h_APROPOS) { external_help(s,-1); return; }
                   1470:   if (long_help && (n = ok_external_help(s))) { external_help(s,n); return; }
                   1471:   switch (*s)
                   1472:   {
                   1473:     case '*' : commands(-1); return;
                   1474:     case '\0': menu_commands(); return;
                   1475:     case '\\': slash_commands(); return;
                   1476:     case '.' : member_commands(); return;
                   1477:   }
                   1478:   ep = is_entry(s);
                   1479:   if (ep && long_help)
                   1480:   {
                   1481:     if (!strcmp(ep->name, "default"))
                   1482:     {
                   1483:       char *t = s+7, *e;
                   1484:       skip_space(t);
                   1485:       if (*t == '(') {
                   1486:        t++; skip_space(t);
                   1487:         e = t; skip_alpha(e); *e = '\0'; /* safe: get_sep() made it a copy */
                   1488:        if (is_default(t)) { external_help(t, 2); return; }
                   1489:       }
                   1490:     }
                   1491:   }
                   1492:   if (!ep)
                   1493:   {
                   1494:     n = is_default(s)? 2: 3;
                   1495:     if (long_help)
                   1496:       external_help(s,n);
                   1497:     else
                   1498:     {
                   1499:       if (n == 2) { aide_print(s,"default",h_RL); return; }
                   1500:       n = whatnow(s,1);
                   1501:       if (n) err(obsoler,s,s, s,n);
                   1502:       aide_print(s,"unknown identifier",flag);
                   1503:     }
                   1504:     return;
                   1505:   }
                   1506:
                   1507:   ep1 = ep;  ep = do_alias(ep);
                   1508:   if (ep1 != ep) pariputsf("%s is aliased to:\n\n",s);
                   1509:
                   1510:   switch(EpVALENCE(ep))
                   1511:   {
                   1512:     case EpUSER:
                   1513:       if (!ep->help || long_help) print_user_fun(ep);
                   1514:       if (!ep->help) return;
                   1515:       if (long_help) { pariputs("\n\n"); long_help=0; }
                   1516:       break;
                   1517:
                   1518:     case EpGVAR:
                   1519:     case EpVAR:
                   1520:       if (!ep->help) { aide_print(s, "user defined variable",h_RL); return; }
                   1521:       long_help=0; break;
                   1522:
                   1523:     case EpINSTALL:
                   1524:       if (!ep->help) { aide_print(s, "installed function",h_RL); return; }
                   1525:       long_help=0; break;
                   1526:   }
                   1527:   if (long_help) { external_help(ep->name,3); return; }
                   1528:   if (ep->help) { print_text(ep->help); return; }
                   1529:
                   1530:   err(bugparier,"aide (no help found)");
                   1531: }
                   1532:
                   1533: void
                   1534: aide(char *s, int flag)
                   1535: {
                   1536:   if ((flag & h_RL) == 0)
                   1537:   {
                   1538:     if (*s == '?') { flag |= h_LONG; s++; }
                   1539:     if (*s == '?') { flag |= h_APROPOS; s++; }
                   1540:   }
                   1541:   term_color(c_HELP); aide0(s,flag); term_color(c_NONE);
                   1542:   if ((flag & h_RL) == 0) pariputc('\n');
                   1543: }
                   1544:
                   1545: /********************************************************************/
                   1546: /**                                                                **/
                   1547: /**                         METACOMMANDS                           **/
                   1548: /**                                                                **/
                   1549: /********************************************************************/
                   1550:
                   1551: static void
                   1552: print_entree(entree *ep, long hash)
                   1553: {
                   1554:   pariputsf(" %s ",ep->name); pariputsf(VOIR_STRING1,(ulong)ep);
                   1555:   pariputsf(":\n   hash = %3ld, valence = %3ld, menu = %2ld, code = %s\n",
                   1556:             hash, ep->valence, ep->menu, ep->code? ep->code: "NULL");
                   1557:   if (ep->next)
                   1558:   {
                   1559:     pariputsf("   next = %s ",(ep->next)->name);
                   1560:     pariputsf(VOIR_STRING1,(ulong)(ep->next));
                   1561:   }
                   1562:   pariputs("\n");
                   1563: }
                   1564:
                   1565: static void
                   1566: print_hash_list(char *s)
                   1567: {
                   1568:   long m,n;
                   1569:   entree *ep;
                   1570:
                   1571:   if (isalpha((int)*s))
                   1572:   {
                   1573:     ep = is_entry_intern(s,functions_hash,&n);
                   1574:     if (!ep) err(talker,"no such function");
                   1575:     print_entree(ep,n); return;
                   1576:   }
                   1577:   if (isdigit((int)*s) || *s == '$')
                   1578:   {
                   1579:     m = functions_tblsz-1; n = atol(s);
                   1580:     if (*s=='$') n = m;
                   1581:     if (m<n) err(talker,"invalid range in print_entree");
                   1582:     while (isdigit((int)*s)) s++;
                   1583:
                   1584:     if (*s++ != '-') m = n;
                   1585:     else
                   1586:     {
                   1587:       if (*s !='$') m = min(atol(s),m);
                   1588:       if (m<n) err(talker,"invalid range in print_entree");
                   1589:     }
                   1590:
                   1591:     for(; n<=m; n++)
                   1592:     {
1.2     ! noro     1593:       pariputsf("*** hashcode = %lu\n",n);
1.1       noro     1594:       for (ep=functions_hash[n]; ep; ep=ep->next)
                   1595:        print_entree(ep,n);
                   1596:     }
                   1597:     return;
                   1598:   }
                   1599:   if (*s=='-')
                   1600:   {
                   1601:     for (n=0; n<functions_tblsz; n++)
                   1602:     {
                   1603:       m=0;
                   1604:       for (ep=functions_hash[n]; ep; ep=ep->next) m++;
                   1605:       pariputsf("%3ld:%3ld ",n,m);
                   1606:       if (n%9 == 8) pariputc('\n');
                   1607:     }
                   1608:     pariputc('\n'); return;
                   1609:   }
                   1610:   for (n=0; n<functions_tblsz; n++)
                   1611:     for (ep=functions_hash[n]; ep; ep=ep->next)
                   1612:       print_entree(ep,n);
                   1613: }
                   1614:
                   1615: static char *
1.2     ! noro     1616: what_readline(void)
1.1       noro     1617: {
                   1618: #ifdef READLINE
1.2     ! noro     1619:   return (GP_DATA->flags & USE_READLINE)? "v"READLINE" enabled": "disabled";
        !          1620: #else
        !          1621:   return "disabled";
1.1       noro     1622: #endif
                   1623: }
                   1624:
                   1625: static void
1.2     ! noro     1626: print_version(void)
1.1       noro     1627: {
                   1628:   char buf[64];
                   1629:
                   1630:   center(PARIVERSION); center(PARIINFO);
                   1631:   sprintf(buf,"(readline %s, extended help%s available)", what_readline(),
                   1632:           has_ext_help()? "": " not");
                   1633:   center(buf);
                   1634: }
                   1635:
                   1636: static void
1.2     ! noro     1637: gp_head(void)
1.1       noro     1638: {
                   1639:   print_version(); pariputs("\n");
1.2     ! noro     1640:   center("Copyright (C) 2002 The PARI Group");
1.1       noro     1641:   print_text("\nPARI/GP is free software, covered by the GNU General Public \
                   1642: License, and comes WITHOUT ANY WARRANTY WHATSOEVER");
                   1643:   pariputs("\n\
                   1644: Type ? for help, \\q to quit.\n\
                   1645: Type ?12 for how to get moral (and possibly technical) support.\n\n");
                   1646:   sd_realprecision  ("",d_ACKNOWLEDGE);
                   1647:   sd_seriesprecision("",d_ACKNOWLEDGE);
                   1648:   sd_format         ("",d_ACKNOWLEDGE);
1.2     ! noro     1649:   pariputsf("\nparisize = %lu, primelimit = %lu\n", top-bot, primelimit);
1.1       noro     1650: }
                   1651:
1.2     ! noro     1652: void
1.1       noro     1653: fix_buffer(Buffer *b, long newlbuf)
                   1654: {
                   1655:   b->len = paribufsize = newlbuf;
1.2     ! noro     1656:   b->buf = gprealloc(b->buf, b->len);
1.1       noro     1657: }
                   1658:
                   1659: void
1.2     ! noro     1660: gp_quit(void)
1.1       noro     1661: {
                   1662:   free_graph(); freeall();
                   1663:   kill_all_buffers(NULL);
                   1664:   if (INIT_SIG) pari_sig_init(SIG_DFL);
                   1665:   term_color(c_NONE);
                   1666:   pariputs_opt("Goodbye!\n");
1.2     ! noro     1667:   if (GP_DATA->flags & TEXMACS) tm_end_output();
1.1       noro     1668:   exit(0);
                   1669: }
                   1670:
                   1671: static GEN
                   1672: gpreadbin(char *s)
                   1673: {
                   1674:   GEN x = readbin(s,infile);
                   1675:   popinfile(); return x;
                   1676: }
                   1677:
                   1678: static void
                   1679: escape0(char *tch)
                   1680: {
                   1681:   char *s, c;
                   1682:
                   1683:   if (compatible != NONE)
                   1684:   {
                   1685:     s = tch;
                   1686:     while (*s)
                   1687:       if (*s++ == '=')
                   1688:       {
                   1689:        GEN (*f)(char*, int) = NULL;
                   1690:        int len = (s-tch) - 1;
                   1691:
                   1692:        if (!strncmp(tch,"precision",len))         f = sd_realprecision;
                   1693:        else if (!strncmp(tch,"serieslength",len)) f = sd_seriesprecision;
                   1694:        else if (!strncmp(tch,"format",len))       f = sd_format;
                   1695:        else if (!strncmp(tch,"prompt",len))       f = sd_prompt;
                   1696:        if (f) { f(get_sep(s), d_ACKNOWLEDGE); return; }
                   1697:        break;
                   1698:       }
                   1699:   }
                   1700:   s = tch;
                   1701:   switch ((c = *s++))
                   1702:   {
                   1703:     case 'w': case 'x': case 'a': case 'b': case 'B': case 'm':
                   1704:     { /* history things */
                   1705:       long d;
                   1706:       GEN x;
                   1707:       if (c != 'w' && c != 'x') d = get_int(s,0);
                   1708:       else
                   1709:       {
                   1710:        d = atol(s); if (*s == '-') s++;
                   1711:        while (isdigit((int)*s)) s++;
                   1712:       }
1.2     ! noro     1713:       x = gp_history(GP_DATA->hist, d, tch+1,tch-1);
1.1       noro     1714:       switch (c)
                   1715:       {
1.2     ! noro     1716:        case 'B':
        !          1717:         { /* prettyprinter */
        !          1718:           gp_data G = *GP_DATA; /* copy */
        !          1719:           gp_hist   h = *(G.hist); /* copy */
        !          1720:           pariout_t f = *(G.fmt);  /* copy */
        !          1721:
        !          1722:           G.hist = &h; h.total = 0; /* no hist number */
        !          1723:           G.fmt  = &f; f.prettyp = f_PRETTY;
        !          1724:           G.flags &= ~(TEST|TEXMACS);
        !          1725:           G.lim_lines = 0;
        !          1726:           gp_output(x, &G); break;
        !          1727:         }
        !          1728:        case 'a': brute   (x, GP_DATA->fmt->format, -1); break;
        !          1729:        case 'm': matbrute(x, GP_DATA->fmt->format, -1); break;
        !          1730:        case 'b': sor(x, GP_DATA->fmt->format, -1, GP_DATA->fmt->fieldw); break;
        !          1731:        case 'x': voir(x, get_int(s, -1)); break;
1.1       noro     1732:         case 'w':
                   1733:        {
                   1734:          GEN g[2]; g[0] = x; g[1] = NULL;
                   1735:          s = get_sep_colon_ok(s); if (!*s) s = current_logfile;
1.2     ! noro     1736:          write0(s, g); return;
1.1       noro     1737:        }
                   1738:       }
                   1739:       pariputc('\n'); return;
                   1740:     }
                   1741:
                   1742:     case 'c': commands(-1); break;
                   1743:     case 'd': help_default(); break;
                   1744:     case 'e':
                   1745:       s = get_sep(s);
1.2     ! noro     1746:       if (!*s) s = (GP_DATA->flags & ECHO)? "0": "1";
1.1       noro     1747:       sd_echo(s,d_ACKNOWLEDGE); break;
                   1748:     case 'g':
                   1749:       switch (*s)
                   1750:       {
                   1751:         case 'm': sd_debugmem(++s,d_ACKNOWLEDGE); break;
                   1752:         case 'f': sd_debugfiles(++s,d_ACKNOWLEDGE); break;
                   1753:         default : sd_debug(s,d_ACKNOWLEDGE); break;
                   1754:       }
                   1755:       break;
                   1756:     case 'h': print_hash_list(s); break;
                   1757:     case 'l':
                   1758:       s = get_sep_colon_ok(s);
                   1759:       if (*s)
                   1760:       {
                   1761:         sd_logfile(s,d_ACKNOWLEDGE);
                   1762:         if (logfile) break;
                   1763:       }
                   1764:       sd_log(logfile?"0":"1",d_ACKNOWLEDGE);
                   1765:       break;
                   1766:     case 'o': sd_output(s,d_ACKNOWLEDGE); break;
                   1767:     case 'p':
                   1768:       switch (*s)
                   1769:       {
                   1770:         case 's': sd_seriesprecision(++s,d_ACKNOWLEDGE); break;
                   1771:         default : sd_realprecision(s,d_ACKNOWLEDGE); break;
                   1772:       }
                   1773:       break;
                   1774:     case 'q': gp_quit(); break;
                   1775:     case 'r':
                   1776:       s = get_sep_colon_ok(s);
                   1777:       switchin(s);
1.2     ! noro     1778:       if (file_is_binary(infile))
        !          1779:       {
        !          1780:         GEN x = gpreadbin(s);
        !          1781:         if (isclone(x)) /* many BIN_GEN */
        !          1782:         {
        !          1783:           long i, l = lg(x);
        !          1784:           err(warner,"setting %ld history entries", l-1);
        !          1785:           for (i=1; i<l; i++) (void)set_hist_entry(GP_DATA->hist, (GEN)x[i]);
        !          1786:         }
        !          1787:       }
1.1       noro     1788:       break;
                   1789:     case 's': etatpile(0); break;
                   1790:     case 't': gentypes(); break;
                   1791:     case 'u':
                   1792:       switch (*s)
                   1793:       {
                   1794:         case 'm': user_member(); break;
                   1795:         default: user_fun();
                   1796:       }
                   1797:       break;
                   1798:     case 'v': print_version(); break;
                   1799:     case 'y':
                   1800:       s = get_sep(s);
1.2     ! noro     1801:       if (!*s) s = (GP_DATA->flags & SIMPLIFY)? "0": "1";
1.1       noro     1802:       sd_simplify(s,d_ACKNOWLEDGE); break;
                   1803:     default: err(caracer1,tch-1,tch-2);
                   1804:   }
                   1805: }
                   1806:
                   1807: static void
                   1808: escape(char *tch)
                   1809: {
1.2     ! noro     1810:   char *old = get_analyseur();
        !          1811:   set_analyseur(tch); /* for error messages */
1.1       noro     1812:   escape0(tch);
1.2     ! noro     1813:   set_analyseur(old);
1.1       noro     1814: }
                   1815: /********************************************************************/
                   1816: /*                                                                  */
                   1817: /*                              GPRC                                */
                   1818: /*                                                                  */
                   1819: /********************************************************************/
                   1820: #if defined(UNIX) || defined(__EMX__)
                   1821: #  include <pwd.h>
                   1822: #endif
                   1823:
1.2     ! noro     1824: static int get_line_from_file(char *prompt, filtre_t *F, FILE *file);
        !          1825: #define err_gprc(s,t,u) { fprintferr("\n"); err(talker2,s,t,u); }
        !          1826:
        !          1827: static void
        !          1828: init_filtre(filtre_t *F, void *data)
1.1       noro     1829: {
1.2     ! noro     1830:   F->data = data;
        !          1831:   F->in_string  = 0;
        !          1832:   F->in_comment = 0;
        !          1833:   F->downcase = 0;
1.1       noro     1834: }
                   1835:
1.2     ! noro     1836: /* LOCATE GPRC */
        !          1837:
1.1       noro     1838: /* return $HOME or the closest we can find */
                   1839: static char *
                   1840: get_home(int *free_it)
                   1841: {
                   1842:   char *drv, *pth = os_getenv("HOME");
                   1843:   if (pth) return pth;
                   1844:   if ((drv = os_getenv("HOMEDRIVE"))
                   1845:    && (pth = os_getenv("HOMEPATH")))
                   1846:   { /* looks like WinNT */
                   1847:     char *buf = gpmalloc(strlen(pth) + strlen(drv) + 1);
                   1848:     sprintf(buf, "%s%s",drv,pth);
                   1849:     *free_it = 1; return buf;
                   1850:   }
                   1851: #if defined(__EMX__) || defined(UNIX)
                   1852:   {
                   1853:     struct passwd *p = getpwuid(geteuid());
                   1854:     if (p) return p->pw_dir;
                   1855:   }
                   1856: #endif
                   1857:   return ".";
                   1858: }
                   1859:
                   1860: static FILE *
                   1861: gprc_chk(char *s)
                   1862: {
                   1863:   FILE *f = fopen(s, "r");
1.2     ! noro     1864:   if (f && !(GP_DATA->flags & QUIET)) fprintferr("Reading GPRC: %s ...", s);
1.1       noro     1865:   return f;
                   1866: }
                   1867:
                   1868: /* Look for [._]gprc: $GPRC, then in $HOME, /, C:/ */
                   1869: static FILE *
1.2     ! noro     1870: gprc_get(void)
1.1       noro     1871: {
                   1872:   FILE *f = NULL;
                   1873:   char *str, *s, c;
                   1874:   long l;
                   1875: #ifdef macintosh
                   1876:   f = gprc_chk("gprc");
                   1877: #else
                   1878:   s = os_getenv("GPRC");
                   1879:   if (s) f = gprc_chk(s);
                   1880:   if (!f)
                   1881:   {
                   1882:     int free_it = 0;
                   1883:     s = get_home(&free_it); l = strlen(s); c = s[l-1];
                   1884:     str = strcpy(gpmalloc(l+7), s);
                   1885:     if (free_it) free(s);
                   1886:     s = str + l;
                   1887:     if (c != '/' && c != '\\') *s++ = '/';
                   1888: #ifdef UNIX
                   1889:     *s = '.'; /* .gprc */
                   1890: #else
                   1891:     *s = '_'; /* _gprc */
                   1892: #endif
                   1893:     strcpy(s+1, "gprc");
                   1894:     f = gprc_chk(str); /* in $HOME */
                   1895:     if (!f) f = gprc_chk(s); /* in . */
                   1896:     if (!f) f = gprc_chk("/etc/gprc");
                   1897:     if (!f) f = gprc_chk("C:/_gprc");
                   1898:     free(str);
                   1899:   }
                   1900: #endif
                   1901:   return f;
                   1902: }
                   1903:
1.2     ! noro     1904: /* PREPROCESSOR */
        !          1905:
        !          1906: static ulong
        !          1907: read_uint(char **s)
        !          1908: {
        !          1909:   long v = atol(*s);
        !          1910:   if (!isdigit((int)**s)) err_gprc("not an integer", *s, *s);
        !          1911:   while (isdigit((int)**s)) (*s)++;
        !          1912:   return v;
        !          1913: }
        !          1914: static ulong
        !          1915: read_dot_uint(char **s)
        !          1916: {
        !          1917:   if (**s != '.') return 0;
        !          1918:   (*s)++; return read_uint(s);
        !          1919: }
        !          1920: /* read a.b.c */
        !          1921: static long
        !          1922: read_version(char **s)
        !          1923: {
        !          1924:   long a, b, c;
        !          1925:   a = read_uint(s);
        !          1926:   b = read_dot_uint(s);
        !          1927:   c = read_dot_uint(s);
        !          1928:   return PARI_VERSION(a,b,c);
        !          1929: }
        !          1930:
        !          1931: static int
        !          1932: get_preproc_value(char **s)
        !          1933: {
        !          1934:   if (!strncmp(*s,"EMACS",5))
        !          1935:   {
        !          1936:     *s += 5;
        !          1937:     return GP_DATA->flags & (EMACS|TEXMACS);
        !          1938:   }
        !          1939:   if (!strncmp(*s,"READL",5))
        !          1940:   {
        !          1941:     *s += 5;
        !          1942:     return GP_DATA->flags & USE_READLINE;
        !          1943:   }
        !          1944:   if (!strncmp(*s,"VERSION",7))
        !          1945:   {
        !          1946:     int less = 0, orequal = 0;
        !          1947:     long d;
        !          1948:     *s += 7;
        !          1949:     switch(**s)
        !          1950:     {
        !          1951:       case '<': (*s)++; less = 1; break;
        !          1952:       case '>': (*s)++; less = 0; break;
        !          1953:       default: return -1;
        !          1954:     }
        !          1955:     if (**s == '=') { (*s)++; orequal = 1; }
        !          1956:     d = PARI_VERSION_CODE - read_version(s);
        !          1957:     if (!d) return orequal;
        !          1958:     return less? (d < 0): (d > 0);
        !          1959:   }
        !          1960:   return -1;
        !          1961: }
        !          1962:
        !          1963: /* PARSE GPRC */
        !          1964:
        !          1965: /* 1) replace next separator by '\0' (t must be writeable)
        !          1966:  * 2) return the next expression ("" if none)
        !          1967:  * see get_sep0() */
        !          1968: static char *
        !          1969: next_expr(char *t)
        !          1970: {
        !          1971:   int outer = 1;
        !          1972:   char *s = t;
        !          1973:
        !          1974:   for(;;)
        !          1975:   {
        !          1976:     char c;
        !          1977:     switch ((c = *s++))
        !          1978:     {
        !          1979:       case '"':
        !          1980:         if (outer || (s >= t+2 && s[-2] != '\\')) outer = !outer;
        !          1981:         break;
        !          1982:       case '\0':
        !          1983:         return "";
        !          1984:       default:
        !          1985:         if (outer && separe(c)) { s[-1] = 0; return s; }
        !          1986:     }
        !          1987:   }
        !          1988: }
1.1       noro     1989:
                   1990: static char **
1.2     ! noro     1991: gp_initrc(void)
1.1       noro     1992: {
1.2     ! noro     1993:   char **flist, *nexts,*s,*t;
1.1       noro     1994:   FILE *file = gprc_get();
                   1995:   long fnum = 4, find = 0;
                   1996:   Buffer *b;
1.2     ! noro     1997:   filtre_t F;
1.1       noro     1998:
                   1999:   if (!file) return NULL;
                   2000:   flist = (char **) gpmalloc(fnum * sizeof(char*));
                   2001:   b = new_buffer();
1.2     ! noro     2002:   init_filtre(&F, (void*)b);
1.1       noro     2003:   for(;;)
                   2004:   {
1.2     ! noro     2005:     if (!get_line_from_file(NULL,&F,file)) break;
        !          2006:     s = b->buf;
        !          2007:     if (*s == '#')
        !          2008:     { /* preprocessor directive */
        !          2009:       int z, NOT = 0;
        !          2010:       s++;
        !          2011:       if (strncmp(s,"if",2)) err_gprc("unknown directive",s,b->buf);
        !          2012:       s += 2;
        !          2013:       if (!strncmp(s,"not",3)) { NOT = !NOT; s += 3; }
        !          2014:       if (*s == '!')           { NOT = !NOT; s++; }
        !          2015:       t = s;
        !          2016:       z = get_preproc_value(&s);
        !          2017:       if (z < 0) err_gprc("unknown preprocessor variable",t,b->buf);
        !          2018:       if (NOT) z = !z;
        !          2019:       if (!*s)
        !          2020:       { /* make sure at least an expr follows the directive */
        !          2021:         if (!get_line_from_file(NULL,&F,file)) break;
        !          2022:         s = b->buf;
        !          2023:       }
        !          2024:       if (!z) continue; /* dump current line */
        !          2025:     }
        !          2026:     /* parse line */
        !          2027:     for ( ; *s; s = nexts)
1.1       noro     2028:     {
1.2     ! noro     2029:       nexts = next_expr(s);
        !          2030:       if (!strncmp(s,"read",4))
1.1       noro     2031:       { /* read file */
1.2     ! noro     2032:        s += 4;
1.1       noro     2033:        if (find == fnum-1)
                   2034:        {
1.2     ! noro     2035:          fnum <<= 1;
        !          2036:          flist = (char**)gprealloc(flist, fnum*sizeof(char*));
1.1       noro     2037:        }
1.2     ! noro     2038:        flist[find++] = t = gpmalloc(strlen(s) + 1);
        !          2039:        if (*s == '"') (void)readstring(s, t);
        !          2040:        else strcpy(t,s);
1.1       noro     2041:       }
                   2042:       else
                   2043:       { /* set default */
1.2     ! noro     2044:        t = s; while (*t && *t != '=') t++;
        !          2045:        if (*t != '=') err_gprc("missing '='",t,b->buf);
        !          2046:        *t++ = 0;
        !          2047:        if (*t == '"') (void)readstring(t, t);
        !          2048:        setdefault(s,t,d_INITRC);
1.1       noro     2049:       }
                   2050:     }
                   2051:   }
1.2     ! noro     2052:   del_buffer(b);
        !          2053:   if (!(GP_DATA->flags & QUIET)) fprintferr("Done.\n\n");
        !          2054:   fclose(file); flist[find] = NULL;
        !          2055:   return flist;
1.1       noro     2056: }
                   2057:
                   2058: /********************************************************************/
                   2059: /*                                                                  */
                   2060: /*                           GP MAIN LOOP                           */
                   2061: /*                                                                  */
                   2062: /********************************************************************/
                   2063: /* flag:
                   2064:  *   ti_NOPRINT   don't print
1.2     ! noro     2065:  *   ti_REGULAR   print elapsed time (flags & CHRONO)
1.1       noro     2066:  *   ti_LAST      print last elapsed time (##)
                   2067:  *   ti_INTERRUPT received a SIGINT
                   2068:  */
                   2069: static char *
                   2070: do_time(long flag)
                   2071: {
1.2     ! noro     2072:   static char buf[64];
1.1       noro     2073:   static long last = 0;
1.2     ! noro     2074:   long delay = (flag == ti_LAST)? last: TIMER(GP_DATA->T);
1.1       noro     2075:   char *s;
                   2076:
                   2077:   last = delay;
                   2078:   switch(flag)
                   2079:   {
                   2080:     case ti_REGULAR:   s = "time = "; break;
                   2081:     case ti_INTERRUPT: s = "user interrupt after "; break;
                   2082:     case ti_LAST:      s = "  ***   last result computed in "; break;
                   2083:     default: return NULL;
                   2084:   }
1.2     ! noro     2085:   strcpy(buf,s); s = buf+strlen(s);
1.1       noro     2086:   strcpy(s, term_get_color(c_TIME)); s+=strlen(s);
                   2087:   if (delay >= 3600000)
                   2088:   {
                   2089:     sprintf(s, "%ldh, ", delay / 3600000); s+=strlen(s);
                   2090:     delay %= 3600000;
                   2091:   }
                   2092:   if (delay >= 60000)
                   2093:   {
                   2094:     sprintf(s, "%ldmn, ", delay / 60000); s+=strlen(s);
                   2095:     delay %= 60000;
                   2096:   }
                   2097:   if (delay >= 1000)
                   2098:   {
                   2099:     sprintf(s, "%ld,", delay / 1000); s+=strlen(s);
                   2100:     delay %= 1000;
                   2101:     if (delay < 100)
                   2102:     {
                   2103:       sprintf(s, "%s", (delay<10)? "00": "0");
                   2104:       s+=strlen(s);
                   2105:     }
                   2106:   }
                   2107:   sprintf(s, "%ld ms", delay); s+=strlen(s);
                   2108:   strcpy(s, term_get_color(c_NONE));
                   2109:   if (flag != ti_INTERRUPT) { s+=strlen(s); *s++='.'; *s++='\n'; *s=0; }
1.2     ! noro     2110:   return buf;
1.1       noro     2111: }
                   2112:
                   2113: static void
1.2     ! noro     2114: gp_handle_SIGINT(void)
1.1       noro     2115: {
                   2116: #ifdef _WIN32
                   2117:   if (++win32ctrlc >= 5) _exit(3);
                   2118: #else
1.2     ! noro     2119:   if (GP_DATA->flags & TEXMACS) tm_start_output();
1.1       noro     2120:   err(siginter, do_time(ti_INTERRUPT));
                   2121: #endif
                   2122: }
                   2123:
                   2124: static void
                   2125: gp_sighandler(int sig)
                   2126: {
                   2127:   char *msg;
                   2128:   os_signal(sig,gp_sighandler);
                   2129:   switch(sig)
                   2130:   {
                   2131: #ifdef SIGBREAK
                   2132:     case SIGBREAK: gp_handle_SIGINT(); return;
                   2133: #endif
                   2134: #ifdef SIGINT
1.2     ! noro     2135:     case SIGINT:   gp_handle_SIGINT(); return;
1.1       noro     2136: #endif
                   2137:
                   2138: #ifdef SIGSEGV
1.2     ! noro     2139:     case SIGSEGV: msg = "GP (Segmentation Fault)"; break;
1.1       noro     2140: #endif
                   2141: #ifdef SIGBUS
1.2     ! noro     2142:     case SIGBUS:  msg = "GP (Bus Error)"; break;
1.1       noro     2143: #endif
                   2144: #ifdef SIGFPE
1.2     ! noro     2145:     case SIGFPE:  msg = "GP (Floating Point Exception)"; break;
1.1       noro     2146: #endif
                   2147:
                   2148: #ifdef SIGPIPE
                   2149:     case SIGPIPE:
1.2     ! noro     2150:     {
        !          2151:       pariFILE *f = GP_DATA->pp->file;
        !          2152:       if (f && pari_outfile == f->file)
1.1       noro     2153:       {
1.2     ! noro     2154:         GP_DATA->pp->file = NULL; /* to avoid oo recursion on error */
1.1       noro     2155:         pari_outfile = stdout; pari_fclose(f);
                   2156:       }
                   2157:       err(talker, "Broken Pipe, resetting file stack...");
1.2     ! noro     2158:       return; /* not reached */
        !          2159:     }
1.1       noro     2160: #endif
1.2     ! noro     2161:     default: msg = "signal handling"; break;
1.1       noro     2162:   }
1.2     ! noro     2163:   err(bugparier, msg);
1.1       noro     2164: }
                   2165:
                   2166: static void
                   2167: brace_color(char *s, int c, int force)
                   2168: {
                   2169:   if (disable_color || (gp_colors[c] == c_NONE && !force)) return;
                   2170: #ifdef RL_PROMPT_START_IGNORE
                   2171:   *s++ = RL_PROMPT_START_IGNORE;
                   2172: #endif
                   2173:   strcpy(s, term_get_color(c));
                   2174: #ifdef RL_PROMPT_START_IGNORE
                   2175:   s+=strlen(s);
                   2176:   *s++ = RL_PROMPT_END_IGNORE; *s = 0;
                   2177: #endif
                   2178: }
                   2179:
                   2180: static char *
1.2     ! noro     2181: do_prompt(int in_comment, char *p)
1.1       noro     2182: {
                   2183:   static char buf[MAX_PROMPT_LEN + 24]; /* + room for color codes */
                   2184:   char *s;
1.2     ! noro     2185:
        !          2186:   if (GP_DATA->flags & TEST) return prompt;
1.1       noro     2187:   s = buf; *s = 0;
                   2188:   /* escape sequences bug readline, so use special bracing (if available) */
                   2189:   brace_color(s, c_PROMPT, 0);
                   2190:   s += strlen(s);
1.2     ! noro     2191:   if (in_comment)
1.1       noro     2192:     strcpy(s, COMMENTPROMPT);
                   2193:   else
1.2     ! noro     2194:     do_strftime(p,s, MAX_PROMPT_LEN-1);
1.1       noro     2195:   s += strlen(s);
                   2196:   brace_color(s, c_INPUT, 1); return buf;
                   2197: }
                   2198:
1.2     ! noro     2199: static char *
        !          2200: fgets_texmacs(char *s, int n, FILE *f)
1.1       noro     2201: {
1.2     ! noro     2202:   tm_start_output(); tm_end_output(); /* tell TeXmacs we need input */
        !          2203:   return fgets(s,n,f);
1.1       noro     2204: }
                   2205:
                   2206: /* Read from file (up to '\n' or EOF) and copy at s0 (points in b->buf) */
                   2207: static char *
1.2     ! noro     2208: file_input(Buffer *b, char **s0, input_method *IM)
1.1       noro     2209: {
                   2210:   int first = 1;
                   2211:   char *s = *s0;
                   2212:   long used0, used = s - b->buf;
                   2213:
                   2214:   used0 = used;
                   2215:   for(;;)
                   2216:   {
1.2     ! noro     2217:     long left = b->len - used, l;
1.1       noro     2218:
                   2219:     if (left < 512)
                   2220:     {
                   2221:       fix_buffer(b, b->len << 1);
                   2222:       left = b->len - used;
                   2223:       *s0 = b->buf + used0;
                   2224:     }
                   2225:     s = b->buf + used;
1.2     ! noro     2226:     if (! IM->fgets(s, left, IM->file))
        !          2227:       return first? NULL: *s0; /* EOF */
        !          2228:
        !          2229:     l = strlen(s); first = 0;
        !          2230:     if (l+1 < left || s[l-1] == '\n') return *s0; /* \n */
        !          2231:     used += l;
1.1       noro     2232:   }
                   2233: }
                   2234:
1.2     ! noro     2235: /* Read a "complete line" and filter it. Return: 0 if EOF, 1 otherwise */
        !          2236: int
        !          2237: input_loop(filtre_t *F, input_method *IM)
1.1       noro     2238: {
1.2     ! noro     2239:   Buffer *b = (Buffer*)F->data;
        !          2240:   char *to_read, *s = b->buf;
        !          2241:
        !          2242:   /* read first line */
        !          2243:   handle_C_C = 0;
        !          2244:   while (! (to_read = IM->getline(b,&s,IM)) )
        !          2245:   { /* EOF */
        !          2246:     if (!handle_C_C) { check_filtre(F); return 0; }
        !          2247:     /* received ^C in getline and coming back from break_loop();
        !          2248:      * retry (as if "\n" were input) */
        !          2249:     handle_C_C = 0;
1.1       noro     2250:   }
                   2251:
                   2252:   /* buffer is not empty, init filter */
1.2     ! noro     2253:   F->in_string = 0;
        !          2254:   F->more_input= 0;
        !          2255:   F->wait_for_brace = 0;
1.1       noro     2256:   for(;;)
                   2257:   {
1.2     ! noro     2258:     F->s = to_read;
        !          2259:     F->t = s;
        !          2260:     (void)filtre0(F);
        !          2261:     if (IM->free) free(to_read);
1.1       noro     2262:
1.2     ! noro     2263:     if (! F->more_input) break;
1.1       noro     2264:
                   2265:     /* read continuation line */
1.2     ! noro     2266:     s = F->end;
        !          2267:     if (IM->prompt) IM->prompt = do_prompt(F->in_comment, prompt_cont);
        !          2268:     to_read = IM->getline(b,&s, IM);
        !          2269:     if (!to_read) break;
1.1       noro     2270:   }
1.2     ! noro     2271:   return 1;
1.1       noro     2272: }
                   2273:
                   2274: /* prompt = NULL --> from gprc. Return 1 if new input, and 0 if EOF */
                   2275: static int
1.2     ! noro     2276: get_line_from_file(char *prompt, filtre_t *F, FILE *file)
1.1       noro     2277: {
1.2     ! noro     2278:   const int TeXmacs = ((GP_DATA->flags & TEXMACS) && file == stdin);
        !          2279:   char *s;
        !          2280:   input_method IM;
1.1       noro     2281:
1.2     ! noro     2282:   IM.file = file;
        !          2283:   IM.fgets= TeXmacs? &fgets_texmacs: &fgets;
        !          2284:   IM.prompt = NULL;
        !          2285:   IM.getline= &file_input;
        !          2286:   IM.free = 0;
        !          2287:   if (! input_loop(F,&IM))
        !          2288:   {
        !          2289:     if (TeXmacs) tm_start_output();
        !          2290:     return 0;
1.1       noro     2291:   }
                   2292:
1.2     ! noro     2293:   s = ((Buffer*)F->data)->buf;
1.1       noro     2294:   if (*s && prompt) /* don't echo if from gprc */
                   2295:   {
1.2     ! noro     2296:     if (GP_DATA->flags & ECHO)
1.1       noro     2297:       { pariputs(prompt); pariputs(s); pariputc('\n'); }
                   2298:     else
                   2299:       if (logfile) fprintf(logfile, "%s%s\n",prompt,s);
                   2300:     pariflush();
                   2301:   }
1.2     ! noro     2302:   if (GP_DATA->flags & TEXMACS) tm_start_output();
1.1       noro     2303:   return 1;
                   2304: }
                   2305:
                   2306: static int
1.2     ! noro     2307: get_line_from_user(char *prompt, filtre_t *F)
1.1       noro     2308: {
                   2309:   pariputs(prompt);
1.2     ! noro     2310:   return get_line_from_file(prompt,F,infile);
1.1       noro     2311: }
                   2312:
                   2313: static int
1.2     ! noro     2314: is_interactive(void)
1.1       noro     2315: {
1.2     ! noro     2316:   ulong f = GP_DATA->flags;
1.1       noro     2317: #if defined(UNIX) || defined(__EMX__)
1.2     ! noro     2318:   return (infile == stdin && !(f & TEXMACS)
        !          2319:                           && (f & EMACS || isatty(fileno(stdin))));
1.1       noro     2320: #else
1.2     ! noro     2321:   return (infile == stdin && !(f & TEXMACS));
1.1       noro     2322: #endif
                   2323: }
                   2324:
1.2     ! noro     2325: extern int get_line_from_readline(char *prompt, filtre_t *F);
        !          2326:
1.1       noro     2327: /* return 0 if no line could be read (EOF) */
                   2328: static int
1.2     ! noro     2329: read_line(filtre_t *F, char *PROMPT)
1.1       noro     2330: {
1.2     ! noro     2331:   int res;
        !          2332:   if (compatible == OLDALL) F->downcase = 1;
1.1       noro     2333:   if (is_interactive())
1.2     ! noro     2334:   {
        !          2335:     if (!PROMPT) PROMPT = do_prompt(F->in_comment, prompt);
        !          2336: #ifdef READLINE
        !          2337:     if (GP_DATA->flags & USE_READLINE)
        !          2338:       res = get_line_from_readline(PROMPT, F);
        !          2339:     else
        !          2340: #endif
        !          2341:       res = get_line_from_user(PROMPT, F);
        !          2342:     if (!disable_color) { term_color(c_NONE); pariflush(); }
        !          2343:   }
1.1       noro     2344:   else
1.2     ! noro     2345:     res = get_line_from_file(DFT_PROMPT,F,infile);
        !          2346:   return res;
1.1       noro     2347: }
                   2348:
1.2     ! noro     2349: static int
1.1       noro     2350: chron(char *s)
                   2351: {
                   2352:   if (*s)
1.2     ! noro     2353:   { /* if "#" or "##" timer metacommand. Otherwise let the parser get it */
        !          2354:     if (*s == '#') s++;
        !          2355:     if (*s) return 0;
        !          2356:     pariputs(do_time(ti_LAST));
1.1       noro     2357:   }
1.2     ! noro     2358:   else { GP_DATA->flags ^= CHRONO; sd_timer("",d_ACKNOWLEDGE); }
        !          2359:   return 1;
1.1       noro     2360: }
                   2361:
1.2     ! noro     2362: /* return 0: can't interpret *buf as a metacommand
        !          2363:  *        1: did interpret *buf as a metacommand or empty command */
1.1       noro     2364: static int
                   2365: check_meta(char *buf)
                   2366: {
                   2367:   switch(*buf++)
                   2368:   {
                   2369:     case '?': aide(buf, h_REGULAR); break;
1.2     ! noro     2370:     case '#': return chron(buf);
1.1       noro     2371:     case '\\': escape(buf); break;
1.2     ! noro     2372:     case '\0': break;
1.1       noro     2373:     default: return 0;
                   2374:   }
                   2375:   return 1;
                   2376: }
                   2377:
1.2     ! noro     2378: /* kill all history entries since loc */
        !          2379: static void
        !          2380: prune_history(gp_hist *H, long loc)
        !          2381: {
        !          2382:   long i, j;
        !          2383:   i = (H->total-1) % H->size;
        !          2384:   j = H->total - loc;
        !          2385:   for ( ; j > 0; i--,j--)
        !          2386:   {
        !          2387:     if (H->res[i])
        !          2388:     {
        !          2389:       gunclone(H->res[i]);
        !          2390:       H->res[i] = NULL;
        !          2391:     }
        !          2392:     if (!i) i = H->size;
        !          2393:   }
        !          2394:   H->total = loc;
        !          2395: }
        !          2396:
        !          2397: static int
        !          2398: is_silent(char *s) { char c = s[strlen(s) - 1]; return separe(c); }
        !          2399:
1.1       noro     2400: /* If there are other buffers open (bufstack != NULL), we are doing an
                   2401:  * immediate read (with read, extern...) */
                   2402: static GEN
                   2403: gp_main_loop(int ismain)
                   2404: {
1.2     ! noro     2405:   gp_hist *H  = GP_DATA->hist;
        !          2406:   gpmem_t av = avma;
        !          2407:   GEN z = gnil;
1.1       noro     2408:   Buffer *b = new_buffer();
1.2     ! noro     2409:   filtre_t F;
        !          2410:
1.1       noro     2411:   if (!setjmp(b->env))
                   2412:   {
                   2413:     b->flenv = 1;
                   2414:     push_stack(&bufstack, (void*)b);
                   2415:   }
1.2     ! noro     2416:   init_filtre(&F, (void*)b);
        !          2417:
        !          2418:   for (; ; setjmp(b->env), avma = av)
1.1       noro     2419:   {
                   2420:     if (ismain)
                   2421:     {
                   2422:       static long tloc, outtyp;
1.2     ! noro     2423:       tloc = H->total;
        !          2424:       outtyp = GP_DATA->fmt->prettyp;
        !          2425:       recover(0);
1.1       noro     2426:       if (setjmp(environnement))
1.2     ! noro     2427:       { /* recover from error */
1.1       noro     2428:         char *s = (char*)global_err_data;
                   2429:         if (s && *s) outerr(lisseq(s));
1.2     ! noro     2430:        avma = top;
        !          2431:         prune_history(H, tloc);
        !          2432:         GP_DATA->fmt->prettyp = outtyp;
1.1       noro     2433:         kill_all_buffers(b);
                   2434:       }
                   2435:     }
                   2436:     if (paribufsize != b->len) fix_buffer(b, paribufsize);
                   2437:
1.2     ! noro     2438:     if (! read_line(&F, NULL))
1.1       noro     2439:     {
1.2     ! noro     2440:     #ifdef _WIN32
        !          2441:       Sleep(10); if (win32ctrlc) dowin32ctrlc();
        !          2442:     #endif
        !          2443:       if (popinfile()) gp_quit();
        !          2444:       if (ismain) continue;
        !          2445:       pop_buffer(); return z;
1.1       noro     2446:     }
1.2     ! noro     2447:     if (check_meta(b->buf)) continue;
        !          2448:
1.1       noro     2449:     if (ismain)
                   2450:     {
1.2     ! noro     2451:       gpsilent = is_silent(b->buf);
        !          2452:       TIMERstart(GP_DATA->T);
        !          2453:     }
        !          2454:     z = readseq(b->buf, GP_DATA->flags & STRICTMATCH);
1.1       noro     2455:     if (! ismain) continue;
1.2     ! noro     2456:
        !          2457:     if (GP_DATA->flags & CHRONO)
        !          2458:       pariputs(do_time(ti_REGULAR));
        !          2459:     else
        !          2460:       do_time(ti_NOPRINT);
1.1       noro     2461:     if (z == gnil) continue;
                   2462:
1.2     ! noro     2463:     if (GP_DATA->flags & SIMPLIFY) z = simplify_i(z);
        !          2464:     z = set_hist_entry(H, z);
        !          2465:     if (!gpsilent) gp_output(z, GP_DATA);
1.1       noro     2466:   }
                   2467: }
                   2468:
                   2469: GEN
                   2470: read0(char *s)
                   2471: {
                   2472:   switchin(s);
                   2473:   if (file_is_binary(infile)) return gpreadbin(s);
                   2474:   return gp_main_loop(0);
                   2475: }
                   2476:
                   2477: static void
                   2478: check_secure(char *s)
                   2479: {
1.2     ! noro     2480:   if (GP_DATA->flags & SECURE)
1.1       noro     2481:     err(talker, "[secure mode]: system commands not allowed\nTried to run '%s'",s);
                   2482: }
                   2483:
                   2484: GEN
                   2485: extern0(char *s)
                   2486: {
                   2487:   check_secure(s);
                   2488:   infile = try_pipe(s, mf_IN)->file;
                   2489:   return gp_main_loop(0);
                   2490: }
                   2491:
                   2492: static int
1.2     ! noro     2493: silent(void)
1.1       noro     2494: {
                   2495:   if (gpsilent) return 1;
1.2     ! noro     2496:   { char c = get_analyseur()[1]; return separe(c); }
1.1       noro     2497: }
                   2498:
                   2499: GEN
                   2500: default0(char *a, char *b, long flag)
                   2501: {
1.2     ! noro     2502:   return setdefault(a,b, flag? d_RETURN
        !          2503:                              : silent()? d_SILENT: d_ACKNOWLEDGE);
1.1       noro     2504: }
                   2505:
                   2506: GEN
1.2     ! noro     2507: input0(void)
1.1       noro     2508: {
                   2509:   Buffer *b = new_buffer();
1.2     ! noro     2510:   filtre_t F;
1.1       noro     2511:   GEN x;
                   2512:
1.2     ! noro     2513:   init_filtre(&F, (void*)b);
1.1       noro     2514:   push_stack(&bufstack, (void*)b);
1.2     ! noro     2515:   while (! get_line_from_file(DFT_INPROMPT,&F,infile))
1.1       noro     2516:     if (popinfile()) { fprintferr("no input ???"); gp_quit(); }
                   2517:   x = lisseq(b->buf);
                   2518:   pop_buffer(); return x;
                   2519: }
                   2520:
                   2521: void
                   2522: system0(char *s)
                   2523: {
                   2524: #if defined(UNIX) || defined(__EMX__)
                   2525:   check_secure(s);
                   2526:   system(s);
                   2527: #else
                   2528:   err(archer);
                   2529: #endif
                   2530: }
                   2531:
                   2532: int
                   2533: break_loop(long numerr)
                   2534: {
                   2535:   static FILE *oldinfile = NULL;
                   2536:   static char *old = NULL;
                   2537:   static Buffer *b = NULL;
1.2     ! noro     2538:   int go_on = 0;
1.1       noro     2539:   char *s, *t, *msg;
1.2     ! noro     2540:   filtre_t F;
1.1       noro     2541:
                   2542:   if (b) jump_to_given_buffer(b);
                   2543:   push_stack(&bufstack, (void*)new_buffer());
                   2544:   b = current_buffer; /* buffer created above */
                   2545:   if (setjmp(b->env))
                   2546:   {
                   2547:     msg = "back to break loop";
                   2548:     s = t = NULL;
                   2549:   }
                   2550:   else
                   2551:   {
                   2552:     msg = "Starting break loop (type 'break' to go back to GP)";
1.2     ! noro     2553:     old = s = get_analyseur();
        !          2554:     t = NULL;
        !          2555:     if (bufstack->prev)
        !          2556:     {
        !          2557:       Buffer *oldb = (Buffer*)bufstack->prev->value;
        !          2558:       t = oldb->buf;
        !          2559:       /* something fishy, probably a ^C, or we overran analyseur */
        !          2560:       if (!s || !s[-1] || s < t || s >= t + oldb->len) s = NULL;
        !          2561:     }
1.1       noro     2562:     b->flenv = 1; oldinfile = infile;
                   2563:   }
1.2     ! noro     2564:   init_filtre(&F, (void*)b);
1.1       noro     2565:
                   2566:   term_color(c_ERR); pariputc('\n');
                   2567:   errcontext(msg, s, t); if (s) pariputc('\n');
                   2568:   term_color(c_NONE);
                   2569:   if (numerr == siginter) pariputs("['' or 'next' will continue]\n");
                   2570:   infile = stdin;
                   2571:   for(;;)
                   2572:   {
1.2     ! noro     2573:     GEN x;
        !          2574:     if (! read_line(&F, BREAK_LOOP_PROMPT)) break;
        !          2575:     if (check_meta(b->buf))
        !          2576:     { /* break loop initiated by ^C? Empty input --> continue computation */
        !          2577:       if (numerr == siginter && *(b->buf) == 0) { handle_C_C=go_on=1; break; }
        !          2578:       continue;
        !          2579:     }
        !          2580:     x = lisseq(b->buf);
        !          2581:     if (did_break())
1.1       noro     2582:     {
1.2     ! noro     2583:       if (numerr == siginter && did_break() == br_NEXT)
1.1       noro     2584:       {
1.2     ! noro     2585:         (void)loop_break(); /* clear status flag */
        !          2586:         go_on = 1;
1.1       noro     2587:       }
1.2     ! noro     2588:       break;
        !          2589:     }
        !          2590:     if (x == gnil || is_silent(b->buf)) continue;
1.1       noro     2591:
1.2     ! noro     2592:     term_color(c_OUTPUT); gen_output(x, GP_DATA->fmt);
        !          2593:     term_color(c_NONE); pariputc('\n');
1.1       noro     2594:   }
1.2     ! noro     2595:   if (old && !s) set_analyseur(old);
1.1       noro     2596:   b = NULL; infile = oldinfile;
                   2597:   pop_buffer(); return go_on;
                   2598: }
                   2599:
                   2600: int
                   2601: gp_exception_handler(long numerr)
                   2602: {
                   2603:   char *s = (char*)global_err_data;
                   2604:   if (s && *s) { fprintferr("\n"); outerr(lisseq(s)); }
                   2605:   else
                   2606:   {
                   2607:     if (numerr == errpile) avma = top;
                   2608:     return break_loop(numerr);
                   2609:   }
                   2610:   return 0;
                   2611: }
                   2612:
                   2613: static void
1.2     ! noro     2614: testuint(char *s, ulong *d) { if (s) *d = get_uint(s); }
1.1       noro     2615:
                   2616: static char *
                   2617: read_arg(int *nread, char *t, long argc, char **argv)
                   2618: {
                   2619:   int i = *nread;
                   2620:   if (isdigit((int)*t)) return t;
                   2621:   if (*t || i==argc) usage(argv[0]);
                   2622:   *nread = i+1; return argv[i];
                   2623: }
                   2624:
                   2625: static char**
                   2626: read_opt(long argc, char **argv)
                   2627: {
                   2628:   char *b=NULL, *p=NULL, *s=NULL, **pre;
                   2629:   int i=1, initrc=1;
                   2630:
                   2631:   pari_outfile=stderr;
                   2632:   while (i<argc)
                   2633:   {
                   2634:     char *t = argv[i++];
                   2635:
                   2636:     if (*t++ != '-') usage(argv[0]);
                   2637:     switch(*t++)
                   2638:     {
                   2639:       case 'b': b = read_arg(&i,t,argc,argv); break;
                   2640:       case 'p': p = read_arg(&i,t,argc,argv); break;
                   2641:       case 's': s = read_arg(&i,t,argc,argv); break;
                   2642:
                   2643:       case 'e':
                   2644:        if (strncmp(t,"macs",4)) usage(argv[0]);
1.2     ! noro     2645:         GP_DATA->flags |= EMACS; break;
1.1       noro     2646:       case 'q':
1.2     ! noro     2647:         GP_DATA->flags |= QUIET; break;
1.1       noro     2648:       case 't':
                   2649:        if (strncmp(t,"est",3)) usage(argv[0]);
1.2     ! noro     2650:         disable_color = 1; GP_DATA->flags |= TEST; /* fall through */
1.1       noro     2651:       case 'f':
                   2652:        initrc = 0; break;
                   2653:       case '-':
                   2654:         if (strcmp(t, "version") == 0) { print_version(); exit(0); }
1.2     ! noro     2655:         if (strcmp(t, "texmacs") == 0) { GP_DATA->flags |= TEXMACS; break; }
1.1       noro     2656:        /* fall through */
                   2657:       default:
                   2658:        usage(argv[0]);
                   2659:     }
                   2660:   }
1.2     ! noro     2661:   if (GP_DATA->flags & TEXMACS) tm_start_output();
1.1       noro     2662:   pre = initrc? gp_initrc(): NULL;
                   2663:
                   2664:   /* override the values from gprc */
1.2     ! noro     2665:   testuint(b, &paribufsize); if (paribufsize < 10) paribufsize = 10;
        !          2666:   testuint(p, &primelimit);
        !          2667:   testuint(s, (ulong*)&top);
        !          2668:   if (GP_DATA->flags & (EMACS|TEXMACS)) disable_color = 1;
        !          2669:   pari_outfile = stdout; return pre;
1.1       noro     2670: }
                   2671:
                   2672: #ifdef WINCE
                   2673: int
                   2674: WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   2675:         LPWSTR lpCmdLine, int nShowCmd)
                   2676: {
                   2677:   char **argv = NULL;
                   2678:   int argc = 1;
                   2679: #else
                   2680: int
                   2681: main(int argc, char **argv)
                   2682: {
                   2683: #endif
                   2684:   char **flist;
                   2685:
1.2     ! noro     2686:   init_defaults(1); gp_preinit();
1.1       noro     2687:   if (setjmp(environnement))
                   2688:   {
                   2689:     pariputs("### Errors on startup, exiting...\n\n");
                   2690:     exit(1);
                   2691:   }
                   2692: #ifdef __MWERKS__
                   2693:   argc = ccommand(&argv);
                   2694: #endif
                   2695:   flist = read_opt(argc,argv);
                   2696:   pari_addfunctions(&pari_modules, functions_gp,helpmessages_gp);
                   2697:   pari_addfunctions(&pari_modules, functions_highlevel,helpmessages_highlevel);
                   2698:   pari_addfunctions(&pari_oldmodules, functions_oldgp,helpmessages_oldgp);
                   2699:
1.2     ! noro     2700:   init_graph();
        !          2701:   INIT_SIG_off;
        !          2702:   pari_init(top-bot, primelimit);
1.1       noro     2703:   INIT_SIG_on;
                   2704:   pari_sig_init(gp_sighandler);
                   2705: #ifdef READLINE
1.2     ! noro     2706:   if (GP_DATA->flags & USE_READLINE) {
        !          2707:     init_readline();
        !          2708:     readline_init = 1;
1.1       noro     2709:   }
                   2710: #endif
                   2711:   whatnow_fun = whatnow;
                   2712:   default_exception_handler = gp_exception_handler;
1.2     ! noro     2713:   gp_expand_path(GP_DATA->path);
1.1       noro     2714:
1.2     ! noro     2715:   if (!(GP_DATA->flags & QUIET)) gp_head();
1.1       noro     2716:   if (flist)
                   2717:   {
1.2     ! noro     2718:     ulong f = GP_DATA->flags;
        !          2719:     FILE *l = logfile;
1.1       noro     2720:     char **s = flist;
1.2     ! noro     2721:     GP_DATA->flags &= ~(CHRONO|ECHO); logfile = NULL;
1.1       noro     2722:     for ( ; *s; s++) { read0(*s); free(*s); }
1.2     ! noro     2723:     GP_DATA->flags = f; logfile = l; free(flist);
1.1       noro     2724:   }
1.2     ! noro     2725:   TIMERstart(GP_DATA->T); (void)timer(); (void)timer2();
1.1       noro     2726:   (void)gp_main_loop(1);
                   2727:   gp_quit(); return 0; /* not reached */
                   2728: }

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