Document --auto-issuer-key-retrieve.
[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     char *p;
241
242 #ifdef __riscos__
243     return riscos_make_basename(filepath, inputpath);
244 #endif
245
246     if ( !(p=strrchr(filepath, '/')) )
247 #ifdef HAVE_DRIVE_LETTERS
248         if ( !(p=strrchr(filepath, '\\')) )
249             if ( !(p=strrchr(filepath, ':')) )
250 #endif
251               {
252                 return jnlib_xstrdup(filepath);
253               }
254
255     return jnlib_xstrdup(p+1);
256 }
257
258
259
260 /***************
261  * Extract from a given filename the path prepended to it.
262  * If their isn't a path prepended to the filename, a dot
263  * is returned ('.').
264  *
265  */
266 char *
267 make_dirname(const char *filepath)
268 {
269     char *dirname;
270     int  dirname_length;
271     char *p;
272
273     if ( !(p=strrchr(filepath, '/')) )
274 #ifdef HAVE_DRIVE_LETTERS
275         if ( !(p=strrchr(filepath, '\\')) )
276             if ( !(p=strrchr(filepath, ':')) )
277 #endif
278               {
279                 return jnlib_xstrdup(".");
280               }
281
282     dirname_length = p-filepath;
283     dirname = jnlib_xmalloc(dirname_length+1);
284     strncpy(dirname, filepath, dirname_length);
285     dirname[dirname_length] = 0;
286
287     return dirname;
288 }
289
290
291
292 /****************
293  * Construct a filename from the NULL terminated list of parts.
294  * Tilde expansion is done here.
295  */
296 char *
297 make_filename( const char *first_part, ... )
298 {
299   va_list arg_ptr ;
300   size_t n;
301   const char *s;
302   char *name, *home, *p;
303   
304   va_start (arg_ptr, first_part);
305   n = strlen (first_part) + 1;
306   while ( (s = va_arg (arg_ptr, const char *)) )
307     n += strlen(s) + 1;
308   va_end(arg_ptr);
309   
310   home = NULL;
311   if ( *first_part == '~' && first_part[1] == '/'
312        && (home = getenv("HOME")) && *home )
313     n += strlen (home);
314   
315   name = jnlib_xmalloc (n);
316   p = (home 
317        ? stpcpy (stpcpy (name,home), first_part + 1)
318        : stpcpy(name, first_part));
319
320   va_start (arg_ptr, first_part) ;
321   while ( (s = va_arg(arg_ptr, const char *)) )
322     p = stpcpy (stpcpy (p,"/"), s);
323   va_end(arg_ptr);
324
325 #ifdef HAVE_DRIVE_LETTERS
326   /* We better avoid mixing slashes and backslashes and prefer
327      backslashes.  There is usual no problem with mixing them, however
328      a very few W32 API calls can't grok plain slashes.  Printing
329      filenames with mixed slashes also looks a bit strange. */
330   if (strchr (name, '\\'))
331     {
332       for (p=name; *p; p++)
333         if (*p == '/')
334           *p = '\\';
335     }
336 #endif /*HAVE_DRIVE_LETTERS*/
337   return name;
338 }
339
340
341 /* Compare whether the filenames are identical.  This is a
342    special version of strcmp() taking the semantics of filenames in
343    account.  Note that this function works only on the supplied names
344    without considereing any context like the current directory.  See
345    also same_file_p(). */
346 int
347 compare_filenames (const char *a, const char *b)
348 {
349 #ifdef HAVE_DRIVE_LETTERS
350   for ( ; *a && *b; a++, b++ ) 
351     {
352       if (*a != *b 
353           && (toupper (*(const unsigned char*)a)
354               != toupper (*(const unsigned char*)b) )
355           && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
356         break;
357     }
358   if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
359     return 0;
360   else
361     return (toupper (*(const unsigned char*)a) 
362             - toupper (*(const unsigned char*)b));
363 #else
364     return strcmp(a,b);
365 #endif
366 }
367
368
369 /* Convert 2 hex characters at S to a byte value.  Return this value
370    or -1 if there is an error. */
371 int
372 hextobyte (const char *s)
373 {
374   int c;
375
376   if ( *s >= '0' && *s <= '9' )
377     c = 16 * (*s - '0');
378   else if ( *s >= 'A' && *s <= 'F' )
379     c = 16 * (10 + *s - 'A');
380   else if ( *s >= 'a' && *s <= 'f' )
381     c = 16 * (10 + *s - 'a');
382   else
383     return -1;
384   s++;
385   if ( *s >= '0' && *s <= '9' )
386     c += *s - '0';
387   else if ( *s >= 'A' && *s <= 'F' )
388     c += 10 + *s - 'A';
389   else if ( *s >= 'a' && *s <= 'f' )
390     c += 10 + *s - 'a';
391   else
392     return -1;
393   return c;
394 }
395
396
397 /* Print a BUFFER to stream FP while replacing all control characters
398    and the characters DELIM and DELIM2 with standard C escape
399    sequences.  Returns the number of characters printed. */
400 size_t 
401 print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
402                          int delim, int delim2)
403 {
404   const unsigned char *p = buffer;
405   size_t count = 0;
406
407   for (; length; length--, p++, count++)
408     {
409       /* Fixme: Check whether *p < 0xa0 is correct for utf8 encoding. */
410       if (*p < 0x20 
411           || (*p >= 0x7f && *p < 0xa0)
412           || *p == delim 
413           || *p == delim2
414           || ((delim || delim2) && *p=='\\'))
415         {
416           putc ('\\', fp);
417           count++;
418           if (*p == '\n')
419             {
420               putc ('n', fp);
421               count++;
422             }
423           else if (*p == '\r')
424             {
425               putc ('r', fp);
426               count++;
427             }
428           else if (*p == '\f')
429             {
430               putc ('f', fp);
431               count++;
432             }
433           else if (*p == '\v')
434             {
435               putc ('v', fp);
436               count++;
437             }
438           else if (*p == '\b')
439             {
440               putc ('b', fp);
441               count++;
442             }
443           else if (!*p)
444             {
445               putc('0', fp);
446               count++;
447             }
448           else
449             {
450               fprintf (fp, "x%02x", *p);
451               count += 3;
452             }
453         }
454       else
455         {
456           putc (*p, fp);
457           count++;
458         }
459     }
460
461   return count;
462 }
463
464 /* Same as print_sanitized_buffer2 but with just one delimiter. */
465 size_t 
466 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
467                         int delim)
468 {
469   return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
470 }
471
472
473 size_t 
474 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
475                              size_t length, int delim)
476 {
477   const char *p = buffer;
478   size_t i;
479
480   /* We can handle plain ascii simpler, so check for it first. */
481   for (i=0; i < length; i++ ) 
482     {
483       if ( (p[i] & 0x80) )
484         break;
485     }
486   if (i < length)
487     {
488         char *buf = utf8_to_native (p, length, delim);
489         /*(utf8 conversion already does the control character quoting)*/
490         i = strlen (buf);
491         fputs (buf, fp);
492         jnlib_free (buf);
493         return i;
494     }
495   else
496     return print_sanitized_buffer (fp, p, length, delim);
497 }
498
499
500 size_t 
501 print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
502 {
503   return string? print_sanitized_buffer2 (fp, string, strlen (string),
504                                           delim, delim2):0;
505 }
506
507 size_t 
508 print_sanitized_string (FILE *fp, const char *string, int delim)
509 {
510   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
511 }
512
513 size_t 
514 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
515 {
516   return string? print_sanitized_utf8_buffer (fp,
517                                               string, strlen (string),
518                                               delim) : 0;
519 }
520
521 /* Create a string from the buffer P_ARG of length N which is suitable for
522    printing.  Caller must release the created string using xfree. */
523 char *
524 sanitize_buffer (const void *p_arg, size_t n, int delim)
525 {
526   const unsigned char *p = p_arg;
527   size_t save_n, buflen;
528   const unsigned char *save_p;
529   char *buffer, *d;
530
531   /* First count length. */
532   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
533     {
534       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
535         {
536           if ( *p=='\n' || *p=='\r' || *p=='\f'
537                || *p=='\v' || *p=='\b' || !*p )
538             buflen += 2;
539           else
540             buflen += 5;
541         }
542       else
543         buflen++;
544     }
545   p = save_p;
546   n = save_n;
547   /* And now make the string */
548   d = buffer = jnlib_xmalloc( buflen );
549   for ( ; n; n--, p++ )
550     {
551       if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
552         *d++ = '\\';
553         if( *p == '\n' )
554           *d++ = 'n';
555         else if( *p == '\r' )
556           *d++ = 'r';
557         else if( *p == '\f' )
558           *d++ = 'f';
559         else if( *p == '\v' )
560           *d++ = 'v';
561         else if( *p == '\b' )
562           *d++ = 'b';
563         else if( !*p )
564           *d++ = '0';
565         else {
566           sprintf(d, "x%02x", *p );
567           d += 3;
568         }
569       }
570       else
571         *d++ = *p;
572     }
573   *d = 0;
574   return buffer;
575 }
576
577
578 /* Given a string containing an UTF-8 encoded text, return the number
579    of characters in this string.  It differs from strlen in that it
580    only counts complete UTF-8 characters.  Note, that this function
581    does not take combined characters into account.  */
582 size_t
583 utf8_charcount (const char *s)
584 {
585   size_t n;
586
587   for (n=0; *s; s++)
588     if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
589       n++;
590
591   return n;
592 }
593
594
595 /****************************************************
596  **********  W32 specific functions  ****************
597  ****************************************************/
598
599 #ifdef HAVE_W32_SYSTEM
600 const char *
601 w32_strerror (int ec)
602 {
603   static char strerr[256];
604   
605   if (ec == -1)
606     ec = (int)GetLastError ();
607   FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
608                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
609                  strerr, DIM (strerr)-1, NULL);
610   return strerr;    
611 }
612 #endif /*HAVE_W32_SYSTEM*/
613
614
615 /****************************************************
616  ******** Locale insensitive ctype functions ********
617  ****************************************************/
618 /* FIXME: replace them by a table lookup and macros */
619 int
620 ascii_isupper (int c)
621 {
622     return c >= 'A' && c <= 'Z';
623 }
624
625 int
626 ascii_islower (int c)
627 {
628     return c >= 'a' && c <= 'z';
629 }
630
631 int 
632 ascii_toupper (int c)
633 {
634     if (c >= 'a' && c <= 'z')
635         c &= ~0x20;
636     return c;
637 }
638
639 int 
640 ascii_tolower (int c)
641 {
642     if (c >= 'A' && c <= 'Z')
643         c |= 0x20;
644     return c;
645 }
646
647
648 int
649 ascii_strcasecmp( const char *a, const char *b )
650 {
651     if (a == b)
652         return 0;
653
654     for (; *a && *b; a++, b++) {
655         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
656             break;
657     }
658     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
659 }
660
661 int 
662 ascii_strncasecmp (const char *a, const char *b, size_t n)
663 {
664   const unsigned char *p1 = (const unsigned char *)a;
665   const unsigned char *p2 = (const unsigned char *)b;
666   unsigned char c1, c2;
667
668   if (p1 == p2 || !n )
669     return 0;
670
671   do
672     {
673       c1 = ascii_tolower (*p1);
674       c2 = ascii_tolower (*p2);
675
676       if ( !--n || c1 == '\0')
677         break;
678
679       ++p1;
680       ++p2;
681     }
682   while (c1 == c2);
683   
684   return c1 - c2;
685 }
686
687
688 int
689 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
690 {
691   const char *a = a_arg;
692   const char *b = b_arg;
693
694   if (a == b)
695     return 0;
696   for ( ; n; n--, a++, b++ )
697     {
698       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
699         return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
700     }
701   return 0;
702 }
703
704 int
705 ascii_strcmp( const char *a, const char *b )
706 {
707     if (a == b)
708         return 0;
709
710     for (; *a && *b; a++, b++) {
711         if (*a != *b )
712             break;
713     }
714     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
715 }
716
717
718 void *
719 ascii_memcasemem (const void *haystack, size_t nhaystack,
720                   const void *needle, size_t nneedle)
721 {
722
723   if (!nneedle)
724     return (void*)haystack; /* finding an empty needle is really easy */
725   if (nneedle <= nhaystack)
726     {
727       const char *a = haystack;
728       const char *b = a + nhaystack - nneedle;
729       
730       for (; a <= b; a++)
731         {
732           if ( !ascii_memcasecmp (a, needle, nneedle) )
733             return (void *)a;
734         }
735     }
736   return NULL;
737 }
738
739 /*********************************************
740  ********** missing string functions *********
741  *********************************************/
742
743 #ifndef HAVE_STPCPY
744 char *
745 stpcpy(char *a,const char *b)
746 {
747     while( *b )
748         *a++ = *b++;
749     *a = 0;
750
751     return (char*)a;
752 }
753 #endif
754
755 #ifndef HAVE_STRSEP
756 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
757 char *
758 strsep (char **stringp, const char *delim)
759 {
760   char *begin, *end;
761
762   begin = *stringp;
763   if (begin == NULL)
764     return NULL;
765
766   /* A frequent case is when the delimiter string contains only one
767      character.  Here we don't need to call the expensive `strpbrk'
768      function and instead work using `strchr'.  */
769   if (delim[0] == '\0' || delim[1] == '\0')
770     {
771       char ch = delim[0];
772
773       if (ch == '\0')
774         end = NULL;
775       else
776         {
777           if (*begin == ch)
778             end = begin;
779           else if (*begin == '\0')
780             end = NULL;
781           else
782             end = strchr (begin + 1, ch);
783         }
784     }
785   else
786     /* Find the end of the token.  */
787     end = strpbrk (begin, delim);
788
789   if (end)
790     {
791       /* Terminate the token and set *STRINGP past NUL character.  */
792       *end++ = '\0';
793       *stringp = end;
794     }
795   else
796     /* No more delimiters; this is the last token.  */
797     *stringp = NULL;
798
799   return begin;
800 }
801 #endif /*HAVE_STRSEP*/
802
803
804 #ifndef HAVE_STRLWR
805 char *
806 strlwr(char *s)
807 {
808     char *p;
809     for(p=s; *p; p++ )
810         *p = tolower(*p);
811     return s;
812 }
813 #endif
814
815
816 #ifndef HAVE_STRCASECMP
817 int
818 strcasecmp( const char *a, const char *b )
819 {
820     for( ; *a && *b; a++, b++ ) {
821         if( *a != *b && toupper(*a) != toupper(*b) )
822             break;
823     }
824     return *(const byte*)a - *(const byte*)b;
825 }
826 #endif
827
828
829 /****************
830  * mingw32/cpd has a memicmp()
831  */
832 #ifndef HAVE_MEMICMP
833 int
834 memicmp( const char *a, const char *b, size_t n )
835 {
836     for( ; n; n--, a++, b++ )
837         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
838             return *(const byte *)a - *(const byte*)b;
839     return 0;
840 }
841 #endif
842
843
844 #ifndef HAVE_MEMRCHR
845 void *
846 memrchr (const void *buffer, int c, size_t n)
847 {
848   const unsigned char *p = buffer;
849
850   for (p += n; n ; n--)
851     if (*--p == c)
852       return (void *)p;
853   return NULL;
854 }
855 #endif /*HAVE_MEMRCHR*/
856
857 \f
858 /* Percent-escape the string STR by replacing colons with '%3a'.  If
859    EXTRA is not NULL all characters in EXTRA are also escaped.  */
860 static char *
861 do_percent_escape (const char *str, const char *extra, int die)
862 {
863   int i, j;
864   char *ptr;
865
866   if (!str)
867     return NULL;
868
869   for (i=j=0; str[i]; i++)
870     if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
871       j++;
872   if (die)
873     ptr = jnlib_xmalloc (i + 2 * j + 1);
874   else
875     {
876       ptr = jnlib_malloc (i + 2 * j + 1);
877       if (!ptr)
878         return NULL;
879     }
880   i = 0;
881   while (*str)
882     {
883       if (*str == ':')
884         {
885           ptr[i++] = '%';
886           ptr[i++] = '3';
887           ptr[i++] = 'a';
888         }
889       else if (*str == '%')
890         {
891           ptr[i++] = '%';
892           ptr[i++] = '2';
893           ptr[i++] = '5';
894         }
895       else if (extra && strchr (extra, *str))
896         {
897           ptr[i++] = '%';
898           ptr[i++] = tohex_lower ((*str>>4)&15);
899           ptr[i++] = tohex_lower (*str&15);
900         }
901       else
902         ptr[i++] = *str;
903       str++;
904     }
905   ptr[i] = '\0';
906
907   return ptr;
908 }
909
910 /* Percent-escape the string STR by replacing colons with '%3a'.  If
911    EXTRA is not NULL all characters in EXTRA are also escaped.  */
912 char *
913 percent_escape (const char *str, const char *extra)
914 {
915   return do_percent_escape (str, extra, 1);
916 }
917
918 /* Same as percent_escape but return NULL instead of exiting on memory
919    error. */
920 char *
921 try_percent_escape (const char *str, const char *extra)
922 {
923   return do_percent_escape (str, extra, 0);
924 }