| #include "system.h" |
| #include <stdarg.h> |
| #include "poptint.h" |
| |
| /* Any pair of 32 bit hashes can be used. lookup3.c generates pairs, will do. */ |
| #define _JLU3_jlu32lpair 1 |
| #define jlu32lpair poptJlu32lpair |
| #include "lookup3.c" |
| |
| /*@-varuse +charint +ignoresigns @*/ |
| /*@unchecked@*/ /*@observer@*/ |
| static const unsigned char utf8_skip_data[256] = { |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
| 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, |
| 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 |
| }; |
| /*@=varuse =charint =ignoresigns @*/ |
| |
| const char * |
| POPT_prev_char (const char *str) |
| { |
| const char *p = str; |
| |
| while (1) { |
| p--; |
| if (((unsigned)*p & 0xc0) != (unsigned)0x80) |
| return p; |
| } |
| } |
| |
| const char * |
| POPT_next_char (const char *str) |
| { |
| const char *p = str; |
| |
| while (*p != '\0') { |
| p++; |
| if (((unsigned)*p & 0xc0) != (unsigned)0x80) |
| break; |
| } |
| return p; |
| } |
| |
| #if !defined(POPT_fprintf) /* XXX lose all the goop ... */ |
| |
| #if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__) |
| /* |
| * Rebind a "UTF-8" codeset for popt's internal use. |
| */ |
| char * |
| POPT_dgettext(const char * dom, const char * str) |
| { |
| char * codeset = NULL; |
| char * retval = NULL; |
| |
| if (!dom) |
| dom = textdomain(NULL); |
| codeset = bind_textdomain_codeset(dom, NULL); |
| bind_textdomain_codeset(dom, "UTF-8"); |
| retval = dgettext(dom, str); |
| bind_textdomain_codeset(dom, codeset); |
| |
| return retval; |
| } |
| #endif |
| |
| #ifdef HAVE_ICONV |
| /** |
| * Return malloc'd string converted from UTF-8 to current locale. |
| * @param istr input string (UTF-8 encoding assumed) |
| * @return localized string |
| */ |
| static /*@only@*/ /*@null@*/ char * |
| strdup_locale_from_utf8 (/*@null@*/ char * istr) |
| /*@*/ |
| { |
| char * codeset = NULL; |
| char * ostr = NULL; |
| iconv_t cd; |
| |
| if (istr == NULL) |
| return NULL; |
| |
| #ifdef HAVE_LANGINFO_H |
| codeset = nl_langinfo ((nl_item)CODESET); |
| #endif |
| |
| if (codeset != NULL && strcmp(codeset, "UTF-8") != 0 |
| && (cd = iconv_open(codeset, "UTF-8")) != (iconv_t)-1) |
| { |
| char * shift_pin = NULL; |
| size_t db = strlen(istr); |
| /*@owned@*/ |
| char * dstr = malloc((db + 1) * sizeof(*dstr)); |
| char * pin = istr; |
| char * pout = dstr; |
| size_t ib = db; |
| size_t ob = db; |
| size_t err; |
| |
| if (dstr == NULL) |
| return NULL; |
| err = iconv(cd, NULL, NULL, NULL, NULL); |
| while (1) { |
| *pout = '\0'; |
| err = iconv(cd, &pin, &ib, &pout, &ob); |
| if (err != (size_t)-1) { |
| if (shift_pin == NULL) { |
| shift_pin = pin; |
| pin = NULL; |
| ib = 0; |
| continue; |
| } |
| } else |
| switch (errno) { |
| case E2BIG: |
| { size_t used = (size_t)(pout - dstr); |
| db *= 2; |
| dstr = realloc(dstr, (db + 1) * sizeof(*dstr)); |
| if (dstr != NULL) { |
| pout = dstr + used; |
| ob = db - used; |
| continue; |
| } |
| } /*@switchbreak@*/ break; |
| case EINVAL: |
| case EILSEQ: |
| default: |
| /*@switchbreak@*/ break; |
| } |
| break; |
| } |
| (void) iconv_close(cd); |
| *pout = '\0'; |
| ostr = xstrdup(dstr); |
| free(dstr); |
| } else |
| ostr = xstrdup(istr); |
| |
| return ostr; |
| } |
| #endif |
| |
| int |
| POPT_fprintf (FILE * stream, const char * format, ...) |
| { |
| char * b = NULL, * ob = NULL; |
| int rc; |
| va_list ap; |
| |
| #if defined(HAVE_VASPRINTF) && !defined(__LCLINT__) |
| va_start(ap, format); |
| if ((rc = vasprintf(&b, format, ap)) < 0) |
| b = NULL; |
| va_end(ap); |
| #else |
| size_t nb = (size_t)1; |
| |
| /* HACK: add +1 to the realloc no. of bytes "just in case". */ |
| /* XXX Likely unneeded, the issues wrto vsnprintf(3) return b0rkage have |
| * to do with whether the final '\0' is counted (or not). The code |
| * below already adds +1 for the (possibly already counted) trailing NUL. |
| */ |
| while ((b = realloc(b, nb+1)) != NULL) { |
| va_start(ap, format); |
| rc = vsnprintf(b, nb, format, ap); |
| va_end(ap); |
| if (rc > -1) { /* glibc 2.1 */ |
| if ((size_t)rc < nb) |
| break; |
| nb = (size_t)(rc + 1); /* precise buffer length known */ |
| } else /* glibc 2.0 */ |
| nb += (nb < (size_t)100 ? (size_t)100 : nb); |
| ob = b; |
| } |
| #endif |
| |
| rc = 0; |
| if (b != NULL) { |
| #ifdef HAVE_ICONV |
| ob = strdup_locale_from_utf8(b); |
| if (ob != NULL) { |
| rc = fprintf(stream, "%s", ob); |
| free(ob); |
| } else |
| #endif |
| rc = fprintf(stream, "%s", b); |
| free (b); |
| } |
| |
| return rc; |
| } |
| |
| #endif /* !defined(POPT_fprintf) */ |