? .dest ? beaver.1x.gz ? config.h ? src/beaver Index: src/Makefile =================================================================== RCS file: /sources/beaver/beaver0.4.0/src/Makefile,v retrieving revision 1.18 diff -u -u -p -r1.18 Makefile --- src/Makefile 14 Dec 2008 17:30:28 -0000 1.18 +++ src/Makefile 22 Dec 2008 02:20:14 -0000 @@ -1,6 +1,6 @@ ## ## Makefile for Beaver -## +## ## Author: Marc Bevand (aka "After") ## Last update: Mon Jul 15 22:29:51 CEST 2002 ## @@ -12,10 +12,10 @@ RM = /bin/rm -f CP = /bin/cp INSTALL = /usr/bin/install -IPATH = -LPATH = -OPTI = -O3 -fPIC -fomit-frame-pointer -funroll-loops -DBUG = #-DGTK_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED #-ggdb -pg -fbounds-check +IPATH = +LPATH = +OPTI = #-O3 -fPIC -fomit-frame-pointer -funroll-loops +DBUG = -g3 #-DGTK_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED #-ggdb -pg -fbounds-check WARN = #-W -Wall #-pedantic -ansi ### Unix version ### @@ -61,7 +61,7 @@ ${OBJ} : ${INC} install : ${INSTALL} -d ${DESTDIR}/bin ${INSTALL} beaver ${DESTDIR}/bin - + ${INSTALL} -d ${DESTDIR}/share/pixmaps ${INSTALL} ../pixmaps/icons/48x48/beaver.png ${DESTDIR}/share/pixmaps ${INSTALL} -d ${DESTDIR}/share/icons/hicolor/48x48/apps @@ -72,7 +72,7 @@ install : ${INSTALL} ../pixmaps/icons/22x22/beaver.png ${DESTDIR}/share/icons/hicolor/22x22/apps ${INSTALL} -d ${DESTDIR}/share/icons/hicolor/16x16/apps ${INSTALL} ../pixmaps/icons/16x16/beaver.png ${DESTDIR}/share/icons/hicolor/16x16/apps - + ${INSTALL} -d ${DESTDIR}/share/beaver/pixmaps/ ${INSTALL} ../pixmaps/about.xpm ${DESTDIR}/share/beaver/pixmaps ${INSTALL} -d ${DESTDIR}/share/beaver/include Index: src/plugin.c =================================================================== RCS file: /sources/beaver/beaver0.4.0/src/plugin.c,v retrieving revision 1.22 diff -u -u -p -r1.22 plugin.c --- src/plugin.c 14 Dec 2008 16:07:55 -0000 1.22 +++ src/plugin.c 22 Dec 2008 02:20:14 -0000 @@ -62,24 +62,24 @@ extern GtkWidget* MainNotebook; /** * Frees an information pointer - * + * * @param plugin information pointer */ static inline void plugin_info_free (plugin_info* plugin) { /* do not free if not pointer */ if (plugin == NULL) return; - + /* free all fields */ if (plugin->name) g_free (plugin->name); if (plugin->description) g_free (plugin->description); - if (plugin->author) + if (plugin->author) g_free (plugin->author); - if (plugin->version) + if (plugin->version) g_free (plugin->version); - if (plugin->filename) + if (plugin->filename) g_free (plugin->filename); /* free structure itself */ @@ -88,27 +88,27 @@ static inline void plugin_info_free (plu /** * Load information about plugin. - * + * * This function loads some information (author, name, version) about * the plugin and returns a structure containing those information. - * + * * @param filename the filename of a plugin, the path must be absolute * @return returns the loaded information */ static inline plugin_info* plugin_info_load (gchar* filename) { GModule* module = NULL; /* module for g_module functions */ - + /* function pointers for some functions in the * plugin */ __plugin_author_func __plugin_author; __plugin_version_func __plugin_version; __plugin_name_func __plugin_name; __plugin_description_func __plugin_description; - + /* result to return */ plugin_info* plugin = g_new (plugin_info, 1); - + /* try to open shared object file */ module = g_module_open (filename, G_MODULE_BIND_LOCAL); if (!module) { @@ -116,7 +116,7 @@ static inline plugin_info* plugin_info_l g_free (plugin); return NULL; } - + /* try to load author information */ if (g_module_symbol (module, "__plugin_author", (gpointer*)&__plugin_author)) { gchar* string = __plugin_author (); @@ -125,7 +125,7 @@ static inline plugin_info* plugin_info_l /* plugin has no author field */ plugin->author = g_strdup ("U. N. Known"); } - + /* try to load version information */ if (g_module_symbol (module, "__plugin_version", (gpointer*)&__plugin_version)) { gchar* string = __plugin_version (); @@ -134,7 +134,7 @@ static inline plugin_info* plugin_info_l /* plugin has no version field */ plugin->version = g_strdup ("0"); } - + /* try to load name information */ if (g_module_symbol (module, "__plugin_name", (gpointer*)&__plugin_name)) { gchar* string = __plugin_name (); @@ -152,20 +152,20 @@ static inline plugin_info* plugin_info_l /* plugin has no version field */ plugin->description = g_strdup (""); } - + /* unload module, we've got the information */ if (!g_module_close (module)) { /* something went wrong */ plugin_info_free (plugin); return NULL; } - + /* set some dummy fields */ plugin->activated = FALSE; plugin->cleanup_func = NULL; plugin->preference_func = NULL; plugin->module = NULL; - + /* save back filename */ plugin->filename = g_strdup (filename); return plugin; @@ -173,7 +173,7 @@ static inline plugin_info* plugin_info_l /** * Loads and initializes plugin. - * + * * @param info a plugin info descriptor */ static inline void plugin_activate (plugin_info* info) @@ -189,31 +189,31 @@ static inline void plugin_activate (plug __plugin_init_func __plugin_init; __plugin_cleanup_func __plugin_cleanup; __plugin_preference_func __plugin_preference; - - /* load the module */ + + /* load the module */ info->module = g_module_open (info->filename, G_MODULE_BIND_LOCAL); if (!info->module) { return; } - + /* try to load some functions */ g_module_symbol (info->module, "__plugin_init", (gpointer*)&__plugin_init); g_module_symbol (info->module, "__plugin_cleanup", (gpointer*)&__plugin_cleanup); g_module_symbol (info->module, "__plugin_preference", (gpointer*)&__plugin_preference); - + /* set the fields */ info->activated = TRUE; info->cleanup_func = (void*)__plugin_cleanup; info->preference_func = NULL; if (__plugin_preference) info->preference_func = (void*)__plugin_preference; - + /* init */ - if (__plugin_init) __plugin_init (); + if (__plugin_init) __plugin_init (); } /** * Unloads and deactivates a plugin. - * + * * @param info a plugin info descriptor */ static inline void plugin_deactivate (plugin_info* info) @@ -223,12 +223,12 @@ static inline void plugin_deactivate (pl if (!info || !info->activated) { return; } - + /* clean up plugin */ __plugin_cleanup_func __plugin_cleanup; __plugin_cleanup = (__plugin_cleanup_func)info->cleanup_func; if (__plugin_cleanup) __plugin_cleanup (); - + /* unload module and set fields */ g_module_close (info->module); info->activated = FALSE; @@ -237,14 +237,14 @@ static inline void plugin_deactivate (pl /** * Loads and stores information about all plugins in a * specified directory. - * + * * @param directory directory in which to search for plugins */ -static inline void plugin_load_plugin_dir (gchar* directory) +static inline void plugin_load_plugin_dir (gchar* directory) { /* open directory */ GDir* dir = g_dir_open (directory, 0, NULL); - + /* if everything went ok, then proceed */ if (dir != NULL) { /* iterate through the directory */ @@ -253,33 +253,33 @@ static inline void plugin_load_plugin_di /* try to load the plugin */ gchar* pfile = g_strconcat (directory, plugin, NULL); plugin_info* info = plugin_info_load (pfile); - + /* store the information about found plugin * into a list */ if (info) { __found_plugins = g_list_append (__found_plugins, (gpointer)info); - + /* if the plugin is marked as "loaded" in the config file * then we should activate it */ - gchar* text = g_strconcat ("/Plugins/", info->filename, NULL); + gchar* text = g_strconcat ("/Plugins/", info->filename, NULL); gchar* setting = get_string_conf (text); - + if (strncmp ("loaded", setting, 6) == 0) { plugin_activate (info); } - + /* free up space */ g_free (text); g_free (setting); } - + /* free up space */ g_free (pfile); } - + /* close directory */ g_dir_close (dir); - } + } } /** @@ -293,13 +293,13 @@ static inline void plugin_setup_api (voi beaver_box_question = beaver_box_question_impl; beaver_box_prompt = beaver_box_prompt_impl; beaver_box_file_selection = beaver_box_file_selection_impl; - + /* ui */ beaver_ui_item_add = beaver_ui_item_add_impl; beaver_ui_item_seperator_add = beaver_ui_item_seperator_add_impl; beaver_ui_item_remove = beaver_ui_item_remove_impl; beaver_ui_item_submenu_add = beaver_ui_item_submenu_add_impl; - + /* text */ beaver_text_insert_string = beaver_text_insert_string_impl; beaver_text_selection_position = beaver_text_selection_position_impl; @@ -308,10 +308,12 @@ static inline void plugin_setup_api (voi beaver_text_format = beaver_text_format_impl; beaver_text_replace = beaver_text_replace_impl; beaver_text_find = beaver_text_find_impl; + beaver_text_find_regex = beaver_text_find_regex_impl; + beaver_text_replace_regex = beaver_text_replace_regex_impl; } /** - * + * * @param data pointer to a plugin_info structure * @param user_data pointer to a GtkListStore structure */ @@ -320,26 +322,26 @@ static void plugin_list_add (gpointer da GtkListStore* store = (GtkListStore*)user_data; plugin_info* info = (plugin_info*)data; GtkTreeIter iter; - + if (info) { gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 1, info->name, + gtk_list_store_set (store, &iter, 1, info->name, 2, info->filename, 3, (gint)info, -1); - - /* set the toggle button correctly (if plugin + + /* set the toggle button correctly (if plugin * was loaded or not) */ gtk_list_store_set (store, &iter, 0, info->activated, -1); } } /** - * + * */ static void signal_toggle (GtkCellRendererToggle* cell_renderer, gchar* spath, gpointer user_data) { GtkTreeModel* model = GTK_TREE_MODEL(user_data); GtkTreePath* path = gtk_tree_path_new_from_string(spath); - gint plugin; + gint plugin; GtkTreeIter it; gboolean toggle; @@ -347,16 +349,16 @@ static void signal_toggle (GtkCellRender gtk_tree_model_get_iter(model, &it, path); gtk_tree_model_get(model, &it, 0, &toggle, -1); gtk_tree_model_get(model, &it, 3, &plugin, -1); - + /* if the toggle button was activated, then a click means - * that it's getting deactivated. - * + * that it's getting deactivated. + * * if it's activated, then unload this plugin. otherwise * we have to activate this plugin */ /* deactivate plugin */ if (toggle) { plugin_deactivate ((plugin_info*)plugin); - + /* mark this plugin as unloaded in the config file */ gchar* text = g_strconcat ("/Plugins/", ((plugin_info*)plugin)->filename, NULL); set_string_conf (text, "unloaded"); @@ -370,13 +372,13 @@ static void signal_toggle (GtkCellRender set_string_conf (text, "loaded"); g_free (text); } - + /* really toggle the checkbox */ toggle ^= 1; gtk_list_store_set(GTK_LIST_STORE(model), &it, 0, toggle, -1); /* free up space */ - gtk_tree_path_free(path); + gtk_tree_path_free(path); } /** @@ -389,14 +391,14 @@ static void signal_activate (GtkTreeView GtkTreeModel* model; gint plugin = 0; plugin_info* info; - + /* get the selected row and read the plugin descriptor out - * of it if possible */ + * of it if possible */ GtkTreeSelection* selection = gtk_tree_view_get_selection (tree_view); if (selection && gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)) { gtk_tree_model_get(model, &iter, 3, &plugin, -1); } - + /* read the information out of the plugin descriptor */ info = (plugin_info*)plugin; if (!info) { @@ -406,7 +408,7 @@ static void signal_activate (GtkTreeView gtk_label_set_text (GTK_LABEL(label_descr), ""); //gtk_label_set_text (label, "Author:\nVersion:\nDescription:"); } else { - /*gchar* text = g_strdup_printf ("Author:\t\t%s\nVersion:\t\t%s\nDescription:\t%s", + /*gchar* text = g_strdup_printf ("Author:\t\t%s\nVersion:\t\t%s\nDescription:\t%s", info->author, info->version, info->description);*/ gtk_label_set_text (GTK_LABEL(label_author), info->author); gtk_label_set_text (GTK_LABEL(label_version), info->version); @@ -417,7 +419,7 @@ static void signal_activate (GtkTreeView } else { gtk_widget_set_sensitive (preference_button, FALSE); } - + /*gtk_label_set_text (label, text); g_free (text);*/ } @@ -434,14 +436,14 @@ static void signal_preference (GtkButton GtkTreeModel* model; gint plugin = 0; plugin_info* info; - + /* get the selected row and read the plugin descriptor out - * of it if possible */ + * of it if possible */ GtkTreeSelection* selection = gtk_tree_view_get_selection (tree_view); if (selection && gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)) { gtk_tree_model_get(model, &iter, 3, &plugin, -1); } - + /* read the information out of the plugin descriptor */ info = (plugin_info*)plugin; if (info && info->preference_func) { @@ -458,7 +460,7 @@ static void plugin_manage (void) /* if manager dialog wasn't created before, then create it */ if (!manager_dialog) { GtkWidget* vbox; - + GtkWidget* top_label; GtkWidget* scroll; GtkWidget* plugins_list; @@ -466,9 +468,9 @@ static void plugin_manage (void) GtkWidget* table; GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_toggle; - + GtkListStore* store; - + /* create a new dialog */ manager_dialog = gtk_dialog_new (); gtk_window_set_modal(GTK_WINDOW(manager_dialog), TRUE); @@ -477,11 +479,11 @@ static void plugin_manage (void) gtk_window_set_transient_for (GTK_WINDOW(manager_dialog), GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(MainNotebook)))); gtk_window_set_title (GTK_WINDOW(manager_dialog), APP_NAME " - Plugin Manager"); - + /* create a preference button (set unsensitive) */ preference_button = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES); gtk_widget_set_sensitive (preference_button, FALSE); - + /* we need four vertical boxes: * - top label * - tree view (plugin list) @@ -492,12 +494,12 @@ static void plugin_manage (void) top_label = gtk_label_new ("Available plugins: "); plugins_list = gtk_tree_view_new (); scroll = gtk_scrolled_window_new(NULL, NULL); - + gtk_misc_set_alignment (GTK_MISC(top_label), 0, 0.3); - gtk_label_set_single_line_mode (GTK_LABEL(top_label), TRUE); + gtk_label_set_single_line_mode (GTK_LABEL(top_label), TRUE); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - + /* create a 3x3 table. one row is for the author, one * row for the version and one for the description. * the third column is empty except for the last row, were @@ -507,14 +509,14 @@ static void plugin_manage (void) gtk_table_set_col_spacings (GTK_TABLE(table), 5); gtk_table_set_homogeneous (GTK_TABLE(table), FALSE); gtk_container_set_border_width (GTK_CONTAINER(table), 10); - + /* populate the virtual box */ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (manager_dialog)->vbox), vbox); gtk_container_add (GTK_CONTAINER (vbox), top_label); gtk_container_add (GTK_CONTAINER (vbox), scroll); gtk_container_add (GTK_CONTAINER (vbox), table); gtk_widget_show_all (vbox); - + /* populate table */ GtkWidget* label = gtk_label_new ("Author: "); label_author = gtk_label_new (""); @@ -529,7 +531,7 @@ static void plugin_manage (void) gtk_misc_set_alignment (GTK_MISC(label_version), 0, 0.3); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, 1, 2); gtk_table_attach_defaults (GTK_TABLE(table), label_version, 1, 2, 1, 2); - + label = gtk_label_new ("Description: "); label_descr = gtk_label_new (""); gtk_label_set_line_wrap (GTK_LABEL(label_descr), TRUE); @@ -539,36 +541,36 @@ static void plugin_manage (void) gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, 3, 4); gtk_table_attach_defaults (GTK_TABLE(table), label_descr, 1, 2, 3, 4); gtk_table_attach_defaults (GTK_TABLE(table), preference_button, 3, 4, 3, 4); - + /* show table */ gtk_widget_show_all (table); - + /* add ok button */ button = gtk_dialog_add_button (GTK_DIALOG(manager_dialog), "OK", 1); - + /* add all items into a store list */ store = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); g_list_foreach (__found_plugins, plugin_list_add, (gpointer)store); - + /* finish setting up store list and display it */ renderer_text = gtk_cell_renderer_text_new (); renderer_toggle = gtk_cell_renderer_toggle_new (); - + gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE(renderer_toggle), FALSE); gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE(renderer_toggle), TRUE); - + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(plugins_list), -1, "Active", renderer_toggle, "active", 0, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(plugins_list), -1, "Plugin", renderer_text, "text", 1, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(plugins_list), -1, "File", renderer_text, "text", 2, NULL); - + gtk_tree_view_set_model (GTK_TREE_VIEW(plugins_list), GTK_TREE_MODEL(store)); gtk_container_add (GTK_CONTAINER(scroll), plugins_list); g_object_unref (GTK_TREE_MODEL(store)); gtk_widget_show (plugins_list); - + /* register some signals */ g_signal_connect (G_OBJECT(renderer_toggle), "toggled", GTK_SIGNAL_FUNC(signal_toggle), store); @@ -579,34 +581,34 @@ static void plugin_manage (void) g_signal_connect (G_OBJECT(manager_dialog), "close", GTK_SIGNAL_FUNC(gtk_widget_hide), manager_dialog); g_signal_connect (G_OBJECT(manager_dialog), "response", - GTK_SIGNAL_FUNC(gtk_widget_hide), manager_dialog); + GTK_SIGNAL_FUNC(gtk_widget_hide), manager_dialog); g_signal_connect (G_OBJECT(preference_button), "clicked", GTK_SIGNAL_FUNC(signal_preference), plugins_list); - + } - + /* show dialog */ gtk_widget_show (GTK_WIDGET(manager_dialog)); } /** * Initialize plugin system. - * + * * Sets all functions pointers to specific implementations for * the API used in the plugins. function pointers are defined - * in api/beaver.h. Also loads all activated plugins and + * in api/beaver.h. Also loads all activated plugins and * initializes them too and loads information about all * found plugins.\n * Plugins can be in the home directory "~/.beaver/plugins/" or * in the installation directory. */ -void plugin_init (void) +void plugin_init (void) { /* check wheter module loading is supported or not */ if (!g_module_supported ()) { return; } - + /* directory of home installed plugins */ gchar* home_plugin_dir = g_strconcat (g_get_home_dir(), PATH_SEP_STRING, CONF_DIR, PATH_SEP_STRING, "plugins", PATH_SEP_STRING, NULL); @@ -617,16 +619,16 @@ void plugin_init (void) /* fill up the function pointers for the API */ plugin_setup_api (); - /* add a menu item into tools section, that starts the + /* add a menu item into tools section, that starts the * plugin manager */ - beaver_ui_item_add (BEAVER_SECTION_MENU_TOOLS, "manager", + beaver_ui_item_add (BEAVER_SECTION_MENU_TOOLS, "manager", GTK_STOCK_EXECUTE, "Plugins ...", plugin_manage); beaver_ui_item_seperator_add (BEAVER_SECTION_MENU_TOOLS); /* check if in the home directory are some plugins to load * information from, and load them. */ plugin_load_plugin_dir (home_plugin_dir); - + /* check if in the installation directory are some plugins * to load information from, and load them */ plugin_load_plugin_dir (PLUGINS_DIR); Index: src/search.c =================================================================== RCS file: /sources/beaver/beaver0.4.0/src/search.c,v retrieving revision 1.5 diff -u -u -p -r1.5 search.c --- src/search.c 14 Dec 2008 16:07:55 -0000 1.5 +++ src/search.c 22 Dec 2008 02:20:15 -0000 @@ -29,7 +29,7 @@ #include #include -#include "search.h" +#include "search.h" #include "struct.h" #include "api/beaver.h" @@ -53,6 +53,7 @@ static GtkWidget* check_case_sensitive = static GtkWidget* check_replace_all = NULL; static GtkWidget* check_start_beginning = NULL; static GtkWidget* check_start_cursor = NULL; +static GtkWidget* check_regex_mode = NULL; /* the main notebook (from interface.c) */ extern GtkWidget* MainNotebook; @@ -65,9 +66,9 @@ extern GArray *FileProperties; /** * signal handler when a row on the treeview is dbl-clicked - * + * * @param treeview the treeview the event occured - * @param path + * @param path * @param column the column on the treeview * @param data data provided at signal registering time */ @@ -78,7 +79,7 @@ static void signal_row_activated (GtkTre GtkTreeModel *model; gint offset = 0; gint length = 0; - + GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview)); if (selection && gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)) { gtk_tree_model_get (model, &iter, 1, &offset, -1); @@ -86,20 +87,20 @@ static void signal_row_activated (GtkTre } else { return; } - + /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - + /* get the text buffer */ GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - + /* mark found position */ GtkTextIter start, end; gtk_text_buffer_get_selection_bounds (buffer, &start, &end); gtk_text_iter_set_offset (&start, offset - 1); gtk_text_iter_set_offset (&end, offset + length - 1); gtk_text_buffer_select_range (buffer, &start, &end); - + /* scroll the text to the right position */ gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW(FPROPS(current_page, Text)), &start, 0.1, FALSE, 0, 0); @@ -107,7 +108,7 @@ static void signal_row_activated (GtkTre /** * called when pressed on goto line button - * + * * @param button the button that was pressed * @param data user defined data */ @@ -121,15 +122,15 @@ static void jump_to (GtkButton* button, /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - + /* get the text buffer */ GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - + /* mark line */ GtkTextIter start; gtk_text_buffer_get_iter_at_line (buffer, &start, line-1); gtk_text_buffer_place_cursor (buffer, &start); - + /* scroll window to position */ gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW(FPROPS(current_page, Text)), &start, 0.1, FALSE, 0, 0); @@ -137,14 +138,14 @@ static void jump_to (GtkButton* button, /** * called when pressed on find button - * + * * @param button the button that was pressed - * @param data user defined data + * @param data user defined data */ -static void find (GtkButton* button, gpointer data) +static void find (GtkButton* button, gpointer data) { const gchar* text = gtk_entry_get_text (GTK_ENTRY(entry_search)); - + /* has the text box some value? if not display message and * abort */ if (strcmp (text, "") == 0) { @@ -154,17 +155,20 @@ static void find (GtkButton* button, gpo /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - + /* get the text buffer */ GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - + /* try to load cursors from selection */ GtkTextIter start, end; - gtk_text_buffer_get_selection_bounds (buffer, &start, &end); + gtk_text_buffer_get_selection_bounds (buffer, &start, &end); /* do we have to search in case sensitive mode? */ gboolean case_sensitive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_case_sensitive)); - + + /* should we treat the input as a regex pattern and execute it? */ + gboolean regex_mode = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_regex_mode)); + /* determine where to start */ gint offset = 0; if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_start_cursor))) { @@ -173,36 +177,72 @@ static void find (GtkButton* button, gpo /* create a new store list */ GtkListStore* store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); - - /* search for all occurences in the text */ - gint m = strlen (text); - gint num = 1; - while (beaver_text_find (text, offset, case_sensitive)) { + + if (regex_mode) { + BeaverRegexResult *res; + gint i; + + res = beaver_text_find_regex(text, offset, case_sensitive); + + if (NULL == res) { + g_print("No match found\n"); + + /* set the treeview model to the new model */ + gtk_tree_view_set_model (GTK_TREE_VIEW(results_treeview), GTK_TREE_MODEL(store)); + g_object_unref (GTK_TREE_MODEL(store)); + + /* restore cursor position */ + gtk_text_buffer_place_cursor (buffer, &start); + return; + } + + for (i=0; icount; i++) { GtkTreeIter iter; - - /* get the position of the selection */ - BeaverTextSelection* pos = beaver_text_selection_position (); - - /* create string with information */ - gchar* string = g_strdup_printf ("%d.\tLine %d (%d - %d)", num++, pos->line, - pos->start, pos->end); - + + gchar* string = g_strdup_printf ("%d.\tLine %d (%d - %d)", i+1, res->results[i].line, + res->results[i].start, res->results[i].end); + /* add found item into results list */ gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, string, 1, pos->offset, 2, m, -1); - - /* proceed */ - offset = pos->offset + m; - + gtk_list_store_set (store, &iter, 0, string, 1, res->results[i].offset, 2, (res->results[i].end - res->results[i].start), -1); + /* free up space */ - g_free (pos); g_free (string); + } + + g_free(res); + + } + else { + /* search for all occurences in the text */ + gint m = strlen (text); + gint num = 1; + while (beaver_text_find (text, offset, case_sensitive)) { + GtkTreeIter iter; + + /* get the position of the selection */ + BeaverTextSelection* pos = beaver_text_selection_position (); + + /* create string with information */ + gchar* string = g_strdup_printf ("%d.\tLine %d (%d - %d)", num++, pos->line, + pos->start, pos->end); + + /* add found item into results list */ + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, string, 1, pos->offset, 2, m, -1); + + /* proceed */ + offset = pos->offset + m; + + /* free up space */ + g_free (pos); + g_free (string); + } } - /* set the treeview model to the new model */ gtk_tree_view_set_model (GTK_TREE_VIEW(results_treeview), GTK_TREE_MODEL(store)); g_object_unref (GTK_TREE_MODEL(store)); - + /* restore cursor position */ gtk_text_buffer_place_cursor (buffer, &start); } @@ -210,22 +250,22 @@ static void find (GtkButton* button, gpo /** * called when pressed on find&replace button - * + * * @param button the button that was pressed - * @param data user defined data + * @param data user defined data */ static void find_replace (GtkButton* button, gpointer data) { const gchar* search_text = gtk_entry_get_text (GTK_ENTRY(entry_search)); const gchar* replace_text = gtk_entry_get_text (GTK_ENTRY(entry_replace)); - + /* has the search text box some value? if not display message and * abort */ if (strcmp (search_text, "") == 0) { beaver_box_error ("Please provide a search string!"); return; } - + /* has the replace text box some value? if not display message and * abort */ if (strcmp (replace_text, "") == 0) { @@ -236,61 +276,69 @@ static void find_replace (GtkButton* but /* do we want to search case sensitive? */ gboolean case_sensitive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_case_sensitive)); - /* if the user wants to replace all, then do so */ - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_replace_all))) { - beaver_text_replace (search_text, replace_text, case_sensitive); - return; - } + /* should we treat the input as a regex pattern and execute it? */ + gboolean regex_mode = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_regex_mode)); - /* get the current page that should be edited */ - gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - - /* get the text buffer */ - GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - - /* try to load cursors from selection */ - GtkTextIter start, end; - gtk_text_buffer_get_selection_bounds (buffer, &start, &end); - - /* determine where to start */ - gint offset = 0; - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_start_cursor))) { - offset = gtk_text_iter_get_offset (&start); + if (regex_mode) { + beaver_text_replace_regex (search_text, replace_text, case_sensitive, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_replace_all))); } - - /* search for the string, if found, then ask the user if - * he wants to replace this string, if not, then search for the - * next. - */ - gint m = strlen (search_text); - if (beaver_text_find (search_text, offset, case_sensitive)) { - /* get the position of the selection */ - BeaverTextSelection* pos = beaver_text_selection_position (); - - /* scroll to the selected position */ - GtkTextIter start, end; - gtk_text_buffer_get_selection_bounds (buffer, &start, &end); - gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW(FPROPS(current_page, Text)), - &start, 0.1, FALSE, 0, 0); - - /* ask the question! */ - gint answer = beaver_box_question ("Do you want to replace?"); - if (answer) { - gtk_text_buffer_select_range (buffer, &start, &end); - beaver_text_selection_set (replace_text); - } - - /* proceed */ - offset = pos->offset + m; - - /* free up space */ - g_free (pos); + else { + /* if the user wants to replace all, then do so */ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_replace_all))) { + beaver_text_replace (search_text, replace_text, case_sensitive); + return; + } + + /* get the current page that should be edited */ + gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); + + /* get the text buffer */ + GtkTextBuffer* buffer = FPROPS(current_page, Buffer); + + /* try to load cursors from selection */ + GtkTextIter start, end; + gtk_text_buffer_get_selection_bounds (buffer, &start, &end); + + /* determine where to start */ + gint offset = 0; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check_start_cursor))) { + offset = gtk_text_iter_get_offset (&start); + } + + /* search for the string, if found, then ask the user if + * he wants to replace this string, if not, then search for the + * next. + */ + gint m = strlen (search_text); + if (beaver_text_find (search_text, offset, case_sensitive)) { + /* get the position of the selection */ + BeaverTextSelection* pos = beaver_text_selection_position (); + + /* scroll to the selected position */ + GtkTextIter start, end; + gtk_text_buffer_get_selection_bounds (buffer, &start, &end); + gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW(FPROPS(current_page, Text)), + &start, 0.1, FALSE, 0, 0); + + /* ask the question! */ + gint answer = beaver_box_question ("Do you want to replace?"); + if (answer) { + gtk_text_buffer_select_range (buffer, &start, &end); + beaver_text_selection_set (replace_text); + } + + /* proceed */ + offset = pos->offset + m; + + /* free up space */ + g_free (pos); + } } } /** * Displays a search window. - * + * * @param replace wheter or not, the search window is a search&replace * window */ @@ -303,115 +351,119 @@ void search (gboolean replace) * a search&replace window, then in the second frame the * user can input the text he wants to written instead of * the found text. - * + * * here we create singleton instances of the frame (the upper * frame and the two possible lower frames). when the window * get's shown, then the appropriate frames get choosen and - * and displayed. + * and displayed. */ - + /* search frame not yet created! */ if (!frame_search) { frame_search = gtk_frame_new ("Search"); - + /* create a new vertical box. this vertical box * will hold a text entry and two radio buttons, as well * as 1 check button */ GtkWidget* vbox = gtk_vbox_new (FALSE, 5); gtk_container_set_border_width (GTK_CONTAINER(vbox), 5); gtk_container_add (GTK_CONTAINER(frame_search), vbox); - + /* create a new text entry and attach it */ entry_search = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY(entry_search), TRUE); gtk_box_pack_start (GTK_BOX(vbox), entry_search, FALSE, FALSE, 0); - + /* create two radio buttons to choose if we want * to start at cursor position or at the beginning of the * text */ check_start_cursor = gtk_radio_button_new_with_mnemonic (NULL, "Start at cursor _position"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(check_start_cursor), TRUE); gtk_box_pack_start (GTK_BOX(vbox), check_start_cursor, FALSE, FALSE, 0); - + GSList* group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (check_start_cursor)); - - check_start_beginning = gtk_radio_button_new_with_mnemonic (group, + + check_start_beginning = gtk_radio_button_new_with_mnemonic (group, "Start at _beginning of the document"); gtk_box_pack_start (GTK_BOX(vbox), check_start_beginning, FALSE, FALSE, 0); - + /* create a check box that let's the user choose if he wants * case sensitive search or not */ check_case_sensitive = gtk_check_button_new_with_mnemonic ("Case _sensitive"); gtk_box_pack_start (GTK_BOX(vbox), check_case_sensitive, FALSE, FALSE, 0); + + /* checkbox to allow pcre-compatible pattern search */ + check_regex_mode = gtk_check_button_new_with_mnemonic ("Use _regular expressions"); + gtk_box_pack_start (GTK_BOX(vbox), check_regex_mode, FALSE, FALSE, 0); } - + /* results frame not yet created! */ if (!frame_results) { frame_results = gtk_frame_new ("Results"); - + /* a box */ GtkWidget* vbox = gtk_vbox_new (FALSE, 1); gtk_container_set_border_width (GTK_CONTAINER(vbox), 5); gtk_container_add (GTK_CONTAINER(frame_results), vbox); - + /* create a scrolled window (for the treeview) */ GtkWidget* scroll = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), - GTK_SHADOW_ETCHED_IN); + GTK_SHADOW_ETCHED_IN); gtk_box_pack_start (GTK_BOX(vbox), scroll, FALSE, FALSE, 0); - + /* create a treeview */ results_treeview = gtk_tree_view_new (); gtk_container_add (GTK_CONTAINER(scroll), results_treeview); - + GtkCellRenderer* renderer = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(results_treeview), -1, "found", renderer, "text", 0, NULL); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(results_treeview), FALSE); - + /* register handlers */ g_signal_connect (G_OBJECT(results_treeview), "row-activated", GTK_SIGNAL_FUNC(signal_row_activated), NULL); } - + /* replace frame not yet created! */ if (!frame_replace) { frame_replace = gtk_frame_new ("Replace"); - + /* a box */ GtkWidget* vbox = gtk_vbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER(vbox), 5); gtk_container_add (GTK_CONTAINER(frame_replace), vbox); - + /* create a text entry for replacement word */ entry_replace = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY(entry_replace), TRUE); gtk_box_pack_start (GTK_BOX(vbox), entry_replace, FALSE, FALSE, 0); - + /* a checkbox for replace_all */ check_replace_all = gtk_check_button_new_with_mnemonic ("Replace _all"); gtk_box_pack_start (GTK_BOX(vbox), check_replace_all, FALSE, FALSE, 0); } - + /* create the window if not done so already */ if (!search_window) { - /* new dialog window */ + /* new dialog window */ search_window = gtk_dialog_new (); gtk_window_set_modal (GTK_WINDOW(search_window), TRUE); gtk_window_set_resizable (GTK_WINDOW(search_window), FALSE); - + /* new virtual box for the upper part of the dialog */ GtkWidget* vbox = gtk_vbox_new (TRUE, 5); - gtk_box_pack_start (GTK_BOX(GTK_DIALOG(search_window)->vbox), + gtk_box_pack_start (GTK_BOX(GTK_DIALOG(search_window)->vbox), vbox, FALSE, FALSE, 0); - + /* window is modal for main window */ gtk_window_set_modal(GTK_WINDOW(search_window), TRUE); gtk_window_set_transient_for (GTK_WINDOW(search_window), GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(MainNotebook)))); - + /* cancel button */ GtkWidget* button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); @@ -429,33 +481,33 @@ void search (gboolean replace) g_signal_connect (G_OBJECT(search_window), "close", GTK_SIGNAL_FUNC(gtk_widget_hide), search_window); g_signal_connect (G_OBJECT(search_window), "response", - GTK_SIGNAL_FUNC(gtk_widget_hide), search_window); + GTK_SIGNAL_FUNC(gtk_widget_hide), search_window); g_signal_connect_swapped (G_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide), search_window); } - - /* remove the widgets from the boxes before reattaching them */ + + /* remove the widgets from the boxes before reattaching them */ if (frame_search->parent == GTK_WIDGET(GTK_DIALOG(search_window)->vbox)) { g_object_ref (frame_search); /* attach reference on it or it will be deleted */ gtk_container_remove (GTK_CONTAINER(GTK_DIALOG(search_window)->vbox), frame_search); } - + if (frame_replace->parent == GTK_WIDGET(GTK_DIALOG(search_window)->vbox)) { g_object_ref (frame_replace); /* attach reference on it or it will be deleted */ gtk_container_remove (GTK_CONTAINER(GTK_DIALOG(search_window)->vbox), frame_replace); } - + if (frame_results->parent == GTK_WIDGET(GTK_DIALOG(search_window)->vbox)) { g_object_ref (frame_results); /* attach reference on it or it will be deleted */ gtk_container_remove (GTK_CONTAINER(GTK_DIALOG(search_window)->vbox), frame_results); } - + /* choose both frames and attach them to the boxes */ gtk_box_pack_start (GTK_BOX(GTK_DIALOG(search_window)->vbox), frame_search, TRUE, TRUE, 0); if (replace) { gtk_window_set_title (GTK_WINDOW (search_window), "Search and Replace Text"); gtk_box_pack_start (GTK_BOX(GTK_DIALOG(search_window)->vbox), frame_replace, TRUE, TRUE, 0); - + /* create a find&replace button */ gtk_widget_destroy (button_find); button_find = gtk_button_new_from_stock (GTK_STOCK_FIND_AND_REPLACE); @@ -477,14 +529,14 @@ void search (gboolean replace) g_signal_connect_swapped (G_OBJECT(button_find), "clicked", GTK_SIGNAL_FUNC(find), NULL); } - + /* clear the text entry fields */ gtk_entry_set_text (GTK_ENTRY(entry_search), ""); gtk_entry_set_text (GTK_ENTRY(entry_replace), ""); - + /* clear the list */ gtk_tree_view_set_model (GTK_TREE_VIEW(results_treeview), NULL); - + /* show the window */ gtk_widget_show_all (search_window); } @@ -507,7 +559,7 @@ void goto_line (void) /* spin box */ entry_line = gtk_spin_button_new_with_range (1, 999, 1); - gtk_box_pack_start (GTK_BOX(GTK_DIALOG(goto_window)->vbox), + gtk_box_pack_start (GTK_BOX(GTK_DIALOG(goto_window)->vbox), entry_line, FALSE, FALSE, 0); /* cancel button */ @@ -517,7 +569,7 @@ void goto_line (void) button, TRUE, TRUE, 0); g_signal_connect_swapped (G_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide), goto_window); - + /* goto button */ button = gtk_button_new_from_stock (GTK_STOCK_JUMP_TO); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); @@ -534,15 +586,15 @@ void goto_line (void) g_signal_connect (G_OBJECT(goto_window), "close", GTK_SIGNAL_FUNC(gtk_widget_hide), goto_window); g_signal_connect (G_OBJECT(goto_window), "response", - GTK_SIGNAL_FUNC(gtk_widget_hide), goto_window); + GTK_SIGNAL_FUNC(gtk_widget_hide), goto_window); } - + /* adjust range of spin box, according to text size */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); GtkTextBuffer* buffer = FPROPS(current_page, Buffer); gint lines = gtk_text_buffer_get_line_count (buffer); gtk_spin_button_set_range (GTK_SPIN_BUTTON(entry_line), 1, lines); - + /* show the window */ gtk_widget_show_all (goto_window); } Index: src/api/api.h =================================================================== RCS file: /sources/beaver/beaver0.4.0/src/api/api.h,v retrieving revision 1.15 diff -u -u -p -r1.15 api.h --- src/api/api.h 14 Dec 2008 16:07:55 -0000 1.15 +++ src/api/api.h 22 Dec 2008 02:20:15 -0000 @@ -38,7 +38,7 @@ gchar* beaver_box_prompt_impl (gchar* me gchar* beaver_box_file_selection_impl (gchar* title, GtkFileChooserAction action); /* ui */ -gint beaver_ui_item_add_impl (enum BeaverMenuSection section, +gint beaver_ui_item_add_impl (enum BeaverMenuSection section, const gchar* stock_id, const gchar* name, const gchar* text, void (*callback)(void)); gint beaver_ui_item_submenu_add_impl (enum BeaverMenuSection section, const gchar* name, const gchar* text); @@ -53,5 +53,7 @@ void beaver_text_selection_set_impl (con enum BeaverTextFormat beaver_text_format_impl (void); void beaver_text_replace_impl (const gchar* needle, const gchar* substitute, gboolean sensitive); gboolean beaver_text_find_impl (const gchar* needle, guint offset, gboolean sensitive); +BeaverRegexResult *beaver_text_find_regex_impl (const gchar* pattern, guint offset, gboolean sensitive); +void beaver_text_replace_regex_impl (const gchar* pattern, const gchar* substitute, gboolean sensitive, gboolean all); #endif /* __API_H_ */ Index: src/api/beaver.h =================================================================== RCS file: /sources/beaver/beaver0.4.0/src/api/beaver.h,v retrieving revision 1.17 diff -u -u -p -r1.17 beaver.h --- src/api/beaver.h 14 Dec 2008 16:07:55 -0000 1.17 +++ src/api/beaver.h 22 Dec 2008 02:20:15 -0000 @@ -35,7 +35,7 @@ /** * Creates a function that returns a string identifying * the author of this plugin. - * + * * @param name_string name of the author */ #define PLUGIN_AUTHOR(name_string) \ @@ -47,7 +47,7 @@ gchar* __plugin_author (void) \ /** * Creates a function that returns a string identifying * the version of this plugin - * + * * @param version_string version */ #define PLUGIN_VERSION(version_string) \ @@ -58,7 +58,7 @@ gchar* __plugin_version (void) \ /** * Creates a function that calls a function for initialization - * + * * @param func_handler pointer to function that should * be called. */ @@ -70,7 +70,7 @@ void __plugin_init (void) \ /** * Creates a function that calls a function for cleanup - * + * * @param func_handler pointer to function that should * be called. */ @@ -83,7 +83,7 @@ void __plugin_cleanup (void) \ /** * Creates a function that returns a string identifying * the name of this plugin - * + * * @param name_string name of this plugin */ #define PLUGIN_NAME(name_string) \ @@ -95,7 +95,7 @@ gchar* __plugin_name (void) \ /** * Creates a function that returns a string identifying * a short description about this plugin. - * + * * @param descr_string a short description */ #define PLUGIN_DESCRIPTION(descr_string) \ @@ -108,7 +108,7 @@ gchar* __plugin_description (void) \ * Creates a function that calls a function when * the preferences button in the plugin manager * was clicked. - * + * * @param func_handler pointer to function that should * be called. */ @@ -135,7 +135,7 @@ gchar* (*beaver_box_file_selection) (gch /** * the different menu sections. - * + * * @param BEAVER_SECTION_MENU_TOOLS * @param BEAVER_SECTION_MENU_VIEW * @param BEAVER_SECTION_MENU_EDIT @@ -150,9 +150,9 @@ enum BeaverMenuSection }; /** @see src/api/menu.c */ -gint (*beaver_ui_item_add) (enum BeaverMenuSection section, const gchar* name, +gint (*beaver_ui_item_add) (enum BeaverMenuSection section, const gchar* name, const gchar* stock_id, const gchar* text, void (*callback)(void)); - + /** @see src/api/menu.c */ gint (*beaver_ui_item_submenu_add) (enum BeaverMenuSection section, const gchar* name, const gchar* text); @@ -168,13 +168,13 @@ void (*beaver_text_insert_string) (const /** * A structure holding the position of the selection. - * + * * @param line the line the selection is in * @param start the start of the selection (according to line) * @param end the end of the selection (according to line) - * @param offset start of the selection (according to whole document) + * @param offset start of the selection (according to whole document) */ -struct beaver_text_selection_s +struct beaver_text_selection_s { gint line; gint start; @@ -183,6 +183,19 @@ struct beaver_text_selection_s }; typedef struct beaver_text_selection_s BeaverTextSelection; +/** + * A structure that holds the regex testing results + * + * @param count the number of elements in results + * @param results an BeaverTextSelection array + */ +struct beaver_regex_result_s +{ + gint count; + BeaverTextSelection* results; +}; +typedef struct beaver_regex_result_s BeaverRegexResult; + /** @see src/api/text.c */ BeaverTextSelection* (*beaver_text_selection_position) (void); @@ -192,9 +205,9 @@ gchar* (*beaver_text_selection_get) (voi /** @see src/api/text.c */ void (*beaver_text_selection_set) (const gchar* text); -/** +/** * the different text formats - * + * * @param BEAVER_FORMAT_UNIX * @param BEAVER_FORMAT_MAC * @param BEAVER_FORMAT_DOS @@ -215,4 +228,10 @@ void (*beaver_text_replace) (const gchar /** @see src/api/text.c */ gboolean (*beaver_text_find) (const gchar* needle, guint offset, gboolean sensitive); +/** @see src/api/text.c */ +BeaverRegexResult* (*beaver_text_find_regex) (const gchar* pattern, guint offset, gboolean sensitive); + +/** @see src/api/text.c */ +void (*beaver_text_replace_regex) (const gchar* pattern, const gchar* substitute, gboolean sensitive, gboolean all); + #endif /* __BEAVER_H_ */ Index: src/api/text.c =================================================================== RCS file: /sources/beaver/beaver0.4.0/src/api/text.c,v retrieving revision 1.9 diff -u -u -p -r1.9 text.c --- src/api/text.c 14 Dec 2008 16:07:56 -0000 1.9 +++ src/api/text.c 22 Dec 2008 02:20:15 -0000 @@ -48,23 +48,23 @@ extern GArray *FileProperties; * Insert text at current cursos position. If no text/cursor position * is avaible then ignore insert. Also if text is read-only, ignore * the call. - * + * * @param text string to be inserted */ void beaver_text_insert_string_impl (const gchar* text) { /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - - /* if no page is open (ie. no files are open) or + + /* if no page is open (ie. no files are open) or * the file is read-only, then abort */ if (!(OpenedFilesCnt >= 0) || FPROPS(current_page, ReadOnly)) { return; } - + /* get the buffer to write into */ GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - + /* insert the text */ gtk_text_buffer_insert_at_cursor (buffer, text, strlen (text)); } @@ -78,65 +78,65 @@ BeaverTextSelection* beaver_text_selecti { /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - + /* if no page is avaiable, so no text is avaiable, * therefore return NULL */ if (!(OpenedFilesCnt >= 0)) { return NULL; } - + /* get the text buffer */ GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - + /* if no selection is avaiable, then return NULL */ if (!gtk_text_buffer_get_has_selection (buffer)) { return NULL; } - + /* try to load cursors from selection */ GtkTextIter start, end; gtk_text_buffer_get_selection_bounds (buffer, &start, &end); - + /* new object to return */ BeaverTextSelection* result = g_malloc (sizeof (BeaverTextSelection)); result->start = gtk_text_iter_get_line_offset (&start) + 1; result->end = gtk_text_iter_get_line_offset (&end) + 1; result->line = gtk_text_iter_get_line (&start) + 1; result->offset = gtk_text_iter_get_offset (&start) + 1; - - return result; + + return result; } /** * Get the text that was selected. Returns NULL if no text was * selected or if no text is avaiable. The returned string * should be freed after usage. - * + * * @returns selected text. should be freed after usage. */ gchar* beaver_text_selection_get_impl (void) { /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - + /* if no page is avaiable, so no text is avaiable, * therefore return NULL */ if (!(OpenedFilesCnt >= 0)) { return NULL; } - + /* get the text buffer */ GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - + /* if no selection is avaiable, then return NULL */ if (!gtk_text_buffer_get_has_selection (buffer)) { return NULL; } - + /* try to load cursors from selection */ GtkTextIter start, end; gtk_text_buffer_get_selection_bounds (buffer, &start, &end); - + /* return selection text */ return gtk_text_buffer_get_text (buffer, &start, &end, FALSE); } @@ -146,23 +146,23 @@ gchar* beaver_text_selection_get_impl (v * is selected then just insert the text at the current cursor * position. If no text is avaiable or text is read-only * then ignore the call. - * + * * @param text the text to be inserted into the selection */ void beaver_text_selection_set_impl (const gchar* text) { /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - - /* if no page is open (ie. no files are open) or + + /* if no page is open (ie. no files are open) or * the file is read-only, then abort */ if (!(OpenedFilesCnt >= 0) || FPROPS(current_page, ReadOnly)) { return; } - + /* get the buffer to write into */ GtkTextBuffer* buffer = FPROPS(current_page, Buffer); - + /* if there's a selection, remove it, and set the cursor * right, so if we then insert the text, it has the feeling * as if we overwritten the selection. */ @@ -171,7 +171,7 @@ void beaver_text_selection_set_impl (con gtk_text_buffer_get_selection_bounds (buffer, &start, &end); gtk_text_buffer_delete (buffer, &start, &end); } - + /* insert the text at the current cursor position. */ beaver_text_insert_string (text); } @@ -179,7 +179,7 @@ void beaver_text_selection_set_impl (con /** * Returns the format of the text. The format revers to the * line-break type of the different OS's. - * + * * @retval 0 UNIX line-break * @retval 2 DOS line-break * @retval 1 MAC line-break @@ -194,11 +194,11 @@ enum BeaverTextFormat beaver_text_format if (!(OpenedFilesCnt >= 0)) { return -1; } - + /* get the text out of the current page */ GtkTextIter start, end; gtk_text_buffer_get_bounds (FPROPS(current_page, Buffer), &start, &end); - gchar* string = gtk_text_buffer_get_slice(FPROPS(current_page, Buffer), + gchar* string = gtk_text_buffer_get_slice(FPROPS(current_page, Buffer), &start, &end, FALSE); /* try to determine the type */ @@ -209,10 +209,10 @@ enum BeaverTextFormat beaver_text_format rv = BEAVER_FORMAT_MAC; else rv = BEAVER_FORMAT_UNIX; /* default is UNIX */ - + /* free up space */ g_free (string); - + return rv; } @@ -220,7 +220,7 @@ enum BeaverTextFormat beaver_text_format * Searches for needle in the text and replaces * it with subsitute. Replaces all occurences of * needle. - * + * * @param needle the search string to replace * @param substitute the replacement of found needle * @param sensitive wheter or not to search case sensitive @@ -229,13 +229,13 @@ void beaver_text_replace_impl (const gch { /* get the current page that should be edited */ gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); - - /* if no page is open (ie. no files are open) or + + /* if no page is open (ie. no files are open) or * the file is read-only, then abort */ if (!(OpenedFilesCnt >= 0) || FPROPS(current_page, ReadOnly)) { return; } - + /* search for the needle. if found then replace it with substitute * and continue searching until nothing can be found */ guint m = strlen (needle); @@ -244,14 +244,14 @@ void beaver_text_replace_impl (const gch /* try to load cursors from selection */ GtkTextIter start, end; gtk_text_buffer_get_selection_bounds (FPROPS(current_page, Buffer), &start, &end); - + /* move the offset */ offset = gtk_text_iter_get_offset (&start) + m + 1; - + /* replace selection */ beaver_text_selection_set (substitute); } - + /* the replacement could have changed something * about the format, so try to get it once more. */ FPROPS(current_page, Format) = beaver_text_format (); @@ -265,7 +265,7 @@ void beaver_text_replace_impl (const gch /** * Calculates the shift table for the "bad character" strategy * of boyer-moore. Helper function for beaver_text_find_impl. - * + * * @param needle the search string, for which to prepare the table * @param table a pointer to preallocated memory, where to put in * the table @@ -274,20 +274,20 @@ static inline void occurence (const gcha { /* get the size of the needle */ gint len = strlen (needle); - + /* set all shift length to the size of the * needle. */ gint i; for (i=0;i= 0)) { return FALSE; } - + /* get the text out of the current page */ GtkTextIter start, end; gtk_text_buffer_get_bounds (FPROPS(current_page, Buffer), &start, &end); - gchar* text = gtk_text_buffer_get_slice(FPROPS(current_page, Buffer), + gchar* text = gtk_text_buffer_get_slice(FPROPS(current_page, Buffer), &start, &end, FALSE); /* if there's no text avaiable so we can stop @@ -338,11 +338,11 @@ gboolean beaver_text_find_impl (const gc if (text == NULL) { return FALSE; } - + /* preprocess */ gint occurence_table[SEARCH_ALPHABET_SIZE]; occurence (needle, occurence_table); - + /* the result */ gboolean result = FALSE; @@ -355,17 +355,17 @@ gboolean beaver_text_find_impl (const gc gchar c = text[i + m - 1]; if (needle[m - 1] == c && /* compare last character of the needle with the text character */ - + /* compare the rest of the pattern. either search case sensitive - * or not */ + * or not */ ((sensitive && memcmp (needle, text+i, m-1) == 0) || - (!sensitive && g_ascii_strncasecmp (needle, text+i, m-1) == 0))) { + (!sensitive && g_ascii_strncasecmp (needle, text+i, m-1) == 0))) { /* select the occurence */ gtk_text_iter_set_offset (&start, i); gtk_text_iter_set_offset (&end, i+m); gtk_text_buffer_select_range (FPROPS(current_page, Buffer), &start, &end); - + /* mark result as TRUE */ result = TRUE; @@ -381,6 +381,192 @@ gboolean beaver_text_find_impl (const gc /* free up space */ g_free (text); - + return result; } + +/** + * Tests the given pattern againts the text. If the function find something + * it returns a BeaverRegexResult which holds offsets for each result. + * + * The pattern testing is done using glib's internal pcre-compatible functions. + * + * @param pattern the perl-compatible pattern to be tested against the current document + * @param offset where in the text to begin to search (0 for beginning + * of text) + * @param sensitive wheter or not to search case sensitive + * @returns NULL if nothing is found or a pointer to the regex results structure + * (dont forget to free it when you dont need it anymore). + */ +BeaverRegexResult *beaver_text_find_regex_impl (const gchar* pattern, guint offset, gboolean sensitive) +{ + /* get the current page that should be edited */ + gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); + + /* stop if theres no open file */ + if (!(OpenedFilesCnt >= 0)) { + return NULL; + } + + /* get the text out of the current page */ + GtkTextIter start, end; + + gtk_text_buffer_get_end_iter (FPROPS(current_page, Buffer), &end); + + /* if offset doesnt exist, we stop here */ + if (offset > gtk_text_iter_get_offset(&end)) + return NULL; + + gtk_text_buffer_get_iter_at_offset (FPROPS(current_page, Buffer), &start, offset); + + gchar* text = gtk_text_buffer_get_slice(FPROPS(current_page, Buffer), + &start, &end, FALSE); + + /* theres no text, so we stop */ + if (text == NULL) { + return NULL; + } + + GRegex *regex; + GError *error = NULL; + + /* pattern compiling options. multiline is default. */ + guint options = G_REGEX_MULTILINE + (sensitive ? 0 : G_REGEX_CASELESS); + + GtkTextIter *iter; + + /* this structure holds information about the results */ + GMatchInfo *matchinf; + + /* the results (doh!) */ + BeaverRegexResult *result; + + /* compiles the pattern and creates a 'instance' of the GRegex structure */ + regex = g_regex_new(pattern, options, 0, &error); + + /* if some error has happened, free the used resources and stop */ + if (error) { + /* Show some message to the user, the line bellow is just for debugging*/ + g_print("g_regex_new() error: %s\n", error->message); + + g_free(regex); + g_free(text); + return NULL; + } + + /* if no match is found, stop. do not allow empty matches */ + if (!g_regex_match(regex, text, G_REGEX_MATCH_NOTEMPTY, &matchinf)) { + g_free(regex); + g_free (text); + return NULL; + } + + /* initializes the result */ + result = g_new(BeaverRegexResult, 1); + result->results = g_new(BeaverTextSelection, 1); + result->count = 0; + + iter = g_new(GtkTextIter, 1); + + gint i = 0, start_o, end_o; + + /* loop while there are matches left */ + while (g_match_info_matches(matchinf)) { + result->results = g_renew (BeaverTextSelection, result->results, i+1); + g_match_info_fetch_pos(matchinf, 0, &start_o, &end_o); + + gtk_text_buffer_get_iter_at_offset(FPROPS(current_page, Buffer), + iter, start_o); + + result->results[i].line = gtk_text_iter_get_line(iter)+1; + result->results[i].start = gtk_text_iter_get_line_offset(iter); + + gtk_text_buffer_get_iter_at_offset(FPROPS(current_page, Buffer), + iter, end_o); + + result->results[i].end = gtk_text_iter_get_line_offset(iter); + result->results[i].offset = start_o+1; + + g_match_info_next(matchinf, NULL); + i++; + } + + /* free the used resources */ + g_free (text); + g_free(matchinf); + g_free(regex); + g_free(iter); + + result->count = i; + + return (!result->count ? NULL : result); +} + +/** + * Searches for needle in the text and replaces + * it with subsitute. Replaces all occurences of + * needle. + * + * @param needle the search pattern + * @param substitute the replacement of found matches + * @param sensitive wheter or not to search case sensitive + * @param all wheter or not replace all + */ +void beaver_text_replace_regex_impl (const gchar* pattern, const gchar* substitute, gboolean sensitive, gboolean all) +{ + /* get the current page that should be edited */ + gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); + + /* no open file or file is read-only */ + if (!(OpenedFilesCnt >= 0) || FPROPS(current_page, ReadOnly)) { + return; + } + + /* get the text out of the current page */ + GtkTextIter start, end; + + gtk_text_buffer_get_bounds (FPROPS(current_page, Buffer), &start, &end); + + gchar* text = gtk_text_buffer_get_slice(FPROPS(current_page, Buffer), &start, &end, FALSE); + + /* theres no text, so we stop */ + if (text == NULL) { + return; + } + + GRegex *regex; + GError *error = NULL; + + /* pattern compiling options. multiline is default. */ + guint options = G_REGEX_MULTILINE + (sensitive ? 0 : G_REGEX_CASELESS); + + /* compiles the pattern and creates a 'instance' of the GRegex structure */ + regex = g_regex_new(pattern, options, 0, &error); + + /* if some error has happened, free the used resources and stop */ + if (error) { + /* Show some message to the user, the line bellow is just for debugging*/ + g_print("g_regex_new() error: %s\n", error->message); + + g_free(regex); + return; + } + + error = NULL; + + gchar *new_text; + + new_text = g_regex_replace(regex, text, strlen(text), 0, substitute, G_REGEX_MATCH_NOTEMPTY, &error); + new_text = g_utf8_normalize(new_text, strlen(new_text), G_NORMALIZE_DEFAULT); + gtk_text_buffer_set_text(FPROPS(current_page, Buffer), new_text, strlen(new_text)); + + if (error) + { + /* Show some message to the user, the line bellow is just for debugging*/ + g_print("g_regex_replace_eval() error: %s\n", error->message); + g_free(regex); + return; + } + + FPROPS(current_page, Format) = beaver_text_format (); +}