1 /*
2 Florence - Florence is a simple virtual keyboard for Gnome.
3
4 Copyright (C) 2012 François Agrech
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include "trace.h"
23 #include "system.h"
24 #include <glib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27
28 /* Global trace level. */
29 static enum trace_level trace_debug_level;
30 /* the buffer records checksum of messages already printed. Used not to print the same message twice */
31 static GSList *trace_buffer=NULL;
32 /* indentation of traces */
33 #define TRACE_MAX_INDENT 64
34 char trace_indent[TRACE_MAX_INDENT];
35 /* function check sum */
36 int trace_fn_cksum[TRACE_MAX_INDENT];
37
38 gint g_vfprintf(FILE *file, gchar const *format, va_list args);
39 gint g_fprintf(FILE *file, gchar const *format, ...) G_GNUC_PRINTF (2, 3);
40
41 /* calculate a simple checksum of a string. */
trace_cksum(const char * str)42 int trace_cksum(const char *str)
43 {
44 int idx, ret=0;
45 for(idx=0; str[idx]!='\0'; idx++) ret+=str[idx];
46 return ret;
47 }
48
49 /* prints a message to stream f, ignores it if there exists a duplicate in the buffer. */
trace_distinct_msg(char * prefix,FILE * f,char * s,va_list args)50 void trace_distinct_msg(char *prefix, FILE *f, char *s, va_list args)
51 {
52 GSList *list=trace_buffer;
53 gchar *str=g_strdup_vprintf((gchar *)s, args);
54 int cksum=trace_cksum((const char *)str);
55 int *pcksum;
56 gboolean ignore=FALSE;
57 while (list) {
58 if ((*(int *)(list->data))==cksum) {
59 ignore=TRUE;
60 break;
61 }
62 list=list->next;
63 }
64 if (!ignore) {
65 pcksum=g_malloc(sizeof(int));
66 *pcksum=cksum;
67 trace_buffer=g_slist_append(trace_buffer, pcksum);
68 g_fprintf(f, "%s%s%s", trace_indent, prefix, str);
69 g_fprintf(f, "\n");
70 }
71 g_free(str);
72 }
73
74 /* prints a message to stream f. */
trace_msg(char * prefix,FILE * f,char * s,va_list args)75 void trace_msg(char *prefix, FILE *f, char *s, va_list args)
76 {
77 gchar *str=g_strdup_vprintf((gchar *)s, args);
78 g_fprintf(f, "%s%s%s", trace_indent, prefix, str);
79 g_fprintf(f, "\n");
80 g_free(str);
81 }
82
83 /********************/
84 /* public functions */
85 /********************/
86
87 /* initializes the trace module. Must be called before any trace function
88 * debug is a boolean. If it's true, the trace module will print debug informations */
trace_init(enum trace_level debug_level)89 void trace_init(enum trace_level debug_level)
90 {
91 trace_debug_level=debug_level;
92 memset(trace_indent, 0, sizeof(trace_indent));
93 }
94
95 /* liberate any memory used by the trace module */
trace_exit()96 void trace_exit()
97 {
98 GSList *list=trace_buffer;
99 while (list) {
100 g_free(list->data);
101 list=list->next;
102 }
103 g_slist_free(trace_buffer);
104 }
105
106 /* return trace level parsed from the string argument */
trace_parse_level(char * s)107 enum trace_level trace_parse_level(char *s)
108 {
109 enum trace_level ret=TRACE_WARNING;
110 if (!strcmp(s, "fatal")) ret=TRACE_SEVERE;
111 else if (!strcmp(s, "error")) ret=TRACE_ERROR;
112 else if (!strcmp(s, "warning")) ret=TRACE_WARNING;
113 else if (!strcmp(s, "debug")) ret=TRACE_DEBUG;
114 else if (!strcmp(s, "hidebug")) ret=TRACE_HIDEBUG;
115 else flo_info(_("Unable to parse debug level <%s>, using default <warning>"), s);
116 if (ret>=TRACE_DEBUG) flo_info(_("Setting debug level to <%s>"), s);
117 return ret;
118 }
119
flo_fatal(char * s,...)120 void flo_fatal(char *s, ...)
121 {
122 va_list ap;
123 g_fprintf(stderr, _("FATAL ERROR: "));
124 va_start(ap, s);
125 g_vfprintf(stderr, s, ap);
126 g_fprintf(stderr, "\n");
127 va_end(ap);
128 if (!g_getenv("FLO_DEBUG") || strcmp(g_getenv("FLO_DEBUG"), "1")) {
129 g_fprintf(stderr, _("If you need help, please rerun with the -d switch (debug)\n"));
130 g_fprintf(stderr, _("and send the output to f.agrech@gmail.com\n\n"));
131 }
132 exit(EXIT_FAILURE);
133 }
134
flo_info(char * s,...)135 void flo_info(char *s, ...)
136 {
137 va_list ap;
138 va_start(ap, s);
139 trace_msg("", stdout, s, ap);
140 va_end(ap);
141 }
142
flo_info_distinct(char * s,...)143 void flo_info_distinct(char *s, ...)
144 {
145 va_list ap;
146 va_start(ap, s);
147 trace_distinct_msg("", stdout, s, ap);
148 va_end(ap);
149 }
150
flo_warn(char * s,...)151 void flo_warn(char *s, ...)
152 {
153 if (trace_debug_level>=TRACE_WARNING) {
154 va_list ap;
155 va_start(ap, s);
156 trace_msg(_("WARNING: "), stderr, s, ap);
157 va_end(ap);
158 }
159 }
160
flo_warn_distinct(char * s,...)161 void flo_warn_distinct(char *s, ...)
162 {
163 if (trace_debug_level>=TRACE_WARNING) {
164 va_list ap;
165 va_start(ap, s);
166 trace_distinct_msg(_("WARNING: "), stderr, s, ap);
167 va_end(ap);
168 }
169 }
170
flo_error(char * s,...)171 void flo_error(char *s, ...)
172 {
173 if (trace_debug_level>=TRACE_ERROR) {
174 va_list ap;
175 va_start(ap, s);
176 trace_msg(_("ERROR: "), stderr, s, ap);
177 va_end(ap);
178 }
179 }
180
flo_debug(enum trace_level level,char * s,...)181 void flo_debug(enum trace_level level, char *s, ...)
182 {
183 if (trace_debug_level>=level) {
184 va_list ap;
185 va_start(ap, s);
186 trace_msg("", stdout, s, ap);
187 va_end(ap);
188 }
189 }
190
flo_debug_distinct(enum trace_level level,char * s,...)191 void flo_debug_distinct(enum trace_level level, char *s, ...)
192 {
193 if (trace_debug_level>=level) {
194 va_list ap;
195 va_start(ap, s);
196 trace_distinct_msg("", stdout, s, ap);
197 va_end(ap);
198 }
199 }
200
flo_start_func(int line,const char * func,const char * file)201 void flo_start_func(int line, const char *func, const char *file)
202 {
203 int indent;
204 if (trace_debug_level>=TRACE_HIDEBUG) {
205 g_fprintf(stdout, "%s<%s@%s:%d>\n", trace_indent, func, file, line);
206 indent=strlen(trace_indent);
207 trace_fn_cksum[indent]=trace_cksum(func);
208 if (indent<TRACE_MAX_INDENT) trace_indent[indent]=' ';
209 else { flo_fatal(_("Too many function levels at function <%s>."), func); }
210 }
211 }
212
flo_end_func(int line,const char * func,const char * file)213 void flo_end_func(int line, const char *func, const char *file)
214 {
215 int indent;
216 if (trace_debug_level>=TRACE_HIDEBUG) {
217 indent=strlen(trace_indent)-1;
218 if (trace_fn_cksum[indent]!=trace_cksum(func)) flo_fatal(_("Trace function checksum error at function <%s>."), func);
219 if (indent>=0) trace_indent[indent]='\0';
220 else flo_fatal(_("Trace indent error at function <%s>."), func);
221 g_fprintf(stdout, "%s</%s@%s:%d>\n", trace_indent, func, file, line);
222 }
223 }
224
225