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
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.
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 * Generate typelib files for use with InterfaceInfo.
40 * http://www.mozilla.org/scriptable/typelib_file.html
45 #include <xpt_struct.h>
46 #include <time.h> /* XXX XP? */
51 GHashTable
*interface_map
;
52 XPTInterfaceDescriptor
*current
;
56 uint16 next_type
; /* used for 'additional_types' for idl arrays */
59 #define HEADER(state) (((struct priv_data *)state->priv)->header)
60 #define IFACES(state) (((struct priv_data *)state->priv)->ifaces)
61 #define IFACE_MAP(state) (((struct priv_data *)state->priv)->interface_map)
62 #define CURRENT(state) (((struct priv_data *)state->priv)->current)
63 #define ARENA(state) (((struct priv_data *)state->priv)->arena)
64 #define NEXT_METH(state) (((struct priv_data *)state->priv)->next_method)
65 #define NEXT_CONST(state) (((struct priv_data *)state->priv)->next_const)
66 #define NEXT_TYPE(state) (((struct priv_data *)state->priv)->next_type)
69 /* #define DEBUG_shaver_sort */
77 gboolean is_forward_dcl
;
80 static NewInterfaceHolder
*
81 CreateNewInterfaceHolder(char *name
, char *name_space
, char *iid
,
82 gboolean is_forward_dcl
)
84 NewInterfaceHolder
*holder
= calloc(1, sizeof(NewInterfaceHolder
));
86 holder
->is_forward_dcl
= is_forward_dcl
;
88 holder
->name
= xpidl_strdup(name
);
90 holder
->name_space
= xpidl_strdup(name_space
);
91 if (holder
->name
&& holder
->name_space
) {
92 holder
->full_name
= calloc(1, strlen(holder
->name
) +
93 strlen(holder
->name_space
) + 2);
95 if (holder
->full_name
) {
96 strcpy(holder
->full_name
, holder
->name_space
);
97 strcat(holder
->full_name
, ".");
98 strcat(holder
->full_name
, holder
->name
);
101 holder
->full_name
= holder
->name
;
103 holder
->iid
= xpidl_strdup(iid
);
109 DeleteNewInterfaceHolder(NewInterfaceHolder
*holder
)
112 if (holder
->full_name
&& holder
->full_name
!= holder
->name
)
113 free(holder
->full_name
);
116 if (holder
->name_space
)
117 free(holder
->name_space
);
125 * If p is an ident for an interface, and we don't have an entry in the
126 * interface map yet, add one.
129 add_interface_maybe(IDL_tree_func_data
*tfd
, gpointer user_data
)
131 TreeState
*state
= user_data
;
133 if (IDL_NODE_TYPE(tfd
->tree
) == IDLN_IDENT
) {
134 IDL_tree_type node_type
= IDL_NODE_TYPE((up
= IDL_NODE_UP(tfd
->tree
)));
135 if (node_type
== IDLN_INTERFACE
|| node_type
== IDLN_FORWARD_DCL
) {
137 /* We only want to add a new entry if there is no entry by this
138 * name or if the previously found entry was just a forward
139 * declaration and the new entry is not.
142 char *iface
= IDL_IDENT(tfd
->tree
).str
;
143 NewInterfaceHolder
*old_holder
= (NewInterfaceHolder
*)
144 g_hash_table_lookup(IFACE_MAP(state
), iface
);
145 if (old_holder
&& old_holder
->is_forward_dcl
&&
146 node_type
!= IDLN_FORWARD_DCL
)
148 g_hash_table_remove(IFACE_MAP(state
), iface
);
149 DeleteNewInterfaceHolder(old_holder
);
153 /* XXX should we parse here and store a struct nsID *? */
154 char *iid
= (char *)IDL_tree_property_get(tfd
->tree
, "uuid");
155 char *name_space
= (char *)
156 IDL_tree_property_get(tfd
->tree
, "namespace");
157 NewInterfaceHolder
*holder
=
158 CreateNewInterfaceHolder(iface
, name_space
, iid
,
159 (gboolean
) node_type
== IDLN_FORWARD_DCL
);
162 g_hash_table_insert(IFACE_MAP(state
),
163 holder
->full_name
, holder
);
165 #ifdef DEBUG_shaver_ifaces
166 fprintf(stderr
, "adding interface #%d: %s/%s\n", IFACES(state
),
167 iface
, iid
[0] ? iid
: "<unresolved>");
171 #ifdef DEBUG_shaver_ifaces
172 fprintf(stderr
, "ident %s isn't an interface (%s)\n",
173 IDL_IDENT(tfd
->tree
).str
, IDL_NODE_TYPE_NAME(up
));
181 /* Find all the interfaces referenced in the tree (uses add_interface_maybe) */
183 find_interfaces(IDL_tree_func_data
*tfd
, gpointer user_data
)
185 IDL_tree node
= NULL
;
187 switch (IDL_NODE_TYPE(tfd
->tree
)) {
189 node
= IDL_ATTR_DCL(tfd
->tree
).param_type_spec
;
192 IDL_tree_walk_in_order(IDL_OP_DCL(tfd
->tree
).parameter_dcls
, find_interfaces
,
194 node
= IDL_OP_DCL(tfd
->tree
).op_type_spec
;
197 node
= IDL_PARAM_DCL(tfd
->tree
).param_type_spec
;
200 node
= IDL_INTERFACE(tfd
->tree
).inheritance_spec
;
202 xpidl_list_foreach(node
, add_interface_maybe
, user_data
);
203 node
= IDL_INTERFACE(tfd
->tree
).ident
;
205 case IDLN_FORWARD_DCL
:
206 node
= IDL_FORWARD_DCL(tfd
->tree
).ident
;
212 if (node
&& IDL_NODE_TYPE(node
) == IDLN_IDENT
) {
213 IDL_tree_func_data new_tfd
;
215 add_interface_maybe(&new_tfd
, user_data
);
222 /* for calling from gdb */
224 print_IID(struct nsID
*iid
, FILE *file
)
226 char iid_buf
[UUID_LENGTH
];
228 xpidl_sprint_iid(iid
, iid_buf
);
229 fprintf(file
, "%s\n", iid_buf
);
233 /* fill the interface_directory IDE table from the interface_map */
235 fill_ide_table(gpointer key
, gpointer value
, gpointer user_data
)
237 TreeState
*state
= user_data
;
238 NewInterfaceHolder
*holder
= (NewInterfaceHolder
*) value
;
240 XPTInterfaceDirectoryEntry
*ide
;
244 #ifdef DEBUG_shaver_ifaces
245 fprintf(stderr
, "filling %s\n", holder
->full_name
);
249 if (strlen(holder
->iid
) != 36) {
250 IDL_tree_error(state
->tree
, "IID %s is the wrong length\n",
254 if (!xpidl_parse_iid(&id
, holder
->iid
)) {
255 IDL_tree_error(state
->tree
, "cannot parse IID %s\n", holder
->iid
);
259 memset(&id
, 0, sizeof(id
));
262 ide
= &(HEADER(state
)->interface_directory
[IFACES(state
)]);
263 if (!XPT_FillInterfaceDirectoryEntry(ARENA(state
), ide
, &id
, holder
->name
,
264 holder
->name_space
, NULL
)) {
265 IDL_tree_error(state
->tree
, "INTERNAL: XPT_FillIDE failed for %s\n",
271 DeleteNewInterfaceHolder(holder
);
276 compare_IDEs(const void *ap
, const void *bp
)
278 const XPTInterfaceDirectoryEntry
*a
= ap
, *b
= bp
;
279 const nsID
*aid
= &a
->iid
, *bid
= &b
->iid
;
280 const char *ans
, *bns
;
283 #define COMPARE(field) if (aid->field > bid->field) return 1; \
284 if (bid->field > aid->field) return -1;
288 for (i
= 0; i
< 8; i
++) {
292 /* defend against NULL name_space by using empty string. */
293 ans
= a
->name_space
? a
->name_space
: "";
294 bns
= b
->name_space
? b
->name_space
: "";
296 if (a
->name_space
&& b
->name_space
) {
297 if ((i
= strcmp(a
->name_space
, b
->name_space
)))
300 if (a
->name_space
|| b
->name_space
) {
306 /* these had better not be NULL... */
307 return strcmp(a
->name
, b
->name
);
311 /* sort the IDE block as per the typelib spec: IID order, unresolved first */
313 sort_ide_block(TreeState
*state
)
315 XPTInterfaceDirectoryEntry
*ide
;
318 /* boy, I sure hope qsort works correctly everywhere */
319 #ifdef DEBUG_shaver_sort
320 fputs("before sort:\n", stderr
);
321 for (i
= 0; i
< IFACES(state
); i
++) {
323 print_IID(&HEADER(state
)->interface_directory
[i
].iid
, stderr
);
327 qsort(HEADER(state
)->interface_directory
, IFACES(state
),
328 sizeof(*ide
), compare_IDEs
);
329 #ifdef DEBUG_shaver_sort
330 fputs("after sort:\n", stderr
);
331 for (i
= 0; i
< IFACES(state
); i
++) {
333 print_IID(&HEADER(state
)->interface_directory
[i
].iid
, stderr
);
338 for (i
= 0; i
< IFACES(state
); i
++) {
339 ide
= HEADER(state
)->interface_directory
+ i
;
340 g_hash_table_insert(IFACE_MAP(state
), ide
->name
, (void *)(i
+ 1));
347 typelib_list(TreeState
*state
)
350 for (iter
= state
->tree
; iter
; iter
= IDL_LIST(iter
).next
) {
351 state
->tree
= IDL_LIST(iter
).data
;
352 if (!xpidl_process_node(state
))
359 typelib_prolog(TreeState
*state
)
361 state
->priv
= calloc(1, sizeof(struct priv_data
));
365 IFACE_MAP(state
) = g_hash_table_new(g_str_hash
, g_str_equal
);
366 if (!IFACE_MAP(state
)) {
367 /* XXX report error */
371 /* find all interfaces, top-level and referenced by others */
372 IDL_tree_walk_in_order(state
->tree
, find_interfaces
, state
);
373 ARENA(state
) = XPT_NewArena(1024, sizeof(double), "main xpidl arena");
374 HEADER(state
) = XPT_NewHeader(ARENA(state
), IFACES(state
),
375 major_version
, minor_version
);
377 /* fill IDEs from hash table */
379 g_hash_table_foreach_remove(IFACE_MAP(state
), fill_ide_table
, state
);
381 /* if any are left then we must have failed in fill_ide_table */
382 if (g_hash_table_size(IFACE_MAP(state
)))
385 /* sort the IDEs by IID order and store indices in the interface map */
386 sort_ide_block(state
);
392 typelib_epilog(TreeState
*state
)
394 XPTState
*xstate
= XPT_NewXDRState(XPT_ENCODE
, NULL
, 0);
395 XPTCursor curs
, *cursor
= &curs
;
396 PRUint32 i
, len
, header_sz
;
401 /* Write any annotations */
402 if (emit_typelib_annotations
) {
403 PRUint32 annotation_len
, written_so_far
;
404 char *annotate_val
, *timestr
;
406 static char *annotation_format
=
407 "Created from %s.idl\nCreation date: %sInterfaces:";
409 /* fill in the annotations, listing resolved interfaces in order */
412 timestr
= ctime(&now
);
414 /* Avoid dependence on nspr; no PR_smprintf and friends. */
416 /* How large should the annotation string be? */
417 annotation_len
= strlen(annotation_format
) + strlen(state
->basename
) +
419 for (i
= 0; i
< HEADER(state
)->num_interfaces
; i
++) {
420 XPTInterfaceDirectoryEntry
*ide
;
421 ide
= &HEADER(state
)->interface_directory
[i
];
422 if (ide
->interface_descriptor
) {
423 annotation_len
+= strlen(ide
->name
) + 1;
427 annotate_val
= (char *) malloc(annotation_len
);
428 written_so_far
= sprintf(annotate_val
, annotation_format
,
429 state
->basename
, timestr
);
431 for (i
= 0; i
< HEADER(state
)->num_interfaces
; i
++) {
432 XPTInterfaceDirectoryEntry
*ide
;
433 ide
= &HEADER(state
)->interface_directory
[i
];
434 if (ide
->interface_descriptor
) {
435 written_so_far
+= sprintf(annotate_val
+ written_so_far
, " %s",
440 HEADER(state
)->annotations
=
441 XPT_NewAnnotation(ARENA(state
),
442 XPT_ANN_LAST
| XPT_ANN_PRIVATE
,
443 XPT_NewStringZ(ARENA(state
), "xpidl 0.99.9"),
444 XPT_NewStringZ(ARENA(state
), annotate_val
));
447 HEADER(state
)->annotations
=
448 XPT_NewAnnotation(ARENA(state
), XPT_ANN_LAST
, NULL
, NULL
);
451 if (!HEADER(state
)->annotations
) {
452 /* XXX report out of memory error */
456 /* Write the typelib */
457 header_sz
= XPT_SizeOfHeaderBlock(HEADER(state
));
460 !XPT_MakeCursor(xstate
, XPT_HEADER
, header_sz
, cursor
))
462 oldOffset
= cursor
->offset
;
463 if (!XPT_DoHeader(ARENA(state
), cursor
, &HEADER(state
)))
465 newOffset
= cursor
->offset
;
466 XPT_GetXDRDataLength(xstate
, XPT_HEADER
, &len
);
467 HEADER(state
)->file_length
= len
;
468 XPT_GetXDRDataLength(xstate
, XPT_DATA
, &len
);
469 HEADER(state
)->file_length
+= len
;
470 XPT_SeekTo(cursor
, oldOffset
);
471 if (!XPT_DoHeaderPrologue(ARENA(state
), cursor
, &HEADER(state
), NULL
))
473 XPT_SeekTo(cursor
, newOffset
);
474 XPT_GetXDRData(xstate
, XPT_HEADER
, &data
, &len
);
475 fwrite(data
, len
, 1, state
->file
);
476 XPT_GetXDRData(xstate
, XPT_DATA
, &data
, &len
);
477 fwrite(data
, len
, 1, state
->file
);
480 XPT_DestroyXDRState(xstate
);
482 /* XXX XPT_DestroyHeader(HEADER(state)) */
484 XPT_FreeHeader(ARENA(state
), HEADER(state
));
485 XPT_DestroyArena(ARENA(state
));
487 /* XXX should destroy priv_data here */
492 static XPTInterfaceDirectoryEntry
*
493 FindInterfaceByName(XPTInterfaceDirectoryEntry
*ides
, uint16 num_interfaces
,
497 for (i
= 0; i
< num_interfaces
; i
++) {
498 if (!strcmp(ides
[i
].name
, name
))
505 typelib_interface(TreeState
*state
)
507 IDL_tree iface
= state
->tree
, iter
;
508 char *name
= IDL_IDENT(IDL_INTERFACE(iface
).ident
).str
;
509 XPTInterfaceDirectoryEntry
*ide
;
510 XPTInterfaceDescriptor
*id
;
511 uint16 parent_id
= 0;
512 PRUint8 interface_flags
= 0;
514 if (!verify_interface_declaration(iface
))
517 if (IDL_tree_property_get(IDL_INTERFACE(iface
).ident
, "scriptable"))
518 interface_flags
|= XPT_ID_SCRIPTABLE
;
520 if (IDL_tree_property_get(IDL_INTERFACE(iface
).ident
, "function"))
521 interface_flags
|= XPT_ID_FUNCTION
;
523 ide
= FindInterfaceByName(HEADER(state
)->interface_directory
,
524 HEADER(state
)->num_interfaces
, name
);
526 IDL_tree_error(iface
, "ERROR: didn't find interface %s in "
527 "IDE block. Giving up.\n", name
);
531 if ((iter
= IDL_INTERFACE(iface
).inheritance_spec
)) {
533 if (IDL_LIST(iter
).next
) {
534 IDL_tree_error(iface
,
535 "ERROR: more than one parent interface for %s\n",
539 parent
= IDL_IDENT(IDL_LIST(iter
).data
).str
;
540 parent_id
= (uint16
)(uint32
)g_hash_table_lookup(IFACE_MAP(state
),
543 IDL_tree_error(iface
,
544 "ERROR: no index found for %s. Giving up.\n",
550 id
= XPT_NewInterfaceDescriptor(ARENA(state
), parent_id
, 0, 0,
555 CURRENT(state
) = ide
->interface_descriptor
= id
;
556 #ifdef DEBUG_shaver_ifaces
557 fprintf(stderr
, "DBG: starting interface %s @ %p\n", name
, id
);
560 NEXT_METH(state
) = 0;
561 NEXT_CONST(state
) = 0;
562 NEXT_TYPE(state
) = 0;
564 state
->tree
= IDL_INTERFACE(iface
).body
;
565 if (state
->tree
&& !xpidl_process_node(state
))
567 #ifdef DEBUG_shaver_ifaces
568 fprintf(stderr
, "DBG: ending interface %s\n", name
);
574 find_arg_with_name(TreeState
*state
, const char *name
, int16
*argnum
)
583 params
= IDL_OP_DCL(IDL_NODE_UP(IDL_NODE_UP(state
->tree
))).parameter_dcls
;
585 params
!= NULL
&& IDL_LIST(params
).data
!= NULL
;
586 params
= IDL_LIST(params
).next
, count
++)
588 const char *cur_name
= IDL_IDENT(
589 IDL_PARAM_DCL(IDL_LIST(params
).data
).simple_declarator
).str
;
590 if (!strcmp(cur_name
, name
)) {
591 /* XXX ought to verify that this is the right type here */
592 /* XXX for iid_is this must be an iid */
593 /* XXX for size_is and length_is this must be a uint32 */
601 /* return value is for success or failure */
603 get_size_and_length(TreeState
*state
, IDL_tree type
,
604 int16
*size_is_argnum
, int16
*length_is_argnum
,
605 gboolean
*has_size_is
, gboolean
*has_length_is
)
607 *has_size_is
= FALSE
;
608 *has_length_is
= FALSE
;
610 if (IDL_NODE_TYPE(state
->tree
) == IDLN_PARAM_DCL
) {
611 IDL_tree sd
= IDL_PARAM_DCL(state
->tree
).simple_declarator
;
613 const char *length_is
;
615 /* only if size_is is found does any of this matter */
616 size_is
= IDL_tree_property_get(sd
, "size_is");
620 if (!find_arg_with_name(state
, size_is
, size_is_argnum
)) {
621 IDL_tree_error(state
->tree
, "can't find matching argument for "
622 "[size_is(%s)]\n", size_is
);
627 /* length_is is optional */
628 length_is
= IDL_tree_property_get(sd
, "length_is");
630 *has_length_is
= TRUE
;
631 if (!find_arg_with_name(state
, length_is
, length_is_argnum
)) {
632 IDL_tree_error(state
->tree
, "can't find matching argument for "
633 "[length_is(%s)]\n", length_is
);
642 fill_td_from_type(TreeState
*state
, XPTTypeDescriptor
*td
, IDL_tree type
)
645 int16 size_is_argnum
;
646 int16 length_is_argnum
;
647 gboolean has_size_is
;
648 gboolean has_length_is
;
649 gboolean is_array
= FALSE
;
653 /* deal with array */
655 if (IDL_NODE_TYPE(state
->tree
) == IDLN_PARAM_DCL
) {
656 IDL_tree sd
= IDL_PARAM_DCL(state
->tree
).simple_declarator
;
657 if (IDL_tree_property_get(sd
, "array")) {
661 /* size_is is required! */
662 if (!get_size_and_length(state
, type
,
663 &size_is_argnum
, &length_is_argnum
,
664 &has_size_is
, &has_length_is
)) {
665 /* error was reported by helper function */
670 IDL_tree_error(state
->tree
, "[array] requires [size_is()]\n");
674 td
->prefix
.flags
= TD_ARRAY
| XPT_TDP_POINTER
;
675 td
->argnum
= size_is_argnum
;
678 td
->argnum2
= length_is_argnum
;
680 td
->argnum2
= size_is_argnum
;
683 * XXX - NOTE - this will be broken for multidimensional
684 * arrays because of the realloc XPT_InterfaceDescriptorAddTypes
685 * uses. The underlying 'td' can change as we recurse in to get
686 * additional dimensions. Luckily, we don't yet support more
687 * than on dimension in the arrays
689 /* setup the additional_type */
690 if (!XPT_InterfaceDescriptorAddTypes(ARENA(state
),
691 CURRENT(state
), 1)) {
692 g_error("out of memory\n");
695 td
->type
.additional_type
= NEXT_TYPE(state
);
696 td
= &CURRENT(state
)->additional_types
[NEXT_TYPE(state
)];
702 switch (IDL_NODE_TYPE(type
)) {
703 case IDLN_TYPE_INTEGER
: {
704 gboolean sign
= IDL_TYPE_INTEGER(type
).f_signed
;
705 switch(IDL_TYPE_INTEGER(type
).f_type
) {
706 case IDL_INTEGER_TYPE_SHORT
:
707 td
->prefix
.flags
= sign
? TD_INT16
: TD_UINT16
;
709 case IDL_INTEGER_TYPE_LONG
:
710 td
->prefix
.flags
= sign
? TD_INT32
: TD_UINT32
;
712 case IDL_INTEGER_TYPE_LONGLONG
:
713 td
->prefix
.flags
= sign
? TD_INT64
: TD_UINT64
;
719 td
->prefix
.flags
= TD_CHAR
;
721 case IDLN_TYPE_WIDE_CHAR
:
722 td
->prefix
.flags
= TD_WCHAR
;
724 case IDLN_TYPE_STRING
:
726 td
->prefix
.flags
= TD_PSTRING
| XPT_TDP_POINTER
;
728 if (!get_size_and_length(state
, type
,
729 &size_is_argnum
, &length_is_argnum
,
730 &has_size_is
, &has_length_is
)) {
731 /* error was reported by helper function */
735 td
->prefix
.flags
= TD_PSTRING_SIZE_IS
| XPT_TDP_POINTER
;
736 td
->argnum
= size_is_argnum
;
738 td
->argnum2
= length_is_argnum
;
740 td
->argnum2
= size_is_argnum
;
742 td
->prefix
.flags
= TD_PSTRING
| XPT_TDP_POINTER
;
746 case IDLN_TYPE_WIDE_STRING
:
748 td
->prefix
.flags
= TD_PWSTRING
| XPT_TDP_POINTER
;
750 if (!get_size_and_length(state
, type
,
751 &size_is_argnum
, &length_is_argnum
,
752 &has_size_is
, &has_length_is
)) {
753 /* error was reported by helper function */
757 td
->prefix
.flags
= TD_PWSTRING_SIZE_IS
| XPT_TDP_POINTER
;
758 td
->argnum
= size_is_argnum
;
760 td
->argnum2
= length_is_argnum
;
762 td
->argnum2
= size_is_argnum
;
764 td
->prefix
.flags
= TD_PWSTRING
| XPT_TDP_POINTER
;
768 case IDLN_TYPE_BOOLEAN
:
769 td
->prefix
.flags
= TD_BOOL
;
771 case IDLN_TYPE_OCTET
:
772 td
->prefix
.flags
= TD_UINT8
;
774 case IDLN_TYPE_FLOAT
:
775 switch (IDL_TYPE_FLOAT (type
).f_type
) {
776 case IDL_FLOAT_TYPE_FLOAT
:
777 td
->prefix
.flags
= TD_FLOAT
;
779 case IDL_FLOAT_TYPE_DOUBLE
:
780 td
->prefix
.flags
= TD_DOUBLE
;
782 /* XXX 'long double' just ignored, or what? */
787 if (!(up
= IDL_NODE_UP(type
))) {
788 IDL_tree_error(state
->tree
,
789 "ERROR: orphan ident %s in param list\n",
790 IDL_IDENT(type
).str
);
793 switch (IDL_NODE_TYPE(up
)) {
794 /* This whole section is abominably ugly */
795 case IDLN_FORWARD_DCL
:
796 case IDLN_INTERFACE
: {
797 XPTInterfaceDirectoryEntry
*ide
, *ides
;
802 ides
= HEADER(state
)->interface_directory
;
803 num_ifaces
= HEADER(state
)->num_interfaces
;
804 /* might get here via the goto, so re-check type */
805 if (IDL_NODE_TYPE(up
) == IDLN_INTERFACE
)
806 className
= IDL_IDENT(IDL_INTERFACE(up
).ident
).str
;
807 else if (IDL_NODE_TYPE(up
) == IDLN_FORWARD_DCL
)
808 className
= IDL_IDENT(IDL_FORWARD_DCL(up
).ident
).str
;
810 className
= IDL_IDENT(IDL_NATIVE(up
).ident
).str
;
813 if (IDL_NODE_TYPE(state
->tree
) == IDLN_PARAM_DCL
) {
815 IDL_tree_property_get(IDL_PARAM_DCL(state
->tree
).simple_declarator
,
820 if (!find_arg_with_name(state
, iid_is
, &argnum
)) {
821 IDL_tree_error(state
->tree
,
822 "can't find matching argument for "
823 "[iid_is(%s)]\n", iid_is
);
826 td
->prefix
.flags
= TD_INTERFACE_IS_TYPE
| XPT_TDP_POINTER
;
829 td
->prefix
.flags
= TD_INTERFACE_TYPE
| XPT_TDP_POINTER
;
830 ide
= FindInterfaceByName(ides
, num_ifaces
, className
);
831 if (!ide
|| ide
< ides
|| ide
> ides
+ num_ifaces
) {
832 IDL_tree_error(state
->tree
,
833 "unknown iface %s in param\n",
837 td
->type
.iface
= ide
- ides
+ 1;
838 #ifdef DEBUG_shaver_index
839 fprintf(stderr
, "DBG: index %d for %s\n",
840 td
->type
.iface
, className
);
848 /* jband - adding goto for iid_is when type is native */
849 if (IDL_NODE_TYPE(state
->tree
) == IDLN_PARAM_DCL
&&
850 IDL_tree_property_get(IDL_PARAM_DCL(state
->tree
).simple_declarator
,
854 ident
= IDL_IDENT(type
).str
;
855 if (IDL_tree_property_get(type
, "nsid")) {
856 td
->prefix
.flags
= TD_PNSIID
;
857 if (IDL_tree_property_get(type
, "ref"))
858 td
->prefix
.flags
|= XPT_TDP_POINTER
| XPT_TDP_REFERENCE
;
859 else if (IDL_tree_property_get(type
,"ptr"))
860 td
->prefix
.flags
|= XPT_TDP_POINTER
;
861 } else if (IDL_tree_property_get(type
, "domstring")) {
862 td
->prefix
.flags
= TD_DOMSTRING
| XPT_TDP_POINTER
;
863 if (IDL_tree_property_get(type
, "ref"))
864 td
->prefix
.flags
|= XPT_TDP_REFERENCE
;
865 } else if (IDL_tree_property_get(type
, "astring")) {
866 td
->prefix
.flags
= TD_ASTRING
| XPT_TDP_POINTER
;
867 if (IDL_tree_property_get(type
, "ref"))
868 td
->prefix
.flags
|= XPT_TDP_REFERENCE
;
869 } else if (IDL_tree_property_get(type
, "utf8string")) {
870 td
->prefix
.flags
= TD_UTF8STRING
| XPT_TDP_POINTER
;
871 if (IDL_tree_property_get(type
, "ref"))
872 td
->prefix
.flags
|= XPT_TDP_REFERENCE
;
873 } else if (IDL_tree_property_get(type
, "cstring")) {
874 td
->prefix
.flags
= TD_CSTRING
| XPT_TDP_POINTER
;
875 if (IDL_tree_property_get(type
, "ref"))
876 td
->prefix
.flags
|= XPT_TDP_REFERENCE
;
878 td
->prefix
.flags
= TD_VOID
| XPT_TDP_POINTER
;
883 if (IDL_NODE_TYPE(IDL_NODE_UP(up
)) == IDLN_TYPE_DCL
) {
884 /* restart with the underlying type */
886 new_type
= IDL_TYPE_DCL(IDL_NODE_UP(up
)).type_spec
;
887 #ifdef DEBUG_shaver_misc
888 fprintf(stderr
, "following %s typedef to %s\n",
889 IDL_IDENT(type
).str
, IDL_NODE_TYPE_NAME(new_type
));
892 * Do a nice messy goto rather than recursion so that
893 * we can avoid screwing up the *array* information.
895 /* return fill_td_from_type(state, td, new_type); */
900 /* do what we would do in recursion if !type */
901 td
->prefix
.flags
= TD_VOID
;
905 IDL_tree_error(state
->tree
,
906 "can't handle %s ident in param list\n",
908 /* XXX is this safe to use on Win now? */
909 IDL_NODE_TYPE_NAME(IDL_NODE_UP(type
))
921 IDL_tree_error(state
->tree
, "can't handle %s in param list\n",
923 /* XXX is this safe to use on Win now? */
924 IDL_NODE_TYPE_NAME(IDL_NODE_UP(type
))
932 td
->prefix
.flags
= TD_VOID
;
939 fill_pd_from_type(TreeState
*state
, XPTParamDescriptor
*pd
, uint8 flags
,
943 return fill_td_from_type(state
, &pd
->type
, type
);
947 fill_pd_from_param(TreeState
*state
, XPTParamDescriptor
*pd
, IDL_tree tree
)
950 gboolean is_dipper_type
= DIPPER_TYPE(IDL_PARAM_DCL(tree
).param_type_spec
);
952 switch (IDL_PARAM_DCL(tree
).attr
) {
959 case IDL_PARAM_INOUT
:
960 flags
= XPT_PD_IN
| XPT_PD_OUT
;
964 if (IDL_tree_property_get(IDL_PARAM_DCL(tree
).simple_declarator
,
966 if (flags
!= XPT_PD_OUT
) {
967 IDL_tree_error(tree
, "can't have [retval] with in%s param "
969 flags
& XPT_PD_OUT
? "out" : "");
972 flags
|= XPT_PD_RETVAL
;
975 if (is_dipper_type
&& (flags
& XPT_PD_OUT
)) {
976 flags
&= ~XPT_PD_OUT
;
977 flags
|= XPT_PD_IN
| XPT_PD_DIPPER
;
980 if (IDL_tree_property_get(IDL_PARAM_DCL(tree
).simple_declarator
,
982 if (flags
& XPT_PD_IN
) {
983 IDL_tree_error(tree
, "can't have [shared] with in%s param "
985 flags
& XPT_PD_OUT
? "out" : "");
988 flags
|= XPT_PD_SHARED
;
991 if (IDL_tree_property_get(IDL_PARAM_DCL(tree
).simple_declarator
,
993 flags
|= XPT_PD_OPTIONAL
;
996 /* stick param where we can see it later */
998 return fill_pd_from_type(state
, pd
, flags
,
999 IDL_PARAM_DCL(tree
).param_type_spec
);
1002 /* XXXshaver common with xpidl_header.c */
1003 #define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data))
1004 #define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec)
1005 #define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree)))
1008 fill_pd_as_nsresult(XPTParamDescriptor
*pd
)
1010 pd
->type
.prefix
.flags
= TD_UINT32
; /* TD_NSRESULT */
1015 typelib_attr_accessor(TreeState
*state
, XPTMethodDescriptor
*meth
,
1016 gboolean getter
, gboolean hidden
)
1018 uint8 methflags
= 0;
1021 methflags
|= getter
? XPT_MD_GETTER
: XPT_MD_SETTER
;
1022 methflags
|= hidden
? XPT_MD_HIDDEN
: 0;
1023 if (!XPT_FillMethodDescriptor(ARENA(state
), meth
, methflags
,
1024 ATTR_IDENT(state
->tree
).str
, 1))
1028 if (DIPPER_TYPE(ATTR_TYPE_DECL(state
->tree
))) {
1029 pdflags
|= (XPT_PD_RETVAL
| XPT_PD_IN
| XPT_PD_DIPPER
);
1031 pdflags
|= (XPT_PD_RETVAL
| XPT_PD_OUT
);
1034 pdflags
|= XPT_PD_IN
;
1037 if (!fill_pd_from_type(state
, meth
->params
, pdflags
,
1038 ATTR_TYPE_DECL(state
->tree
)))
1041 fill_pd_as_nsresult(meth
->result
);
1047 typelib_attr_dcl(TreeState
*state
)
1049 XPTInterfaceDescriptor
*id
= CURRENT(state
);
1050 XPTMethodDescriptor
*meth
;
1051 gboolean read_only
= IDL_ATTR_DCL(state
->tree
).f_readonly
;
1053 /* XXX this only handles the first ident; elsewhere too... */
1055 IDL_LIST(IDL_ATTR_DCL(state
->tree
).simple_declarations
).data
;
1057 /* If it's marked [noscript], mark it as hidden in the typelib. */
1058 gboolean hidden
= (IDL_tree_property_get(ident
, "noscript") != NULL
);
1060 if (!verify_attribute_declaration(state
->tree
))
1063 if (!XPT_InterfaceDescriptorAddMethods(ARENA(state
), id
,
1064 (PRUint16
) (read_only
? 1 : 2)))
1067 meth
= &id
->method_descriptors
[NEXT_METH(state
)];
1069 return typelib_attr_accessor(state
, meth
, TRUE
, hidden
) &&
1070 (read_only
|| typelib_attr_accessor(state
, meth
+ 1, FALSE
, hidden
));
1074 typelib_op_dcl(TreeState
*state
)
1076 XPTInterfaceDescriptor
*id
= CURRENT(state
);
1077 XPTMethodDescriptor
*meth
;
1078 struct _IDL_OP_DCL
*op
= &IDL_OP_DCL(state
->tree
);
1080 uint16 num_args
= 0;
1082 gboolean op_notxpcom
= (IDL_tree_property_get(op
->ident
, "notxpcom")
1084 gboolean op_noscript
= (IDL_tree_property_get(op
->ident
, "noscript")
1087 if (!verify_method_declaration(state
->tree
))
1090 if (!XPT_InterfaceDescriptorAddMethods(ARENA(state
), id
, 1))
1093 meth
= &id
->method_descriptors
[NEXT_METH(state
)];
1095 for (iter
= op
->parameter_dcls
; iter
; iter
= IDL_LIST(iter
).next
)
1096 num_args
++; /* count params */
1097 if (op
->op_type_spec
&& !op_notxpcom
)
1098 num_args
++; /* fake param for _retval */
1101 op_flags
|= XPT_MD_HIDDEN
;
1103 op_flags
|= XPT_MD_NOTXPCOM
;
1105 /* XXXshaver constructor? */
1107 #ifdef DEBUG_shaver_method
1108 fprintf(stdout
, "DBG: adding method %s (nargs %d)\n",
1109 IDL_IDENT(op
->ident
).str
, num_args
);
1111 if (!XPT_FillMethodDescriptor(ARENA(state
), meth
, op_flags
,
1112 IDL_IDENT(op
->ident
).str
,
1116 for (num_args
= 0, iter
= op
->parameter_dcls
; iter
;
1117 iter
= IDL_LIST(iter
).next
, num_args
++) {
1118 XPTParamDescriptor
*pd
= &meth
->params
[num_args
];
1119 if (!fill_pd_from_param(state
, pd
, IDL_LIST(iter
).data
))
1123 /* stick retval param where we can see it later */
1124 state
->tree
= op
->op_type_spec
;
1126 /* XXX unless [notxpcom] */
1128 if (op
->op_type_spec
) {
1129 uint8 pdflags
= DIPPER_TYPE(op
->op_type_spec
) ?
1130 (XPT_PD_RETVAL
| XPT_PD_IN
| XPT_PD_DIPPER
) :
1131 (XPT_PD_RETVAL
| XPT_PD_OUT
);
1133 if (!fill_pd_from_type(state
, &meth
->params
[num_args
],
1134 pdflags
, op
->op_type_spec
))
1138 if (!fill_pd_as_nsresult(meth
->result
))
1141 #ifdef DEBUG_shaver_notxpcom
1142 fprintf(stderr
, "%s is notxpcom\n", IDL_IDENT(op
->ident
).str
);
1144 if (!fill_pd_from_type(state
, meth
->result
, XPT_PD_RETVAL
,
1153 typelib_const_dcl(TreeState
*state
)
1155 struct _IDL_CONST_DCL
*dcl
= &IDL_CONST_DCL(state
->tree
);
1156 const char *name
= IDL_IDENT(dcl
->ident
).str
;
1160 XPTInterfaceDescriptor
*id
;
1161 XPTConstDescriptor
*cd
;
1162 IDL_longlong_t value
;
1164 if (!verify_const_declaration(state
->tree
))
1167 /* Could be a typedef; try to map it to the real type. */
1168 real_type
= find_underlying_type(dcl
->const_type
);
1169 real_type
= real_type
? real_type
: dcl
->const_type
;
1170 is_long
= (IDL_TYPE_INTEGER(real_type
).f_type
== IDL_INTEGER_TYPE_LONG
);
1172 id
= CURRENT(state
);
1173 if (!XPT_InterfaceDescriptorAddConsts(ARENA(state
), id
, 1))
1175 cd
= &id
->const_descriptors
[NEXT_CONST(state
)];
1177 cd
->name
= IDL_IDENT(dcl
->ident
).str
;
1178 #ifdef DEBUG_shaver_const
1179 fprintf(stderr
, "DBG: adding const %s\n", cd
->name
);
1181 if (!fill_td_from_type(state
, &cd
->type
, dcl
->const_type
))
1184 value
= IDL_INTEGER(dcl
->const_exp
).value
;
1185 sign
= IDL_TYPE_INTEGER(dcl
->const_type
).f_signed
;
1188 cd
->value
.i32
= value
;
1190 cd
->value
.ui32
= value
;
1193 cd
->value
.i16
= value
;
1195 cd
->value
.ui16
= value
;
1197 NEXT_CONST(state
)++;
1202 typelib_enum(TreeState
*state
)
1204 XPIDL_WARNING((state
->tree
, IDL_WARNING1
,
1205 "enums not supported, enum \'%s\' ignored",
1206 IDL_IDENT(IDL_TYPE_ENUM(state
->tree
).ident
).str
));
1211 xpidl_typelib_dispatch(void)
1213 static backend result
;
1214 static nodeHandler table
[IDLN_LAST
];
1215 static gboolean initialized
= FALSE
;
1217 result
.emit_prolog
= typelib_prolog
;
1218 result
.emit_epilog
= typelib_epilog
;
1221 /* Initialize non-NULL elements */
1222 table
[IDLN_LIST
] = typelib_list
;
1223 table
[IDLN_ATTR_DCL
] = typelib_attr_dcl
;
1224 table
[IDLN_OP_DCL
] = typelib_op_dcl
;
1225 table
[IDLN_INTERFACE
] = typelib_interface
;
1226 table
[IDLN_CONST_DCL
] = typelib_const_dcl
;
1227 table
[IDLN_TYPE_ENUM
] = typelib_enum
;
1228 table
[IDLN_NATIVE
] = check_native
;
1232 result
.dispatch_table
= table
;