wrong character in the GSM 03.38 table (ç for Ç)
[gammu.git] / libgammu / debug.c
blob4b95f6ec12489f15818ce3d0441a32460189c416
1 /* Gammu logging/debugging functions */
2 /* Copyright (c) 2008-2009 by Michal Cihar <michal@cihar.com> */
3 /* Licensed under GPL2+ */
5 #include "debug.h"
7 #include <string.h>
8 #include <ctype.h>
10 /* Commit flag for opening files is MS extension, some other
11 * implementations (like BCC 5.5) don't like this flag at all */
12 #ifdef _MSC_VER
13 # define COMMIT_FLAG "c"
14 #else
15 # define COMMIT_FLAG ""
16 #endif
18 GSM_Debug_Info GSM_none_debug = {
20 NULL,
21 FALSE,
22 "",
23 FALSE,
24 FALSE,
25 NULL,
26 NULL
29 GSM_Debug_Info GSM_global_debug = {
31 NULL,
32 FALSE,
33 "",
34 FALSE,
35 FALSE,
36 NULL,
37 NULL
40 /**
41 * Actually writes message to debuging file.
43 void dbg_write(GSM_Debug_Info *d, const char *text)
45 if (d->log_function != NULL) {
46 d->log_function(text, d->user_data);
47 } else if (d->df != NULL) {
48 fprintf(d->df, "%s", text);
52 PRINTF_STYLE(2, 0)
53 int dbg_vprintf(GSM_Debug_Info *d, const char *format, va_list argp)
55 int result=0;
56 char buffer[3000], timestamp[60];
57 char *pos, *end;
58 char save = 0;
59 GSM_DateTime date_time;
60 Debug_Level l;
62 l = d->dl;
64 if (l == DL_NONE) return 0;
66 result = vsnprintf(buffer, sizeof(buffer) - 1, format, argp);
67 pos = buffer;
69 while (*pos != 0) {
71 /* Find new line in string */
72 end = strstr(pos, "\n");
74 /* Are we at start of line? */
75 if (d->was_lf) {
76 /* Show date? */
77 if (l == DL_TEXTALLDATE || l == DL_TEXTERRORDATE || l == DL_TEXTDATE) {
78 GSM_GetCurrentDateTime(&date_time);
79 sprintf(timestamp, "%s %4d/%02d/%02d %02d:%02d:%02d: ",
80 DayOfWeek(date_time.Year, date_time.Month, date_time.Day),
81 date_time.Year, date_time.Month, date_time.Day,
82 date_time.Hour, date_time.Minute, date_time.Second);
83 dbg_write(d, timestamp);
85 d->was_lf = FALSE;
88 /* Remember end char */
89 if (end != NULL) {
90 save = *end;
91 *end = 0;
94 /* Output */
95 dbg_write(d, pos);
97 if (end != NULL) {
98 /* We had new line */
99 dbg_write(d, "\n");
100 d->was_lf = TRUE;
102 /* Restore saved char */
103 *end = save;
105 /* Advance to next line */
106 pos = end + strlen("\n");
107 } else {
108 /* We hit end of string */
109 break;
113 /* Flush buffers, this might be configurable, but it could cause drop of last log messages */
114 if (d->df != NULL) {
115 fflush(d->df);
118 return result;
121 GSM_Error GSM_SetDebugFileDescriptor(FILE *fd, gboolean closable, GSM_Debug_Info *privdi)
123 privdi->was_lf = TRUE;
125 if (privdi->df != NULL
126 && fileno(privdi->df) != fileno(stderr)
127 && fileno(privdi->df) != fileno(stdout)
128 && privdi->closable) {
129 fclose(privdi->df);
132 privdi->df = fd;
133 privdi->closable = closable;
135 return ERR_NONE;
138 GSM_Error GSM_SetDebugFile(const char *info, GSM_Debug_Info *privdi)
140 FILE *testfile;
142 if (info == NULL || strlen(info) == 0) {
143 return GSM_SetDebugFileDescriptor(NULL, FALSE, privdi);
146 switch (privdi->dl) {
147 case DL_BINARY:
148 testfile = fopen(info,"wb" COMMIT_FLAG);
149 break;
150 case DL_TEXTERROR:
151 case DL_TEXTERRORDATE:
152 testfile = fopen(info,"a" COMMIT_FLAG);
153 if (!testfile) {
154 dbgprintf(privdi, "Can't open debug file\n");
155 return ERR_CANTOPENFILE;
157 fseek(testfile, 0, SEEK_END);
158 if (ftell(testfile) > 5000000) {
159 fclose(testfile);
160 testfile = fopen(info,"w" COMMIT_FLAG);
162 break;
163 default:
164 testfile = fopen(info,"w" COMMIT_FLAG);
167 if (testfile == NULL) {
168 dbgprintf(privdi, "Can't open debug file\n");
169 return ERR_CANTOPENFILE;
170 } else {
171 return GSM_SetDebugFileDescriptor(testfile, TRUE, privdi);
175 GSM_Error GSM_SetDebugFunction(GSM_Log_Function info, void *data, GSM_Debug_Info * privdi)
177 privdi->log_function = info;
178 privdi->user_data = data;
179 return ERR_NONE;
182 gboolean GSM_SetDebugLevel(const char *info, GSM_Debug_Info *privdi)
184 if (info == NULL) {
185 privdi->dl = DL_NONE;
186 return TRUE;
188 if (!strcasecmp(info, "nothing")) {
189 privdi->dl = DL_NONE;
190 return TRUE;
192 if (!strcasecmp(info, "text")) {
193 privdi->dl = DL_TEXT;
194 return TRUE;
196 if (!strcasecmp(info, "textall")) {
197 privdi->dl = DL_TEXTALL;
198 return TRUE;
200 if (!strcasecmp(info, "binary")) {
201 privdi->dl = DL_BINARY;
202 return TRUE;
204 if (!strcasecmp(info, "errors")) {
205 privdi->dl = DL_TEXTERROR;
206 return TRUE;
208 if (!strcasecmp(info, "textdate")) {
209 privdi->dl = DL_TEXTDATE;
210 return TRUE;
212 if (!strcasecmp(info, "textalldate")) {
213 privdi->dl = DL_TEXTALLDATE;
214 return TRUE;
216 if (!strcasecmp(info, "errorsdate")) {
217 privdi->dl = DL_TEXTERRORDATE;
218 return TRUE;
220 return FALSE;
223 gboolean GSM_SetDebugCoding(const char *info, GSM_Debug_Info *privdi)
225 privdi->coding = info;
226 return TRUE;
229 gboolean GSM_SetDebugGlobal(gboolean info, GSM_Debug_Info *privdi)
231 privdi->use_global = info;
232 return TRUE;
235 PRINTF_STYLE(2, 3)
236 int smfprintf(GSM_Debug_Info *d, const char *format, ...)
238 va_list argp;
239 int result;
240 GSM_Debug_Info *tmpdi;
242 if (d == NULL || d->use_global) {
243 tmpdi = &GSM_global_debug;
244 } else {
245 tmpdi = d;
248 va_start(argp, format);
249 result = dbg_vprintf(tmpdi, format, argp);
250 va_end(argp);
252 return result;
256 PRINTF_STYLE(2, 3)
257 int smprintf(GSM_StateMachine *s, const char *format, ...)
259 va_list argp;
260 int result=0;
261 GSM_Debug_Info *curdi;
263 curdi = GSM_GetDI(s);
265 va_start(argp, format);
267 result = dbg_vprintf(curdi, format, argp);
269 va_end(argp);
270 return result;
273 PRINTF_STYLE(3, 4)
274 int smprintf_level(GSM_StateMachine * s, GSM_DebugSeverity severity, const char *format, ...)
276 va_list argp;
277 int result=0;
278 GSM_Debug_Info *curdi;
280 curdi = GSM_GetDI(s);
282 if (severity == D_TEXT) {
283 if (curdi->dl != DL_TEXT &&
284 curdi->dl != DL_TEXTALL &&
285 curdi->dl != DL_TEXTDATE &&
286 curdi->dl != DL_TEXTALLDATE) {
287 return 0;
289 } else if (severity == D_ERROR) {
290 if (curdi->dl != DL_TEXT &&
291 curdi->dl != DL_TEXTALL &&
292 curdi->dl != DL_TEXTDATE &&
293 curdi->dl != DL_TEXTALLDATE &&
294 curdi->dl != DL_TEXTERROR &&
295 curdi->dl != DL_TEXTERRORDATE) {
296 return 0;
299 va_start(argp, format);
301 result = dbg_vprintf(curdi, format, argp);
303 va_end(argp);
304 return result;
307 #define CHARS_PER_LINE (16)
309 /* Dumps a message */
310 void DumpMessage(GSM_Debug_Info *d, const unsigned char *message, const int messagesize)
312 int i, j = 0;
313 char buffer[(CHARS_PER_LINE * 5) + 1];
315 smfprintf(d, "\n");
317 if (messagesize == 0) return;
319 memset(buffer, ' ', CHARS_PER_LINE * 5);
320 buffer[CHARS_PER_LINE * 5] = 0;
322 for (i = 0; i < messagesize; i++) {
323 /* Write hex number */
324 snprintf(buffer + (j * 4), 3, "%02X", message[i]);
325 buffer[(j * 4) + 2] = ' '; /* wipe snprintf's \0 */
327 /* Write char if possible */
328 if (isprint(message[i])
329 /* 0x09 = tab */
330 && message[i] != 0x09
331 /* 0x01 = beep in windows xp */
332 && message[i] != 0x01
333 /* these are empty in windows xp */
334 && message[i] != 0x85
335 && message[i] != 0x95
336 && message[i] != 0xA6
337 && message[i] != 0xB7) {
338 buffer[(j * 4) + 2] = message[i];
339 buffer[(CHARS_PER_LINE - 1) * 4 + j + 4] = message[i];
340 } else {
341 buffer[(CHARS_PER_LINE - 1) * 4 + j + 4] = '.';
344 /* Write char separator */
345 if (j != CHARS_PER_LINE - 1 && i != messagesize - 1) {
346 buffer[j * 4 + 3] = '|';
349 /* Print out buffer */
350 if (j == CHARS_PER_LINE - 1) {
351 smfprintf(d, "%s\n", buffer);
352 memset(buffer, ' ', CHARS_PER_LINE * 5);
353 j = 0;
354 } else {
355 j++;
359 /* Anything remains to be printed? */
360 if (j != 0) {
361 smfprintf(d, "%s\n", buffer);
365 #undef CHARS_PER_LINE
367 void DumpMessageText(GSM_Debug_Info *d, const unsigned char *message, const int messagesize)
369 if (d == NULL || (d->dl != DL_TEXTALL && d->dl == DL_TEXTALLDATE)) return;
370 DumpMessage(d, message, messagesize);
373 /* How should editor hadle tabs in this file? Add editor commands here.
374 * vim: noexpandtab sw=8 ts=8 sts=8: