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

Generated by: LCOV version 2.0-1