Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - language - gplib.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.10.0 lcov report (development 21061-8feaff2) Lines: 340 884 38.5 %
Date: 2017-09-24 06:24:57 Functions: 46 90 51.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation. It is distributed in the hope that it will be useful, but WITHOUT
       8             : ANY WARRANTY WHATSOEVER.
       9             : 
      10             : Check the License for details. You should have received a copy of it, along
      11             : with the package; see the file 'COPYING'. If not, write to the Free Software
      12             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13             : 
      14             : /*******************************************************************/
      15             : /**                                                               **/
      16             : /**            LIBRARY ROUTINES FOR PARI CALCULATOR               **/
      17             : /**                                                               **/
      18             : /*******************************************************************/
      19             : #ifdef _WIN32
      20             : #  include "../systems/mingw/pwinver.h"
      21             : #  include <windows.h>
      22             : #  include "../systems/mingw/mingw.h"
      23             : #  include <process.h>
      24             : #endif
      25             : 
      26             : #include "pari.h"
      27             : #include "paripriv.h"
      28             : #ifdef __EMSCRIPTEN__
      29             : #include "../systems/emscripten/emscripten.h"
      30             : #endif
      31             : 
      32             : /********************************************************************/
      33             : /**                                                                **/
      34             : /**                            STRINGS                             **/
      35             : /**                                                                **/
      36             : /********************************************************************/
      37             : 
      38             : void
      39          28 : pari_skip_space(char **s) {
      40          28 :   char *t = *s;
      41          28 :   while (isspace((int)*t)) t++;
      42          28 :   *s = t;
      43          28 : }
      44             : void
      45           7 : pari_skip_alpha(char **s) {
      46           7 :   char *t = *s;
      47           7 :   while (isalpha((int)*t)) t++;
      48           7 :   *s = t;
      49           7 : }
      50             : 
      51             : /*******************************************************************/
      52             : /**                                                               **/
      53             : /**                          BUFFERS                              **/
      54             : /**                                                               **/
      55             : /*******************************************************************/
      56             : static Buffer **bufstack;
      57             : static pari_stack s_bufstack;
      58             : void
      59        1503 : pari_init_buffers(void)
      60        1503 : { pari_stack_init(&s_bufstack, sizeof(Buffer*), (void**)&bufstack); }
      61             : 
      62             : void
      63        1571 : pop_buffer(void)
      64             : {
      65        1571 :   if (s_bufstack.n)
      66        1571 :     delete_buffer( bufstack[ --s_bufstack.n ] );
      67        1571 : }
      68             : 
      69             : /* kill all buffers until B is met or nothing is left */
      70             : void
      71        9561 : kill_buffers_upto(Buffer *B)
      72             : {
      73       20630 :   while (s_bufstack.n) {
      74        9568 :     if (bufstack[ s_bufstack.n-1 ] == B) break;
      75        1508 :     pop_buffer();
      76             :   }
      77        9561 : }
      78             : void
      79           0 : kill_buffers_upto_including(Buffer *B)
      80             : {
      81           0 :   while (s_bufstack.n) {
      82           0 :     if (bufstack[ s_bufstack.n-1 ] == B) { pop_buffer(); break; }
      83           0 :     pop_buffer();
      84             :   }
      85           0 : }
      86             : 
      87             : static int disable_exception_handler = 0;
      88             : #define BLOCK_EH_START                \
      89             : {                                     \
      90             :   int block=disable_exception_handler;\
      91             :   disable_exception_handler = 1;
      92             : 
      93             : #define BLOCK_EH_END                \
      94             :   disable_exception_handler = block;\
      95             : }
      96             : /* numerr < 0: from SIGINT */
      97             : int
      98        7846 : gp_handle_exception(long numerr)
      99             : {
     100        7846 :   if (disable_exception_handler)
     101           0 :     disable_exception_handler = 0;
     102        7846 :   else if (GP_DATA->breakloop && cb_pari_break_loop
     103          56 :                               && cb_pari_break_loop(numerr))
     104           0 :     return 1;
     105        7839 :   return 0;
     106             : }
     107             : 
     108             : /********************************************************************/
     109             : /**                                                                **/
     110             : /**                             HELP                               **/
     111             : /**                                                                **/
     112             : /********************************************************************/
     113             : void
     114           0 : pari_hit_return(void)
     115             : {
     116             :   int c;
     117           0 :   if (GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS)) return;
     118           0 :   BLOCK_EH_START
     119           0 :   pari_puts("/*-- (type RETURN to continue) --*/");
     120           0 :   pari_flush();
     121             :   /* if called from a readline callback, may be in a funny TTY mode */
     122           0 :   do c = fgetc(stdin); while (c >= 0 && c != '\n' && c != '\r');
     123           0 :   pari_putc('\n');
     124           0 :   BLOCK_EH_END
     125             : }
     126             : 
     127             : static int
     128           9 : has_ext_help(void) { return (GP_DATA->help && *GP_DATA->help); }
     129             : 
     130             : static int
     131         168 : compare_str(char **s1, char **s2) { return strcmp(*s1, *s2); }
     132             : 
     133             : /* Print all elements of list in columns, pausing every nbli lines
     134             :  * if nbli is non-zero.
     135             :  * list is a NULL terminated list of function names
     136             :  */
     137             : void
     138           7 : print_fun_list(char **list, long nbli)
     139             : {
     140           7 :   long i=0, j=0, maxlen=0, nbcol,len, w = term_width();
     141             :   char **l;
     142             : 
     143           7 :   while (list[i]) i++;
     144           7 :   qsort (list, i, sizeof(char *), (QSCOMP)compare_str);
     145             : 
     146          84 :   for (l=list; *l; l++)
     147             :   {
     148          77 :     len = strlen(*l);
     149          77 :     if (len > maxlen) maxlen=len;
     150             :   }
     151           7 :   maxlen++; nbcol= w / maxlen;
     152           7 :   if (nbcol * maxlen == w) nbcol--;
     153           7 :   if (!nbcol) nbcol = 1;
     154             : 
     155           7 :   pari_putc('\n'); i=0;
     156          84 :   for (l=list; *l; l++)
     157             :   {
     158          77 :     pari_puts(*l); i++;
     159          77 :     if (i >= nbcol)
     160             :     {
     161           7 :       i=0; pari_putc('\n');
     162           7 :       if (nbli && j++ > nbli) { j = 0; pari_hit_return(); }
     163           7 :       continue;
     164             :     }
     165          70 :     len = maxlen - strlen(*l);
     166          70 :     while (len--) pari_putc(' ');
     167             :   }
     168           7 :   if (i) pari_putc('\n');
     169           7 : }
     170             : 
     171             : static const long MAX_SECTION = 16;
     172             : static void
     173           7 : commands(long n)
     174             : {
     175             :   long i;
     176             :   entree *ep;
     177             :   char **t_L;
     178             :   pari_stack s_L;
     179             : 
     180           7 :   pari_stack_init(&s_L, sizeof(*t_L), (void**)&t_L);
     181         952 :   for (i = 0; i < functions_tblsz; i++)
     182        8687 :     for (ep = functions_hash[i]; ep; ep = ep->next)
     183             :     {
     184             :       long m;
     185        7742 :       switch (EpVALENCE(ep))
     186             :       {
     187             :         case EpVAR:
     188          21 :           if (typ((GEN)ep->value) == t_CLOSURE) break;
     189             :           /* fall through */
     190          28 :         case EpNEW: continue;
     191             :       }
     192        7714 :       m = ep->menu;
     193        7714 :       if (m == n || (n < 0 && m && m <= MAX_SECTION))
     194          77 :         pari_stack_pushp(&s_L, (void*)ep->name);
     195             :     }
     196           7 :   pari_stack_pushp(&s_L, NULL);
     197           7 :   print_fun_list(t_L, term_height()-4);
     198           7 :   pari_stack_delete(&s_L);
     199           7 : }
     200             : 
     201             : void
     202          10 : pari_center(const char *s)
     203             : {
     204          10 :   pari_sp av = avma;
     205          10 :   long i, l = strlen(s), pad = term_width() - l;
     206             :   char *buf, *u;
     207             : 
     208          10 :   if (pad<0) pad=0; else pad >>= 1;
     209          10 :   u = buf = stack_malloc(l + pad + 2);
     210          10 :   for (i=0; i<pad; i++) *u++ = ' ';
     211          10 :   while (*s) *u++ = *s++;
     212          10 :   *u++ = '\n'; *u = 0;
     213          10 :   pari_puts(buf); avma = av;
     214          10 : }
     215             : 
     216             : static void
     217           0 : community(void)
     218             : {
     219           0 :   print_text("The PARI/GP distribution includes a reference manual, a \
     220             : tutorial, a reference card and quite a few examples. They have been installed \
     221             : in the directory ");
     222           0 :   pari_puts("  ");
     223           0 :   pari_puts(pari_datadir);
     224           0 :   pari_puts("\nYou can also download them from http://pari.math.u-bordeaux.fr/.\
     225             : \n\nThree mailing lists are devoted to PARI:\n\
     226             :   - pari-announce (moderated) to announce major version changes.\n\
     227             :   - pari-dev for everything related to the development of PARI, including\n\
     228             :     suggestions, technical questions, bug reports and patch submissions.\n\
     229             :   - pari-users for everything else!\n\
     230             : To subscribe, send an empty message to\n\
     231             :   <pari_list_name>-request@pari.math.u-bordeaux.fr\n\
     232             : with a Subject: field containing the word 'subscribe'.\n\n");
     233           0 :   print_text("An archive is kept at the WWW site mentioned above. You can also \
     234             : reach the authors at pari@math.u-bordeaux.fr (answer not guaranteed)."); }
     235             : 
     236             : static void
     237           7 : gentypes(void)
     238             : {
     239           7 :   pari_puts("List of the PARI types:\n\
     240             :   t_INT    : long integers     [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     241             :   t_REAL   : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     242             :   t_INTMOD : integermods       [ code ] [ mod  ] [ integer ]\n\
     243             :   t_FRAC   : irred. rationals  [ code ] [ num. ] [ den. ]\n\
     244             :   t_FFELT  : finite field elt. [ code ] [ cod2 ] [ elt ] [ mod ] [ p ]\n\
     245             :   t_COMPLEX: complex numbers   [ code ] [ real ] [ imag ]\n\
     246             :   t_PADIC  : p-adic numbers    [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ]\n\
     247             :   t_QUAD   : quadratic numbers [ cod1 ] [ mod  ] [ real ] [ imag ]\n\
     248             :   t_POLMOD : poly mod          [ code ] [ mod  ] [ polynomial ]\n\
     249             :   -------------------------------------------------------------\n\
     250             :   t_POL    : polynomials       [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     251             :   t_SER    : power series      [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     252             :   t_RFRAC  : irred. rat. func. [ code ] [ num. ] [ den. ]\n\
     253             :   t_QFR    : real qfb          [ code ] [ a ] [ b ] [ c ] [ del ]\n\
     254             :   t_QFI    : imaginary qfb     [ code ] [ a ] [ b ] [ c ]\n\
     255             :   t_VEC    : row vector        [ code ] [  x_1  ] ... [  x_k  ]\n\
     256             :   t_COL    : column vector     [ code ] [  x_1  ] ... [  x_k  ]\n\
     257             :   t_MAT    : matrix            [ code ] [ col_1 ] ... [ col_k ]\n\
     258             :   t_LIST   : list              [ cod1 ] [ cod2 ][ vec ]\n\
     259             :   t_STR    : string            [ code ] [ man_1 ] ... [ man_k ]\n\
     260             :   t_VECSMALL: vec. small ints  [ code ] [ x_1 ] ... [ x_k ]\n\
     261             :   t_CLOSURE: functions [ code ] [ arity ] [ code ] [ operand ] [ data ] [ text ]\n\
     262             :   t_ERROR  : error context     [ code ] [ errnum ] [ dat_1 ] ... [ dat_k ]\n\
     263             :   t_INFINITY: a*infinity       [ code ] [ a ]\n\
     264             : \n");
     265           7 : }
     266             : 
     267             : static void
     268           7 : menu_commands(void)
     269             : {
     270             :   ulong i;
     271           7 :   const char *s[] = {
     272             :   "user-defined functions (aliases, installed and user functions)",
     273             :   "Standard monadic or dyadic OPERATORS",
     274             :   "CONVERSIONS and similar elementary functions",
     275             :   "functions related to COMBINATORICS",
     276             :   "TRANSCENDENTAL functions",
     277             :   "NUMBER THEORETICAL functions",
     278             :   "ELLIPTIC CURVES",
     279             :   "L-FUNCTIONS",
     280             :   "MODULAR FORMS",
     281             :   "MODULAR SYMBOLS",
     282             :   "General NUMBER FIELDS",
     283             :   "Associative and central simple ALGEBRAS",
     284             :   "POLYNOMIALS and power series",
     285             :   "Vectors, matrices, LINEAR ALGEBRA and sets",
     286             :   "SUMS, products, integrals and similar functions",
     287             :   "GRAPHIC functions",
     288             :   "PROGRAMMING under GP",
     289             :   "The PARI community"
     290             :   };
     291           7 :   pari_puts("Help topics: for a list of relevant subtopics, type ?n for n in\n");
     292           7 :   for (i = 0; i < numberof(s); i++) pari_printf("  %2lu: %s\n", i, s[i]);
     293           7 :   pari_puts("Also:\n\
     294             :   ? functionname (short on-line help)\n\
     295             :   ?\\             (keyboard shortcuts)\n\
     296             :   ?.             (member functions)\n");
     297           7 :   if (has_ext_help()) pari_puts("\
     298             : Extended help (if available):\n\
     299             :   ??             (opens the full user's manual in a dvi previewer)\n\
     300             :   ??  tutorial / refcard / libpari (tutorial/reference card/libpari manual)\n\
     301             :   ??  refcard-ell (or -lfun/-mf/-nf: specialized reference card)\n\
     302             :   ??  keyword    (long help text about \"keyword\" from the user's manual)\n\
     303             :   ??? keyword    (a propos: list of related functions).");
     304           7 : }
     305             : 
     306             : static void
     307           7 : slash_commands(void)
     308             : {
     309           7 :   pari_puts("#       : enable/disable timer\n\
     310             : ##      : print time for last result\n\
     311             : \\\\      : comment up to end of line\n\
     312             : \\a {n}  : print result in raw format (readable by PARI)\n\
     313             : \\B {n}  : print result in beautified format\n\
     314             : \\c      : list all commands (same effect as ?*)\n\
     315             : \\d      : print all defaults\n\
     316             : \\e {n}  : enable/disable echo (set echo=n)\n\
     317             : \\g {n}  : set debugging level\n\
     318             : \\gf{n}  : set file debugging level\n\
     319             : \\gm{n}  : set memory debugging level\n\
     320             : \\h {m-n}: hashtable information\n\
     321             : \\l {f}  : enable/disable logfile (set logfile=f)\n\
     322             : \\m {n}  : print result in prettymatrix format\n\
     323             : \\o {n}  : set output method (0=raw, 1=prettymatrix, 2=prettyprint, 3=2-dim)\n\
     324             : \\p {n}  : change real precision\n\
     325             : \\pb{n}  : change real bit precision\n\
     326             : \\ps{n}  : change series precision\n\
     327             : \\q      : quit completely this GP session\n\
     328             : \\r {f}  : read in a file\n\
     329             : \\s      : print stack information\n\
     330             : \\t      : print the list of PARI types\n\
     331             : \\u      : print the list of user-defined functions\n\
     332             : \\um     : print the list of user-defined member functions\n\
     333             : \\v      : print current version of GP\n\
     334             : \\w {nf} : write to a file\n\
     335             : \\x {n}  : print complete inner structure of result\n\
     336             : \\y {n}  : disable/enable automatic simplification (set simplify=n)\n\
     337             : \n\
     338             : {f}=optional filename. {n}=optional integer\n");
     339           7 : }
     340             : 
     341             : static void
     342           7 : member_commands(void)
     343             : {
     344           7 :   pari_puts("\
     345             : Member functions, followed by relevant objects\n\n\
     346             : a1-a6, b2-b8, c4-c6 : coeff. of the curve.         ell\n\
     347             : area : area                                        ell\n\
     348             : bid  : big ideal                     bid,                     bnr\n\
     349             : bnf  : big number field                                   bnf,bnr\n\
     350             : clgp : class group                   bid,                 bnf,bnr\n\
     351             : cyc  : cyclic decomposition (SNF)    bid,     clgp,ell,   bnf,bnr\n\
     352             : diff, codiff: different and codifferent                nf,bnf,bnr\n\
     353             : disc : discriminant                                ell,nf,bnf,bnr,rnf\n\
     354             : e, f : inertia/residue  degree           prid\n\
     355             : fu   : fundamental units                                  bnf,bnr\n\
     356             : gen  : generators                    bid,prid,clgp,ell,   bnf,bnr,    gal\n\
     357             : group: group                                       ell,               gal\n\
     358             : index: index                                           nf,bnf,bnr\n\
     359             : j    : j-invariant                                 ell\n");
     360             : /* split: some compilers can't handle long constant strings */
     361           7 :   pari_puts("\
     362             : mod  : modulus                       bid,                     bnr,    gal\n\
     363             : nf   : number field                                    nf,bnf,bnr,rnf\n\
     364             : no   : number of elements            bid,     clgp,ell,   bnf,bnr\n\
     365             : omega, eta: [w1,w2] and [eta1, eta2]               ell\n\
     366             : orders: relative orders of generators                                 gal\n\
     367             : p    : rational prime                    prid,     ell,           rnf,gal\n\
     368             : pol  : defining polynomial                             nf,bnf,bnr,    gal\n\
     369             : polabs: defining polynomial over Q                                rnf\n\
     370             : reg  : regulator                                          bnf,bnr\n\
     371             : roots: roots                                       ell,nf,bnf,bnr,    gal\n\
     372             : sign,r1,r2 : signature                                 nf,bnf,bnr\n\
     373             : t2   : t2 matrix                                       nf,bnf,bnr\n\
     374             : tate : Tate's [u^2, u, q, [a,b], L, Ei]            ell\n\
     375             : tu   : torsion unit and its order                         bnf,bnr\n\
     376             : zk   : integral basis                                  nf,bnf,bnr,rnf\n\
     377             : zkst : structure of (Z_K/m)*         bid,                     bnr\n");
     378           7 : }
     379             : 
     380             : #define QUOTE "_QUOTE"
     381             : #define DOUBQUOTE "_DOUBQUOTE"
     382             : #define BACKQUOTE "_BACKQUOTE"
     383             : 
     384             : static char *
     385           0 : _cat(char *s, const char *t)
     386             : {
     387           0 :   *s = 0; strcat(s,t); return s + strlen(t);
     388             : }
     389             : 
     390             : static char *
     391           0 : filter_quotes(const char *s)
     392             : {
     393           0 :   int i, l = strlen(s);
     394           0 :   int quote = 0;
     395           0 :   int backquote = 0;
     396           0 :   int doubquote = 0;
     397             :   char *str, *t;
     398             : 
     399           0 :   for (i=0; i < l; i++)
     400           0 :     switch(s[i])
     401             :     {
     402           0 :       case '\'': quote++; break;
     403           0 :       case '`' : backquote++; break;
     404           0 :       case '"' : doubquote++;
     405             :     }
     406           0 :   str = (char*)pari_malloc(l + quote * (strlen(QUOTE)-1)
     407           0 :                           + doubquote * (strlen(DOUBQUOTE)-1)
     408           0 :                           + backquote * (strlen(BACKQUOTE)-1) + 1);
     409           0 :   t = str;
     410           0 :   for (i=0; i < l; i++)
     411           0 :     switch(s[i])
     412             :     {
     413           0 :       case '\'': t = _cat(t, QUOTE); break;
     414           0 :       case '`' : t = _cat(t, BACKQUOTE); break;
     415           0 :       case '"' : t = _cat(t, DOUBQUOTE); break;
     416           0 :       default: *t++ = s[i];
     417             :     }
     418           0 :   *t = 0; return str;
     419             : }
     420             : 
     421             : static int
     422           0 : nl_read(char *s) { size_t l = strlen(s); return s[l-1] == '\n'; }
     423             : 
     424             : /* query external help program for s. num < 0 [keyword] or chapter number */
     425             : static void
     426           0 : external_help(const char *s, int num)
     427             : {
     428           0 :   long nbli = term_height()-3, li = 0;
     429             :   char buf[256], *str;
     430           0 :   const char *opt = "", *ar = "", *cdir = "";
     431           0 :   char *t, *help = GP_DATA->help;
     432             :   pariFILE *z;
     433             :   FILE *f;
     434             : #ifdef __EMSCRIPTEN__
     435             :   pari_emscripten_help(s);
     436             : #endif
     437             : 
     438           0 :   if (!has_ext_help()) pari_err(e_MISC,"no external help program");
     439           0 :   t = filter_quotes(s);
     440           0 :   if (num < 0)
     441           0 :     opt = "-k";
     442           0 :   else if (t[strlen(t)-1] != '@')
     443           0 :     ar = stack_sprintf("@%d",num);
     444             : #ifdef _WIN32
     445             :   if (*help=='@')
     446             :   {
     447             :     const char *basedir = win32_basedir();
     448             :     help++;
     449             :     cdir = stack_sprintf("%c:& cd %s & ", *basedir, basedir);
     450             :   }
     451             : #endif
     452           0 :   str=stack_sprintf("%s%s -fromgp %s %c%s%s%c",cdir,help,opt,
     453             :                                                SHELL_Q,t,ar,SHELL_Q);
     454           0 :   z = try_pipe(str,0); f = z->file;
     455           0 :   pari_free(t);
     456           0 :   while (fgets(buf, numberof(buf), f))
     457             :   {
     458           0 :     if (!strncmp("ugly_kludge_done",buf,16)) break;
     459           0 :     pari_puts(buf);
     460           0 :     if (nl_read(buf) && ++li > nbli) { pari_hit_return(); li = 0; }
     461             :   }
     462           0 :   pari_fclose(z);
     463           0 : }
     464             : 
     465             : const char **
     466           0 : gphelp_keyword_list(void)
     467             : {
     468             :   static const char *L[]={
     469             :   "operator",
     470             :   "libpari",
     471             :   "member",
     472             :   "integer",
     473             :   "real",
     474             :   "readline",
     475             :   "refcard",
     476             :   "refcard-nf",
     477             :   "refcard-ell",
     478             :   "refcard-mf",
     479             :   "refcard-lfun",
     480             :   "tutorial",
     481             :   "nf",
     482             :   "bnf",
     483             :   "bnr",
     484             :   "ell",
     485             :   "rnf",
     486             :   "bid",
     487             :   "modulus",
     488             :   "prototype",
     489             :   "Lmath",
     490             :   "Ldata",
     491             :   "Linit",
     492             :   NULL};
     493           0 :   return L;
     494             : }
     495             : 
     496             : static int
     497           0 : ok_external_help(char **s)
     498             : {
     499             :   const char **L;
     500             :   long n;
     501           0 :   if (!**s) return 1;
     502           0 :   if (!isalpha((int)**s)) return 3; /* operator or section number */
     503           0 :   if (!strncmp(*s,"t_",2)) { *s += 2; return 2; } /* type name */
     504             : 
     505           0 :   L = gphelp_keyword_list();
     506           0 :   for (n=0; L[n]; n++)
     507           0 :     if (!strcmp(*s,L[n])) return 3;
     508           0 :   return 0;
     509             : }
     510             : 
     511             : static void
     512         113 : cut_trailing_garbage(char *s)
     513             : {
     514             :   char c;
     515         686 :   while ( (c = *s++) )
     516             :   {
     517         474 :     if (c == '\\' && ! *s++) return; /* gobble next char, return if none. */
     518         474 :     if (!is_keyword_char(c) && c != '@') { s[-1] = 0; return; }
     519             :   }
     520             : }
     521             : 
     522             : static void
     523           7 : digit_help(char *s, long flag)
     524             : {
     525           7 :   long n = atoi(s);
     526           7 :   if (n < 0 || n > MAX_SECTION+4)
     527           0 :     pari_err(e_SYNTAX,"no such section in help: ?",s,s);
     528           7 :   if (n == MAX_SECTION+1)
     529           0 :     community();
     530           7 :   else if (flag & h_LONG)
     531           0 :     external_help(s,3);
     532             :   else
     533           7 :     commands(n);
     534           7 :   return;
     535             : }
     536             : 
     537             : static void
     538          39 : simple_help(const char *s1, const char *s2) { pari_printf("%s: %s\n", s1, s2); }
     539             : 
     540             : static void
     541          21 : default_help(char *s, long flag)
     542             : {
     543          21 :   if (flag & h_LONG)
     544           0 :     external_help(stack_strcat("se:def,",s),3);
     545             :   else
     546          21 :     simple_help(s,"default");
     547          21 : }
     548             : 
     549             : static void
     550         141 : help(const char *s0, int flag)
     551             : {
     552         141 :   const long long_help = flag & h_LONG;
     553             :   long n;
     554             :   entree *ep;
     555         141 :   char *s = get_sep(s0);
     556             : 
     557         222 :   if (isdigit((int)*s)) { digit_help(s,flag); return; }
     558         134 :   if (flag & h_APROPOS) { external_help(s,-1); return; }
     559             :   /* Get meaningful answer on '\ps 5' (e.g. from <F1>) */
     560         134 :   if (*s == '\\') { char *t = s+1; pari_skip_alpha(&t); *t = '\0'; }
     561         134 :   if (isalpha((int)*s))
     562             :   {
     563         113 :     if (!strncmp(s, "default", 7))
     564             :     { /* special-case ?default(dft_name), e.g. default(log) */
     565          14 :       char *t = s+7;
     566          14 :       pari_skip_space(&t);
     567          14 :       if (*t == '(')
     568             :       {
     569          14 :         t++; pari_skip_space(&t);
     570          14 :         cut_trailing_garbage(t);
     571          14 :         if (pari_is_default(t)) { default_help(t,flag); return; }
     572             :       }
     573             :     }
     574          99 :     if (!strncmp(s, "refcard-", 8))
     575           0 :       cut_trailing_garbage(s+8);
     576             :     else
     577          99 :       cut_trailing_garbage(s);
     578             :   }
     579             : 
     580         120 :   if (long_help && (n = ok_external_help(&s))) { external_help(s,n); return; }
     581         120 :   switch (*s)
     582             :   {
     583           0 :     case '*' : commands(-1); return;
     584           7 :     case '\0': menu_commands(); return;
     585           7 :     case '\\': slash_commands(); return;
     586           7 :     case '.' : member_commands(); return;
     587             :   }
     588          99 :   ep = is_entry(s);
     589          99 :   if (!ep)
     590             :   {
     591          14 :     if (pari_is_default(s))
     592           7 :       default_help(s,flag);
     593           7 :     else if (long_help)
     594           0 :       external_help(s,3);
     595           7 :     else if (!cb_pari_whatnow || !cb_pari_whatnow(pariOut, s,1))
     596           7 :       simple_help(s,"unknown identifier");
     597          14 :     return;
     598             :   }
     599             : 
     600          85 :   if (EpVALENCE(ep) == EpALIAS)
     601             :   {
     602          14 :     pari_printf("%s is aliased to:\n\n",s);
     603          14 :     ep = do_alias(ep);
     604             :   }
     605          85 :   switch(EpVALENCE(ep))
     606             :   {
     607             :     case EpVAR:
     608          35 :       if (!ep->help)
     609             :       {
     610          21 :         if (typ((GEN)ep->value)!=t_CLOSURE)
     611           7 :           simple_help(s, "user defined variable");
     612             :         else
     613             :         {
     614          14 :           GEN str = closure_get_text((GEN)ep->value);
     615          14 :           if (typ(str) == t_VEC)
     616          14 :             pari_printf("%s =\n  %Ps\n", ep->name, ep->value);
     617             :         }
     618          21 :         return;
     619             :       }
     620          14 :       break;
     621             : 
     622             :     case EpINSTALL:
     623           4 :       if (!ep->help) { simple_help(s, "installed function"); return; }
     624           4 :       break;
     625             : 
     626             :     case EpNEW:
     627          18 :       if (!ep->help) { simple_help(s, "new identifier"); return; };
     628          14 :       break;
     629             : 
     630             :     default: /* built-in function */
     631          28 :       if (!ep->help) pari_err_BUG("gp_help (no help found)"); /*paranoia*/
     632          28 :       if (long_help) { external_help(ep->name,3); return; }
     633             :   }
     634          60 :   print_text(ep->help);
     635             : }
     636             : 
     637             : void
     638         141 : gp_help(const char *s, long flag)
     639             : {
     640         141 :   pari_sp av = avma;
     641         141 :   if ((flag & h_RL) == 0)
     642             :   {
     643         141 :     if (*s == '?') { flag |= h_LONG; s++; }
     644         141 :     if (*s == '?') { flag |= h_APROPOS; s++; }
     645             :   }
     646         141 :   term_color(c_HELP); help(s,flag); term_color(c_NONE);
     647         141 :   if ((flag & h_RL) == 0) pari_putc('\n');
     648         141 :   avma = av;
     649         141 : }
     650             : 
     651             : /********************************************************************/
     652             : /**                                                                **/
     653             : /**                         GP HEADER                              **/
     654             : /**                                                                **/
     655             : /********************************************************************/
     656             : static char *
     657           2 : what_readline(void)
     658             : {
     659             : #ifdef READLINE
     660           2 :   const char *v = READLINE;
     661           2 :   char *s = stack_malloc(3 + strlen(v) + 8);
     662           2 :   (void)sprintf(s, "v%s %s", v, GP_DATA->use_readline? "enabled": "disabled");
     663           2 :   return s;
     664             : #else
     665             :   return (char*)"not compiled in";
     666             : #endif
     667             : }
     668             : 
     669             : static char *
     670           2 : what_cc(void)
     671             : {
     672             :   char *s;
     673             : #ifdef GCC_VERSION
     674             : #  ifdef __cplusplus
     675             : #    define Format "(C++) %s"
     676             : #  else
     677             : #    define Format "%s"
     678             : #  endif
     679           2 :   s = stack_malloc(6 + strlen(GCC_VERSION) + 1);
     680           2 :   (void)sprintf(s, Format, GCC_VERSION);
     681             : #else
     682             : #  ifdef _MSC_VER
     683             :   s = stack_malloc(32);
     684             :   (void)sprintf(s, "MSVC-%i", _MSC_VER);
     685             : #  else
     686             :   s = NULL;
     687             : #  endif
     688             : #endif
     689           2 :   return s;
     690             : }
     691             : 
     692             : static void
     693           6 : convert_time(char *s, long delay)
     694             : {
     695           6 :   if (delay >= 3600000)
     696             :   {
     697           0 :     sprintf(s, "%ldh, ", delay / 3600000); s+=strlen(s);
     698           0 :     delay %= 3600000;
     699             :   }
     700           6 :   if (delay >= 60000)
     701             :   {
     702           0 :     sprintf(s, "%ldmin, ", delay / 60000); s+=strlen(s);
     703           0 :     delay %= 60000;
     704             :   }
     705           6 :   if (delay >= 1000)
     706             :   {
     707           4 :     sprintf(s, "%ld,", delay / 1000); s+=strlen(s);
     708           4 :     delay %= 1000;
     709           4 :     if (delay < 100)
     710             :     {
     711           3 :       sprintf(s, "%s", (delay<10)? "00": "0");
     712           3 :       s+=strlen(s);
     713             :     }
     714             :   }
     715           6 :   sprintf(s, "%ld ms", delay); s+=strlen(s);
     716           6 : }
     717             : 
     718             : /* Format a time of 'delay' ms */
     719             : const char *
     720           0 : gp_format_time(long delay)
     721             : {
     722             :   static char buf[64];
     723           0 :   char *s = buf;
     724             : 
     725           0 :   term_get_color(s, c_TIME);
     726           0 :   convert_time(s + strlen(s), delay);
     727           0 :   s+=strlen(s);
     728           0 :   term_get_color(s, c_NONE);
     729           0 :   s+=strlen(s);
     730           0 :   s[0] = '.';
     731           0 :   s[1] = '\n';
     732           0 :   s[2] = 0; return buf;
     733             : }
     734             : 
     735             : /********************************************************************/
     736             : /*                                                                  */
     737             : /*                              GPRC                                */
     738             : /*                                                                  */
     739             : /********************************************************************/
     740             : /* LOCATE GPRC */
     741             : static void
     742           0 : err_gprc(const char *s, char *t, char *u)
     743             : {
     744           0 :   err_printf("\n");
     745           0 :   pari_err(e_SYNTAX,s,t,u);
     746           0 : }
     747             : 
     748             : /* return $HOME or the closest we can find */
     749             : static const char *
     750           0 : get_home(int *free_it)
     751             : {
     752           0 :   char *drv, *pth = os_getenv("HOME");
     753           0 :   if (pth) return pth;
     754           0 :   if ((drv = os_getenv("HOMEDRIVE"))
     755           0 :    && (pth = os_getenv("HOMEPATH")))
     756             :   { /* looks like WinNT */
     757           0 :     char *buf = (char*)pari_malloc(strlen(pth) + strlen(drv) + 1);
     758           0 :     sprintf(buf, "%s%s",drv,pth);
     759           0 :     *free_it = 1; return buf;
     760             :   }
     761           0 :   pth = pari_get_homedir("");
     762           0 :   return pth? pth: ".";
     763             : }
     764             : 
     765             : static FILE *
     766           0 : gprc_chk(const char *s)
     767             : {
     768           0 :   FILE *f = fopen(s, "r");
     769           0 :   if (f && !(GP_DATA->flags & gpd_QUIET)) err_printf("Reading GPRC: %s ...", s);
     770           0 :   return f;
     771             : }
     772             : 
     773             : /* Look for [._]gprc: $GPRC, then in $HOME, ., /etc, pari_datadir */
     774             : static FILE *
     775           0 : gprc_get(void)
     776             : {
     777           0 :   FILE *f = NULL;
     778           0 :   const char *gprc = os_getenv("GPRC");
     779           0 :   if (gprc) f = gprc_chk(gprc);
     780           0 :   if (!f)
     781             :   {
     782           0 :     int free_it = 0;
     783           0 :     const char *home = get_home(&free_it);
     784             :     char *str, *s, c;
     785             :     long l;
     786           0 :     l = strlen(home); c = home[l-1];
     787             :     /* + "/gprc.txt" + \0*/
     788           0 :     str = strcpy((char*)pari_malloc(l+10), home);
     789           0 :     if (free_it) pari_free((void*)home);
     790           0 :     s = str + l;
     791           0 :     if (c != '/' && c != '\\') *s++ = '/';
     792             : #ifndef _WIN32
     793           0 :     strcpy(s, ".gprc");
     794             : #else
     795             :     strcpy(s, "gprc.txt");
     796             : #endif
     797           0 :     f = gprc_chk(str); /* in $HOME */
     798           0 :     if (!f) f = gprc_chk(s); /* in . */
     799             : #ifndef _WIN32
     800           0 :     if (!f) f = gprc_chk("/etc/gprc");
     801             : #else
     802             :     if (!f)  /* in basedir */
     803             :     {
     804             :       const char *basedir = win32_basedir();
     805             :       char *t = (char *) pari_malloc(strlen(basedir)+strlen(s)+2);
     806             :       sprintf(t, "%s/%s", basedir, s);
     807             :       f = gprc_chk(t); free(t);
     808             :     }
     809             : #endif
     810           0 :     pari_free(str);
     811             :   }
     812           0 :   return f;
     813             : }
     814             : 
     815             : /* PREPROCESSOR */
     816             : 
     817             : static ulong
     818           0 : read_uint(char **s)
     819             : {
     820           0 :   long v = atol(*s);
     821           0 :   if (!isdigit((int)**s)) err_gprc("not an integer", *s, *s);
     822           0 :   while (isdigit((int)**s)) (*s)++;
     823           0 :   return v;
     824             : }
     825             : static ulong
     826           0 : read_dot_uint(char **s)
     827             : {
     828           0 :   if (**s != '.') return 0;
     829           0 :   (*s)++; return read_uint(s);
     830             : }
     831             : /* read a.b.c */
     832             : static long
     833           0 : read_version(char **s)
     834             : {
     835             :   long a, b, c;
     836           0 :   a = read_uint(s);
     837           0 :   b = read_dot_uint(s);
     838           0 :   c = read_dot_uint(s);
     839           0 :   return PARI_VERSION(a,b,c);
     840             : }
     841             : 
     842             : static int
     843           0 : get_preproc_value(char **s)
     844             : {
     845           0 :   if (!strncmp(*s,"EMACS",5)) {
     846           0 :     *s += 5;
     847           0 :     return GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS);
     848             :   }
     849           0 :   if (!strncmp(*s,"READL",5)) {
     850           0 :     *s += 5;
     851           0 :     return GP_DATA->use_readline;
     852             :   }
     853           0 :   if (!strncmp(*s,"VERSION",7)) {
     854           0 :     int less = 0, orequal = 0;
     855             :     long d;
     856           0 :     *s += 7;
     857           0 :     switch(**s)
     858             :     {
     859           0 :       case '<': (*s)++; less = 1; break;
     860           0 :       case '>': (*s)++; less = 0; break;
     861           0 :       default: return -1;
     862             :     }
     863           0 :     if (**s == '=') { (*s)++; orequal = 1; }
     864           0 :     d = paricfg_version_code - read_version(s);
     865           0 :     if (!d) return orequal;
     866           0 :     return less? (d < 0): (d > 0);
     867             :   }
     868           0 :   if (!strncmp(*s,"BITS_IN_LONG",12)) {
     869           0 :     *s += 12;
     870           0 :     if ((*s)[0] == '=' && (*s)[1] == '=')
     871             :     {
     872           0 :       *s += 2;
     873           0 :       return BITS_IN_LONG == read_uint(s);
     874             :     }
     875             :   }
     876           0 :   return -1;
     877             : }
     878             : 
     879             : /* PARSE GPRC */
     880             : 
     881             : /* 1) replace next separator by '\0' (t must be writable)
     882             :  * 2) return the next expression ("" if none)
     883             :  * see get_sep() */
     884             : static char *
     885           0 : next_expr(char *t)
     886             : {
     887           0 :   int outer = 1;
     888           0 :   char *s = t;
     889             : 
     890             :   for(;;)
     891             :   {
     892             :     char c;
     893           0 :     switch ((c = *s++))
     894             :     {
     895             :       case '"':
     896           0 :         if (outer || (s >= t+2 && s[-2] != '\\')) outer = !outer;
     897           0 :         break;
     898             :       case '\0':
     899           0 :         return (char*)"";
     900             :       default:
     901           0 :         if (outer && c == ';') { s[-1] = 0; return s; }
     902             :     }
     903           0 :   }
     904             : }
     905             : 
     906             : Buffer *
     907        1571 : filtered_buffer(filtre_t *F)
     908             : {
     909        1571 :   Buffer *b = new_buffer();
     910        1571 :   init_filtre(F, b);
     911        1571 :   pari_stack_pushp(&s_bufstack, (void*)b);
     912        1571 :   return b;
     913             : }
     914             : 
     915             : /* parse src of the form s=t (or s="t"), set *ps to s, and *pt to t.
     916             :  * modifies src (replaces = by \0) */
     917             : void
     918           0 : parse_key_val(char *src, char **ps, char **pt)
     919             : {
     920             :   char *s_end, *t;
     921           0 :   t = src; while (*t && *t != '=') t++;
     922           0 :   if (*t != '=') err_gprc("missing '='",t,src);
     923           0 :   s_end = t;
     924           0 :   t++;
     925           0 :   if (*t == '"') (void)pari_translate_string(t, t, src);
     926           0 :   *s_end = 0; *ps = src; *pt = t;
     927           0 : }
     928             : 
     929             : void
     930           0 : gp_initrc(pari_stack *p_A)
     931             : {
     932           0 :   FILE *file = gprc_get();
     933             :   Buffer *b;
     934             :   filtre_t F;
     935           0 :   VOLATILE long c = 0;
     936             :   jmp_buf *env;
     937             :   pari_stack s_env;
     938             : 
     939           0 :   if (!file) return;
     940           0 :   b = filtered_buffer(&F);
     941           0 :   pari_stack_init(&s_env, sizeof(*env), (void**)&env);
     942           0 :   (void)pari_stack_new(&s_env);
     943             :   for(;;)
     944             :   {
     945             :     char *nexts, *s, *t;
     946           0 :     if (setjmp(env[s_env.n-1])) err_printf("...skipping line %ld.\n", c);
     947           0 :     c++;
     948           0 :     if (!get_line_from_file(NULL,&F,file)) break;
     949           0 :     s = b->buf;
     950           0 :     if (*s == '#')
     951             :     { /* preprocessor directive */
     952           0 :       int z, NOT = 0;
     953           0 :       s++;
     954           0 :       if (strncmp(s,"if",2)) err_gprc("unknown directive",s,b->buf);
     955           0 :       s += 2;
     956           0 :       if (!strncmp(s,"not",3)) { NOT = !NOT; s += 3; }
     957           0 :       if (*s == '!')           { NOT = !NOT; s++; }
     958           0 :       t = s;
     959           0 :       z = get_preproc_value(&s);
     960           0 :       if (z < 0) err_gprc("unknown preprocessor variable",t,b->buf);
     961           0 :       if (NOT) z = !z;
     962           0 :       if (!*s)
     963             :       { /* make sure at least an expr follows the directive */
     964           0 :         if (!get_line_from_file(NULL,&F,file)) break;
     965           0 :         s = b->buf;
     966             :       }
     967           0 :       if (!z) continue; /* dump current line */
     968             :     }
     969             :     /* parse line */
     970           0 :     for ( ; *s; s = nexts)
     971             :     {
     972           0 :       nexts = next_expr(s);
     973           0 :       if (!strncmp(s,"read",4) && (s[4] == ' ' || s[4] == '\t' || s[4] == '"'))
     974             :       { /* read file */
     975           0 :         s += 4;
     976           0 :         t = (char*)pari_malloc(strlen(s) + 1);
     977           0 :         if (*s == '"') (void)pari_translate_string(s, t, s-4); else strcpy(t,s);
     978           0 :         pari_stack_pushp(p_A,t);
     979             :       }
     980             :       else
     981             :       { /* set default */
     982           0 :         parse_key_val(s, &s,&t);
     983           0 :         (void)setdefault(s,t,d_INITRC);
     984             :       }
     985             :     }
     986           0 :   }
     987           0 :   pari_stack_delete(&s_env);
     988           0 :   pop_buffer();
     989           0 :   if (!(GP_DATA->flags & gpd_QUIET)) err_printf("Done.\n\n");
     990           0 :   fclose(file);
     991             : }
     992             : 
     993             : void
     994           0 : gp_load_gprc(void)
     995             : {
     996             :   pari_stack sA;
     997             :   char **A;
     998             :   long i;
     999           0 :   pari_stack_init(&sA,sizeof(*A),(void**)&A);
    1000           0 :   gp_initrc(&sA);
    1001           0 :   for (i = 0; i < sA.n; pari_free(A[i]),i++)
    1002             :   {
    1003           0 :     pari_CATCH(CATCH_ALL) { err_printf("... skipping file '%s'\n", A[i]); }
    1004           0 :     pari_TRY { gp_read_file(A[i]); } pari_ENDCATCH;
    1005             :   }
    1006           0 :   pari_stack_delete(&sA);
    1007           0 : }
    1008             : 
    1009             : /********************************************************************/
    1010             : /*                                                                  */
    1011             : /*                             PROMPTS                              */
    1012             : /*                                                                  */
    1013             : /********************************************************************/
    1014             : /* if prompt is coloured, tell readline to ignore the ANSI escape sequences */
    1015             : /* s must be able to store 14 chars (including final \0) */
    1016             : #ifdef READLINE
    1017             : static void
    1018           0 : readline_prompt_color(char *s, int c)
    1019             : {
    1020             : #ifdef _WIN32
    1021             :   (void)s; (void)c;
    1022             : #else
    1023           0 :   *s++ = '\001'; /*RL_PROMPT_START_IGNORE*/
    1024           0 :   term_get_color(s, c);
    1025           0 :   s += strlen(s);
    1026           0 :   *s++ = '\002'; /*RL_PROMPT_END_IGNORE*/
    1027           0 :   *s = 0;
    1028             : #endif
    1029           0 : }
    1030             : #endif
    1031             : /* s must be able to store 14 chars (including final \0) */
    1032             : static void
    1033           0 : brace_color(char *s, int c, int force)
    1034             : {
    1035           0 :   if (disable_color || (gp_colors[c] == c_NONE && !force)) return;
    1036             : #ifdef READLINE
    1037           0 :   if (GP_DATA->use_readline)
    1038           0 :     readline_prompt_color(s, c);
    1039             :   else
    1040             : #endif
    1041           0 :     term_get_color(s, c);
    1042             : }
    1043             : 
    1044             : /* strlen(prompt) + 28 chars */
    1045             : static const char *
    1046           0 : color_prompt(const char *prompt)
    1047             : {
    1048           0 :   long n = strlen(prompt);
    1049           0 :   char *t = stack_malloc(n + 28), *s = t;
    1050           0 :   *s = 0;
    1051             :   /* escape sequences bug readline, so use special bracing (if available) */
    1052           0 :   brace_color(s, c_PROMPT, 0);
    1053           0 :   s += strlen(s); strncpy(s, prompt, n);
    1054           0 :   s += n; *s = 0;
    1055           0 :   brace_color(s, c_INPUT, 1);
    1056           0 :   return t;
    1057             : }
    1058             : 
    1059             : const char *
    1060        6768 : gp_format_prompt(const char *prompt)
    1061             : {
    1062        6768 :   if (GP_DATA->flags & gpd_TEST)
    1063        6768 :     return prompt;
    1064             :   else
    1065             :   {
    1066             :     char b[256]; /* longer is truncated */
    1067           0 :     strftime_expand(prompt, b, sizeof(b));
    1068           0 :     return color_prompt(b);
    1069             :   }
    1070             : }
    1071             : 
    1072             : /********************************************************************/
    1073             : /*                                                                  */
    1074             : /*                           GP MAIN LOOP                           */
    1075             : /*                                                                  */
    1076             : /********************************************************************/
    1077             : static int
    1078      149228 : is_interactive(void)
    1079      149228 : { return cb_pari_is_interactive? cb_pari_is_interactive(): 0; }
    1080             : 
    1081             : static char *
    1082           0 : strip_prompt(const char *s)
    1083             : {
    1084           0 :   long l = strlen(s);
    1085           0 :   char *t, *t0 = stack_malloc(l+1);
    1086           0 :   t = t0;
    1087           0 :   for (; *s; s++)
    1088             :   {
    1089             :     /* RL_PROMPT_START_IGNORE / RL_PROMPT_END_IGNORE */
    1090           0 :     if (*s == 1 || *s == 2) continue;
    1091           0 :     if (*s == '\x1b') /* skip ANSI color escape sequence */
    1092             :     {
    1093           0 :       while (*++s != 'm')
    1094           0 :         if (!*s) goto end;
    1095           0 :       continue;
    1096             :     }
    1097           0 :     *t = *s; t++;
    1098             :   }
    1099             : end:
    1100           0 :   *t = 0; return t0;
    1101             : }
    1102             : static void
    1103        6173 : update_logfile(const char *prompt, const char *s)
    1104             : {
    1105             :   pari_sp av;
    1106             :   const char *p;
    1107       12346 :   if (!pari_logfile) return;
    1108           0 :   av = avma;
    1109           0 :   p = strip_prompt(prompt); /* raw prompt */
    1110             : 
    1111           0 :   switch (logstyle) {
    1112             :     case logstyle_TeX:
    1113           0 :       fprintf(pari_logfile,
    1114             :               "\\PARIpromptSTART|%s\\PARIpromptEND|%s\\PARIinputEND|%%\n",
    1115             :               p, s);
    1116           0 :     break;
    1117             :     case logstyle_plain:
    1118           0 :       fprintf(pari_logfile,"%s%s\n",p, s);
    1119           0 :     break;
    1120             :     case logstyle_color:
    1121           0 :       fprintf(pari_logfile,"%s%s%s%s%s\n",term_get_color(NULL,c_PROMPT), p,
    1122             :                                           term_get_color(NULL,c_INPUT), s,
    1123             :                                           term_get_color(NULL,c_NONE));
    1124           0 :       break;
    1125             :   }
    1126           0 :   avma = av;
    1127             : }
    1128             : 
    1129             : void
    1130       67868 : gp_echo_and_log(const char *prompt, const char *s)
    1131             : {
    1132       67868 :   if (!is_interactive())
    1133             :   {
    1134      135736 :     if (!GP_DATA->echo) return;
    1135             :     /* not pari_puts(): would duplicate in logfile */
    1136        6173 :     fputs(prompt, pari_outfile);
    1137        6173 :     fputs(s,      pari_outfile);
    1138        6173 :     fputc('\n',   pari_outfile);
    1139        6173 :     pari_set_last_newline(1);
    1140             :   }
    1141        6173 :   update_logfile(prompt, s);
    1142        6173 :   pari_flush();
    1143             : }
    1144             : 
    1145             : /* prompt = NULL --> from gprc. Return 1 if new input, and 0 if EOF */
    1146             : int
    1147       81367 : get_line_from_file(const char *prompt, filtre_t *F, FILE *file)
    1148             : {
    1149             :   char *s;
    1150             :   input_method IM;
    1151             : 
    1152       81367 :   IM.file = (void*)file;
    1153       81367 :   if (file==stdin && cb_pari_fgets_interactive)
    1154           0 :     IM.fgets = (fgets_t)cb_pari_fgets_interactive;
    1155             :   else
    1156       81367 :     IM.fgets = (fgets_t)&fgets;
    1157       81367 :   IM.getline = &file_input;
    1158       81367 :   IM.free = 0;
    1159       81367 :   if (! input_loop(F,&IM))
    1160             :   {
    1161        1501 :     if (file==stdin && cb_pari_start_output) cb_pari_start_output();
    1162        1501 :     return 0;
    1163             :   }
    1164       79866 :   s = F->buf->buf;
    1165             :   /* don't log if from gprc or empty input */
    1166       79866 :   if (*s && prompt) gp_echo_and_log(prompt, s);
    1167       79866 :   return 1;
    1168             : }
    1169             : 
    1170             : /* return 0 if no line could be read (EOF). If PROMPT = NULL, expand and
    1171             :  * color default prompt; otherwise, use PROMPT as-is. */
    1172             : int
    1173       81360 : gp_read_line(filtre_t *F, const char *PROMPT)
    1174             : {
    1175             :   static const char *DFT_PROMPT = "? ";
    1176       81360 :   Buffer *b = (Buffer*)F->buf;
    1177             :   const char *p;
    1178             :   int res, interactive;
    1179       81360 :   if (b->len > 100000) fix_buffer(b, 100000);
    1180       81360 :   interactive = is_interactive();
    1181       81360 :   if (interactive || pari_logfile || GP_DATA->echo)
    1182             :   {
    1183        6873 :     p = PROMPT;
    1184       13746 :     if (!p) {
    1185        6705 :       p = F->in_comment? GP_DATA->prompt_comment: GP_DATA->prompt;
    1186        6705 :       p = gp_format_prompt(p);
    1187             :     }
    1188             :   }
    1189             :   else
    1190       74487 :     p = DFT_PROMPT;
    1191             : 
    1192       81360 :   if (interactive)
    1193             :   {
    1194           0 :     BLOCK_EH_START
    1195           0 :     if (cb_pari_get_line_interactive)
    1196           0 :       res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F);
    1197             :     else {
    1198           0 :       pari_puts(p); pari_flush();
    1199           0 :       res = get_line_from_file(p, F, pari_infile);
    1200             :     }
    1201           0 :     BLOCK_EH_END
    1202             :   }
    1203             :   else
    1204             :   { /* in case UI fakes non-interactivity, e.g. TeXmacs */
    1205       81360 :     if (cb_pari_start_output && cb_pari_get_line_interactive)
    1206           0 :       res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F);
    1207             :     else
    1208       81360 :       res = get_line_from_file(p, F, pari_infile);
    1209             :   }
    1210             : 
    1211       81360 :   if (!disable_color && p != DFT_PROMPT &&
    1212           0 :       (gp_colors[c_PROMPT] != c_NONE || gp_colors[c_INPUT] != c_NONE))
    1213             :   {
    1214           0 :     term_color(c_NONE); pari_flush();
    1215             :   }
    1216       81360 :   return res;
    1217             : }
    1218             : 
    1219             : /********************************************************************/
    1220             : /*                                                                  */
    1221             : /*                      EXCEPTION HANDLER                           */
    1222             : /*                                                                  */
    1223             : /********************************************************************/
    1224             : static THREAD pari_timer ti_alarm;
    1225             : 
    1226             : #if defined(_WIN32) || defined(SIGALRM)
    1227             : static void
    1228           6 : gp_alarm_fun(void) {
    1229             :   char buf[64];
    1230           6 :   if (cb_pari_start_output) cb_pari_start_output();
    1231           6 :   convert_time(buf, timer_get(&ti_alarm));
    1232           6 :   pari_err(e_ALARM, buf);
    1233           0 : }
    1234             : #endif /* SIGALRM */
    1235             : 
    1236             : void
    1237           0 : gp_sigint_fun(void) {
    1238             :   char buf[64];
    1239             : #if defined(_WIN32)
    1240             :   if (win32alrm) { win32alrm = 0; gp_alarm_fun(); return;}
    1241             : #endif
    1242           0 :   if (cb_pari_start_output) cb_pari_start_output();
    1243           0 :   convert_time(buf, timer_get(GP_DATA->T));
    1244           0 :   pari_sigint(buf);
    1245           0 : }
    1246             : 
    1247             : #ifdef SIGALRM
    1248             : void
    1249           8 : gp_alarm_handler(int sig)
    1250             : {
    1251             : #ifndef HAS_SIGACTION
    1252             :   /*SYSV reset the signal handler in the handler*/
    1253             :   (void)os_signal(sig,gp_alarm_handler);
    1254             : #endif
    1255           8 :   if (PARI_SIGINT_block) PARI_SIGINT_pending=sig;
    1256           6 :   else gp_alarm_fun();
    1257           2 :   return;
    1258             : }
    1259             : #endif /* SIGALRM */
    1260             : 
    1261             : /********************************************************************/
    1262             : /*                                                                  */
    1263             : /*                      GP-SPECIFIC ROUTINES                        */
    1264             : /*                                                                  */
    1265             : /********************************************************************/
    1266             : void
    1267          84 : gp_allocatemem(GEN z)
    1268             : {
    1269             :   ulong newsize;
    1270          84 :   if (!z) newsize = 0;
    1271             :   else {
    1272          84 :     if (typ(z) != t_INT) pari_err_TYPE("allocatemem",z);
    1273          84 :     newsize = itou(z);
    1274          84 :     if (signe(z) < 0) pari_err_DOMAIN("allocatemem","size","<",gen_0,z);
    1275             :   }
    1276          84 :   if (pari_mainstack->vsize)
    1277           0 :     paristack_resize(newsize);
    1278             :   else
    1279          84 :     paristack_newrsize(newsize);
    1280           0 : }
    1281             : 
    1282             : GEN
    1283           7 : gp_input(void)
    1284             : {
    1285             :   filtre_t F;
    1286           7 :   Buffer *b = filtered_buffer(&F);
    1287             :   GEN x;
    1288             : 
    1289          14 :   while (! get_line_from_file("",&F,pari_infile))
    1290           0 :     if (popinfile()) { err_printf("no input ???"); cb_pari_quit(1); }
    1291           7 :   x = readseq(b->buf);
    1292           7 :   pop_buffer(); return x;
    1293             : }
    1294             : 
    1295             : static GEN
    1296         112 : closure_alarmer(GEN C, long s)
    1297             : {
    1298             :   struct pari_evalstate state;
    1299             :   VOLATILE GEN x;
    1300         112 :   if (!s) { pari_alarm(0); return closure_evalgen(C); }
    1301         112 :   evalstate_save(&state);
    1302             : #if !defined(HAS_ALARM) && !defined(_WIN32)
    1303             :   pari_err(e_ARCH,"alarm");
    1304             : #endif
    1305         112 :   pari_CATCH(CATCH_ALL) /* We need to stop the timer after any error */
    1306             :   {
    1307           6 :     GEN E = pari_err_last();
    1308           6 :     if (err_get_num(E) != e_ALARM) { pari_alarm(0); pari_err(0, E); }
    1309           6 :     x = evalstate_restore_err(&state);
    1310             :   }
    1311         112 :   pari_TRY { pari_alarm(s); x = closure_evalgen(C); pari_alarm(0); } pari_ENDCATCH;
    1312         112 :   return x;
    1313             : }
    1314             : 
    1315             : void
    1316       67454 : pari_alarm(long s)
    1317             : {
    1318       67454 :   if (s < 0) pari_err_DOMAIN("alarm","delay","<",gen_0,stoi(s));
    1319       67454 :   if (s) timer_start(&ti_alarm);
    1320             : #ifdef _WIN32
    1321             :   win32_alarm(s);
    1322             : #elif defined(HAS_ALARM)
    1323       67454 :   alarm(s);
    1324             : #else
    1325             :   if (s) pari_err(e_ARCH,"alarm");
    1326             : #endif
    1327       67454 : }
    1328             : 
    1329             : GEN
    1330         112 : gp_alarm(long s, GEN code)
    1331             : {
    1332         112 :   if (!code) { pari_alarm(s); return gnil; }
    1333         112 :   return closure_alarmer(code,s);
    1334             : }
    1335             : 
    1336             : /*******************************************************************/
    1337             : /**                                                               **/
    1338             : /**                    EXTERNAL PRETTYPRINTER                     **/
    1339             : /**                                                               **/
    1340             : /*******************************************************************/
    1341             : /* Wait for prettinprinter to finish, to prevent new prompt from overwriting
    1342             :  * the output.  Fill the output buffer, wait until it is read.
    1343             :  * Better than sleep(2): give possibility to print */
    1344             : static void
    1345           0 : prettyp_wait(FILE *out)
    1346             : {
    1347           0 :   const char *s = "                                                     \n";
    1348           0 :   long i = 2000;
    1349             : 
    1350           0 :   fputs("\n\n", out); fflush(out); /* start translation */
    1351           0 :   while (--i) fputs(s, out);
    1352           0 :   fputs("\n", out); fflush(out);
    1353           0 : }
    1354             : 
    1355             : /* initialise external prettyprinter (tex2mail) */
    1356             : static int
    1357           0 : prettyp_init(void)
    1358             : {
    1359           0 :   gp_pp *pp = GP_DATA->pp;
    1360           0 :   if (!pp->cmd) return 0;
    1361           0 :   if (pp->file || (pp->file = try_pipe(pp->cmd, mf_OUT))) return 1;
    1362             : 
    1363           0 :   pari_warn(warner,"broken prettyprinter: '%s'",pp->cmd);
    1364           0 :   pari_free(pp->cmd); pp->cmd = NULL;
    1365           0 :   sd_output("1", d_SILENT);
    1366           0 :   return 0;
    1367             : }
    1368             : 
    1369             : /* n = history number. if n = 0 no history */
    1370             : int
    1371           0 : tex2mail_output(GEN z, long n)
    1372             : {
    1373           0 :   pariout_t T = *(GP_DATA->fmt); /* copy */
    1374           0 :   FILE *log = pari_logfile, *out;
    1375             : 
    1376           0 :   if (!prettyp_init()) return 0;
    1377           0 :   out = GP_DATA->pp->file->file;
    1378             :   /* Emit first: there may be lines before the prompt */
    1379           0 :   if (n) term_color(c_OUTPUT);
    1380           0 :   pari_flush();
    1381           0 :   T.prettyp = f_TEX;
    1382             :   /* history number */
    1383           0 :   if (n)
    1384             :   {
    1385           0 :     pari_sp av = avma;
    1386           0 :     const char *c_hist = term_get_color(NULL, c_HIST);
    1387           0 :     const char *c_out = term_get_color(NULL, c_OUTPUT);
    1388           0 :     if (!(GP_DATA->flags & gpd_QUIET))
    1389             :     {
    1390           0 :       if (*c_hist || *c_out)
    1391           0 :         fprintf(out, "\\LITERALnoLENGTH{%s}\\%%%ld =\\LITERALnoLENGTH{%s} ",
    1392             :                      c_hist, n, c_out);
    1393             :       else
    1394           0 :         fprintf(out, "\\%%%ld = ", n);
    1395             :     }
    1396           0 :     if (log) {
    1397           0 :       switch (logstyle) {
    1398             :       case logstyle_plain:
    1399           0 :         fprintf(log, "%%%ld = ", n);
    1400           0 :         break;
    1401             :       case logstyle_color:
    1402           0 :         fprintf(log, "%s%%%ld = %s", c_hist, n, c_out);
    1403           0 :         break;
    1404             :       case logstyle_TeX:
    1405           0 :         fprintf(log, "\\PARIout{%ld}", n);
    1406           0 :         break;
    1407             :       }
    1408             :     }
    1409           0 :     avma = av;
    1410             :   }
    1411             :   /* output */
    1412           0 :   fputGEN_pariout(z, &T, out);
    1413             :   /* flush and restore, output to logfile */
    1414           0 :   prettyp_wait(out);
    1415           0 :   if (log) {
    1416           0 :     if (logstyle == logstyle_TeX) {
    1417           0 :       T.TeXstyle |= TEXSTYLE_BREAK;
    1418           0 :       fputGEN_pariout(z, &T, log);
    1419           0 :       fputc('%', log);
    1420             :     } else {
    1421           0 :       T.prettyp = f_RAW;
    1422           0 :       fputGEN_pariout(z, &T, log);
    1423             :     }
    1424           0 :     fputc('\n', log); fflush(log);
    1425             :   }
    1426           0 :   if (n) term_color(c_NONE);
    1427           0 :   pari_flush(); return 1;
    1428             : }
    1429             : 
    1430             : /*******************************************************************/
    1431             : /**                                                               **/
    1432             : /**                     GP-SPECIFIC DEFAULTS                      **/
    1433             : /**                                                               **/
    1434             : /*******************************************************************/
    1435             : 
    1436             : static long
    1437           0 : atocolor(const char *s)
    1438             : {
    1439           0 :   long l = atol(s);
    1440           0 :   if (l <   0) l =   0;
    1441           0 :   if (l > 255) l = 255;
    1442           0 :   return l;
    1443             : }
    1444             : 
    1445             : GEN
    1446           0 : sd_graphcolormap(const char *v, long flag)
    1447             : {
    1448             :   char *p, *q;
    1449             :   long i, j, l, a, s, *lp;
    1450             : 
    1451           0 :   if (v)
    1452             :   {
    1453           0 :     char *t = gp_filter(v);
    1454           0 :     if (*t != '[' || t[strlen(t)-1] != ']')
    1455           0 :       pari_err(e_SYNTAX, "incorrect value for graphcolormap", t, t);
    1456           0 :     for (s = 0, p = t+1, l = 2, a=0; *p; p++)
    1457           0 :       if (*p == '[')
    1458             :       {
    1459           0 :         a++;
    1460           0 :         while (*++p != ']')
    1461           0 :           if (!*p || *p == '[')
    1462           0 :             pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
    1463             :       }
    1464           0 :       else if (*p == '"')
    1465             :       {
    1466           0 :         s += sizeof(long)+1;
    1467           0 :         while (*p && *++p != '"') s++;
    1468           0 :         if (!*p) pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
    1469           0 :         s = (s+sizeof(long)-1) & ~(sizeof(long)-1);
    1470             :       }
    1471           0 :       else if (*p == ',')
    1472           0 :         l++;
    1473           0 :     if (l < 4)
    1474           0 :       pari_err(e_MISC, "too few colors (< 4) in graphcolormap");
    1475           0 :     if (GP_DATA->colormap) pari_free(GP_DATA->colormap);
    1476           0 :     GP_DATA->colormap = (GEN)pari_malloc((l+4*a)*sizeof(long) + s);
    1477           0 :     GP_DATA->colormap[0] = evaltyp(t_VEC)|evallg(l);
    1478           0 :     for (p = t+1, i = 1, lp = GP_DATA->colormap+l; i < l; p++)
    1479           0 :       switch(*p)
    1480             :       {
    1481             :       case '"':
    1482           0 :         gel(GP_DATA->colormap, i) = lp;
    1483           0 :         q = ++p; while (*q != '"') q++;
    1484           0 :         *q = 0;
    1485           0 :         j = 1 + nchar2nlong(q-p+1);
    1486           0 :         lp[0] = evaltyp(t_STR)|evallg(j);
    1487           0 :         strncpy(GSTR(lp), p, q-p+1);
    1488           0 :         lp += j; p = q;
    1489           0 :         break;
    1490             :       case '[': {
    1491             :         const char *ap[3];
    1492           0 :         gel(GP_DATA->colormap, i) = lp;
    1493           0 :         lp[0] = evaltyp(t_VECSMALL)|_evallg(4);
    1494           0 :         for (ap[0] = ++p, j=0; *p && *p != ']'; p++)
    1495           0 :           if (*p == ',' && j<2) { *p++ = 0; ap[++j] = p; }
    1496           0 :         while (j<2) ap[++j] = "0";
    1497           0 :         if (j>2 || *p != ']')
    1498             :         {
    1499             :           char buf[100];
    1500           0 :           sprintf(buf, "incorrect value for graphcolormap[%ld]: ", i);
    1501           0 :           pari_err(e_SYNTAX, buf, p, t);
    1502             :         }
    1503           0 :         *p = '\0';
    1504           0 :         lp[1] = atocolor(ap[0]);
    1505           0 :         lp[2] = atocolor(ap[1]);
    1506           0 :         lp[3] = atocolor(ap[2]);
    1507           0 :         lp += 4;
    1508           0 :         break;
    1509             :       }
    1510             :       case ',':
    1511             :       case ']':
    1512           0 :         i++;
    1513           0 :         break;
    1514             :       default:
    1515           0 :         pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
    1516             :       }
    1517           0 :     pari_free(t);
    1518             :   }
    1519           0 :   if (flag == d_RETURN || flag == d_ACKNOWLEDGE)
    1520             :   {
    1521           0 :     GEN cols = cgetg(lg(GP_DATA->colormap), t_VEC);
    1522             :     long i;
    1523             : 
    1524           0 :     for (i = 1; i < lg(cols); i++)
    1525             :     {
    1526           0 :       GEN c = gel(GP_DATA->colormap, i);
    1527           0 :       if (typ(c) == t_STR)
    1528           0 :         gel(cols, i) = gcopy(c);
    1529             :       else
    1530           0 :         gel(cols, i) = vecsmall_to_vec(c);
    1531             :     }
    1532           0 :     if (flag == d_RETURN) return cols;
    1533           0 :     pari_printf("   graphcolormap = %Ps\n", cols);
    1534             :   }
    1535           0 :   return gnil;
    1536             : }
    1537             : 
    1538             : GEN
    1539           0 : sd_graphcolors(const char *v, long flag)
    1540             : {
    1541             :   long i, l;
    1542             :   char *p;
    1543             : 
    1544           0 :   if (v) {
    1545           0 :     char *t = gp_filter(v);
    1546           0 :     for (p = t+1, l=2; *p != ']'; p++)
    1547           0 :       if (*p == ',') l++;
    1548           0 :       else if (*p < '0' || *p > '9')
    1549           0 :         pari_err(e_SYNTAX, "incorrect value for graphcolors", p, t);
    1550           0 :     if (*++p) pari_err(e_SYNTAX, "incorrect value for graphcolors", p, t);
    1551           0 :     if (GP_DATA->graphcolors) pari_free(GP_DATA->graphcolors);
    1552           0 :     GP_DATA->graphcolors = cgetalloc(t_VECSMALL, l);
    1553           0 :     for (p = t+1, i=0; *p; p++)
    1554             :     {
    1555           0 :       long n = 0;
    1556           0 :       while (*p >= '0' && *p <= '9')
    1557             :       {
    1558           0 :         n *= 10;
    1559           0 :         n += *p-'0';
    1560           0 :         p++;
    1561             :       }
    1562           0 :       GP_DATA->graphcolors[++i] = n;
    1563             :     }
    1564           0 :     pari_free(t);
    1565             :   }
    1566           0 :   switch(flag)
    1567             :   {
    1568             :   case d_RETURN:
    1569           0 :     return vecsmall_to_vec(GP_DATA->graphcolors);
    1570             :   case d_ACKNOWLEDGE:
    1571           0 :     pari_printf("   graphcolors = %Ps\n", vecsmall_to_vec(GP_DATA->graphcolors));
    1572             :   }
    1573           0 :   return gnil;
    1574             : }
    1575             : 
    1576             : GEN
    1577           0 : sd_help(const char *v, long flag)
    1578             : {
    1579             :   const char *str;
    1580           0 :   if (v)
    1581             :   {
    1582           0 :     if (GP_DATA->secure)
    1583           0 :       pari_err(e_MISC,"[secure mode]: can't modify 'help' default (to %s)",v);
    1584           0 :     if (GP_DATA->help) pari_free((void*)GP_DATA->help);
    1585             : #ifndef _WIN32
    1586           0 :     GP_DATA->help = path_expand(v);
    1587             : #else
    1588             :     GP_DATA->help = pari_strdup(v);
    1589             : #endif
    1590             :   }
    1591           0 :   str = GP_DATA->help? GP_DATA->help: "none";
    1592           0 :   if (flag == d_RETURN) return strtoGENstr(str);
    1593           0 :   if (flag == d_ACKNOWLEDGE)
    1594           0 :     pari_printf("   help = \"%s\"\n", str);
    1595           0 :   return gnil;
    1596             : }
    1597             : 
    1598             : static GEN
    1599           0 : sd_prompt_set(const char *v, long flag, const char *how, char **p)
    1600             : {
    1601           0 :   if (v) {
    1602           0 :     if (*p) free(*p);
    1603           0 :     *p = pari_strdup(v);
    1604             :   }
    1605           0 :   if (flag == d_RETURN) return strtoGENstr(*p);
    1606           0 :   if (flag == d_ACKNOWLEDGE)
    1607           0 :     pari_printf("   prompt%s = \"%s\"\n", how, *p);
    1608           0 :   return gnil;
    1609             : }
    1610             : GEN
    1611           0 : sd_prompt(const char *v, long flag)
    1612           0 : { return sd_prompt_set(v, flag, "", &(GP_DATA->prompt)); }
    1613             : GEN
    1614           0 : sd_prompt_cont(const char *v, long flag)
    1615           0 : { return sd_prompt_set(v, flag, "_cont", &(GP_DATA->prompt_cont)); }
    1616             : 
    1617             : GEN
    1618           7 : sd_breakloop(const char *v, long flag)
    1619           7 : { return sd_toggle(v,flag,"breakloop", &(GP_DATA->breakloop)); }
    1620             : GEN
    1621         130 : sd_echo(const char *v, long flag)
    1622         130 : { return sd_toggle(v,flag,"echo", &(GP_DATA->echo)); }
    1623             : GEN
    1624           0 : sd_timer(const char *v, long flag)
    1625           0 : { return sd_toggle(v,flag,"timer", &(GP_DATA->chrono)); }
    1626             : GEN
    1627           0 : sd_recover(const char *v, long flag)
    1628           0 : { return sd_toggle(v,flag,"recover", &(GP_DATA->recover)); }
    1629             : 
    1630             : GEN
    1631           0 : sd_psfile(const char *v, long flag)
    1632           0 : { return sd_string(v, flag, "psfile", &current_psfile); }
    1633             : 
    1634             : GEN
    1635           0 : sd_lines(const char *v, long flag)
    1636           0 : { return sd_ulong(v,flag,"lines",&(GP_DATA->lim_lines), 0,LONG_MAX,NULL); }
    1637             : GEN
    1638           0 : sd_linewrap(const char *v, long flag)
    1639             : {
    1640           0 :   ulong old = GP_DATA->linewrap, n = GP_DATA->linewrap;
    1641           0 :   GEN z = sd_ulong(v,flag,"linewrap",&n, 0,LONG_MAX,NULL);
    1642           0 :   if (old)
    1643           0 :   { if (!n) resetout(1); }
    1644             :   else
    1645           0 :   { if (n) init_linewrap(n); }
    1646           0 :   GP_DATA->linewrap = n; return z;
    1647             : }
    1648             : 
    1649             : /* readline-specific defaults */
    1650             : GEN
    1651           0 : sd_readline(const char *v, long flag)
    1652             : {
    1653           0 :   const char *msg[] = {
    1654             :     "(bits 0x2/0x4 control matched-insert/arg-complete)", NULL};
    1655           0 :   ulong state = GP_DATA->readline_state;
    1656           0 :   GEN res = sd_ulong(v,flag,"readline", &GP_DATA->readline_state, 0, 7, msg);
    1657             : 
    1658           0 :   if (state != GP_DATA->readline_state)
    1659           0 :     (void)sd_toggle(GP_DATA->readline_state? "1": "0", d_SILENT, "readline", &(GP_DATA->use_readline));
    1660           0 :   return res;
    1661             : }
    1662             : GEN
    1663           0 : sd_histfile(const char *v, long flag)
    1664             : {
    1665           0 :   char *old = GP_DATA->histfile;
    1666           0 :   GEN r = sd_string(v, flag, "histfile", &GP_DATA->histfile);
    1667           0 :   if (v && !*v)
    1668             :   {
    1669           0 :     free(GP_DATA->histfile);
    1670           0 :     GP_DATA->histfile = NULL;
    1671             :   }
    1672           0 :   else if (GP_DATA->histfile != old && (!old || strcmp(old,GP_DATA->histfile)))
    1673             :   {
    1674           0 :     if (cb_pari_init_histfile) cb_pari_init_histfile();
    1675             :   }
    1676           0 :   return r;
    1677             : }
    1678             : 
    1679             : /********************************************************************/
    1680             : /**                                                                **/
    1681             : /**                         METACOMMANDS                           **/
    1682             : /**                                                                **/
    1683             : /********************************************************************/
    1684             : void
    1685           2 : pari_print_version(void)
    1686             : {
    1687           2 :   pari_sp av = avma;
    1688           2 :   char *buf, *ver = what_cc();
    1689           2 :   const char *date = paricfg_compiledate;
    1690             : 
    1691           2 :   pari_center(paricfg_version);
    1692           2 :   pari_center(paricfg_buildinfo);
    1693           2 :   buf = stack_malloc(strlen(date) +  32 + (ver? strlen(ver): 0));
    1694           2 :   if (ver) (void)sprintf(buf, "compiled: %s, %s", date, ver);
    1695           0 :   else     (void)sprintf(buf, "compiled: %s", date);
    1696           2 :   pari_center(buf);
    1697           2 :   sprintf(buf, "threading engine: %s",paricfg_mt_engine);
    1698           2 :   pari_center(buf);
    1699           2 :   ver = what_readline();
    1700           2 :   buf = stack_malloc(strlen(ver) + 64);
    1701           2 :   (void)sprintf(buf, "(readline %s, extended help%s enabled)", ver,
    1702           2 :                 has_ext_help()? "": " not");
    1703           2 :   pari_center(buf); avma = av;
    1704           2 : }
    1705             : 
    1706             : static int
    1707           7 : cmp_epname(void *E, GEN e, GEN f)
    1708             : {
    1709             :   (void)E;
    1710           7 :   return strcmp(((entree*)e)->name, ((entree*)f)->name);
    1711             : }
    1712             : static void
    1713           7 : print_all_user_fun(int member)
    1714             : {
    1715           7 :   pari_sp av = avma;
    1716           7 :   long iL = 0, lL = 1024;
    1717           7 :   GEN L = cgetg(lL+1, t_VECSMALL);
    1718             :   entree *ep;
    1719             :   int i;
    1720         952 :   for (i = 0; i < functions_tblsz; i++)
    1721        8694 :     for (ep = functions_hash[i]; ep; ep = ep->next)
    1722             :     {
    1723             :       const char *f;
    1724             :       int is_member;
    1725        7749 :       if (EpVALENCE(ep) != EpVAR || typ((GEN)ep->value)!=t_CLOSURE) continue;
    1726          14 :       f = ep->name;
    1727          14 :       is_member = (f[0] == '_' && f[1] == '.');
    1728          14 :       if (member != is_member) continue;
    1729             : 
    1730          14 :       if (iL >= lL)
    1731             :       {
    1732           0 :         GEN oL = L;
    1733             :         long j;
    1734           0 :         lL *= 2; L = cgetg(lL+1, t_VECSMALL);
    1735           0 :         for (j = 1; j <= iL; j++) gel(L,j) = gel(oL,j);
    1736             :       }
    1737          14 :       L[++iL] = (long)ep;
    1738             :     }
    1739           7 :   if (iL)
    1740             :   {
    1741           7 :     setlg(L, iL+1);
    1742           7 :     gen_sort_inplace(L, NULL, &cmp_epname, NULL);
    1743          21 :     for (i = 1; i <= iL; i++)
    1744             :     {
    1745          14 :       ep = (entree*)L[i];
    1746          14 :       pari_printf("%s =\n  %Ps\n\n", ep->name, ep->value);
    1747             :     }
    1748             :   }
    1749           7 :   avma = av;
    1750           7 : }
    1751             : 
    1752             : static void
    1753         323 : escape(const char *tch, int ismain)
    1754             : {
    1755         323 :   const char *s = tch;
    1756             :   char c;
    1757         323 :   switch ((c = *s++))
    1758             :   {
    1759             :     case 'w': case 'x': case 'a': case 'b': case 'B': case 'm':
    1760             :     { /* history things */
    1761             :       long d;
    1762             :       GEN x;
    1763           0 :       if (c != 'w' && c != 'x') d = get_int(s,0);
    1764             :       else
    1765             :       {
    1766           0 :         d = atol(s); if (*s == '-') s++;
    1767           0 :         while (isdigit((int)*s)) s++;
    1768             :       }
    1769           0 :       x = pari_get_hist(d);
    1770           0 :       switch (c)
    1771             :       {
    1772             :         case 'B': /* prettyprinter */
    1773           0 :           if (tex2mail_output(x,0)) break;
    1774             :         case 'b': /* fall through */
    1775           0 :         case 'm': matbrute(x, GP_DATA->fmt->format, -1); break;
    1776           0 :         case 'a': brute(x, GP_DATA->fmt->format, -1); break;
    1777           0 :         case 'x': dbgGEN(x, get_int(s, -1)); break;
    1778             :         case 'w':
    1779           0 :           s = get_sep(s); if (!*s) s = current_logfile;
    1780           0 :           write0(s, mkvec(x)); return;
    1781             :       }
    1782           0 :       pari_putc('\n'); return;
    1783             :     }
    1784             : 
    1785           0 :     case 'c': commands(-1); break;
    1786           0 :     case 'd': (void)setdefault(NULL,NULL,d_SILENT); break;
    1787             :     case 'e':
    1788         109 :       s = get_sep(s);
    1789         109 :       if (!*s) s = (GP_DATA->echo)? "0": "1";
    1790         109 :       (void)sd_echo(s,d_ACKNOWLEDGE); break;
    1791             :     case 'g':
    1792           7 :       switch (*s)
    1793             :       {
    1794           0 :         case 'm': s++; (void)sd_debugmem(*s? s: NULL,d_ACKNOWLEDGE); break;
    1795           0 :         case 'f': s++; (void)sd_debugfiles(*s? s: NULL,d_ACKNOWLEDGE); break;
    1796           7 :         default : (void)sd_debug(*s? s: NULL,d_ACKNOWLEDGE); break;
    1797             :       }
    1798           7 :       break;
    1799           0 :     case 'h': print_functions_hash(s); break;
    1800             :     case 'l':
    1801           0 :       s = get_sep(s);
    1802           0 :       if (*s)
    1803             :       {
    1804           0 :         (void)sd_logfile(s,d_ACKNOWLEDGE);
    1805           0 :         if (pari_logfile) break;
    1806             :       }
    1807           0 :       (void)sd_log(pari_logfile?"0":"1",d_ACKNOWLEDGE);
    1808           0 :       break;
    1809           0 :     case 'o': (void)sd_output(*s? s: NULL,d_ACKNOWLEDGE); break;
    1810             :     case 'p':
    1811         193 :       switch (*s)
    1812             :       {
    1813           0 :         case 's': s++;
    1814           0 :           (void)sd_seriesprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
    1815           7 :         case 'b' : s++;
    1816           7 :           (void)sd_realbitprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
    1817             :         default :
    1818         186 :           (void)sd_realprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
    1819             :       }
    1820         193 :       break;
    1821           0 :     case 'q': cb_pari_quit(0); break;
    1822             :     case 'r':
    1823           0 :       s = get_sep(s);
    1824           0 :       if (!ismain) { (void)gp_read_file(s); break; }
    1825           0 :       switchin(s);
    1826           0 :       if (file_is_binary(pari_infile))
    1827             :       {
    1828             :         int vector;
    1829           0 :         GEN x = readbin(s,pari_infile, &vector);
    1830           0 :         popinfile();
    1831           0 :         if (!x) pari_err_FILE("input file",s);
    1832           0 :         if (vector) /* many BIN_GEN */
    1833             :         {
    1834           0 :           long i, l = lg(x);
    1835           0 :           pari_warn(warner,"setting %ld history entries", l-1);
    1836           0 :           for (i=1; i<l; i++) pari_add_hist(gel(x,i), 0);
    1837             :         }
    1838             :       }
    1839           0 :       break;
    1840           0 :     case 's': dbg_pari_heap(); break;
    1841           7 :     case 't': gentypes(); break;
    1842             :     case 'u':
    1843           7 :       print_all_user_fun((*s == 'm')? 1: 0);
    1844           7 :       break;
    1845           0 :     case 'v': pari_print_version(); break;
    1846             :     case 'y':
    1847           0 :       s = get_sep(s);
    1848           0 :       if (!*s) s = (GP_DATA->simplify)? "0": "1";
    1849           0 :       (void)sd_simplify(s,d_ACKNOWLEDGE); break;
    1850           0 :     default: pari_err(e_SYNTAX,"unexpected character", tch,tch-1);
    1851             :   }
    1852             : }
    1853             : 
    1854             : static int
    1855         144 : chron(const char *s)
    1856             : {
    1857         144 :   if (*s)
    1858             :   { /* if "#" or "##" timer metacommand. Otherwise let the parser get it */
    1859             :     const char *t;
    1860         144 :     if (*s == '#') s++;
    1861         144 :     if (*s) return 0;
    1862           0 :     t = gp_format_time(pari_get_histtime(0));
    1863           0 :     pari_printf("  ***   last result computed in %s", t);
    1864             :   }
    1865           0 :   else { GP_DATA->chrono ^= 1; (void)sd_timer(NULL,d_ACKNOWLEDGE); }
    1866           0 :   return 1;
    1867             : }
    1868             : 
    1869             : /* return 0: can't interpret *buf as a metacommand
    1870             :  *        1: did interpret *buf as a metacommand or empty command */
    1871             : int
    1872       84246 : gp_meta(const char *buf, int ismain)
    1873             : {
    1874       84246 :   switch(*buf++)
    1875             :   {
    1876         141 :     case '?': gp_help(buf, h_REGULAR); break;
    1877         144 :     case '#': return chron(buf);
    1878         323 :     case '\\': escape(buf, ismain); break;
    1879       11991 :     case '\0': break;
    1880       71647 :     default: return 0;
    1881             :   }
    1882       12455 :   return 1;
    1883             : }

Generated by: LCOV version 1.11