Remember fragment of the splitted char and decode it next time. Idea by Jonas.
[elinks.git] / src / util / error.c
blobe2d5408e81fc8622ca2be9b3efd4989f520e8743
1 /* Error handling and debugging stuff */
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE /* Needed for vasprintf() */
5 #endif
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
11 #include <signal.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
20 #ifdef HAVE_SYS_TIME_H
21 #include <sys/time.h>
22 #endif
23 #ifdef HAVE_TIME_H
24 #include <time.h>
25 #endif
27 #include "elinks.h"
29 #include "util/error.h"
30 #include "util/lists.h"
31 #include "util/memlist.h"
32 #include "util/memory.h"
33 #include "util/snprintf.h"
34 #include "util/string.h"
37 unsigned char full_static_version[1024] = "ELinks " VERSION_STRING;
39 static void
40 er(int bell, int shall_sleep, unsigned char *fmt, va_list params)
42 if (bell)
43 #ifdef CONFIG_OS_WIN32
44 MessageBeep(MB_ICONEXCLAMATION);
45 #else
46 fputc(7, stderr); /* load and annoying on Windows */
47 #endif
48 vfprintf(stderr, fmt, params);
49 fputc('\n', stderr);
50 fflush(stderr);
51 if (shall_sleep) sleep(1);
54 int errline;
55 unsigned char *errfile;
57 void
58 elinks_debug(unsigned char *fmt, ...)
60 unsigned char errbuf[4096];
61 va_list params;
63 va_start(params, fmt);
65 snprintf(errbuf, sizeof(errbuf), "DEBUG MESSAGE at %s:%d: %s",
66 errfile, errline, fmt);
68 er(0, 0, errbuf, params);
70 va_end(params);
73 void
74 elinks_wdebug(unsigned char *fmt, ...)
76 unsigned char errbuf[4096];
77 va_list params;
79 va_start(params, fmt);
81 snprintf(errbuf, sizeof(errbuf), "DEBUG MESSAGE at %s:%d: %s",
82 errfile, errline, fmt);
84 er(0, 1, errbuf, params);
86 va_end(params);
89 void
90 elinks_error(unsigned char *fmt, ...)
92 unsigned char errbuf[4096];
93 va_list params;
95 va_start(params, fmt);
97 snprintf(errbuf, sizeof(errbuf), "ERROR at %s:%d: %s",
98 errfile, errline, fmt);
100 er(1, 1, errbuf, params);
102 va_end(params);
105 void
106 elinks_internal(unsigned char *fmt, ...)
108 unsigned char errbuf[4096];
109 va_list params;
111 va_start(params, fmt);
113 snprintf(errbuf, sizeof(errbuf),
114 "\033[1mINTERNAL ERROR\033[0m at %s:%d: %s",
115 errfile, errline, fmt);
117 er(1, 1, errbuf, params);
119 va_end(params);
120 #ifdef CONFIG_DEBUG
121 force_dump();
122 #endif
126 void
127 usrerror(unsigned char *fmt, ...)
129 va_list params;
131 va_start(params, fmt);
133 fputs("ELinks: ", stderr);
134 vfprintf(stderr, fmt, params);
135 fputc('\n', stderr);
136 fflush(stderr);
138 va_end(params);
142 int assert_failed = 0;
144 void
145 elinks_assertm(int x, unsigned char *fmt, ...)
147 unsigned char *buf = NULL;
148 va_list params;
150 if (assert_failed) return;
151 if (!(assert_failed = !x)) return;
153 va_start(params, fmt);
154 vasprintf((char **) &buf, fmt, params);
155 va_end(params);
156 elinks_internal("assertion failed: %s", buf);
157 if (buf) free(buf);
161 #ifdef CONFIG_DEBUG
162 void
163 force_dump(void)
165 fprintf(stderr,
166 "\n\033[1m%s\033[0m %s\n", "Forcing core dump!",
167 "Man the Lifeboats! Women and children first!\n");
168 fputs("But please DO NOT report this as a segfault!!! It is an internal error, not a\n"
169 "normal segfault, there is a huge difference in these for us the developers.\n"
170 "Also, noting the EXACT error you got above is crucial for hunting the problem\n"
171 "down. Thanks, and please get in touch with us.\n",
172 stderr);
173 #ifndef CONFIG_BACKTRACE
174 fputs(full_static_version, stderr);
175 fputc('\n', stderr);
176 #endif
177 fflush(stderr);
178 raise(SIGSEGV);
181 static FILE *log_file = NULL;
183 static void
184 done_log(void)
186 unsigned char errbuf[4096];
187 time_t curtime = time(NULL);
188 struct tm *loctime = localtime(&curtime);
189 int len;
191 len = strftime(errbuf, sizeof(errbuf), "%a, %d %b %Y %H:%M:%S %z",
192 loctime);
193 errbuf[len] = '\0';
195 fprintf(log_file, "[%-5s %-15s %4s]: Log stopped at %s\n\n\n",
196 "", "", "", errbuf);
198 fclose(log_file);
201 void
202 elinks_log(unsigned char *msg, unsigned char *file, int line,
203 unsigned char *fmt, ...)
205 static unsigned char *log_files = NULL;
206 static unsigned char *log_msg = NULL;
207 unsigned char errbuf[4096];
208 va_list params;
210 if (!log_file) {
211 unsigned char *log_name;
212 time_t curtime = time(NULL);
213 struct tm *loctime = localtime(&curtime);
214 int len;
216 log_files = getenv("ELINKS_FILES");
217 log_msg = getenv("ELINKS_MSG");
218 log_name = getenv("ELINKS_LOG");
219 log_file = log_name ? fopen(log_name, "ab") : stderr;
221 if (!log_file) return;
223 len = strftime(errbuf, sizeof(errbuf), "%a, %d %b %Y %H:%M:%S %z",
224 loctime);
225 errbuf[len] = '\0';
227 fprintf(log_file, "\n\n[%-5s %-15s %4s]: Log started at %s\n",
228 "type", "file", "line", errbuf);
230 atexit(done_log);
233 if (log_files && !strstr(log_files, file))
234 return;
236 if (log_msg && !strstr(log_msg, msg))
237 return;
239 va_start(params, fmt);
241 snprintf(errbuf, sizeof(errbuf), "[%-5s %-15s %4d]: %s",
242 msg, file, line, fmt);
244 vfprintf(log_file, errbuf, params);
245 fputc('\n', log_file);
246 fflush(log_file);
248 va_end(params);
250 #endif
253 void
254 do_not_optimize_here(void *p)
256 /* stop GCC optimization - avoid bugs in it */
260 #ifdef CONFIG_BACKTRACE
262 /* The backtrace corner. */
264 #include <stdio.h>
265 #include <stdlib.h>
267 #ifdef HAVE_EXECINFO_H
268 #include <execinfo.h>
269 #endif
271 void
272 dump_backtrace(FILE *f, int trouble)
274 /* If trouble is set, when we get here, we can be in various
275 * interesting situations like inside of the SIGSEGV handler etc. So be
276 * especially careful here. Dynamic memory allocation may not work
277 * (corrupted stack). A lot of other things may not work too. So better
278 * don't do anything not 100% necessary. */
280 #ifdef HAVE_EXECINFO_H
281 /* glibc way of doing this */
283 void *stack[20];
284 size_t size;
285 char **strings;
286 size_t i;
288 size = backtrace(stack, 20);
290 if (trouble) {
291 /* Let's hope fileno() is safe. */
292 backtrace_symbols_fd(stack, size, fileno(f));
293 /* Now out! */
294 return;
297 strings = backtrace_symbols(stack, size);
299 fprintf(f, "Obtained %d stack frames:\n", (int) size);
301 for (i = 0; i < size; i++)
302 fprintf(f, "[%p] %s\n", stack[i], strings[i]);
304 free(strings);
306 #else
307 /* User torturation. */
308 /* You are worried about what you see here? You don't see anything in
309 * the first place. Also, be assured that we know what are we doing. */
310 /* (We are killing the user, obviously.) */
312 /* TODO: Gettextify? Er, better not. More people (translators) could
313 * find out what are we doing... ;-) --pasky */
314 /* TODO: Be more cruel when in trouble? ;-) --pasky */
316 fputs( "Wheeeeeeeeeee! You played with the config.h by hand, didn't you?\n"
317 "Of _COURSE_ you did! Is that how a nice .. creature behaves like?\n"
318 "Of _COURSE_ it isn't! I feel offended and thus I will revenge now!\n"
319 "You will _suffer_ >:).\n"
320 "\n"
321 "CPU burning sequence initiated...\n", f);
323 /* TODO: Include cpuburn.c here. --pasky */
324 while (1);
325 #endif
326 fflush(f);
329 #endif