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