Add Python wizard to class-gen plugin
[anjuta.git] / plugins / class-gen / transform.c
blob01d3fc4f2fb68caf2be47bb8fe0eea4c55571787
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /* transform.c
3 * Copyright (C) 2006 Armin Burgmeier
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "transform.h"
22 #include <string.h>
23 #include <ctype.h>
25 typedef struct _CgTransformParamGuess CgTransformParamGuess;
26 struct _CgTransformParamGuess
28 const gchar *gtype;
29 const gchar *paramspec;
32 typedef struct _CgTransformGTypeGuess CgTransformGTypeGuess;
33 struct _CgTransformGTypeGuess
35 const gchar *ctype;
36 const gchar *gtype_prefix;
37 const gchar *gtype_name;
40 /* This function looks up a flag with the given abbrevation (which has not
41 * to be null-terminated) in the given flag list. */
42 static const CgElementEditorFlags *
43 cg_transform_lookup_flag (const CgElementEditorFlags *flags,
44 gchar *abbrevation,
45 size_t len)
47 const CgElementEditorFlags *flag;
48 for (flag = flags; flag->name != NULL; ++ flag)
50 if (strncmp (flag->abbrevation, abbrevation, len) == 0)
52 if(flag->abbrevation[len] == '\0')
54 return flag;
59 return NULL;
62 /* This function tries to convert a native C Type like int, float or
63 * unsigned long into a GType like G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_ULONG. */
64 gboolean
65 cg_transform_default_c_type_to_g_type (const gchar *c_type,
66 const gchar **g_type_prefix,
67 const gchar **g_type_name)
69 static const CgTransformGTypeGuess DEFAULT_TYPES[] =
71 { "int", "G", "INT" },
72 { "gint", "G", "INT" },
73 { "unsigned int", "G", "UINT" },
74 { "guint", "G", "UINT" },
75 { "char", "G", "CHAR" },
76 { "gchar", "G", "CHAR" },
77 { "unsigned char", "G", "UCHAR" },
78 { "guchar", "G", "UCHAR" },
79 { "long", "G", "LONG" },
80 { "glong", "G", "LONG" },
81 { "unsigned long", "G", "ULONG" },
82 { "gulong", "G", "ULONG" },
83 { "gint64", "G", "INT64" },
84 { "guint64", "G", "UINT64" },
85 { "float", "G", "FLOAT" },
86 { "double", "G", "DOUBLE" },
87 { "char*", "G", "STRING" },
88 { "gchar*", "G", "STRING" },
89 { "char *", "G", "STRING" },
90 { "gchar *", "G", "STRING" },
91 { "const char*", "G", "STRING" },
92 { "const gchar*", "G", "STRING" },
93 { "const char *", "G", "STRING" },
94 { "const gchar *", "G", "STRING" },
95 { "gpointer", "G", "POINTER" },
96 { "void*", "G", "POINTER" },
97 { "void *", "G", "POINTER" },
98 { "gconstpointer", "G", "POINTER" },
99 { "const void*", "G", "POINTER" },
100 { "const void *", "G", "POINTER" },
101 { "void", "G", "NONE" },
102 { "gboolean", "G", "BOOLEAN" },
103 { "GParamSpec*", "G", "PARAM" },
104 { "GParamSpec *", "G", "PARAM" },
105 { NULL, NULL, NULL }
108 const CgTransformGTypeGuess *guess;
110 for (guess = DEFAULT_TYPES; guess->ctype != NULL; ++ guess)
112 if (strcmp (guess->ctype, c_type) == 0)
114 *g_type_prefix = guess->gtype_prefix;
115 *g_type_name = guess->gtype_name;
116 return TRUE;
120 return FALSE;
123 /* This function tries to convert a custom c_type like GtkTreeIter to
124 * a gobject type like GTK_TYPE_TREE_ITER. It does this by parsing the C type.
125 * The code is mostly borrowed from old action-callbacks.c by Dave
126 * Huseby and Massimo Cora'. */
127 void
128 cg_transform_custom_c_type_to_g_type (const gchar *c_type,
129 gchar **g_type_prefix,
130 gchar **g_type_name,
131 gchar **g_func_prefix)
133 size_t name_len;
134 gboolean first;
135 gboolean prefix;
136 GString *str_type_prefix = NULL;
137 GString *str_type_name = NULL;
138 GString *str_func_prefix = NULL;
140 name_len = strlen (c_type);
142 if (g_type_prefix != NULL) str_type_prefix = g_string_sized_new (name_len);
143 if (g_type_name != NULL) str_type_name = g_string_sized_new (name_len);
144 if (g_type_prefix != NULL) str_func_prefix = g_string_sized_new (name_len);
146 first = TRUE;
147 prefix = TRUE;
149 for (; *c_type != '\0'; ++ c_type)
151 if (first == TRUE)
153 if (g_func_prefix != NULL)
154 g_string_append_c (str_func_prefix, tolower (*c_type));
155 if (g_type_prefix != NULL)
156 g_string_append_c (str_type_prefix, toupper (*c_type));
158 first = FALSE;
160 else
162 if (isupper (*c_type))
164 if (g_func_prefix != NULL)
165 g_string_append_c (str_func_prefix, '_');
167 prefix = FALSE;
170 if (g_func_prefix != NULL)
171 g_string_append_c (str_func_prefix, tolower (*c_type));
173 if (prefix == TRUE)
175 if (g_type_prefix != NULL)
176 g_string_append_c (str_type_prefix, toupper (*c_type));
178 else
180 if (g_type_name != NULL)
182 if (isupper (*c_type) && str_type_name->len > 0)
183 g_string_append_c (str_type_name, '_');
185 g_string_append_c (str_type_name, toupper (*c_type));
191 if (g_type_prefix != NULL)
192 *g_type_prefix = g_string_free (str_type_prefix, FALSE);
194 if (g_type_name != NULL)
195 *g_type_name = g_string_free (str_type_name, FALSE);
197 if (g_func_prefix != NULL)
198 *g_func_prefix = g_string_free (str_func_prefix, FALSE);
201 /* This function tries to convert any possible C type to its corresponding
202 * GObject type. First, it looks whether the C type is a default type. If not,
203 * it strips leading const or a trailing * away (because it does not matter
204 * whether we have const GtkTreeIter* or GtkTreeIter, it all results in the
205 * same gobject type, namely GTK_TYPE_TREE_ITER) and calls
206 * cg_transform_custom_c_type_to_g_type. */
207 void
208 cg_transform_c_type_to_g_type (const gchar *c_type,
209 gchar **g_type_prefix,
210 gchar **g_type_name)
212 const gchar *default_prefix;
213 const gchar *default_name;
214 gchar *plain_c_type;
215 gboolean result;
216 size_t len;
218 result = cg_transform_default_c_type_to_g_type (c_type, &default_prefix,
219 &default_name);
221 if (result == TRUE)
223 *g_type_prefix = g_strdup (default_prefix);
224 *g_type_name = g_strdup (default_name);
226 else
228 if (strncmp (c_type, "const ", 6) == 0)
229 plain_c_type = g_strdup (c_type + 6);
230 else
231 plain_c_type = g_strdup (c_type);
233 len = strlen (plain_c_type);
234 if (plain_c_type[len - 1] == '*')
236 plain_c_type[len - 1] = '\0';
237 g_strchomp (plain_c_type);
240 cg_transform_custom_c_type_to_g_type (plain_c_type, g_type_prefix,
241 g_type_name, NULL);
243 g_free (plain_c_type);
247 /* Looks up the given index in the hash table and removes enclosing quotes,
248 * if any. Those are added again by the autogen template. */
249 void
250 cg_transform_string (GHashTable *table,
251 const gchar *index)
253 gchar *str;
254 gchar *unescaped;
255 size_t len;
257 str = g_hash_table_lookup (table, index);
259 if (str != NULL)
261 len = strlen (str);
262 if (len >= 2 && str[0] == '\"' && str[len - 1] == '\"')
264 /* Unescape string because it was most likely already escaped
265 * by the user because s/he also added quotes around it. */
266 str = g_strndup (str + 1, len - 2);
267 unescaped = g_strcompress (str);
268 g_free (str);
270 g_hash_table_insert (table, (gpointer) index, unescaped);
275 /* Looks up the given index in the hash table which is assumed to be a string
276 * with '|'-separated abbrevations of the given flags. This function replaces
277 * the abbrevations by the full names. If no flags are set, it produces "0". */
278 void
279 cg_transform_flags (GHashTable *table,
280 const gchar *index,
281 const CgElementEditorFlags *flags)
283 const CgElementEditorFlags *flag;
284 GString *res_str;
285 gchar *flags_str;
286 gchar *prev;
287 gchar *pos;
289 flags_str = g_hash_table_lookup (table, index);
290 res_str = g_string_sized_new (128);
292 if (flags_str != NULL)
294 prev = flags_str;
295 pos = flags_str;
297 while (*prev != '\0')
299 while (*pos != '|' && *pos != '\0')
300 ++ pos;
302 flag = cg_transform_lookup_flag (flags, prev, pos - prev);
303 g_assert (flag != NULL);
305 if (res_str->len > 0) g_string_append (res_str, " | ");
306 g_string_append (res_str, flag->name);
308 if (*pos != '\0') ++ pos;
309 prev = pos;
313 if (res_str->len == 0) g_string_append_c (res_str, '0');
314 g_hash_table_insert (table, (gpointer) index,
315 g_string_free (res_str, FALSE));
318 /* Looks up the given param_index in the hash table. If it contains
319 * guess_entry, the value is replaced by guessing the param spec from
320 * the GObject type stored in type_index. */
321 void
322 cg_transform_guess_paramspec (GHashTable *table,
323 const gchar *param_index,
324 const gchar *type_index,
325 const gchar *guess_entry)
327 const CgTransformParamGuess GUESS_TABLE[] =
329 { "G_TYPE_BOOLEAN", "g_param_spec_boolean" },
330 { "G_TYPE_BOXED", "g_param_spec_boxed" },
331 { "G_TYPE_CHAR", "g_param_spec_char" },
332 { "G_TYPE_DOUBLE", "g_param_spec_double" },
333 { "G_TYPE_ENUM", "g_param_spec_enum" },
334 { "G_TYPE_FLAGS", "g_param_spec_flags" },
335 { "G_TYPE_FLOAT", "g_param_spec_float" },
336 { "G_TYPE_INT", "g_param_spec_int" },
337 { "G_TYPE_INT64", "g_param_spec_int64" },
338 { "G_TYPE_LONG", "g_param_spec_long" },
339 { "G_TYPE_OBJECT", "g_param_spec_object" },
340 { "G_TYPE_PARAM", "g_param_spec_param" },
341 { "G_TYPE_POINTER", "g_param_spec_pointer" },
342 { "G_TYPE_STRING", "g_param_spec_string" },
343 { "G_TYPE_UCHAR", "g_param_spec_uchar" },
344 { "G_TYPE_UINT", "g_param_spec_uint" },
345 { "G_TYPE_UINT64", "g_param_spec_uint64" },
346 { "G_TYPE_ULONG", "g_param_spec_ulong" },
347 { "G_TYPE_UNICHAR", "g_param_spec_unichar" },
348 { NULL, NULL }
351 const CgTransformParamGuess *guess;
352 gchar *paramspec;
353 gchar *type;
355 paramspec = g_hash_table_lookup (table, param_index);
357 if (paramspec != NULL && strcmp (paramspec, guess_entry) == 0)
359 type = g_hash_table_lookup (table, type_index);
360 if (type != NULL)
362 for (guess = GUESS_TABLE; guess->gtype != NULL; ++ guess)
364 if (strcmp (type, guess->gtype) == 0)
366 paramspec = g_strdup (guess->paramspec);
367 break;
371 /* Not in list, so assume it is an object */
372 if (guess->gtype == NULL)
373 paramspec = g_strdup ("g_param_spec_object");
375 g_hash_table_insert (table, (gpointer) param_index, paramspec);
380 /* This function looks up index in the given hash table and encloses it by
381 * surrounding parenthesis if they do not already exist and the field is
382 * non-empty. If make_void is TRUE and the arguments are only "()" it makes
383 * "(void)" out of it to stay ANSI C compliant. */
384 void
385 cg_transform_arguments (GHashTable *table,
386 const gchar *index,
387 gboolean make_void)
389 gchar *arg_res;
390 gchar *arguments;
391 size_t len;
393 arguments = g_hash_table_lookup (table, index);
395 if (arguments != NULL)
397 g_strstrip (arguments);
398 len = strlen (arguments);
400 /* Do nothing if the field was left empty */
401 if (len > 0)
403 /* Surround arguments with paranthesis if they do
404 * not already exist. */
405 if (arguments[0] != '(' && arguments[len - 1] != ')')
406 arg_res = g_strdup_printf ("(%s)", arguments);
407 else if (arguments[0] != '(')
408 arg_res = g_strdup_printf ("(%s", arguments);
409 else if (arguments[len - 1] != ')')
410 arg_res = g_strdup_printf ("%s)", arguments);
411 else
412 arg_res = NULL;
414 /* Set arguments to the transformed result, if a transformation
415 * has happend. */
416 if (arg_res != NULL)
417 arguments = arg_res;
419 if (make_void == TRUE)
421 /* Make "(void)" out of "()" if make_void is set. If this is
422 * the case, we do not need to store arg_res in the hash
423 * table lateron, so we delete it right here. */
424 if (strcmp (arguments, "()") == 0)
426 g_hash_table_insert (table, (gpointer) index,
427 g_strdup ("(void)"));
429 g_free (arg_res);
430 arg_res = NULL;
434 if (arg_res != NULL)
435 g_hash_table_insert (table, (gpointer) index, arg_res);
440 /**
441 * Add a self reference to the arguments list, if necessary. Python only.
443 void
444 cg_transform_python_arguments (GHashTable *table,
445 const gchar *index)
447 gchar *arg_res;
448 gchar *arguments;
449 size_t len;
451 arguments = g_hash_table_lookup (table, index);
453 arg_res = NULL;
454 if (arguments != NULL)
456 g_strstrip (arguments);
457 len = strlen (arguments);
458 /* Do nothing if the field was left empty */
459 if (len > 0)
461 if (arguments[0] != '(')
463 /* Check if self is in arguments. If yes,
464 * cg_transform_arguments will take care of the
465 * rest, if not then add the self argument. */
466 if (g_strcmp0 (arguments, "self") != 0)
468 g_hash_table_insert (table, (gpointer) index,
469 g_strdup_printf ("(self, %s)", arguments));
471 g_free (arg_res);
472 arg_res = NULL;
475 else
477 if (g_strcmp0 (arguments, "()") == 0)
479 g_hash_table_insert (table, (gpointer) index,
480 g_strdup ("(self)"));
482 g_free (arg_res);
483 arg_res = NULL;
487 else
489 g_hash_table_insert (table, (gpointer) index,
490 g_strdup_printf ("%s", "(self)"));
491 g_free (arg_res);
492 arg_res = NULL;
496 cg_transform_arguments (table, index, FALSE);
499 /* This function makes a valid C identifier out of a string. It does this
500 * by ignoring anything but digits, letters, hyphens and underscores. Digits
501 * at the beginning of the string are also ignored. Hpyhens are transformed
502 * to underscores. */
503 void
504 cg_transform_string_to_identifier (GHashTable *table,
505 const gchar *string_index,
506 const gchar *identifier_index)
508 gchar *name;
509 gchar *identifier_name;
510 size_t name_len;
511 size_t i, j;
513 name = g_hash_table_lookup (table, "Name");
514 if (name != NULL)
516 name_len = strlen (name);
517 identifier_name = g_malloc ((name_len + 1) * sizeof(gchar));
519 for (i = 0, j = 0; i < name_len; ++ i)
521 if (isupper (name[i]) || islower (name[i]))
522 identifier_name[j ++] = name[i];
523 else if (isdigit (name[i]) && j > 0)
524 identifier_name[j ++] = name[i];
525 else if (isspace (name[i]) || name[i] == '-' || name[i] == '_')
526 identifier_name[j ++] = '_';
529 identifier_name[j] = '\0';
531 g_hash_table_insert (table, (gpointer) identifier_index,
532 identifier_name);
534 /* Ownership is given to hash table, so no g_free here. */
538 /* This function looks up the given index in the hash table and expects an
539 * argument list like cg_transform_arguments generates it. It then checks
540 * whether the first argument is of the given type. If it is, it does
541 * nothing, otherwise it adds the first argument to the argument list
542 * and writes the result back into the hash table. */
543 void
544 cg_transform_first_argument (GHashTable *table,
545 const gchar *index,
546 const gchar *type)
548 gchar *arguments;
549 guint pointer_count;
550 guint arg_pointer_count;
551 size_t type_len;
552 const gchar *type_pos;
553 gchar *arg_pos;
554 gchar *pointer_str;
555 gboolean arg_present;
556 guint i;
558 arguments = g_hash_table_lookup (table, index);
560 /* Count the length of the basic type */
561 type_len = 0;
562 while (isalnum (type[type_len])) ++ type_len;
563 type_pos = type + type_len;
565 /* Count pointer indicators */
566 pointer_count = 0;
567 for (type_pos = type + type_len; *type_pos != '\0'; ++ type_pos)
568 if (*type_pos == '*') ++ pointer_count;
570 /* Build a string of all pointer indicators that we can append to the
571 * basic type to get the final type. */
572 pointer_str = g_malloc ((pointer_count + 2) * sizeof(gchar));
573 pointer_str[0] = ' ';
574 pointer_str[pointer_count + 1] = '\0';
575 for (i = 0; i < pointer_count; ++ i) pointer_str[i + 1] = '*';
577 /* We do not just prepend type to the argument string because then
578 * we would have to fiddle around where spaces and pointer indicators
579 * belong. We can now always just build a string like
580 * BasicType+PointerStr+Name to get a fully qualified parameter like
581 * GtkTreeIter *iter, gint the_int or gchar **dest. */
583 if (arguments == NULL || *arguments == '\0')
585 arguments = g_strdup_printf ("(%.*s%sself)", (int)type_len,
586 type, pointer_str);
588 g_hash_table_insert (table, (gpointer) index, arguments);
590 else
592 g_assert (arguments[0] == '(');
594 /* Step over '(' and any leading whitespace */
595 ++ arguments;
596 while (isspace (*arguments)) ++ arguments;
598 arg_present = FALSE;
599 if (strncmp (arguments, type, type_len) == 0)
601 /* We cannot just check (via string comparison) whether arguments
602 * begins with the whole type because the pointer indicator might
603 * be directly behind the basic type, but there might as well exist
604 * an arbitrary amount of spaces inbetween.
605 * GtkTreeIter* self vs. GtkTreeIter *self vs.
606 * GtkTreeIter *self. */
607 arg_pointer_count = 0;
608 for (arg_pos = arguments + type_len;
609 isspace (*arg_pos) || *arg_pos == '*';
610 ++ arg_pos)
612 if (*arg_pos == '*') ++ arg_pointer_count;
615 /* Type matches */
616 if (arg_pointer_count == pointer_count)
617 arg_present = TRUE;
620 /* The argument list does not contain the specified type as first
621 * argument, so add it. */
622 if (arg_present == FALSE)
624 arguments = g_strdup_printf ("(%.*s%sself, %s", (int) type_len,
625 type, pointer_str, arguments);
626 g_hash_table_insert (table, (gpointer) index, arguments);
630 g_free (pointer_str);
633 /* This function looks up the given arguments_index in the hash table and
634 * expects an argument list with at least one argument like
635 * cg_transform_first_argument generates it. Then, it makes a new
636 * comma-separated list of the corresponding GTypes and writes it to
637 * gtypes_index. It returns the amount of arguments. The first
638 * argument is not part of the output.
640 * Additionally, if the arguments field was left empty, it makes (void) out
641 * of it. Normally, the arguments field may be left empty to indicate that
642 * the whole thing is a variable rather than a function. However, if someone
643 * requires a list of gtypes of the arguments, it is most likely a function
644 * and only a function. */
645 guint
646 cg_transform_arguments_to_gtypes (GHashTable *table,
647 const gchar *arguments_index,
648 const gchar *gtypes_index)
650 guint arg_count;
651 GString *arg_str;
652 gchar *arguments;
654 gchar *arg_prev;
655 gchar *arg_pos;
656 gchar *arg_type = NULL;
658 gchar *argtype_prefix;
659 gchar *argtype_suffix;
661 arg_count = 0;
662 arg_str = g_string_sized_new (128);
663 arguments = g_hash_table_lookup (table, arguments_index);
665 g_assert (arguments != NULL && *arguments != '\0');
667 /* Step over '(' */
668 arg_prev = arguments + 1;
670 /* Ignore first argument */
671 while (*arg_prev != ',' && *arg_prev != ')') ++ arg_prev;
673 /* Step over ',' */
674 if (*arg_prev == ',') ++ arg_prev;
676 while (isspace (*arg_prev)) ++ arg_prev;
677 arg_pos = arg_prev;
679 while (*arg_prev != ')')
681 ++ arg_count;
683 /* Advance to end of this argument. */
684 while (*arg_pos != ',' && *arg_pos != ')')
685 ++ arg_pos;
687 /* Try to find argument type by going back the last identifier
688 * which should be the argument name. */
689 if (arg_pos > arg_prev)
691 arg_type = arg_pos - 1;
692 while (isspace (*arg_type)) -- arg_type;
695 while ((isalnum (*arg_type) || *arg_type == '_') &&
696 arg_type > arg_prev)
698 -- arg_type;
701 /* If the name is everything in this arguments this is most
702 * probably the type and the name has been omitted. If a type was
703 * given that ends on a special character (i.e. '*' because it is
704 * a pointer) we also want to get that character. */
705 if (arg_type == arg_prev || !isspace (*arg_type))
706 arg_type = arg_pos;
708 /* Go back any whitespace to find end of type. Note that
709 * *(arg_type - 1) is always valid because arg_prev is at
710 * a character that is not a whitespace and arg_type is
711 * always >= arg_prev. */
712 if (arg_type > arg_prev)
713 while (isspace(*(arg_type - 1)))
714 -- arg_type;
716 /* The arguments type should now be enclosed by arg_prev and
717 * arg_type. */
718 arg_type = g_strndup (arg_prev, arg_type - arg_prev);
719 cg_transform_c_type_to_g_type (arg_type, &argtype_prefix,
720 &argtype_suffix);
721 g_free (arg_type);
723 if (arg_str->len > 0) g_string_append (arg_str, ", ");
724 g_string_append (arg_str, argtype_prefix);
725 g_string_append (arg_str, "_TYPE_");
726 g_string_append (arg_str, argtype_suffix);
728 g_free (argtype_prefix);
729 g_free (argtype_suffix);
731 if (*arg_pos != ')')
733 /* Step over comma and following whitespace */
734 ++ arg_pos;
735 while (isspace (*arg_pos)) ++ arg_pos;
738 arg_prev = arg_pos;
741 g_hash_table_insert (table, (gpointer) gtypes_index,
742 g_string_free (arg_str, FALSE));
744 return arg_count;