#!/usr/bin/perl -w open (FILE, "treefuncs.def") || die ("Can't open treefuncs.def"); open (OUTC, ">treefuncs.c") || die ("Can't open treefuncs.c"); open (OUTH, ">treefuncs.h") || die ("Can't open treefuncs.h"); print OUTC "/* Generated by generate_treefuncs.pl from treefuncs.def!\n"; print OUTC " * Do not edit by hand! */\n\n"; print OUTH "/* Generated by generate_treefuncs.pl from treefuncs.def!\n"; print OUTH " * Do not edit by hand! */\n\n"; $typedefs = "typedef union _Node Node;\n"; $typeenums = "enum {\n"; $typename = ""; %typestruct = (); %freefunc = (); %freefunc_prot = (); %copyfunc = (); %copyfunc_prot = (); %setfunc = (); %setfunc_prot = (); $quarks = "static gboolean quarks_set_up = FALSE;\n" . "static GHashTable *quark_ht;\n" . "enum {\n\tQUARK_0,\n"; $setupquarks = "static void\nensure_quarks (void)\n{\n" . "\tif (quarks_set_up)\n\t\treturn;\n" . "\tquark_ht = g_hash_table_new (g_str_hash, g_str_equal);\n" . "\tquarks_set_up = TRUE;\n"; %got_quarks = (); $var = ""; $type = ""; $copy = ""; $free = ""; $steal = 0; $headercode = ""; $inheadercode = 0; sub end_var { $typestruct{$typename} .= "\t$type $var;\n"; if ($copy ne "") { $tmp = $copy; $tmp =~ s/__VAL__/self->$var/g; $tmp =~ s/__LVAL__/new->$var/g; $copyfunc{$typename} .= "\t$tmp\n"; } else { $copyfunc{$typename} .= "\tnew->$var = self->$var;\n"; } if ($free ne "") { $tmp = $free; $tmp =~ s/__VAL__/self->$var/g; $freefunc{$typename} .= "\t$tmp\n"; } if ( ! $got_quarks{$var}) { $quarks .= "\tQUARK_$var,\n"; $setupquarks .= "\tg_hash_table_insert (quark_ht, \"$var\", " . "GINT_TO_POINTER (QUARK_$var));\n"; $got_quarks{$var} = 1; } if ($steal && ! $got_quarks{$var . ":steal"}) { $quarks .= "\tQUARK_$var" . "_STEAL,\n"; $setupquarks .= "\tg_hash_table_insert (quark_ht, \"$var" . ":steal\", " . "GINT_TO_POINTER (QUARK_$var" . "_STEAL));\n"; $got_quarks{$var . ":steal"} = 1; } $setfunc{$typename} .= "\t\tcase QUARK_$var: {\n"; $setfunc{$typename} .= "\t\t\t$type $var = va_arg (__ap, $type);\n"; if ($free ne "") { $setfunc{$typename} .= "\t\t\t$type __old_value = self->$var;\n"; } if ($copy ne "") { $tmp = $copy; $tmp =~ s/__VAL__/$var/g; $tmp =~ s/__LVAL__/self->$var/g; $setfunc{$typename} .= "\t\t\t$tmp\n"; } else { $setfunc{$typename} .= "\t\t\tself->$var = $var;\n"; } if ($free ne "") { $tmp = $free; $tmp =~ s/__VAL__/__old_value/g; $setfunc{$typename} .= "\t\t\t$tmp\n"; } $setfunc{$typename} .= "\t\t\tbreak;\n\t\t}\n"; if ($steal) { $setfunc{$typename} .= "\t\tcase QUARK_$var" . "_STEAL: {\n"; $setfunc{$typename} .= "\t\t\t$type $var = va_arg (__ap, $type);\n"; $setfunc{$typename} .= "\t\t\tself->$var = $var;\n"; $setfunc{$typename} .= "\t\t\tbreak;\n\t\t}\n"; } } while () { if ($inheadercode) { if (/^ENDHEADER$/) { $inheadercode = 0; next; } $headercode .= $_; next; } s/#.*$//; if (/^[ \t]*HEADER[ \t]*$/) { $inheadercode = 1; next; } if (/^[ \t]*CLASS[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $typename = $1; $lct = lc $typename; $uct = uc $typename; $typeenums .= "\t$uct"."_NODE,\n"; $typedefs .= "typedef struct _$typename $typename;\n"; $typestruct{$typename} = "struct _$typename {\n\tNodeType type;\n"; $copyfunc_prot{$typename} = "static $typename *\ncopy_$lct ($typename * self)"; $setfunc_prot{$typename} = "static void\nsetv_$lct ($typename * self, va_list __ap)"; $freefunc_prot{$typename} = "void\nfree_$lct ($typename * self)"; $setfunc{$typename} = "{\n" . "\tint quark;\n" . "\tconst char *arg;\n" . "\tensure_quarks ();\n" . "\twhile ((arg = va_arg (__ap, char *)) != NULL) {\n" . "\t\tquark = GPOINTER_TO_INT (g_hash_table_lookup (quark_ht, arg));\n" . "\t\tswitch (quark) {\n"; $copyfunc{$typename} = "{\n" . "\t$typename * new;\n" . "\tg_return_val_if_fail (self != NULL, NULL);\n" . "\tg_return_val_if_fail (self->type == $uct"."_NODE, NULL);\n" . "\tnew = g_new0($typename, 1);\n" . "\tnew->type = $uct"."_NODE;\n"; $freefunc{$typename} = "{\n\tg_return_if_fail (self != NULL);\n" . "\tg_return_if_fail (self->type == $uct"."_NODE);\n"; next; } #ignore everything until we get some typename if ($typename eq "") { next; } #some predefined VARIABLE types if (/^[ \t]*INT[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $var = $1; $type = "int"; $copy = "__LVAL__ = __VAL__;"; $free = ""; $steal = 0; end_var; next; } elsif (/^[ \t]*BOOL[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $var = $1; $type = "gboolean"; $copy = "__LVAL__ = __VAL__;"; $free = ""; $steal = 0; end_var; next; } elsif (/^[ \t]*STRING[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $var = $1; $type = "char *"; $copy = "__LVAL__ = g_strdup (__VAL__);"; $free = "g_free (__VAL__);"; $steal = 1; end_var; next; } elsif (/^[ \t]*STRINGLIST[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $var = $1; $type = "GList *"; $copy = "__LVAL__ = g_list_copy (__VAL__); COPY_LIST_VALS(__LVAL__, g_strdup);"; $free = "g_list_foreach (__VAL__, (GFunc)g_free, NULL); g_list_free (__VAL__);"; $steal = 1; end_var; next; } elsif (/^[ \t]*NODELIST[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $var = $1; $type = "GList *"; $copy = "__LVAL__ = node_list_copy (__VAL__);"; $free = "node_list_free (__VAL__);"; $steal = 1; end_var; next; #We assume one of the classes we are creating is named Type } elsif (/^[ \t]*TYPE[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $var = $1; $type = "Type *"; $copy = "__LVAL__ = copy_type (__VAL__);"; $free = "free_type (__VAL__);"; $steal = 1; end_var; next; #generic variable type } elsif (/^[ \t]*VAR[ \t]+([_A-Za-z][A-Za-z_0-9]+)[ \t]*$/) { $var = $1; $type = "int"; $copy = "__LVAL__ = __VAL__;"; $free = ""; $steal = 0; next; } elsif (/^[ \t]*CTYPE[ \t]+(.+)[ \t]*$/) { $type = $1; next; } elsif (/^[ \t]*COPY[ \t]+(.+)$/) { $copy = $1; $steal = 1; next; } elsif (/^[ \t]*FREE[ \t]+(.+)$/) { $free = $1; $steal = 1; next; } elsif (/^[ \t]*ENDVAR[ \t]*$/) { end_var; next; } elsif (/^[ \t]*ENDCLASS[ \t]*$/) { $typestruct{$typename} .= "};"; $copyfunc{$typename} .= "\treturn new;\n}"; $freefunc{$typename} .= "\tg_free (self);\n}"; $setfunc{$typename} .= "\t\tdefault:\n" . "\t\t\tg_warning (\"Argument named '" . $typename . "::\%s' does not exist\", arg);\n" . "\t\t\tbreak;\n" . "\t\t}\n" . "\t}\n" . "}"; $typename = ""; next; } else { next; } } $typeenums .= "\tLAST_NODE_TYPE\n};"; print OUTH "\n#ifndef TREEFUNCS_H\n"; print OUTH "#define TREEFUNCS_H\n"; print OUTH "\n$headercode\n\n"; print OUTH "typedef long NodeType;\n"; print OUTH "$typeenums\n\n"; print OUTH "$typedefs\n\n"; foreach $t (sort keys %typestruct) { print OUTH "$typestruct{$t}\n\n"; } print OUTH "union _Node {\n\tNodeType type;\n"; foreach $t (sort keys %typestruct) { $foo = lc $t; if ($foo eq "type") { print OUTH "\t$t _type;\n"; } else { print OUTH "\t$t $foo;\n"; } } print OUTH "};\n\n"; print OUTH "\n/* General copy/free functions */\n"; print OUTH "Node * node_copy (Node *node);\n"; print OUTH "void node_free (Node *node);\n\n"; print OUTH "GList * node_list_copy (GList *nodes);\n"; print OUTH "void node_list_free (GList *nodes);\n"; print OUTH "\n/* Node new/set functions */\n"; print OUTH "Node * node_new (NodeType type, ...);\n"; print OUTH "void node_set (Node *node, ...);\n\n"; print OUTH "\n#endif /* TREEFUNCS_H */\n"; close (OUTH); print OUTC "#include \n"; print OUTC "#include \n"; print OUTC "#include \"treefuncs.h\"\n\n"; print OUTC "#define COPY_LIST_VALS(list,func) " . "{ GList *li; for (li=(list);li;li=li->next) { li->data=func (li->data); } }\n\n"; foreach $t (sort keys %copyfunc_prot) { print OUTC "$copyfunc_prot{$t};\n"; } print OUTC "\n"; foreach $t (sort keys %freefunc_prot) { print OUTC "$freefunc_prot{$t};\n"; } print OUTC "\n"; foreach $t (sort keys %setfunc_prot) { print OUTC "$setfunc_prot{$t};\n"; } print OUTC "\n"; print OUTC $quarks . "\tQUARK_LAST\n};\n\n"; print OUTC $setupquarks . "}\n\n"; foreach $t (sort keys %copyfunc_prot) { print OUTC "$copyfunc_prot{$t}\n$copyfunc{$t}\n\n"; } foreach $t (sort keys %freefunc_prot) { print OUTC "$freefunc_prot{$t}\n$freefunc{$t}\n\n"; } foreach $t (sort keys %setfunc_prot) { print OUTC "$setfunc_prot{$t}\n$setfunc{$t}\n\n"; } print OUTC "Node *\nnode_copy (Node *node)\n" . "{\n" . "\tg_return_val_if_fail (node != NULL, NULL);\n" . "\tg_return_val_if_fail (node->type >= 0 && node->type < LAST_NODE_TYPE, NULL);\n" . "\tswitch (node->type) {\n"; foreach $t (sort keys %typestruct) { print OUTC "\tcase " . uc ($t) . "_NODE: return (Node *)copy_" . lc ($t) . " (($t *)node);\n"; } print OUTC "\tdefault: return NULL;\n\t}\n}\n\n"; print OUTC "static void\nnode_setv (Node *node, va_list __ap)\n" . "{\n" . "\tg_return_if_fail (node != NULL);\n" . "\tg_return_if_fail (node->type >= 0 && node->type < LAST_NODE_TYPE);\n" . "\tswitch (node->type) {\n"; foreach $t (sort keys %typestruct) { print OUTC "\tcase " . uc ($t) . "_NODE: setv_" . lc ($t) . " (($t *)node, __ap); break;\n"; } print OUTC "\tdefault: break;\n\t}\n}\n\n"; print OUTC "void\nnode_set (Node *node, ...)\n" . "{\n" . "\tva_list __ap;\n" . "\tva_start (__ap, node);\n" . "\tnode_setv (node, __ap);\n" . "\tva_end (__ap);\n" . "}\n\n"; print OUTC "Node *\nnode_new (NodeType type, ...)\n" . "{\n" . "\tva_list __ap;\n" . "\tNode *node = NULL;\n" . "\tva_start (__ap, type);\n" . "\tg_return_val_if_fail (type >= 0 && type < LAST_NODE_TYPE, NULL);\n" . "\tswitch (type) {\n"; foreach $t (sort keys %typestruct) { print OUTC "\tcase " . uc ($t) . "_NODE:\n" . "\t\tnode = (Node *)g_new0 ($t, 1);\n" . "\t\tnode->type = type;\n" . "\t\tsetv_" . lc ($t) . " (($t *)node, __ap);\n" . "\t\tbreak;\n"; } print OUTC "\tdefault: break;\n\t}\n" . "\tva_end (__ap);\n" . "\treturn node;\n" . "}\n\n"; print OUTC "void\nnode_free (Node *node)\n" . "{\n" . "\tg_return_if_fail (node != NULL);\n" . "\tg_return_if_fail (node->type >= 0 && node->type < LAST_NODE_TYPE);\n" . "\tswitch (node->type) {\n"; foreach $t (sort keys %typestruct) { print OUTC "\tcase " . uc ($t) . "_NODE: free_" . lc ($t) . " (($t *)node); return;\n"; } print OUTC "\tdefault: return;\n\t}\n}\n\n"; print OUTC "GList *\nnode_list_copy (GList *nodes)\n" . "{\n" . "\tGList *li;\n" . "\tnodes = g_list_copy (nodes);\n" . "\tfor (li = nodes; li != NULL; li = li->next) {\n" . "\t\tli->data = node_copy (li->data);\n" . "\t}\n" . "\treturn nodes;\n" . "}\n\n"; print OUTC "void\nnode_list_free (GList *nodes)\n" . "{\n" . "\tGList *li;\n" . "\tfor (li = nodes; li != NULL; li = li->next) {\n" . "\t\tnode_free (li->data);\n" . "\t}\n" . "\tg_list_free (nodes);\n" . "}\n\n"; close (OUTC);