* sexp.c (gcry_sexp_canon_len): Describe the error codes and
[libgcrypt.git] / src / sexp.c
1 /* sexp.c  -  S-Expression handling
2  *      Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt 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  * Libgcrypt 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
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #include <assert.h>
29
30 #define GCRYPT_NO_MPI_MACROS 1
31 #include "g10lib.h"
32 #include "memory.h"
33
34 typedef struct gcry_sexp *NODE;
35 typedef unsigned short DATALEN;
36
37 struct gcry_sexp {
38     byte d[1];
39 };
40
41 #define ST_STOP  0
42 #define ST_DATA  1  /* datalen follows */
43 #define ST_HINT  2  /* datalen follows */
44 #define ST_OPEN  3
45 #define ST_CLOSE 4
46
47 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
48 #define hexdigitp(a) (digitp (a)                     \
49                       || (*(a) >= 'A' && *(a) <= 'F')  \
50                       || (*(a) >= 'a' && *(a) <= 'f'))
51 /* the atoi macros assume that the buffer has only valid digits */
52 #define atoi_1(p)   (*(p) - '0' )
53
54
55 #if 0
56 static void
57 dump_mpi( GCRY_MPI a )
58 {
59     char buffer[1000];
60     size_t n = 1000;
61
62     if( !a )
63         fputs("[no MPI]", stderr );
64     else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
65         fputs("[MPI too large to print]", stderr );
66     else
67         fputs( buffer, stderr );
68 }
69 #endif
70
71 static void
72 dump_string (const byte *p, size_t n, int delim )
73 {
74   for (; n; n--, p++ )
75     {
76       if ((*p & 0x80) || iscntrl( *p ) || *p == delim ) 
77         {
78           if( *p == '\n' )
79             log_printf ("\\n");
80           else if( *p == '\r' )
81             log_printf ("\\r");
82           else if( *p == '\f' )
83             log_printf ("\\f");
84           else if( *p == '\v' )
85             log_printf ("\\v");
86             else if( *p == '\b' )
87               log_printf ("\\b");
88           else if( !*p )       
89             log_printf ("\\0");
90           else
91             log_printf ("\\x%02x", *p );
92         }
93       else
94         log_printf ("%c", *p);
95     }
96 }
97
98
99 void
100 gcry_sexp_dump (const GCRY_SEXP a)
101 {
102   const byte *p;
103   int indent = 0;
104   int type;
105
106   if (!a)
107     {
108       log_printf ( "[nil]\n");
109       return;
110     }
111
112   p = a->d;
113   while ( (type = *p) != ST_STOP )
114     {
115       p++;
116       switch ( type )
117         {
118         case ST_OPEN:
119           log_printf ("%*s[open]\n", 2*indent, "");
120           indent++;
121           break;
122         case ST_CLOSE:
123           if( indent )
124             indent--;
125           log_printf ("%*s[close]\n", 2*indent, "");
126           break;
127         case ST_DATA: {
128           DATALEN n;
129           memcpy ( &n, p, sizeof n );
130           p += sizeof n;
131           log_printf ("%*s[data=\"", 2*indent, "" );
132           dump_string (p, n, '\"' );
133           log_printf ("\"]\n");
134           p += n;
135         }
136         break;
137         default:
138           log_printf ("%*s[unknown tag %d]\n", 2*indent, "", type);
139           break;
140         }
141     }
142 }
143
144 /****************
145  * Pass list through except when it is an empty list - in that case
146  * return NULL and release the passed list.
147  */
148 static GCRY_SEXP
149 normalize ( GCRY_SEXP list )
150 {
151     char *p;
152     if ( !list )
153         return NULL;
154     p = list->d;
155     if ( *p == ST_STOP ) {
156         /* this is "" */
157         gcry_sexp_release ( list );
158         return NULL;
159     }
160     if( *p == ST_OPEN && p[1] == ST_CLOSE ) {
161         /* this is "()" */
162         gcry_sexp_release ( list );
163         return NULL;
164     }
165
166     return list;
167 }
168
169 /****************
170  * Release resource of the given SEXP object.
171  */
172 void
173 gcry_sexp_release( GCRY_SEXP sexp )
174 {
175     gcry_free ( sexp );
176 }
177
178
179 /****************
180  * Make a pair from lists a and b, don't use a or b later on.
181  * Special behaviour:  If one is a single element list we put the
182  * element straight into the new pair.
183  */
184 GCRY_SEXP
185 gcry_sexp_cons( const GCRY_SEXP a, const GCRY_SEXP b )
186 {
187     /* NYI: Implementation should be quite easy with our new data representation */
188     BUG ();
189     return NULL;
190 }
191
192
193 /****************
194  * Make a list from all items in the array the end of the array is marked
195  * with a NULL.                                                                       y a NULL
196  */
197 GCRY_SEXP
198 gcry_sexp_alist( const GCRY_SEXP *array )
199 {
200     /* NYI: Implementaion should be quite easy with our new data representation */
201     BUG ();
202     return NULL;
203 }
204
205 /****************
206  * Make a list from all items, the end of list is indicated by a NULL
207  */
208 GCRY_SEXP
209 gcry_sexp_vlist( const GCRY_SEXP a, ... )
210 {
211     /* NYI: Implementaion should be quite easy with our new data representation */
212     BUG ();
213     return NULL;
214 }
215
216
217 /****************
218  * Append n to the list a
219  * Returns: a new ist (which maybe a)
220  */
221 GCRY_SEXP
222 gcry_sexp_append( const GCRY_SEXP a, const GCRY_SEXP n )
223 {
224     /* NYI: Implementaion should be quite easy with our new data representation */
225     BUG ();
226     return NULL;
227 }
228
229 GCRY_SEXP
230 gcry_sexp_prepend( const GCRY_SEXP a, const GCRY_SEXP n )
231 {
232     /* NYI: Implementaion should be quite easy with our new data representation */
233     BUG ();
234     return NULL;
235 }
236
237
238
239 /****************
240  * Locate token in a list. The token must be the car of a sublist.
241  * Returns: A new list with this sublist or NULL if not found.
242  */
243 GCRY_SEXP
244 gcry_sexp_find_token( const GCRY_SEXP list, const char *tok, size_t toklen )
245 {
246     const byte *p;
247     DATALEN n;
248
249     if ( !list )
250         return NULL;
251
252     if( !toklen )
253         toklen = strlen(tok);
254     p = list->d;
255     while ( *p != ST_STOP ) {
256         if ( *p == ST_OPEN && p[1] == ST_DATA ) {
257             const byte *head = p;
258
259             p += 2;
260             memcpy ( &n, p, sizeof n ); p += sizeof n;
261             if ( n == toklen && !memcmp( p, tok, toklen ) ) { /* found it */
262                 GCRY_SEXP newlist;
263                 byte *d;
264                 int level = 1;
265
266                 /* look for the end of the list */
267                 for ( p += n; level; p++ ) {
268                     if ( *p == ST_DATA ) {
269                         memcpy ( &n, ++p, sizeof n );
270                         p += sizeof n + n;
271                         p--; /* compensate for later increment */
272                     }
273                     else if ( *p == ST_OPEN ) {
274                         level++;
275                     }
276                     else if ( *p == ST_CLOSE ) {
277                         level--;
278                     }
279                     else if ( *p == ST_STOP ) {
280                         BUG ();
281                     }
282                 } while ( level );
283                 n = p - head;
284
285                 newlist = gcry_xmalloc ( sizeof *newlist + n );
286                 d = newlist->d;
287                 memcpy ( d, head, n ); d += n;
288                 *d++ = ST_STOP;
289                 return normalize ( newlist );
290             }
291             p += n;
292         }
293         else if ( *p == ST_DATA ) {
294             memcpy ( &n, ++p, sizeof n ); p += sizeof n;
295             p += n;
296         }
297         else
298             p++;
299     }
300     return NULL;
301 }
302
303 /****************
304  * return the length of the given list
305  */
306 int
307 gcry_sexp_length( const GCRY_SEXP list )
308 {
309     const byte *p;
310     DATALEN n;
311     int type;
312     int length = 0;
313     int level = 0;
314
315     if ( !list )
316         return 0;
317
318     p = list->d;
319     while ( (type=*p) != ST_STOP ) {
320         p++;
321         if ( type == ST_DATA ) {
322             memcpy ( &n, ++p, sizeof n );
323             p += sizeof n + n;
324             p--;
325             if ( !level )
326                 length++;
327         }
328         else if ( type == ST_OPEN ) {
329             if ( !level )
330                 length++;
331             level++;
332         }
333         else if ( type == ST_CLOSE ) {
334             level--;
335         }
336     }
337     return length;
338 }
339
340
341
342 /****************
343  * Extract the CAR of the given list
344  */
345 GCRY_SEXP
346 gcry_sexp_nth( const GCRY_SEXP list, int number )
347 {
348     const byte *p;
349     DATALEN n;
350     GCRY_SEXP newlist;
351     byte *d;
352     int level = 0;
353
354     if ( !list || list->d[0] != ST_OPEN )
355         return NULL;
356     p = list->d;
357
358     while ( number > 0 ) {
359         p++;
360         if ( *p == ST_DATA ) {
361             memcpy ( &n, ++p, sizeof n );
362             p += sizeof n + n;
363             p--;
364             if ( !level )
365                 number--;
366         }
367         else if ( *p == ST_OPEN ) {
368             level++;
369         }
370         else if ( *p == ST_CLOSE ) {
371             level--;
372             if ( !level )
373                 number--;
374         }
375         else if ( *p == ST_STOP ) {
376             return NULL;
377         }
378     }
379     p++;
380
381     if ( *p == ST_DATA ) {
382         memcpy ( &n, p, sizeof n ); p += sizeof n;
383         newlist = gcry_xmalloc ( sizeof *newlist + n + 1 );
384         d = newlist->d;
385         memcpy ( d, p, n ); d += n;
386         *d++ = ST_STOP;
387     }
388     else if ( *p == ST_OPEN ) {
389         const byte *head = p;
390
391         level = 1;
392         do {
393             p++;
394             if ( *p == ST_DATA ) {
395                 memcpy ( &n, ++p, sizeof n );
396                 p += sizeof n + n;
397                 p--;
398             }
399             else if ( *p == ST_OPEN ) {
400                 level++;
401             }
402             else if ( *p == ST_CLOSE ) {
403                 level--;
404             }
405             else if ( *p == ST_STOP ) {
406                 BUG ();
407             }
408         } while ( level );
409         n = p + 1 - head;
410
411         newlist = gcry_xmalloc ( sizeof *newlist + n );
412         d = newlist->d;
413         memcpy ( d, head, n ); d += n;
414         *d++ = ST_STOP;
415     }
416     else
417         newlist = NULL;
418
419     return normalize (newlist);
420 }
421
422 GCRY_SEXP
423 gcry_sexp_car( const GCRY_SEXP list )
424 {
425     return gcry_sexp_nth ( list, 0 );
426 }
427
428 /****************
429  * Get data from the car.  The returned value is valid as long as the list
430  * is not modified.
431  */
432 const char *
433 gcry_sexp_nth_data( const GCRY_SEXP list, int number, size_t *datalen )
434 {
435     const byte *p;
436     DATALEN n;
437     int level = 0;
438
439     *datalen = 0;
440     if ( !list ) {
441         return NULL;
442     }
443     p = list->d;
444     if ( *p == ST_OPEN )
445         p++;         /* yep, a list */
446     else if (number )
447         return NULL; /* not a list but an n > 0 element requested */
448
449     /* skip n elements */
450     while ( number > 0 ) {
451         if ( *p == ST_DATA ) {
452             memcpy ( &n, ++p, sizeof n );
453             p += sizeof n + n;
454             p--;
455             if ( !level )
456                 number--;
457         }
458         else if ( *p == ST_OPEN ) {
459             level++;
460         }
461         else if ( *p == ST_CLOSE ) {
462             level--;
463             if ( !level )
464                 number--;
465         }
466         else if ( *p == ST_STOP ) {
467             return NULL;
468         }
469         p++;
470     }
471
472
473     if ( *p == ST_DATA ) {
474         memcpy ( &n, ++p, sizeof n );
475         *datalen = n;
476         return p + sizeof n;
477     }
478
479     return NULL;
480 }
481
482 /****************
483  * Get a MPI from the car
484  */
485 GCRY_MPI
486 gcry_sexp_nth_mpi( GCRY_SEXP list, int number, int mpifmt )
487 {
488     const byte *p;
489     DATALEN n;
490     int level = 0;
491
492     if ( !list )
493         return NULL;
494     if ( !mpifmt )
495         mpifmt = GCRYMPI_FMT_STD;
496
497     p = list->d;
498     if ( *p == ST_OPEN )
499         p++;         /* yep, a list */
500     else if (number )
501         return NULL; /* not a list but an n > 0 element requested */
502
503     /* skip n elements */
504     while ( number > 0 ) {
505         if ( *p == ST_DATA ) {
506             memcpy ( &n, ++p, sizeof n );
507             p += sizeof n + n;
508             p--;
509             if ( !level )
510                 number--;
511         }
512         else if ( *p == ST_OPEN ) {
513             level++;
514         }
515         else if ( *p == ST_CLOSE ) {
516             level--;
517             if ( !level )
518                 number--;
519         }
520         else if ( *p == ST_STOP ) {
521             return NULL;
522         }
523         p++;
524     }
525
526     if ( *p == ST_DATA ) {
527         MPI a;
528         size_t nbytes;
529
530         memcpy ( &n, ++p, sizeof n );
531         p += sizeof n;
532         nbytes = n;
533         if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
534             return a;
535     }
536
537     return NULL;
538 }
539
540
541 /****************
542  * Get the CDR
543  */
544 GCRY_SEXP
545 gcry_sexp_cdr( const GCRY_SEXP list )
546 {
547     const byte *p;
548     const byte *head;
549     DATALEN n;
550     GCRY_SEXP newlist;
551     byte *d;
552     int level = 0;
553     int skip = 1;
554
555     if ( !list || list->d[0] != ST_OPEN )
556         return NULL;
557     p = list->d;
558
559     while ( skip > 0 ) {
560         p++;
561         if ( *p == ST_DATA ) {
562             memcpy ( &n, ++p, sizeof n );
563             p += sizeof n + n;
564             p--;
565             if ( !level )
566                 skip--;
567         }
568         else if ( *p == ST_OPEN ) {
569             level++;
570         }
571         else if ( *p == ST_CLOSE ) {
572             level--;
573             if ( !level )
574                 skip--;
575         }
576         else if ( *p == ST_STOP ) {
577             return NULL;
578         }
579     }
580     p++;
581
582     head = p;
583     level = 0;
584     do {
585         if ( *p == ST_DATA ) {
586             memcpy ( &n, ++p, sizeof n );
587             p += sizeof n + n;
588             p--;
589         }
590         else if ( *p == ST_OPEN ) {
591             level++;
592         }
593         else if ( *p == ST_CLOSE ) {
594             level--;
595         }
596         else if ( *p == ST_STOP ) {
597             return NULL;
598         }
599         p++;
600     } while ( level );
601     n = p - head;
602
603     newlist = gcry_xmalloc ( sizeof *newlist + n + 2 );
604     d = newlist->d;
605     *d++ = ST_OPEN;
606     memcpy ( d, head, n ); d += n;
607     *d++ = ST_CLOSE;
608     *d++ = ST_STOP;
609
610     return normalize (newlist);
611 }
612
613 GCRY_SEXP
614 gcry_sexp_cadr ( const GCRY_SEXP list )
615 {
616     GCRY_SEXP a, b;
617
618     a = gcry_sexp_cdr ( list );
619     b = gcry_sexp_car ( a );
620     gcry_sexp_release ( a );
621     return b;
622 }
623
624
625
626 static int
627 hextobyte( const byte *s )
628 {
629     int c=0;
630
631     if( *s >= '0' && *s <= '9' )
632         c = 16 * (*s - '0');
633     else if( *s >= 'A' && *s <= 'F' )
634         c = 16 * (10 + *s - 'A');
635     else if( *s >= 'a' && *s <= 'f' ) {
636         c = 16 * (10 + *s - 'a');
637     }
638     s++;
639     if( *s >= '0' && *s <= '9' )
640         c += *s - '0';
641     else if( *s >= 'A' && *s <= 'F' )
642         c += 10 + *s - 'A';
643     else if( *s >= 'a' && *s <= 'f' ) {
644         c += 10 + *s - 'a';
645     }
646     return c;
647 }
648
649 struct make_space_ctx {
650     GCRY_SEXP sexp;
651     size_t allocated;
652     byte *pos;
653 };
654
655 static void
656 make_space ( struct make_space_ctx *c, size_t n )
657 {
658     size_t used = c->pos - c->sexp->d;
659
660     if ( used + n + sizeof(DATALEN) + 1 >= c->allocated ) {
661         GCRY_SEXP newsexp;
662         byte *newhead;
663
664         c->allocated += 2*(n+sizeof(DATALEN)+1);
665         newsexp = gcry_xrealloc ( c->sexp, sizeof *newsexp + c->allocated - 1 );
666         newhead = newsexp->d;
667         c->pos = newhead + used;
668         c->sexp = newsexp;
669     }
670 }
671
672
673 /****************
674  * Scan the provided buffer and return the S expression in our internal
675  * format.  Returns a newly allocated expression.  If erroff is not NULL and
676  * a parsing error has occured, the offset into buffer will be returned.
677  * If ARGFLAG is true, the function supports some printf like
678  * expressions.
679  *  These are:
680  *      %m - MPI
681  *      %s - string (no autoswitch to secure allocation)
682  *      %d - integer stored as string (no autoswitch to secure allocation)
683  *  all other format elements are currently not defined and return an error.
684  *  this includes the "%%" sequence becauce the percent sign is not an
685  *  allowed character.
686  * FIXME: We should find a way to store the secure-MPIS not in the string
687  * but as reference to somewhere - this can help us to save huge amounts
688  * of secure memory.  The problem is, that if only one element is secure, all
689  * other elements are automagicaly copied to secure meory too, so the most
690  * common operation gcry_sexp_cdr_mpi() will always return a secure MPI
691  * regardless whether it is needed or not.
692  */
693 static int
694 sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff ,
695             const char *buffer, size_t length, va_list arg_ptr, int argflag )
696 {
697     static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz"
698                                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
699                                      "0123456789-./_:*+=";
700     const char *p;
701     size_t n;
702     const char *digptr=NULL;
703     const char *quoted=NULL;
704     const char *tokenp=NULL;
705     const char *hexfmt=NULL;
706     const char *base64=NULL;
707     const char *disphint=NULL;
708     const char *percent=NULL;
709     int hexcount=0;
710     int quoted_esc=0;
711     int datalen=0;
712     size_t dummy_erroff;
713
714     struct make_space_ctx c;
715
716     if( !erroff )
717         erroff = &dummy_erroff;
718
719     /* FIXME: replace all the returns by a jump to the leave label
720      * and invent better error codes. Make sure that everything is cleaned up*/
721   #define MAKE_SPACE(n)  do { make_space ( &c, (n) ); } while (0)
722   #define STORE_LEN(p,n) do {                                              \
723                             DATALEN ashort = (n);                          \
724                             memcpy ( (p), &ashort, sizeof(ashort) );       \
725                             (p) += sizeof (ashort);                        \
726                         } while (0)
727
728     /* We assume that the internal representation takes less memory
729      * than the provided one.  However, we add space for one extra datalen
730      * so that the code which does the ST_CLOSE can use MAKE_SPACE */
731     c.allocated = length + sizeof(DATALEN);
732     c.sexp = gcry_xmalloc ( sizeof *c.sexp + c.allocated - 1 );
733     c.pos = c.sexp->d;
734
735     for(p=buffer,n=length; n; p++, n-- ) {
736         if( tokenp && !hexfmt ) {
737             if( strchr( tokenchars, *p ) )
738                 continue;
739             datalen = p - tokenp;
740             MAKE_SPACE ( datalen );
741             *c.pos++ = ST_DATA;
742             STORE_LEN ( c.pos, datalen );
743             memcpy ( c.pos, tokenp, datalen );
744             c.pos += datalen;
745             tokenp = NULL;
746         }
747         if( quoted ) {
748             if( quoted_esc ) {
749                 switch( *p ) {
750                   case 'b': case 't': case 'v': case 'n': case 'f':
751                   case 'r': case '"': case '\'': case '\\':
752                     quoted_esc = 0;
753                     break;
754                   case '0': case '1': case '2': case '3': case '4':
755                   case '5': case '6': case '7':
756                     if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
757                                 && p[2] >= '0' && p[2] <= '7') ) {
758                         *erroff = p - buffer;
759                         return -6;   /* invalid octal value */
760                     }
761                     p += 2; n -= 2;
762                     quoted_esc = 0;
763                     break;
764                   case 'x':
765                     if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
766                         *erroff = p - buffer;
767                         return -6;   /* invalid hex value */
768                     }
769                     p += 2; n -= 2;
770                     quoted_esc = 0;
771                     break;
772                   case '\r':  /* ignore CR[,LF] */
773                     if( n && p[1] == '\n' ) {
774                         p++; n--;
775                     }
776                     quoted_esc = 0;
777                     break;
778                   case '\n':  /* ignore LF[,CR] */
779                     if( n && p[1] == '\r' ) {
780                         p++; n--;
781                     }
782                     quoted_esc = 0;
783                     break;
784                   default:
785                     *erroff = p - buffer;
786                     return -6;   /* invalid quoted string escape */
787                 }
788             }
789             else if( *p == '\\' )
790                 quoted_esc = 1;
791             else if( *p == '\"' ) {
792                 /* fixme: add item */
793                 quoted = NULL;
794             }
795         }
796         else if( hexfmt ) {
797             if( isxdigit( *p ) )
798                 hexcount++;
799             else if( *p == '#' ) {
800                 if( (hexcount & 1) ) {
801                     *erroff = p - buffer;
802                     return -12;  /* odd number of hex digits */
803                 }
804
805                 datalen = hexcount/2;
806                 MAKE_SPACE (datalen);
807                 *c.pos++ = ST_DATA;
808                 STORE_LEN (c.pos, datalen);
809                 for( hexfmt++; hexfmt < p; hexfmt++ ) {
810                     if( isspace( *hexfmt ) )
811                         continue;
812                     *c.pos++ = hextobyte( hexfmt );
813                     hexfmt++;
814                 }
815                 hexfmt = NULL;
816             }
817             else if( !isspace( *p ) ) {
818                 *erroff = p - buffer;
819                 return -11;  /* invalid hex character */
820             }
821         }
822         else if( base64 ) {
823             if( *p == '|' )
824                base64 = NULL;
825         }
826         else if( digptr ) {
827             if( isdigit(*p) )
828                 ;
829             else if( *p == ':' ) {
830                 datalen = atoi( digptr ); /* fixme: check for overflow */
831                 digptr = NULL;
832                 if( datalen > n-1 ) {
833                     *erroff = p - buffer;
834                     return -2; /* buffer too short */
835                 }
836                 /* make a new list entry */
837                 MAKE_SPACE (datalen);
838                 *c.pos++ = ST_DATA;
839                 STORE_LEN (c.pos, datalen);
840                 memcpy (c.pos, p+1, datalen );
841                 c.pos += datalen;
842                 n -= datalen;
843                 p += datalen;
844             }
845             else if( *p == '\"' ) {
846                 digptr = NULL; /* we ignore the optional length */
847                 quoted = p;
848                 quoted_esc = 0;
849             }
850             else if( *p == '#' ) {
851                 digptr = NULL; /* we ignore the optional length */
852                 hexfmt = p;
853                 hexcount = 0;
854             }
855             else if( *p == '|' ) {
856                 digptr = NULL; /* we ignore the optional length */
857                 base64 = p;
858             }
859             else {
860                 *erroff = p - buffer;
861                 return -1;
862             }
863         }
864         else if ( percent ) {
865             if ( *p == 'm' ) { /* insert an MPI */
866                 GCRY_MPI m = va_arg (arg_ptr, GCRY_MPI);
867                 size_t nm;
868
869                 if ( gcry_mpi_print( GCRYMPI_FMT_STD, NULL, &nm, m ) )
870                     BUG ();
871
872                 MAKE_SPACE (nm);
873                 if ( !gcry_is_secure ( c.sexp->d )
874                      &&  gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE ) ) {
875                     /* we have to switch to secure allocation */
876                     GCRY_SEXP newsexp;
877                     byte *newhead;
878
879                     newsexp = gcry_xmalloc_secure ( sizeof *newsexp
880                                                    + c.allocated - 1 );
881                     newhead = newsexp->d;
882                     memcpy ( newhead, c.sexp->d, (c.pos - c.sexp->d) );
883                     c.pos = newhead + ( c.pos - c.sexp->d );
884                     gcry_free ( c.sexp );
885                     c.sexp = newsexp;
886                 }
887
888                 *c.pos++ = ST_DATA;
889                 STORE_LEN (c.pos, nm);
890                 if ( gcry_mpi_print( GCRYMPI_FMT_STD, c.pos, &nm, m ) )
891                     BUG ();
892                 c.pos += nm;
893             }
894             else if ( *p == 's' ) { /* insert an string */
895                 const char *astr = va_arg (arg_ptr, const char *);
896                 size_t alen = strlen ( astr );
897
898                 MAKE_SPACE (alen);
899                 *c.pos++ = ST_DATA;
900                 STORE_LEN (c.pos, alen);
901                 memcpy ( c.pos, astr, alen );
902                 c.pos += alen;
903             }
904             else if ( *p == 'd' ) { /* insert an integer as string */
905                 int aint = va_arg (arg_ptr, int);
906                 size_t alen;
907                 char buf[20];
908
909                 sprintf ( buf, "%d", aint );
910                 alen = strlen ( buf );
911                 MAKE_SPACE (alen);
912                 *c.pos++ = ST_DATA;
913                 STORE_LEN (c.pos, alen);
914                 memcpy ( c.pos, buf, alen );
915                 c.pos += alen;
916             }
917             else {
918                 *erroff = p - buffer;
919                 return -1;  /* invalid format specifier */
920             }
921             percent = NULL;
922         }
923         else if( *p == '(' ) {
924             if( disphint ) {
925                 *erroff = p - buffer;
926                 return -9; /* open display hint */
927             }
928             MAKE_SPACE (0);
929             *c.pos++ = ST_OPEN;
930         }
931         else if( *p == ')' ) { /* walk up */
932             if( disphint ) {
933                 *erroff = p - buffer;
934                 return -9; /* open display hint */
935             }
936             MAKE_SPACE (0);
937             *c.pos++ = ST_CLOSE;
938         }
939         else if( *p == '\"' ) {
940             quoted = p;
941             quoted_esc = 0;
942         }
943         else if( *p == '#' ) {
944             hexfmt = p;
945             hexcount = 0;
946         }
947         else if( *p == '|' )
948             base64 = p;
949         else if( *p == '[' ) {
950             if( disphint ) {
951                 *erroff = p - buffer;
952                 return -8; /* nested display hints */
953             }
954             disphint = p;
955         }
956         else if( *p == ']' ) {
957             if( !disphint ) {
958                 *erroff = p - buffer;
959                 return -9; /* unmatched display hint close */
960             }
961             disphint = NULL;
962         }
963         else if( isdigit(*p) ) {
964             if( *p == '0' ) { /* a length may not begin with zero */
965                 *erroff = p - buffer;
966                 return -7;
967             }
968             digptr = p;
969         }
970         else if( strchr( tokenchars, *p ) )
971             tokenp = p;
972         else if( isspace(*p) )
973             ;
974         else if( *p == '{' ) {
975             /* fixme: handle rescanning:
976              * we can do this by saving our current state
977              * and start over at p+1 -- Hmmm. At this point here
978              * we are in a well defined state, so we don't need to save
979              * it.  Great.
980              */
981             *erroff = p - buffer;
982             return -10; /* unexpected reserved punctuation */
983         }
984         else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
985             *erroff = p - buffer;
986             return -10; /* unexpected reserved punctuation */
987         }
988         else if( argflag && *p == '%' ) {
989             percent = p;
990         }
991         else { /* bad or unavailable*/
992             *erroff = p - buffer;
993             return -5;
994         }
995
996     }
997     MAKE_SPACE (0);
998     *c.pos++ = ST_STOP;
999
1000     *retsexp = normalize ( c.sexp );
1001     return 0;
1002   #undef MAKE_SPACE
1003   #undef STORE_LEN
1004 }
1005
1006 int
1007 gcry_sexp_build( GCRY_SEXP *retsexp, size_t *erroff, const char *format, ... )
1008 {
1009     int rc;
1010     va_list arg_ptr ;
1011
1012     va_start( arg_ptr, format ) ;
1013     rc = sexp_sscan( retsexp, erroff, format, strlen(format), arg_ptr, 1 );
1014     va_end(arg_ptr);
1015
1016     return rc;
1017 }
1018
1019 int
1020 gcry_sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff,
1021                             const char *buffer, size_t length )
1022 {
1023     va_list dummy_arg_ptr = 0;
1024
1025     return sexp_sscan( retsexp, erroff, buffer, length, dummy_arg_ptr, 0 );
1026 }
1027
1028 /****************
1029  * Print SEXP to buffer using the MODE.  Returns the length of the
1030  * SEXP in buffer or 0 if the buffer is too short (We have at least an
1031  * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
1032  * the required length is returned.
1033  */
1034 size_t
1035 gcry_sexp_sprint( const GCRY_SEXP list, int mode,
1036                                         char *buffer, size_t maxlength )
1037 {
1038     static byte empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
1039     const byte *s;
1040     char *d;
1041     DATALEN n;
1042     char numbuf[20];
1043     size_t len = 0;
1044
1045     s = list? list->d : empty;
1046     d = buffer;
1047     while ( *s != ST_STOP ) {
1048         switch ( *s ) {
1049           case ST_OPEN:
1050             s++;
1051             len++;
1052             if ( buffer ) {
1053                 if ( len >= maxlength )
1054                     return 0;
1055                 *d++ = '(';
1056             }
1057             break;
1058           case ST_CLOSE:
1059             s++;
1060             len++;
1061             if ( mode != GCRYSEXP_FMT_CANON )
1062                 len++;
1063             if ( buffer ) {
1064                 if ( len >= maxlength )
1065                     return 0;
1066                 *d++ = ')';
1067                 if ( mode != GCRYSEXP_FMT_CANON )
1068                     *d++ = '\n';
1069             }
1070             break;
1071           case ST_DATA:
1072             s++;
1073             memcpy ( &n, s, sizeof n ); s += sizeof n;
1074             sprintf (numbuf, "%u:", (unsigned int)n );
1075             len += strlen (numbuf) + n;
1076             if ( buffer ) {
1077                 if ( len >= maxlength )
1078                     return 0;
1079                 d = stpcpy ( d, numbuf );
1080                 memcpy ( d, s, n ); d += n;
1081             }
1082             s += n;
1083             break;
1084           default:
1085             BUG ();
1086         }
1087     }
1088     if (buffer) {
1089         if ( len >= maxlength )
1090             return 0;
1091         *d++ = 0; /* for convenience we make a C string */
1092     }
1093     else
1094         len++; /* we need one byte more for this */
1095
1096     return len;
1097 }
1098
1099
1100
1101
1102 /* Scan a cannocial encoded buffer with implicit length values and
1103    return the actual length this S-expression uses.  For a valid S-Exp
1104    it should never return 0.  If LENGTH is not zero, the maximum
1105    length to scan is given - this can be used for syntax checks of
1106    data passed from outside. erroce and erroff may both be passed as
1107    NULL
1108
1109    Errorcodes (for historic reasons they are all negative):
1110     -1 := invalid length specification
1111     -2 := string too long 
1112     -3 := unmatched parenthesis
1113     -4 := not a (canonical) S-expression
1114     -5 := bad character 
1115     -6 := invalid hex octal value or bad quotation
1116     -7 := a length may not begin with zero 
1117     -8 := nested display hints 
1118     -9 := unmatched display hint close
1119    -10 := unexpected reserved punctuation 
1120  */
1121 size_t
1122 gcry_sexp_canon_len (const unsigned char *buffer, size_t length, 
1123                      size_t *erroff, int *errcode)
1124 {
1125   const unsigned char *p;
1126   const char *disphint=NULL;
1127   unsigned int datalen = 0;
1128   size_t dummy_erroff;
1129   int    dummy_errcode;
1130   size_t count = 0;
1131   int level = 0;
1132
1133   if (!erroff)
1134     erroff = &dummy_erroff;
1135   if (!errcode)
1136     errcode = &dummy_errcode;
1137
1138   *errcode = 0;
1139   *erroff = 0;
1140   if (!buffer)
1141     return 0;
1142   if (*buffer != '(')
1143     return -4; /* not a canonical S-expression */
1144
1145   for (p=buffer; ; p++, count++ )
1146     {
1147       if (length && count >= length)
1148         {
1149           *erroff = count;
1150           *errcode = -2; /* string too long */
1151           return 0;
1152         }
1153       
1154       if (datalen)
1155         {
1156           if (*p == ':')
1157             {
1158               if (length && (count+datalen) >= length)
1159                 {
1160                   *erroff = count;
1161                   *errcode = -2; /* string too long */
1162                   return 0;
1163                 }
1164               count += datalen;
1165               p += datalen;
1166               datalen = 0;
1167             }
1168           else if (digitp(p))
1169             datalen = datalen*10 + atoi_1(p);
1170           else 
1171             {
1172               *erroff = count;
1173               *errcode = -1;
1174               return 0;
1175             }
1176         }
1177       else if (*p == '(')
1178         {
1179           if (disphint)
1180             {
1181               *erroff = count;
1182               *errcode = -9; /* open display hint */
1183               return 0;
1184             }
1185           level++;
1186         }
1187       else if (*p == ')')
1188         { /* walk up */
1189           if (!level)
1190             {
1191               *erroff = count;
1192               *errcode = -3; /* unmatched parenthesis */
1193               return 0;
1194             }
1195           if (disphint)
1196             {
1197               *erroff = count;
1198               *errcode = -9; /* open display hint */
1199               return 0;
1200             }
1201           if (!--level)
1202             return ++count; /* ready */
1203         }
1204       else if (*p == '[')
1205         {
1206           if (disphint) 
1207             {
1208               *erroff = count;
1209               *errcode = -8; /* nested display hints */
1210               return 0;
1211             }
1212           disphint = p;
1213         }
1214       else if (*p == ']')
1215         {
1216           if( !disphint ) 
1217             {
1218               *erroff = count;
1219               *errcode = -9; /* unmatched display hint close */
1220               return 0;
1221             }
1222           disphint = NULL;
1223         }
1224       else if (digitp (p) )
1225         {
1226           if (*p == '0')
1227             { 
1228               *erroff = count;
1229               *errcode = -7; /* a length may not begin with zero */
1230               return 0;
1231             }
1232           datalen = atoi_1 (p);
1233         }
1234       else if (*p == '&' || *p == '\\')
1235         {
1236           *erroff = count;
1237           *errcode = -10; /* unexpected reserved punctuation */
1238           return 0;
1239         }
1240       else
1241         { 
1242           *erroff = count;
1243           *errcode = -5; /* bad character */
1244           return 0;
1245         }
1246     }
1247 }
1248
1249