1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif /* HAVE_CONFIG_H */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib.h>
27
28 #include "cut-backtrace-entry.h"
29 #include "cut-utils.h"
30
31 #define CUT_BACKTRACE_ENTRY_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE((obj), CUT_TYPE_BACKTRACE_ENTRY, CutBacktraceEntryPrivate))
33
34 typedef struct _CutBacktraceEntryPrivate CutBacktraceEntryPrivate;
35 struct _CutBacktraceEntryPrivate
36 {
37 gchar *file;
38 guint line;
39 gchar *function;
40 gchar *info;
41 };
42
43 enum
44 {
45 PROP_0,
46 PROP_FILE,
47 PROP_LINE,
48 PROP_FUNCTION,
49 PROP_INFO
50 };
51
52
53 G_DEFINE_TYPE(CutBacktraceEntry, cut_backtrace_entry, G_TYPE_OBJECT)
54
55 static void dispose (GObject *object);
56 static void set_property (GObject *object,
57 guint prop_id,
58 const GValue *value,
59 GParamSpec *pspec);
60 static void get_property (GObject *object,
61 guint prop_id,
62 GValue *value,
63 GParamSpec *pspec);
64
65 static void
cut_backtrace_entry_class_init(CutBacktraceEntryClass * klass)66 cut_backtrace_entry_class_init (CutBacktraceEntryClass *klass)
67 {
68 GObjectClass *gobject_class;
69 GParamSpec *spec;
70
71 gobject_class = G_OBJECT_CLASS(klass);
72
73 gobject_class->dispose = dispose;
74 gobject_class->set_property = set_property;
75 gobject_class->get_property = get_property;
76
77 spec = g_param_spec_string("file",
78 "File",
79 "The file name of the backtrace entry",
80 NULL,
81 G_PARAM_READWRITE);
82 g_object_class_install_property(gobject_class, PROP_FILE, spec);
83
84 spec = g_param_spec_uint("line",
85 "Line number",
86 "The line number of the backtrace entry",
87 0, G_MAXUINT32, 0,
88 G_PARAM_READWRITE);
89 g_object_class_install_property(gobject_class, PROP_LINE, spec);
90
91 spec = g_param_spec_string("function",
92 "Function",
93 "The function name of the backtrace entry",
94 NULL,
95 G_PARAM_READWRITE);
96 g_object_class_install_property(gobject_class, PROP_FUNCTION, spec);
97
98 spec = g_param_spec_string("info",
99 "Information",
100 "The information of the backtrace entry",
101 NULL,
102 G_PARAM_READWRITE);
103 g_object_class_install_property(gobject_class, PROP_INFO, spec);
104
105 g_type_class_add_private(gobject_class, sizeof(CutBacktraceEntryPrivate));
106 }
107
108 static void
cut_backtrace_entry_init(CutBacktraceEntry * entry)109 cut_backtrace_entry_init (CutBacktraceEntry *entry)
110 {
111 CutBacktraceEntryPrivate *priv;
112
113 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry);
114 priv->file = NULL;
115 priv->line = 0;
116 priv->function = NULL;
117 priv->info = NULL;
118 }
119
120 static void
dispose(GObject * object)121 dispose (GObject *object)
122 {
123 CutBacktraceEntryPrivate *priv;
124
125 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(object);
126 if (priv->file) {
127 g_free(priv->file);
128 priv->file = NULL;
129 }
130
131 if (priv->function) {
132 g_free(priv->function);
133 priv->function = NULL;
134 }
135
136 if (priv->info) {
137 g_free(priv->info);
138 priv->info = NULL;
139 }
140
141 G_OBJECT_CLASS(cut_backtrace_entry_parent_class)->dispose(object);
142 }
143
144 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)145 set_property (GObject *object,
146 guint prop_id,
147 const GValue *value,
148 GParamSpec *pspec)
149 {
150 CutBacktraceEntryPrivate *priv;
151
152 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(object);
153 switch (prop_id) {
154 case PROP_FILE:
155 cut_backtrace_entry_set_file(CUT_BACKTRACE_ENTRY(object),
156 g_value_get_string(value));
157 break;
158 case PROP_LINE:
159 priv->line = g_value_get_uint(value);
160 break;
161 case PROP_FUNCTION:
162 cut_backtrace_entry_set_function(CUT_BACKTRACE_ENTRY(object),
163 g_value_get_string(value));
164 break;
165 case PROP_INFO:
166 cut_backtrace_entry_set_info(CUT_BACKTRACE_ENTRY(object),
167 g_value_get_string(value));
168 break;
169 default:
170 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
171 break;
172 }
173 }
174
175 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)176 get_property (GObject *object,
177 guint prop_id,
178 GValue *value,
179 GParamSpec *pspec)
180 {
181 CutBacktraceEntryPrivate *priv;
182
183 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(object);
184 switch (prop_id) {
185 case PROP_FILE:
186 g_value_set_string(value, priv->file);
187 break;
188 case PROP_LINE:
189 g_value_set_uint(value, priv->line);
190 break;
191 case PROP_FUNCTION:
192 g_value_set_string(value, priv->function);
193 break;
194 case PROP_INFO:
195 g_value_set_string(value, priv->info);
196 break;
197 default:
198 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
199 break;
200 }
201 }
202
203 CutBacktraceEntry *
cut_backtrace_entry_new(const gchar * file,guint line,const gchar * function,const gchar * info)204 cut_backtrace_entry_new (const gchar *file, guint line,
205 const gchar *function, const gchar *info)
206 {
207 return g_object_new(CUT_TYPE_BACKTRACE_ENTRY,
208 "file", file,
209 "line", line,
210 "function", function,
211 "info", info,
212 NULL);
213 }
214
215 CutBacktraceEntry *
cut_backtrace_entry_new_empty(void)216 cut_backtrace_entry_new_empty (void)
217 {
218 return cut_backtrace_entry_new(NULL, 0, NULL, NULL);
219 }
220
221 const gchar *
cut_backtrace_entry_get_file(CutBacktraceEntry * entry)222 cut_backtrace_entry_get_file (CutBacktraceEntry *entry)
223 {
224 return CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry)->file;
225 }
226
227 void
cut_backtrace_entry_set_file(CutBacktraceEntry * entry,const gchar * file)228 cut_backtrace_entry_set_file (CutBacktraceEntry *entry, const gchar *file)
229 {
230 CutBacktraceEntryPrivate *priv;
231
232 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry);
233 if (priv->file) {
234 g_free(priv->file);
235 priv->file = NULL;
236 }
237 if (file)
238 priv->file = g_strdup(file);
239 }
240
241 guint
cut_backtrace_entry_get_line(CutBacktraceEntry * entry)242 cut_backtrace_entry_get_line (CutBacktraceEntry *entry)
243 {
244 return CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry)->line;
245 }
246
247 void
cut_backtrace_entry_set_line(CutBacktraceEntry * entry,guint line)248 cut_backtrace_entry_set_line (CutBacktraceEntry *entry, guint line)
249 {
250 CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry)->line = line;
251 }
252
253 const gchar *
cut_backtrace_entry_get_function(CutBacktraceEntry * entry)254 cut_backtrace_entry_get_function (CutBacktraceEntry *entry)
255 {
256 return CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry)->function;
257 }
258
259 void
cut_backtrace_entry_set_function(CutBacktraceEntry * entry,const gchar * function)260 cut_backtrace_entry_set_function (CutBacktraceEntry *entry,
261 const gchar *function)
262 {
263 CutBacktraceEntryPrivate *priv;
264
265 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry);
266 if (priv->function) {
267 g_free(priv->function);
268 priv->function = NULL;
269 }
270 if (function)
271 priv->function = g_strdup(function);
272 }
273
274 const gchar *
cut_backtrace_entry_get_info(CutBacktraceEntry * entry)275 cut_backtrace_entry_get_info (CutBacktraceEntry *entry)
276 {
277 return CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry)->info;
278 }
279
280 void
cut_backtrace_entry_set_info(CutBacktraceEntry * entry,const gchar * info)281 cut_backtrace_entry_set_info (CutBacktraceEntry *entry, const gchar *info)
282 {
283 CutBacktraceEntryPrivate *priv;
284
285 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry);
286 if (priv->info) {
287 g_free(priv->info);
288 priv->info = NULL;
289 }
290 if (info)
291 priv->info = g_strdup(info);
292 }
293
294 gchar *
cut_backtrace_entry_to_xml(CutBacktraceEntry * entry)295 cut_backtrace_entry_to_xml (CutBacktraceEntry *entry)
296 {
297 GString *string;
298
299 string = g_string_new(NULL);
300 cut_backtrace_entry_to_xml_string(entry, string, 0);
301 return g_string_free(string, FALSE);
302 }
303
304 static void
append_element_valist(GString * string,guint indent,const gchar * element_name,va_list var_args)305 append_element_valist (GString *string, guint indent,
306 const gchar *element_name, va_list var_args)
307 {
308 const gchar *name;
309
310 name = element_name;
311
312 while (name) {
313 const gchar *value = va_arg(var_args, gchar *);
314 if (value)
315 cut_utils_append_xml_element_with_value(string, indent, name, value);
316 name = va_arg(var_args, gchar *);
317 }
318 }
319
320 static void
append_element_with_children(GString * string,guint indent,const gchar * element_name,const gchar * first_child_element,...)321 append_element_with_children (GString *string, guint indent,
322 const gchar *element_name,
323 const gchar *first_child_element, ...)
324 {
325 gchar *escaped;
326 va_list var_args;
327
328 escaped = g_markup_escape_text(element_name, -1);
329 cut_utils_append_indent(string, indent);
330 g_string_append_printf(string, "<%s>\n", escaped);
331
332 va_start(var_args, first_child_element);
333 append_element_valist(string, indent + 2, first_child_element, var_args);
334 va_end(var_args);
335
336 cut_utils_append_indent(string, indent);
337 g_string_append_printf(string, "</%s>\n", escaped);
338 g_free(escaped);
339 }
340
341 void
cut_backtrace_entry_to_xml_string(CutBacktraceEntry * entry,GString * string,guint indent)342 cut_backtrace_entry_to_xml_string (CutBacktraceEntry *entry, GString *string,
343 guint indent)
344 {
345 CutBacktraceEntryPrivate *priv;
346 gchar *line_string = NULL;
347 gchar *info_string = NULL;
348
349 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry);
350 if (priv->file == NULL && priv->function == NULL)
351 return;
352
353 if (priv->line > 0)
354 line_string = g_strdup_printf("%d", priv->line);
355 if (priv->function) {
356 if (g_str_has_suffix(priv->function, ")")) {
357 info_string = strdup(priv->function);
358 } else {
359 info_string = g_strdup_printf("%s()", priv->function);
360 }
361 }
362 if (priv->info) {
363 if (info_string) {
364 gchar *function_string = info_string;
365 info_string = g_strconcat(function_string, ": ", priv->info, NULL);
366 g_free(function_string);
367 } else {
368 info_string = g_strdup(priv->info);
369 }
370 }
371
372 append_element_with_children(string, indent, "entry",
373 "file", priv->file,
374 "line", line_string,
375 "info", info_string,
376 NULL);
377
378 if (line_string)
379 g_free(line_string);
380 if (info_string)
381 g_free(info_string);
382 }
383
384 gchar *
cut_backtrace_entry_format(CutBacktraceEntry * entry)385 cut_backtrace_entry_format (CutBacktraceEntry *entry)
386 {
387 GString *string;
388
389 string = g_string_new(NULL);
390 cut_backtrace_entry_format_string(entry, string);
391 return g_string_free(string, FALSE);
392 }
393
394 void
cut_backtrace_entry_format_string(CutBacktraceEntry * entry,GString * string)395 cut_backtrace_entry_format_string (CutBacktraceEntry *entry, GString *string)
396 {
397 CutBacktraceEntryPrivate *priv;
398
399 priv = CUT_BACKTRACE_ENTRY_GET_PRIVATE(entry);
400
401 g_string_append_printf(string,
402 "%s:%d",
403 priv->file ? priv->file : "(null)",
404 priv->line);
405 if (priv->function) {
406 g_string_append(string, ": ");
407 g_string_append(string, priv->function);
408 if (!g_str_has_suffix(priv->function, ")")) {
409 g_string_append(string, "()");
410 }
411 }
412 if (priv->info)
413 g_string_append_printf(string, ": %s", priv->info);
414 if (priv->function == NULL && priv->info == NULL)
415 g_string_append(string, ":");
416 }
417
418 /*
419 vi:ts=4:nowrap:ai:expandtab:sw=4
420 */
421