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))