Rework xpidl_idl to not use a circular buffer. This fixes many problems with buffer boundaries. Fixes

9716 unterminated %{ escape causes endless loop

Clean up memory handling and other aspects of xpidl. Fixes
        11058 bad free in xpidl
        13464 memory leak in xpidl

Store doc comments in IDL-processing phase, and emit them into generated header files.  Fixes
        24734 xpidl should emit doc comments

Add error towards fixing 24965, and fix 13100 'xpidl should error on multiple inheritance'

r=jband
This commit is contained in:
mccabe%netscape.com 2000-01-28 08:28:48 +00:00
Родитель 2e0819a6c6
Коммит acad3b303e
5 изменённых файлов: 385 добавлений и 324 удалений

Просмотреть файл

@ -210,4 +210,7 @@ verify_method_declaration(IDL_tree method_tree);
gboolean
check_native(TreeState *state);
void
printlist(FILE *outfile, GSList *slist);
#endif /* __xpidl_h */

Просмотреть файл

@ -68,6 +68,8 @@ header_prolog(TreeState *state)
fprintf(state->file, "#include \"%s.h\"\n",
(char *)g_slist_nth_data(state->base_includes, i));
}
if (i > 0)
fputc('\n', state->file);
}
return TRUE;
@ -108,17 +110,14 @@ interface(TreeState *state)
const char *name_space;
struct nsID id;
char iid_parsed[UUID_LENGTH];
GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments;
#define FAIL do {ok = FALSE; goto out;} while(0)
orig = state->tree;
fprintf(state->file, "\n/* starting interface: %s */\n",
className);
name_space = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "namespace");
iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid");
if (name_space) {
fprintf(state->file, "/* namespace: %s */\n",
name_space);
@ -126,6 +125,7 @@ interface(TreeState *state)
name_space,className);
}
iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid");
if (iid) {
/* Redundant, but a better error than 'cannot parse.' */
if (strlen(iid) != 36) {
@ -147,7 +147,6 @@ interface(TreeState *state)
}
/* #define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" */
fputc('\n', state->file);
fputs("#define ", state->file);
write_classname_iid_define(state->file, className);
fprintf(state->file, "_STR \"%s\"\n", iid_parsed);
@ -166,25 +165,30 @@ interface(TreeState *state)
fputc('\n', state->file);
}
if (doc_comments != NULL)
printlist(state->file, doc_comments);
/* The interface declaration itself. */
fprintf(state->file, "class %s", className);
if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
fputs(" : ", state->file);
do {
fprintf(state->file, "public %s",
IDL_IDENT(IDL_LIST(iter).data).str);
if (IDL_LIST(iter).next)
fputs(", ", state->file);
} while ((iter = IDL_LIST(iter).next));
if (IDL_LIST(iter).next != NULL) {
IDL_tree_error(iter,
"multiple inheritance is not supported by xpidl");
FAIL;
}
fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str);
}
fputs(" {\n"
" public: \n", state->file);
" public: \n\n", state->file);
if (iid) {
fputs(" NS_DEFINE_STATIC_IID_ACCESSOR(", state->file);
write_classname_iid_define(state->file, className);
fputs(")\n", state->file);
fputs(")\n\n", state->file);
}
orig = state->tree; /* It would be nice to remove this state-twiddling. */
state->tree = IDL_INTERFACE(iface).body;
if (state->tree && !xpidl_process_node(state))
@ -487,6 +491,27 @@ write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
static gboolean
attr_dcl(TreeState *state)
{
/*
* XXX lists of attributes with the same type, e.g.
* attribute string foo, bar sil;
* are legal IDL... but we don't do anything with 'em.
*/
GSList *doc_comments =
IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
(state->tree).simple_declarations).data).comments;
if (doc_comments != NULL) {
write_indent(state->file);
printlist(state->file, doc_comments);
}
if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) {
XPIDL_WARNING((state->tree, IDL_WARNING1,
"multiple attributes in a single declaration aren't "
"currently supported by xpidl"));
}
xpidl_write_comment(state, 2);
write_indent(state->file);
@ -500,6 +525,8 @@ attr_dcl(TreeState *state)
return FALSE;
fputs(" = 0;\n", state->file);
}
fputc('\n', state->file);
return TRUE;
}
@ -517,6 +544,7 @@ do_const_dcl(TreeState *state)
struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree);
const char *name = IDL_IDENT(dcl->ident).str;
gboolean success, is_signed;
GSList *doc_comments = IDL_IDENT(dcl->ident).comments;
/* const -> list -> interface */
if (!IDL_NODE_UP(IDL_NODE_UP(state->tree)) ||
@ -541,11 +569,17 @@ do_const_dcl(TreeState *state)
is_signed = IDL_TYPE_INTEGER(dcl->const_type).f_signed;
}
if (doc_comments != NULL) {
write_indent(state->file);
printlist(state->file, doc_comments);
}
if (success) {
const char *const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "u";
fprintf(state->file, "\n enum { %s = ", name);
write_indent(state->file);
fprintf(state->file, "enum { %s = ", name);
fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value);
fprintf(state->file, " };\n");
fprintf(state->file, " };\n\n");
} else {
IDL_tree_error(state->tree,
"const declaration \'%s\' must be of type short or long",
@ -558,21 +592,26 @@ do_const_dcl(TreeState *state)
static gboolean
do_typedef(TreeState *state)
{
IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec,
dcls = IDL_TYPE_DCL(state->tree).dcls,
complex;
IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
IDL_tree complex;
GSList *doc_comments;
if (IDL_NODE_TYPE(type) == IDLN_TYPE_SEQUENCE) {
XPIDL_WARNING((state->tree, IDL_WARNING1,
"sequences not supported, ignored"));
} else {
state->tree = type;
fputs("\ntypedef ", state->file);
if (!write_type(state->tree, state->file))
return FALSE;
fputs(" ", state->file);
if (IDL_NODE_TYPE(complex = IDL_LIST(dcls).data) == IDLN_TYPE_ARRAY) {
IDL_tree dim = IDL_TYPE_ARRAY(complex).size_list;
doc_comments = IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).comments;
if (doc_comments != NULL)
printlist(state->file, doc_comments);
fputs("typedef ", state->file);
if (!write_type(type, state->file))
return FALSE;
fputs(" ", state->file);
fprintf(state->file, "%s",
IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).str);
@ -585,10 +624,18 @@ do_typedef(TreeState *state)
fputc(']', state->file);
} while ((dim = IDL_LIST(dim).next) != NULL);
} else {
doc_comments = IDL_IDENT(IDL_LIST(dcls).data).comments;
if (doc_comments != NULL)
printlist(state->file, doc_comments);
fputs("typedef ", state->file);
if (!write_type(type, state->file))
return FALSE;
fputs(" ", state->file);
fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file);
}
fputs(";\n", state->file);
fputs(";\n\n", state->file);
}
return TRUE;
}
@ -634,7 +681,8 @@ write_param(IDL_tree param_tree, FILE *outfile)
/* arrays get a bonus * too */
/* XXX Should this be a leading '*' or a trailing "[]" ?*/
if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, "array"))
if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
"array"))
fputc('*', outfile);
fputs(IDL_IDENT(IDL_PARAM_DCL(param_tree).simple_declarator).str, outfile);
@ -650,9 +698,15 @@ forward_dcl(TreeState *state)
{
IDL_tree iface = state->tree;
const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments;
if (!className)
return FALSE;
fprintf(state->file, "class %s; /* forward decl */\n", className);
if (doc_comments != NULL)
printlist(state->file, doc_comments);
fprintf(state->file, "class %s; /* forward declaration */\n\n", className);
return TRUE;
}
@ -746,19 +800,25 @@ write_method_signature(IDL_tree method_tree, FILE *outfile, gboolean as_call)
static gboolean
op_dcl(TreeState *state)
{
GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments;
/*
* Verify that e.g. non-scriptable methods in [scriptable] interfaces
* are declared so. Do this in a seperate verification pass?
* are declared so. Do this in a separate verification pass?
*/
if (!verify_method_declaration(state->tree))
return FALSE;
if (doc_comments != NULL) {
write_indent(state->file);
printlist(state->file, doc_comments);
}
xpidl_write_comment(state, 2);
write_indent(state->file);
if (!write_method_signature(state->tree, state->file, FALSE))
return FALSE;
fputs(" = 0;\n", state->file);
fputs(" = 0;\n\n", state->file);
return TRUE;
}
@ -776,6 +836,8 @@ static gboolean
codefrag(TreeState *state)
{
const char *desc = IDL_CODEFRAG(state->tree).desc;
GSList *lines = IDL_CODEFRAG(state->tree).lines;
guint fragment_length;
if (strcmp(desc, "C++") && /* libIDL bug? */ strcmp(desc, "C++\r")) {
XPIDL_WARNING((state->tree, IDL_WARNING1,
@ -784,8 +846,28 @@ codefrag(TreeState *state)
return TRUE;
}
g_slist_foreach(IDL_CODEFRAG(state->tree).lines, write_codefrag_line,
(gpointer)state);
/*
* Emit #file directive to point debuggers back to the original .idl file
* for the duration of the code fragment. We look at internal IDL node
* properties _file, _line to do this; hopefully they won't change.
*
* _line seems to refer to the line immediately after the closing %}, so
* we backtrack to get the proper line for the beginning of the block.
*/
/*
* Looks like getting this right means maintaining an accurate line
* count of everything generated, so we can set the file back to the
* correct line in the generated file afterwards. Skipping for now...
*/
fragment_length = g_slist_length(lines);
/* fprintf(state->file, "#line %d \"%s\"\n", */
/* state->tree->_line - fragment_length - 1, */
/* state->tree->_file); */
g_slist_foreach(lines, write_codefrag_line, (gpointer)state);
return TRUE;
}

Просмотреть файл

@ -26,20 +26,6 @@
#include "xpidl.h"
void
xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data)
{
IDL_tree_func_data tfd;
while (p) {
struct _IDL_LIST *list = &IDL_LIST(p);
tfd.tree = list->data;
if (!foreach(&tfd, user_data))
return;
p = list->next;
}
}
/*
* The bulk of the generation happens here.
*/
@ -52,11 +38,7 @@ xpidl_process_node(TreeState *state)
assert(state->tree);
type = IDL_NODE_TYPE(state->tree);
/*
* type == 0 shouldn't ever happen for real, so we use that slot for
* pass-1 processing
*/
if (type && (dispatch = state->dispatch) && (handler = dispatch[type]))
if ((dispatch = state->dispatch) && (handler = dispatch[type]))
return handler(state);
return TRUE;
}
@ -85,36 +67,28 @@ msg_callback(int level, int num, int line, const char *file,
return 1;
}
#define INPUT_BUF_CHUNK 8192
/*
* To keep track of the state associated with a given input file. The 'next'
* field lets us maintain a stack of input files.
*/
typedef struct input_data {
FILE *input; /* stream for getting data */
char *filename; /* where did I come from? */
unsigned int lineno; /* last lineno processed */
char *buf; /* buffer for data */
char *buf; /* contents of file */
char *point; /* next char to feed to libIDL */
int start; /* are we at the start of the file? */
unsigned int len; /* amount of data read into the buffer */
unsigned int max; /* size of the buffer */
char *max; /* 1 past last char in buf */
struct input_data *next; /* file from which we were included */
int f_raw : 2, /* in a raw block when starting next block */
f_comment : 2, /* in a comment when starting next block */
f_include : 2; /* in an #include when starting next block */
char last_read[2]; /* last 1/2 chars read, for spanning blocks */
} input_data;
/* values for f_{raw,comment,include} */
#define INPUT_IN_NONE 0x0
#define INPUT_IN_FULL 0x1 /* we've already started one */
#define INPUT_IN_START 0x2 /* we're about to start one */
#define INPUT_IN_MAYBE 0x3 /* we might be about to start one (check
last_read to be sure) */
/*
* Passed to us by libIDL. Holds global information and the current stack of
* include files.
*/
typedef struct input_callback_state {
struct input_data *input_stack; /* linked list of input_data */
GHashTable *already_included; /* to prevent redundant includes */
IncludePathEntry *include_path;
GSList *base_includes; /* to accumulate #includes in *first* file;
IncludePathEntry *include_path; /* search path for included files */
GSList *base_includes; /* to accumulate #includes from *first* file;
* for passing thru TreeState to
* xpidl_header backend. */
} input_callback_state;
@ -125,39 +99,28 @@ fopen_from_includes(const char *filename, const char *mode,
{
IncludePathEntry *current_path = include_path;
char *pathname;
FILE *file;
FILE *inputfile;
if (!strcmp(filename, "-"))
return stdin;
if (filename[0] != '/') {
while (current_path) {
#ifdef XP_MAC
if (!*current_path->directory)
pathname = g_strdup_printf("%s", filename);
else
pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
current_path->directory, filename);
#else
pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
current_path->directory, filename);
#endif
pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
current_path->directory, filename);
if (!pathname)
return NULL;
#ifdef DEBUG_shaver_bufmgmt
fprintf(stderr, "looking for %s as %s\n", filename, pathname);
#endif
file = fopen(pathname, mode);
inputfile = fopen(pathname, mode);
free(pathname);
if (file)
return file;
if (inputfile)
return inputfile;
current_path = current_path->next;
}
} else {
file = fopen(filename, mode);
if (file)
return file;
inputfile = fopen(filename, mode);
if (inputfile)
return inputfile;
}
return NULL;
return NULL;
}
#ifdef XP_MAC
@ -167,123 +130,168 @@ extern FILE* mac_fopen(const char* filename, const char *mode);
static input_data *
new_input_data(const char *filename, IncludePathEntry *include_path)
{
input_data *new_data = xpidl_malloc(sizeof *new_data);
memset(new_data, 0, sizeof *new_data);
input_data *new_data;
FILE *inputfile;
char *buffer = NULL;
size_t offset = 0;
size_t buffer_size;
#ifdef XP_MAC
size_t i;
#endif
#ifdef XP_MAC
// if file is a full path name, just use fopen, otherwise search access paths.
#if 0
if (strchr(filename, ':') == NULL)
new_data->input = mac_fopen(filename, "r");
inputfile = mac_fopen(filename, "r");
else
new_data->input = fopen(filename, "r");
inputfile = fopen(filename, "r");
#else
// on Mac, fopen knows how to find files.
new_data->input = fopen(filename, "r");
inputfile = fopen(filename, "r");
#endif
#else
new_data->input = fopen_from_includes(filename, "r", include_path);
inputfile = fopen_from_includes(filename, "r", include_path);
#endif
if (!new_data->input)
return NULL;
new_data->buf = xpidl_malloc(INPUT_BUF_CHUNK + 1); /* trailing NUL */
new_data->point = new_data->buf;
new_data->max = INPUT_BUF_CHUNK;
new_data->filename = xpidl_strdup(filename);
if (!inputfile)
return NULL;
/*
* Rather than try to keep track of many different varieties of state
* around the boundaries of a circular buffer, we just read in the entire
* file.
*
* We iteratively grow the buffer here; an alternative would be to use
* stat to find the exact buffer size we need, as xpt_dump does.
*/
for (buffer_size = 8191; ; buffer_size *= 2) {
size_t just_read;
buffer = realloc(buffer, buffer_size + 1); /* +1 for trailing nul */
just_read = fread(buffer + offset, 1, buffer_size - offset, inputfile);
if (ferror(inputfile))
return NULL;
if (just_read < buffer_size - offset || just_read == 0) {
/* Done reading. */
offset += just_read;
break;
}
offset += just_read;
}
fclose(inputfile);
#ifdef XP_MAC
/*
* libIDL doesn't speak '\r' properly - always make sure lines end with
* '\n'.
*/
for (i = 0; i < offset; i++) {
if (buffer[i] == '\r')
buffer[i] = '\n';
}
#endif
new_data = xpidl_malloc(sizeof (struct input_data));
new_data->point = new_data->buf = buffer;
new_data->max = buffer + offset;
*new_data->max = '\0';
new_data->filename = xpidl_strdup(filename);
/* libIDL expects the line number to be that of the *next* line */
new_data->lineno = 2;
new_data->next = NULL;
return new_data;
}
/* process pending raw section */
static int
NextIsRaw(input_data *data, char **startp, int *lenp)
{
char *end, *start;
char *data_end = data->buf + data->len;
#ifdef DEBUG_shaver_input
fputs("[R]", stderr);
#endif
/* process pending raw section, or rest of current one */
if (!(data->f_raw ||
(data->point[0] == '%' && data->point[1] == '{')))
/*
* XXXmccabe still needed: an in_raw flag to handle the case where we're in
* a raw block, but haven't managed to copy it all to xpidl. This will
* happen when we have a raw block larger than
* IDL_input_data->fill.max_size (currently 8192.)
*/
if (!(data->point[0] == '%' && data->point[1] == '{'))
return 0;
start = *startp = data->point;
while (start < data_end && (end = strstr(start, "%}"))) {
end = NULL;
while (start < data->max && (end = strstr(start, "%}"))) {
if (end[-1] == '\r' ||
end[-1] == '\n')
break;
start = end + 1;
}
if (end) {
if (end && start < data->max) {
*lenp = end - data->point + 2;
data->f_raw = 0;
return 1;
} else {
*lenp = data->buf + data->len - data->point;
data->f_raw = 1;
const char *filename;
int lineno;
IDL_file_get(&filename, &lineno);
msg_callback(IDL_ERROR, 0, lineno, filename,
"unterminated %{ block");
return -1;
}
return 1;
}
/* process pending comment */
static int
NextIsComment(input_data *data, char **startp, int *lenp)
{
char *end;
/* process pending comment, or rest of current one */
/*
* XXX someday, my prince will come. Also, we'll upgrade to a
* libIDL that handles comments for us.
*/
#ifdef DEBUG_shaver_input
fputs("[C]", stderr);
#endif
/*
* I tried to do the right thing by handing doc comments to libIDL, but
* it barfed. Go figger.
*/
if (!(data->f_comment ||
(data->point[0] == '/' && data->point[1] == '*')))
if (!(data->point[0] == '/' && data->point[1] == '*'))
return 0;
end = strstr(data->point, "*/");
*lenp = 0;
if (end) {
int skippedLines;
int skippedLines = 0;
char *tempPoint;
/* get current lineno */
IDL_file_get(NULL,(int *)&data->lineno);
/* get current lineno */
IDL_file_get(NULL,(int *)&data->lineno);
*startp = data->point;
/* get line count */
for(skippedLines = 0;;)
{
*startp = strstr(*startp,"\n");
if (!*startp || *startp >= end)
break;
*startp += 1;
skippedLines++;
}
data->lineno += skippedLines;
IDL_file_set(data->filename, (int)data->lineno);
/* get line count */
for (tempPoint = data->point; tempPoint < end; tempPoint++) {
if (*tempPoint == '\n')
skippedLines++;
}
data->lineno += skippedLines;
IDL_file_set(data->filename, (int)data->lineno);
*startp = end + 2;
data->f_comment = 0;
/* If it's a ** comment, tell libIDL about it. */
if (data->point[2] == '*') {
/* hack termination. +2 to get past '*' '/' */
char t = *(end + 2);
*(end + 2) = '\0';
IDL_queue_new_ident_comment(data->point);
*(end + 2) = t;
}
data->point = *startp; /* XXXmccabe move this out of function? */
return 1;
} else {
*startp = data->buf + data->len;
data->f_comment = 1;
const char *filename;
int lineno;
IDL_file_get(&filename, &lineno);
msg_callback(IDL_ERROR, 0, lineno, filename,
"unterminated comment");
return -1;
}
data->point = *startp;
return 1;
}
static int
@ -295,58 +303,53 @@ NextIsInclude(input_callback_state *callback_state, char **startp,
char *filename, *start, *end;
const char *scratch;
#ifdef DEBUG_shaver_input
fputs("[I", stderr);
#endif
/* process the #include that we're in now */
if (strncmp(data->point, "#include \"", 10)) {
#ifdef DEBUG_shaver_input
fputs("0]", stderr);
#endif
return 0;
}
start = filename = data->point + 10; /* skip #include " */
assert(start < data->buf + data->len);
end = strchr(filename, '\"');
if (!end) {
/* filename probably stops at next whitespace */
char *data_end = data->buf + data->len;
start = end = filename - 1;
while (end < data_end) {
if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t') {
*end = '\0';
filename = data->point + 10; /* skip #include " */
assert(filename < data->max);
end = filename;
while (end < data->max) {
if (*end == '\"' || *end == '\n' || *end == '\r')
break;
end++;
}
if (*end != '\"') {
/*
* Didn't find end of include file. Scan 'til next whitespace to find
* some reasonable approximation of the filename, and use it to report
* an error.
*/
end = filename;
while (end < data->max) {
if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t')
break;
}
end++;
}
*end = '\0';
/* make sure we have accurate line info */
IDL_file_get(&scratch, (int *)&data->lineno);
fprintf(stderr,
"%s:%d: didn't find end of quoted include name %*s\n",
scratch, data->lineno, end - start, start);
"%s:%d: didn't find end of quoted include name \"%s\n",
scratch, data->lineno, filename);
return -1;
}
if (*end == '\r' || *end == '\n')
IDL_file_set(NULL,(int)(++data->lineno));
*end = '\0';
*startp = end + 1;
#ifdef DEBUG_shaver_inc
fprintf(stderr, "found #include %s\n", filename);
#endif
if (data->next == NULL) {
/*
* If we're in the initial file, add this filename to the list
* of filenames to be turned into #include "filename.h"
* directives in xpidl_header.c. We do it here rather than in the
* block below so it still gets added to the list even if it's
* already been included from some included file.
* already been recursively included from some other file.
*/
char *filename_cp = xpidl_strdup(filename);
@ -358,36 +361,32 @@ NextIsInclude(input_callback_state *callback_state, char **startp,
/* store offset for when we pop, or if we skip this one */
data->point = *startp;
assert(callback_state->already_included);
if (!g_hash_table_lookup(callback_state->already_included, filename)) {
filename = xpidl_strdup(filename);
g_hash_table_insert(callback_state->already_included,
filename, (void *)TRUE);
new_data = new_input_data(filename,
callback_state->include_path);
new_data = new_input_data(filename, callback_state->include_path);
if (!new_data) {
char *error_message;
IDL_file_get(&scratch, (int *)&data->lineno);
error_message =
g_strdup_printf("can't open included file %s for reading\n",
filename);
msg_callback(IDL_ERROR, 0 /* unused */,
msg_callback(IDL_ERROR, 0,
data->lineno, scratch, error_message);
free(error_message);
return -1;
}
new_data->next = data;
/* tell libIDL to exclude this IDL from the toplevel tree */
IDL_inhibit_push();
IDL_file_get(&scratch, (int *)&data->lineno);
data = callback_state->input_stack = new_data;
IDL_file_set(data->filename, (int)data->lineno);
callback_state->input_stack = new_data;
IDL_file_set(new_data->filename, (int)new_data->lineno);
}
*lenp = 0; /* this is magic, see the comment below */
#ifdef DEBUG_shaver_input
fputs("1]", stderr);
#endif
return 1;
}
@ -395,28 +394,28 @@ static void
FindSpecial(input_data *data, char **startp, int *lenp)
{
char *point = data->point;
char *end = data->buf + data->len;
/* magic sequences are:
* "%{" raw block
* "/\*" comment
* "/\*" comment
* "#include \"" include
* The first and last want a newline [\r\n] before, or the start of the
* file.
*/
#define LINE_START(data, point) (data->start || \
#define LINE_START(data, point) (point == data->buf || \
(point > data->point && \
(point[-1] == '\r' || point[-1] == '\n')))
while (point < end) {
/* XXX unroll? */
if (point[0] == '%' && LINE_START(data, point) && point[1] == '{')
break;
if (point[0] == '/' && point[1] == '*') /* && point[2] != '*') */
break;
if (!strncmp(point, "#include \"", 10) && LINE_START(data, point))
while (point < data->max) {
if (point[0] == '/' && point[1] == '*')
break;
if (LINE_START(data, point)) {
if (point[0] == '%' && point[1] == '{')
break;
if (point[0] == '#' && !strncmp(point + 1, "include \"", 9))
break;
}
point++;
}
@ -424,22 +423,8 @@ FindSpecial(input_data *data, char **startp, int *lenp)
*startp = data->point;
*lenp = point - data->point;
#ifdef DEBUG_shaver_input
fprintf(stderr, "*startp = offset %d, *lenp = %d\n", *startp - data->buf,
*lenp);
#endif
}
#ifdef XP_MAC
static void cr2lf(char* str)
{
int ch;
while ((ch = *str++) != '\0') {
if (ch == '\r') str[-1] = '\n';
}
}
#endif
/* set this with a debugger to see exactly what libIDL sees */
static FILE *tracefile;
@ -450,7 +435,7 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
input_callback_state *callback_state = user_data;
input_data *data = callback_state->input_stack;
input_data *new_data = NULL;
unsigned int len, copy, avail;
unsigned int len, copy;
int rv;
char *start;
@ -462,6 +447,10 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
* file, we only look for it in the first entry in the include
* path, which we assume to be the current directory.
*/
/* XXXmccabe proper assumption? Do we handle files in other
directories? */
IncludePathEntry first_entry;
first_entry.directory = callback_state->include_path->directory;
@ -482,58 +471,29 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
return 0;
case IDL_INPUT_REASON_FILL:
/* get data into the buffer */
data->start = 0;
start = NULL;
len = 0;
while (!(avail = data->buf + data->len - data->point)) {
data->point = data->buf;
/* fill the buffer */
data->len = fread(data->buf, 1, data->max, data->input);
/* if we've got data in the buffer, no need for the tricks below */
if (data->len) {
data->start = 1;
break;
}
if (ferror(data->input))
return -1;
/* pop include */
/* beard: what about closing the file? */
fclose(data->input);
data->input = NULL; /* prevent double close */
while (data->point >= data->max) {
if (!data->next)
return 0;
data->input = NULL;
#ifdef DEBUG_shaver_includes
fprintf(stderr, "leaving %s, returning to %s\n",
data->filename, data->next->filename);
#endif
/* Current file is done; revert to including file */
callback_state->input_stack = data->next;
/* shaver: what about freeing the input structure? */
free(data->filename);
free(data->buf);
free(data);
data = callback_state->input_stack;
IDL_file_set(data->filename, (int)data->lineno);
IDL_inhibit_pop();
data->f_include = INPUT_IN_NONE;
}
/* force NUL-termination on the buffer */
#ifdef XP_MAC
/* always make sure lines end with '\n' */
cr2lf(data->buf);
#endif
data->buf[data->len] = 0;
/*
* Now we scan for sequences which require special attention:
* \n#include begins an include statement
* \n%{ begins a raw-source block
* /\* begins a comment
* /\* begins a comment
*
* We used to be fancier here, so make sure that we sent the most
* data possible at any given time. To that end, we skipped over
@ -544,30 +504,21 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
* state! what fun! -- so now we just do this:
*
* if (special at start) {
* process that special;
* send next chunk of data to libIDL;
* process that special -
* - raw: send it to libIDL, and don't look inside for specials
* - comments: adjust point and start over
* - includes: push new input_data struct for included file, and
* start over
* } else {
* scan for next special;
* send data up to that special to libIDL;
* scan for next special
* send data up to that special to libIDL
* }
*
* Easy as pie. Except that libIDL takes a return of zero to mean
* ``all done'', so whenever we would want to do that, we send a single
* space in the buffer. Nobody'll notice, promise. (For the curious,
* we would want to send zero bytes but be called again when we start
* include processing or when a comment/raw follows another
* immediately, etc.)
*
* XXX we don't handle the case where the \n#include or /\* or \n%{
* sequence straddles a block boundary. We should really fix that.
*
* XXX we don't handle doc-comments correctly (correct would be sending
* them to through to libIDL where they will get tokenized and made
* available to backends that want to generate docs). When we next
* upgrade libIDL versions, it'll handle comments for us, which will
* help a lot.
* If len is set to zero, it is a sentinel value indicating we a comment
* or include was found, and parsing should start over.
*
* XXX const string foo = "/\*" will just screw us horribly.
* Hm but. We could treat strings as we treat raw blocks, eh?
*/
/*
@ -575,37 +526,43 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
* #includes within raw sections, and so that you can comment out
* #includes.
*/
/* XXX should check for errors here, too */
rv = NextIsRaw(data, &start, (int *)&len);
if (rv == -1) return -1;
if (!rv) {
/*
* When NextIsComment succeeds, it returns a 0 len (requesting a
* restart) and adjusts data->point to pick up after the comment.
*/
rv = NextIsComment(data, &start, (int *)&len);
if (rv == -1) return -1;
if (!rv) {
/* includes might need to push a new file */
/*
* NextIsInclude might push a new input_data struct; if so, it
* will return a 0 len, letting the callback pick up the new
* file the next time around.
*/
rv = NextIsInclude(callback_state, &start, (int *)&len);
if (rv == -1) return -1;
if (!rv)
/* FindSpecial can't fail? */
FindSpecial(data, &start, (int *)&len);
}
}
assert(start);
copy = MIN(len, (unsigned int) cb_data->fill.max_size);
if (copy) {
memcpy(cb_data->fill.buffer, start, copy);
data->point = start + copy;
} else {
cb_data->fill.buffer[0] = ' ';
copy = 1;
if (len == 0) {
/*
* len == 0 is a sentinel value that means we found a comment or
* include. If we found a comment, point has been adjusted to
* point past the comment. If we found an include, a new input_data
* has been pushed. In both cases, calling the input_callback again
* will pick up the new state.
*/
return input_callback(reason, cb_data, user_data);
}
#ifdef DEBUG_shaver_input
fprintf(stderr, "COPYING %d->%.*s<-COPYING\n", copy, (int)copy,
cb_data->fill.buffer);
#endif
copy = MIN(len, (unsigned int) cb_data->fill.max_size);
memcpy(cb_data->fill.buffer, start, copy);
data->point = start + copy;
if (tracefile)
fwrite(cb_data->fill.buffer, copy, 1, tracefile);
@ -613,12 +570,15 @@ input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
case IDL_INPUT_REASON_ABORT:
case IDL_INPUT_REASON_FINISH:
if (data->input && data->input != stdin)
fclose(data->input);
data->input = NULL;
free(data->buf);
data->buf = data->point = NULL;
data->len = data->max = 0;
while (data != NULL) {
input_data *next;
next = data->next;
free(data->filename);
free(data->buf);
free(data);
data = next;
}
return 0;
default:
@ -657,17 +617,15 @@ xpidl_process_idl(char *filename, IncludePathEntry *include_path,
int rv;
input_callback_state callback_state;
gboolean ok;
char *fopen_mode;
backend *emitter;
/*
* Initialize so that callback_state->top, etc. doesn't come up as garbage.
*/
memset(&callback_state, 0, sizeof(struct input_callback_state));
callback_state.input_stack = NULL;
callback_state.base_includes = NULL;
callback_state.include_path = include_path;
callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal);
if (!callback_state.already_included) {
fprintf(stderr, "failed to create hashtable (EOM?)\n");
fprintf(stderr, "failed to create hashtable. out of memory?\n");
return 0;
}
@ -678,28 +636,15 @@ xpidl_process_idl(char *filename, IncludePathEntry *include_path,
if (tmp)
*tmp = '\0';
#ifdef XP_MAC
// on the Mac, we let CodeWarrior tell us where to put the output file.
if (!file_basename) {
outname = xpidl_strdup(filename);
tmp = strrchr(outname, '.');
if (tmp != NULL) *tmp = '\0';
} else {
outname = xpidl_strdup(file_basename);
}
#else
if (!file_basename)
outname = xpidl_strdup(state.basename);
else
outname = xpidl_strdup(file_basename);
#endif
/* so we don't include it again! */
g_hash_table_insert(callback_state.already_included,
xpidl_strdup(filename), (void *)TRUE);
callback_state.include_path = include_path;
rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
msg_callback, &top,
&state.ns,
@ -725,10 +670,11 @@ xpidl_process_idl(char *filename, IncludePathEntry *include_path,
state.base_includes = callback_state.base_includes;
emitter = mode->factory();
/* assert(emitter); */
state.dispatch = emitter->dispatch_table;
if (strcmp(outname, "-")) {
const char *fopen_mode;
mode_outname = g_strdup_printf("%s.%s", outname, mode->suffix);
/* Use binary write for typelib mode */
fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb";
@ -761,10 +707,8 @@ xpidl_process_idl(char *filename, IncludePathEntry *include_path,
if (mode_outname != NULL) {
/*
* Delete partial output file on failure. Looks like this is tricky
* XP, so only enable for unix and win32. Lacking this won't hurt
* compiles of already-working IDL for mac. (NSPR code too scary
* to steal is in macio.c:_MD_Delete(). )
* Delete partial output file on failure. (Mac does this in the plugin
* driver code, if the compiler returns failure.)
*/
#if defined(XP_UNIX) || defined(XP_WIN)
if (!ok)
@ -800,7 +744,7 @@ xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...)
}
/* call our message callback, like IDL_tree_warning would */
msg_callback(level, 0 /* unused in callee */, lineno, file, msg);
msg_callback(level, 0, lineno, file, msg);
va_end(ap);
}

Просмотреть файл

@ -451,6 +451,7 @@ method_declaration(TreeState *state)
if (!verify_method_declaration(state->tree))
return FALSE;
fputc('\n', state->file);
xpidl_write_comment(state, 4);
/*
@ -621,7 +622,8 @@ constant_declaration(TreeState *state)
}
if (success) {
xpidl_write_comment(state, 4);
fputc('\n', state->file);
xpidl_write_comment(state, 4);
fprintf(state->file, " public static final %s %s = %d;\n",
(isshort ? "short" : "int"),
@ -652,6 +654,7 @@ attribute_declaration(TreeState *state)
/* Comment */
fputc('\n', state->file);
xpidl_write_comment(state, 4);
state->tree = ATTR_TYPE_DECL(state->tree);

Просмотреть файл

@ -65,7 +65,7 @@ xpidl_strdup(const char *s)
void
xpidl_write_comment(TreeState *state, int indent)
{
fprintf(state->file, "\n%*s/* ", indent, "");
fprintf(state->file, "%*s/* ", indent, "");
IDL_tree_to_IDL(state->tree, state->ns, state->file,
IDLF_OUTPUT_NO_NEWLINES |
IDLF_OUTPUT_NO_QUALIFY_IDENTS |
@ -240,3 +240,32 @@ check_native(TreeState *state)
native_name, native_name);
return FALSE;
}
/*
* Print a GSList as char strings to a file.
*/
void
printlist(FILE *outfile, GSList *slist)
{
guint i;
guint len = g_slist_length(slist);
for(i = 0; i < len; i++) {
fprintf(outfile,
"%s\n", (char *)g_slist_nth_data(slist, i));
}
}
void
xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data)
{
IDL_tree_func_data tfd;
while (p) {
struct _IDL_LIST *list = &IDL_LIST(p);
tfd.tree = list->data;
if (!foreach(&tfd, user_data))
return;
p = list->next;
}
}