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-bordeaux1.fr machine (x86_64 architecture), and agregate them in the final report:

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

LCOV - code coverage report
Current view: top level - gp - gp.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.8.0 lcov report (development 16624-25b9976) Lines: 521 1294 40.3 %
Date: 2014-06-24 Functions: 54 125 43.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 276 942 29.3 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (C) 2000  The PARI group.
       2                 :            : 
       3                 :            : This file is part of the PARI/GP package.
       4                 :            : 
       5                 :            : PARI/GP is free software; you can redistribute it and/or modify it under the
       6                 :            : terms of the GNU General Public License as published by the Free Software
       7                 :            : Foundation. It is distributed in the hope that it will be useful, but WITHOUT
       8                 :            : ANY WARRANTY WHATSOEVER.
       9                 :            : 
      10                 :            : Check the License for details. You should have received a copy of it, along
      11                 :            : with the package; see the file 'COPYING'. If not, write to the Free Software
      12                 :            : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13                 :            : 
      14                 :            : /*******************************************************************/
      15                 :            : /**                                                               **/
      16                 :            : /**                        PARI CALCULATOR                        **/
      17                 :            : /**                                                               **/
      18                 :            : /*******************************************************************/
      19                 :            : #include "pari.h"
      20                 :            : #include "paripriv.h"
      21                 :            : #include "gp.h"
      22                 :            : 
      23                 :            : #ifdef _WIN32
      24                 :            : #  include <windows.h>
      25                 :            : #  include "../systems/mingw/mingw.h"
      26                 :            : #  ifndef WINCE
      27                 :            : #    include <process.h>
      28                 :            : #  endif
      29                 :            : #endif
      30                 :            : 
      31                 :            : /********************************************************************/
      32                 :            : /**                                                                **/
      33                 :            : /**                            STRINGS                             **/
      34                 :            : /**                                                                **/
      35                 :            : /********************************************************************/
      36                 :            : 
      37                 :            : static void
      38                 :         20 : skip_space(char **s) {
      39                 :         20 :   char *t = *s;
      40         [ -  + ]:         20 :   while (isspace((int)*t)) t++;
      41                 :         20 :   *s = t;
      42                 :         20 : }
      43                 :            : static void
      44                 :          5 : skip_alpha(char **s) {
      45                 :          5 :   char *t = *s;
      46         [ -  + ]:          5 :   while (isalpha((int)*t)) t++;
      47                 :          5 :   *s = t;
      48                 :          5 : }
      49                 :            : 
      50                 :            : static char *
      51                 :          0 : translate(char **src, char *s, char *entry)
      52                 :            : {
      53                 :          0 :   char *t = *src;
      54         [ #  # ]:          0 :   while (*t)
      55                 :            :   {
      56         [ #  # ]:          0 :     while (*t == '\\')
      57                 :            :     {
      58   [ #  #  #  # ]:          0 :       switch(*++t)
      59                 :            :       {
      60                 :          0 :         case 'e':  *s='\033'; break; /* escape */
      61                 :          0 :         case 'n':  *s='\n'; break;
      62                 :          0 :         case 't':  *s='\t'; break;
      63                 :          0 :         default:   *s=*t;
      64         [ #  # ]:          0 :                    if (!*t) pari_err(e_SYNTAX,"unfinished string",s,entry);
      65                 :            :       }
      66                 :          0 :       t++; s++;
      67                 :            :     }
      68         [ #  # ]:          0 :     if (*t == '"')
      69                 :            :     {
      70         [ #  # ]:          0 :       if (t[1] != '"') break;
      71                 :          0 :       t += 2; continue;
      72                 :            :     }
      73                 :          0 :     *s++ = *t++;
      74                 :            :   }
      75                 :          0 :   *s=0; *src=t; return s;
      76                 :            : }
      77                 :            : 
      78                 :            : static void
      79                 :          0 : matchQ(char *s, char *entry)
      80                 :            : {
      81         [ #  # ]:          0 :   if (*s != '"')
      82                 :          0 :     pari_err(e_SYNTAX,"expected character: '\"' instead of",s,entry);
      83                 :          0 : }
      84                 :            : 
      85                 :            : /*  Read a "string" from src. Format then copy it, starting at s. Return
      86                 :            :  *  pointer to char following the end of the input string */
      87                 :            : static char *
      88                 :          0 : readstring(char *src, char *s, char *entry)
      89                 :            : {
      90                 :          0 :   matchQ(src, entry); src++; s = translate(&src, s, entry);
      91                 :          0 :   matchQ(src, entry); return src+1;
      92                 :            : }
      93                 :            : /*******************************************************************/
      94                 :            : /**                                                               **/
      95                 :            : /**                    TEXMACS-SPECIFIC STUFF                     **/
      96                 :            : /**                                                               **/
      97                 :            : /*******************************************************************/
      98                 :            : static int tm_is_waiting = 0, tm_did_complete = 0;
      99                 :            : 
     100                 :            : /* tell TeXmacs GP will start outputing data */
     101                 :            : static void
     102                 :          0 : tm_start_output(void)
     103                 :            : {
     104         [ #  # ]:          0 :   if (!tm_is_waiting) { printf("%cverbatim:",DATA_BEGIN); fflush(stdout); }
     105                 :          0 :   tm_is_waiting = 1;
     106                 :          0 : }
     107                 :            : /* tell TeXmacs GP is done and is waiting for new data */
     108                 :            : static void
     109                 :          0 : tm_end_output(void)
     110                 :            : {
     111         [ #  # ]:          0 :   if (tm_is_waiting) { printf("%c", DATA_END); fflush(stdout); }
     112                 :          0 :   tm_is_waiting = 0;
     113                 :          0 : }
     114                 :            : static char *
     115                 :          0 : fgets_texmacs(char *s, int n, FILE *f)
     116                 :            : {
     117         [ #  # ]:          0 :   if (!tm_did_complete)
     118                 :            :   {
     119                 :          0 :     tm_start_output(); tm_end_output(); /* tell TeXmacs we need input */
     120                 :            :   }
     121                 :          0 :   return fgets(s,n,f);
     122                 :            : }
     123                 :            : 
     124                 :            : #ifdef READLINE
     125                 :            : typedef struct {
     126                 :            :   char *cmd;
     127                 :            :   long n; /* number of args */
     128                 :            :   char **v; /* args */
     129                 :            : } tm_cmd;
     130                 :            : 
     131                 :            : static void
     132                 :          0 : parse_texmacs_command(tm_cmd *c, const char *ch)
     133                 :            : {
     134                 :          0 :   long l = strlen(ch);
     135                 :          0 :   char *t, *s = (char*)ch, *send = s+l-1;
     136                 :            :   char **A;
     137                 :            :   pari_stack s_A;
     138                 :            : 
     139 [ #  # ][ #  # ]:          0 :   if (*s != DATA_BEGIN || *send-- != DATA_END)
     140                 :          0 :     pari_err(e_MISC, "missing DATA_[BEGIN | END] in TeXmacs command");
     141                 :          0 :   s++;
     142         [ #  # ]:          0 :   if (strncmp(s, "special:", 8)) pari_err(e_MISC, "unrecognized TeXmacs command");
     143                 :          0 :   s += 8;
     144 [ #  # ][ #  # ]:          0 :   if (*s != '(' || *send-- != ')')
     145                 :          0 :     pari_err(e_MISC, "missing enclosing parentheses for TeXmacs command");
     146                 :          0 :   s++; t = s;
     147                 :          0 :   skip_alpha(&s);
     148                 :          0 :   c->cmd = pari_strndup(t, s - t);
     149                 :          0 :   pari_stack_init(&s_A,sizeof(*A),(void**)&A);
     150         [ #  # ]:          0 :   for (c->n = 0; s <= send; c->n++)
     151                 :            :   {
     152                 :          0 :     char *u = (char*)pari_malloc(strlen(s) + 1);
     153                 :          0 :     skip_space(&s);
     154         [ #  # ]:          0 :     if (*s == '"') s = readstring(s, u, t);
     155                 :            :     else
     156                 :            :     { /* read integer */
     157                 :          0 :       t = s;
     158         [ #  # ]:          0 :       while (isdigit((int)*s)) s++;
     159                 :          0 :       strncpy(u, t, s - t); u[s-t] = 0;
     160                 :            :     }
     161                 :          0 :     pari_stack_pushp(&s_A, u);
     162                 :            :   }
     163                 :          0 :   c->v = A;
     164                 :          0 : }
     165                 :            : 
     166                 :            : static void
     167                 :          0 : free_cmd(tm_cmd *c)
     168                 :            : {
     169         [ #  # ]:          0 :   while (c->n--) pari_free((void*)c->v[c->n]);
     170                 :          0 :   pari_free((void*)c->v);
     171                 :          0 : }
     172                 :            : 
     173                 :            : static void
     174                 :          0 : handle_texmacs_command(const char *s)
     175                 :            : {
     176                 :            :   tm_cmd c;
     177                 :          0 :   parse_texmacs_command(&c, s);
     178         [ #  # ]:          0 :   if (strcmp(c.cmd, "complete"))
     179                 :          0 :     pari_err(e_MISC,"Texmacs_stdin command %s not implemented", c.cmd);
     180         [ #  # ]:          0 :   if (c.n != 2)
     181                 :          0 :     pari_err(e_MISC,"was expecting 2 arguments for Texmacs_stdin command");
     182                 :          0 :   texmacs_completion(c.v[0], atol(c.v[1]));
     183                 :          0 :   free_cmd(&c);
     184                 :          0 :   tm_did_complete = 1;
     185                 :          0 : }
     186                 :            : #else
     187                 :            : static void
     188                 :            : handle_texmacs_command(const char *s)
     189                 :            : { (void)s;pari_err(e_MISC, "readline not available"); }
     190                 :            : #endif
     191                 :            : 
     192                 :            : /*******************************************************************/
     193                 :            : /**                                                               **/
     194                 :            : /**                          BUFFERS                              **/
     195                 :            : /**                                                               **/
     196                 :            : /*******************************************************************/
     197                 :            : static Buffer **bufstack;
     198                 :            : static pari_stack s_bufstack;
     199                 :            : 
     200                 :            : static void
     201                 :        894 : pop_buffer(void)
     202                 :            : {
     203         [ +  - ]:        894 :   if (s_bufstack.n)
     204                 :        894 :     delete_buffer( bufstack[ --s_bufstack.n ] );
     205                 :        894 : }
     206                 :            : 
     207                 :            : /* kill all buffers until B is met or nothing is left */
     208                 :            : static void
     209                 :       2780 : kill_buffers_upto(Buffer *B)
     210                 :            : {
     211         [ +  + ]:       3634 :   while (s_bufstack.n) {
     212         [ +  + ]:       2785 :     if (bufstack[ s_bufstack.n-1 ] == B) break;
     213                 :        854 :     pop_buffer();
     214                 :            :   }
     215                 :       2780 : }
     216                 :            : static void
     217                 :          0 : kill_buffers_upto_including(Buffer *B)
     218                 :            : {
     219         [ #  # ]:          0 :   while (s_bufstack.n) {
     220         [ #  # ]:          0 :     if (bufstack[ s_bufstack.n-1 ] == B) { pop_buffer(); break; }
     221                 :          0 :     pop_buffer();
     222                 :            :   }
     223                 :          0 : }
     224                 :            : 
     225                 :            : /********************************************************************/
     226                 :            : /**                                                                **/
     227                 :            : /**                             HELP                               **/
     228                 :            : /**                                                                **/
     229                 :            : /********************************************************************/
     230                 :            : static int disable_exception_handler = 0;
     231                 :            : #define BLOCK_EH_START                \
     232                 :            : {                                     \
     233                 :            :   int block=disable_exception_handler;\
     234                 :            :   disable_exception_handler = 1;
     235                 :            : 
     236                 :            : #define BLOCK_EH_END                \
     237                 :            :   disable_exception_handler = block;\
     238                 :            : }
     239                 :            : static char *Help;
     240                 :            : 
     241                 :            : static char *
     242                 :        913 : init_help(void)
     243                 :            : {
     244                 :        913 :   char *h = os_getenv("GPHELP");
     245                 :            : # ifdef GPHELP
     246         [ +  - ]:        913 :   if (!h) h = (char*)GPHELP;
     247                 :            : # endif
     248                 :            : #ifdef _WIN32
     249                 :            :   win32_set_pdf_viewer();
     250                 :            : #endif
     251         [ +  - ]:        913 :   if (h) h = pari_strdup(h);
     252                 :        913 :   return h;
     253                 :            : }
     254                 :            : 
     255                 :            : static void
     256                 :          0 : hit_return(void)
     257                 :            : {
     258                 :            :   int c;
     259         [ #  # ]:          0 :   if (GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS)) return;
     260                 :          0 :   BLOCK_EH_START
     261                 :          0 :   pari_puts("/*-- (type RETURN to continue) --*/");
     262                 :          0 :   pari_flush();
     263                 :            :   /* if called from a readline callback, may be in a funny TTY mode */
     264 [ #  # ][ #  # ]:          0 :   do c = fgetc(stdin); while (c >= 0 && c != '\n' && c != '\r');
                 [ #  # ]
     265                 :          0 :   pari_putc('\n');
     266                 :          0 :   BLOCK_EH_END
     267                 :            : }
     268                 :            : static void
     269                 :          0 : gp_ask_confirm(const char *s)
     270                 :            : {
     271                 :          0 :   err_printf(s);
     272                 :          0 :   err_printf(". OK ? (^C if not)\n");
     273                 :          0 :   hit_return();
     274                 :          0 : }
     275                 :            : 
     276                 :            : static int
     277 [ +  - ][ +  - ]:          5 : has_ext_help(void) { return (Help && *Help); }
     278                 :            : 
     279                 :            : static int
     280                 :        110 : compare_str(char **s1, char **s2) { return strcmp(*s1, *s2); }
     281                 :            : 
     282                 :            : /* Print all elements of list in columns, pausing every nbli lines
     283                 :            :  * if nbli is non-zero.
     284                 :            :  * list is a NULL terminated list of function names
     285                 :            :  */
     286                 :            : void
     287                 :          5 : print_fun_list(char **list, long nbli)
     288                 :            : {
     289                 :          5 :   long i=0, j=0, maxlen=0, nbcol,len, w = term_width();
     290                 :            :   char **l;
     291                 :            : 
     292         [ +  + ]:         55 :   while (list[i]) i++;
     293                 :          5 :   qsort (list, i, sizeof(char *), (QSCOMP)compare_str);
     294                 :            : 
     295         [ +  + ]:         55 :   for (l=list; *l; l++)
     296                 :            :   {
     297                 :         50 :     len = strlen(*l);
     298         [ +  + ]:         50 :     if (len > maxlen) maxlen=len;
     299                 :            :   }
     300                 :          5 :   maxlen++; nbcol= w / maxlen;
     301         [ -  + ]:          5 :   if (nbcol * maxlen == w) nbcol--;
     302         [ -  + ]:          5 :   if (!nbcol) nbcol = 1;
     303                 :            : 
     304                 :          5 :   pari_putc('\n'); i=0;
     305         [ +  + ]:         55 :   for (l=list; *l; l++)
     306                 :            :   {
     307                 :         50 :     pari_puts(*l); i++;
     308         [ +  + ]:         50 :     if (i >= nbcol)
     309                 :            :     {
     310                 :          5 :       i=0; pari_putc('\n');
     311 [ +  - ][ -  + ]:          5 :       if (nbli && j++ > nbli) { j = 0; hit_return(); }
     312                 :          5 :       continue;
     313                 :            :     }
     314                 :         45 :     len = maxlen - strlen(*l);
     315         [ +  + ]:        235 :     while (len--) pari_putc(' ');
     316                 :            :   }
     317         [ +  - ]:          5 :   if (i) pari_putc('\n');
     318                 :          5 : }
     319                 :            : 
     320                 :            : static const long MAX_SECTION = 12;
     321                 :            : static void
     322                 :          5 : commands(long n)
     323                 :            : {
     324                 :            :   long i;
     325                 :            :   entree *ep;
     326                 :            :   char **t_L;
     327                 :            :   pari_stack s_L;
     328                 :            : 
     329                 :          5 :   pari_stack_init(&s_L, sizeof(*t_L), (void**)&t_L);
     330         [ +  + ]:        680 :   for (i = 0; i < functions_tblsz; i++)
     331         [ +  + ]:       4700 :     for (ep = functions_hash[i]; ep; ep = ep->next)
     332                 :            :     {
     333                 :            :       long m;
     334      [ +  +  + ]:       4025 :       switch (EpVALENCE(ep))
     335                 :            :       {
     336                 :            :         case EpVAR:
     337         [ +  + ]:         10 :           if (typ((GEN)ep->value) == t_CLOSURE) break;
     338                 :            :           /* fall through */
     339                 :         10 :         case EpNEW: continue;
     340                 :            :       }
     341                 :       4015 :       m = ep->menu;
     342 [ +  + ][ -  + ]:       4015 :       if (m == n || (n < 0 && m && m <= MAX_SECTION))
         [ #  # ][ #  # ]
     343                 :         50 :         pari_stack_pushp(&s_L, (void*)ep->name);
     344                 :            :     }
     345                 :          5 :   pari_stack_pushp(&s_L, NULL);
     346                 :          5 :   print_fun_list(t_L, term_height()-4);
     347                 :          5 :   pari_stack_delete(&s_L);
     348                 :          5 : }
     349                 :            : 
     350                 :            : static void
     351                 :          0 : center(const char *s)
     352                 :            : {
     353                 :          0 :   long i, l = strlen(s), pad = term_width() - l;
     354                 :            :   char *buf, *u;
     355                 :            : 
     356         [ #  # ]:          0 :   if (pad<0) pad=0; else pad >>= 1;
     357                 :          0 :   u = buf = (char*)pari_malloc(l + pad + 2);
     358         [ #  # ]:          0 :   for (i=0; i<pad; i++) *u++ = ' ';
     359         [ #  # ]:          0 :   while (*s) *u++ = *s++;
     360                 :          0 :   *u++ = '\n'; *u = 0;
     361                 :          0 :   pari_puts(buf); pari_free(buf);
     362                 :          0 : }
     363                 :            : 
     364                 :            : static void
     365                 :          0 : usage(char *s)
     366                 :            : {
     367                 :          0 :   printf("### Usage: %s [options] [GP files]\n", s);
     368                 :          0 :   printf("Available options:\n");
     369                 :          0 :   printf("  [-f,--fast]\t\tFast start: do not read .gprc\n");
     370                 :          0 :   printf("  [-q,--quiet]\t\tQuiet mode: do not print banner and history numbers\n");
     371                 :          0 :   printf("  [-s stacksize]\tStart with the PARI stack of given size (in bytes)\n");
     372                 :          0 :   printf("  [--default key=val]\tExecute default(key,val) on startup\n");
     373                 :          0 :   printf("  [--emacs]\t\tRun as if in Emacs shell\n");
     374                 :          0 :   printf("  [--help]\t\tPrint this message\n");
     375                 :          0 :   printf("  [--test]\t\tTest mode. No history, wrap long lines (bench only)\n");
     376                 :          0 :   printf("  [--texmacs]\t\tRun as if using TeXmacs frontend\n");
     377                 :          0 :   printf("  [--version]\t\tOutput version info and exit\n");
     378                 :          0 :   printf("  [--version-short]\tOutput version number and exit\n\n");
     379                 :          0 :   exit(0);
     380                 :            : }
     381                 :            : 
     382                 :            : static void
     383                 :          0 : community(void)
     384                 :            : {
     385                 :          0 :   print_text("The PARI/GP distribution includes a reference manual, a \
     386                 :            : tutorial, a reference card and quite a few examples. They have been installed \
     387                 :            : in the directory ");
     388                 :          0 :   pari_puts("  ");
     389                 :          0 :   pari_puts(pari_datadir);
     390                 :          0 :   pari_puts("\nYou can also download them from http://pari.math.u-bordeaux.fr/.\
     391                 :            : \n\nThree mailing lists are devoted to PARI:\n\
     392                 :            :   - pari-announce (moderated) to announce major version changes.\n\
     393                 :            :   - pari-dev for everything related to the development of PARI, including\n\
     394                 :            :     suggestions, technical questions, bug reports and patch submissions.\n\
     395                 :            :   - pari-users for everything else!\n\
     396                 :            : To subscribe, send an empty message to\n\
     397                 :            :   <pari_list_name>-request@pari.math.u-bordeaux.fr\n\
     398                 :            : with a Subject: field containing the word 'subscribe'.\n\n");
     399                 :          0 :   print_text("An archive is kept at the WWW site mentioned above. You can also \
     400                 :            : reach the authors at pari@math.u-bordeaux.fr (answer not guaranteed)."); }
     401                 :            : 
     402                 :            : static void
     403                 :          5 : gentypes(void)
     404                 :            : {
     405                 :          5 :   pari_puts("List of the PARI types:\n\
     406                 :            :   t_INT    : long integers     [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     407                 :            :   t_REAL   : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     408                 :            :   t_INTMOD : integermods       [ code ] [ mod  ] [ integer ]\n\
     409                 :            :   t_FRAC   : irred. rationals  [ code ] [ num. ] [ den. ]\n\
     410                 :            :   t_FFELT  : finite field elt. [ code ] [ cod2 ] [ elt ] [ mod ] [ p ]\n\
     411                 :            :   t_COMPLEX: complex numbers   [ code ] [ real ] [ imag ]\n\
     412                 :            :   t_PADIC  : p-adic numbers    [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ]\n\
     413                 :            :   t_QUAD   : quadratic numbers [ cod1 ] [ mod  ] [ real ] [ imag ]\n\
     414                 :            :   t_POLMOD : poly mod          [ code ] [ mod  ] [ polynomial ]\n\
     415                 :            :   -------------------------------------------------------------\n\
     416                 :            :   t_POL    : polynomials       [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     417                 :            :   t_SER    : power series      [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\
     418                 :            :   t_RFRAC  : irred. rat. func. [ code ] [ num. ] [ den. ]\n\
     419                 :            :   t_QFR    : real qfb          [ code ] [ a ] [ b ] [ c ] [ del ]\n\
     420                 :            :   t_QFI    : imaginary qfb     [ code ] [ a ] [ b ] [ c ]\n\
     421                 :            :   t_VEC    : row vector        [ code ] [  x_1  ] ... [  x_k  ]\n\
     422                 :            :   t_COL    : column vector     [ code ] [  x_1  ] ... [  x_k  ]\n\
     423                 :            :   t_MAT    : matrix            [ code ] [ col_1 ] ... [ col_k ]\n\
     424                 :            :   t_LIST   : list              [ code ] [ n ] [ nmax ][ vec ]\n\
     425                 :            :   t_STR    : string            [ code ] [ man_1 ] ... [ man_k ]\n\
     426                 :            :   t_VECSMALL: vec. small ints  [ code ] [ x_1 ] ... [ x_k ]\n\
     427                 :            :   t_CLOSURE: functions [ code ] [ arity ] [ code ] [ operand ] [ data ] [ text ]\n\
     428                 :            :   t_ERROR  : error context     [ code ] [ errnum ] [ dat_1 ] ... [ dat_k ]\n\
     429                 :            :   t_INFINITY: a*infinity       [ code ] [ a ]\n\
     430                 :            : \n");
     431                 :          5 : }
     432                 :            : 
     433                 :            : static void
     434                 :          5 : menu_commands(void)
     435                 :            : {
     436                 :          5 :   pari_puts("Help topics: for a list of relevant subtopics, type ?n for n in\n\
     437                 :            :   0: user-defined functions (aliases, installed and user functions)\n\
     438                 :            :   1: Standard monadic or dyadic OPERATORS\n\
     439                 :            :   2: CONVERSIONS and similar elementary functions\n\
     440                 :            :   3: TRANSCENDENTAL functions\n\
     441                 :            :   4: NUMBER THEORETICAL functions\n\
     442                 :            :   5: Functions related to ELLIPTIC CURVES\n\
     443                 :            :   6: Functions related to MODULAR FORMS and MODULAR SYMBOLS\n\
     444                 :            :   7: Functions related to general NUMBER FIELDS\n\
     445                 :            :   8: POLYNOMIALS and power series\n\
     446                 :            :   9: Vectors, matrices, LINEAR ALGEBRA and sets\n\
     447                 :            :  10: SUMS, products, integrals and similar functions\n\
     448                 :            :  11: GRAPHIC functions\n\
     449                 :            :  12: PROGRAMMING under GP\n\
     450                 :            :  13: The PARI community\n\
     451                 :            : \n\
     452                 :            : Also:\n\
     453                 :            :   ? functionname (short on-line help)\n\
     454                 :            :   ?\\             (keyboard shortcuts)\n\
     455                 :            :   ?.             (member functions)\n");
     456         [ +  - ]:          5 :   if (has_ext_help()) pari_puts("\
     457                 :            : Extended help (if available):\n\
     458                 :            :   ??             (opens the full user's manual in a dvi previewer)\n\
     459                 :            :   ??  tutorial / refcard / libpari (tutorial/reference card/libpari manual)\n\
     460                 :            :   ??  keyword    (long help text about \"keyword\" from the user's manual)\n\
     461                 :            :   ??? keyword    (a propos: list of related functions).");
     462                 :          5 : }
     463                 :            : 
     464                 :            : static void
     465                 :          5 : slash_commands(void)
     466                 :            : {
     467                 :          5 :   pari_puts("#       : enable/disable timer\n\
     468                 :            : ##      : print time for last result\n\
     469                 :            : \\\\      : comment up to end of line\n\
     470                 :            : \\a {n}  : print result in raw format (readable by PARI)\n\
     471                 :            : \\B {n}  : print result in beautified format\n\
     472                 :            : \\c      : list all commands (same effect as ?*)\n\
     473                 :            : \\d      : print all defaults\n\
     474                 :            : \\e {n}  : enable/disable echo (set echo=n)\n\
     475                 :            : \\g {n}  : set debugging level\n\
     476                 :            : \\gf{n}  : set file debugging level\n\
     477                 :            : \\gm{n}  : set memory debugging level\n\
     478                 :            : \\h {m-n}: hashtable information\n\
     479                 :            : \\l {f}  : enable/disable logfile (set logfile=f)\n\
     480                 :            : \\m {n}  : print result in prettymatrix format\n\
     481                 :            : \\o {n}  : set output method (0=raw, 1=prettymatrix, 2=prettyprint, 3=2-dim)\n\
     482                 :            : \\p {n}  : change real precision\n\
     483                 :            : \\ps{n}  : change series precision\n\
     484                 :            : \\q      : quit completely this GP session\n\
     485                 :            : \\r {f}  : read in a file\n\
     486                 :            : \\s      : print stack information\n\
     487                 :            : \\t      : print the list of PARI types\n\
     488                 :            : \\u      : print the list of user-defined functions\n\
     489                 :            : \\um     : print the list of user-defined member functions\n\
     490                 :            : \\v      : print current version of GP\n\
     491                 :            : \\w {nf} : write to a file\n\
     492                 :            : \\x {n}  : print complete inner structure of result\n\
     493                 :            : \\y {n}  : disable/enable automatic simplification (set simplify=n)\n\
     494                 :            : \n\
     495                 :            : {f}=optional filename. {n}=optional integer\n");
     496                 :          5 : }
     497                 :            : 
     498                 :            : static void
     499                 :          5 : member_commands(void)
     500                 :            : {
     501                 :          5 :   pari_puts("\
     502                 :            : Member functions, followed by relevant objects\n\n\
     503                 :            : a1-a6, b2-b8, c4-c6 : coeff. of the curve.         ell\n\
     504                 :            : area : area                                        ell\n\
     505                 :            : bid  : big ideal                     bid,                     bnr\n\
     506                 :            : bnf  : big number field                                   bnf,bnr\n\
     507                 :            : clgp : class group                   bid,                 bnf,bnr\n\
     508                 :            : cyc  : cyclic decomposition (SNF)    bid,     clgp,ell,   bnf,bnr\n\
     509                 :            : diff, codiff: different and codifferent                nf,bnf,bnr\n\
     510                 :            : disc : discriminant                                ell,nf,bnf,bnr,rnf\n\
     511                 :            : e, f : inertia/residue  degree           prid\n\
     512                 :            : fu   : fundamental units                                  bnf,bnr\n\
     513                 :            : gen  : generators                    bid,prid,clgp,ell,   bnf,bnr,    gal\n\
     514                 :            : group: group                                       ell,          ,rnf,gal\n\
     515                 :            : index: index                                           nf,bnf,bnr\n\
     516                 :            : j    : j-invariant                                 ell\n");
     517                 :            : /* split: some compilers can't handle long constant strings */
     518                 :          5 :   pari_puts("\
     519                 :            : mod  : modulus                       bid,                     bnr,    gal\n\
     520                 :            : nf   : number field                                    nf,bnf,bnr,rnf\n\
     521                 :            : no   : number of elements            bid,     clgp,ell,   bnf,bnr\n\
     522                 :            : omega, eta: [w1,w2] and [eta1, eta2]               ell\n\
     523                 :            : orders: relative orders of generators                                 gal\n\
     524                 :            : p    : rational prime                    prid,     ell,           rnf,gal\n\
     525                 :            : pol  : defining polynomial                             nf,bnf,bnr,    gal\n\
     526                 :            : polabs: defining polynomial over Q                                rnf\n\
     527                 :            : reg  : regulator                                          bnf,bnr\n\
     528                 :            : roots: roots                                       ell,nf,bnf,bnr,    gal\n\
     529                 :            : sign,r1,r2 : signature                                 nf,bnf,bnr\n\
     530                 :            : t2   : t2 matrix                                       nf,bnf,bnr\n\
     531                 :            : tate : Tate's [u^2, u, q, [a,b]]                   ell\n\
     532                 :            : tu   : torsion unit and its order                         bnf,bnr\n\
     533                 :            : zk   : integral basis                                  nf,bnf,bnr,rnf\n\
     534                 :            : zkst : structure of (Z_K/m)*         bid,                     bnr\n");
     535                 :          5 : }
     536                 :            : 
     537                 :            : #define QUOTE "_QUOTE"
     538                 :            : #define DOUBQUOTE "_DOUBQUOTE"
     539                 :            : #define BACKQUOTE "_BACKQUOTE"
     540                 :            : 
     541                 :            : static char *
     542                 :          0 : _cat(char *s, const char *t)
     543                 :            : {
     544                 :          0 :   *s = 0; strcat(s,t); return s + strlen(t);
     545                 :            : }
     546                 :            : 
     547                 :            : static char *
     548                 :          0 : filter_quotes(const char *s)
     549                 :            : {
     550                 :          0 :   int i, l = strlen(s);
     551                 :          0 :   int quote = 0;
     552                 :          0 :   int backquote = 0;
     553                 :          0 :   int doubquote = 0;
     554                 :            :   char *str, *t;
     555                 :            : 
     556         [ #  # ]:          0 :   for (i=0; i < l; i++)
     557   [ #  #  #  # ]:          0 :     switch(s[i])
     558                 :            :     {
     559                 :          0 :       case '\'': quote++; break;
     560                 :          0 :       case '`' : backquote++; break;
     561                 :          0 :       case '"' : doubquote++;
     562                 :            :     }
     563                 :          0 :   str = (char*)pari_malloc(l + quote * (strlen(QUOTE)-1)
     564                 :          0 :                           + doubquote * (strlen(DOUBQUOTE)-1)
     565                 :          0 :                           + backquote * (strlen(BACKQUOTE)-1) + 1);
     566                 :          0 :   t = str;
     567         [ #  # ]:          0 :   for (i=0; i < l; i++)
     568   [ #  #  #  # ]:          0 :     switch(s[i])
     569                 :            :     {
     570                 :          0 :       case '\'': t = _cat(t, QUOTE); break;
     571                 :          0 :       case '`' : t = _cat(t, BACKQUOTE); break;
     572                 :          0 :       case '"' : t = _cat(t, DOUBQUOTE); break;
     573                 :          0 :       default: *t++ = s[i];
     574                 :            :     }
     575                 :          0 :   *t = 0; return str;
     576                 :            : }
     577                 :            : 
     578                 :            : static int
     579                 :          0 : nl_read(char *s) { size_t l = strlen(s); return s[l-1] == '\n'; }
     580                 :            : 
     581                 :            : #define nbof(a) sizeof(a) / sizeof(a[0])
     582                 :            : /* query external help program for s. num < 0 [keyword] or chapter number */
     583                 :            : static void
     584                 :          0 : external_help(const char *s, int num)
     585                 :            : {
     586                 :          0 :   long nbli = term_height()-3, li = 0;
     587                 :            :   char buf[256], *str;
     588                 :          0 :   const char *opt = "", *ar = "", *cdir = "";
     589                 :          0 :   char *t, *help = Help;
     590                 :            :   pariFILE *z;
     591                 :            :   FILE *f;
     592                 :            : 
     593         [ #  # ]:          0 :   if (!has_ext_help()) pari_err(e_MISC,"no external help program");
     594                 :          0 :   t = filter_quotes(s);
     595         [ #  # ]:          0 :   if (num < 0)
     596                 :          0 :     opt = "-k";
     597         [ #  # ]:          0 :   else if (t[strlen(t)-1] != '@')
     598                 :          0 :     ar = stack_sprintf("@%d",num);
     599                 :            : #ifdef _WIN32
     600                 :            :   if (*help=='@')
     601                 :            :   {
     602                 :            :     const char *basedir = win32_basedir();
     603                 :            :     help++;
     604                 :            :     cdir = stack_sprintf("%c:& cd %s & ", *basedir, basedir);
     605                 :            :   }
     606                 :            : #endif
     607                 :          0 :   str=stack_sprintf("%s%s -fromgp %s %c%s%s%c",cdir,help,opt,
     608                 :            :                                                SHELL_Q,t,ar,SHELL_Q);
     609                 :          0 :   z = try_pipe(str,0); f = z->file;
     610                 :          0 :   pari_free(t);
     611         [ #  # ]:          0 :   while (fgets(buf, nbof(buf), f))
     612                 :            :   {
     613         [ #  # ]:          0 :     if (!strncmp("ugly_kludge_done",buf,16)) break;
     614                 :          0 :     pari_puts(buf);
     615 [ #  # ][ #  # ]:          0 :     if (nl_read(buf) && ++li > nbli) { hit_return(); li = 0; }
     616                 :            :   }
     617                 :          0 :   pari_fclose(z);
     618                 :          0 : }
     619                 :            : 
     620                 :            : const char *keyword_list[]={
     621                 :            :   "operator",
     622                 :            :   "libpari",
     623                 :            :   "member",
     624                 :            :   "integer",
     625                 :            :   "real",
     626                 :            :   "readline",
     627                 :            :   "refcard",
     628                 :            :   "tutorial",
     629                 :            :   "nf",
     630                 :            :   "bnf",
     631                 :            :   "bnr",
     632                 :            :   "ell",
     633                 :            :   "rnf",
     634                 :            :   "bid",
     635                 :            :   "modulus",
     636                 :            :   "prototype",
     637                 :            :   NULL
     638                 :            : };
     639                 :            : 
     640                 :            : static int
     641                 :          0 : ok_external_help(char **s)
     642                 :            : {
     643                 :            :   long n;
     644         [ #  # ]:          0 :   if (!**s) return 1;
     645         [ #  # ]:          0 :   if (!isalpha((int)**s)) return 3; /* operator or section number */
     646         [ #  # ]:          0 :   if (!strncmp(*s,"t_",2)) { *s += 2; return 2; } /* type name */
     647                 :            : 
     648         [ #  # ]:          0 :   for (n=0; keyword_list[n]; n++)
     649         [ #  # ]:          0 :     if (!strcmp(*s,keyword_list[n])) return 3;
     650                 :          0 :   return 0;
     651                 :            : }
     652                 :            : 
     653                 :            : static void
     654                 :         70 : cut_trailing_garbage(char *s)
     655                 :            : {
     656                 :            :   char c;
     657         [ +  + ]:        355 :   while ( (c = *s++) )
     658                 :            :   {
     659 [ -  + ][ #  # ]:        285 :     if (c == '\\' && ! *s++) return; /* gobble next char, return if none. */
     660 [ +  + ][ +  - ]:        285 :     if (!is_keyword_char(c) && c != '@') { s[-1] = 0; return; }
     661                 :            :   }
     662                 :            : }
     663                 :            : 
     664                 :            : static void
     665                 :          5 : digit_help(char *s, long flag)
     666                 :            : {
     667                 :          5 :   long n = atoi(s);
     668 [ +  - ][ -  + ]:          5 :   if (n < 0 || n > MAX_SECTION+4)
     669                 :          0 :     pari_err(e_SYNTAX,"no such section in help: ?",s,s);
     670         [ -  + ]:          5 :   if (n == MAX_SECTION+1)
     671                 :          0 :     community();
     672         [ -  + ]:          5 :   else if (flag & h_LONG)
     673                 :          0 :     external_help(s,3);
     674                 :            :   else
     675                 :          5 :     commands(n);
     676                 :          5 :   return;
     677                 :            : }
     678                 :            : 
     679                 :            : static void
     680                 :         25 : simple_help(const char *s1, const char *s2) { pari_printf("%s: %s\n", s1, s2); }
     681                 :            : 
     682                 :            : static void
     683                 :         15 : default_help(char *s, long flag)
     684                 :            : {
     685         [ -  + ]:         15 :   if (flag & h_LONG)
     686                 :          0 :     external_help(stack_strcat("se:def,",s),3);
     687                 :            :   else
     688                 :         15 :     simple_help(s,"default");
     689                 :         15 : }
     690                 :            : 
     691                 :            : static void
     692                 :         90 : aide0(const char *s0, int flag)
     693                 :            : {
     694                 :         90 :   const long long_help = flag & h_LONG;
     695                 :            :   long n;
     696                 :            :   entree *ep;
     697                 :         90 :   char *s = get_sep(s0);
     698                 :            : 
     699         [ +  + ]:         90 :   if (isdigit((int)*s)) { digit_help(s,flag); return; }
     700         [ -  + ]:         85 :   if (flag & h_APROPOS) { external_help(s,-1); return; }
     701                 :            :   /* Get meaningful answer on '\ps 5' (e.g. from <F1>) */
     702         [ +  + ]:         85 :   if (*s == '\\') { char *t = s+1; skip_alpha(&t); *t = '\0'; }
     703         [ +  + ]:         85 :   if (isalpha((int)*s))
     704                 :            :   {
     705         [ +  + ]:         70 :     if (!strncmp(s, "default", 7))
     706                 :            :     { /* special-case ?default(dft_name), e.g. default(log) */
     707                 :         10 :       char *t = s+7;
     708                 :         10 :       skip_space(&t);
     709         [ +  - ]:         10 :       if (*t == '(')
     710                 :            :       {
     711                 :         10 :         t++; skip_space(&t);
     712                 :         10 :         cut_trailing_garbage(t);
     713         [ +  - ]:         10 :         if (pari_is_default(t)) { default_help(t,flag); return; }
     714                 :            :       }
     715                 :            :     }
     716                 :         60 :     cut_trailing_garbage(s);
     717                 :            :   }
     718                 :            : 
     719 [ -  + ][ #  # ]:         75 :   if (long_help && (n = ok_external_help(&s))) { external_help(s,n); return; }
     720   [ -  +  +  +  :         75 :   switch (*s)
                      + ]
     721                 :            :   {
     722                 :          0 :     case '*' : commands(-1); return;
     723                 :          5 :     case '\0': menu_commands(); return;
     724                 :          5 :     case '\\': slash_commands(); return;
     725                 :          5 :     case '.' : member_commands(); return;
     726                 :            :   }
     727                 :         60 :   ep = is_entry(s);
     728         [ +  + ]:         60 :   if (!ep)
     729                 :            :   {
     730         [ +  + ]:         10 :     if (pari_is_default(s))
     731                 :          5 :       default_help(s,flag);
     732         [ -  + ]:          5 :     else if (long_help)
     733                 :          0 :       external_help(s,3);
     734         [ +  - ]:          5 :     else if (!cb_pari_whatnow(pariOut, s,1))
     735                 :          5 :       simple_help(s,"unknown identifier");
     736                 :            :     return;
     737                 :            :   }
     738                 :            : 
     739         [ +  + ]:         50 :   if (EpVALENCE(ep) == EpALIAS)
     740                 :            :   {
     741                 :         10 :     pari_printf("%s is aliased to:\n\n",s);
     742                 :         10 :     ep = do_alias(ep);
     743                 :            :   }
     744   [ +  -  +  + ]:         50 :   switch(EpVALENCE(ep))
     745                 :            :   {
     746                 :            :     case EpVAR:
     747         [ +  + ]:         25 :       if (!ep->help)
     748                 :            :       {
     749         [ +  + ]:         15 :         if (typ((GEN)ep->value)!=t_CLOSURE)
     750                 :          5 :           simple_help(s, "user defined variable");
     751                 :            :         else
     752                 :            :         {
     753                 :         10 :           GEN str = closure_get_text((GEN)ep->value);
     754         [ +  - ]:         10 :           if (typ(str) == t_VEC)
     755                 :         10 :             pari_printf("%s =\n  %Ps\n", ep->name, ep->value);
     756                 :            :         }
     757                 :            :         return;
     758                 :            :       }
     759                 :         10 :       break;
     760                 :            : 
     761                 :            :     case EpINSTALL:
     762         [ #  # ]:          0 :       if (!ep->help) { simple_help(s, "installed function"); return; }
     763                 :          0 :       break;
     764                 :            : 
     765                 :            :     case EpNEW:
     766         [ -  + ]:          5 :       if (!ep->help) { simple_help(s, "new identifier"); return; };
     767                 :          5 :       break;
     768                 :            : 
     769                 :            :     default: /* built-in function */
     770         [ -  + ]:         20 :       if (!ep->help) pari_err_BUG("aide (no help found)"); /*paranoia*/
     771         [ -  + ]:         20 :       if (long_help) { external_help(ep->name,3); return; }
     772                 :            :   }
     773                 :         90 :   print_text(ep->help);
     774                 :            : }
     775                 :            : 
     776                 :            : void
     777                 :         90 : aide(const char *s, long flag)
     778                 :            : {
     779                 :         90 :   pari_sp av = avma;
     780         [ +  - ]:         90 :   if ((flag & h_RL) == 0)
     781                 :            :   {
     782         [ -  + ]:         90 :     if (*s == '?') { flag |= h_LONG; s++; }
     783         [ -  + ]:         90 :     if (*s == '?') { flag |= h_APROPOS; s++; }
     784                 :            :   }
     785                 :         90 :   term_color(c_HELP); aide0(s,flag); term_color(c_NONE);
     786         [ +  - ]:         90 :   if ((flag & h_RL) == 0) pari_putc('\n');
     787                 :         90 :   avma = av;
     788                 :         90 : }
     789                 :            : 
     790                 :            : /********************************************************************/
     791                 :            : /**                                                                **/
     792                 :            : /**                         GP HEADER                              **/
     793                 :            : /**                                                                **/
     794                 :            : /********************************************************************/
     795                 :            : static char *
     796                 :          0 : what_readline(void)
     797                 :            : {
     798                 :            : #ifdef READLINE
     799                 :          0 :   const char *v = READLINE;
     800                 :          0 :   char *s = stack_malloc(3 + strlen(v) + 8);
     801         [ #  # ]:          0 :   (void)sprintf(s, "v%s %s", v, GP_DATA->use_readline? "enabled": "disabled");
     802                 :          0 :   return s;
     803                 :            : #else
     804                 :            :   return (char*)"not compiled in";
     805                 :            : #endif
     806                 :            : }
     807                 :            : 
     808                 :            : static void
     809                 :          0 : print_shortversion(void)
     810                 :            : {
     811                 :          0 :   const ulong mask = (1UL<<PARI_VERSION_SHIFT) - 1;
     812                 :          0 :   ulong n = paricfg_version_code, major, minor, patch;
     813                 :            : 
     814                 :          0 :   patch = n & mask; n >>= PARI_VERSION_SHIFT;
     815                 :          0 :   minor = n & mask; n >>= PARI_VERSION_SHIFT;
     816                 :          0 :   major = n;
     817                 :          0 :   printf("%lu.%lu.%lu\n", major,minor,patch); exit(0);
     818                 :            : }
     819                 :            : 
     820                 :            : static char *
     821                 :          0 : what_cc(void)
     822                 :            : {
     823                 :            :   char *s;
     824                 :            : #ifdef GCC_VERSION
     825                 :            : #  ifdef __cplusplus
     826                 :            : #    define Format "(C++) %s"
     827                 :            : #  else
     828                 :            : #    define Format "%s"
     829                 :            : #  endif
     830                 :          0 :   s = stack_malloc(6 + strlen(GCC_VERSION) + 1);
     831                 :          0 :   (void)sprintf(s, Format, GCC_VERSION);
     832                 :            : #else
     833                 :            : #  ifdef _MSC_VER
     834                 :            :   s = stack_malloc(32);
     835                 :            :   (void)sprintf(s, "MSVC-%i", _MSC_VER);
     836                 :            : #  else
     837                 :            :   s = NULL;
     838                 :            : #  endif
     839                 :            : #endif
     840                 :          0 :   return s;
     841                 :            : }
     842                 :            : 
     843                 :            : static void
     844                 :          0 : print_version(void)
     845                 :            : {
     846                 :          0 :   pari_sp av = avma;
     847                 :          0 :   char *buf, *ver = what_cc();
     848                 :          0 :   const char *date = paricfg_compiledate;
     849                 :            : 
     850                 :          0 :   center(paricfg_version);
     851                 :          0 :   center(paricfg_buildinfo);
     852         [ #  # ]:          0 :   buf = stack_malloc(strlen(date) +  32 + (ver? strlen(ver): 0));
     853         [ #  # ]:          0 :   if (ver) (void)sprintf(buf, "compiled: %s, %s", date, ver);
     854                 :          0 :   else     (void)sprintf(buf, "compiled: %s", date);
     855                 :          0 :   center(buf);
     856                 :          0 :   sprintf(buf, "threading engine: %s",paricfg_mt_engine);
     857                 :          0 :   center(buf);
     858                 :          0 :   ver = what_readline();
     859                 :          0 :   buf = stack_malloc(strlen(ver) + 64);
     860         [ #  # ]:          0 :   (void)sprintf(buf, "(readline %s, extended help%s enabled)", ver,
     861                 :          0 :                 has_ext_help()? "": " not");
     862                 :          0 :   center(buf); avma = av;
     863                 :          0 : }
     864                 :            : 
     865                 :            : static void
     866                 :          0 : gp_head(void)
     867                 :            : {
     868                 :            : #ifdef READLINE
     869         [ #  # ]:          0 :   if (GP_DATA->flags & gpd_TEXMACS)
     870                 :          0 :     printf("%ccommand:(cas-supports-completions-set! \"pari\")%c\n",
     871                 :            :            DATA_BEGIN, DATA_END);
     872                 :            : #endif
     873                 :          0 :   print_version();
     874                 :          0 :   pari_putc('\n');
     875                 :          0 :   center("Copyright (C) 2000-2014 The PARI Group");
     876                 :          0 :   pari_putc('\n');
     877                 :          0 :   print_text("PARI/GP is free software, covered by the GNU General Public \
     878                 :            : License, and comes WITHOUT ANY WARRANTY WHATSOEVER.");
     879                 :          0 :   pari_puts("\nType ? for help, \\q to quit.\n");
     880                 :          0 :   print_text("Type ?12 for how to get moral (and possibly technical) support.");
     881         [ #  # ]:          0 :   if (pari_mainstack->vsize)
     882                 :          0 :     pari_printf("\nparisizemax = %lu, primelimit = %lu",
     883                 :          0 :                 pari_mainstack->vsize,GP_DATA->primelimit);
     884                 :            :   else
     885                 :          0 :     pari_printf("\nparisize = %lu, primelimit = %lu",
     886                 :          0 :                 pari_mainstack->rsize,GP_DATA->primelimit);
     887         [ #  # ]:          0 :   if (pari_mt_nbthreads > 1)
     888                 :          0 :     pari_printf(", nbthreads = %lu", pari_mt_nbthreads);
     889                 :          0 :   pari_putc('\n');
     890                 :          0 : }
     891                 :            : 
     892                 :            : /********************************************************************/
     893                 :            : /**                                                                **/
     894                 :            : /**                         METACOMMANDS                           **/
     895                 :            : /**                                                                **/
     896                 :            : /********************************************************************/
     897                 :            : #define pariputs_opt(s) if (!(GP_DATA->flags & gpd_QUIET)) pari_puts(s)
     898                 :            : 
     899                 :            : void
     900                 :        849 : gp_quit(long exitcode)
     901                 :            : {
     902         [ +  - ]:        849 :   if (Help) pari_free((void*)Help);
     903                 :        849 :   free_graph();
     904                 :        849 :   pari_close();
     905                 :        849 :   kill_buffers_upto(NULL);
     906         [ -  + ]:        849 :   pariputs_opt("Goodbye!\n");
     907         [ -  + ]:        849 :   if (GP_DATA->flags & gpd_TEXMACS) tm_end_output();
     908                 :        849 :   exit(exitcode);
     909                 :            : }
     910                 :            : 
     911                 :            : static void
     912                 :        356 : escape(char *tch, int ismain)
     913                 :            : {
     914                 :            :   const char *s;
     915                 :            :   char c;
     916                 :            : 
     917         [ +  + ]:        356 :   if (compatible != NONE)
     918                 :            :   {
     919                 :         50 :     s = tch;
     920         [ +  - ]:        500 :     while (*s)
     921         [ +  + ]:        500 :       if (*s++ == '=')
     922                 :            :       {
     923                 :         50 :         GEN (*f)(const char *v, long flag) = NULL;
     924                 :         50 :         long len = (s-tch) - 1;
     925         [ +  - ]:         50 :         if      (!strncmp(tch,"precision",len))    f = sd_realprecision;
     926         [ #  # ]:          0 :         else if (!strncmp(tch,"serieslength",len)) f = sd_seriesprecision;
     927         [ #  # ]:          0 :         else if (!strncmp(tch,"format",len))       f = sd_format;
     928         [ #  # ]:          0 :         else if (!strncmp(tch,"prompt",len))       f = sd_prompt;
     929         [ +  - ]:         50 :         if (f) { (void)f(s, d_ACKNOWLEDGE); return; }
     930                 :          0 :         break;
     931                 :            :       }
     932                 :            :   }
     933                 :        306 :   s = tch;
     934   [ -  -  -  +  :        306 :   switch ((c = *s++))
          -  -  -  -  +  
          -  -  -  +  -  
                -  -  - ]
     935                 :            :   {
     936                 :            :     case 'w': case 'x': case 'a': case 'b': case 'B': case 'm':
     937                 :            :     { /* history things */
     938                 :            :       long d;
     939                 :            :       GEN x;
     940 [ #  # ][ #  # ]:          0 :       if (c != 'w' && c != 'x') d = get_int(s,0);
     941                 :            :       else
     942                 :            :       {
     943         [ #  # ]:          0 :         d = atol(s); if (*s == '-') s++;
     944         [ #  # ]:          0 :         while (isdigit((int)*s)) s++;
     945                 :            :       }
     946                 :          0 :       x = pari_get_hist(d);
     947   [ #  #  #  #  :          0 :       switch (c)
                   #  # ]
     948                 :            :       {
     949                 :            :         case 'B':
     950                 :            :         { /* prettyprinter */
     951                 :          0 :           gp_data G = *GP_DATA; /* copy */
     952                 :          0 :           gp_hist   h = *(G.hist); /* copy */
     953                 :          0 :           pariout_t f = *(G.fmt);  /* copy */
     954                 :            : 
     955                 :          0 :           G.hist = &h; h.total = 0; /* no hist number */
     956                 :          0 :           G.fmt  = &f; f.prettyp = f_PRETTY;
     957                 :          0 :           G.flags &= ~(gpd_TEST|gpd_TEXMACS);
     958                 :          0 :           G.lim_lines = 0;
     959                 :          0 :           gp_output(x, &G); break;
     960                 :            :         }
     961                 :          0 :         case 'a': brute   (x, GP_DATA->fmt->format, -1); break;
     962                 :            :         case 'b': /* fall through */
     963                 :          0 :         case 'm': matbrute(x, GP_DATA->fmt->format, -1); break;
     964                 :          0 :         case 'x': dbgGEN(x, get_int(s, -1)); break;
     965                 :            :         case 'w':
     966         [ #  # ]:          0 :           s = get_sep(s); if (!*s) s = current_logfile;
     967                 :          0 :           write0(s, mkvec(x)); return;
     968                 :            :       }
     969                 :          0 :       pari_putc('\n'); return;
     970                 :            :     }
     971                 :            : 
     972                 :          0 :     case 'c': commands(-1); break;
     973                 :          0 :     case 'd': (void)setdefault(NULL,NULL,d_SILENT); break;
     974                 :            :     case 'e':
     975                 :        148 :       s = get_sep(s);
     976 [ +  - ][ -  + ]:        148 :       if (!*s) s = (GP_DATA->echo)? "0": "1";
     977                 :        148 :       (void)sd_echo(s,d_ACKNOWLEDGE); break;
     978                 :            :     case 'g':
     979      [ #  #  # ]:          0 :       switch (*s)
     980                 :            :       {
     981         [ #  # ]:          0 :         case 'm': s++; (void)sd_debugmem(*s? s: NULL,d_ACKNOWLEDGE); break;
     982         [ #  # ]:          0 :         case 'f': s++; (void)sd_debugfiles(*s? s: NULL,d_ACKNOWLEDGE); break;
     983         [ #  # ]:          0 :         default : (void)sd_debug(*s? s: NULL,d_ACKNOWLEDGE); break;
     984                 :            :       }
     985                 :          0 :       break;
     986                 :          0 :     case 'h': print_functions_hash(s); break;
     987                 :            :     case 'l':
     988                 :          0 :       s = get_sep(s);
     989         [ #  # ]:          0 :       if (*s)
     990                 :            :       {
     991                 :          0 :         (void)sd_logfile(s,d_ACKNOWLEDGE);
     992         [ #  # ]:          0 :         if (pari_logfile) break;
     993                 :            :       }
     994         [ #  # ]:          0 :       (void)sd_log(pari_logfile?"0":"1",d_ACKNOWLEDGE);
     995                 :          0 :       break;
     996         [ #  # ]:          0 :     case 'o': (void)sd_output(*s? s: NULL,d_ACKNOWLEDGE); break;
     997                 :            :     case 'p':
     998         [ -  + ]:        153 :       switch (*s)
     999                 :            :       {
    1000                 :          0 :         case 's': s++;
    1001         [ #  # ]:          0 :           (void)sd_seriesprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
    1002                 :            :         default :
    1003         [ +  - ]:        153 :           (void)sd_realprecision(*s? s: NULL,d_ACKNOWLEDGE); break;
    1004                 :            :       }
    1005                 :        153 :       break;
    1006                 :          0 :     case 'q': gp_quit(0); break;
    1007                 :            :     case 'r':
    1008                 :          0 :       s = get_sep(s);
    1009         [ #  # ]:          0 :       if (!ismain) { (void)gp_read_file(s); break; }
    1010                 :          0 :       switchin(s);
    1011         [ #  # ]:          0 :       if (file_is_binary(pari_infile))
    1012                 :            :       {
    1013                 :            :         int vector;
    1014                 :          0 :         GEN x = readbin(s,pari_infile, &vector);
    1015                 :          0 :         popinfile();
    1016         [ #  # ]:          0 :         if (!x) pari_err_FILE("input file",s);
    1017         [ #  # ]:          0 :         if (vector) /* many BIN_GEN */
    1018                 :            :         {
    1019                 :          0 :           long i, l = lg(x);
    1020                 :          0 :           pari_warn(warner,"setting %ld history entries", l-1);
    1021         [ #  # ]:          0 :           for (i=1; i<l; i++) pari_add_hist(gel(x,i), 0);
    1022                 :            :         }
    1023                 :            :       }
    1024                 :          0 :       break;
    1025                 :          0 :     case 's': dbg_pari_heap(); break;
    1026                 :          5 :     case 't': gentypes(); break;
    1027                 :            :     case 'u':
    1028                 :          0 :       print_all_user_fun((*s == 'm')? 1: 0);
    1029                 :          0 :       break;
    1030                 :          0 :     case 'v': print_version(); break;
    1031                 :            :     case 'y':
    1032                 :          0 :       s = get_sep(s);
    1033 [ #  # ][ #  # ]:          0 :       if (!*s) s = (GP_DATA->simplify)? "0": "1";
    1034                 :          0 :       (void)sd_simplify(s,d_ACKNOWLEDGE); break;
    1035                 :        356 :     default: pari_err(e_SYNTAX,"unexpected character", tch,tch-1);
    1036                 :            :   }
    1037                 :            : }
    1038                 :            : 
    1039                 :            : static void
    1040                 :          0 : convert_time(char *s, long delay)
    1041                 :            : {
    1042         [ #  # ]:          0 :   if (delay >= 3600000)
    1043                 :            :   {
    1044                 :          0 :     sprintf(s, "%ldh, ", delay / 3600000); s+=strlen(s);
    1045                 :          0 :     delay %= 3600000;
    1046                 :            :   }
    1047         [ #  # ]:          0 :   if (delay >= 60000)
    1048                 :            :   {
    1049                 :          0 :     sprintf(s, "%ldmin, ", delay / 60000); s+=strlen(s);
    1050                 :          0 :     delay %= 60000;
    1051                 :            :   }
    1052         [ #  # ]:          0 :   if (delay >= 1000)
    1053                 :            :   {
    1054                 :          0 :     sprintf(s, "%ld,", delay / 1000); s+=strlen(s);
    1055                 :          0 :     delay %= 1000;
    1056         [ #  # ]:          0 :     if (delay < 100)
    1057                 :            :     {
    1058         [ #  # ]:          0 :       sprintf(s, "%s", (delay<10)? "00": "0");
    1059                 :          0 :       s+=strlen(s);
    1060                 :            :     }
    1061                 :            :   }
    1062                 :          0 :   sprintf(s, "%ld ms", delay); s+=strlen(s);
    1063                 :          0 : }
    1064                 :            : 
    1065                 :            : /* Format a time of 'delay' ms */
    1066                 :            : static char *
    1067                 :          0 : gp_format_time(long delay)
    1068                 :            : {
    1069                 :            :   static char buf[64];
    1070                 :          0 :   char *s = buf;
    1071                 :            : 
    1072                 :          0 :   term_get_color(s, c_TIME);
    1073                 :          0 :   convert_time(s + strlen(s), delay);
    1074                 :          0 :   s+=strlen(s);
    1075                 :          0 :   term_get_color(s, c_NONE);
    1076                 :          0 :   s+=strlen(s);
    1077                 :          0 :   s[0] = '.';
    1078                 :          0 :   s[1] = '\n';
    1079                 :          0 :   s[2] = 0; return buf;
    1080                 :            : }
    1081                 :            : 
    1082                 :            : static int
    1083                 :         54 : chron(char *s)
    1084                 :            : {
    1085         [ +  - ]:         54 :   if (*s)
    1086                 :            :   { /* if "#" or "##" timer metacommand. Otherwise let the parser get it */
    1087                 :            :     char *t;
    1088         [ -  + ]:         54 :     if (*s == '#') s++;
    1089         [ +  - ]:         54 :     if (*s) return 0;
    1090                 :          0 :     t = gp_format_time(pari_get_histtime(0));
    1091                 :          0 :     pari_printf("  ***   last result computed in %s", t);
    1092                 :            :   }
    1093                 :          0 :   else { GP_DATA->chrono ^= 1; (void)sd_timer(NULL,d_ACKNOWLEDGE); }
    1094                 :         54 :   return 1;
    1095                 :            : }
    1096                 :            : 
    1097                 :            : /* return 0: can't interpret *buf as a metacommand
    1098                 :            :  *        1: did interpret *buf as a metacommand or empty command */
    1099                 :            : static int
    1100                 :      33957 : check_meta(char *buf, int ismain)
    1101                 :            : {
    1102   [ +  +  +  +  :      33957 :   switch(*buf++)
                      + ]
    1103                 :            :   {
    1104                 :         90 :     case '?': aide(buf, h_REGULAR); break;
    1105                 :         54 :     case '#': return chron(buf);
    1106                 :        356 :     case '\\': escape(buf, ismain); break;
    1107                 :       4513 :     case '\0': break;
    1108                 :      28944 :     default: return 0;
    1109                 :            :   }
    1110                 :      33957 :   return 1;
    1111                 :            : }
    1112                 :            : 
    1113                 :            : /********************************************************************/
    1114                 :            : /*                                                                  */
    1115                 :            : /*                              GPRC                                */
    1116                 :            : /*                                                                  */
    1117                 :            : /********************************************************************/
    1118                 :            : /* LOCATE GPRC */
    1119                 :            : 
    1120                 :            : static int get_line_from_file(const char *prompt, filtre_t *F, FILE *file);
    1121                 :            : static void
    1122                 :          0 : err_gprc(const char *s, char *t, char *u)
    1123                 :            : {
    1124                 :          0 :   err_printf("\n");
    1125                 :          0 :   pari_err(e_SYNTAX,s,t,u);
    1126                 :          0 : }
    1127                 :            : 
    1128                 :            : /* return $HOME or the closest we can find */
    1129                 :            : static const char *
    1130                 :          0 : get_home(int *free_it)
    1131                 :            : {
    1132                 :          0 :   char *drv, *pth = os_getenv("HOME");
    1133         [ #  # ]:          0 :   if (pth) return pth;
    1134         [ #  # ]:          0 :   if ((drv = os_getenv("HOMEDRIVE"))
    1135         [ #  # ]:          0 :    && (pth = os_getenv("HOMEPATH")))
    1136                 :            :   { /* looks like WinNT */
    1137                 :          0 :     char *buf = (char*)pari_malloc(strlen(pth) + strlen(drv) + 1);
    1138                 :          0 :     sprintf(buf, "%s%s",drv,pth);
    1139                 :          0 :     *free_it = 1; return buf;
    1140                 :            :   }
    1141                 :          0 :   pth = pari_get_homedir("");
    1142         [ #  # ]:          0 :   return pth? pth: ".";
    1143                 :            : }
    1144                 :            : 
    1145                 :            : static FILE *
    1146                 :          0 : gprc_chk(const char *s)
    1147                 :            : {
    1148                 :          0 :   FILE *f = fopen(s, "r");
    1149 [ #  # ][ #  # ]:          0 :   if (f && !(GP_DATA->flags & gpd_QUIET)) err_printf("Reading GPRC: %s ...", s);
    1150                 :          0 :   return f;
    1151                 :            : }
    1152                 :            : 
    1153                 :            : /* Look for [._]gprc: $GPRC, then in $HOME, ., /etc, pari_datadir */
    1154                 :            : static FILE *
    1155                 :          0 : gprc_get(void)
    1156                 :            : {
    1157                 :          0 :   FILE *f = NULL;
    1158                 :          0 :   const char *gprc = os_getenv("GPRC");
    1159         [ #  # ]:          0 :   if (gprc) f = gprc_chk(gprc);
    1160         [ #  # ]:          0 :   if (!f)
    1161                 :            :   {
    1162                 :          0 :     int free_it = 0;
    1163                 :          0 :     const char *home = get_home(&free_it);
    1164                 :            :     char *str, *s, c;
    1165                 :            :     long l;
    1166                 :          0 :     l = strlen(home); c = home[l-1];
    1167                 :            :     /* + "/gprc.txt" + \0*/
    1168                 :          0 :     str = strcpy((char*)pari_malloc(l+10), home);
    1169         [ #  # ]:          0 :     if (free_it) pari_free((void*)home);
    1170                 :          0 :     s = str + l;
    1171 [ #  # ][ #  # ]:          0 :     if (c != '/' && c != '\\') *s++ = '/';
    1172                 :            : #ifndef _WIN32
    1173                 :          0 :     strcpy(s, ".gprc");
    1174                 :            : #else
    1175                 :            :     strcpy(s, "gprc.txt");
    1176                 :            : #endif
    1177                 :          0 :     f = gprc_chk(str); /* in $HOME */
    1178         [ #  # ]:          0 :     if (!f) f = gprc_chk(s); /* in . */
    1179                 :            : #ifndef _WIN32
    1180         [ #  # ]:          0 :     if (!f) f = gprc_chk("/etc/gprc");
    1181                 :            : #else
    1182                 :            :     if (!f)  /* in basedir */
    1183                 :            :     {
    1184                 :            :       const char *basedir = win32_basedir();
    1185                 :            :       char *t = (char *) pari_malloc(strlen(basedir) + 9);
    1186                 :            :       sprintf(t, "%s/%s", basedir, s);
    1187                 :            :       f = gprc_chk(t);
    1188                 :            :     }
    1189                 :            : #endif
    1190                 :          0 :     pari_free(str);
    1191                 :            :   }
    1192                 :          0 :   return f;
    1193                 :            : }
    1194                 :            : 
    1195                 :            : /* PREPROCESSOR */
    1196                 :            : 
    1197                 :            : static ulong
    1198                 :          0 : read_uint(char **s)
    1199                 :            : {
    1200                 :          0 :   long v = atol(*s);
    1201         [ #  # ]:          0 :   if (!isdigit((int)**s)) err_gprc("not an integer", *s, *s);
    1202         [ #  # ]:          0 :   while (isdigit((int)**s)) (*s)++;
    1203                 :          0 :   return v;
    1204                 :            : }
    1205                 :            : static ulong
    1206                 :          0 : read_dot_uint(char **s)
    1207                 :            : {
    1208         [ #  # ]:          0 :   if (**s != '.') return 0;
    1209                 :          0 :   (*s)++; return read_uint(s);
    1210                 :            : }
    1211                 :            : /* read a.b.c */
    1212                 :            : static long
    1213                 :          0 : read_version(char **s)
    1214                 :            : {
    1215                 :            :   long a, b, c;
    1216                 :          0 :   a = read_uint(s);
    1217                 :          0 :   b = read_dot_uint(s);
    1218                 :          0 :   c = read_dot_uint(s);
    1219                 :          0 :   return PARI_VERSION(a,b,c);
    1220                 :            : }
    1221                 :            : 
    1222                 :            : static int
    1223                 :          0 : get_preproc_value(char **s)
    1224                 :            : {
    1225         [ #  # ]:          0 :   if (!strncmp(*s,"EMACS",5)) {
    1226                 :          0 :     *s += 5;
    1227                 :          0 :     return GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS);
    1228                 :            :   }
    1229         [ #  # ]:          0 :   if (!strncmp(*s,"READL",5)) {
    1230                 :          0 :     *s += 5;
    1231                 :          0 :     return GP_DATA->use_readline;
    1232                 :            :   }
    1233         [ #  # ]:          0 :   if (!strncmp(*s,"VERSION",7)) {
    1234                 :          0 :     int less = 0, orequal = 0;
    1235                 :            :     long d;
    1236                 :          0 :     *s += 7;
    1237      [ #  #  # ]:          0 :     switch(**s)
    1238                 :            :     {
    1239                 :          0 :       case '<': (*s)++; less = 1; break;
    1240                 :          0 :       case '>': (*s)++; less = 0; break;
    1241                 :          0 :       default: return -1;
    1242                 :            :     }
    1243         [ #  # ]:          0 :     if (**s == '=') { (*s)++; orequal = 1; }
    1244                 :          0 :     d = paricfg_version_code - read_version(s);
    1245         [ #  # ]:          0 :     if (!d) return orequal;
    1246         [ #  # ]:          0 :     return less? (d < 0): (d > 0);
    1247                 :            :   }
    1248         [ #  # ]:          0 :   if (!strncmp(*s,"BITS_IN_LONG",12)) {
    1249                 :          0 :     *s += 12;
    1250 [ #  # ][ #  # ]:          0 :     if ((*s)[0] == '=' && (*s)[1] == '=')
    1251                 :            :     {
    1252                 :          0 :       *s += 2;
    1253                 :          0 :       return BITS_IN_LONG == read_uint(s);
    1254                 :            :     }
    1255                 :            :   }
    1256                 :          0 :   return -1;
    1257                 :            : }
    1258                 :            : 
    1259                 :            : /* PARSE GPRC */
    1260                 :            : 
    1261                 :            : /* 1) replace next separator by '\0' (t must be writable)
    1262                 :            :  * 2) return the next expression ("" if none)
    1263                 :            :  * see get_sep() */
    1264                 :            : static char *
    1265                 :          0 : next_expr(char *t)
    1266                 :            : {
    1267                 :          0 :   int outer = 1;
    1268                 :          0 :   char *s = t;
    1269                 :            : 
    1270                 :            :   for(;;)
    1271                 :            :   {
    1272                 :            :     char c;
    1273      [ #  #  # ]:          0 :     switch ((c = *s++))
    1274                 :            :     {
    1275                 :            :       case '"':
    1276 [ #  # ][ #  # ]:          0 :         if (outer || (s >= t+2 && s[-2] != '\\')) outer = !outer;
                 [ #  # ]
    1277                 :          0 :         break;
    1278                 :            :       case '\0':
    1279                 :          0 :         return (char*)"";
    1280                 :            :       default:
    1281 [ #  # ][ #  # ]:          0 :         if (outer && c == ';') { s[-1] = 0; return s; }
    1282                 :            :     }
    1283                 :          0 :   }
    1284                 :            : }
    1285                 :            : 
    1286                 :            : static Buffer *
    1287                 :        958 : filtered_buffer(filtre_t *F)
    1288                 :            : {
    1289                 :        958 :   Buffer *b = new_buffer();
    1290                 :        958 :   init_filtre(F, b);
    1291                 :        958 :   pari_stack_pushp(&s_bufstack, (void*)b);
    1292                 :        958 :   return b;
    1293                 :            : }
    1294                 :            : 
    1295                 :            : static jmp_buf *env;
    1296                 :            : static pari_stack s_env;
    1297                 :            : /* parse src of the form s=t (or s="t"), set *ps to s, and *pt to t.
    1298                 :            :  * modifies src (replaces = by \0) */
    1299                 :            : static void
    1300                 :          0 : parse_key_val(char *src, char **ps, char **pt)
    1301                 :            : {
    1302                 :            :   char *s_end, *t;
    1303 [ #  # ][ #  # ]:          0 :   t = src; while (*t && *t != '=') t++;
    1304         [ #  # ]:          0 :   if (*t != '=') err_gprc("missing '='",t,src);
    1305                 :          0 :   s_end = t;
    1306                 :          0 :   t++;
    1307         [ #  # ]:          0 :   if (*t == '"') (void)readstring(t, t, src);
    1308                 :          0 :   *s_end = 0; *ps = src; *pt = t;
    1309                 :          0 : }
    1310                 :            : 
    1311                 :            : static void
    1312                 :          0 : gp_initrc(pari_stack *p_A)
    1313                 :            : {
    1314                 :          0 :   FILE *file = gprc_get();
    1315                 :            :   Buffer *b;
    1316                 :            :   filtre_t F;
    1317                 :          0 :   VOLATILE long c = 0;
    1318                 :            : 
    1319         [ #  # ]:          0 :   if (!file) return;
    1320                 :          0 :   b = filtered_buffer(&F);
    1321                 :          0 :   (void)pari_stack_new(&s_env);
    1322                 :            :   for(;;)
    1323                 :            :   {
    1324                 :            :     char *nexts, *s, *t;
    1325         [ #  # ]:          0 :     if (setjmp(env[s_env.n-1])) err_printf("...skipping line %ld.\n", c);
    1326                 :          0 :     c++;
    1327         [ #  # ]:          0 :     if (!get_line_from_file(NULL,&F,file)) break;
    1328                 :          0 :     s = b->buf;
    1329         [ #  # ]:          0 :     if (*s == '#')
    1330                 :            :     { /* preprocessor directive */
    1331                 :          0 :       int z, NOT = 0;
    1332                 :          0 :       s++;
    1333         [ #  # ]:          0 :       if (strncmp(s,"if",2)) err_gprc("unknown directive",s,b->buf);
    1334                 :          0 :       s += 2;
    1335         [ #  # ]:          0 :       if (!strncmp(s,"not",3)) { NOT = !NOT; s += 3; }
    1336         [ #  # ]:          0 :       if (*s == '!')           { NOT = !NOT; s++; }
    1337                 :          0 :       t = s;
    1338                 :          0 :       z = get_preproc_value(&s);
    1339         [ #  # ]:          0 :       if (z < 0) err_gprc("unknown preprocessor variable",t,b->buf);
    1340         [ #  # ]:          0 :       if (NOT) z = !z;
    1341         [ #  # ]:          0 :       if (!*s)
    1342                 :            :       { /* make sure at least an expr follows the directive */
    1343         [ #  # ]:          0 :         if (!get_line_from_file(NULL,&F,file)) break;
    1344                 :          0 :         s = b->buf;
    1345                 :            :       }
    1346         [ #  # ]:          0 :       if (!z) continue; /* dump current line */
    1347                 :            :     }
    1348                 :            :     /* parse line */
    1349         [ #  # ]:          0 :     for ( ; *s; s = nexts)
    1350                 :            :     {
    1351                 :          0 :       nexts = next_expr(s);
    1352 [ #  # ][ #  # ]:          0 :       if (!strncmp(s,"read",4) && (s[4] == ' ' || s[4] == '\t' || s[4] == '"'))
         [ #  # ][ #  # ]
    1353                 :            :       { /* read file */
    1354                 :          0 :         s += 4;
    1355                 :          0 :         t = (char*)pari_malloc(strlen(s) + 1);
    1356         [ #  # ]:          0 :         if (*s == '"') (void)readstring(s, t, s-4); else strcpy(t,s);
    1357                 :          0 :         pari_stack_pushp(p_A,t);
    1358                 :            :       }
    1359                 :            :       else
    1360                 :            :       { /* set default */
    1361                 :          0 :         parse_key_val(s, &s,&t);
    1362                 :          0 :         (void)setdefault(s,t,d_INITRC);
    1363                 :            :       }
    1364                 :            :     }
    1365                 :          0 :   }
    1366                 :          0 :   s_env.n--;
    1367                 :          0 :   pop_buffer();
    1368         [ #  # ]:          0 :   if (!(GP_DATA->flags & gpd_QUIET)) err_printf("Done.\n\n");
    1369                 :          0 :   fclose(file);
    1370                 :            : }
    1371                 :            : 
    1372                 :            : /********************************************************************/
    1373                 :            : /*                                                                  */
    1374                 :            : /*                             PROMPTS                              */
    1375                 :            : /*                                                                  */
    1376                 :            : /********************************************************************/
    1377                 :            : static int gp_is_interactive = 0;
    1378                 :            : static const char *DFT_PROMPT = "? ";
    1379                 :            : static const char *CONTPROMPT = "";
    1380                 :            : static const char *COMMENTPROMPT = "comment> ";
    1381                 :            : static const char *DFT_INPROMPT = "";
    1382                 :            : 
    1383                 :            : static char Prompt[MAX_PROMPT_LEN], Prompt_cont[MAX_PROMPT_LEN];
    1384                 :            : 
    1385                 :            : #ifndef _WIN32
    1386                 :            : /* if prompt is coloured, we must tell readline to ignore the
    1387                 :            :  * corresponding ANSI escape sequences */
    1388                 :            : static void
    1389                 :          0 : brace_color(char *s, int c, int force)
    1390                 :            : {
    1391 [ #  # ][ #  # ]:          0 :   if (disable_color || (gp_colors[c] == c_NONE && !force)) return;
                 [ #  # ]
    1392                 :            : #ifdef READLINE
    1393         [ #  # ]:          0 :   if (GP_DATA->use_readline)
    1394                 :          0 :     readline_prompt_color(s, c);
    1395                 :            :   else
    1396                 :            : #endif
    1397                 :          0 :     term_get_color(s, c);
    1398                 :            : }
    1399                 :            : 
    1400                 :            : static void
    1401                 :          0 : color_prompt(char *buf, const char *prompt)
    1402                 :            : {
    1403                 :          0 :   char *s = buf;
    1404                 :          0 :   *s = 0;
    1405                 :            :   /* escape sequences bug readline, so use special bracing (if available) */
    1406                 :          0 :   brace_color(s, c_PROMPT, 0);
    1407                 :          0 :   s += strlen(s); strcpy(s, prompt);
    1408                 :          0 :   s += strlen(s);
    1409                 :          0 :   brace_color(s, c_INPUT, 1);
    1410                 :          0 : }
    1411                 :            : #else
    1412                 :            : static void
    1413                 :            : color_prompt(char *buf, const char *prompt) { strcpy(buf,prompt); }
    1414                 :            : #endif
    1415                 :            : 
    1416                 :            : static const char *
    1417                 :          0 : expand_prompt(char *buf, const char *prompt, filtre_t *F)
    1418                 :            : {
    1419 [ #  # ][ #  # ]:          0 :   if (F && F->in_comment) return COMMENTPROMPT;
    1420                 :          0 :   strftime_expand(prompt, buf, MAX_PROMPT_LEN-1);
    1421                 :          0 :   return buf;
    1422                 :            : }
    1423                 :            : 
    1424                 :            : const char *
    1425                 :       8760 : do_prompt(char *buf, const char *prompt, filtre_t *F)
    1426                 :            : {
    1427         [ +  - ]:       8760 :   if (GP_DATA->flags & gpd_TEST)
    1428                 :       8760 :     strcpy(buf, prompt);
    1429                 :            :   else
    1430                 :            :   {
    1431                 :            :     char b[MAX_PROMPT_LEN];
    1432                 :          0 :     const char *s = expand_prompt(b, prompt, F);
    1433                 :          0 :     color_prompt(buf, s);
    1434                 :            :   }
    1435                 :       8760 :   return buf;
    1436                 :            : }
    1437                 :            : 
    1438                 :            : /********************************************************************/
    1439                 :            : /*                                                                  */
    1440                 :            : /*                           GP MAIN LOOP                           */
    1441                 :            : /*                                                                  */
    1442                 :            : /********************************************************************/
    1443                 :            : static int
    1444                 :      43092 : is_interactive(void)
    1445                 :            : {
    1446                 :      43092 :   ulong f = GP_DATA->flags&(gpd_TEXMACS|gpd_TEST);
    1447 [ +  - ][ +  + ]:      43092 :   return pari_infile == stdin && !f && gp_is_interactive;
                 [ -  + ]
    1448                 :            : }
    1449                 :            : 
    1450                 :            : static const char esc = (0x1f & '['); /* C-[ = escape */
    1451                 :            : static char *
    1452                 :          0 : strip_prompt(const char *s)
    1453                 :            : {
    1454                 :          0 :   long l = strlen(s);
    1455                 :          0 :   char *t, *t0 = stack_malloc(l+1);
    1456                 :          0 :   t = t0;
    1457         [ #  # ]:          0 :   for (; *s; s++)
    1458                 :            :   {
    1459                 :            :     /* RL_PROMPT_START_IGNORE / RL_PROMPT_END_IGNORE */
    1460 [ #  # ][ #  # ]:          0 :     if (*s == 1 || *s == 2) continue;
    1461         [ #  # ]:          0 :     if (*s == esc) /* skip ANSI color escape sequence */
    1462                 :            :     {
    1463         [ #  # ]:          0 :       while (*++s != 'm')
    1464         [ #  # ]:          0 :         if (!*s) goto end;
    1465                 :          0 :       continue;
    1466                 :            :     }
    1467                 :          0 :     *t = *s; t++;
    1468                 :            :   }
    1469                 :            : end:
    1470                 :          0 :   *t = 0; return t0;
    1471                 :            : }
    1472                 :            : static void
    1473                 :      29454 : update_logfile(const char *prompt, const char *s)
    1474                 :            : {
    1475                 :            :   pari_sp av;
    1476                 :            :   const char *p;
    1477         [ +  - ]:      29454 :   if (!pari_logfile) return;
    1478 [ #  # ][ #  # ]:          0 :   if (!is_interactive() && !GP_DATA->echo) return;
    1479                 :          0 :   av = avma;
    1480                 :          0 :   p = strip_prompt(prompt); /* raw prompt */
    1481                 :            : 
    1482   [ #  #  #  # ]:          0 :   switch (logstyle) {
    1483                 :            :     case logstyle_TeX:
    1484                 :          0 :       fprintf(pari_logfile,
    1485                 :            :               "\\PARIpromptSTART|%s\\PARIpromptEND|%s\\PARIinputEND|%%\n",
    1486                 :            :               p, s);
    1487                 :          0 :     break;
    1488                 :            :     case logstyle_plain:
    1489                 :          0 :       fprintf(pari_logfile,"%s%s\n",p, s);
    1490                 :          0 :     break;
    1491                 :            :     case logstyle_color:
    1492                 :          0 :       fprintf(pari_logfile,"%s%s%s%s%s\n",term_get_color(NULL,c_PROMPT), p,
    1493                 :            :                                           term_get_color(NULL,c_INPUT), s,
    1494                 :            :                                           term_get_color(NULL,c_NONE));
    1495                 :          0 :       break;
    1496                 :            :   }
    1497                 :      29454 :   avma = av;
    1498                 :            : }
    1499                 :            : 
    1500                 :            : void
    1501                 :      29454 : echo_and_log(const char *prompt, const char *s)
    1502                 :            : {
    1503 [ +  + ][ +  - ]:      29454 :   if (GP_DATA->echo && !is_interactive()) {
    1504                 :            :     /* not pari_puts(): would duplicate in logfile */
    1505                 :       8281 :     fputs(prompt, pari_outfile);
    1506                 :       8281 :     fputs(s,      pari_outfile);
    1507                 :       8281 :     fputc('\n',   pari_outfile);
    1508                 :       8281 :     pari_set_last_newline(1);
    1509                 :            :   }
    1510                 :      29454 :   update_logfile(prompt, s);
    1511                 :      29454 :   pari_flush();
    1512                 :      29454 : }
    1513                 :            : 
    1514                 :            : /* prompt = NULL --> from gprc. Return 1 if new input, and 0 if EOF */
    1515                 :            : static int
    1516                 :      34821 : get_line_from_file(const char *prompt, filtre_t *F, FILE *file)
    1517                 :            : {
    1518 [ -  + ][ #  # ]:      34821 :   const int Texmacs_stdin = ((GP_DATA->flags & gpd_TEXMACS) && file == stdin);
    1519                 :            :   char *s;
    1520                 :            :   input_method IM;
    1521                 :            : 
    1522                 :      34821 :   IM.file = file;
    1523         [ -  + ]:      34821 :   IM.fgets= Texmacs_stdin? &fgets_texmacs: &fgets;
    1524                 :      34821 :   IM.getline = &file_input;
    1525                 :      34821 :   IM.free = 0;
    1526         [ +  + ]:      34821 :   if (! input_loop(F,&IM))
    1527                 :            :   {
    1528         [ -  + ]:        849 :     if (Texmacs_stdin) tm_start_output();
    1529                 :        849 :     return 0;
    1530                 :            :   }
    1531                 :            : 
    1532                 :      33972 :   s = ((Buffer*)F->buf)->buf;
    1533                 :            :   /* don't log if from gprc or empty input */
    1534 [ +  + ][ +  - ]:      33972 :   if (*s && prompt) echo_and_log(prompt, s);
    1535         [ -  + ]:      33972 :   if (GP_DATA->flags & gpd_TEXMACS)
    1536                 :            :   {
    1537                 :          0 :     tm_did_complete = 0;
    1538 [ #  # ][ #  # ]:          0 :     if (Texmacs_stdin && *s == DATA_BEGIN)
    1539                 :          0 :     { handle_texmacs_command(s); *s = 0; }
    1540                 :            :     else
    1541                 :          0 :       tm_start_output();
    1542                 :            :   }
    1543                 :      34821 :   return 1;
    1544                 :            : }
    1545                 :            : 
    1546                 :            : /* return 0 if no line could be read (EOF). If PROMPT = NULL, expand and
    1547                 :            :  * color default prompt; otherwise, use PROMPT as-is. */
    1548                 :            : static int
    1549                 :      34811 : gp_read_line(filtre_t *F, const char *PROMPT)
    1550                 :            : {
    1551                 :      34811 :   Buffer *b = (Buffer*)F->buf;
    1552                 :            :   char buf[MAX_PROMPT_LEN + 24];
    1553                 :            :   const char *p;
    1554                 :            :   int res, interactive;
    1555                 :      34811 :   F->downcase = (compatible == OLDALL);
    1556         [ +  + ]:      34811 :   if (b->len > 100000) fix_buffer(b, 100000);
    1557                 :      34811 :   interactive = is_interactive();
    1558 [ +  - ][ +  - ]:      34811 :   if (interactive || pari_logfile || GP_DATA->echo)
                 [ +  + ]
    1559         [ +  + ]:       8805 :     p = PROMPT? PROMPT: do_prompt(buf, Prompt, F);
    1560                 :            :   else
    1561                 :      26006 :     p = DFT_PROMPT;
    1562                 :            : 
    1563         [ -  + ]:      34811 :   if (interactive)
    1564                 :            :   {
    1565                 :          0 :     BLOCK_EH_START
    1566                 :            : #ifdef READLINE
    1567         [ #  # ]:          0 :     if (GP_DATA->use_readline)
    1568                 :          0 :       res = get_line_from_readline(p, Prompt_cont, F);
    1569                 :            :     else
    1570                 :            : #endif
    1571                 :            :     {
    1572                 :          0 :       pari_puts(p); pari_flush();
    1573                 :          0 :       res = get_line_from_file(p, F, pari_infile);
    1574                 :            :     }
    1575                 :          0 :     BLOCK_EH_END
    1576                 :            :   }
    1577                 :            :   else
    1578                 :      34811 :     res = get_line_from_file(p, F, pari_infile);
    1579                 :            : 
    1580 [ -  + ][ #  # ]:      34811 :   if (!disable_color && p != DFT_PROMPT &&
                 [ #  # ]
    1581         [ #  # ]:          0 :       (gp_colors[c_PROMPT] != c_NONE || gp_colors[c_INPUT] != c_NONE))
    1582                 :            :   {
    1583                 :          0 :     term_color(c_NONE); pari_flush();
    1584                 :            :   }
    1585                 :      34811 :   return res;
    1586                 :            : }
    1587                 :            : 
    1588                 :            : static int
    1589                 :      21816 : is_silent(char *s) { return s[strlen(s) - 1] == ';'; }
    1590                 :            : 
    1591                 :            : static void
    1592                 :      28998 : reset_ctrlc(void)
    1593                 :            : {
    1594                 :            : #if defined(_WIN32) || defined(__CYGWIN32__)
    1595                 :            :   win32ctrlc = 0;
    1596                 :            : #endif
    1597                 :      28998 : }
    1598                 :            : 
    1599                 :            : enum { gp_ISMAIN = 1, gp_RECOVER = 2 };
    1600                 :            : 
    1601                 :            : static GEN
    1602                 :        913 : gp_main_loop(long flag)
    1603                 :            : {
    1604                 :        913 :   VOLATILE const long dorecover = flag & gp_RECOVER;
    1605                 :        913 :   VOLATILE const long ismain    = flag & gp_ISMAIN;
    1606                 :        913 :   VOLATILE GEN z = gnil;
    1607                 :        913 :   VOLATILE long t = 0;
    1608                 :        913 :   VOLATILE pari_sp av = avma;
    1609                 :            :   filtre_t F;
    1610                 :        913 :   Buffer *b = filtered_buffer(&F);
    1611                 :            :   struct gp_context rec;
    1612                 :            : 
    1613         [ +  - ]:        913 :   if (dorecover) /* set recovery point */
    1614                 :            :   {
    1615                 :            :     long er;
    1616         [ +  + ]:        913 :     if ((er = setjmp(env[s_env.n-1])))
    1617                 :            :     { /* recover: jump from error [ > 0 ] or allocatemem [ -1 ] */
    1618         [ +  + ]:       1931 :       if (er > 0) { /* true error */
    1619         [ -  + ]:       1856 :         if (!(GP_DATA->recover)) exit(1);
    1620                 :       1856 :         gp_context_restore(&rec);
    1621                 :            :         /* true error not from main instance, let caller sort it out */
    1622         [ -  + ]:       1856 :         if (!ismain) { kill_buffers_upto_including(b); return NULL; }
    1623                 :            :       } else { /* allocatemem */
    1624                 :         75 :         filestate_restore(rec.file);
    1625                 :         75 :         gp_context_save(&rec);
    1626                 :            :       }
    1627                 :       1931 :       avma = av = pari_mainstack->top;
    1628                 :       1931 :       parivstack_reset();
    1629                 :       1931 :       kill_buffers_upto(b);
    1630                 :       1931 :       alarm0(0);
    1631                 :            :     }
    1632                 :            :   }
    1633                 :            :   for(;;)
    1634                 :            :   {
    1635         [ +  - ]:      34731 :     if (dorecover) gp_context_save(&rec);
    1636         [ +  + ]:      34731 :     if (! gp_read_line(&F, NULL))
    1637                 :            :     {
    1638         [ +  - ]:        849 :       if (popinfile()) gp_quit(0);
    1639         [ #  # ]:          0 :       if (ismain) continue;
    1640                 :          0 :       pop_buffer(); return z;
    1641                 :            :     }
    1642         [ +  + ]:      33882 :     if (check_meta(b->buf, ismain)) continue;
    1643                 :            : 
    1644                 :      28923 :     avma = av;
    1645         [ +  - ]:      28923 :     if (ismain)
    1646                 :            :     {
    1647                 :      28923 :       reset_ctrlc();
    1648                 :      28923 :       timer_start(GP_DATA->T);
    1649                 :      28923 :       pari_set_last_newline(1);
    1650                 :            :     }
    1651                 :      28923 :     z = closure_evalres(pari_compile_str(b->buf, GP_DATA->strictmatch));
    1652         [ -  + ]:      26928 :     if (! ismain) continue;
    1653                 :      26928 :     alarm0(0);
    1654                 :            : 
    1655         [ +  + ]:      26928 :     if (!pari_last_was_newline()) pari_putc('\n');
    1656                 :            : 
    1657                 :      26928 :     t = timer_delay(GP_DATA->T);
    1658 [ +  + ][ -  + ]:      26928 :     if (t && GP_DATA->chrono)
    1659                 :            :     {
    1660                 :          0 :       pari_puts("time = ");
    1661                 :          0 :       pari_puts(gp_format_time(t));
    1662                 :            :     }
    1663         [ +  - ]:      26928 :     if (GP_DATA->simplify) z = simplify_shallow(z);
    1664                 :      26928 :     pari_add_hist(z, t);
    1665 [ +  + ][ +  + ]:      26928 :     if (z != gnil && ! is_silent(b->buf) ) gp_output(z, GP_DATA);
    1666                 :      26928 :     parivstack_reset();
    1667                 :      31887 :   }
    1668                 :            : }
    1669                 :            : 
    1670                 :            : /********************************************************************/
    1671                 :            : /*                                                                  */
    1672                 :            : /*                      EXCEPTION HANDLER                           */
    1673                 :            : /*                                                                  */
    1674                 :            : /********************************************************************/
    1675                 :            : static THREAD pari_timer ti_alarm;
    1676                 :            : 
    1677                 :            : #if defined(_WIN32) || defined(SIGALRM)
    1678                 :            : static void
    1679                 :          0 : gp_alarm_fun(void) {
    1680                 :            :   char buf[64];
    1681         [ #  # ]:          0 :   if (GP_DATA->flags & gpd_TEXMACS) tm_start_output();
    1682                 :          0 :   convert_time(buf, timer_get(&ti_alarm));
    1683                 :          0 :   pari_err(e_ALARM, buf);
    1684                 :          0 : }
    1685                 :            : #endif /* SIGALRM */
    1686                 :            : 
    1687                 :            : static void
    1688                 :          0 : gp_sigint_fun(void) {
    1689                 :            :   char buf[64];
    1690                 :            : #if defined(_WIN32)
    1691                 :            :   if (win32alrm) { win32alrm = 0; gp_alarm_fun(); return;}
    1692                 :            : #endif
    1693         [ #  # ]:          0 :   if (GP_DATA->flags & gpd_TEXMACS) tm_start_output();
    1694                 :          0 :   convert_time(buf, timer_get(GP_DATA->T));
    1695                 :          0 :   pari_sigint(buf);
    1696                 :          0 : }
    1697                 :            : 
    1698                 :            : static const char *
    1699                 :         35 : break_loop_prompt(char *buf, long n)
    1700                 :            : {
    1701                 :            :   char s[128];
    1702         [ +  - ]:         35 :   if (n == 1)
    1703                 :         35 :     strcpy(s, "break> ");
    1704                 :            :   else
    1705                 :          0 :     sprintf(s, "break[%ld]> ", n);
    1706                 :         35 :   return do_prompt(buf, s, NULL);
    1707                 :            : }
    1708                 :            : 
    1709                 :            : static long frame_level=0, dbg_level = 0;
    1710                 :            : 
    1711                 :            : static int
    1712                 :         35 : break_loop(int numerr)
    1713                 :            : {
    1714                 :            :   filtre_t F;
    1715                 :            :   Buffer *b;
    1716                 :         35 :   int sigint = numerr<0, go_on = sigint;
    1717                 :            :   struct gp_context rec;
    1718                 :            :   const char *prompt, *msg;
    1719                 :            :   char promptbuf[MAX_PROMPT_LEN + 24];
    1720                 :         35 :   long nenv, oldframe_level = frame_level;
    1721                 :            :   pari_sp av;
    1722                 :            : 
    1723         [ -  + ]:         35 :   if (numerr == e_SYNTAX) return 0;
    1724         [ -  + ]:         35 :   if (numerr == e_STACK) { evalstate_clone(); avma = pari_mainstack->top; }
    1725                 :            : 
    1726                 :         35 :   b = filtered_buffer(&F);
    1727                 :         35 :   nenv=pari_stack_new(&s_env);
    1728                 :         35 :   gp_context_save(&rec);
    1729                 :         35 :   iferr_env = NULL;
    1730                 :         35 :   dbg_level = 0;
    1731                 :         35 :   frame_level = closure_context(oldframe_level, dbg_level);
    1732                 :         35 :   pari_infile = newfile(stdin, "stdin", mf_IN)->file;
    1733                 :         35 :   term_color(c_ERR); pari_putc('\n');
    1734         [ +  + ]:         35 :   if (sigint)
    1735                 :          5 :     msg = "Break loop: <Return> to continue; 'break' to go back to GP prompt";
    1736                 :            :   else
    1737                 :         30 :     msg = "Break loop: type 'break' to go back to GP prompt";
    1738                 :         35 :   print_errcontext(pariOut, msg, NULL, NULL);
    1739                 :         35 :   term_color(c_NONE);
    1740                 :         35 :   prompt = break_loop_prompt(promptbuf, s_env.n-1);
    1741                 :         35 :   av = avma;
    1742                 :            :   for(;;)
    1743                 :            :   {
    1744                 :            :     GEN x;
    1745                 :            :     long er, br_status;
    1746                 :         75 :     avma = av;
    1747         [ +  + ]:         75 :     if ((er=setjmp(env[nenv])))
    1748                 :            :     {
    1749         [ +  + ]:         10 :       if (er < 0)
    1750                 :            :       {
    1751                 :          5 :         s_env.n = 1;
    1752                 :          5 :         frame_level = oldframe_level;
    1753                 :          5 :         longjmp(env[s_env.n-1], er);
    1754                 :            :       }
    1755                 :          5 :       gp_context_restore(&rec);
    1756                 :          5 :       iferr_env = NULL;
    1757                 :          5 :       closure_err(dbg_level);
    1758                 :          5 :       (void) closure_context(oldframe_level, dbg_level);
    1759                 :          5 :       pari_infile = newfile(stdin, "stdin", mf_IN)->file;
    1760                 :            :     }
    1761                 :         80 :     term_color(c_NONE);
    1762         [ -  + ]:         80 :     if (!gp_read_line(&F, prompt))
    1763                 :          0 :       br_status = br_BREAK; /* EOF */
    1764                 :            :     else
    1765                 :            :     {
    1766                 :            :       /* Empty input ? Continue if entry on sigint (exit debugger frame) */
    1767 [ +  + ][ -  + ]:         80 :       if (! *(b->buf) && sigint) break;
    1768                 :         75 :       reset_ctrlc();
    1769         [ -  + ]:         75 :       if (check_meta(b->buf, 0)) continue;
    1770                 :         75 :       x = closure_evalbrk(pari_compile_str(b->buf,0), &br_status);
    1771                 :            :     }
    1772      [ -  +  + ]:         65 :     switch (br_status)
    1773                 :            :     {
    1774                 :            :       case br_NEXT: case br_MULTINEXT:
    1775                 :          0 :         popinfile(); /* exit frame. Don't exit debugger if s_env.n > 2 */
    1776                 :          0 :         go_on = 0; goto BR_EXIT;
    1777                 :            :       case br_BREAK: case br_RETURN:
    1778                 :         25 :         killallfiles(); /* completely exit the debugger */
    1779                 :         25 :         go_on = 0; goto BR_EXIT;
    1780                 :            :     }
    1781                 :            : 
    1782 [ +  - ][ +  - ]:         40 :     if (x != gnil && !is_silent(b->buf))
    1783                 :            :     {
    1784                 :         40 :       term_color(c_OUTPUT);
    1785                 :         40 :       gen_output(x, GP_DATA->fmt);
    1786                 :         70 :       pari_putc('\n');
    1787                 :            :     }
    1788                 :         40 :   }
    1789                 :            : BR_EXIT:
    1790                 :         30 :   s_env.n=nenv;
    1791                 :         30 :   frame_level = oldframe_level;
    1792                 :         30 :   gp_context_restore(&rec);
    1793                 :         30 :   pop_buffer(); return go_on;
    1794                 :            : }
    1795                 :            : 
    1796                 :            : /* numerr < 0: from SIGINT */
    1797                 :            : static void
    1798                 :       1856 : gp_pre_recover(long numerr)
    1799                 :            : {
    1800         [ +  - ]:       1856 :   if (numerr>=0)
    1801                 :            :   {
    1802                 :       1856 :     out_puts(pariErr, "\n"); pariErr->flush();
    1803                 :            :   }
    1804                 :       1856 :   longjmp(env[s_env.n-1], numerr);
    1805                 :            : }
    1806                 :            : 
    1807                 :            : /* numerr < 0: from SIGINT */
    1808                 :            : static void
    1809                 :         80 : gp_err_recover(long numerr)
    1810                 :            : {
    1811                 :         80 :   longjmp(env[s_env.n-1], numerr);
    1812                 :            : }
    1813                 :            : 
    1814                 :            : void
    1815                 :          5 : dbg_up(long k)
    1816                 :            : {
    1817         [ -  + ]:          5 :   if (k<0) k=0;
    1818                 :          5 :   dbg_level += k;
    1819         [ -  + ]:          5 :   if (dbg_level>frame_level) dbg_level=frame_level;
    1820                 :          5 :   gp_err_recover(e_NONE);
    1821                 :          0 : }
    1822                 :            : 
    1823                 :            : void
    1824                 :          0 : dbg_down(long k)
    1825                 :            : {
    1826         [ #  # ]:          0 :   if (k<0) k=0;
    1827                 :          0 :   dbg_level -= k;
    1828         [ #  # ]:          0 :   if (dbg_level<0) dbg_level=0;
    1829                 :          0 :   gp_err_recover(e_NONE);
    1830                 :          0 : }
    1831                 :            : 
    1832                 :            : GEN
    1833         [ +  - ]:          5 : dbg_err(void) { GEN E = pari_err_last(); return E? gcopy(E):gnil; }
    1834                 :            : 
    1835                 :            : void
    1836                 :          5 : pari_breakpoint(void)
    1837                 :            : {
    1838         [ -  + ]:          5 :   if (!pari_last_was_newline()) pari_putc('\n');
    1839                 :          5 :   closure_err(0);
    1840         [ +  - ]:          5 :   if (break_loop(-1)) return;
    1841                 :          0 :   gp_err_recover(e_MISC);
    1842                 :            : }
    1843                 :            : 
    1844                 :            : /* numerr < 0: from SIGINT */
    1845                 :            : static int
    1846                 :       1861 : gp_handle_exception(long numerr)
    1847                 :            : {
    1848         [ -  + ]:       1861 :   if (disable_exception_handler) disable_exception_handler = 0;
    1849 [ +  + ][ -  + ]:       1861 :   else if ((GP_DATA->breakloop) && break_loop(numerr)) return 1;
    1850                 :       1856 :   return 0;
    1851                 :            : }
    1852                 :            : 
    1853                 :            : #ifdef SIGALRM
    1854                 :            : static void
    1855                 :          0 : gp_alarm_handler(int sig)
    1856                 :            : {
    1857                 :            : #ifndef HAS_SIGACTION
    1858                 :            :   /*SYSV reset the signal handler in the handler*/
    1859                 :            :   (void)os_signal(sig,gp_alarm_handler);
    1860                 :            : #endif
    1861         [ #  # ]:          0 :   if (PARI_SIGINT_block) PARI_SIGINT_pending=sig;
    1862                 :          0 :   else gp_alarm_fun();
    1863                 :          0 :   return;
    1864                 :            : }
    1865                 :            : #endif /* SIGALRM */
    1866                 :            : 
    1867                 :            : /********************************************************************/
    1868                 :            : /*                                                                  */
    1869                 :            : /*                      GP-SPECIFIC ROUTINES                        */
    1870                 :            : /*                                                                  */
    1871                 :            : /********************************************************************/
    1872                 :            : static void
    1873                 :         20 : check_secure(const char *s)
    1874                 :            : {
    1875         [ -  + ]:         20 :   if (GP_DATA->secure)
    1876                 :          0 :     pari_err(e_MISC, "[secure mode]: system commands not allowed\nTried to run '%s'",s);
    1877                 :         20 : }
    1878                 :            : 
    1879                 :            : /* as gp_read_file, before running the main gp instance */
    1880                 :            : static void
    1881                 :          0 : read_main(const char *s)
    1882                 :            : {
    1883                 :            :   GEN z;
    1884         [ #  # ]:          0 :   if (setjmp(env[s_env.n-1]))
    1885                 :          0 :     z = NULL;
    1886                 :            :   else {
    1887                 :          0 :     switchin(s);
    1888         [ #  # ]:          0 :     if (file_is_binary(pari_infile)) {
    1889                 :          0 :       z = readbin(s,pari_infile, NULL);
    1890                 :          0 :       popinfile();
    1891                 :            :     }
    1892                 :          0 :     else z = gp_main_loop(gp_RECOVER);
    1893                 :            :   }
    1894         [ #  # ]:          0 :   if (!z) err_printf("... skipping file '%s'\n", s);
    1895                 :          0 :   avma = pari_mainstack->top;
    1896                 :          0 : }
    1897                 :            : 
    1898                 :            : static GEN
    1899                 :          4 : get_lines(FILE *F)
    1900                 :            : {
    1901                 :          4 :   pari_sp av = avma;
    1902                 :          4 :   long i, nz = 16;
    1903                 :          4 :   GEN z = cgetg(nz + 1, t_VEC);
    1904                 :          4 :   Buffer *b = new_buffer();
    1905                 :            :   input_method IM;
    1906                 :          4 :   IM.fgets = &fgets;
    1907                 :          4 :   IM.file = F;
    1908                 :          4 :   for(i = 1;;)
    1909                 :            :   {
    1910                 :         20 :     char *s = b->buf, *e;
    1911         [ +  + ]:         20 :     if (!file_getline(b, &s, &IM)) break;
    1912         [ -  + ]:         16 :     if (i > nz) { nz <<= 1; z = vec_lengthen(z, nz); }
    1913                 :         16 :     e = s + strlen(s)-1;
    1914         [ +  - ]:         16 :     if (*e == '\n') *e = 0;
    1915                 :         16 :     gel(z,i++) = strtoGENstr(s);
    1916                 :         16 :   }
    1917                 :          4 :   delete_buffer(b); setlg(z, i);
    1918                 :          4 :   return gerepilecopy(av, z);
    1919                 :            : }
    1920                 :            : 
    1921                 :            : GEN
    1922                 :          0 : externstr(const char *s)
    1923                 :            : {
    1924                 :            :   pariFILE *F;
    1925                 :            :   GEN z;
    1926                 :          0 :   check_secure(s);
    1927                 :          0 :   F = try_pipe(s, mf_IN);
    1928                 :          0 :   z = get_lines(F->file);
    1929                 :          0 :   pari_fclose(F); return z;
    1930                 :            : }
    1931                 :            : GEN
    1932                 :          4 : readstr(const char *s)
    1933                 :            : {
    1934                 :          4 :   GEN z = get_lines(switchin(s));
    1935                 :          4 :   popinfile(); return z;
    1936                 :            : }
    1937                 :            : 
    1938                 :            : GEN
    1939                 :          0 : extern0(const char *s)
    1940                 :            : {
    1941                 :          0 :   check_secure(s);
    1942                 :          0 :   pari_infile = try_pipe(s, mf_IN)->file;
    1943                 :          0 :   return gp_main_loop(0);
    1944                 :            : }
    1945                 :            : 
    1946                 :            : GEN
    1947                 :         10 : input0(void)
    1948                 :            : {
    1949                 :            :   filtre_t F;
    1950                 :         10 :   Buffer *b = filtered_buffer(&F);
    1951                 :            :   GEN x;
    1952                 :            : 
    1953         [ -  + ]:         10 :   while (! get_line_from_file(DFT_INPROMPT,&F,pari_infile))
    1954         [ #  # ]:          0 :     if (popinfile()) { err_printf("no input ???"); gp_quit(1); }
    1955                 :         10 :   x = readseq(b->buf);
    1956                 :         10 :   pop_buffer(); return x;
    1957                 :            : }
    1958                 :            : 
    1959                 :            : void
    1960                 :         20 : system0(const char *s)
    1961                 :            : {
    1962                 :            : /*FIXME: HAS_SYSTEM */
    1963                 :            : #if defined(UNIX) || defined(__EMX__) || defined(_WIN32)
    1964                 :         20 :   check_secure(s);
    1965         [ -  + ]:         20 :   if (system(s) < 0)
    1966                 :          0 :     pari_err(e_MISC, "system(\"%s\") failed", s);
    1967                 :            : #else
    1968                 :            :   pari_err(e_ARCH,"system");
    1969                 :            : #endif
    1970                 :         20 : }
    1971                 :            : 
    1972                 :            : static GEN
    1973                 :          0 : closure_alarmer(GEN C, long s)
    1974                 :            : {
    1975                 :            :   struct pari_evalstate state;
    1976                 :            :   VOLATILE GEN x;
    1977         [ #  # ]:          0 :   if (!s) { alarm0(0); return closure_evalgen(C); }
    1978                 :          0 :   evalstate_save(&state);
    1979                 :            : #if !defined(HAS_ALARM) && !defined(_WIN32)
    1980                 :            :   pari_err(e_ARCH,"alarm");
    1981                 :            : #endif
    1982         [ #  # ]:          0 :   pari_CATCH(CATCH_ALL) /* We need to stop the timer after any error */
    1983                 :            :   {
    1984                 :          0 :     GEN E = pari_err_last();
    1985         [ #  # ]:          0 :     if (err_get_num(E) != e_ALARM) { alarm0(0); pari_err(0, E); }
    1986                 :          0 :     x = evalstate_restore_err(&state);
    1987                 :            :   }
    1988                 :          0 :   pari_TRY { alarm0(s); x = closure_evalgen(C); alarm0(0); } pari_ENDCATCH;
    1989                 :          0 :   return x;
    1990                 :            : }
    1991                 :            : 
    1992                 :            : void
    1993                 :      28859 : alarm0(long s)
    1994                 :            : {
    1995         [ -  + ]:      28859 :   if (s < 0) pari_err_DOMAIN("alarm","delay","<",gen_0,stoi(s));
    1996         [ -  + ]:      28859 :   if (s) timer_start(&ti_alarm);
    1997                 :            : #ifdef _WIN32
    1998                 :            :   win32_alarm(s);
    1999                 :            : #elif defined(HAS_ALARM)
    2000                 :      28859 :   alarm(s);
    2001                 :            : #else
    2002                 :            :   if (s) pari_err(e_ARCH,"alarm");
    2003                 :            : #endif
    2004                 :      28859 : }
    2005                 :            : 
    2006                 :            : GEN
    2007                 :          0 : gp_alarm(long s, GEN code)
    2008                 :            : {
    2009         [ #  # ]:          0 :   if (!code) { alarm0(s); return gnil; }
    2010                 :          0 :   return closure_alarmer(code,s);
    2011                 :            : }
    2012                 :            : 
    2013                 :            : /*******************************************************************/
    2014                 :            : /**                                                               **/
    2015                 :            : /**                        INITIALIZATION                         **/
    2016                 :            : /**                                                               **/
    2017                 :            : /*******************************************************************/
    2018                 :            : static char *
    2019                 :          0 : read_arg(long *nread, char *t, long argc, char **argv)
    2020                 :            : {
    2021                 :          0 :   long i = *nread;
    2022         [ #  # ]:          0 :   if (isdigit((int)*t)) return t;
    2023 [ #  # ][ #  # ]:          0 :   if (*t || i==argc) usage(argv[0]);
    2024                 :          0 :   *nread = i+1; return argv[i];
    2025                 :            : }
    2026                 :            : 
    2027                 :            : static char *
    2028                 :          0 : read_arg_equal(long *nread, char *t, long argc, char **argv)
    2029                 :            : {
    2030                 :          0 :   long i = *nread;
    2031 [ #  # ][ #  # ]:          0 :   if (*t=='=' && isdigit((int)t[1])) return t+1;
    2032 [ #  # ][ #  # ]:          0 :   if (*t || i==argc) usage(argv[0]);
    2033                 :          0 :   *nread = i+1; return argv[i];
    2034                 :            : }
    2035                 :            : 
    2036                 :            : static void
    2037                 :          0 : init_trivial_stack(void)
    2038                 :            : {
    2039                 :          0 :   const size_t s = 2048;
    2040                 :          0 :   pari_mainstack->size = s;
    2041                 :          0 :   pari_mainstack->bot = (pari_sp)pari_malloc(s);
    2042                 :          0 :   avma = pari_mainstack->top = pari_mainstack->bot + s;
    2043                 :          0 : }
    2044                 :            : 
    2045                 :            : static void
    2046                 :          0 : free_trivial_stack(void)
    2047                 :            : {
    2048                 :          0 :   free((void*)pari_mainstack->bot);
    2049                 :          0 : }
    2050                 :            : 
    2051                 :            : typedef struct { char *key, *val; } pair_t;
    2052                 :            : /* If ab of the form key=val, record pair in new stack entry
    2053                 :            :  * P[n].key must be freed by caller to avoid memory leak */
    2054                 :            : static void
    2055                 :          0 : record_default(pari_stack *s_P, char *ab)
    2056                 :            : {
    2057                 :          0 :   pair_t *P = (pair_t*)*pari_stack_base(s_P);
    2058                 :            :   char *k, *v;
    2059                 :            :   long n;
    2060                 :          0 :   ab = pari_strdup(ab);
    2061                 :          0 :   parse_key_val(ab, &k, &v);
    2062                 :          0 :   n = pari_stack_new(s_P);
    2063                 :          0 :   P[n].key = k;
    2064                 :          0 :   P[n].val = v;
    2065                 :          0 : }
    2066                 :            : static void
    2067                 :        913 : read_opt(pari_stack *p_A, long argc, char **argv)
    2068                 :            : {
    2069                 :            :   pair_t *P;
    2070                 :            :   pari_stack s_P; /* key / value to record default() settings */
    2071                 :        913 :   char *b = NULL, *p = NULL, *s = NULL;
    2072                 :        913 :   ulong f = GP_DATA->flags;
    2073                 :        913 :   long i = 1, initrc = 1;
    2074                 :            : 
    2075                 :            :   (void)&p; (void)&b; (void)&s; /* -Wall gcc-2.95 */
    2076                 :            : 
    2077                 :        913 :   pari_stack_init(&s_P,sizeof(*P),(void**)&P);
    2078                 :        913 :   pari_stack_alloc(&s_P, 64);
    2079                 :        913 :   pari_outfile = stderr;
    2080         [ +  + ]:       2739 :   while (i < argc)
    2081                 :            :   {
    2082                 :       1826 :     char *t = argv[i];
    2083                 :            : 
    2084         [ -  + ]:       1826 :     if (*t++ != '-') break;
    2085                 :       1826 :     i++;
    2086                 :            : START:
    2087   [ -  -  -  +  :       1826 :     switch(*t++)
             -  +  -  +  
                      - ]
    2088                 :            :     {
    2089                 :          0 :       case 'p': p = read_arg(&i,t,argc,argv); break;
    2090                 :          0 :       case 's': s = read_arg(&i,t,argc,argv); break;
    2091                 :            :       case 'e':
    2092         [ #  # ]:          0 :         f |= gpd_EMACS; if (*t) goto START;
    2093                 :          0 :         break;
    2094                 :            :       case 'q':
    2095         [ -  + ]:        913 :         f |= gpd_QUIET; if (*t) goto START;
    2096                 :        913 :         break;
    2097                 :            :       case 't':
    2098         [ #  # ]:          0 :         f |= gpd_TEST; if (*t) goto START;
    2099                 :          0 :         break;
    2100                 :            :       case 'f':
    2101         [ -  + ]:         17 :         initrc = 0; if (*t) goto START;
    2102                 :         17 :         break;
    2103                 :            :       case 'D':
    2104 [ #  # ][ #  # ]:          0 :         if (*t || i == argc) usage(argv[0]);
    2105                 :          0 :         record_default(&s_P, argv[i++]);
    2106                 :          0 :         break;
    2107                 :            :       case '-':
    2108         [ -  + ]:        896 :         if (strcmp(t, "version-short") == 0) { print_shortversion(); exit(0); }
    2109         [ -  + ]:        896 :         if (strcmp(t, "version") == 0) {
    2110                 :          0 :           init_trivial_stack(); print_version();
    2111                 :          0 :           free_trivial_stack(); exit(0);
    2112                 :            :         }
    2113         [ -  + ]:        896 :         if (strcmp(t, "default") == 0) {
    2114         [ #  # ]:          0 :           if (i == argc) usage(argv[0]);
    2115                 :          0 :           record_default(&s_P, argv[i++]);
    2116                 :          0 :           break;
    2117                 :            :         }
    2118         [ -  + ]:        896 :         if (strcmp(t, "texmacs") == 0) { f |= gpd_TEXMACS; break; }
    2119         [ -  + ]:        896 :         if (strcmp(t, "emacs") == 0) { f |= gpd_EMACS; break; }
    2120         [ +  - ]:        896 :         if (strcmp(t, "test") == 0) { f |= gpd_TEST; break; }
    2121         [ #  # ]:          0 :         if (strcmp(t, "quiet") == 0) { f |= gpd_QUIET; break; }
    2122         [ #  # ]:          0 :         if (strcmp(t, "fast") == 0) { initrc = 0; break; }
    2123         [ #  # ]:          0 :         if (strncmp(t, "primelimit",10) == 0) {p = read_arg_equal(&i,t+10,argc,argv); break; }
    2124         [ #  # ]:          0 :         if (strncmp(t, "stacksize",9) == 0) {s = read_arg_equal(&i,t+9,argc,argv); break; }
    2125                 :            :        /* fall through */
    2126                 :            :       default:
    2127                 :          0 :         usage(argv[0]);
    2128                 :            :     }
    2129                 :            :   }
    2130                 :            : #ifdef READLINE
    2131                 :        913 :   GP_DATA->use_readline = gp_is_interactive;
    2132                 :            : #else
    2133                 :            :   GP_DATA->use_readline = 0;
    2134                 :            : #endif
    2135 [ +  - ][ +  - ]:        913 :   if (!gp_is_interactive && !(GP_DATA->flags & gpd_EMACS))
    2136                 :        913 :     GP_DATA->breakloop = 0;
    2137         [ -  + ]:        913 :   if (f & gpd_TEXMACS) tm_start_output();
    2138                 :        913 :   GP_DATA->flags = f;
    2139         [ +  + ]:        913 :   if (f & gpd_TEST) {
    2140                 :        896 :     GP_DATA->breakloop = 0;
    2141                 :        896 :     init_linewrap(76);
    2142         [ -  + ]:         17 :   } else if (initrc)
    2143                 :          0 :     gp_initrc(p_A);
    2144         [ -  + ]:        913 :   for ( ; i < argc; i++) pari_stack_pushp(p_A, pari_strdup(argv[i]));
    2145                 :            : 
    2146                 :            :   /* override the values from gprc */
    2147         [ -  + ]:        913 :   if (p) (void)sd_primelimit(p, d_INITRC);
    2148         [ -  + ]:        913 :   if (s) (void)sd_parisize(s, d_INITRC);
    2149         [ -  + ]:        913 :   for (i = 0; i < s_P.n; i++) {
    2150                 :          0 :     setdefault(P[i].key, P[i].val, d_INITRC);
    2151                 :          0 :     free((void*)P[i].key);
    2152                 :            :   }
    2153                 :        913 :   pari_stack_delete(&s_P);
    2154                 :            : 
    2155         [ +  + ]:        913 :   if (GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS|gpd_TEST)) disable_color = 1;
    2156                 :        913 :   pari_outfile = stdout;
    2157                 :        913 : }
    2158                 :            : 
    2159                 :            : #ifdef __CYGWIN32__
    2160                 :            : void
    2161                 :            : cyg_environment(int argc, char ** argv)
    2162                 :            : {
    2163                 :            :   char *ti_dirs = getenv("TERMINFO_DIRS");
    2164                 :            :   char *argv0, *p;
    2165                 :            :   char *newdir;
    2166                 :            :   long n;
    2167                 :            : 
    2168                 :            :   if (!argc || !argv) return;
    2169                 :            :   argv0 = *argv;
    2170                 :            :   if (!argv0 || !*argv0) return;
    2171                 :            :   p = strrchr(argv0, '/');
    2172                 :            :   if (!p)
    2173                 :            :     p = argv0 = "";
    2174                 :            :   else
    2175                 :            :     p++;
    2176                 :            :   n = p - argv0;
    2177                 :            :   if (ti_dirs)
    2178                 :            :   {
    2179                 :            :     n += 14 + strlen(ti_dirs) + 1 + 8 + 1;
    2180                 :            :     newdir = malloc(n);
    2181                 :            :     if (!newdir) return;
    2182                 :            :     snprintf(newdir, n-8, "TERMINFO_DIRS=%s:%s", ti_dirs, argv0);
    2183                 :            :   }
    2184                 :            :   else
    2185                 :            :   {
    2186                 :            :     n += 14 + 8 + 1;
    2187                 :            :     newdir = malloc(n);
    2188                 :            :     if (!newdir) return;
    2189                 :            :     snprintf(newdir, n-8, "TERMINFO_DIRS=%s", argv0);
    2190                 :            :   }
    2191                 :            :   strcpy(newdir+n-9,"terminfo");
    2192                 :            :   putenv(newdir);
    2193                 :            : }
    2194                 :            : #endif
    2195                 :            : 
    2196                 :            : #ifndef WINCE
    2197                 :            : int
    2198                 :        913 : main(int argc, char **argv)
    2199                 :            : {
    2200                 :            : #else
    2201                 :            : int
    2202                 :            : WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    2203                 :            :         LPWSTR lpCmdLine, int nShowCmd)
    2204                 :            : {
    2205                 :            :   char **argv = NULL;
    2206                 :            :   int argc = 1;
    2207                 :            : #endif
    2208                 :            :   void **A;
    2209                 :            :   pari_stack s_A;
    2210                 :            : 
    2211                 :        913 :   GP_DATA = default_gp_data();
    2212                 :        913 :   pari_stack_init(&s_env, sizeof(*env), (void**)&env);
    2213                 :        913 :   (void)pari_stack_new(&s_env);
    2214                 :            : 
    2215         [ -  + ]:        913 :   if (setjmp(env[s_env.n-1]))
    2216                 :            :   {
    2217                 :          0 :     puts("### Errors on startup, exiting...\n\n");
    2218                 :          0 :     exit(1);
    2219                 :            :   }
    2220                 :            : #ifdef __CYGWIN32__
    2221                 :            :   cyg_environment(argc, argv);
    2222                 :            : #endif
    2223                 :        913 :   gp_is_interactive = pari_stdin_isatty();
    2224                 :        913 :   pari_init_defaults();
    2225                 :        913 :   pari_library_path = DL_DFLT_NAME;
    2226                 :        913 :   pari_stack_init(&s_A,sizeof(*A),(void**)&A);
    2227                 :        913 :   pari_stack_init(&s_bufstack, sizeof(Buffer*), (void**)&bufstack);
    2228                 :        913 :   cb_pari_err_recover = gp_err_recover;
    2229                 :        913 :   pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm);
    2230                 :        913 :   cb_pari_pre_recover = gp_pre_recover;
    2231                 :        913 :   pari_add_defaults_module(functions_gp_default);
    2232                 :        913 :   (void)sd_graphcolormap("[\"white\",\"black\",\"blue\",\"violetred\",\"red\",\"green\",\"grey\",\"gainsboro\"]", d_SILENT);
    2233                 :        913 :   (void)sd_graphcolors("[4, 5]", d_SILENT);
    2234                 :        913 :   strcpy(Prompt,      DFT_PROMPT);
    2235                 :        913 :   strcpy(Prompt_cont, CONTPROMPT);
    2236                 :        913 :   Help = init_help();
    2237                 :            : 
    2238                 :        913 :   read_opt(&s_A, argc,argv);
    2239                 :        913 :   initprimetable(GP_DATA->primelimit);
    2240                 :            : #ifdef SIGALRM
    2241                 :        913 :   (void)os_signal(SIGALRM,gp_alarm_handler);
    2242                 :            : #endif
    2243                 :        913 :   pari_add_module(functions_gp);
    2244                 :        913 :   pari_add_module(functions_highlevel);
    2245                 :        913 :   pari_add_oldmodule(functions_oldgp);
    2246                 :            : 
    2247                 :        913 :   init_graph();
    2248                 :            : #ifdef READLINE
    2249                 :        913 :   init_readline();
    2250                 :            : #endif
    2251                 :        913 :   cb_pari_whatnow = whatnow;
    2252                 :        913 :   cb_pari_sigint = gp_sigint_fun;
    2253                 :        913 :   cb_pari_handle_exception = gp_handle_exception;
    2254                 :        913 :   cb_pari_ask_confirm = gp_ask_confirm;
    2255                 :        913 :   gp_expand_path(GP_DATA->path);
    2256                 :            : 
    2257                 :        913 :   timer_start(GP_DATA->T);
    2258         [ -  + ]:        913 :   if (!(GP_DATA->flags & gpd_QUIET)) gp_head();
    2259         [ -  + ]:        913 :   if (s_A.n)
    2260                 :            :   {
    2261                 :          0 :     FILE *l = pari_logfile;
    2262                 :            :     long i;
    2263                 :          0 :     pari_logfile = NULL;
    2264         [ #  # ]:          0 :     for (i = 0; i < s_A.n; pari_free(A[i]),i++) read_main((char*)A[i]);
    2265                 :            :     /* Reading one of the input files above can set pari_logfile.
    2266                 :            :      * Don't restore in that case. */
    2267         [ #  # ]:          0 :     if (!pari_logfile) pari_logfile = l;
    2268                 :            :   }
    2269                 :        913 :   pari_stack_delete(&s_A);
    2270                 :        913 :   (void)gp_main_loop(gp_RECOVER|gp_ISMAIN);
    2271                 :          0 :   gp_quit(0); return 0; /* not reached */
    2272                 :            : }
    2273                 :            : 
    2274                 :            : /*******************************************************************/
    2275                 :            : /**                                                               **/
    2276                 :            : /**                          GP OUTPUT                            **/
    2277                 :            : /**                                                               **/
    2278                 :            : /*******************************************************************/
    2279                 :            :     /* EXTERNAL PRETTYPRINTER */
    2280                 :            : /* Wait for prettinprinter to finish, to prevent new prompt from overwriting
    2281                 :            :  * the output.  Fill the output buffer, wait until it is read.
    2282                 :            :  * Better than sleep(2): give possibility to print */
    2283                 :            : static void
    2284                 :          0 : prettyp_wait(FILE *out)
    2285                 :            : {
    2286                 :          0 :   const char *s = "                                                     \n";
    2287                 :          0 :   long i = 2000;
    2288                 :            : 
    2289                 :          0 :   fputs("\n\n", out); fflush(out); /* start translation */
    2290         [ #  # ]:          0 :   while (--i) fputs(s, out);
    2291                 :          0 :   fputs("\n", out); fflush(out);
    2292                 :          0 : }
    2293                 :            : 
    2294                 :            : /* initialise external prettyprinter (tex2mail) */
    2295                 :            : static int
    2296                 :          0 : prettyp_init(void)
    2297                 :            : {
    2298                 :          0 :   gp_pp *pp = GP_DATA->pp;
    2299         [ #  # ]:          0 :   if (!pp->cmd) return 0;
    2300 [ #  # ][ #  # ]:          0 :   if (pp->file || (pp->file = try_pipe(pp->cmd, mf_OUT))) return 1;
    2301                 :            : 
    2302                 :          0 :   pari_warn(warner,"broken prettyprinter: '%s'",pp->cmd);
    2303                 :          0 :   pari_free(pp->cmd); pp->cmd = NULL;
    2304                 :          0 :   sd_output("1", d_SILENT);
    2305                 :          0 :   return 0;
    2306                 :            : }
    2307                 :            : 
    2308                 :            : /* n = history number. if n = 0 no history */
    2309                 :            : static int
    2310                 :          0 : tex2mail_output(GEN z, long n)
    2311                 :            : {
    2312                 :          0 :   pariout_t T = *(GP_DATA->fmt); /* copy */
    2313                 :          0 :   FILE *log = pari_logfile, *out;
    2314                 :            : 
    2315         [ #  # ]:          0 :   if (!prettyp_init()) return 0;
    2316                 :          0 :   out = GP_DATA->pp->file->file;
    2317                 :            :   /* Emit first: there may be lines before the prompt */
    2318         [ #  # ]:          0 :   if (n) term_color(c_OUTPUT);
    2319                 :          0 :   pari_flush();
    2320                 :          0 :   T.prettyp = f_TEX;
    2321                 :            :   /* history number */
    2322         [ #  # ]:          0 :   if (n)
    2323                 :            :   {
    2324                 :          0 :     pari_sp av = avma;
    2325                 :          0 :     const char *c_hist = term_get_color(NULL, c_HIST);
    2326                 :          0 :     const char *c_out = term_get_color(NULL, c_OUTPUT);
    2327         [ #  # ]:          0 :     if (!(GP_DATA->flags & gpd_QUIET))
    2328                 :            :     {
    2329 [ #  # ][ #  # ]:          0 :       if (*c_hist || *c_out)
    2330                 :          0 :         fprintf(out, "\\LITERALnoLENGTH{%s}\\%%%ld =\\LITERALnoLENGTH{%s} ",
    2331                 :            :                      c_hist, n, c_out);
    2332                 :            :       else
    2333                 :          0 :         fprintf(out, "\\%%%ld = ", n);
    2334                 :            :     }
    2335         [ #  # ]:          0 :     if (log) {
    2336   [ #  #  #  # ]:          0 :       switch (logstyle) {
    2337                 :            :       case logstyle_plain:
    2338                 :          0 :         fprintf(log, "%%%ld = ", n);
    2339                 :          0 :         break;
    2340                 :            :       case logstyle_color:
    2341                 :          0 :         fprintf(log, "%s%%%ld = %s", c_hist, n, c_out);
    2342                 :          0 :         break;
    2343                 :            :       case logstyle_TeX:
    2344                 :          0 :         fprintf(log, "\\PARIout{%ld}", n);
    2345                 :          0 :         break;
    2346                 :            :       }
    2347                 :            :     }
    2348                 :          0 :     avma = av;
    2349                 :            :   }
    2350                 :            :   /* output */
    2351                 :          0 :   fputGEN_pariout(z, &T, out);
    2352                 :            :   /* flush and restore, output to logfile */
    2353                 :          0 :   prettyp_wait(out);
    2354         [ #  # ]:          0 :   if (log) {
    2355         [ #  # ]:          0 :     if (logstyle == logstyle_TeX) {
    2356                 :          0 :       T.TeXstyle |= TEXSTYLE_BREAK;
    2357                 :          0 :       fputGEN_pariout(z, &T, log);
    2358                 :          0 :       fputc('%', log);
    2359                 :            :     } else {
    2360                 :          0 :       T.prettyp = f_RAW;
    2361                 :          0 :       fputGEN_pariout(z, &T, log);
    2362                 :            :     }
    2363                 :          0 :     fputc('\n', log); fflush(log);
    2364                 :            :   }
    2365         [ #  # ]:          0 :   if (n) term_color(c_NONE);
    2366                 :          0 :   return 1;
    2367                 :            : }
    2368                 :            : 
    2369                 :            :     /* TEXMACS */
    2370                 :            : static void
    2371                 :          0 : texmacs_output(GEN z, long n)
    2372                 :            : {
    2373                 :          0 :   char *sz = GENtoTeXstr(z);
    2374                 :          0 :   printf("%clatex:", DATA_BEGIN);
    2375         [ #  # ]:          0 :   if (n) printf("\\magenta\\%%%ld = ", n);
    2376                 :          0 :   printf("$\\blue %s$%c", sz,DATA_END);
    2377                 :          0 :   pari_free(sz); fflush(stdout);
    2378                 :          0 : }
    2379                 :            : 
    2380                 :            :     /* REGULAR */
    2381                 :            : static void
    2382                 :          0 : normal_output(GEN z, long n)
    2383                 :            : {
    2384                 :          0 :   long l = 0;
    2385                 :            :   char *s;
    2386                 :            :   /* history number */
    2387         [ #  # ]:          0 :   if (n)
    2388                 :            :   {
    2389                 :            :     char buf[64];
    2390         [ #  # ]:          0 :     if (!(GP_DATA->flags & gpd_QUIET))
    2391                 :            :     {
    2392                 :          0 :       term_color(c_HIST);
    2393                 :          0 :       sprintf(buf, "%%%ld = ", n);
    2394                 :          0 :       pari_puts(buf);
    2395                 :          0 :       l = strlen(buf);
    2396                 :            :     }
    2397                 :            :   }
    2398                 :            :   /* output */
    2399                 :          0 :   term_color(c_OUTPUT);
    2400                 :          0 :   s = GENtostr(z);
    2401         [ #  # ]:          0 :   if (GP_DATA->lim_lines)
    2402                 :          0 :     lim_lines_output(s, l, GP_DATA->lim_lines);
    2403                 :            :   else
    2404                 :          0 :     pari_puts(s);
    2405                 :          0 :   pari_free(s);
    2406                 :          0 :   term_color(c_NONE); pari_putc('\n');
    2407                 :          0 : }
    2408                 :            : 
    2409                 :            : void
    2410                 :      15678 : gp_output(GEN z, gp_data *G)
    2411                 :            : {
    2412         [ +  - ]:      15678 :   if (G->flags & gpd_TEST) {
    2413                 :      15678 :     init_linewrap(76);
    2414                 :      15678 :     gen_output(z, G->fmt); pari_putc('\n');
    2415                 :            :   }
    2416         [ #  # ]:          0 :   else if (G->flags & gpd_TEXMACS)
    2417                 :          0 :     texmacs_output(z, G->hist->total);
    2418 [ #  # ][ #  # ]:          0 :   else if (G->fmt->prettyp != f_PRETTY || !tex2mail_output(z, G->hist->total))
    2419                 :          0 :     normal_output(z, G->hist->total);
    2420                 :      15678 :   pari_flush();
    2421                 :      15678 : }
    2422                 :            : 
    2423                 :            : /*******************************************************************/
    2424                 :            : /**                                                               **/
    2425                 :            : /**                     GP-SPECIFIC DEFAULTS                      **/
    2426                 :            : /**                                                               **/
    2427                 :            : /*******************************************************************/
    2428                 :            : 
    2429                 :            : static long
    2430                 :          0 : atocolor(const char *s)
    2431                 :            : {
    2432                 :          0 :   long l = atol(s);
    2433         [ #  # ]:          0 :   if (l <   0) l =   0;
    2434         [ #  # ]:          0 :   if (l > 255) l = 255;
    2435                 :          0 :   return l;
    2436                 :            : }
    2437                 :            : 
    2438                 :            : GEN
    2439                 :        913 : sd_graphcolormap(const char *v, long flag)
    2440                 :            : {
    2441                 :            :   char *p, *q;
    2442                 :            :   long i, j, l, a, s, *lp;
    2443                 :            : 
    2444         [ +  - ]:        913 :   if (v)
    2445                 :            :   {
    2446                 :        913 :     char *t = filtre(v, 0);
    2447 [ +  - ][ -  + ]:        913 :     if (*t != '[' || t[strlen(t)-1] != ']')
    2448                 :          0 :       pari_err(e_SYNTAX, "incorrect value for graphcolormap", t, t);
    2449         [ +  + ]:      15521 :     for (s = 0, p = t+1, l = 2, a=0; *p; p++)
    2450         [ -  + ]:      14608 :       if (*p == '[')
    2451                 :            :       {
    2452                 :          0 :         a++;
    2453         [ #  # ]:          0 :         while (*++p != ']')
    2454 [ #  # ][ #  # ]:          0 :           if (!*p || *p == '[')
    2455                 :          0 :             pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
    2456                 :            :       }
    2457         [ +  + ]:      14608 :       else if (*p == '"')
    2458                 :            :       {
    2459                 :       7304 :         s += sizeof(long)+1;
    2460 [ +  - ][ +  + ]:      47476 :         while (*p && *++p != '"') s++;
    2461         [ -  + ]:       7304 :         if (!*p) pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
    2462                 :       7304 :         s = (s+sizeof(long)-1) & ~(sizeof(long)-1);
    2463                 :            :       }
    2464         [ +  + ]:       7304 :       else if (*p == ',')
    2465                 :       6391 :         l++;
    2466         [ -  + ]:        913 :     if (l < 4)
    2467                 :          0 :       pari_err(e_MISC, "too few colors (< 4) in graphcolormap");
    2468         [ -  + ]:        913 :     if (pari_colormap) pari_free(pari_colormap);
    2469                 :        913 :     pari_colormap = (GEN)pari_malloc((l+4*a)*sizeof(long) + s);
    2470                 :        913 :     pari_colormap[0] = evaltyp(t_VEC)|evallg(l);
    2471         [ +  + ]:      15521 :     for (p = t+1, i = 1, lp = pari_colormap+l; i < l; p++)
    2472   [ +  -  +  - ]:      14608 :       switch(*p)
    2473                 :            :       {
    2474                 :            :       case '"':
    2475                 :       7304 :         gel(pari_colormap, i) = lp;
    2476         [ +  + ]:      47476 :         q = ++p; while (*q != '"') q++;
    2477                 :       7304 :         *q = 0;
    2478                 :       7304 :         j = 1 + nchar2nlong(q-p+1);
    2479                 :       7304 :         lp[0] = evaltyp(t_STR)|evallg(j);
    2480                 :       7304 :         strncpy(GSTR(lp), p, q-p+1);
    2481                 :       7304 :         lp += j; p = q;
    2482                 :       7304 :         break;
    2483                 :            :       case '[': {
    2484                 :            :         const char *ap[3];
    2485                 :          0 :         gel(pari_colormap, i) = lp;
    2486                 :          0 :         lp[0] = evaltyp(t_VECSMALL)|_evallg(4);
    2487 [ #  # ][ #  # ]:          0 :         for (ap[0] = ++p, j=0; *p && *p != ']'; p++)
    2488 [ #  # ][ #  # ]:          0 :           if (*p == ',' && j<2) { *p++ = 0; ap[++j] = p; }
    2489         [ #  # ]:          0 :         while (j<2) ap[++j] = "0";
    2490 [ #  # ][ #  # ]:          0 :         if (j>2 || *p != ']')
    2491                 :            :         {
    2492                 :            :           char buf[100];
    2493                 :          0 :           sprintf(buf, "incorrect value for graphcolormap[%ld]: ", i);
    2494                 :          0 :           pari_err(e_SYNTAX, buf, p, t);
    2495                 :            :         }
    2496                 :          0 :         *p = '\0';
    2497                 :          0 :         lp[1] = atocolor(ap[0]);
    2498                 :          0 :         lp[2] = atocolor(ap[1]);
    2499                 :          0 :         lp[3] = atocolor(ap[2]);
    2500                 :          0 :         lp += 4;
    2501                 :            :         break;
    2502                 :            :       }
    2503                 :            :       case ',':
    2504                 :            :       case ']':
    2505                 :       7304 :         i++;
    2506                 :       7304 :         break;
    2507                 :            :       default:
    2508                 :          0 :         pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);
    2509                 :            :       }
    2510                 :        913 :     pari_free(t);
    2511                 :            :   }
    2512 [ +  - ][ -  + ]:        913 :   if (flag == d_RETURN || flag == d_ACKNOWLEDGE)
    2513                 :            :   {
    2514                 :          0 :     GEN cols = cgetg(lg(pari_colormap), t_VEC);
    2515                 :            :     long i;
    2516                 :            : 
    2517         [ #  # ]:          0 :     for (i = 1; i < lg(cols); i++)
    2518                 :            :     {
    2519                 :          0 :       GEN c = gel(pari_colormap, i);
    2520         [ #  # ]:          0 :       if (typ(c) == t_STR)
    2521                 :          0 :         gel(cols, i) = gcopy(c);
    2522                 :            :       else
    2523                 :          0 :         gel(cols, i) = vecsmall_to_vec(c);
    2524                 :            :     }
    2525         [ #  # ]:          0 :     if (flag == d_RETURN) return cols;
    2526                 :          0 :     pari_printf("   graphcolormap = %Ps\n", cols);
    2527                 :            :   }
    2528                 :        913 :   return gnil;
    2529                 :            : }
    2530                 :            : 
    2531                 :            : GEN
    2532                 :        913 : sd_graphcolors(const char *v, long flag)
    2533                 :            : {
    2534                 :            :   long i, l;
    2535                 :            :   char *p;
    2536                 :            : 
    2537         [ +  - ]:        913 :   if (v) {
    2538                 :        913 :     char *t = filtre(v, 0);
    2539         [ +  + ]:       3652 :     for (p = t+1, l=2; *p != ']'; p++)
    2540         [ +  + ]:       2739 :       if (*p == ',') l++;
    2541 [ +  - ][ -  + ]:       1826 :       else if (*p < '0' || *p > '9')
    2542                 :          0 :         pari_err(e_SYNTAX, "incorrect value for graphcolors", p, t);
    2543         [ -  + ]:        913 :     if (*++p) pari_err(e_SYNTAX, "incorrect value for graphcolors", p, t);
    2544         [ -  + ]:        913 :     if (pari_graphcolors) pari_free(pari_graphcolors);
    2545                 :        913 :     pari_graphcolors = cgetalloc(t_VECSMALL, l);
    2546         [ +  + ]:       2739 :     for (p = t+1, i=0; *p; p++)
    2547                 :            :     {
    2548                 :       1826 :       long n = 0;
    2549 [ +  + ][ +  + ]:       3652 :       while (*p >= '0' && *p <= '9')
    2550                 :            :       {
    2551                 :       1826 :         n *= 10;
    2552                 :       1826 :         n += *p-'0';
    2553                 :       1826 :         p++;
    2554                 :            :       }
    2555                 :       1826 :       pari_graphcolors[++i] = n;
    2556                 :            :     }
    2557                 :        913 :     pari_free(t);
    2558                 :            :   }
    2559      [ -  -  + ]:        913 :   switch(flag)
    2560                 :            :   {
    2561                 :            :   case d_RETURN:
    2562                 :          0 :     return vecsmall_to_vec(pari_graphcolors);
    2563                 :            :   case d_ACKNOWLEDGE:
    2564                 :          0 :     pari_printf("   graphcolors = %Ps\n", vecsmall_to_vec(pari_graphcolors));
    2565                 :            :   }
    2566                 :        913 :   return gnil;
    2567                 :            : }
    2568                 :            : 
    2569                 :            : GEN
    2570                 :          0 : sd_help(const char *v, long flag)
    2571                 :            : {
    2572                 :            :   const char *str;
    2573         [ #  # ]:          0 :   if (v)
    2574                 :            :   {
    2575         [ #  # ]:          0 :     if (GP_DATA->secure)
    2576                 :          0 :       pari_err(e_MISC,"[secure mode]: can't modify 'help' default (to %s)",v);
    2577         [ #  # ]:          0 :     if (Help) pari_free((void*)Help);
    2578                 :            : #ifndef _WIN32
    2579                 :          0 :     Help = path_expand(v);
    2580                 :            : #else
    2581                 :            :     Help = strdup(v);
    2582                 :            : #endif
    2583                 :            :   }
    2584         [ #  # ]:          0 :   str = Help? Help: "none";
    2585         [ #  # ]:          0 :   if (flag == d_RETURN) return strtoGENstr(str);
    2586         [ #  # ]:          0 :   if (flag == d_ACKNOWLEDGE)
    2587                 :          0 :     pari_printf("   help = \"%s\"\n", str);
    2588                 :          0 :   return gnil;
    2589                 :            : }
    2590                 :            : 
    2591                 :            : static GEN
    2592                 :          0 : sd_prompt_set(const char *v, long flag, const char *how, char *p)
    2593                 :            : {
    2594         [ #  # ]:          0 :   if (v) strncpy(p,v,MAX_PROMPT_LEN);
    2595         [ #  # ]:          0 :   if (flag == d_RETURN) return strtoGENstr(p);
    2596         [ #  # ]:          0 :   if (flag == d_ACKNOWLEDGE)
    2597                 :          0 :     pari_printf("   prompt%s = \"%s\"\n", how, p);
    2598                 :          0 :   return gnil;
    2599                 :            : }
    2600                 :            : GEN
    2601                 :          0 : sd_prompt(const char *v, long flag)
    2602                 :          0 : { return sd_prompt_set(v, flag, "", Prompt); }
    2603                 :            : GEN
    2604                 :          0 : sd_prompt_cont(const char *v, long flag)
    2605                 :          0 : { return sd_prompt_set(v, flag, "_cont", Prompt_cont); }
    2606                 :            : 
    2607                 :            : GEN
    2608                 :          5 : sd_breakloop(const char *v, long flag)
    2609                 :          5 : { return sd_toggle(v,flag,"breakloop", &(GP_DATA->breakloop)); }
    2610                 :            : GEN
    2611                 :        163 : sd_echo(const char *v, long flag)
    2612                 :        163 : { return sd_toggle(v,flag,"echo", &(GP_DATA->echo)); }
    2613                 :            : GEN
    2614                 :          0 : sd_timer(const char *v, long flag)
    2615                 :          0 : { return sd_toggle(v,flag,"timer", &(GP_DATA->chrono)); }
    2616                 :            : GEN
    2617                 :          0 : sd_recover(const char *v, long flag)
    2618                 :          0 : { return sd_toggle(v,flag,"recover", &(GP_DATA->recover)); }
    2619                 :            : 
    2620                 :            : #ifndef READLINE /* default not implemented */
    2621                 :            : GEN
    2622                 :            : sd_readline(const char *v, long flag)
    2623                 :            : { (void)v; (void)flag; return gnil; }
    2624                 :            : GEN
    2625                 :            : sd_histfile(const char *v, long flag)
    2626                 :            : { (void)v; (void)flag; return gnil; }
    2627                 :            : #endif
    2628                 :            : 
    2629                 :            : GEN
    2630                 :          0 : sd_psfile(const char *v, long flag)
    2631                 :          0 : { return sd_string(v, flag, "psfile", &current_psfile); }
    2632                 :            : 
    2633                 :            : GEN
    2634                 :          0 : sd_lines(const char *v, long flag)
    2635                 :          0 : { return sd_ulong(v,flag,"lines",&(GP_DATA->lim_lines), 0,LONG_MAX,NULL); }
    2636                 :            : GEN
    2637                 :          0 : sd_linewrap(const char *v, long flag)
    2638                 :            : {
    2639                 :          0 :   ulong old = GP_DATA->linewrap, n = GP_DATA->linewrap;
    2640                 :          0 :   GEN z = sd_ulong(v,flag,"linewrap",&n, 0,LONG_MAX,NULL);
    2641         [ #  # ]:          0 :   if (old)
    2642         [ #  # ]:          0 :   { if (!n) resetout(1); }
    2643                 :            :   else
    2644         [ #  # ]:          0 :   { if (n) init_linewrap(n); }
    2645                 :          0 :   GP_DATA->linewrap = n; return z;
    2646                 :            : }

Generated by: LCOV version 1.9