• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "system.h"
2 #include <stdarg.h>
3 #include <errno.h>
4 #ifdef HAVE_LANGINFO_H
5 #include <langinfo.h>
6 #endif
7 #include "poptint.h"
8 
9 /* Any pair of 32 bit hashes can be used. lookup3.c generates pairs, will do. */
10 #define _JLU3_jlu32lpair        1
11 #define	jlu32lpair	poptJlu32lpair
12 #include "lookup3.c"
13 
14 const char *
POPT_prev_char(const char * str)15 POPT_prev_char (const char *str)
16 {
17     const char *p = str;
18 
19     while (1) {
20 	p--;
21 	if (((unsigned)*p & 0xc0) != (unsigned)0x80)
22 	    return p;
23     }
24 }
25 
26 const char *
POPT_next_char(const char * str)27 POPT_next_char (const char *str)
28 {
29     const char *p = str;
30 
31     while (*p != '\0') {
32 	p++;
33 	if (((unsigned)*p & 0xc0) != (unsigned)0x80)
34 	    break;
35     }
36     return p;
37 }
38 
39 #if !defined(POPT_fprintf)	/* XXX lose all the goop ... */
40 
41 #if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) && defined(HAVE_DCGETTEXT)
42 /*
43  * Rebind a "UTF-8" codeset for popt's internal use.
44  */
45 char *
POPT_dgettext(const char * dom,const char * str)46 POPT_dgettext(const char * dom, const char * str)
47 {
48     char * codeset = NULL;
49     char * retval = NULL;
50 
51     if (!dom)
52 	dom = textdomain(NULL);
53     codeset = bind_textdomain_codeset(dom, NULL);
54     bind_textdomain_codeset(dom, "UTF-8");
55     retval = dgettext(dom, str);
56     bind_textdomain_codeset(dom, codeset);
57 
58     return retval;
59 }
60 #endif
61 
62 #ifdef HAVE_ICONV
63 /**
64  * Return malloc'd string converted from UTF-8 to current locale.
65  * @param istr		input string (UTF-8 encoding assumed)
66  * @return		localized string
67  */
68 static char *
strdup_locale_from_utf8(char * istr)69 strdup_locale_from_utf8 (char * istr)
70 {
71     char * codeset = NULL;
72     char * ostr = NULL;
73     iconv_t cd;
74 
75     if (istr == NULL)
76 	return NULL;
77 
78 #ifdef HAVE_LANGINFO_H
79     codeset = nl_langinfo ((nl_item)CODESET);
80 #endif
81 
82     if (codeset != NULL && strcmp(codeset, "UTF-8") != 0
83      && (cd = iconv_open(codeset, "UTF-8")) != (iconv_t)-1)
84     {
85 	char * shift_pin = NULL;
86 	size_t db = strlen(istr);
87 	char * dstr = malloc((db + 1) * sizeof(*dstr));
88 	char * dstr_tmp;
89 	char * pin = istr;
90 	char * pout = dstr;
91 	size_t ib = db;
92 	size_t ob = db;
93 	size_t err;
94 
95 	if (dstr == NULL) {
96 	    (void) iconv_close(cd);
97 	    return NULL;
98 	}
99 	err = iconv(cd, NULL, NULL, NULL, NULL);
100 	while (1) {
101 	    *pout = '\0';
102 	    err = iconv(cd, &pin, &ib, &pout, &ob);
103 	    if (err != (size_t)-1) {
104 		if (shift_pin == NULL) {
105 		    shift_pin = pin;
106 		    pin = NULL;
107 		    ib = 0;
108 		    continue;
109 		}
110 	    } else
111 	    switch (errno) {
112 	    case E2BIG:
113 	    {	size_t used = (size_t)(pout - dstr);
114 		db *= 2;
115 		dstr_tmp = realloc(dstr, (db + 1) * sizeof(*dstr));
116 		if (dstr_tmp == NULL) {
117 		    free(dstr);
118 		    (void) iconv_close(cd);
119 		    return NULL;
120 		}
121 		dstr = dstr_tmp;
122 		pout = dstr + used;
123 		ob = db - used;
124 		continue;
125 	    }   break;
126 	    case EINVAL:
127 	    case EILSEQ:
128 	    default:
129 		break;
130 	    }
131 	    break;
132 	}
133 	(void) iconv_close(cd);
134 	*pout = '\0';
135 	ostr = xstrdup(dstr);
136 	free(dstr);
137     } else
138 	ostr = xstrdup(istr);
139 
140     return ostr;
141 }
142 #endif
143 
144 int
POPT_fprintf(FILE * stream,const char * format,...)145 POPT_fprintf (FILE * stream, const char * format, ...)
146 {
147     char * b = NULL, * ob = NULL;
148     int rc;
149     va_list ap;
150 
151 #if defined(HAVE_VASPRINTF)
152     va_start(ap, format);
153     if ((rc = vasprintf(&b, format, ap)) < 0)
154 	b = NULL;
155     va_end(ap);
156 #else
157     size_t nb = (size_t)1;
158 
159     /* HACK: add +1 to the realloc no. of bytes "just in case". */
160     /* XXX Likely unneeded, the issues wrto vsnprintf(3) return b0rkage have
161      * to do with whether the final '\0' is counted (or not). The code
162      * below already adds +1 for the (possibly already counted) trailing NUL.
163      */
164     while ((b = realloc(b, nb+1)) != NULL) {
165 	va_start(ap, format);
166 	rc = vsnprintf(b, nb, format, ap);
167 	va_end(ap);
168 	if (rc > -1) {	/* glibc 2.1 */
169 	    if ((size_t)rc < nb)
170 		break;
171 	    nb = (size_t)(rc + 1);	/* precise buffer length known */
172 	} else 		/* glibc 2.0 */
173 	    nb += (nb < (size_t)100 ? (size_t)100 : nb);
174 	ob = b;
175     }
176 #endif
177 
178     rc = 0;
179     if (b != NULL) {
180 #ifdef HAVE_ICONV
181 	ob = strdup_locale_from_utf8(b);
182 	if (ob != NULL) {
183 	    rc = fprintf(stream, "%s", ob);
184 	    free(ob);
185 	} else
186 #endif
187 	    rc = fprintf(stream, "%s", b);
188 	free (b);
189     }
190 
191     return rc;
192 }
193 
194 #endif	/* !defined(POPT_fprintf) */
195