grass  7.8.6
About: GRASS (Geographic Resources Analysis Support System) is a raster- and vector-based GIS, image processing system, graphics production system and spatial modeling system.
  Fossies Dox: grass-7.8.6.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

error.c
Go to the documentation of this file.
1/*!
2 * \file lib/gis/error.c
3 *
4 * \brief GIS Library - Error messages functions
5 *
6 * (C) 1999-2011 by the GRASS Development Team
7 *
8 * This program is free software under the GNU General Public
9 * License (>=v2). Read the file COPYING that comes with GRASS
10 * for details.
11 *
12 * \author USACERL and many others
13 */
14
15#include <stdlib.h>
16#include <string.h>
17#include <setjmp.h>
18#include <unistd.h>
19#include <time.h>
20#include <stdarg.h>
21#include <sys/types.h>
22#include <grass/glocale.h>
23#include <grass/gis.h>
24
25#include "gis_local_proto.h"
26
27/*!
28 * \def MSG
29 *
30 * \brief A message
31 */
32#define MSG 0
33/*!
34 * \def WARN
35 *
36 * \brief A warning message
37 */
38#define WARN 1
39/*!
40 * \def ERR
41 *
42 * \brief A fatal error message
43 */
44#define ERR 2
45
46
47/* static int (*error)() = 0; */
48static int (*ext_error) (const char *, int); /* Roger Bivand 17 June 2000 */
49static int no_warn = FALSE;
50static int no_sleep = TRUE;
51
53static char *logfile;
54static char *prefix_std[3];
55static struct Counter message_id;
56
57static int print_word(FILE *, char **, int *, const int);
58static void print_sentence(FILE *, const int, const char *);
59static void print_error(const char *, const int);
60static void mail_msg(const char *, int);
61static int write_error(const char *, int, time_t, const char *);
62static void log_error(const char *, int);
63
64static int fatal_longjmp;
65static jmp_buf fatal_jmp_buf;
66
67jmp_buf *G_fatal_longjmp(int enable)
68{
69 fatal_longjmp = enable;
70 return &fatal_jmp_buf;
71}
72
73static void vfprint_error(int type, const char *template, va_list ap)
74{
75 char *buffer = NULL;
76
77 G_vasprintf(&buffer, template, ap);
78
81}
82
83/*!
84 * \brief Print a message to stderr
85 *
86 * The output format depends on environment variable GRASS_MESSAGE_FORMAT
87 *
88 * \param msg string (cannot be NULL)
89 */
90void G_message(const char *msg, ...)
91{
92 if (G_verbose() >= G_verbose_std()) {
93 va_list ap;
94
95 va_start(ap, msg);
96 vfprint_error(MSG, msg, ap);
97 va_end(ap);
98 }
99}
100
101/*!
102 * \brief Print a message to stderr but only if module is in verbose mode
103 *
104 * The output format depends on environment variables
105 * GRASS_MESSAGE_FORMAT and GRASS_VERBOSE
106 *
107 * \param msg string (cannot be NULL)
108 */
109void G_verbose_message(const char *msg, ...)
110{
111 if (G_verbose() > G_verbose_std()) {
112 va_list ap;
113
114 va_start(ap, msg);
115 vfprint_error(MSG, msg, ap);
116 va_end(ap);
117 }
118}
119
120/*!
121 * \brief Print a message to stderr even in brief mode (verbosity=1)
122 *
123 * Usually just G_percent()/G_clicker() would be shown at this level.
124 * This allows important non-error/warning messages to display as well.
125 *
126 * The output format depends on environment variables
127 * GRASS_MESSAGE_FORMAT and GRASS_VERBOSE
128 *
129 * \param msg string (cannot be NULL)
130 */
131void G_important_message(const char *msg, ...)
132{
133 if (G_verbose() > G_verbose_min()) {
134 va_list ap;
135
136 va_start(ap, msg);
137 vfprint_error(MSG, msg, ap);
138 va_end(ap);
139 }
140}
141
142/*!
143 * \brief Print a fatal error message to stderr
144 *
145 * The output format depends on environment variable
146 * GRASS_MESSAGE_FORMAT
147 *
148 * By default, the message is handled by an internal routine which
149 * prints the message to the screen. Using G_set_error_routine() the
150 * programmer can have the message handled by another routine. This is
151 * especially useful if the message should go to a particular location
152 * on the screen when using curses or to a location on a graphics
153 * device (monitor).
154 *
155 * \param msg string (cannot be NULL)
156
157 * \return Terminates with an exit status of EXIT_FAILURE if no external
158 * routine is specified by G_set_error_routine()
159 */
160void G_fatal_error(const char *msg, ...)
161{
162 static int busy;
163 va_list ap;
164
165 if (busy)
166 exit(EXIT_FAILURE);
167 busy = 1;
168
169 if (G_verbose() > -1) {
170 va_start(ap, msg);
171 vfprint_error(ERR, msg, ap);
172 va_end(ap);
173 }
174
175 if (fatal_longjmp) {
176 busy = 0;
177 longjmp(fatal_jmp_buf, 1);
178 }
179
181
182 /* Raise SIGABRT, useful for debugging only.
183 * Type "export GRASS_ABORT_ON_ERROR=1"
184 * to enable this feature using bash.
185 */
186 if (getenv("GRASS_ABORT_ON_ERROR"))
187 abort();
188
189 exit(EXIT_FAILURE);
190}
191
192/*!
193 * \brief Print a warning message to stderr
194 *
195 * The output format depends on environment variable
196 * GRASS_MESSAGE_FORMAT
197 *
198 * A warning message can be suppressed by G_suppress_warnings()
199 *
200 * \param msg string (cannot be NULL)
201 *
202 * \return
203 */
204void G_warning(const char *msg, ...)
205{
206 va_list ap;
207
208 if (no_warn || G_verbose() < 0)
209 return;
210
211 va_start(ap, msg);
212 vfprint_error(WARN, msg, ap);
213 va_end(ap);
214}
215
216/*!
217 * \brief Suppress printing a warning message to stderr
218 *
219 * \param flag a warning message will be suppressed if non-zero value is given
220 *
221 * \return previous flag
222 */
224{
225 int prev;
226
227 prev = no_warn;
228 no_warn = flag;
229 return prev;
230}
231
232/*!
233 * \brief Turn on/off no_sleep flag
234 *
235 * If <em>flag</em> is 0, then no pause will occur after printing an
236 * error or warning message. Otherwise the pause will occur.
237 *
238 * \param flag if non-zero/zero value is given G_sleep() will be
239 * activated/deactivated
240 *
241 * \return previous no_sleep value
242 */
243int G_sleep_on_error(int flag)
244{
245 int prev;
246
247 prev = !no_sleep;
248 no_sleep = !flag;
249 return prev;
250}
251
252/*!
253 * \brief Establishes error_routine as the routine that will handle
254 * the printing of subsequent error messages.
255 *
256 * \param error_routine routine will be called like this: error_routine(msg,
257 * fatal)
258 *
259 * \return
260 */
261void G_set_error_routine(int (*error_routine) (const char *, int))
262{
263 ext_error = error_routine; /* Roger Bivand 17 June 2000 */
264}
265
266/*!
267 * \brief After this call subsequent error messages will be handled in the
268 * default method.
269 *
270 * Error messages are printed directly to the screen: ERROR: message or WARNING: message
271 *
272 * \return 0
273 */
275{
276 ext_error = 0; /* Roger Bivand 17 June 2000 */
277}
278
279/* Print info to stderr and optionally to log file and optionally send mail */
280static void print_error(const char *msg, const int type)
281{
282 int fatal, format;
283
284 if (type == ERR)
285 fatal = TRUE;
286 else /* WARN */
287 fatal = FALSE;
288
289 if ((type == MSG || type == WARN || type == ERR) && ext_error) { /* Function defined by application */
290 ext_error(msg, fatal);
291 }
292 else {
295
296 if (type == WARN || type == ERR)
297 log_error(msg, fatal);
298
300 return;
301
302 if (format != G_INFO_FORMAT_GUI) {
304 char *w;
305 int len, lead;
306
307 fprintf(stderr, "%s", prefix_std[type]);
308 len = lead = strlen(prefix_std[type]);
309 w = (char *)msg;
310
311 while (print_word(stderr, &w, &len, lead)) ;
312 }
313 else {
314 fprintf(stderr, "%s%s\n", prefix_std[type], msg);
315 }
316
317 if ((type != MSG) && isatty(fileno(stderr))
318 && (G_info_format() == G_INFO_FORMAT_STANDARD)) { /* Bell */
319 fprintf(stderr, "\7");
320 fflush(stderr);
321 if (!no_sleep)
322 G_sleep(5);
323 }
324 else if ((type == WARN || type == ERR) && getenv("GRASS_ERROR_MAIL")) { /* Mail */
325 mail_msg(msg, fatal);
326 }
327 }
328 else { /* GUI */
329 print_sentence(stderr, type, msg);
330 }
331 }
332}
333
334static void log_error(const char *msg, int fatal)
335{
336 char cwd[GPATH_MAX];
337 time_t clock;
338 const char *gisbase;
339
340 /* get time */
341 clock = time(NULL);
342
343 /* get current working directory */
344 getcwd(cwd, sizeof(cwd));
345
346 /* write the error log file */
347 if ((gisbase = G_gisbase()))
348 write_error(msg, fatal, clock, cwd);
349}
350
352{
353 static int initialized;
354 char *fstr;
355
357 return;
358
360
361 prefix_std[0] = "";
362 prefix_std[1] = _("WARNING: ");
363 prefix_std[2] = _("ERROR: ");
364
365 logfile = getenv("GIS_ERROR_LOG");
366 if (!logfile) {
367 char buf[GPATH_MAX];
368 sprintf(buf, "%s/GIS_ERROR_LOG", G__home());
369 logfile = G_store(buf);
370 }
371
372 fstr = getenv("GRASS_MESSAGE_FORMAT");
373
374 if (fstr && G_strcasecmp(fstr, "gui") == 0)
376 else if (fstr && G_strcasecmp(fstr, "silent") == 0)
378 else if (fstr && G_strcasecmp(fstr, "plain") == 0)
380 else
382
384}
385
386/* Write a message to the log file */
387static int write_error(const char *msg, int fatal,
388 time_t clock, const char *cwd)
389{
390 FILE *log;
391
393
394 log = fopen(logfile, "r");
395 if (!log)
396 /* GIS_ERROR_LOG file is not readable or does not exist */
397 return 1;
398
399 log = freopen(logfile, "a", log);
400 if (!log)
401 /* the user doesn't have write permission */
402 return 1;
403
404 fprintf(log, "-------------------------------------\n");
405 fprintf(log, "%-10s %s\n", "program:", G_program_name());
406 fprintf(log, "%-10s %s\n", "user:", G_whoami());
407 fprintf(log, "%-10s %s\n", "cwd:", cwd);
408 fprintf(log, "%-10s %s\n", "date:", ctime(&clock));
409 fprintf(log, "%-10s %s\n", fatal ? "error:" : "warning:", msg);
410 fprintf(log, "-------------------------------------\n");
411
412 fclose(log);
413
414 return 0;
415}
416
417/* Mail a message */
418static void mail_msg(const char *msg, int fatal)
419{
420 struct Popen mail;
421 FILE *fp = G_open_mail(&mail);
422
423 if (fp)
424 fprintf(fp, "GIS %s: %s\n", fatal ? "ERROR" : "WARNING", msg);
425
426 G_close_mail(&mail);
427}
428
429/* Print one word, new line if necessary */
430static int print_word(FILE * fd, char **word, int *len, const int lead)
431{
432 int wlen, start, totlen;
433 int nl;
434 char *w, *b;
435
436 start = *len;
437 w = *word;
438
439 nl = 0;
440 while (*w == ' ' || *w == '\t' || *w == '\n')
441 if (*w++ == '\n')
442 nl++;
443
444 wlen = 0;
445 for (b = w; *b != 0 && *b != ' ' && *b != '\t' && *b != '\n'; b++)
446 wlen++;
447
448 if (wlen == 0) {
449 fprintf(fd, "\n");
450 return 0;
451 }
452
453 if (start > lead) { /* add space */
454 totlen = start + wlen + 1;
455 }
456 else {
457 totlen = start + wlen;
458 }
459
460 if (nl != 0 || totlen > 75) {
461 while (--nl > 0)
462 fprintf(fd, "\n");
463 fprintf(fd, "\n%*s", lead, "");
464 start = lead;
465 }
466
467 if (start > lead) {
468 fprintf(fd, " ");
469 start++;
470 }
471
472 *len = start + wlen;
473
474 fwrite(w, 1, wlen, fd);
475 w += wlen;
476
477 *word = w;
478
479 return 1;
480}
481
482/* Print one message, prefix inserted before each new line */
483static void print_sentence(FILE * fd, const int type, const char *msg)
484{
485 char prefix[100];
486 const char *start;
487 int id = G_counter_next(&message_id);
488
489 switch (type) {
490 case MSG:
491 sprintf(prefix, "GRASS_INFO_MESSAGE(%d,%d): ", getpid(), id);
492 break;
493 case WARN:
494 sprintf(prefix, "GRASS_INFO_WARNING(%d,%d): ", getpid(), id);
495 break;
496 case ERR:
497 sprintf(prefix, "GRASS_INFO_ERROR(%d,%d): ", getpid(), id);
498 break;
499 }
500
501 start = msg;
502
503 fprintf(stderr, "\n");
504 while (*start != '\0') {
505 const char *next = start;
506
507 fprintf(fd, "%s", prefix);
508
509 while (*next != '\0') {
510 next++;
511
512 if (*next == '\n') {
513 next++;
514 break;
515 }
516 }
517
518 fwrite(start, 1, next - start, fd);
519 fprintf(fd, "\n");
520 start = next;
521 }
522 fprintf(stderr, "GRASS_INFO_END(%d,%d)\n", getpid(), id);
523}
524
525/*!
526 * \brief Get current message format
527 *
528 * Maybe set to either "standard" or "gui" (normally GRASS takes care)
529 *
530 * \return grass_info_format value
531 */
533{
535
536 return grass_info_format;
537}
int G_vasprintf(char **out, const char *fmt, va_list ap)
Safe replacement for asprintf().
Definition: asprintf.c:42
#define NULL
Definition: ccmath.h:32
void G_initialize_done(int *p)
Definition: counter.c:76
void G_init_counter(struct Counter *c, int v)
Definition: counter.c:38
int G_is_initialized(int *p)
Definition: counter.c:59
int G_counter_next(struct Counter *c)
Definition: counter.c:46
char * getenv()
static int initialized
Definition: debug.c:21
static int type
Definition: fpxdr.c:101
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
void G_verbose_message(const char *msg,...)
Print a message to stderr but only if module is in verbose mode.
Definition: error.c:109
static void log_error(const char *, int)
Definition: error.c:334
int G_sleep_on_error(int flag)
Turn on/off no_sleep flag.
Definition: error.c:243
#define MSG
A message.
Definition: error.c:32
void G_set_error_routine(int(*error_routine)(const char *, int))
Establishes error_routine as the routine that will handle the printing of subsequent error messages.
Definition: error.c:261
static void print_error(const char *, const int)
Definition: error.c:280
#define WARN
A warning message.
Definition: error.c:38
static int(* ext_error)(const char *, int)
Definition: error.c:48
static char * logfile
Definition: error.c:53
static int fatal_longjmp
Definition: error.c:64
static int print_word(FILE *, char **, int *, const int)
Definition: error.c:430
static int grass_info_format
Definition: error.c:52
void G_important_message(const char *msg,...)
Print a message to stderr even in brief mode (verbosity=1)
Definition: error.c:131
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: error.c:160
#define ERR
A fatal error message.
Definition: error.c:44
void G_message(const char *msg,...)
Print a message to stderr.
Definition: error.c:90
int G_suppress_warnings(int flag)
Suppress printing a warning message to stderr.
Definition: error.c:223
jmp_buf * G_fatal_longjmp(int enable)
Definition: error.c:67
static char * prefix_std[3]
Definition: error.c:54
static int no_warn
Definition: error.c:49
static int no_sleep
Definition: error.c:50
static void print_sentence(FILE *, const int, const char *)
Definition: error.c:483
void G_unset_error_routine(void)
After this call subsequent error messages will be handled in the default method.
Definition: error.c:274
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: error.c:204
int G_info_format(void)
Get current message format.
Definition: error.c:532
void G_init_logging(void)
Definition: error.c:351
static void vfprint_error(int type, const char *template, va_list ap)
Definition: error.c:73
static jmp_buf fatal_jmp_buf
Definition: error.c:65
static int write_error(const char *, int, time_t, const char *)
Definition: error.c:387
static struct Counter message_id
Definition: error.c:55
static void mail_msg(const char *, int)
Definition: error.c:418
const char * G_whoami(void)
Gets user's name.
Definition: whoami.c:35
#define G_INFO_FORMAT_GUI
Definition: gis.h:361
#define G_INFO_FORMAT_PLAIN
Definition: gis.h:363
#define GPATH_MAX
Definition: gis.h:170
#define TRUE
Definition: gis.h:59
#define FALSE
Definition: gis.h:63
#define G_INFO_FORMAT_STANDARD
Definition: gis.h:360
#define G_INFO_FORMAT_SILENT
Definition: gis.h:362
const char * G__home(void)
Get user's home directory (internal use only)
Definition: home.c:53
void G__call_error_handlers(void)
Call available error handlers (internal use only)
Definition: handler.c:101
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:41
#define _(str)
Definition: glocale.h:13
static void format(char *, int, int, double, char)
Definition: ll_format.c:87
static int next(char **replace, int num_replace)
Definition: mkstemp.c:24
def fatal(msg)
Definition: grass.py:209
void G_close_mail(struct Popen *mail)
Definition: pager.c:65
FILE * G_open_mail(struct Popen *mail)
Definition: pager.c:45
static char * buffer
Definition: portable.c:47
const char * G_program_name(void)
Return module name.
Definition: progrm_nme.c:28
double b
Definition: r_raster.c:39
void G_sleep(unsigned int seconds)
Definition: sleep.c:11
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:46
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:86
Definition: gis.h:594
Definition: gis.h:598
FILE * fp
Definition: gis.h:599
int G_verbose(void)
Get current verbosity level.
Definition: verbose.c:55
int G_verbose_min(void)
Get min verbosity level.
Definition: verbose.c:96
int G_verbose_std(void)
Get standard verbosity level.
Definition: verbose.c:86