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(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 * pin = istr;
89 char * pout = dstr;
90 size_t ib = db;
91 size_t ob = db;
92 size_t err;
93
94 if (dstr == NULL)
95 return NULL;
96 err = iconv(cd, NULL, NULL, NULL, NULL);
97 while (1) {
98 *pout = '\0';
99 err = iconv(cd, &pin, &ib, &pout, &ob);
100 if (err != (size_t)-1) {
101 if (shift_pin == NULL) {
102 shift_pin = pin;
103 pin = NULL;
104 ib = 0;
105 continue;
106 }
107 } else
108 switch (errno) {
109 case E2BIG:
110 { size_t used = (size_t)(pout - dstr);
111 db *= 2;
112 dstr = realloc(dstr, (db + 1) * sizeof(*dstr));
113 if (dstr != NULL) {
114 pout = dstr + used;
115 ob = db - used;
116 continue;
117 }
118 } break;
119 case EINVAL:
120 case EILSEQ:
121 default:
122 break;
123 }
124 break;
125 }
126 (void) iconv_close(cd);
127 *pout = '\0';
128 ostr = xstrdup(dstr);
129 free(dstr);
130 } else
131 ostr = xstrdup(istr);
132
133 return ostr;
134 }
135 #endif
136
137 int
POPT_fprintf(FILE * stream,const char * format,...)138 POPT_fprintf (FILE * stream, const char * format, ...)
139 {
140 char * b = NULL, * ob = NULL;
141 int rc;
142 va_list ap;
143
144 #if defined(HAVE_VASPRINTF)
145 va_start(ap, format);
146 if ((rc = vasprintf(&b, format, ap)) < 0)
147 b = NULL;
148 va_end(ap);
149 #else
150 size_t nb = (size_t)1;
151
152 /* HACK: add +1 to the realloc no. of bytes "just in case". */
153 /* XXX Likely unneeded, the issues wrto vsnprintf(3) return b0rkage have
154 * to do with whether the final '\0' is counted (or not). The code
155 * below already adds +1 for the (possibly already counted) trailing NUL.
156 */
157 while ((b = realloc(b, nb+1)) != NULL) {
158 va_start(ap, format);
159 rc = vsnprintf(b, nb, format, ap);
160 va_end(ap);
161 if (rc > -1) { /* glibc 2.1 */
162 if ((size_t)rc < nb)
163 break;
164 nb = (size_t)(rc + 1); /* precise buffer length known */
165 } else /* glibc 2.0 */
166 nb += (nb < (size_t)100 ? (size_t)100 : nb);
167 ob = b;
168 }
169 #endif
170
171 rc = 0;
172 if (b != NULL) {
173 #ifdef HAVE_ICONV
174 ob = strdup_locale_from_utf8(b);
175 if (ob != NULL) {
176 rc = fprintf(stream, "%s", ob);
177 free(ob);
178 } else
179 #endif
180 rc = fprintf(stream, "%s", b);
181 free (b);
182 }
183
184 return rc;
185 }
186
187 #endif /* !defined(POPT_fprintf) */
188