summaryrefslogtreecommitdiffstats
path: root/src/gripes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gripes.c')
-rw-r--r--src/gripes.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/gripes.c b/src/gripes.c
new file mode 100644
index 0000000..505f8b8
--- /dev/null
+++ b/src/gripes.c
@@ -0,0 +1,139 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "gripes.h"
+#include "man.h" /* for progname */
+
+extern char *msg[];
+
+static char *mantexts = "man"; /* e.g. /usr/lib/locale/%L/man.cat */
+
+#ifdef NONLS
+
+static char *
+getmsg (int n) {
+ char *s;
+
+ if (0 < n && n <= MAXMSG)
+ s = msg[n];
+ else {
+ fprintf (stderr, "man: internal error - cannot find message %d\n", n);
+ exit (1);
+ }
+ return s;
+}
+
+#else /* NONLS */
+
+#include <string.h>
+#include <nl_types.h>
+#include "../catopen/catopen.c"
+
+nl_catd catfd = (nl_catd) -1;
+int cat_is_open = 0;
+
+static void
+catinit (void) {
+ if (!cat_is_open) {
+#ifdef NL_CAT_LOCALE
+ catfd = my_catopen(mantexts,NL_CAT_LOCALE);
+#else
+ catfd = my_catopen(mantexts,0);
+#endif
+ if (catfd == (nl_catd) -1) {
+ /*
+ * Only complain if LANG exists, and LANG != "en"
+ * (or when debugging). Also accept en_ZA etc.
+ * No messages for C locale.
+ */
+ char *s, *lg;
+ s = getenv("NLSPATH");
+ lg = getenv("LANG");
+ if (!lg)
+ lg = getenv("LC_MESSAGES");
+ if (!lg)
+ lg = getenv("LC_ALL");
+ if (lg && strncmp(lg, "en", 2) && strcmp(lg, "C") && strcmp(lg, "POSIX")) {
+ fprintf(stderr,
+ "Cannot open the message catalog \"%s\" for locale \"%s\"\n"
+ "(NLSPATH=\"%s\")\n\n",
+ mantexts, lg, s ? s : "<none>");
+ } else if (debug) {
+ fprintf(stderr,
+"Looked whether there exists a message catalog %s, but there is none\n"
+"(and for English messages none is needed)\n\n",
+ mantexts);
+ }
+ }
+ }
+ cat_is_open = 1;
+}
+
+/*
+ * This routine is unnecessary, but people ask for such things.
+ *
+ * Maybe man is suid or sgid to some user that owns the cat directories.
+ * Maybe NLSPATH can be manipulated by the user - even though
+ * modern glibc avoids using environment variables when the
+ * program is suid or sgid.
+ * So, maybe the string s that we are returning was user invented
+ * and we have to avoid %n and the like.
+ *
+ * As a random hack, only allow %s,%d,%o, and only two %-signs.
+ */
+static int
+is_suspect (char *s) {
+ int ct = 0;
+
+ while (*s) {
+ if (*s++ == '%') {
+ ct++;
+ if (*s != 's' && *s != 'd' && *s != 'o')
+ return 1;
+ }
+ }
+ return (ct > 2);
+}
+
+static char *
+getmsg (int n) {
+ char *s = "";
+
+ catinit ();
+ if (catfd != (nl_catd) -1) {
+ s = catgets(catfd, 1, n, "");
+ if (*s && is_suspect(s))
+ s = "";
+ }
+ if (*s == 0 && 0 < n && n <= MAXMSG)
+ s = msg[n];
+ if (*s == 0) {
+ fprintf(stderr,
+ "man: internal error - cannot find message %d\n", n);
+ exit (1);
+ }
+ return s;
+}
+
+#endif /* NONLS */
+
+void
+gripe (int n, ...) {
+ va_list p;
+
+ va_start(p, n);
+ vfprintf (stderr, getmsg(n), p);
+ va_end(p);
+ fflush (stderr);
+}
+
+void
+fatal (int n, ...) {
+ va_list p;
+ fprintf (stderr, "%s: ", progname);
+ va_start(p, n);
+ vfprintf (stderr, getmsg(n), p);
+ va_end(p);
+ exit (1);
+}