зеркало из https://github.com/mozilla/pjs.git
Update usage message.
Add #include processing. Generate #define NS_IFOO_IID_STR for kipp. More header-generation niceties: #ifndef __nsIFoo_h__, DO NOT EDIT warning now mentions source filename. Generate #include in header to match #include in IDL, not by grovelling for referenced interfaces. (XXX: Need to polish up memory management.)
This commit is contained in:
Родитель
4e3777064f
Коммит
13b3f944f5
|
@ -31,13 +31,14 @@ gboolean generate_headers = FALSE;
|
|||
gboolean generate_nothing = FALSE;
|
||||
|
||||
static char xpidl_usage_str[] =
|
||||
"Usage: %s -idhwvn filename.idl\n"
|
||||
" -i generate Invoke glue (filename_invoke.c)\n"
|
||||
" -d generate HTML documenation (filename.html)\n"
|
||||
" -h generate C++ headers (filename.h)\n"
|
||||
"Usage: %s [-i] [-d] [-h] [-w] [-v] [-I path] [-n] filename.idl\n"
|
||||
" -i generate InterfaceInfo data (filename.int) (NYI)\n"
|
||||
" -d generate HTML documenation (filename.html) (NYI)\n"
|
||||
" -h generate C++ headers (filename.h)\n"
|
||||
" -w turn on warnings (recommended)\n"
|
||||
" -v verbose mode\n"
|
||||
" -n do not generate output files, just test IDL\n";
|
||||
" -v verbose mode (NYI)\n"
|
||||
" -I add entry to start of include path for ``#include \"nsIThing.idl\"''\n"
|
||||
" -n do not generate output files, just test IDL (NYI)\n";
|
||||
|
||||
static void
|
||||
xpidl_usage(int argc, char *argv[])
|
||||
|
@ -50,32 +51,56 @@ int
|
|||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, idlfiles;
|
||||
IncludePathEntry *inc, *inc_head = NULL;
|
||||
|
||||
inc_head = malloc(sizeof *inc);
|
||||
if (!inc_head)
|
||||
return 1;
|
||||
inc_head->directory = ".";
|
||||
inc_head->next = NULL;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
switch (argv[i][1]) {
|
||||
case 'd':
|
||||
generate_docs = TRUE;
|
||||
break;
|
||||
case 'i':
|
||||
generate_invoke = TRUE;
|
||||
break;
|
||||
case 'h':
|
||||
if (argv[i][0] != '-')
|
||||
break;
|
||||
switch (argv[i][1]) {
|
||||
case 'd':
|
||||
generate_docs = TRUE;
|
||||
break;
|
||||
case 'i':
|
||||
generate_invoke = TRUE;
|
||||
break;
|
||||
case 'h':
|
||||
generate_headers = TRUE;
|
||||
break;
|
||||
case 'w':
|
||||
enable_warnings = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose_mode = TRUE;
|
||||
break;
|
||||
case 'n':
|
||||
generate_nothing = TRUE;
|
||||
break;
|
||||
default:
|
||||
case 'w':
|
||||
enable_warnings = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose_mode = TRUE;
|
||||
break;
|
||||
case 'n':
|
||||
generate_nothing = TRUE;
|
||||
break;
|
||||
case 'I':
|
||||
if (i == argc) {
|
||||
fputs("ERROR: missing path after -I\n", stderr);
|
||||
xpidl_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
inc = malloc(sizeof *inc);
|
||||
if (!inc)
|
||||
return 1;
|
||||
inc->directory = argv[i + 1];
|
||||
#ifdef DEBUG_shaver
|
||||
fprintf(stderr, "adding %s to include path\n", inc->directory);
|
||||
#endif
|
||||
inc->next = inc_head;
|
||||
inc_head = inc;
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
xpidl_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,9 +109,9 @@ main(int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
for (i = 1, idlfiles = 0; i < argc; i++) {
|
||||
for (idlfiles = 0; i < argc; i++) {
|
||||
if (argv[i][0] && argv[i][0] != '-')
|
||||
idlfiles += xpidl_process_idl(argv[i]);
|
||||
idlfiles += xpidl_process_idl(argv[i], inc_head);
|
||||
}
|
||||
|
||||
if (!idlfiles) {
|
||||
|
|
|
@ -43,11 +43,19 @@ extern gboolean generate_invoke;
|
|||
extern gboolean generate_headers;
|
||||
extern gboolean generate_nothing;
|
||||
|
||||
typedef struct IncludePathEntry {
|
||||
char *directory;
|
||||
struct IncludePathEntry *next;
|
||||
} IncludePathEntry;
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char *basename;
|
||||
IDL_ns ns;
|
||||
IDL_tree tree;
|
||||
int mode;
|
||||
GHashTable *includes;
|
||||
IncludePathEntry *include_path;
|
||||
} TreeState;
|
||||
|
||||
#define TREESTATE_HEADER 0
|
||||
|
@ -75,11 +83,11 @@ extern nodeHandler *docDispatch();
|
|||
gboolean node_is_error(TreeState *state);
|
||||
|
||||
/*
|
||||
* Process an IDL file, generating typelib, invoke glue and headers as
|
||||
* Process an IDL file, generating InterfaceInfo, documentation and headers as
|
||||
* appropriate.
|
||||
*/
|
||||
int
|
||||
xpidl_process_idl(char *filename);
|
||||
xpidl_process_idl(char *filename, IncludePathEntry *include_path);
|
||||
|
||||
/*
|
||||
* Iterate over an IDLN_LIST -- why is this not part of libIDL?
|
||||
|
|
|
@ -84,7 +84,7 @@ find_interface_refs(IDL_tree p, gpointer user_data)
|
|||
static void
|
||||
write_header(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
char *ident = (char *)key;
|
||||
char *ident = (char *)value;
|
||||
TreeState *state = (TreeState *)user_data;
|
||||
fprintf(state->file, "#include \"%s.h\" /* interface %s */\n",
|
||||
ident, ident);
|
||||
|
@ -93,16 +93,32 @@ write_header(gpointer key, gpointer value, gpointer user_data)
|
|||
static gboolean
|
||||
pass_1(TreeState *state)
|
||||
{
|
||||
GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
if (!hash)
|
||||
return FALSE;
|
||||
fputs("/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM"
|
||||
" <filename goes here>\n */\n",
|
||||
state->file);
|
||||
fputs("#include \"nscore.h\"\n", state->file);
|
||||
IDL_tree_walk_in_order(state->tree, find_interface_refs, hash);
|
||||
g_hash_table_foreach(hash, write_header, state);
|
||||
g_hash_table_destroy(hash);
|
||||
if (state->tree) {
|
||||
fprintf(state->file, "/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM"
|
||||
" %s.idl\n */\n", state->basename);
|
||||
fprintf(state->file, "\n#ifndef __%s_h__\n#define __%s_h__\n\n",
|
||||
state->basename, state->basename);
|
||||
g_hash_table_foreach(state->includes, write_header, state);
|
||||
} else {
|
||||
fprintf(state->file, "\n#endif /* __%s_h__ */\n", state->basename);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_classname_iid_define(FILE *file, const char *className)
|
||||
{
|
||||
const char *iidName;
|
||||
if (className[0] == 'n' && className[1] == 's') {
|
||||
/* backcompat naming styles */
|
||||
fputs("NS_", file);
|
||||
iidName = className + 2;
|
||||
} else {
|
||||
iidName = className;
|
||||
}
|
||||
while (*iidName)
|
||||
fputc(toupper(*iidName++), file);
|
||||
fputs("_IID", file);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -122,20 +138,14 @@ interface(TreeState *state)
|
|||
if (strlen(iid) != 36)
|
||||
/* XXX report error */
|
||||
return FALSE;
|
||||
fprintf(state->file, "\n/* {%s} */\n#define ", iid);
|
||||
if (className[0] == 'n' && className[1] == 's') {
|
||||
/* backcompat naming styles */
|
||||
fputs("NS_", state->file);
|
||||
iidName = className + 2;
|
||||
} else {
|
||||
iidName = className;
|
||||
}
|
||||
while (*iidName)
|
||||
fputc(toupper(*iidName++), state->file);
|
||||
fputs("_IID \\\n", state->file);
|
||||
|
||||
fputs("#define ", state->file);
|
||||
if (!output_classname_iid_define(state->file, className))
|
||||
return FALSE;
|
||||
fprintf(state->file, "_STR \"%s\"\n\n/* {%s} */\n#define ", iid, iid);
|
||||
if (!output_classname_iid_define(state->file, className))
|
||||
return FALSE;
|
||||
/* This is such a gross hack... */
|
||||
fprintf(state->file, " {0x%.8s, 0x%.4s, 0x%.4s, \\\n "
|
||||
fprintf(state->file, " \\\n {0x%.8s, 0x%.4s, 0x%.4s, \\\n "
|
||||
"{ 0x%.2s, 0x%.2s, 0x%.2s, 0x%.2s, "
|
||||
"0x%.2s, 0x%.2s, 0x%.2s, 0x%.2s }}\n\n",
|
||||
iid, iid + 9, iid + 14, iid + 19, iid + 21, iid + 24,
|
||||
|
|
|
@ -29,7 +29,7 @@ FILE *header_file = NULL;
|
|||
nodeHandler *nodeDispatch[TREESTATE_NUM] = { NULL };
|
||||
|
||||
/*
|
||||
* Pass 1 generates #includes for headers.
|
||||
* Pass 1 generates #includes for headers and the like.
|
||||
*/
|
||||
static gboolean
|
||||
process_tree_pass1(TreeState *state)
|
||||
|
@ -80,6 +80,11 @@ process_node(TreeState *state)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the IDLN_NONE handler for pre-generation, then process the tree,
|
||||
* then call the IDLN_NONE handler again with state->tree == NULL for
|
||||
* post-generation.
|
||||
*/
|
||||
static gboolean
|
||||
process_tree(TreeState *state)
|
||||
{
|
||||
|
@ -87,7 +92,12 @@ process_tree(TreeState *state)
|
|||
if (!process_tree_pass1(state))
|
||||
return FALSE;
|
||||
state->tree = top; /* pass1 might mutate state */
|
||||
return process_node(state);
|
||||
if (!process_node(state))
|
||||
return FALSE;
|
||||
state->tree = NULL;
|
||||
if (!process_tree_pass1(state))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -103,39 +113,97 @@ msg_callback(int level, int num, int line, const char *file,
|
|||
|
||||
struct input_callback_data {
|
||||
FILE *input;
|
||||
char *filename;
|
||||
int lineno;
|
||||
char *buf;
|
||||
char *point;
|
||||
int len;
|
||||
int max;
|
||||
struct input_callback_data *next;
|
||||
};
|
||||
|
||||
struct input_callback_stack {
|
||||
struct input_callback_data *top;
|
||||
GHashTable *includes;
|
||||
IncludePathEntry *include_path;
|
||||
};
|
||||
|
||||
static FILE *
|
||||
fopen_from_includes(const char *filename, const char *mode,
|
||||
IncludePathEntry *include_path)
|
||||
{
|
||||
char *filebuf = NULL;
|
||||
FILE *file = NULL;
|
||||
for (; include_path && !file; include_path = include_path->next) {
|
||||
filebuf = g_strdup_printf("%s/%s", include_path->directory, filename);
|
||||
if (!filebuf)
|
||||
return NULL;
|
||||
#ifdef DEBUG_shaver
|
||||
fprintf(stderr, "looking for %s as %s\n", filename, filebuf);
|
||||
#endif
|
||||
file = fopen(filebuf, mode);
|
||||
free(filebuf);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
static struct input_callback_data *
|
||||
new_input_callback_data(const char *filename, IncludePathEntry *include_path)
|
||||
{
|
||||
struct input_callback_data *new_data = malloc(sizeof *new_data);
|
||||
if (!new_data)
|
||||
return NULL;
|
||||
new_data->input = fopen_from_includes(filename, "r", include_path);
|
||||
if (!new_data->input)
|
||||
return NULL;
|
||||
new_data->buf = malloc(INPUT_BUF_CHUNK);
|
||||
if (!new_data->buf) {
|
||||
fclose(new_data->input);
|
||||
return NULL;
|
||||
}
|
||||
new_data->len = 0;
|
||||
new_data->point = new_data->buf;
|
||||
new_data->max = INPUT_BUF_CHUNK;
|
||||
new_data->filename = strdup(filename);
|
||||
if (!new_data->filename) {
|
||||
free(new_data->buf);
|
||||
fclose(new_data->input);
|
||||
return NULL;
|
||||
}
|
||||
new_data->lineno = 1;
|
||||
new_data->next = NULL;
|
||||
return new_data;
|
||||
}
|
||||
|
||||
static int
|
||||
input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct input_callback_data *data = user_data;
|
||||
struct input_callback_stack *stack = user_data;
|
||||
struct input_callback_data *data = stack->top, *new_data = NULL;
|
||||
int rv, avail, copy;
|
||||
char *include_start, *ptr;
|
||||
|
||||
switch(reason) {
|
||||
case IDL_INPUT_REASON_INIT:
|
||||
data->input = fopen(cb_data->init.filename, "r");
|
||||
data->buf = malloc(INPUT_BUF_CHUNK);
|
||||
data->len = 0;
|
||||
data->point = data->buf;
|
||||
data->max = INPUT_BUF_CHUNK;
|
||||
if (data->input && data->buf) {
|
||||
data->len = sprintf(data->buf, "# 1 \"%s\"\n",
|
||||
new_data = new_input_callback_data(cb_data->init.filename,
|
||||
stack->include_path);
|
||||
if (!new_data)
|
||||
return -1;
|
||||
|
||||
/* XXX replace with IDL_set_file_position */
|
||||
new_data->len = sprintf(new_data->buf, "# 1 \"%s\"\n",
|
||||
cb_data->init.filename);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
stack->top = new_data;
|
||||
return 0;
|
||||
|
||||
case IDL_INPUT_REASON_FILL:
|
||||
fill_start:
|
||||
avail = data->buf + data->len - data->point;
|
||||
assert(avail >= 0);
|
||||
|
||||
if (!avail) {
|
||||
char *comment_start = NULL, *ptr;
|
||||
char *comment_start = NULL, *include_start = NULL, *ptr;
|
||||
data->point = data->buf;
|
||||
|
||||
/* fill the buffer */
|
||||
|
@ -144,6 +212,18 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
if (!data->len) {
|
||||
if (ferror(data->input))
|
||||
return -1;
|
||||
/* pop include */
|
||||
if (data->next) {
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "leaving %s, returning to %s\n",
|
||||
data->filename, data->next->filename);
|
||||
#endif
|
||||
data = data->next;
|
||||
stack->top = data;
|
||||
IDL_file_set(data->filename, ++data->lineno);
|
||||
IDL_inhibit_pop();
|
||||
goto fill_start;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -158,7 +238,7 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
* think there are any legal IDL syntaxes with '/' in them.
|
||||
*
|
||||
* XXX what about "/* " appearing in the IDL?
|
||||
*/
|
||||
*/
|
||||
if (!comment_start)
|
||||
comment_start = strstr(data->buf, "/*");
|
||||
while (comment_start) {
|
||||
|
@ -196,9 +276,70 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
} /* while(comment_start) */
|
||||
|
||||
/* we set avail here, because data->len is changed above */
|
||||
|
||||
avail = data->buf + data->len - data->point;
|
||||
}
|
||||
|
||||
/*
|
||||
* process includes
|
||||
*/
|
||||
|
||||
/*
|
||||
* we only do #include magic at the beginning of the buffer.
|
||||
* otherwise, we just set avail to cap the amount of data sent
|
||||
* on this pass.
|
||||
*/
|
||||
include_start = strstr(data->point, "#include \"");
|
||||
if (include_start == data->point) {
|
||||
/* time to process the #include */
|
||||
const char *scratch;
|
||||
char *filename = include_start + 10;
|
||||
ptr = strchr(filename, '\"');
|
||||
if (!ptr) {
|
||||
/* XXX report error */
|
||||
return -1;
|
||||
}
|
||||
data->point = ptr+1;
|
||||
|
||||
*ptr = 0;
|
||||
ptr = strrchr(filename, '.');
|
||||
/* XXX is this a safe optimization? */
|
||||
if (!g_hash_table_lookup(stack->includes, filename)) {
|
||||
char *basename = filename;
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "processing #include %s\n", filename);
|
||||
#endif
|
||||
filename = strdup(filename);
|
||||
ptr = strrchr(basename, '.');
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
basename = strdup(basename);
|
||||
g_hash_table_insert(stack->includes, filename, basename);
|
||||
new_data = new_input_callback_data(filename,
|
||||
stack->include_path);
|
||||
if (!new_data) {
|
||||
free(filename);
|
||||
return -1;
|
||||
}
|
||||
new_data->next = stack->top;
|
||||
IDL_inhibit_push();
|
||||
IDL_file_get(&scratch, &data->lineno);
|
||||
data = stack->top = new_data;
|
||||
IDL_file_set(data->filename, data->lineno);
|
||||
/* now continue getting data from new file */
|
||||
goto fill_start;
|
||||
} else {
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "not processing #include %s again\n",
|
||||
filename);
|
||||
#endif
|
||||
}
|
||||
} else if (include_start) {
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "not processing #include yet\n");
|
||||
#endif
|
||||
avail = include_start - data->point;
|
||||
}
|
||||
copy = MIN(avail, cb_data->fill.max_size);
|
||||
memcpy(cb_data->fill.buffer, data->point, copy);
|
||||
data->point += copy;
|
||||
|
@ -220,14 +361,20 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
}
|
||||
|
||||
int
|
||||
xpidl_process_idl(char *filename) {
|
||||
xpidl_process_idl(char *filename, IncludePathEntry *include_path)
|
||||
{
|
||||
char *basename, *tmp;
|
||||
IDL_tree top;
|
||||
TreeState state;
|
||||
int rv;
|
||||
struct input_callback_data data;
|
||||
struct input_callback_stack stack;
|
||||
|
||||
rv = IDL_parse_filename_with_input(filename, input_callback, &data,
|
||||
stack.includes = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
stack.include_path = include_path;
|
||||
if (!stack.includes)
|
||||
return 0;
|
||||
|
||||
rv = IDL_parse_filename_with_input(filename, input_callback, &stack,
|
||||
msg_callback, &top,
|
||||
&state.ns, IDLF_XPIDL,
|
||||
enable_warnings ? IDL_WARNING1 : 0);
|
||||
|
@ -246,6 +393,9 @@ xpidl_process_idl(char *filename) {
|
|||
*tmp = '\0';
|
||||
|
||||
state.file = stdout; /* XXX */
|
||||
state.basename = basename;
|
||||
state.includes = stack.includes;
|
||||
state.include_path = include_path;
|
||||
nodeDispatch[TREESTATE_HEADER] = headerDispatch();
|
||||
nodeDispatch[TREESTATE_INVOKE] = invokeDispatch();
|
||||
nodeDispatch[TREESTATE_DOC] = docDispatch();
|
||||
|
@ -267,6 +417,10 @@ xpidl_process_idl(char *filename) {
|
|||
if (!process_tree(&state))
|
||||
return 0;
|
||||
}
|
||||
free(state.basename);
|
||||
/* g_hash_table_foreach(state.includes, free_name, NULL);
|
||||
g_hash_table_destroy(state.includes);
|
||||
*/
|
||||
IDL_ns_free(state.ns);
|
||||
IDL_tree_free(top);
|
||||
|
||||
|
|
|
@ -31,13 +31,14 @@ gboolean generate_headers = FALSE;
|
|||
gboolean generate_nothing = FALSE;
|
||||
|
||||
static char xpidl_usage_str[] =
|
||||
"Usage: %s -idhwvn filename.idl\n"
|
||||
" -i generate Invoke glue (filename_invoke.c)\n"
|
||||
" -d generate HTML documenation (filename.html)\n"
|
||||
" -h generate C++ headers (filename.h)\n"
|
||||
"Usage: %s [-i] [-d] [-h] [-w] [-v] [-I path] [-n] filename.idl\n"
|
||||
" -i generate InterfaceInfo data (filename.int) (NYI)\n"
|
||||
" -d generate HTML documenation (filename.html) (NYI)\n"
|
||||
" -h generate C++ headers (filename.h)\n"
|
||||
" -w turn on warnings (recommended)\n"
|
||||
" -v verbose mode\n"
|
||||
" -n do not generate output files, just test IDL\n";
|
||||
" -v verbose mode (NYI)\n"
|
||||
" -I add entry to start of include path for ``#include \"nsIThing.idl\"''\n"
|
||||
" -n do not generate output files, just test IDL (NYI)\n";
|
||||
|
||||
static void
|
||||
xpidl_usage(int argc, char *argv[])
|
||||
|
@ -50,32 +51,56 @@ int
|
|||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, idlfiles;
|
||||
IncludePathEntry *inc, *inc_head = NULL;
|
||||
|
||||
inc_head = malloc(sizeof *inc);
|
||||
if (!inc_head)
|
||||
return 1;
|
||||
inc_head->directory = ".";
|
||||
inc_head->next = NULL;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
switch (argv[i][1]) {
|
||||
case 'd':
|
||||
generate_docs = TRUE;
|
||||
break;
|
||||
case 'i':
|
||||
generate_invoke = TRUE;
|
||||
break;
|
||||
case 'h':
|
||||
if (argv[i][0] != '-')
|
||||
break;
|
||||
switch (argv[i][1]) {
|
||||
case 'd':
|
||||
generate_docs = TRUE;
|
||||
break;
|
||||
case 'i':
|
||||
generate_invoke = TRUE;
|
||||
break;
|
||||
case 'h':
|
||||
generate_headers = TRUE;
|
||||
break;
|
||||
case 'w':
|
||||
enable_warnings = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose_mode = TRUE;
|
||||
break;
|
||||
case 'n':
|
||||
generate_nothing = TRUE;
|
||||
break;
|
||||
default:
|
||||
case 'w':
|
||||
enable_warnings = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose_mode = TRUE;
|
||||
break;
|
||||
case 'n':
|
||||
generate_nothing = TRUE;
|
||||
break;
|
||||
case 'I':
|
||||
if (i == argc) {
|
||||
fputs("ERROR: missing path after -I\n", stderr);
|
||||
xpidl_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
inc = malloc(sizeof *inc);
|
||||
if (!inc)
|
||||
return 1;
|
||||
inc->directory = argv[i + 1];
|
||||
#ifdef DEBUG_shaver
|
||||
fprintf(stderr, "adding %s to include path\n", inc->directory);
|
||||
#endif
|
||||
inc->next = inc_head;
|
||||
inc_head = inc;
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
xpidl_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,9 +109,9 @@ main(int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
for (i = 1, idlfiles = 0; i < argc; i++) {
|
||||
for (idlfiles = 0; i < argc; i++) {
|
||||
if (argv[i][0] && argv[i][0] != '-')
|
||||
idlfiles += xpidl_process_idl(argv[i]);
|
||||
idlfiles += xpidl_process_idl(argv[i], inc_head);
|
||||
}
|
||||
|
||||
if (!idlfiles) {
|
||||
|
|
|
@ -43,11 +43,19 @@ extern gboolean generate_invoke;
|
|||
extern gboolean generate_headers;
|
||||
extern gboolean generate_nothing;
|
||||
|
||||
typedef struct IncludePathEntry {
|
||||
char *directory;
|
||||
struct IncludePathEntry *next;
|
||||
} IncludePathEntry;
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char *basename;
|
||||
IDL_ns ns;
|
||||
IDL_tree tree;
|
||||
int mode;
|
||||
GHashTable *includes;
|
||||
IncludePathEntry *include_path;
|
||||
} TreeState;
|
||||
|
||||
#define TREESTATE_HEADER 0
|
||||
|
@ -75,11 +83,11 @@ extern nodeHandler *docDispatch();
|
|||
gboolean node_is_error(TreeState *state);
|
||||
|
||||
/*
|
||||
* Process an IDL file, generating typelib, invoke glue and headers as
|
||||
* Process an IDL file, generating InterfaceInfo, documentation and headers as
|
||||
* appropriate.
|
||||
*/
|
||||
int
|
||||
xpidl_process_idl(char *filename);
|
||||
xpidl_process_idl(char *filename, IncludePathEntry *include_path);
|
||||
|
||||
/*
|
||||
* Iterate over an IDLN_LIST -- why is this not part of libIDL?
|
||||
|
|
|
@ -84,7 +84,7 @@ find_interface_refs(IDL_tree p, gpointer user_data)
|
|||
static void
|
||||
write_header(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
char *ident = (char *)key;
|
||||
char *ident = (char *)value;
|
||||
TreeState *state = (TreeState *)user_data;
|
||||
fprintf(state->file, "#include \"%s.h\" /* interface %s */\n",
|
||||
ident, ident);
|
||||
|
@ -93,16 +93,32 @@ write_header(gpointer key, gpointer value, gpointer user_data)
|
|||
static gboolean
|
||||
pass_1(TreeState *state)
|
||||
{
|
||||
GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
if (!hash)
|
||||
return FALSE;
|
||||
fputs("/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM"
|
||||
" <filename goes here>\n */\n",
|
||||
state->file);
|
||||
fputs("#include \"nscore.h\"\n", state->file);
|
||||
IDL_tree_walk_in_order(state->tree, find_interface_refs, hash);
|
||||
g_hash_table_foreach(hash, write_header, state);
|
||||
g_hash_table_destroy(hash);
|
||||
if (state->tree) {
|
||||
fprintf(state->file, "/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM"
|
||||
" %s.idl\n */\n", state->basename);
|
||||
fprintf(state->file, "\n#ifndef __%s_h__\n#define __%s_h__\n\n",
|
||||
state->basename, state->basename);
|
||||
g_hash_table_foreach(state->includes, write_header, state);
|
||||
} else {
|
||||
fprintf(state->file, "\n#endif /* __%s_h__ */\n", state->basename);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_classname_iid_define(FILE *file, const char *className)
|
||||
{
|
||||
const char *iidName;
|
||||
if (className[0] == 'n' && className[1] == 's') {
|
||||
/* backcompat naming styles */
|
||||
fputs("NS_", file);
|
||||
iidName = className + 2;
|
||||
} else {
|
||||
iidName = className;
|
||||
}
|
||||
while (*iidName)
|
||||
fputc(toupper(*iidName++), file);
|
||||
fputs("_IID", file);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -122,20 +138,14 @@ interface(TreeState *state)
|
|||
if (strlen(iid) != 36)
|
||||
/* XXX report error */
|
||||
return FALSE;
|
||||
fprintf(state->file, "\n/* {%s} */\n#define ", iid);
|
||||
if (className[0] == 'n' && className[1] == 's') {
|
||||
/* backcompat naming styles */
|
||||
fputs("NS_", state->file);
|
||||
iidName = className + 2;
|
||||
} else {
|
||||
iidName = className;
|
||||
}
|
||||
while (*iidName)
|
||||
fputc(toupper(*iidName++), state->file);
|
||||
fputs("_IID \\\n", state->file);
|
||||
|
||||
fputs("#define ", state->file);
|
||||
if (!output_classname_iid_define(state->file, className))
|
||||
return FALSE;
|
||||
fprintf(state->file, "_STR \"%s\"\n\n/* {%s} */\n#define ", iid, iid);
|
||||
if (!output_classname_iid_define(state->file, className))
|
||||
return FALSE;
|
||||
/* This is such a gross hack... */
|
||||
fprintf(state->file, " {0x%.8s, 0x%.4s, 0x%.4s, \\\n "
|
||||
fprintf(state->file, " \\\n {0x%.8s, 0x%.4s, 0x%.4s, \\\n "
|
||||
"{ 0x%.2s, 0x%.2s, 0x%.2s, 0x%.2s, "
|
||||
"0x%.2s, 0x%.2s, 0x%.2s, 0x%.2s }}\n\n",
|
||||
iid, iid + 9, iid + 14, iid + 19, iid + 21, iid + 24,
|
||||
|
|
|
@ -29,7 +29,7 @@ FILE *header_file = NULL;
|
|||
nodeHandler *nodeDispatch[TREESTATE_NUM] = { NULL };
|
||||
|
||||
/*
|
||||
* Pass 1 generates #includes for headers.
|
||||
* Pass 1 generates #includes for headers and the like.
|
||||
*/
|
||||
static gboolean
|
||||
process_tree_pass1(TreeState *state)
|
||||
|
@ -80,6 +80,11 @@ process_node(TreeState *state)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the IDLN_NONE handler for pre-generation, then process the tree,
|
||||
* then call the IDLN_NONE handler again with state->tree == NULL for
|
||||
* post-generation.
|
||||
*/
|
||||
static gboolean
|
||||
process_tree(TreeState *state)
|
||||
{
|
||||
|
@ -87,7 +92,12 @@ process_tree(TreeState *state)
|
|||
if (!process_tree_pass1(state))
|
||||
return FALSE;
|
||||
state->tree = top; /* pass1 might mutate state */
|
||||
return process_node(state);
|
||||
if (!process_node(state))
|
||||
return FALSE;
|
||||
state->tree = NULL;
|
||||
if (!process_tree_pass1(state))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -103,39 +113,97 @@ msg_callback(int level, int num, int line, const char *file,
|
|||
|
||||
struct input_callback_data {
|
||||
FILE *input;
|
||||
char *filename;
|
||||
int lineno;
|
||||
char *buf;
|
||||
char *point;
|
||||
int len;
|
||||
int max;
|
||||
struct input_callback_data *next;
|
||||
};
|
||||
|
||||
struct input_callback_stack {
|
||||
struct input_callback_data *top;
|
||||
GHashTable *includes;
|
||||
IncludePathEntry *include_path;
|
||||
};
|
||||
|
||||
static FILE *
|
||||
fopen_from_includes(const char *filename, const char *mode,
|
||||
IncludePathEntry *include_path)
|
||||
{
|
||||
char *filebuf = NULL;
|
||||
FILE *file = NULL;
|
||||
for (; include_path && !file; include_path = include_path->next) {
|
||||
filebuf = g_strdup_printf("%s/%s", include_path->directory, filename);
|
||||
if (!filebuf)
|
||||
return NULL;
|
||||
#ifdef DEBUG_shaver
|
||||
fprintf(stderr, "looking for %s as %s\n", filename, filebuf);
|
||||
#endif
|
||||
file = fopen(filebuf, mode);
|
||||
free(filebuf);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
static struct input_callback_data *
|
||||
new_input_callback_data(const char *filename, IncludePathEntry *include_path)
|
||||
{
|
||||
struct input_callback_data *new_data = malloc(sizeof *new_data);
|
||||
if (!new_data)
|
||||
return NULL;
|
||||
new_data->input = fopen_from_includes(filename, "r", include_path);
|
||||
if (!new_data->input)
|
||||
return NULL;
|
||||
new_data->buf = malloc(INPUT_BUF_CHUNK);
|
||||
if (!new_data->buf) {
|
||||
fclose(new_data->input);
|
||||
return NULL;
|
||||
}
|
||||
new_data->len = 0;
|
||||
new_data->point = new_data->buf;
|
||||
new_data->max = INPUT_BUF_CHUNK;
|
||||
new_data->filename = strdup(filename);
|
||||
if (!new_data->filename) {
|
||||
free(new_data->buf);
|
||||
fclose(new_data->input);
|
||||
return NULL;
|
||||
}
|
||||
new_data->lineno = 1;
|
||||
new_data->next = NULL;
|
||||
return new_data;
|
||||
}
|
||||
|
||||
static int
|
||||
input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct input_callback_data *data = user_data;
|
||||
struct input_callback_stack *stack = user_data;
|
||||
struct input_callback_data *data = stack->top, *new_data = NULL;
|
||||
int rv, avail, copy;
|
||||
char *include_start, *ptr;
|
||||
|
||||
switch(reason) {
|
||||
case IDL_INPUT_REASON_INIT:
|
||||
data->input = fopen(cb_data->init.filename, "r");
|
||||
data->buf = malloc(INPUT_BUF_CHUNK);
|
||||
data->len = 0;
|
||||
data->point = data->buf;
|
||||
data->max = INPUT_BUF_CHUNK;
|
||||
if (data->input && data->buf) {
|
||||
data->len = sprintf(data->buf, "# 1 \"%s\"\n",
|
||||
new_data = new_input_callback_data(cb_data->init.filename,
|
||||
stack->include_path);
|
||||
if (!new_data)
|
||||
return -1;
|
||||
|
||||
/* XXX replace with IDL_set_file_position */
|
||||
new_data->len = sprintf(new_data->buf, "# 1 \"%s\"\n",
|
||||
cb_data->init.filename);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
stack->top = new_data;
|
||||
return 0;
|
||||
|
||||
case IDL_INPUT_REASON_FILL:
|
||||
fill_start:
|
||||
avail = data->buf + data->len - data->point;
|
||||
assert(avail >= 0);
|
||||
|
||||
if (!avail) {
|
||||
char *comment_start = NULL, *ptr;
|
||||
char *comment_start = NULL, *include_start = NULL, *ptr;
|
||||
data->point = data->buf;
|
||||
|
||||
/* fill the buffer */
|
||||
|
@ -144,6 +212,18 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
if (!data->len) {
|
||||
if (ferror(data->input))
|
||||
return -1;
|
||||
/* pop include */
|
||||
if (data->next) {
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "leaving %s, returning to %s\n",
|
||||
data->filename, data->next->filename);
|
||||
#endif
|
||||
data = data->next;
|
||||
stack->top = data;
|
||||
IDL_file_set(data->filename, ++data->lineno);
|
||||
IDL_inhibit_pop();
|
||||
goto fill_start;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -158,7 +238,7 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
* think there are any legal IDL syntaxes with '/' in them.
|
||||
*
|
||||
* XXX what about "/* " appearing in the IDL?
|
||||
*/
|
||||
*/
|
||||
if (!comment_start)
|
||||
comment_start = strstr(data->buf, "/*");
|
||||
while (comment_start) {
|
||||
|
@ -196,9 +276,70 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
} /* while(comment_start) */
|
||||
|
||||
/* we set avail here, because data->len is changed above */
|
||||
|
||||
avail = data->buf + data->len - data->point;
|
||||
}
|
||||
|
||||
/*
|
||||
* process includes
|
||||
*/
|
||||
|
||||
/*
|
||||
* we only do #include magic at the beginning of the buffer.
|
||||
* otherwise, we just set avail to cap the amount of data sent
|
||||
* on this pass.
|
||||
*/
|
||||
include_start = strstr(data->point, "#include \"");
|
||||
if (include_start == data->point) {
|
||||
/* time to process the #include */
|
||||
const char *scratch;
|
||||
char *filename = include_start + 10;
|
||||
ptr = strchr(filename, '\"');
|
||||
if (!ptr) {
|
||||
/* XXX report error */
|
||||
return -1;
|
||||
}
|
||||
data->point = ptr+1;
|
||||
|
||||
*ptr = 0;
|
||||
ptr = strrchr(filename, '.');
|
||||
/* XXX is this a safe optimization? */
|
||||
if (!g_hash_table_lookup(stack->includes, filename)) {
|
||||
char *basename = filename;
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "processing #include %s\n", filename);
|
||||
#endif
|
||||
filename = strdup(filename);
|
||||
ptr = strrchr(basename, '.');
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
basename = strdup(basename);
|
||||
g_hash_table_insert(stack->includes, filename, basename);
|
||||
new_data = new_input_callback_data(filename,
|
||||
stack->include_path);
|
||||
if (!new_data) {
|
||||
free(filename);
|
||||
return -1;
|
||||
}
|
||||
new_data->next = stack->top;
|
||||
IDL_inhibit_push();
|
||||
IDL_file_get(&scratch, &data->lineno);
|
||||
data = stack->top = new_data;
|
||||
IDL_file_set(data->filename, data->lineno);
|
||||
/* now continue getting data from new file */
|
||||
goto fill_start;
|
||||
} else {
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "not processing #include %s again\n",
|
||||
filename);
|
||||
#endif
|
||||
}
|
||||
} else if (include_start) {
|
||||
#ifdef DEBUG_shaver_includes
|
||||
fprintf(stderr, "not processing #include yet\n");
|
||||
#endif
|
||||
avail = include_start - data->point;
|
||||
}
|
||||
copy = MIN(avail, cb_data->fill.max_size);
|
||||
memcpy(cb_data->fill.buffer, data->point, copy);
|
||||
data->point += copy;
|
||||
|
@ -220,14 +361,20 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
|||
}
|
||||
|
||||
int
|
||||
xpidl_process_idl(char *filename) {
|
||||
xpidl_process_idl(char *filename, IncludePathEntry *include_path)
|
||||
{
|
||||
char *basename, *tmp;
|
||||
IDL_tree top;
|
||||
TreeState state;
|
||||
int rv;
|
||||
struct input_callback_data data;
|
||||
struct input_callback_stack stack;
|
||||
|
||||
rv = IDL_parse_filename_with_input(filename, input_callback, &data,
|
||||
stack.includes = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
stack.include_path = include_path;
|
||||
if (!stack.includes)
|
||||
return 0;
|
||||
|
||||
rv = IDL_parse_filename_with_input(filename, input_callback, &stack,
|
||||
msg_callback, &top,
|
||||
&state.ns, IDLF_XPIDL,
|
||||
enable_warnings ? IDL_WARNING1 : 0);
|
||||
|
@ -246,6 +393,9 @@ xpidl_process_idl(char *filename) {
|
|||
*tmp = '\0';
|
||||
|
||||
state.file = stdout; /* XXX */
|
||||
state.basename = basename;
|
||||
state.includes = stack.includes;
|
||||
state.include_path = include_path;
|
||||
nodeDispatch[TREESTATE_HEADER] = headerDispatch();
|
||||
nodeDispatch[TREESTATE_INVOKE] = invokeDispatch();
|
||||
nodeDispatch[TREESTATE_DOC] = docDispatch();
|
||||
|
@ -267,6 +417,10 @@ xpidl_process_idl(char *filename) {
|
|||
if (!process_tree(&state))
|
||||
return 0;
|
||||
}
|
||||
free(state.basename);
|
||||
/* g_hash_table_foreach(state.includes, free_name, NULL);
|
||||
g_hash_table_destroy(state.includes);
|
||||
*/
|
||||
IDL_ns_free(state.ns);
|
||||
IDL_tree_free(top);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче