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 16393-29b9383) Lines: 493 1288 38.3 %
Date: 2014-04-24 Functions: 50 127 39.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 270 934 28.9 %

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

Generated by: LCOV version 1.9