summaryrefslogtreecommitdiffstats
path: root/src/man-iconv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/man-iconv.c')
-rw-r--r--src/man-iconv.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/man-iconv.c b/src/man-iconv.c
new file mode 100644
index 0000000..9ce1236
--- /dev/null
+++ b/src/man-iconv.c
@@ -0,0 +1,163 @@
+/*
+ * From andy@pylesos.asp-linux.com.ua Tue Dec 3 14:17:38 2002
+ * (polished, aeb)
+ *
+ * Manpages for a given language have a traditional character set.
+ * E.g., for Russian this is koi8r.
+ * If the user uses a different locale, throw in an invocation of iconv.
+ *
+ * Exports:
+ * const char *get_converter (const char *path);
+ * Conversion is to the users locale. Conversion is from the
+ * manpage charset, found in environment variables, or in
+ * PATH/.charset, where PATH is the directory (below that) containing
+ * the man page.
+ *
+ * TODO: adapt this to man.conf way
+ */
+
+/*
+ * By default iconv is not used - this is the wrong interface.
+ * But if you want it, define USE_ICONV.
+ */
+#undef USE_ICONV
+
+#include <stdio.h> /* NULL */
+
+#if defined __GLIBC__ && __GLIBC__ >= 2 && defined USE_ICONV
+#include <stdlib.h> /* getenv */
+#include <unistd.h> /* access */
+#include <string.h> /* strcmp */
+#include <locale.h> /* setlocale */
+#include <langinfo.h> /* nl_langinfo */
+#include <iconv.h> /* iconv_open */
+#include "man-iconv.h" /* get_converter */
+#include "util.h" /* my_strdup */
+#include "man.h" /* debug */
+
+static char *
+find_iconv(void) {
+ static char *iconv_path = NULL;
+ static int inited = 0;
+
+ if (!inited) {
+ char *file = getenv("MAN_ICONV_PATH");
+ if (!file)
+ file = "/usr/bin/iconv";
+ if (access(file, X_OK) == 0)
+ iconv_path = my_strdup(file);
+ inited = 1;
+ }
+ return iconv_path;
+}
+
+static char *
+iconv_extra_flags(void) {
+ static char *iconv_flags = "-cs";
+ static int inited = 0;
+
+ if (!inited) {
+ char *opt = getenv("MAN_ICONV_OPT");
+ if (opt)
+ iconv_flags = my_strdup(opt);
+ inited = 1;
+ }
+ return iconv_flags;
+}
+
+static char *
+get_locale_charset (void) {
+ char *old_lc_ctype, *charset;
+
+ if ((charset = getenv("MAN_ICONV_OUTPUT_CHARSET")) == NULL) {
+ old_lc_ctype = setlocale(LC_CTYPE, "");
+ charset = nl_langinfo(CODESET);
+ setlocale(LC_CTYPE, old_lc_ctype);
+ }
+ return charset;
+}
+
+static char *
+get_man_charset (const char *path) {
+ char *charset_env, *file, *path2, *p;
+ FILE *f = NULL;
+
+ charset_env = getenv("MAN_ICONV_INPUT_CHARSET");
+ if (charset_env)
+ return charset_env;
+
+ if (!path || !*path)
+ return NULL;
+
+ if (debug)
+ fprintf(stderr, "get_man_charset: path=%s\n", path);
+
+ /* strip trailing "/.." and try that directory first */
+ path2 = my_strdup(path);
+ p = strrchr(path2, '/');
+ if (p && !strcmp(p, "/..")) {
+ *p = 0;
+ file = my_xsprintf("%s/.charset", path2);
+ f = fopen(file, "r");
+ free(file);
+ }
+ free(path2);
+
+ /* if that fails, try path itself */
+ if (f == NULL) {
+ file = my_xsprintf("%s/.charset", path);
+ f = fopen(file, "r");
+ free(file);
+ }
+
+ if (f) {
+ char charset[100], *p;
+
+ fgets(charset, sizeof(charset), f);
+ fclose(f);
+ fprintf(stderr, "read %s\n", charset);
+ p = strchr(charset, '\n');
+ if (p) {
+ *p = 0;
+ return my_strdup(charset);
+ }
+ }
+ return NULL;
+}
+
+static int
+is_conversion_supported (char *from, char *to) {
+ iconv_t cd;
+
+ if (!from || !*from || !to || !*to || !strcmp(from,to))
+ return 0;
+ if ((cd = iconv_open(to, from)) != (iconv_t) -1) {
+ iconv_close(cd);
+ return 1;
+ }
+ return 0;
+}
+
+const char *
+get_converter (const char *path) {
+ char *from, *to, *iconv_path;
+
+ iconv_path = find_iconv();
+ from = get_man_charset(path);
+ to = get_locale_charset();
+ if (debug)
+ fprintf(stderr, "get_converter: iconv_path=%s from=%s to=%s\n",
+ iconv_path, from, to);
+ if (iconv_path && is_conversion_supported(from, to))
+ return my_xsprintf("%s %s -f %s -t %s",
+ iconv_path, iconv_extra_flags(), from, to);
+ return NULL;
+}
+#else
+#include "man-iconv.h"
+
+const char *
+get_converter (const char *path) {
+ return NULL;
+}
+#endif /* __GLIBC__ && __GLIBC__ >= 2 */