/* * Copyright (C) 2004 NVIDIA Corporation. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #if defined(__sun) #include #endif #include "msg.h" #include "common-utils.h" /* * verbosity, controls output of errors, warnings and other * information. */ static NvVerbosity __verbosity = NV_VERBOSITY_DEFAULT; NvVerbosity nv_get_verbosity() { return __verbosity; } void nv_set_verbosity(NvVerbosity level) { __verbosity = level; } /****************************************************************************/ /* Formatted I/O functions */ /****************************************************************************/ #define DEFAULT_WIDTH 75 static unsigned short __terminal_width = 0; /* * reset_current_terminal_width() - if new_val is zero, then use the * TIOCGWINSZ ioctl to get the current width of the terminal, and * assign it the value to __terminal_width. If the ioctl fails, use a * hardcoded constant. If new_val is non-zero, then use new_val. */ void reset_current_terminal_width(unsigned short new_val) { struct winsize ws; if (new_val) { __terminal_width = new_val; return; } if (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { __terminal_width = DEFAULT_WIDTH; } else { __terminal_width = ws.ws_col - 1; } } static void format(FILE *stream, const char *prefix, const char *buf, const int whitespace) { int i; TextRows *t; if (!__terminal_width) reset_current_terminal_width(0); t = nv_format_text_rows(prefix, buf, __terminal_width, whitespace); for (i = 0; i < t->n; i++) fprintf(stream, "%s\n", t->t[i]); nv_free_text_rows(t); } #define NV_FORMAT(stream, prefix, fmt, whitespace) \ do { \ char *buf; \ NV_VSNPRINTF(buf, fmt); \ format(stream, prefix, buf, whitespace); \ free (buf); \ } while(0) /* * nv_error_msg() - print an error message, nicely formatted using the * format() function. * * This function should be used for all errors. */ void nv_error_msg(const char *fmt, ...) { if (__verbosity < NV_VERBOSITY_ERROR) return; format(stderr, NULL, "", TRUE); NV_FORMAT(stderr, "ERROR: ", fmt, TRUE); format(stderr, NULL, "", TRUE); } /* nv_error_msg() */ /* * nv_deprecated_msg() - print a deprecation message, nicely formatted using * the format() function. * * This function should be used for all deprecation messages. */ void nv_deprecated_msg(const char *fmt, ...) { if (__verbosity < NV_VERBOSITY_DEPRECATED) return; format(stderr, NULL, "", TRUE); NV_FORMAT(stderr, "DEPRECATED: ", fmt, TRUE); format(stderr, NULL, "", TRUE); } /* * nv_warning_msg() - print a warning message, nicely formatted using * the format() function. * * This function should be used for all warnings. */ void nv_warning_msg(const char *fmt, ...) { if (__verbosity < NV_VERBOSITY_WARNING) return; format(stderr, NULL, "", TRUE); NV_FORMAT(stderr, "WARNING: ", fmt, TRUE); format(stderr, NULL, "", TRUE); } /* nv_warning_msg() */ /* * nv_info_msg() - print an info message, nicely formatted using * the format() function. * * This function should be used to display verbose information. */ void nv_info_msg(const char *prefix, const char *fmt, ...) { if (__verbosity < NV_VERBOSITY_ALL) return; NV_FORMAT(stdout, prefix, fmt, TRUE); } /* nv_info_msg() */ /* * nv_info_msg_to_file() - Prints the message, just like nv_info_msg() * using format() the difference is, it prints to any stream defined by * the corresponding argument. */ void nv_info_msg_to_file(FILE *stream, const char *prefix, const char *fmt, ...) { if (__verbosity < NV_VERBOSITY_ALL) return; NV_FORMAT(stream, prefix, fmt, TRUE); } /* nv_info_msg_to_file() */ /* * nv_msg() - print a message, nicely formatted using the format() * function. * * This function should be used to display messages independent * of the verbosity level. */ void nv_msg(const char *prefix, const char *fmt, ...) { NV_FORMAT(stdout, prefix, fmt, TRUE); } /* nv_msg() */ /* * nv_msg_preserve_whitespace() - Prints the message, just like nv_msg() * using format(), the difference is, whitespace characters are not * skipped during the text processing. */ void nv_msg_preserve_whitespace(const char *prefix, const char *fmt, ...) { NV_FORMAT(stdout, prefix, fmt, FALSE); } /* nv_msg_preserve_whitespace() */ /* * XXX gcc's '-ansi' option causes vsnprintf to not be defined, so * declare the prototype here. */ #if defined(__STRICT_ANSI__) int vsnprintf(char *str, size_t size, const char *format, va_list ap); #endif /****************************************************************************/ /* TextRows helper functions */ /****************************************************************************/ /* * nv_format_text_rows() - this function breaks the given string str * into some number of rows, where each row is not longer than the * specified width. * * If prefix is non-NULL, the first line is prepended with the prefix, * and subsequent lines are indented to line up with the prefix. * * If word_boundary is TRUE, then attempt to only break lines on * boundaries between words. */ TextRows *nv_format_text_rows(const char *prefix, const char *str, int width, int word_boundary) { int len, prefix_len, z, w, i; char *line, *buf, *local_prefix, *a, *b, *c; TextRows *t; /* initialize the TextRows structure */ t = (TextRows *) malloc(sizeof(TextRows)); if (!t) return NULL; t->t = NULL; t->n = 0; t->m = 0; if (!str) return t; buf = strdup(str); if (!buf) return t; z = strlen(buf); /* length of entire string */ a = buf; /* pointer to the start of the string */ /* initialize the prefix fields */ if (prefix) { prefix_len = strlen(prefix); local_prefix = strdup(prefix); } else { prefix_len = 0; local_prefix = NULL; } /* adjust the max width for any prefix */ w = width - prefix_len; do { /* * if the string will fit on one line, point b to the end of the * string */ if (z < w) b = a + z; /* * if the string won't fit on one line, move b to where the * end of the line should be, and then move b back until we * find a space; if we don't find a space before we back b all * the way up to a, just assign b to where the line should end. */ else { b = a + w; if (word_boundary) { while ((b >= a) && (!isspace(*b))) b--; if (b <= a) b = a + w; } } /* look for any newline between a and b, and move b to it */ for (c = a; c < b; c++) if (*c == '\n') { b = c; break; } /* * copy the string that starts at a and ends at b, prepending * with a prefix, if present */ len = b-a; len += prefix_len; line = (char *) malloc(len+1); if (local_prefix) strncpy(line, local_prefix, prefix_len); strncpy(line + prefix_len, a, len - prefix_len); line[len] = '\0'; /* append the new line to the array of text rows */ t->t = (char **) realloc(t->t, sizeof(char *) * (t->n + 1)); t->t[t->n] = line; t->n++; if (t->m < len) t->m = len; /* * adjust the length of the string and move the pointer to the * beginning of the new line */ z -= (b - a + 1); a = b + 1; /* move to the first non whitespace character (excluding newlines) */ if (word_boundary && isspace(*b)) { while ((z) && (isspace(*a)) && (*a != '\n')) a++, z--; } else { if (!isspace(*b)) z++, a--; } if (local_prefix) { for (i = 0; i < prefix_len; i++) local_prefix[i] = ' '; } } while (z > 0); if (local_prefix) free(local_prefix); free(buf); return t; } /* * nv_text_rows_append() - append the given msg to the existing TextRows */ void nv_text_rows_append(TextRows *t, const char *msg) { int len; t->t = realloc(t->t, sizeof(char *) * (t->n + 1)); if (msg) { t->t[t->n] = strdup(msg); len = strlen(msg); if (t->m < len) t->m = len; } else { t->t[t->n] = NULL; } t->n++; } /* * nv_concat_text_rows() - concatenate two text rows, storing the * result in t0 */ void nv_concat_text_rows(TextRows *t0, TextRows *t1) { int n, i; n = t0->n + t1->n; t0->t = realloc(t0->t, sizeof(char *) * n); for (i = 0; i < t1->n; i++) { t0->t[i + t0->n] = strdup(t1->t[i]); } t0->m = NV_MAX(t0->m, t1->m); t0->n = n; } /* nv_concat_text_rows() */ /* * nv_free_text_rows() - free the TextRows data structure allocated by * nv_format_text_rows() */ void nv_free_text_rows(TextRows *t) { int i; if (!t) return; for (i = 0; i < t->n; i++) free(t->t[i]); if (t->t) free(t->t); free(t); } /* nv_free_text_rows() */