[anjuta] dir-project: Use regular expression and add object node
- From: Sebastien Granjoux <sgranjoux src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta] dir-project: Use regular expression and add object node
- Date: Sat, 4 Jun 2011 15:06:44 +0000 (UTC)
commit 1f1a28e466556e6573a2605ce96d4825425eaf7a
Author: Sébastien Granjoux <seb sfo free fr>
Date: Sat Jun 4 15:58:25 2011 +0200
dir-project: Use regular expression and add object node
plugins/dir-project/dir-node.c | 51 ++++++-
plugins/dir-project/dir-node.h | 8 +
plugins/dir-project/dir-project.c | 339 +++++++++++++++++++++++--------------
plugins/dir-project/sources.list | 16 +-
4 files changed, 280 insertions(+), 134 deletions(-)
---
diff --git a/plugins/dir-project/dir-node.c b/plugins/dir-project/dir-node.c
index 019fc79..9c76d71 100644
--- a/plugins/dir-project/dir-node.c
+++ b/plugins/dir-project/dir-node.c
@@ -76,7 +76,7 @@ anjuta_dir_root_node_class_init (AnjutaDirRootNodeClass *klass)
-/* Group objects
+/* Group node
*---------------------------------------------------------------------------*/
struct _AnjutaDirGroupNode {
@@ -172,8 +172,55 @@ anjuta_dir_group_node_class_init (AnjutaDirGroupNodeClass *klass)
object_class->finalize = anjuta_dir_group_node_finalize;
}
+/* Object node
+ *---------------------------------------------------------------------------*/
+
+struct _AnjutaDirObjectNode {
+ AnjutaProjectNode base;
+};
+
+
+AnjutaProjectNode*
+dir_object_node_new (GFile *file)
+{
+ AnjutaDirObjectNode *node = NULL;
+
+ node = g_object_new (ANJUTA_TYPE_DIR_OBJECT_NODE, NULL);
+ node->base.type = ANJUTA_PROJECT_OBJECT;
+ node->base.native_properties = NULL;
+ node->base.custom_properties = NULL;
+ node->base.name = NULL;
+ node->base.file = g_file_dup (file);
+ node->base.state = ANJUTA_PROJECT_CAN_REMOVE |
+ ANJUTA_PROJECT_REMOVE_FILE;
+
+ return ANJUTA_PROJECT_NODE (node);
+}
+
+/* GObjet implementation
+ *---------------------------------------------------------------------------*/
+
+typedef struct _AnjutaDirObjectNodeClass AnjutaDirObjectNodeClass;
+
+struct _AnjutaDirObjectNodeClass {
+ AnjutaProjectNodeClass parent_class;
+};
+
+G_DEFINE_TYPE (AnjutaDirObjectNode, anjuta_dir_object_node, ANJUTA_TYPE_PROJECT_NODE);
+
+static void
+anjuta_dir_object_node_init (AnjutaDirObjectNode *node)
+{
+}
+
+static void
+anjuta_dir_object_node_class_init (AnjutaDirObjectNodeClass *klass)
+{
+}
+
+
-/* Source object
+/* Source node
*---------------------------------------------------------------------------*/
struct _AnjutaDirSourceNode {
diff --git a/plugins/dir-project/dir-node.h b/plugins/dir-project/dir-node.h
index 3aca209..3765e1d 100644
--- a/plugins/dir-project/dir-node.h
+++ b/plugins/dir-project/dir-node.h
@@ -42,6 +42,12 @@ typedef struct _AnjutaDirGroupNode AnjutaDirGroupNode;
GType anjuta_dir_group_node_get_type (void) G_GNUC_CONST;
+#define ANJUTA_TYPE_DIR_OBJECT_NODE (anjuta_dir_object_node_get_type ())
+#define ANJUTA_DIR_OBJECT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANJUTA_TYPE_DIR_OBJECT_NODE, AnjutaDirObjectNode))
+
+typedef struct _AnjutaDirObjectNode AnjutaDirObjectNode;
+GType anjuta_dir_object_node_get_type (void) G_GNUC_CONST;
+
#define ANJUTA_TYPE_DIR_SOURCE_NODE (anjuta_dir_source_node_get_type ())
#define ANJUTA_DIR_SOURCE_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANJUTA_TYPE_DIR_SOURCE_NODE, AnjutaDirSourceNode))
@@ -55,6 +61,8 @@ AnjutaProjectNode* dir_root_node_new (GFile *file);
AnjutaProjectNode *dir_group_node_new (GFile *file, GObject *emitter);
+AnjutaProjectNode *dir_object_node_new (GFile *file);
+
AnjutaProjectNode *dir_source_node_new (GFile *file);
diff --git a/plugins/dir-project/dir-project.c b/plugins/dir-project/dir-project.c
index 5dcff45..535064a 100644
--- a/plugins/dir-project/dir-project.c
+++ b/plugins/dir-project/dir-project.c
@@ -44,7 +44,7 @@
#include <gio/gio.h>
#include <glib.h>
-#define SOURCES_FILE PACKAGE_DATA_DIR"/sources.list"
+#define SOURCES_FILE PACKAGE_DATA_DIR "/sources.list"
struct _DirProject {
GObject parent;
@@ -79,10 +79,10 @@ typedef struct _DirPattern DirPattern;
struct _DirPattern
{
- GList *names;
gboolean match;
- gboolean local;
gboolean directory;
+ GRegex *source;
+ gchar *object;
};
/* A list of pattern found in one file */
@@ -146,6 +146,29 @@ project_node_new (DirProject *project, AnjutaProjectNode *parent, AnjutaProjectN
node = dir_group_node_new (file, G_OBJECT (project));
}
break;
+ case ANJUTA_PROJECT_OBJECT:
+ if (file == NULL)
+ {
+ if (name == NULL)
+ {
+ g_set_error (error, IANJUTA_PROJECT_ERROR,
+ IANJUTA_PROJECT_ERROR_VALIDATION_FAILED,
+ _("Missing name"));
+ }
+ else
+ {
+ GFile *object_file;
+
+ object_file = g_file_get_child (anjuta_project_node_get_file (parent), name);
+ node = dir_object_node_new (object_file);
+ g_object_unref (object_file);
+ }
+ }
+ else
+ {
+ node = dir_object_node_new (file);
+ }
+ break;
case ANJUTA_PROJECT_SOURCE:
if (file == NULL)
{
@@ -186,83 +209,25 @@ project_node_new (DirProject *project, AnjutaProjectNode *parent, AnjutaProjectN
}
-/* File name objects
+/* Pattern objects
*---------------------------------------------------------------------------*/
-static DirMatchString*
-dir_match_string_new (gchar *string)
-{
- DirMatchString *str = NULL;
-
- str = g_slice_new0(DirMatchString);
- str->length = strlen (string);
- str->string = string;
- str->reverse = g_strreverse(g_strdup (string));
-
- return str;
-}
-
static void
-dir_match_string_free (DirMatchString *str)
-{
- g_free (str->string);
- g_free (str->reverse);
- if (str->file) g_object_unref (str->file);
- g_slice_free (DirMatchString, str);
-}
-
-/* Cut a filename is part representing one directory or file name. By example
- * /home/user/project/foo will be generate a list containing:
- * foo, project, user, home */
-static GList*
-dir_cut_filename (GFile *file)
+dir_pattern_free (DirPattern *pat)
{
- GList *name_list = NULL;
-
- g_object_ref (file);
- do
- {
- DirMatchString *str;
- gchar *name = g_file_get_basename (file);
-
- if (strcmp(name, G_DIR_SEPARATOR_S) == 0)
- {
- g_free (name);
- g_object_unref (file);
- break;
- }
-
- str = dir_match_string_new (name);
- str->file = file;
-
- name_list = g_list_prepend (name_list, str);
-
- file = g_file_get_parent (file);
- }
- while (file != NULL);
+ if (pat->source != NULL) g_regex_unref (pat->source);
+ g_free (pat->object);
- name_list = g_list_reverse (name_list);
-
- return name_list;
-}
-
-static void
-dir_filename_free (GList *name)
-{
- g_list_foreach (name, (GFunc)dir_match_string_free, NULL);
- g_list_free (name);
+ g_slice_free (DirPattern, pat);
}
-/* Pattern objects
- *---------------------------------------------------------------------------*/
-
/* Create a new pattern matching a directory of a file name in a path */
static DirPattern*
dir_pattern_new (const gchar *pattern, gboolean reverse)
{
DirPattern *pat = NULL;
- GString *str = g_string_new (NULL);
+ GString *regex = g_string_new (NULL);
const char *ptr = pattern;
pat = g_slice_new0(DirPattern);
@@ -276,52 +241,127 @@ dir_pattern_new (const gchar *pattern, gboolean reverse)
{
pat->match = reverse ? FALSE : TRUE;
}
+
/* Check if the pattern is local */
if (*ptr == '/')
{
- pat->local = TRUE;
+ g_string_append_c (regex, '^');
ptr++;
}
else
{
- pat->local = FALSE;
+ g_string_append (regex, "(?:^|\\" G_DIR_SEPARATOR_S ")");
}
- pat->names = NULL;
+
while (*ptr != '\0')
{
- const gchar *next = strchr (ptr, '/');
+ const gchar *next;
- if (next == NULL)
+ next = ptr + strcspn (ptr, "\\:.^$[|()?*+{");
+
+ g_string_append_len (regex, ptr, next - ptr);
+ ptr = next;
+ if (*ptr == ':')
{
- pat->names = g_list_prepend (pat->names, g_pattern_spec_new (ptr));
+ /* Remaining data are for object */
break;
}
- else
+ else if (*ptr == '*')
{
- if (next != ptr)
+ /* Replace with corresponding regular expression */
+ g_string_append (regex, "(.+)");
+ ptr++;
+ }
+ else if (*ptr == '?')
+ {
+ /* Replace with corresponding regular expression */
+ do
+ {
+ ptr++;
+ } while (*ptr == '?');
+ g_string_append_printf (regex, "(.{%d})", ptr - next);
+ }
+ else if (*ptr == '\\')
+ {
+ /* Add next character without a special signification */
+ g_string_append_c (regex, *ptr++);
+ if (*ptr != '\0') g_string_append_c (regex, *ptr++);
+ }
+ else if (isspace (*ptr))
+ {
+ /* Skip space */
+ continue;
+ }
+ else if (*ptr != '\0')
+ {
+ /* Automatically escape character if not done */
+ if ((ptr == pattern) || (*(ptr - 1) != '\\'))
{
- g_string_overwrite_len (str, 0, ptr, next - ptr);
- pat->names = g_list_prepend (pat->names, g_pattern_spec_new (str->str));
+ g_string_append_c (regex, '\\');
}
- ptr = next + 1;
+ g_string_append_c (regex, *ptr++);
}
}
- g_string_free (str, TRUE);
+ if ((regex->len > 1) && (regex->str[regex->len - 1] == '/'))
+ {
+ /* Match directory only */
+ pat->directory = TRUE;
+ g_string_truncate (regex, regex->len - 1);
+ }
+ g_string_append_c (regex, '$');
+ pat->source = g_regex_new (regex->str, 0, 0, NULL);
+ if (pat->source == NULL)
+ {
+ dir_pattern_free (pat);
+ pat = NULL;
+ }
- /* Check if the pattern has to match a directory */
- pat->directory = (ptr != pattern) && (*(ptr-1) == '/');
+ if ((pat != NULL) && (*ptr == ':'))
+ {
+ g_string_truncate (regex, 0);
- return pat;
-}
+ ptr++;
+ while (isspace (*ptr)) ptr++;
-static void
-dir_pattern_free (DirPattern *pat)
-{
- g_list_foreach (pat->names, (GFunc)g_pattern_spec_free, NULL);
- g_list_free (pat->names);
-
- g_slice_free (DirPattern, pat);
+ while (*ptr != '\0')
+ {
+ const gchar *next;
+ gint replace = 1;
+
+ next = ptr + strcspn (ptr, "\\?*");
+
+ g_string_append_len (regex, ptr, next - ptr);
+ ptr = next;
+ if (*ptr == '*')
+ {
+ /* Replace with corresponding replacement */
+ g_string_append_printf (regex, "\\%d", replace++);
+ ptr++;
+ }
+ else if (*ptr == '?')
+ {
+ do
+ {
+ ptr++;
+ } while (*ptr == '?');
+ g_string_append_printf (regex, "\\%d", replace++);
+ }
+ else if (*ptr == '\\')
+ {
+ /* Add next character without a special signification */
+ g_string_append_c (regex, *ptr++);
+ if (*ptr != '\0') g_string_append_c (regex, *ptr++);
+ }
+ }
+ pat->object = g_string_free (regex, FALSE);
+ }
+ else
+ {
+ g_string_free (regex, TRUE);
+ }
+
+ return pat;
}
/* Read a file containing pattern, the syntax is similar to .gitignore file.
@@ -339,6 +379,7 @@ dir_pattern_free (DirPattern *pat)
* and add pattern afterward to remove some of these files.
* A name starting with # is a comment.
* All spaces at the beginning of a name are ignored.
+ * If a name is followed by : a following name is taken as the object file name
*/
static GList*
dir_push_pattern_list (GList *stack, GFile *dir, GFile *file, gboolean ignore, GError **error)
@@ -346,7 +387,7 @@ dir_push_pattern_list (GList *stack, GFile *dir, GFile *file, gboolean ignore, G
char *content;
char *ptr;
DirPatternList *list = NULL;
-
+ guint line;
if (!g_file_load_contents (file, NULL, &content, NULL, NULL, error))
{
@@ -357,12 +398,14 @@ dir_push_pattern_list (GList *stack, GFile *dir, GFile *file, gboolean ignore, G
list->pattern = NULL;
list->directory = dir;
+ line = 1;
for (ptr = content; *ptr != '\0';)
{
gchar *next;
next = strchr (ptr, '\n');
if (next != NULL) *next = '\0';
+ line++;
/* Discard space at the beginning */
while (isspace (*ptr)) ptr++;
@@ -374,7 +417,16 @@ dir_push_pattern_list (GList *stack, GFile *dir, GFile *file, gboolean ignore, G
if (next != NULL) *next = '\0';
pat = dir_pattern_new (ptr, ignore);
- list->pattern = g_list_prepend (list->pattern, pat);
+ if (pat != NULL)
+ {
+ list->pattern = g_list_prepend (list->pattern, pat);
+ }
+ else
+ {
+ gchar *filename = g_file_get_path (file);
+ g_warning("Invalid pattern in %s line %d", filename, line);
+ g_free (filename);
+ }
}
if (next == NULL) break;
@@ -403,15 +455,15 @@ dir_pop_pattern_list (GList *stack)
}
static gboolean
-dir_pattern_stack_is_match (GList *stack, GFile *file)
+dir_pattern_stack_is_match (GFile *root, GList *stack, GFile *file)
{
gboolean match;
GList *list;
- GList *name_list;
+ gchar *filename;
gboolean directory;
- /* Create name list from file */
- name_list = dir_cut_filename (file);
+ /* Create name from file */
+ filename = g_file_get_relative_path (root, file);
directory = g_file_query_file_type (file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_DIRECTORY;
/* Include directories by default */
@@ -422,47 +474,68 @@ dir_pattern_stack_is_match (GList *stack, GFile *file)
{
DirPatternList *pat_list = (DirPatternList *)list->data;
GList *node;
-
- /* Mark parent level */
- for (node = g_list_first (name_list); node != NULL; node = g_list_next (node))
- {
- DirMatchString *str = (DirMatchString *)node->data;
-
- str->parent = g_file_equal (pat_list->directory, str->file);
- }
-
+
for (node = g_list_first (pat_list->pattern); node != NULL; node = g_list_next (node))
{
DirPattern *pat = (DirPattern *)node->data;
- GList *pat_part;
- GList *name_part;
- gboolean match_part;
if (pat->directory && !directory)
continue;
- name_part = g_list_first (name_list);
- for (pat_part = g_list_first (pat->names); pat_part != NULL; pat_part = g_list_next (pat_part))
+ if (g_regex_match (pat->source, filename, 0, NULL))
{
- DirMatchString *part = (DirMatchString *)name_part->data;
- match_part = g_pattern_match ((GPatternSpec *)pat_part->data, part->length, part->string, part->reverse);
-
- if (!match_part) break;
- name_part = g_list_next (name_part);
+ match = pat->match;
}
+ }
+ }
+ g_free (filename);
+
+ return match;
+}
- /* Local match are relative to parent directory only */
- if (match_part && pat->local && (!((DirMatchString *)name_part->data)->parent)) match_part = FALSE;
+static GFile *
+dir_pattern_find_file_object (GFile *root, GList *stack, GFile *file)
+{
+ GFile *object = NULL;
+
+ if (g_file_query_file_type (file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) != G_FILE_TYPE_DIRECTORY)
+ {
+ GList *list;
+ gchar *filename;
+
+ /* Create name from file */
+ filename = g_file_get_relative_path (root, file);
+
+ /* Check all valid patterns */
+ for (list = g_list_last (stack); list != NULL; list = g_list_previous (list))
+ {
+ DirPatternList *pat_list = (DirPatternList *)list->data;
+ GList *node;
+
+ for (node = g_list_first (pat_list->pattern); node != NULL; node = g_list_next (node))
+ {
+ DirPattern *pat = (DirPattern *)node->data;
- if (match_part) match = pat->match;
+ if (pat->directory || !pat->match || (pat->object == NULL) )
+ continue;
+
+ if (g_regex_match (pat->source, filename, 0, NULL))
+ {
+ gchar *objname;
+
+ objname = g_regex_replace (pat->source, filename, -1, 0, pat->object, 0, NULL);
+ object = g_file_get_child (root, objname);
+ g_free (objname);
+ }
+ }
}
+ g_free (filename);
}
- dir_filename_free (name_list);
-
- return match;
+ return object;
}
+
typedef struct {
DirProject *proj;
AnjutaProjectNode *parent;
@@ -480,6 +553,7 @@ dir_project_load_directory_callback (GObject *source_object,
GList *infos, *l;
GError *err = NULL;
DirData *data = (DirData *) user_data;
+ GFile *root;
infos = g_file_enumerator_next_files_finish (enumerator, res, &err);
if (infos == NULL) {
@@ -525,6 +599,7 @@ dir_project_load_directory_callback (GObject *source_object,
return;
}
+ root = anjuta_project_node_get_file (data->proj->root);
for (l = infos; l != NULL; l = g_list_next(l))
{
GFileInfo *info;
@@ -538,8 +613,8 @@ dir_project_load_directory_callback (GObject *source_object,
g_object_unref (info);
/* Check if file is a source */
- if (!dir_pattern_stack_is_match (data->proj->sources, file)) continue;
-
+ if (!dir_pattern_stack_is_match (root, data->proj->sources, file)) continue;
+
if (g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL) == G_FILE_TYPE_DIRECTORY)
{
AnjutaProjectNode *group;
@@ -580,9 +655,25 @@ dir_project_load_directory_callback (GObject *source_object,
if (source == NULL)
{
+ GFile *object;
+ AnjutaProjectNode *parent;
+
+ /* Create object if possible */
+ object = dir_pattern_find_file_object (root, data->proj->sources, file);
+ if (object != NULL)
+ {
+ parent = project_node_new (data->proj, NULL, ANJUTA_PROJECT_OBJECT | ANJUTA_PROJECT_PROJECT, object, NULL, NULL);
+ g_object_unref (object);
+ anjuta_project_node_append (data->parent, parent);
+ }
+ else
+ {
+ parent = data->parent;
+ }
+
/* Create a source for files */
source = project_node_new (data->proj, NULL, ANJUTA_PROJECT_SOURCE | ANJUTA_PROJECT_PROJECT, file, NULL, NULL);
- anjuta_project_node_append (data->parent, source);
+ anjuta_project_node_append (parent, source);
}
}
}
diff --git a/plugins/dir-project/sources.list b/plugins/dir-project/sources.list
index 4f16b36..7c8354a 100644
--- a/plugins/dir-project/sources.list
+++ b/plugins/dir-project/sources.list
@@ -1,17 +1,17 @@
-*.c
+*.c: *.o
*.h
-*.C
-*.cpp
+*.C: *.o
+*.cpp: *.o
*.hpp
-*.cxx
-*.c++
-*.cc
+*.cxx: *.o
+*.c++: *.o
+*.cc: *.o
*.java
*.py
*.pl
*.rb
-*.y
-*.l
+*.y: *.o
+*.l: *.o
*.vala
*.gs
*.in
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]