diff --git a/tools/widl/parser.y b/tools/widl/parser.y index afab0d2b7ae..96e9891f7fd 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 007d1cb0311..68b74b4d804 100644 --- a/tools/widl/utils.c +++ b/tools/widl/utils.c @@ -153,6 +153,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 aa1d6b48172..c4dbb317cd9 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 094195a5473..53c9e29780b 100644 --- a/tools/widl/widl.c +++ b/tools/widl/widl.c @@ -22,6 +22,7 @@ #include "config.h" #include "wine/port.h" +#include #include #include #include @@ -51,10 +52,12 @@ static const char usage[] = "Usage: widl [options...] infile.idl\n" +" or: widl [options...] --dlldata-only name1 [name2...]\n" " -c Generate client stub\n" " -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=file Name of the 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" @@ -99,6 +102,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; @@ -106,6 +110,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; @@ -128,6 +133,8 @@ time_t now; enum { OLDNAMES_OPTION = CHAR_MAX + 1, + DLLDATA_OPTION, + DLLDATA_ONLY_OPTION, PREFIX_ALL_OPTION, PREFIX_CLIENT_OPTION, PREFIX_SERVER_OPTION @@ -136,6 +143,8 @@ enum { static const char short_options[] = "cC:d:D:EhH:I:NpP:sS:tT:uU:VW"; static const struct option long_options[] = { + { "dlldata", required_argument, 0, DLLDATA_OPTION }, + { "dlldata-only", no_argument, 0, DLLDATA_ONLY_OPTION }, { "oldnames", no_argument, 0, OLDNAMES_OPTION }, { "prefix-all", required_argument, 0, PREFIX_ALL_OPTION }, { "prefix-client", required_argument, 0, PREFIX_CLIENT_OPTION }, @@ -185,6 +194,135 @@ static void set_everything(int x) do_client = x; do_server = x; do_idfile = x; + do_dlldata = x; +} + +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 void write_dlldata_list(struct list *filenames) +{ + FILE *dlldata; + filename_node_t *node; + + 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 \n"); + fprintf(dlldata, "#include \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); +} + +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 || !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); + write_dlldata_list(&filenames); + free_filename_nodes(&filenames); } int main(int argc,char *argv[]) @@ -205,6 +343,13 @@ int main(int argc,char *argv[]) while((optc = getopt_long(argc, argv, short_options, long_options, &opti)) != EOF) { switch(optc) { + case DLLDATA_OPTION: + dlldata_name = xstrdup(optarg); + break; + case DLLDATA_ONLY_OPTION: + do_everything = 0; + do_dlldata = 1; + break; case OLDNAMES_OPTION: old_names = 1; break; @@ -291,8 +436,26 @@ int main(int argc,char *argv[]) if(do_everything) { set_everything(TRUE); } + + if (!dlldata_name && do_dlldata) + dlldata_name = xstrdup("dlldata.c"); + if(optind < argc) { - input_name = xstrdup(argv[optind]); + if (do_dlldata && !do_everything) { + struct list filenames = LIST_INIT(filenames); + for ( ; optind < argc; ++optind) + add_filename_node(&filenames, argv[optind]); + + write_dlldata_list(&filenames); + free_filename_nodes(&filenames); + return 0; + } + else if (optind != argc - 1) { + fprintf(stderr, "%s", usage); + return 1; + } + else + input_name = xstrdup(argv[optind]); } else { fprintf(stderr, usage); @@ -388,9 +551,7 @@ int main(int argc,char *argv[]) fprintf(header, "#include \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) { @@ -407,9 +568,7 @@ int main(int argc,char *argv[]) fprintf(idfile, "#include \n"); fprintf(idfile, "#include \n\n"); fprintf(idfile, "#include \n\n"); - fprintf(idfile, "#ifdef __cplusplus\n"); - fprintf(idfile, "extern \"C\" {\n"); - fprintf(idfile, "#endif\n\n"); + start_cplusplus_guard(idfile); } init_types(); @@ -423,18 +582,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 a2b905c2225..4496a81b8c5 100644 --- a/tools/widl/widl.h +++ b/tools/widl/widl.h @@ -43,11 +43,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; @@ -67,5 +69,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