]> git.draconx.ca Git - gob-dx.git/blob - src/util.c
Release 2.0.3
[gob-dx.git] / src / util.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999-2000 the Free Software Foundation.
3  * Copyright (C) 2000 Eazel, Inc.
4  *
5  * Author: George Lebl
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the  Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  * USA.
21  */
22
23 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <glib.h>
28
29 #include "treefuncs.h"
30 #include "main.h"
31
32 #include "util.h"
33
34 void
35 error_print(int type, int line, const char *error)
36 {
37         const char *w = NULL;
38
39         switch(type) {
40         case GOB_WARN:
41                 w = "Warning:";
42                 break;
43         case GOB_ERROR:
44                 w = "Error:";
45                 got_error = TRUE;
46                 break;
47         default:
48                 g_assert_not_reached();
49         }
50         if(line > 0)
51                 fprintf(stderr, "%s:%d: %s %s\n", filename, line, w, error);
52         else
53                 fprintf(stderr, "%s: %s %s\n", filename, w, error);
54         if(exit_on_error &&
55            (type == GOB_ERROR ||
56             (type == GOB_WARN && exit_on_warn)))
57                 exit(1);
58 }
59
60 void
61 error_printf(int type, int line, const char *error, ...)
62 {
63         va_list ap;
64         char *s;
65
66         va_start(ap, error);
67         s = g_strdup_vprintf(error, ap);
68         va_end(ap);
69
70         error_print(type, line, s);
71
72         g_free(s);
73 }
74
75 char *
76 remove_sep(const char *base)
77 {
78         char *p;
79         char *s = g_strdup(base);
80
81         /* don't eat C++ :: thingies */
82         if (for_cpp && strstr (s, "::") != NULL)
83                 return s;
84
85         while((p = strchr(s, ':')))
86                 strcpy(p, p+1);
87         return s;
88 }
89
90 char *
91 replace_sep(const char *base, char r)
92 {
93         char *p;
94         char *s = g_strdup(base);
95
96         /* don't eat C++ :: thingies */
97         if (for_cpp && strstr (s, "::") != NULL)
98                 return s;
99
100         while((p=strchr(s,':')))
101                 *p = r;
102         if(*s == r) {
103                 p = g_strdup(s+1);
104                 g_free(s);
105                 return p;
106         }
107         return s;
108 }
109
110 /*separate the namespace part and then replace rest of
111   separators with r*/
112 void
113 separns_replace_sep(const char *base, char **ns, char **name, char r)
114 {
115         char *p;
116         char *s = g_strdup(base);
117
118         *ns = NULL;
119         
120         /* don't eat C++ :: thingies */
121         if (for_cpp && strstr (s, "::") != NULL) {
122                 *name = s;
123                 return;
124         }
125
126         if((p=strchr(s,':')) && p!=s) {
127                 *p = '\0';
128                 *ns = g_strdup(s);
129                 p = g_strdup(p+1);
130                 g_free(s);
131                 s = p;
132         }
133         while((p=strchr(s,':')))
134                 *p = r;
135         if(*s == r) {
136                 *name = g_strdup(s+1);
137                 g_free(s);
138         } else
139                 *name = s;
140 }
141
142 /* make a macro with some prefix before the name but after
143    namespace */
144 char *
145 make_pre_macro(const char *base, const char *pre)
146 {
147         char *ns, *name;
148         char *s;
149         char **v = NULL;
150
151         if(strchr(base, ' ')) {
152                 int i;
153                 v = g_strsplit(base, " ", 0);
154                 for(i = 0; v[i] != NULL; i++) {
155                         if(*v[i] && strcmp(v[i], "const") != 0) {
156                                 base = v[i];
157                                 break;
158                         }
159                 }
160         }
161
162         separns_replace_sep(base, &ns, &name, '_');
163         if(ns)
164                 s = g_strconcat(ns, "_", pre, "_", name,NULL);
165         else
166                 s = g_strconcat(pre, "_", name, NULL);
167
168         g_strup(s);
169         
170         g_free(ns);
171         g_free(name);
172
173         g_strfreev(v);
174
175         return s;
176 }
177
178 /* here we will find out how inconsistent gtk really is :) */
179 /* the commented out types mean that these types don't actually
180    exist. so we "emulate them" with an equivalent */
181 typedef struct _OurGtkType OurGtkType;
182 struct _OurGtkType {
183         gboolean simple;
184         char *gtkname;
185         char *cast;
186         char *type_name;
187         char *type_pointer;
188         int special;
189 };
190 const OurGtkType our_gtk_type_table[] = {
191         { TRUE, "NONE",         "void ",        "void",         NULL,   -1 },
192         { TRUE, "CHAR",         "gchar ",       "gchar",        NULL,   -1 },
193         { TRUE, "UCHAR",        "guchar ",      "guchar",       NULL,   -1 },
194         { TRUE, "UNICHAR",      "gunichar ",    "gunichar",     NULL,   -1 },
195         { TRUE, "BOOLEAN",      "gboolean ",    "gboolean",     NULL,   -1 },
196         { TRUE, "INT",          "gint ",        "gint",         NULL,   -1 },
197         { TRUE, "UINT",         "guint ",       "guint",        NULL,   -1 },
198         { TRUE, "LONG",         "glong ",       "glong",        NULL,   -1 },
199         { TRUE, "ULONG",        "gulong ",      "gulong",       NULL,   -1 },
200         { TRUE, "INT64",        "gint64 ",      "gint64",       NULL,   -1 },
201         { TRUE, "UINT64",       "guint64 ",     "guint64",      NULL,   -1 },
202         { TRUE, "ENUM",         /*"enum"*/"gint ", "gint",      NULL,   -1 },
203         { TRUE, "FLAGS",        /*"flags"*/"guint ", "guint",   NULL,   -1 },
204         { TRUE, "FLOAT",        "gfloat ",      "gfloat",       NULL,   -1 },
205         { TRUE, "DOUBLE",       "gdouble ",     "gdouble",      NULL,   -1 },
206         { TRUE, "STRING",       /*"string"*/"gchar *", "gchar", "*",    -1 },
207         { TRUE, "POINTER",      "gpointer ",    "gpointer",     NULL,   -1 },
208         { TRUE, "BOXED",        /*"boxed"*/"gpointer ", "gpointer", NULL, -1 },
209         { TRUE, "OBJECT",       "GObject *",    "GObject",      "*",    -1 },
210         { TRUE, "PARAM",        "GParamSpec *", "GParamSpec",   "*",    -1 },
211
212         /* FIXME: VALUE_ARRAY, CLOSURE */
213         /* Note that those have some issues with g_value_ calls etc... so
214          * we can't just add them */
215
216         /* Do we need this??? */
217 #if 0
218         { FALSE, "SIGNAL",      /*"GtkSignal"*/"___twopointertype ",
219                 SPECIAL_2POINTER },
220         { FALSE, "ARGS",        /*"GtkArgs"*/"___intpointertype ",
221                 SPECIAL_INT_POINTER },
222         { FALSE, "CALLBACK",    /*"GtkCallback"*/"___threepointertype ",
223                 SPECIAL_3POINTER },
224         { FALSE, "C_CALLBACK",  /*"GtkCCallback"*/"___twopointertype ",
225                 SPECIAL_2POINTER },
226         { FALSE, "FOREIGN",     /*"GtkForeign"*/"___twopointertype ",
227                 SPECIAL_2POINTER },
228 #endif
229
230         { FALSE, NULL, NULL }
231 };
232
233 static GHashTable *type_hash = NULL;
234
235 static void
236 init_type_hash(void)
237 {
238         int i;
239
240         if(type_hash) return;
241
242         type_hash = g_hash_table_new(g_str_hash, g_str_equal);
243
244         for(i=0; our_gtk_type_table[i].gtkname; i++)
245                 g_hash_table_insert(type_hash,
246                                     our_gtk_type_table[i].gtkname,
247                                     (gpointer)&our_gtk_type_table[i]);
248 }
249
250 const char *
251 get_cast (const char *type, gboolean simple_only)
252 {
253         OurGtkType *gtype;
254
255         init_type_hash ();
256
257         gtype = g_hash_table_lookup (type_hash, type);
258
259         if (gtype == NULL ||
260             (simple_only &&
261              ! gtype->simple))
262                 return NULL;
263
264         return gtype->cast;
265 }
266
267 Type *
268 get_tree_type (const char *type, gboolean simple_only)
269 {
270         OurGtkType *gtype;
271         Node *node;
272
273         init_type_hash ();
274
275         gtype = g_hash_table_lookup (type_hash, type);
276
277         if (gtype == NULL ||
278             (simple_only &&
279              ! gtype->simple))
280                 return NULL;
281
282         node = node_new (TYPE_NODE,
283                          "name", gtype->type_name,
284                          "pointer", gtype->type_pointer,
285                          NULL);
286
287         return (Type *)node;
288 }
289
290 static void
291 mask_special_array (const char *type, gboolean *special_array, gboolean *any_special)
292 {
293         OurGtkType *gtype;
294
295         init_type_hash();
296
297         gtype = g_hash_table_lookup(type_hash, type);
298
299         if(gtype && gtype->special >= 0) {
300                 special_array[gtype->special] = TRUE;
301                 *any_special = TRUE;
302         }
303 }
304
305 gboolean
306 setup_special_array(Class *c, gboolean *special_array)
307 {
308         GList *li;
309         gboolean any_special = FALSE;
310
311         memset(special_array, 0, sizeof(gboolean)*SPECIAL_LAST);
312
313         for(li=c->nodes; li; li=g_list_next(li)) {
314                 Node *n = li->data;
315                 if(n->type == METHOD_NODE) {
316                         Method *m = (Method *)n;
317                         GList *l;
318                         if(m->method != SIGNAL_LAST_METHOD &&
319                            m->method != SIGNAL_FIRST_METHOD)
320                                 continue;
321
322                         for(l=m->gtktypes; l; l=l->next)
323                                 mask_special_array(l->data, special_array,
324                                                    &any_special);
325                 } else if(n->type == ARGUMENT_NODE) {
326                         Argument *a = (Argument *)n;
327                         mask_special_array(a->gtktype, special_array,
328                                            &any_special);
329                 }
330         }
331
332         return any_special;
333 }
334
335 char *
336 get_type (const Type *t, gboolean postfix_to_stars)
337 {
338         char *s;
339         int i;
340         int extra;
341         GString *gs;
342
343         s = remove_sep(t->name);
344         gs = g_string_new(s);
345         g_free(s);
346
347         extra = 0;
348         if (postfix_to_stars) {
349                 const char *p;
350                 /*XXX: this is ugly perhaps we can do this whole postfix thing
351                   in a nicer way, we just count the number of '[' s and from
352                   that we deduce the number of dimensions, so that we can print
353                   that many stars */
354                 for (p = t->postfix; p && *p; p++)
355                         if(*p == '[') extra++;
356         }
357         g_string_append_c(gs, ' ');
358
359         if (t->pointer != NULL) {
360                 g_string_append (gs, t->pointer);
361                 for (i=0; i < extra; i++)
362                         g_string_append_c (gs, '*');
363                 g_string_append_c (gs, ' ');
364         }
365         
366         return g_string_free (gs, FALSE);
367 }
368