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