#ifdef HAVE_CONFIG_H #include #endif #if !defined(HAVE_ICONV) #error "csconv needs iconv" #endif #include "csconv.h" #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_LOCALE_H #include #endif struct _csconv_info { iconv_t cd; }; #define skip_space(p) for(; *p != '\0' && isspace(*p); p++); static char* get_item(char *item_buf, char *line, char **next_ptr) { char *p = line; size_t r = 0; skip_space(p); for(; p[r] != '\0' && isgraph(p[r]); r++) ; *next_ptr = p + r; if (!item_buf) return NULL; strncpy(item_buf, p, r); item_buf[r] = '\0'; return item_buf; } static int read_conf( const char *locale, const char *to, const char *from, char **norm_to, char **norm_from ) { FILE *fp; char buf[128]; int retval = -1; /* TODO */ *norm_to = *norm_from = NULL; /* FIXME */ /* should we read other configuration files * such as ~/.iiim/encoding.norm ? */ fp = fopen(CSCONV_DIR "/encoding.norm", "r"); if (!fp) return -1; while((fgets(buf, sizeof(buf), fp) != NULL)) { /* TODO */ char tmp[16]; char *p = buf; int len = strlen(buf); /* skip comment */ if (('#' == *p ) || ((1 < len) && ('/' == *p) && ('/' == *(p + 1)))) continue; if ('\n' == *p || '\0' == *p) continue; get_item(NULL, p, &p); /* skip os */ if (strcmp(locale, get_item(tmp, p, &p))) continue; if (strcmp(to, get_item(tmp, p, &p))) continue; if (strcmp(from, get_item(tmp, p, &p))) continue; /* found */ get_item(NULL, p, &p); /* skip locale */ if (get_item(tmp, p, &p) != NULL) *norm_to = strdup(tmp); if (get_item(tmp, p, &p) != NULL) { *norm_from = strdup(tmp); retval = 0; } break; } fclose(fp); return retval; } csconv_t csconv_open_locale( const char *locale, const char *tocode, const char *fromcode ) { csconv_t conv = NULL; char *from = NULL, *to = NULL; if (locale == NULL) goto error; if ((read_conf(locale, tocode, fromcode, &to, &from) == -1)) goto error; conv = calloc(1, sizeof(*conv)); if (!conv) goto error; conv->cd = iconv_open(to, from); if (conv->cd == (iconv_t) -1) goto error; free(from); free(to); return conv; error: if (conv) free(conv); if (from) free(from); if (to) free(to); #ifdef HAVE_ERRNO_H errno = EINVAL; #endif return (csconv_t)-1; } csconv_t csconv_open( const char *tocode, const char *fromcode ) { #ifdef HAVE_LOCALE_H /* try to find current locale */ /* we should pass NULL as a second argument */ return csconv_open_locale(setlocale(LC_CTYPE, NULL), tocode, fromcode); #endif #ifdef HAVE_ERRNO_H /* we cannot determine locale */ /* set errno to EINVAL */ errno = EINVAL; #endif return (csconv_t)-1; } size_t csconv(csconv_t cd, const char **inbuf, size_t *inbytesleft, char **putbuf, size_t *outbytesleft ) { if (!cd || cd == (csconv_t)-1) { #ifdef HAVE_ERRNO_H errno = EINVAL; #endif return (size_t)-1; } return iconv(cd->cd, (ICONV_CONST char**)inbuf, inbytesleft, putbuf, outbytesleft); } int csconv_close( csconv_t cd ) { int retval = 0; if (!cd || cd == (csconv_t)-1) return -1; retval = iconv_close(cd->cd); free(cd); return retval; }