Mercurial > libpst
annotate src/debug.c @ 60:97b7706bdda2
Work around bogus 7c.b5 blocks in some messages that have been read.
They appear to have attachments, but of some unknown format.
Before the message was read, it did not have any attachments.
Use autoscan to cleanup our autoconf system.
Use autoconf to detect when we need to use our XGetopt files
and other header files.
More fields, including BCC.
Fix missing LE32_CPU byte swapping for FILETIME types.
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Sat, 16 Feb 2008 12:26:35 -0800 |
parents | f66078abed38 |
children | b12f4e50e2e8 |
rev | line source |
---|---|
48 | 1 |
2 #include "define.h" | |
3 | |
16 | 4 #include <stdio.h> |
5 #include <stdlib.h> | |
6 #include <stdarg.h> | |
7 #include <ctype.h> | |
8 #include <string.h> | |
9 #include <limits.h> | |
10 | |
11 #ifdef _WIN32 | |
12 # define vsnprintf _vsnprintf | |
13 #endif | |
14 | |
46 | 15 struct pst_debug_item { |
16 int type; | |
17 char * function; | |
18 unsigned int line; | |
19 char * file; | |
20 char * text; | |
21 struct pst_debug_item *next; | |
16 | 22 } *item_head=NULL, *item_tail=NULL, *item_ptr=NULL, *info_ptr=NULL, *temp_list=NULL; |
23 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
24 |
46 | 25 struct pst_debug_func { |
26 char * name; | |
27 struct pst_debug_func *next; | |
16 | 28 } *func_head=NULL, *func_ptr=NULL; |
29 | |
30 | |
46 | 31 void pst_debug_write_msg(struct pst_debug_item *item, char *fmt, va_list *ap, int size); |
32 void pst_debug_write_hex(struct pst_debug_item *item, unsigned char *buf, size_t size, int col); | |
16 | 33 void * xmalloc(size_t size); |
34 | |
35 // the largest text size we will store in memory. Otherwise we | |
36 // will do a debug_write, then create a new record, and write the | |
37 // text body directly to the file | |
38 #define MAX_MESSAGE_SIZE 4096 | |
39 | |
46 | 40 void pst_debug(char *fmt, ...) { |
41 va_list ap; | |
42 va_start(ap,fmt); | |
43 vfprintf(stderr, fmt, ap); | |
44 va_end(ap); | |
16 | 45 } |
46 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
47 |
16 | 48 #define NUM_COL 30 |
46 | 49 void pst_debug_hexdumper(FILE *out, unsigned char *buf, size_t size, int col, int delta) { |
50 int off = 0, toff; | |
51 int count = 0; | |
16 | 52 |
46 | 53 if (!out) return; // no file |
54 if (col == -1) col = NUM_COL; | |
55 fprintf(out, "\n"); | |
56 while (off < size) { | |
57 fprintf(out, "%06X\t:", off+delta); | |
58 toff = off; | |
59 while (count < col && off < size) { | |
60 fprintf(out, "%02hhx ", buf[off]); | |
61 off++; count++; | |
62 } | |
63 off = toff; | |
64 while (count < col) { | |
65 // only happens at end of block to pad the text over to the text column | |
66 fprintf(out, " "); | |
67 count++; | |
68 } | |
69 count = 0; | |
70 fprintf(out, ":"); | |
71 while (count < col && off < size) { | |
72 fprintf(out, "%c", isgraph(buf[off])?buf[off]:'.'); | |
73 off++; count ++; | |
74 } | |
16 | 75 |
46 | 76 fprintf(out, "\n"); |
77 count=0; | |
78 } | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
79 |
46 | 80 fprintf(out, "\n"); |
16 | 81 } |
82 | |
83 | |
84 FILE *debug_fp = NULL; | |
85 unsigned int max_items=DEBUG_MAX_ITEMS, curr_items=0; | |
86 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
87 |
46 | 88 void pst_debug_init(char* fname) { |
89 unsigned char version = DEBUG_VERSION; | |
90 item_head = item_tail = NULL; | |
91 curr_items = 0; | |
92 if (debug_fp) pst_debug_close(); | |
93 if (!fname) return; | |
94 if ((debug_fp = fopen(fname, "wb")) == NULL) { | |
95 fprintf(stderr, "Opening of file %s failed\n", fname); | |
96 exit(1); | |
97 } | |
98 fwrite(&version, 1, sizeof(char), debug_fp); | |
16 | 99 } |
100 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
101 |
46 | 102 // function must be called before pst_debug_msg. It sets up the |
16 | 103 // structure for the function that follows |
46 | 104 void pst_debug_msg_info(int line, char* file, int type) { |
105 char *x; | |
106 if (!debug_fp) return; // no file | |
107 info_ptr = (struct pst_debug_item*) xmalloc(sizeof(struct pst_debug_item)); | |
108 info_ptr->type = type; | |
109 info_ptr->line = line; | |
110 x = (func_head==NULL?"No Function":func_head->name); | |
111 info_ptr->function = (char*) xmalloc(strlen(x)+1); | |
112 strcpy(info_ptr->function, x); | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
113 |
46 | 114 info_ptr->file = (char*) xmalloc(strlen(file)+1); |
115 strcpy(info_ptr->file, file); | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
116 |
46 | 117 //put the current record on a temp linked list |
118 info_ptr->next = temp_list; | |
119 temp_list = info_ptr; | |
16 | 120 } |
121 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
122 |
46 | 123 void pst_debug_msg_text(char* fmt, ...) { |
124 va_list ap; | |
125 int f, g; | |
126 char x[2]; | |
127 struct pst_debug_item *temp; | |
128 if (!debug_fp) return; // no file | |
129 va_start(ap, fmt); | |
130 // get the record off of the temp_list | |
131 info_ptr = temp_list; | |
132 if (info_ptr) | |
133 temp_list = info_ptr->next; | |
134 else { | |
135 fprintf(stderr, "NULL info_ptr. ERROR!!\n"); | |
136 exit(-2); | |
137 } | |
138 // according to glibc 2.1, this should return the req. number of bytes for | |
139 // the string | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
140 #ifdef _WIN32 |
46 | 141 // vsnprintf trick doesn't work. must use function called _vscprintf |
142 // cannot find much documentation about this on internet or anywhere. | |
143 // I assume it isn't a standard function, but only in VisualC++ | |
144 f = _vscprintf(fmt, ap); | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
145 #else |
46 | 146 f = vsnprintf(x, 1, fmt, ap); |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
147 #endif |
46 | 148 va_end(ap); // must be called after vsnprintf() |
16 | 149 |
46 | 150 if (f > 0 && f < MAX_MESSAGE_SIZE) { |
151 info_ptr->text = (char*) xmalloc(f+1); | |
152 va_start(ap, fmt); | |
153 if ((g = vsnprintf(info_ptr->text, f, fmt, ap)) == -1) { | |
154 fprintf(stderr, "_debug_msg: Dieing! vsnprintf returned -1 for format \"%s\"\n", fmt); | |
155 exit(-2); | |
156 } | |
157 va_end(ap); | |
158 info_ptr->text[g] = '\0'; | |
159 if (f != g) { | |
160 fprintf(stderr, "_debug_msg: f != g\n"); | |
161 } | |
162 } else if (f > 0) { // it is over the max_message_size then | |
163 f += strlen(info_ptr->file)+strlen(info_ptr->function); | |
164 temp = info_ptr; | |
165 pst_debug_write(); // dump the current messages | |
166 info_ptr = temp; | |
167 va_start(ap, fmt); | |
168 pst_debug_write_msg(info_ptr, fmt, &ap, f); | |
169 va_end(ap); | |
170 free(info_ptr->function); | |
171 free(info_ptr->file); | |
172 free(info_ptr); | |
173 info_ptr = NULL; | |
174 return; | |
175 } else { | |
176 fprintf(stderr, "_debug_msg: error getting requested size of debug message\n"); | |
177 info_ptr->text = "ERROR Saving\n"; | |
178 } | |
16 | 179 |
46 | 180 if (!item_head) |
181 item_head = info_ptr; | |
16 | 182 |
46 | 183 info_ptr->next = NULL; |
184 if (item_tail) item_tail->next = info_ptr; | |
185 item_tail = info_ptr; | |
16 | 186 |
46 | 187 if (++curr_items == max_items) { |
188 // here we will jump off and save the contents | |
189 pst_debug_write(); | |
190 info_ptr = NULL; | |
191 } | |
16 | 192 } |
193 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
194 |
46 | 195 void pst_debug_hexdump(unsigned char *x, size_t y, int cols, int delta) { |
196 struct pst_debug_item *temp; | |
197 if (!debug_fp) return; // no file | |
198 info_ptr = temp_list; | |
199 if (info_ptr) temp_list = info_ptr->next; | |
200 temp = info_ptr; | |
201 pst_debug_write(); | |
202 info_ptr = temp; | |
203 pst_debug_write_hex(info_ptr, x, y, cols); | |
204 free(info_ptr->function); | |
205 free(info_ptr->file); | |
206 free(info_ptr); | |
207 info_ptr = NULL; | |
16 | 208 } |
209 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
210 |
46 | 211 void pst_debug_func(char *function) { |
212 func_ptr = xmalloc (sizeof(struct pst_debug_func)); | |
213 func_ptr->name = xmalloc(strlen(function)+1); | |
214 strcpy(func_ptr->name, function); | |
215 func_ptr->next = func_head; | |
216 func_head = func_ptr; | |
16 | 217 } |
218 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
219 |
46 | 220 void pst_debug_func_ret() { |
221 //remove the head item | |
222 func_ptr = func_head; | |
223 if (func_head) { | |
224 func_head = func_head->next; | |
225 free(func_ptr->name); | |
226 free(func_ptr); | |
227 } else { | |
228 DIE(("function list is empty!\n")); | |
229 } | |
16 | 230 } |
231 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
232 |
46 | 233 void pst_debug_close(void) { |
234 pst_debug_write(); | |
235 while (func_head) { | |
236 func_ptr = func_head; | |
237 func_head = func_head->next; | |
238 free(func_ptr->name); | |
239 free(func_ptr); | |
240 } | |
241 if (debug_fp) fclose(debug_fp); | |
242 debug_fp = NULL; | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
243 } |
16 | 244 |
245 | |
46 | 246 void pst_debug_write() { |
247 size_t size, ptr, funcname, filename, text, end; | |
248 char *buf = NULL, rec_type; | |
249 if (!debug_fp) return; // no file | |
48 | 250 off_t index_pos = ftell(debug_fp); |
43 | 251 off_t file_pos = index_pos; |
46 | 252 // add 2. One for the pointer to the next index, |
253 // one for the count of this index | |
254 int index_size = ((curr_items+2) * sizeof(off_t)); | |
255 off_t *index; | |
256 int index_ptr = 0; | |
257 struct pst_debug_file_rec_m mfile_rec; | |
258 struct pst_debug_file_rec_l lfile_rec; | |
16 | 259 |
46 | 260 if (curr_items == 0) return; // no items to write. |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
261 |
46 | 262 index = (off_t*)xmalloc(index_size); |
263 memset(index, 0, index_size); // valgrind, avoid writing uninitialized data | |
264 file_pos += index_size; | |
265 // write the index first, we will re-write it later, but | |
266 // we want to allocate the space | |
267 fwrite(index, index_size, 1, debug_fp); | |
268 index[index_ptr++] = curr_items; | |
16 | 269 |
46 | 270 item_ptr = item_head; |
271 while (item_ptr) { | |
272 file_pos = ftell(debug_fp); | |
273 index[index_ptr++] = file_pos; | |
274 size = strlen(item_ptr->function) + | |
275 strlen(item_ptr->file) + | |
276 strlen(item_ptr->text) + 3; //for the three \0s | |
277 if (buf) free(buf); | |
278 buf = xmalloc(size+1); | |
279 ptr = 0; | |
280 funcname=ptr; | |
281 ptr += sprintf(&(buf[ptr]), "%s", item_ptr->function)+1; | |
282 filename=ptr; | |
283 ptr += sprintf(&(buf[ptr]), "%s", item_ptr->file)+1; | |
284 text=ptr; | |
285 ptr += sprintf(&(buf[ptr]), "%s", item_ptr->text)+1; | |
286 end=ptr; | |
287 if (end > USHRT_MAX) { // bigger than can be stored in a short | |
288 rec_type = 'L'; | |
289 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
290 lfile_rec.type = item_ptr->type; | |
291 lfile_rec.line = item_ptr->line; | |
292 lfile_rec.funcname = funcname; | |
293 lfile_rec.filename = filename; | |
294 lfile_rec.text = text; | |
295 lfile_rec.end = end; | |
296 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
297 } else { | |
298 rec_type = 'M'; | |
299 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
300 mfile_rec.type = item_ptr->type; | |
301 mfile_rec.line = item_ptr->line; | |
302 mfile_rec.funcname = funcname; | |
303 mfile_rec.filename = filename; | |
304 mfile_rec.text = text; | |
305 mfile_rec.end = end; | |
306 fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); | |
307 } | |
308 fwrite(buf, 1, ptr, debug_fp); | |
309 if (buf) free(buf); buf = NULL; | |
310 item_head = item_ptr->next; | |
311 free(item_ptr->function); | |
312 free(item_ptr->file); | |
313 free(item_ptr->text); | |
314 free(item_ptr); | |
315 item_ptr = item_head; | |
316 } | |
317 curr_items = 0; | |
318 index[index_ptr] = ftell(debug_fp); | |
16 | 319 |
46 | 320 // we should now have a complete index |
321 fseek(debug_fp, index_pos, SEEK_SET); | |
322 fwrite(index, index_size, 1, debug_fp); | |
323 fseek(debug_fp, 0, SEEK_END); | |
324 item_ptr = item_head = item_tail = NULL; | |
325 free(index); | |
326 if (buf) free(buf); | |
16 | 327 } |
328 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
329 |
46 | 330 void pst_debug_write_msg(struct pst_debug_item *item, char *fmt, va_list *ap, int size) { |
331 struct pst_debug_file_rec_l lfile_rec; | |
332 struct pst_debug_file_rec_m mfile_rec; | |
333 unsigned char rec_type; | |
334 int index_size = 3 * sizeof(off_t); | |
335 off_t index[3]; | |
336 off_t index_pos, file_pos; | |
337 char zero='\0'; | |
338 unsigned int end; | |
339 if (!debug_fp) return; // no file | |
340 index[0] = 1; //only one item in this index | |
341 index_pos = ftell(debug_fp); | |
342 fwrite(index, index_size, 1, debug_fp); | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
343 |
46 | 344 index[1] = ftell(debug_fp); |
16 | 345 |
46 | 346 if (size > USHRT_MAX) { // bigger than can be stored in a short |
347 rec_type = 'L'; | |
348 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
349 lfile_rec.type = item->type; | |
350 lfile_rec.line = item->line; | |
351 lfile_rec.funcname = 0; | |
352 lfile_rec.filename = strlen(item->function)+1; | |
353 lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; | |
354 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
355 } else { | |
356 rec_type = 'M'; | |
357 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
358 mfile_rec.type = item->type; | |
359 mfile_rec.line = item->line; | |
360 mfile_rec.funcname = 0; | |
361 mfile_rec.filename = strlen(item->function)+1; | |
362 mfile_rec.text = mfile_rec.filename+strlen(item->file)+1; | |
363 fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); | |
364 } | |
365 file_pos = ftell(debug_fp); | |
366 fwrite(item->function, strlen(item->function)+1, 1, debug_fp); | |
367 fwrite(item->file, strlen(item->file)+1, 1, debug_fp); | |
368 vfprintf(debug_fp, fmt, *ap); | |
369 fwrite(&zero, 1, 1, debug_fp); | |
16 | 370 |
46 | 371 end = ftell(debug_fp)-file_pos; |
16 | 372 |
46 | 373 index[2] = ftell(debug_fp); |
374 fseek(debug_fp, index_pos, SEEK_SET); | |
375 fwrite(index, index_size, 1, debug_fp); | |
376 if (size > USHRT_MAX) { | |
377 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
378 lfile_rec.end = end; | |
379 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
380 } else { | |
381 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
382 mfile_rec.end = end; | |
383 fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); | |
384 } | |
385 fseek(debug_fp, 0, SEEK_END); | |
16 | 386 } |
387 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
388 |
46 | 389 void pst_debug_write_hex(struct pst_debug_item *item, unsigned char *buf, size_t size, int col) { |
390 struct pst_debug_file_rec_l lfile_rec; | |
391 unsigned char rec_type; | |
392 int index_size = 3 * sizeof(off_t); | |
393 off_t index_pos, file_pos, index[3]; | |
394 char zero='\0'; | |
395 if (!debug_fp) return; // no file | |
396 index[0] = 1; // only one item in this index run | |
397 index[1] = 0; // valgrind, avoid writing uninitialized data | |
398 index[2] = 0; // "" | |
399 index_pos = ftell(debug_fp); | |
400 fwrite(index, index_size, 1, debug_fp); | |
401 index[1] = ftell(debug_fp); | |
16 | 402 |
46 | 403 // always use the long |
404 rec_type = 'L'; | |
405 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
406 lfile_rec.funcname = 0; | |
407 lfile_rec.filename = strlen(item->function)+1; | |
408 lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; | |
409 lfile_rec.end = 0; // valgrind, avoid writing uninitialized data | |
410 lfile_rec.line = item->line; | |
411 lfile_rec.type = item->type; | |
412 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
16 | 413 |
46 | 414 file_pos = ftell(debug_fp); |
415 fwrite(item->function, strlen(item->function)+1, 1, debug_fp); | |
416 fwrite(item->file, strlen(item->file)+1, 1, debug_fp); | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
417 |
46 | 418 pst_debug_hexdumper(debug_fp, buf, size, col, 0); |
419 fwrite(&zero, 1, 1, debug_fp); | |
420 lfile_rec.end = ftell(debug_fp) - file_pos; | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
421 |
46 | 422 index[2] = ftell(debug_fp); |
423 fseek(debug_fp, index_pos, SEEK_SET); | |
424 fwrite(index, index_size, 1, debug_fp); | |
425 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
426 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
427 fseek(debug_fp, 0, SEEK_END); | |
16 | 428 } |
429 | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
430 |
36 | 431 void *xmalloc(size_t size) { |
46 | 432 void *mem = malloc(size); |
433 if (!mem) { | |
434 fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size); | |
435 exit(1); | |
436 } | |
437 return mem; | |
33
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
438 } |
12cac756bc05
enable -d option, but if not specified, don't generate a debug file
carl
parents:
31
diff
changeset
|
439 |