Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / xpcom / typelib / xpidl / xpidl_util.c
blob5ef85b96ad78b001de7ae1109ca4d80810bff7ce
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * Utility functions called by various backends.
40 */
42 #include "xpidl.h"
44 #ifdef XP_WIN
45 #define strdup _strdup
46 #endif
48 /* XXXbe static */ char OOM[] = "ERROR: out of memory\n";
50 void *
51 xpidl_malloc(size_t nbytes)
53 void *p = malloc(nbytes);
54 if (!p) {
55 fputs(OOM, stderr);
56 exit(1);
58 return p;
61 char *
62 xpidl_strdup(const char *s)
64 char *ns = strdup(s);
65 if (!ns) {
66 fputs(OOM, stderr);
67 exit(1);
69 return ns;
72 void
73 xpidl_write_comment(TreeState *state, int indent)
75 fprintf(state->file, "%*s/* ", indent, "");
76 IDL_tree_to_IDL(state->tree, state->ns, state->file,
77 IDLF_OUTPUT_NO_NEWLINES |
78 IDLF_OUTPUT_NO_QUALIFY_IDENTS |
79 IDLF_OUTPUT_PROPERTIES);
80 fputs(" */\n", state->file);
84 * Print an iid to into a supplied buffer; the buffer should be at least
85 * UUID_LENGTH bytes.
87 gboolean
88 xpidl_sprint_iid(nsID *id, char iidbuf[])
90 int printed;
92 printed = sprintf(iidbuf,
93 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
94 (PRUint32) id->m0, (PRUint32) id->m1,(PRUint32) id->m2,
95 (PRUint32) id->m3[0], (PRUint32) id->m3[1],
96 (PRUint32) id->m3[2], (PRUint32) id->m3[3],
97 (PRUint32) id->m3[4], (PRUint32) id->m3[5],
98 (PRUint32) id->m3[6], (PRUint32) id->m3[7]);
100 #ifdef SPRINTF_RETURNS_STRING
101 return (printed && strlen((char *)printed) == 36);
102 #else
103 return (printed == 36);
104 #endif
107 /* We only parse the {}-less format. */
108 static const char nsIDFmt2[] =
109 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
112 * Parse a uuid string into an nsID struct. We cannot link against libxpcom,
113 * so we re-implement nsID::Parse here.
115 gboolean
116 xpidl_parse_iid(nsID *id, const char *str)
118 PRInt32 count = 0;
119 PRUint32 n0, n1, n2;
120 PRUint32 n3[8];
121 PRUint32 i;
123 XPT_ASSERT(str != NULL);
125 if (strlen(str) != 36) {
126 return FALSE;
129 #ifdef DEBUG_shaver_iid
130 fprintf(stderr, "parsing iid %s\n", str);
131 #endif
133 count = sscanf(str, nsIDFmt2,
134 &n0, &n1, &n2,
135 &n3[0],&n3[1],&n3[2],&n3[3],
136 &n3[4],&n3[5],&n3[6],&n3[7]);
138 id->m0 = n0;
139 id->m1 = (PRUint16) n1;
140 id->m2 = (PRUint16) n2;
141 for (i = 0; i < 8; i++) {
142 id->m3[i] = (PRUint8) n3[i];
145 #ifdef DEBUG_shaver_iid
146 if (count == 11) {
147 fprintf(stderr, "IID parsed to ");
148 print_IID(id, stderr);
149 fputs("\n", stderr);
151 #endif
152 return (gboolean)(count == 11);
155 gboolean
156 verify_const_declaration(IDL_tree const_tree) {
157 struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(const_tree);
158 const char *name = IDL_IDENT(dcl->ident).str;
159 IDL_tree real_type;
161 /* const -> list -> interface */
162 if (!IDL_NODE_UP(IDL_NODE_UP(const_tree)) ||
163 IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(const_tree)))
164 != IDLN_INTERFACE) {
165 IDL_tree_error(const_tree,
166 "const declaration \'%s\' outside interface",
167 name);
168 return FALSE;
171 /* Could be a typedef; try to map it to the real type. */
172 real_type = find_underlying_type(dcl->const_type);
173 real_type = real_type ? real_type : dcl->const_type;
174 if (IDL_NODE_TYPE(real_type) == IDLN_TYPE_INTEGER &&
175 (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_SHORT ||
176 IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG))
178 if (!IDL_TYPE_INTEGER(real_type).f_signed &&
179 IDL_INTEGER(dcl->const_exp).value < 0)
181 #ifndef G_HAVE_GINT64
183 * For platforms without longlong support turned on we can get
184 * confused by the high bit of the long value and think that it
185 * represents a negative value in an unsigned declaration.
186 * In that case we don't know if it is the programmer who is
187 * confused or the compiler. So we issue a warning instead of
188 * an error.
190 if (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG)
192 XPIDL_WARNING((const_tree, IDL_WARNING1,
193 "unsigned const declaration \'%s\' "
194 "initialized with (possibly) negative constant",
195 name));
196 return TRUE;
198 #endif
199 IDL_tree_error(const_tree,
200 "unsigned const declaration \'%s\' initialized with "
201 "negative constant",
202 name);
203 return FALSE;
205 } else {
206 IDL_tree_error(const_tree,
207 "const declaration \'%s\' must be of type short or long",
208 name);
209 return FALSE;
212 return TRUE;
218 * This method consolidates error checking needed when coercing the XPIDL compiler
219 * via the -t flag to generate output for a specific version of XPConnect.
221 static gboolean
222 verify_type_fits_version(IDL_tree in_tree, IDL_tree error_tree)
224 if (major_version == 1 && minor_version == 1)
226 /* XPIDL Version 1.1 checks */
228 /* utf8string, cstring, and astring types are not supported */
229 if (IDL_tree_property_get(in_tree, "utf8string") != NULL ||
230 IDL_tree_property_get(in_tree, "cstring") != NULL ||
231 IDL_tree_property_get(in_tree, "astring") != NULL)
233 IDL_tree_error(error_tree,
234 "Cannot use [utf8string], [cstring] and [astring] "
235 "types when generating version 1.1 typelibs\n");
236 return FALSE;
239 return TRUE;
242 static gboolean
243 IsNot_AlphaUpper(char letter)
245 return letter < 'A' || letter > 'Z';
248 static gboolean
249 IsNot_AlphaLower(char letter)
251 return letter < 'a' || letter > 'z';
254 static gboolean
255 matches_IFoo(const char* substring)
257 if (substring[0] != 'I')
258 return FALSE;
259 if (IsNot_AlphaUpper(substring[1]))
260 return FALSE;
261 if (IsNot_AlphaLower(substring[2]))
262 return FALSE;
263 return TRUE;
266 static gboolean
267 matches_nsIFoo(const char* attribute_name)
269 if (IsNot_AlphaLower(attribute_name[0]))
270 return FALSE;
271 if (IsNot_AlphaLower(attribute_name[1]))
272 return FALSE;
273 if (matches_IFoo(attribute_name + 2))
274 return TRUE;
275 if (IsNot_AlphaLower(attribute_name[2]))
276 return FALSE;
277 return matches_IFoo(attribute_name + 3);
281 * Returns TRUE if the method is probably scriptable, FALSE otherwise.
282 * The first parameter may also be an attr_tree parameter, since these two are
283 * the same with respect to discovering the interface node.
285 gboolean
286 is_method_scriptable(IDL_tree method_tree, IDL_tree ident)
288 IDL_tree iface;
289 gboolean scriptable_interface;
292 * Look up the tree to find the interface. If we can't find the interface,
293 * then the caller is being called on an incorrect tree. If we find it, we
294 * see if it's [scriptable] and duly note it.
296 if (IDL_NODE_UP(method_tree) && IDL_NODE_UP(IDL_NODE_UP(method_tree)) &&
297 IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(method_tree)))
298 == IDLN_INTERFACE)
300 scriptable_interface =
301 (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
302 != NULL);
303 } else {
304 IDL_tree_error(method_tree,
305 "is_method_scriptable called on a non-interface?");
306 return FALSE;
309 /* If the interface isn't scriptable, the method sure can't be... */
310 if (!scriptable_interface)
311 return FALSE;
313 /* [notxpcom] implies [noscript] */
314 if (IDL_tree_property_get(ident, "notxpcom") != NULL)
315 return FALSE;
317 /* [noscript] methods obviously aren't scriptable */
318 if (IDL_tree_property_get(ident, "noscript") != NULL)
319 return FALSE;
321 /* The interface is scriptable, so therefore the method is, if the
322 * interfaces are accessible. That's good enough for this method.
324 return TRUE;
327 gboolean
328 verify_attribute_declaration(IDL_tree attr_tree)
330 IDL_tree iface;
331 IDL_tree ident;
332 IDL_tree attr_type;
334 /* We don't support attributes named IID, conflicts with static GetIID
335 * member. The conflict is due to certain compilers (VC++) choosing a
336 * different vtable order, placing GetIID at the beginning regardless
337 * of its placement
339 if (strcmp(
340 IDL_IDENT(
341 IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data).str,
342 "IID") == 0) {
343 IDL_tree_error(attr_tree,
344 "Attributes named IID not supported, causes vtable "
345 "ordering problems");
346 return FALSE;
350 * Grab the first of the list of idents and hope that it'll
351 * say scriptable or no.
353 ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data;
356 * If the interface isn't scriptable, or the attribute is marked noscript,
357 * there's no need to check. This also verifies that we've been called on
358 * an interface.
360 if (!is_method_scriptable(attr_tree, ident))
361 return TRUE;
364 * If it should be scriptable, check that the type is non-native. nsid,
365 * domstring, utf8string, cstring, astring are exempted.
367 attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec;
369 if (attr_type != NULL)
371 if (UP_IS_NATIVE(attr_type) &&
372 IDL_tree_property_get(attr_type, "nsid") == NULL &&
373 IDL_tree_property_get(attr_type, "domstring") == NULL &&
374 IDL_tree_property_get(attr_type, "utf8string") == NULL &&
375 IDL_tree_property_get(attr_type, "cstring") == NULL &&
376 IDL_tree_property_get(attr_type, "astring") == NULL)
378 IDL_tree_error(attr_tree,
379 "attributes in [scriptable] interfaces that are "
380 "non-scriptable because they refer to native "
381 "types must be marked [noscript]\n");
382 return FALSE;
385 * We currently don't support properties of type nsid that aren't
386 * pointers or references, unless they are marked [notxpcom} and
387 * must be read-only
390 if ((IDL_tree_property_get(ident, "notxpcom") == NULL || !(IDL_ATTR_DCL(attr_tree).f_readonly)) &&
391 IDL_tree_property_get(attr_type,"nsid") != NULL &&
392 IDL_tree_property_get(attr_type,"ptr") == NULL &&
393 IDL_tree_property_get(attr_type,"ref") == NULL)
395 IDL_tree_error(attr_tree,
396 "Feature not currently supported: "
397 "attributes with a type of nsid must be marked "
398 "either [ptr] or [ref], or "
399 "else must be marked [notxpcom] "
400 "and must be read-only\n");
401 return FALSE;
405 * canIGoHomeNow is a bad name for an attribute.
406 * /^[a-z]{2,3}I[A-Z][a-z]/ => bad, reserved for
407 * interface flattening.
409 if (matches_nsIFoo(IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(attr_tree).
410 simple_declarations).data).str)) {
411 XPIDL_WARNING((attr_tree, IDL_WARNING1,
412 "Naming an attribute nsIFoo causes "
413 "problems for interface flattening"));
417 * Run additional error checks on the attribute type if targetting an
418 * older version of XPConnect.
421 if (!verify_type_fits_version(attr_type, attr_tree))
422 return FALSE;
425 if (IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).next != NULL)
427 IDL_tree_error(attr_tree,
428 "multiple attributes in a single declaration is not supported\n");
429 return FALSE;
431 return TRUE;
435 * Find the underlying type of an identifier typedef.
437 * All the needed tree-walking seems pretty shaky; isn't there something in
438 * libIDL to automate this?
440 IDL_tree /* IDL_TYPE_DCL */
441 find_underlying_type(IDL_tree typedef_ident)
443 IDL_tree up;
445 if (typedef_ident == NULL || IDL_NODE_TYPE(typedef_ident) != IDLN_IDENT)
446 return NULL;
448 up = IDL_NODE_UP(typedef_ident);
449 if (up == NULL || IDL_NODE_TYPE(up) != IDLN_LIST)
450 return NULL;
451 up = IDL_NODE_UP(up);
452 if (up == NULL || IDL_NODE_TYPE(up) != IDLN_TYPE_DCL)
453 return NULL;
455 return IDL_TYPE_DCL(up).type_spec;
458 static IDL_tree /* IDL_PARAM_DCL */
459 find_named_parameter(IDL_tree method_tree, const char *param_name)
461 IDL_tree iter;
462 for (iter = IDL_OP_DCL(method_tree).parameter_dcls; iter;
463 iter = IDL_LIST(iter).next)
465 IDL_tree param = IDL_LIST(iter).data;
466 IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator;
467 const char *current_name = IDL_IDENT(simple_decl).str;
468 if (strcmp(current_name, param_name) == 0)
469 return param;
471 return NULL;
474 typedef enum ParamAttrType {
475 IID_IS,
476 LENGTH_IS,
477 SIZE_IS
478 } ParamAttrType;
481 * Check that parameters referred to by attributes such as size_is exist and
482 * refer to parameters of the appropriate type.
484 static gboolean
485 check_param_attribute(IDL_tree method_tree, IDL_tree param,
486 ParamAttrType whattocheck)
488 const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str;
489 const char *referred_name = NULL;
490 IDL_tree param_type = IDL_PARAM_DCL(param).param_type_spec;
491 IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator;
492 const char *param_name = IDL_IDENT(simple_decl).str;
493 const char *attr_name;
494 const char *needed_type;
496 if (whattocheck == IID_IS) {
497 attr_name = "iid_is";
498 needed_type = "IID";
499 } else if (whattocheck == LENGTH_IS) {
500 attr_name = "length_is";
501 needed_type = "unsigned long (or PRUint32)";
502 } else if (whattocheck == SIZE_IS) {
503 attr_name = "size_is";
504 needed_type = "unsigned long (or PRUint32)";
505 } else {
506 XPT_ASSERT("asked to check an unknown attribute type!");
507 return TRUE;
510 referred_name = IDL_tree_property_get(simple_decl, attr_name);
511 if (referred_name != NULL) {
512 IDL_tree referred_param = find_named_parameter(method_tree,
513 referred_name);
514 IDL_tree referred_param_type;
515 if (referred_param == NULL) {
516 IDL_tree_error(method_tree,
517 "attribute [%s(%s)] refers to missing "
518 "parameter \"%s\"",
519 attr_name, referred_name, referred_name);
520 return FALSE;
522 if (referred_param == param) {
523 IDL_tree_error(method_tree,
524 "attribute [%s(%s)] refers to its own parameter",
525 attr_name, referred_name);
526 return FALSE;
529 referred_param_type = IDL_PARAM_DCL(referred_param).param_type_spec;
530 if (whattocheck == IID_IS) {
531 /* require IID type */
532 if (IDL_tree_property_get(referred_param_type, "nsid") == NULL) {
533 IDL_tree_error(method_tree,
534 "target \"%s\" of [%s(%s)] attribute "
535 "must be of %s type",
536 referred_name, attr_name, referred_name,
537 needed_type);
538 return FALSE;
540 } else if (whattocheck == LENGTH_IS || whattocheck == SIZE_IS) {
541 /* require PRUint32 type */
542 IDL_tree real_type;
544 /* Could be a typedef; try to map it to the real type. */
545 real_type = find_underlying_type(referred_param_type);
546 real_type = real_type ? real_type : referred_param_type;
548 if (IDL_NODE_TYPE(real_type) != IDLN_TYPE_INTEGER ||
549 IDL_TYPE_INTEGER(real_type).f_signed != FALSE ||
550 IDL_TYPE_INTEGER(real_type).f_type != IDL_INTEGER_TYPE_LONG)
552 IDL_tree_error(method_tree,
553 "target \"%s\" of [%s(%s)] attribute "
554 "must be of %s type",
555 referred_name, attr_name, referred_name,
556 needed_type);
558 return FALSE;
563 return TRUE;
567 * Common method verification code, called by *op_dcl in the various backends.
569 gboolean
570 verify_method_declaration(IDL_tree method_tree)
572 struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
573 IDL_tree iface;
574 IDL_tree iter;
575 gboolean notxpcom;
576 gboolean scriptable_method;
577 gboolean seen_retval = FALSE;
578 gboolean hasoptional = PR_FALSE;
579 const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str;
581 /* We don't support attributes named IID, conflicts with static GetIID
582 * member. The conflict is due to certain compilers (VC++) choosing a
583 * different vtable order, placing GetIID at the beginning regardless
584 * of its placement
586 if (strcmp(method_name, "GetIID") == 0) {
587 IDL_tree_error(method_tree,
588 "Methods named GetIID not supported, causes vtable "
589 "ordering problems");
590 return FALSE;
592 if (op->f_varargs) {
593 /* We don't currently support varargs. */
594 IDL_tree_error(method_tree, "varargs are not currently supported");
595 return FALSE;
599 * Decide if we are a scriptable method, or if we were are notxpcom.
600 * In doing so, we also verify that we've been called on an interface.
602 scriptable_method = is_method_scriptable(method_tree, op->ident);
603 notxpcom = IDL_tree_property_get(op->ident, "notxpcom") != NULL;
605 /* Loop through the parameters and check. */
606 for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
607 IDL_tree param = IDL_LIST(iter).data;
608 IDL_tree param_type =
609 IDL_PARAM_DCL(param).param_type_spec;
610 IDL_tree simple_decl =
611 IDL_PARAM_DCL(param).simple_declarator;
612 const char *param_name = IDL_IDENT(simple_decl).str;
615 * Reject this method if it should be scriptable and some parameter is
616 * native that isn't marked with either nsid, domstring, utf8string,
617 * cstring, astring or iid_is.
619 if (scriptable_method &&
620 UP_IS_NATIVE(param_type) &&
621 IDL_tree_property_get(param_type, "nsid") == NULL &&
622 IDL_tree_property_get(simple_decl, "iid_is") == NULL &&
623 IDL_tree_property_get(param_type, "domstring") == NULL &&
624 IDL_tree_property_get(param_type, "utf8string") == NULL &&
625 IDL_tree_property_get(param_type, "cstring") == NULL &&
626 IDL_tree_property_get(param_type, "astring") == NULL)
628 IDL_tree_error(method_tree,
629 "methods in [scriptable] interfaces that are "
630 "non-scriptable because they refer to native "
631 "types (parameter \"%s\") must be marked "
632 "[noscript]", param_name);
633 return FALSE;
637 * nsid's parameters that aren't ptr's or ref's are not currently
638 * supported in xpcom or non-xpcom (marked with [notxpcom]) methods
639 * as input parameters
641 if (!(notxpcom && IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) &&
642 IDL_tree_property_get(param_type, "nsid") != NULL &&
643 IDL_tree_property_get(param_type, "ptr") == NULL &&
644 IDL_tree_property_get(param_type, "ref") == NULL)
646 IDL_tree_error(method_tree,
647 "Feature currently not supported: "
648 "parameter \"%s\" is of type nsid and "
649 "must be marked either [ptr] or [ref] "
650 "or method \"%s\" must be marked [notxpcom] "
651 "and must not be an input parameter",
652 param_name,
653 method_name);
654 return FALSE;
657 * Sanity checks on return values.
659 if (IDL_tree_property_get(simple_decl, "retval") != NULL) {
660 if (IDL_LIST(iter).next != NULL) {
661 IDL_tree_error(method_tree,
662 "only the last parameter can be marked [retval]");
663 return FALSE;
665 if (op->op_type_spec) {
666 IDL_tree_error(method_tree,
667 "can't have [retval] with non-void return type");
668 return FALSE;
670 /* In case XPConnect relaxes the retval-is-last restriction. */
671 if (seen_retval) {
672 IDL_tree_error(method_tree,
673 "can't have more than one [retval] parameter");
674 return FALSE;
676 seen_retval = TRUE;
680 * Confirm that [shared] attributes are only used with string, wstring,
681 * or native (but not nsid, domstring, utf8string, cstring or astring)
682 * and can't be used with [array].
684 if (IDL_tree_property_get(simple_decl, "shared") != NULL) {
685 IDL_tree real_type;
686 real_type = find_underlying_type(param_type);
687 real_type = real_type ? real_type : param_type;
689 if (IDL_tree_property_get(simple_decl, "array") != NULL) {
690 IDL_tree_error(method_tree,
691 "[shared] parameter \"%s\" cannot "
692 "be of array type", param_name);
693 return FALSE;
696 if (!(IDL_NODE_TYPE(real_type) == IDLN_TYPE_STRING ||
697 IDL_NODE_TYPE(real_type) == IDLN_TYPE_WIDE_STRING ||
698 (UP_IS_NATIVE(real_type) &&
699 !IDL_tree_property_get(real_type, "nsid") &&
700 !IDL_tree_property_get(real_type, "domstring") &&
701 !IDL_tree_property_get(real_type, "utf8string") &&
702 !IDL_tree_property_get(real_type, "cstring") &&
703 !IDL_tree_property_get(real_type, "astring"))))
705 IDL_tree_error(method_tree,
706 "[shared] parameter \"%s\" must be of type "
707 "string, wstring or native", param_name);
708 return FALSE;
713 * confirm that once an optional argument is used, all remaining
714 * arguments are marked as optional
716 if (IDL_tree_property_get(simple_decl, "optional") != NULL) {
717 hasoptional = PR_TRUE;
719 else if (hasoptional) {
720 IDL_tree_error(method_tree,
721 "non-optional parameter used after one marked [optional]");
722 return FALSE;
726 * inout is not allowed with "domstring", "UTF8String", "CString"
727 * and "AString" types
729 if (IDL_PARAM_DCL(param).attr == IDL_PARAM_INOUT &&
730 UP_IS_NATIVE(param_type) &&
731 (IDL_tree_property_get(param_type, "domstring") != NULL ||
732 IDL_tree_property_get(param_type, "utf8string") != NULL ||
733 IDL_tree_property_get(param_type, "cstring") != NULL ||
734 IDL_tree_property_get(param_type, "astring") != NULL )) {
735 IDL_tree_error(method_tree,
736 "[domstring], [utf8string], [cstring], [astring] "
737 "types cannot be used as inout parameters");
738 return FALSE;
743 * arrays of domstring, utf8string, cstring, astring types not allowed
745 if (IDL_tree_property_get(simple_decl, "array") != NULL &&
746 UP_IS_NATIVE(param_type) &&
747 (IDL_tree_property_get(param_type, "domstring") != NULL ||
748 IDL_tree_property_get(param_type, "utf8string") != NULL ||
749 IDL_tree_property_get(param_type, "cstring") != NULL ||
750 IDL_tree_property_get(param_type, "astring") != NULL)) {
751 IDL_tree_error(method_tree,
752 "[domstring], [utf8string], [cstring], [astring] "
753 "types cannot be used in array parameters");
754 return FALSE;
757 if (!check_param_attribute(method_tree, param, IID_IS) ||
758 !check_param_attribute(method_tree, param, LENGTH_IS) ||
759 !check_param_attribute(method_tree, param, SIZE_IS))
760 return FALSE;
763 * Run additional error checks on the parameter type if targetting an
764 * older version of XPConnect.
767 if (!verify_type_fits_version(param_type, method_tree))
768 return FALSE;
772 /* XXX q: can return type be nsid? */
773 /* Native return type? */
774 if (scriptable_method &&
775 op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) &&
776 IDL_tree_property_get(op->op_type_spec, "nsid") == NULL &&
777 IDL_tree_property_get(op->op_type_spec, "domstring") == NULL &&
778 IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL &&
779 IDL_tree_property_get(op->op_type_spec, "cstring") == NULL &&
780 IDL_tree_property_get(op->op_type_spec, "astring") == NULL)
782 IDL_tree_error(method_tree,
783 "methods in [scriptable] interfaces that are "
784 "non-scriptable because they return native "
785 "types must be marked [noscript]");
786 return FALSE;
791 * nsid's parameters that aren't ptr's or ref's are not currently
792 * supported in xpcom
794 if (!notxpcom &&
795 op->op_type_spec != NULL &&
796 IDL_tree_property_get(op->op_type_spec, "nsid") != NULL &&
797 IDL_tree_property_get(op->op_type_spec, "ptr") == NULL &&
798 IDL_tree_property_get(op->op_type_spec, "ref") == NULL)
800 IDL_tree_error(method_tree,
801 "Feature currently not supported: "
802 "return value is of type nsid and "
803 "must be marked either [ptr] or [ref], "
804 "or else method \"%s\" must be marked [notxpcom] ",
805 method_name);
806 return FALSE;
810 * Run additional error checks on the return type if targetting an
811 * older version of XPConnect.
814 if (op->op_type_spec != NULL &&
815 !verify_type_fits_version(op->op_type_spec, method_tree))
817 return FALSE;
820 return TRUE;
824 * Verify that a native declaration has an associated C++ expression, i.e. that
825 * it's of the form native <idl-name>(<c++-name>)
827 gboolean
828 check_native(TreeState *state)
830 char *native_name;
831 /* require that native declarations give a native type */
832 if (IDL_NATIVE(state->tree).user_type)
833 return TRUE;
834 native_name = IDL_IDENT(IDL_NATIVE(state->tree).ident).str;
835 IDL_tree_error(state->tree,
836 "``native %s;'' needs C++ type: ``native %s(<C++ type>);''",
837 native_name, native_name);
838 return FALSE;
842 * Print a GSList as char strings to a file.
844 void
845 printlist(FILE *outfile, GSList *slist)
847 guint i;
848 guint len = g_slist_length(slist);
850 for(i = 0; i < len; i++) {
851 fprintf(outfile,
852 "%s\n", (char *)g_slist_nth_data(slist, i));
856 void
857 xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data)
859 IDL_tree_func_data tfd;
861 while (p) {
862 struct _IDL_LIST *list = &IDL_LIST(p);
863 tfd.tree = list->data;
864 if (!foreach(&tfd, user_data))
865 return;
866 p = list->next;
871 * Verify that the interface declaration is correct
873 gboolean
874 verify_interface_declaration(IDL_tree interface_tree)
876 IDL_tree iter;
878 * If we have the scriptable attribute then make sure all of our direct
879 * parents have it as well.
880 * NOTE: We don't recurse since all interfaces will fall through here
882 if (IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident,
883 "scriptable")) {
884 for (iter = IDL_INTERFACE(interface_tree).inheritance_spec; iter;
885 iter = IDL_LIST(iter).next) {
886 if (IDL_tree_property_get(
887 IDL_INTERFACE(iter).ident, "scriptable") == 0) {
888 XPIDL_WARNING((interface_tree,IDL_WARNING1,
889 "%s is scriptable but inherits from the non-scriptable interface %s\n",
890 IDL_IDENT(IDL_INTERFACE(interface_tree).ident).str,
891 IDL_IDENT(IDL_INTERFACE(iter).ident).str));
895 return TRUE;
899 * Return a pointer to the start of the base filename of path
901 const char *
902 xpidl_basename(const char * path)
904 const char * result = g_basename(path);
906 *If this is windows then we'll handle either / or \ as a separator
907 * g_basename only handles \ for windows
909 #if defined(XP_WIN32)
910 const char * slash = strrchr(path, '/');
911 /* If we found a slash and its after the current default OS separator */
912 if (slash != NULL && (slash > result))
913 result = slash + 1;
914 #endif
915 return result;