/* * 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 /* NULL */ #if defined __GLIBC__ && __GLIBC__ >= 2 && defined USE_ICONV #include /* getenv */ #include /* access */ #include /* strcmp */ #include /* setlocale */ #include /* nl_langinfo */ #include /* 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 */