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:
shaver%netscape.com 1998-12-06 18:41:44 +00:00
parent 4ed36763d4
commit c567e3d343
8 changed files with 536 additions and 142 deletions

View File

@ -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) {

View File

@ -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?

View File

@ -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,

View File

@ -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);

View File

@ -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) {

View File

@ -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?

View File

@ -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,

View File

@ -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);