root/lang/pascal/xpidlpas/xpidlpas_util.c

Revision 4249, 30.3 kB (checked in by plus7, 12 months ago)

initial import

  • Property svn:executable set to *
Line 
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *   Itou Takanori <necottie@nesitive.net>
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the NPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the NPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39/*
40 * Utility functions called by various backends.
41 */
42
43#include "xpidlpas.h"
44
45/* XXXbe static */ char OOM[] = "ERROR: out of memory\n";
46
47void *
48xpidl_malloc(size_t nbytes)
49{
50    void *p = malloc(nbytes);
51    if (!p) {
52        fputs(OOM, stderr);
53        exit(1);
54    }
55    return p;
56}
57
58#ifdef XP_MAC
59static char *strdup(const char *c)
60{
61    char    *newStr = malloc(strlen(c) + 1);
62    if (newStr)
63    {
64        strcpy(newStr, c);
65    }
66    return newStr;
67}
68#endif
69
70char *
71xpidl_strdup(const char *s)
72{
73    char *ns = strdup(s);
74    if (!ns) {
75        fputs(OOM, stderr);
76        exit(1);
77    }
78    return ns;
79}
80
81void
82xpidl_write_comment(TreeState *state, int indent)
83{
84    if (comment_level < 2) return;
85   
86    fprintf(state->file, "%*s(* ", indent, "");
87    IDL_tree_to_IDL(state->tree, state->ns, state->file,
88                    IDLF_OUTPUT_NO_NEWLINES |
89                    IDLF_OUTPUT_NO_QUALIFY_IDENTS |
90                    IDLF_OUTPUT_PROPERTIES);
91    fputs(" *)\n", state->file);
92}
93
94/*
95 * Print an iid to into a supplied buffer; the buffer should be at least
96 * UUID_LENGTH bytes.
97 */
98gboolean
99xpidl_sprint_iid(nsID *id, char iidbuf[])
100{
101    int printed;
102
103    printed = sprintf(iidbuf,
104                       "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
105                       (PRUint32) id->m0, (PRUint32) id->m1,(PRUint32) id->m2,
106                       (PRUint32) id->m3[0], (PRUint32) id->m3[1],
107                       (PRUint32) id->m3[2], (PRUint32) id->m3[3],
108                       (PRUint32) id->m3[4], (PRUint32) id->m3[5],
109                       (PRUint32) id->m3[6], (PRUint32) id->m3[7]);
110
111#ifdef SPRINTF_RETURNS_STRING
112    return (printed && strlen((char *)printed) == 36);
113#else
114    return (printed == 36);
115#endif
116}
117
118/* We only parse the {}-less format. */
119static const char nsIDFmt2[] =
120  "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
121
122/*
123 * Parse a uuid string into an nsID struct.  We cannot link against libxpcom,
124 * so we re-implement nsID::Parse here.
125 */
126gboolean
127xpidl_parse_iid(nsID *id, const char *str)
128{
129    PRInt32 count = 0;
130    PRInt32 n1, n2, n3[8];
131    PRInt32 n0, i;
132
133    XPT_ASSERT(str != NULL);
134   
135    if (strlen(str) != 36) {
136        return FALSE;
137    }
138     
139#ifdef DEBUG_shaver_iid
140    fprintf(stderr, "parsing iid   %s\n", str);
141#endif
142
143    count = sscanf(str, nsIDFmt2,
144                   &n0, &n1, &n2,
145                   &n3[0],&n3[1],&n3[2],&n3[3],
146                   &n3[4],&n3[5],&n3[6],&n3[7]);
147
148    id->m0 = (PRInt32) n0;
149    id->m1 = (PRInt16) n1;
150    id->m2 = (PRInt16) n2;
151    for (i = 0; i < 8; i++) {
152      id->m3[i] = (PRInt8) n3[i];
153    }
154
155#ifdef DEBUG_shaver_iid
156    if (count == 11) {
157        fprintf(stderr, "IID parsed to ");
158        print_IID(id, stderr);
159        fputs("\n", stderr);
160    }
161#endif
162    return (gboolean)(count == 11);
163}
164
165gboolean
166verify_const_declaration(IDL_tree const_tree) {
167    struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(const_tree);
168    const char *name = IDL_IDENT(dcl->ident).str;
169    IDL_tree real_type;
170
171    /* const -> list -> interface */
172    if (!IDL_NODE_UP(IDL_NODE_UP(const_tree)) ||
173        IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(const_tree)))
174        != IDLN_INTERFACE) {
175        IDL_tree_error(const_tree,
176                       "const declaration \'%s\' outside interface",
177                       name);
178        return FALSE;
179    }
180
181    /* Could be a typedef; try to map it to the real type. */
182    real_type = find_underlying_type(dcl->const_type);
183    real_type = real_type ? real_type : dcl->const_type;
184    if (IDL_NODE_TYPE(real_type) == IDLN_TYPE_INTEGER &&
185        (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_SHORT ||
186         IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG))
187    {
188        if (!IDL_TYPE_INTEGER(real_type).f_signed &&
189            IDL_INTEGER(dcl->const_exp).value < 0)
190        {
191#ifndef G_HAVE_GINT64
192            /*
193             * For platforms without longlong support turned on we can get
194             * confused by the high bit of the long value and think that it
195             * represents a negative value in an unsigned declaration.
196             * In that case we don't know if it is the programmer who is
197             * confused or the compiler. So we issue a warning instead of
198             * an error.
199             */
200            if (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG)
201            {
202                XPIDL_WARNING((const_tree, IDL_WARNING1,
203                              "unsigned const declaration \'%s\' "
204                              "initialized with (possibly) negative constant",
205                              name));
206                return TRUE;
207            }
208#endif
209            IDL_tree_error(const_tree,
210                           "unsigned const declaration \'%s\' initialized with "
211                           "negative constant",
212                           name);
213            return FALSE;
214        }
215    } else {
216        IDL_tree_error(const_tree,
217                       "const declaration \'%s\' must be of type short or long",
218                       name);
219        return FALSE;
220    }
221
222    return TRUE;
223}
224
225
226
227/*
228 * This method consolidates error checking needed when coercing the XPIDL compiler
229 * via the -t flag to generate output for a specific version of XPConnect.
230 */
231static gboolean
232verify_type_fits_version(IDL_tree in_tree, IDL_tree error_tree)
233{
234    if (major_version == 1 && minor_version == 1)
235    {
236        /* XPIDL Version 1.1 checks */
237
238        /* utf8string, cstring, and astring types are not supported */
239        if (IDL_tree_property_get(in_tree, "utf8string") != NULL ||
240            IDL_tree_property_get(in_tree, "cstring")    != NULL ||
241            IDL_tree_property_get(in_tree, "astring")    != NULL)
242        {
243            IDL_tree_error(error_tree,
244                           "Cannot use [utf8string], [cstring] and [astring] "
245                           "types when generating version 1.1 typelibs\n");
246            return FALSE;
247        }
248    }
249    return TRUE;
250}
251
252gboolean
253verify_attribute_declaration(IDL_tree attr_tree)
254{
255    IDL_tree iface;
256    IDL_tree ident;
257    IDL_tree attr_type;
258    gboolean scriptable_interface;
259
260    /* We don't support attributes named IID, conflicts with static GetIID
261     * member. The conflict is due to certain compilers (VC++) choosing a
262     * different vtable order, placing GetIID at the beginning regardless
263     * of it's placement
264     */
265    if (strcmp(
266        IDL_IDENT(
267            IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data).str,
268        "IID") == 0) {
269        IDL_tree_error(attr_tree,
270                       "Attributes named IID not supported, causes vtable "
271                       "ordering problems");
272        return FALSE;
273    }
274    /*
275     * Verify that we've been called on an interface, and decide if the
276     * interface was marked [scriptable].
277     */
278    if (IDL_NODE_UP(attr_tree) && IDL_NODE_UP(IDL_NODE_UP(attr_tree)) &&
279        IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(attr_tree)))
280        == IDLN_INTERFACE)
281    {
282        scriptable_interface =
283            (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
284             != NULL);
285    } else {
286        IDL_tree_error(attr_tree,
287                    "verify_attribute_declaration called on a non-interface?");
288        return FALSE;
289    }
290
291    /*
292     * Grab the first of the list of idents and hope that it'll
293     * say scriptable or no.
294     */
295    ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data;
296
297    /*
298     * If the interface isn't scriptable, or the attribute is marked noscript,
299     * there's no need to check.
300     */
301    if (!scriptable_interface ||
302        IDL_tree_property_get(ident, "noscript") != NULL)
303        return TRUE;
304
305    /*
306     * If it should be scriptable, check that the type is non-native. nsid,
307     * domstring, utf8string, cstring, astring are exempted.
308     */
309    attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec;
310
311    if (attr_type != NULL)
312    {
313        if (UP_IS_NATIVE(attr_type) &&
314            IDL_tree_property_get(attr_type, "nsid") == NULL &&
315            IDL_tree_property_get(attr_type, "domstring") == NULL &&
316            IDL_tree_property_get(attr_type, "utf8string") == NULL &&
317            IDL_tree_property_get(attr_type, "cstring") == NULL &&
318            IDL_tree_property_get(attr_type, "astring") == NULL)
319        {
320            IDL_tree_error(attr_tree,
321                           "attributes in [scriptable] interfaces that are "
322                           "non-scriptable because they refer to native "
323                           "types must be marked [noscript]\n");
324            return FALSE;
325        }
326        /*
327         * We currently don't support properties of type nsid that aren't
328         * pointers or references, unless they are marked [notxpcom} and
329         * must be read-only
330         */
331         
332        if ((IDL_tree_property_get(ident, "notxpcom") == NULL || !(IDL_ATTR_DCL(attr_tree).f_readonly)) &&
333            IDL_tree_property_get(attr_type,"nsid") != NULL &&
334            IDL_tree_property_get(attr_type,"ptr") == NULL &&
335            IDL_tree_property_get(attr_type,"ref") == NULL)
336        {
337            IDL_tree_error(attr_tree,
338                           "Feature not currently supported: "
339                           "attributes with a type of nsid must be marked "
340                           "either [ptr] or [ref], or "
341                           "else must be marked [notxpcom] "
342                           "and must be read-only\n");
343            return FALSE;
344        }
345
346        /*
347         * Run additional error checks on the attribute type if targetting an
348         * older version of XPConnect.
349         */
350
351        if (!verify_type_fits_version(attr_type, attr_tree))
352            return FALSE;
353    }
354
355    if (IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).next != NULL)
356    {
357        IDL_tree_error(attr_tree,
358            "multiple attributes in a single declaration is not supported\n");
359        return FALSE;
360    }
361    return TRUE;
362}
363
364/*
365 * Find the underlying type of an identifier typedef.
366 *
367 * All the needed tree-walking seems pretty shaky; isn't there something in
368 * libIDL to automate this?
369 */
370IDL_tree /* IDL_TYPE_DCL */
371find_underlying_type(IDL_tree typedef_ident)
372{
373    IDL_tree up;
374
375    if (typedef_ident == NULL || IDL_NODE_TYPE(typedef_ident) != IDLN_IDENT)
376        return NULL;
377
378    up = IDL_NODE_UP(typedef_ident);
379    if (up == NULL || IDL_NODE_TYPE(up) != IDLN_LIST)
380        return NULL;
381    up = IDL_NODE_UP(up);
382    if (up == NULL || IDL_NODE_TYPE(up) != IDLN_TYPE_DCL)
383        return NULL;
384
385    return IDL_TYPE_DCL(up).type_spec;
386}
387
388static IDL_tree /* IDL_PARAM_DCL */
389find_named_parameter(IDL_tree method_tree, const char *param_name)
390{
391    IDL_tree iter;
392    for (iter = IDL_OP_DCL(method_tree).parameter_dcls; iter;
393         iter = IDL_LIST(iter).next)
394    {
395        IDL_tree param = IDL_LIST(iter).data;
396        IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator;
397        const char *current_name = IDL_IDENT(simple_decl).str;
398        if (strcmp(current_name, param_name) == 0)
399            return param;
400    }
401    return NULL;
402}
403
404typedef enum ParamAttrType {
405    IID_IS,
406    LENGTH_IS,
407    SIZE_IS
408} ParamAttrType;
409
410/*
411 * Check that parameters referred to by attributes such as size_is exist and
412 * refer to parameters of the appropriate type.
413 */
414static gboolean
415check_param_attribute(IDL_tree method_tree, IDL_tree param,
416                      ParamAttrType whattocheck)
417{
418    const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str;
419    const char *referred_name = NULL;
420    IDL_tree param_type = IDL_PARAM_DCL(param).param_type_spec;
421    IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator;
422    const char *param_name = IDL_IDENT(simple_decl).str;
423    const char *attr_name;
424    const char *needed_type;
425
426    if (whattocheck == IID_IS) {
427        attr_name = "iid_is";
428        needed_type = "IID";
429    } else if (whattocheck == LENGTH_IS) {
430        attr_name = "length_is";
431        needed_type = "unsigned long (or PRUint32)";
432    } else if (whattocheck == SIZE_IS) {
433        attr_name = "size_is";
434        needed_type = "unsigned long (or PRUint32)";
435    } else {
436        XPT_ASSERT("asked to check an unknown attribute type!");
437        return TRUE;
438    }
439   
440    referred_name = IDL_tree_property_get(simple_decl, attr_name);
441    if (referred_name != NULL) {
442        IDL_tree referred_param = find_named_parameter(method_tree,
443                                                       referred_name);
444        IDL_tree referred_param_type;
445        if (referred_param == NULL) {
446            IDL_tree_error(method_tree,
447                           "attribute [%s(%s)] refers to missing "
448                           "parameter \"%s\"",
449                           attr_name, referred_name, referred_name);
450            return FALSE;
451        }
452        if (referred_param == param) {
453            IDL_tree_error(method_tree,
454                           "attribute [%s(%s)] refers to it's own parameter",
455                           attr_name, referred_name);
456            return FALSE;
457        }
458       
459        referred_param_type = IDL_PARAM_DCL(referred_param).param_type_spec;
460        if (whattocheck == IID_IS) {
461            /* require IID type */
462            if (IDL_tree_property_get(referred_param_type, "nsid") == NULL) {
463                IDL_tree_error(method_tree,
464                               "target \"%s\" of [%s(%s)] attribute "
465                               "must be of %s type",
466                               referred_name, attr_name, referred_name,
467                               needed_type);
468                return FALSE;
469            }
470        } else if (whattocheck == LENGTH_IS || whattocheck == SIZE_IS) {
471            /* require PRUint32 type */
472            IDL_tree real_type;
473
474            /* Could be a typedef; try to map it to the real type. */
475            real_type = find_underlying_type(referred_param_type);
476            real_type = real_type ? real_type : referred_param_type;
477
478            if (IDL_NODE_TYPE(real_type) != IDLN_TYPE_INTEGER ||
479                IDL_TYPE_INTEGER(real_type).f_signed != FALSE ||
480                IDL_TYPE_INTEGER(real_type).f_type != IDL_INTEGER_TYPE_LONG)
481            {
482                IDL_tree_error(method_tree,
483                               "target \"%s\" of [%s(%s)] attribute "
484                               "must be of %s type",
485                               referred_name, attr_name, referred_name,
486                               needed_type);
487
488                return FALSE;
489            }
490        }
491    }
492
493    return TRUE;
494}
495
496
497/*
498 * Common method verification code, called by *op_dcl in the various backends.
499 */
500gboolean
501verify_method_declaration(IDL_tree method_tree)
502{
503    struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
504    IDL_tree iface;
505    IDL_tree iter;
506    gboolean notxpcom;
507    gboolean scriptable_interface;
508    gboolean scriptable_method;
509    gboolean seen_retval = FALSE;
510    const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str;
511
512    /* We don't support attributes named IID, conflicts with static GetIID
513     * member. The conflict is due to certain compilers (VC++) choosing a
514     * different vtable order, placing GetIID at the beginning regardless
515     * of it's placement
516     */
517    if (strcmp(method_name, "GetIID") == 0) {
518        IDL_tree_error(method_tree,
519                       "Methods named GetIID not supported, causes vtable "
520                       "ordering problems");
521        return FALSE;
522    }
523    if (op->f_varargs) {
524        /* We don't currently support varargs. */
525        IDL_tree_error(method_tree, "varargs are not currently supported");
526        return FALSE;
527    }
528
529    /*
530     * Verify that we've been called on an interface, and decide if the
531     * interface was marked [scriptable].
532     */
533    if (IDL_NODE_UP(method_tree) && IDL_NODE_UP(IDL_NODE_UP(method_tree)) &&
534        IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(method_tree)))
535        == IDLN_INTERFACE)
536    {
537        scriptable_interface =
538            (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
539             != NULL);
540    } else {
541        IDL_tree_error(method_tree,
542                       "verify_method_declaration called on a non-interface?");
543        return FALSE;
544    }
545
546    /*
547     * Require that any method in an interface marked as [scriptable], that
548     * *isn't* scriptable because it refers to some native type, be marked
549     * [noscript] or [notxpcom].
550     *
551     * Also check that iid_is points to nsid, and length_is, size_is points
552     * to unsigned long.
553     */
554    notxpcom = IDL_tree_property_get(op->ident, "notxpcom") != NULL;
555
556    scriptable_method = scriptable_interface &&
557        !notxpcom &&
558        IDL_tree_property_get(op->ident, "noscript") == NULL;
559
560    /* Loop through the parameters and check. */
561    for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
562        IDL_tree param = IDL_LIST(iter).data;
563        IDL_tree param_type =
564            IDL_PARAM_DCL(param).param_type_spec;
565        IDL_tree simple_decl =
566            IDL_PARAM_DCL(param).simple_declarator;
567        const char *param_name = IDL_IDENT(simple_decl).str;
568       
569        /*
570         * Reject this method if it should be scriptable and some parameter is
571         * native that isn't marked with either nsid, domstring, utf8string,
572         * cstring, astring or iid_is.
573         */
574        if (scriptable_method &&
575            UP_IS_NATIVE(param_type) &&
576            IDL_tree_property_get(param_type, "nsid") == NULL &&
577            IDL_tree_property_get(simple_decl, "iid_is") == NULL &&
578            IDL_tree_property_get(param_type, "domstring") == NULL &&
579            IDL_tree_property_get(param_type, "utf8string") == NULL &&
580            IDL_tree_property_get(param_type, "cstring") == NULL &&
581            IDL_tree_property_get(param_type, "astring") == NULL)
582        {
583            IDL_tree_error(method_tree,
584                           "methods in [scriptable] interfaces that are "
585                           "non-scriptable because they refer to native "
586                           "types (parameter \"%s\") must be marked "
587                           "[noscript]", param_name);
588            return FALSE;
589        }
590
591        /*
592         * nsid's parameters that aren't ptr's or ref's are not currently
593         * supported in xpcom or non-xpcom (marked with [notxpcom]) methods
594         * as input parameters
595         */
596        if (!(notxpcom && IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) &&
597            IDL_tree_property_get(param_type, "nsid") != NULL &&
598            IDL_tree_property_get(param_type, "ptr") == NULL &&
599            IDL_tree_property_get(param_type, "ref") == NULL)
600        {
601            IDL_tree_error(method_tree,
602                           "Feature currently not supported: "
603                           "parameter \"%s\" is of type nsid and "
604                           "must be marked either [ptr] or [ref] "
605                           "or method \"%s\" must be marked [notxpcom] "
606                           "and must not be an input parameter",
607                           param_name,
608                           method_name);
609            return FALSE;
610        }
611        /*
612         * Sanity checks on return values.
613         */
614        if (IDL_tree_property_get(simple_decl, "retval") != NULL) {
615            if (IDL_LIST(iter).next != NULL) {
616                IDL_tree_error(method_tree,
617                               "only the last parameter can be marked [retval]");
618                return FALSE;
619            }
620            if (op->op_type_spec) {
621                IDL_tree_error(method_tree,
622                               "can't have [retval] with non-void return type");
623                return FALSE;
624            }
625            /* In case XPConnect relaxes the retval-is-last restriction. */
626            if (seen_retval) {
627                IDL_tree_error(method_tree,
628                               "can't have more than one [retval] parameter");
629                return FALSE;
630            }
631            seen_retval = TRUE;
632        }
633
634        /*
635         * Confirm that [shared] attributes are only used with string, wstring,
636         * or native (but not nsid, domstring, utf8string, cstring or astring)
637         * and can't be used with [array].
638         */
639        if (IDL_tree_property_get(simple_decl, "shared") != NULL) {
640            IDL_tree real_type;
641            real_type = find_underlying_type(param_type);
642            real_type = real_type ? real_type : param_type;
643
644            if (IDL_tree_property_get(simple_decl, "array") != NULL) {
645                IDL_tree_error(method_tree,
646                               "[shared] parameter \"%s\" cannot "
647                               "be of array type", param_name);
648                return FALSE;
649            }               
650
651            if (!(IDL_NODE_TYPE(real_type) == IDLN_TYPE_STRING ||
652                  IDL_NODE_TYPE(real_type) == IDLN_TYPE_WIDE_STRING ||
653                  (UP_IS_NATIVE(real_type) &&
654                   !IDL_tree_property_get(real_type, "nsid") &&
655                   !IDL_tree_property_get(real_type, "domstring")  &&
656                   !IDL_tree_property_get(real_type, "utf8string") &&
657                   !IDL_tree_property_get(real_type, "cstring")    &&
658                   !IDL_tree_property_get(real_type, "astring"))))
659            {
660                IDL_tree_error(method_tree,
661                               "[shared] parameter \"%s\" must be of type "
662                               "string, wstring or native", param_name);
663                return FALSE;
664            }
665        }
666
667        /*
668         * inout is not allowed with "domstring", "UTF8String", "CString"
669         * and "AString" types
670         */
671        if (IDL_PARAM_DCL(param).attr == IDL_PARAM_INOUT &&
672            UP_IS_NATIVE(param_type) &&
673            (IDL_tree_property_get(param_type, "domstring")  != NULL ||
674             IDL_tree_property_get(param_type, "utf8string") != NULL ||
675             IDL_tree_property_get(param_type, "cstring")    != NULL ||
676             IDL_tree_property_get(param_type, "astring")    != NULL )) {
677            IDL_tree_error(method_tree,
678                           "[domstring], [utf8string], [cstring], [astring] "
679                           "types cannot be used as inout parameters");
680            return FALSE;
681        }
682
683
684        /*
685         * arrays of domstring, utf8string, cstring, astring types not allowed
686         */
687        if (IDL_tree_property_get(simple_decl, "array") != NULL &&
688            UP_IS_NATIVE(param_type) &&
689            (IDL_tree_property_get(param_type, "domstring")  != NULL ||
690             IDL_tree_property_get(param_type, "utf8string") != NULL ||
691             IDL_tree_property_get(param_type, "cstring")    != NULL ||
692             IDL_tree_property_get(param_type, "astring")    != NULL)) {
693            IDL_tree_error(method_tree,
694                           "[domstring], [utf8string], [cstring], [astring] "
695                           "types cannot be used in array parameters");
696            return FALSE;
697        }               
698
699        if (!check_param_attribute(method_tree, param, IID_IS) ||
700            !check_param_attribute(method_tree, param, LENGTH_IS) ||
701            !check_param_attribute(method_tree, param, SIZE_IS))
702            return FALSE;
703
704        /*
705         * Run additional error checks on the parameter type if targetting an
706         * older version of XPConnect.
707         */
708
709        if (!verify_type_fits_version(param_type, method_tree))
710            return FALSE;
711       
712    }
713   
714    /* XXX q: can return type be nsid? */
715    /* Native return type? */
716    if (scriptable_method &&
717        op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) &&
718        IDL_tree_property_get(op->op_type_spec, "nsid") == NULL &&
719        IDL_tree_property_get(op->op_type_spec, "domstring") == NULL &&
720        IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL &&
721        IDL_tree_property_get(op->op_type_spec, "cstring") == NULL &&
722        IDL_tree_property_get(op->op_type_spec, "astring") == NULL)
723    {
724        IDL_tree_error(method_tree,
725                       "methods in [scriptable] interfaces that are "
726                       "non-scriptable because they return native "
727                       "types must be marked [noscript]");
728        return FALSE;
729    }
730
731
732    /*
733     * nsid's parameters that aren't ptr's or ref's are not currently
734     * supported in xpcom
735     */
736    if (!notxpcom &&
737        op->op_type_spec != NULL &&
738        IDL_tree_property_get(op->op_type_spec, "nsid") != NULL &&
739        IDL_tree_property_get(op->op_type_spec, "ptr") == NULL &&
740        IDL_tree_property_get(op->op_type_spec, "ref") == NULL)
741    {
742        IDL_tree_error(method_tree,
743                       "Feature currently not supported: "
744                       "return value is of type nsid and "
745                       "must be marked either [ptr] or [ref], "
746                       "or else method \"%s\" must be marked [notxpcom] ",
747                       method_name);
748        return FALSE;
749    }
750
751    /*
752     * Run additional error checks on the return type if targetting an
753     * older version of XPConnect.
754     */
755
756    if (op->op_type_spec != NULL &&
757        !verify_type_fits_version(op->op_type_spec, method_tree))
758    {
759        return FALSE;
760    }
761
762    return TRUE;
763}
764
765/*
766 * Verify that a native declaration has an associated C++ expression, i.e. that
767 * it's of the form native <idl-name>(<c++-name>)
768 */
769gboolean
770check_native(TreeState *state)
771{
772    char *native_name;
773    /* require that native declarations give a native type */
774    if (IDL_NATIVE(state->tree).user_type)
775        return TRUE;
776    native_name = IDL_IDENT(IDL_NATIVE(state->tree).ident).str;
777    IDL_tree_error(state->tree,
778                   "``native %s;'' needs C++ type: ``native %s(<C++ type>);''",
779                   native_name, native_name);
780    return FALSE;
781}
782
783/*
784 * Print a GSList as char strings to a file.
785 */
786void
787printlist(FILE *outfile, GSList *slist)
788{
789    guint i, j;
790    guint len = g_slist_length(slist);
791    char prev, cur;
792    char* text;
793    gboolean comment = FALSE;
794   
795    for(i = 0; i < len; i++) {
796        prev = '\0';
797        text = (char *)g_slist_nth_data(slist, i);
798       
799        for(j=0; (cur=text[j])!='\0'; j++, prev=cur) {
800            if(comment) {
801                if(prev == '*') {
802                    fputc('*', outfile);
803                    if(cur == '/') {
804                        fputc(')', outfile);
805                        comment = FALSE;
806                        cur = '\0';
807                        continue;
808                    }
809                }
810                if(cur!='*')
811                    fputc(cur, outfile);
812            } else {
813                if(prev == '/') {
814                    if(cur == '*') {
815                        fputs("(*", outfile);
816                        comment = TRUE;
817                        prev = '\0';
818                        continue;
819                    } else
820                        fputc('/', outfile);
821                }
822                if(cur!='/')
823                    fputc(cur, outfile);
824            }
825        }
826        fputc('\n', outfile);
827    }
828}
829
830void
831xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data)
832{
833    IDL_tree_func_data tfd;
834
835    while (p) {
836        struct _IDL_LIST *list = &IDL_LIST(p);
837        tfd.tree = list->data;
838        if (!foreach(&tfd, user_data))
839            return;
840        p = list->next;
841    }
842}
843
844/*
845 * Verify that the interface declaration is correct
846 */
847gboolean
848verify_interface_declaration(IDL_tree interface_tree)
849{
850    IDL_tree iter;
851    /*
852     * If we have the scriptable attribute then make sure all of our direct
853     * parents have it as well.
854     * NOTE: We don't recurse since all interfaces will fall through here
855     */
856    if (IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident,
857        "scriptable")) {
858        for (iter = IDL_INTERFACE(interface_tree).inheritance_spec; iter;
859            iter = IDL_LIST(iter).next) {
860            if (IDL_tree_property_get(
861                IDL_INTERFACE(iter).ident, "scriptable") == 0) {
862                XPIDL_WARNING((interface_tree,IDL_WARNING1,
863                    "%s is scriptable but inherits from the non-scriptable interface %s\n",
864                    IDL_IDENT(IDL_INTERFACE(interface_tree).ident).str,
865                    IDL_IDENT(IDL_INTERFACE(iter).ident).str));
866            }
867        }
868    }
869    return TRUE;
870}
871
872/*
873 * Return a pointer to the start of the base filename of path
874 */
875const char *
876xpidl_basename(const char * path)
877{
878    const char * result = g_basename(path);
879    /*
880     *If this is windows then we'll handle either / or \ as a separator
881     * g_basename only handles \ for windows
882     */
883#if defined(XP_WIN32)
884    const char * slash = strrchr(path, '/');
885    /* If we found a slash and its after the current default OS separator */
886    if (slash != NULL && (slash > result))
887        result = slash + 1;
888#endif
889    return result;
890}
Note: See TracBrowser for help on using the browser.