code-analyzer: Fixed bgo#667903 - Code Analyzer Crashes
[anjuta.git] / plugins / git / git-log-data-command.c
blobe9821c61fdab52ccf9ea42b449a57ac57d57350a
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) James Liggett 2010 <jrliggett@cox.net>
5 *
6 * anjuta is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * anjuta is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "git-log-data-command.h"
22 #define COMMIT_REGEX "^commit ([[:xdigit:]]{40})"
23 #define PARENT_REGEX "^parents (.*)"
24 #define AUTHOR_REGEX "^author (.*)"
25 #define TIME_REGEX "^time (\\d*)"
26 #define SHORT_LOG_REGEX "^(?:short log) (.*)"
28 struct _GitLogDataCommandPriv
30 GAsyncQueue *input_queue;
31 GQueue *output_queue;
32 GHashTable *revisions;
33 GitRevision *current_revision;
34 GRegex *commit_regex;
35 GRegex *parent_regex;
36 GRegex *author_regex;
37 GRegex *time_regex;
38 GRegex *short_log_regex;
41 G_DEFINE_TYPE (GitLogDataCommand, git_log_data_command,
42 ANJUTA_TYPE_ASYNC_COMMAND);
44 static void
45 git_log_data_command_init (GitLogDataCommand *self)
47 self->priv = g_new0 (GitLogDataCommandPriv, 1);
48 self->priv->input_queue = g_async_queue_new_full (g_free);
49 self->priv->output_queue = g_queue_new ();
50 self->priv->revisions = g_hash_table_new_full (g_str_hash, g_str_equal,
51 g_free, g_object_unref);
52 self->priv->commit_regex = g_regex_new (COMMIT_REGEX, 0, 0, NULL);
53 self->priv->parent_regex = g_regex_new (PARENT_REGEX, 0, 0, NULL);
54 self->priv->author_regex = g_regex_new (AUTHOR_REGEX, 0, 0, NULL);
55 self->priv->time_regex = g_regex_new (TIME_REGEX, 0, 0, NULL);
56 self->priv->short_log_regex = g_regex_new (SHORT_LOG_REGEX, 0, 0, NULL);
59 static void
60 git_log_data_command_finalize (GObject *object)
62 GitLogDataCommand *self;
63 GList *current_output;
65 self = GIT_LOG_DATA_COMMAND (object);
67 g_async_queue_unref (self->priv->input_queue);
68 current_output = self->priv->output_queue->head;
70 while (current_output)
72 g_object_unref (current_output->data);
73 current_output = g_list_next (current_output);
76 g_queue_free (self->priv->output_queue);
77 g_hash_table_destroy (self->priv->revisions);
78 g_regex_unref (self->priv->commit_regex);
79 g_regex_unref (self->priv->parent_regex);
80 g_regex_unref (self->priv->author_regex);
81 g_regex_unref (self->priv->time_regex);
82 g_regex_unref (self->priv->short_log_regex);
84 G_OBJECT_CLASS (git_log_data_command_parent_class)->finalize (object);
87 static guint
88 git_log_data_command_run (AnjutaCommand *command)
90 GitLogDataCommand *self;
91 gchar *line;
92 GMatchInfo *commit_match_info;
93 GMatchInfo *parent_match_info;
94 GMatchInfo *author_match_info;
95 GMatchInfo *time_match_info;
96 GMatchInfo *short_log_match_info;
97 gchar *commit_sha;
98 gchar *parents;
99 gchar **parent_shas;
100 gint i;
101 GitRevision *parent_revision;
102 gchar *author;
103 gchar *time;
104 gchar *short_log;
106 self = GIT_LOG_DATA_COMMAND (command);
108 while ((line = g_async_queue_pop (self->priv->input_queue)))
110 /* An empty string means there's nothing left to process */
111 if (g_utf8_strlen (line, -1) == 0)
113 g_free (line);
114 break;
117 commit_match_info = NULL;
118 parent_match_info = NULL;
119 author_match_info = NULL;
120 time_match_info = NULL;
121 short_log_match_info = NULL;
123 /* Entries are delimited by the hex value 0x0c */
124 if (*line == 0x0c && self->priv->current_revision)
126 anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (command));
127 g_queue_push_tail (self->priv->output_queue,
128 self->priv->current_revision);
129 anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (command));
131 anjuta_command_notify_data_arrived (command);
134 if (g_regex_match (self->priv->commit_regex, line, 0, &commit_match_info))
136 commit_sha = g_match_info_fetch (commit_match_info, 1);
138 self->priv->current_revision = g_hash_table_lookup (self->priv->revisions,
139 commit_sha);
141 if (!self->priv->current_revision)
143 self->priv->current_revision = git_revision_new ();
144 git_revision_set_sha (self->priv->current_revision, commit_sha);
145 g_hash_table_insert (self->priv->revisions, g_strdup (commit_sha),
146 g_object_ref (self->priv->current_revision));
149 g_free (commit_sha);
151 else if (g_regex_match (self->priv->parent_regex, line, 0,
152 &parent_match_info))
154 parents = g_match_info_fetch (parent_match_info, 1);
155 parent_shas = g_strsplit (parents, " ", -1);
157 for (i = 0; parent_shas[i]; i++)
159 parent_revision = g_hash_table_lookup (self->priv->revisions,
160 parent_shas[i]);
162 if (!parent_revision)
164 parent_revision = git_revision_new ();
165 git_revision_set_sha (parent_revision, parent_shas[i]);
166 g_hash_table_insert (self->priv->revisions,
167 g_strdup (parent_shas[i]),
168 g_object_ref (parent_revision));
171 git_revision_add_child (parent_revision,
172 self->priv->current_revision);
175 g_free (parents);
176 g_strfreev (parent_shas);
178 else if (g_regex_match (self->priv->author_regex, line, 0,
179 &author_match_info))
181 author = g_match_info_fetch (author_match_info, 1);
182 git_revision_set_author (self->priv->current_revision, author);
184 g_free (author);
186 else if (g_regex_match (self->priv->time_regex, line, 0,
187 &time_match_info))
189 time = g_match_info_fetch (time_match_info, 1);
190 git_revision_set_date (self->priv->current_revision, atol (time));
192 g_free (time);
194 else if (g_regex_match (self->priv->short_log_regex, line, 0,
195 &short_log_match_info))
197 short_log = g_match_info_fetch (short_log_match_info, 1);
198 git_revision_set_short_log (self->priv->current_revision, short_log);
200 g_free (short_log);
203 if (commit_match_info)
204 g_match_info_free (commit_match_info);
206 if (parent_match_info)
207 g_match_info_free (parent_match_info);
209 if (author_match_info)
210 g_match_info_free (author_match_info);
212 if (time_match_info)
213 g_match_info_free (time_match_info);
215 if (short_log_match_info)
216 g_match_info_free (short_log_match_info);
218 g_free (line);
221 return 0;
224 static void
225 git_log_data_command_class_init (GitLogDataCommandClass *klass)
227 GObjectClass* object_class = G_OBJECT_CLASS (klass);
228 AnjutaCommandClass *command_class = ANJUTA_COMMAND_CLASS (klass);
230 object_class->finalize = git_log_data_command_finalize;
231 command_class->run = git_log_data_command_run;
234 GitLogDataCommand *
235 git_log_data_command_new (void)
237 return g_object_new (GIT_TYPE_LOG_DATA_COMMAND, NULL);
240 GQueue *
241 git_log_data_command_get_output (GitLogDataCommand *self)
243 return self->priv->output_queue;
246 void
247 git_log_data_command_push_line (GitLogDataCommand *self, const gchar *line)
249 g_async_queue_push (self->priv->input_queue, g_strdup (line));