GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
lib/gis/error.c
Go to the documentation of this file.
00001 
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <unistd.h>
00018 #include <time.h>
00019 #include <stdarg.h>
00020 #include <sys/types.h>
00021 #include <grass/glocale.h>
00022 #include <grass/gis.h>
00023 
00029 #define MSG  0
00030 
00035 #define WARN 1
00036 
00041 #define ERR  2
00042 
00043 
00044 /* static int (*error)() = 0; */
00045 static int (*ext_error) (const char *, int);    /* Roger Bivand 17 June 2000 */
00046 static int no_warn = 0;
00047 static int no_sleep = 1;
00048 static int message_id = 1;
00049 
00050 static int print_word(FILE *, char **, int *, const int);
00051 static void print_sentence(FILE *, const int, const char *);
00052 static int print_error(const char *, const int);
00053 static int mail_msg(const char *, int);
00054 static int write_error(const char *, int, time_t, const char *);
00055 static int log_error(const char *, int);
00056 
00057 static int vfprint_error(int type, const char *template, va_list ap)
00058 {
00059     char buffer[2000];          /* G_asprintf does not work */
00060 
00061     vsprintf(buffer, template, ap);
00062 
00063     /* . */
00064     return print_error(buffer, type);
00065 }
00066 
00074 void G_message(const char *msg, ...)
00075 {
00076     if (G_verbose() >= G_verbose_std()) {
00077         va_list ap;
00078 
00079         va_start(ap, msg);
00080         vfprint_error(MSG, msg, ap);
00081         va_end(ap);
00082     }
00083 
00084     return;
00085 }
00086 
00095 void G_verbose_message(const char *msg, ...)
00096 {
00097     if (G_verbose() > G_verbose_std()) {
00098         va_list ap;
00099 
00100         va_start(ap, msg);
00101         vfprint_error(MSG, msg, ap);
00102         va_end(ap);
00103     }
00104 
00105     return;
00106 }
00107 
00119 void G_important_message(const char *msg, ...)
00120 {
00121     if (G_verbose() > G_verbose_min()) {
00122         va_list ap;
00123 
00124         va_start(ap, msg);
00125         vfprint_error(MSG, msg, ap);
00126         va_end(ap);
00127     }
00128 
00129     return;
00130 }
00131 
00150 int G_fatal_error(const char *msg, ...)
00151 {
00152     va_list ap;
00153 
00154     va_start(ap, msg);
00155     vfprint_error(ERR, msg, ap);
00156     va_end(ap);
00157 
00158     exit(EXIT_FAILURE);
00159 }
00160 
00173 int G_warning(const char *msg, ...)
00174 {
00175     va_list ap;
00176 
00177     if (no_warn)
00178         return 0;
00179 
00180     va_start(ap, msg);
00181     vfprint_error(WARN, msg, ap);
00182     va_end(ap);
00183 
00184     return 0;
00185 }
00186 
00194 int G_suppress_warnings(int flag)
00195 {
00196     int prev;
00197 
00198     prev = no_warn;
00199     no_warn = flag;
00200     return prev;
00201 }
00202 
00210 int G_sleep_on_error(int flag)
00211 {
00212     int prev;
00213 
00214     prev = !no_sleep;
00215     no_sleep = !flag;
00216     return prev;
00217 }
00218 
00228 int G_set_error_routine(int (*error_routine) (const char *, int))
00229 {
00230     ext_error = error_routine;  /* Roger Bivand 17 June 2000 */
00231     return 0;
00232 }
00233 
00242 int G_unset_error_routine(void)
00243 {
00244     ext_error = 0;              /* Roger Bivand 17 June 2000 */
00245 
00246     return 0;
00247 }
00248 
00249 /* Print info to stderr and optionally to log file and optionally send mail */
00250 static int print_error(const char *msg, const int type)
00251 {
00252     static char *prefix_std[3];
00253     int fatal, format;
00254 
00255     if (!prefix_std[0]) {       /* First time: set prefixes  */
00256         prefix_std[0] = "";
00257         prefix_std[1] = _("WARNING: ");
00258         prefix_std[2] = _("ERROR: ");
00259     }
00260 
00261     if (type == ERR)
00262         fatal = TRUE;
00263     else                        /* WARN */
00264         fatal = FALSE;
00265 
00266     if ((type == MSG || type == WARN || type == ERR) && ext_error) {    /* Function defined by application */
00267         ext_error(msg, fatal);
00268     }
00269     else {
00270         format = G_info_format();
00271 
00272         if (type == WARN || type == ERR)
00273             log_error(msg, fatal);
00274 
00275         if (format == G_INFO_FORMAT_SILENT)
00276             return;
00277 
00278         if (format != G_INFO_FORMAT_GUI) {
00279             if (format != G_INFO_FORMAT_PLAIN) {
00280                 char *w;
00281                 int len, lead;
00282                 
00283                 fprintf(stderr, "%s", prefix_std[type]);
00284                 len = lead = strlen(prefix_std[type]);
00285                 w = (char *)msg;
00286                 
00287                 while (print_word(stderr, &w, &len, lead)) ;
00288             }
00289             else {
00290                 fprintf(stderr, "%s\n", msg);
00291             }
00292 
00293             if ((type != MSG) && isatty(fileno(stderr))
00294                 && (G_info_format() == G_INFO_FORMAT_STANDARD)) {       /* Bell */
00295                 fprintf(stderr, "\7");
00296                 fflush(stderr);
00297                 if (!no_sleep)
00298                     G_sleep(5);
00299             }
00300             else if ((type == WARN || type == ERR) && getenv("GRASS_ERROR_MAIL")) {     /* Mail */
00301                 mail_msg(msg, fatal);
00302             }
00303         }
00304         else {  /* GUI */
00305             print_sentence(stderr, type, msg);
00306         }
00307     }
00308 
00309     return 0;
00310 }
00311 
00312 static int log_error(const char *msg, int fatal)
00313 {
00314     char cwd[GPATH_MAX];
00315     time_t clock;
00316     char *gisbase;
00317 
00318     /* get time */
00319     clock = time(NULL);
00320 
00321     /* get current working directory */
00322     getcwd(cwd, sizeof(cwd));
00323 
00324     /* write the error log file */
00325     if ((gisbase = G_gisbase()))
00326         write_error(msg, fatal, clock, cwd);
00327 
00328     return 0;
00329 }
00330 
00331 /* Write a message to the log file */
00332 static int write_error(const char *msg, int fatal,
00333                        time_t clock, const char *cwd)
00334 {
00335     static char *logfile;
00336     FILE *log;
00337 
00338     if (!logfile) {
00339         logfile = getenv("GIS_ERROR_LOG");
00340         if (!logfile) {
00341             char buf[GPATH_MAX];
00342 
00343             sprintf(buf, "%s/GIS_ERROR_LOG", G__home());
00344             logfile = G_store(buf);
00345         }
00346     }
00347 
00348     log = fopen(logfile, "r");
00349     if (!log)
00350         /* GIS_ERROR_LOG file is not readable or does not exist */
00351         return 1;
00352 
00353     log = freopen(logfile, "a", log);
00354     if (!log)
00355         /* the user doesn't have write permission */
00356         return 1;
00357 
00358     fprintf(log, "-------------------------------------\n");
00359     fprintf(log, "%-10s %s\n", "program:", G_program_name());
00360     fprintf(log, "%-10s %s\n", "user:", G_whoami());
00361     fprintf(log, "%-10s %s\n", "cwd:", cwd);
00362     fprintf(log, "%-10s %s\n", "date:", ctime(&clock));
00363     fprintf(log, "%-10s %s\n", fatal ? "error:" : "warning:", msg);
00364     fprintf(log, "-------------------------------------\n");
00365 
00366     fclose(log);
00367 
00368     return 0;
00369 }
00370 
00371 /* Mail a message */
00372 static int mail_msg(const char *msg, int fatal)
00373 {
00374     FILE *mail;
00375     char command[64];
00376     char *user;
00377 
00378     user = G_whoami();
00379     if (user == 0 || *user == 0)
00380         return 1;
00381 
00382     sprintf(command, "mail '%s'", G_whoami());
00383     if ((mail = popen(command, "w"))) {
00384         fprintf(mail, "GIS %s: %s\n", fatal ? "ERROR" : "WARNING", msg);
00385         pclose(mail);
00386     }
00387 
00388     return 0;
00389 }
00390 
00391 /* Print one word, new line if necessary */
00392 static int print_word(FILE * fd, char **word, int *len, const int lead)
00393 {
00394     int wlen, start, totlen;
00395     int nl;
00396     char *w, *b;
00397 
00398     start = *len;
00399     w = *word;
00400 
00401     nl = 0;
00402     while (*w == ' ' || *w == '\t' || *w == '\n')
00403         if (*w++ == '\n')
00404             nl++;
00405 
00406     wlen = 0;
00407     for (b = w; *b != 0 && *b != ' ' && *b != '\t' && *b != '\n'; b++)
00408         wlen++;
00409 
00410     if (wlen == 0) {
00411         fprintf(fd, "\n");
00412         return 0;
00413     }
00414 
00415     if (start > lead) {         /* add space */
00416         totlen = start + wlen + 1;
00417     }
00418     else {
00419         totlen = start + wlen;
00420     }
00421 
00422     if (nl != 0 || totlen > 75) {
00423         while (--nl > 0)
00424             fprintf(fd, "\n");
00425         fprintf(fd, "\n%*s", lead, "");
00426         start = lead;
00427     }
00428 
00429     if (start > lead) {
00430         fprintf(fd, " ");
00431         start++;
00432     }
00433 
00434     *len = start + wlen;
00435 
00436     fwrite(w, 1, wlen, fd);
00437     w += wlen;
00438 
00439     *word = w;
00440 
00441     return 1;
00442 }
00443 
00444 /* Print one message, prefix inserted before each new line */
00445 static void print_sentence(FILE * fd, const int type, const char *msg)
00446 {
00447     char prefix[100];
00448     const char *start;
00449 
00450     switch (type) {
00451     case MSG:
00452         sprintf(prefix, "GRASS_INFO_MESSAGE(%d,%d): ", getpid(), message_id);
00453         break;
00454     case WARN:
00455         sprintf(prefix, "GRASS_INFO_WARNING(%d,%d): ", getpid(), message_id);
00456         break;
00457     case ERR:
00458         sprintf(prefix, "GRASS_INFO_ERROR(%d,%d): ", getpid(), message_id);
00459         break;
00460     }
00461 
00462     start = msg;
00463 
00464     fprintf(stderr, "\n");
00465     while (*start != '\0') {
00466         const char *next = start;
00467 
00468         fprintf(fd, "%s", prefix);
00469 
00470         while (*next != '\0') {
00471             next++;
00472 
00473             if (*next == '\n') {
00474                 next++;
00475                 break;
00476             }
00477         }
00478 
00479         fwrite(start, 1, next - start, fd);
00480         fprintf(fd, "\n");
00481         start = next;
00482     }
00483     fprintf(stderr, "GRASS_INFO_END(%d,%d)\n", getpid(), message_id);
00484     message_id++;
00485 }
00486 
00494 int G_info_format(void)
00495 {
00496     static int grass_info_format = -1;
00497     char *fstr;
00498 
00499     if (grass_info_format < 0) {
00500         fstr = getenv("GRASS_MESSAGE_FORMAT");
00501 
00502         if (fstr && G_strcasecmp(fstr, "gui") == 0)
00503             grass_info_format = G_INFO_FORMAT_GUI;
00504         else if (fstr && G_strcasecmp(fstr, "silent") == 0)
00505             grass_info_format = G_INFO_FORMAT_SILENT;
00506         else if (fstr && G_strcasecmp(fstr, "plain") == 0)
00507             grass_info_format = G_INFO_FORMAT_PLAIN;
00508         else
00509             grass_info_format = G_INFO_FORMAT_STANDARD;
00510     }
00511 
00512     return grass_info_format;
00513 }