| 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 | * Generate XPCOM headers from XPIDL. |
|---|
| 41 | */ |
|---|
| 42 | |
|---|
| 43 | #include "xpidlpas.h" |
|---|
| 44 | #include <ctype.h> |
|---|
| 45 | |
|---|
| 46 | #define AS_DECL 0 |
|---|
| 47 | #define AS_CALL 1 |
|---|
| 48 | #define AS_IMPL 2 |
|---|
| 49 | |
|---|
| 50 | static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile, |
|---|
| 51 | int mode, const char *className); |
|---|
| 52 | static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile, |
|---|
| 53 | gboolean getter, |
|---|
| 54 | int mode, const char *className); |
|---|
| 55 | |
|---|
| 56 | static void |
|---|
| 57 | write_classname_iid_define(FILE *file, const char *className) |
|---|
| 58 | { |
|---|
| 59 | const char *iidName; |
|---|
| 60 | if (className[0] == 'n' && className[1] == 's') { |
|---|
| 61 | /* backcompat naming styles */ |
|---|
| 62 | fputs("NS_", file); |
|---|
| 63 | iidName = className + 2; |
|---|
| 64 | } else { |
|---|
| 65 | iidName = className; |
|---|
| 66 | } |
|---|
| 67 | while (*iidName) |
|---|
| 68 | fputc(toupper(*iidName++), file); |
|---|
| 69 | fputs("_IID", file); |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | static void |
|---|
| 73 | write_classname_const_define(FILE *file, const char *className) |
|---|
| 74 | { |
|---|
| 75 | const char *iidName; |
|---|
| 76 | if (className[0] == 'n' && className[1] == 's') { |
|---|
| 77 | /* backcompat naming styles */ |
|---|
| 78 | fputs("NS_", file); |
|---|
| 79 | iidName = className + 2; |
|---|
| 80 | } else { |
|---|
| 81 | iidName = className; |
|---|
| 82 | } |
|---|
| 83 | while (*iidName) |
|---|
| 84 | fputc(toupper(*iidName++), file); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | static gboolean |
|---|
| 88 | interface(TreeState *state) |
|---|
| 89 | { |
|---|
| 90 | IDL_tree iface = state->tree, iter, orig; |
|---|
| 91 | char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str; |
|---|
| 92 | gboolean ok = TRUE; |
|---|
| 93 | const char *iid; |
|---|
| 94 | struct nsID id; |
|---|
| 95 | char iid_parsed[UUID_LENGTH]; |
|---|
| 96 | GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments; |
|---|
| 97 | |
|---|
| 98 | if (!verify_interface_declaration(iface)) |
|---|
| 99 | return FALSE; |
|---|
| 100 | |
|---|
| 101 | #define FAIL do {ok = FALSE; goto out;} while(0) |
|---|
| 102 | |
|---|
| 103 | iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid"); |
|---|
| 104 | if (iid) { |
|---|
| 105 | /* Redundant, but a better error than 'cannot parse.' */ |
|---|
| 106 | if (strlen(iid) != 36) { |
|---|
| 107 | IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid); |
|---|
| 108 | FAIL; |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | /* |
|---|
| 112 | * Parse uuid and then output resulting nsID to string, to validate |
|---|
| 113 | * uuid and normalize resulting .h files. |
|---|
| 114 | */ |
|---|
| 115 | if (!xpidl_parse_iid(&id, iid)) { |
|---|
| 116 | IDL_tree_error(state->tree, "cannot parse IID %s\n", iid); |
|---|
| 117 | FAIL; |
|---|
| 118 | } |
|---|
| 119 | if (!xpidl_sprint_iid(&id, iid_parsed)) { |
|---|
| 120 | IDL_tree_error(state->tree, "error formatting IID %s\n", iid); |
|---|
| 121 | FAIL; |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | /* NS_ISUPPORTS_IID: TGUID = '{00000000-0000-0000-c000-000000000046}'; */ |
|---|
| 125 | /*fputs("#define ", state->file);*/ |
|---|
| 126 | write_indent(state->file); |
|---|
| 127 | write_classname_iid_define(state->file, className); |
|---|
| 128 | fprintf(state->file, ": TGUID = \'{%s}\';", iid_parsed); |
|---|
| 129 | fputc('\n', state->file); |
|---|
| 130 | } else { |
|---|
| 131 | IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n", |
|---|
| 132 | className); |
|---|
| 133 | FAIL; |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | orig = state->tree; /* It would be nice to remove this state-twiddling. */ |
|---|
| 137 | |
|---|
| 138 | state->tree = IDL_INTERFACE(iface).body; |
|---|
| 139 | |
|---|
| 140 | if (state->tree && !xpidl_process_node(state)) |
|---|
| 141 | FAIL; |
|---|
| 142 | |
|---|
| 143 | fputc('\n', state->file); |
|---|
| 144 | |
|---|
| 145 | #undef FAIL |
|---|
| 146 | |
|---|
| 147 | out: |
|---|
| 148 | return ok; |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | static gboolean |
|---|
| 152 | do_const_dcl(TreeState *state) |
|---|
| 153 | { |
|---|
| 154 | IDL_tree parent = IDL_get_parent_node(state->tree, IDLN_INTERFACE, NULL); |
|---|
| 155 | /*IDL_tree parent = state->tree->up;*/ |
|---|
| 156 | char *className = IDL_IDENT(IDL_INTERFACE(parent).ident).str; |
|---|
| 157 | gboolean ok = FALSE; |
|---|
| 158 | struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree); |
|---|
| 159 | const char *name = IDL_IDENT(dcl->ident).str; |
|---|
| 160 | gboolean is_signed; |
|---|
| 161 | GSList *doc_comments = IDL_IDENT(dcl->ident).comments; |
|---|
| 162 | IDL_tree real_type; |
|---|
| 163 | const char *const_format; |
|---|
| 164 | |
|---|
| 165 | if (!verify_const_declaration(state->tree)) |
|---|
| 166 | goto FAIL; |
|---|
| 167 | |
|---|
| 168 | if (doc_comments != NULL && comment_level >= 2) { |
|---|
| 169 | write_indent(state->file); |
|---|
| 170 | printlist(state->file, doc_comments); |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | /* Could be a typedef; try to map it to the real type. */ |
|---|
| 174 | real_type = find_underlying_type(dcl->const_type); |
|---|
| 175 | real_type = real_type ? real_type : dcl->const_type; |
|---|
| 176 | is_signed = IDL_TYPE_INTEGER(real_type).f_signed; |
|---|
| 177 | |
|---|
| 178 | const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "u"; |
|---|
| 179 | write_indent(state->file); |
|---|
| 180 | write_classname_const_define(state->file, className); |
|---|
| 181 | fprintf(state->file, "_%s = ", name); |
|---|
| 182 | fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value); |
|---|
| 183 | fprintf(state->file, ";\n"); |
|---|
| 184 | |
|---|
| 185 | ok = TRUE; |
|---|
| 186 | FAIL:; |
|---|
| 187 | return ok; |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | static gboolean |
|---|
| 191 | codefrag(TreeState *state) |
|---|
| 192 | { |
|---|
| 193 | const char *desc = IDL_CODEFRAG(state->tree).desc; |
|---|
| 194 | GSList *lines = IDL_CODEFRAG(state->tree).lines; |
|---|
| 195 | guint fragment_length; |
|---|
| 196 | |
|---|
| 197 | if (strcmp(desc, "PASCAL") && /* libIDL bug? */ strcmp(desc, "PASCAL\r")) { |
|---|
| 198 | XPIDL_WARNING((state->tree, IDL_WARNING1, |
|---|
| 199 | "ignoring '%%{%s' escape. " |
|---|
| 200 | "(Use '%%{PASCAL' to escape verbatim PASCAL code.)", desc)); |
|---|
| 201 | |
|---|
| 202 | return TRUE; |
|---|
| 203 | } |
|---|
| 204 | |
|---|
| 205 | /* |
|---|
| 206 | * Emit #file directive to point debuggers back to the original .idl file |
|---|
| 207 | * for the duration of the code fragment. We look at internal IDL node |
|---|
| 208 | * properties _file, _line to do this; hopefully they won't change. |
|---|
| 209 | * |
|---|
| 210 | * _line seems to refer to the line immediately after the closing %}, so |
|---|
| 211 | * we backtrack to get the proper line for the beginning of the block. |
|---|
| 212 | */ |
|---|
| 213 | /* |
|---|
| 214 | * Looks like getting this right means maintaining an accurate line |
|---|
| 215 | * count of everything generated, so we can set the file back to the |
|---|
| 216 | * correct line in the generated file afterwards. Skipping for now... |
|---|
| 217 | */ |
|---|
| 218 | |
|---|
| 219 | fragment_length = g_slist_length(lines); |
|---|
| 220 | /* fprintf(state->file, "#line %d \"%s\"\n", */ |
|---|
| 221 | /* state->tree->_line - fragment_length - 1, */ |
|---|
| 222 | /* state->tree->_file); */ |
|---|
| 223 | |
|---|
| 224 | g_slist_foreach(lines, write_codefrag_line, (gpointer)state); |
|---|
| 225 | |
|---|
| 226 | return TRUE; |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | backend * |
|---|
| 230 | xpidl_const_dispatch(void) |
|---|
| 231 | { |
|---|
| 232 | static backend result; |
|---|
| 233 | static nodeHandler table[IDLN_LAST]; |
|---|
| 234 | static gboolean initialized = FALSE; |
|---|
| 235 | |
|---|
| 236 | result.emit_prolog = pascal_prolog; |
|---|
| 237 | result.emit_epilog = pascal_epilog; |
|---|
| 238 | |
|---|
| 239 | if (!initialized) { |
|---|
| 240 | table[IDLN_LIST] = pascal_list; |
|---|
| 241 | table[IDLN_INTERFACE] = interface; |
|---|
| 242 | table[IDLN_CODEFRAG] = codefrag; |
|---|
| 243 | table[IDLN_CONST_DCL] = do_const_dcl; |
|---|
| 244 | table[IDLN_NATIVE] = check_native; |
|---|
| 245 | initialized = TRUE; |
|---|
| 246 | } |
|---|
| 247 | |
|---|
| 248 | result.dispatch_table = table; |
|---|
| 249 | return &result; |
|---|
| 250 | } |
|---|