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