Jeroen Demeyer on Tue, 22 Sep 2015 12:27:55 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: Reading a stream from a C string


On 2015-09-22 09:57, Bill Allombert wrote:
Your patch looks fine, but could you add the documentantion for
gp_read_str_multiline ?

Also please remove the tabs.
Done!

commit df8cf45bbe3f9f68af0146bc162082c5d0be9fc6
Author: Jeroen Demeyer <jdemeyer@cage.ugent.be>
Date:   Thu Sep 10 19:35:22 2015 +0200

    New function gp_read_str_multiline

diff --git a/doc/usersch4.tex b/doc/usersch4.tex
index c2014dc..719e512 100644
--- a/doc/usersch4.tex
+++ b/doc/usersch4.tex
@@ -1694,15 +1694,27 @@ library mode: input and output of PARI objects.
 \subsec{Input}
 
 \noindent
-For \idx{input}, PARI provides a powerful high level function
-which enables you to input your objects as if you were under \kbd{gp}. In fact,
+For \idx{input}, PARI provides several powerful high level functions
+which enable you to input your objects as if you were under \kbd{gp}. In fact,
 it \emph{is} essentially the GP syntactical parser.
-It has the following syntax:\label{se:gp_read_str}
 
-\fun{GEN}{gp_read_str}{const char *s}
+There are two similar functions available to parse a string:
+
+\fun{GEN}{gp_read_str}{const char *s}\label{se:gp_read_str}
+
+\fun{GEN}{gp_read_str_multiline}{const char *s}
 
 \noindent
-Note that \kbd{gp}'s metacommands \emph{are} recognized.
+Both functions read the whole string \kbd{s}. The function
+\kbd{gp\_read\_str} ignores newlines: it assumes that the input is one
+expression and returns the result of this expression.
+
+The function \kbd{gp\_read\_str\_multiline} processes the text in the
+same way as the GP command \tet{read}: newlines are significant and can
+be used to separate expressions.
+The return value is that of the last non-empty expression evaluated.
+
+For both functions, \kbd{gp}'s metacommands \emph{are} recognized.
 
 \misctitle{Note} The obsolete form
 
diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h
index a46cfc3..d101dc9 100644
--- a/src/headers/paridecl.h
+++ b/src/headers/paridecl.h
@@ -2462,6 +2462,7 @@ void    err_flush(void);
 void    err_printf(const char* pat, ...);
 GEN     gp_getenv(const char *s);
 GEN     gp_read_file(const char *s);
+GEN     gp_read_str_multiline(const char *s);
 GEN     gp_read_stream(FILE *f);
 GEN     gp_readvec_file(char *s);
 GEN     gp_readvec_stream(FILE *f);
diff --git a/src/headers/paripriv.h b/src/headers/paripriv.h
index e9526fb..a6548d4 100644
--- a/src/headers/paripriv.h
+++ b/src/headers/paripriv.h
@@ -482,15 +482,17 @@ void gp_expand_path(gp_path *p);
 const char *pari_default_path(void);
 int path_is_absolute(char *s);
 
+typedef char *(*fgets_t)(char *, int, void*);
+
 typedef struct input_method {
+/* optional */
+  fgets_t fgets;  /* like libc fgets() but last argument is (void*) */
 /* mandatory */
-  char * (*fgets)(char *,int,FILE*);
   char * (*getline)(char**, int f, struct input_method*, filtre_t *F);
   int free; /* boolean: must we free the output of getline() ? */
-/* for interactive methods */
+/* optional */
   const char *prompt, *prompt_cont;
-/* for non-interactive methods */
-  FILE *file;
+  void *file;  /* can be used as last argument for fgets() */
 } input_method;
 
 int input_loop(filtre_t *F, input_method *IM);
diff --git a/src/language/es.c b/src/language/es.c
index 47061e5..8ea6f59 100644
--- a/src/language/es.c
+++ b/src/language/es.c
@@ -246,9 +246,9 @@ gp_read_stream_buf(FILE *fi, Buffer *b)
 
   init_filtre(&F, b);
 
-  IM.file = fi;
-  IM.fgets= &fgets;
-  IM.getline= &file_input;
+  IM.file = (void*)fi;
+  IM.fgets = (fgets_t)&fgets;
+  IM.getline = &file_input;
   IM.free = 0;
   return input_loop(&F,&IM);
 }
@@ -261,6 +261,21 @@ gp_read_stream(FILE *fi)
   delete_buffer(b); return x;
 }
 
+static GEN
+gp_read_from_input(input_method* IM, int loop)
+{
+  Buffer *b = new_buffer();
+  GEN x = gnil;
+  filtre_t F;
+  do {
+    init_filtre(&F, b);
+    if (!input_loop(&F, IM)) break;
+    if (*(b->buf)) x = readseq(b->buf);
+  } while (loop);
+  delete_buffer(b);
+  return x;
+}
+
 GEN
 gp_read_file(const char *s)
 {
@@ -283,6 +298,41 @@ gp_read_file(const char *s)
   popinfile(); return x;
 }
 
+static char*
+string_gets(char *s, int size, const char **ptr)
+{
+  /* f is actually a const char** */
+  const char *in = *ptr;
+  int i;
+  char c;
+
+  /* Copy from in to s */
+  for (i = 0; i+1 < size && in[i] != 0;)
+  {
+    s[i] = c = in[i]; i++;
+    if (c == '\n') break;
+  }
+  s[i] = 0;  /* Terminating 0 byte */
+  if (i == 0) return NULL;
+
+  *ptr += i;
+  return s;
+}
+
+GEN
+gp_read_str_multiline(const char *s)
+{
+  input_method IM;
+  const char *ptr = s;
+
+  IM.file = (void*)(&ptr);
+  IM.fgets = (fgets_t)&string_gets;
+  IM.getline = &file_input;
+  IM.free = 0;
+
+  return gp_read_from_input(&IM, 1);
+}
+
 GEN
 gp_readvec_stream(FILE *fi)
 {
@@ -4165,8 +4215,8 @@ get_lines(FILE *F)
   GEN z = cgetg(nz + 1, t_VEC);
   Buffer *b = new_buffer();
   input_method IM;
-  IM.fgets = &fgets;
-  IM.file = F;
+  IM.fgets = (fgets_t)&fgets;
+  IM.file = (void*)F;
   for(i = 1;;)
   {
     char *s = b->buf, *e;
diff --git a/src/language/gplib.c b/src/language/gplib.c
index c3bdc3e..dac1eff 100644
--- a/src/language/gplib.c
+++ b/src/language/gplib.c
@@ -1122,8 +1122,11 @@ get_line_from_file(const char *prompt, filtre_t *F, FILE *file)
   char *s;
   input_method IM;
 
-  IM.file = file;
-  IM.fgets= (file==stdin && cb_pari_fgets_interactive)? cb_pari_fgets_interactive: &fgets;
+  IM.file = (void*)file;
+  if (file==stdin && cb_pari_fgets_interactive)
+    IM.fgets = (fgets_t)cb_pari_fgets_interactive;
+  else
+    IM.fgets = (fgets_t)&fgets;
   IM.getline = &file_input;
   IM.free = 0;
   if (! input_loop(F,&IM))