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