1 /* GLIB-GenMarshal - Marshaller generator for GObject library 2 * Copyright (C) 2000-2001 Red Hat, Inc. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19 20 #include "config.h" 21 22 #include <stdlib.h> 23 #include <fcntl.h> 24 #include <string.h> 25 #include <errno.h> 26 #ifdef HAVE_UNISTD_H 27 #include <unistd.h> 28 #endif 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 32 #undef G_LOG_DOMAIN 33 #define G_LOG_DOMAIN "GLib-Genmarshal" 34 #include <glib.h> 35 #include <glib/gprintf.h> 36 37 #ifdef G_OS_WIN32 38 #include <io.h> 39 #endif 40 41 /* --- defines --- */ 42 #define PRG_NAME "glib-genmarshal" 43 #define PKG_NAME "GLib" 44 #define PKG_HTTP_HOME "http://www.gtk.org" 45 46 47 /* --- typedefs & structures --- */ 48 typedef struct 49 { 50 gchar *keyword; /* marhaller list keyword [MY_STRING] */ 51 const gchar *sig_name; /* signature name [STRING] */ 52 const gchar *ctype; /* C type name [gchar*] */ 53 const gchar *getter; /* value getter function [g_value_get_string] */ 54 } InArgument; 55 typedef struct 56 { 57 gchar *keyword; /* marhaller list keyword [MY_STRING] */ 58 const gchar *sig_name; /* signature name [STRING] */ 59 const gchar *ctype; /* C type name [gchar*] */ 60 const gchar *setter; /* value setter function [g_value_set_string] */ 61 } OutArgument; 62 typedef struct 63 { 64 gchar *ploc; 65 OutArgument *rarg; 66 GList *args; /* of type InArgument* */ 67 } Signature; 68 69 70 /* --- prototypes --- */ 71 static void parse_args (gint *argc_p, 72 gchar ***argv_p); 73 static void print_blurb (FILE *bout, 74 gboolean print_help); 75 76 77 /* --- variables --- */ 78 static const GScannerConfig scanner_config_template = 79 { 80 ( 81 " \t\r" /* "\n" is statement delimiter */ 82 ) /* cset_skip_characters */, 83 ( 84 G_CSET_a_2_z 85 "_" 86 G_CSET_A_2_Z 87 ) /* cset_identifier_first */, 88 ( 89 G_CSET_a_2_z 90 "_0123456789" 91 G_CSET_A_2_Z 92 ) /* cset_identifier_nth */, 93 ( "#\n" ) /* cpair_comment_single */, 94 95 FALSE /* case_sensitive */, 96 97 TRUE /* skip_comment_multi */, 98 TRUE /* skip_comment_single */, 99 TRUE /* scan_comment_multi */, 100 TRUE /* scan_identifier */, 101 FALSE /* scan_identifier_1char */, 102 FALSE /* scan_identifier_NULL */, 103 TRUE /* scan_symbols */, 104 FALSE /* scan_binary */, 105 TRUE /* scan_octal */, 106 TRUE /* scan_float */, 107 TRUE /* scan_hex */, 108 FALSE /* scan_hex_dollar */, 109 TRUE /* scan_string_sq */, 110 TRUE /* scan_string_dq */, 111 TRUE /* numbers_2_int */, 112 FALSE /* int_2_float */, 113 FALSE /* identifier_2_string */, 114 TRUE /* char_2_token */, 115 FALSE /* symbol_2_token */, 116 FALSE /* scope_0_fallback */, 117 }; 118 static gchar * const std_marshaller_prefix = "g_cclosure_marshal"; 119 static gchar *marshaller_prefix = "g_cclosure_user_marshal"; 120 static GHashTable *marshallers = NULL; 121 static FILE *fout = NULL; 122 static gboolean gen_cheader = FALSE; 123 static gboolean gen_cbody = FALSE; 124 static gboolean gen_internal = FALSE; 125 static gboolean skip_ploc = FALSE; 126 static gboolean std_includes = TRUE; 127 static gint exit_status = 0; 128 129 130 /* --- functions --- */ 131 static void 132 put_marshal_value_getters (void) 133 { 134 fputs ("\n", fout); 135 fputs ("#ifdef G_ENABLE_DEBUG\n", fout); 136 fputs ("#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)\n", fout); 137 fputs ("#define g_marshal_value_peek_char(v) g_value_get_char (v)\n", fout); 138 fputs ("#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)\n", fout); 139 fputs ("#define g_marshal_value_peek_int(v) g_value_get_int (v)\n", fout); 140 fputs ("#define g_marshal_value_peek_uint(v) g_value_get_uint (v)\n", fout); 141 fputs ("#define g_marshal_value_peek_long(v) g_value_get_long (v)\n", fout); 142 fputs ("#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)\n", fout); 143 fputs ("#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)\n", fout); 144 fputs ("#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)\n", fout); 145 fputs ("#define g_marshal_value_peek_enum(v) g_value_get_enum (v)\n", fout); 146 fputs ("#define g_marshal_value_peek_flags(v) g_value_get_flags (v)\n", fout); 147 fputs ("#define g_marshal_value_peek_float(v) g_value_get_float (v)\n", fout); 148 fputs ("#define g_marshal_value_peek_double(v) g_value_get_double (v)\n", fout); 149 fputs ("#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)\n", fout); 150 fputs ("#define g_marshal_value_peek_param(v) g_value_get_param (v)\n", fout); 151 fputs ("#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)\n", fout); 152 fputs ("#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)\n", fout); 153 fputs ("#define g_marshal_value_peek_object(v) g_value_get_object (v)\n", fout); 154 fputs ("#else /* !G_ENABLE_DEBUG */\n", fout); 155 fputs ("/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.\n", fout); 156 fputs (" * Do not access GValues directly in your code. Instead, use the\n", fout); 157 fputs (" * g_value_get_*() functions\n", fout); 158 fputs (" */\n", fout); 159 fputs ("#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int\n", fout); 160 fputs ("#define g_marshal_value_peek_char(v) (v)->data[0].v_int\n", fout); 161 fputs ("#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint\n", fout); 162 fputs ("#define g_marshal_value_peek_int(v) (v)->data[0].v_int\n", fout); 163 fputs ("#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint\n", fout); 164 fputs ("#define g_marshal_value_peek_long(v) (v)->data[0].v_long\n", fout); 165 fputs ("#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong\n", fout); 166 fputs ("#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64\n", fout); 167 fputs ("#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64\n", fout); 168 fputs ("#define g_marshal_value_peek_enum(v) (v)->data[0].v_long\n", fout); 169 fputs ("#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong\n", fout); 170 fputs ("#define g_marshal_value_peek_float(v) (v)->data[0].v_float\n", fout); 171 fputs ("#define g_marshal_value_peek_double(v) (v)->data[0].v_double\n", fout); 172 fputs ("#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer\n", fout); 173 fputs ("#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer\n", fout); 174 fputs ("#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer\n", fout); 175 fputs ("#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer\n", fout); 176 fputs ("#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer\n", fout); 177 fputs ("#endif /* !G_ENABLE_DEBUG */\n", fout); 178 fputs ("\n", fout); 179 } 180 181 static gboolean 182 complete_in_arg (InArgument *iarg) 183 { 184 static const InArgument args[] = { 185 /* keyword sig_name ctype getter */ 186 { "VOID", "VOID", "void", NULL, }, 187 { "BOOLEAN", "BOOLEAN", "gboolean", "g_marshal_value_peek_boolean", }, 188 { "CHAR", "CHAR", "gchar", "g_marshal_value_peek_char", }, 189 { "UCHAR", "UCHAR", "guchar", "g_marshal_value_peek_uchar", }, 190 { "INT", "INT", "gint", "g_marshal_value_peek_int", }, 191 { "UINT", "UINT", "guint", "g_marshal_value_peek_uint", }, 192 { "LONG", "LONG", "glong", "g_marshal_value_peek_long", }, 193 { "ULONG", "ULONG", "gulong", "g_marshal_value_peek_ulong", }, 194 { "INT64", "INT64", "gint64", "g_marshal_value_peek_int64", }, 195 { "UINT64", "UINT64", "guint64", "g_marshal_value_peek_uint64", }, 196 { "ENUM", "ENUM", "gint", "g_marshal_value_peek_enum", }, 197 { "FLAGS", "FLAGS", "guint", "g_marshal_value_peek_flags", }, 198 { "FLOAT", "FLOAT", "gfloat", "g_marshal_value_peek_float", }, 199 { "DOUBLE", "DOUBLE", "gdouble", "g_marshal_value_peek_double", }, 200 { "STRING", "STRING", "gpointer", "g_marshal_value_peek_string", }, 201 { "PARAM", "PARAM", "gpointer", "g_marshal_value_peek_param", }, 202 { "BOXED", "BOXED", "gpointer", "g_marshal_value_peek_boxed", }, 203 { "POINTER", "POINTER", "gpointer", "g_marshal_value_peek_pointer", }, 204 { "OBJECT", "OBJECT", "gpointer", "g_marshal_value_peek_object", }, 205 /* deprecated: */ 206 { "NONE", "VOID", "void", NULL, }, 207 { "BOOL", "BOOLEAN", "gboolean", "g_marshal_value_peek_boolean", }, 208 }; 209 guint i; 210 211 g_return_val_if_fail (iarg != NULL, FALSE); 212 213 for (i = 0; i < G_N_ELEMENTS (args); i++) 214 if (strcmp (args[i].keyword, iarg->keyword) == 0) 215 { 216 iarg->sig_name = args[i].sig_name; 217 iarg->ctype = args[i].ctype; 218 iarg->getter = args[i].getter; 219 220 return TRUE; 221 } 222 return FALSE; 223 } 224 225 static gboolean 226 complete_out_arg (OutArgument *oarg) 227 { 228 static const OutArgument args[] = { 229 /* keyword sig_name ctype setter */ 230 { "VOID", "VOID", "void", NULL, }, 231 { "BOOLEAN", "BOOLEAN", "gboolean", "g_value_set_boolean", }, 232 { "CHAR", "CHAR", "gchar", "g_value_set_char", }, 233 { "UCHAR", "UCHAR", "guchar", "g_value_set_uchar", }, 234 { "INT", "INT", "gint", "g_value_set_int", }, 235 { "UINT", "UINT", "guint", "g_value_set_uint", }, 236 { "LONG", "LONG", "glong", "g_value_set_long", }, 237 { "ULONG", "ULONG", "gulong", "g_value_set_ulong", }, 238 { "INT64", "INT64", "gint64", "g_value_set_int64", }, 239 { "UINT64", "UINT64", "guint64", "g_value_set_uint64", }, 240 { "ENUM", "ENUM", "gint", "g_value_set_enum", }, 241 { "FLAGS", "FLAGS", "guint", "g_value_set_flags", }, 242 { "FLOAT", "FLOAT", "gfloat", "g_value_set_float", }, 243 { "DOUBLE", "DOUBLE", "gdouble", "g_value_set_double", }, 244 { "STRING", "STRING", "gchar*", "g_value_take_string", }, 245 { "PARAM", "PARAM", "GParamSpec*", "g_value_take_param", }, 246 { "BOXED", "BOXED", "gpointer", "g_value_take_boxed", }, 247 { "POINTER", "POINTER", "gpointer", "g_value_set_pointer", }, 248 { "OBJECT", "OBJECT", "GObject*", "g_value_take_object", }, 249 /* deprecated: */ 250 { "NONE", "VOID", "void", NULL, }, 251 { "BOOL", "BOOLEAN", "gboolean", "g_value_set_boolean", }, 252 }; 253 guint i; 254 255 g_return_val_if_fail (oarg != NULL, FALSE); 256 257 for (i = 0; i < G_N_ELEMENTS (args); i++) 258 if (strcmp (args[i].keyword, oarg->keyword) == 0) 259 { 260 oarg->sig_name = args[i].sig_name; 261 oarg->ctype = args[i].ctype; 262 oarg->setter = args[i].setter; 263 264 return TRUE; 265 } 266 return FALSE; 267 } 268 269 static const gchar* 270 pad (const gchar *string) 271 { 272 #define PAD_LENGTH 12 273 static gchar *buffer = NULL; 274 gint i; 275 276 g_return_val_if_fail (string != NULL, NULL); 277 278 if (!buffer) 279 buffer = g_new (gchar, PAD_LENGTH + 1); 280 281 /* paranoid check */ 282 if (strlen (string) >= PAD_LENGTH) 283 { 284 g_free (buffer); 285 buffer = g_strdup_printf ("%s ", string); 286 g_warning ("overfull string (%u bytes) for padspace", 287 (guint) strlen (string)); 288 exit_status |= 2; 289 290 return buffer; 291 } 292 293 for (i = 0; i < PAD_LENGTH; i++) 294 { 295 gboolean done = *string == 0; 296 297 buffer[i] = done ? ' ' : *string++; 298 } 299 buffer[i] = 0; 300 301 return buffer; 302 } 303 304 static const gchar* 305 indent (guint n_spaces) 306 { 307 static gchar *buffer = NULL; 308 static guint blength = 0; 309 310 if (blength <= n_spaces) 311 { 312 blength = n_spaces + 1; 313 g_free (buffer); 314 buffer = g_new (gchar, blength); 315 } 316 memset (buffer, ' ', n_spaces); 317 buffer[n_spaces] = 0; 318 319 return buffer; 320 } 321 322 static void 323 generate_marshal (const gchar *signame, 324 Signature *sig) 325 { 326 guint ind, a; 327 GList *node; 328 gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL); 329 gboolean have_std_marshaller = FALSE; 330 331 /* here we have to make sure a marshaller named <marshaller_prefix>_<signame> 332 * exists. we might have put it out already, can revert to a standard 333 * marshaller provided by glib, or need to generate one. 334 */ 335 336 if (g_hash_table_lookup (marshallers, tmp)) 337 { 338 /* done, marshaller already generated */ 339 g_free (tmp); 340 return; 341 } 342 else 343 { 344 /* need to alias/generate marshaller, register name */ 345 g_hash_table_insert (marshallers, tmp, tmp); 346 } 347 348 /* can we revert to a standard marshaller? */ 349 if (std_includes) 350 { 351 tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL); 352 have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL; 353 g_free (tmp); 354 } 355 356 if (gen_cheader && have_std_marshaller) 357 { 358 g_fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame); 359 } 360 if (gen_cheader && !have_std_marshaller) 361 { 362 ind = g_fprintf (fout, gen_internal ? "G_GNUC_INTERNAL " : "extern "); 363 ind += g_fprintf (fout, "void "); 364 ind += g_fprintf (fout, "%s_%s (", marshaller_prefix, signame); 365 g_fprintf (fout, "GClosure *closure,\n"); 366 g_fprintf (fout, "%sGValue *return_value,\n", indent (ind)); 367 g_fprintf (fout, "%sguint n_param_values,\n", indent (ind)); 368 g_fprintf (fout, "%sconst GValue *param_values,\n", indent (ind)); 369 g_fprintf (fout, "%sgpointer invocation_hint,\n", indent (ind)); 370 g_fprintf (fout, "%sgpointer marshal_data);\n", 371 indent (ind)); 372 } 373 if (gen_cbody && !have_std_marshaller) 374 { 375 /* cfile marshal header */ 376 g_fprintf (fout, "void\n"); 377 ind = g_fprintf (fout, "%s_%s (", marshaller_prefix, signame); 378 g_fprintf (fout, "GClosure *closure,\n"); 379 g_fprintf (fout, "%sGValue *return_value G_GNUC_UNUSED,\n", indent (ind)); 380 g_fprintf (fout, "%sguint n_param_values,\n", indent (ind)); 381 g_fprintf (fout, "%sconst GValue *param_values,\n", indent (ind)); 382 g_fprintf (fout, "%sgpointer invocation_hint G_GNUC_UNUSED,\n", indent (ind)); 383 g_fprintf (fout, "%sgpointer marshal_data)\n", indent (ind)); 384 g_fprintf (fout, "{\n"); 385 386 /* cfile GMarshalFunc typedef */ 387 ind = g_fprintf (fout, " typedef %s (*GMarshalFunc_%s) (", sig->rarg->ctype, signame); 388 g_fprintf (fout, "%s data1,\n", pad ("gpointer")); 389 for (a = 1, node = sig->args; node; node = node->next) 390 { 391 InArgument *iarg = node->data; 392 393 if (iarg->getter) 394 g_fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (iarg->ctype), a++); 395 } 396 g_fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer")); 397 398 /* cfile marshal variables */ 399 g_fprintf (fout, " register GMarshalFunc_%s callback;\n", signame); 400 g_fprintf (fout, " register GCClosure *cc = (GCClosure*) closure;\n"); 401 g_fprintf (fout, " register gpointer data1, data2;\n"); 402 if (sig->rarg->setter) 403 g_fprintf (fout, " %s v_return;\n", sig->rarg->ctype); 404 405 if (sig->args || sig->rarg->setter) 406 { 407 g_fprintf (fout, "\n"); 408 409 if (sig->rarg->setter) 410 g_fprintf (fout, " g_return_if_fail (return_value != NULL);\n"); 411 if (sig->args) 412 { 413 for (a = 0, node = sig->args; node; node = node->next) 414 { 415 InArgument *iarg = node->data; 416 417 if (iarg->getter) 418 a++; 419 } 420 g_fprintf (fout, " g_return_if_fail (n_param_values == %u);\n", 1 + a); 421 } 422 } 423 424 /* cfile marshal data1, data2 and callback setup */ 425 g_fprintf (fout, "\n"); 426 g_fprintf (fout, " if (G_CCLOSURE_SWAP_DATA (closure))\n {\n"); 427 g_fprintf (fout, " data1 = closure->data;\n"); 428 g_fprintf (fout, " data2 = g_value_peek_pointer (param_values + 0);\n"); 429 g_fprintf (fout, " }\n else\n {\n"); 430 g_fprintf (fout, " data1 = g_value_peek_pointer (param_values + 0);\n"); 431 g_fprintf (fout, " data2 = closure->data;\n"); 432 g_fprintf (fout, " }\n"); 433 g_fprintf (fout, " callback = (GMarshalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame); 434 435 /* cfile marshal callback action */ 436 g_fprintf (fout, "\n"); 437 ind = g_fprintf (fout, " %s callback (", sig->rarg->setter ? " v_return =" : ""); 438 g_fprintf (fout, "data1,\n"); 439 for (a = 1, node = sig->args; node; node = node->next) 440 { 441 InArgument *iarg = node->data; 442 443 if (iarg->getter) 444 g_fprintf (fout, "%s%s (param_values + %d),\n", indent (ind), iarg->getter, a++); 445 } 446 g_fprintf (fout, "%sdata2);\n", indent (ind)); 447 448 /* cfile marshal return value storage */ 449 if (sig->rarg->setter) 450 { 451 g_fprintf (fout, "\n"); 452 g_fprintf (fout, " %s (return_value, v_return);\n", sig->rarg->setter); 453 } 454 455 /* cfile marshal footer */ 456 g_fprintf (fout, "}\n"); 457 } 458 } 459 460 static void 461 process_signature (Signature *sig) 462 { 463 gchar *pname, *sname, *tmp; 464 GList *node; 465 466 /* lookup and complete info on arguments */ 467 if (!complete_out_arg (sig->rarg)) 468 { 469 g_warning ("unknown type: %s", sig->rarg->keyword); 470 exit_status |= 1; 471 return; 472 } 473 for (node = sig->args; node; node = node->next) 474 { 475 InArgument *iarg = node->data; 476 477 if (!complete_in_arg (iarg)) 478 { 479 g_warning ("unknown type: %s", iarg->keyword); 480 exit_status |= 1; 481 return; 482 } 483 } 484 485 /* construct requested marshaller name and technical marshaller name */ 486 pname = g_strconcat (sig->rarg->keyword, "_", NULL); 487 sname = g_strconcat (sig->rarg->sig_name, "_", NULL); 488 for (node = sig->args; node; node = node->next) 489 { 490 InArgument *iarg = node->data; 491 gchar *tmp; 492 493 tmp = sname; 494 sname = g_strconcat (tmp, "_", iarg->sig_name, NULL); 495 g_free (tmp); 496 tmp = pname; 497 pname = g_strconcat (tmp, "_", iarg->keyword, NULL); 498 g_free (tmp); 499 } 500 501 /* introductionary comment */ 502 g_fprintf (fout, "\n/* %s", sig->rarg->keyword); 503 for (node = sig->args; node; node = node->next) 504 { 505 InArgument *iarg = node->data; 506 507 g_fprintf (fout, "%c%s", node->prev ? ',' : ':', iarg->keyword); 508 } 509 if (!skip_ploc) 510 g_fprintf (fout, " (%s)", sig->ploc); 511 g_fprintf (fout, " */\n"); 512 513 /* ensure technical marshaller exists (<marshaller_prefix>_<sname>) */ 514 generate_marshal (sname, sig); 515 516 /* put out marshaller alias for requested name if required (<marshaller_prefix>_<pname>) */ 517 tmp = g_strconcat (marshaller_prefix, "_", pname, NULL); 518 if (gen_cheader && !g_hash_table_lookup (marshallers, tmp)) 519 { 520 g_fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname); 521 522 g_hash_table_insert (marshallers, tmp, tmp); 523 } 524 else 525 g_free (tmp); 526 527 g_free (pname); 528 g_free (sname); 529 } 530 531 static InArgument* 532 new_in_arg (const gchar *pname) 533 { 534 InArgument *iarg = g_new0 (InArgument, 1); 535 536 iarg->keyword = g_strdup (pname); 537 538 return iarg; 539 } 540 541 static OutArgument* 542 new_out_arg (const gchar *pname) 543 { 544 OutArgument *oarg = g_new0 (OutArgument, 1); 545 546 oarg->keyword = g_strdup (pname); 547 548 return oarg; 549 } 550 551 static guint 552 parse_line (GScanner *scanner, 553 Signature *sig) 554 { 555 /* parse identifier for return value */ 556 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER) 557 return G_TOKEN_IDENTIFIER; 558 sig->rarg = new_out_arg (scanner->value.v_identifier); 559 560 /* keep a note on the location */ 561 sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line); 562 563 /* expect ':' */ 564 if (g_scanner_get_next_token (scanner) != ':') 565 return ':'; 566 567 /* parse first argument */ 568 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER) 569 return G_TOKEN_IDENTIFIER; 570 sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier)); 571 572 /* parse rest of argument list */ 573 while (g_scanner_peek_next_token (scanner) == ',') 574 { 575 /* eat comma */ 576 g_scanner_get_next_token (scanner); 577 578 /* parse arg identifier */ 579 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER) 580 return G_TOKEN_IDENTIFIER; 581 sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier)); 582 } 583 584 /* expect end of line, done */ 585 if (g_scanner_get_next_token (scanner) != '\n') 586 return '\n'; 587 588 /* success */ 589 return G_TOKEN_NONE; 590 } 591 592 static gboolean 593 string_key_destroy (gpointer key, 594 gpointer value, 595 gpointer user_data) 596 { 597 g_free (key); 598 599 return TRUE; 600 } 601 602 int 603 main (int argc, 604 char *argv[]) 605 { 606 const gchar *gobject_marshallers[] = { 607 #include "gmarshal.strings" 608 }; 609 GScanner *scanner; 610 GSList *slist, *files = NULL; 611 gint i; 612 613 /* parse args and do fast exits */ 614 parse_args (&argc, &argv); 615 616 /* list input files */ 617 for (i = 1; i < argc; i++) 618 files = g_slist_prepend (files, argv[i]); 619 if (files) 620 files = g_slist_reverse (files); 621 else 622 files = g_slist_prepend (files, "/dev/stdin"); 623 624 /* setup auxillary structs */ 625 scanner = g_scanner_new (&scanner_config_template); 626 fout = stdout; 627 marshallers = g_hash_table_new (g_str_hash, g_str_equal); 628 629 /* add standard marshallers of the GObject library */ 630 if (std_includes) 631 for (i = 0; i < G_N_ELEMENTS (gobject_marshallers); i++) 632 { 633 gchar *tmp = g_strdup (gobject_marshallers[i]); 634 635 g_hash_table_insert (marshallers, tmp, tmp); 636 } 637 638 /* put out initial heading */ 639 g_fprintf (fout, "\n"); 640 641 if (gen_cheader && std_includes) 642 { 643 g_fprintf (fout, "#ifndef __%s_MARSHAL_H__\n", marshaller_prefix); 644 g_fprintf (fout, "#define __%s_MARSHAL_H__\n\n", marshaller_prefix); 645 } 646 647 if ((gen_cheader || gen_cbody) && std_includes) 648 g_fprintf (fout, "#include\t<glib-object.h>\n\n"); 649 650 if (gen_cheader) 651 g_fprintf (fout, "G_BEGIN_DECLS\n"); 652 653 /* generate necessary preprocessor directives */ 654 if (gen_cbody) 655 put_marshal_value_getters (); 656 657 /* process input files */ 658 for (slist = files; slist; slist = slist->next) 659 { 660 gchar *file = slist->data; 661 gint fd; 662 663 if (strcmp (file, "/dev/stdin") == 0) 664 /* Mostly for Win32. This is equivalent to opening /dev/stdin */ 665 fd = dup (0); 666 else 667 fd = open (file, O_RDONLY); 668 669 if (fd < 0) 670 { 671 g_warning ("failed to open \"%s\": %s", file, g_strerror (errno)); 672 exit_status |= 1; 673 continue; 674 } 675 676 /* set file name for error reports */ 677 scanner->input_name = file; 678 679 /* parse & process file */ 680 g_scanner_input_file (scanner, fd); 681 682 /* scanning loop, we parse the input until its end is reached, 683 * or our sub routine came across invalid syntax 684 */ 685 do 686 { 687 guint expected_token = G_TOKEN_NONE; 688 689 switch (g_scanner_peek_next_token (scanner)) 690 { 691 case '\n': 692 /* eat newline and restart */ 693 g_scanner_get_next_token (scanner); 694 continue; 695 case G_TOKEN_EOF: 696 /* done */ 697 break; 698 default: 699 /* parse and process signatures */ 700 { 701 Signature signature = { NULL, NULL, NULL }; 702 GList *node; 703 704 expected_token = parse_line (scanner, &signature); 705 706 /* once we got a valid signature, process it */ 707 if (expected_token == G_TOKEN_NONE) 708 process_signature (&signature); 709 710 /* clean up signature contents */ 711 g_free (signature.ploc); 712 if (signature.rarg) 713 g_free (signature.rarg->keyword); 714 g_free (signature.rarg); 715 for (node = signature.args; node; node = node->next) 716 { 717 InArgument *iarg = node->data; 718 719 g_free (iarg->keyword); 720 g_free (iarg); 721 } 722 g_list_free (signature.args); 723 } 724 break; 725 } 726 727 /* bail out on errors */ 728 if (expected_token != G_TOKEN_NONE) 729 { 730 g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE); 731 exit_status |= 1; 732 break; 733 } 734 735 g_scanner_peek_next_token (scanner); 736 } 737 while (scanner->next_token != G_TOKEN_EOF); 738 739 close (fd); 740 } 741 742 /* put out trailer */ 743 if (gen_cheader) 744 { 745 g_fprintf (fout, "\nG_END_DECLS\n"); 746 747 if (std_includes) 748 g_fprintf (fout, "\n#endif /* __%s_MARSHAL_H__ */\n", marshaller_prefix); 749 } 750 g_fprintf (fout, "\n"); 751 752 /* clean up */ 753 g_slist_free (files); 754 g_scanner_destroy (scanner); 755 g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL); 756 g_hash_table_destroy (marshallers); 757 758 return exit_status; 759 } 760 761 static void 762 parse_args (gint *argc_p, 763 gchar ***argv_p) 764 { 765 guint argc = *argc_p; 766 gchar **argv = *argv_p; 767 guint i, e; 768 769 for (i = 1; i < argc; i++) 770 { 771 if (strcmp ("--header", argv[i]) == 0) 772 { 773 gen_cheader = TRUE; 774 argv[i] = NULL; 775 } 776 else if (strcmp ("--body", argv[i]) == 0) 777 { 778 gen_cbody = TRUE; 779 argv[i] = NULL; 780 } 781 else if (strcmp ("--skip-source", argv[i]) == 0) 782 { 783 skip_ploc = TRUE; 784 argv[i] = NULL; 785 } 786 else if (strcmp ("--nostdinc", argv[i]) == 0) 787 { 788 std_includes = FALSE; 789 argv[i] = NULL; 790 } 791 else if (strcmp ("--stdinc", argv[i]) == 0) 792 { 793 std_includes = TRUE; 794 argv[i] = NULL; 795 } 796 else if (strcmp ("--internal", argv[i]) == 0) 797 { 798 gen_internal = TRUE; 799 argv[i] = NULL; 800 } 801 else if ((strcmp ("--prefix", argv[i]) == 0) || 802 (strncmp ("--prefix=", argv[i], 9) == 0)) 803 { 804 gchar *equal = argv[i] + 8; 805 806 if (*equal == '=') 807 marshaller_prefix = g_strdup (equal + 1); 808 else if (i + 1 < argc) 809 { 810 marshaller_prefix = g_strdup (argv[i + 1]); 811 argv[i] = NULL; 812 i += 1; 813 } 814 argv[i] = NULL; 815 } 816 else if (strcmp ("-h", argv[i]) == 0 || 817 strcmp ("-?", argv[i]) == 0 || 818 strcmp ("--help", argv[i]) == 0) 819 { 820 print_blurb (stderr, TRUE); 821 argv[i] = NULL; 822 exit (0); 823 } 824 else if (strcmp ("-v", argv[i]) == 0 || 825 strcmp ("--version", argv[i]) == 0) 826 { 827 print_blurb (stderr, FALSE); 828 argv[i] = NULL; 829 exit (0); 830 } 831 else if (strcmp (argv[i], "--g-fatal-warnings") == 0) 832 { 833 GLogLevelFlags fatal_mask; 834 835 fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); 836 fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; 837 g_log_set_always_fatal (fatal_mask); 838 839 argv[i] = NULL; 840 } 841 } 842 843 e = 0; 844 for (i = 1; i < argc; i++) 845 { 846 if (e) 847 { 848 if (argv[i]) 849 { 850 argv[e++] = argv[i]; 851 argv[i] = NULL; 852 } 853 } 854 else if (!argv[i]) 855 e = i; 856 } 857 if (e) 858 *argc_p = e; 859 } 860 861 static void 862 print_blurb (FILE *bout, 863 gboolean print_help) 864 { 865 if (!print_help) 866 { 867 g_fprintf (bout, "%s version ", PRG_NAME); 868 g_fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); 869 g_fprintf (bout, "\n"); 870 g_fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME); 871 g_fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME); 872 g_fprintf (bout, "the GNU General Public License which can be found in the\n"); 873 g_fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME); 874 g_fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME); 875 } 876 else 877 { 878 g_fprintf (bout, "Usage:\n"); 879 g_fprintf (bout, " %s [OPTION...] [FILES...]\n\n", PRG_NAME); 880 g_fprintf (bout, "Help Options:\n"); 881 g_fprintf (bout, " -h, --help Show this help message\n\n"); 882 g_fprintf (bout, "Utility Options:\n"); 883 g_fprintf (bout, " --header Generate C headers\n"); 884 g_fprintf (bout, " --body Generate C code\n"); 885 g_fprintf (bout, " --prefix=string Specify marshaller prefix\n"); 886 g_fprintf (bout, " --skip-source Skip source location comments\n"); 887 g_fprintf (bout, " --stdinc, --nostdinc Include/use standard marshallers\n"); 888 g_fprintf (bout, " --internal Mark generated functions as internal\n"); 889 g_fprintf (bout, " -v, --version Print version informations\n"); 890 g_fprintf (bout, " --g-fatal-warnings Make warnings fatal (abort)\n"); 891 } 892 } 893