wpp: add I/O hooks

Matteo Bruni matteo.mystral at gmail.com
Sun Jul 12 14:55:43 CDT 2009


This patch adds I/O callbacks to wpp. I will need them for the
upcoming D3D shader assembler.
This patch defines the wpp_set_callback function that can be used to
override the functions called by wpp to read the input file and write
to the output file. The default behavior is the same as before, using
fopen/fread/fprintf functions.
As there are no specific unit tests for wpp, I verified the patch by
rebuilding wine (wpp is used by widl and wrc, so being able to
recompile wine should be something as a test).

Regards,
Matteo Bruni
-------------- next part --------------
From 1c3abffb10248ff479f85b406b7aa7f74ec6703d Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sun, 12 Jul 2009 21:23:49 +0200
Subject: wpp: add I/O hooks

---
 include/wine/wpp.h     |   20 +++++
 libs/wpp/ppl.l         |   26 +++++--
 libs/wpp/ppy.y         |   15 ++--
 libs/wpp/preproc.c     |  191 +++++++++++++++++++++++++++++-------------------
 libs/wpp/wpp.c         |   32 +++++++-
 libs/wpp/wpp_private.h |   12 +++-
 6 files changed, 202 insertions(+), 94 deletions(-)

diff --git a/include/wine/wpp.h b/include/wine/wpp.h
index 10b71e0..b61da01 100644
--- a/include/wine/wpp.h
+++ b/include/wine/wpp.h
@@ -33,4 +33,24 @@ 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 *(*lookupfile)( const char *filename, const char *parent_name,
+                      char **includepath, int nincludepath );
+    /* loadfile reads an include file and returns it in buffer */
+    /* the type param is true if it is a local ("...") include */
+    int (*loadfile)( const char *filename, int type, char **buffer );
+    /* closes a previously opened include file, freeing buffer */
+    void (*unloadfile)( const char *filename, char *buffer );
+    /* writes buffer string to the output */
+    void (*appendstring)( const char *buffer, int len );
+    /* writes a formatted string, specified with printf-like syntax,
+     * to the output */
+    void (*appendformatstring)( const char *format, ... );
+};
+
+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..8fb3bde 100644
--- a/libs/wpp/ppl.l
+++ b/libs/wpp/ppl.l
@@ -178,6 +178,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"
 
@@ -1259,8 +1260,7 @@ 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->appendformatstring("# %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)
@@ -1441,7 +1441,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->appendstring(s, len);
 }
 
 
@@ -1455,6 +1455,7 @@ void pp_do_include(char *fname, int type)
 	char *newpath;
 	int n;
 	includelogicentry_t *iep;
+	char *text;
 
 	for(iep = pp_includelogiclist; iep; iep = iep->next)
 	{
@@ -1477,7 +1478,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((text = 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 +1490,11 @@ 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));
+	fname[n-1] = '\0';      /* Undo quotes */
+	fill_buffer(fname+1, text);
+	fname[n-1] = *fname;	/* Redo the quotes */
 
-	fprintf(ppy_out, "# 1 \"%s\" 1%s\n", newpath, type ? "" : " 3");
+	io_callback->appendformatstring("# 1 \"%s\" 1%s\n", newpath, type ? "" : " 3");
 }
 
 /*
@@ -1509,3 +1512,14 @@ void pp_pop_ignore_state(void)
 {
 	yy_pop_state();
 }
+
+
+/* used to fill up the buffer before parsing, instead of reading from file */
+void fill_buffer(const char* filename, char *text)
+{
+	YY_BUFFER_STATE buffer;
+
+	buffer = ppy__scan_string(text);
+	io_callback->unloadfile(filename, text);
+	ppy__switch_to_buffer(buffer);
+}
diff --git a/libs/wpp/ppy.y b/libs/wpp/ppy.y
index fc94bb5..3d1c66f 100644
--- a/libs/wpp/ppy.y
+++ b/libs/wpp/ppy.y
@@ -38,6 +38,7 @@
 #include <ctype.h>
 #include <string.h>
 
+#include "wine/wpp.h"
 #include "wpp_private.h"
 
 
@@ -271,20 +272,20 @@ preprocessor
 	| 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	{ io_callback->appendformatstring("# %d %s\n", $2 , $3); free($3); }
+	| tGCCLINE tSINT tDQSTRING tNL	{ io_callback->appendformatstring("# %d %s\n", $2 , $3); free($3); }
 	| tGCCLINE tSINT tDQSTRING tSINT tNL
