• 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(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