wpp: add I/O hooks [try 3]
Matteo Bruni
matteo.mystral at gmail.com
Sun Aug 23 17:50:57 CDT 2009
The change from try 2 is removing the glibc >= 2.1 assumption (related
to vsnprintf usage). You can look at [
http://www.winehq.org/pipermail/wine-patches/2009-August/077205.html ]
and [ http://www.winehq.org/pipermail/wine-patches/2009-August/077206.html
] for a couple of use cases for this patch.
-------------- next part --------------
From 2f5ad8f75334dab98b43289739b2ee4b2182cf66 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Mon, 24 Aug 2009 00:38:53 +0200
Subject: wpp: Add I/O hooks
---
include/wine/wpp.h | 19 ++++++
libs/wpp/ppl.l | 75 ++++++++++++++++++++--
libs/wpp/ppy.y | 16 +++---
libs/wpp/preproc.c | 163 +++++++++++++++++++++++++++++-------------------
libs/wpp/wpp.c | 16 ++++-
libs/wpp/wpp_private.h | 6 ++-
6 files changed, 210 insertions(+), 85 deletions(-)
diff --git a/include/wine/wpp.h b/include/wine/wpp.h
index 10b71e0..763c348 100644
--- a/include/wine/wpp.h
+++ b/include/wine/wpp.h
@@ -33,4 +33,23 @@ extern char *wpp_find_include( const char *name, const char *parent_name );
extern int wpp_parse( const char *input, FILE *output );
extern int wpp_parse_temp( const char *input, const char *output_base, char **output_name );
+struct wpp_io_callback {
+ /* looks for a file to include, returning the path where it is found */
+ /* parent_name is the directory of the parent source file (for local
+ * includes), includepath is an array of additional include paths */
+ char *(*lookup)( const char *filename, const char *parent_name,
+ char **include_path, int include_path_count );
+ /* opens an include file */
+ /* the type param is true if it is a local ("...") include */
+ void *(*open)( const char *filename, int type );
+ /* closes a previously opened file */
+ void (*close)( void *file );
+ /* reads buffer from the input */
+ int (*read)( void *file, char *buffer, unsigned int len );
+ /* writes buffer to the output */
+ void (*write)( const char *buffer, unsigned int len );
+};
+
+void wpp_set_callback( struct wpp_io_callback *callback );
+
#endif /* __WINE_WPP_H */
diff --git a/libs/wpp/ppl.l b/libs/wpp/ppl.l
index e71bf6e..ccbfbee 100644
--- a/libs/wpp/ppl.l
+++ b/libs/wpp/ppl.l
@@ -160,6 +160,7 @@ ul [uUlL]|[uUlL][lL]|[lL][uU]|[lL][lL][uU]|[uU][lL][lL]|[lL][uU][lL]
#include "wine/port.h"
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
@@ -178,6 +179,7 @@ ul [uUlL]|[uUlL][lL]|[lL][uU]|[lL][lL][uU]|[uU][lL][lL]|[lL][uU][lL]
#define YY_NO_UNISTD_H
#endif
+#include "wine/wpp.h"
#include "wpp_private.h"
#include "ppy.tab.h"
@@ -205,6 +207,7 @@ ul [uUlL]|[uUlL][lL]|[lL][uU]|[lL][lL][uU]|[uU][lL][lL]|[lL][uU][lL]
typedef struct bufferstackentry {
YY_BUFFER_STATE bufferstate; /* Buffer to switch back to */
+ void *filehandle; /* Handle to be used for io_callback->read */
pp_entry_t *define; /* Points to expanding define or NULL if handling includes */
int line_number; /* Line that we were handling */
int char_number; /* The current position on that line */
@@ -298,6 +301,60 @@ include_state_t pp_incl_state =
includelogicentry_t *pp_includelogiclist = NULL;
+void *currentfile;
+
+#define YY_INPUT(buf,result,max_size) \
+ { \
+ result = io_callback->read(currentfile,buf,max_size); \
+/*if(result < max_size) ((char *)buf)[result] = YY_NULL;*/ \
+ }
+
+#define BUFFERINITIALCAPACITY 256
+
+void writestring( const char *format, ... )
+{
+ va_list valist;
+ int len;
+ static char *buffer;
+ static int buffercapacity;
+
+ if(buffercapacity == 0)
+ {
+ buffer = malloc( BUFFERINITIALCAPACITY );
+ if(!buffer)
+ {
+ fprintf(stderr, "Error allocating memory\n");
+ exit(2);
+ }
+ buffercapacity = BUFFERINITIALCAPACITY;
+ }
+
+ va_start(valist, format);
+ len = vsnprintf(buffer, buffercapacity,
+ format, valist);
+ /* If the string is longer than buffersize, vsnprintf returns
+ * the string length with glibc >= 2.1, -1 with glibc < 2.1 */
+ while(len > buffercapacity || len < 0)
+ {
+ do
+ {
+ buffercapacity *= 2;
+ } while(len > buffercapacity);
+
+ buffer = realloc(buffer, buffercapacity);
+ if(!buffer)
+ {
+ fprintf(stderr, "Error allocating memory\n");
+ exit(2);
+ }
+ len = vsnprintf(buffer, buffercapacity,
+ format, valist);
+ }
+ va_end(valist);
+
+ io_callback->write(buffer, len);
+}
+
%}
/*
@@ -1214,6 +1271,7 @@ static void push_buffer(pp_entry_t *ppp, char *filename, char *incname, int pop)
memset(&bufferstack[bufferstackidx], 0, sizeof(bufferstack[0]));
bufferstack[bufferstackidx].bufferstate = YY_CURRENT_BUFFER;
+ bufferstack[bufferstackidx].filehandle = currentfile;
bufferstack[bufferstackidx].define = ppp;
bufferstack[bufferstackidx].line_number = pp_status.line_number;
bufferstack[bufferstackidx].char_number = pp_status.char_number;
@@ -1259,8 +1317,8 @@ static bufferstackentry_t *pop_buffer(void)
ncontinuations = bufferstack[bufferstackidx].ncontinuations;
if(!bufferstack[bufferstackidx].should_pop)
{
- fclose(ppy_in);
- fprintf(ppy_out, "# %d \"%s\" 2\n", pp_status.line_number, pp_status.input);
+ io_callback->close(currentfile);
+ writestring("# %d \"%s\" 2\n", pp_status.line_number, pp_status.input);
/* We have EOF, check the include logic */
if(pp_incl_state.state == 2 && !pp_incl_state.seen_junk && pp_incl_state.ppp)
@@ -1300,7 +1358,8 @@ static bufferstackentry_t *pop_buffer(void)
bufferstack[bufferstackidx].filename,
bufferstack[bufferstackidx].should_pop);
- ppy__switch_to_buffer(bufferstack[bufferstackidx].bufferstate);
+ currentfile = bufferstack[bufferstackidx].filehandle;
+ ppy__switch_to_buffer(bufferstack[bufferstackidx].bufferstate);
if(bufferstack[bufferstackidx].should_pop)
{
@@ -1441,7 +1500,7 @@ static void put_buffer(const char *s, int len)
if(top_macro())
add_text_to_macro(s, len);
else
- fwrite(s, 1, len, ppy_out);
+ io_callback->write(s, len);
}
@@ -1455,6 +1514,7 @@ void pp_do_include(char *fname, int type)
char *newpath;
int n;
includelogicentry_t *iep;
+ void *fp;
for(iep = pp_includelogiclist; iep; iep = iep->next)
{
@@ -1477,7 +1537,7 @@ void pp_do_include(char *fname, int type)
/* Undo the effect of the quotation */
fname[n-1] = '\0';
- if((ppy_in = pp_open_include(fname+1, type ? pp_status.input : NULL, &newpath)) == NULL)
+ if((fp = pp_open_include(fname+1, type ? pp_status.input : NULL, &newpath)) == NULL)
ppy_error("Unable to open include file %s", fname+1);
fname[n-1] = *fname; /* Redo the quotes */
@@ -1489,9 +1549,10 @@ void pp_do_include(char *fname, int type)
if(pp_status.debug)
fprintf(stderr, "pp_do_include: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n",
pp_status.input, pp_status.line_number, pp_incl_state.state, pp_incl_state.ppp, pp_incl_state.ifdepth);
- ppy__switch_to_buffer(ppy__create_buffer(ppy_in, YY_BUF_SIZE));
+ currentfile = fp;
+ ppy__switch_to_buffer(ppy__create_buffer(NULL, YY_BUF_SIZE));
- fprintf(ppy_out, "# 1 \"%s\" 1%s\n", newpath, type ? "" : " 3");
+ writestring("# 1 \"%s\" 1%s\n", newpath, type ? "" : " 3");
}
/*
diff --git a/libs/wpp/ppy.y b/libs/wpp/ppy.y
index fc94bb5..c5723ef 100644
--- a/libs/wpp/ppy.y
+++ b/libs/wpp/ppy.y
@@ -264,27 +264,27 @@ preprocessor
}
if(pp_status.debug)
fprintf(stderr, "tENDIF: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n",
- pp_status.input, pp_status.line_number, pp_incl_state.state, pp_incl_state.ppp, pp_incl_state.ifdepth);
+ pp_status.input, pp_status.line_number, pp_incl_state.state, pp_incl_state.ppp, pp_incl_state.ifdepth);
}
| tUNDEF tIDENT tNL { pp_del_define($2); free($2); }
| tDEFINE opt_text tNL { pp_add_define($1, $2); }
| tMACRO res_arg allmargs tMACROEND opt_mtexts tNL {
pp_add_macro($1, macro_args, nmacro_args, $5);
}
- | tLINE tSINT tDQSTRING tNL { fprintf(ppy_out, "# %d %s\n", $2 , $3); free($3); }
- | tGCCLINE tSINT tDQSTRING tNL { fprintf(ppy_out, "# %d %s\n", $2 , $3); free($3); }
+ | tLINE tSINT tDQSTRING tNL { writestring("# %d %s\n", $2 , $3); free($3); }
+ | tGCCLINE tSINT tDQSTRING tNL { writestring("# %d %s\n", $2 , $3); free($3); }
| tGCCLINE tSINT tDQSTRING tSINT tNL
- { fprintf(ppy_out, "# %d %s %d\n", $2, $3, $4); free($3); }
+ { writestring("# %d %s %d\n", $2, $3, $4); free($3); }
| tGCCLINE tSINT tDQSTRING tSINT tSINT tNL
- { fprintf(ppy_out, "# %d %s %d %d\n", $2 ,$3, $4, $5); free($3); }
+ { writestring("# %d %s %d %d\n", $2 ,$3, $4, $5); free($3); }
| tGCCLINE tSINT tDQSTRING tSINT tSINT tSINT tNL
- { fprintf(ppy_out, "# %d %s %d %d %d\n", $2 ,$3 ,$4 ,$5, $6); free($3); }
+ { writestring("# %d %s %d %d %d\n", $2 ,$3 ,$4 ,$5, $6); free($3); }
| tGCCLINE tSINT tDQSTRING tSINT tSINT tSINT tSINT tNL
- { fprintf(ppy_out, "# %d %s %d %d %d %d\n", $2 ,$3 ,$4 ,$5, $6, $7); free($3); }
+ { writestring("# %d %s %d %d %d %d\n", $2 ,$3 ,$4 ,$5, $6, $7); free($3); }
| tGCCLINE tNL /* The null-token */
| tERROR opt_text tNL { ppy_error("#error directive: '%s'", $2); free($2); }
| tWARNING opt_text tNL { ppy_warning("#warning directive: '%s'", $2); free($2); }
- | tPRAGMA opt_text tNL { fprintf(ppy_out, "#pragma %s\n", $2 ? $2 : ""); free($2); }
+ | tPRAGMA opt_text tNL { writestring("#pragma %s\n", $2 ? $2 : ""); free($2); }
| tPPIDENT opt_text tNL { if(pp_status.pedantic) ppy_warning("#ident ignored (arg: '%s')", $2); free($2); }
| tRCINCLUDE tRCINCLUDEPATH {
int nl=strlen($2) +3;
diff --git a/libs/wpp/preproc.c b/libs/wpp/preproc.c
index 63455ce..c3e5ff0 100644
--- a/libs/wpp/preproc.c
+++ b/libs/wpp/preproc.c
@@ -113,6 +113,98 @@ char *pp_xstrdup(const char *str)
return memcpy(s, str, len);
}
+char *wpp_default_lookup( const char *name, const char *parent_name,
+ char **include_path, int include_path_count )
+{
+ char *cpy;
+ char *cptr;
+ char *path;
+ const char *ccptr;
+ int i, fd;
+
+ cpy = pp_xmalloc(strlen(name)+1);
+ cptr = cpy;
+
+ for(ccptr = name; *ccptr; ccptr++)
+ {
+ /* Convert to forward slash */
+ if(*ccptr == '\\') {
+ /* kill double backslash */
+ if(ccptr[1] == '\\')
+ ccptr++;
+ *cptr = '/';
+ }else {
+ *cptr = *ccptr;
+ }
+ cptr++;
+ }
+ *cptr = '\0';
+
+ if(parent_name)
+ {
+ /* Search directory of parent include and then -I path */
+ const char *p;
+
+ if ((p = strrchr( parent_name, '/' ))) p++;
+ else p = parent_name;
+ path = pp_xmalloc( (p - parent_name) + strlen(cpy) + 1 );
+ memcpy( path, parent_name, p - parent_name );
+ strcpy( path + (p - parent_name), cpy );
+ fd = open( path, O_RDONLY );
+ if (fd != -1)
+ {
+ close( fd );
+ free( cpy );
+ return path;
+ }
+ free( path );
+ }
+ /* Search -I path */
+ for(i = 0; i < include_path_count; i++)
+ {
+ path = pp_xmalloc(strlen(include_path[i]) + strlen(cpy) + 2);
+ strcpy(path, include_path[i]);
+ strcat(path, "/");
+ strcat(path, cpy);
+ fd = open( path, O_RDONLY );
+ if (fd != -1)
+ {
+ close( fd );
+ free( cpy );
+ return path;
+ }
+ free( path );
+ }
+ free( cpy );
+ return NULL;
+}
+
+void *wpp_default_open(const char *filename, int type) {
+ return fopen(filename,"rt");
+}
+
+void wpp_default_close(void *file) {
+ fclose(file);
+}
+
+int wpp_default_read(void *file, char *buffer, unsigned int len){
+ return fread(buffer, 1, len, file);
+}
+
+void wpp_default_write( const char *buffer, unsigned int len ) {
+ fwrite(buffer, 1, len, ppy_out);
+}
+
+struct wpp_io_callback default_callback = {
+ wpp_default_lookup,
+ wpp_default_open,
+ wpp_default_close,
+ wpp_default_read,
+ wpp_default_write,
+};
+
+struct wpp_io_callback *io_callback = &default_callback;
+
/* Don't comment on the hash, its primitive but functional... */
static int pphash(const char *str)
{
@@ -358,76 +450,17 @@ void wpp_add_include_path(const char *path)
char *wpp_find_include(const char *name, const char *parent_name)
{
- char *cpy;
- char *cptr;
- char *path;
- const char *ccptr;
- int i, fd;
-
- cpy = pp_xmalloc(strlen(name)+1);
- cptr = cpy;
-
- for(ccptr = name; *ccptr; ccptr++)
- {
- /* Convert to forward slash */
- if(*ccptr == '\\') {
- /* kill double backslash */
- if(ccptr[1] == '\\')
- ccptr++;
- *cptr = '/';
- }else {
- *cptr = *ccptr;
- }
- cptr++;
- }
- *cptr = '\0';
-
- if(parent_name)
- {
- /* Search directory of parent include and then -I path */
- const char *p;
-
- if ((p = strrchr( parent_name, '/' ))) p++;
- else p = parent_name;
- path = pp_xmalloc( (p - parent_name) + strlen(cpy) + 1 );
- memcpy( path, parent_name, p - parent_name );
- strcpy( path + (p - parent_name), cpy );
- fd = open( path, O_RDONLY );
- if (fd != -1)
- {
- close( fd );
- free( cpy );
- return path;
- }
- free( path );
- }
- /* Search -I path */
- for(i = 0; i < nincludepath; i++)
- {
- path = pp_xmalloc(strlen(includepath[i]) + strlen(cpy) + 2);
- strcpy(path, includepath[i]);
- strcat(path, "/");
- strcat(path, cpy);
- fd = open( path, O_RDONLY );
- if (fd != -1)
- {
- close( fd );
- free( cpy );
- return path;
- }
- free( path );
- }
- free( cpy );
- return NULL;
+ return wpp_default_lookup(name, parent_name, includepath, nincludepath);
}
-FILE *pp_open_include(const char *name, const char *parent_name, char **newpath)
+void *pp_open_include(const char *name, const char *parent_name, char **newpath)
{
char *path;
- FILE *fp;
+ void *fp;
- if (!(path = wpp_find_include( name, parent_name ))) return NULL;
- fp = fopen(path, "rt");
+ if (!(path = io_callback->lookup( name, parent_name, includepath,
+ nincludepath))) return NULL;
+ fp = io_callback->open(path, parent_name==NULL ? 1 : 0);
if (fp)
{
diff --git a/libs/wpp/wpp.c b/libs/wpp/wpp.c
index d149591..9130812 100644
--- a/libs/wpp/wpp.c
+++ b/libs/wpp/wpp.c
@@ -149,8 +149,8 @@ int wpp_parse( const char *input, FILE *output )
add_cmdline_defines();
add_special_defines();
- if (!input) ppy_in = stdin;
- else if (!(ppy_in = fopen(input, "rt")))
+ if (!input) currentfile = stdin;
+ else if (!(currentfile = io_callback->open(input, 1)))
{
fprintf(stderr,"Could not open %s\n", input);
exit(2);
@@ -159,11 +159,11 @@ int wpp_parse( const char *input, FILE *output )
pp_status.input = input;
ppy_out = output;
- fprintf(ppy_out, "# 1 \"%s\" 1\n", input ? input : "");
+ writestring("# 1 \"%s\" 1\n", input ? input : "");
ret = ppy_parse();
- if (input) fclose(ppy_in);
+ if (input) io_callback->close(currentfile);
pp_pop_define_state();
return ret;
}
@@ -199,3 +199,11 @@ int wpp_parse_temp( const char *input, const char *output_base, char **output_na
fclose( output );
return ret;
}
+
+void wpp_set_callback( struct wpp_io_callback *callback )
+{
+ if(callback == NULL){
+ io_callback = &default_callback;
+ }
+ else io_callback = callback;
+}
diff --git a/libs/wpp/wpp_private.h b/libs/wpp/wpp_private.h
index 24ed6b8..d04fab8 100644
--- a/libs/wpp/wpp_private.h
+++ b/libs/wpp/wpp_private.h
@@ -195,6 +195,9 @@ typedef struct cval {
} val;
} cval_t;
+extern struct wpp_io_callback *io_callback;
+extern struct wpp_io_callback default_callback;
+extern void *currentfile;
void *pp_xmalloc(size_t);
@@ -206,7 +209,7 @@ void pp_pop_define_state(void);
pp_entry_t *pp_add_define(char *def, char *text);
pp_entry_t *pp_add_macro(char *ident, marg_t *args[], int nargs, mtext_t *exp);
void pp_del_define(const char *name);
-FILE *pp_open_include(const char *name, const char *parent_name, char **newpath);
+void *pp_open_include(const char *name, const char *parent_name, char **newpath);
void pp_push_if(pp_if_state_t s);
void pp_next_if_state(int);
pp_if_state_t pp_pop_if(void);
@@ -249,6 +252,7 @@ void pp_do_include(char *fname, int type);
void pp_push_ignore_state(void);
void pp_pop_ignore_state(void);
+void writestring( const char *format, ... );
/*
* From ppy.y
--
1.6.3.3
More information about the wine-patches
mailing list