See ChangeLog: Mon Jan 24 13:04:28 CET 2000 Werner Koch
[libgcrypt.git] / src / sexp.c
1 /* sexp.c  -  S-Expression handling
2  *      Copyright (C) 1999 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 /****************
23  * TODO:
24  *  - implement reference counting to defere freeing of
25  *    data and make copies of the data on demand.
26  *    --> do we really need this?
27  *
28  */
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <ctype.h>
36 #include <assert.h>
37
38 #define GCRYPT_NO_MPI_MACROS 1
39 #include "g10lib.h"
40 #include "memory.h"
41
42
43
44 #if 0
45 struct sexp_node;
46 typedef struct sexp_node *NODE;
47
48 struct gcry_sexp {
49     int orig_format;  /* format which we used to create this object */
50     NODE sexp;        /* a NULL indicates an empty list */
51 };
52 #else
53 typedef struct gcry_sexp *NODE;
54 #endif
55
56
57 enum node_types { ntLIST, ntDATA, ntMPI };
58
59 struct gcry_sexp {
60     NODE next;
61     NODE up;        /* helper needed for faster traversal */
62     enum node_types type;
63     union {
64         NODE list;
65         GCRY_MPI mpi;
66         struct {
67             size_t len;
68             byte  d[1];
69         } data;
70     } u;
71 };
72
73
74 static void
75 dump_mpi( GCRY_MPI a )
76 {
77     char buffer[1000];
78     size_t n = 1000;
79
80     if( !a )
81         fputs("[no MPI]", stderr );
82     else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
83         fputs("[MPI too large to print]", stderr );
84     else
85         fputs( buffer, stderr );
86 }
87
88 static void
89 dump_string( FILE *fp, const byte *p, size_t n, int delim )
90 {
91     for( ; n; n--, p++ )
92         if( iscntrl( *p ) || *p == delim ) {
93             putc('\\', fp);
94             if( *p == '\n' )
95                 putc('n', fp);
96             else if( *p == '\r' )
97                 putc('r', fp);
98             else if( *p == '\f' )
99                 putc('f', fp);
100             else if( *p == '\v' )
101                 putc('v', fp);
102             else if( *p == '\b' )
103                 putc('b', fp);
104             else if( !*p )
105                 putc('0', fp);
106             else
107                 fprintf(fp, "x%02x", *p );
108         }
109         else
110             putc(*p, fp);
111 }
112
113 static void
114 do_dump_list( NODE node, int indent )
115 {
116     for( ; node; node = node->next ) {
117         switch( node->type ) {
118           case ntLIST:
119             if( indent )
120                 putc('\n', stderr);
121             fprintf(stderr, "%*s(", indent, "");
122             do_dump_list( node->u.list, indent+1 );
123             putc(')', stderr);
124             break;
125           case ntDATA:
126             if( !node->u.data.len )
127                 fputs("EMPTY", stderr );
128             else
129                 dump_string(stderr, node->u.data.d, node->u.data.len, ')');
130             putc(' ', stderr);
131             break;
132           case ntMPI:
133             dump_mpi( node->u.mpi );
134             putc(' ', stderr);
135             break;
136         }
137         if( !indent )
138             putc('\n', stderr);
139     }
140 }
141
142 static void
143 dump_sexp( NODE node )
144 {
145     do_dump_list( node, 0 );
146 }
147
148
149 void
150 gcry_sexp_dump( GCRY_SEXP a )
151 {
152     do_dump_list( a, 0 );
153 }
154
155
156 /****************
157  * Create a new SEXP element (data)
158  * If length is 0 it is assumed that buffer is a C string.
159  */
160 GCRY_SEXP
161 gcry_sexp_new_data( const char *buffer, size_t length )
162 {
163     NODE list, node;
164
165     if( !length )
166         length = strlen(buffer);
167     node = g10_xcalloc( 1, sizeof *node + length );
168     node->type = ntDATA;
169     node->u.data.len = length;
170     memcpy(node->u.data.d, buffer, length );
171     list = g10_xcalloc( 1, sizeof *list );
172     list->type = ntLIST;
173     list->u.list = node;
174     return list;
175 }
176
177 /****************
178  * Create a new SEXP element (mpi)
179  */
180 GCRY_SEXP
181 gcry_sexp_new_mpi( GCRY_MPI mpi )
182 {
183     NODE list, node;
184
185     node = g10_xcalloc( 1, sizeof *node );
186     node->type = ntMPI;
187     node->u.mpi = gcry_mpi_copy( mpi );
188     list = g10_xcalloc( 1, sizeof *list );
189     list->type = ntLIST;
190     list->u.list = node;
191     return list;
192 }
193
194
195 /****************
196  * Create a pair of a name and some arbitrary data.
197  */
198 GCRY_SEXP
199 gcry_sexp_new_name_data( const char *name, const char *buffer, size_t length )
200 {
201     return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
202                            gcry_sexp_new_data( buffer, length ) );
203 }
204
205 /****************
206  * Create a pair of a name and a MPI
207  */
208 GCRY_SEXP
209 gcry_sexp_new_name_mpi( const char *name, GCRY_MPI mpi )
210 {
211     return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
212                            gcry_sexp_new_mpi( mpi ) );
213 }
214
215
216 /****************
217  * Release resource of the given SEXP object.
218  */
219 void
220 gcry_sexp_release( GCRY_SEXP sexp )
221 {
222     /* FIXME! */
223 }
224
225
226
227
228 /****************
229  * Make a pair from lists a and b, don't use a or b later on.
230  * Special behaviour:  If one is a single element list we put the
231  * element straight into the new pair.
232  */
233 GCRY_SEXP
234 gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b )
235 {
236     NODE head;
237
238     if( a->type != ntLIST ) {
239         fputs("sexp_cons: arg 1 is not a list\n", stderr );
240         return NULL;
241     }
242     if( b->type != ntLIST ) {
243         fputs("sexp_cons: arg 2 is not a list\n", stderr );
244         return NULL;
245     }
246
247
248     head = g10_xcalloc( 1, sizeof *head );
249     head->type = ntLIST;
250     if( !a->u.list->next ) { /* a has only one item */
251         NODE tmp = a;
252         a = a->u.list;
253         /* fixme: release tmp here */
254     }
255     if( !b->u.list->next ) { /* b has only one item */
256         NODE tmp = b;
257         b = b->u.list;
258         /* fixme: release tmp here */
259     }
260
261     head->u.list = a;
262     a->up = head;
263     a->next = b;
264     b->up = head;
265
266     return head;
267 }
268
269
270 /****************
271  * Make a list from all items, the end of list is indicated by a NULL
272  * don't use the passed lists later on, they are void.
273  */
274 GCRY_SEXP
275 gcry_sexp_vlist( GCRY_SEXP a, ... )
276 {
277     NODE head, tail, node;
278     va_list arg_ptr ;
279
280     if( a->type != ntLIST ) {
281         fputs("sexp_vlist: arg 1 is not a list\n", stderr );
282         return NULL;
283     }
284     head = g10_xcalloc( 1, sizeof *node );
285     head->type = ntLIST;
286     if( !a->u.list->next ) { /* a has only one item */
287         NODE tmp = a;
288         a = a->u.list;
289         /* fixme: release tmp here */
290     }
291     head->u.list = a;
292     a->up = head;
293     tail = a;
294
295     va_start( arg_ptr, a ) ;
296     while( (node = va_arg( arg_ptr, NODE )) ) {
297         if( node->type != ntLIST ) {
298             fputs("sexp_vlist: an arg is not a list\n", stderr );
299             return NULL;  /* fixme: we should release alread allocated nodes */
300         }
301         if( !node->u.list->next ) { /* node has only one item */
302             NODE tmp = node;
303             node = node->u.list;
304             /* fixme: release tmp here */
305         }
306         tail->next = node;
307         node->up = head;
308         tail = node;
309     }
310
311     va_end( arg_ptr );
312     return head;
313 }
314
315
316 /****************
317  * Append n to the list a
318  * Don't use n later on.
319  * Returns: a new ist (which maybe a)
320  */
321 GCRY_SEXP
322 gcry_sexp_append( GCRY_SEXP a, GCRY_SEXP n )
323 {
324
325     GCRY_SEXP node;
326
327     if( a->type != ntLIST ) {
328         fputs("sexp_append: a is not a list\n", stderr );
329         return a;
330     }
331
332     if( n->type != ntLIST ) {
333         fputs("sexp_append: n is not a list\n", stderr );
334         return a;
335     }
336
337     for( node = a; node->next; node = node->next )
338         ;
339
340     node->next = n;
341     return a;
342 }
343
344 GCRY_SEXP
345 gcry_sexp_prepend( GCRY_SEXP a, GCRY_SEXP n )
346 {
347
348     fputs("sexp_prepend: not impl.\n", stderr );
349     return a;
350 }
351
352
353
354 /****************
355  * Locate data in a list. Data must be the first item in the list.
356  * Returns: The sublist with that Data (don't modify it!)
357  */
358 GCRY_SEXP
359 gcry_sexp_find_token( GCRY_SEXP list, const char *tok, size_t toklen )
360 {
361     NODE node;
362
363     if( !toklen )
364         toklen = strlen(tok);
365
366     for( node=list ; node; node = node->next )
367       {
368         switch( node->type ) {
369           case ntLIST: {
370                 NODE n = gcry_sexp_find_token( node->u.list, tok, toklen );
371                 if( n )
372                     return n;
373             }
374             break;
375           case ntDATA:
376             if( node == list
377                 && node->u.data.len == toklen
378                 && !memcmp( node->u.data.d, tok, toklen ) )
379               {
380                 return node;
381               }
382             break;
383           case ntMPI:
384             break;
385         }
386       }
387
388     return NULL;
389 }
390
391
392 /****************
393  * Enumerate all objects in the list.  Ther first time you call this, pass
394  * the address of a void pointer initialized to NULL.  Then don't touch this
395  * variable anymore but pass it verbatim to the function; you will get
396  * all lists back in turn. End of lists is indicated by a returned NIL in
397  * whic case you should not continue to use this function
398  * (it would wrap around).  If you decide to cancel the operation before
399  * the final NIL you vae to release the context by calling the function
400  * with a the context but a LIST set to NULL.
401  * Note that this function returns only lists and not single objects.
402  */
403 GCRY_SEXP
404 gcry_sexp_enum( GCRY_SEXP list, void **context, int mode )
405 {
406     NODE node;
407
408     if( mode )
409         return NULL; /* mode is reserved and must be 0 */
410     if( !list ) {
411         /* we are lucky that we can hold all information in the pointer
412          * value ;-) - so there is no need to release any memory */
413         *context = NULL;
414         return NULL;
415     }
416     if( !*context )  /* start enumeration */
417         node = list;
418     else {
419         node = *context;
420         node = node->next;
421     }
422
423     for( ; node; node = node->next ) {
424         *context = node; /* store our context */
425         if( node->type == ntLIST )
426             return node->u.list;
427         return node;
428     }
429
430     /* release resources and return nil */
431     return gcry_sexp_enum( NULL, context, mode );
432 }
433
434
435
436 /****************
437  * Get the CAR
438  */
439 GCRY_SEXP
440 gcry_sexp_car( GCRY_SEXP list )
441 {
442     return list;
443 }
444
445 /****************
446  * Get data from the car
447  */
448 const char *
449 gcry_sexp_car_data( GCRY_SEXP list, size_t *datalen )
450 {
451     if( list && list->type == ntLIST && !list->next )
452         list = list->u.list;
453     if( list && list->type == ntDATA ) {
454         *datalen = list->u.data.len;
455         return list->u.data.d;
456     }
457
458     return NULL;
459 }
460
461 /****************
462  * Get a MPI from the car
463  */
464 GCRY_MPI
465 gcry_sexp_car_mpi( GCRY_SEXP list, int mpifmt )
466 {
467     if( list && list->type == ntLIST && !list->next )
468         list = list->u.list;
469     if( mpifmt && list->type == ntDATA ) {
470         MPI a;
471         size_t n = list->u.data.len;
472         if( gcry_mpi_scan( &a, mpifmt, list->u.data.d, &n ) )
473             return NULL;
474         return a;
475     }
476     else if( list->type == ntMPI )
477         return gcry_mpi_copy( list->u.mpi );
478
479     return NULL;
480 }
481
482 /****************
483  * Get the CDR
484  */
485 GCRY_SEXP
486 gcry_sexp_cdr( GCRY_SEXP list )
487 {
488     if( list && (list = list->next) )
489         return list;
490     return NULL;
491 }
492
493 /****************
494  * Get data from the cdr assuming this is a pair
495  */
496 const char *
497 gcry_sexp_cdr_data( GCRY_SEXP list, size_t *datalen )
498 {
499     if( list && (list = list->next) && list->type == ntDATA ) {
500         *datalen = list->u.data.len;
501         return list->u.data.d;
502     }
503
504     return NULL;
505 }
506
507
508 /****************
509  * cdr the mpi from the list or NULL if there is no MPI.
510  * This function tries to convert plain data to an MPI.
511  * Actually this funtion returns only the second item of the list
512  * and ignores any further arguments.
513  */
514 GCRY_MPI
515 gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt )
516 {
517     NODE node = list;
518
519     if( !node || !(node = node->next) || node == ntLIST )
520         return NULL;
521     if( mpifmt && node->type == ntDATA ) {
522         MPI a;
523         size_t n = node->u.data.len;
524         if( gcry_mpi_scan( &a, mpifmt, node->u.data.d, &n ) )
525             return NULL;
526         return a;
527     }
528     else if( node->type == ntMPI )
529         return gcry_mpi_copy( node->u.mpi );
530     else
531         return NULL;
532 }
533
534
535 /****************
536  * Scan the provided buffer and return the S expression in our internal
537  * format.  Returns a newly allocated expression.  If erroff is not NULL and
538  * a parsing error has occured, the offset into buffer will be returned.
539  */
540 int
541 gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
542                                      size_t length, size_t *erroff )
543 {
544     static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz"
545                                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
546                                      "0123456789-./_:*+=";
547     const char *p;
548     size_t n;
549     NODE head, tail, node;
550     const char *digptr=NULL;
551     const char *quoted=NULL;
552     const char *tokenp=NULL;
553     const char *hexfmt=NULL;
554     const char *base64=NULL;
555     const char *disphint=NULL;
556     int quoted_esc=0;
557     int datalen=0;
558     int first;
559
560     tail = head = NULL;
561     first = 0;
562     for(p=buffer,n=length; n; p++, n-- ) {
563         if( tokenp ) {
564             if( strchr( tokenchars, *p ) )
565                 continue;
566         }
567         if( quoted ) {
568             if( quoted_esc ) {
569                 switch( *p ) {
570                   case 'b': case 't': case 'v': case 'n': case 'f':
571                   case 'r': case '"': case '\'': case '\\':
572                     quoted_esc = 0;
573                     break;
574                   case '0': case '1': case '2': case '3': case '4':
575                   case '5': case '6': case '7':
576                     if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
577                                 && p[2] >= '0' && p[2] <= '7') ) {
578                         *erroff = p - buffer;
579                         return -6;   /* invalid octal value */
580                     }
581                     p += 2; n -= 2;
582                     quoted_esc = 0;
583                     break;
584                   case 'x':
585                     if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
586                         *erroff = p - buffer;
587                         return -6;   /* invalid hex value */
588                     }
589                     p += 2; n -= 2;
590                     quoted_esc = 0;
591                     break;
592                   case '\r':  /* ignore CR[,LF] */
593                     if( n && p[1] == '\n' ) {
594                         p++; n--;
595                     }
596                     quoted_esc = 0;
597                     break;
598                   case '\n':  /* ignore LF[,CR] */
599                     if( n && p[1] == '\r' ) {
600                         p++; n--;
601                     }
602                     quoted_esc = 0;
603                     break;
604                   default:
605                     *erroff = p - buffer;
606                     return -6;   /* invalid quoted string escape */
607                 }
608             }
609             else if( *p == '\\' )
610                 quoted_esc = 1;
611             else if( *p == '\"' ) {
612                 /* fixme: add item */
613                 quoted = NULL;
614             }
615         }
616         else if( hexfmt ) {
617             if( *p == '#' )
618                hexfmt = NULL;
619         }
620         else if( base64 ) {
621             if( *p == '|' )
622                base64 = NULL;
623         }
624         else if( digptr ) {
625             if( isdigit(*p) )
626                 ;
627             else if( *p == ':' ) {
628                 if( !head ) {
629                     *erroff = 0;
630                     return -4;   /* not a list */
631                 }
632                 datalen = atoi( digptr ); /* fixme: check for overflow */
633                 digptr = NULL;
634                 if( datalen > n-1 ) {
635                     *erroff = p - buffer;
636                     return -2; /* buffer too short */
637                 }
638                 /* make a new list entry */
639                 node = g10_xcalloc( 1, sizeof *node + datalen );
640                 if( first ) { /* stuff it into the first node */
641                     first = 0;
642                     node->up = tail;
643                     tail->u.list = node;
644                 }
645                 else {
646                     node->up = tail->up;
647                     tail->next = node;
648                 }
649                 tail = node;
650                 /* and fill in the value (we store the value in the node)*/
651                 node->type = ntDATA;
652                 node->u.data.len = datalen;
653                 memcpy(node->u.data.d, p+1, datalen );
654
655                 n -= datalen;
656                 p += datalen;
657             }
658             else if( *p == '\"' ) {
659                 digptr = NULL; /* we ignore the optional length */
660                 quoted = p;
661                 quoted_esc = 0;
662             }
663             else if( *p == '#' ) {
664                 digptr = NULL; /* we ignore the optional length */
665                 hexfmt = p;
666             }
667             else if( *p == '|' ) {
668                 digptr = NULL; /* we ignore the optional length */
669                 base64 = p;
670             }
671             else {
672                 *erroff = p - buffer;
673                 return -1;
674             }
675         }
676         else if( *p == '(' ) {
677             if( disphint ) {
678                 *erroff = p - buffer;
679                 return -9; /* open display hint */
680             }
681             node = g10_xcalloc( 1, sizeof *node );
682             if( !head )
683                 head = node;
684             else {
685                 node->up = tail->up;
686                 tail->next = node;
687             }
688             node->type = ntLIST;
689             tail = node;
690             first = 1;
691         }
692         else if( *p == ')' ) { /* walk up */
693             if( disphint ) {
694                 *erroff = p - buffer;
695                 return -9; /* open display hint */
696             }
697             if( !head ) {
698                 *erroff = 0;
699                 return -4;   /* not a list */
700             }
701             tail = tail->up;
702             if( !tail ) {
703                 *erroff = p - buffer;
704                 return -3;
705             }
706         }
707         else if( *p == '\"' ) {
708             quoted = p;
709             quoted_esc = 0;
710         }
711         else if( *p == '#' )
712             hexfmt = p;
713         else if( *p == '|' )
714             base64 = p;
715         else if( *p == '[' ) {
716             if( disphint ) {
717                 *erroff = p - buffer;
718                 return -8; /* nested display hints */
719             }
720             disphint = p;
721         }
722         else if( *p == ']' ) {
723             if( !disphint ) {
724                 *erroff = p - buffer;
725                 return -9; /* unmatched display hint close */
726             }
727             disphint = NULL;
728         }
729         else if( isdigit(*p) ) {
730             if( *p == '0' ) { /* a length may not begin with zero */
731                 *erroff = p - buffer;
732                 return -7;
733             }
734             digptr = p;
735         }
736         else if( strchr( tokenchars, *p ) )
737             tokenp = p;
738         else if( isspace(*p) )
739             ;
740         else if( *p == '{' ) {
741             /* fixme: handle rescanning:
742              * we can do this by saving our current state
743              * and start over at p+1 -- Hmmm. At this point here
744              * we are in a well defined state, so we don't need to save
745              * it.  Great.
746              */
747             *erroff = p - buffer;
748             return -10; /* unexpected reserved punctuation */
749         }
750         else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
751             *erroff = p - buffer;
752             return -10; /* unexpected reserved punctuation */
753         }
754         else { /* bad or unavailable*/
755             *erroff = p - buffer;
756             return -5;
757         }
758
759     }
760     *retsexp = head;
761     return 0;
762 }
763
764
765 /****************
766  * Print SEXP to buffer using the MODE.  Returns the length of the
767  * SEXP in buffer or 0 if the buffer is too short (We have at least an
768  * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
769  * the required length is returned.
770  */
771 size_t
772 gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer, size_t maxlength )
773 {
774     return 0;
775 }
776
777
778
779
780
781 #if 0
782 /***********************************************************/
783
784 const char *
785 strusage( int level )
786 {
787     return default_strusage(level);
788 }
789
790
791 static int
792 sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
793 {
794     GCRY_SEXP list, l2;
795     const char *name;
796     const char *s;
797     size_t n;
798     int i, idx;
799     int algo;
800     const char *elems1, *elems2;
801     GCRY_MPI *array;
802     static struct { const char* name; int algo;
803                     const char* common_elements;
804                     const char* public_elements;
805                     const char* secret_elements;
806                   } algos[] = {
807         {  "dsa"            , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
808         {  "rsa"            , PUBKEY_ALGO_RSA       , "ne",   "", "dpqu" },
809         {  "openpgp-dsa"    , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
810         {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "pqgy", "", "x"    },
811         {  "openpgp-elg"    , PUBKEY_ALGO_ELGAMAL_E , "pgy",  "", "x"    },
812         {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
813         {  NULL }};
814
815     /* check that the first element is valid */
816     list = gcry_sexp_find_token( sexp, want_private? "private-key"
817                                                     :"public-key", 0 );
818     if( !list )
819         return -1; /* Does not contain a public- or private-key object */
820     list = gcry_sexp_cdr( list );
821     if( !list )
822         return -2; /* no cdr for the key object */
823     name = gcry_sexp_car_data( list, &n );
824     if( !name )
825         return -3; /* invalid structure of object */
826     fprintf(stderr, "algorithm name: `%.*s'\n", (int)n, name );
827     for(i=0; (s=algos[i].name); i++ ) {
828         if( strlen(s) == n && !memcmp( s, name, n ) )
829             break;
830     }
831     if( !s )
832         return -4; /* unknown algorithm */
833     algo = algos[i].algo;
834     elems1 = algos[i].common_elements;
835     elems2 = want_private? algos[i].secret_elements : algos[i].public_elements;
836     array = g10_xcalloc( (strlen(elems1)+strlen(elems2)+1) , sizeof *array );
837     idx = 0;
838     for(s=elems1; *s; s++, idx++ ) {
839         l2 = gcry_sexp_find_token( list, s, 1 );
840         if( !l2 ) {
841             g10_free( array );
842             return -5; /* required parameter not found */
843         }
844         array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
845         if( !array[idx] ) {
846             g10_free( array );
847             return -6; /* required parameter is invalid */
848         }
849     }
850     for(s=elems2; *s; s++, idx++ ) {
851         l2 = gcry_sexp_find_token( list, s, 1 );
852         if( !l2 ) {
853             g10_free( array );
854             return -5; /* required parameter not found */
855         }
856         /* FIXME: put the MPI in secure memory when needed */
857         array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
858         if( !array[idx] ) {
859             g10_free( array );
860             return -6; /* required parameter is invalid */
861         }
862     }
863
864     *retarray = array;
865     *retalgo = algo;
866
867     return 0;
868 }
869
870
871
872 int
873 main(int argc, char **argv)
874 {
875     char buffer[5000];
876     size_t erroff;
877     int rc, n;
878     FILE *fp;
879     GCRY_SEXP s_pk, s_dsa, s_p, s_q, s_g, s_y, sexp;
880
881   #if 0
882     fp = stdin;
883     n = fread(buffer, 1, 5000, fp );
884     rc = gcry_sexp_sscan( &sexp, buffer, n, &erroff );
885     if( rc ) {
886         fprintf(stderr, "parse error %d at offset %u\n", rc, erroff );
887         exit(1);
888     }
889     fputs("We have this S-Exp:\n",stderr);
890     dump_sexp( sexp );
891   #else
892     s_pk = SEXP_NEW( "public-key", 10 );
893     fputs("pk:\n",stderr);dump_sexp( s_pk );
894     s_dsa = SEXP_NEW( "dsa", 3 );
895     s_p = SEXP_CONS( SEXP_NEW( "p", 1 ), SEXP_NEW( "PPPPPP", 6 ) );
896     fputs("p:\n",stderr);dump_sexp( s_p );
897     s_y = SEXP_CONS( SEXP_NEW( "y", 1 ), SEXP_NEW( "YYYYYYYY", 8 ) );
898     fputs("y:\n",stderr);dump_sexp( s_y );
899     s_q = gcry_sexp_new_name_data( "q", "QQQ", 3 );
900     fputs("q:\n",stderr);dump_sexp( s_q );
901     s_g = gcry_sexp_new_name_mpi( "g" , gcry_mpi_set_ui(NULL, 42) );
902     fputs("g:\n",stderr);dump_sexp( s_g );
903     sexp = SEXP_CONS( s_pk, gcry_sexp_vlist( s_dsa,
904                                              s_y,
905                                              s_p,
906                                              s_q,
907                                              s_g,
908                                              NULL ));
909     fputs("Here is what we have:\n",stderr);
910     dump_sexp( sexp );
911   #endif
912
913     /* now find something */
914     if( argc > 1 )
915       {
916         GCRY_SEXP s1;
917
918         s1 = gcry_sexp_find_token( sexp, argv[1], strlen(argv[1]) );
919         if( !s1 )
920           {
921             fprintf(stderr, "didn't found `%s'\n", argv[1] );
922           }
923         else
924           {
925             fprintf(stderr, "found `%s':\n", argv[1] );
926             dump_sexp( s1 );
927           }
928
929         #if 1
930         {  int i,rc, algo;
931            GCRY_MPI *array;
932
933            rc = sexp_to_pk( s1, 0, &array, &algo);
934            if( rc )
935               fprintf(stderr, "sexp_to_pk failed: rc=%d\n", rc );
936            else {
937                for(i=0; array[i]; i++ ) {
938                    fprintf(stderr, "MPI[%d]: ", i);
939                    dump_mpi( array[i] );
940                    fprintf(stderr, "\n");
941                }
942             }
943         }
944         #endif
945
946
947         if( argc > 2 ) /* get the MPI out of the list */
948         #if 0
949           {
950             GCRY_SEXP s2;
951             const char *p;
952             size_t n;
953
954             p = gcry_sexp_car_data( s1, &n );
955             if( !p ) {
956                 fputs("no CAR\n", stderr );
957                 exit(1);
958             }
959             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
960
961             p = gcry_sexp_cdr_data( s1, &n );
962             if( !p ) {
963                 s2 = gcry_sexp_cdr( s1 );
964                 if( !s2 ) {
965                     fputs("no CDR at all\n", stderr );
966                     exit(1);
967                 }
968                 p = gcry_sexp_car_data( s2, &n );
969             }
970             if( !p ) {
971                 fputs("no CDR data\n", stderr );
972                 exit(1);
973             }
974             fprintf(stderr, "CDR=`%.*s'\n", (int)n, p );
975
976
977
978           }
979         #elif 1
980           {
981             GCRY_SEXP s2;
982             MPI a;
983             const char *p;
984             size_t n;
985
986             fprintf(stderr,"*********************************\n");
987             p = gcry_sexp_car_data( s1, &n );
988             if( !p ) {
989                 fputs("no CAR\n", stderr );
990                 exit(1);
991             }
992             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
993             s2 = gcry_sexp_cdr( s1 );
994             if( !s2 ) {
995                 fputs("no CDR\n", stderr );
996                 exit(1);
997
998             }
999             p = gcry_sexp_car_data( s2, &n );
1000             if( !p ) {
1001                 fputs("no data at CAR\n", stderr );
1002                 exit(1);
1003             }
1004             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
1005
1006             s2 = gcry_sexp_find_token( s1, argv[2], strlen(argv[2]) );
1007             if( !s2 )
1008             {
1009                fprintf(stderr, "didn't found `%s'\n", argv[2] );
1010                exit(1);
1011             }
1012             p = gcry_sexp_car_data( s2, &n );
1013             if( !p ) {
1014                 fputs("no CAR\n", stderr );
1015                 exit(1);
1016             }
1017             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
1018
1019             a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
1020             if( a ) {
1021                 fprintf(stderr, "MPI: ");
1022                 dump_mpi( a );
1023                 fprintf(stderr, "\n");
1024             }
1025             else
1026                 fprintf(stderr, "cannot cdr a mpi\n" );
1027           }
1028          #else
1029           {    /* print all MPIs */
1030             void *ctx = NULL;
1031             GCRY_SEXP s2;
1032             MPI a;
1033
1034             while( (s2 = gcry_sexp_enum( s1, &ctx, 0 )) )
1035               {
1036                 const char *car_d;
1037                 size_t car_n;
1038
1039                 car_d = gcry_sexp_car_data( s2, &car_n );
1040                 if( car_d ) {
1041                    fprintf(stderr, "CAR: %.*s=", (int)car_n, car_d );
1042                    a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
1043                    dump_mpi( a );
1044                    fprintf(stderr, "\n");
1045
1046                 }
1047                 else
1048                     fprintf(stderr, "no CAR\n");
1049               }
1050           }
1051          #endif
1052       }
1053     return 0;
1054 }
1055 #endif