VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.3 KB
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 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the NPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the NPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39/*
40 * Common IDL-processing code.
41 */
42
43#include "xpidl.h"
44
45#ifdef XP_MAC
46#include <stat.h>
47#endif
48
49static gboolean parsed_empty_file;
50
51/*
52 * The bulk of the generation happens here.
53 */
54gboolean
55xpidl_process_node(TreeState *state)
56{
57 gint type;
58 nodeHandler *dispatch, handler;
59
60 XPT_ASSERT(state->tree);
61 type = IDL_NODE_TYPE(state->tree);
62
63 if ((dispatch = state->dispatch) && (handler = dispatch[type]))
64 return handler(state);
65 return TRUE;
66}
67
68#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
69extern void mac_warning(const char* warning_message);
70#endif
71
72static int
73msg_callback(int level, int num, int line, const char *file,
74 const char *message)
75{
76 char *warning_message;
77
78 /*
79 * Egregious hack to permit empty files.
80 * XXX libIDL needs an API to detect this case robustly.
81 */
82 if (0 == strcmp(message, "File empty after optimization")) {
83 parsed_empty_file = TRUE;
84 return 1;
85 }
86
87 if (!file)
88 file = "<unknown file>";
89 warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message);
90
91#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
92 mac_warning(warning_message);
93#else
94 fputs(warning_message, stderr);
95#endif
96
97 g_free(warning_message);
98 return 1;
99}
100
101/*
102 * To keep track of the state associated with a given input file. The 'next'
103 * field lets us maintain a stack of input files.
104 */
105typedef struct input_data {
106 char *filename; /* where did I come from? */
107 unsigned int lineno; /* last lineno processed */
108 char *buf; /* contents of file */
109 char *point; /* next char to feed to libIDL */
110 char *max; /* 1 past last char in buf */
111 struct input_data *next; /* file from which we were included */
112} input_data;
113
114/*
115 * Passed to us by libIDL. Holds global information and the current stack of
116 * include files.
117 */
118typedef struct input_callback_state {
119 struct input_data *input_stack; /* linked list of input_data */
120 GHashTable *already_included; /* to prevent redundant includes */
121 IncludePathEntry *include_path; /* search path for included files */
122 GSList *base_includes; /* to accumulate #includes from *first* file;
123 * for passing thru TreeState to
124 * xpidl_header backend. */
125} input_callback_state;
126
127static FILE *
128fopen_from_includes(const char *filename, const char *mode,
129 IncludePathEntry *include_path)
130{
131 IncludePathEntry *current_path = include_path;
132 char *pathname;
133 FILE *inputfile;
134 if (!strcmp(filename, "-"))
135 return stdin;
136
137 if (filename[0] != '/') {
138 while (current_path) {
139 pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
140 current_path->directory, filename);
141 if (!pathname)
142 return NULL;
143 inputfile = fopen(pathname, mode);
144 g_free(pathname);
145 if (inputfile)
146 return inputfile;
147 current_path = current_path->next;
148 }
149 } else {
150 inputfile = fopen(filename, mode);
151 if (inputfile)
152 return inputfile;
153 }
154 return NULL;
155}
156
157#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
158extern FILE* mac_fopen(const char* filename, const char *mode);
159#endif
160
161static input_data *
162new_input_data(const char *filename, IncludePathEntry *include_path)
163{
164 input_data *new_data;
165 FILE *inputfile;
166 char *buffer = NULL;
167 size_t offset = 0;
168 size_t buffer_size;
169#ifdef XP_MAC
170 size_t i;
171#endif
172
173#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
174 /* on Mac, fopen knows how to find files. */
175 inputfile = fopen(filename, "r");
176#elif defined(XP_OS2) || defined(XP_WIN32)
177 /*
178 * if filename is fully qualified (starts with driver letter), then
179 * just call fopen(); else, go with fopen_from_includes()
180 */
181 if( filename[1] == ':' )
182 inputfile = fopen(filename, "r");
183 else
184 inputfile = fopen_from_includes(filename, "r", include_path);
185#else
186 inputfile = fopen_from_includes(filename, "r", include_path);
187#endif
188
189 if (!inputfile)
190 return NULL;
191
192#ifdef XP_MAC
193 {
194 struct stat input_stat;
195 if (fstat(fileno(inputfile), &input_stat))
196 return NULL;
197 buffer = malloc(input_stat.st_size + 1);
198 if (!buffer)
199 return NULL;
200 offset = fread(buffer, 1, input_stat.st_size, inputfile);
201 if (ferror(inputfile))
202 return NULL;
203 }
204#else
205 /*
206 * Rather than try to keep track of many different varieties of state
207 * around the boundaries of a circular buffer, we just read in the entire
208 * file.
209 *
210 * We iteratively grow the buffer here; an alternative would be to use
211 * stat to find the exact buffer size we need, as xpt_dump does.
212 */
213 for (buffer_size = 8191; ; buffer_size *= 2) {
214 size_t just_read;
215 buffer = realloc(buffer, buffer_size + 1); /* +1 for trailing nul */
216 just_read = fread(buffer + offset, 1, buffer_size - offset, inputfile);
217 if (ferror(inputfile))
218 return NULL;
219
220 if (just_read < buffer_size - offset || just_read == 0) {
221 /* Done reading. */
222 offset += just_read;
223 break;
224 }
225 offset += just_read;
226 }
227#endif
228
229 fclose(inputfile);
230
231#ifdef XP_MAC
232 /*
233 * libIDL doesn't speak '\r' properly - always make sure lines end with
234 * '\n'.
235 */
236 for (i = 0; i < offset; i++) {
237 if (buffer[i] == '\r')
238 buffer[i] = '\n';
239 }
240#endif
241
242 new_data = xpidl_malloc(sizeof (struct input_data));
243 new_data->point = new_data->buf = buffer;
244 new_data->max = buffer + offset;
245 *new_data->max = '\0';
246 new_data->filename = xpidl_strdup(filename);
247 /* libIDL expects the line number to be that of the *next* line */
248 new_data->lineno = 2;
249 new_data->next = NULL;
250
251 return new_data;
252}
253
254/* process pending raw section */
255static int
256NextIsRaw(input_data *data, char **startp, int *lenp)
257{
258 char *end, *start;
259
260 /*
261 * XXXmccabe still needed: an in_raw flag to handle the case where we're in
262 * a raw block, but haven't managed to copy it all to xpidl. This will
263 * happen when we have a raw block larger than
264 * IDL_input_data->fill.max_size (currently 8192.)
265 */
266 if (!(data->point[0] == '%' && data->point[1] == '{'))
267 return 0;
268
269 start = *startp = data->point;
270
271 end = NULL;
272 while (start < data->max && (end = strstr(start, "%}"))) {
273 if (end[-1] == '\r' ||
274 end[-1] == '\n')
275 break;
276 start = end + 1;
277 }
278
279 if (end && start < data->max) {
280 *lenp = end - data->point + 2;
281 return 1;
282 } else {
283 const char *filename;
284 int lineno;
285
286 IDL_file_get(&filename, &lineno);
287 msg_callback(IDL_ERROR, 0, lineno, filename,
288 "unterminated %{ block");
289 return -1;
290 }
291}
292
293/* process pending comment */
294static int
295NextIsComment(input_data *data, char **startp, int *lenp)
296{
297 char *end;
298
299 if (!(data->point[0] == '/' && data->point[1] == '*'))
300 return 0;
301
302 end = strstr(data->point, "*/");
303 *lenp = 0;
304 if (end) {
305 int skippedLines = 0;
306 char *tempPoint;
307
308 /* get current lineno */
309 IDL_file_get(NULL,(int *)&data->lineno);
310
311 /* get line count */
312 for (tempPoint = data->point; tempPoint < end; tempPoint++) {
313 if (*tempPoint == '\n')
314 skippedLines++;
315 }
316
317 data->lineno += skippedLines;
318 IDL_file_set(data->filename, (int)data->lineno);
319
320 *startp = end + 2;
321
322 /* If it's a ** comment, tell libIDL about it. */
323 if (data->point[2] == '*') {
324 /* hack termination. +2 to get past '*' '/' */
325 char t = *(end + 2);
326 *(end + 2) = '\0';
327 IDL_queue_new_ident_comment(data->point);
328 *(end + 2) = t;
329 }
330
331 data->point = *startp; /* XXXmccabe move this out of function? */
332 return 1;
333 } else {
334 const char *filename;
335 int lineno;
336
337 IDL_file_get(&filename, &lineno);
338 msg_callback(IDL_ERROR, 0, lineno, filename,
339 "unterminated comment");
340 return -1;
341 }
342}
343
344static int
345NextIsInclude(input_callback_state *callback_state, char **startp,
346 int *lenp)
347{
348 input_data *data = callback_state->input_stack;
349 input_data *new_data;
350 char *filename, *end;
351 const char *scratch;
352
353 /* process the #include that we're in now */
354 if (strncmp(data->point, "#include \"", 10)) {
355 return 0;
356 }
357
358 filename = data->point + 10; /* skip #include " */
359 XPT_ASSERT(filename < data->max);
360 end = filename;
361 while (end < data->max) {
362 if (*end == '\"' || *end == '\n' || *end == '\r')
363 break;
364 end++;
365 }
366
367 if (*end != '\"') {
368 /*
369 * Didn't find end of include file. Scan 'til next whitespace to find
370 * some reasonable approximation of the filename, and use it to report
371 * an error.
372 */
373
374 end = filename;
375 while (end < data->max) {
376 if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t')
377 break;
378 end++;
379 }
380 *end = '\0';
381
382 /* make sure we have accurate line info */
383 IDL_file_get(&scratch, (int *)&data->lineno);
384 fprintf(stderr,
385 "%s:%d: didn't find end of quoted include name \"%s\n",
386 scratch, data->lineno, filename);
387 return -1;
388 }
389
390 *end = '\0';
391 *startp = end + 1;
392
393 if (data->next == NULL) {
394 /*
395 * If we're in the initial file, add this filename to the list
396 * of filenames to be turned into #include "filename.h"
397 * directives in xpidl_header.c. We do it here rather than in the
398 * block below so it still gets added to the list even if it's
399 * already been recursively included from some other file.
400 */
401 char *filename_cp = xpidl_strdup(filename);
402
403 /* note that g_slist_append accepts and likes null as list-start. */
404 callback_state->base_includes =
405 g_slist_append(callback_state->base_includes, filename_cp);
406 }
407
408 /* store offset for when we pop, or if we skip this one */
409 data->point = *startp;
410
411 if (!g_hash_table_lookup(callback_state->already_included, filename)) {
412 filename = xpidl_strdup(filename);
413 g_hash_table_insert(callback_state->already_included,
414 filename, (void *)TRUE);
415 new_data = new_input_data(filename, callback_state->include_path);
416 if (!new_data) {
417 char *error_message;
418 IDL_file_get(&scratch, (int *)&data->lineno);
419 error_message =
420 g_strdup_printf("can't open included file %s for reading\n",
421 filename);
422 msg_callback(IDL_ERROR, 0,
423 data->lineno, scratch, error_message);
424 g_free(error_message);
425 return -1;
426 }
427
428 new_data->next = data;
429 /* tell libIDL to exclude this IDL from the toplevel tree */
430 IDL_inhibit_push();
431 IDL_file_get(&scratch, (int *)&data->lineno);
432 callback_state->input_stack = new_data;
433 IDL_file_set(new_data->filename, (int)new_data->lineno);
434 }
435
436 *lenp = 0; /* this is magic, see the comment below */
437 return 1;
438}
439
440static void
441FindSpecial(input_data *data, char **startp, int *lenp)
442{
443 char *point = data->point;
444
445 /* magic sequences are:
446 * "%{" raw block
447 * "/\*" comment
448 * "#include \"" include
449 * The first and last want a newline [\r\n] before, or the start of the
450 * file.
451 */
452
453#define LINE_START(data, point) (point == data->buf || \
454 (point > data->point && \
455 (point[-1] == '\r' || point[-1] == '\n')))
456
457 while (point < data->max) {
458 if (point[0] == '/' && point[1] == '*')
459 break;
460 if (LINE_START(data, point)) {
461 if (point[0] == '%' && point[1] == '{')
462 break;
463 if (point[0] == '#' && !strncmp(point + 1, "include \"", 9))
464 break;
465 }
466 point++;
467 }
468
469#undef LINE_START
470
471 *startp = data->point;
472 *lenp = point - data->point;
473}
474
475/* set this with a debugger to see exactly what libIDL sees */
476static FILE *tracefile;
477
478static int
479input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
480 gpointer user_data)
481{
482 input_callback_state *callback_state = user_data;
483 input_data *data = callback_state->input_stack;
484 input_data *new_data = NULL;
485 unsigned int len, copy;
486 int rv;
487 char *start;
488
489 switch(reason) {
490 case IDL_INPUT_REASON_INIT:
491 if (data == NULL || data->next == NULL) {
492 /*
493 * This is the first file being processed. As it's the target
494 * file, we only look for it in the first entry in the include
495 * path, which we assume to be the current directory.
496 */
497
498 /* XXXmccabe proper assumption? Do we handle files in other
499 directories? */
500
501 IncludePathEntry first_entry;
502
503 first_entry.directory = callback_state->include_path->directory;
504 first_entry.next = NULL;
505
506 new_data = new_input_data(cb_data->init.filename,
507 &first_entry);
508 } else {
509 new_data = new_input_data(cb_data->init.filename,
510 callback_state->include_path);
511 }
512
513 if (!new_data)
514 return -1;
515
516 IDL_file_set(new_data->filename, (int)new_data->lineno);
517 callback_state->input_stack = new_data;
518 return 0;
519
520 case IDL_INPUT_REASON_FILL:
521 start = NULL;
522 len = 0;
523
524 while (data->point >= data->max) {
525 if (!data->next)
526 return 0;
527
528 /* Current file is done; revert to including file */
529 callback_state->input_stack = data->next;
530 free(data->filename);
531 free(data->buf);
532 free(data);
533 data = callback_state->input_stack;
534
535 IDL_file_set(data->filename, (int)data->lineno);
536 IDL_inhibit_pop();
537 }
538
539 /*
540 * Now we scan for sequences which require special attention:
541 * \n#include begins an include statement
542 * \n%{ begins a raw-source block
543 * /\* begins a comment
544 *
545 * We used to be fancier here, so make sure that we sent the most
546 * data possible at any given time. To that end, we skipped over
547 * \n%{ raw \n%} blocks and then _continued_ the search for special
548 * sequences like \n#include or /\* comments .
549 *
550 * It was really ugly, though -- liberal use of goto! lots of implicit
551 * state! what fun! -- so now we just do this:
552 *
553 * if (special at start) {
554 * process that special -
555 * - raw: send it to libIDL, and don't look inside for specials
556 * - comments: adjust point and start over
557 * - includes: push new input_data struct for included file, and
558 * start over
559 * } else {
560 * scan for next special
561 * send data up to that special to libIDL
562 * }
563 *
564 * If len is set to zero, it is a sentinel value indicating we a comment
565 * or include was found, and parsing should start over.
566 *
567 * XXX const string foo = "/\*" will just screw us horribly.
568 * Hm but. We could treat strings as we treat raw blocks, eh?
569 */
570
571 /*
572 * Order is important, so that you can have /\* comments and
573 * #includes within raw sections, and so that you can comment out
574 * #includes.
575 */
576 rv = NextIsRaw(data, &start, (int *)&len);
577 if (rv == -1) return -1;
578 if (!rv) {
579 /*
580 * When NextIsComment succeeds, it returns a 0 len (requesting a
581 * restart) and adjusts data->point to pick up after the comment.
582 */
583 rv = NextIsComment(data, &start, (int *)&len);
584 if (rv == -1) return -1;
585 if (!rv) {
586 /*
587 * NextIsInclude might push a new input_data struct; if so, it
588 * will return a 0 len, letting the callback pick up the new
589 * file the next time around.
590 */
591 rv = NextIsInclude(callback_state, &start, (int *)&len);
592 if (rv == -1) return -1;
593 if (!rv)
594 FindSpecial(data, &start, (int *)&len);
595 }
596 }
597
598 if (len == 0) {
599 /*
600 * len == 0 is a sentinel value that means we found a comment or
601 * include. If we found a comment, point has been adjusted to
602 * point past the comment. If we found an include, a new input_data
603 * has been pushed. In both cases, calling the input_callback again
604 * will pick up the new state.
605 */
606 return input_callback(reason, cb_data, user_data);
607 }
608
609 copy = MIN(len, (unsigned int) cb_data->fill.max_size);
610 memcpy(cb_data->fill.buffer, start, copy);
611 data->point = start + copy;
612
613 if (tracefile)
614 fwrite(cb_data->fill.buffer, copy, 1, tracefile);
615
616 return copy;
617
618 case IDL_INPUT_REASON_ABORT:
619 case IDL_INPUT_REASON_FINISH:
620 while (data != NULL) {
621 input_data *next;
622
623 next = data->next;
624 free(data->filename);
625 free(data->buf);
626 free(data);
627 data = next;
628 }
629 return 0;
630
631 default:
632 g_error("unknown input reason %d!", reason);
633 return -1;
634 }
635}
636
637static void
638free_ghash_key(gpointer key, gpointer value, gpointer user_data)
639{
640 /* We're only storing TRUE in the value... */
641 free(key);
642}
643
644static void
645free_gslist_data(gpointer data, gpointer user_data)
646{
647 free(data);
648}
649
650/* Pick up unlink. */
651#ifdef XP_UNIX
652#include <unistd.h>
653#elif XP_WIN
654/* We get it from stdio.h. */
655#endif
656
657int
658xpidl_process_idl(char *filename, IncludePathEntry *include_path,
659 char *file_basename, ModeData *mode)
660{
661 char *tmp, *outname, *real_outname = NULL;
662 IDL_tree top;
663 TreeState state;
664 int rv;
665 input_callback_state callback_state;
666 gboolean ok = TRUE;
667 backend *emitter;
668
669 callback_state.input_stack = NULL;
670 callback_state.base_includes = NULL;
671 callback_state.include_path = include_path;
672 callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal);
673
674 if (!callback_state.already_included) {
675 fprintf(stderr, "failed to create hashtable. out of memory?\n");
676 return 0;
677 }
678
679 state.basename = xpidl_strdup(filename);
680
681 /* if basename has an .extension, truncate it. */
682 tmp = strrchr(state.basename, '.');
683 if (tmp)
684 *tmp = '\0';
685
686 if (!file_basename)
687 outname = xpidl_strdup(state.basename);
688 else
689 outname = xpidl_strdup(file_basename);
690
691 /* so we don't include it again! */
692 g_hash_table_insert(callback_state.already_included,
693 xpidl_strdup(filename), (void *)TRUE);
694
695 parsed_empty_file = FALSE;
696
697 rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
698 msg_callback, &top,
699 &state.ns,
700 IDLF_IGNORE_FORWARDS |
701 IDLF_XPIDL,
702 enable_warnings ? IDL_WARNING1 :
703 IDL_ERROR);
704 if (parsed_empty_file) {
705 /*
706 * If we've detected (via hack in msg_callback) that libIDL returned
707 * failure because it found a file with no IDL, set the parse tree to
708 * null and proceed. Allowing this is useful to permit .idl files that
709 * collect #includes.
710 */
711 top = NULL;
712 state.ns = NULL;
713 } else if (rv != IDL_SUCCESS) {
714 if (rv == -1) {
715 g_warning("Parse of %s failed: %s", filename, g_strerror(errno));
716 } else {
717 g_warning("Parse of %s failed", filename);
718 }
719 return 0;
720 }
721
722 state.basename = xpidl_strdup(filename);
723 tmp = strrchr(state.basename, '.');
724 if (tmp)
725 *tmp = '\0';
726
727 /* so xpidl_header.c can use it to generate a list of #include directives */
728 state.base_includes = callback_state.base_includes;
729
730 emitter = mode->factory();
731 state.dispatch = emitter->dispatch_table;
732
733 if (strcmp(outname, "-")) {
734 const char *fopen_mode;
735 const char *out_basename;
736
737 /* explicit_output_filename can't be true without a filename */
738 if (explicit_output_filename) {
739 real_outname = g_strdup(outname);
740 } else {
741/*
742 *This combination seems a little strange, what about OS/2?
743 * Assume it's some build issue
744 */
745#if defined(XP_UNIX) || defined(XP_WIN)
746 if (!file_basename) {
747 out_basename = xpidl_basename(outname);
748 } else {
749 out_basename = outname;
750 }
751#else
752 out_basename = outname;
753#endif
754 real_outname = g_strdup_printf("%s.%s", out_basename, mode->suffix);
755 }
756
757 /* Use binary write for typelib mode */
758 fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb";
759 state.file = fopen(real_outname, fopen_mode);
760 if (!state.file) {
761 perror("error opening output file");
762 return 0;
763 }
764 } else {
765 state.file = stdout;
766 }
767 state.tree = top;
768
769 if (emitter->emit_prolog)
770 emitter->emit_prolog(&state);
771 if (state.tree) /* Only if we have a tree to process. */
772 ok = xpidl_process_node(&state);
773 if (emitter->emit_epilog)
774 emitter->emit_epilog(&state);
775
776 if (state.file != stdout)
777 fclose(state.file);
778 free(state.basename);
779 free(outname);
780 g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL);
781 g_hash_table_destroy(callback_state.already_included);
782 g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL);
783
784 if (state.ns)
785 IDL_ns_free(state.ns);
786 if (top)
787 IDL_tree_free(top);
788
789 if (real_outname != NULL) {
790 /*
791 * Delete partial output file on failure. (Mac does this in the plugin
792 * driver code, if the compiler returns failure.)
793 */
794#if defined(XP_UNIX) || defined(XP_WIN)
795 if (!ok)
796 unlink(real_outname);
797#endif
798 g_free(real_outname);
799 }
800
801 return ok;
802}
803
804/*
805 * Our own version of IDL_tree_warning, which we use when IDL_tree_warning
806 * would crash on us.
807 */
808void
809xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...)
810{
811 va_list ap;
812 char *msg, *file;
813 int lineno;
814
815 /* XXX need to check against __IDL_max_msg_level, no accessor */
816 va_start(ap, fmt);
817 msg = g_strdup_vprintf(fmt, ap);
818
819 if (p) {
820 file = p->_file;
821 lineno = p->_line;
822 } else {
823 file = NULL;
824 lineno = 0;
825 }
826
827 /* call our message callback, like IDL_tree_warning would */
828 msg_callback(level, 0, lineno, file, msg);
829 g_free(msg);
830 va_end(ap);
831}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use