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