-		{ fprintf(ppy_out, "# %d %s %d\n", $2, $3, $4); free($3); }
+		{ io_callback->appendformatstring("# %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); }
+		{ io_callback->appendformatstring("# %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); }
+		{ io_callback->appendformatstring("# %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); }
+		{ io_callback->appendformatstring("# %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	{ io_callback->appendformatstring("#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..d851d84 100644
--- a/libs/wpp/preproc.c
+++ b/libs/wpp/preproc.c
@@ -113,6 +113,109 @@ char *pp_xstrdup(const char *str)
 	return memcpy(s, str, len);
 }
 
+char *wpp_default_lookupfile( const char *name, const char *parent_name,
+			      char **includepath, int nincludepath )
+{
+    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;
+}
+
+int wpp_default_loadfile(const char *filename, int type, char **buffer) {
+    FILE *file;
+    int size;
+    char *buf;
+
+    file=fopen(filename,"rt");
+    if(!file) return 0;
+    fseek(file,0,SEEK_END);
+    size = ftell(file);
+    buf = pp_xmalloc(size+1);
+    if(!buf){
+        printf("Error allocating memory\n");
+        return 0;
+    }
+    fseek(file,0,SEEK_SET);
+    fread(buf,size,1,file);
+    buf[size]='\0';
+    *buffer = buf;
+    return 1;
+}
+
+void wpp_default_unloadfile(const char *filename, char *buffer) {
+    free(buffer);
+}
+
+void wpp_default_appendstring( const char *buffer, int len ) {
+    fwrite(buffer, 1, len, ppy_out);
+}
+
+void wpp_default_appendformatstring( const char *format, ... ) {
+    va_list valist;
+
+    va_start(valist, format);
+    vfprintf(ppy_out, format, valist);
+    va_end(valist);
+}
+
 /* Don't comment on the hash, its primitive but functional... */
 static int pphash(const char *str)
 {
@@ -358,87 +461,27 @@ 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_lookupfile(name, parent_name, includepath, nincludepath);
 }
 
-FILE *pp_open_include(const char *name, const char *parent_name, char **newpath)
+char *pp_open_include(const char *name, const char *parent_name, char **newpath)
 {
     char *path;
-    FILE *fp;
+    char *text;
 
-    if (!(path = wpp_find_include( name, parent_name ))) return NULL;
-    fp = fopen(path, "rt");
-
-    if (fp)
+    if (!(path = io_callback->lookupfile( name, parent_name, includepath, nincludepath ))) return NULL;
+    if (!io_callback->loadfile(path, parent_name==NULL ? 1 : 0, &text))
     {
-        if (pp_status.debug)
-            printf("Going to include <%s>\n", path);
-        if (newpath) *newpath = path;
-        else free( path );
-        return fp;
+        fprintf(stderr,"Could not open %s\n", path);
+        free( path );
+        return NULL;
     }
-    free( path );
-    return NULL;
+
+    if (pp_status.debug)
+        printf("Going to include <%s>\n", path);
+    if (newpath) *newpath = path;
+    else free( path );
+    return text;
 }
 
 /*
diff --git a/libs/wpp/wpp.c b/libs/wpp/wpp.c
index d149591..9c543e2 100644
--- a/libs/wpp/wpp.c
+++ b/libs/wpp/wpp.c
@@ -30,6 +30,16 @@
 
 int ppy_debug, pp_flex_debug;
 
+struct wpp_io_callback default_callback = {
+    wpp_default_lookupfile,
+    wpp_default_loadfile,
+    wpp_default_unloadfile,
+    wpp_default_appendstring,
+    wpp_default_appendformatstring,
+};
+
+struct wpp_io_callback *io_callback = &default_callback;
+
 struct define
 {
     struct define *next;
@@ -142,6 +152,7 @@ void wpp_set_pedantic( int on )
 int wpp_parse( const char *input, FILE *output )
 {
     int ret;
+    char *text;
 
     pp_status.input = NULL;
 
@@ -150,20 +161,23 @@ int wpp_parse( const char *input, FILE *output )
     add_special_defines();
 
     if (!input) ppy_in = stdin;
-    else if (!(ppy_in = fopen(input, "rt")))
+    else
     {
-        fprintf(stderr,"Could not open %s\n", input);
-        exit(2);
+        if (!io_callback->loadfile(input, 1, &text))
+        {
+            fprintf(stderr,"Could not open %s\n", input);
+            exit(2);
+        }
+        fill_buffer(input, text);
     }
 
     pp_status.input = input;
 
     ppy_out = output;
-    fprintf(ppy_out, "# 1 \"%s\" 1\n", input ? input : "");
+    io_callback->appendformatstring("# 1 \"%s\" 1\n", input ? input : "");
 
     ret = ppy_parse();
 
-    if (input) fclose(ppy_in);
     pp_pop_define_state();
     return ret;
 }
@@ -199,3 +213,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..279cd4f 100644
--- a/libs/wpp/wpp_private.h
+++ b/libs/wpp/wpp_private.h
@@ -195,7 +195,7 @@ typedef struct cval {
 	} val;
 } cval_t;
 
-
+extern struct wpp_io_callback *io_callback;
 
 void *pp_xmalloc(size_t);
 void *pp_xrealloc(void *, size_t);
@@ -206,13 +206,20 @@ 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);
+char *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);
 pp_if_state_t pp_if_state(void);
 int pp_get_if_depth(void);
 
+char *wpp_default_lookupfile( const char *name, const char *parent_name,
+			      char **includepath, int nincludepath );
+int wpp_default_loadfile(const char *filename, int type, char **buffer);
+void wpp_default_unloadfile(const char *filename, char *buffer);
+void wpp_default_appendstring( const char *buffer, int len );
+void wpp_default_appendformatstring( const char *format, ... );
+
 #ifndef __GNUC__
 #define __attribute__(x)  /*nothing*/
 #endif
@@ -249,6 +256,7 @@ void pp_do_include(char *fname, int type);
 void pp_push_ignore_state(void);
 void pp_pop_ignore_state(void);
 
+void fill_buffer(const char *filename, char *text);
 
 /*
  * From ppy.y
-- 
1.6.3.3


More information about the wine-patches mailing list