Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
xpidl_idl.c File Reference
#include "xpidl.h"
#include "limits.h"

Go to the source code of this file.

Classes

struct  input_data
struct  input_callback_state

Defines

#define LINE_START(data, point)

Typedefs

typedef struct input_data input_data
typedef struct input_callback_state input_callback_state

Functions

gboolean xpidl_process_node (TreeState *state)
static int msg_callback (int level, int num, int line, const char *file, const char *message)
static FILEfopen_from_includes (const char *filename, const char *mode, IncludePathEntry *include_path)
static input_datanew_input_data (const char *filename, IncludePathEntry *include_path)
static int NextIsRaw (input_data *data, char **startp, int *lenp)
static int NextIsComment (input_data *data, char **startp, int *lenp)
static int NextIsInclude (input_callback_state *callback_state, char **startp, int *lenp)
static void FindSpecial (input_data *data, char **startp, int *lenp)
static int input_callback (IDL_input_reason reason, union IDL_input_data *cb_data, gpointer user_data)
static void free_ghash_key (gpointer key, gpointer value, gpointer user_data)
static void free_gslist_data (gpointer data, gpointer user_data)
int xpidl_process_idl (char *filename, IncludePathEntry *include_path, char *file_basename, char *package, ModeData *mode)
void xpidl_tree_warning (IDL_tree p, int level, const char *fmt,...)

Variables

static gboolean parsed_empty_file
static FILEtracefile

Class Documentation

struct input_data

Definition at line 106 of file xpidl_idl.c.

Collaboration diagram for input_data:
Class Members
char * buf
char * filename
unsigned int lineno
char * max
struct input_data * next
char * point
struct input_callback_state

Definition at line 119 of file xpidl_idl.c.

Collaboration diagram for input_callback_state:
Class Members
GHashTable * already_included
GSList * base_includes
IncludePathEntry * include_path
struct input_data * input_stack

Define Documentation

#define LINE_START (   data,
  point 
)
Value:
(point == data->buf ||                       \
                                 (point > data->point &&                     \
                                  (point[-1] == '\r' || point[-1] == '\n')))

Typedef Documentation

typedef struct input_data input_data

Function Documentation

static void FindSpecial ( input_data data,
char **  startp,
int lenp 
) [static]

Definition at line 442 of file xpidl_idl.c.

{
    char *point = data->point;

    /* magic sequences are:
     * "%{"               raw block
     * "/\*"              comment
     * "#include \""      include
     * The first and last want a newline [\r\n] before, or the start of the
     * file.
     */

#define LINE_START(data, point) (point == data->buf ||                       \
                                 (point > data->point &&                     \
                                  (point[-1] == '\r' || point[-1] == '\n')))
                                                 
    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++;
    }

#undef LINE_START

    *startp = data->point;
    *lenp = point - data->point;
}

Here is the caller graph for this function:

static FILE* fopen_from_includes ( const char *  filename,
const char *  mode,
IncludePathEntry include_path 
) [static]

Definition at line 129 of file xpidl_idl.c.

{
    IncludePathEntry *current_path = include_path;
    char *pathname;
    FILE *inputfile;
    if (!strcmp(filename, "-"))
        return stdin;

    if (filename[0] != '/') {
        while (current_path) {
            pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
                                       current_path->directory, filename);
            if (!pathname)
                return NULL;
            inputfile = fopen(pathname, mode);
            g_free(pathname);
            if (inputfile)
                return inputfile;
            current_path = current_path->next;
        }
    } else {
        inputfile = fopen(filename, mode);
        if (inputfile)
            return inputfile;
    }
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void free_ghash_key ( gpointer  key,
gpointer  value,
gpointer  user_data 
) [static]

Definition at line 639 of file xpidl_idl.c.

{
    /* We're only storing TRUE in the value... */
    free(key);
}

Here is the caller graph for this function:

static void free_gslist_data ( gpointer  data,
gpointer  user_data 
) [static]

Definition at line 646 of file xpidl_idl.c.

{
    free(data);
}

Here is the caller graph for this function:

