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