Back to index

lightning-sunbird  0.9+nobinonly
xpidl_util.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * Utility functions called by various backends.
00040  */ 
00041 
00042 #include "xpidl.h"
00043 
00044 /* XXXbe static */ char OOM[] = "ERROR: out of memory\n";
00045 
00046 void *
00047 xpidl_malloc(size_t nbytes)
00048 {
00049     void *p = malloc(nbytes);
00050     if (!p) {
00051         fputs(OOM, stderr);
00052         exit(1);
00053     }
00054     return p;
00055 }
00056 
00057 #ifdef XP_MAC
00058 static char *strdup(const char *c)
00059 {
00060        char   *newStr = malloc(strlen(c) + 1);
00061        if (newStr)
00062        {
00063               strcpy(newStr, c);
00064        }
00065        return newStr;
00066 }
00067 #endif
00068 
00069 char *
00070 xpidl_strdup(const char *s)
00071 {
00072     char *ns = strdup(s);
00073     if (!ns) {
00074         fputs(OOM, stderr);
00075         exit(1);
00076     }
00077     return ns;
00078 }
00079 
00080 void
00081 xpidl_write_comment(TreeState *state, int indent)
00082 {
00083     fprintf(state->file, "%*s/* ", indent, "");
00084     IDL_tree_to_IDL(state->tree, state->ns, state->file,
00085                     IDLF_OUTPUT_NO_NEWLINES |
00086                     IDLF_OUTPUT_NO_QUALIFY_IDENTS |
00087                     IDLF_OUTPUT_PROPERTIES);
00088     fputs(" */\n", state->file);
00089 }
00090 
00091 /*
00092  * Print an iid to into a supplied buffer; the buffer should be at least
00093  * UUID_LENGTH bytes.
00094  */
00095 gboolean
00096 xpidl_sprint_iid(nsID *id, char iidbuf[])
00097 {
00098     int printed;
00099 
00100     printed = sprintf(iidbuf,
00101                        "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
00102                        (PRUint32) id->m0, (PRUint32) id->m1,(PRUint32) id->m2,
00103                        (PRUint32) id->m3[0], (PRUint32) id->m3[1],
00104                        (PRUint32) id->m3[2], (PRUint32) id->m3[3],
00105                        (PRUint32) id->m3[4], (PRUint32) id->m3[5],
00106                        (PRUint32) id->m3[6], (PRUint32) id->m3[7]);
00107 
00108 #ifdef SPRINTF_RETURNS_STRING
00109     return (printed && strlen((char *)printed) == 36);
00110 #else
00111     return (printed == 36);
00112 #endif
00113 }
00114 
00115 /* We only parse the {}-less format. */
00116 static const char nsIDFmt2[] =
00117   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
00118 
00119 /*
00120  * Parse a uuid string into an nsID struct.  We cannot link against libxpcom,
00121  * so we re-implement nsID::Parse here.
00122  */
00123 gboolean
00124 xpidl_parse_iid(nsID *id, const char *str)
00125 {
00126     PRInt32 count = 0;
00127     PRInt32 n1, n2, n3[8];
00128     PRInt32 n0, i;
00129 
00130     XPT_ASSERT(str != NULL);
00131     
00132     if (strlen(str) != 36) {
00133         return FALSE;
00134     }
00135      
00136 #ifdef DEBUG_shaver_iid
00137     fprintf(stderr, "parsing iid   %s\n", str);
00138 #endif
00139 
00140     count = sscanf(str, nsIDFmt2,
00141                    &n0, &n1, &n2,
00142                    &n3[0],&n3[1],&n3[2],&n3[3],
00143                    &n3[4],&n3[5],&n3[6],&n3[7]);
00144 
00145     id->m0 = (PRInt32) n0;
00146     id->m1 = (PRInt16) n1;
00147     id->m2 = (PRInt16) n2;
00148     for (i = 0; i < 8; i++) {
00149       id->m3[i] = (PRInt8) n3[i];
00150     }
00151 
00152 #ifdef DEBUG_shaver_iid
00153     if (count == 11) {
00154         fprintf(stderr, "IID parsed to ");
00155         print_IID(id, stderr);
00156         fputs("\n", stderr);
00157     }
00158 #endif
00159     return (gboolean)(count == 11);
00160 }
00161 
00162 gboolean
00163 verify_const_declaration(IDL_tree const_tree) {
00164     struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(const_tree);
00165     const char *name = IDL_IDENT(dcl->ident).str;
00166     IDL_tree real_type;
00167 
00168     /* const -> list -> interface */
00169     if (!IDL_NODE_UP(IDL_NODE_UP(const_tree)) ||
00170         IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(const_tree)))
00171         != IDLN_INTERFACE) {
00172         IDL_tree_error(const_tree,
00173                        "const declaration \'%s\' outside interface",
00174                        name);
00175         return FALSE;
00176     }
00177 
00178     /* Could be a typedef; try to map it to the real type. */
00179     real_type = find_underlying_type(dcl->const_type);
00180     real_type = real_type ? real_type : dcl->const_type;
00181     if (IDL_NODE_TYPE(real_type) == IDLN_TYPE_INTEGER &&
00182         (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_SHORT ||
00183          IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG))
00184     {
00185         if (!IDL_TYPE_INTEGER(real_type).f_signed &&
00186             IDL_INTEGER(dcl->const_exp).value < 0)
00187         {
00188 #ifndef G_HAVE_GINT64
00189             /*
00190              * For platforms without longlong support turned on we can get
00191              * confused by the high bit of the long value and think that it
00192              * represents a negative value in an unsigned declaration.
00193              * In that case we don't know if it is the programmer who is 
00194              * confused or the compiler. So we issue a warning instead of 
00195              * an error.
00196              */
00197             if (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG)
00198             {
00199                 XPIDL_WARNING((const_tree, IDL_WARNING1,
00200                               "unsigned const declaration \'%s\' "
00201                               "initialized with (possibly) negative constant",
00202                               name));
00203                 return TRUE;
00204             }
00205 #endif
00206             IDL_tree_error(const_tree,
00207                            "unsigned const declaration \'%s\' initialized with "
00208                            "negative constant",
00209                            name);
00210             return FALSE;
00211         }
00212     } else {
00213         IDL_tree_error(const_tree,
00214                        "const declaration \'%s\' must be of type short or long",
00215                        name);
00216         return FALSE;
00217     }
00218 
00219     return TRUE;
00220 }
00221 
00222 
00223 
00224 /*
00225  * This method consolidates error checking needed when coercing the XPIDL compiler 
00226  * via the -t flag to generate output for a specific version of XPConnect.
00227  */
00228 static gboolean
00229 verify_type_fits_version(IDL_tree in_tree, IDL_tree error_tree)
00230 {
00231     if (major_version == 1 && minor_version == 1)
00232     {
00233         /* XPIDL Version 1.1 checks */
00234 
00235         /* utf8string, cstring, and astring types are not supported */
00236         if (IDL_tree_property_get(in_tree, "utf8string") != NULL ||
00237             IDL_tree_property_get(in_tree, "cstring")    != NULL ||
00238             IDL_tree_property_get(in_tree, "astring")    != NULL)
00239         {
00240             IDL_tree_error(error_tree,
00241                            "Cannot use [utf8string], [cstring] and [astring] "
00242                            "types when generating version 1.1 typelibs\n");
00243             return FALSE;
00244         }
00245     }
00246     return TRUE;
00247 }
00248 
00249 gboolean
00250 verify_attribute_declaration(IDL_tree attr_tree)
00251 {
00252     IDL_tree iface;
00253     IDL_tree ident;
00254     IDL_tree attr_type;
00255     gboolean scriptable_interface;
00256 
00257     /* We don't support attributes named IID, conflicts with static GetIID 
00258      * member. The conflict is due to certain compilers (VC++) choosing a
00259      * different vtable order, placing GetIID at the beginning regardless
00260      * of it's placement
00261      */
00262     if (strcmp(
00263         IDL_IDENT(
00264             IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data).str, 
00265         "IID") == 0) {
00266         IDL_tree_error(attr_tree,
00267                        "Attributes named IID not supported, causes vtable "
00268                        "ordering problems");
00269         return FALSE;
00270     }
00271     /* 
00272      * Verify that we've been called on an interface, and decide if the
00273      * interface was marked [scriptable].
00274      */
00275     if (IDL_NODE_UP(attr_tree) && IDL_NODE_UP(IDL_NODE_UP(attr_tree)) &&
00276         IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(attr_tree))) 
00277         == IDLN_INTERFACE)
00278     {
00279         scriptable_interface =
00280             (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
00281              != NULL);
00282     } else {
00283         IDL_tree_error(attr_tree,
00284                     "verify_attribute_declaration called on a non-interface?");
00285         return FALSE;
00286     }
00287 
00288     /*
00289      * Grab the first of the list of idents and hope that it'll
00290      * say scriptable or no.
00291      */
00292     ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data;
00293 
00294     /*
00295      * If the interface isn't scriptable, or the attribute is marked noscript,
00296      * there's no need to check.
00297      */
00298     if (!scriptable_interface ||
00299         IDL_tree_property_get(ident, "noscript") != NULL)
00300         return TRUE;
00301 
00302     /*
00303      * If it should be scriptable, check that the type is non-native. nsid,
00304      * domstring, utf8string, cstring, astring are exempted.
00305      */
00306     attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec;
00307 
00308     if (attr_type != NULL)
00309     {
00310         if (UP_IS_NATIVE(attr_type) &&
00311             IDL_tree_property_get(attr_type, "nsid") == NULL &&
00312             IDL_tree_property_get(attr_type, "domstring") == NULL &&
00313             IDL_tree_property_get(attr_type, "utf8string") == NULL &&
00314             IDL_tree_property_get(attr_type, "cstring") == NULL &&
00315             IDL_tree_property_get(attr_type, "astring") == NULL)
00316         {
00317             IDL_tree_error(attr_tree,
00318                            "attributes in [scriptable] interfaces that are "
00319                            "non-scriptable because they refer to native "
00320                            "types must be marked [noscript]\n");
00321             return FALSE;
00322         }
00323         /*
00324          * We currently don't support properties of type nsid that aren't 
00325          * pointers or references, unless they are marked [notxpcom} and 
00326          * must be read-only 
00327          */
00328          
00329         if ((IDL_tree_property_get(ident, "notxpcom") == NULL || !(IDL_ATTR_DCL(attr_tree).f_readonly)) &&
00330             IDL_tree_property_get(attr_type,"nsid") != NULL &&
00331             IDL_tree_property_get(attr_type,"ptr") == NULL &&
00332             IDL_tree_property_get(attr_type,"ref") == NULL)
00333         {
00334             IDL_tree_error(attr_tree,
00335                            "Feature not currently supported: "
00336                            "attributes with a type of nsid must be marked "
00337                            "either [ptr] or [ref], or "
00338                            "else must be marked [notxpcom] "
00339                            "and must be read-only\n");
00340             return FALSE;
00341         }
00342 
00343         /* 
00344          * Run additional error checks on the attribute type if targetting an 
00345          * older version of XPConnect.
00346          */
00347 
00348         if (!verify_type_fits_version(attr_type, attr_tree))
00349             return FALSE;
00350     }
00351 
00352     if (IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).next != NULL)
00353     {
00354         IDL_tree_error(attr_tree,
00355             "multiple attributes in a single declaration is not supported\n");
00356         return FALSE;
00357     }
00358     return TRUE;
00359 }
00360 
00361 /*
00362  * Find the underlying type of an identifier typedef.
00363  * 
00364  * All the needed tree-walking seems pretty shaky; isn't there something in
00365  * libIDL to automate this?
00366  */
00367 IDL_tree /* IDL_TYPE_DCL */
00368 find_underlying_type(IDL_tree typedef_ident)
00369 {
00370     IDL_tree up;
00371 
00372     if (typedef_ident == NULL || IDL_NODE_TYPE(typedef_ident) != IDLN_IDENT)
00373         return NULL;
00374 
00375     up = IDL_NODE_UP(typedef_ident);
00376     if (up == NULL || IDL_NODE_TYPE(up) != IDLN_LIST)
00377         return NULL;
00378     up = IDL_NODE_UP(up);
00379     if (up == NULL || IDL_NODE_TYPE(up) != IDLN_TYPE_DCL)
00380         return NULL;
00381 
00382     return IDL_TYPE_DCL(up).type_spec;
00383 }
00384 
00385 static IDL_tree /* IDL_PARAM_DCL */
00386 find_named_parameter(IDL_tree method_tree, const char *param_name)
00387 {
00388     IDL_tree iter;
00389     for (iter = IDL_OP_DCL(method_tree).parameter_dcls; iter;
00390          iter = IDL_LIST(iter).next)
00391     {
00392         IDL_tree param = IDL_LIST(iter).data;
00393         IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator;
00394         const char *current_name = IDL_IDENT(simple_decl).str;
00395         if (strcmp(current_name, param_name) == 0)
00396             return param;
00397     }
00398     return NULL;
00399 }
00400 
00401 typedef enum ParamAttrType {
00402     IID_IS,
00403     LENGTH_IS,
00404     SIZE_IS
00405 } ParamAttrType;
00406 
00407 /*
00408  * Check that parameters referred to by attributes such as size_is exist and
00409  * refer to parameters of the appropriate type.
00410  */
00411 static gboolean
00412 check_param_attribute(IDL_tree method_tree, IDL_tree param,
00413                       ParamAttrType whattocheck)
00414 {
00415     const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str;
00416     const char *referred_name = NULL;
00417     IDL_tree param_type = IDL_PARAM_DCL(param).param_type_spec;
00418     IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator;
00419     const char *param_name = IDL_IDENT(simple_decl).str;
00420     const char *attr_name;
00421     const char *needed_type;
00422 
00423     if (whattocheck == IID_IS) {
00424         attr_name = "iid_is";
00425         needed_type = "IID";
00426     } else if (whattocheck == LENGTH_IS) {
00427         attr_name = "length_is";
00428         needed_type = "unsigned long (or PRUint32)";
00429     } else if (whattocheck == SIZE_IS) {
00430         attr_name = "size_is";
00431         needed_type = "unsigned long (or PRUint32)";
00432     } else {
00433         XPT_ASSERT("asked to check an unknown attribute type!");
00434         return TRUE;
00435     }
00436     
00437     referred_name = IDL_tree_property_get(simple_decl, attr_name);
00438     if (referred_name != NULL) {
00439         IDL_tree referred_param = find_named_parameter(method_tree,
00440                                                        referred_name);
00441         IDL_tree referred_param_type;
00442         if (referred_param == NULL) {
00443             IDL_tree_error(method_tree,
00444                            "attribute [%s(%s)] refers to missing "
00445                            "parameter \"%s\"",
00446                            attr_name, referred_name, referred_name);
00447             return FALSE;
00448         }
00449         if (referred_param == param) {
00450             IDL_tree_error(method_tree,
00451                            "attribute [%s(%s)] refers to it's own parameter",
00452                            attr_name, referred_name);
00453             return FALSE;
00454         }
00455         
00456         referred_param_type = IDL_PARAM_DCL(referred_param).param_type_spec;
00457         if (whattocheck == IID_IS) {
00458             /* require IID type */
00459             if (IDL_tree_property_get(referred_param_type, "nsid") == NULL) {
00460                 IDL_tree_error(method_tree,
00461                                "target \"%s\" of [%s(%s)] attribute "
00462                                "must be of %s type",
00463                                referred_name, attr_name, referred_name,
00464                                needed_type);
00465                 return FALSE;
00466             }
00467         } else if (whattocheck == LENGTH_IS || whattocheck == SIZE_IS) {
00468             /* require PRUint32 type */
00469             IDL_tree real_type;
00470 
00471             /* Could be a typedef; try to map it to the real type. */
00472             real_type = find_underlying_type(referred_param_type);
00473             real_type = real_type ? real_type : referred_param_type;
00474 
00475             if (IDL_NODE_TYPE(real_type) != IDLN_TYPE_INTEGER ||
00476                 IDL_TYPE_INTEGER(real_type).f_signed != FALSE ||
00477                 IDL_TYPE_INTEGER(real_type).f_type != IDL_INTEGER_TYPE_LONG)
00478             {
00479                 IDL_tree_error(method_tree,
00480                                "target \"%s\" of [%s(%s)] attribute "
00481                                "must be of %s type",
00482                                referred_name, attr_name, referred_name,
00483                                needed_type);
00484 
00485                 return FALSE;
00486             }
00487         }
00488     }
00489 
00490     return TRUE;
00491 }
00492 
00493 
00494 /*
00495  * Common method verification code, called by *op_dcl in the various backends.
00496  */
00497 gboolean
00498 verify_method_declaration(IDL_tree method_tree)
00499 {
00500     struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
00501     IDL_tree iface;
00502     IDL_tree iter;
00503     gboolean notxpcom;
00504     gboolean scriptable_interface;
00505     gboolean scriptable_method;
00506     gboolean seen_retval = FALSE;
00507     const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str;
00508 
00509     /* We don't support attributes named IID, conflicts with static GetIID 
00510      * member. The conflict is due to certain compilers (VC++) choosing a
00511      * different vtable order, placing GetIID at the beginning regardless
00512      * of it's placement
00513      */
00514     if (strcmp(method_name, "GetIID") == 0) {
00515         IDL_tree_error(method_tree,
00516                        "Methods named GetIID not supported, causes vtable "
00517                        "ordering problems");
00518         return FALSE;
00519     }
00520     if (op->f_varargs) {
00521         /* We don't currently support varargs. */
00522         IDL_tree_error(method_tree, "varargs are not currently supported");
00523         return FALSE;
00524     }
00525 
00526     /* 
00527      * Verify that we've been called on an interface, and decide if the
00528      * interface was marked [scriptable].
00529      */
00530     if (IDL_NODE_UP(method_tree) && IDL_NODE_UP(IDL_NODE_UP(method_tree)) &&
00531         IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(method_tree))) 
00532         == IDLN_INTERFACE)
00533     {
00534         scriptable_interface =
00535             (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
00536              != NULL);
00537     } else {
00538         IDL_tree_error(method_tree,
00539                        "verify_method_declaration called on a non-interface?");
00540         return FALSE;
00541     }
00542 
00543     /*
00544      * Require that any method in an interface marked as [scriptable], that
00545      * *isn't* scriptable because it refers to some native type, be marked
00546      * [noscript] or [notxpcom].
00547      *
00548      * Also check that iid_is points to nsid, and length_is, size_is points
00549      * to unsigned long.
00550      */
00551     notxpcom = IDL_tree_property_get(op->ident, "notxpcom") != NULL;
00552 
00553     scriptable_method = scriptable_interface &&
00554         !notxpcom &&
00555         IDL_tree_property_get(op->ident, "noscript") == NULL;
00556 
00557     /* Loop through the parameters and check. */
00558     for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
00559         IDL_tree param = IDL_LIST(iter).data;
00560         IDL_tree param_type =
00561             IDL_PARAM_DCL(param).param_type_spec;
00562         IDL_tree simple_decl =
00563             IDL_PARAM_DCL(param).simple_declarator;
00564         const char *param_name = IDL_IDENT(simple_decl).str;
00565         
00566         /*
00567          * Reject this method if it should be scriptable and some parameter is
00568          * native that isn't marked with either nsid, domstring, utf8string, 
00569          * cstring, astring or iid_is.
00570          */
00571         if (scriptable_method &&
00572             UP_IS_NATIVE(param_type) &&
00573             IDL_tree_property_get(param_type, "nsid") == NULL &&
00574             IDL_tree_property_get(simple_decl, "iid_is") == NULL &&
00575             IDL_tree_property_get(param_type, "domstring") == NULL &&
00576             IDL_tree_property_get(param_type, "utf8string") == NULL &&
00577             IDL_tree_property_get(param_type, "cstring") == NULL &&
00578             IDL_tree_property_get(param_type, "astring") == NULL)
00579         {
00580             IDL_tree_error(method_tree,
00581                            "methods in [scriptable] interfaces that are "
00582                            "non-scriptable because they refer to native "
00583                            "types (parameter \"%s\") must be marked "
00584                            "[noscript]", param_name);
00585             return FALSE;
00586         }
00587 
00588         /* 
00589          * nsid's parameters that aren't ptr's or ref's are not currently 
00590          * supported in xpcom or non-xpcom (marked with [notxpcom]) methods 
00591          * as input parameters
00592          */
00593         if (!(notxpcom && IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) &&
00594             IDL_tree_property_get(param_type, "nsid") != NULL &&
00595             IDL_tree_property_get(param_type, "ptr") == NULL &&
00596             IDL_tree_property_get(param_type, "ref") == NULL) 
00597         {
00598             IDL_tree_error(method_tree,
00599                            "Feature currently not supported: "
00600                            "parameter \"%s\" is of type nsid and "
00601                            "must be marked either [ptr] or [ref] "
00602                            "or method \"%s\" must be marked [notxpcom] "
00603                            "and must not be an input parameter",
00604                            param_name,
00605                            method_name);
00606             return FALSE;
00607         }
00608         /*
00609          * Sanity checks on return values.
00610          */
00611         if (IDL_tree_property_get(simple_decl, "retval") != NULL) {
00612             if (IDL_LIST(iter).next != NULL) {
00613                 IDL_tree_error(method_tree,
00614                                "only the last parameter can be marked [retval]");
00615                 return FALSE;
00616             }
00617             if (op->op_type_spec) {
00618                 IDL_tree_error(method_tree,
00619                                "can't have [retval] with non-void return type");
00620                 return FALSE;
00621             }
00622             /* In case XPConnect relaxes the retval-is-last restriction. */
00623             if (seen_retval) {
00624                 IDL_tree_error(method_tree,
00625                                "can't have more than one [retval] parameter");
00626                 return FALSE;
00627             }
00628             seen_retval = TRUE;
00629         }
00630 
00631         /*
00632          * Confirm that [shared] attributes are only used with string, wstring,
00633          * or native (but not nsid, domstring, utf8string, cstring or astring) 
00634          * and can't be used with [array].
00635          */
00636         if (IDL_tree_property_get(simple_decl, "shared") != NULL) {
00637             IDL_tree real_type;
00638             real_type = find_underlying_type(param_type);
00639             real_type = real_type ? real_type : param_type;
00640 
00641             if (IDL_tree_property_get(simple_decl, "array") != NULL) {
00642                 IDL_tree_error(method_tree,
00643                                "[shared] parameter \"%s\" cannot "
00644                                "be of array type", param_name);
00645                 return FALSE;
00646             }                
00647 
00648             if (!(IDL_NODE_TYPE(real_type) == IDLN_TYPE_STRING ||
00649                   IDL_NODE_TYPE(real_type) == IDLN_TYPE_WIDE_STRING ||
00650                   (UP_IS_NATIVE(real_type) &&
00651                    !IDL_tree_property_get(real_type, "nsid") &&
00652                    !IDL_tree_property_get(real_type, "domstring")  &&
00653                    !IDL_tree_property_get(real_type, "utf8string") &&
00654                    !IDL_tree_property_get(real_type, "cstring")    &&
00655                    !IDL_tree_property_get(real_type, "astring"))))
00656             {
00657                 IDL_tree_error(method_tree,
00658                                "[shared] parameter \"%s\" must be of type "
00659                                "string, wstring or native", param_name);
00660                 return FALSE;
00661             }
00662         }
00663 
00664         /*
00665          * inout is not allowed with "domstring", "UTF8String", "CString" 
00666          * and "AString" types
00667          */
00668         if (IDL_PARAM_DCL(param).attr == IDL_PARAM_INOUT &&
00669             UP_IS_NATIVE(param_type) &&
00670             (IDL_tree_property_get(param_type, "domstring")  != NULL ||
00671              IDL_tree_property_get(param_type, "utf8string") != NULL ||
00672              IDL_tree_property_get(param_type, "cstring")    != NULL ||
00673              IDL_tree_property_get(param_type, "astring")    != NULL )) {
00674             IDL_tree_error(method_tree,
00675                            "[domstring], [utf8string], [cstring], [astring] "
00676                            "types cannot be used as inout parameters");
00677             return FALSE;
00678         }
00679 
00680 
00681         /*
00682          * arrays of domstring, utf8string, cstring, astring types not allowed
00683          */
00684         if (IDL_tree_property_get(simple_decl, "array") != NULL &&
00685             UP_IS_NATIVE(param_type) &&
00686             (IDL_tree_property_get(param_type, "domstring")  != NULL ||
00687              IDL_tree_property_get(param_type, "utf8string") != NULL ||
00688              IDL_tree_property_get(param_type, "cstring")    != NULL ||
00689              IDL_tree_property_get(param_type, "astring")    != NULL)) {
00690             IDL_tree_error(method_tree,
00691                            "[domstring], [utf8string], [cstring], [astring] "
00692                            "types cannot be used in array parameters");
00693             return FALSE;
00694         }                
00695 
00696         if (!check_param_attribute(method_tree, param, IID_IS) ||
00697             !check_param_attribute(method_tree, param, LENGTH_IS) ||
00698             !check_param_attribute(method_tree, param, SIZE_IS))
00699             return FALSE;
00700 
00701         /* 
00702          * Run additional error checks on the parameter type if targetting an 
00703          * older version of XPConnect.
00704          */
00705 
00706         if (!verify_type_fits_version(param_type, method_tree))
00707             return FALSE;
00708         
00709     }
00710     
00711     /* XXX q: can return type be nsid? */
00712     /* Native return type? */
00713     if (scriptable_method &&
00714         op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) &&
00715         IDL_tree_property_get(op->op_type_spec, "nsid") == NULL &&
00716         IDL_tree_property_get(op->op_type_spec, "domstring") == NULL &&
00717         IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL &&
00718         IDL_tree_property_get(op->op_type_spec, "cstring") == NULL &&
00719         IDL_tree_property_get(op->op_type_spec, "astring") == NULL)
00720     {
00721         IDL_tree_error(method_tree,
00722                        "methods in [scriptable] interfaces that are "
00723                        "non-scriptable because they return native "
00724                        "types must be marked [noscript]");
00725         return FALSE;
00726     }
00727 
00728 
00729     /* 
00730      * nsid's parameters that aren't ptr's or ref's are not currently 
00731      * supported in xpcom
00732      */
00733     if (!notxpcom &&
00734         op->op_type_spec != NULL &&
00735         IDL_tree_property_get(op->op_type_spec, "nsid") != NULL &&
00736         IDL_tree_property_get(op->op_type_spec, "ptr") == NULL &&
00737         IDL_tree_property_get(op->op_type_spec, "ref") == NULL) 
00738     {
00739         IDL_tree_error(method_tree,
00740                        "Feature currently not supported: "
00741                        "return value is of type nsid and "
00742                        "must be marked either [ptr] or [ref], "
00743                        "or else method \"%s\" must be marked [notxpcom] ",
00744                        method_name);
00745         return FALSE;
00746     }
00747 
00748     /* 
00749      * Run additional error checks on the return type if targetting an 
00750      * older version of XPConnect.
00751      */
00752 
00753     if (op->op_type_spec != NULL &&
00754         !verify_type_fits_version(op->op_type_spec, method_tree))
00755     {
00756         return FALSE;
00757     }
00758 
00759     return TRUE;
00760 }
00761 
00762 /*
00763  * Verify that a native declaration has an associated C++ expression, i.e. that
00764  * it's of the form native <idl-name>(<c++-name>)
00765  */
00766 gboolean
00767 check_native(TreeState *state)
00768 {
00769     char *native_name;
00770     /* require that native declarations give a native type */
00771     if (IDL_NATIVE(state->tree).user_type) 
00772         return TRUE;
00773     native_name = IDL_IDENT(IDL_NATIVE(state->tree).ident).str;
00774     IDL_tree_error(state->tree,
00775                    "``native %s;'' needs C++ type: ``native %s(<C++ type>);''",
00776                    native_name, native_name);
00777     return FALSE;
00778 }
00779 
00780 /*
00781  * Print a GSList as char strings to a file.
00782  */
00783 void
00784 printlist(FILE *outfile, GSList *slist)
00785 {
00786     guint i;
00787     guint len = g_slist_length(slist);
00788 
00789     for(i = 0; i < len; i++) {
00790         fprintf(outfile, 
00791                 "%s\n", (char *)g_slist_nth_data(slist, i));
00792     }
00793 }
00794 
00795 void
00796 xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data)
00797 {
00798     IDL_tree_func_data tfd;
00799 
00800     while (p) {
00801         struct _IDL_LIST *list = &IDL_LIST(p);
00802         tfd.tree = list->data;
00803         if (!foreach(&tfd, user_data))
00804             return;
00805         p = list->next;
00806     }
00807 }
00808 
00809 /*
00810  * Verify that the interface declaration is correct
00811  */
00812 gboolean
00813 verify_interface_declaration(IDL_tree interface_tree)
00814 {
00815     IDL_tree iter;
00816     /* 
00817      * If we have the scriptable attribute then make sure all of our direct
00818      * parents have it as well.
00819      * NOTE: We don't recurse since all interfaces will fall through here
00820      */
00821     if (IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident, 
00822         "scriptable")) {
00823         for (iter = IDL_INTERFACE(interface_tree).inheritance_spec; iter; 
00824             iter = IDL_LIST(iter).next) {
00825             if (IDL_tree_property_get(
00826                 IDL_INTERFACE(iter).ident, "scriptable") == 0) {
00827                 XPIDL_WARNING((interface_tree,IDL_WARNING1,
00828                     "%s is scriptable but inherits from the non-scriptable interface %s\n",
00829                     IDL_IDENT(IDL_INTERFACE(interface_tree).ident).str,
00830                     IDL_IDENT(IDL_INTERFACE(iter).ident).str));
00831             }
00832         }
00833     }
00834     return TRUE;
00835 }
00836 
00837 /*
00838  * Return a pointer to the start of the base filename of path
00839  */
00840 const char *
00841 xpidl_basename(const char * path)
00842 {
00843     const char * result = g_basename(path);
00844     /* 
00845      *If this is windows then we'll handle either / or \ as a separator
00846      * g_basename only handles \ for windows
00847      */
00848 #if defined(XP_WIN32)
00849     const char * slash = strrchr(path, '/');
00850     /* If we found a slash and its after the current default OS separator */
00851     if (slash != NULL && (slash > result))
00852         result = slash + 1;
00853 #endif
00854     return result;
00855 }