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