diff options
Diffstat (limited to 'util.c')
-rw-r--r-- | util.c | 3683 |
1 files changed, 3683 insertions, 0 deletions
@@ -0,0 +1,3683 @@ +/************************************************************************** + + util.c + + Copyright (C) 1998, 1999 Andrew T. Veliath + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ + +***************************************************************************/ +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include "rename.h" +#include "util.h" + +#ifdef G_OS_WIN32 +#include <fcntl.h> +#include <direct.h> +#define popen _popen +#define pclose _pclose +#endif + +const char *IDL_tree_type_names[] = { + "IDLN_NONE", + "IDLN_ANY", + "IDLN_LIST", + "IDLN_GENTREE", + "IDLN_INTEGER", + "IDLN_STRING", + "IDLN_WIDE_STRING", + "IDLN_CHAR", + "IDLN_WIDE_CHAR", + "IDLN_FIXED", + "IDLN_FLOAT", + "IDLN_BOOLEAN", + "IDLN_IDENT", + "IDLN_TYPE_DCL", + "IDLN_CONST_DCL", + "IDLN_EXCEPT_DCL", + "IDLN_ATTR_DCL", + "IDLN_OP_DCL", + "IDLN_PARAM_DCL", + "IDLN_FORWARD_DCL", + "IDLN_TYPE_INTEGER", + "IDLN_TYPE_FLOAT", + "IDLN_TYPE_FIXED", + "IDLN_TYPE_CHAR", + "IDLN_TYPE_WIDE_CHAR", + "IDLN_TYPE_STRING", + "IDLN_TYPE_WIDE_STRING", + "IDLN_TYPE_BOOLEAN", + "IDLN_TYPE_OCTET", + "IDLN_TYPE_ANY", + "IDLN_TYPE_OBJECT", + "IDLN_TYPE_TYPECODE", + "IDLN_TYPE_ENUM", + "IDLN_TYPE_SEQUENCE", + "IDLN_TYPE_ARRAY", + "IDLN_TYPE_STRUCT", + "IDLN_TYPE_UNION", + "IDLN_MEMBER", + "IDLN_NATIVE", + "IDLN_CASE_STMT", + "IDLN_INTERFACE", + "IDLN_MODULE", + "IDLN_BINOP", + "IDLN_UNARYOP", + "IDLN_CODEFRAG", + /* IDLN_LAST */ +}; + +int __IDL_check_type_casts = FALSE; +#ifndef HAVE_CPP_PIPE_STDIN +const char * __IDL_tmp_filename = NULL; +#endif +const char * __IDL_real_filename = NULL; +char * __IDL_cur_filename = NULL; +int __IDL_cur_line; +GHashTable * __IDL_filename_hash; +IDL_fileinfo * __IDL_cur_fileinfo; +GHashTable * __IDL_structunion_ht; +int __IDL_inhibits; +int __IDL_typecodes_as_tok; +int __IDL_pidl; +IDL_tree __IDL_root; +IDL_ns __IDL_root_ns; +int __IDL_is_okay; +int __IDL_is_parsing; +unsigned long __IDL_flags; +unsigned long __IDL_flagsi; +gpointer __IDL_inputcb_user_data; +IDL_input_callback __IDL_inputcb; +GSList * __IDL_new_ident_comments; +static int __IDL_max_msg_level; +static int __IDL_nerrors, __IDL_nwarnings; +static IDL_msg_callback __IDL_msgcb; + +/* Case-insensitive version of g_str_hash */ +guint IDL_strcase_hash (gconstpointer v) +{ + const char *p; + guint h = 0, g; + + for (p = (char *) v; *p != '\0'; ++p) { + h = (h << 4) + isupper ((int)*p) ? tolower (*p) : *p; + if ((g = h & 0xf0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + + return h /* % M */; +} + +gint IDL_strcase_equal (gconstpointer a, gconstpointer b) +{ + return g_ascii_strcasecmp (a, b) == 0; +} + +gint IDL_strcase_cmp (gconstpointer a, gconstpointer b) +{ + return g_ascii_strcasecmp (a, b); +} + +static int my_strcmp (IDL_tree p, IDL_tree q) +{ + const char *a = IDL_IDENT (p).str; + const char *b = IDL_IDENT (q).str; + int cmp = IDL_strcase_cmp (a, b); + + if (__IDL_is_parsing && + cmp == 0 && + strcmp (a, b) != 0 && + !(IDL_IDENT (p)._flags & IDLF_IDENT_CASE_MISMATCH_HIT || + IDL_IDENT (q)._flags & IDLF_IDENT_CASE_MISMATCH_HIT)) { + IDL_tree_warning (p, IDL_WARNING1, "Case mismatch between `%s'", a); + IDL_tree_warning (q, IDL_WARNING1, "and `%s'", b); + yywarning (IDL_WARNING1, + "(Identifiers should be case-consistent after initial declaration)"); + IDL_IDENT (p)._flags |= IDLF_IDENT_CASE_MISMATCH_HIT; + IDL_IDENT (q)._flags |= IDLF_IDENT_CASE_MISMATCH_HIT; + } + + return cmp; +} + +guint IDL_ident_hash (gconstpointer v) +{ + return IDL_strcase_hash (IDL_IDENT ((IDL_tree) v).str); +} + +gint IDL_ident_equal (gconstpointer a, gconstpointer b) +{ + return my_strcmp ((IDL_tree) a, (IDL_tree) b) == 0; +} + +gint IDL_ident_cmp (gconstpointer a, gconstpointer b) +{ + return my_strcmp ((IDL_tree) a, (IDL_tree) b); +} + +const char *IDL_get_libver_string (void) +{ + return LIBIDL_VERSION; +} + +const char *IDL_get_IDLver_string (void) +{ + return "2.2"; +} + +static void IDL_tree_optimize (IDL_tree *p, IDL_ns ns) +{ + if (!(__IDL_flags & IDLF_IGNORE_FORWARDS)) + IDL_tree_process_forward_dcls (p, ns); + if (!(__IDL_flags & IDLF_INHIBIT_TAG_ONLY)) + IDL_tree_remove_inhibits (p, ns); + IDL_tree_remove_empty_modules (p, ns); +} + +static void IDL_parse_setup(unsigned long parse_flags, int max_msg_level) { + if (parse_flags & IDLF_XPIDL) + parse_flags |= IDLF_PROPERTIES; + + __IDL_max_msg_level = max_msg_level; + __IDL_nerrors = __IDL_nwarnings = 0; + __IDL_inhibits = 0; + __IDL_typecodes_as_tok = (parse_flags & IDLF_TYPECODES) ? 1 : 0; + __IDL_pidl = (parse_flags & IDLF_XPIDL) ? 1 : 0; + __IDL_flags = parse_flags; + __IDL_flagsi = 0; + __IDL_is_parsing = TRUE; + __IDL_is_okay = TRUE; + __IDL_new_ident_comments = NULL; +} + +int IDL_parse_filename (const char *filename, const char *cpp_args, + IDL_msg_callback msg_cb, IDL_tree *tree, IDL_ns *ns, + unsigned long parse_flags, int max_msg_level) +{ + extern void __IDL_lex_init (void); + extern void __IDL_lex_cleanup (void); + extern int yyparse (void); + extern FILE *__IDL_in; + FILE *input; + char *cmd; +#ifdef HAVE_CPP_PIPE_STDIN + char *fmt = CPP_PROGRAM " - %s%s %s < \"%s\" %s"; + char *wd; +#else + char *fmt = CPP_PROGRAM " -I%s %s \"%s\" %s"; + char cwd[2048]; +#ifdef HAVE_SYMLINK + char *s, *tmpfilename; + gchar *linkto; +#else + const char *tmpfilename; +#endif +#endif + +#ifndef G_OS_WIN32 + char *cpperrs = (parse_flags & IDLF_SHOW_CPP_ERRORS) + ? "" : "2>/dev/null"; +#else + char *cpperrs = ""; +#endif + GSList *slist; + int rv; + +#if 0 && defined(YYDEBUG) + { + extern int __IDL_debug; + __IDL_debug = 1; + } +#endif + + if (!filename || !tree) { + errno = EINVAL; + return -1; + } + +#ifdef HAVE_ACCESS + if (access (filename, R_OK)) + return -1; +#endif + +#ifdef HAVE_CPP_PIPE_STDIN + wd = g_path_get_dirname (filename); + + cmd = g_strdup_printf (fmt, "-I", wd, cpp_args ? cpp_args : "", + filename, cpperrs); + + g_free (wd); +#else + if (!getcwd (cwd, sizeof (cwd))) + return -1; + +#ifdef HAVE_SYMLINK + s = tmpnam (NULL); + if (s == NULL) + return -1; + + if (g_path_is_absolute (filename)) { + linkto = g_strdup (filename); + } else { + linkto = g_strconcat (cwd, "/", filename, NULL); + } + + tmpfilename = g_strconcat (s, ".c", NULL); + + if (symlink (linkto, tmpfilename) < 0) { + g_free (linkto); + g_free (tmpfilename); + return -1; + } + g_free (linkto); +#else + tmpfilename = filename; +#endif + + cmd = g_strdup_printf (fmt, cwd, cpp_args ? cpp_args : "", + tmpfilename, cpperrs); +#endif + + /* Many versions of cpp do evil translating internal + * strings, producing bogus output, so clobber LC_ALL */ + putenv ("LC_ALL=C"); + +#ifdef HAVE_POPEN +#if defined (G_OS_WIN32) && !defined (_MSC_VER) + if (!(parse_flags & IDLF_SHOW_CPP_ERRORS)) { + int save_stderr = dup (2); + int null = open ("NUL:", O_WRONLY); + dup2 (null, 2); + input = popen (cmd, "r"); + close (2); + close (null); + dup2 (save_stderr, 2); + close (save_stderr); + } else + input = popen (cmd, "r"); +#else + input = popen (cmd, "r"); +#endif +#else +#error Must have popen +#endif + g_free (cmd); + + if (input == NULL || ferror (input)) { +#if !defined (HAVE_CPP_PIPE_STDIN) && defined (HAVE_SYMLINK) + g_free (tmpfilename); +#endif + return IDL_ERROR; + } + + IDL_parse_setup(parse_flags, max_msg_level); + + __IDL_in = input; + __IDL_msgcb = msg_cb; + __IDL_root_ns = IDL_ns_new (); + __IDL_lex_init (); + + __IDL_real_filename = filename; +#ifndef HAVE_CPP_PIPE_STDIN + __IDL_tmp_filename = tmpfilename; +#endif + __IDL_filename_hash = IDL_NS (__IDL_root_ns).filename_hash; + __IDL_structunion_ht = g_hash_table_new (g_direct_hash, g_direct_equal); + rv = yyparse (); + g_hash_table_destroy (__IDL_structunion_ht); + __IDL_is_parsing = FALSE; + __IDL_lex_cleanup (); + __IDL_parser_reset (); + __IDL_real_filename = NULL; +#ifndef HAVE_CPP_PIPE_STDIN + __IDL_tmp_filename = NULL; +#endif +#ifdef HAVE_POPEN + pclose (input); +#else + fclose (input); +#endif +#if !defined (HAVE_CPP_PIPE_STDIN) && defined (HAVE_SYMLINK) + unlink (tmpfilename); + g_free (tmpfilename); +#endif + for (slist = __IDL_new_ident_comments; slist; slist = slist->next) + g_free (slist->data); + g_slist_free (__IDL_new_ident_comments); + + if (__IDL_root != NULL) { + IDL_tree_optimize (&__IDL_root, __IDL_root_ns); + + if (__IDL_root == NULL) + yyerror ("File empty after optimization"); + } + + __IDL_msgcb = NULL; + + if (rv != 0 || !__IDL_is_okay) { + *tree = NULL; + + if (ns) + *ns = NULL; + + return IDL_ERROR; + } + + if (__IDL_flags & IDLF_PREFIX_FILENAME) + IDL_ns_prefix (__IDL_root_ns, filename); + + *tree = __IDL_root; + + if (ns) + *ns = __IDL_root_ns; + else + IDL_ns_free (__IDL_root_ns); + + return IDL_SUCCESS; +} + +int IDL_parse_filename_with_input (const char *filename, + IDL_input_callback input_cb, + gpointer input_cb_user_data, + IDL_msg_callback msg_cb, + IDL_tree *tree, IDL_ns *ns, + unsigned long parse_flags, + int max_msg_level) +{ + extern void __IDL_lex_init (void); + extern void __IDL_lex_cleanup (void); + extern int yyparse (void); + union IDL_input_data data; + GSList *slist; + int rv; + + if (!filename || !input_cb || !tree) { + errno = EINVAL; + return -1; + } + + IDL_parse_setup(parse_flags, max_msg_level); + + __IDL_msgcb = msg_cb; + __IDL_root_ns = IDL_ns_new (); + + __IDL_lex_init (); + __IDL_inputcb = input_cb; + __IDL_inputcb_user_data = input_cb_user_data; + + __IDL_real_filename = filename; +#ifndef HAVE_CPP_PIPE_STDIN + __IDL_tmp_filename = NULL; +#endif + __IDL_filename_hash = IDL_NS (__IDL_root_ns).filename_hash; + data.init.filename = filename; + if ((*__IDL_inputcb) ( + IDL_INPUT_REASON_INIT, &data, __IDL_inputcb_user_data)) { + IDL_ns_free (__IDL_root_ns); + __IDL_lex_cleanup (); + __IDL_real_filename = NULL; + return -1; + } + __IDL_structunion_ht = g_hash_table_new (g_direct_hash, g_direct_equal); + rv = yyparse (); + g_hash_table_destroy (__IDL_structunion_ht); + __IDL_is_parsing = FALSE; + __IDL_lex_cleanup (); + __IDL_parser_reset (); + __IDL_real_filename = NULL; + for (slist = __IDL_new_ident_comments; slist; slist = slist->next) + g_free (slist->data); + g_slist_free (__IDL_new_ident_comments); + + if (__IDL_root != NULL) { + IDL_tree_optimize (&__IDL_root, __IDL_root_ns); + + if (__IDL_root == NULL) + yyerror ("File empty after optimization"); + } + + __IDL_msgcb = NULL; + + if (rv != 0 || !__IDL_is_okay) { + *tree = NULL; + + if (ns) + *ns = NULL; + + (*__IDL_inputcb) ( + IDL_INPUT_REASON_ABORT, NULL, __IDL_inputcb_user_data); + + return IDL_ERROR; + } + + (*__IDL_inputcb) (IDL_INPUT_REASON_FINISH, NULL, __IDL_inputcb_user_data); + + if (__IDL_flags & IDLF_PREFIX_FILENAME) + IDL_ns_prefix (__IDL_root_ns, filename); + + *tree = __IDL_root; + + if (ns) + *ns = __IDL_root_ns; + else + IDL_ns_free (__IDL_root_ns); + + return IDL_SUCCESS; +} + +void yyerrorl (const char *s, int ofs) +{ + int line = __IDL_cur_line - 1 + ofs; + gchar *freeme = NULL, *filename = NULL; + + if (__IDL_cur_filename) { +#ifdef HAVE_CPP_PIPE_STDIN + filename = __IDL_cur_filename; +#else + freeme = filename = g_path_get_basename (__IDL_cur_filename); +#endif + } else + line = -1; + + ++__IDL_nerrors; + __IDL_is_okay = FALSE; + + /* Errors are counted, even if not printed */ + if (__IDL_max_msg_level < IDL_ERROR) { + g_free (freeme); + return; + } + + if (__IDL_msgcb) + (*__IDL_msgcb)(IDL_ERROR, __IDL_nerrors, line, filename, s); + else { + if (line > 0) + fprintf (stderr, "%s:%d: Error: %s\n", filename, line, s); + else + fprintf (stderr, "Error: %s\n", s); + } + g_free (freeme); +} + +void yywarningl (int level, const char *s, int ofs) +{ + int line = __IDL_cur_line - 1 + ofs; + gchar *freeme = NULL, *filename = NULL; + + /* Unprinted warnings are not counted */ + if (__IDL_max_msg_level < level) + return; + + if (__IDL_cur_filename) { +#ifdef HAVE_CPP_PIPE_STDIN + filename = __IDL_cur_filename; +#else + freeme = filename = g_path_get_basename (__IDL_cur_filename); +#endif + } else + line = -1; + + ++__IDL_nwarnings; + + if (__IDL_msgcb) + (*__IDL_msgcb)(level, __IDL_nwarnings, line, filename, s); + else { + if (line > 0) + fprintf (stderr, "%s:%d: Warning: %s\n", filename, line, s); + else + fprintf (stderr, "Warning: %s\n", s); + } + g_free (freeme); +} + +void yyerror (const char *s) +{ + yyerrorl (s, 0); +} + +void yywarning (int level, const char *s) +{ + yywarningl (level, s, 0); +} + +void yyerrorlv (const char *fmt, int ofs, ...) +{ + gchar *msg; + va_list args; + + va_start (args, ofs); + + msg = g_strdup_vprintf (fmt, args); + yyerrorl (msg, ofs); + + va_end (args); + + g_free (msg); +} + +void yywarninglv (int level, const char *fmt, int ofs, ...) +{ + gchar *msg; + va_list args; + + va_start (args, ofs); + + msg = g_strdup_vprintf (fmt, args); + yywarningl (level, msg, ofs); + + va_end (args); + + g_free (msg); +} + +void yyerrorv (const char *fmt, ...) +{ + gchar *msg; + va_list args; + + va_start (args, fmt); + + msg = g_strdup_vprintf (fmt, args); + yyerror (msg); + + va_end (args); + + g_free (msg); +} + +void yywarningv (int level, const char *fmt, ...) +{ + gchar *msg; + va_list args; + + va_start (args, fmt); + + msg = g_strdup_vprintf (fmt, args); + yywarning (level, msg); + + va_end (args); + + g_free (msg); +} + +void IDL_tree_error (IDL_tree p, const char *fmt, ...) +{ + char *file_save = __IDL_cur_filename; + int line_save = __IDL_cur_line; + gchar *msg; + va_list args; + + if (p) { + __IDL_cur_filename = p->_file; + __IDL_cur_line = p->_line; + } else { + __IDL_cur_filename = NULL; + __IDL_cur_line = -1; + } + + va_start (args, fmt); + + msg = g_strdup_vprintf (fmt, args); + yyerror (msg); + + va_end (args); + + g_free (msg); + + __IDL_cur_filename = file_save; + __IDL_cur_line = line_save; +} + +void IDL_tree_warning (IDL_tree p, int level, const char *fmt, ...) +{ + char *file_save = __IDL_cur_filename; + int line_save = __IDL_cur_line; + gchar *msg; + va_list args; + + if (p) { + __IDL_cur_filename = p->_file; + __IDL_cur_line = p->_line; + } else { + __IDL_cur_filename = NULL; + __IDL_cur_line = -1; + } + + va_start (args, fmt); + + msg = g_strdup_vprintf (fmt, args); + yywarning (level, msg); + + va_end (args); + + g_free (msg); + + __IDL_cur_filename = file_save; + __IDL_cur_line = line_save; +} + +int IDL_tree_get_node_info (IDL_tree p, char **what, char **who) +{ + int dienow = 0; + + assert (what != NULL); + assert (who != NULL); + + switch (IDL_NODE_TYPE (p)) { + case IDLN_TYPE_STRUCT: + *what = "structure definition"; + *who = IDL_IDENT (IDL_TYPE_STRUCT (p).ident).str; + break; + + case IDLN_TYPE_UNION: + *what = "union definition"; + *who = IDL_IDENT (IDL_TYPE_UNION (p).ident).str; + break; + + case IDLN_TYPE_ARRAY: + *what = "array"; + *who = IDL_IDENT (IDL_TYPE_ARRAY (p).ident).str; + break; + + case IDLN_TYPE_ENUM: + *what = "enumeration definition"; + *who = IDL_IDENT (IDL_TYPE_ENUM (p).ident).str; + break; + + case IDLN_IDENT: + *what = "identifier"; + *who = IDL_IDENT (p).str; + break; + + case IDLN_TYPE_DCL: + *what = "type definition"; + assert (IDL_TYPE_DCL (p).dcls != NULL); + assert (IDL_NODE_TYPE (IDL_TYPE_DCL (p).dcls) == IDLN_LIST); + assert (IDL_LIST (IDL_TYPE_DCL (p).dcls)._tail != NULL); + assert (IDL_NODE_TYPE (IDL_LIST (IDL_TYPE_DCL (p).dcls)._tail) == IDLN_LIST); + *who = IDL_IDENT (IDL_LIST (IDL_LIST (IDL_TYPE_DCL (p).dcls)._tail).data).str; + break; + + case IDLN_MEMBER: + *what = "member declaration"; + assert (IDL_MEMBER (p).dcls != NULL); + assert (IDL_NODE_TYPE (IDL_MEMBER (p).dcls) == IDLN_LIST); + assert (IDL_LIST (IDL_MEMBER (p).dcls)._tail != NULL); + assert (IDL_NODE_TYPE (IDL_LIST (IDL_MEMBER (p).dcls)._tail) == IDLN_LIST); + *who = IDL_IDENT (IDL_LIST (IDL_LIST (IDL_MEMBER (p).dcls)._tail).data).str; + break; + + case IDLN_NATIVE: + *what = "native declaration"; + assert (IDL_NATIVE (p).ident != NULL); + assert (IDL_NODE_TYPE (IDL_NATIVE (p).ident) == IDLN_IDENT); + *who = IDL_IDENT (IDL_NATIVE (p).ident).str; + break; + + case IDLN_LIST: + if (!IDL_LIST (p).data) + break; + dienow = IDL_tree_get_node_info (IDL_LIST (p).data, what, who); + break; + + case IDLN_ATTR_DCL: + *what = "interface attribute"; + assert (IDL_ATTR_DCL (p).simple_declarations != NULL); + assert (IDL_NODE_TYPE (IDL_ATTR_DCL (p).simple_declarations) == IDLN_LIST); + assert (IDL_LIST (IDL_ATTR_DCL (p).simple_declarations)._tail != NULL); + assert (IDL_NODE_TYPE (IDL_LIST ( + IDL_ATTR_DCL (p).simple_declarations)._tail) == IDLN_LIST); + *who = IDL_IDENT (IDL_LIST (IDL_LIST ( + IDL_ATTR_DCL (p).simple_declarations)._tail).data).str; + break; + + case IDLN_PARAM_DCL: + *what = "operation parameter"; + assert (IDL_PARAM_DCL (p).simple_declarator != NULL); + assert (IDL_NODE_TYPE (IDL_PARAM_DCL (p).simple_declarator) == IDLN_IDENT); + *who = IDL_IDENT (IDL_PARAM_DCL (p).simple_declarator).str; + break; + + case IDLN_CONST_DCL: + *what = "constant declaration for"; + *who = IDL_IDENT (IDL_CONST_DCL (p).ident).str; + break; + + case IDLN_EXCEPT_DCL: + *what = "exception"; + *who = IDL_IDENT (IDL_EXCEPT_DCL (p).ident).str; + break; + + case IDLN_OP_DCL: + *what = "interface operation"; + *who = IDL_IDENT (IDL_OP_DCL (p).ident).str; + break; + + case IDLN_MODULE: + *what = "module"; + *who = IDL_IDENT (IDL_MODULE (p).ident).str; + break; + + case IDLN_FORWARD_DCL: + *what = "forward declaration"; + *who = IDL_IDENT (IDL_FORWARD_DCL (p).ident).str; + break; + + case IDLN_INTERFACE: + *what = "interface"; + *who = IDL_IDENT (IDL_INTERFACE (p).ident).str; + break; + + default: + g_warning ("Node type: %s\n", IDL_NODE_TYPE_NAME (p)); + *what = "unknown (internal error)"; + break; + } + + return dienow; +} + +static IDL_tree IDL_node_new (IDL_tree_type type) +{ + IDL_tree p; + + p = g_new0 (IDL_tree_node, 1); + if (p == NULL) { + yyerror ("IDL_node_new: memory exhausted"); + return NULL; + } + + IDL_NODE_TYPE (p) = type; + IDL_NODE_REFS (p) = 1; + + p->_file = __IDL_cur_filename; + p->_line = __IDL_cur_line; + + return p; +} + +void __IDL_assign_up_node (IDL_tree up, IDL_tree node) +{ + if (node == NULL) + return; + + assert (node != up); + + switch (IDL_NODE_TYPE (node)) { + case IDLN_LIST: + if (IDL_NODE_UP (node) == NULL) + for (; node != NULL; node = IDL_LIST (node).next) + IDL_NODE_UP (node) = up; + break; + + default: + if (IDL_NODE_UP (node) == NULL) + IDL_NODE_UP (node) = up; + break; + } +} + +void __IDL_assign_location (IDL_tree node, IDL_tree from_node) +{ + assert (node != NULL); + + if (from_node) { + node->_file = from_node->_file; + node->_line = from_node->_line; + } +} + +void __IDL_assign_this_location (IDL_tree node, char *filename, int line) +{ + assert (node != NULL); + + node->_file = filename; + node->_line = line; +} + +IDL_tree IDL_list_new (IDL_tree data) +{ + IDL_tree p = IDL_node_new (IDLN_LIST); + + __IDL_assign_up_node (p, data); + IDL_LIST (p).data = data; + IDL_LIST (p)._tail = p; + + return p; +} + +IDL_tree IDL_list_concat (IDL_tree orig, IDL_tree append) +{ + IDL_tree p; + + if (orig == NULL) + return append; + + if (append == NULL) + return orig; + + IDL_LIST (IDL_LIST (orig)._tail).next = append; + IDL_LIST (append).prev = IDL_LIST (orig)._tail; + IDL_LIST (orig)._tail = IDL_LIST (append)._tail; + + /* Set tails on original */ + for (p = IDL_LIST (orig).next; p && p != append; p = IDL_LIST (p).next) + IDL_LIST (p)._tail = IDL_LIST (orig)._tail; + + /* Set up nodes on appended list */ + for (p = append; p; p = IDL_LIST (p).next) + IDL_NODE_UP (p) = IDL_NODE_UP (orig); + + return orig; +} + +IDL_tree IDL_list_remove (IDL_tree list, IDL_tree p) +{ + IDL_tree new_list = list; + + if (IDL_LIST (p).prev == NULL) { + assert (list == p); + new_list = IDL_LIST (p).next; + if (new_list) + IDL_LIST (new_list).prev = NULL; + } else { + IDL_tree prev = IDL_LIST (p).prev; + IDL_tree next = IDL_LIST (p).next; + + IDL_LIST (prev).next = next; + if (next) + IDL_LIST (next).prev = prev; + } + + IDL_LIST (p).prev = NULL; + IDL_LIST (p).next = NULL; + IDL_LIST (p)._tail = p; + + /* Not all tails updated... */ + + return new_list; +} + +IDL_tree IDL_gentree_new (GHashFunc hash_func, GCompareFunc key_compare_func, IDL_tree data) +{ + IDL_tree p = IDL_node_new (IDLN_GENTREE); + + __IDL_assign_up_node (p, data); + IDL_GENTREE (p).data = data; + IDL_GENTREE (p).hash_func = hash_func; + IDL_GENTREE (p).key_compare_func = key_compare_func; + IDL_GENTREE (p).siblings = g_hash_table_new (hash_func, key_compare_func); + IDL_GENTREE (p).children = g_hash_table_new (hash_func, key_compare_func); + + g_hash_table_insert (IDL_GENTREE (p).siblings, data, p); + + return p; +} + +IDL_tree IDL_gentree_new_sibling (IDL_tree from, IDL_tree data) +{ + IDL_tree p = IDL_node_new (IDLN_GENTREE); + + __IDL_assign_up_node (p, data); + IDL_GENTREE (p).data = data; + IDL_GENTREE (p).hash_func = IDL_GENTREE (from).hash_func; + IDL_GENTREE (p).key_compare_func = IDL_GENTREE (from).key_compare_func; + IDL_GENTREE (p).siblings = IDL_GENTREE (from).siblings; + IDL_GENTREE (p).children = g_hash_table_new (IDL_GENTREE (from).hash_func, + IDL_GENTREE (from).key_compare_func); + + return p; +} + +IDL_tree IDL_integer_new (IDL_longlong_t value) +{ + IDL_tree p = IDL_node_new (IDLN_INTEGER); + + IDL_INTEGER (p).value = value; + + return p; +} + +IDL_tree IDL_string_new (char *value) +{ + IDL_tree p = IDL_node_new (IDLN_STRING); + + IDL_STRING (p).value = value; + + return p; +} + +IDL_tree IDL_wide_string_new (wchar_t *value) +{ + IDL_tree p = IDL_node_new (IDLN_WIDE_STRING); + + IDL_WIDE_STRING (p).value = value; + + return p; +} + +IDL_tree IDL_char_new (char *value) +{ + IDL_tree p = IDL_node_new (IDLN_CHAR); + + IDL_CHAR (p).value = value; + + return p; +} + +IDL_tree IDL_wide_char_new (wchar_t *value) +{ + IDL_tree p = IDL_node_new (IDLN_WIDE_CHAR); + + IDL_WIDE_CHAR (p).value = value; + + return p; +} + +IDL_tree IDL_fixed_new (char *value) +{ + IDL_tree p = IDL_node_new (IDLN_FIXED); + + IDL_FIXED (p).value = value; + + return p; +} + +IDL_tree IDL_float_new (double value) +{ + IDL_tree p = IDL_node_new (IDLN_FLOAT); + + IDL_FLOAT (p).value = value; + + return p; +} + +IDL_tree IDL_boolean_new (unsigned value) +{ + IDL_tree p = IDL_node_new (IDLN_BOOLEAN); + + IDL_BOOLEAN (p).value = value; + + return p; +} + +IDL_tree IDL_ident_new (char *str) +{ + IDL_tree p = IDL_node_new (IDLN_IDENT); + + IDL_IDENT (p).str = str; + + return p; +} + +IDL_tree IDL_member_new (IDL_tree type_spec, IDL_tree dcls) +{ + IDL_tree p = IDL_node_new (IDLN_MEMBER); + + __IDL_assign_up_node (p, type_spec); + __IDL_assign_up_node (p, dcls); + IDL_MEMBER (p).type_spec = type_spec; + IDL_MEMBER (p).dcls = dcls; + + return p; +} + +IDL_tree IDL_native_new (IDL_tree ident) +{ + IDL_tree p = IDL_node_new (IDLN_NATIVE); + + __IDL_assign_up_node (p, ident); + __IDL_assign_location (p, ident); + IDL_NATIVE (p).ident = ident; + + return p; +} + +IDL_tree IDL_type_dcl_new (IDL_tree type_spec, IDL_tree dcls) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_DCL); + + __IDL_assign_up_node (p, type_spec); + __IDL_assign_up_node (p, dcls); + __IDL_assign_location (p, IDL_LIST (dcls).data); + IDL_TYPE_DCL (p).type_spec = type_spec; + IDL_TYPE_DCL (p).dcls = dcls; + + return p; +} + +IDL_tree IDL_type_float_new (enum IDL_float_type f_type) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_FLOAT); + + IDL_TYPE_FLOAT (p).f_type = f_type; + + return p; +} + +IDL_tree IDL_type_fixed_new (IDL_tree positive_int_const, + IDL_tree integer_lit) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_FIXED); + + __IDL_assign_up_node (p, positive_int_const); + __IDL_assign_up_node (p, integer_lit); + IDL_TYPE_FIXED (p).positive_int_const = positive_int_const; + IDL_TYPE_FIXED (p).integer_lit = integer_lit; + + return p; +} + +IDL_tree IDL_type_integer_new (unsigned f_signed, enum IDL_integer_type f_type) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_INTEGER); + + IDL_TYPE_INTEGER (p).f_signed = f_signed; + IDL_TYPE_INTEGER (p).f_type = f_type; + + return p; +} + +IDL_tree IDL_type_char_new (void) +{ + return IDL_node_new (IDLN_TYPE_CHAR); +} + +IDL_tree IDL_type_wide_char_new (void) +{ + return IDL_node_new (IDLN_TYPE_WIDE_CHAR); +} + +IDL_tree IDL_type_boolean_new (void) +{ + return IDL_node_new (IDLN_TYPE_BOOLEAN); +} + +IDL_tree IDL_type_octet_new (void) +{ + return IDL_node_new (IDLN_TYPE_OCTET); +} + +IDL_tree IDL_type_any_new (void) +{ + return IDL_node_new (IDLN_TYPE_ANY); +} + +IDL_tree IDL_type_object_new (void) +{ + return IDL_node_new (IDLN_TYPE_OBJECT); +} + +IDL_tree IDL_type_typecode_new (void) +{ + return IDL_node_new (IDLN_TYPE_TYPECODE); +} + +IDL_tree IDL_type_string_new (IDL_tree positive_int_const) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_STRING); + + __IDL_assign_up_node (p, positive_int_const); + IDL_TYPE_STRING (p).positive_int_const = positive_int_const; + + return p; +} + +IDL_tree IDL_type_wide_string_new (IDL_tree positive_int_const) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_WIDE_STRING); + + __IDL_assign_up_node (p, positive_int_const); + IDL_TYPE_WIDE_STRING (p).positive_int_const = positive_int_const; + + return p; +} + +IDL_tree IDL_type_array_new (IDL_tree ident, + IDL_tree size_list) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_ARRAY); + + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, size_list); + __IDL_assign_location (p, ident); + IDL_TYPE_ARRAY (p).ident = ident; + IDL_TYPE_ARRAY (p).size_list = size_list; + + return p; +} + +IDL_tree IDL_type_sequence_new (IDL_tree simple_type_spec, + IDL_tree positive_int_const) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_SEQUENCE); + + __IDL_assign_up_node (p, simple_type_spec); + __IDL_assign_up_node (p, positive_int_const); + IDL_TYPE_SEQUENCE (p).simple_type_spec = simple_type_spec; + IDL_TYPE_SEQUENCE (p).positive_int_const = positive_int_const; + + return p; +} + +IDL_tree IDL_type_struct_new (IDL_tree ident, IDL_tree member_list) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_STRUCT); + + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, member_list); + __IDL_assign_location (p, ident); + IDL_TYPE_STRUCT (p).ident = ident; + IDL_TYPE_STRUCT (p).member_list = member_list; + + return p; +} + +IDL_tree IDL_type_union_new (IDL_tree ident, IDL_tree switch_type_spec, IDL_tree switch_body) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_UNION); + + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, switch_type_spec); + __IDL_assign_up_node (p, switch_body); + __IDL_assign_location (p, ident); + IDL_TYPE_UNION (p).ident = ident; + IDL_TYPE_UNION (p).switch_type_spec = switch_type_spec; + IDL_TYPE_UNION (p).switch_body = switch_body; + + return p; +} + +IDL_tree IDL_type_enum_new (IDL_tree ident, IDL_tree enumerator_list) +{ + IDL_tree p = IDL_node_new (IDLN_TYPE_ENUM); + + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, enumerator_list); + __IDL_assign_location (p, ident); + IDL_TYPE_ENUM (p).ident = ident; + IDL_TYPE_ENUM (p).enumerator_list = enumerator_list; + + return p; +} + +IDL_tree IDL_case_stmt_new (IDL_tree labels, IDL_tree element_spec) +{ + IDL_tree p = IDL_node_new (IDLN_CASE_STMT); + + __IDL_assign_up_node (p, labels); + __IDL_assign_up_node (p, element_spec); + IDL_CASE_STMT (p).labels = labels; + IDL_CASE_STMT (p).element_spec = element_spec; + + return p; +} + +IDL_tree IDL_interface_new (IDL_tree ident, IDL_tree inheritance_spec, IDL_tree body) +{ + IDL_tree p = IDL_node_new (IDLN_INTERFACE); + + /* Make sure the up node points to the interface */ + if (ident && IDL_NODE_UP (ident) && + IDL_NODE_TYPE (IDL_NODE_UP (ident)) != IDLN_INTERFACE) + IDL_NODE_UP (ident) = NULL; + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, inheritance_spec); + __IDL_assign_up_node (p, body); + IDL_INTERFACE (p).ident = ident; + IDL_INTERFACE (p).inheritance_spec = inheritance_spec; + IDL_INTERFACE (p).body = body; + + return p; +} + +IDL_tree IDL_module_new (IDL_tree ident, IDL_tree definition_list) +{ + IDL_tree p = IDL_node_new (IDLN_MODULE); + + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, definition_list); + __IDL_assign_location (p, ident); + IDL_MODULE (p).ident = ident; + IDL_MODULE (p).definition_list = definition_list; + + return p; +} + +IDL_tree IDL_binop_new (enum IDL_binop op, IDL_tree left, IDL_tree right) +{ + IDL_tree p = IDL_node_new (IDLN_BINOP); + + __IDL_assign_up_node (p, left); + __IDL_assign_up_node (p, right); + IDL_BINOP (p).op = op; + IDL_BINOP (p).left = left; + IDL_BINOP (p).right = right; + + return p; +} + +IDL_tree IDL_unaryop_new (enum IDL_unaryop op, IDL_tree operand) +{ + IDL_tree p = IDL_node_new (IDLN_UNARYOP); + + __IDL_assign_up_node (p, operand); + IDL_UNARYOP (p).op = op; + IDL_UNARYOP (p).operand = operand; + + return p; +} + +IDL_tree IDL_codefrag_new (char *desc, GSList *lines) +{ + IDL_tree p = IDL_node_new (IDLN_CODEFRAG); + + IDL_CODEFRAG (p).desc = desc; + IDL_CODEFRAG (p).lines = lines; + + return p; +} + +IDL_tree IDL_srcfile_new (char *filename, int seenCnt, gboolean isTop, gboolean wasInhibit) +{ + IDL_tree p = IDL_node_new (IDLN_SRCFILE); + IDL_SRCFILE (p).filename = filename; + IDL_SRCFILE (p).seenCnt = seenCnt; + IDL_SRCFILE (p).isTop = isTop; + IDL_SRCFILE (p).wasInhibit = wasInhibit; + + return p; +} + +IDL_tree IDL_const_dcl_new (IDL_tree const_type, IDL_tree ident, IDL_tree const_exp) +{ + IDL_tree p = IDL_node_new (IDLN_CONST_DCL); + + __IDL_assign_up_node (p, const_type); + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, const_exp); + __IDL_assign_location (p, ident); + IDL_CONST_DCL (p).const_type = const_type; + IDL_CONST_DCL (p).ident = ident; + IDL_CONST_DCL (p).const_exp = const_exp; + + return p; +} + +IDL_tree IDL_except_dcl_new (IDL_tree ident, IDL_tree members) +{ + IDL_tree p = IDL_node_new (IDLN_EXCEPT_DCL); + + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, members); + __IDL_assign_location (p, ident); + IDL_EXCEPT_DCL (p).ident = ident; + IDL_EXCEPT_DCL (p).members = members; + + return p; +} + +IDL_tree IDL_attr_dcl_new (unsigned f_readonly, + IDL_tree param_type_spec, + IDL_tree simple_declarations) +{ + IDL_tree p = IDL_node_new (IDLN_ATTR_DCL); + + __IDL_assign_up_node (p, param_type_spec); + __IDL_assign_up_node (p, simple_declarations); + __IDL_assign_location (p, IDL_LIST (simple_declarations).data); + IDL_ATTR_DCL (p).f_readonly = f_readonly; + IDL_ATTR_DCL (p).param_type_spec = param_type_spec; + IDL_ATTR_DCL (p).simple_declarations = simple_declarations; + + return p; +} + +IDL_tree IDL_op_dcl_new (unsigned f_oneway, + IDL_tree op_type_spec, + IDL_tree ident, + IDL_tree parameter_dcls, + IDL_tree raises_expr, + IDL_tree context_expr) +{ + IDL_tree p = IDL_node_new (IDLN_OP_DCL); + + __IDL_assign_up_node (p, op_type_spec); + __IDL_assign_up_node (p, ident); + __IDL_assign_up_node (p, parameter_dcls); + __IDL_assign_up_node (p, raises_expr); + __IDL_assign_up_node (p, context_expr); + __IDL_assign_location (p, ident); + IDL_OP_DCL (p).f_oneway = f_oneway; + IDL_OP_DCL (p).op_type_spec = op_type_spec; + IDL_OP_DCL (p).ident = ident; + IDL_OP_DCL (p).parameter_dcls = parameter_dcls; + IDL_OP_DCL (p).raises_expr = raises_expr; + IDL_OP_DCL (p).context_expr = context_expr; + + return p; +} + +IDL_tree IDL_param_dcl_new (enum IDL_param_attr attr, + IDL_tree param_type_spec, + IDL_tree simple_declarator) +{ + IDL_tree p = IDL_node_new (IDLN_PARAM_DCL); + + __IDL_assign_up_node (p, param_type_spec); + __IDL_assign_up_node (p, simple_declarator); + __IDL_assign_location (p, simple_declarator); + IDL_PARAM_DCL (p).attr = attr; + IDL_PARAM_DCL (p).param_type_spec = param_type_spec; + IDL_PARAM_DCL (p).simple_declarator = simple_declarator; + + return p; +} + +IDL_tree IDL_forward_dcl_new (IDL_tree ident) +{ + IDL_tree p = IDL_node_new (IDLN_FORWARD_DCL); + + __IDL_assign_up_node (p, ident); + __IDL_assign_location (p, ident); + IDL_FORWARD_DCL (p).ident = ident; + + return p; +} + +IDL_tree IDL_check_type_cast (const IDL_tree tree, IDL_tree_type type, + const char *file, int line, const char *function) +{ + if (__IDL_check_type_casts) { + if (tree == NULL) { + g_warning ("file %s: line %d: (%s) invalid type cast attempt," + " NULL tree to %s\n", + file, line, function, + IDL_tree_type_names[type]); + } + else if (IDL_NODE_TYPE (tree) != type) { + g_warning ("file %s: line %d: (%s) expected IDL tree type %s," + " but got %s\n", + file, line, function, + IDL_tree_type_names[type], IDL_NODE_TYPE_NAME (tree)); + + } + } + return tree; +} + +IDL_tree IDL_gentree_chain_sibling (IDL_tree from, IDL_tree data) +{ + IDL_tree p; + + if (from == NULL) + return NULL; + + p = IDL_gentree_new_sibling (from, data); + IDL_NODE_UP (p) = IDL_NODE_UP (from); + + return p; +} + +IDL_tree IDL_gentree_chain_child (IDL_tree from, IDL_tree data) +{ + IDL_tree p; + + if (from == NULL) + return NULL; + + p = IDL_gentree_new (IDL_GENTREE (from).hash_func, + IDL_GENTREE (from).key_compare_func, + data); + IDL_NODE_UP (p) = from; + + g_hash_table_insert (IDL_GENTREE (from).children, data, p); + + return p; +} + +IDL_tree IDL_get_parent_node (IDL_tree p, IDL_tree_type type, int *levels) +{ + int count = 0; + + if (p == NULL) + return NULL; + + if (type == IDLN_ANY) + return IDL_NODE_UP (p); + + while (p != NULL && IDL_NODE_TYPE (p) != type) { + + if (IDL_NODE_IS_SCOPED (p)) + ++count; + + p = IDL_NODE_UP (p); + } + + if (p != NULL) + if (levels != NULL) + *levels = count; + + return p; +} + +IDL_tree IDL_tree_get_scope (IDL_tree p) +{ + g_return_val_if_fail (p != NULL, NULL); + + if (IDL_NODE_TYPE (p) == IDLN_GENTREE) + return p; + + if (!IDL_NODE_IS_SCOPED (p)) { + g_warning ("Node type %s isn't scoped", IDL_NODE_TYPE_NAME (p)); + return NULL; + } + + switch (IDL_NODE_TYPE (p)) { + case IDLN_IDENT: + return IDL_IDENT_TO_NS (p); + + case IDLN_INTERFACE: + return IDL_IDENT_TO_NS (IDL_INTERFACE (p).ident); + + case IDLN_MODULE: + return IDL_IDENT_TO_NS (IDL_MODULE (p).ident); + + case IDLN_EXCEPT_DCL: + return IDL_IDENT_TO_NS (IDL_EXCEPT_DCL (p).ident); + + case IDLN_OP_DCL: + return IDL_IDENT_TO_NS (IDL_OP_DCL (p).ident); + + case IDLN_TYPE_ENUM: + return IDL_IDENT_TO_NS (IDL_TYPE_ENUM (p).ident); + + case IDLN_TYPE_STRUCT: + return IDL_IDENT_TO_NS (IDL_TYPE_STRUCT (p).ident); + + case IDLN_TYPE_UNION: + return IDL_IDENT_TO_NS (IDL_TYPE_UNION (p).ident); + + default: + return NULL; + } +} + +typedef struct { + IDL_tree_func pre_tree_func; + IDL_tree_func post_tree_func; + gpointer user_data; +} IDLTreeWalkRealData; + +static void IDL_tree_walk_real (IDL_tree_func_data *tfd, IDLTreeWalkRealData *data) +{ + IDL_tree_func_data down_tfd; + gboolean recurse = TRUE; + IDL_tree p, q; + + if (tfd->tree == NULL) + return; + + tfd->state->bottom = tfd; + tfd->step = 0; + tfd->data = NULL; + + if (data->pre_tree_func) + recurse = (*data->pre_tree_func) (tfd, data->user_data); + ++tfd->step; + + down_tfd.state = tfd->state; + down_tfd.up = tfd; + down_tfd.level = tfd->level + 1; + + p = tfd->tree; + + if (recurse) switch (IDL_NODE_TYPE (p)) { + case IDLN_INTEGER: + case IDLN_STRING: + case IDLN_CHAR: + case IDLN_FIXED: + case IDLN_FLOAT: + case IDLN_BOOLEAN: + case IDLN_IDENT: + case IDLN_TYPE_WIDE_CHAR: + case IDLN_TYPE_BOOLEAN: + case IDLN_TYPE_OCTET: + case IDLN_TYPE_ANY: + case IDLN_TYPE_OBJECT: + case IDLN_TYPE_TYPECODE: + case IDLN_TYPE_FLOAT: + case IDLN_TYPE_INTEGER: + case IDLN_TYPE_CHAR: + case IDLN_CODEFRAG: + case IDLN_SRCFILE: + break; + + case IDLN_LIST: + for (q = p; q; q = IDL_LIST (q).next) { + down_tfd.tree = IDL_LIST (q).data; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_GENTREE: + g_error ("IDLN_GENTREE walk not implemented!"); + break; + + case IDLN_MEMBER: + down_tfd.tree = IDL_MEMBER (p).type_spec; + IDL_tree_walk_real (&down_tfd, data); + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_MEMBER (p).dcls; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_NATIVE: + down_tfd.tree = IDL_NATIVE (p).ident; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_TYPE_DCL: + down_tfd.tree = IDL_TYPE_DCL (p).type_spec; + IDL_tree_walk_real (&down_tfd, data); + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_TYPE_DCL (p).dcls; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_CONST_DCL: + down_tfd.tree = IDL_CONST_DCL (p).const_type; + IDL_tree_walk_real (&down_tfd, data); + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_CONST_DCL (p).ident; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_CONST_DCL (p).const_exp; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_EXCEPT_DCL: + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_EXCEPT_DCL (p).ident; + IDL_tree_walk_real (&down_tfd, data); + } + down_tfd.tree = IDL_EXCEPT_DCL (p).members; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_ATTR_DCL: + down_tfd.tree = IDL_ATTR_DCL (p).param_type_spec; + IDL_tree_walk_real (&down_tfd, data); + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_ATTR_DCL (p).simple_declarations; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_OP_DCL: + down_tfd.tree = IDL_OP_DCL (p).op_type_spec; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_OP_DCL (p).ident; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_OP_DCL (p).parameter_dcls; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_OP_DCL (p).raises_expr; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_OP_DCL (p).context_expr; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_PARAM_DCL: + down_tfd.tree = IDL_PARAM_DCL (p).param_type_spec; + IDL_tree_walk_real (&down_tfd, data); + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_PARAM_DCL (p).simple_declarator; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_FORWARD_DCL: + down_tfd.tree = IDL_FORWARD_DCL (p).ident; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_TYPE_FIXED: + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_TYPE_FIXED (p).positive_int_const; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_TYPE_FIXED (p).integer_lit; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_TYPE_STRING: + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_TYPE_STRING (p).positive_int_const; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_TYPE_WIDE_STRING: + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_TYPE_WIDE_STRING (p).positive_int_const; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_TYPE_ENUM: + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_TYPE_ENUM (p).ident; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_TYPE_ENUM (p).enumerator_list; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_TYPE_SEQUENCE: + down_tfd.tree = IDL_TYPE_SEQUENCE (p).simple_type_spec; + IDL_tree_walk_real (&down_tfd, data); + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_TYPE_SEQUENCE (p).positive_int_const; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_TYPE_ARRAY: + down_tfd.tree = IDL_TYPE_ARRAY (p).ident; + IDL_tree_walk_real (&down_tfd, data); + if ( (tfd->state->flags & IDL_WalkF_TypespecOnly)==0 ) { + down_tfd.tree = IDL_TYPE_ARRAY (p).size_list; + IDL_tree_walk_real (&down_tfd, data); + } + break; + + case IDLN_TYPE_STRUCT: + down_tfd.tree = IDL_TYPE_STRUCT (p).ident; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_TYPE_STRUCT (p).member_list; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_TYPE_UNION: + down_tfd.tree = IDL_TYPE_UNION (p).ident; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_TYPE_UNION (p).switch_type_spec; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_TYPE_UNION (p).switch_body; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_CASE_STMT: + down_tfd.tree = IDL_CASE_STMT (p).labels; + IDL_tree_walk_real (&down_tfd, data); + /* FIXME */ + down_tfd.tree = IDL_CASE_STMT (p).element_spec; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_INTERFACE: + down_tfd.tree = IDL_INTERFACE (p).ident; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_INTERFACE (p).inheritance_spec; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_INTERFACE (p).body; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_MODULE: + down_tfd.tree = IDL_MODULE (p).ident; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_MODULE (p).definition_list; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_BINOP: + down_tfd.tree = IDL_BINOP (p).left; + IDL_tree_walk_real (&down_tfd, data); + down_tfd.tree = IDL_BINOP (p).right; + IDL_tree_walk_real (&down_tfd, data); + break; + + case IDLN_UNARYOP: + down_tfd.tree = IDL_UNARYOP (p).operand; + IDL_tree_walk_real (&down_tfd, data); + break; + + default: + g_warning ("IDL_tree_walk_real: unknown node type %s\n", + IDL_NODE_TYPE_NAME (p)); + break; + } + + if (data->post_tree_func) + (void) (*data->post_tree_func) (tfd, data->user_data); + + tfd->state->bottom = tfd->up; +} + +void IDL_tree_walk2 (IDL_tree p, IDL_tree_func_data *current, + glong flags, + IDL_tree_func pre_tree_func, IDL_tree_func post_tree_func, + gpointer user_data) +{ + IDLTreeWalkRealData data; + IDL_tree_func_state tfs; + IDL_tree_func_data tfd; + + g_return_if_fail (!(pre_tree_func == NULL && post_tree_func == NULL)); + + data.pre_tree_func = pre_tree_func; + data.post_tree_func = post_tree_func; + data.user_data = user_data; + + tfs.up = current ? current->state : NULL; + tfs.start = p; + tfs.flags = flags; + + tfd.level = 0; + if (current) { + tfd = *current; + tfd.level = ((tfd.level / 1000)+1) * 1000; + } + tfd.state = &tfs; + tfd.up = current; + tfd.tree = p; + + IDL_tree_walk_real (&tfd, &data); +} + +void IDL_tree_walk (IDL_tree p, IDL_tree_func_data *current, + IDL_tree_func pre_tree_func, IDL_tree_func post_tree_func, + gpointer user_data) +{ + IDL_tree_walk2 (p, current, /*flags*/0, + pre_tree_func, post_tree_func, user_data); +} + +void IDL_tree_walk_in_order (IDL_tree p, IDL_tree_func tree_func, gpointer user_data) +{ + IDL_tree_walk2 (p, NULL, /*flags*/0, tree_func, NULL, user_data); +} + +static void __IDL_tree_free (IDL_tree p); + +static int tree_free_but_this (IDL_tree data, IDL_tree p, IDL_tree this_one) +{ + if (p == this_one) + return TRUE; + + __IDL_tree_free (p); + + return TRUE; +} + +static void property_free (char *key, char *value) +{ + g_free (key); + g_free (value); +} + +void __IDL_free_properties (GHashTable *table) +{ + if (table) { + g_hash_table_foreach (table, (GHFunc) property_free, NULL); + g_hash_table_destroy (table); + } +} + +/* Free associated node data, regardless of refcounts */ +static void IDL_tree_free_real (IDL_tree p) +{ + GSList *slist; + + assert (p != NULL); + + switch (IDL_NODE_TYPE (p)) { + case IDLN_GENTREE: + g_hash_table_foreach (IDL_GENTREE (p).children, + (GHFunc) tree_free_but_this, NULL); + g_hash_table_destroy (IDL_GENTREE (p).children); + break; + + case IDLN_FIXED: + g_free (IDL_FIXED (p).value); + break; + + case IDLN_STRING: + g_free (IDL_STRING (p).value); + break; + + case IDLN_WIDE_STRING: + g_free (IDL_WIDE_STRING (p).value); + break; + + case IDLN_CHAR: + g_free (IDL_CHAR (p).value); + break; + + case IDLN_WIDE_CHAR: + g_free (IDL_WIDE_CHAR (p).value); + break; + + case IDLN_IDENT: + g_free (IDL_IDENT (p).str); + g_free (IDL_IDENT_REPO_ID (p)); + for (slist = IDL_IDENT (p).comments; slist; slist = slist->next) + g_free (slist->data); + g_slist_free (IDL_IDENT (p).comments); + break; + + case IDLN_NATIVE: + g_free (IDL_NATIVE (p).user_type); + break; + + case IDLN_INTERFACE: + break; + + case IDLN_CODEFRAG: + g_free (IDL_CODEFRAG (p).desc); + for (slist = IDL_CODEFRAG (p).lines; slist; slist = slist->next) + g_free (slist->data); + g_slist_free (IDL_CODEFRAG (p).lines); + break; + + default: + break; + } + + __IDL_free_properties (IDL_NODE_PROPERTIES (p)); + + g_free (p); +} + +/* Free node taking into account refcounts */ +static void __IDL_tree_free (IDL_tree p) +{ + if (p == NULL) + return; + + if (--IDL_NODE_REFS (p) <= 0) + IDL_tree_free_real (p); +} + +/* Free a set of references of an entire tree */ +void IDL_tree_free (IDL_tree p) +{ + IDL_tree q; + + if (p == NULL) + return; + + switch (IDL_NODE_TYPE (p)) { + case IDLN_INTEGER: + case IDLN_FLOAT: + case IDLN_BOOLEAN: + case IDLN_TYPE_FLOAT: + case IDLN_TYPE_INTEGER: + case IDLN_TYPE_CHAR: + case IDLN_TYPE_WIDE_CHAR: + case IDLN_TYPE_BOOLEAN: + case IDLN_TYPE_OCTET: + case IDLN_TYPE_ANY: + case IDLN_TYPE_OBJECT: + case IDLN_TYPE_TYPECODE: + case IDLN_FIXED: + case IDLN_STRING: + case IDLN_WIDE_STRING: + case IDLN_CHAR: + case IDLN_WIDE_CHAR: + case IDLN_IDENT: + case IDLN_CODEFRAG: + case IDLN_SRCFILE: + __IDL_tree_free (p); + break; + + case IDLN_LIST: + while (p) { + IDL_tree_free (IDL_LIST (p).data); + q = IDL_LIST (p).next; + __IDL_tree_free (p); + p = q; + } + break; + + case IDLN_GENTREE: + g_hash_table_foreach (IDL_GENTREE (p).siblings, + (GHFunc) tree_free_but_this, p); + g_hash_table_destroy (IDL_GENTREE (p).siblings); + __IDL_tree_free (p); + break; + + case IDLN_MEMBER: + IDL_tree_free (IDL_MEMBER (p).type_spec); + IDL_tree_free (IDL_MEMBER (p).dcls); + __IDL_tree_free (p); + break; + + case IDLN_NATIVE: + IDL_tree_free (IDL_NATIVE (p).ident); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_ENUM: + IDL_tree_free (IDL_TYPE_ENUM (p).ident); + IDL_tree_free (IDL_TYPE_ENUM (p).enumerator_list); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_SEQUENCE: + IDL_tree_free (IDL_TYPE_SEQUENCE (p).simple_type_spec); + IDL_tree_free (IDL_TYPE_SEQUENCE (p).positive_int_const); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_ARRAY: + IDL_tree_free (IDL_TYPE_ARRAY (p).ident); + IDL_tree_free (IDL_TYPE_ARRAY (p).size_list); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_STRUCT: + IDL_tree_free (IDL_TYPE_STRUCT (p).ident); + IDL_tree_free (IDL_TYPE_STRUCT (p).member_list); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_UNION: + IDL_tree_free (IDL_TYPE_UNION (p).ident); + IDL_tree_free (IDL_TYPE_UNION (p).switch_type_spec); + IDL_tree_free (IDL_TYPE_UNION (p).switch_body); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_DCL: + IDL_tree_free (IDL_TYPE_DCL (p).type_spec); + IDL_tree_free (IDL_TYPE_DCL (p).dcls); + __IDL_tree_free (p); + break; + + case IDLN_CONST_DCL: + IDL_tree_free (IDL_CONST_DCL (p).const_type); + IDL_tree_free (IDL_CONST_DCL (p).ident); + IDL_tree_free (IDL_CONST_DCL (p).const_exp); + __IDL_tree_free (p); + break; + + case IDLN_EXCEPT_DCL: + IDL_tree_free (IDL_EXCEPT_DCL (p).ident); + IDL_tree_free (IDL_EXCEPT_DCL (p).members); + __IDL_tree_free (p); + break; + + case IDLN_ATTR_DCL: + IDL_tree_free (IDL_ATTR_DCL (p).param_type_spec); + IDL_tree_free (IDL_ATTR_DCL (p).simple_declarations); + __IDL_tree_free (p); + break; + + case IDLN_OP_DCL: + IDL_tree_free (IDL_OP_DCL (p).op_type_spec); + IDL_tree_free (IDL_OP_DCL (p).ident); + IDL_tree_free (IDL_OP_DCL (p).parameter_dcls); + IDL_tree_free (IDL_OP_DCL (p).raises_expr); + IDL_tree_free (IDL_OP_DCL (p).context_expr); + __IDL_tree_free (p); + break; + + case IDLN_PARAM_DCL: + IDL_tree_free (IDL_PARAM_DCL (p).param_type_spec); + IDL_tree_free (IDL_PARAM_DCL (p).simple_declarator); + __IDL_tree_free (p); + break; + + case IDLN_FORWARD_DCL: + IDL_tree_free (IDL_FORWARD_DCL (p).ident); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_STRING: + IDL_tree_free (IDL_TYPE_STRING (p).positive_int_const); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_WIDE_STRING: + IDL_tree_free (IDL_TYPE_WIDE_STRING (p).positive_int_const); + __IDL_tree_free (p); + break; + + case IDLN_TYPE_FIXED: + IDL_tree_free (IDL_TYPE_FIXED (p).positive_int_const); + IDL_tree_free (IDL_TYPE_FIXED (p).integer_lit); + __IDL_tree_free (p); + break; + + case IDLN_CASE_STMT: + IDL_tree_free (IDL_CASE_STMT (p).labels); + IDL_tree_free (IDL_CASE_STMT (p).element_spec); + __IDL_tree_free (p); + break; + + case IDLN_INTERFACE: + IDL_tree_free (IDL_INTERFACE (p).ident); + IDL_tree_free (IDL_INTERFACE (p).inheritance_spec); + IDL_tree_free (IDL_INTERFACE (p).body); + __IDL_tree_free (p); + break; + + case IDLN_MODULE: + IDL_tree_free (IDL_MODULE (p).ident); + IDL_tree_free (IDL_MODULE (p).definition_list); + __IDL_tree_free (p); + break; + + case IDLN_BINOP: + IDL_tree_free (IDL_BINOP (p).left); + IDL_tree_free (IDL_BINOP (p).right); + __IDL_tree_free (p); + break; + + case IDLN_UNARYOP: + IDL_tree_free (IDL_UNARYOP (p).operand); + __IDL_tree_free (p); + break; + + default: + g_warning ("Free unknown node: %d\n", IDL_NODE_TYPE (p)); + break; + } +} + +#define C_ESC(a,b) case a: *p++ = b; ++s; break +gchar *IDL_do_escapes (const char *s) +{ + char *p, *q; + + if (!s) + return NULL; + + p = q = g_malloc (strlen (s) + 1); + + while (*s) { + if (*s != '\\') { + *p++ = *s++; + continue; + } + ++s; + if (*s == 'x') { + char hex[3]; + int n; + hex[0] = 0; + ++s; + sscanf (s, "%2[0-9a-fA-F]", hex); + s += strlen (hex); + sscanf (hex, "%x", &n); + *p++ = n; + continue; + } + if (*s >= '0' && *s <= '7') { + char oct[4]; + int n; + oct[0] = 0; + sscanf (s, "%3[0-7]", oct); + s += strlen (oct); + sscanf (oct, "%o", &n); + *p++ = n; + continue; + } + switch (*s) { + C_ESC ('n','\n'); + C_ESC ('t','\t'); + C_ESC ('v','\v'); + C_ESC ('b','\b'); + C_ESC ('r','\r'); + C_ESC ('f','\f'); + C_ESC ('a','\a'); + C_ESC ('\\','\\'); + C_ESC ('?','?'); + C_ESC ('\'','\''); + C_ESC ('"','"'); + } + } + *p = 0; + + return q; +} + +int IDL_list_length (IDL_tree list) +{ + IDL_tree curitem; + int length; + + for (curitem = list, length = 0; curitem; + curitem = IDL_LIST (curitem).next) + length++; + + return length; +} + +IDL_tree IDL_list_nth (IDL_tree list, int n) +{ + IDL_tree curitem; + int i; + + for (curitem = list, i = 0; i < n && curitem; + curitem = IDL_LIST (curitem).next, i++) ; + + return curitem; +} + +const char *IDL_tree_property_get (IDL_tree tree, const char *key) +{ + g_return_val_if_fail (tree != NULL, NULL); + g_return_val_if_fail (key != NULL, NULL); + + if (!IDL_NODE_PROPERTIES (tree)) + return NULL; + + return g_hash_table_lookup (IDL_NODE_PROPERTIES (tree), key); +} + +void IDL_tree_property_set (IDL_tree tree, const char *key, const char *value) +{ + g_return_if_fail (tree != NULL); + g_return_if_fail (key != NULL); + + if (!IDL_NODE_PROPERTIES (tree)) + IDL_NODE_PROPERTIES (tree) = g_hash_table_new ( + IDL_strcase_hash, IDL_strcase_equal); + else if (IDL_tree_property_get (tree, key)) + IDL_tree_property_remove (tree, key); + + g_hash_table_insert (IDL_NODE_PROPERTIES (tree), g_strdup (key), g_strdup (value)); +} + +gboolean IDL_tree_property_remove (IDL_tree tree, const char *key) +{ + gboolean removed = FALSE; + char *val; + + g_return_val_if_fail (tree != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + if (!IDL_NODE_PROPERTIES (tree)) + return FALSE; + + if ((val = g_hash_table_lookup (IDL_NODE_PROPERTIES (tree), key))) { + g_hash_table_remove (IDL_NODE_PROPERTIES (tree), key); + g_free (val); + removed = TRUE; + } + + return removed; +} + +static void property_set (char *key, char *value, IDL_tree tree) +{ + IDL_tree_property_set (tree, key, value); +} + +void IDL_tree_properties_copy (IDL_tree from_tree, IDL_tree to_tree) +{ + g_return_if_fail (from_tree != NULL); + g_return_if_fail (to_tree != NULL); + + if (IDL_NODE_PROPERTIES (from_tree)) + g_hash_table_foreach (IDL_NODE_PROPERTIES (from_tree), + (GHFunc) property_set, to_tree); +} + +typedef struct { + IDL_tree *root; + GHashTable *removed_nodes; +} RemoveListNodeData; + +static int remove_list_node (IDL_tree p, IDL_tree *list_head, RemoveListNodeData *data) +{ + assert (p != NULL); + assert (IDL_NODE_TYPE (p) == IDLN_LIST); + + if (list_head) + *list_head = IDL_list_remove (*list_head, p); + else + *data->root = IDL_list_remove (*data->root, p); + + if (data->removed_nodes) { + if (!g_hash_table_lookup_extended (data->removed_nodes, p, NULL, NULL)) + g_hash_table_insert (data->removed_nodes, p, p); + /* + We shouldn't need this since we have removed it from the tree, + but we might need it for multiple declspec (inhibits) in the same + subtree. + IDL_tree_walk_in_order (p, (IDL_tree_func) inc_node_ref, NULL); + */ + } else + IDL_tree_free (p); + + return TRUE; +} + +/* Forward Declaration Resolution */ +static int load_forward_dcls (IDL_tree_func_data *tfd, GHashTable *table) +{ + if (IDL_NODE_TYPE (tfd->tree) == IDLN_FORWARD_DCL) { + char *s = IDL_ns_ident_to_qstring (IDL_FORWARD_DCL (tfd->tree).ident, "::", 0); + + if (!g_hash_table_lookup_extended (table, s, NULL, NULL)) + g_hash_table_insert (table, s, tfd->tree); + else + g_free (s); + } + + return TRUE; +} + +static int resolve_forward_dcls (IDL_tree_func_data *tfd, GHashTable *table) +{ + if (IDL_NODE_TYPE (tfd->tree) == IDLN_INTERFACE) { + char *orig, *s = IDL_ns_ident_to_qstring (IDL_INTERFACE (tfd->tree).ident, "::", 0); + + if (g_hash_table_lookup_extended (table, s, (gpointer)&orig, NULL)) { + g_hash_table_remove (table, orig); + g_free (orig); + } + g_free (s); + } + + return TRUE; +} + +static int print_unresolved_forward_dcls (char *s, IDL_tree p) +{ + if (__IDL_flags & IDLF_PEDANTIC) + IDL_tree_error (p, "Unresolved forward declaration `%s'", s); + else + IDL_tree_warning (p, + IDL_WARNING1, "Unresolved forward declaration `%s'", s); + g_free (s); + + return TRUE; +} + +void IDL_tree_process_forward_dcls (IDL_tree *p, IDL_ns ns) +{ + GHashTable *table = g_hash_table_new (IDL_strcase_hash, IDL_strcase_equal); + gint total, resolved; + + IDL_tree_walk_in_order (*p, (IDL_tree_func) load_forward_dcls, table); + total = g_hash_table_size (table); + IDL_tree_walk_in_order (*p, (IDL_tree_func) resolve_forward_dcls, table); + resolved = total - g_hash_table_size (table); + g_hash_table_foreach (table, (GHFunc) print_unresolved_forward_dcls, NULL); + g_hash_table_destroy (table); + if (__IDL_flags & IDLF_VERBOSE) + g_message ("Forward declarations resolved: %d of %d", resolved, total); +} + +/* Inhibit Creation Removal */ +static int load_inhibits (IDL_tree_func_data *tfd, GHashTable *table) +{ + IDL_tree p, q, *list_head; + + p = tfd->tree; + + if (p != NULL && + IDL_NODE_UP (p) && + IDL_NODE_TYPE (IDL_NODE_UP (p)) == IDLN_LIST && + IDL_NODE_DECLSPEC (p) & IDLF_DECLSPEC_INHIBIT && + !g_hash_table_lookup_extended (table, IDL_NODE_UP (p), NULL, NULL)) { + list_head = NULL; + q = IDL_NODE_UP (IDL_NODE_UP (p)); + if (q) { + switch (IDL_NODE_TYPE (q)) { + case IDLN_MODULE: + list_head = &IDL_MODULE (q).definition_list; + break; + + case IDLN_INTERFACE: + list_head = &IDL_INTERFACE (q).body; + break; + + default: + g_warning ("Unhandled node %s in load_inhibits", + IDL_NODE_TYPE_NAME (q)); + break; + } + } + g_hash_table_insert (table, IDL_NODE_UP (p), list_head); + + return FALSE; + } + + return TRUE; +} + +void IDL_tree_remove_inhibits (IDL_tree *tree, IDL_ns ns) +{ + RemoveListNodeData data; + GHashTable *table = g_hash_table_new (g_direct_hash, g_direct_equal); + gint removed; + + g_return_if_fail (tree != NULL); + g_return_if_fail (ns != NULL); + + IDL_tree_walk_in_order (*tree, (IDL_tree_func) load_inhibits, table); + removed = g_hash_table_size (table); + data.root = tree; + data.removed_nodes = IDL_NS (ns).inhibits; + g_hash_table_foreach (table, (GHFunc) remove_list_node, &data); + g_hash_table_destroy (table); + if (__IDL_flags & IDLF_VERBOSE) + g_message ("Inhibited nodes removed: %d", removed); +} + +/* Multi-Pass Empty Module Removal */ +static int load_empty_modules (IDL_tree_func_data *tfd, GHashTable *table) +{ + IDL_tree p, q, *list_head; + + p = tfd->tree; + + if (IDL_NODE_TYPE (p) == IDLN_MODULE && + IDL_MODULE (p).definition_list == NULL && + IDL_NODE_UP (p) && + IDL_NODE_TYPE (IDL_NODE_UP (p)) == IDLN_LIST && + !g_hash_table_lookup_extended (table, IDL_NODE_UP (p), NULL, NULL)) { + + list_head = NULL; + q = IDL_NODE_UP (IDL_NODE_UP (p)); + if (q) { + assert (IDL_NODE_TYPE (q) == IDLN_MODULE); + list_head = &IDL_MODULE (q).definition_list; + } + g_hash_table_insert (table, IDL_NODE_UP (p), list_head); + } + + return TRUE; +} + +void IDL_tree_remove_empty_modules (IDL_tree *p, IDL_ns ns) +{ + RemoveListNodeData data; + gboolean done = FALSE; + gint removed = 0; + + data.root = p; + data.removed_nodes = NULL; + + while (!done) { + GHashTable *table = g_hash_table_new (g_direct_hash, g_direct_equal); + IDL_tree_walk_in_order (*p, (IDL_tree_func) load_empty_modules, table); + removed += g_hash_table_size (table); + done = g_hash_table_size (table) == 0; + g_hash_table_foreach (table, (GHFunc) remove_list_node, &data); + g_hash_table_destroy (table); + } + if (__IDL_flags & IDLF_VERBOSE) + g_message ("Empty modules removed: %d", removed); +} + +/* + * IDL_tree to IDL backend + */ + +#define DELIM_COMMA ", " +#define DELIM_ARRAY "][" +#define DELIM_SPACE " " + +#define indent() ++data->ilev +#define unindent() --data->ilev +#define doindent() do { \ + int i; \ + if (!(data->flags & IDLF_OUTPUT_NO_NEWLINES)) \ + for (i = 0; i < data->ilev; ++i) { \ + switch (data->mode) { \ + case OUTPUT_FILE: \ + fputc ('\t', data->u.o); \ + break; \ + \ + case OUTPUT_STRING: \ + g_string_append_c (data->u.s, '\t'); \ + break; \ + \ + default: \ + break; \ + } \ + } \ + else if (data->ilev > 0) \ + dataf (data, DELIM_SPACE); \ +} while (0) +#define nl() do { \ + if (!(data->flags & IDLF_OUTPUT_NO_NEWLINES)) { \ + switch (data->mode) { \ + case OUTPUT_FILE: \ + fputc ('\n', data->u.o); \ + break; \ + \ + case OUTPUT_STRING: \ + g_string_append_c (data->u.s, '\n'); \ + break; \ + \ + default: \ + break; \ + } \ + } \ +} while (0) +#define save_flag(flagbit,val) do { \ + tfd->data = GUINT_TO_POINTER ( \ + GPOINTER_TO_UINT (tfd->data) | \ + (data->flagbit ? (1U << flagbit##bit) : 0)); \ + data->flagbit = val; \ +} while (0) +#define restore_flag(flagbit) do { \ + data->flagbit = (GPOINTER_TO_UINT ( \ + tfd->data) >> flagbit##bit) & 1U; \ +} while (0) + +typedef struct { + IDL_ns ns; + enum { + OUTPUT_FILE, + OUTPUT_STRING + } mode; + union { + FILE *o; + GString *s; + } u; + int ilev; + unsigned long flags; + +#define identsbit 0 + guint idents : 1; + +#define literalsbit 1 + guint literals : 1; + +#define inline_propsbit 2 + guint inline_props : 1; + +#define su_defbit 3 + guint su_def : 1; +} IDL_output_data; + +static void dataf (IDL_output_data *data, const char *fmt, ...) +G_GNUC_PRINTF (2, 3); + +static void idataf (IDL_output_data *data, const char *fmt, ...) +G_GNUC_PRINTF (2, 3); + +static void dataf (IDL_output_data *data, const char *fmt, ...) +{ + gchar *buffer; + va_list args; + + va_start (args, fmt); + switch (data->mode) { + case OUTPUT_FILE: + vfprintf (data->u.o, fmt, args); + break; + + case OUTPUT_STRING: + buffer = g_strdup_vprintf (fmt, args); + g_string_append (data->u.s, buffer); + g_free (buffer); + break; + + default: + break; + } + va_end (args); +} + +static void idataf (IDL_output_data *data, const char *fmt, ...) +{ + gchar *buffer; + va_list args; + + va_start (args, fmt); + doindent (); + switch (data->mode) { + case OUTPUT_FILE: + vfprintf (data->u.o, fmt, args); + break; + + case OUTPUT_STRING: + buffer = g_strdup_vprintf (fmt, args); + g_string_append (data->u.s, buffer); + g_free (buffer); + break; + + default: + break; + } + va_end (args); +} + +static gboolean IDL_emit_node_pre_func (IDL_tree_func_data *tfd, IDL_output_data *data); +static gboolean IDL_emit_node_post_func (IDL_tree_func_data *tfd, IDL_output_data *data); + +typedef struct { + IDL_tree_func pre_func; + IDL_tree_func post_func; + IDL_tree_type type, type2; + gboolean limit; + IDL_output_data *data; + const char *delim; + gboolean hit; +} IDL_output_delim_data; + +static gboolean IDL_output_delim_match (IDL_tree_func_data *tfd, IDL_output_delim_data *delim) +{ + return delim->type == IDLN_ANY || + IDL_NODE_TYPE (tfd->tree) == delim->type || + IDL_NODE_TYPE (tfd->tree) == delim->type2; +} + +static gboolean IDL_output_delim_pre (IDL_tree_func_data *tfd, IDL_output_delim_data *delim) +{ + if (IDL_output_delim_match (tfd, delim)) { + if (delim->hit) + dataf (delim->data, "%s", delim->delim); + else + delim->hit = TRUE; + return delim->pre_func + ? (*delim->pre_func) (tfd, delim->data) + : TRUE; + } else { + if (!delim->limit) + return delim->pre_func + ? (*delim->pre_func) (tfd, delim->data) + : TRUE; + else + return TRUE; + } +} + +static gboolean IDL_output_delim_post (IDL_tree_func_data *tfd, IDL_output_delim_data *delim) +{ + if (delim->limit && !IDL_output_delim_match (tfd, delim)) + return TRUE; + + return delim->post_func + ? (*delim->post_func) (tfd, delim->data) + : TRUE; +} + +static void IDL_output_delim (IDL_tree p, IDL_tree_func_data *current, + IDL_output_data *data, + IDL_tree_func pre_func, IDL_tree_func post_func, + IDL_tree_type type, IDL_tree_type type2, + gboolean limit, + const char *str) +{ + IDL_output_delim_data delim; + + delim.pre_func = pre_func; + delim.post_func = post_func; + delim.type = type; + delim.type2 = type2; + delim.limit = limit; + delim.data = data; + delim.hit = FALSE; + delim.delim = str; + + IDL_tree_walk2 (p, current, /*flags*/0, + (IDL_tree_func) IDL_output_delim_pre, + (IDL_tree_func) IDL_output_delim_post, + &delim); +} + +typedef struct { + IDL_output_data *data; + gboolean hit; +} IDL_property_emit_data; + +static void IDL_emit_IDL_property (const char *key, const char *value, + IDL_property_emit_data *emit_data) +{ + IDL_output_data *data = emit_data->data; + + if (!emit_data->hit) + emit_data->hit = TRUE; + else + dataf (emit_data->data, DELIM_COMMA); + if (!data->inline_props) { + nl (); + doindent (); + } + if (value && *value) + dataf (emit_data->data, "%s%s(%s)", + key, DELIM_SPACE, value); + else + dataf (emit_data->data, "%s", key); +} + +static gboolean IDL_emit_IDL_properties (IDL_tree p, IDL_output_data *data) +{ + IDL_property_emit_data emit_data; + + if (IDL_NODE_PROPERTIES (p) && + data->flags & IDLF_OUTPUT_PROPERTIES && + g_hash_table_size (IDL_NODE_PROPERTIES (p)) > 0) { + emit_data.data = data; + emit_data.hit = FALSE; + if (!data->inline_props) + idataf (data, "[" DELIM_SPACE); + else + dataf (data, "["); + indent (); + g_hash_table_foreach (IDL_NODE_PROPERTIES (p), + (GHFunc) IDL_emit_IDL_property, + &emit_data); + unindent (); + if (!data->inline_props) { + nl (); + doindent (); + } + dataf (data, "]"); + if (!data->inline_props) + nl (); + else + dataf (data, DELIM_SPACE); + } + + return TRUE; +} + +static gboolean IDL_emit_IDL_sc (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + dataf (data, ";"); nl (); + + return TRUE; +} + +static gboolean IDL_emit_IDL_indent (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + doindent (); + + return TRUE; +} + +static gboolean IDL_emit_IDL_curly_brace_open (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + dataf (data, "{"); nl (); indent (); + + return TRUE; +} + +static gboolean IDL_emit_IDL_curly_brace_close (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + unindent (); idataf (data, "}"); + + return TRUE; +} + +static gboolean IDL_emit_IDL_curly_brace_close_sc (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_emit_IDL_curly_brace_close (tfd, data); + IDL_emit_IDL_sc (tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_ident_real (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_tree_func_data *up_path; + IDL_tree up_real, scope; + char *s; + int levels; + + up_path = tfd; + up_real = tfd->tree; + while (up_path && up_real) { + if (IDL_NODE_TYPE (up_path->tree) != IDL_NODE_TYPE (up_real)) + break; + up_path = up_path->up; + up_real = IDL_NODE_UP (up_real); + } + + assert (IDL_NODE_TYPE (tfd->tree) == IDLN_IDENT); + + if (!up_real || data->flags & IDLF_OUTPUT_NO_QUALIFY_IDENTS) { + /* TODO: If the IDENT is also a keyword, escape it by + prepending an underscore. */ + dataf (data, "%s", IDL_IDENT (tfd->tree).str); + } else { + if (up_path == NULL) { + levels = 0; + } else { + /* Determine minimal required levels of scoping */ + scope = up_path->tree ? up_path->tree : up_real; + levels = IDL_ns_scope_levels_from_here (data->ns, tfd->tree, scope); + } + s = IDL_ns_ident_to_qstring (IDL_IDENT_TO_NS (tfd->tree), "::", levels); + dataf (data, "%s", s); + g_free (s); + } + + return TRUE; +} + +static gboolean IDL_emit_IDL_ident_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + if (data->idents) + IDL_emit_IDL_ident_real (tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_ident_force_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_emit_IDL_ident_real (tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_ident (IDL_tree ident, IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_tree_walk2 (ident, tfd, /*flags*/0, + (IDL_tree_func) IDL_emit_IDL_ident_real, NULL, + data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_literal (IDL_tree p, IDL_output_data *data) +{ + switch (IDL_NODE_TYPE (p)) { + case IDLN_FLOAT: + dataf (data, "%f", IDL_FLOAT (p).value); + break; + + case IDLN_INTEGER: + /* FIXME: sign */ + dataf (data, "%" IDL_LL "d", IDL_INTEGER (p).value); + break; + + case IDLN_FIXED: + dataf (data, "%s", IDL_FIXED (p).value); + break; + + case IDLN_CHAR: + dataf (data, "'%s'", IDL_CHAR (p).value); + break; + + case IDLN_WIDE_CHAR: +/* dataf (data, "'%s'", IDL_WIDE_CHAR (p).value); */ + g_warning ("IDL_emit_IDL_literal: %s is currently unhandled", + "Wide character output"); + break; + + case IDLN_BOOLEAN: + dataf (data, "%s", IDL_BOOLEAN (p).value ? "TRUE" : "FALSE"); + break; + + case IDLN_STRING: + dataf (data, "\"%s\"", IDL_STRING (p).value); + break; + + case IDLN_WIDE_STRING: +/* dataf (data, "\"%s\"", IDL_STRING (p).value); */ + g_warning ("IDL_emit_IDL_literal: %s is currently unhandled", + "Wide string output"); + break; + + default: + g_warning ("Unhandled literal: %s", IDL_NODE_TYPE_NAME (p)); + break; + } + + return TRUE; +} + +static gboolean IDL_emit_IDL_literal_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + if (data->literals) + IDL_emit_IDL_literal (tfd->tree, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_literal_force_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_emit_IDL_literal (tfd->tree, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_type_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_tree p, q; + + p = tfd->tree; + + switch (IDL_NODE_TYPE (p)) { + case IDLN_IDENT: + IDL_emit_IDL_ident (p, tfd, data); + break; + + case IDLN_TYPE_CHAR: + dataf (data, "char"); + break; + + case IDLN_TYPE_WIDE_CHAR: + dataf (data, "wchar"); + break; + + case IDLN_TYPE_BOOLEAN: + dataf (data, "boolean"); + break; + + case IDLN_TYPE_OCTET: + dataf (data, "octet"); + break; + + case IDLN_TYPE_ANY: + dataf (data, "any"); + break; + + case IDLN_TYPE_OBJECT: + dataf (data, "Object"); + break; + + case IDLN_TYPE_TYPECODE: + dataf (data, "TypeCode"); + break; + + case IDLN_TYPE_FLOAT: + switch (IDL_TYPE_FLOAT (p).f_type) { + case IDL_FLOAT_TYPE_FLOAT: dataf (data, "float"); break; + case IDL_FLOAT_TYPE_DOUBLE: dataf (data, "double"); break; + case IDL_FLOAT_TYPE_LONGDOUBLE: dataf (data, "long" DELIM_SPACE "double"); break; + } + break; + + case IDLN_TYPE_FIXED: + dataf (data, "fixed<"); + IDL_emit_IDL_literal (IDL_TYPE_FIXED (p).positive_int_const, data); + dataf (data, DELIM_COMMA); + IDL_emit_IDL_literal (IDL_TYPE_FIXED (p).integer_lit, data); + dataf (data, ">"); + return FALSE; + + case IDLN_TYPE_INTEGER: + if (!IDL_TYPE_INTEGER (p).f_signed) + dataf (data, "unsigned" DELIM_SPACE); + switch (IDL_TYPE_INTEGER (p).f_type) { + case IDL_INTEGER_TYPE_SHORT: dataf (data, "short"); break; + case IDL_INTEGER_TYPE_LONG: dataf (data, "long"); break; + case IDL_INTEGER_TYPE_LONGLONG: dataf (data, "long" DELIM_SPACE "long"); break; + } + break; + + case IDLN_TYPE_STRING: + case IDLN_TYPE_WIDE_STRING: + if (IDL_NODE_TYPE (p) == IDLN_TYPE_STRING) { + dataf (data, "string"); + q = IDL_TYPE_STRING (p).positive_int_const; + } else { + dataf (data, "wstring"); + q = IDL_TYPE_WIDE_STRING (p).positive_int_const; + } + if (q) { + dataf (data, "<"); + if (IDL_NODE_TYPE (p) == IDLN_TYPE_STRING) + IDL_emit_IDL_literal ( + IDL_TYPE_STRING (p).positive_int_const, data); + else + IDL_emit_IDL_literal ( + IDL_TYPE_WIDE_STRING (p).positive_int_const, data); + dataf (data, ">"); + } + return FALSE; + + case IDLN_TYPE_ENUM: + IDL_emit_IDL_indent (tfd, data); + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_TYPE_ENUM (tfd->tree).ident, data); + dataf (data, "enum" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_TYPE_ENUM (p).ident, tfd, data); + dataf (data, DELIM_SPACE "{" DELIM_SPACE); + IDL_output_delim (IDL_TYPE_ENUM (p).enumerator_list, tfd, data, + (IDL_tree_func) IDL_emit_IDL_ident_force_pre, NULL, + IDLN_IDENT, IDLN_NONE, TRUE, DELIM_COMMA); + dataf (data, DELIM_SPACE "};"); nl (); + return FALSE; + + case IDLN_TYPE_ARRAY: + IDL_emit_IDL_ident (IDL_TYPE_ARRAY (p).ident, tfd, data); + dataf (data, "["); + IDL_output_delim (IDL_TYPE_ARRAY (p).size_list, tfd, data, + (IDL_tree_func) IDL_emit_IDL_literal_force_pre, NULL, + IDLN_INTEGER, IDLN_NONE, TRUE, DELIM_ARRAY); + dataf (data, "]"); + return FALSE; + + case IDLN_TYPE_SEQUENCE: + dataf (data, "sequence<"); + save_flag (idents, TRUE); + IDL_tree_walk2 (IDL_TYPE_SEQUENCE (tfd->tree).simple_type_spec, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (idents); + if (IDL_TYPE_SEQUENCE (tfd->tree).positive_int_const) { + dataf (data, DELIM_COMMA); + IDL_emit_IDL_literal ( + IDL_TYPE_SEQUENCE (tfd->tree).positive_int_const, data); + } + dataf (data, ">"); + return FALSE; + + case IDLN_TYPE_STRUCT: + if (!data->su_def) + doindent (); + save_flag (su_def, TRUE); + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_TYPE_STRUCT (tfd->tree).ident, data); + dataf (data, "struct" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_TYPE_STRUCT (p).ident, tfd, data); + dataf (data, DELIM_SPACE); + IDL_emit_IDL_curly_brace_open (tfd, data); + IDL_tree_walk2 (IDL_TYPE_STRUCT (p).member_list, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (su_def); + if (data->su_def) + IDL_emit_IDL_curly_brace_close (tfd, data); + else + IDL_emit_IDL_curly_brace_close_sc (tfd, data); + return FALSE; + + case IDLN_TYPE_UNION: + if (!data->su_def) + doindent (); + save_flag (su_def, TRUE); + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_TYPE_UNION (tfd->tree).ident, data); + dataf (data, "union" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_TYPE_UNION (p).ident, tfd, data); + dataf (data, DELIM_SPACE); + dataf (data, "switch" DELIM_SPACE "("); + save_flag (idents, TRUE); + IDL_tree_walk2 (IDL_TYPE_UNION (p).switch_type_spec, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (idents); + dataf (data, ")" DELIM_SPACE "{"); nl (); + IDL_tree_walk2 (IDL_TYPE_UNION (p).switch_body, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (su_def); + if (data->su_def) + idataf (data, "}"); + else { + idataf (data, "};"); + nl (); + } + return FALSE; + + default: + break; + } + + return TRUE; +} + +static gboolean IDL_emit_IDL_module_all (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + if (tfd->step == 0) { + idataf (data, "module" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_MODULE (tfd->tree).ident, tfd, data); + dataf (data, DELIM_SPACE); + IDL_emit_IDL_curly_brace_open (tfd, data); + save_flag (idents, FALSE); + } else { + restore_flag (idents); + IDL_emit_IDL_curly_brace_close_sc (tfd, data); + } + + return TRUE; +} + +static gboolean IDL_emit_IDL_interface_all (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + if (tfd->step == 0) { + data->inline_props = FALSE; + IDL_emit_IDL_properties (IDL_INTERFACE (tfd->tree).ident, data); + idataf (data, "interface" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_INTERFACE (tfd->tree).ident, tfd, data); + dataf (data, DELIM_SPACE); + if (IDL_INTERFACE (tfd->tree).inheritance_spec) { + dataf (data, ":" DELIM_SPACE); + IDL_output_delim (IDL_INTERFACE (tfd->tree).inheritance_spec, tfd, data, + (IDL_tree_func) IDL_emit_IDL_ident_force_pre, NULL, + IDLN_IDENT, IDLN_NONE, TRUE, DELIM_COMMA); + dataf (data, DELIM_SPACE); + } + IDL_emit_IDL_curly_brace_open (tfd, data); + save_flag (idents, FALSE); + } else { + restore_flag (idents); + IDL_emit_IDL_curly_brace_close_sc (tfd, data); + } + + return TRUE; +} + +static gboolean IDL_emit_IDL_forward_dcl_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + idataf (data, "interface" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_FORWARD_DCL (tfd->tree).ident, tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_attr_dcl_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_emit_IDL_indent (tfd, data); + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_LIST (IDL_ATTR_DCL (tfd->tree).simple_declarations).data, + data); + if (IDL_ATTR_DCL (tfd->tree).f_readonly) dataf (data, "readonly" DELIM_SPACE); + dataf (data, "attribute" DELIM_SPACE); + save_flag (idents, TRUE); + IDL_tree_walk2 (IDL_ATTR_DCL (tfd->tree).param_type_spec, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (idents); + dataf (data, DELIM_SPACE); + IDL_output_delim (IDL_ATTR_DCL (tfd->tree).simple_declarations, tfd, data, + (IDL_tree_func) IDL_emit_IDL_ident_force_pre, NULL, + IDLN_IDENT, IDLN_NONE, TRUE, DELIM_COMMA); + IDL_emit_IDL_sc (tfd, data); + + return FALSE; +} + +static gboolean IDL_emit_IDL_op_dcl_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_emit_IDL_indent (tfd, data); + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_OP_DCL (tfd->tree).ident, data); + if (IDL_OP_DCL (tfd->tree).f_oneway) dataf (data, "oneway" DELIM_SPACE); + if (IDL_OP_DCL (tfd->tree).op_type_spec) { + save_flag (idents, TRUE); + IDL_tree_walk2 (IDL_OP_DCL (tfd->tree).op_type_spec, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (idents); + } else + dataf (data, "void"); + dataf (data, DELIM_SPACE "%s" DELIM_SPACE "(", + IDL_IDENT (IDL_OP_DCL (tfd->tree).ident).str); + if (IDL_OP_DCL (tfd->tree).parameter_dcls) + IDL_output_delim (IDL_OP_DCL (tfd->tree).parameter_dcls, tfd, data, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + IDLN_PARAM_DCL, IDLN_NONE, FALSE, DELIM_COMMA); + if (IDL_OP_DCL (tfd->tree).f_varargs) + dataf (data, DELIM_COMMA "..."); + dataf (data, ")"); + if (IDL_OP_DCL (tfd->tree).raises_expr) { + nl (); indent (); + idataf (data, DELIM_SPACE "raises" DELIM_SPACE "("); + IDL_output_delim (IDL_OP_DCL (tfd->tree).raises_expr, tfd, data, + (IDL_tree_func) IDL_emit_IDL_ident_force_pre, NULL, + IDLN_IDENT, IDLN_NONE, TRUE, DELIM_COMMA); + dataf (data, ")"); + unindent (); + } + if (IDL_OP_DCL (tfd->tree).context_expr) { + nl (); indent (); + idataf (data, DELIM_SPACE "context" DELIM_SPACE "("); + IDL_output_delim (IDL_OP_DCL (tfd->tree).context_expr, tfd, data, + (IDL_tree_func) IDL_emit_IDL_literal_force_pre, NULL, + IDLN_STRING, IDLN_NONE, TRUE, DELIM_COMMA); + dataf (data, ")"); + unindent (); + } + IDL_emit_IDL_sc (tfd, data); + + return FALSE; +} + +static gboolean IDL_emit_IDL_param_dcl_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_PARAM_DCL (tfd->tree).simple_declarator, data); + switch (IDL_PARAM_DCL (tfd->tree).attr) { + case IDL_PARAM_IN: dataf (data, "in" DELIM_SPACE); break; + case IDL_PARAM_OUT: dataf (data, "out" DELIM_SPACE); break; + case IDL_PARAM_INOUT: dataf (data, "inout" DELIM_SPACE); break; + } + save_flag (idents, TRUE); + IDL_tree_walk2 (IDL_PARAM_DCL (tfd->tree).param_type_spec, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (idents); + dataf (data, DELIM_SPACE); + IDL_emit_IDL_ident (IDL_PARAM_DCL (tfd->tree).simple_declarator, tfd, data); + + return FALSE; +} + +static gboolean IDL_emit_IDL_type_dcl_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_tree_func_data down_tfd; + IDL_tree q; + + IDL_emit_IDL_indent (tfd, data); + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_LIST (IDL_TYPE_DCL (tfd->tree).dcls).data, data); + dataf (data, "typedef" DELIM_SPACE); + save_flag (idents, TRUE); + save_flag (su_def, TRUE); + IDL_tree_walk2 (IDL_TYPE_DCL (tfd->tree).type_spec, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + dataf (data, DELIM_SPACE); + down_tfd = *tfd; + down_tfd.up = tfd; + for (q = IDL_TYPE_DCL (tfd->tree).dcls; q; q = IDL_LIST (q).next) { + down_tfd.tree = q; + IDL_tree_walk2 (IDL_LIST (q).data, &down_tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + if (IDL_LIST (q).next) + dataf (data, DELIM_COMMA); + } + restore_flag (idents); + restore_flag (su_def); + IDL_emit_IDL_sc (tfd, data); + + return FALSE; +} + +static gboolean IDL_emit_IDL_const_dcl_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + idataf (data, "const" DELIM_SPACE); + save_flag (idents, TRUE); + IDL_tree_walk2 (IDL_CONST_DCL (tfd->tree).const_type, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (idents); + dataf (data, DELIM_SPACE); + IDL_emit_IDL_ident (IDL_CONST_DCL (tfd->tree).ident, tfd, data); + dataf (data, DELIM_SPACE "=" DELIM_SPACE); + save_flag (literals, TRUE); + IDL_tree_walk2 (IDL_CONST_DCL (tfd->tree).const_exp, tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (literals); + IDL_emit_IDL_sc (tfd, data); + + return FALSE; +} + +static gboolean IDL_emit_IDL_except_dcl_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + idataf (data, "exception" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_EXCEPT_DCL (tfd->tree).ident, tfd, data); + dataf (data, DELIM_SPACE); + IDL_emit_IDL_curly_brace_open (tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_native_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_emit_IDL_indent (tfd, data); + data->inline_props = TRUE; + IDL_emit_IDL_properties (IDL_NATIVE (tfd->tree).ident, data); + dataf (data, "native" DELIM_SPACE); + IDL_emit_IDL_ident (IDL_NATIVE (tfd->tree).ident, tfd, data); + if (IDL_NATIVE (tfd->tree).user_type) + dataf (data, DELIM_SPACE "(%s)", IDL_NATIVE (tfd->tree).user_type); + IDL_emit_IDL_sc (tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_case_stmt_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_tree_func_data down_tfd; + IDL_tree q; + + save_flag (idents, TRUE); + save_flag (literals, TRUE); + down_tfd = *tfd; + down_tfd.up = tfd; + for (q = IDL_CASE_STMT (tfd->tree).labels; q; q = IDL_LIST (q).next) { + if (IDL_LIST (q).data) { + down_tfd.tree = q; + idataf (data, "case" DELIM_SPACE); + IDL_tree_walk2 (IDL_LIST (q).data, &down_tfd,/*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + dataf (data, ":"); + } else + idataf (data, "default:"); + nl (); + } + restore_flag (literals); + restore_flag (idents); + indent (); + + return FALSE; +} + +static gboolean IDL_emit_IDL_case_stmt_post (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_tree_walk2 (IDL_CASE_STMT (tfd->tree).element_spec, tfd, /*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + unindent (); + + return FALSE; +} + +static gboolean IDL_emit_IDL_member_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + IDL_emit_IDL_indent (tfd, data); + save_flag (idents, TRUE); + IDL_tree_walk2 (IDL_MEMBER (tfd->tree).type_spec, tfd, /*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + data); + restore_flag (idents); + + return FALSE; +} + +static gboolean IDL_emit_IDL_member_post (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + dataf (data, DELIM_SPACE); + IDL_output_delim (IDL_MEMBER (tfd->tree).dcls, tfd, data, + (IDL_tree_func) IDL_emit_IDL_type_pre, NULL, + IDLN_IDENT, IDLN_TYPE_ARRAY, FALSE, DELIM_COMMA); + IDL_emit_IDL_sc (tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_IDL_codefrag_pre (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + if (data->flags & IDLF_OUTPUT_CODEFRAGS) { + GSList *slist; + + dataf (data, "%%{ %s", IDL_CODEFRAG (tfd->tree).desc); nl (); + for (slist = IDL_CODEFRAG (tfd->tree).lines; slist; slist = slist->next) { + dataf (data, "%s", (char *) slist->data); nl (); + } + dataf (data, "%%}"); nl (); + } + + return TRUE; +} + +struct IDL_emit_node { + IDL_tree_func pre; + IDL_tree_func post; +}; + +static struct IDL_emit_node * IDL_get_IDL_emission_table (void) +{ + static gboolean initialized = FALSE; + static struct IDL_emit_node table[IDLN_LAST]; + struct IDL_emit_node *s; + + if (!initialized) { + + s = &table[IDLN_MODULE]; + s->pre = s->post = (IDL_tree_func) IDL_emit_IDL_module_all; + + s = &table[IDLN_INTERFACE]; + s->pre = s->post = (IDL_tree_func) IDL_emit_IDL_interface_all; + + s = &table[IDLN_FORWARD_DCL]; + s->pre = (IDL_tree_func) IDL_emit_IDL_forward_dcl_pre; + s->post = (IDL_tree_func) IDL_emit_IDL_sc; + + s = &table[IDLN_ATTR_DCL]; + s->pre = (IDL_tree_func) IDL_emit_IDL_attr_dcl_pre; + + s = &table[IDLN_OP_DCL]; + s->pre = (IDL_tree_func) IDL_emit_IDL_op_dcl_pre; + + s = &table[IDLN_PARAM_DCL]; + s->pre = (IDL_tree_func) IDL_emit_IDL_param_dcl_pre; + + s = &table[IDLN_TYPE_DCL]; + s->pre = (IDL_tree_func) IDL_emit_IDL_type_dcl_pre; + + s = &table[IDLN_CONST_DCL]; + s->pre = (IDL_tree_func) IDL_emit_IDL_const_dcl_pre; + + s = &table[IDLN_EXCEPT_DCL]; + s->pre = (IDL_tree_func) IDL_emit_IDL_except_dcl_pre; + s->post = (IDL_tree_func) IDL_emit_IDL_curly_brace_close_sc; + + s = &table[IDLN_MEMBER]; + s->pre = (IDL_tree_func) IDL_emit_IDL_member_pre; + s->post = (IDL_tree_func) IDL_emit_IDL_member_post; + + s = &table[IDLN_NATIVE]; + s->pre = (IDL_tree_func) IDL_emit_IDL_native_pre; + + s = &table[IDLN_CASE_STMT]; + s->pre = (IDL_tree_func) IDL_emit_IDL_case_stmt_pre; + s->post = (IDL_tree_func) IDL_emit_IDL_case_stmt_post; + + s = &table[IDLN_IDENT]; + s->pre = (IDL_tree_func) IDL_emit_IDL_ident_pre; + + s = &table[IDLN_CODEFRAG]; + s->pre = (IDL_tree_func) IDL_emit_IDL_codefrag_pre; + + table[IDLN_TYPE_FLOAT].pre = + table[IDLN_TYPE_CHAR].pre = + table[IDLN_TYPE_WIDE_CHAR].pre = + table[IDLN_TYPE_BOOLEAN].pre = + table[IDLN_TYPE_OCTET].pre = + table[IDLN_TYPE_ANY].pre = + table[IDLN_TYPE_OBJECT].pre = + table[IDLN_TYPE_TYPECODE].pre = + table[IDLN_TYPE_FIXED].pre = + table[IDLN_TYPE_INTEGER].pre = + table[IDLN_TYPE_STRING].pre = + table[IDLN_TYPE_WIDE_STRING].pre = + table[IDLN_TYPE_ENUM].pre = + table[IDLN_TYPE_ARRAY].pre = + table[IDLN_TYPE_SEQUENCE].pre = + table[IDLN_TYPE_STRUCT].pre = + table[IDLN_TYPE_UNION].pre = (IDL_tree_func) IDL_emit_IDL_type_pre; + + table[IDLN_FLOAT].pre = + table[IDLN_INTEGER].pre = + table[IDLN_FIXED].pre = + table[IDLN_CHAR].pre = + table[IDLN_WIDE_CHAR].pre = + table[IDLN_BOOLEAN].pre = + table[IDLN_STRING].pre = + table[IDLN_WIDE_STRING].pre = (IDL_tree_func) IDL_emit_IDL_literal_pre; + + initialized = TRUE; + } + + return table; +} + +static gboolean IDL_emit_node_pre_func (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + const struct IDL_emit_node * const s = + &IDL_get_IDL_emission_table () [IDL_NODE_TYPE (tfd->tree)]; + + if (s->pre) + return (*s->pre) (tfd, data); + + return TRUE; +} + +static gboolean IDL_emit_node_post_func (IDL_tree_func_data *tfd, IDL_output_data *data) +{ + const struct IDL_emit_node * const s = + &IDL_get_IDL_emission_table () [IDL_NODE_TYPE (tfd->tree)]; + + if (s->post) + return (*s->post) (tfd, data); + + return TRUE; +} + +void IDL_tree_to_IDL (IDL_tree p, IDL_ns ns, FILE *output, unsigned long output_flags) +{ + IDL_output_data data; + + g_return_if_fail (output != NULL); + + data.ns = ns; + data.mode = OUTPUT_FILE; + data.u.o = output; + data.flags = output_flags; + data.ilev = 0; + data.idents = TRUE; + data.literals = TRUE; + data.inline_props = TRUE; + data.su_def = FALSE; + + if (ns == NULL) + data.flags |= IDLF_OUTPUT_NO_QUALIFY_IDENTS; + + IDL_tree_walk2 (p, NULL, /*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + &data); +} + +GString *IDL_tree_to_IDL_string (IDL_tree p, IDL_ns ns, unsigned long output_flags) +{ + IDL_output_data data; + + data.ns = ns; + data.mode = OUTPUT_STRING; + data.u.s = g_string_new (NULL); + data.flags = output_flags; + data.ilev = 0; + data.idents = TRUE; + data.literals = TRUE; + data.inline_props = TRUE; + data.su_def = FALSE; + + if (ns == NULL) + data.flags |= IDLF_OUTPUT_NO_QUALIFY_IDENTS; + + IDL_tree_walk2 (p, NULL, /*flags*/0, + (IDL_tree_func) IDL_emit_node_pre_func, + (IDL_tree_func) IDL_emit_node_post_func, + &data); + + return data.u.s; +} + +typedef struct { + IDL_tree searchNode; + gboolean found; +} ContainsNodeWalkerInfo; + +static gboolean +contains_node_walker (IDL_tree_func_data *tfd, gpointer data) { + ContainsNodeWalkerInfo *info = data; + /* skip root! */ + if (tfd->up != NULL && tfd->tree == info->searchNode) { + info->found = TRUE; + return FALSE; + } + return TRUE; /* continue walking */ +} + +gboolean IDL_tree_contains_node(IDL_tree tree, IDL_tree node) { + ContainsNodeWalkerInfo info; + info.searchNode = node; + info.found = 0; + IDL_tree_walk2 (tree, /*curwalk*/NULL, /*flags*/0, + /*pre*/contains_node_walker, /*post*/NULL, &info); + return info.found; +} + +struct IDL_recursive_walker_info { + GSList *ident_list; + gboolean recursive; + }; + +/* + * IDL_tree_is_recursive_walker_pre: + * @walk_frame: a #IDL_tree_func_data structure + * @user_data: a #IDL_recursive_walker_info structure. + * + * If the current node in the parse tree is a structure or union + * add its IDLN_IDENT to the ident list contained in @user_data; + * + * If the current node in the parse tree is a sequence, check to + * see if the sequence element type is on the list of IDLN_IDENTs. + * + * Return value: %FALSE if recursion is detected - this stops the + * walk to the parse tree -, %TRUE otherwise. + */ +static gboolean +IDL_tree_is_recursive_walker_pre (IDL_tree_func_data *walk_frame, + gpointer user_data) +{ + struct IDL_recursive_walker_info *info = user_data; + IDL_tree node = walk_frame->tree; + + switch (IDL_NODE_TYPE (node)) { + case IDLN_TYPE_STRUCT: + case IDLN_TYPE_UNION: + info->ident_list = g_slist_prepend (info->ident_list, + IDL_TYPE_STRUCT (node).ident); + break; + case IDLN_TYPE_SEQUENCE: { + IDL_tree seq_type = IDL_TYPE_SEQUENCE (node).simple_type_spec; + GSList *l = info->ident_list; + + if (IDL_NODE_TYPE (seq_type) != IDLN_IDENT) + break; + + g_assert (IDL_IDENT (seq_type).repo_id); + + for (; l; l = l->next) { + IDL_tree n = (IDL_tree)l->data; + + g_assert (IDL_IDENT (n).repo_id); + + if (!strcmp (IDL_IDENT (n).repo_id, + IDL_IDENT (seq_type).repo_id)) { + + info->recursive = TRUE; + return FALSE; + } + } + } + break; + default: + break; + } + + return TRUE; +} + +/* + * IDL_tree_is_recursive_walker_post: + * @walk_frame: a #IDL_tree_func_data structure + * @user_data: a #IDL_recursive_walker_info structure. + * + * If the current node in the parse tree is a structure or + * union, remove the IDLN_IDENT from the ident list. + * + * Return value: %TRUE. + */ +static gboolean +IDL_tree_is_recursive_walker_post (IDL_tree_func_data *walk_frame, + gpointer user_data) +{ + struct IDL_recursive_walker_info *info = user_data; + IDL_tree node = walk_frame->tree; + + switch (IDL_NODE_TYPE (node)) { + case IDLN_TYPE_STRUCT: + case IDLN_TYPE_UNION: { + GSList *link = info->ident_list; + + g_assert (((IDL_tree)link->data) == IDL_TYPE_STRUCT (node).ident); + + info->ident_list = g_slist_remove_link (info->ident_list, + link); + g_slist_free_1 (link); + } + break; + default: + break; + } + + return TRUE; +} + +/* + * IDL_tree_is_recursive: + * @tree: a #IDL_tree. + * @hasRecur: dummy argument, not used, deprecated, compatibility cruft. + * + * Checks whether or not @tree contains recursive types. + * + * Recursive types may only be constructed using structs/unions which + * contain sequences that hold the parent struct/union type. + * + * Return value: %TRUE if @tree contains recursive types, + * %FALSE otherwise. + */ +gboolean +IDL_tree_is_recursive (IDL_tree tree, gpointer dummy) +{ + struct IDL_recursive_walker_info info; + + info.ident_list = NULL; + info.recursive = FALSE; + + IDL_tree_walk2 (tree, NULL, IDL_WalkF_TypespecOnly, + IDL_tree_is_recursive_walker_pre, + IDL_tree_is_recursive_walker_post, + &info); + + g_assert (!info.ident_list); + + return info.recursive; +} + +/* + * Local variables: + * mode: C + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + */ |