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