Jeroen Demeyer on Thu, 10 Sep 2015 20:07:16 +0200


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

Re: Reading a stream from a C string


On 2015-09-08 19:22, Bill Allombert wrote:
Alas this is not implemented. At minimum one would need to implement an
'input_method' which handle C strings.

This (attached patch) works for me. It adds a function gp_read_file_from_str() which is like gp_read_file() but from a string.

Note that there is a hack involved: a cast of FILE* to char** for the third argument of fgets(). Perhaps using a void* in all cases would be cleaner.

I added a helper function gp_read_from_input() which is general enough that it could be used to implement gp_read_file() and gp_read_stream() also. I didn't do this since I wanted some feedback first.

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

    New function gp_read_file_from_str

diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h
index b17bced..107484f 100644
--- a/src/headers/paridecl.h
+++ b/src/headers/paridecl.h
@@ -2459,6 +2459,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_file_from_str(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..76d047a 100644
--- a/src/headers/paripriv.h
+++ b/src/headers/paripriv.h
@@ -484,13 +484,13 @@ int path_is_absolute(char *s);
 
 typedef struct input_method {
 /* 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 */
   const char *prompt, *prompt_cont;
 /* for non-interactive methods */
   FILE *file;
+  char * (*fgets)(char *, int, FILE*);
 } input_method;
 
 int input_loop(filtre_t *F, input_method *IM);
diff --git a/src/language/es.c b/src/language/es.c
index 2ac5919..20f347f 100644
--- a/src/language/es.c
+++ b/src/language/es.c
@@ -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_file_from_str(const char *s)
+{
+  input_method IM;
+  const char *ptr = s;
+
+  IM.file = (FILE*)(&ptr);
+  IM.fgets = (char* (*)(char*, int, FILE*))&string_gets;
+  IM.getline = &file_input;
+  IM.free = 0;
+
+  return gp_read_from_input(&IM, 1);
+}
+
 GEN
 gp_readvec_stream(FILE *fi)
 {