Code coverage tests

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

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

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

LCOV - code coverage report
Current view: top level - gp - gp_rl.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.8.0 lcov report (development 19361-ac4f238) Lines: 39 212 18.4 %
Date: 2016-08-28 06:11:39 Functions: 2 18 11.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation. It is distributed in the hope that it will be useful, but WITHOUT
       8             : ANY WARRANTY WHATSOEVER.
       9             : 
      10             : Check the License for details. You should have received a copy of it, along
      11             : with the package; see the file 'COPYING'. If not, write to the Free Software
      12             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13             : 
      14             : /*******************************************************************/
      15             : /*                                                                 */
      16             : /*                 INTERFACE TO READLINE COMPLETION                */
      17             : /*                                                                 */
      18             : /*******************************************************************/
      19             : #include "pari.h"
      20             : 
      21             : #ifdef READLINE
      22             : 
      23             : #include "paripriv.h"
      24             : #include "gp.h"
      25             : 
      26             : typedef int (*RLCI)(int, int); /* rl_complete and rl_insert functions */
      27             : 
      28             : BEGINEXTERN
      29             : /* otherwise C++ compilers will choke on rl_message() prototype */
      30             : #define USE_VARARGS
      31             : #define PREFER_STDARG
      32             : #include <readline/readline.h>
      33             : #include <readline/history.h>
      34             : ENDEXTERN
      35             : 
      36             : /**************************************************************************/
      37             : static pari_rl_interface pari_rl;
      38             : static int did_init_matched = 0;
      39             : 
      40             : static int
      41           0 : change_state(const char *msg, ulong flag, int count)
      42             : {
      43           0 :   int c = (GP_DATA->readline_state & flag) != 0;
      44           0 :   ulong state = GP_DATA->readline_state;
      45             : 
      46           0 :   switch(count)
      47             :   {
      48           0 :     default: c = 0; break; /* off */
      49           0 :     case -1: c = 1; break; /* on  */
      50           0 :     case -2: c = 1 - c; /* toggle */
      51             :   }
      52           0 :   if (c)
      53           0 :     GP_DATA->readline_state |= flag;
      54             :   else {
      55           0 :     GP_DATA->readline_state &= ~flag;
      56           0 :     if (!GP_DATA->readline_state && state) GP_DATA->readline_state = 1;
      57             :   }
      58           0 :   rl_save_prompt();
      59           0 :   rl_message("[%s: %s] ", msg, c? "on": "off");
      60           0 :   c = rl_read_key();
      61           0 :   rl_restore_prompt();
      62           0 :   rl_clear_message();
      63           0 :   rl_stuff_char(c); return 1;
      64             : }
      65             : 
      66             : /* Wrapper around rl_complete to allow toggling insertion of arguments */
      67             : static int
      68           0 : pari_rl_complete(int count, int key)
      69             : {
      70             :   int ret;
      71             : 
      72           0 :   pari_rl.back = 0;
      73           0 :   if (count <= 0)
      74           0 :     return change_state("complete args", DO_ARGS_COMPLETE, count);
      75             : 
      76           0 :   rl_begin_undo_group();
      77           0 :   if (rl_last_func == pari_rl_complete)
      78           0 :     rl_last_func = (RLCI) rl_complete; /* Make repeated TABs different */
      79           0 :   ret = ((RLCI)rl_complete)(count,key);
      80           0 :   if (pari_rl.back && (pari_rl.back <= rl_point))
      81           0 :     rl_point -= pari_rl.back;
      82           0 :   rl_end_undo_group(); return ret;
      83             : }
      84             : 
      85             : static int did_matched_insert;
      86             : 
      87             : static int
      88           0 : pari_rl_matched_insert_suspend(int count, int key)
      89             : {
      90           0 :   ulong state = GP_DATA->readline_state;
      91             :   (void)count; (void)key;
      92             : 
      93           0 :   did_matched_insert = (GP_DATA->readline_state & DO_MATCHED_INSERT);
      94           0 :   GP_DATA->readline_state &= ~DO_MATCHED_INSERT;
      95           0 :   if (!GP_DATA->readline_state && state) GP_DATA->readline_state = 1;
      96           0 :   return 1;
      97             : }
      98             : 
      99             : static int
     100           0 : pari_rl_matched_insert_restore(int count, int key)
     101             : {
     102             :   (void)count; (void)key;
     103           0 :   if (did_matched_insert)
     104           0 :     GP_DATA->readline_state |= DO_MATCHED_INSERT;
     105           0 :   return 1;
     106             : }
     107             : 
     108             : static const char paropen[] = "([{";
     109             : static const char parclose[] = ")]}";
     110             : 
     111             : /* To allow insertion of () with a point in between. */
     112             : static int
     113           0 : pari_rl_matched_insert(int count, int key)
     114             : {
     115           0 :   int i = 0, ret;
     116             : 
     117           0 :   if (count <= 0)
     118           0 :     return change_state("electric parens", DO_MATCHED_INSERT, count);
     119           0 :   while (paropen[i] && paropen[i] != key) i++;
     120           0 :   if (!paropen[i] || !(GP_DATA->readline_state & DO_MATCHED_INSERT) || GP_DATA->flags & gpd_EMACS)
     121           0 :     return ((RLCI)rl_insert)(count,key);
     122           0 :   rl_begin_undo_group();
     123           0 :   ((RLCI)rl_insert)(count,key);
     124           0 :   ret = ((RLCI)rl_insert)(count,parclose[i]);
     125           0 :   rl_point -= count;
     126           0 :   rl_end_undo_group(); return ret;
     127             : }
     128             : 
     129             : static int
     130           0 : pari_rl_default_matched_insert(int count, int key)
     131             : {
     132           0 :     if (!did_init_matched) {
     133           0 :       did_init_matched = 1;
     134           0 :       GP_DATA->readline_state |= DO_MATCHED_INSERT;
     135             :     }
     136           0 :     return pari_rl_matched_insert(count, key);
     137             : }
     138             : 
     139             : static int
     140           0 : pari_rl_forward_sexp(int count, int key)
     141             : {
     142           0 :   int deep = 0, dir = 1, move_point = 0, lfail;
     143             : 
     144             :   (void)key;
     145           0 :   if (count < 0)
     146             :   {
     147           0 :     count = -count; dir = -1;
     148           0 :     if (!rl_point) goto fail;
     149           0 :     rl_point--;
     150             :   }
     151           0 :   while (count || deep)
     152             :   {
     153           0 :     move_point = 1;        /* Need to move point if moving left. */
     154           0 :     lfail = 0;                /* Do not need to fail left movement yet. */
     155           0 :     while ( !is_keyword_char(rl_line_buffer[rl_point])
     156           0 :             && !strchr("\"([{}])",rl_line_buffer[rl_point])
     157           0 :             && !( (dir == 1)
     158             :                   ? (rl_point >= rl_end)
     159           0 :                   : (rl_point <= 0 && (lfail = 1))))
     160           0 :         rl_point += dir;
     161           0 :     if (lfail || !rl_line_buffer[rl_point]) goto fail;
     162             : 
     163           0 :     if (is_keyword_char(rl_line_buffer[rl_point]))
     164             :     {
     165           0 :       while ( is_keyword_char(rl_line_buffer[rl_point])
     166           0 :               && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0 && (lfail = 1)))
     167           0 :                   || (move_point = 0)))
     168           0 :         rl_point += dir;
     169           0 :       if (deep && lfail) goto fail;
     170           0 :       if (!deep) count--;
     171             :     }
     172           0 :     else if (strchr(paropen,rl_line_buffer[rl_point]))
     173             :     {
     174           0 :       if (deep == 0 && dir == -1) goto fail; /* We are already out of pars. */
     175           0 :       rl_point += dir;
     176           0 :       deep++; if (!deep) count--;
     177             :     }
     178           0 :     else if (strchr(parclose,rl_line_buffer[rl_point]))
     179             :     {
     180           0 :       if (deep == 0 && dir == 1)
     181             :       {
     182           0 :         rl_point++; goto fail; /* Get out of pars. */
     183             :       }
     184           0 :       rl_point += dir;
     185           0 :       deep--; if (!deep) count--;
     186             :     }
     187           0 :     else if (rl_line_buffer[rl_point] == '\"')
     188             :     {
     189           0 :       int bad = 1;
     190             : 
     191           0 :       rl_point += dir;
     192           0 :       while ( ((rl_line_buffer[rl_point] != '\"') || (bad = 0))
     193           0 :               && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0))
     194           0 :                   || (move_point = 0)) )
     195           0 :         rl_point += dir;
     196           0 :       if (bad) goto fail;
     197           0 :       rl_point += dir;        /* Skip the other delimiter */
     198           0 :       if (!deep) count--;
     199             :     }
     200             :     else
     201             :     {
     202           0 :       fail: rl_ding(); return 1;
     203             :     }
     204             :   }
     205           0 :   if (dir != 1 && move_point) rl_point++;
     206           0 :   return 1;
     207             : }
     208             : 
     209             : static int
     210           0 : pari_rl_backward_sexp(int count, int key)
     211             : {
     212           0 :   return pari_rl_forward_sexp(-count, key);
     213             : }
     214             : 
     215             : static void
     216           0 : rl_print_aide(char *s, int flag)
     217             : {
     218           0 :   int p = rl_point, e = rl_end;
     219           0 :   FILE *save = pari_outfile;
     220             : 
     221           0 :   rl_point = 0; rl_end = 0; pari_outfile = rl_outstream;
     222           0 :   rl_save_prompt();
     223           0 :   rl_message("%s",""); /* rl_message("") ==> "zero length format" warning */
     224           0 :   gp_help(s, flag);
     225           0 :   rl_restore_prompt();
     226           0 :   rl_point = p; rl_end = e; pari_outfile = save;
     227           0 :   rl_clear_message();
     228           0 :   rl_refresh_line(0,0);
     229           0 : }
     230             : 
     231             : /* long help if count < 0 */
     232             : static int
     233           0 : rl_short_help(int count, int key)
     234             : {
     235           0 :   int flag = h_RL;
     236           0 :   char *s = rl_line_buffer + rl_point;
     237             : 
     238             :   (void)key;
     239             :   /* func() with cursor on ')', e.g. following completion */
     240           0 :   if (s > rl_line_buffer && *s == ')' && s[-1] == '(') s--;
     241           0 :   while (s > rl_line_buffer && is_keyword_char(s[-1])) s--;
     242             :   /* check for '\c' */
     243           0 :   if (s > rl_line_buffer && s[-1] == '\\') s--;
     244             : 
     245           0 :   if (count < 0 || rl_last_func == rl_short_help) flag |= h_LONG;
     246           0 :   rl_print_aide(s, flag); return 0;
     247             : }
     248             : 
     249             : static int
     250           0 : rl_long_help(int count, int key) { (void)count; return rl_short_help(-1,key); }
     251             : 
     252             : static void
     253        1843 : init_histfile(void)
     254             : {
     255        1843 :   char *h = GP_DATA->histfile;
     256        1843 :   if (h && read_history(h)) write_history(h);
     257        1843 : }
     258             : 
     259             : /*******************************************************************/
     260             : /*                                                                 */
     261             : /*                   GET LINE FROM READLINE                        */
     262             : /*                                                                 */
     263             : /*******************************************************************/
     264             : static int
     265           0 : history_is_new(char *s)
     266             : {
     267             :   HIST_ENTRY *e;
     268           0 :   if (!*s) return 0;
     269           0 :   if (!history_length) return 1;
     270           0 :   e = history_get(history_length);
     271             :   /* paranoia: e != NULL, unless readline is in a weird state */
     272           0 :   return e? strcmp(s, e->line): 0;
     273             : }
     274             : 
     275             : static void
     276           0 : gp_add_history(char *s)
     277             : {
     278           0 :   if (history_is_new(s)) { add_history(s); append_history(1,GP_DATA->histfile); }
     279           0 : }
     280             : 
     281             : /* Read line; returns a malloc()ed string of the user input or NULL on EOF.
     282             :    Increments the buffer size appropriately if needed; fix *endp if so. */
     283             : static char *
     284           0 : gprl_input(char **endp, int first, input_method *IM, filtre_t *F)
     285             : {
     286           0 :   pari_sp av = avma;
     287           0 :   Buffer *b = F->buf;
     288           0 :   ulong used = *endp - b->buf;
     289           0 :   ulong left = b->len - used, l;
     290             :   const char *p;
     291             :   char *s, *t;
     292             : 
     293           0 :   if (first) p = IM->prompt;
     294             :   else {
     295           0 :     p = F->in_comment ? GP_DATA->prompt_comment: IM->prompt_cont;
     296           0 :     p = gp_format_prompt(p);
     297             :   }
     298           0 :   if (! (s = readline(p)) ) { avma = av; return NULL; } /* EOF */
     299           0 :   gp_add_history(s); /* Makes a copy */
     300           0 :   l = strlen(s) + 1;
     301             :   /* put back \n that readline stripped. This is needed for
     302             :    * { print("a
     303             :    *   b"); }
     304             :    * and conforms with the other input methods anyway. */
     305           0 :   t = (char*)pari_malloc(l + 1);
     306           0 :   strncpy(t, s, l-1);
     307           0 :   t[l-1] = '\n';
     308           0 :   t[l]   = 0; /* equivalent to sprintf(t,"%s\n", s) */
     309           0 :   if (left < l)
     310             :   {
     311           0 :     ulong incr = b->len;
     312           0 :     if (incr < l) incr = l;
     313           0 :     fix_buffer(b, b->len + incr);
     314           0 :     *endp = b->buf + used;
     315             :   }
     316           0 :   avma = av; return t;
     317             : }
     318             : 
     319             : /* request one line interactively.
     320             :  * Return 0: EOF
     321             :  *        1: got one line from readline or pari_infile */
     322             : int
     323           0 : get_line_from_readline(const char *prompt, const char *prompt_cont, filtre_t *F)
     324             : {
     325           0 :   const int index = history_length;
     326             :   char *s;
     327             :   input_method IM;
     328             : 
     329           0 :   if (!GP_DATA->use_readline)
     330             :   {
     331           0 :     pari_puts(prompt); pari_flush();
     332           0 :     return get_line_from_file(prompt, F, pari_infile);
     333             :   }
     334             : 
     335           0 :   IM.prompt      = prompt;
     336           0 :   IM.prompt_cont = prompt_cont;
     337           0 :   IM.getline = &gprl_input;
     338           0 :   IM.free = 1;
     339           0 :   if (! input_loop(F,&IM)) { pari_puts("\n"); return 0; }
     340             : 
     341           0 :   s = F->buf->buf;
     342           0 :   if (*s)
     343             :   {
     344           0 :     if (history_length > index+1)
     345             :     { /* Multi-line input. Remove incomplete lines */
     346           0 :       int i = history_length;
     347           0 :       while (i > index) {
     348           0 :         HIST_ENTRY *e = remove_history(--i);
     349           0 :         pari_free(e->line); pari_free(e);
     350             :       }
     351           0 :       gp_add_history(s);
     352             :     }
     353           0 :     gp_echo_and_log(prompt, s);
     354             :   }
     355           0 :   return 1;
     356             : }
     357             : 
     358             : static char**
     359           0 : gp_completion(char *text, int START, int END)
     360             : {
     361           0 :   return pari_completion(&pari_rl, text, START, END);
     362             : }
     363             : 
     364             : void
     365        1843 : init_readline(void)
     366             : {
     367             :   static int init_done = 0;
     368             : 
     369        3686 :   if (init_done) return;
     370             : 
     371        1843 :   pari_use_readline(pari_rl);
     372             : 
     373        1843 :   if (! GP_DATA->use_readline) GP_DATA->readline_state = 0;
     374        1843 :   init_done = 1;
     375        1843 :   init_histfile();
     376        1843 :   cb_pari_init_histfile = init_histfile;
     377        1843 :   cb_pari_get_line_interactive = get_line_from_readline;
     378             : 
     379             :   /* Allow conditional parsing of the ~/.inputrc file. */
     380        1843 :   rl_readline_name = "Pari-GP";
     381             : 
     382             :   /* added ~, ? and , */
     383        1843 :   rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(?~";
     384        1843 :   rl_special_prefixes = "~";
     385             : 
     386             :   /* custom completer */
     387        1843 :   rl_attempted_completion_function = (rl_completion_func_t*) gp_completion;
     388             : 
     389             :   /* we always want the whole list of completions under emacs */
     390        1843 :   if (GP_DATA->flags & gpd_EMACS) rl_completion_query_items = 0x8fff;
     391             : 
     392        1843 :   rl_add_defun("short-help", rl_short_help, -1);
     393        1843 :   rl_add_defun("long-help", rl_long_help, -1);
     394        1843 :   rl_add_defun("pari-complete", pari_rl_complete, '\t');
     395        1843 :   rl_add_defun("pari-matched-insert", pari_rl_default_matched_insert, -1);
     396        1843 :   rl_add_defun("pari-matched-insert-suspend", pari_rl_matched_insert_suspend, -1);
     397        1843 :   rl_add_defun("pari-matched-insert-restore", pari_rl_matched_insert_restore, -1);
     398        1843 :   rl_add_defun("pari-forward-sexp", pari_rl_forward_sexp, -1);
     399        1843 :   rl_add_defun("pari-backward-sexp", pari_rl_backward_sexp, -1);
     400             : 
     401        1843 :   rl_bind_key_in_map('h', rl_short_help, emacs_meta_keymap);
     402        1843 :   rl_bind_key_in_map('H', rl_long_help,  emacs_meta_keymap);
     403             : 
     404             : #define KSbind(s,f,k) rl_generic_bind(ISFUNC, (s), (char*)(f), (k))
     405             : 
     406        1843 :   KSbind("OP",   rl_short_help,  emacs_meta_keymap); /* f1, vt100 */
     407        1843 :   KSbind("[11~", rl_short_help,  emacs_meta_keymap); /* f1, xterm */
     408        1843 :   KSbind("OP",   rl_short_help,  vi_movement_keymap); /* f1, vt100 */
     409        1843 :   KSbind("[11~", rl_short_help,  vi_movement_keymap); /* f1, xterm */
     410             :   /* XTerm may signal start/end of paste by emitting F200/F201
     411             :    * TODO: check to what extent this patch has been applied */
     412             :   /* FIXME: For vi mode something more intelligent is needed - to switch to the
     413             :      insert mode - and back when restoring. */
     414        1843 :   KSbind("[200~", pari_rl_matched_insert_suspend,  emacs_meta_keymap);  /* pre-paste xterm */
     415        1843 :   KSbind("[200~", pari_rl_matched_insert_suspend,  vi_movement_keymap); /* pre-paste xterm */
     416        1843 :   KSbind("[201~", pari_rl_matched_insert_restore,  emacs_meta_keymap);  /* post-paste xterm */
     417        1843 :   KSbind("[201~", pari_rl_matched_insert_restore,  vi_movement_keymap); /* post-paste xterm */
     418        1843 :   rl_bind_key_in_map('(', pari_rl_matched_insert, emacs_standard_keymap);
     419        1843 :   rl_bind_key_in_map('[', pari_rl_matched_insert, emacs_standard_keymap);
     420        1843 :   rl_bind_key_in_map(6, pari_rl_forward_sexp,  emacs_meta_keymap); /* M-C-f */
     421        1843 :   rl_bind_key_in_map(2, pari_rl_backward_sexp, emacs_meta_keymap); /* M-C-b */
     422             : }
     423             : #endif

Generated by: LCOV version 1.11