* strgutil.c (set_native_charset): Allow NULL as argument to use
[gnupg.git] / util / strgutil.c
1 /* strgutil.c -  string utilities
2  * Copyright (C) 1994, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #ifdef HAVE_LANGINFO_CODESET
26 #include <langinfo.h>
27 #endif
28
29 #include "types.h"
30 #include "util.h"
31 #include "memory.h"
32
33
34 static ushort koi8_unicode[128] = {
35     0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
36     0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
37     0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
38     0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
39     0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556,
40     0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,
41     0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565,
42     0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9,
43     0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
44     0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
45     0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
46     0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
47     0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
48     0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
49     0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
50     0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
51 };
52
53 static ushort latin2_unicode[128] = {
54     0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
55     0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F,
56     0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
57     0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F,
58     0x00A0,0x0104,0x02D8,0x0141,0x00A4,0x013D,0x015A,0x00A7,
59     0x00A8,0x0160,0x015E,0x0164,0x0179,0x00AD,0x017D,0x017B,
60     0x00B0,0x0105,0x02DB,0x0142,0x00B4,0x013E,0x015B,0x02C7,
61     0x00B8,0x0161,0x015F,0x0165,0x017A,0x02DD,0x017E,0x017C,
62     0x0154,0x00C1,0x00C2,0x0102,0x00C4,0x0139,0x0106,0x00C7,
63     0x010C,0x00C9,0x0118,0x00CB,0x011A,0x00CD,0x00CE,0x010E,
64     0x0110,0x0143,0x0147,0x00D3,0x00D4,0x0150,0x00D6,0x00D7,
65     0x0158,0x016E,0x00DA,0x0170,0x00DC,0x00DD,0x0162,0x00DF,
66     0x0155,0x00E1,0x00E2,0x0103,0x00E4,0x013A,0x0107,0x00E7,
67     0x010D,0x00E9,0x0119,0x00EB,0x011B,0x00ED,0x00EE,0x010F,
68     0x0111,0x0144,0x0148,0x00F3,0x00F4,0x0151,0x00F6,0x00F7,
69     0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9
70 };
71
72
73 static const char *active_charset_name = "iso-8859-1";
74 static ushort *active_charset = NULL;
75 static int no_translation = 0;
76
77 void
78 free_strlist( STRLIST sl )
79 {
80     STRLIST sl2;
81
82     for(; sl; sl = sl2 ) {
83         sl2 = sl->next;
84         m_free(sl);
85     }
86 }
87
88
89 STRLIST
90 add_to_strlist( STRLIST *list, const char *string )
91 {
92     STRLIST sl;
93
94     sl = m_alloc( sizeof *sl + strlen(string));
95     sl->flags = 0;
96     strcpy(sl->d, string);
97     sl->next = *list;
98     *list = sl;
99     return sl;
100 }
101
102 /****************
103  * ame as add_to_strlist() but if is_utf8 is *not* set a conversion
104  * to UTF8 is done
105  */
106 STRLIST
107 add_to_strlist2( STRLIST *list, const char *string, int is_utf8 )
108 {
109     STRLIST sl;
110
111     if( is_utf8 )
112         sl = add_to_strlist( list, string );
113     else {
114         char *p = native_to_utf8( string );
115         sl = add_to_strlist( list, p );
116         m_free( p );
117     }
118     return sl;
119 }
120
121 STRLIST
122 append_to_strlist( STRLIST *list, const char *string )
123 {
124     STRLIST r, sl;
125
126     sl = m_alloc( sizeof *sl + strlen(string));
127     sl->flags = 0;
128     strcpy(sl->d, string);
129     sl->next = NULL;
130     if( !*list )
131         *list = sl;
132     else {
133         for( r = *list; r->next; r = r->next )
134             ;
135         r->next = sl;
136     }
137     return sl;
138 }
139
140 STRLIST
141 append_to_strlist2( STRLIST *list, const char *string, int is_utf8 )
142 {
143     STRLIST sl;
144
145     if( is_utf8 )
146         sl = append_to_strlist( list, string );
147     else {
148         char *p = native_to_utf8( string );
149         sl = append_to_strlist( list, p );
150         m_free( p );
151     }
152     return sl;
153 }
154
155
156 STRLIST
157 strlist_prev( STRLIST head, STRLIST node )
158 {
159     STRLIST n;
160
161     for(n=NULL; head && head != node; head = head->next )
162         n = head;
163     return n;
164 }
165
166 STRLIST
167 strlist_last( STRLIST node )
168 {
169     if( node )
170         for( ; node->next ; node = node->next )
171             ;
172     return node;
173 }
174
175 char *
176 pop_strlist( STRLIST *list )
177 {
178   char *str=NULL;
179   STRLIST sl=*list;
180
181   if(sl)
182     {
183       str=m_alloc(strlen(sl->d)+1);
184       strcpy(str,sl->d);
185
186       *list=sl->next;
187       m_free(sl);
188     }
189
190   return str;
191 }
192
193 /****************
194  * look for the substring SUB in buffer and return a pointer to that
195  * substring in BUF or NULL if not found.
196  * Comparison is case-insensitive.
197  */
198 const char *
199 memistr( const char *buf, size_t buflen, const char *sub )
200 {
201     const byte *t, *s ;
202     size_t n;
203
204     for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
205         if( toupper(*t) == toupper(*s) ) {
206             for( buf=t++, buflen = n--, s++;
207                  n && toupper(*t) == toupper(*s); t++, s++, n-- )
208                 ;
209             if( !*s )
210                 return buf;
211             t = buf; n = buflen; s = sub ;
212         }
213
214     return NULL ;
215 }
216
217 const char *
218 ascii_memistr( const char *buf, size_t buflen, const char *sub )
219 {
220     const byte *t, *s ;
221     size_t n;
222
223     for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
224         if( ascii_toupper(*t) == ascii_toupper(*s) ) {
225             for( buf=t++, buflen = n--, s++;
226                  n && ascii_toupper(*t) == ascii_toupper(*s); t++, s++, n-- )
227                 ;
228             if( !*s )
229                 return buf;
230             t = buf; n = buflen; s = sub ;
231         }
232
233     return NULL ;
234 }
235
236 /****************
237  * Wie strncpy(), aber es werden maximal n-1 zeichen kopiert und ein
238  * '\0' angehängt. Ist n = 0, so geschieht nichts, ist Destination
239  * gleich NULL, so wird via m_alloc Speicher besorgt, ist dann nicht
240  * genügend Speicher vorhanden, so bricht die funktion ab.
241  */
242 char *
243 mem2str( char *dest , const void *src , size_t n )
244 {
245     char *d;
246     const char *s;
247
248     if( n ) {
249         if( !dest )
250             dest = m_alloc( n ) ;
251         d = dest;
252         s = src ;
253         for(n--; n && *s; n-- )
254             *d++ = *s++;
255         *d = '\0' ;
256     }
257
258     return dest ;
259 }
260
261
262 /****************
263  * remove leading and trailing white spaces
264  */
265 char *
266 trim_spaces( char *str )
267 {
268     char *string, *p, *mark;
269
270     string = str;
271     /* find first non space character */
272     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
273         ;
274     /* move characters */
275     for( (mark = NULL); (*string = *p); string++, p++ )
276         if( isspace( *(byte*)p ) ) {
277             if( !mark )
278                 mark = string ;
279         }
280         else
281             mark = NULL ;
282     if( mark )
283         *mark = '\0' ;  /* remove trailing spaces */
284
285     return str ;
286 }
287
288
289
290 unsigned int
291 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
292 {
293     byte *p, *mark;
294     unsigned n;
295
296     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
297         if( strchr(trimchars, *p ) ) {
298             if( !mark )
299                 mark = p;
300         }
301         else
302             mark = NULL;
303     }
304
305     if( mark ) {
306         *mark = 0;
307         return mark - line;
308     }
309     return len;
310 }
311
312 /****************
313  * remove trailing white spaces and return the length of the buffer
314  */
315 unsigned
316 trim_trailing_ws( byte *line, unsigned len )
317 {
318     return trim_trailing_chars( line, len, " \t\r\n" );
319 }
320
321 unsigned int
322 check_trailing_chars( const byte *line, unsigned int len,
323                       const char *trimchars )
324 {
325     const byte *p, *mark;
326     unsigned int n;
327
328     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
329         if( strchr(trimchars, *p ) ) {
330             if( !mark )
331                 mark = p;
332         }
333         else
334             mark = NULL;
335     }
336
337     if( mark ) {
338         return mark - line;
339     }
340     return len;
341 }
342
343 /****************
344  * remove trailing white spaces and return the length of the buffer
345  */
346 unsigned int
347 check_trailing_ws( const byte *line, unsigned int len )
348 {
349     return check_trailing_chars( line, len, " \t\r\n" );
350 }
351
352
353
354 int
355 string_count_chr( const char *string, int c )
356 {
357     int count;
358     for(count=0; *string; string++ )
359         if( *string == c )
360             count++;
361     return count;
362 }
363
364
365 int
366 set_native_charset( const char *newset )
367 {
368     if (!newset) 
369 #ifdef HAVE_LANGINFO_CODESET
370         newset = nl_langinfo (CODESET);
371 #else
372         newset = "8859-1";
373 #endif
374
375     if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3)) {
376         newset += 3;
377         if (*newset == '-' || *newset == '_')
378             newset++;
379     }
380
381     if( !*newset
382         || !ascii_strcasecmp (newset, "8859-1" )
383         || !ascii_strcasecmp (newset, "8859-15" ) ) {
384         active_charset_name = "iso-8859-1";
385         no_translation = 0;
386         active_charset = NULL;
387     }
388     else if( !ascii_strcasecmp( newset, "8859-2" ) ) {
389         active_charset_name = "iso-8859-2";
390         no_translation = 0;
391         active_charset = latin2_unicode;
392     }
393     else if( !ascii_strcasecmp( newset, "koi8-r" ) ) {
394         active_charset_name = "koi8-r";
395         no_translation = 0;
396         active_charset = koi8_unicode;
397     }
398     else if( !ascii_strcasecmp (newset, "utf8" )
399              || !ascii_strcasecmp(newset, "utf-8") ) {
400         active_charset_name = "utf-8";
401         no_translation = 1;
402         active_charset = NULL;
403     }
404     else
405         return G10ERR_GENERAL;
406     return 0;
407 }
408
409 const char*
410 get_native_charset()
411 {
412     return active_charset_name;
413 }
414
415 /****************
416  * Convert string, which is in native encoding to UTF8 and return the
417  * new allocated UTF8 string.
418  */
419 char *
420 native_to_utf8( const char *string )
421 {
422     const byte *s;
423     char *buffer;
424     byte *p;
425     size_t length=0;
426
427     if (no_translation) {
428         buffer = m_strdup (string);
429     }
430     else if( active_charset ) {
431         for(s=string; *s; s++ ) {
432             length++;
433             if( *s & 0x80 )
434                 length += 2; /* we may need 3 bytes */
435         }
436         buffer = m_alloc( length + 1 );
437         for(p=buffer, s=string; *s; s++ ) {
438             if( *s & 0x80 ) {
439                 ushort val = active_charset[ *s & 0x7f ];
440                 if( val < 0x0800 ) {
441                     *p++ = 0xc0 | ( (val >> 6) & 0x1f );
442                     *p++ = 0x80 | (  val & 0x3f );
443                 }
444                 else {
445                     *p++ = 0xe0 | ( (val >> 12) & 0x0f );
446                     *p++ = 0x80 | ( (val >>  6) & 0x3f );
447                     *p++ = 0x80 | (  val & 0x3f );
448                 }
449             }
450             else
451                 *p++ = *s;
452         }
453         *p = 0;
454     }
455     else {
456         for(s=string; *s; s++ ) {
457             length++;
458             if( *s & 0x80 )
459                 length++;
460         }
461         buffer = m_alloc( length + 1 );
462         for(p=buffer, s=string; *s; s++ ) {
463             if( *s & 0x80 ) {
464                 *p++ = 0xc0 | ((*s >> 6) & 3);
465                 *p++ = 0x80 | ( *s & 0x3f );
466             }
467             else
468                 *p++ = *s;
469         }
470         *p = 0;
471     }
472     return buffer;
473 }
474
475
476 /****************
477  * Convert string, which is in UTF8 to native encoding.  illegal
478  * encodings by some "\xnn" and quote all control characters. A
479  * character with value DELIM will always be quoted, it must be a
480  * vanilla ASCII character.  
481   */
482 char *
483 utf8_to_native( const char *string, size_t length, int delim )
484 {
485     int nleft;
486     int i;
487     byte encbuf[8];
488     int encidx;
489     const byte *s;
490     size_t n;
491     byte *buffer = NULL, *p = NULL;
492     unsigned long val = 0;
493     size_t slen;
494     int resync = 0;
495
496     /* 1. pass (p==NULL): count the extended utf-8 characters */
497     /* 2. pass (p!=NULL): create string */
498     for( ;; ) {
499         for( slen=length, nleft=encidx=0, n=0, s=string; slen; s++, slen-- ) {
500             if( resync ) {
501                 if( !(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)) ) {
502                     /* still invalid */
503                     if( p ) {
504                         sprintf(p, "\\x%02x", *s );
505                         p += 4;
506                     }
507                     n += 4;
508                     continue;
509                 }
510                 resync = 0;
511             }
512             if( !nleft ) {
513                 if( !(*s & 0x80) ) { /* plain ascii */
514                     if( *s < 0x20 || *s == 0x7f || *s == delim ||
515                         (delim && *s=='\\')) {
516                         n++;
517                         if( p )
518                             *p++ = '\\';
519                         switch( *s ) {
520                           case '\n': n++; if( p ) *p++ = 'n'; break;
521                           case '\r': n++; if( p ) *p++ = 'r'; break;
522                           case '\f': n++; if( p ) *p++ = 'f'; break;
523                           case '\v': n++; if( p ) *p++ = 'v'; break;
524                           case '\b': n++; if( p ) *p++ = 'b'; break;
525                           case   0 : n++; if( p ) *p++ = '0'; break;
526                           default:
527                             n += 3;
528                             if ( p ) {
529                                 sprintf( p, "x%02x", *s );
530                                 p += 3;
531                             }
532                             break;
533                         }
534                     }
535                     else {
536                         if( p ) *p++ = *s;
537                         n++;
538                     }
539                 }
540                 else if( (*s & 0xe0) == 0xc0 ) { /* 110x xxxx */
541                     val = *s & 0x1f;
542                     nleft = 1;
543                     encidx = 0;
544                     encbuf[encidx++] = *s;
545                 }
546                 else if( (*s & 0xf0) == 0xe0 ) { /* 1110 xxxx */
547                     val = *s & 0x0f;
548                     nleft = 2;
549                     encidx = 0;
550                     encbuf[encidx++] = *s;
551                 }
552                 else if( (*s & 0xf8) == 0xf0 ) { /* 1111 0xxx */
553                     val = *s & 0x07;
554                     nleft = 3;
555                     encidx = 0;
556                     encbuf[encidx++] = *s;
557                 }
558                 else if( (*s & 0xfc) == 0xf8 ) { /* 1111 10xx */
559                     val = *s & 0x03;
560                     nleft = 4;
561                     encidx = 0;
562                     encbuf[encidx++] = *s;
563                 }
564                 else if( (*s & 0xfe) == 0xfc ) { /* 1111 110x */
565                     val = *s & 0x01;
566                     nleft = 5;
567                     encidx = 0;
568                     encbuf[encidx++] = *s;
569                 }
570                 else {  /* invalid encoding: print as \xnn */
571                     if( p ) {
572                         sprintf(p, "\\x%02x", *s );
573                         p += 4;
574                     }
575                     n += 4;
576                     resync = 1;
577                 }
578             }
579             else if( *s < 0x80 || *s >= 0xc0 ) { /* invalid */
580                 if( p ) {
581                     for(i=0; i < encidx; i++ ) {
582                         sprintf(p, "\\x%02x", encbuf[i] );
583                         p += 4;
584                     }
585                     sprintf(p, "\\x%02x", *s );
586                     p += 4;
587                 }
588                 n += 4 + 4*encidx;
589                 nleft = 0;
590                 encidx = 0;
591                 resync = 1;
592             }
593             else {
594                 encbuf[encidx++] = *s;
595                 val <<= 6;
596                 val |= *s & 0x3f;
597                 if( !--nleft ) { /* ready */
598                     if (no_translation) {
599                         if( p ) {
600                             for(i=0; i < encidx; i++ )
601                                 *p++ = encbuf[i];
602                         }
603                         n += encidx;
604                         encidx = 0;
605                     }
606                     else if( active_charset ) { /* table lookup */
607                         for(i=0; i < 128; i++ ) {
608                             if( active_charset[i] == val )
609                                 break;
610                         }
611                         if( i < 128 ) { /* we can print this one */
612                             if( p ) *p++ = i+128;
613                             n++;
614                         }
615                         else { /* we do not have a translation: print utf8 */
616                             if( p ) {
617                                 for(i=0; i < encidx; i++ ) {
618                                     sprintf(p, "\\x%02x", encbuf[i] );
619                                     p += 4;
620                                 }
621                             }
622                             n += encidx*4;
623                             encidx = 0;
624                         }
625                     }
626                     else { /* native set */
627                         if( val >= 0x80 && val < 256 ) {
628                             n++;    /* we can simply print this character */
629                             if( p ) *p++ = val;
630                         }
631                         else { /* we do not have a translation: print utf8 */
632                             if( p ) {
633                                 for(i=0; i < encidx; i++ ) {
634                                     sprintf(p, "\\x%02x", encbuf[i] );
635                                     p += 4;
636                                 }
637                             }
638                             n += encidx*4;
639                             encidx = 0;
640                         }
641                     }
642                 }
643
644             }
645         }
646         if( !buffer ) { /* allocate the buffer after the first pass */
647             buffer = p = m_alloc( n + 1 );
648         }
649         else {
650             *p = 0; /* make a string */
651             return buffer;
652         }
653     }
654 }
655
656 /****************************************************
657  ******** locale insensitive ctype functions ********
658  ****************************************************/
659 /* FIXME: replace them by a table lookup and macros */
660 int
661 ascii_isupper (int c)
662 {
663     return c >= 'A' && c <= 'Z';
664 }
665
666 int
667 ascii_islower (int c)
668 {
669     return c >= 'a' && c <= 'z';
670 }
671
672 int 
673 ascii_toupper (int c)
674 {
675     if (c >= 'a' && c <= 'z')
676         c &= ~0x20;
677     return c;
678 }
679
680 int 
681 ascii_tolower (int c)
682 {
683     if (c >= 'A' && c <= 'Z')
684         c |= 0x20;
685     return c;
686 }
687
688
689 int
690 ascii_strcasecmp( const char *a, const char *b )
691 {
692     if (a == b)
693         return 0;
694
695     for (; *a && *b; a++, b++) {
696         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
697             break;
698     }
699     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
700 }
701
702 int
703 ascii_memcasecmp( const char *a, const char *b, size_t n )
704 {
705     if (a == b)
706         return 0;
707     for ( ; n; n--, a++, b++ ) {
708         if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
709             return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
710     }
711     return 0;
712 }
713
714
715 /*********************************************
716  ********** missing string functions *********
717  *********************************************/
718
719 #ifndef HAVE_STPCPY
720 char *
721 stpcpy(char *a,const char *b)
722 {
723     while( *b )
724         *a++ = *b++;
725     *a = 0;
726
727     return (char*)a;
728 }
729 #endif
730
731
732 #ifndef HAVE_STRSEP
733 /* code taken from glibc-2.2.1/sysdeps/generic/strsep.c */
734 char *
735 strsep (char **stringp, const char *delim)
736 {
737   char *begin, *end;
738
739   begin = *stringp;
740   if (begin == NULL)
741     return NULL;
742
743   /* A frequent case is when the delimiter string contains only one
744      character.  Here we don't need to call the expensive `strpbrk'
745      function and instead work using `strchr'.  */
746   if (delim[0] == '\0' || delim[1] == '\0')
747     {
748       char ch = delim[0];
749
750       if (ch == '\0')
751         end = NULL;
752       else
753         {
754           if (*begin == ch)
755             end = begin;
756           else if (*begin == '\0')
757             end = NULL;
758           else
759             end = strchr (begin + 1, ch);
760         }
761     }
762   else
763     /* Find the end of the token.  */
764     end = strpbrk (begin, delim);
765
766   if (end)
767     {
768       /* Terminate the token and set *STRINGP past NUL character.  */
769       *end++ = '\0';
770       *stringp = end;
771     }
772   else
773     /* No more delimiters; this is the last token.  */
774     *stringp = NULL;
775
776   return begin;
777 }
778 #endif /*HAVE_STRSEP*/
779
780
781 #ifndef HAVE_STRLWR
782 char *
783 strlwr(char *s)
784 {
785     char *p;
786     for(p=s; *p; p++ )
787         *p = tolower(*p);
788     return s;
789 }
790 #endif
791
792 #ifndef HAVE_STRCASECMP
793 int
794 strcasecmp( const char *a, const char *b )
795 {
796     for( ; *a && *b; a++, b++ ) {
797         if( *a != *b && toupper(*a) != toupper(*b) )
798             break;
799     }
800     return *(const byte*)a - *(const byte*)b;
801 }
802 #endif
803
804 #ifndef HAVE_STRNCASECMP
805 int
806 strncasecmp( const char *a, const char *b, size_t n )
807 {
808     for( ; n && *a && *b; a++, b++, n--) {
809         if( *a != *b && toupper(*a) != toupper(*b) )
810             break;
811     }
812     if (!n)
813       return 0;
814     return *(const byte*)a - *(const byte*)b;
815 }
816 #endif
817
818
819 #ifdef __MINGW32__
820 /* 
821  * Like vsprintf but provides a pointer to malloc'd storage, which
822  * must be freed by the caller (m_free).  Taken from libiberty as
823  * found in gcc-2.95.2 and a little bit modernized.
824  * FIXME: Write a new CRT for W32.
825  */
826 int
827 vasprintf ( char **result, const char *format, va_list args)
828 {
829   const char *p = format;
830   /* Add one to make sure that it is never zero, which might cause malloc
831      to return NULL.  */
832   int total_width = strlen (format) + 1;
833   va_list ap;
834
835   /* this is not really portable but works under Windows */
836   memcpy ( &ap, &args, sizeof (va_list));
837
838   while (*p != '\0')
839     {
840       if (*p++ == '%')
841         {
842           while (strchr ("-+ #0", *p))
843             ++p;
844           if (*p == '*')
845             {
846               ++p;
847               total_width += abs (va_arg (ap, int));
848             }
849           else
850             {
851               char *endp;  
852               total_width += strtoul (p, &endp, 10);
853               p = endp;
854             }
855           if (*p == '.')
856             {
857               ++p;
858               if (*p == '*')
859                 {
860                   ++p;
861                   total_width += abs (va_arg (ap, int));
862                 }
863               else
864                 {
865                   char *endp;
866                   total_width += strtoul (p, &endp, 10);
867                   p = endp;
868                 }
869             }
870           while (strchr ("hlL", *p))
871             ++p;
872           /* Should be big enough for any format specifier except %s
873              and floats.  */
874           total_width += 30;
875           switch (*p)
876             {
877             case 'd':
878             case 'i':
879             case 'o':
880             case 'u':
881             case 'x':
882             case 'X':
883             case 'c':
884               (void) va_arg (ap, int);
885               break;
886             case 'f':
887             case 'e':
888             case 'E':
889             case 'g':
890             case 'G':
891               (void) va_arg (ap, double);
892               /* Since an ieee double can have an exponent of 307, we'll
893                  make the buffer wide enough to cover the gross case. */
894               total_width += 307;
895             
896             case 's':
897               total_width += strlen (va_arg (ap, char *));
898               break;
899             case 'p':
900             case 'n':
901               (void) va_arg (ap, char *);
902               break;
903             }
904         }
905     }
906   *result = m_alloc (total_width);
907   if (*result != NULL)
908     return vsprintf (*result, format, args);
909   else
910     return 0;
911 }
912
913 #endif /*__MINGW32__*/
914