diff options
Diffstat (limited to 'common-utils/common-utils.c')
-rw-r--r-- | common-utils/common-utils.c | 338 |
1 files changed, 337 insertions, 1 deletions
diff --git a/common-utils/common-utils.c b/common-utils/common-utils.c index 701bb07..98b92fe 100644 --- a/common-utils/common-utils.c +++ b/common-utils/common-utils.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 NVIDIA Corporation + * Copyright (C) 2010-2012 NVIDIA Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -150,6 +150,35 @@ char *nvstrdup(const char *s) /* + * nvstrndup() - implementation of strndup() that checks return values; if + * an error occurs, an error is printed to stderr and exit is called + * -- this function will only return on success. + */ + +char *nvstrndup(const char *s, size_t n) +{ + char *m; + + if (!s) return NULL; + + m = malloc(n + 1); + + if (!m) { + fprintf(stderr, "%s: memory allocation failure during malloc (%s)! \n", + PROGRAM_NAME, strerror(errno)); + exit(1); + } + + strncpy (m, s, n); + m[n] = '\0'; + + return m; + +} /* nvstrndup() */ + + + +/* * nvstrtolower() - convert the given string to lowercase. */ @@ -250,3 +279,310 @@ char *tilde_expansion(const char *str) return ret; } /* tilde_expansion() */ + + +/****************************************************************************/ +/* 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 inbetween 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 + */ + +#define NV_MAX(x,y) ((x) > (y) ? (x) : (y)) + +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() */ + + +/****************************************************************************/ +/* printing helper 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; + } +} + +/* + * Call silence_fmt(1) to turn fmtout(), fmtoutp() and format() into noops. + */ +static int __silent = 0; + +void silence_fmt(int val) +{ + __silent = val; +} + + +static void vformat(FILE *stream, const int wb, + const char *prefix, const char *buf) +{ + int i; + TextRows *t; + + if (!__terminal_width) reset_current_terminal_width(0); + + t = nv_format_text_rows(prefix, buf, __terminal_width, wb); + + for (i = 0; i < t->n; i++) fprintf(stream, "%s\n", t->t[i]); + + nv_free_text_rows(t); +} + + +#define NV_VFORMAT(stream, wb, prefix, fmt) \ +do { \ + char *buf; \ + NV_VSNPRINTF(buf, fmt); \ + vformat(stream, wb, prefix, buf); \ + free (buf); \ +} while(0) + + +void fmtout(const char *fmt, ...) +{ + if (__silent > 0) { + return; + } + NV_VFORMAT(stdout, TRUE, NULL, fmt); +} + + +void fmtoutp(const char *prefix, const char *fmt, ...) +{ + if (__silent > 0) { + return; + } + NV_VFORMAT(stdout, TRUE, prefix, fmt); +} + + +void fmterr(const char *fmt, ...) +{ + vformat(stderr, 0, NULL, ""); + NV_VFORMAT(stderr, TRUE, "ERROR: ", fmt); + vformat(stderr, 0, NULL, ""); +} + + +void fmtwarn(const char *fmt, ...) +{ + vformat(stderr, 0, NULL, ""); + NV_VFORMAT(stderr, TRUE, "WARNING: ", fmt); + vformat(stderr, 0, NULL, ""); +} + + +void fmt(FILE *stream, const char *prefix, const char *fmt, ...) +{ + if (__silent > 0) { + return; + } + NV_VFORMAT(stream, TRUE, prefix, fmt); +} |