widl [2/2]: Generate dlldata files. [take 3]

Dan Hipschman dsh at linux.ucla.edu
Tue Oct 16 22:19:59 CDT 2007


This is my third attempt at getting widl to generate dlldata files.
This time I'm using the basename of the proxy file instead of the
input file, so the identifier written in the dlldata file and the
proxy file are always the same.  (If we generate the dlldata file
separately with --dlldata, then the -P option can affect the file
name).  Secondly, I got rid of the arbitrary line length limit.  I
also output a #include for objbase.h in the dlldata file since this
isn't included in rpc.h if __WINESRC__ is defined.  This fixes compile
errors when dlldata files are used in wine, and doesn't seem to bother
Windows.  One more change from the last try: I took out the validation
of the proxy file name and massaging of it into a C identifier since
MIDL doesn't do this, and we weren't doing it when we output the
filename in the proxy file.  I think we should still do this as long
as it's done consistently, but I'd be more than happy to do that
separately once this goes in.

---
 tools/widl/parser.y |    1 +
 tools/widl/utils.c  |   29 +++++++++
 tools/widl/utils.h  |    1 +
 tools/widl/widl.c   |  170 ++++++++++++++++++++++++++++++++++++++++++++++-----
 tools/widl/widl.h   |    3 +
 5 files changed, 189 insertions(+), 15 deletions(-)

diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index afab0d2..96e9891 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -288,6 +288,7 @@ input:   gbl_statements				{ fix_incomplete();
 						  write_proxies($1);
 						  write_client($1);
 						  write_server($1);
+						  write_dlldata($1);
 						}
 	;
 
diff --git a/tools/widl/utils.c b/tools/widl/utils.c
index 3b8d20e..f7a9442 100644
--- a/tools/widl/utils.c
+++ b/tools/widl/utils.c
@@ -156,6 +156,35 @@ char *dup_basename(const char *name, const char *ext)
 	return base;
 }
 
