Updated Spanish translation
[anjuta-git-plugin.git] / plugins / indent / indent-util.c
blobec76974a9151ff74bc0c572ddfe805fac6772a7b
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <gnome.h>
20 #include <glade/glade.h>
22 #include <sys/wait.h>
24 #include <libgnomevfs/gnome-vfs.h>
25 #include <gconf/gconf-client.h>
27 #include <libanjuta/anjuta-utils.h>
28 #include <libanjuta/anjuta-debug.h>
30 #include "config.h"
32 //#include "text_editor.h"
33 #include "indent-util.h"
34 #include "indent-dialog.h"
37 #define INDENT_FILE_INPUT PACKAGE_DATA_DIR"/indent_test.c"
38 #define INDENT_FILE_OUTPUT TMPDIR"/indent_test.c"
40 #define AUTOFORMAT_DISABLE "autoformat.disable"
41 #define AUTOFORMAT_STYLE "autoformat.style"
42 #define AUTOFORMAT_LIST_STYLE "autoformat.list.style"
43 #define AUTOFORMAT_OPTS "autoformat.opts"
45 static IndentOption indent_option[] = {
46 {"bl", FALSE, "bl_checkbutton", NULL},
47 {"bli", FALSE, "bli_checkbutton", "bli_spinbutton"},
48 {"br", FALSE, "br_checkbutton", NULL},
49 {"ci", FALSE, "ci_checkbutton", "ci_spinbutton"},
50 {"cli", FALSE, "cli_checkbutton", "cli_spinbutton"},
51 {"cs", FALSE, "cs_checkbutton", NULL},
52 {"pcs", TRUE, "pcs_checkbutton", NULL},
53 {"saf", TRUE, "saf_checkbutton", NULL},
54 {"sai", TRUE, "sai_checkbutton", NULL},
55 {"saw", TRUE, "saw_checkbutton", NULL},
56 {"bad", TRUE, "bad_checkbutton", NULL},
57 {"bap", TRUE, "bap_checkbutton", NULL},
58 {"sob", TRUE, "sob_checkbutton", NULL},
59 {"cdb", TRUE, "cdb_checkbutton", NULL},
60 {"bbb", FALSE, "bbb_checkbutton", NULL},
61 {"cd", FALSE, "cd_checkbutton", "cd_spinbutton"},
62 {"ce", TRUE, "ce_checkbutton", NULL},
63 {"c", FALSE, "c_checkbutton", "c_spinbutton"},
64 {"cp", FALSE, "cp_checkbutton", "cp_spinbutton"},
65 {"d", FALSE, "d_checkbutton", "d_spinbutton"},
66 {"fc1", TRUE, "fc1_checkbutton", NULL},
67 {"fca", TRUE, "fca_checkbutton", NULL},
68 {"sc", TRUE, "sc_checkbutton", NULL},
69 {"bc", TRUE, "bc_checkbutton", NULL},
70 {"bls", FALSE, "bls_checkbutton", NULL},
71 {"brs", FALSE, "brs_checkbutton", NULL},
72 {"di", FALSE, "di_checkbutton", "di_spinbutton"},
73 {"psl", TRUE, "psl_checkbutton", NULL},
74 {"i", FALSE, "i_checkbutton", "i_spinbutton"},
75 {"ip", FALSE, "ip_checkbutton", "ip_spinbutton"},
76 {"lp", TRUE, "lp_checkbutton", NULL},
77 {"ts", FALSE, "ts_checkbutton", "ts_spinbutton"},
78 {"bbo", TRUE, "bbo_checkbutton", NULL},
79 {"hnl", TRUE, "hnl_checkbutton", NULL},
80 {"l", FALSE, "l_checkbutton", "l_spinbutton"},
81 {NULL, FALSE, NULL, NULL}
85 static IndentStyle standard_indent_style[] = {
86 {"GNU coding style", "-nbad -bap -bbo -nbc -bl -bli2 -bls -ncdb -nce -cp1 "
87 "-cs -di2 -nfc1 -nfca -hnl -i2 -ip5 -lp -pcs -nprs -psl -saf -sai -saw "
88 "-nsc -nsob", FALSE},
89 {"Kernighan and Ritchie style", "-nbad -bap -nbc -bbo -br -brs -c33 -cd33 "
90 "-ncdb -ce -ci4 -cli0 -cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i4 -ip0 -l75 "
91 "-lp -npcs -nprs -npsl -saf -sai -saw -nsc -nsob -nss" , FALSE},
92 {"Original Berkeley style", "-nbad -nbap -bbo -bc -br -brs -c33 -cd33 -cdb "
93 "-ce -ci4 -cli0 -cp33 -di16 -fc1 -fca -hnl -i4 -ip4 -l75 -lp -npcs "
94 "-nprs -psl", FALSE},
95 {"Anjuta coding style", "-l80 -lc80 -ts4 -i4 -sc -bli0 -bl0 -cbi0 -ss", FALSE},
96 {"Style of Kangleipak", "-i8 -sc -bli0 -bl0 -cbi0 -ss", FALSE},
97 {"Hello World style", "-gnu -i0 -bli0 -cbi0 -cdb -sc -bl0 -ss", FALSE},
98 {NULL, NULL, FALSE}
101 /******************************************************************************/
102 void indent_init_hash(IndentData *idt);
104 void indent_destroy_hash_data(gpointer key, gpointer data, gpointer user_data);
105 void indent_free_data(IndentData *idt);
106 void indent_free_style(IndentData *idt);
108 void indent_init_indent_style(IndentData *idt);
109 gint indent_load_all_style(IndentData *idt);
111 gchar *indent_alpha_string(gchar *option);
112 gboolean indent_option_is_numeric(gchar *option);
113 void indent_anal_option(gchar *option, IndentData *idt);
114 gint indent_compare_options(gchar *opt1, gchar *opt2);
115 gchar *indent_sort_options(gchar *line);
116 gint indent_compare_style(IndentStyle *style, gchar *name_style);
118 void indent_save_list_style(GList *list, IndentData *idt);
120 /*****************************************************************************/
122 IndentData *
123 indent_init(AnjutaPreferences *prefs)
125 IndentData *idt;
127 idt = g_new(IndentData, 1);
128 indent_init_hash(idt);
129 idt->dialog = NULL;
130 idt->style_list = NULL;
131 idt->checkbutton_blocked = FALSE;
132 return idt;
135 void
136 indent_init_hash(IndentData *idt)
138 int i;
139 OptionData *ptroption;
140 CheckData *ptrcheck;
142 idt->option_hash = g_hash_table_new_full ((GHashFunc) g_str_hash,
143 (GEqualFunc) g_str_equal,
144 (GDestroyNotify) g_free,
145 (GDestroyNotify) g_free);
146 idt->check_hash = g_hash_table_new_full ((GHashFunc) g_str_hash,
147 (GEqualFunc) g_str_equal,
148 (GDestroyNotify) g_free,
149 (GDestroyNotify) g_free);
150 idt->spin_hash = g_hash_table_new_full ((GHashFunc) g_str_hash,
151 (GEqualFunc) g_str_equal,
152 (GDestroyNotify) g_free,
153 (GDestroyNotify) g_free);
154 for (i=0; indent_option[i].option != NULL; i++)
156 ptroption = g_new(OptionData, 1);
157 ptroption->not_option = indent_option[i].not_option;
158 ptroption->checkbutton = indent_option[i].checkbutton;
159 ptroption->spinbutton = indent_option[i].spinbutton;
160 g_hash_table_insert (idt->option_hash, indent_option[i].option, ptroption);
161 ptrcheck = g_new(CheckData, 1);
162 ptrcheck->option = indent_option[i].option;
163 ptrcheck->not_option = indent_option[i].not_option;
164 ptrcheck->spinbutton = indent_option[i].spinbutton;
165 g_hash_table_insert (idt->check_hash, indent_option[i].checkbutton, ptrcheck);
166 if (indent_option[i].spinbutton)
167 g_hash_table_insert (idt->spin_hash, indent_option[i].spinbutton,
168 indent_option[i].option);
174 void
175 indent_destroy_hash_data(gpointer key, gpointer data, gpointer user_data)
177 g_free(data);
180 void
181 indent_free_data(IndentData *idt)
183 g_hash_table_foreach(idt->option_hash, indent_destroy_hash_data, NULL);
184 g_hash_table_foreach(idt->check_hash, indent_destroy_hash_data, NULL);
187 void
188 indent_free_style(IndentData *idt)
190 GList *list;
192 list = idt->style_list;
193 while (list)
195 g_free(list->data);
196 list = g_list_next(list);
198 g_list_free(idt->style_list);
201 void
202 indent_free(IndentData *idt)
204 indent_free_style(idt);
205 indent_free_data(idt);
208 void
209 indent_init_indent_style(IndentData *idt)
211 IndentStyle *indent_style;
212 gint i;
214 for (i=0; standard_indent_style[i].name != NULL; i++)
216 indent_style = g_new(IndentStyle, 1);
217 indent_style->name = standard_indent_style[i].name;
218 indent_style->options = standard_indent_style[i].options;
219 indent_style->modifiable = standard_indent_style[i].modifiable;
220 idt->style_list = g_list_append(idt->style_list, indent_style);
224 void
225 indent_init_load_style(IndentData *idt)
227 indent_init_indent_style(idt);
228 idt->style_active = indent_load_all_style(idt);
232 gint
233 indent_load_all_style(IndentData *idt)
235 GSList *list2 = NULL;
236 gchar *key;
237 gchar *style_name = NULL;
238 gchar *options = NULL;
239 IndentStyle *indent_style;
241 list2 = anjuta_preferences_get_list (idt->prefs, AUTOFORMAT_LIST_STYLE,
242 GCONF_VALUE_STRING);
243 if (list2 == NULL)
244 return 0;
245 while (list2)
247 indent_style = g_new(IndentStyle, 1);
248 indent_style->name = g_strdup((gchar*)list2->data);
249 key = g_strdup((gchar*)list2->data);
250 key = g_strconcat(AUTOFORMAT_OPTS, "/", g_strdelimit(key, " ", '_'), NULL);
251 options = anjuta_preferences_get (idt->prefs, key);
252 indent_style->options = g_strdup(options);
253 indent_style->modifiable = TRUE;
254 idt->style_list =g_list_append(idt->style_list, indent_style);
255 g_free(key);
256 g_free(options);
257 list2 = g_slist_next(list2);
259 g_slist_free(list2);
260 if (!anjuta_preferences_get_pair (idt->prefs, AUTOFORMAT_STYLE,
261 GCONF_VALUE_STRING, GCONF_VALUE_STRING,
262 &style_name, &options))
263 return 0;
264 else
265 return indent_find_index(style_name, idt);
268 gchar *
269 indent_alpha_string(gchar *option)
271 gchar *ptr = option;
273 while(g_ascii_isalpha(*(ptr)) )
274 ptr++;
275 if (ptr == option)
276 return NULL;
277 return g_strndup(option, ptr - option);
280 gboolean
281 indent_option_is_numeric(gchar *option)
283 gboolean numeric = FALSE;
284 while (*option)
286 if (! g_ascii_isdigit(*(option++)) )
287 return FALSE;
288 else
289 numeric = TRUE;
291 return numeric;
294 void
295 indent_anal_option(gchar *option, IndentData *idt)
297 gboolean flag_n = FALSE;
298 gchar *alpha_option;
299 gchar *num;
300 OptionData *ptrdata;
302 if (*(option++) != '-') return;
303 if (*option == 'n')
305 option++;
306 flag_n = TRUE;
308 if (*option == 0) return;
310 if ((ptrdata = g_hash_table_lookup(idt->option_hash, option)) == NULL
311 || ptrdata->spinbutton)
313 if ( (alpha_option = indent_alpha_string(option)) == NULL)
314 return;
315 if ((ptrdata = g_hash_table_lookup(idt->option_hash, alpha_option)) == NULL)
316 return;
317 if ( flag_n && ptrdata->not_option)
319 g_free(alpha_option);
320 return;
322 if ( !flag_n && (ptrdata->spinbutton != NULL))
324 num = g_strdup(option + strlen(alpha_option));
325 if (!indent_option_is_numeric(num))
327 g_free(num);
328 return;
330 indent_toggle_button_set_active(ptrdata->checkbutton, !flag_n, idt);
331 indent_widget_set_sensitive(ptrdata->spinbutton, TRUE, idt);
332 indent_spinbutton_set_value(ptrdata->spinbutton, num, idt);
333 g_free(num);
335 g_free(alpha_option);
337 else
339 if (!flag_n)
340 indent_toggle_button_set_active(ptrdata->checkbutton, TRUE, idt);
341 else
342 if (ptrdata->not_option)
343 indent_toggle_button_set_active(ptrdata->checkbutton, FALSE, idt);
348 void
349 indent_anal_line_option(gchar *line, IndentData *idt)
351 gchar **split;
352 gint i = 0;
354 split = g_strsplit(line, " ", -1);
355 while (split[i])
357 if (strlen(split[i]) > 0)
358 indent_anal_option(split[i], idt);
359 i++;
361 g_strfreev(split);
365 gchar *
366 indent_delete_option(gchar *line, gchar *short_option, gboolean num)
368 gchar **split;
369 gint i=0;
370 gchar *result;
371 gchar *ptr_start = NULL;
372 gchar *ptr_end = NULL;
373 gchar *opt;
375 result = g_strdup("");
376 split = g_strsplit(line, " ", -1);
377 while (split[i])
379 if (strlen(split[i]) != 0)
381 ptr_start = split[i];
382 if (*(ptr_start++) == '-')
384 if (*(ptr_start) == 'n')
385 ptr_start++;
386 ptr_end = ptr_start;
387 if (num)
389 while(g_ascii_isalpha(*ptr_end))
390 ptr_end++;
391 opt = g_strndup(ptr_start, ptr_end - ptr_start);
393 else
395 while(g_ascii_isalnum(*ptr_end))
396 ptr_end++;
397 opt = g_strndup(ptr_start, ptr_end - ptr_start);
399 if (strlen(opt) > 0 && g_ascii_strcasecmp(opt, short_option) != 0)
400 result= g_strconcat(result, split[i], " ", NULL);
401 g_free(opt);
404 i++;
406 g_strfreev(split);
407 return result;
410 gint
411 indent_compare_options(gchar *opt1, gchar *opt2)
413 if (*(opt1) == '-')
415 opt1++;
416 if (*(opt1) == 'n') opt1++;
418 if (*(opt2) == '-')
420 opt2++;
421 if (*(opt2) == 'n') opt2++;
423 return g_ascii_strcasecmp(opt1, opt2);
426 gchar *
427 indent_sort_options(gchar *line)
429 gchar **split;
430 gint i=0, j=0;
431 gchar *tmp;
432 gboolean exch = TRUE;
433 gchar *result = "";
435 split = g_strsplit(line, " ", -1);
436 /* Remove empty items or not beginning by '-' */
437 while (split[i])
439 if ((strlen(split[i]) != 0) && (*(split[i]) == '-'))
440 split[j++] = split[i];
441 i++;
442 } /* j = number of items */
444 /* Sort split[] */
445 while (exch)
447 exch = FALSE;
448 for (i=0; i<j-1; i++)
450 if (indent_compare_options(split[i], split[i+1]) > 0)
452 tmp = split[i]; split[i] = split[i+1]; split[i+1] = tmp;
453 exch = TRUE;
458 for (i=0; i<j; i++)
459 result = g_strconcat(result, split[i], " ", NULL);
461 g_strfreev(split);
462 return result;
465 gchar *
466 indent_insert_option(gchar *line, gchar *option)
468 line = g_strconcat(option, " ", line, NULL);
469 line = indent_sort_options(line);
470 return line;
473 gint
474 indent_execute(gchar *line_option, IndentData *idt)
476 gchar *cmd;
477 gchar *options;
478 pid_t pid;
479 int status;
481 options = g_strconcat(line_option, " ",INDENT_FILE_INPUT, NULL);
482 cmd = g_strconcat ("indent ", options, " -o ", INDENT_FILE_OUTPUT, NULL);
483 g_free(options);
485 pid = anjuta_util_execute_shell (PACKAGE_DATA_DIR, cmd);
487 waitpid (pid, &status, 0);
488 g_free (cmd);
489 return status;
492 gchar *
493 indent_get_buffer(void)
495 GnomeVFSResult result;
496 GnomeVFSHandle *handle;
497 GnomeVFSFileInfo info;
498 gchar *read_buf = NULL;
499 gchar *text_uri;
501 text_uri = gnome_vfs_get_uri_from_local_path(INDENT_FILE_OUTPUT);
502 result = gnome_vfs_get_file_info(text_uri, &info,
503 GNOME_VFS_FILE_INFO_DEFAULT |
504 GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS);
505 if(result != GNOME_VFS_OK )
507 DEBUG_PRINT("Cannot get info: %s\n", text_uri);
508 return NULL;
510 if((result = gnome_vfs_open (&handle, text_uri,
511 GNOME_VFS_OPEN_READ)) != GNOME_VFS_OK)
513 DEBUG_PRINT("Cannot open: %s\n", text_uri);
514 return NULL;
516 read_buf = g_new0(char, info.size + 1);
518 result = gnome_vfs_read (handle, read_buf, info.size, NULL);
519 if(!(result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_EOF))
521 g_free (read_buf);
522 DEBUG_PRINT("No file: %s\n", text_uri);
523 return NULL;
525 gnome_vfs_close (handle);
526 return read_buf;
530 void
531 indent_save_list_style(GList *list, IndentData *idt)
533 GSList *list2 = NULL;
534 IndentStyle *idtst;
536 while (list)
538 idtst = list->data;
539 if (idtst->modifiable)
540 list2 = g_slist_append(list2, idtst->name);
541 list = g_list_next(list);
543 anjuta_preferences_set_list (idt->prefs, AUTOFORMAT_LIST_STYLE,
544 GCONF_VALUE_STRING, list2);
545 g_slist_free(list2);
548 void
549 indent_save_style(gchar *style_name, gchar *options, IndentData *idt)
551 gchar *key;
553 if (!anjuta_preferences_dir_exists (idt->prefs, AUTOFORMAT_OPTS))
554 anjuta_preferences_add_dir (idt->prefs, AUTOFORMAT_OPTS,
555 GCONF_CLIENT_PRELOAD_NONE);
557 key = g_strdup(style_name);
558 key = g_strconcat(AUTOFORMAT_OPTS, "/", g_strdelimit(key, " ", '_'), NULL);
560 anjuta_preferences_set(idt->prefs, key, options); //**//
561 g_free(key);
564 void
565 indent_save_all_style(IndentData *idt)
567 GList *list1;
568 IndentStyle *idtst;
570 if (anjuta_preferences_dir_exists (idt->prefs, AUTOFORMAT_OPTS) )
571 anjuta_preferences_remove_dir (idt->prefs, AUTOFORMAT_OPTS);
572 anjuta_preferences_add_dir (idt->prefs, AUTOFORMAT_OPTS,
573 GCONF_CLIENT_PRELOAD_NONE);
575 list1 = idt->style_list;
576 indent_save_list_style(list1, idt);
578 list1 = idt->style_list;
579 while (list1)
581 idtst = list1->data;
582 if (idtst->modifiable)
583 indent_save_style(idtst->name, idtst->options, idt);
584 list1 = g_list_next(list1);
588 gint
589 indent_compare_style(IndentStyle *style, gchar *name_style)
591 return g_ascii_strcasecmp(style->name, name_style);
594 gchar *
595 indent_find_style(gchar *style_name, IndentData *idt)
597 GList *list;
599 list = g_list_find_custom(idt->style_list, style_name,
600 (GCompareFunc) indent_compare_style);
601 if (list)
602 return ((IndentStyle*)list->data)->options;
603 else
604 return NULL;
607 gint
608 indent_find_index(gchar *style_name, IndentData *idt)
610 gint index;
611 GList *list;
613 if (style_name == NULL)
614 return 0;
615 list = g_list_find_custom(idt->style_list, style_name,
616 (GCompareFunc) indent_compare_style);
617 index = g_list_index(idt->style_list, list->data);
618 return index;
621 gboolean
622 indent_remove_style(gchar *style_name, IndentData *idt)
624 GList *list;
626 list = g_list_find_custom(idt->style_list, style_name,
627 (GCompareFunc) indent_compare_style);
628 if ( list && ((IndentStyle*)list->data)->modifiable)
630 list = g_list_remove(list, list->data);
631 return TRUE;
633 return FALSE;
636 gboolean
637 indent_update_style(gchar *style_name, gchar *options, IndentData *idt)
639 GList *list;
641 list = g_list_find_custom(idt->style_list, style_name,
642 (GCompareFunc) indent_compare_style);
643 if ( list && ((IndentStyle*)list->data)->modifiable)
645 ((IndentStyle*)list->data)->name = style_name;
646 ((IndentStyle*)list->data)->options = options;
648 return TRUE;
650 return FALSE;
653 void
654 indent_save_active_style(gchar *style_name, gchar *options, IndentData *idt)
656 anjuta_preferences_set_pair (idt->prefs, AUTOFORMAT_STYLE,
657 GCONF_VALUE_STRING, GCONF_VALUE_STRING,
658 &style_name, &options);
661 gboolean
662 indent_add_style(gchar *style_name, IndentData *idt)
664 GList *list;
665 IndentStyle *indent_style;
667 list = g_list_find_custom(idt->style_list, style_name,
668 (GCompareFunc) indent_compare_style);
669 if (list)
670 return FALSE;
671 else
673 indent_style = g_new(IndentStyle, 1);
674 indent_style->name = style_name;
675 indent_style->options = standard_indent_style[0].options;
676 indent_style->modifiable = TRUE;
677 idt->style_list =g_list_append(idt->style_list, indent_style);
678 return TRUE;