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