67dafcee5751d7fc79fdd871aae2ca2787625630
[gnupg.git] / util / strgutil.c
1 /* strgutil.c -  string utilities
2  * Copyright (C) 1994, 1998, 1999, 2000, 2001,
3  *               2003 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #ifdef HAVE_LANGINFO_CODESET
28 #include <langinfo.h>
29 #endif
30
31 /* For W32 we use dynamic loading of the iconv dll and don't need any
32  * iconv headers at all. */
33 #ifndef _WIN32
34 # ifndef HAVE_ICONV
35 #  undef USE_GNUPG_ICONV
36 # endif
37 #endif
38
39 #ifdef USE_GNUPG_ICONV
40 # include <limits.h>
41 # ifndef _WIN32
42 #  include <iconv.h>
43 # endif
44 #endif
45
46 #include "types.h"
47 #include "util.h"
48 #include "memory.h"
49 #include "i18n.h"
50 #include "dynload.h"
51
52
53 #ifndef USE_GNUPG_ICONV
54 static ushort koi8_unicode[128] = {
55     0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
56     0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
57     0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
58     0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
59     0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556,
60     0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,
61     0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565,
62     0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9,
63     0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
64     0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
65     0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
66     0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
67     0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
68     0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
69     0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
70     0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
71 };
72
73 static ushort latin2_unicode[128] = {
74     0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
75     0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F,
76     0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
77     0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F,
78     0x00A0,0x0104,0x02D8,0x0141,0x00A4,0x013D,0x015A,0x00A7,
79     0x00A8,0x0160,0x015E,0x0164,0x0179,0x00AD,0x017D,0x017B,
80     0x00B0,0x0105,0x02DB,0x0142,0x00B4,0x013E,0x015B,0x02C7,
81     0x00B8,0x0161,0x015F,0x0165,0x017A,0x02DD,0x017E,0x017C,
82     0x0154,0x00C1,0x00C2,0x0102,0x00C4,0x0139,0x0106,0x00C7,
83     0x010C,0x00C9,0x0118,0x00CB,0x011A,0x00CD,0x00CE,0x010E,
84     0x0110,0x0143,0x0147,0x00D3,0x00D4,0x0150,0x00D6,0x00D7,
85     0x0158,0x016E,0x00DA,0x0170,0x00DC,0x00DD,0x0162,0x00DF,
86     0x0155,0x00E1,0x00E2,0x0103,0x00E4,0x013A,0x0107,0x00E7,
87     0x010D,0x00E9,0x0119,0x00EB,0x011B,0x00ED,0x00EE,0x010F,
88     0x0111,0x0144,0x0148,0x00F3,0x00F4,0x0151,0x00F6,0x00F7,
89     0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9
90 };
91 #endif /*!USE_GNUPG_ICONV*/
92
93
94 #ifndef MB_LEN_MAX
95 #define MB_LEN_MAX 16
96 #endif
97
98
99 static const char *active_charset_name = "iso-8859-1";
100 static ushort *active_charset = NULL;
101 static int no_translation = 0;
102 static int use_iconv = 0;
103
104
105 #ifdef _WIN32
106 typedef void* iconv_t;
107 #ifndef ICONV_CONST
108 #define ICONV_CONST const 
109 #endif
110
111 iconv_t (* __stdcall iconv_open) (const char *tocode, const char *fromcode);
112 size_t  (* __stdcall iconv) (iconv_t cd,
113                              const char **inbuf, size_t *inbytesleft,
114                              char **outbuf, size_t *outbytesleft);
115 int     (* __stdcall iconv_close) (iconv_t cd);
116
117 #endif /*_WIN32*/
118
119
120
121 #ifdef _WIN32
122 static int 
123 load_libiconv (void)
124 {
125   static int done;
126   
127   if (!done)
128     {
129       void *handle;
130
131       done = 1; /* Do it right now because we might get called recursivly
132                    through gettext.  */
133     
134       handle = dlopen ("iconv.dll", RTLD_LAZY);
135       if (handle)
136         {
137           iconv_open  = dlsym (handle, "libiconv_open");
138           if (iconv_open)
139             iconv      = dlsym (handle, "libiconv");
140           if (iconv)    
141             iconv_close = dlsym (handle, "libiconv_close");
142         }
143       if (!handle || !iconv_close)
144         {
145           log_error (_("error loading `%s': %s\n"),
146                      "iconv.dll",  dlerror ());
147           iconv_open = NULL;
148           iconv = NULL;
149           iconv_close = NULL;
150           if (handle)
151               dlclose (handle);
152         }
153     }
154   return iconv_open? 0: -1;
155 }    
156 #endif /* _WIN32 */
157
158
159
160
161 void
162 free_strlist( STRLIST sl )
163 {
164     STRLIST sl2;
165
166     for(; sl; sl = sl2 ) {
167         sl2 = sl->next;
168         m_free(sl);
169     }
170 }
171
172
173 STRLIST
174 add_to_strlist( STRLIST *list, const char *string )
175 {
176     STRLIST sl;
177
178     sl = m_alloc( sizeof *sl + strlen(string));
179     sl->flags = 0;
180     strcpy(sl->d, string);
181     sl->next = *list;
182     *list = sl;
183     return sl;
184 }
185
186 /****************
187  * Same as add_to_strlist() but if is_utf8 is *not* set a conversion
188  * to UTF8 is done
189  */
190 STRLIST
191 add_to_strlist2( STRLIST *list, const char *string, int is_utf8 )
192 {
193     STRLIST sl;
194
195     if( is_utf8 )
196         sl = add_to_strlist( list, string );
197     else {
198         char *p = native_to_utf8( string );
199         sl = add_to_strlist( list, p );
200         m_free( p );
201     }
202     return sl;
203 }
204
205 STRLIST
206 append_to_strlist( STRLIST *list, const char *string )
207 {
208     STRLIST r, sl;
209
210     sl = m_alloc( sizeof *sl + strlen(string));
211     sl->flags = 0;
212     strcpy(sl->d, string);
213     sl->next = NULL;
214     if( !*list )
215         *list = sl;
216     else {
217         for( r = *list; r->next; r = r->next )
218             ;
219         r->next = sl;
220     }
221     return sl;
222 }
223
224 STRLIST
225 append_to_strlist2( STRLIST *list, const char *string, int is_utf8 )
226 {
227     STRLIST sl;
228
229     if( is_utf8 )
230         sl = append_to_strlist( list, string );
231     else {
232         char *p = native_to_utf8( string );
233         sl = append_to_strlist( list, p );
234         m_free( p );
235     }
236     return sl;
237 }
238
239
240 STRLIST
241 strlist_prev( STRLIST head, STRLIST node )
242 {
243     STRLIST n;
244
245     for(n=NULL; head && head != node; head = head->next )
246         n = head;
247     return n;
248 }
249
250 STRLIST
251 strlist_last( STRLIST node )
252 {
253     if( node )
254         for( ; node->next ; node = node->next )
255             ;
256     return node;
257 }
258
259 char *
260 pop_strlist( STRLIST *list )
261 {
262   char *str=NULL;
263   STRLIST sl=*list;
264
265   if(sl)
266     {
267       str=m_alloc(strlen(sl->d)+1);
268       strcpy(str,sl->d);
269
270       *list=sl->next;
271       m_free(sl);
272     }
273
274   return str;
275 }
276
277 /****************
278  * Look for the substring SUB in buffer and return a pointer to that
279  * substring in BUF or NULL if not found.
280  * Comparison is case-insensitive.
281  */
282 const char *
283 memistr( const char *buf, size_t buflen, const char *sub )
284 {
285     const byte *t, *s ;
286     size_t n;
287
288     for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
289         if( toupper(*t) == toupper(*s) ) {
290             for( buf=t++, buflen = n--, s++;
291                  n && toupper(*t) == toupper(*s); t++, s++, n-- )
292                 ;
293             if( !*s )
294                 return buf;
295             t = buf; n = buflen; s = sub ;
296         }
297
298     return NULL ;
299 }
300
301 const char *
302 ascii_memistr( const char *buf, size_t buflen, const char *sub )
303 {
304     const byte *t, *s ;
305     size_t n;
306
307     for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
308         if( ascii_toupper(*t) == ascii_toupper(*s) ) {
309             for( buf=t++, buflen = n--, s++;
310                  n && ascii_toupper(*t) == ascii_toupper(*s); t++, s++, n-- )
311                 ;
312             if( !*s )
313                 return buf;
314             t = buf; n = buflen; s = sub ;
315         }
316
317     return NULL ;
318 }
319
320
321 /* Like strncpy() but copy at max N-1 bytes and append a '\0'.  With
322  * N given as 0 nothing is copied at all. With DEST given as NULL
323  * sufficient memory is allocated using m_alloc (note that m_alloc is
324  * guaranteed to succeed or to abort the process).  */
325 char *
326 mem2str( char *dest , const void *src , size_t n )
327 {
328     char *d;
329     const char *s;
330
331     if( n ) {
332         if( !dest )
333             dest = m_alloc( n ) ;
334         d = dest;
335         s = src ;
336         for(n--; n && *s; n-- )
337             *d++ = *s++;
338         *d = '\0' ;
339     }
340
341     return dest ;
342 }
343
344
345 /*
346  * Remove leading and trailing white spaces
347  */
348 char *
349 trim_spaces( char *str )
350 {
351     char *string, *p, *mark;
352
353     string = str;
354     /* Find first non space character. */
355     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
356         ;
357     /* Move characters. */
358     for( (mark = NULL); (*string = *p); string++, p++ )
359         if( isspace( *(byte*)p ) ) {
360             if( !mark )
361                 mark = string ;
362         }
363         else
364             mark = NULL ;
365     if( mark )
366         *mark = '\0' ;  /* Remove trailing spaces.  */
367
368     return str ;
369 }
370
371
372
373 unsigned int
374 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
375 {
376     byte *p, *mark;
377     unsigned n;
378
379     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
380         if( strchr(trimchars, *p ) ) {
381             if( !mark )
382                 mark = p;
383         }
384         else
385             mark = NULL;
386     }
387
388     if( mark ) {
389         *mark = 0;
390         return mark - line;
391     }
392     return len;
393 }
394
395 /****************
396  * Remove trailing white spaces and return the length of the buffer
397  */
398 unsigned
399 trim_trailing_ws( byte *line, unsigned len )
400 {
401     return trim_trailing_chars( line, len, " \t\r\n" );
402 }
403
404
405 unsigned int
406 check_trailing_chars( const byte *line, unsigned int len,
407                       const char *trimchars )
408 {
409     const byte *p, *mark;
410     unsigned int n;
411
412     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
413         if( strchr(trimchars, *p ) ) {
414             if( !mark )
415                 mark = p;
416         }
417         else
418             mark = NULL;
419     }
420
421     if( mark ) {
422         return mark - line;
423     }
424     return len;
425 }
426
427
428 /****************
429  * Remove trailing white spaces and return the length of the buffer
430  */
431 unsigned int
432 check_trailing_ws( const byte *line, unsigned int len )
433 {
434     return check_trailing_chars( line, len, " \t\r\n" );
435 }
436
437
438
439 int
440 string_count_chr( const char *string, int c )
441 {
442     int count;
443     for(count=0; *string; string++ )
444         if( *string == c )
445             count++;
446     return count;
447 }
448
449 #ifdef USE_GNUPG_ICONV
450 static void
451 handle_iconv_error (const char *to, const char *from, int use_fallback)
452 {
453   if (errno == EINVAL)
454     log_error (_("conversion from `%s' to `%s' not available\n"),
455                from, to);
456   else
457     log_error (_("iconv_open failed: %s\n"), strerror (errno));
458
459   if (use_fallback)
460     {
461       /* To avoid further error messages we fallback to Latin-1 for the
462          native encoding.  This is justified as one can expect that on a
463          utf-8 enabled system nl_langinfo() will work and thus we won't
464          never get to here.  Thus Latin-1 seems to be a reasonable
465          default.  */
466       active_charset_name = "iso-8859-1";
467       no_translation = 0;
468       active_charset = NULL;
469       use_iconv = 0;
470     }
471 }
472 #endif /*USE_GNUPG_ICONV*/
473
474 int
475 set_native_charset( const char *newset )
476 {
477     const char *full_newset;
478
479     if (!newset) {
480 #ifdef _WIN32
481         static char codepage[30];
482
483         /* We are a console program thus we need to use the
484            GetConsoleOutputCP fucntion and not the the GetACP which
485            would give the codepage for a GUI program.  Note this is
486            not a bulletproof detection because GetConsoleCP might
487            retrun a different one for console input.  Not sure how to
488            cope with that.  */
489         sprintf (codepage, "CP%u", (unsigned int)GetConsoleOutputCP ());
490         /* If it is the Windows name for Latin-1 we use the standard
491            name instead to avoid loading of iconv.dll.  Unfortunately
492            it is often CP850 and we don't have a custom translation
493            for it. */
494         if (!strcmp (codepage, "CP1252"))
495             newset = "iso-8859-1";
496         else
497             newset = codepage;
498 #else
499 #ifdef HAVE_LANGINFO_CODESET
500         newset = nl_langinfo (CODESET);
501 #else
502         newset = "iso-8859-1";
503 #endif
504 #endif
505     }
506
507     full_newset = newset;
508     if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3)) {
509         newset += 3;
510         if (*newset == '-' || *newset == '_')
511             newset++;
512     }
513
514     if( !*newset
515         || !ascii_strcasecmp (newset, "8859-1" )
516         || !ascii_strcasecmp (newset, "8859-15" ) ) {
517         active_charset_name = "iso-8859-1";
518         no_translation = 0;
519         active_charset = NULL;
520         use_iconv = 0;
521     }
522     else if( !ascii_strcasecmp (newset, "utf8" )
523              || !ascii_strcasecmp(newset, "utf-8") ) {
524         active_charset_name = "utf-8";
525         no_translation = 1;
526         active_charset = NULL;
527         use_iconv = 0;
528     }
529 #ifdef USE_GNUPG_ICONV
530     else {
531       iconv_t cd;
532
533 #ifdef _WIN32
534       if (load_libiconv ())
535           return G10ERR_GENERAL;
536 #endif /*_WIN32*/      
537
538       cd = iconv_open (full_newset, "utf-8");
539       if (cd == (iconv_t)-1) {
540           handle_iconv_error (full_newset, "utf-8", 0);
541           return G10ERR_GENERAL;
542       }
543       iconv_close (cd);
544       cd = iconv_open ("utf-8", full_newset);
545       if (cd == (iconv_t)-1) {
546           handle_iconv_error ("utf-8", full_newset, 0);
547           return G10ERR_GENERAL;
548       }
549       iconv_close (cd);
550       active_charset_name = full_newset;
551       no_translation = 0;
552       active_charset = NULL; 
553       use_iconv = 1;
554     }
555 #else /*!USE_GNUPG_ICONV*/
556     else if( !ascii_strcasecmp( newset, "8859-2" ) ) {
557         active_charset_name = "iso-8859-2";
558         no_translation = 0;
559         active_charset = latin2_unicode;
560         use_iconv = 0;
561     }
562     else if( !ascii_strcasecmp( newset, "koi8-r" ) ) {
563         active_charset_name = "koi8-r";
564         no_translation = 0;
565         active_charset = koi8_unicode;
566         use_iconv = 0;
567     }
568     else
569         return G10ERR_GENERAL;
570 #endif /*!USE_GNUPG_ICONV*/
571     return 0;
572 }
573
574 const char*
575 get_native_charset()
576 {
577     return active_charset_name;
578 }
579
580 /****************
581  * Convert string, which is in native encoding to UTF8 and return the
582  * new allocated UTF8 string.
583  */
584 char *
585 native_to_utf8( const char *string )
586 {
587   const byte *s;
588   char *buffer;
589   byte *p;
590   size_t length=0;
591   
592   if (no_translation)
593     { /* Already utf-8 encoded. */
594       buffer = m_strdup (string);
595     }
596   else if( !active_charset && !use_iconv) /* Shortcut implementation
597                                              for Latin-1.  */
598     { 
599       for(s=string; *s; s++ ) 
600         {
601           length++;
602           if( *s & 0x80 )
603             length++;
604         }
605       buffer = m_alloc( length + 1 );
606       for(p=buffer, s=string; *s; s++ )
607         {
608           if( *s & 0x80 )
609             {
610               *p++ = 0xc0 | ((*s >> 6) & 3);
611               *p++ = 0x80 | ( *s & 0x3f );
612             }
613           else
614             *p++ = *s;
615         }
616       *p = 0;
617     }
618   else       /* Need to use a translation table. */
619     { 
620 #ifdef USE_GNUPG_ICONV
621       iconv_t cd;
622       const char *inptr;
623       char *outptr;
624       size_t inbytes, outbytes;
625      
626       cd = iconv_open ("utf-8", active_charset_name);
627       if (cd == (iconv_t)-1)
628         {
629           handle_iconv_error ("utf-8", active_charset_name, 1);
630           return native_to_utf8 (string);
631         }
632
633       for (s=string; *s; s++ ) 
634         {
635           length++;
636           if ((*s & 0x80))
637             length += 5; /* We may need up to 6 bytes for the utf8 output. */
638         }
639       buffer = m_alloc (length + 1);
640
641       inptr = string;
642       inbytes = strlen (string);
643       outptr = buffer;
644       outbytes = length;
645       if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
646                   &outptr, &outbytes) == (size_t)-1)
647         {
648           log_error (_("conversion from `%s' to `%s' failed: %s\n"),
649                        active_charset_name, "utf-8", strerror (errno));
650           /* We don't do any conversion at all but use the strings as is. */
651           strcpy (buffer, string);
652         }
653       else /* Success.  */
654         {
655           *outptr = 0;
656           /* We could realloc the buffer now but I doubt that it makes
657              much sense given that it will get freed anyway soon
658              after.  */
659         }
660       iconv_close (cd);
661
662 #else /*!USE_GNUPG_ICONV*/
663       for(s=string; *s; s++ ) 
664         {
665           length++;
666           if( *s & 0x80 )
667             length += 2; /* We may need up to 3 bytes. */
668         }
669       buffer = m_alloc( length + 1 );
670       for(p=buffer, s=string; *s; s++ ) {
671         if( *s & 0x80 ) {
672           ushort val = active_charset[ *s & 0x7f ];
673           if( val < 0x0800 ) {
674             *p++ = 0xc0 | ( (val >> 6) & 0x1f );
675             *p++ = 0x80 | (  val & 0x3f );
676           }
677           else {
678             *p++ = 0xe0 | ( (val >> 12) & 0x0f );
679             *p++ = 0x80 | ( (val >>  6) & 0x3f );
680             *p++ = 0x80 | (  val & 0x3f );
681           }
682         }
683         else
684           *p++ = *s;
685       }
686       *p = 0;
687 #endif /*!USE_GNUPG_ICONV*/
688
689     }
690   return buffer;
691 }
692
693
694 /****************
695  * Convert string, which is in UTF8 to native encoding.  illegal
696  * encodings by some "\xnn" and quote all control characters. A
697  * character with value DELIM will always be quoted, it must be a
698  * vanilla ASCII character.  A DELIM value of -1 is special: it disables 
699  * all quoting of control characters.
700  */
701 char *
702 utf8_to_native( const char *string, size_t length, int delim )
703 {
704     int nleft;
705     int i;
706     byte encbuf[8];
707     int encidx;
708     const byte *s;
709     size_t n;
710     byte *buffer = NULL, *p = NULL;
711     unsigned long val = 0;
712     size_t slen;
713     int resync = 0;
714
715     /* 1. pass (p==NULL): count the extended utf-8 characters */
716     /* 2. pass (p!=NULL): create string */
717     for( ;; ) {
718         for( slen=length, nleft=encidx=0, n=0, s=string; slen; s++, slen-- ) {
719             if( resync ) {
720                 if( !(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)) ) {
721                     /* still invalid */
722                     if( p ) {
723                         sprintf(p, "\\x%02x", *s );
724                         p += 4;
725                     }
726                     n += 4;
727                     continue;
728                 }
729                 resync = 0;
730             }
731             if( !nleft ) {
732                 if( !(*s & 0x80) ) { /* plain ascii */
733                     if( delim != -1 
734                         && (*s < 0x20 || *s == 0x7f || *s == delim
735                             || (delim && *s=='\\'))) {
736                         n++;
737                         if( p )
738                             *p++ = '\\';
739                         switch( *s ) {
740                           case '\n': n++; if( p ) *p++ = 'n'; break;
741                           case '\r': n++; if( p ) *p++ = 'r'; break;
742                           case '\f': n++; if( p ) *p++ = 'f'; break;
743                           case '\v': n++; if( p ) *p++ = 'v'; break;
744                           case '\b': n++; if( p ) *p++ = 'b'; break;
745                           case   0 : n++; if( p ) *p++ = '0'; break;
746                           default:
747                             n += 3;
748                             if ( p ) {
749                                 sprintf( p, "x%02x", *s );
750                                 p += 3;
751                             }
752                             break;
753                         }
754                     }
755                     else {
756                         if( p ) *p++ = *s;
757                         n++;
758                     }
759                 }
760                 else if( (*s & 0xe0) == 0xc0 ) { /* 110x xxxx */
761                     val = *s & 0x1f;
762                     nleft = 1;
763                     encidx = 0;
764                     encbuf[encidx++] = *s;
765                 }
766                 else if( (*s & 0xf0) == 0xe0 ) { /* 1110 xxxx */
767                     val = *s & 0x0f;
768                     nleft = 2;
769                     encidx = 0;
770                     encbuf[encidx++] = *s;
771                 }
772                 else if( (*s & 0xf8) == 0xf0 ) { /* 1111 0xxx */
773                     val = *s & 0x07;
774                     nleft = 3;
775                     encidx = 0;
776                     encbuf[encidx++] = *s;
777                 }
778                 else if( (*s & 0xfc) == 0xf8 ) { /* 1111 10xx */
779                     val = *s & 0x03;
780                     nleft = 4;
781                     encidx = 0;
782                     encbuf[encidx++] = *s;
783                 }
784                 else if( (*s & 0xfe) == 0xfc ) { /* 1111 110x */
785                     val = *s & 0x01;
786                     nleft = 5;
787                     encidx = 0;
788                     encbuf[encidx++] = *s;
789                 }
790                 else {  /* invalid encoding: print as \xnn */
791                     if( p ) {
792                         sprintf(p, "\\x%02x", *s );
793                         p += 4;
794                     }
795                     n += 4;
796                     resync = 1;
797                 }
798             }
799             else if( *s < 0x80 || *s >= 0xc0 ) { /* invalid */
800                 if( p ) {
801                     for(i=0; i < encidx; i++ ) {
802                         sprintf(p, "\\x%02x", encbuf[i] );
803                         p += 4;
804                     }
805                     sprintf(p, "\\x%02x", *s );
806                     p += 4;
807                 }
808                 n += 4 + 4*encidx;
809                 nleft = 0;
810                 encidx = 0;
811                 resync = 1;
812             }
813             else {
814                 encbuf[encidx++] = *s;
815                 val <<= 6;
816                 val |= *s & 0x3f;
817                 if( !--nleft ) { /* ready */
818                     if (no_translation) {
819                         if( p ) {
820                             for(i=0; i < encidx; i++ )
821                                 *p++ = encbuf[i];
822                         }
823                         n += encidx;
824                         encidx = 0;
825                     }
826 #ifdef USE_GNUPG_ICONV
827                     else if(use_iconv) {
828                         /* Our strategy for using iconv is a bit
829                          * strange but it better keeps compatibility
830                          * with previous versions in regard to how
831                          * invalid encodings are displayed.  What we
832                          * do is to keep the utf-8 as is and have the
833                          * real translation step then at the end.
834                          * Yes, I know that this is ugly.  However we
835                          * are short of the 1.4 release and for this
836                          * branch we should not mee too much around
837                          * with iconv things.  One reason for this is
838                          * that we don't know enough about non-GNU
839                          * iconv implementation and want to minimize
840                          * the risk of breaking the code on too many
841                          * platforms.  */
842                         if( p ) {
843                             for(i=0; i < encidx; i++ )
844                                 *p++ = encbuf[i];
845                         }
846                         n += encidx;
847                         encidx = 0;
848                     }
849 #endif /*USE_GNUPG_ICONV*/
850                     else if( active_charset ) { /* table lookup */
851                         for(i=0; i < 128; i++ ) {
852                             if( active_charset[i] == val )
853                                 break;
854                         }
855                         if( i < 128 ) { /* we can print this one */
856                             if( p ) *p++ = i+128;
857                             n++;
858                         }
859                         else { /* we do not have a translation: print utf8 */
860                             if( p ) {
861                                 for(i=0; i < encidx; i++ ) {
862                                     sprintf(p, "\\x%02x", encbuf[i] );
863                                     p += 4;
864                                 }
865                             }
866                             n += encidx*4;
867                             encidx = 0;
868                         }
869                     }
870                     else { /* native set */
871                         if( val >= 0x80 && val < 256 ) {
872                             n++;    /* we can simply print this character */
873                             if( p ) *p++ = val;
874                         }
875                         else { /* we do not have a translation: print utf8 */
876                             if( p ) {
877                                 for(i=0; i < encidx; i++ ) {
878                                     sprintf(p, "\\x%02x", encbuf[i] );
879                                     p += 4;
880                                 }
881                             }
882                             n += encidx*4;
883                             encidx = 0;
884                         }
885                     }
886                 }
887
888             }
889         }
890         if( !buffer ) { /* allocate the buffer after the first pass */
891             buffer = p = m_alloc( n + 1 );
892         }
893 #ifdef USE_GNUPG_ICONV
894         else if(use_iconv) {
895             /* Note: See above for comments.  */
896             iconv_t cd;
897             const char *inptr;
898             char *outbuf, *outptr;
899             size_t inbytes, outbytes;
900             
901             *p = 0;  /* Terminate the buffer. */
902
903             cd = iconv_open (active_charset_name, "utf-8");
904             if (cd == (iconv_t)-1)
905                 {
906                     handle_iconv_error (active_charset_name, "utf-8", 1);
907                     m_free (buffer);
908                     return utf8_to_native (string, length, delim);
909                 }
910
911             /* Allocate a new buffer large enough to hold all possible
912              * encodings. */
913             n = p - buffer + 1;
914             inbytes = n - 1;;
915             inptr = buffer;
916             outbytes = n * MB_LEN_MAX;
917             if (outbytes / MB_LEN_MAX != n) 
918                 BUG (); /* Actually an overflow. */
919             outbuf = outptr = m_alloc (outbytes);
920             if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
921                         &outptr, &outbytes) == (size_t)-1) {
922                 log_error (_("conversion from `%s' to `%s' failed: %s\n"),
923                            "utf-8", active_charset_name, strerror (errno));
924                 /* Didn't worked out.  Temporary disable the use of
925                  * iconv and fall back to our old code. */
926                 m_free (buffer);
927                 buffer = NULL;
928                 m_free (outbuf);
929                 use_iconv = 0;
930                 outbuf = utf8_to_native (string, length, delim);
931                 use_iconv = 1;
932             }
933             else { /* Success.  */
934                 *outptr = 0;
935                 /* We could realloc the buffer now but I doubt that it makes
936                    much sense given that it will get freed anyway soon
937                    after.  */
938                 m_free (buffer);
939             }
940             iconv_close (cd);
941             return outbuf;
942         }
943 #endif /*USE_GNUPG_ICONV*/
944         else {
945             *p = 0; /* make a string */
946             return buffer;
947         }
948     }
949 }
950
951 /****************************************************
952  ******** locale insensitive ctype functions ********
953  ****************************************************/
954 /* FIXME: replace them by a table lookup and macros */
955 int
956 ascii_isupper (int c)
957 {
958     return c >= 'A' && c <= 'Z';
959 }
960
961 int
962 ascii_islower (int c)
963 {
964     return c >= 'a' && c <= 'z';
965 }
966
967 int 
968 ascii_toupper (int c)
969 {
970     if (c >= 'a' && c <= 'z')
971         c &= ~0x20;
972     return c;
973 }
974
975 int 
976 ascii_tolower (int c)
977 {
978     if (c >= 'A' && c <= 'Z')
979         c |= 0x20;
980     return c;
981 }
982
983
984 int
985 ascii_strcasecmp (const char *a, const char *b)
986 {
987   const unsigned char *p1 = (const unsigned char *)a;
988   const unsigned char *p2 = (const unsigned char *)b;
989   unsigned char c1, c2;
990
991   if (p1 == p2)
992     return 0;
993
994   do
995     {
996       c1 = ascii_tolower (*p1);
997       c2 = ascii_tolower (*p2);
998
999       if (c1 == '\0')
1000         break;
1001
1002       ++p1;
1003       ++p2;
1004     }
1005   while (c1 == c2);
1006   
1007   return c1 - c2;
1008 }
1009
1010 int 
1011 ascii_strncasecmp (const char *a, const char *b, size_t n)
1012 {
1013   const unsigned char *p1 = (const unsigned char *)a;
1014   const unsigned char *p2 = (const unsigned char *)b;
1015   unsigned char c1, c2;
1016
1017   if (p1 == p2 || !n )
1018     return 0;
1019
1020   do
1021     {
1022       c1 = ascii_tolower (*p1);
1023       c2 = ascii_tolower (*p2);
1024
1025       if ( !--n || c1 == '\0')
1026         break;
1027
1028       ++p1;
1029       ++p2;
1030     }
1031   while (c1 == c2);
1032   
1033   return c1 - c2;
1034 }
1035
1036
1037 int
1038 ascii_memcasecmp( const char *a, const char *b, size_t n )
1039 {
1040     if (a == b)
1041         return 0;
1042     for ( ; n; n--, a++, b++ ) {
1043         if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
1044             return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
1045     }
1046     return 0;
1047 }
1048
1049
1050
1051 /*********************************************
1052  ********** missing string functions *********
1053  *********************************************/
1054
1055 #ifndef HAVE_STPCPY
1056 char *
1057 stpcpy(char *a,const char *b)
1058 {
1059     while( *b )
1060         *a++ = *b++;
1061     *a = 0;
1062
1063     return (char*)a;
1064 }
1065 #endif
1066
1067
1068 #ifndef HAVE_STRSEP
1069 /* code taken from glibc-2.2.1/sysdeps/generic/strsep.c */
1070 char *
1071 strsep (char **stringp, const char *delim)
1072 {
1073   char *begin, *end;
1074
1075   begin = *stringp;
1076   if (begin == NULL)
1077     return NULL;
1078
1079   /* A frequent case is when the delimiter string contains only one
1080      character.  Here we don't need to call the expensive `strpbrk'
1081      function and instead work using `strchr'.  */
1082   if (delim[0] == '\0' || delim[1] == '\0')
1083     {
1084       char ch = delim[0];
1085
1086       if (ch == '\0')
1087         end = NULL;
1088       else
1089         {
1090           if (*begin == ch)
1091             end = begin;
1092           else if (*begin == '\0')
1093             end = NULL;
1094           else
1095             end = strchr (begin + 1, ch);
1096         }
1097     }
1098   else
1099     /* Find the end of the token.  */
1100     end = strpbrk (begin, delim);
1101
1102   if (end)
1103     {
1104       /* Terminate the token and set *STRINGP past NUL character.  */
1105       *end++ = '\0';
1106       *stringp = end;
1107     }
1108   else
1109     /* No more delimiters; this is the last token.  */
1110     *stringp = NULL;
1111
1112   return begin;
1113 }
1114 #endif /*HAVE_STRSEP*/
1115
1116
1117 #ifndef HAVE_STRLWR
1118 char *
1119 strlwr(char *s)
1120 {
1121     char *p;
1122     for(p=s; *p; p++ )
1123         *p = tolower(*(unsigned char *)p);
1124     return s;
1125 }
1126 #endif
1127
1128 #ifndef HAVE_STRCASECMP
1129 int
1130 strcasecmp( const char *a, const char *b )
1131 {
1132     for( ; *a && *b; a++, b++ ) {
1133         if( *a != *b
1134             && toupper(*(const byte *)a) != toupper(*(const byte *)b) )
1135             break;
1136     }
1137     return *(const byte*)a - *(const byte*)b;
1138 }
1139 #endif
1140
1141 #ifndef HAVE_STRNCASECMP
1142 int
1143 strncasecmp( const char *a, const char *b, size_t n )
1144 {
1145     for( ; n && *a && *b; a++, b++, n--) {
1146         if( *a != *b
1147             && toupper(*(const byte *)a) != toupper(*(const byte *)b) )
1148             break;
1149     }
1150     if (!n)
1151       return 0;
1152     return *(const byte*)a - *(const byte*)b;
1153 }
1154 #endif
1155
1156
1157 #ifdef _WIN32
1158 /* 
1159  * Like vsprintf but provides a pointer to malloc'd storage, which
1160  * must be freed by the caller (m_free).  Taken from libiberty as
1161  * found in gcc-2.95.2 and a little bit modernized.
1162  * FIXME: Write a new CRT for W32.
1163  */
1164 int
1165 vasprintf (char **result, const char *format, va_list args)
1166 {
1167   const char *p = format;
1168   /* Add one to make sure that it is never zero, which might cause malloc
1169      to return NULL.  */
1170   int total_width = strlen (format) + 1;
1171   va_list ap;
1172
1173   /* this is not really portable but works under Windows */
1174   memcpy ( &ap, &args, sizeof (va_list));
1175
1176   while (*p != '\0')
1177     {
1178       if (*p++ == '%')
1179         {
1180           while (strchr ("-+ #0", *p))
1181             ++p;
1182           if (*p == '*')
1183             {
1184               ++p;
1185               total_width += abs (va_arg (ap, int));
1186             }
1187           else
1188             {
1189               char *endp;  
1190               total_width += strtoul (p, &endp, 10);
1191               p = endp;
1192             }
1193           if (*p == '.')
1194             {
1195               ++p;
1196               if (*p == '*')
1197                 {
1198                   ++p;
1199                   total_width += abs (va_arg (ap, int));
1200                 }
1201               else
1202                 {
1203                   char *endp;
1204                   total_width += strtoul (p, &endp, 10);
1205                   p = endp;
1206                 }
1207             }
1208           while (strchr ("hlL", *p))
1209             ++p;
1210           /* Should be big enough for any format specifier except %s
1211              and floats.  */
1212           total_width += 30;
1213           switch (*p)
1214             {
1215             case 'd':
1216             case 'i':
1217             case 'o':
1218             case 'u':
1219             case 'x':
1220             case 'X':
1221             case 'c':
1222               (void) va_arg (ap, int);
1223               break;
1224             case 'f':
1225             case 'e':
1226             case 'E':
1227             case 'g':
1228             case 'G':
1229               (void) va_arg (ap, double);
1230               /* Since an ieee double can have an exponent of 307, we'll
1231                  make the buffer wide enough to cover the gross case. */
1232               total_width += 307;
1233             
1234             case 's':
1235               total_width += strlen (va_arg (ap, char *));
1236               break;
1237             case 'p':
1238             case 'n':
1239               (void) va_arg (ap, char *);
1240               break;
1241             }
1242         }
1243     }
1244   *result = m_alloc (total_width);
1245   if (*result != NULL)
1246     return vsprintf (*result, format, args);
1247   else
1248     return 0;
1249 }
1250
1251 int
1252 asprintf (char **buf, const char *fmt, ...)
1253 {
1254   int status;
1255   va_list ap;
1256
1257   va_start (ap, fmt);
1258   status = vasprintf (buf, fmt, ap);
1259   va_end (ap);
1260   return status;  
1261 }
1262
1263 #endif /*_WIN32*/