diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2012-05-02 08:06:55 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2012-05-02 08:06:55 -0700 |
commit | 783a1b15e786c5fd75928dfb1b4b31900de94df0 (patch) | |
tree | 6cab864eee729ae5bb2c078b20b79f2dc4a441e1 | |
parent | d2681269ec685639076b13c493cbb22215aa0eeb (diff) |
302.07302.07
-rw-r--r-- | Makefile | 34 | ||||
-rw-r--r-- | common-utils/common-utils.c | 338 | ||||
-rw-r--r-- | common-utils/common-utils.h | 78 | ||||
-rw-r--r-- | common-utils/gen-manpage-opts-helper.c | 181 | ||||
-rw-r--r-- | common-utils/gen-manpage-opts-helper.h | 24 | ||||
-rw-r--r-- | common-utils/nvgetopt.c | 125 | ||||
-rw-r--r-- | common-utils/nvgetopt.h | 24 | ||||
-rw-r--r-- | common-utils/src.mk | 6 | ||||
-rw-r--r-- | extract_edids.c | 282 | ||||
-rw-r--r-- | gen-manpage-opts.c | 140 | ||||
-rw-r--r-- | nvidia-xconfig.c | 277 | ||||
-rw-r--r-- | nvidia-xconfig.h | 24 | ||||
-rw-r--r-- | option_table.h | 58 | ||||
-rw-r--r-- | options.c | 4 | ||||
-rw-r--r-- | query_gpu_info.c | 2 | ||||
-rw-r--r-- | util.c | 381 | ||||
-rw-r--r-- | utils.mk | 30 | ||||
-rw-r--r-- | version.mk | 2 |
18 files changed, 1139 insertions, 871 deletions
@@ -88,14 +88,14 @@ CFLAGS += -DPROGRAM_NAME=\"nvidia-xconfig\" HOST_CFLAGS += $(CFLAGS) -LDFLAGS += -lm +LIBS += -lm ifneq ($(TARGET_OS),FreeBSD) - LDFLAGS += -ldl + LIBS += -ldl endif ifeq ($(TARGET_OS),SunOS) - LDFLAGS += -lscf + LIBS += -lscf endif @@ -110,16 +110,16 @@ all: $(NVIDIA_XCONFIG) $(MANPAGE) install: NVIDIA_XCONFIG_install MANPAGE_install NVIDIA_XCONFIG_install: $(NVIDIA_XCONFIG) - $(MKDIR) $(bindir) - $(INSTALL) $(INSTALL_BIN_ARGS) $< $(bindir)/$(notdir $<) + $(MKDIR) $(BINDIR) + $(INSTALL) $(INSTALL_BIN_ARGS) $< $(BINDIR)/$(notdir $<) MANPAGE_install: $(MANPAGE) - $(MKDIR) $(mandir) - $(INSTALL) $(INSTALL_DOC_ARGS) $< $(mandir)/$(notdir $<) + $(MKDIR) $(MANDIR) + $(INSTALL) $(INSTALL_DOC_ARGS) $< $(MANDIR)/$(notdir $<) $(NVIDIA_XCONFIG): $(OBJS) - $(call quiet_cmd,LINK) -o $@ $(OBJS) $(CFLAGS) \ - $(LDFLAGS) $(BIN_LDFLAGS) + $(call quiet_cmd,LINK) $(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) \ + -o $@ $(OBJS) $(LIBS) $(call quiet_cmd,STRIP_CMD) $@ # define the rule to build each object file @@ -142,16 +142,22 @@ AUTO_TEXT = ".\\\" WARNING: THIS FILE IS AUTO-GENERATED! Edit $< instead." doc: $(MANPAGE) -$(eval $(call DEFINE_OBJECT_RULE,HOST_CC,gen-manpage-opts.c)) +GEN_MANPAGE_OPTS_SRC = gen-manpage-opts.c +GEN_MANPAGE_OPTS_SRC += $(COMMON_UTILS_DIR)/gen-manpage-opts-helper.c -$(GEN_MANPAGE_OPTS): $(call BUILD_OBJECT_LIST,gen-manpage-opts.c) - $(call quiet_cmd,HOST_LINK) $< -o $@ \ - $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_BIN_LDFLAGS) +GEN_MANPAGE_OPTS_OBJS = $(call BUILD_OBJECT_LIST,$(GEN_MANPAGE_OPTS_SRC)) + +$(foreach src, $(GEN_MANPAGE_OPTS_SRC), \ + $(eval $(call DEFINE_OBJECT_RULE,HOST_CC,$(src)))) + +$(GEN_MANPAGE_OPTS): $(GEN_MANPAGE_OPTS_OBJS) + $(call quiet_cmd,HOST_LINK) \ + $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_BIN_LDFLAGS) $^ -o $@ $(OPTIONS_1_INC): $(GEN_MANPAGE_OPTS) @./$< > $@ -$(MANPAGE_not_gzipped): nvidia-xconfig.1.m4 $(OPTIONS_1_INC) +$(MANPAGE_not_gzipped): nvidia-xconfig.1.m4 $(OPTIONS_1_INC) $(VERSION_MK) $(call quiet_cmd,M4) -D__HEADER__=$(AUTO_TEXT) -I $(OUTPUTDIR) \ -D__VERSION__=$(NVIDIA_VERSION) \ -D__DATE__="`$(DATE) +%F`" \ 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); +} diff --git a/common-utils/common-utils.h b/common-utils/common-utils.h index 04d5f3b..e0d9314 100644 --- a/common-utils/common-utils.h +++ b/common-utils/common-utils.h @@ -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, @@ -17,6 +17,9 @@ #ifndef __COMMON_UTILS_H__ #define __COMMON_UTILS_H__ +#include <stdio.h> +#include <stdarg.h> + #if !defined(TRUE) #define TRUE 1 #endif @@ -25,13 +28,86 @@ #define FALSE 0 #endif +#define ARRAY_LEN(_arr) (sizeof(_arr) / sizeof(_arr[0])) + +#define TAB " " +#define BIGTAB " " + +typedef struct { + char **t; /* the text rows */ + int n; /* number of rows */ + int m; /* maximum row length */ +} TextRows; + void *nvalloc(size_t size); char *nvstrcat(const char *str, ...); void *nvrealloc(void *ptr, size_t size); char *nvstrdup(const char *s); +char *nvstrndup(const char *s, size_t n); char *nvstrtolower(char *s); void nvfree(void *s); char *tilde_expansion(const char *str); +TextRows *nv_format_text_rows(const char *prefix, + const char *str, + int width, int word_boundary); +void nv_text_rows_append(TextRows *t, const char *msg); +void nv_concat_text_rows(TextRows *t0, TextRows *t1); +void nv_free_text_rows(TextRows *t); + +void reset_current_terminal_width(unsigned short new_val); + +void silence_fmt(int val); +void fmtout(const char *fmt, ...); +void fmtoutp(const char *prefix, const char *fmt, ...); +void fmterr(const char *fmt, ...); +void fmtwarn(const char *fmt, ...); +void fmt(FILE *stream, const char *prefix, const char *fmt, ...); + +/* + * NV_VSNPRINTF(): macro that assigns buf using vsnprintf(). This is + * correct for differing semantics of the vsnprintf() return value: + * + * -1 when the buffer is not long enough (glibc < 2.1) + * + * or + * + * the length the string would have been if the buffer had been large + * enough (glibc >= 2.1) + * + * This macro allocates memory for buf; the caller should free it when + * done. + */ + +#define NV_FMT_BUF_LEN 256 + +#define NV_VSNPRINTF(buf, fmt) \ +do { \ + if (!fmt) { \ + (buf) = NULL; \ + } else { \ + va_list ap; \ + int len, current_len = NV_FMT_BUF_LEN; \ + \ + (buf) = malloc(current_len); \ + \ + while (1) { \ + va_start(ap, fmt); \ + len = vsnprintf((buf), current_len, (fmt), ap); \ + va_end(ap); \ + \ + if ((len > -1) && (len < current_len)) { \ + break; \ + } else if (len > -1) { \ + current_len = len + 1; \ + } else { \ + current_len += NV_FMT_BUF_LEN; \ + } \ + free(buf); \ + (buf) = malloc(current_len); \ + } \ + } \ +} while (0) + #endif /* __COMMON_UTILS_H__ */ diff --git a/common-utils/gen-manpage-opts-helper.c b/common-utils/gen-manpage-opts-helper.c new file mode 100644 index 0000000..d2abb1c --- /dev/null +++ b/common-utils/gen-manpage-opts-helper.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> + +#include "nvgetopt.h" +#include "gen-manpage-opts-helper.h" + +static void print_option(const NVGetoptOption *o) +{ + char scratch[64], *s; + int j, len; + + int italics, bold, omitWhiteSpace; + + /* if we are going to need the argument, process it now */ + if (o->flags & NVGETOPT_HAS_ARGUMENT) { + if (o->arg_name) { + strcpy(scratch, o->arg_name); + } else { + len = strlen(o->name); + for (j = 0; j < len; j++) scratch[j] = toupper(o->name[j]); + scratch[len] = '\0'; + } + } + + printf(".TP\n.BI \""); + /* Print the name of the option */ + /* XXX We should backslashify the '-' characters in o->name. */ + + if (isalpha(o->val)) { + /* '\-c' */ + printf("\\-%c", o->val); + + if (o->flags & NVGETOPT_HAS_ARGUMENT) { + /* ' " "ARG" "' */ + printf(" \" \"%s\" \"", scratch); + } + /* ', ' */ + printf(", "); + } + + /* '\-\-name' */ + printf("\\-\\-%s", o->name); + + /* '=" "ARG' */ + if (o->flags & NVGETOPT_HAS_ARGUMENT) { + printf("=\" \"%s", scratch); + + /* '" "' */ + if ((o->flags & NVGETOPT_IS_BOOLEAN) || + (o->flags & NVGETOPT_ALLOW_DISABLE)) { + printf("\" \""); + } + } + + /* ', \-\-no\-name' */ + if (((o->flags & NVGETOPT_IS_BOOLEAN) && + !(o->flags & NVGETOPT_HAS_ARGUMENT)) || + (o->flags & NVGETOPT_ALLOW_DISABLE)) { + printf(", \\-\\-no\\-%s", o->name); + } + + printf("\"\n"); + + /* Print the option description */ + /* XXX Each sentence should be on its own line! */ + + /* + * Print the option description: write each character one at a + * time (ugh) so that we can special-case a few characters: + * + * '&' : toggles italics on and off + * '^' : toggles bold on and off + * '-' : is backslashified: "\-" + * + * Whitespace is omited when italics or bold is on + */ + + italics = 0; + bold = 0; + omitWhiteSpace = 0; + + for (s = o->description; s && *s; s++) { + + switch (*s) { + case '&': + if (italics) { + printf("\n"); + } else { + printf("\n.I "); + } + omitWhiteSpace = italics; + italics = !italics; + break; + case '^': + if (bold) { + printf("\n"); + } else { + printf("\n.B "); + } + omitWhiteSpace = bold; + bold = !bold; + break; + case '-': + printf("\\-"); + omitWhiteSpace = 0; + break; + case ' ': + if (!omitWhiteSpace) { + printf(" "); + } + break; + default: + printf("%c", *s); + omitWhiteSpace = 0; + break; + } + } + + printf("\n"); +} + +void gen_manpage_opts_helper(const NVGetoptOption *options) +{ + int i; + int has_advanced_options = 0; + + /* Print the "simple" options; i.e. the ones you get with --help. */ + printf(".SH OPTIONS\n"); + for (i = 0; options[i].name; i++) { + const NVGetoptOption *o = &options[i]; + + if (!o->description) { + continue; + } + + if (!(o->flags & NVGETOPT_HELP_ALWAYS)) { + has_advanced_options = 1; + continue; + } + + print_option(o); + } + + if (has_advanced_options) { + /* + * If any exist, print the advanced options; i.e., the ones + * you get with --advanced-help + */ + printf(".SH \"ADVANCED OPTIONS\"\n"); + for (i = 0; options[i].name; i++) { + const NVGetoptOption *o = &options[i]; + + if (!o->description) { + continue; + } + + if (o->flags & NVGETOPT_HELP_ALWAYS) { + continue; + } + + print_option(o); + } + } +} diff --git a/common-utils/gen-manpage-opts-helper.h b/common-utils/gen-manpage-opts-helper.h new file mode 100644 index 0000000..b09852e --- /dev/null +++ b/common-utils/gen-manpage-opts-helper.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined(__GEN_MANPAGE_OPTS_HELPER_H__) +#define __GEN_MANPAGE_OPTS_HELPER_H__ + +#include "nvgetopt.h" + +void gen_manpage_opts_helper(const NVGetoptOption *options); + +#endif /* __GEN_MANPAGE_OPTS_HELPER_H__ */ diff --git a/common-utils/nvgetopt.c b/common-utils/nvgetopt.c index a89dcac..f04cef3 100644 --- a/common-utils/nvgetopt.c +++ b/common-utils/nvgetopt.c @@ -21,8 +21,10 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <ctype.h> #include "nvgetopt.h" +#include "common-utils.h" int nvgetopt(int argc, @@ -309,3 +311,126 @@ int nvgetopt(int argc, return ret; } /* nvgetopt() */ + + +/* + * cook_description() - the description string may contain text within + * special characters which are interpreted by the manpage generator. + * We want to omit those characters here. + */ + +static char *cook_description(const char *description) +{ + const char *src; + char *s, *dst; + + if (!description) { + return NULL; + } + + s = strdup(description); + + if (!s) { + return NULL; + } + + for (src = description, dst = s; *src; src++) { + if ((*src == '&') || (*src == '^')) { + continue; + } + *dst = *src; + dst++; + } + + *dst = '\0'; + + return s; +} + + +void nvgetopt_print_help(const NVGetoptOption *options, + unsigned int include_mask, + nvgetopt_print_help_callback_ptr callback) +{ + const NVGetoptOption *o; + int i; + + for (i = 0; options[i].name; i++) { + + char *msg = NULL, *arg = NULL, *description = NULL; + + o = &options[i]; + + /* Skip options with no help text */ + if (!o->description) { + continue; + } + + /* skip options who don't have all the bits of include_mask */ + if ((o->flags & include_mask) != include_mask) { + continue; + } + + /* if we are going to need the argument, process it now */ + arg = NULL; + if (o->flags & NVGETOPT_HAS_ARGUMENT) { + if (o->arg_name) { + arg = strdup(o->arg_name); + } else { + char *tmp; + arg = strdup(o->name); + for (tmp = arg; tmp && *tmp; tmp++) { + *tmp = toupper(*tmp); + } + } + } + + msg = NULL; + + /* + * create the long version of the option, possibly with an + * argument; e.g., "--foo" or "--foo=BAR" + */ + if (arg) { + msg = nvstrcat("--", o->name, "=", arg, NULL); + } else { + msg = nvstrcat("--", o->name, NULL); + } + + /* + * prepend the single character version of the option, + * possibly with an argument; e.g., "-f" or "-f BAR" + */ + if (isalpha(o->val)) { + char scratch[16]; + char *tmp; + snprintf(scratch, sizeof(scratch), "%c", o->val); + if (arg) { + tmp = nvstrcat("-", scratch, " ", arg, ", ", msg, NULL); + } else { + tmp = nvstrcat("-", scratch, ", ", msg, NULL); + } + free(msg); + msg = tmp; + } + + /* append the boolean version of the option; e.g., "--no-foo" */ + if (((o->flags & NVGETOPT_IS_BOOLEAN) && + !(o->flags & NVGETOPT_HAS_ARGUMENT)) || + (o->flags & NVGETOPT_ALLOW_DISABLE)) { + char *tmp = nvstrcat(msg, ", --no-", o->name, NULL); + free(msg); + msg = tmp; + } + + /* process the description text */ + description = cook_description(o->description); + + /* give the strings to the caller to format and print */ + callback(msg, description); + + free(msg); + free(arg); + free(description); + } +} diff --git a/common-utils/nvgetopt.h b/common-utils/nvgetopt.h index 127f40b..5847546 100644 --- a/common-utils/nvgetopt.h +++ b/common-utils/nvgetopt.h @@ -155,5 +155,29 @@ int nvgetopt(int argc, double *doubleval, int *disable_val); +/* + * nvgetopt_print_help() - print a help message for each option in the + * provided NVGetoptOption array. This is useful for a utility's + * "--help" output. + * + * Options will only be printed if they have every bit set that + * include_mask includes. + * + * For each option, the provided callback function wil be called with + * two strings: a name string that lists the option's name, and a + * description string for the option. The callback function is + * responsible for actually printing these strings. Examples: + * + * name = "-v, --version"; + * description = "Print usage information for the common commandline " + * "options and exit."; + */ + +typedef void nvgetopt_print_help_callback_ptr(const char *name, + const char *description); + +void nvgetopt_print_help(const NVGetoptOption *options, + unsigned int include_mask, + nvgetopt_print_help_callback_ptr callback); #endif /* __NVGETOPT_H__ */ diff --git a/common-utils/src.mk b/common-utils/src.mk index 14e4131..12ba143 100644 --- a/common-utils/src.mk +++ b/common-utils/src.mk @@ -7,3 +7,9 @@ COMMON_UTILS_EXTRA_DIST += nvgetopt.h COMMON_UTILS_EXTRA_DIST += common-utils.h COMMON_UTILS_EXTRA_DIST += src.mk +# gen-manpage-opts-helper.c is listed in EXTRA_DIST, rather than SRC, +# because it is not compiled into the utilities themselves, but used +# when building the utility's gen-manpage-opts +COMMON_UTILS_EXTRA_DIST += gen-manpage-opts-helper.c +COMMON_UTILS_EXTRA_DIST += gen-manpage-opts-helper.h + diff --git a/extract_edids.c b/extract_edids.c index b62ad4c..cd0569d 100644 --- a/extract_edids.c +++ b/extract_edids.c @@ -34,7 +34,6 @@ * (--) NVIDIA(0): 69 65 77 53 6f 6e 69 63 20 56 50 44 00 00 00 fc * (--) NVIDIA(0): 00 31 35 30 0a 20 20 20 20 20 20 20 20 20 00 ce * (--) NVIDIA(0): - * (--) NVIDIA(0): --- End of EDID for ViewSonic VPD150 (DFP-1) --- * * The added possibilities for the X log are, that the log file contains * timestamps along with the raw EDID byte dump like this: @@ -54,6 +53,9 @@ * (STATE_LOOKING_FOR_START_OF_LABEL & STATE_LOOKING_FOR_SCREEN_NUMBER_IN_LABEL) * for handling these special cases. * + * Note that in some cases the label could have the form + * "NVIDIA(GPU-0)" rather than "NVIDIA(0)". + * A .txt file will contain a raw EDID byte dump like this: * * 00 FF FF FF FF FF FF 00-06 10 F4 01 01 01 01 01 ................ @@ -146,6 +148,27 @@ static int writeEdidFile(EdidPtr pEdid, char *filename); static void freeEdid(EdidPtr pEdid); +/* + * Moves FilePtr::current to the end of the next occurrence of the + * specified string within the file. Return TRUE if the string is + * found in the file; return FALSE otherwise. + */ + +static inline int moveFilePointerPastString(FilePtr pFile, const char *s) +{ + size_t len = strlen(s); + + while (((pFile->current - pFile->start) + len) <= pFile->length) { + + if (strncmp(pFile->current, s, len) == 0) { + + pFile->current += len; + return TRUE; + } + pFile->current++; + } + return FALSE; +} /* @@ -373,32 +396,8 @@ static EdidPtr findEdidforTextFile(FilePtr pFile) static int findEdidHeaderforLogFile(FilePtr pFile) { - while (((pFile->current - pFile->start) + 15) <= pFile->length) { - - if ((pFile->current[0] == 'R') && - (pFile->current[1] == 'a') && - (pFile->current[2] == 'w') && - (pFile->current[3] == ' ') && - (pFile->current[4] == 'E') && - (pFile->current[5] == 'D') && - (pFile->current[6] == 'I') && - (pFile->current[7] == 'D') && - (pFile->current[8] == ' ') && - (pFile->current[9] == 'b') && - (pFile->current[10] == 'y') && - (pFile->current[11] == 't') && - (pFile->current[12] == 'e') && - (pFile->current[13] == 's') && - (pFile->current[14] == ':')) { - - pFile->current += 15; - return TRUE; - } - pFile->current++; - } + return moveFilePointerPastString(pFile, "Raw EDID bytes:"); - return FALSE; - } // findEdidHeaderforLogFile() @@ -413,21 +412,30 @@ static int findEdidHeaderforLogFile(FilePtr pFile) * character of the string, because the readEdidDataforLogFile() * state machine will move pFile->current forward one character when * findLogFileLineLabel() succeeds. + * + * This handles both "NVIDIA(#)" and "NVIDIA(GPU-#)". */ static int findLogFileLineLabel(FilePtr pFile) { - while (((pFile->current - pFile->start) + 7) <= pFile->length) { + while ((pFile->current - pFile->start) <= pFile->length) { + + const char *gpuTag = "NVIDIA(GPU"; + const char *screenTag = "NVIDIA("; + + size_t remainder = pFile->length - (pFile->current - pFile->start); + + if ((remainder > strlen(gpuTag)) && + (strncmp(pFile->current, gpuTag, strlen(gpuTag)) == 0)) { - if ((pFile->current[0] == 'N') && - (pFile->current[1] == 'V') && - (pFile->current[2] == 'I') && - (pFile->current[3] == 'D') && - (pFile->current[4] == 'I') && - (pFile->current[5] == 'A') && - (pFile->current[6] == '(')) { + pFile->current += strlen(gpuTag); + return TRUE; + } - pFile->current += 6; + if ((remainder > strlen(screenTag)) && + (strncmp(pFile->current, screenTag, strlen(screenTag)) == 0)) { + + pFile->current += strlen(screenTag); return TRUE; } pFile->current++; @@ -508,20 +516,13 @@ static int readEdidDataforLogFile(FilePtr pFile, EdidPtr pEdid) state = STATE_LOOKING_FOR_BOTTOM_NIBBLE; goto nextChar; } - + /* - * if we find the text "--- End of EDID for ... ---", then - * we want to parse that to find out the name of the - * display device whose EDID we are reading; this is also - * our exit condition for the state machine + * if we hit anything else, we have reached the end of the + * EDID: exit the state machine. */ - - if (c == '-') { - goto done; - } - - goto fail; /* anything else is an error */ - + + goto done; break; case STATE_LOOKING_FOR_BOTTOM_NIBBLE: @@ -803,88 +804,75 @@ static int readEdidDataforTextFile(FilePtr pFile, EdidPtr pEdid) } // readEdidDataforTextFile() /* - * readEdidFooter() - the EDID footer is in the form: + * readEdidFooter() - the optional EDID footer is in the form: * * --- End of EDID for [dpy name] --- * - * Parse the footer to get the dpy name. pFile->current is expected - * to point at the start of the footer. On success, pEdid->name is - * assigned and TRUE is returned. On failure, FALSE is returned. + * Parse the footer to get the dpy name. If a footer is present, + * pFile->current is expected to point at the start of it. On + * success, pEdid->name is assigned and TRUE is returned. On failure, + * FALSE is returned. */ static int readEdidFooterforLogFile(FilePtr pFile, EdidPtr pEdid) { char *begin; - int len; + int len, ret; + const char *edidFooterStart = "--- End of EDID for "; + const char *edidFooterEnd = " ---"; /* check that the mapping is large enough */ - if (((pFile->current - pFile->start) + 20) > pFile->length) { + if (((pFile->current - pFile->start) + strlen(edidFooterStart)) > + pFile->length) { return FALSE; } - /* make sure that the expected text is there */ - - if ((pFile->current[0] != '-') || - (pFile->current[1] != '-') || - (pFile->current[2] != '-') || - (pFile->current[3] != ' ') || - (pFile->current[4] != 'E') || - (pFile->current[5] != 'n') || - (pFile->current[6] != 'd') || - (pFile->current[7] != ' ') || - (pFile->current[8] != 'o') || - (pFile->current[9] != 'f') || - (pFile->current[10] != ' ') || - (pFile->current[11] != 'E') || - (pFile->current[12] != 'D') || - (pFile->current[13] != 'I') || - (pFile->current[14] != 'D') || - (pFile->current[15] != ' ') || - (pFile->current[16] != 'f') || - (pFile->current[17] != 'o') || - (pFile->current[18] != 'r') || - (pFile->current[19] != ' ')) { - - return FALSE; + /* check whether the footer text is there */ + + if (strncmp(pFile->current, edidFooterStart, strlen(edidFooterStart)) != 0) { + + /* if not, we do not know the name of the display device */ + + pEdid->name = strdup("unknown"); + + return TRUE; } /* skip past the start */ - pFile->current += 20; + pFile->current += strlen(edidFooterStart); begin = pFile->current; /* search for the end of the expected text */ - while (((pFile->current - pFile->start) + 5) <= pFile->length) { + ret = moveFilePointerPastString(pFile, edidFooterEnd); - if ((pFile->current[0] == ' ') && - (pFile->current[1] == '-') && - (pFile->current[2] == '-') && - (pFile->current[3] == '-')) { - - len = pFile->current - begin; + if (!ret) { + return FALSE; + } + + /* + * moveFilePointerPastString() will have moved current past the + * end of the footer + */ - /* make sure the name length seems reasonable */ + len = pFile->current - begin - strlen(edidFooterEnd); - if ((len > 512) || (len < 1)) { - return FALSE; - } - - pEdid->name = nvalloc(len + 1); - - strncpy(pEdid->name, begin, len); - pEdid->name[len] = '\0'; - - return TRUE; - } + /* make sure the name length seems reasonable */ - pFile->current++; + if ((len > 512) || (len < 1)) { + return FALSE; } - return FALSE; - + pEdid->name = nvalloc(len + 1); + + strncpy(pEdid->name, begin, len); + pEdid->name[len] = '\0'; + + return TRUE; + } // readEdidFooterforLogFile() /* @@ -894,30 +882,8 @@ static int readEdidFooterforLogFile(FilePtr pFile, EdidPtr pEdid) */ static int findEdidfooterforTextFile(FilePtr pFile) -{ - pFile->current = pFile->start; - while (((pFile->current - pFile->start) + 12) <= pFile->length) { - - if ((pFile->current[0] == 'E') && - (pFile->current[1] == 'D') && - (pFile->current[2] == 'I') && - (pFile->current[3] == 'D') && - (pFile->current[4] == ' ') && - (pFile->current[5] == 'V') && - (pFile->current[6] == 'e') && - (pFile->current[7] == 'r') && - (pFile->current[8] == 's') && - (pFile->current[9] == 'i') && - (pFile->current[10] == 'o') && - (pFile->current[11] == 'n')) { - - pFile->current = pFile->start; - return TRUE; - } - pFile->current++; - } - -return FALSE; +{ + return moveFilePointerPastString(pFile, "EDID Version"); } // findEdidfooterforTextFile() @@ -928,62 +894,42 @@ static int readMonitorNameforTextFile(FilePtr pFile, EdidPtr pEdid) char *begin; int len; - while (((pFile->current - pFile->start) + 12) <= pFile->length) { - - if ((pFile->current[0] == 'M') && - (pFile->current[1] == 'o') && - (pFile->current[2] == 'n') && - (pFile->current[3] == 'i') && - (pFile->current[4] == 't') && - (pFile->current[5] == 'o') && - (pFile->current[6] == 'r') && - (pFile->current[7] == ' ') && - (pFile->current[8] == 'N') && - (pFile->current[9] == 'a') && - (pFile->current[10] == 'm') && - (pFile->current[11] == 'e')) { - - pFile->current += 12; - goto next; - } - - pFile->current++; + int ret = moveFilePointerPastString(pFile, "Monitor Name"); + if (!ret) { + return FALSE; } - return FALSE; - next: + /* search for start of the expected text */ - /* search for start of the expected text */ + while (pFile->current[0] != ':') pFile->current++; + pFile->current += 2; - while (pFile->current[0] != ':') pFile->current++; - pFile->current += 2; + begin = pFile->current; - begin = pFile->current; + /* search for the end of expected text */ - /* search for the end of expected text */ - - while (((pFile->current - pFile->start) + 2) <= pFile->length) { + while (((pFile->current - pFile->start) + 2) <= pFile->length) { - if ((pFile->current[0] == '\r') && (pFile->current[1] == '\n')) { + if ((pFile->current[0] == '\r') && (pFile->current[1] == '\n')) { - len = pFile->current - begin; - - if ((len > 512) || (len < 1)) { - return FALSE; - } - - pEdid->name = nvalloc(len + 1); + len = pFile->current - begin; - strncpy(pEdid->name, begin, len); - pEdid->name[len] = '\0'; + if ((len > 512) || (len < 1)) { + return FALSE; + } + + pEdid->name = nvalloc(len + 1); + + strncpy(pEdid->name, begin, len); + pEdid->name[len] = '\0'; - return TRUE; - } - pFile->current++; - } + return TRUE; + } + pFile->current++; + } - return FALSE; + return FALSE; } // readMonitorNameforTextFile() diff --git a/gen-manpage-opts.c b/gen-manpage-opts.c index c8d82b1..00d0b9f 100644 --- a/gen-manpage-opts.c +++ b/gen-manpage-opts.c @@ -5,145 +5,11 @@ #include <ctype.h> #include <string.h> -#include "XF86Config-parser/xf86Parser.h" -#include "nvidia-xconfig.h" -#include "nvgetopt.h" +#include "gen-manpage-opts-helper.h" #include "option_table.h" -static void print_option(const NVGetoptOption *o) +int main(void) { - char scratch[64], *s; - int j, len; - - int omitWhiteSpace; - - /* if we are going to need the argument, process it now */ - if (o->flags & NVGETOPT_HAS_ARGUMENT) { - if (o->arg_name) { - strcpy(scratch, o->arg_name); - } else { - len = strlen(o->name); - for (j = 0; j < len; j++) scratch[j] = toupper(o->name[j]); - scratch[len] = '\0'; - } - } - - printf(".TP\n.BI \""); - /* Print the name of the option */ - /* XXX We should backslashify the '-' characters in o->name. */ - - if (isalpha(o->val)) { - /* '\-c' */ - printf("\\-%c", o->val); - - if (o->flags & NVGETOPT_HAS_ARGUMENT) { - /* ' " "ARG" "' */ - printf(" \" \"%s\" \"", scratch); - } - /* ', ' */ - printf(", "); - } - - /* '\-\-name' */ - printf("\\-\\-%s", o->name); - - /* '=" "ARG' */ - if (o->flags & NVGETOPT_HAS_ARGUMENT) { - printf("=\" \"%s", scratch); - - /* '" "' */ - if ((o->flags & NVGETOPT_IS_BOOLEAN) || - (o->flags & NVGETOPT_ALLOW_DISABLE)) { - printf("\" \""); - } - } - - /* ', \-\-no\-name' */ - if (((o->flags & NVGETOPT_IS_BOOLEAN) && - !(o->flags & NVGETOPT_HAS_ARGUMENT)) || - (o->flags & NVGETOPT_ALLOW_DISABLE)) { - printf(", \\-\\-no\\-%s", o->name); - } - - printf("\"\n"); - - /* Print the option description */ - /* XXX Each sentence should be on its own line! */ - - /* - * Print the option description: write each character one at a - * time (ugh) so that we can special-case a few characters: - * - * "[" --> "\n.I " - * "]" --> "\n" - * "-" --> "\-" - * - * Brackets are used to mark the text inbetween as italics. - * '-' is special cased so that we can backslashify it. - * - * XXX Each sentence should be on its own line! - */ - - omitWhiteSpace = 0; - - for (s = o->description; s && *s; s++) { - - switch (*s) { - case '[': - printf("\n.I "); - omitWhiteSpace = 0; - break; - case ']': - printf("\n"); - omitWhiteSpace = 1; - break; - case '-': - printf("\\-"); - omitWhiteSpace = 0; - break; - case ' ': - if (!omitWhiteSpace) { - printf("%c", *s); - } - break; - default: - printf("%c", *s); - omitWhiteSpace = 0; - break; - } - } - - printf("\n"); -} - -int main(int argc, char* argv[]) -{ - int i; - const NVGetoptOption *o; - - /* Print the "simple" options, i.e. the ones you get by running - * nvidia-xconfig --help. - */ - printf(".SH OPTIONS\n"); - for (i = 0; __options[i].name; i++) { - o = &__options[i]; - - if (!(o->flags & NVGETOPT_HELP_ALWAYS)) - continue; - - print_option(o); - } - - /* Print the advanced options. */ - printf(".SH \"ADVANCED OPTIONS\"\n"); - for (i = 0; __options[i].name; i++) { - o = &__options[i]; - - if (o->flags & NVGETOPT_HELP_ALWAYS) - continue; - - print_option(o); - } - + gen_manpage_opts_helper(__options); return 0; } diff --git a/nvidia-xconfig.c b/nvidia-xconfig.c index 54934cc..afd4cdf 100644 --- a/nvidia-xconfig.c +++ b/nvidia-xconfig.c @@ -37,6 +37,8 @@ #define TAB " " #define BIGTAB " " +#define ORIG_SUFFIX ".nvidia-xconfig-original" +#define BACKUP_SUFFIX ".backup" /* @@ -79,111 +81,35 @@ static void print_summary(void) /* - * cook_description() - the description string may contain text within - * brackets, which is used by the manpage generator to denote text to - * be italicized. We want to omit the bracket characters here. - */ - -static char *cook_description(const char *description) -{ - int len; - char *s, *dst; - const char *src; - - len = strlen(description); - s = nvalloc(len + 1); - - for (src = description, dst = s; *src; src++) { - if (*src != '[' && (*src != ']')) { - *dst = *src; - dst++; - } - } - - *dst = '\0'; - - return s; - -} /* cook_description() */ - - -/* * print_help() - loop through the __options[] table, and print the * description of each option. */ +static void print_help_helper(const char *name, const char *description) +{ + fmtoutp(TAB, name); + fmtoutp(BIGTAB, description); + fmtout(""); +} + static void print_help(int advanced) { - int i, j, len; - char *msg, *tmp, scratch[8], arg[64]; - const NVGetoptOption *o; - + unsigned int include_mask = 0; + print_version(); print_summary(); fmtout(""); fmtout("nvidia-xconfig [options]"); fmtout(""); - - for (i = 0; __options[i].name; i++) { - o = &__options[i]; - - /* - * if non-advanced help is requested, and the ALWAYS flag is - * not set, then skip this option - */ - - if (!advanced && !(o->flags & NVGETOPT_HELP_ALWAYS)) continue; - - /* if we are going to need the argument, process it now */ - - if (o->flags & NVGETOPT_HAS_ARGUMENT) { - if (o->arg_name) { - strcpy(arg, o->arg_name); - } else { - len = strlen(o->name); - for (j = 0; j < len; j++) arg[j] = toupper(o->name[j]); - arg[len] = '\0'; - } - } - - msg = nvstrcat("--", o->name, NULL); - - if (isalpha(o->val)) { - sprintf(scratch, "%c", o->val); - if (o->flags & NVGETOPT_HAS_ARGUMENT) { - tmp = nvstrcat("-", scratch, " ", arg, ", ", msg, NULL); - } else { - tmp = nvstrcat("-", scratch, ", ", msg, NULL); - } - free(msg); - msg = tmp; - } - - if (o->flags & NVGETOPT_HAS_ARGUMENT) { - tmp = nvstrcat(msg, "=", arg, NULL); - free(msg); - msg = tmp; - } - if (((o->flags & NVGETOPT_IS_BOOLEAN) && - !(o->flags & NVGETOPT_HAS_ARGUMENT)) || - (o->flags & NVGETOPT_ALLOW_DISABLE)) { - tmp = nvstrcat(msg, ", --no-", o->name, NULL); - free(msg); - msg = tmp; - } - - fmtoutp(TAB, msg); - if (o->description) { - tmp = cook_description(o->description); - fmtoutp(BIGTAB, tmp); - free(tmp); - } - fmtout(""); - free(msg); + if (!advanced) { + /* only print options with the ALWAYS flag */ + include_mask |= NVGETOPT_HELP_ALWAYS; } -} /* print_help() */ + + nvgetopt_print_help(__options, include_mask, print_help_helper); +} @@ -227,7 +153,7 @@ static void parse_commandline(Options *op, int argc, char *argv[]) case 'T': op->post_tree = TRUE; break; case 'h': print_help(FALSE); exit(0); break; case 'A': print_help(TRUE); exit(0); break; - case 's': op->silent = TRUE; break; + case 's': silence_fmt(1); break; case 'a': op->enable_all_gpus = TRUE; break; case '1': op->only_one_screen = TRUE; break; @@ -751,6 +677,10 @@ static void parse_commandline(Options *op, int argc, char *argv[]) op->nvidia_3dvision_display_type = intval; break; + case RESTORE_ORIGINAL_BACKUP_OPTION: + op->restore_original_backup = TRUE; + break; + default: goto fail; } @@ -816,21 +746,22 @@ static Options *load_default_options(void) /* * backup_file() - create a backup of orig_filename, naming the backup - * file "<original>.backup". + * file "<orig_filename>.<suffix>". * * XXX If we fail to write to the backup file (eg, it is in a * read-only directory), then we should do something intelligent like * write the backup to the user's home directory. */ -static int backup_file(Options *op, const char *orig_filename) +static int backup_file(Options *op, const char *orig_filename, + const char *suffix) { char *filename; int ret = FALSE; /* construct the backup filename */ - filename = nvstrcat(orig_filename, ".backup", NULL); + filename = nvstrcat(orig_filename, suffix, NULL); /* if the backup file already exists, remove it */ @@ -849,7 +780,7 @@ static int backup_file(Options *op, const char *orig_filename) goto done; } - fmtmsg("Backed up file '%s' as '%s'", orig_filename, filename); + fmtout("Backed up file '%s' as '%s'", orig_filename, filename); ret = TRUE; done: @@ -863,7 +794,7 @@ static int backup_file(Options *op, const char *orig_filename) /* - * write_xconfig() - write the Xconfig to file. + * find_xconfig() - search for an X config file. * * We search for the filename is this order: * @@ -874,14 +805,12 @@ static int backup_file(Options *op, const char *orig_filename) * 3) use xf86openConfigFile() * * 4) If the detected X server is XFree86, we use use "/etc/X11/XF86Config" - * Otherwise we use "/etc/X11/xorg.conf",. + * Otherwise we use "/etc/X11/xorg.conf". */ -static int write_xconfig(Options *op, XConfigPtr config) +static char *find_xconfig(Options *op, XConfigPtr config) { char *filename = NULL; - char *d, *tmp = NULL; - int ret = FALSE; /* 1) "--output-xconfig" option */ @@ -891,7 +820,7 @@ static int write_xconfig(Options *op, XConfigPtr config) /* config->filename */ - if (!filename && config->filename) { + if (!filename && config && config->filename) { filename = nvstrdup(config->filename); } @@ -917,7 +846,103 @@ static int write_xconfig(Options *op, XConfigPtr config) filename = nvstrdup("/etc/X11/xorg.conf"); } } + + return filename; +} /* find_xconfig() */ + + +/* + * restore_backup - search for a backup file with the given suffix; + * if one is found, restore it. + */ +static int restore_backup(Options *op, XConfigPtr config, const char *suffix) +{ + char *filename = find_xconfig(op, config); + char *backup = nvstrcat(filename, suffix, NULL); + struct stat st; + int ret = FALSE; + + if (lstat(backup, &st) != 0) { + fmterr("Unable to restore from original backup file '%s' (%s)", + backup, strerror(errno)); + goto done; + } + + /* + * do not restore files if the permissions might allow a malicious user to + * modify the backup, potentially tricking an administrator into restoring + * the modified backup. + */ + if (!S_ISREG(st.st_mode) /* non-regular files */ || + st.st_uid != 0 /* not owned by root*/ || + (st.st_gid != 0 && (st.st_mode & S_IWGRP)) /* non-root group write */ || + (st.st_mode & S_IWOTH) /* world writable */ ) { + fmterr("The permissions of the original backup file '%s' are too loose " + "to be trusted. The file will not be restored.", backup); + goto done; + } + + /* + * if the backup is empty, assume that no original x config file existed + * and delete the current X config file. + */ + + if (st.st_size == 0) { + if (unlink(filename) != 0) { + fmterr("Unable to remove file '%s' (%s)", + filename, strerror(errno)); + goto done; + } + } else { + /* copy the file */ + + if (!copy_file(backup, filename, 0644)) { + /* copy_file() prints out its own error messages */ + goto done; + } + } + + /* remove backup: a new one is created if nvidia-xconfig is run again */ + + if (access(backup, F_OK) == 0) { + if (unlink(backup) != 0) { + fmterr("Unable to remove backup file '%s' (%s)", + backup, strerror(errno)); + goto done; + } + } + + if (st.st_size == 0) { + fmtout("The backup file '%s' was empty. This usually means that nvidia-" + "xconfig did not find an X configuration file the first time it " + "was run. The X configuration file '%s' was deleted.", + backup, filename); + } else { + fmtout("Restored backup file '%s' to '%s'", backup, filename); + } + + ret = TRUE; + + done: + + free(backup); + free(filename); + return ret; +} /* restore_backup() */ + + + +/* + * write_xconfig() - write the Xconfig to file. + */ + +static int write_xconfig(Options *op, XConfigPtr config, int first_touch) +{ + char *filename = find_xconfig(op, config); + char *d, *tmp = NULL; + int ret = FALSE; + /* * XXX it's strange that lack of permission to write to the target * location (the likely case with users not having write @@ -937,10 +962,27 @@ static int write_xconfig(Options *op, XConfigPtr config) goto done; } - /* if the file already exists, create a backup first */ + /* + * if the file already exists, create a backup first. if this is our first + * time writing the x config, create a separate "original" backup file. + */ if (access(filename, F_OK) == 0) { - if (!backup_file(op, filename)) goto done; + if (first_touch && !backup_file(op, filename, ORIG_SUFFIX)) goto done; + if (!backup_file(op, filename, BACKUP_SUFFIX)) goto done; + } + + /* + * if no file exists, and this is our first time writing the x config, back + * up an empty file to use as the "original" backup. + */ + + else if (first_touch) { + char *fakeorig = nvstrcat(filename, ORIG_SUFFIX, NULL); + if (!copy_file("/dev/null", fakeorig, 0644)) { + fmtwarn("Unable to write an empty backup file \"%s\".", fakeorig); + } + free(fakeorig); } /* write the config file */ @@ -952,8 +994,8 @@ static int write_xconfig(Options *op, XConfigPtr config) goto done; } - fmtmsg("New X configuration file written to '%s'", filename); - fmtmsg(""); + fmtout("New X configuration file written to '%s'", filename); + fmtout(""); /* Set the default depth in the Solaris Management Facility @@ -1092,8 +1134,8 @@ static XConfigPtr find_system_xconfig(Options *op) filename = xconfigOpenConfigFile(op->xconfig, op->gop.x_project_root); if (filename) { - fmtmsg(""); - fmtmsg("Using X configuration file: \"%s\".", filename); + fmtout(""); + fmtout("Using X configuration file: \"%s\".", filename); } else { fmtwarn("Unable to locate/open X configuration file."); return NULL; @@ -1213,6 +1255,7 @@ int main(int argc, char *argv[]) Options *op; int ret; XConfigPtr config = NULL; + int first_touch = 0; /* Load defaults */ @@ -1256,6 +1299,13 @@ int main(int argc, char *argv[]) return (ret ? 0 : 1); } + if (op->restore_original_backup) { + config = find_system_xconfig(op); + xconfigGetXServerInUse(&op->gop); + ret = restore_backup(op, config, ORIG_SUFFIX); + return (ret ? 0 : 1); + } + /* * we want to open and parse the system's existing X config file, * if possible @@ -1286,6 +1336,7 @@ int main(int argc, char *argv[]) if (!config) { config = xconfigGenerate(&op->gop); + first_touch = 1; } /* @@ -1298,6 +1349,14 @@ int main(int argc, char *argv[]) return 1; } + /* if a config file existed, check to see if it had an nvidia-xconfig + * banner: this would suggest that we've touched this file before. + */ + + if (!first_touch) { + first_touch = (find_banner_prefix(config->comment) == NULL); + } + /* now, we have a good config; apply whatever the user requested */ update_xconfig(op, config); @@ -1311,7 +1370,7 @@ int main(int argc, char *argv[]) /* write the config back out to file */ - if (!write_xconfig(op, config)) { + if (!write_xconfig(op, config, first_touch)) { return 1; } diff --git a/nvidia-xconfig.h b/nvidia-xconfig.h index ef55d8d..99402e2 100644 --- a/nvidia-xconfig.h +++ b/nvidia-xconfig.h @@ -29,12 +29,6 @@ #include <sys/types.h> -typedef struct { - char **t; /* the text rows */ - int n; /* number of rows */ - int m; /* maximum row length */ -} TextRows; - /* Boolean options */ #define NOLOGO_BOOL_OPTION 0 @@ -107,7 +101,6 @@ typedef struct __options { int force_generate; int tree; int post_tree; - int silent; int keyboard_list; int mouse_list; int enable_all_gpus; @@ -115,6 +108,7 @@ typedef struct __options { int disable_scf; int query_gpu_info; int preserve_driver; + int restore_original_backup; /* * the option parser will set bits in boolean_options to indicate @@ -208,24 +202,8 @@ int copy_file(const char *srcfile, const char *dstfile, mode_t mode); int directory_exists(const char *dir); -void reset_current_terminal_width(unsigned short new_val); - -TextRows *nv_format_text_rows(const char *prefix, - const char *str, - int width, int word_boundary); -void nv_text_rows_append(TextRows *t, const char *msg); -void nv_free_text_rows(TextRows *t); -void nv_concat_text_rows(TextRows *t0, TextRows *t1); - char *fget_next_line(FILE *fp, int *eof); -void fmtout(const char *fmt, ...); -void fmtoutp(const char *prefix, const char *fmt, ...); -void fmtmsg(const char *fmt, ...); -void fmterr(const char *fmt, ...); -void fmtwarn(const char *fmt, ...); - - /* make_usable.c */ int update_modules(XConfigPtr config); diff --git a/option_table.h b/option_table.h index fa247da..e2e627d 100644 --- a/option_table.h +++ b/option_table.h @@ -10,6 +10,8 @@ * description - text for use by print_help() to describe the option */ +#include "nvidia-xconfig.h" + #define SCREEN_OPTION 1 #define LAYOUT_OPTION 2 #define X_PREFIX_OPTION 3 @@ -56,6 +58,8 @@ #define NVIDIA_3DVISION_USB_PATH_OPTION 45 #define NVIDIA_3DVISIONPRO_CONFIG_FILE_OPTION 46 #define NVIDIA_3DVISION_DISPLAY_TYPE_OPTION 47 +/* skip 48-57, as these are '0' - '9' */ +#define RESTORE_ORIGINAL_BACKUP_OPTION 58 /* * To add a boolean option to nvidia-xconfig: @@ -95,13 +99,13 @@ static const NVGetoptOption __options[] = { /* These options are printed by "nvidia-xconfig --help" */ { "xconfig", 'c', NVGETOPT_STRING_ARGUMENT | NVGETOPT_HELP_ALWAYS, NULL, - "Use [XCONFIG] as the input X config file; if this option is not " + "Use &XCONFIG& as the input X config file; if this option is not " "specified, then the same search path used by the X server will be " "used to find the X configuration file." }, { "output-xconfig", 'o', NVGETOPT_STRING_ARGUMENT | NVGETOPT_HELP_ALWAYS, NULL, - "Use [OUTPUT-XCONFIG] as the output X configuration file; if this " + "Use &OUTPUT-XCONFIG& as the output X configuration file; if this " "option is not specified, then the input X configuration filename will " "also be used as the output X configuration filename." }, @@ -213,13 +217,13 @@ static const NVGetoptOption __options[] = { "to use an 8 bit (LUT)." }, { "depth", 'd', NVGETOPT_INTEGER_ARGUMENT, NULL, - "Set the default depth to [DEPTH]; valid values for [DEPTH] are " + "Set the default depth to &DEPTH&; valid values for &DEPTH& are " "8, 15, 16, 24, and 30." }, { "device", DEVICE_OPTION, NVGETOPT_STRING_ARGUMENT, NULL, "The nvidia-xconfig utility operates on one or more devices in " "the X configuration file. If this option is specified, the " - "device named [DEVICE] in the X configuration file will be " + "device named &DEVICE& in the X configuration file will be " "used. If this option is not specified, all the devices within " "the X configuration file will be used." }, @@ -273,7 +277,7 @@ static const NVGetoptOption __options[] = { { "extract-edids-from-file", 'E', NVGETOPT_STRING_ARGUMENT, "FILE", "Extract any raw EDID byte blocks contained in the specified X " - "log file [LOG]; raw EDID bytes are printed by the NVIDIA X driver to " + "log file &LOG&; raw EDID bytes are printed by the NVIDIA X driver to " "the X log as hexidecimal when verbose logging is enabled with the " "\"-logverbose 6\" X server commandline option. Any extracted EDIDs " "are then written as binary data to individual files. These files " @@ -291,8 +295,8 @@ static const NVGetoptOption __options[] = { { "flatpanel-properties", FLATPANEL_PROPERTIES_OPTION, NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, NULL, - "Set the flat panel properties. The supported properties are: " - "'scaling', 'dithering' & 'ditheringmode'. Please see the NVIDIA " + "Set the flat panel properties. The supported properties are " + "'scaling', 'dithering' and 'ditheringmode'. Please see the NVIDIA " "README 'Appendix B. X Config Options' for more details on the " "possible values and syntax." }, @@ -318,7 +322,7 @@ static const NVGetoptOption __options[] = { NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, "WHEN", "Specify when the X server should use the builtin keyboard handler to " "process special key combinations (such as Ctrl+Alt+Backspace); see " - "the X configuration man page for details. The value of [WHEN] can be " + "the X configuration man page for details. The value of &WHEN& can be " "'Always', 'Never', or 'WhenNeeded'." }, { "include-implicit-metamodes", @@ -330,7 +334,7 @@ static const NVGetoptOption __options[] = { { "keyboard", KEYBOARD_OPTION, NVGETOPT_STRING_ARGUMENT, NULL, "When generating a new X configuration file (which happens when no " "system X configuration file can be found, or the '--force-generate' " - "option is specified), use [KEYBOARD] as the keyboard type, rather " + "option is specified), use &KEYBOARD& as the keyboard type, rather " "than attempting to probe the system for the keyboard type. " "For a list of possible keyboard types, see the '--keyboard-list' " "option." }, @@ -350,7 +354,7 @@ static const NVGetoptOption __options[] = { { "layout", LAYOUT_OPTION, NVGETOPT_STRING_ARGUMENT, NULL, "The nvidia-xconfig utility operates on a Server Layout within the X " "configuration file. If this option is specified, the layout named " - "[LAYOUT] in the X configuration file will be used. If this option is " + "&LAYOUT& in the X configuration file will be used. If this option is " "not specified, the first Server Layout in the X configuration " "file is used." }, @@ -375,20 +379,20 @@ static const NVGetoptOption __options[] = { { "mode-list", MODE_LIST_OPTION, NVGETOPT_STRING_ARGUMENT, "MODELIST", "Remove all existing modes from the X configuration's modelist and " - "add the one(s) specified in the [MODELIST] string." }, + "add the one(s) specified in the &MODELIST& string." }, { "remove-mode", REMOVE_MODE_OPTION, NVGETOPT_STRING_ARGUMENT, "MODE", "Remove the specified mode from the mode list." }, { "metamodes", META_MODES_OPTION, NVGETOPT_STRING_ARGUMENT, "METAMODES", - "Add the MetaMode X configuration option with the value [METAMODES] " + "Add the MetaMode X configuration option with the value &METAMODES& " "which will replace any existing MetaMode option already in the X " "configuration file." }, { "mouse", MOUSE_OPTION, NVGETOPT_STRING_ARGUMENT, NULL, "When generating a new X configuration file (which happens when no " "system X configuration file can be found, or the '--force-generate' " - "option is specified), use [MOUSE] as the mouse type, rather than " + "option is specified), use &MOUSE& as the mouse type, rather than " "attempting to probe the system for the mouse type. For a list of " "possible mouse types, see the '--mouse-list' option." }, @@ -398,8 +402,8 @@ static const NVGetoptOption __options[] = { { "multigpu", MULTI_GPU_OPTION, NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, NULL, - "Enable or disable MultiGPU. Valid values for [MULTIGPU] are 'Off', 'On'," - " 'Auto', 'AFR', 'SFR', 'AA'." }, + "Enable or disable MultiGPU. Valid values for &MULTIGPU& are " + "'Off', 'On', 'Auto', 'AFR', 'SFR', 'AA'." }, { "multisample-compatibility", XCONFIG_BOOL_VAL(MULTISAMPLE_COMPATIBILITY_BOOL_OPTION), @@ -443,7 +447,7 @@ static const NVGetoptOption __options[] = { { "transparent-index", TRANSPARENT_INDEX_OPTION, NVGETOPT_INTEGER_ARGUMENT | NVGETOPT_ALLOW_DISABLE, "INDEX", "Pixel to use as transparent when using color index overlays. " - "Valid values for [TRANSPARENT-INDEX] are 0-255."}, + "Valid values for &TRANSPARENT-INDEX& are 0-255."}, { "post-tree", 'T', 0, NULL, "Like the '--tree' option, but goes through the full process of " @@ -485,13 +489,13 @@ static const NVGetoptOption __options[] = { { "rotate", ROTATE_OPTION, NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, NULL, "Enable or disable the \"Rotate\" X configuration option. Valid values " - "for [ROTATE] are 'normal', 'left', 'CCW', 'inverted', " + "for &ROTATE& are 'normal', 'left', 'CCW', 'inverted', " "'right', and 'CW'. Rotation can be disabled " }, { "screen", SCREEN_OPTION, NVGETOPT_STRING_ARGUMENT, NULL, "The nvidia-xconfig utility operates on one or more screens within a " "Server Layout in the X configuration file. If this option is " - "specified, the screen named [SCREEN] in the X configuration file will " + "specified, the screen named &SCREEN& in the X configuration file will " "be used. If this option is not specified, all screens within the " "selected Server Layout in the X configuration file " "will be used used." }, @@ -510,12 +514,12 @@ static const NVGetoptOption __options[] = { { "sli", SLI_OPTION, NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, NULL, - "Enable or disable SLI. Valid values for [SLI] are 'Off', 'On', 'Auto', " + "Enable or disable SLI. Valid values for &SLI& are 'Off', 'On', 'Auto', " "'AFR', 'SFR', 'AA', 'AFRofAA', 'Mosaic'." }, { "stereo", STEREO_OPTION, NVGETOPT_INTEGER_ARGUMENT | NVGETOPT_ALLOW_DISABLE, NULL, - "Enable or disable the stereo mode. Valid values for [STEREO] are: 0 " + "Enable or disable the stereo mode. Valid values for &STEREO& are: 0 " "(Disabled), 1 (DDC glasses), 2 (Blueline glasses), 3 (Onboard stereo), " "4 (TwinView clone mode stereo), 5 (SeeReal digital flat panel), 6 " "(Sharp3D digital flat panel), 7 (Arisawa/Hyundai/Zalman/Pavione/Miracube), " @@ -551,7 +555,7 @@ static const NVGetoptOption __options[] = { { "twinview-orientation", TWINVIEW_ORIENTATION_OPTION, NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, "ORIENTATION", - "Specify the TwinViewOrientation. Valid values for [ORIENTATION] are: " + "Specify the TwinViewOrientation. Valid values for &ORIENTATION& are: " "\"RightOf\" (the default), \"LeftOf\", \"Above\", \"Below\", or " "\"Clone\"." }, @@ -564,7 +568,7 @@ static const NVGetoptOption __options[] = { TWINVIEW_XINERAMA_INFO_ORDER_OPTION, NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, NULL, "Enable or disable the \"TwinViewXineramaInfoOrder\" X configuration " - "option. [TWINVIEW-XINERAMA-INFO-ORDER] is a comma-separated list " + "option. &TWINVIEW-XINERAMA-INFO-ORDER& is a comma-separated list " "of display device names that describe the order in which " "TwinViewXineramaInfo should be reported. E.g., \"CRT, DFP, TV\"." }, @@ -667,5 +671,15 @@ static const NVGetoptOption __options[] = { XCONFIG_BOOL_VAL(BASE_MOSAIC_BOOL_OPTION), NVGETOPT_IS_BOOLEAN, NULL, "Enable or disable the \"BaseMosaic\" X configuration option." }, + { "restore-original-backup", RESTORE_ORIGINAL_BACKUP_OPTION, 0, NULL, + "Restore a backup of the X configuration that was made before any " + "changes were made by nvidia-xconfig, if such a backup is available. " + "This type of backup is made by nvidia-xconfig before it modifies an " + "X configuration file that it has not previously touched; this is " + "assumed to be an X configuration file that predates the involvement " + "of the NVIDIA X driver. As an example, nvidia-xconfig will copy an " + "X configuration file at /etc/X11/xorg.conf to /etc/X11/xorg.conf." + "nvidia-xconfig-original the first time it makes changes to that file."}, + { NULL, 0, 0, NULL, NULL }, }; @@ -563,7 +563,7 @@ void update_options(Options *op, XConfigScreenPtr screen) } set_option_value(screen, o->name, val); - fmtmsg("Option \"%s\" \"%s\" added to " + fmtout("Option \"%s\" \"%s\" added to " "Screen \"%s\".", o->name, val, screen->identifier); } } @@ -672,7 +672,6 @@ void update_options(Options *op, XConfigScreenPtr screen) op->twinview_orientation); if (remove_metamode_offsets(screen, &old_metamodes, &new_metamodes)) { - fmtmsg(""); fmtwarn("The MetaModes option contained explicit offsets, " "which would have overridden the specified " "TwinViewOrientation; in order to honor the " @@ -681,7 +680,6 @@ void update_options(Options *op, XConfigScreenPtr screen) "Old MetaModes option: \"%s\"\n" "New MetaModes option: \"%s\".", old_metamodes, new_metamodes); - fmtmsg(""); nvfree(old_metamodes); nvfree(new_metamodes); } diff --git a/query_gpu_info.c b/query_gpu_info.c index 762c05f..3caf7a7 100644 --- a/query_gpu_info.c +++ b/query_gpu_info.c @@ -26,8 +26,6 @@ static char *display_device_mask_to_display_device_name(unsigned int mask); -#define TAB " " -#define BIGTAB " " #define BUS_ID_STRING_LENGTH 32 @@ -42,54 +42,6 @@ Options *__op = NULL; -static void vformat(FILE *stream, const char *prefix, const char *msg); - - -/* - * NV_VSNPRINTF(): macro that assigns b using vsnprintf(). This is - * supposedly correct for differing semantics of vsnprintf() in - * different versions of glibc: - * - * different semantics of the return value from (v)snprintf: - * - * -1 when the buffer is not long enough (glibc < 2.1) - * - * or - * - * the length the string would have been if the buffer had been large - * enough (glibc >= 2.1) - * - * This macro allocates memory for b; the caller should free it when - * done. - */ - -#define NV_FMT_BUF_LEN 64 - -#define NV_VSNPRINTF(b, f) \ -{ \ - va_list ap; \ - int len, current_len = NV_FMT_BUF_LEN; \ - \ - (b) = nvalloc(current_len); \ - \ - while (1) { \ - va_start(ap, f); \ - len = vsnprintf((b), current_len, (f), ap); \ - va_end(ap); \ - \ - if ((len > -1) && (len < current_len)) { \ - break; \ - } else if (len > -1) { \ - current_len = len + 1; \ - } else { \ - current_len += NV_FMT_BUF_LEN; \ - } \ - \ - free(b); \ - (b) = nvalloc(current_len); \ - } \ -} - /* * copy_file() - copy the file specified by srcfile to dstfile, using @@ -230,256 +182,13 @@ void xconfigPrint(MsgType t, const char *msg) } } - if (newline) vformat(stream, NULL, ""); - vformat(stream, prefix, msg); - if (newline) vformat(stream, NULL, ""); + if (newline) fmt(stream, NULL, ""); + fmt(stream, prefix, msg); + if (newline) fmt(stream, NULL, ""); } /* xconfigPrint */ - -static unsigned short __terminal_width = 0; - -#define DEFAULT_WIDTH 75 - -/* - * 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; - } -} /* get_current_terminal_width() */ - - - -/* - * vformat() - we use nv_format_text_rows() to format the string so - * that not more than __terminal_width characters are printed across. - * - * The resulting formatted output is written to the specified stream. - * The output may also include an optional prefix (to be prepended on - * the first line, and filled with spaces on subsequent lines. - */ - -static void vformat(FILE *stream, const char *prefix, const char *msg) -{ - int i; - TextRows *t; - - if (!__terminal_width) reset_current_terminal_width(0); - - t = nv_format_text_rows(prefix, msg, __terminal_width, TRUE); - - for (i = 0; i < t->n; i++) fprintf(stream, "%s\n", t->t[i]); - - nv_free_text_rows(t); - -} /* vformat() */ - - - -/* - * 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 *) nvalloc(sizeof(TextRows)); - t->t = NULL; - t->n = 0; - t->m = 0; - - if (!str) return t; - - buf = strdup(str); - - 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_format_text_rows() */ - - - -void nv_text_rows_append(TextRows *t, const char *msg) -{ - int len; - - t->t = (char **) nvrealloc(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 - */ - -#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 = (char **) nvrealloc(t0->t, sizeof(char *) * n); - - for (i = 0; i < t1->n; i++) { - t0->t[i + t0->n] = nvstrdup(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() */ - - /* * fget_next_line() - read from the given FILE stream until a newline, * EOF, or null terminator is encountered, writing data into a @@ -532,87 +241,3 @@ char *fget_next_line(FILE *fp, int *eof) return NULL; /* should never get here */ } /* fget_next_line() */ - - -#define NV_MSG_LEVEL_LINE 0 -#define NV_MSG_LEVEL_MESSAGE 1 -#define NV_MSG_LEVEL_WARNING 2 -#define NV_MSG_LEVEL_ERROR 3 - -static void __print_message(const int level, const char *caller_prefix, - const char *msg) -{ - typedef struct { - char *prefix; - FILE *stream; - int newline; - } MessageLevelAttributes; - - const char *prefix = NULL; - - const MessageLevelAttributes msg_attrs[] = { - { NULL, stdout, FALSE }, /* NV_MSG_LEVEL_LOG */ - { NULL, stdout, FALSE }, /* NV_MSG_LEVEL_MESSAGE */ - { "WARNING: ", stderr, TRUE }, /* NV_MSG_LEVEL_WARNING */ - { "ERROR: ", stderr, TRUE } /* NV_MSG_LEVEL_ERROR */ - }; - - if (caller_prefix) { - prefix = caller_prefix; - } else { - prefix = msg_attrs[level].prefix; - } - - if (msg_attrs[level].newline) vformat(msg_attrs[level].stream, NULL, ""); - vformat(msg_attrs[level].stream, prefix, msg); - if (msg_attrs[level].newline) vformat(msg_attrs[level].stream, NULL, ""); -} - -void fmtout(const char *fmt, ...) -{ - char *msg; - - NV_VSNPRINTF(msg, fmt); - if (!__op || !__op->silent) - __print_message(NV_MSG_LEVEL_LINE, NULL, msg); - free(msg); -} - -void fmtoutp(const char *prefix, const char *fmt, ...) -{ - char *msg; - - NV_VSNPRINTF(msg, fmt); - if (!__op || !__op->silent) - __print_message(NV_MSG_LEVEL_LINE, prefix, msg); - free(msg); -} - -void fmtmsg(const char *fmt, ...) -{ - char *msg; - - NV_VSNPRINTF(msg, fmt); - if (!__op || !__op->silent) - __print_message(NV_MSG_LEVEL_MESSAGE, NULL, msg); - free(msg); -} - -void fmterr(const char *fmt, ...) -{ - char *msg; - - NV_VSNPRINTF(msg, fmt); - __print_message(NV_MSG_LEVEL_ERROR, NULL, msg); - free(msg); -} - -void fmtwarn(const char *fmt, ...) -{ - char *msg; - - NV_VSNPRINTF(msg, fmt); - __print_message(NV_MSG_LEVEL_WARNING, NULL, msg); - free(msg); -} - @@ -28,9 +28,10 @@ CC ?= gcc LD ?= ld -CFLAGS ?= -CFLAGS += -Wall -fno-strict-aliasing -Wno-unused-parameter -CFLAGS += -O2 -fno-omit-frame-pointer +# only set these warnings and optimizations if CFLAGS is unset +CFLAGS ?= -Wall -Wno-unused-parameter -O2 +# always set these -f CFLAGS +CFLAGS += -fno-strict-aliasing -fno-omit-frame-pointer CC_ONLY_CFLAGS ?= LDFLAGS ?= BIN_LDFLAGS ?= @@ -93,9 +94,9 @@ ifndef TARGET_ARCH endif ifeq ($(TARGET_OS),Linux) - LIBDL_LDFLAGS = -ldl + LIBDL_LIBS = -ldl else - LIBDL_LDFLAGS = + LIBDL_LIBS = endif OUTPUTDIR ?= _out/$(TARGET_OS)_$(TARGET_ARCH) @@ -124,11 +125,10 @@ endif # the source tarball ############################################################################## -prefix = /usr/local +PREFIX ?= /usr/local -exec_prefix = $(prefix) -bindir = $(exec_prefix)/bin -mandir = $(exec_prefix)/share/man/man1 +BINDIR = $(DESTDIR)$(PREFIX)/bin +MANDIR = $(DESTDIR)$(PREFIX)/share/man/man1 ############################################################################## @@ -145,10 +145,16 @@ default build: all # version.mk may be in one of two places: either in $(OUTPUTDIR) when # building as part of the NVIDIA driver build, or directly in the # source directory when building from the source tarball +# +# Throw an error if one of these two places did not define NVIDIA_VERSION. ############################################################################## -include $(wildcard $(OUTPUTDIR)/version.mk version.mk) +VERSION_MK := $(wildcard $(OUTPUTDIR)/version.mk version.mk) +include $(VERSION_MK) +ifndef NVIDIA_VERSION +$(error NVIDIA_VERSION undefined) +endif ############################################################################## # to generate the dependency files, use the compiler's "-MM" option to @@ -260,7 +266,7 @@ BUILD_DEPENDENCY_LIST = \ define DEFINE_OBJECT_RULE_WITH_OBJECT_NAME $(3): $(2) @$(MKDIR) $(OUTPUTDIR) - $$(call quiet_cmd,$(1)) -c $$< -o $$@ $$(CFLAGS) \ + $$(call quiet_cmd,$(1)) $$(CFLAGS) -c $$< -o $$@ \ $(call AUTO_DEP_CMD,$(1),$(2),$(3)) -include $$(call BUILD_DEPENDENCY_LIST,$(3)) @@ -298,7 +304,7 @@ define DEFINE_STAMP_C_RULE $$(STAMP_C): $$(filter-out \ $$(call BUILD_OBJECT_LIST,$$(STAMP_C)),$(1)) \ - $$(wildcard version.mk $$(OUTPUTDIR)/version.mk) + $$(VERSION_MK) @ $$(RM) $$@ @ $$(PRINTF) "const char NV_ID[] = \"nvidia id: " >> $$@ @ $$(PRINTF) "$(2): " >> $$@ @@ -1 +1 @@ -NVIDIA_VERSION = 295.40 +NVIDIA_VERSION = 302.07 |