static int input_callback ( IDL_input_reason  reason,
union IDL_input_data *  cb_data,
gpointer  user_data 
) [static]

Definition at line 480 of file xpidl_idl.c.

{
    input_callback_state *callback_state = user_data;
    input_data *data = callback_state->input_stack;
    input_data *new_data = NULL;
    unsigned int len, copy;
    int rv;
    char *start;

    switch(reason) {
      case IDL_INPUT_REASON_INIT:
        if (data == NULL || data->next == NULL) {
            /*
             * This is the first file being processed.  As it's the target
             * 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;
            first_entry.next = NULL;

            new_data = new_input_data(cb_data->init.filename,
                                               &first_entry);
        } else {
            new_data = new_input_data(cb_data->init.filename,
                                               callback_state->include_path);
        }

        if (!new_data)
            return -1;

        IDL_file_set(new_data->filename, (int)new_data->lineno);
        callback_state->input_stack = new_data;
        return 0;

      case IDL_INPUT_REASON_FILL:
        start = NULL;
        len = 0;

        while (data->point >= data->max) {
            if (!data->next)
                return 0;

            /* Current file is done; revert to including file */
            callback_state->input_stack = data->next;
            free(data->filename);
            free(data->buf);
            free(data);
            data = callback_state->input_stack;

            IDL_file_set(data->filename, (int)data->lineno);
            IDL_inhibit_pop();
        }
        
        /*
         * Now we scan for sequences which require special attention:
         *   \n#include                   begins an include statement
         *   \n%{                         begins a raw-source block
         *   /\*                          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
         * \n%{ raw \n%} blocks and then _continued_ the search for special
         * sequences like \n#include or /\* comments .
         * 
         * It was really ugly, though -- liberal use of goto!  lots of implicit
         * state!  what fun! -- so now we just do this:
         *
         * if (special at start) {
         *     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
         * }
         *
         * 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?
         */

        /*
         * Order is important, so that you can have /\* comments and
         * #includes within raw sections, and so that you can comment out
         * #includes.
         */
        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) {
                /*
                 * 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(data, &start, (int *)&len);
            }
        }

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

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

        return copy;

      case IDL_INPUT_REASON_ABORT:
      case IDL_INPUT_REASON_FINISH:
        while (data != NULL) {
            input_data *next;

            next = data->next;
            free(data->filename);
            free(data->buf);
            free(data);
            data = next;
        }
        return 0;

      default:
        g_error("unknown input reason %d!", reason);
        return -1;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int msg_callback ( int  level,
int  num,
int  line,
const char *  file,
const char *  message 
) [static]

Definition at line 74 of file xpidl_idl.c.

{
    char *warning_message;

    /*
     * Egregious hack to permit empty files.
     * XXX libIDL needs an API to detect this case robustly.
     */
    if (0 == strcmp(message, "File empty after optimization")) {
        parsed_empty_file = TRUE;
        return 1;
    }

    if (!file)
        file = "<unknown file>";
    warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message);

#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
    mac_warning(warning_message);
#else
    fputs(warning_message, stderr);
#endif

    g_free(warning_message);
    return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static input_data* new_input_data ( const char *  filename,
IncludePathEntry include_path 
) [static]

Definition at line 163 of file xpidl_idl.c.

{
    input_data *new_data;
    FILE *inputfile;
    char *buffer = NULL;
    size_t offset = 0;
    size_t buffer_size;
#ifdef XP_MAC
    size_t i;
#endif

#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
    /* on Mac, fopen knows how to find files. */
    inputfile = fopen(filename, "r");
#elif defined(XP_OS2) || defined(XP_WIN32)
    /*
     * if filename is fully qualified (starts with driver letter), then
     * just call fopen();  else, go with fopen_from_includes()
     */
    if( filename[1] == ':' )
      inputfile = fopen(filename, "r");
    else
      inputfile = fopen_from_includes(filename, "r", include_path);
#else
    inputfile = fopen_from_includes(filename, "r", include_path);
#endif

    if (!inputfile)
        return NULL;

#ifdef XP_MAC
    {
        struct stat input_stat;
        if (fstat(fileno(inputfile), &input_stat))
            return NULL;
        buffer = malloc(input_stat.st_size + 1);
        if (!buffer)
            return NULL;
        offset = fread(buffer, 1, input_stat.st_size, inputfile);
        if (ferror(inputfile))
            return NULL;
    }
#else
    /*
     * 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;
    }
#endif

    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int NextIsComment ( input_data data,
char **  startp,
int lenp 
) [static]

Definition at line 296 of file xpidl_idl.c.

{
    char *end;

    if (!(data->point[0] == '/' && data->point[1] == '*'))
        return 0;

    end = strstr(data->point, "*/");
    *lenp = 0;
    if (end) {
        int skippedLines = 0;
        char *tempPoint;
        
        /* get current lineno */
        IDL_file_get(NULL,(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;

        /* 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 {
        const char *filename;
        int lineno;

        IDL_file_get(&filename, &lineno);
        msg_callback(IDL_ERROR, 0, lineno, filename,
                     "unterminated comment");
        return -1;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int NextIsInclude ( input_callback_state callback_state,
char **  startp,
int lenp 
) [static]

Definition at line 346 of file xpidl_idl.c.

{
    input_data *data = callback_state->input_stack;
    input_data *new_data;
    char *filename, *end;
    const char *scratch;

    /* process the #include that we're in now */
    if (strncmp(data->point, "#include \"", 10)) {
        return 0;
    }
    
    filename = data->point + 10; /* skip #include " */
    XPT_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, filename);
        return -1;
    }

    *end = '\0';
    *startp = end + 1;

    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 recursively included from some other file.
         */
        char *filename_cp = xpidl_strdup(filename);
        
        /* note that g_slist_append accepts and likes null as list-start. */
        callback_state->base_includes =
            g_slist_append(callback_state->base_includes, filename_cp);
    }

    /* store offset for when we pop, or if we skip this one */
    data->point = *startp;

    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);
        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,
                         data->lineno, scratch, error_message);
            g_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);
        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 */
    return 1;
}    

