1/* 2 * From andy@pylesos.asp-linux.com.ua Tue Dec 3 14:17:38 2002 3 * (polished, aeb) 4 * 5 * Manpages for a given language have a traditional character set. 6 * E.g., for Russian this is koi8r. 7 * If the user uses a different locale, throw in an invocation of iconv. 8 * 9 * Exports: 10 * const char *get_converter (const char *path); 11 * Conversion is to the users locale. Conversion is from the 12 * manpage charset, found in environment variables, or in 13 * PATH/.charset, where PATH is the directory (below that) containing 14 * the man page. 15 * 16 * TODO: adapt this to man.conf way 17 */ 18 19/* 20 * By default iconv is not used - this is the wrong interface. 21 * But if you want it, define USE_ICONV. 22 */ 23#undef USE_ICONV 24 25#include <stdio.h> /* NULL */ 26 27#if defined __GLIBC__ && __GLIBC__ >= 2 && defined USE_ICONV 28#include <stdlib.h> /* getenv */ 29#include <unistd.h> /* access */ 30#include <string.h> /* strcmp */ 31#include <locale.h> /* setlocale */ 32#include <langinfo.h> /* nl_langinfo */ 33#include <iconv.h> /* iconv_open */ 34#include "man-iconv.h" /* get_converter */ 35#include "util.h" /* my_strdup */ 36#include "man.h" /* debug */ 37 38static char * 39find_iconv(void) { 40 static char *iconv_path = NULL; 41 static int inited = 0; 42 43 if (!inited) { 44 char *file = getenv("MAN_ICONV_PATH"); 45 if (!file) 46 file = "/usr/bin/iconv"; 47 if (access(file, X_OK) == 0) 48 iconv_path = my_strdup(file); 49 inited = 1; 50 } 51 return iconv_path; 52} 53 54static char * 55iconv_extra_flags(void) { 56 static char *iconv_flags = "-cs"; 57 static int inited = 0; 58 59 if (!inited) { 60 char *opt = getenv("MAN_ICONV_OPT"); 61 if (opt) 62 iconv_flags = my_strdup(opt); 63 inited = 1; 64 } 65 return iconv_flags; 66} 67 68static char * 69get_locale_charset (void) { 70 char *old_lc_ctype, *charset; 71 72 if ((charset = getenv("MAN_ICONV_OUTPUT_CHARSET")) == NULL) { 73 old_lc_ctype = setlocale(LC_CTYPE, ""); 74 charset = nl_langinfo(CODESET); 75 setlocale(LC_CTYPE, old_lc_ctype); 76 } 77 return charset; 78} 79 80static char * 81get_man_charset (const char *path) { 82 char *charset_env, *file, *path2, *p; 83 FILE *f = NULL; 84 85 charset_env = getenv("MAN_ICONV_INPUT_CHARSET"); 86 if (charset_env) 87 return charset_env; 88 89 if (!path || !*path) 90 return NULL; 91 92 if (debug) 93 fprintf(stderr, "get_man_charset: path=%s\n", path); 94 95 /* strip trailing "/.." and try that directory first */ 96 path2 = my_strdup(path); 97 p = strrchr(path2, '/'); 98 if (p && !strcmp(p, "/..")) { 99 *p = 0; 100 file = my_xsprintf("%s/.charset", path2); 101 f = fopen(file, "r"); 102 free(file); 103 } 104 free(path2); 105 106 /* if that fails, try path itself */ 107 if (f == NULL) { 108 file = my_xsprintf("%s/.charset", path); 109 f = fopen(file, "r"); 110 free(file); 111 } 112 113 if (f) { 114 char charset[100], *p; 115 116 fgets(charset, sizeof(charset), f); 117 fclose(f); 118 fprintf(stderr, "read %s\n", charset); 119 p = strchr(charset, '\n'); 120 if (p) { 121 *p = 0; 122 return my_strdup(charset); 123 } 124 } 125 return NULL; 126} 127 128static int 129is_conversion_supported (char *from, char *to) { 130 iconv_t cd; 131 132 if (!from || !*from || !to || !*to || !strcmp(from,to)) 133 return 0; 134 if ((cd = iconv_open(to, from)) != (iconv_t) -1) { 135 iconv_close(cd); 136 return 1; 137 } 138 return 0; 139} 140 141const char * 142get_converter (const char *path) { 143 char *from, *to, *iconv_path; 144 145 iconv_path = find_iconv(); 146 from = get_man_charset(path); 147 to = get_locale_charset(); 148 if (debug) 149 fprintf(stderr, "get_converter: iconv_path=%s from=%s to=%s\n", 150 iconv_path, from, to); 151 if (iconv_path && is_conversion_supported(from, to)) 152 return my_xsprintf("%s %s -f %s -t %s", 153 iconv_path, iconv_extra_flags(), from, to); 154 return NULL; 155} 156#else 157#include "man-iconv.h" 158 159const char * 160get_converter (const char *path) { 161 return NULL; 162} 163#endif /* __GLIBC__ && __GLIBC__ >= 2 */ 164