]> git.draconx.ca Git - gob-dx.git/blob - src/util.c
Release 2.0.17
[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         const char *fname = NULL;
39
40         switch(type) {
41         case GOB_WARN:
42                 w = "Warning:";
43                 if (exit_on_warn)
44                         got_error = TRUE;
45                 break;
46         case GOB_ERROR:
47                 w = "Error:";
48                 got_error = TRUE;
49                 break;
50         default:
51                 g_assert_not_reached();
52         }
53         fname = filename;
54         if (fname == NULL)
55                 fname = "gob2";
56         if (line > 0)
57                 fprintf(stderr, "%s:%d: %s %s\n", fname, line, w, error);
58         else
59                 fprintf(stderr, "%s: %s %s\n", fname, w, error);
60         if (exit_on_error && got_error)
61                 exit(1);
62 }
63
64 void
65 error_printf(int type, int line, const char *error, ...)
66 {
67         va_list ap;
68         char *s;
69
70         va_start(ap, error);
71         s = g_strdup_vprintf(error, ap);
72         va_end(ap);
73
74         error_print(type, line, s);
75
76         g_free(s);
77 }
78
79 char *
80 remove_sep(const char *base)
81 {
82         char *p;
83         char *s = g_strdup(base);
84         char *q=s;
85
86         /* don't eat C++ :: thingies */
87         if (for_cpp && strstr (s, "::") != NULL)
88                 return s;
89
90         for(p=(char *)base;*p;p++){
91                 if (*p!=':')
92                         *q++=*p;
93         }
94         *q='\0';
95         return s;
96 }
97
98 char *
99 replace_sep(const char *base, char r)
100 {
101         char *p;
102         char *s = g_strdup(base);
103
104         /* don't eat C++ :: thingies */
105         if (for_cpp && strstr (s, "::") != NULL)
106                 return s;
107
108         if (r == '\0') {
109                 while ((p=strchr(s,':')) != NULL) {
110                         char *t = p;
111                         while (*t != '\0') {
112                                 *t = *(t+1);
113                                 t++;
114                         }
115                 }
116         } else {
117                 while ((p=strchr(s,':')) != NULL)
118                         *p = r;
119         }
120         if(*s == r) {
121                 p = g_strdup(s+1);
122                 g_free(s);
123                 return p;
124         }
125         return s;
126 }
127
128 /*separate the namespace part and then replace rest of
129   separators with r*/
130 void
131 separns_replace_sep(const char *base, char **ns, char **name, char r)
132 {
133         char *p;
134         char *s = g_strdup(base);
135
136         *ns = NULL;
137         
138         /* don't eat C++ :: thingies */
139         if (for_cpp && strstr (s, "::") != NULL) {
140                 *name = s;
141                 return;
142         }
143
144         if((p=strchr(s,':')) && p!=s) {
145                 *p = '\0';
146                 *ns = g_strdup(s);
147                 p = g_strdup(p+1);
148                 g_free(s);
149                 s = p;
150         }
151         while((p=strchr(s,':')))
152                 *p = r;
153         if(*s == r) {
154                 *name = g_strdup(s+1);
155                 g_free(s);
156         } else
157                 *name = s;
158 }
159
160 /* make a macro with some prefix before the name but after
161    namespace */
162 char *
163 make_pre_macro(const char *base, const char *pre)
164 {
165         char *ns, *name;
166         char *s;
167         char **v = NULL;
168
169         if(strchr(base, ' ')) {
170                 int i;
171                 v = g_strsplit(base, " ", 0);
172                 for(i = 0; v[i] != NULL; i++) {
173                         if(*v[i] && strcmp(v[i], "const") != 0) {
174                                 base = v[i];
175                                 break;
176                         }
177                 }
178         }
179
180         separns_replace_sep(base, &ns, &name, '_');
181         if(ns)
182                 s = g_strconcat(ns, "_", pre, "_", name,NULL);
183         else
184                 s = g_strconcat(pre, "_", name, NULL);
185
186         gob_strup (s);
187         
188         g_free(ns);
189         g_free(name);
190
191         g_strfreev(v);
192
193         return s;
194 }
195
196 /* here we will find out how inconsistent gtk really is :) */
197 /* the commented out types mean that these types don't actually
198    exist. so we "emulate them" with an equivalent */
199 typedef struct _OurGtkType OurGtkType;
200 struct _OurGtkType {
201         gboolean simple;
202         char *gtkname;
203         char *cast;
204         char *type_name;
205         char *type_pointer;
206         int special;
207 };
208 const OurGtkType our_gtk_type_table[] = {
209         { TRUE, "NONE",         "void ",        "void",         NULL,   -1 },
210         { TRUE, "CHAR",         "gchar ",       "gchar",        NULL,   -1 },
211         { TRUE, "UCHAR",        "guchar ",      "guchar",       NULL,   -1 },
212         { TRUE, "UNICHAR",      "gunichar ",    "gunichar",     NULL,   -1 },
213         { TRUE, "BOOLEAN",      "gboolean ",    "gboolean",     NULL,   -1 },
214         { TRUE, "INT",          "gint ",        "gint",         NULL,   -1 },
215         { TRUE, "UINT",         "guint ",       "guint",        NULL,   -1 },
216         { TRUE, "LONG",         "glong ",       "glong",        NULL,   -1 },
217         { TRUE, "ULONG",        "gulong ",      "gulong",       NULL,   -1 },
218         { TRUE, "INT64",        "gint64 ",      "gint64",       NULL,   -1 },
219         { TRUE, "UINT64",       "guint64 ",     "guint64",      NULL,   -1 },
220         { TRUE, "ENUM",         /*"enum"*/"gint ", "gint",      NULL,   -1 },
221         { TRUE, "FLAGS",        /*"flags"*/"guint ", "guint",   NULL,   -1 },
222         { TRUE, "FLOAT",        "gfloat ",      "gfloat",       NULL,   -1 },
223         { TRUE, "DOUBLE",       "gdouble ",     "gdouble",      NULL,   -1 },
224         { TRUE, "STRING",       /*"string"*/"gchar *", "gchar", "*",    -1 },
225         { TRUE, "POINTER",      "gpointer ",    "gpointer",     NULL,   -1 },
226         { TRUE, "BOXED",        /*"boxed"*/"gpointer ", "gpointer", NULL, -1 },
227         { TRUE, "OBJECT",       "GObject *",    "GObject",      "*",    -1 },
228         { TRUE, "PARAM",        "GParamSpec *", "GParamSpec",   "*",    -1 },
229
230         /* FIXME: VALUE_ARRAY, CLOSURE */
231         /* Note that those have some issues with g_value_ calls etc... so
232          * we can't just add them */
233
234         /* Do we need this??? */
235 #if 0
236         { FALSE, "SIGNAL",      /*"GtkSignal"*/"___twopointertype ",
237                 SPECIAL_2POINTER },
238         { FALSE, "ARGS",        /*"GtkArgs"*/"___intpointertype ",
239                 SPECIAL_INT_POINTER },
240         { FALSE, "CALLBACK",    /*"GtkCallback"*/"___threepointertype ",
241                 SPECIAL_3POINTER },
242         { FALSE, "C_CALLBACK",  /*"GtkCCallback"*/"___twopointertype ",
243                 SPECIAL_2POINTER },
244         { FALSE, "FOREIGN",     /*"GtkForeign"*/"___twopointertype ",
245                 SPECIAL_2POINTER },
246 #endif
247
248         { FALSE, NULL, NULL }
249 };
250
251 static GHashTable *type_hash = NULL;
252
253 static void
254 init_type_hash(void)
255 {
256         int i;
257
258         if(type_hash) return;
259
260         type_hash = g_hash_table_new(g_str_hash, g_str_equal);
261
262         for(i=0; our_gtk_type_table[i].gtkname; i++)
263                 g_hash_table_insert(type_hash,
264                                     our_gtk_type_table[i].gtkname,
265                                     (gpointer)&our_gtk_type_table[i]);
266 }
267
268 const char *
269 get_cast (const char *type, gboolean simple_only)
270 {
271         OurGtkType *gtype;
272
273         init_type_hash ();
274
275         if(strncmp(type, "BOXED_", 6) == 0)      
276           gtype = g_hash_table_lookup (type_hash, "BOXED");
277         else
278           gtype = g_hash_table_lookup (type_hash, type);
279
280         if (gtype == NULL ||
281             (simple_only &&
282              ! gtype->simple))
283                 return NULL;
284
285         return gtype->cast;
286 }
287
288 Type *
289 get_tree_type (const char *type, gboolean simple_only)
290 {
291         OurGtkType *gtype;
292         Node *node;
293
294         init_type_hash ();
295
296         gtype = g_hash_table_lookup (type_hash, type);
297
298         if (gtype == NULL ||
299             (simple_only &&
300              ! gtype->simple))
301                 return NULL;
302
303         node = node_new (TYPE_NODE,
304                          "name", gtype->type_name,
305                          "pointer", gtype->type_pointer,
306                          NULL);
307
308         return (Type *)node;
309 }
310
311 static void
312 mask_special_array (const char *type, gboolean *special_array, gboolean *any_special)
313 {
314         OurGtkType *gtype;
315
316         init_type_hash();
317
318         gtype = g_hash_table_lookup(type_hash, type);
319
320         if(gtype && gtype->special >= 0) {
321                 special_array[gtype->special] = TRUE;
322                 *any_special = TRUE;
323         }
324 }
325
326 gboolean
327 setup_special_array(Class *c, gboolean *special_array)
328 {
329         GList *li;
330         gboolean any_special = FALSE;
331
332         memset(special_array, 0, sizeof(gboolean)*SPECIAL_LAST);
333
334         for(li=c->nodes; li; li=g_list_next(li)) {
335                 Node *n = li->data;
336                 if(n->type == METHOD_NODE) {
337                         Method *m = (Method *)n;
338                         GList *l;
339                         if(m->method != SIGNAL_LAST_METHOD &&
340                            m->method != SIGNAL_FIRST_METHOD)
341                                 continue;
342
343                         for(l=m->gtktypes; l; l=l->next)
344                                 mask_special_array(l->data, special_array,
345                                                    &any_special);
346                 } else if(n->type == ARGUMENT_NODE) {
347                         Argument *a = (Argument *)n;
348                         mask_special_array(a->gtktype, special_array,
349                                            &any_special);
350                 }
351         }
352
353         return any_special;
354 }
355
356 char *
357 get_type (const Type *t, gboolean postfix_to_stars)
358 {
359         char *s;
360         int i;
361         int extra;
362         GString *gs;
363
364         s = remove_sep(t->name);
365         gs = g_string_new(s);
366         g_free(s);
367
368         extra = 0;
369         if (postfix_to_stars) {
370                 const char *p;
371                 /*XXX: this is ugly perhaps we can do this whole postfix thing
372                   in a nicer way, we just count the number of '[' s and from
373                   that we deduce the number of dimensions, so that we can print
374                   that many stars */
375                 for (p = t->postfix; p && *p; p++)
376                         if(*p == '[') extra++;
377         }
378         g_string_append_c(gs, ' ');
379
380         if (t->pointer != NULL) {
381                 g_string_append (gs, t->pointer);
382                 for (i=0; i < extra; i++)
383                         g_string_append_c (gs, '*');
384                 g_string_append_c (gs, ' ');
385         }
386         
387         return g_string_free (gs, FALSE);
388 }
389
390 char *
391 gob_strup (char *str)
392 {
393         char *s;
394         for (s = str; *s; s++)
395                 *s = g_ascii_toupper (*s);
396
397         return str;
398 }
399
400 char *
401 gob_strdown (char *str)
402 {
403         char *s;
404         for (s = str; *s; s++)
405                 *s = g_ascii_tolower (*s);
406
407         return str;
408 }
409
410 char *
411 make_me_type (const char *type, const char *alt)
412 {
413         if (type == NULL)
414                 return g_strdup (alt);
415         /* HACK!  just in case someone made this
416          * work with 2.0.0 by using the TYPE
417          * macro directly */
418         if ((strstr (type, "_TYPE_") != NULL ||
419              strstr (type, "TYPE_") == type) &&
420             strchr (type, ':') == NULL)
421                 return g_strdup (type);
422         return make_pre_macro (type, "TYPE");
423 }