Here is the call graph for this function:

Here is the caller graph for this function:

static int NextIsRaw ( input_data data,
char **  startp,
int lenp 
) [static]

Definition at line 257 of file xpidl_idl.c.

{
    char *end, *start;

    /*
     * 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;
    
    end = NULL;
    while (start < data->max && (end = strstr(start, "%}"))) {
        if (end[-1] == '\r' ||
            end[-1] == '\n')
            break;
        start = end + 1;
    }

    if (end && start < data->max) {
        *lenp = end - data->point + 2;
        return 1;
    } else {
        const char *filename;
        int lineno;

        IDL_file_get(&filename, &lineno);
        msg_callback(IDL_ERROR, 0, lineno, filename,
                     "unterminated %{ block");
        return -1;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int xpidl_process_idl ( char *  filename,
IncludePathEntry include_path,
char *  file_basename,
char *  package,
ModeData mode 
)

Definition at line 659 of file xpidl_idl.c.

{
    char *tmp, *outname, *real_outname = NULL;
    IDL_tree top;
    TreeState state;
    int rv;
    input_callback_state callback_state;
    gboolean ok = TRUE;
    backend *emitter;

    memset(&state, 0, sizeof(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.  out of memory?\n");
        return 0;
    }

    state.basename = xpidl_strdup(filename);
    if (package)
      state.package = xpidl_strdup(package);

    /* if basename has an .extension, truncate it. */
    tmp = strrchr(state.basename, '.');
    if (tmp)
        *tmp = '\0';

    if (!file_basename)
        outname = xpidl_strdup(state.basename);
    else
        outname = xpidl_strdup(file_basename);

    /* so we don't include it again! */
    g_hash_table_insert(callback_state.already_included,
                        xpidl_strdup(filename), (void *)TRUE);

    parsed_empty_file = FALSE;

    rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
                                       msg_callback, &top,
                                       &state.ns,
                                       IDLF_IGNORE_FORWARDS |
                                       IDLF_XPIDL,
                                       enable_warnings ? IDL_WARNING1 :
                                       IDL_ERROR);
    if (parsed_empty_file) {
        /*
         * If we've detected (via hack in msg_callback) that libIDL returned
         * failure because it found a file with no IDL, set the parse tree to
         * null and proceed.  Allowing this is useful to permit .idl files that
         * collect #includes.
         */
        top = NULL;
        state.ns = NULL;
    } else if (rv != IDL_SUCCESS) {
        if (rv == -1) {
            g_warning("Parse of %s failed: %s", filename, g_strerror(errno));
        } else {
            g_warning("Parse of %s failed", filename);
        }
        return 0;
    }

    state.basename = xpidl_strdup(filename);
    tmp = strrchr(state.basename, '.');
    if (tmp)
        *tmp = '\0';

    /* so xpidl_header.c can use it to generate a list of #include directives */
    state.base_includes = callback_state.base_includes;

    emitter = mode->factory();
    state.dispatch = emitter->dispatch_table;

    if (strcmp(outname, "-")) {
        const char *fopen_mode;
        const char *out_basename;

        /* explicit_output_filename can't be true without a filename */
        if (explicit_output_filename) {
            real_outname = g_strdup(outname);
        } else {
/* 
 *This combination seems a little strange, what about OS/2?
 * Assume it's some build issue
 */
#if defined(XP_UNIX) || defined(XP_WIN)
            if (!file_basename) {
                out_basename = xpidl_basename(outname);
            } else {
                out_basename = outname;
            }
#else
            out_basename = outname;
#endif
            real_outname = g_strdup_printf("%s.%s", out_basename, mode->suffix);
        }

        /* don't create/open file here for Java */
        if (strcmp(mode->mode, "java") == 0)
        {
            state.filename = real_outname;
        } else {
            /* Use binary write for typelib mode */
            fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb";
            state.file = fopen(real_outname, fopen_mode);
            if (!state.file) {
                perror("error opening output file");
                return 0;
            }
        }
    } else {
        state.file = stdout;
    }
    state.tree = top;

    if (emitter->emit_prolog)
        emitter->emit_prolog(&state);
    if (state.tree) /* Only if we have a tree to process. */
        ok = xpidl_process_node(&state);
    if (emitter->emit_epilog)
        emitter->emit_epilog(&state);

    if (strcmp(mode->mode, "java") != 0)
    {
        if (state.file != stdout)
            fclose(state.file);
    }

    free(state.basename);
    free(state.package);
    free(outname);
    g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL);
    g_hash_table_destroy(callback_state.already_included);
    g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL);

    if (state.ns)
        IDL_ns_free(state.ns);
    if (top)
        IDL_tree_free(top);

    if (real_outname != NULL) {
        /*
         * 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)
            unlink(real_outname);
#endif
        g_free(real_outname);
    }

    return ok;
}

Here is the call graph for this function:

Here is the caller graph for this function:

gboolean xpidl_process_node ( TreeState state)

Definition at line 56 of file xpidl_idl.c.

{
    gint type;
    nodeHandler *dispatch, handler;

    XPT_ASSERT(state->tree);
    type = IDL_NODE_TYPE(state->tree);

    if ((dispatch = state->dispatch) && (handler = dispatch[type]))
        return handler(state);
    return TRUE;
}
void xpidl_tree_warning ( IDL_tree  p,
int  level,
const char *  fmt,
  ... 
)

Definition at line 825 of file xpidl_idl.c.

{
    va_list ap;
    char *msg, *file;
    int lineno;

    /* XXX need to check against __IDL_max_msg_level, no accessor */
    va_start(ap, fmt);
    msg = g_strdup_vprintf(fmt, ap);

    if (p) {
        file = p->_file;
        lineno = p->_line;
    } else {
        file = NULL;
        lineno = 0;
    }

    /* call our message callback, like IDL_tree_warning would */
    msg_callback(level, 0, lineno, file, msg);
    g_free(msg);
    va_end(ap);
}

Here is the call graph for this function:


Variable Documentation

gboolean parsed_empty_file [static]

Definition at line 50 of file xpidl_idl.c.

FILE* tracefile [static]

Definition at line 477 of file xpidl_idl.c.