summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c1196
1 files changed, 1196 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c
new file mode 100644
index 00000000..f4fe9d5b
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c
@@ -0,0 +1,1196 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Generate XPCOM headers from XPIDL.
+ */
+
+#include "xpidl.h"
+#include <ctype.h>
+
+#define AS_DECL 0
+#define AS_CALL 1
+#define AS_IMPL 2
+
+static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile,
+ int mode, const char *className);
+static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
+ gboolean getter,
+ int mode, const char *className);
+
+static void
+write_indent(FILE *outfile) {
+ fputs(" ", outfile);
+}
+
+static gboolean
+header_prolog(TreeState *state)
+{
+ char *define = xpidl_basename(state->basename);
+ fprintf(state->file, "/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM"
+ " %s.idl\n */\n", state->basename);
+ fprintf(state->file,
+ "\n#ifndef __gen_%s_h__\n"
+ "#define __gen_%s_h__\n",
+ define, define);
+ g_free(define);
+ if (state->base_includes != NULL) {
+ guint len = g_slist_length(state->base_includes);
+ guint i;
+
+ fputc('\n', state->file);
+ for (i = 0; i < len; i++) {
+ char *ident, *dot;
+
+ ident = (char *)g_slist_nth_data(state->base_includes, i);
+
+ /* suppress any trailing .extension */
+
+ /* XXX use g_basename instead ? ? */
+
+ dot = strrchr(ident, '.');
+ if (dot != NULL)
+ *dot = '\0';
+
+
+ /* begin include guard */
+ fprintf(state->file,
+ "\n#ifndef __gen_%s_h__\n",
+ ident);
+
+ fprintf(state->file, "#include \"%s.h\"\n",
+ (char *)g_slist_nth_data(state->base_includes, i));
+
+ fprintf(state->file, "#endif\n");
+
+ }
+ if (i > 0)
+ fputc('\n', state->file);
+ }
+ /*
+ * Support IDL files that don't include a root IDL file that defines
+ * NS_NO_VTABLE.
+ */
+ fprintf(state->file,
+ "/* For IDL files that don't want to include root IDL files. */\n"
+ "#ifndef NS_NO_VTABLE\n"
+ "#define NS_NO_VTABLE\n"
+ "#endif\n");
+
+ return TRUE;
+}
+
+static gboolean
+header_epilog(TreeState *state)
+{
+ char *define = xpidl_basename(state->basename);
+ fprintf(state->file, "\n#endif /* __gen_%s_h__ */\n", define);
+ g_free(define);
+ return TRUE;
+}
+
+static void
+write_classname_iid_define(FILE *file, const char *className)
+{
+ const char *iidName;
+ if (className[0] == 'n' && className[1] == 's') {
+ /* backcompat naming styles */
+ fputs("NS_", file);
+ iidName = className + 2;
+ } else {
+ iidName = className;
+ }
+ while (*iidName)
+ fputc(toupper(*iidName++), file);
+ fputs("_IID", file);
+}
+
+static gboolean
+interface(TreeState *state)
+{
+ IDL_tree iface = state->tree, iter, orig;
+ char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
+ char *classNameUpper = NULL;
+ char *classNameImpl = NULL;
+ char *cp;
+ gboolean ok = TRUE;
+ gboolean keepvtable;
+ const char *iid;
+ const char *name_space;
+ struct nsID id;
+ char iid_parsed[UUID_LENGTH];
+ GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments;
+
+ if (!verify_interface_declaration(iface))
+ return FALSE;
+
+#define FAIL do {ok = FALSE; goto out;} while(0)
+
+ fprintf(state->file, "\n/* starting interface: %s */\n",
+ className);
+
+ name_space = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "namespace");
+ if (name_space) {
+ fprintf(state->file, "/* namespace: %s */\n",
+ name_space);
+ fprintf(state->file, "/* fully qualified name: %s.%s */\n",
+ name_space,className);
+ }
+
+ iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid");
+ if (iid) {
+ /* Redundant, but a better error than 'cannot parse.' */
+ if (strlen(iid) != 36) {
+ IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid);
+ FAIL;
+ }
+
+ /*
+ * Parse uuid and then output resulting nsID to string, to validate
+ * uuid and normalize resulting .h files.
+ */
+ if (!xpidl_parse_iid(&id, iid)) {
+ IDL_tree_error(state->tree, "cannot parse IID %s\n", iid);
+ FAIL;
+ }
+ if (!xpidl_sprint_iid(&id, iid_parsed)) {
+ IDL_tree_error(state->tree, "error formatting IID %s\n", iid);
+ FAIL;
+ }
+
+ /* #define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" */
+ fputs("#define ", state->file);
+ write_classname_iid_define(state->file, className);
+ fprintf(state->file, "_STR \"%s\"\n", iid_parsed);
+ fputc('\n', state->file);
+
+ /* #define NS_ISUPPORTS_IID { {0x00000000 .... 0x46 }} */
+ fprintf(state->file, "#define ");
+ write_classname_iid_define(state->file, className);
+ fprintf(state->file, " \\\n"
+ " {0x%.8x, 0x%.4x, 0x%.4x, \\\n"
+ " { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, "
+ "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }}\n",
+ id.m0, id.m1, id.m2,
+ id.m3[0], id.m3[1], id.m3[2], id.m3[3],
+ id.m3[4], id.m3[5], id.m3[6], id.m3[7]);
+ fputc('\n', state->file);
+ } else {
+ IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n",
+ className);
+ FAIL;
+ }
+
+ if (doc_comments != NULL)
+ printlist(state->file, doc_comments);
+
+ /*
+ * NS_NO_VTABLE is defined in nsISupportsUtils.h, and defined on windows
+ * to __declspec(novtable) on windows. This optimization is safe
+ * whenever the constructor calls no virtual methods. Writing in IDL
+ * almost guarantees this, except for the case when a %{C++ block occurs in
+ * the interface. We detect that case, and emit a macro call that disables
+ * the optimization.
+ */
+ keepvtable = FALSE;
+ for (iter = IDL_INTERFACE(state->tree).body;
+ iter != NULL;
+ iter = IDL_LIST(iter).next)
+ {
+ IDL_tree data = IDL_LIST(iter).data;
+ if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG)
+ keepvtable = TRUE;
+ }
+
+ /* The interface declaration itself. */
+ fprintf(state->file,
+ "class %s%s",
+ (keepvtable ? "" : "NS_NO_VTABLE "), className);
+
+ if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
+ fputs(" : ", state->file);
+ if (IDL_LIST(iter).next != NULL) {
+ IDL_tree_error(iter,
+ "multiple inheritance is not supported by xpidl");
+ FAIL;
+ }
+ fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str);
+ }
+ fputs(" {\n"
+ " public: \n\n", state->file);
+ if (iid) {
+ fputs(" NS_DEFINE_STATIC_IID_ACCESSOR(", state->file);
+ write_classname_iid_define(state->file, className);
+ fputs(")\n\n", state->file);
+ }
+
+ orig = state->tree; /* It would be nice to remove this state-twiddling. */
+
+ state->tree = IDL_INTERFACE(iface).body;
+
+ if (state->tree && !xpidl_process_node(state))
+ FAIL;
+
+ fputs("};\n", state->file);
+ fputc('\n', state->file);
+
+ /*
+ * #define NS_DECL_NSIFOO - create method prototypes that can be used in
+ * class definitions that support this interface.
+ *
+ * Walk the tree explicitly to prototype a reworking of xpidl to get rid of
+ * the callback mechanism.
+ */
+ state->tree = orig;
+ fputs("/* Use this macro when declaring classes that implement this "
+ "interface. */\n", state->file);
+ fputs("#define NS_DECL_", state->file);
+ classNameUpper = xpidl_strdup(className);
+ for (cp = classNameUpper; *cp != '\0'; cp++)
+ *cp = toupper(*cp);
+ fprintf(state->file, "%s \\\n", classNameUpper);
+ if (IDL_INTERFACE(state->tree).body == NULL) {
+ write_indent(state->file);
+ fputs("/* no methods! */\n", state->file);
+ }
+
+ for (iter = IDL_INTERFACE(state->tree).body;
+ iter != NULL;
+ iter = IDL_LIST(iter).next)
+ {
+ IDL_tree data = IDL_LIST(iter).data;
+
+ switch(IDL_NODE_TYPE(data)) {
+ case IDLN_OP_DCL:
+ write_indent(state->file);
+ write_method_signature(data, state->file, AS_DECL, NULL);
+ break;
+
+ case IDLN_ATTR_DCL:
+ write_indent(state->file);
+ if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
+ FAIL;
+ if (!IDL_ATTR_DCL(data).f_readonly) {
+ fputs("; \\\n", state->file); /* Terminate the previous one. */
+ write_indent(state->file);
+ if (!write_attr_accessor(data, state->file,
+ FALSE, AS_DECL, NULL))
+ FAIL;
+ /* '; \n' at end will clean up. */
+ }
+ break;
+
+ case IDLN_CONST_DCL:
+ /* ignore it here; it doesn't contribute to the macro. */
+ continue;
+
+ case IDLN_CODEFRAG:
+ XPIDL_WARNING((iter, IDL_WARNING1,
+ "%%{ .. %%} code fragment within interface "
+ "ignored when generating NS_DECL_%s macro; "
+ "if the code fragment contains method "
+ "declarations, the macro probably isn't "
+ "complete.", classNameUpper));
+ continue;
+
+ default:
+ IDL_tree_error(iter,
+ "unexpected node type %d! "
+ "Please file a bug against the xpidl component.",
+ IDL_NODE_TYPE(data));
+ FAIL;
+ }
+
+ if (IDL_LIST(iter).next != NULL) {
+ fprintf(state->file, "; \\\n");
+ } else {
+ fprintf(state->file, "; \n");
+ }
+ }
+ fputc('\n', state->file);
+
+ /* XXX abstract above and below into one function? */
+ /*
+ * #define NS_FORWARD_NSIFOO - create forwarding methods that can delegate
+ * behavior from in implementation to another object. As generated by
+ * idlc.
+ */
+ fprintf(state->file,
+ "/* Use this macro to declare functions that forward the "
+ "behavior of this interface to another object. */\n"
+ "#define NS_FORWARD_%s(_to) \\\n",
+ classNameUpper);
+ if (IDL_INTERFACE(state->tree).body == NULL) {
+ write_indent(state->file);
+ fputs("/* no methods! */\n", state->file);
+ }
+
+ for (iter = IDL_INTERFACE(state->tree).body;
+ iter != NULL;
+ iter = IDL_LIST(iter).next)
+ {
+ IDL_tree data = IDL_LIST(iter).data;
+
+ switch(IDL_NODE_TYPE(data)) {
+ case IDLN_OP_DCL:
+ write_indent(state->file);
+ write_method_signature(data, state->file, AS_DECL, NULL);
+ fputs(" { return _to ", state->file);
+ write_method_signature(data, state->file, AS_CALL, NULL);
+ break;
+
+ case IDLN_ATTR_DCL:
+ write_indent(state->file);
+ if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
+ FAIL;
+ fputs(" { return _to ", state->file);
+ if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
+ FAIL;
+ if (!IDL_ATTR_DCL(data).f_readonly) {
+ fputs("; } \\\n", state->file); /* Terminate the previous one. */
+ write_indent(state->file);
+ if (!write_attr_accessor(data, state->file,
+ FALSE, AS_DECL, NULL))
+ FAIL;
+ fputs(" { return _to ", state->file);
+ if (!write_attr_accessor(data, state->file,
+ FALSE, AS_CALL, NULL))
+ FAIL;
+ /* '; } \n' at end will clean up. */
+ }
+ break;
+
+ case IDLN_CONST_DCL:
+ case IDLN_CODEFRAG:
+ continue;
+
+ default:
+ FAIL;
+ }
+
+ if (IDL_LIST(iter).next != NULL) {
+ fprintf(state->file, "; } \\\n");
+ } else {
+ fprintf(state->file, "; } \n");
+ }
+ }
+ fputc('\n', state->file);
+
+
+ /* XXX abstract above and below into one function? */
+ /*
+ * #define NS_FORWARD_SAFE_NSIFOO - create forwarding methods that can delegate
+ * behavior from in implementation to another object. As generated by
+ * idlc.
+ */
+ fprintf(state->file,
+ "/* Use this macro to declare functions that forward the "
+ "behavior of this interface to another object in a safe way. */\n"
+ "#define NS_FORWARD_SAFE_%s(_to) \\\n",
+ classNameUpper);
+ if (IDL_INTERFACE(state->tree).body == NULL) {
+ write_indent(state->file);
+ fputs("/* no methods! */\n", state->file);
+ }
+
+ for (iter = IDL_INTERFACE(state->tree).body;
+ iter != NULL;
+ iter = IDL_LIST(iter).next)
+ {
+ IDL_tree data = IDL_LIST(iter).data;
+
+ switch(IDL_NODE_TYPE(data)) {
+ case IDLN_OP_DCL:
+ write_indent(state->file);
+ write_method_signature(data, state->file, AS_DECL, NULL);
+ fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
+ write_method_signature(data, state->file, AS_CALL, NULL);
+ break;
+
+ case IDLN_ATTR_DCL:
+ write_indent(state->file);
+ if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
+ FAIL;
+ fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
+ if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
+ FAIL;
+ if (!IDL_ATTR_DCL(data).f_readonly) {
+ fputs("; } \\\n", state->file); /* Terminate the previous one. */
+ write_indent(state->file);
+ if (!write_attr_accessor(data, state->file,
+ FALSE, AS_DECL, NULL))
+ FAIL;
+ fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
+ if (!write_attr_accessor(data, state->file,
+ FALSE, AS_CALL, NULL))
+ FAIL;
+ /* '; } \n' at end will clean up. */
+ }
+ break;
+
+ case IDLN_CONST_DCL:
+ case IDLN_CODEFRAG:
+ continue;
+
+ default:
+ FAIL;
+ }
+
+ if (IDL_LIST(iter).next != NULL) {
+ fprintf(state->file, "; } \\\n");
+ } else {
+ fprintf(state->file, "; } \n");
+ }
+ }
+ fputc('\n', state->file);
+
+ /*
+ * Build a sample implementation template.
+ */
+ if (strlen(className) >= 3 && className[2] == 'I') {
+ classNameImpl = xpidl_strdup(className);
+ if (!classNameImpl)
+ FAIL;
+ memmove(&classNameImpl[2], &classNameImpl[3], strlen(classNameImpl) - 2);
+ } else {
+ classNameImpl = xpidl_strdup("_MYCLASS_");
+ if (!classNameImpl)
+ FAIL;
+ }
+
+ fputs("#if 0\n"
+ "/* Use the code below as a template for the "
+ "implementation class for this interface. */\n"
+ "\n"
+ "/* Header file */"
+ "\n",
+ state->file);
+ fprintf(state->file, "class %s : public %s\n", classNameImpl, className);
+ fputs("{\n"
+ "public:\n", state->file);
+ write_indent(state->file);
+ fputs("NS_DECL_ISUPPORTS\n", state->file);
+ write_indent(state->file);
+ fprintf(state->file, "NS_DECL_%s\n", classNameUpper);
+ fputs("\n", state->file);
+ write_indent(state->file);
+ fprintf(state->file, "%s();\n", classNameImpl);
+ fputs("\n"
+ "private:\n", state->file);
+ write_indent(state->file);
+ fprintf(state->file, "~%s();\n", classNameImpl);
+ fputs("\n"
+ "protected:\n", state->file);
+ write_indent(state->file);
+ fputs("/* additional members */\n", state->file);
+ fputs("};\n\n", state->file);
+
+ fputs("/* Implementation file */\n", state->file);
+
+ fprintf(state->file,
+ "NS_IMPL_ISUPPORTS1(%s, %s)\n", classNameImpl, className);
+ fputs("\n", state->file);
+
+ fprintf(state->file, "%s::%s()\n", classNameImpl, classNameImpl);
+ fputs("{\n", state->file);
+ write_indent(state->file);
+ fputs("/* member initializers and constructor code */\n", state->file);
+ fputs("}\n\n", state->file);
+
+ fprintf(state->file, "%s::~%s()\n", classNameImpl, classNameImpl);
+ fputs("{\n", state->file);
+ write_indent(state->file);
+ fputs("/* destructor code */\n", state->file);
+ fputs("}\n\n", state->file);
+
+ for (iter = IDL_INTERFACE(state->tree).body;
+ iter != NULL;
+ iter = IDL_LIST(iter).next)
+ {
+ IDL_tree data = IDL_LIST(iter).data;
+
+ switch(IDL_NODE_TYPE(data)) {
+ case IDLN_OP_DCL:
+ /* It would be nice to remove this state-twiddling. */
+ orig = state->tree;
+ state->tree = data;
+ xpidl_write_comment(state, 0);
+ state->tree = orig;
+
+ write_method_signature(data, state->file, AS_IMPL, classNameImpl);
+ fputs("\n{\n", state->file);
+ write_indent(state->file);
+ write_indent(state->file);
+ fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
+ "}\n"
+ "\n", state->file);
+ break;
+
+ case IDLN_ATTR_DCL:
+ /* It would be nice to remove this state-twiddling. */
+ orig = state->tree;
+ state->tree = data;
+ xpidl_write_comment(state, 0);
+ state->tree = orig;
+
+ if (!write_attr_accessor(data, state->file, TRUE,
+ AS_IMPL, classNameImpl))
+ FAIL;
+ fputs("\n{\n", state->file);
+ write_indent(state->file);
+ write_indent(state->file);
+ fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
+ "}\n", state->file);
+
+ if (!IDL_ATTR_DCL(data).f_readonly) {
+ if (!write_attr_accessor(data, state->file, FALSE,
+ AS_IMPL, classNameImpl))
+ FAIL;
+ fputs("\n{\n", state->file);
+ write_indent(state->file);
+ write_indent(state->file);
+ fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
+ "}\n", state->file);
+ }
+ fputs("\n", state->file);
+ break;
+
+ case IDLN_CONST_DCL:
+ case IDLN_CODEFRAG:
+ continue;
+
+ default:
+ FAIL;
+ }
+ }
+
+ fputs("/* End of implementation class template. */\n"
+ "#endif\n"
+ "\n", state->file);
+
+#undef FAIL
+
+out:
+ if (classNameUpper)
+ free(classNameUpper);
+ if (classNameImpl)
+ free(classNameImpl);
+ return ok;
+}
+
+static gboolean
+list(TreeState *state)
+{
+ IDL_tree iter;
+ for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
+ state->tree = IDL_LIST(iter).data;
+ if (!xpidl_process_node(state))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile)
+{
+ if (!type_tree) {
+ fputs("void", outfile);
+ return TRUE;
+ }
+
+ switch (IDL_NODE_TYPE(type_tree)) {
+ case IDLN_TYPE_INTEGER: {
+ gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed;
+ switch (IDL_TYPE_INTEGER(type_tree).f_type) {
+ case IDL_INTEGER_TYPE_SHORT:
+ fputs(sign ? "PRInt16" : "PRUint16", outfile);
+ break;
+ case IDL_INTEGER_TYPE_LONG:
+ fputs(sign ? "PRInt32" : "PRUint32", outfile);
+ break;
+ case IDL_INTEGER_TYPE_LONGLONG:
+ fputs(sign ? "PRInt64" : "PRUint64", outfile);
+ break;
+ default:
+ g_error("Unknown integer type %d\n",
+ IDL_TYPE_INTEGER(type_tree).f_type);
+ return FALSE;
+ }
+ break;
+ }
+ case IDLN_TYPE_CHAR:
+ fputs("char", outfile);
+ break;
+ case IDLN_TYPE_WIDE_CHAR:
+ fputs("PRUnichar", outfile); /* wchar_t? */
+ break;
+ case IDLN_TYPE_WIDE_STRING:
+ fputs("PRUnichar *", outfile);
+ break;
+ case IDLN_TYPE_STRING:
+ fputs("char *", outfile);
+ break;
+ case IDLN_TYPE_BOOLEAN:
+ fputs("PRBool", outfile);
+ break;
+ case IDLN_TYPE_OCTET:
+ fputs("PRUint8", outfile);
+ break;
+ case IDLN_TYPE_FLOAT:
+ switch (IDL_TYPE_FLOAT(type_tree).f_type) {
+ case IDL_FLOAT_TYPE_FLOAT:
+ fputs("float", outfile);
+ break;
+ case IDL_FLOAT_TYPE_DOUBLE:
+ fputs("double", outfile);
+ break;
+ /* XXX 'long double' just ignored, or what? */
+ default:
+ fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
+ break;
+ }
+ break;
+ case IDLN_IDENT:
+ if (UP_IS_NATIVE(type_tree)) {
+ if (IDL_tree_property_get(type_tree, "domstring") ||
+ IDL_tree_property_get(type_tree, "astring")) {
+ fputs("nsAString", outfile);
+ } else if (IDL_tree_property_get(type_tree, "utf8string")) {
+ fputs("nsACString", outfile);
+ } else if (IDL_tree_property_get(type_tree, "cstring")) {
+ fputs("nsACString", outfile);
+ } else {
+ fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile);
+ }
+ if (IDL_tree_property_get(type_tree, "ptr")) {
+ fputs(" *", outfile);
+ } else if (IDL_tree_property_get(type_tree, "ref")) {
+ fputs(" &", outfile);
+ }
+ } else {
+ fputs(IDL_IDENT(type_tree).str, outfile);
+ }
+ if (UP_IS_AGGREGATE(type_tree))
+ fputs(" *", outfile);
+ break;
+ default:
+ fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
+ break;
+ }
+ return TRUE;
+}
+
+/*
+ * An attribute declaration looks like:
+ *
+ * [ IDL_ATTR_DCL]
+ * - param_type_spec [IDL_TYPE_* or NULL for void]
+ * - simple_declarations [IDL_LIST]
+ * - data [IDL_IDENT]
+ * - next [IDL_LIST or NULL if no more idents]
+ * - data [IDL_IDENT]
+ */
+
+#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data))
+#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec)
+#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree)))
+
+/*
+ * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
+ * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
+ * AS_CALL writes 'foo(bar, sil)'
+ */
+static gboolean
+write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
+ gboolean getter, int mode, const char *className)
+{
+ char *attrname = ATTR_IDENT(attr_tree).str;
+
+ if (mode == AS_DECL) {
+ fputs("NS_IMETHOD ", outfile);
+ } else if (mode == AS_IMPL) {
+ fprintf(outfile, "NS_IMETHODIMP %s::", className);
+ }
+ fprintf(outfile, "%cet%c%s(",
+ getter ? 'G' : 'S',
+ toupper(*attrname), attrname + 1);
+ if (mode == AS_DECL || mode == AS_IMPL) {
+ /* Setters for string, wstring, nsid, domstring, utf8string,
+ * cstring and astring get const.
+ */
+ if (!getter &&
+ (IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING ||
+ IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING ||
+ IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") ||
+ IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") ||
+ IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") ||
+ IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") ||
+ IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring")))
+ {
+ fputs("const ", outfile);
+ }
+
+ if (!write_type(ATTR_TYPE_DECL(attr_tree), getter, outfile))
+ return FALSE;
+ fprintf(outfile, "%s%s",
+ (STARRED_TYPE(attr_tree) ? "" : " "),
+ (getter && !DIPPER_TYPE(ATTR_TYPE_DECL(attr_tree)))? "*" : "");
+ }
+ fprintf(outfile, "a%c%s)", toupper(attrname[0]), attrname + 1);
+ return TRUE;
+}
+
+static gboolean
+attr_dcl(TreeState *state)
+{
+ GSList *doc_comments;
+
+ if (!verify_attribute_declaration(state->tree))
+ return FALSE;
+
+ doc_comments =
+ IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
+ (state->tree).simple_declarations).data).comments;
+
+ if (doc_comments != NULL) {
+ write_indent(state->file);
+ printlist(state->file, doc_comments);
+ }
+
+ /*
+ * XXX lists of attributes with the same type, e.g.
+ * attribute string foo, bar sil;
+ * are legal IDL... but we don't do anything with 'em.
+ */
+ if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) {
+ XPIDL_WARNING((state->tree, IDL_WARNING1,
+ "multiple attributes in a single declaration aren't "
+ "currently supported by xpidl"));
+ }
+
+ xpidl_write_comment(state, 2);
+
+ write_indent(state->file);
+ if (!write_attr_accessor(state->tree, state->file, TRUE, AS_DECL, NULL))
+ return FALSE;
+ fputs(" = 0;\n", state->file);
+
+ if (!IDL_ATTR_DCL(state->tree).f_readonly) {
+ write_indent(state->file);
+ if (!write_attr_accessor(state->tree, state->file, FALSE, AS_DECL, NULL))
+ return FALSE;
+ fputs(" = 0;\n", state->file);
+ }
+ fputc('\n', state->file);
+
+ return TRUE;
+}
+
+static gboolean
+do_enum(TreeState *state)
+{
+ IDL_tree_error(state->tree, "enums not supported, "
+ "see http://bugzilla.mozilla.org/show_bug.cgi?id=8781");
+ return FALSE;
+}
+
+static gboolean
+do_const_dcl(TreeState *state)
+{
+ struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree);
+ const char *name = IDL_IDENT(dcl->ident).str;
+ gboolean is_signed;
+ GSList *doc_comments = IDL_IDENT(dcl->ident).comments;
+ IDL_tree real_type;
+ const char *const_format;
+
+ if (!verify_const_declaration(state->tree))
+ return FALSE;
+
+ if (doc_comments != NULL) {
+ write_indent(state->file);
+ printlist(state->file, doc_comments);
+ }
+
+ /* Could be a typedef; try to map it to the real type. */
+ real_type = find_underlying_type(dcl->const_type);
+ real_type = real_type ? real_type : dcl->const_type;
+ is_signed = IDL_TYPE_INTEGER(real_type).f_signed;
+
+ const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "uU";
+ write_indent(state->file);
+ fprintf(state->file, "enum { %s = ", name);
+ fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value);
+ fprintf(state->file, " };\n\n");
+
+ return TRUE;
+}
+
+static gboolean
+do_typedef(TreeState *state)
+{
+ IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
+ IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
+ IDL_tree complex;
+ GSList *doc_comments;
+
+ if (IDL_NODE_TYPE(type) == IDLN_TYPE_SEQUENCE) {
+ XPIDL_WARNING((state->tree, IDL_WARNING1,
+ "sequences not supported, ignored"));
+ } else {
+ if (IDL_NODE_TYPE(complex = IDL_LIST(dcls).data) == IDLN_TYPE_ARRAY) {
+ IDL_tree dim = IDL_TYPE_ARRAY(complex).size_list;
+ doc_comments = IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).comments;
+
+ if (doc_comments != NULL)
+ printlist(state->file, doc_comments);
+
+ fputs("typedef ", state->file);
+ if (!write_type(type, FALSE, state->file))
+ return FALSE;
+ fputs(" ", state->file);
+
+ fprintf(state->file, "%s",
+ IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).str);
+ do {
+ fputc('[', state->file);
+ if (IDL_LIST(dim).data) {
+ fprintf(state->file, "%ld",
+ (long)IDL_INTEGER(IDL_LIST(dim).data).value);
+ }
+ fputc(']', state->file);
+ } while ((dim = IDL_LIST(dim).next) != NULL);
+ } else {
+ doc_comments = IDL_IDENT(IDL_LIST(dcls).data).comments;
+
+ if (doc_comments != NULL)
+ printlist(state->file, doc_comments);
+
+ fputs("typedef ", state->file);
+ if (!write_type(type, FALSE, state->file))
+ return FALSE;
+ fputs(" ", state->file);
+ fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file);
+ }
+ fputs(";\n\n", state->file);
+ }
+ return TRUE;
+}
+
+/*
+ * param generation:
+ * in string foo --> nsString *foo
+ * out string foo --> nsString **foo;
+ * inout string foo --> nsString **foo;
+ */
+
+/* If notype is true, just write the param name. */
+static gboolean
+write_param(IDL_tree param_tree, FILE *outfile)
+{
+ IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec;
+ gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN;
+ /* in string, wstring, nsid, domstring, utf8string, cstring and
+ * astring any explicitly marked [const] are const
+ */
+
+ if (is_in &&
+ (IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_STRING ||
+ IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_WIDE_STRING ||
+ IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
+ "const") ||
+ IDL_tree_property_get(param_type_spec, "nsid") ||
+ IDL_tree_property_get(param_type_spec, "domstring") ||
+ IDL_tree_property_get(param_type_spec, "utf8string") ||
+ IDL_tree_property_get(param_type_spec, "cstring") ||
+ IDL_tree_property_get(param_type_spec, "astring"))) {
+ fputs("const ", outfile);
+ }
+ else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT &&
+ IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
+ "shared")) {
+ fputs("const ", outfile);
+ }
+
+ if (!write_type(param_type_spec, !is_in, outfile))
+ return FALSE;
+
+ /* unless the type ended in a *, add a space */
+ if (!STARRED_TYPE(param_type_spec))
+ fputc(' ', outfile);
+
+ /* out and inout params get a bonus '*' (unless this is type that has a
+ * 'dipper' class that is passed in to receive 'out' data)
+ */
+ if (IDL_PARAM_DCL(param_tree).attr != IDL_PARAM_IN &&
+ !DIPPER_TYPE(param_type_spec)) {
+ fputc('*', outfile);
+ }
+ /* arrays get a bonus * too */
+ /* XXX Should this be a leading '*' or a trailing "[]" ?*/
+ if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
+ "array"))
+ fputc('*', outfile);
+
+ fputs(IDL_IDENT(IDL_PARAM_DCL(param_tree).simple_declarator).str, outfile);
+
+ return TRUE;
+}
+
+/*
+ * A forward declaration, usually an interface.
+ */
+static gboolean
+forward_dcl(TreeState *state)
+{
+ IDL_tree iface = state->tree;
+ const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
+
+ if (!className)
+ return FALSE;
+
+ fprintf(state->file, "class %s; /* forward declaration */\n\n", className);
+ return TRUE;
+}
+
+/*
+ * Shared between the interface class declaration and the NS_DECL_IFOO macro
+ * provided to aid declaration of implementation classes.
+ * mode...
+ * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
+ * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
+ * AS_CALL writes 'foo(bar, sil)'
+ */
+static gboolean
+write_method_signature(IDL_tree method_tree, FILE *outfile, int mode,
+ const char *className)
+{
+ struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
+ gboolean no_generated_args = TRUE;
+ gboolean op_notxpcom =
+ (IDL_tree_property_get(op->ident, "notxpcom") != NULL);
+ const char *name;
+ IDL_tree iter;
+
+ if (mode == AS_DECL) {
+ if (op_notxpcom) {
+ fputs("NS_IMETHOD_(", outfile);
+ if (!write_type(op->op_type_spec, FALSE, outfile))
+ return FALSE;
+ fputc(')', outfile);
+ } else {
+ fputs("NS_IMETHOD", outfile);
+ }
+ fputc(' ', outfile);
+ }
+ else if (mode == AS_IMPL) {
+ if (op_notxpcom) {
+ fputs("NS_IMETHODIMP_(", outfile);
+ if (!write_type(op->op_type_spec, FALSE, outfile))
+ return FALSE;
+ fputc(')', outfile);
+ } else {
+ fputs("NS_IMETHODIMP", outfile);
+ }
+ fputc(' ', outfile);
+ }
+ name = IDL_IDENT(op->ident).str;
+ if (mode == AS_IMPL) {
+ fprintf(outfile, "%s::%c%s(", className, toupper(*name), name + 1);
+ } else {
+ fprintf(outfile, "%c%s(", toupper(*name), name + 1);
+ }
+ for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
+ if (mode == AS_DECL || mode == AS_IMPL) {
+ if (!write_param(IDL_LIST(iter).data, outfile))
+ return FALSE;
+ } else {
+ fputs(IDL_IDENT(IDL_PARAM_DCL(IDL_LIST(iter).data)
+ .simple_declarator).str,
+ outfile);
+ }
+ if ((IDL_LIST(iter).next ||
+ (!op_notxpcom && op->op_type_spec) || op->f_varargs))
+ fputs(", ", outfile);
+ no_generated_args = FALSE;
+ }
+
+ /* make IDL return value into trailing out argument */
+ if (op->op_type_spec && !op_notxpcom) {
+ IDL_tree fake_param = IDL_param_dcl_new(IDL_PARAM_OUT,
+ op->op_type_spec,
+ IDL_ident_new("_retval"));
+ if (!fake_param)
+ return FALSE;
+ if (mode == AS_DECL || mode == AS_IMPL) {
+ if (!write_param(fake_param, outfile))
+ return FALSE;
+ } else {
+ fputs("_retval", outfile);
+ }
+ if (op->f_varargs)
+ fputs(", ", outfile);
+ no_generated_args = FALSE;
+ }
+
+ /* varargs go last */
+ if (op->f_varargs) {
+ if (mode == AS_DECL || mode == AS_IMPL) {
+ fputs("nsVarArgs *", outfile);
+ }
+ fputs("_varargs", outfile);
+ no_generated_args = FALSE;
+ }
+
+ /*
+ * If generated method has no arguments, output 'void' to avoid C legacy
+ * behavior of disabling type checking.
+ */
+ if (no_generated_args && mode == AS_DECL) {
+ fputs("void", outfile);
+ }
+
+ fputc(')', outfile);
+
+ return TRUE;
+}
+
+/*
+ * A method is an `operation', therefore a method decl is an `op dcl'.
+ * I blame Elliot.
+ */
+static gboolean
+op_dcl(TreeState *state)
+{
+ GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments;
+
+ /*
+ * Verify that e.g. non-scriptable methods in [scriptable] interfaces
+ * are declared so. Do this in a separate verification pass?
+ */
+ if (!verify_method_declaration(state->tree))
+ return FALSE;
+
+ if (doc_comments != NULL) {
+ write_indent(state->file);
+ printlist(state->file, doc_comments);
+ }
+ xpidl_write_comment(state, 2);
+
+ write_indent(state->file);
+ if (!write_method_signature(state->tree, state->file, AS_DECL, NULL))
+ return FALSE;
+ fputs(" = 0;\n\n", state->file);
+
+ return TRUE;
+}
+
+static void
+write_codefrag_line(gpointer data, gpointer user_data)
+{
+ TreeState *state = (TreeState *)user_data;
+ const char *line = (const char *)data;
+ fputs(line, state->file);
+ fputc('\n', state->file);
+}
+
+static gboolean
+codefrag(TreeState *state)
+{
+ const char *desc = IDL_CODEFRAG(state->tree).desc;
+ GSList *lines = IDL_CODEFRAG(state->tree).lines;
+ guint fragment_length;
+
+ if (strcmp(desc, "C++") && /* libIDL bug? */ strcmp(desc, "C++\r")) {
+ XPIDL_WARNING((state->tree, IDL_WARNING1,
+ "ignoring '%%{%s' escape. "
+ "(Use '%%{C++' to escape verbatim C++ code.)", desc));
+
+ return TRUE;
+ }
+
+ /*
+ * Emit #file directive to point debuggers back to the original .idl file
+ * for the duration of the code fragment. We look at internal IDL node
+ * properties _file, _line to do this; hopefully they won't change.
+ *
+ * _line seems to refer to the line immediately after the closing %}, so
+ * we backtrack to get the proper line for the beginning of the block.
+ */
+ /*
+ * Looks like getting this right means maintaining an accurate line
+ * count of everything generated, so we can set the file back to the
+ * correct line in the generated file afterwards. Skipping for now...
+ */
+
+ fragment_length = g_slist_length(lines);
+/* fprintf(state->file, "#line %d \"%s\"\n", */
+/* state->tree->_line - fragment_length - 1, */
+/* state->tree->_file); */
+
+ g_slist_foreach(lines, write_codefrag_line, (gpointer)state);
+
+ return TRUE;
+}
+
+backend *
+xpidl_header_dispatch(void)
+{
+ static backend result;
+ static nodeHandler table[IDLN_LAST];
+ static gboolean initialized = FALSE;
+
+ result.emit_prolog = header_prolog;
+ result.emit_epilog = header_epilog;
+
+ if (!initialized) {
+ table[IDLN_LIST] = list;
+ table[IDLN_ATTR_DCL] = attr_dcl;
+ table[IDLN_OP_DCL] = op_dcl;
+ table[IDLN_FORWARD_DCL] = forward_dcl;
+ table[IDLN_TYPE_ENUM] = do_enum;
+ table[IDLN_INTERFACE] = interface;
+ table[IDLN_CODEFRAG] = codefrag;
+ table[IDLN_TYPE_DCL] = do_typedef;
+ table[IDLN_CONST_DCL] = do_const_dcl;
+ table[IDLN_NATIVE] = check_native;
+ initialized = TRUE;
+ }
+
+ result.dispatch_table = table;
+ return &result;
+}