third_party: Update popt to 1.16 release
[samba.git] / third_party / popt / poptint.c
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. */
6 #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) */