GRASS Programmer's Manual  6.4.3(2013)-r
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
lib/gis/error.c
Go to the documentation of this file.
1 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <time.h>
19 #include <stdarg.h>
20 #include <sys/types.h>
21 #include <grass/glocale.h>
22 #include <grass/gis.h>
23 
29 #define MSG 0
30 
35 #define WARN 1
36 
41 #define ERR 2
42 
43 
44 /* static int (*error)() = 0; */
45 static int (*ext_error) (const char *, int); /* Roger Bivand 17 June 2000 */
46 static int no_warn = 0;
47 static int no_sleep = 1;
48 static int message_id = 1;
49 
50 static int print_word(FILE *, char **, int *, const int);
51 static void print_sentence(FILE *, const int, const char *);
52 static int print_error(const char *, const int);
53 static int mail_msg(const char *, int);
54 static int write_error(const char *, int, time_t, const char *);
55 static int log_error(const char *, int);
56 
57 static int vfprint_error(int type, const char *template, va_list ap)
58 {
59  char buffer[2000]; /* G_asprintf does not work */
60 
61  vsprintf(buffer, template, ap);
62 
63  /* . */
64  return print_error(buffer, type);
65 }
66 
74 void G_message(const char *msg, ...)
75 {
76  if (G_verbose() >= G_verbose_std()) {
77  va_list ap;
78 
79  va_start(ap, msg);
80  vfprint_error(MSG, msg, ap);
81  va_end(ap);
82  }
83 
84  return;
85 }
86 
95 void G_verbose_message(const char *msg, ...)
96 {
97  if (G_verbose() > G_verbose_std()) {
98  va_list ap;
99 
100  va_start(ap, msg);
101  vfprint_error(MSG, msg, ap);
102  va_end(ap);
103  }
104 
105  return;
106 }
107 
119 void G_important_message(const char *msg, ...)
120 {
121  if (G_verbose() > G_verbose_min()) {
122  va_list ap;
123 
124  va_start(ap, msg);
125  vfprint_error(MSG, msg, ap);
126  va_end(ap);
127  }
128 
129  return;
130 }
131 
150 int G_fatal_error(const char *msg, ...)
151 {
152  va_list ap;
153 
154  va_start(ap, msg);
155  vfprint_error(ERR, msg, ap);
156  va_end(ap);
157 
158  exit(EXIT_FAILURE);
159 }
160 
173 int G_warning(const char *msg, ...)
174 {
175  va_list ap;
176 
177  if (no_warn)
178  return 0;
179 
180  va_start(ap, msg);
181  vfprint_error(WARN, msg, ap);
182  va_end(ap);
183 
184  return 0;
185 }
186 
195 {
196  int prev;
197 
198  prev = no_warn;
199  no_warn = flag;
200  return prev;
201 }
202 
211 {
212  int prev;
213 
214  prev = !no_sleep;
215  no_sleep = !flag;
216  return prev;
217 }
218 
228 int G_set_error_routine(int (*error_routine) (const char *, int))
229 {
230  ext_error = error_routine; /* Roger Bivand 17 June 2000 */
231  return 0;
232 }
233 
243 {
244  ext_error = 0; /* Roger Bivand 17 June 2000 */
245 
246  return 0;
247 }
248 
249 /* Print info to stderr and optionally to log file and optionally send mail */
250 static int print_error(const char *msg, const int type)
251 {
252  static char *prefix_std[3];
253  int fatal, format;
254 
255  if (!prefix_std[0]) { /* First time: set prefixes */
256  prefix_std[0] = "";
257  prefix_std[1] = _("WARNING: ");
258  prefix_std[2] = _("ERROR: ");
259  }
260 
261  if (type == ERR)
262  fatal = TRUE;
263  else /* WARN */
264  fatal = FALSE;
265 
266  if ((type == WARN || type == ERR) && ext_error) { /* Function defined by application */
267  ext_error(msg, fatal);
268  }
269  else {
270  char *w;
271  int len, lead;
272 
273  format = G_info_format();
274 
275  if (format != G_INFO_FORMAT_GUI) {
276  if (type == WARN || type == ERR) {
277  log_error(msg, fatal);
278  }
279 
280  fprintf(stderr, "%s", prefix_std[type]);
281  len = lead = strlen(prefix_std[type]);
282  w = (char *)msg;
283 
284  while (print_word(stderr, &w, &len, lead)) ;
285 
286  if ((type != MSG) && isatty(fileno(stderr))
287  && (G_info_format() == G_INFO_FORMAT_STANDARD)) { /* Bell */
288  fprintf(stderr, "\7");
289  fflush(stderr);
290  if (!no_sleep)
291  G_sleep(5);
292  }
293  else if ((type == WARN || type == ERR) && getenv("GRASS_ERROR_MAIL")) { /* Mail */
294  mail_msg(msg, fatal);
295  }
296  }
297  else { /* GUI */
298  print_sentence(stderr, type, msg);
299  }
300  }
301 
302  return 0;
303 }
304 
305 static int log_error(const char *msg, int fatal)
306 {
307  char cwd[GPATH_MAX];
308  time_t clock;
309  char *gisbase;
310 
311  /* get time */
312  clock = time(NULL);
313 
314  /* get current working directory */
315  getcwd(cwd, sizeof(cwd));
316 
317  /* write the error log file */
318  if ((gisbase = G_gisbase()))
319  write_error(msg, fatal, clock, cwd);
320 
321  return 0;
322 }
323 
324 /* Write a message to the log file */
325 static int write_error(const char *msg, int fatal,
326  time_t clock, const char *cwd)
327 {
328  static char *logfile;
329  FILE *log;
330 
331  if (!logfile) {
332  logfile = getenv("GIS_ERROR_LOG");
333  if (!logfile) {
334  char buf[GPATH_MAX];
335 
336  sprintf(buf, "%s/GIS_ERROR_LOG", G__home());
337  logfile = G_store(buf);
338  }
339  }
340 
341  log = fopen(logfile, "r");
342  if (!log)
343  /* GIS_ERROR_LOG file is not readable or does not exist */
344  return 1;
345 
346  log = freopen(logfile, "a", log);
347  if (!log)
348  /* the user doesn't have write permission */
349  return 1;
350 
351  fprintf(log, "-------------------------------------\n");
352  fprintf(log, "%-10s %s\n", "program:", G_program_name());
353  fprintf(log, "%-10s %s\n", "user:", G_whoami());
354  fprintf(log, "%-10s %s\n", "cwd:", cwd);
355  fprintf(log, "%-10s %s\n", "date:", ctime(&clock));
356  fprintf(log, "%-10s %s\n", fatal ? "error:" : "warning:", msg);
357  fprintf(log, "-------------------------------------\n");
358 
359  fclose(log);
360 
361  return 0;
362 }
363 
364 /* Mail a message */
365 static int mail_msg(const char *msg, int fatal)
366 {
367  FILE *mail;
368  char command[64];
369  char *user;
370 
371  user = G_whoami();
372  if (user == 0 || *user == 0)
373  return 1;
374 
375  sprintf(command, "mail '%s'", G_whoami());
376  if ((mail = popen(command, "w"))) {
377  fprintf(mail, "GIS %s: %s\n", fatal ? "ERROR" : "WARNING", msg);
378  G_pclose(mail);
379  }
380 
381  return 0;
382 }
383 
384 /* Print one word, new line if necessary */
385 static int print_word(FILE * fd, char **word, int *len, const int lead)
386 {
387  int wlen, start, totlen;
388  int nl;
389  char *w, *b;
390 
391  start = *len;
392  w = *word;
393 
394  nl = 0;
395  while (*w == ' ' || *w == '\t' || *w == '\n')
396  if (*w++ == '\n')
397  nl++;
398 
399  wlen = 0;
400  for (b = w; *b != 0 && *b != ' ' && *b != '\t' && *b != '\n'; b++)
401  wlen++;
402 
403  if (wlen == 0) {
404  fprintf(fd, "\n");
405  return 0;
406  }
407 
408  if (start > lead) { /* add space */
409  totlen = start + wlen + 1;
410  }
411  else {
412  totlen = start + wlen;
413  }
414 
415  if (nl != 0 || totlen > 75) {
416  while (--nl > 0)
417  fprintf(fd, "\n");
418  fprintf(fd, "\n%*s", lead, "");
419  start = lead;
420  }
421 
422  if (start > lead) {
423  fprintf(fd, " ");
424  start++;
425  }
426 
427  *len = start + wlen;
428 
429  fwrite(w, 1, wlen, fd);
430  w += wlen;
431 
432  *word = w;
433 
434  return 1;
435 }
436 
437 /* Print one message, prefix inserted before each new line */
438 static void print_sentence(FILE * fd, const int type, const char *msg)
439 {
440  char prefix[100];
441  const char *start;
442 
443  switch (type) {
444  case MSG:
445  sprintf(prefix, "GRASS_INFO_MESSAGE(%d,%d): ", getpid(), message_id);
446  break;
447  case WARN:
448  sprintf(prefix, "GRASS_INFO_WARNING(%d,%d): ", getpid(), message_id);
449  break;
450  case ERR:
451  sprintf(prefix, "GRASS_INFO_ERROR(%d,%d): ", getpid(), message_id);
452  break;
453  }
454 
455  start = msg;
456 
457  fprintf(stderr, "\n");
458  while (*start != '\0') {
459  const char *next = start;
460 
461  fprintf(fd, "%s", prefix);
462 
463  while (*next != '\0') {
464  next++;
465 
466  if (*next == '\n') {
467  next++;
468  break;
469  }
470  }
471 
472  fwrite(start, 1, next - start, fd);
473  fprintf(fd, "\n");
474  start = next;
475  }
476  fprintf(stderr, "GRASS_INFO_END(%d,%d)\n", getpid(), message_id);
477  message_id++;
478 }
479 
487 int G_info_format(void)
488 {
489  static int grass_info_format = -1;
490  char *fstr;
491 
492  if (grass_info_format < 0) {
493  fstr = getenv("GRASS_MESSAGE_FORMAT");
494 
495  if (fstr && G_strcasecmp(fstr, "gui") == 0)
496  grass_info_format = G_INFO_FORMAT_GUI;
497  else if (fstr && G_strcasecmp(fstr, "silent") == 0)
498  grass_info_format = G_INFO_FORMAT_SILENT;
499  else if (fstr && G_strcasecmp(fstr, "plain") == 0)
500  grass_info_format = G_INFO_FORMAT_PLAIN;
501  else
502  grass_info_format = G_INFO_FORMAT_STANDARD;
503  }
504 
505  return grass_info_format;
506 }