Back to index

lightning-sunbird  0.9+nobinonly
xpidl_idl.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Michael Ang <mang@subcarrier.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040  * Common IDL-processing code.
00041  */
00042 
00043 #include "xpidl.h"
00044 #include <limits.h>
00045 
00046 #ifdef XP_MAC
00047 #include <stat.h>
00048 #endif
00049 
00050 static gboolean parsed_empty_file;
00051 
00052 /*
00053  * The bulk of the generation happens here.
00054  */
00055 gboolean
00056 xpidl_process_node(TreeState *state)
00057 {
00058     gint type;
00059     nodeHandler *dispatch, handler;
00060 
00061     XPT_ASSERT(state->tree);
00062     type = IDL_NODE_TYPE(state->tree);
00063 
00064     if ((dispatch = state->dispatch) && (handler = dispatch[type]))
00065         return handler(state);
00066     return TRUE;
00067 }
00068 
00069 #if defined(XP_MAC) && defined(XPIDL_PLUGIN)
00070 extern void mac_warning(const char* warning_message);
00071 #endif
00072 
00073 static int
00074 msg_callback(int level, int num, int line, const char *file,
00075              const char *message)
00076 {
00077     char *warning_message;
00078 
00079     /*
00080      * Egregious hack to permit empty files.
00081      * XXX libIDL needs an API to detect this case robustly.
00082      */
00083     if (0 == strcmp(message, "File empty after optimization")) {
00084         parsed_empty_file = TRUE;
00085         return 1;
00086     }
00087 
00088     if (!file)
00089         file = "<unknown file>";
00090     warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message);
00091 
00092 #if defined(XP_MAC) && defined(XPIDL_PLUGIN)
00093     mac_warning(warning_message);
00094 #else
00095     fputs(warning_message, stderr);
00096 #endif
00097 
00098     g_free(warning_message);
00099     return 1;
00100 }
00101 
00102 /*
00103  * To keep track of the state associated with a given input file.  The 'next'
00104  * field lets us maintain a stack of input files.
00105  */
00106 typedef struct input_data {
00107     char *filename;             /* where did I come from? */
00108     unsigned int lineno;        /* last lineno processed */
00109     char *buf;                  /* contents of file */
00110     char *point;                /* next char to feed to libIDL */
00111     char *max;                  /* 1 past last char in buf */
00112     struct input_data *next;    /* file from which we were included */
00113 } input_data;
00114 
00115 /*
00116  * Passed to us by libIDL.  Holds global information and the current stack of
00117  * include files.
00118  */
00119 typedef struct input_callback_state {
00120     struct input_data *input_stack; /* linked list of input_data */   
00121     GHashTable *already_included;   /* to prevent redundant includes */
00122     IncludePathEntry *include_path; /* search path for included files */
00123     GSList *base_includes;          /* to accumulate #includes from *first* file;
00124                                      * for passing thru TreeState to
00125                                      * xpidl_header backend. */
00126 } input_callback_state;
00127 
00128 static FILE *
00129 fopen_from_includes(const char *filename, const char *mode,
00130                     IncludePathEntry *include_path)
00131 {
00132     IncludePathEntry *current_path = include_path;
00133     char *pathname;
00134     FILE *inputfile;
00135     if (!strcmp(filename, "-"))
00136         return stdin;
00137 
00138     if (filename[0] != '/') {
00139         while (current_path) {
00140             pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
00141                                        current_path->directory, filename);
00142             if (!pathname)
00143                 return NULL;
00144             inputfile = fopen(pathname, mode);
00145             g_free(pathname);
00146             if (inputfile)
00147                 return inputfile;
00148             current_path = current_path->next;
00149         }
00150     } else {
00151         inputfile = fopen(filename, mode);
00152         if (inputfile)
00153             return inputfile;
00154     }
00155     return NULL;
00156 }
00157 
00158 #if defined(XP_MAC) && defined(XPIDL_PLUGIN)
00159 extern FILE* mac_fopen(const char* filename, const char *mode);
00160 #endif
00161 
00162 static input_data *
00163 new_input_data(const char *filename, IncludePathEntry *include_path)
00164 {
00165     input_data *new_data;
00166     FILE *inputfile;
00167     char *buffer = NULL;
00168     size_t offset = 0;
00169     size_t buffer_size;
00170 #ifdef XP_MAC
00171     size_t i;
00172 #endif
00173 
00174 #if defined(XP_MAC) && defined(XPIDL_PLUGIN)
00175     /* on Mac, fopen knows how to find files. */
00176     inputfile = fopen(filename, "r");
00177 #elif defined(XP_OS2) || defined(XP_WIN32)
00178     /*
00179      * if filename is fully qualified (starts with driver letter), then
00180      * just call fopen();  else, go with fopen_from_includes()
00181      */
00182     if( filename[1] == ':' )
00183       inputfile = fopen(filename, "r");
00184     else
00185       inputfile = fopen_from_includes(filename, "r", include_path);
00186 #else
00187     inputfile = fopen_from_includes(filename, "r", include_path);
00188 #endif
00189 
00190     if (!inputfile)
00191         return NULL;
00192 
00193 #ifdef XP_MAC
00194     {
00195         struct stat input_stat;
00196         if (fstat(fileno(inputfile), &input_stat))
00197             return NULL;
00198         buffer = malloc(input_stat.st_size + 1);
00199         if (!buffer)
00200             return NULL;
00201         offset = fread(buffer, 1, input_stat.st_size, inputfile);
00202         if (ferror(inputfile))
00203             return NULL;
00204     }
00205 #else
00206     /*
00207      * Rather than try to keep track of many different varieties of state
00208      * around the boundaries of a circular buffer, we just read in the entire
00209      * file.
00210      *
00211      * We iteratively grow the buffer here; an alternative would be to use
00212      * stat to find the exact buffer size we need, as xpt_dump does.
00213      */
00214     for (buffer_size = 8191; ; buffer_size *= 2) {
00215         size_t just_read;
00216         buffer = realloc(buffer, buffer_size + 1); /* +1 for trailing nul */
00217         just_read = fread(buffer + offset, 1, buffer_size - offset, inputfile);
00218         if (ferror(inputfile))
00219             return NULL;
00220 
00221         if (just_read < buffer_size - offset || just_read == 0) {
00222             /* Done reading. */
00223             offset += just_read;
00224             break;
00225         }
00226         offset += just_read;
00227     }
00228 #endif
00229 
00230     fclose(inputfile);
00231 
00232 #ifdef XP_MAC
00233     /*
00234      * libIDL doesn't speak '\r' properly - always make sure lines end with
00235      * '\n'.
00236      */
00237     for (i = 0; i < offset; i++) {
00238         if (buffer[i] == '\r')
00239             buffer[i] = '\n';
00240     }
00241 #endif
00242 
00243     new_data = xpidl_malloc(sizeof (struct input_data));
00244     new_data->point = new_data->buf = buffer;
00245     new_data->max = buffer + offset;
00246     *new_data->max = '\0';
00247     new_data->filename = xpidl_strdup(filename);
00248     /* libIDL expects the line number to be that of the *next* line */
00249     new_data->lineno = 2;
00250     new_data->next = NULL;
00251 
00252     return new_data;
00253 }
00254 
00255 /* process pending raw section */
00256 static int
00257 NextIsRaw(input_data *data, char **startp, int *lenp)
00258 {
00259     char *end, *start;
00260 
00261     /*
00262      * XXXmccabe still needed: an in_raw flag to handle the case where we're in
00263      * a raw block, but haven't managed to copy it all to xpidl.  This will
00264      * happen when we have a raw block larger than
00265      * IDL_input_data->fill.max_size (currently 8192.)
00266      */
00267     if (!(data->point[0] == '%' && data->point[1] == '{'))
00268         return 0;
00269         
00270     start = *startp = data->point;
00271     
00272     end = NULL;
00273     while (start < data->max && (end = strstr(start, "%}"))) {
00274         if (end[-1] == '\r' ||
00275             end[-1] == '\n')
00276             break;
00277         start = end + 1;
00278     }
00279 
00280     if (end && start < data->max) {
00281         *lenp = end - data->point + 2;
00282         return 1;
00283     } else {
00284         const char *filename;
00285         int lineno;
00286 
00287         IDL_file_get(&filename, &lineno);
00288         msg_callback(IDL_ERROR, 0, lineno, filename,
00289                      "unterminated %{ block");
00290         return -1;
00291     }
00292 }
00293 
00294 /* process pending comment */
00295 static int
00296 NextIsComment(input_data *data, char **startp, int *lenp)
00297 {
00298     char *end;
00299 
00300     if (!(data->point[0] == '/' && data->point[1] == '*'))
00301         return 0;
00302 
00303     end = strstr(data->point, "*/");
00304     *lenp = 0;
00305     if (end) {
00306         int skippedLines = 0;
00307         char *tempPoint;
00308         
00309         /* get current lineno */
00310         IDL_file_get(NULL,(int *)&data->lineno);
00311 
00312         /* get line count */
00313         for (tempPoint = data->point; tempPoint < end; tempPoint++) {
00314             if (*tempPoint == '\n')
00315                 skippedLines++;
00316         }
00317 
00318         data->lineno += skippedLines;
00319         IDL_file_set(data->filename, (int)data->lineno);
00320         
00321         *startp = end + 2;
00322 
00323         /* If it's a ** comment, tell libIDL about it. */
00324         if (data->point[2] == '*') {
00325             /* hack termination.  +2 to get past '*' '/' */
00326             char t = *(end + 2);
00327             *(end + 2) = '\0';
00328             IDL_queue_new_ident_comment(data->point);
00329             *(end + 2) = t;
00330         }
00331 
00332         data->point = *startp; /* XXXmccabe move this out of function? */
00333         return 1;
00334     } else {
00335         const char *filename;
00336         int lineno;
00337 
00338         IDL_file_get(&filename, &lineno);
00339         msg_callback(IDL_ERROR, 0, lineno, filename,
00340                      "unterminated comment");
00341         return -1;
00342     }
00343 }
00344 
00345 static int
00346 NextIsInclude(input_callback_state *callback_state, char **startp,
00347               int *lenp)
00348 {
00349     input_data *data = callback_state->input_stack;
00350     input_data *new_data;
00351     char *filename, *end;
00352     const char *scratch;
00353 
00354     /* process the #include that we're in now */
00355     if (strncmp(data->point, "#include \"", 10)) {
00356         return 0;
00357     }
00358     
00359     filename = data->point + 10; /* skip #include " */
00360     XPT_ASSERT(filename < data->max);
00361     end = filename;
00362     while (end < data->max) {
00363         if (*end == '\"' || *end == '\n' || *end == '\r')
00364             break;
00365         end++;
00366     }
00367 
00368     if (*end != '\"') {
00369         /*
00370          * Didn't find end of include file.  Scan 'til next whitespace to find
00371          * some reasonable approximation of the filename, and use it to report
00372          * an error.
00373          */
00374 
00375         end = filename;
00376         while (end < data->max) {
00377             if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t')
00378                 break;
00379             end++;
00380         }
00381         *end = '\0';
00382         
00383         /* make sure we have accurate line info */
00384         IDL_file_get(&scratch, (int *)&data->lineno);
00385         fprintf(stderr,
00386                 "%s:%d: didn't find end of quoted include name \"%s\n",
00387                 scratch, data->lineno, filename);
00388         return -1;
00389     }
00390 
00391     *end = '\0';
00392     *startp = end + 1;
00393 
00394     if (data->next == NULL) {
00395         /*
00396          * If we're in the initial file, add this filename to the list
00397          * of filenames to be turned into #include "filename.h"
00398          * directives in xpidl_header.c.  We do it here rather than in the
00399          * block below so it still gets added to the list even if it's
00400          * already been recursively included from some other file.
00401          */
00402         char *filename_cp = xpidl_strdup(filename);
00403         
00404         /* note that g_slist_append accepts and likes null as list-start. */
00405         callback_state->base_includes =
00406             g_slist_append(callback_state->base_includes, filename_cp);
00407     }
00408 
00409     /* store offset for when we pop, or if we skip this one */
00410     data->point = *startp;
00411 
00412     if (!g_hash_table_lookup(callback_state->already_included, filename)) {
00413         filename = xpidl_strdup(filename);
00414         g_hash_table_insert(callback_state->already_included,
00415                             filename, (void *)TRUE);
00416         new_data = new_input_data(filename, callback_state->include_path);
00417         if (!new_data) {
00418             char *error_message;
00419             IDL_file_get(&scratch, (int *)&data->lineno);
00420             error_message =
00421                 g_strdup_printf("can't open included file %s for reading\n",
00422                                 filename);
00423             msg_callback(IDL_ERROR, 0,
00424                          data->lineno, scratch, error_message);
00425             g_free(error_message);
00426             return -1;
00427         }
00428 
00429         new_data->next = data;
00430         /* tell libIDL to exclude this IDL from the toplevel tree */
00431         IDL_inhibit_push();
00432         IDL_file_get(&scratch, (int *)&data->lineno);
00433         callback_state->input_stack = new_data;
00434         IDL_file_set(new_data->filename, (int)new_data->lineno);
00435     }
00436 
00437     *lenp = 0;               /* this is magic, see the comment below */
00438     return 1;
00439 }    
00440 
00441 static void
00442 FindSpecial(input_data *data, char **startp, int *lenp)
00443 {
00444     char *point = data->point;
00445 
00446     /* magic sequences are:
00447      * "%{"               raw block
00448      * "/\*"              comment
00449      * "#include \""      include
00450      * The first and last want a newline [\r\n] before, or the start of the
00451      * file.
00452      */
00453 
00454 #define LINE_START(data, point) (point == data->buf ||                       \
00455                                  (point > data->point &&                     \
00456                                   (point[-1] == '\r' || point[-1] == '\n')))
00457                                                  
00458     while (point < data->max) {
00459         if (point[0] == '/' && point[1] == '*')
00460             break;
00461         if (LINE_START(data, point)) {
00462             if (point[0] == '%' && point[1] == '{')
00463                 break;
00464             if (point[0] == '#' && !strncmp(point + 1, "include \"", 9))
00465                 break;
00466         }
00467         point++;
00468     }
00469 
00470 #undef LINE_START
00471 
00472     *startp = data->point;
00473     *lenp = point - data->point;
00474 }
00475 
00476 /* set this with a debugger to see exactly what libIDL sees */
00477 static FILE *tracefile;
00478 
00479 static int
00480 input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
00481                gpointer user_data)
00482 {
00483     input_callback_state *callback_state = user_data;
00484     input_data *data = callback_state->input_stack;
00485     input_data *new_data = NULL;
00486     unsigned int len, copy;
00487     int rv;
00488     char *start;
00489 
00490     switch(reason) {
00491       case IDL_INPUT_REASON_INIT:
00492         if (data == NULL || data->next == NULL) {
00493             /*
00494              * This is the first file being processed.  As it's the target
00495              * file, we only look for it in the first entry in the include
00496              * path, which we assume to be the current directory.
00497              */
00498 
00499             /* XXXmccabe proper assumption?  Do we handle files in other
00500                directories? */
00501 
00502             IncludePathEntry first_entry;
00503 
00504             first_entry.directory = callback_state->include_path->directory;
00505             first_entry.next = NULL;
00506 
00507             new_data = new_input_data(cb_data->init.filename,
00508                                                &first_entry);
00509         } else {
00510             new_data = new_input_data(cb_data->init.filename,
00511                                                callback_state->include_path);
00512         }
00513 
00514         if (!new_data)
00515             return -1;
00516 
00517         IDL_file_set(new_data->filename, (int)new_data->lineno);
00518         callback_state->input_stack = new_data;
00519         return 0;
00520 
00521       case IDL_INPUT_REASON_FILL:
00522         start = NULL;
00523         len = 0;
00524 
00525         while (data->point >= data->max) {
00526             if (!data->next)
00527                 return 0;
00528 
00529             /* Current file is done; revert to including file */
00530             callback_state->input_stack = data->next;
00531             free(data->filename);
00532             free(data->buf);
00533             free(data);
00534             data = callback_state->input_stack;
00535 
00536             IDL_file_set(data->filename, (int)data->lineno);
00537             IDL_inhibit_pop();
00538         }
00539         
00540         /*
00541          * Now we scan for sequences which require special attention:
00542          *   \n#include                   begins an include statement
00543          *   \n%{                         begins a raw-source block
00544          *   /\*                          begins a comment
00545          * 
00546          * We used to be fancier here, so make sure that we sent the most
00547          * data possible at any given time.  To that end, we skipped over
00548          * \n%{ raw \n%} blocks and then _continued_ the search for special
00549          * sequences like \n#include or /\* comments .
00550          * 
00551          * It was really ugly, though -- liberal use of goto!  lots of implicit
00552          * state!  what fun! -- so now we just do this:
00553          *
00554          * if (special at start) {
00555          *     process that special -
00556          *         - raw: send it to libIDL, and don't look inside for specials
00557          *         - comments: adjust point and start over
00558          *         - includes: push new input_data struct for included file, and
00559          *           start over
00560          * } else {
00561          *     scan for next special
00562          *     send data up to that special to libIDL
00563          * }
00564          *
00565          * If len is set to zero, it is a sentinel value indicating we a comment
00566          * or include was found, and parsing should start over.
00567          *
00568          * XXX const string foo = "/\*" will just screw us horribly.
00569          * Hm but.  We could treat strings as we treat raw blocks, eh?
00570          */
00571 
00572         /*
00573          * Order is important, so that you can have /\* comments and
00574          * #includes within raw sections, and so that you can comment out
00575          * #includes.
00576          */
00577         rv = NextIsRaw(data, &start, (int *)&len);
00578         if (rv == -1) return -1;
00579         if (!rv) {
00580             /*
00581              * When NextIsComment succeeds, it returns a 0 len (requesting a
00582              * restart) and adjusts data->point to pick up after the comment.
00583              */
00584             rv = NextIsComment(data, &start, (int *)&len);
00585             if (rv == -1) return -1;
00586             if (!rv) {
00587                 /*
00588                  * NextIsInclude might push a new input_data struct; if so, it
00589                  * will return a 0 len, letting the callback pick up the new
00590                  * file the next time around.
00591                  */
00592                 rv = NextIsInclude(callback_state, &start, (int *)&len);
00593                 if (rv == -1) return -1;
00594                 if (!rv)
00595                     FindSpecial(data, &start, (int *)&len);
00596             }
00597         }
00598 
00599         if (len == 0) {
00600             /*
00601              * len == 0 is a sentinel value that means we found a comment or
00602              * include.  If we found a comment, point has been adjusted to
00603              * point past the comment.  If we found an include, a new input_data
00604              * has been pushed.  In both cases, calling the input_callback again
00605              * will pick up the new state.
00606              */
00607             return input_callback(reason, cb_data, user_data);
00608         }
00609 
00610         copy = MIN(len, (unsigned int) cb_data->fill.max_size);
00611         memcpy(cb_data->fill.buffer, start, copy);
00612         data->point = start + copy;
00613 
00614         if (tracefile)
00615             fwrite(cb_data->fill.buffer, copy, 1, tracefile);
00616 
00617         return copy;
00618 
00619       case IDL_INPUT_REASON_ABORT:
00620       case IDL_INPUT_REASON_FINISH:
00621         while (data != NULL) {
00622             input_data *next;
00623 
00624             next = data->next;
00625             free(data->filename);
00626             free(data->buf);
00627             free(data);
00628             data = next;
00629         }
00630         return 0;
00631 
00632       default:
00633         g_error("unknown input reason %d!", reason);
00634         return -1;
00635     }
00636 }
00637 
00638 static void
00639 free_ghash_key(gpointer key, gpointer value, gpointer user_data)
00640 {
00641     /* We're only storing TRUE in the value... */
00642     free(key);
00643 }
00644 
00645 static void
00646 free_gslist_data(gpointer data, gpointer user_data)
00647 {
00648     free(data);
00649 }
00650 
00651 /* Pick up unlink. */
00652 #ifdef XP_UNIX
00653 #include <unistd.h>
00654 #elif XP_WIN
00655 /* We get it from stdio.h. */
00656 #define unlink _unlink
00657 #endif
00658 
00659 int
00660 xpidl_process_idl(char *filename, IncludePathEntry *include_path,
00661                   char *file_basename, ModeData *mode)
00662 {
00663     char *tmp, *outname, *real_outname = NULL;
00664     IDL_tree top;
00665     TreeState state;
00666     int rv;
00667     input_callback_state callback_state;
00668     gboolean ok = TRUE;
00669     backend *emitter;
00670 
00671     callback_state.input_stack = NULL;
00672     callback_state.base_includes = NULL;
00673     callback_state.include_path = include_path;
00674     callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal);
00675 
00676     if (!callback_state.already_included) {
00677         fprintf(stderr, "failed to create hashtable.  out of memory?\n");
00678         return 0;
00679     }
00680 
00681     state.basename = xpidl_strdup(filename);
00682 
00683     /* if basename has an .extension, truncate it. */
00684     tmp = strrchr(state.basename, '.');
00685     if (tmp)
00686         *tmp = '\0';
00687 
00688     if (!file_basename)
00689         outname = xpidl_strdup(state.basename);
00690     else
00691         outname = xpidl_strdup(file_basename);
00692 
00693     /* so we don't include it again! */
00694     g_hash_table_insert(callback_state.already_included,
00695                         xpidl_strdup(filename), (void *)TRUE);
00696 
00697     parsed_empty_file = FALSE;
00698 
00699     rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
00700                                        msg_callback, &top,
00701                                        &state.ns,
00702                                        IDLF_IGNORE_FORWARDS |
00703                                        IDLF_XPIDL,
00704                                        enable_warnings ? IDL_WARNING1 :
00705                                        IDL_ERROR);
00706     if (parsed_empty_file) {
00707         /*
00708          * If we've detected (via hack in msg_callback) that libIDL returned
00709          * failure because it found a file with no IDL, set the parse tree to
00710          * null and proceed.  Allowing this is useful to permit .idl files that
00711          * collect #includes.
00712          */
00713         top = NULL;
00714         state.ns = NULL;
00715     } else if (rv != IDL_SUCCESS) {
00716         if (rv == -1) {
00717             g_warning("Parse of %s failed: %s", filename, g_strerror(errno));
00718         } else {
00719             g_warning("Parse of %s failed", filename);
00720         }
00721         return 0;
00722     }
00723 
00724     state.basename = xpidl_strdup(filename);
00725     tmp = strrchr(state.basename, '.');
00726     if (tmp)
00727         *tmp = '\0';
00728 
00729     /* so xpidl_header.c can use it to generate a list of #include directives */
00730     state.base_includes = callback_state.base_includes;
00731 
00732     emitter = mode->factory();
00733     state.dispatch = emitter->dispatch_table;
00734 
00735     if (strcmp(outname, "-")) {
00736         const char *fopen_mode;
00737         const char *out_basename;
00738 
00739         /* explicit_output_filename can't be true without a filename */
00740         if (explicit_output_filename) {
00741             real_outname = g_strdup(outname);
00742         } else {
00743 /* 
00744  *This combination seems a little strange, what about OS/2?
00745  * Assume it's some build issue
00746  */
00747 #if defined(XP_UNIX) || defined(XP_WIN)
00748             if (!file_basename) {
00749                 out_basename = xpidl_basename(outname);
00750             } else {
00751                 out_basename = outname;
00752             }
00753 #else
00754             out_basename = outname;
00755 #endif
00756             real_outname = g_strdup_printf("%s.%s", out_basename, mode->suffix);
00757         }
00758 
00759         /* don't create/open file here for Java */
00760         if (strcmp(mode->mode, "java") == 0) {
00761             state.filename = real_outname;
00762         } else {
00763             /* Use binary write for typelib mode */
00764             fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb";
00765             state.file = fopen(real_outname, fopen_mode);
00766             if (!state.file) {
00767                 perror("error opening output file");
00768                 return 0;
00769             }
00770         }
00771     } else {
00772         state.file = stdout;
00773     }
00774     state.tree = top;
00775 
00776     if (emitter->emit_prolog)
00777         emitter->emit_prolog(&state);
00778     if (state.tree) /* Only if we have a tree to process. */
00779         ok = xpidl_process_node(&state);
00780     if (emitter->emit_epilog)
00781         emitter->emit_epilog(&state);
00782 
00783     if (strcmp(mode->mode, "java") != 0) {
00784         if (state.file != stdout)
00785             fclose(state.file);
00786     }
00787 
00788     free(state.basename);
00789     free(outname);
00790     g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL);
00791     g_hash_table_destroy(callback_state.already_included);
00792     g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL);
00793 
00794     if (state.ns)
00795         IDL_ns_free(state.ns);
00796     if (top)
00797         IDL_tree_free(top);
00798 
00799     if (strcmp(mode->mode, "java") != 0) {
00800         if (real_outname != NULL) {
00801             /*
00802              * Delete partial output file on failure.  (Mac does this in the
00803              * plugin driver code, if the compiler returns failure.)
00804              */
00805 #if defined(XP_UNIX) || defined(XP_WIN)
00806             if (!ok)
00807                 unlink(real_outname);
00808 #endif
00809             g_free(real_outname);
00810         }
00811     }
00812 
00813     return ok;
00814 }
00815 
00816 /*
00817  * Our own version of IDL_tree_warning, which we use when IDL_tree_warning
00818  * would crash on us.
00819  */
00820 void
00821 xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...)
00822 {
00823     va_list ap;
00824     char *msg, *file;
00825     int lineno;
00826 
00827     /* XXX need to check against __IDL_max_msg_level, no accessor */
00828     va_start(ap, fmt);
00829     msg = g_strdup_vprintf(fmt, ap);
00830 
00831     if (p) {
00832         file = p->_file;
00833         lineno = p->_line;
00834     } else {
00835         file = NULL;
00836         lineno = 0;
00837     }
00838 
00839     /* call our message callback, like IDL_tree_warning would */
00840     msg_callback(level, 0, lineno, file, msg);
00841     g_free(msg);
00842     va_end(ap);
00843 }