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