b13d8b0016c60420f0040542de3479e992ca80cc
[gnupg.git] / jnlib / stringhelp.c
1 /* stringhelp.c -  standard string helper functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
3  *               2006, 2007  Free Software Foundation, Inc.
4  *
5  * This file is part of JNLIB.
6  *
7  * JNLIB is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * JNLIB is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <ctype.h>
26 #ifdef HAVE_W32_SYSTEM
27 #include <windows.h>
28 #endif
29
30 #include "libjnlib-config.h"
31 #include "utf8conv.h"
32 #include "stringhelp.h"
33
34
35 #define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
36
37 /*
38  * Look for the substring SUB in buffer and return a pointer to that
39  * substring in BUFFER or NULL if not found.
40  * Comparison is case-insensitive.
41  */
42 const char *
43 memistr (const void *buffer, size_t buflen, const char *sub)
44 {
45   const unsigned char *buf = buffer;
46   const unsigned char *t = (const unsigned char *)buffer;
47   const unsigned char *s = (const unsigned char *)sub;
48   size_t n = buflen;
49
50   for ( ; n ; t++, n-- )
51     {
52       if ( toupper (*t) == toupper (*s) )
53         {
54           for ( buf=t++, buflen = n--, s++;
55                 n && toupper (*t) == toupper (*s); t++, s++, n-- )
56             ;
57           if (!*s)
58             return (const char*)buf;
59           t = buf;
60           s = (const unsigned char *)sub ;
61           n = buflen;
62         }
63     }
64   return NULL;
65 }
66
67 const char *
68 ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
69 {
70   const unsigned char *buf = buffer;
71   const unsigned char *t = (const unsigned char *)buf;
72   const unsigned char *s = (const unsigned char *)sub;
73   size_t n = buflen;
74
75   for ( ; n ; t++, n-- )
76     {
77       if (ascii_toupper (*t) == ascii_toupper (*s) )
78         {
79           for ( buf=t++, buflen = n--, s++;
80                 n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
81             ;
82           if (!*s)
83             return (const char*)buf;
84           t = (const unsigned char *)buf;
85           s = (const unsigned char *)sub ;
86           n = buflen;
87         }
88     }
89   return NULL;
90 }
91
92 /* This function is similar to strncpy().  However it won't copy more
93    than N - 1 characters and makes sure that a '\0' is appended. With
94    N given as 0, nothing will happen.  With DEST given as NULL, memory
95    will be allocated using jnlib_xmalloc (i.e. if it runs out of core
96    the function terminates).  Returns DES or a pointer to the
97    allocated memory.
98  */
99 char *
100 mem2str( char *dest , const void *src , size_t n )
101 {
102     char *d;
103     const char *s;
104
105     if( n ) {
106         if( !dest )
107             dest = jnlib_xmalloc( n ) ;
108         d = dest;
109         s = src ;
110         for(n--; n && *s; n-- )
111             *d++ = *s++;
112         *d = '\0' ;
113     }
114
115     return dest ;
116 }
117
118
119 /****************
120  * remove leading and trailing white spaces
121  */
122 char *
123 trim_spaces( char *str )
124 {
125     char *string, *p, *mark;
126
127     string = str;
128     /* find first non space character */
129     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
130         ;
131     /* move characters */
132     for( (mark = NULL); (*string = *p); string++, p++ )
133         if( isspace( *(byte*)p ) ) {
134             if( !mark )
135                 mark = string ;
136         }
137         else
138             mark = NULL ;
139     if( mark )
140         *mark = '\0' ;  /* remove trailing spaces */
141
142     return str ;
143 }
144
145 /****************
146  * remove trailing white spaces
147  */
148 char *
149 trim_trailing_spaces( char *string )
150 {
151     char *p, *mark;
152
153     for( mark = NULL, p = string; *p; p++ ) {
154         if( isspace( *(byte*)p ) ) {
155             if( !mark )
156                 mark = p;
157         }
158         else
159             mark = NULL;
160     }
161     if( mark )
162         *mark = '\0' ;
163
164     return string ;
165 }
166
167
168 unsigned
169 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
170 {
171     byte *p, *mark;
172     unsigned n;
173
174     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
175         if( strchr(trimchars, *p ) ) {
176             if( !mark )
177                 mark = p;
178         }
179         else
180             mark = NULL;
181     }
182
183     if( mark ) {
184         *mark = 0;
185         return mark - line;
186     }
187     return len;
188 }
189
190 /****************
191  * remove trailing white spaces and return the length of the buffer
192  */
193 unsigned
194 trim_trailing_ws( byte *line, unsigned len )
195 {
196     return trim_trailing_chars( line, len, " \t\r\n" );
197 }
198
199 size_t
200 length_sans_trailing_chars (const unsigned char *line, size_t len,
201                             const char *trimchars )
202 {
203   const unsigned char *p, *mark;
204   size_t n;
205   
206   for( mark=NULL, p=line, n=0; n < len; n++, p++ )
207     {
208       if (strchr (trimchars, *p ))
209         {
210           if( !mark )
211             mark = p;
212         }
213       else
214         mark = NULL;
215     }
216   
217   if (mark) 
218     return mark - line;
219   return len;
220 }
221
222 /*
223  *  Return the length of line ignoring trailing white-space.
224  */
225 size_t
226 length_sans_trailing_ws (const unsigned char *line, size_t len)
227 {
228   return length_sans_trailing_chars (line, len, " \t\r\n");
229 }
230
231
232
233 /***************
234  * Extract from a given path the filename component.
235  *
236  */
237 char *
238 make_basename(const char *filepath, const char *inputpath)
239 {
240 #ifdef __riscos__
241     return riscos_make_basename(filepath, inputpath);
242 #else
243     char *p;
244
245     (void)inputpath; /* Only required for riscos.  */
246
247     if ( !(p=strrchr(filepath, '/')) )
248 #ifdef HAVE_DRIVE_LETTERS
249         if ( !(p=strrchr(filepath, '\\')) )
250             if ( !(p=strrchr(filepath, ':')) )
251 #endif
252               {
253                 return jnlib_xstrdup(filepath);
254               }
255
256     return jnlib_xstrdup(p+1);
257 #endif
258 }
259
260
261
262 /***************
263  * Extract from a given filename the path prepended to it.
264  * If their isn't a path prepended to the filename, a dot
265  * is returned ('.').
266  *
267  */
268 char *
269 make_dirname(const char *filepath)
270 {
271     char *dirname;
272     int  dirname_length;
273     char *p;
274
275     if ( !(p=strrchr(filepath, '/')) )
276 #ifdef HAVE_DRIVE_LETTERS
277         if ( !(p=strrchr(filepath, '\\')) )
278             if ( !(p=strrchr(filepath, ':')) )
279 #endif
280               {
281                 return jnlib_xstrdup(".");
282               }
283
284     dirname_length = p-filepath;
285     dirname = jnlib_xmalloc(dirname_length+1);
286     strncpy(dirname, filepath, dirname_length);
287     dirname[dirname_length] = 0;
288
289     return dirname;
290 }
291
292
293
294 /****************
295  * Construct a filename from the NULL terminated list of parts.
296  * Tilde expansion is done here.
297  */
298 char *
299 make_filename( const char *first_part, ... )
300 {
301   va_list arg_ptr ;
302   size_t n;
303   const char *s;
304   char *name, *home, *p;
305   
306   va_start (arg_ptr, first_part);
307   n = strlen (first_part) + 1;
308   while ( (s = va_arg (arg_ptr, const char *)) )
309     n += strlen(s) + 1;
310   va_end(arg_ptr);
311   
312   home = NULL;
313   if ( *first_part == '~' && first_part[1] == '/'
314        && (home = getenv("HOME")) && *home )
315     n += strlen (home);
316   
317   name = jnlib_xmalloc (n);
318   p = (home 
319        ? stpcpy (stpcpy (name,home), first_part + 1)
320        : stpcpy(name, first_part));
321
322   va_start (arg_ptr, first_part) ;
323   while ( (s = va_arg(arg_ptr, const char *)) )
324     p = stpcpy (stpcpy (p,"/"), s);
325   va_end(arg_ptr);
326
327 #ifdef HAVE_DRIVE_LETTERS
328   /* We better avoid mixing slashes and backslashes and prefer
329      backslashes.  There is usual no problem with mixing them, however
330      a very few W32 API calls can't grok plain slashes.  Printing
331      filenames with mixed slashes also looks a bit strange. */
332   if (strchr (name, '\\'))
333     {
334       for (p=name; *p; p++)
335         if (*p == '/')
336           *p = '\\';
337     }
338 #endif /*HAVE_DRIVE_LETTERS*/
339   return name;
340 }
341
342
343 /* Compare whether the filenames are identical.  This is a
344    special version of strcmp() taking the semantics of filenames in
345    account.  Note that this function works only on the supplied names
346    without considereing any context like the current directory.  See
347    also same_file_p(). */
348 int
349 compare_filenames (const char *a, const char *b)
350 {
351 #ifdef HAVE_DRIVE_LETTERS
352   for ( ; *a && *b; a++, b++ ) 
353     {
354       if (*a != *b 
355           && (toupper (*(const unsigned char*)a)
356               != toupper (*(const unsigned char*)b) )
357           && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
358         break;
359     }
360   if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
361     return 0;
362   else
363     return (toupper (*(const unsigned char*)a) 
364             - toupper (*(const unsigned char*)b));
365 #else
366     return strcmp(a,b);
367 #endif
368 }
369
370
371 /* Convert 2 hex characters at S to a byte value.  Return this value
372    or -1 if there is an error. */
373 int
374 hextobyte (const char *s)
375 {
376   int c;
377
378   if ( *s >= '0' && *s <= '9' )
379     c = 16 * (*s - '0');
380   else if ( *s >= 'A' && *s <= 'F' )
381     c = 16 * (10 + *s - 'A');
382   else if ( *s >= 'a' && *s <= 'f' )
383     c = 16 * (10 + *s - 'a');
384   else
385     return -1;
386   s++;
387   if ( *s >= '0' && *s <= '9' )
388     c += *s - '0';
389   else if ( *s >= 'A' && *s <= 'F' )
390     c += 10 + *s - 'A';
391   else if ( *s >= 'a' && *s <= 'f' )
392     c += 10 + *s - 'a';
393   else
394     return -1;
395   return c;
396 }
397
398
399 /* Print a BUFFER to stream FP while replacing all control characters
400    and the characters DELIM and DELIM2 with standard C escape
401    sequences.  Returns the number of characters printed. */
402 size_t 
403 print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
404                          int delim, int delim2)
405 {
406   const unsigned char *p = buffer;
407   size_t count = 0;
408
409   for (; length; length--, p++, count++)
410     {
411       if (*p < 0x20 
412           || *p == 0x7f
413           || *p == delim 
414           || *p == delim2
415           || ((delim || delim2) && *p=='\\'))
416         {
417           putc ('\\', fp);
418           count++;
419           if (*p == '\n')
420             {
421               putc ('n', fp);
422               count++;
423             }
424           else if (*p == '\r')
425             {
426               putc ('r', fp);
427               count++;
428             }
429           else if (*p == '\f')
430             {
431               putc ('f', fp);
432               count++;
433             }
434           else if (*p == '\v')
435             {
436               putc ('v', fp);
437               count++;
438             }
439           else if (*p == '\b')
440             {
441               putc ('b', fp);
442               count++;
443             }
444           else if (!*p)
445             {
446               putc('0', fp);
447               count++;
448             }
449           else
450             {
451               fprintf (fp, "x%02x", *p);
452               count += 3;
453             }
454         }
455       else
456         {
457           putc (*p, fp);
458           count++;
459         }
460     }
461
462   return count;
463 }
464
465 /* Same as print_sanitized_buffer2 but with just one delimiter. */
466 size_t 
467 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
468                         int delim)
469 {
470   return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
471 }
472
473
474 size_t 
475 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
476                              size_t length, int delim)
477 {
478   const char *p = buffer;
479   size_t i;
480
481   /* We can handle plain ascii simpler, so check for it first. */
482   for (i=0; i < length; i++ ) 
483     {
484       if ( (p[i] & 0x80) )
485         break;
486     }
487   if (i < length)
488     {
489         char *buf = utf8_to_native (p, length, delim);
490         /*(utf8 conversion already does the control character quoting)*/
491         i = strlen (buf);
492         fputs (buf, fp);
493         jnlib_free (buf);
494         return i;
495     }
496   else
497     return print_sanitized_buffer (fp, p, length, delim);
498 }
499
500
501 size_t 
502 print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
503 {
504   return string? print_sanitized_buffer2 (fp, string, strlen (string),
505                                           delim, delim2):0;
506 }
507
508 size_t 
509 print_sanitized_string (FILE *fp, const char *string, int delim)
510 {
511   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
512 }
513
514 size_t 
515 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
516 {
517   return string? print_sanitized_utf8_buffer (fp,
518                                               string, strlen (string),
519                                               delim) : 0;
520 }
521
522 /* Create a string from the buffer P_ARG of length N which is suitable for
523    printing.  Caller must release the created string using xfree. */
524 char *
525 sanitize_buffer (const void *p_arg, size_t n, int delim)
526 {
527   const unsigned char *p = p_arg;
528   size_t save_n, buflen;
529   const unsigned char *save_p;
530   char *buffer, *d;
531
532   /* First count length. */
533   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
534     {
535       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
536         {
537           if ( *p=='\n' || *p=='\r' || *p=='\f'
538                || *p=='\v' || *p=='\b' || !*p )
539             buflen += 2;
540           else
541             buflen += 5;
542         }
543       else
544         buflen++;
545     }
546   p = save_p;
547   n = save_n;
548   /* And now make the string */
549   d = buffer = jnlib_xmalloc( buflen );
550   for ( ; n; n--, p++ )
551     {
552       if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
553         *d++ = '\\';
554         if( *p == '\n' )
555           *d++ = 'n';
556         else if( *p == '\r' )
557           *d++ = 'r';
558         else if( *p == '\f' )
559           *d++ = 'f';
560         else if( *p == '\v' )
561           *d++ = 'v';
562         else if( *p == '\b' )
563           *d++ = 'b';
564         else if( !*p )
565           *d++ = '0';
566         else {
567           sprintf(d, "x%02x", *p );
568           d += 3;
569         }
570       }
571       else
572         *d++ = *p;
573     }
574   *d = 0;
575   return buffer;
576 }
577
578
579 /* Given a string containing an UTF-8 encoded text, return the number
580    of characters in this string.  It differs from strlen in that it
581    only counts complete UTF-8 characters.  Note, that this function
582    does not take combined characters into account.  */
583 size_t
584 utf8_charcount (const char *s)
585 {
586   size_t n;
587
588   for (n=0; *s; s++)
589     if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
590       n++;
591
592   return n;
593 }
594
595
596 /****************************************************
597  **********  W32 specific functions  ****************
598  ****************************************************/
599
600 #ifdef HAVE_W32_SYSTEM
601 const char *
602 w32_strerror (int ec)
603 {
604   static char strerr[256];
605   
606   if (ec == -1)
607     ec = (int)GetLastError ();
608   FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
609                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
610                  strerr, DIM (strerr)-1, NULL);
611   return strerr;    
612 }
613 #endif /*HAVE_W32_SYSTEM*/
614
615
616 /****************************************************
617  ******** Locale insensitive ctype functions ********
618  ****************************************************/
619 /* FIXME: replace them by a table lookup and macros */
620 int
621 ascii_isupper (int c)
622 {
623     return c >= 'A' && c <= 'Z';
624 }
625
626 int
627 ascii_islower (int c)
628 {
629     return c >= 'a' && c <= 'z';
630 }
631
632 int 
633 ascii_toupper (int c)
634 {
635     if (c >= 'a' && c <= 'z')
636         c &= ~0x20;
637     return c;
638 }
639
640 int 
641 ascii_tolower (int c)
642 {
643     if (c >= 'A' && c <= 'Z')
644         c |= 0x20;
645     return c;
646 }
647
648
649 int
650 ascii_strcasecmp( const char *a, const char *b )
651 {
652     if (a == b)
653         return 0;
654
655     for (; *a && *b; a++, b++) {
656         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
657             break;
658     }
659     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
660 }
661
662 int 
663 ascii_strncasecmp (const char *a, const char *b, size_t n)
664 {
665   const unsigned char *p1 = (const unsigned char *)a;
666   const unsigned char *p2 = (const unsigned char *)b;
667   unsigned char c1, c2;
668
669   if (p1 == p2 || !n )
670     return 0;
671
672   do
673     {
674       c1 = ascii_tolower (*p1);
675       c2 = ascii_tolower (*p2);
676
677       if ( !--n || c1 == '\0')
678         break;
679
680       ++p1;
681       ++p2;
682     }
683   while (c1 == c2);
684   
685   return c1 - c2;
686 }
687
688
689 int
690 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
691 {
692   const char *a = a_arg;
693   const char *b = b_arg;
694
695   if (a == b)
696     return 0;
697   for ( ; n; n--, a++, b++ )
698     {
699       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
700         return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
701     }
702   return 0;
703 }
704
705 int
706 ascii_strcmp( const char *a, const char *b )
707 {
708     if (a == b)
709         return 0;
710
711     for (; *a && *b; a++, b++) {
712         if (*a != *b )
713             break;
714     }
715     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
716 }
717
718
719 void *
720 ascii_memcasemem (const void *haystack, size_t nhaystack,
721                   const void *needle, size_t nneedle)
722 {
723
724   if (!nneedle)
725     return (void*)haystack; /* finding an empty needle is really easy */
726   if (nneedle <= nhaystack)
727     {
728       const char *a = haystack;
729       const char *b = a + nhaystack - nneedle;
730       
731       for (; a <= b; a++)
732         {
733           if ( !ascii_memcasecmp (a, needle, nneedle) )
734             return (void *)a;
735         }
736     }
737   return NULL;
738 }
739
740 /*********************************************
741  ********** missing string functions *********
742  *********************************************/
743
744 #ifndef HAVE_STPCPY
745 char *
746 stpcpy(char *a,const char *b)
747 {
748     while( *b )
749         *a++ = *b++;
750     *a = 0;
751
752     return (char*)a;
753 }
754 #endif
755
756 #ifndef HAVE_STRSEP
757 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
758 char *
759 strsep (char **stringp, const char *delim)
760 {
761   char *begin, *end;
762
763   begin = *stringp;
764   if (begin == NULL)
765     return NULL;
766
767   /* A frequent case is when the delimiter string contains only one
768      character.  Here we don't need to call the expensive `strpbrk'
769      function and instead work using `strchr'.  */
770   if (delim[0] == '\0' || delim[1] == '\0')
771     {
772       char ch = delim[0];
773
774       if (ch == '\0')
775         end = NULL;
776       else
777         {
778           if (*begin == ch)
779             end = begin;
780           else if (*begin == '\0')
781             end = NULL;
782           else
783             end = strchr (begin + 1, ch);
784         }
785     }
786   else
787     /* Find the end of the token.  */
788     end = strpbrk (begin, delim);
789
790   if (end)
791     {
792       /* Terminate the token and set *STRINGP past NUL character.  */
793       *end++ = '\0';
794       *stringp = end;
795     }
796   else
797     /* No more delimiters; this is the last token.  */
798     *stringp = NULL;
799
800   return begin;
801 }
802 #endif /*HAVE_STRSEP*/
803
804
805 #ifndef HAVE_STRLWR
806 char *
807 strlwr(char *s)
808 {
809     char *p;
810     for(p=s; *p; p++ )
811         *p = tolower(*p);
812     return s;
813 }
814 #endif
815
816
817 #ifndef HAVE_STRCASECMP
818 int
819 strcasecmp( const char *a, const char *b )
820 {
821     for( ; *a && *b; a++, b++ ) {
822         if( *a != *b && toupper(*a) != toupper(*b) )
823             break;
824     }
825     return *(const byte*)a - *(const byte*)b;
826 }
827 #endif
828
829
830 /****************
831  * mingw32/cpd has a memicmp()
832  */
833 #ifndef HAVE_MEMICMP
834 int
835 memicmp( const char *a, const char *b, size_t n )
836 {
837     for( ; n; n--, a++, b++ )
838         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
839             return *(const byte *)a - *(const byte*)b;
840     return 0;
841 }
842 #endif
843
844
845 #ifndef HAVE_MEMRCHR
846 void *
847 memrchr (const void *buffer, int c, size_t n)
848 {
849   const unsigned char *p = buffer;
850
851   for (p += n; n ; n--)
852     if (*--p == c)
853       return (void *)p;
854   return NULL;
855 }
856 #endif /*HAVE_MEMRCHR*/
857
858 \f
859 /* Percent-escape the string STR by replacing colons with '%3a'.  If
860    EXTRA is not NULL all characters in EXTRA are also escaped.  */
861 static char *
862 do_percent_escape (const char *str, const char *extra, int die)
863 {
864   int i, j;
865   char *ptr;
866
867   if (!str)
868     return NULL;
869
870   for (i=j=0; str[i]; i++)
871     if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
872       j++;
873   if (die)
874     ptr = jnlib_xmalloc (i + 2 * j + 1);
875   else
876     {
877       ptr = jnlib_malloc (i + 2 * j + 1);
878       if (!ptr)
879         return NULL;
880     }
881   i = 0;
882   while (*str)
883     {
884       if (*str == ':')
885         {
886           ptr[i++] = '%';
887           ptr[i++] = '3';
888           ptr[i++] = 'a';
889         }
890       else if (*str == '%')
891         {
892           ptr[i++] = '%';
893           ptr[i++] = '2';
894           ptr[i++] = '5';
895         }
896       else if (extra && strchr (extra, *str))
897         {
898           ptr[i++] = '%';
899           ptr[i++] = tohex_lower ((*str>>4)&15);
900           ptr[i++] = tohex_lower (*str&15);
901         }
902       else
903         ptr[i++] = *str;
904       str++;
905     }
906   ptr[i] = '\0';
907
908   return ptr;
909 }
910
911 /* Percent-escape the string STR by replacing colons with '%3a'.  If
912    EXTRA is not NULL all characters in EXTRA are also escaped.  */
913 char *
914 percent_escape (const char *str, const char *extra)
915 {
916   return do_percent_escape (str, extra, 1);
917 }
918
919 /* Same as percent_escape but return NULL instead of exiting on memory
920    error. */
921 char *
922 try_percent_escape (const char *str, const char *extra)
923 {
924   return do_percent_escape (str, extra, 0);
925 }