root/lang/pascal/xpidlpas/xpidlpas_idl.c

Revision 4249, 32.1 kB (checked in by plus7, 12 months ago)

initial import

  • Property svn:executable set to *
Line 
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *       Michael Ang <mang@subcarrier.org>
24 *   Itou Takanori <necottie@nesitive.net>
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the NPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the NPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40/*
41 * Common IDL-processing code.
42 */
43
44#include "xpidlpas.h"
45
46#ifdef XP_MAC
47#include <stat.h>
48#endif
49
50static gboolean parsed_empty_file;
51
52/*
53 * The bulk of the generation happens here.
54 */
55gboolean
56xpidl_process_node(TreeState *state)
57{
58    gint type;
59    nodeHandler *dispatch, handler;
60
61    XPT_ASSERT(state->tree);
62    type = IDL_NODE_TYPE(state->tree);
63
64    if ((dispatch = state->dispatch) && (handler = dispatch[type]))
65        return handler(state);
66    return TRUE;
67}
68
69#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
70extern void mac_warning(const char* warning_message);
71#endif
72
73static int
74msg_callback(int level, int num, int line, const char *file,
75             const char *message)
76{
77    char *warning_message;
78
79    /*
80     * Egregious hack to permit empty files.
81     * XXX libIDL needs an API to detect this case robustly.
82     */
83    if (0 == strcmp(message, "File empty after optimization")) {
84        parsed_empty_file = TRUE;
85        return 1;
86    }
87
88    if (!file)
89        file = "<unknown file>";
90    warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message);
91
92#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
93    mac_warning(warning_message);
94#else
95    fputs(warning_message, stderr);
96#endif
97
98    g_free(warning_message);
99    return 1;
100}
101
102/*
103 * To keep track of the state associated with a given input file.  The 'next'
104 * field lets us maintain a stack of input files.
105 */
106typedef struct input_data {
107    char *filename;             /* where did I come from? */
108    unsigned int lineno;        /* last lineno processed */
109    char *buf;                  /* contents of file */
110    char *point;                /* next char to feed to libIDL */
111    char *max;                  /* 1 past last char in buf */
112    struct input_data *next;    /* file from which we were included */
113} input_data;
114
115/*
116 * Passed to us by libIDL.  Holds global information and the current stack of
117 * include files.
118 */
119typedef struct input_callback_state {
120    struct input_data *input_stack; /* linked list of input_data */   
121    GHashTable *already_included;   /* to prevent redundant includes */
122    IncludePathEntry *include_path; /* search path for included files */
123    GSList *base_includes;          /* to accumulate #includes from *first* file;
124                                     * for passing thru TreeState to
125                                     * xpidl_header backend. */
126} input_callback_state;
127
128static FILE *
129fopen_from_includes(const char *filename, const char *mode,
130                    IncludePathEntry *include_path)
131{
132    IncludePathEntry *current_path = include_path;
133    char *pathname;
134    FILE *inputfile;
135    if (!strcmp(filename, "-"))
136        return stdin;
137
138    if (filename[0] != '/') {
139        while (current_path) {
140            pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
141                                       current_path->directory, filename);
142            if (!pathname)
143                return NULL;
144            inputfile = fopen(pathname, mode);
145            g_free(pathname);
146            if (inputfile)
147                return inputfile;
148            current_path = current_path->next;
149        }
150    } else {
151        inputfile = fopen(filename, mode);
152        if (inputfile)
153            return inputfile;
154    }
155    return NULL;
156}
157
158#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
159extern FILE* mac_fopen(const char* filename, const char *mode);
160#endif
161
162static input_data *
163new_input_data(const char *filename, IncludePathEntry *include_path)
164{
165    input_data *new_data;
166    FILE *inputfile;
167    char *buffer = NULL;
168    size_t offset = 0;
169    size_t buffer_size;
170#ifdef XP_MAC
171    size_t i;
172#endif
173
174#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
175    /* on Mac, fopen knows how to find files. */
176    inputfile = fopen(filename, "r");
177#elif defined(XP_OS2) || defined(XP_WIN32)
178    /*
179     * if filename is fully qualified (starts with driver letter), then
180     * just call fopen();  else, go with fopen_from_includes()
181     */
182    if( filename[1] == ':' )
183      inputfile = fopen(filename, "r");
184    else
185      inputfile = fopen_from_includes(filename, "r", include_path);
186#else
187    inputfile = fopen_from_includes(filename, "r", include_path);
188#endif
189
190    if (!inputfile)
191        return NULL;
192
193#ifdef XP_MAC
194    {
195        struct stat input_stat;
196        if (fstat(fileno(inputfile), &input_stat))
197            return NULL;
198        buffer = malloc(input_stat.st_size + 1);
199        if (!buffer)
200            return NULL;
201        offset = fread(buffer, 1, input_stat.st_size, inputfile);
202        if (ferror(inputfile))
203            return NULL;
204    }
205#else
206    /*
207     * Rather than try to keep track of many different varieties of state
208     * around the boundaries of a circular buffer, we just read in the entire
209     * file.
210     *
211     * We iteratively grow the buffer here; an alternative would be to use
212     * stat to find the exact buffer size we need, as xpt_dump does.
213     */
214    for (buffer_size = 8191; ; buffer_size *= 2) {
215        size_t just_read;
216        buffer = realloc(buffer, buffer_size + 1); /* +1 for trailing nul */
217        just_read = fread(buffer + offset, 1, buffer_size - offset, inputfile);
218        if (ferror(inputfile))
219            return NULL;
220
221        if (just_read < buffer_size - offset || just_read == 0) {
222            /* Done reading. */
223            offset += just_read;
224            break;
225        }
226        offset += just_read;
227    }
228#endif
229
230    fclose(inputfile);
231
232#ifdef XP_MAC
233    /*
234     * libIDL doesn't speak '\r' properly - always make sure lines end with
235     * '\n'.
236     */
237    for (i = 0; i < offset; i++) {
238        if (buffer[i] == '\r')
239            buffer[i] = '\n';
240    }
241#endif
242
243    new_data = xpidl_malloc(sizeof (struct input_data));
244    new_data->point = new_data->buf = buffer;
245    new_data->max = buffer + offset;
246    *new_data->max = '\0';
247    new_data->filename = xpidl_strdup(filename);
248    /* libIDL expects the line number to be that of the *next* line */
249    new_data->lineno = 2;
250    new_data->next = NULL;
251
252    return new_data;
253}
254
255/* process pending raw section */
256static int
257NextIsRaw(input_data *data, char **startp, int *lenp)
258{
259    char *end, *start;
260
261    /*
262     * XXXmccabe still needed: an in_raw flag to handle the case where we're in
263     * a raw block, but haven't managed to copy it all to xpidl.  This will
264     * happen when we have a raw block larger than
265     * IDL_input_data->fill.max_size (currently 8192.)
266     */
267    if (!(data->point[0] == '%' && data->point[1] == '{'))
268        return 0;
269       
270    start = *startp = data->point;
271   
272    end = NULL;
273    while (start < data->max && (end = strstr(start, "%}"))) {
274        if (end[-1] == '\r' ||
275            end[-1] == '\n')
276            break;
277        start = end + 1;
278    }
279
280    if (end && start < data->max) {
281        *lenp = end - data->point + 2;
282        return 1;
283    } else {
284        const char *filename;
285        int lineno;
286
287        IDL_file_get(&filename, &lineno);
288        msg_callback(IDL_ERROR, 0, lineno, filename,
289                     "unterminated %{ block");
290        return -1;
291    }
292}
293
294/* process pending comment */
295static int
296NextIsComment(input_data *data, char **startp, int *lenp)
297{
298    char *end;
299
300    if (!(data->point[0] == '/' && data->point[1] == '*'))
301        return 0;
302
303    end = strstr(data->point, "*/");
304    *lenp = 0;
305    if (end) {
306        int skippedLines = 0;
307        char *tempPoint;
308       
309        /* get current lineno */
310        IDL_file_get(NULL,(int *)&data->lineno);
311
312        /* get line count */
313        for (tempPoint = data->point; tempPoint < end; tempPoint++) {
314            if (*tempPoint == '\n')
315                skippedLines++;
316        }
317
318        data->lineno += skippedLines;
319        IDL_file_set(data->filename, (int)data->lineno);
320       
321        *startp = end + 2;
322
323        /* If it's a ** comment, tell libIDL about it. */
324        if (data->point[2] == '*') {
325            /* hack termination.  +2 to get past '*' '/' */
326            char t = *(end + 2);
327            *(end + 2) = '\0';
328            IDL_queue_new_ident_comment(data->point);
329            *(end + 2) = t;
330        }
331
332        data->point = *startp; /* XXXmccabe move this out of function? */
333        return 1;
334    } else {
335        const char *filename;
336        int lineno;
337
338        IDL_file_get(&filename, &lineno);
339        msg_callback(IDL_ERROR, 0, lineno, filename,
340                     "unterminated comment");
341        return -1;
342    }
343}
344
345static int
346NextIsInclude(input_callback_state *callback_state, char **startp,
347              int *lenp)
348{
349    input_data *data = callback_state->input_stack;
350    input_data *new_data;
351    char *filename, *end;
352    const char *scratch;
353
354    /* process the #include that we're in now */
355    if (strncmp(data->point, "#include \"", 10)) {
356        return 0;
357    }
358   
359    filename = data->point + 10; /* skip #include " */
360    XPT_ASSERT(filename < data->max);
361    end = filename;
362    while (end < data->max) {
363        if (*end == '\"' || *end == '\n' || *end == '\r')
364            break;
365        end++;
366    }
367
368    if (*end != '\"') {
369        /*
370         * Didn't find end of include file.  Scan 'til next whitespace to find
371         * some reasonable approximation of the filename, and use it to report
372         * an error.
373         */
374
375        end = filename;
376        while (end < data->max) {
377            if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t')
378                break;
379            end++;
380        }
381        *end = '\0';
382       
383        /* make sure we have accurate line info */
384        IDL_file_get(&scratch, (int *)&data->lineno);
385        fprintf(stderr,
386                "%s:%d: didn't find end of quoted include name \"%s\n",
387                scratch, data->lineno, filename);
388        return -1;
389    }
390
391    *end = '\0';
392    *startp = end + 1;
393
394    if (data->next == NULL) {
395        /*
396         * If we're in the initial file, add this filename to the list
397         * of filenames to be turned into #include "filename.h"
398         * directives in xpidl_header.c.  We do it here rather than in the
399         * block below so it still gets added to the list even if it's
400         * already been recursively included from some other file.
401         */
402        char *filename_cp = xpidl_strdup(filename);
403       
404        /* note that g_slist_append accepts and likes null as list-start. */
405        callback_state->base_includes =
406            g_slist_append(callback_state->base_includes, filename_cp);
407    }
408
409    /* store offset for when we pop, or if we skip this one */
410    data->point = *startp;
411
412    if (!g_hash_table_lookup(callback_state->already_included, filename)) {
413        filename = xpidl_strdup(filename);
414        g_hash_table_insert(callback_state->already_included,
415                            filename, (void *)TRUE);
416        new_data = new_input_data(filename, callback_state->include_path);
417        if (!new_data) {
418            char *error_message;
419            IDL_file_get(&scratch, (int *)&data->lineno);
420            error_message =
421                g_strdup_printf("can't open included file %s for reading\n",
422                                filename);
423            msg_callback(IDL_ERROR, 0,
424                         data->lineno, scratch, error_message);
425            g_free(error_message);
426            return -1;
427        }
428
429        new_data->next = data;
430        /* tell libIDL to exclude this IDL from the toplevel tree */
431        IDL_inhibit_push();
432        IDL_file_get(&scratch, (int *)&data->lineno);
433        callback_state->input_stack = new_data;
434        IDL_file_set(new_data->filename, (int)new_data->lineno);
435    }
436
437    *lenp = 0;               /* this is magic, see the comment below */
438    return 1;
439}   
440
441static void
442FindSpecial(input_data *data, char **startp, int *lenp)
443{
444    char *point = data->point;
445
446    /* magic sequences are:
447     * "%{"               raw block
448     * "/\*"              comment
449     * "#include \""      include
450     * The first and last want a newline [\r\n] before, or the start of the
451     * file.
452     */
453
454#define LINE_START(data, point) (point == data->buf ||                       \
455                                 (point > data->point &&                     \
456                                  (point[-1] == '\r' || point[-1] == '\n')))
457                                                 
458    while (point < data->max) {
459        if (point[0] == '/' && point[1] == '*')
460            break;
461        if (LINE_START(data, point)) {
462            if (point[0] == '%' && point[1] == '{')
463                break;
464            if (point[0] == '#' && !strncmp(point + 1, "include \"", 9))
465                break;
466        }
467        point++;
468    }
469
470#undef LINE_START
471
472    *startp = data->point;
473    *lenp = point - data->point;
474}
475
476/* set this with a debugger to see exactly what libIDL sees */
477static FILE *tracefile;
478
479static int
480input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
481               gpointer user_data)
482{
483    input_callback_state *callback_state = user_data;
484    input_data *data = callback_state->input_stack;
485    input_data *new_data = NULL;
486    unsigned int len, copy;
487    int rv;
488    char *start;
489
490    switch(reason) {
491      case IDL_INPUT_REASON_INIT:
492        if (data == NULL || data->next == NULL) {
493            /*
494             * This is the first file being processed.  As it's the target
495             * file, we only look for it in the first entry in the include
496             * path, which we assume to be the current directory.
497             */
498
499            /* XXXmccabe proper assumption?  Do we handle files in other
500               directories? */
501
502            IncludePathEntry first_entry;
503
504            first_entry.directory = callback_state->include_path->directory;
505            first_entry.next = NULL;
506
507            new_data = new_input_data(cb_data->init.filename,
508                                               &first_entry);
509        } else {
510            new_data = new_input_data(cb_data->init.filename,
511                                               callback_state->include_path);
512        }
513
514        if (!new_data)
515            return -1;
516
517        IDL_file_set(new_data->filename, (int)new_data->lineno);
518        callback_state->input_stack = new_data;
519        return 0;
520
521      case IDL_INPUT_REASON_FILL:
522        start = NULL;
523        len = 0;
524
525        while (data->point >= data->max) {
526            if (!data->next)
527                return 0;
528
529            /* Current file is done; revert to including file */
530            callback_state->input_stack = data->next;
531            free(data->filename);
532            free(data->buf);
533            free(data);
534            data = callback_state->input_stack;
535
536            IDL_file_set(data->filename, (int)data->lineno);
537            IDL_inhibit_pop();
538        }
539       
540        /*
541         * Now we scan for sequences which require special attention:
542         *   \n#include                   begins an include statement
543         *   \n%{                         begins a raw-source block
544         *   /\*                          begins a comment
545         *
546         * We used to be fancier here, so make sure that we sent the most
547         * data possible at any given time.  To that end, we skipped over
548         * \n%{ raw \n%} blocks and then _continued_ the search for special
549         * sequences like \n#include or /\* comments .
550         *
551         * It was really ugly, though -- liberal use of goto!  lots of implicit
552         * state!  what fun! -- so now we just do this:
553         *
554         * if (special at start) {
555         *     process that special -
556         *         - raw: send it to libIDL, and don't look inside for specials
557         *         - comments: adjust point and start over
558         *         - includes: push new input_data struct for included file, and
559         *           start over
560         * } else {
561         *     scan for next special
562         *     send data up to that special to libIDL
563         * }
564         *
565         * If len is set to zero, it is a sentinel value indicating we a comment
566         * or include was found, and parsing should start over.
567         *
568         * XXX const string foo = "/\*" will just screw us horribly.
569         * Hm but.  We could treat strings as we treat raw blocks, eh?
570         */
571
572        /*
573         * Order is important, so that you can have /\* comments and
574         * #includes within raw sections, and so that you can comment out
575         * #includes.
576         */
577        rv = NextIsRaw(data, &start, (int *)&len);
578        if (rv == -1) return -1;
579        if (!rv) {
580            /*
581             * When NextIsComment succeeds, it returns a 0 len (requesting a
582             * restart) and adjusts data->point to pick up after the comment.
583             */
584            rv = NextIsComment(data, &start, (int *)&len);
585            if (rv == -1) return -1;
586            if (!rv) {
587                /*
588                 * NextIsInclude might push a new input_data struct; if so, it
589                 * will return a 0 len, letting the callback pick up the new
590                 * file the next time around.
591                 */
592                rv = NextIsInclude(callback_state, &start, (int *)&len);
593                if (rv == -1) return -1;
594                if (!rv)
595                    FindSpecial(data, &start, (int *)&len);
596            }
597        }
598
599        if (len == 0) {
600            /*
601             * len == 0 is a sentinel value that means we found a comment or
602             * include.  If we found a comment, point has been adjusted to
603             * point past the comment.  If we found an include, a new input_data
604             * has been pushed.  In both cases, calling the input_callback again
605             * will pick up the new state.
606             */
607            return input_callback(reason, cb_data, user_data);
608        }
609
610        copy = MIN(len, (unsigned int) cb_data->fill.max_size);
611        memcpy(cb_data->fill.buffer, start, copy);
612        data->point = start + copy;
613
614        if (tracefile)
615            fwrite(cb_data->fill.buffer, copy, 1, tracefile);
616
617        return copy;
618
619      case IDL_INPUT_REASON_ABORT:
620      case IDL_INPUT_REASON_FINISH:
621        while (data != NULL) {
622            input_data *next;
623
624            next = data->next;
625            free(data->filename);
626            free(data->buf);
627            free(data);
628            data = next;
629        }
630        return 0;
631
632      default:
633        g_error("unknown input reason %d!", reason);
634        return -1;
635    }
636}
637
638static void
639free_ghash_key(gpointer key, gpointer value, gpointer user_data)
640{
641    /* We're only storing TRUE in the value... */
642    free(key);
643}
644
645static void
646free_gslist_data(gpointer data, gpointer user_data)
647{
648    free(data);
649}
650
651/* Pick up unlink. */
652#ifdef XP_UNIX
653#include <unistd.h>
654#elif XP_WIN
655/* We get it from stdio.h. */
656#endif
657
658int
659xpidl_process_idl(char *filename, IncludePathEntry *include_path,
660                  FILE* fd, backendFactory factory)
661{
662    char *tmp;
663    IDL_tree top;
664    TreeState state;
665    int rv;
666    input_callback_state callback_state;
667    gboolean ok = TRUE;
668    backend *emitter;
669
670    callback_state.input_stack = NULL;
671    callback_state.base_includes = NULL;
672    callback_state.include_path = include_path;
673    callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal);
674
675    if (!callback_state.already_included) {
676        fprintf(stderr, "failed to create hashtable.  out of memory?\n");
677        return 0;
678    }
679
680    state.basename = xpidl_strdup(filename);
681
682    /* if basename has an .extension, truncate it. */
683    tmp = strrchr(state.basename, '.');
684    if (tmp)
685        *tmp = '\0';
686
687    /* so we don't include it again! */
688    g_hash_table_insert(callback_state.already_included,
689                        xpidl_strdup(filename), (void *)TRUE);
690
691    parsed_empty_file = FALSE;
692
693    rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
694                                       msg_callback, &top,
695                                       &state.ns,
696                                       IDLF_IGNORE_FORWARDS |
697                                       IDLF_XPIDL,
698                                       enable_warnings ? IDL_WARNING1 :
699                                       IDL_ERROR);
700    if (parsed_empty_file) {
701        /*
702         * If we've detected (via hack in msg_callback) that libIDL returned
703         * failure because it found a file with no IDL, set the parse tree to
704         * null and proceed.  Allowing this is useful to permit .idl files that
705         * collect #includes.
706         */
707        top = NULL;
708        state.ns = NULL;
709    } else if (rv != IDL_SUCCESS) {
710        if (rv == -1) {
711            g_warning("Parse of %s failed: %s", filename, g_strerror(errno));
712        } else {
713            g_warning("Parse of %s failed", filename);
714        }
715        return 0;
716    }
717
718    state.basename = xpidl_strdup(filename);
719    tmp = strrchr(state.basename, '.');
720    if (tmp)
721        *tmp = '\0';
722
723    /* so xpidl_header.c can use it to generate a list of #include directives */
724    state.base_includes = callback_state.base_includes;
725
726    emitter = factory();
727    state.dispatch = emitter->dispatch_table;
728
729    state.file = fd;
730    state.tree = top;
731
732    if (emitter->emit_prolog)
733        emitter->emit_prolog(&state);
734    if (state.tree) /* Only if we have a tree to process. */
735        ok = xpidl_process_node(&state);
736    if (emitter->emit_epilog)
737        emitter->emit_epilog(&state);
738
739    free(state.basename);
740    g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL);
741    g_hash_table_destroy(callback_state.already_included);
742    g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL);
743
744    if (state.ns)
745        IDL_ns_free(state.ns);
746    if (top)
747        IDL_tree_free(top);
748
749    return ok;
750}
751
752GSList*
753xpidl_get_include(char *filename, IncludePathEntry *include_path)
754{
755    IDL_tree top;
756    IDL_ns ns;
757    int rv;
758    input_callback_state callback_state;
759
760    callback_state.input_stack = NULL;
761    callback_state.base_includes = NULL;
762    callback_state.include_path = include_path;
763    callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal);
764
765    if (!callback_state.already_included) {
766        fprintf(stderr, "failed to create hashtable.  out of memory?\n");
767        return 0;
768    }
769
770    /* so we don't include it again! */
771    g_hash_table_insert(callback_state.already_included,
772                        xpidl_strdup(filename), (void *)TRUE);
773
774    parsed_empty_file = FALSE;
775
776    rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
777                                       msg_callback, &top,
778                                       &ns,
779                                       IDLF_IGNORE_FORWARDS |
780                                       IDLF_XPIDL,
781                                       enable_warnings ? IDL_WARNING1 :
782                                       IDL_ERROR);
783    if (parsed_empty_file) {
784        /*
785         * If we've detected (via hack in msg_callback) that libIDL returned
786         * failure because it found a file with no IDL, set the parse tree to
787         * null and proceed.  Allowing this is useful to permit .idl files that
788         * collect #includes.
789         */
790        top = NULL;
791        ns = NULL;
792    } else if (rv != IDL_SUCCESS) {
793        if (rv == -1) {
794            g_warning("Parse of %s failed: %s", filename, g_strerror(errno));
795        } else {
796            g_warning("Parse of %s failed", filename);
797        }
798        return 0;
799    }
800
801    g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL);
802    g_hash_table_destroy(callback_state.already_included);
803
804    if (ns)
805        IDL_ns_free(ns);
806    if (top)
807        IDL_tree_free(top);
808
809    return callback_state.base_includes;
810}
811
812/*
813 * Our own version of IDL_tree_warning, which we use when IDL_tree_warning
814 * would crash on us.
815 */
816void
817xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...)
818{
819    va_list ap;
820    char *msg, *file;
821    int lineno;
822
823    /* XXX need to check against __IDL_max_msg_level, no accessor */
824    va_start(ap, fmt);
825    msg = g_strdup_vprintf(fmt, ap);
826
827    if (p) {
828        file = p->_file;
829        lineno = p->_line;
830    } else {
831        file = NULL;
832        lineno = 0;
833    }
834
835    /* call our message callback, like IDL_tree_warning would */
836    msg_callback(level, 0, lineno, file, msg);
837    g_free(msg);
838    va_end(ap);
839}
840
841#include <windows.h>
842
843static GSList*
844append_file(GSList *slist, char* fullpath, char* filename)
845{
846    IncludeData *data;
847    char*   tmp;
848   
849    data = xpidl_malloc(sizeof(IncludeData));
850    if (data == NULL) return slist;
851    data->FullPath = NULL;
852    data->FileName = NULL;
853    data->Includes = NULL;
854   
855    tmp = xpidl_strdup(fullpath);
856    if (tmp == NULL) goto FAIL;
857    data->FullPath = tmp;
858    tmp = xpidl_strdup(filename);
859    if (tmp == NULL) goto FAIL;
860    data->FileName = tmp;
861   
862    return g_slist_append(slist, data);
863FAIL:;
864    if (data->FullPath)
865        free(data->FullPath);
866    if (data->FileName)
867        free(data->FileName);
868    free(data);
869   
870    return slist;
871}
872
873GSList*
874xpidlpas_append_process_files(GSList *slist, const char* filename)
875{
876    char    drv[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
877    char    path[_MAX_PATH];
878    HANDLE  hFind;
879    WIN32_FIND_DATA fData;
880   
881    _splitpath(filename, drv, dir, fname, ext);
882    hFind = FindFirstFile(filename, &fData);
883    if (hFind == INVALID_HANDLE_VALUE) {
884        if (enable_warnings)
885            fprintf(stderr, "Warning: '%s%' is not found.\n", filename);
886        return slist;
887    }
888    do {
889        _makepath(path, drv, dir, fData.cFileName, NULL);
890        slist = append_file(slist, path, fData.cFileName);
891    } while (FindNextFile(hFind, &fData));
892   
893    return slist;
894}
895
896static gint
897IncludeCompare(gconstpointer a, gconstpointer b)
898{
899    const IncludeData* A = a;
900    const IncludeData* B = b;
901    guint len_a = g_slist_length(A->Includes);
902    guint len_b = g_slist_length(B->Includes);
903    guint i;
904   
905    for (i=0; i<len_a; i++) {
906        char *file;
907       
908        file = (char *)g_slist_nth_data(A->Includes, i);
909        if (strcmp(file, B->FileName) == 0) {
910            if (verbose_mode) {
911                fprintf(stderr, "'%s' includes '%s'\n", A->FileName, B->FileName);
912            }
913            return 1;
914        }
915    }
916   
917    for (i=0; i<len_b; i++) {
918        char *file;
919       
920        file = (char *)g_slist_nth_data(B->Includes, i);
921        if (strcmp(file, A->FileName) == 0) {
922            if (verbose_mode) {
923                fprintf(stderr, "'%s' is included in '%s'\n", A->FileName, B->FileName);
924            }
925            return -1;
926        }
927    }
928   
929    return (len_a>0) - (len_b>0);
930}
931
932static void
933CheckInclude(gpointer data, gpointer user_data)
934{
935    IncludeData *iData = data;
936    IncludePathEntry *include_path = user_data;
937    GSList *Includes = NULL;
938   
939    Includes = xpidl_get_include(iData->FullPath, include_path);
940    iData->Includes = Includes;
941}
942
943GSList*
944xpidlpas_sort(GSList *slist)
945{
946    GSList *top, *next;
947    gpointer tdata, ndata;
948    gint    i, n;
949   
950    top = slist;
951    if (top->next != NULL) {
952        n = g_slist_length(top);
953        next = top;
954        for (next = top; next!=NULL; next = g_slist_next(next)) {
955            if (IncludeCompare(top->data, next->data) > 0) {
956                if (verbose_mode) {
957                    IncludeData *n, *t;
958                    n = next->data; t = top->data;
959                    fprintf(stderr, "Switching %s and %s\n", t->FileName, n->FileName);
960                }
961                ndata = next->data;
962                top = g_slist_remove(top, ndata);
963                top = g_slist_prepend(top, ndata);
964                next = top;
965            }
966        }
967        top->next = xpidlpas_sort(top->next);
968    }
969    return top;
970}
971
972GSList*
973xpidlpas_sort_files(GSList *slist, IncludePathEntry *include_path)
974{
975    if (verbose_mode)
976        fputs("Search Include Files ...\n", stderr);
977    g_slist_foreach(slist, CheckInclude, include_path);
978   
979    if (verbose_mode)
980        fputs("Sorting ...\n", stderr);
981       
982    return xpidlpas_sort(slist);
983}
984
985static void
986PrintFullPath(gpointer data, gpointer user_data)
987{
988    IncludeData *iData = data;
989    printf ("%s\n", iData->FullPath);
990}
991
992typedef struct ProcessData {
993    FILE*   file;
994    backendFactory  factory;
995    IncludePathEntry*   include_path;
996} ProcessData;
997
998static void
999ProcessIDLFile(gpointer data, gpointer user_data)
1000{
1001    IncludeData* iData = data;
1002    ProcessData* pData = user_data;
1003   
1004    xpidl_process_idl(iData->FullPath, pData->include_path, pData->file, pData->factory);
1005}
1006
1007static void
1008xpidl_process_inc(const char* filename, FILE* file)
1009{
1010    char *inc_file;
1011    char *ptr;
1012    FILE *in_file;
1013   
1014    inc_file = xpidl_strdup(filename);
1015    if (!inc_file) return;
1016    for(ptr = inc_file; *ptr; ptr++);
1017    for(; ptr>=inc_file && *ptr!='.'; ptr--);
1018    if(ptr<inc_file) goto end1;
1019    strcpy(ptr, ".inc");
1020   
1021    in_file = fopen(inc_file, "rt");
1022    if (!in_file) goto end1;
1023    while(!feof(in_file)) {
1024        char buffer[256];
1025        fgets(buffer, 256, in_file);
1026        fputs(buffer, file);
1027    }
1028    fclose(in_file);
1029   
1030end1:;
1031    free(inc_file);
1032}
1033
1034static void
1035ProcessIncFile(gpointer data, gpointer user_data)
1036{
1037    IncludeData* iData = data;
1038    ProcessData* pData = user_data;
1039   
1040    xpidl_process_inc(iData->FullPath, pData->file);
1041}
1042
1043gboolean
1044xpidlpas_process_files(GSList *slist, IncludePathEntry *include_path,
1045                       char *file_basename, ModeData *mode)
1046{
1047    FILE *file;
1048    ProcessData pData;
1049    char *outname, *real_outname;
1050    char *basename;
1051   
1052    outname = g_strdup_printf("%s.pas", file_basename);
1053    file = fopen(outname, "w");
1054    if (!file) return FALSE;
1055   
1056    pData.file = file;
1057    pData.include_path = include_path;
1058   
1059    basename = strrchr(file_basename, '\\');
1060    if (!basename)
1061        basename = file_basename;
1062   
1063    fprintf(file, "unit %s;\n\n", basename);
1064    fputs("interface\n\n", file);
1065    if (uses_units) {
1066        GSList *unit = uses_units;
1067        fputs("uses\n  ", file);
1068        do {
1069            fputs((const char*)unit->data, file);
1070            unit = g_slist_next(unit);
1071            if (unit)
1072                fputs(", ", file);
1073        } while(unit);
1074        fputs(";\n\n", file);
1075    }
1076   
1077    fputs("const\n", file);
1078    pData.factory = xpidl_const_dispatch;
1079    g_slist_foreach(slist, ProcessIDLFile, &pData);
1080   
1081    fputs("type\n", file);
1082    pData.factory = xpidl_forward_dispatch;
1083    g_slist_foreach(slist, ProcessIDLFile, &pData);
1084   
1085    g_slist_foreach(slist, ProcessIncFile, &pData);
1086   
1087    pData.factory = xpidl_typedef_dispatch;
1088    g_slist_foreach(slist, ProcessIDLFile, &pData);
1089   
1090    pData.factory = mode->factory;
1091    g_slist_foreach(slist, ProcessIDLFile, &pData);
1092   
1093    fputs("implementation\n\n"
1094          "end.\n", file);
1095         
1096    return TRUE;
1097}
Note: See TracBrowser for help on using the browser.