+size_t widl_getline(char **linep, size_t *lenp, FILE *fp)
+{
+    char *line = *linep;
+    size_t len = *lenp;
+    size_t n = 0;
+
+    if (!line)
+    {
+        len = 64;
+        line = xmalloc(len);
+    }
+
+    while (fgets(&line[n], len - n, fp))
+    {
+        n += strlen(&line[n]);
+        if (line[n - 1] == '\n')
+            break;
+        else if (n == len - 1)
+        {
+            len *= 2;
+            line = xrealloc(line, len);
+        }
+    }
+
+    *linep = line;
+    *lenp = len;
+    return n;
+}
+
 void *xmalloc(size_t size)
 {
     void *res;
diff --git a/tools/widl/utils.h b/tools/widl/utils.h
index aa1d6b4..c4dbb31 100644
--- a/tools/widl/utils.h
+++ b/tools/widl/utils.h
@@ -41,6 +41,7 @@ void warning(const char *s, ...) __attribute__((format (printf, 1, 2)));
 void chat(const char *s, ...) __attribute__((format (printf, 1, 2)));
 
 char *dup_basename(const char *name, const char *ext);
+size_t widl_getline(char **linep, size_t *lenp, FILE *fp);
 
 UUID *parse_uuid(const char *u);
 int is_valid_uuid(const char *s);
diff --git a/tools/widl/widl.c b/tools/widl/widl.c
index 8b4e397..2893f18 100644
--- a/tools/widl/widl.c
+++ b/tools/widl/widl.c
@@ -22,6 +22,7 @@
 #include "config.h"
 #include "wine/port.h"
 
+#include <errno.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -55,6 +56,8 @@ static const char usage[] =
 "   -C file     Name of client stub file (default is infile_c.c)\n"
 "   -d n        Set debug level to 'n'\n"
 "   -D id[=val] Define preprocessor identifier id=val\n"
+"   --dlldata   Generate dlldata file\n"
+"   --dlldata-file=file  Name of dlldata file (default is dlldata.c)\n"
 "   -E          Preprocess only\n"
 "   -h          Generate headers\n"
 "   -H file     Name of header file (default is infile.h)\n"
@@ -100,6 +103,7 @@ int do_proxies = 0;
 int do_client = 0;
 int do_server = 0;
 int do_idfile = 0;
+int do_dlldata = 0;
 int no_preprocess = 0;
 int old_names = 0;
 
@@ -107,6 +111,7 @@ char *input_name;
 char *header_name;
 char *header_token;
 char *typelib_name;
+char *dlldata_name;
 char *proxy_name;
 char *proxy_token;
 char *client_name;
@@ -129,6 +134,8 @@ time_t now;
 
 enum {
     OLDNAMES_OPTION = CHAR_MAX + 1,
+    DLLDATA_OPTION,
+    DLLDATA_FILE_OPTION,
     PREFIX_ALL_OPTION,
     PREFIX_CLIENT_OPTION,
     PREFIX_SERVER_OPTION
@@ -137,6 +144,8 @@ enum {
 static const char short_options[] =
     "cC:d:D:EhH:I:NpP:sS:tT:uU:VW";
 static const struct option long_options[] = {
+    { "dlldata", no_argument, 0, DLLDATA_OPTION },
+    { "dlldata-file", required_argument, 0, DLLDATA_FILE_OPTION },
     { "oldnames", no_argument, 0, OLDNAMES_OPTION },
     { "prefix-all", required_argument, 0, PREFIX_ALL_OPTION },
     { "prefix-client", required_argument, 0, PREFIX_CLIENT_OPTION },
@@ -178,6 +187,129 @@ static void exit_on_signal( int sig )
     exit(1);  /* this will call the atexit functions */
 }
 
+static void start_cplusplus_guard(FILE *fp)
+{
+  fprintf(fp, "#ifdef __cplusplus\n");
+  fprintf(fp, "extern \"C\" {\n");
+  fprintf(fp, "#endif\n\n");
+}
+
+static void end_cplusplus_guard(FILE *fp)
+{
+  fprintf(fp, "#ifdef __cplusplus\n");
+  fprintf(fp, "}\n");
+  fprintf(fp, "#endif\n\n");
+}
+
+typedef struct
+{
+  char *filename;
+  struct list link;
+} filename_node_t;
+
+static void add_filename_node(struct list *list, const char *name)
+{
+  filename_node_t *node = xmalloc(sizeof *node);
+  node->filename = xstrdup(name);
+  list_add_tail(list, &node->link);
+}
+
+static void free_filename_nodes(struct list *list)
+{
+  filename_node_t *node, *next;
+  LIST_FOR_EACH_ENTRY_SAFE(node, next, list, filename_node_t, link) {
+    list_remove(&node->link);
+    free(node->filename);
+    free(node);
+  }
+}
+
+static char *eat_space(char *s)
+{
+  while (isspace((unsigned char) *s))
+    ++s;
+  return s;
+}
+
+void write_dlldata(ifref_list_t *ifaces)
+{
+  struct list filenames = LIST_INIT(filenames);
+  filename_node_t *node;
+  FILE *dlldata;
+
+  if (!do_dlldata)
+    return;
+  if (do_everything && !need_proxy_file(ifaces))
+    return;
+
+  dlldata = fopen(dlldata_name, "r");
+  if (dlldata) {
+    static char marker[] = "REFERENCE_PROXY_FILE";
+    char *line = NULL;
+    size_t len = 0;
+
+    while (widl_getline(&line, &len, dlldata)) {
+      char *start, *end;
+      start = eat_space(line);
+      if (strncmp(start, marker, sizeof marker - 1) == 0) {
+        start = eat_space(start + sizeof marker - 1);
+        if (*start != '(')
+          continue;
+        end = start = eat_space(start + 1);
+        while (*end && *end != ')')
+          ++end;
+        if (*end != ')')
+          continue;
+        while (isspace((unsigned char) end[-1]))
+          --end;
+        *end = '\0';
+        if (start < end)
+          add_filename_node(&filenames, start);
+      }
+    }
+
+    if (ferror(dlldata))
+      error("couldn't read from %s: %s\n", dlldata_name, strerror(errno));
+
+    free(line);
+    fclose(dlldata);
+  }
+
+  LIST_FOR_EACH_ENTRY(node, &filenames, filename_node_t, link)
+    if (strcmp(proxy_token, node->filename) == 0) {
+      /* We're already in the list, no need to regenerate this file.  */
+      free_filename_nodes(&filenames);
+      return;
+    }
+
+  add_filename_node(&filenames, proxy_token);
+
+  dlldata = fopen(dlldata_name, "w");
+  if (!dlldata)
+    error("couldn't open %s: %s\n", dlldata_name, strerror(errno));
+
+  fprintf(dlldata, "/*** Autogenerated by WIDL %s ", PACKAGE_VERSION);
+  fprintf(dlldata, "- Do not edit ***/\n\n");
+  fprintf(dlldata, "#include <objbase.h>\n");
+  fprintf(dlldata, "#include <rpcproxy.h>\n\n");
+  start_cplusplus_guard(dlldata);
+
+  LIST_FOR_EACH_ENTRY(node, &filenames, filename_node_t, link)
+    fprintf(dlldata, "EXTERN_PROXY_FILE(%s)\n", node->filename);
+
+  fprintf(dlldata, "\nPROXYFILE_LIST_START\n");
+  fprintf(dlldata, "/* Start of list */\n");
+  LIST_FOR_EACH_ENTRY(node, &filenames, filename_node_t, link)
+    fprintf(dlldata, "  REFERENCE_PROXY_FILE(%s),\n", node->filename);
+  fprintf(dlldata, "/* End of list */\n");
+  fprintf(dlldata, "PROXYFILE_LIST_END\n\n");
+
+  fprintf(dlldata, "DLLDATA_ROUTINES(aProxyFileList, GET_DLL_CLSID)\n\n");
+  end_cplusplus_guard(dlldata);
+  fclose(dlldata);
+  free_filename_nodes(&filenames);
+}
+
 int main(int argc,char *argv[])
 {
   extern char* optarg;
@@ -196,6 +328,13 @@ int main(int argc,char *argv[])
 
   while((optc = getopt_long(argc, argv, short_options, long_options, &opti)) != EOF) {
     switch(optc) {
+    case DLLDATA_OPTION:
+      do_everything = 0;
+      do_dlldata = 1;
+      break;
+    case DLLDATA_FILE_OPTION:
+      dlldata_name = xstrdup(optarg);
+      break;
     case OLDNAMES_OPTION:
       old_names = 1;
       break;
@@ -280,7 +419,13 @@ int main(int argc,char *argv[])
   }
 
   if(do_everything) {
-      do_header = do_typelib = do_proxies = do_client = do_server = do_idfile = 1;
+    do_header = 1;
+    do_typelib = 1;
+    do_proxies = 1;
+    do_client = 1;
+    do_server = 1;
+    do_idfile = 1;
+    do_dlldata = 1;
   }
   if(optind < argc) {
     input_name = xstrdup(argv[optind]);
@@ -313,7 +458,7 @@ int main(int argc,char *argv[])
     strcat(typelib_name, ".tlb");
   }
 
-  if (!proxy_name && do_proxies) {
+  if (!proxy_name && (do_proxies || do_dlldata)) {
     proxy_name = dup_basename(input_name, ".idl");
     strcat(proxy_name, "_p.c");
   }
@@ -333,7 +478,10 @@ int main(int argc,char *argv[])
     strcat(idfile_name, "_i.c");
   }
 
-  if (do_proxies) proxy_token = dup_basename_token(proxy_name,"_p.c");
+  if (!dlldata_name && do_dlldata)
+    dlldata_name = xstrdup("dlldata.c");
+
+  if (do_proxies || do_dlldata) proxy_token = dup_basename_token(proxy_name,"_p.c");
   if (do_client) client_token = dup_basename_token(client_name,"_c.c");
   if (do_server) server_token = dup_basename_token(server_name,"_s.c");
 
@@ -379,9 +527,7 @@ int main(int argc,char *argv[])
     fprintf(header, "#include <rpcndr.h>\n\n" );
     fprintf(header, "#ifndef __WIDL_%s\n", header_token);
     fprintf(header, "#define __WIDL_%s\n", header_token);
-    fprintf(header, "#ifdef __cplusplus\n");
-    fprintf(header, "extern \"C\" {\n");
-    fprintf(header, "#endif\n");
+    start_cplusplus_guard(header);
   }
 
   if (do_idfile) {
@@ -398,9 +544,7 @@ int main(int argc,char *argv[])
     fprintf(idfile, "#include <rpc.h>\n");
     fprintf(idfile, "#include <rpcndr.h>\n\n");
     fprintf(idfile, "#include <initguid.h>\n\n");
-    fprintf(idfile, "#ifdef __cplusplus\n");
-    fprintf(idfile, "extern \"C\" {\n");
-    fprintf(idfile, "#endif\n\n");
+    start_cplusplus_guard(idfile);
   }
 
   init_types();
@@ -414,18 +558,14 @@ int main(int argc,char *argv[])
     fprintf(header, "\n");
     fprintf(header, "/* End additional prototypes */\n");
     fprintf(header, "\n");
-    fprintf(header, "#ifdef __cplusplus\n");
-    fprintf(header, "}\n");
-    fprintf(header, "#endif\n");
+    end_cplusplus_guard(header);
     fprintf(header, "#endif /* __WIDL_%s */\n", header_token);
     fclose(header);
   }
 
   if (do_idfile) {
     fprintf(idfile, "\n");
-    fprintf(idfile, "#ifdef __cplusplus\n");
-    fprintf(idfile, "}\n");
-    fprintf(idfile, "#endif\n");
+    end_cplusplus_guard(idfile);
 
     fclose(idfile);
   }
diff --git a/tools/widl/widl.h b/tools/widl/widl.h
index 497e05a..72e6ee8 100644
--- a/tools/widl/widl.h
+++ b/tools/widl/widl.h
@@ -44,11 +44,13 @@ extern int do_proxies;
 extern int do_client;
 extern int do_server;
 extern int do_idfile;
+extern int do_dlldata;
 extern int old_names;
 
 extern char *input_name;
 extern char *header_name;
 extern char *typelib_name;
+extern char *dlldata_name;
 extern char *proxy_name;
 extern char *proxy_token;
 extern char *client_name;
@@ -68,5 +70,6 @@ extern FILE* idfile;
 extern void write_proxies(ifref_list_t *ifaces);
 extern void write_client(ifref_list_t *ifaces);
 extern void write_server(ifref_list_t *ifaces);
+extern void write_dlldata(ifref_list_t *ifaces);
 
 #endif




More information about the wine-patches mailing list