* tsexp.c (back_and_forth): Very minimal test of the new functions.
[libgcrypt.git] / src / sexp.c
1 /* sexp.c  -  S-Expression handling
2  *      Copyright (C) 1999, 2000, 2001, 2002 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 Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (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 Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License 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 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
48 #define octdigitp(p) (*(p) >= '0' && *(p) <= '7')
49 #define alphap(a)    (   (*(a) >= 'A' && *(a) <= 'Z')  \
50                       || (*(a) >= 'a' && *(a) <= 'z'))
51 #define hexdigitp(a) (digitp (a)                     \
52                       || (*(a) >= 'A' && *(a) <= 'F')  \
53                       || (*(a) >= 'a' && *(a) <= 'f'))
54 /* the atoi macros assume that the buffer has only valid digits */
55 #define atoi_1(p)   (*(p) - '0' )
56 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
57                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
58 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
59
60 #define TOKEN_SPECIALS  "-./_:*+="
61
62 #define OLDPARSECODE(a) (-((GCRYERR_SEXP_ ## a)-GCRYERR_SEXP_INV_LEN_SPEC+1))
63
64
65 static int
66 sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff ,
67             const char *buffer, size_t length, va_list arg_ptr, int argflag);
68
69
70 #if 0
71 static void
72 dump_mpi( GCRY_MPI a )
73 {
74     char buffer[1000];
75     size_t n = 1000;
76
77     if( !a )
78         fputs("[no MPI]", stderr );
79     else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
80         fputs("[MPI too large to print]", stderr );
81     else
82         fputs( buffer, stderr );
83 }
84 #endif
85
86 static void
87 dump_string (const byte *p, size_t n, int delim )
88 {
89   for (; n; n--, p++ )
90     {
91       if ((*p & 0x80) || iscntrl( *p ) || *p == delim ) 
92         {
93           if( *p == '\n' )
94             log_printf ("\\n");
95           else if( *p == '\r' )
96             log_printf ("\\r");
97           else if( *p == '\f' )
98             log_printf ("\\f");
99           else if( *p == '\v' )
100             log_printf ("\\v");
101             else if( *p == '\b' )
102               log_printf ("\\b");
103           else if( !*p )       
104             log_printf ("\\0");
105           else
106             log_printf ("\\x%02x", *p );
107         }
108       else
109         log_printf ("%c", *p);
110     }
111 }
112
113
114 void
115 gcry_sexp_dump (const GCRY_SEXP a)
116 {
117   const byte *p;
118   int indent = 0;
119   int type;
120
121   if (!a)
122     {
123       log_printf ( "[nil]\n");
124       return;
125     }
126
127   p = a->d;
128   while ( (type = *p) != ST_STOP )
129     {
130       p++;
131       switch ( type )
132         {
133         case ST_OPEN:
134           log_printf ("%*s[open]\n", 2*indent, "");
135           indent++;
136           break;
137         case ST_CLOSE:
138           if( indent )
139             indent--;
140           log_printf ("%*s[close]\n", 2*indent, "");
141           break;
142         case ST_DATA: {
143           DATALEN n;
144           memcpy ( &n, p, sizeof n );
145           p += sizeof n;
146           log_printf ("%*s[data=\"", 2*indent, "" );
147           dump_string (p, n, '\"' );
148           log_printf ("\"]\n");
149           p += n;
150         }
151         break;
152         default:
153           log_printf ("%*s[unknown tag %d]\n", 2*indent, "", type);
154           break;
155         }
156     }
157 }
158
159 /****************
160  * Pass list through except when it is an empty list - in that case
161  * return NULL and release the passed list.
162  */
163 static GCRY_SEXP
164 normalize ( GCRY_SEXP list )
165 {
166     char *p;
167     if ( !list )
168         return NULL;
169     p = list->d;
170     if ( *p == ST_STOP ) {
171         /* this is "" */
172         gcry_sexp_release ( list );
173         return NULL;
174     }
175     if( *p == ST_OPEN && p[1] == ST_CLOSE ) {
176         /* this is "()" */
177         gcry_sexp_release ( list );
178         return NULL;
179     }
180
181     return list;
182 }
183
184 /* Create a new S-expression object by reading LENGTH bytes from
185    BUFFER, assuming it is canonilized encoded or autodetected encoding
186    when AUTODETECT is set to 1.  With FREEFNC not NULL, ownership of
187    the buffer is transferred to tyhe newle created object.  FREEFNC
188    should be the freefnc used to release BUFFER; there is no guarantee
189    at which point this function is called; most likey you want to use
190    free() or gcry_free(). 
191  
192    Passing LENGTH and AUTODETECT as 0 is allowed to indicate that
193    BUFFER points to a valid canonical encoded S-expression.  A LENGTH
194    of 0 and AUTODETECT 1 indicates that buffer points to a
195    null-terminated string.
196   
197    This function returns 0 and and the pointer to the new object in
198    RETSEXP or an error code in which case RETSEXP is set to NULL.  */
199 int 
200 gcry_sexp_create (GCRY_SEXP *retsexp, void *buffer, size_t length,
201                   int autodetect, void (*freefnc)(void*) )
202 {
203   int errcode;
204   GCRY_SEXP se;
205   volatile va_list dummy_arg_ptr;
206
207   if (!retsexp)
208     return GCRYERR_INV_ARG;
209   *retsexp = NULL;
210   if (autodetect < 0 || autodetect > 1 || !buffer)
211     return GCRYERR_INV_ARG;
212
213   if (!length && !autodetect)
214     { /* What a brave caller to assume that there is really a canonical
215          encoded S-expression in buffer */
216       length = gcry_sexp_canon_len (buffer, 0, NULL, &errcode);
217       if (!length)
218         return 200 - errcode;
219     }
220   else if (!length && autodetect)
221     { /* buffer is a string */
222       length = strlen ((char *)buffer);
223     }
224
225   errcode = sexp_sscan (&se, NULL, buffer, length, dummy_arg_ptr, 0);
226   if (errcode)
227     return 200 - errcode;
228
229   *retsexp = se;
230   if (freefnc)
231     {
232       /* For now we release the buffer immediately.  As soon as we
233          have changed the internal represenation of S-expression to
234          the canoncial format - which has the advantage of faster
235          parsing - we will use this function as a closure in our
236          GCRYSEXP object and use the BUFFER directly */
237       freefnc (buffer);
238     }
239   return 0;
240 }
241
242 /* Same as gcry_sexp_create but don't transfer ownership */
243 int
244 gcry_sexp_new (GCRY_SEXP *retsexp, const void *buffer, size_t length,
245                int autodetect)
246 {
247   return gcry_sexp_create (retsexp, (void *)buffer, length, autodetect, NULL);
248 }
249
250
251 /****************
252  * Release resource of the given SEXP object.
253  */
254 void
255 gcry_sexp_release( GCRY_SEXP sexp )
256 {
257     gcry_free ( sexp );
258 }
259
260
261 /****************
262  * Make a pair from lists a and b, don't use a or b later on.
263  * Special behaviour:  If one is a single element list we put the
264  * element straight into the new pair.
265  */
266 GCRY_SEXP
267 gcry_sexp_cons( const GCRY_SEXP a, const GCRY_SEXP b )
268 {
269     /* NYI: Implementation should be quite easy with our new data representation */
270     BUG ();
271     return NULL;
272 }
273
274
275 /****************
276  * Make a list from all items in the array the end of the array is marked
277  * with a NULL.                                                                       y a NULL
278  */
279 GCRY_SEXP
280 gcry_sexp_alist( const GCRY_SEXP *array )
281 {
282     /* NYI: Implementaion should be quite easy with our new data representation */
283     BUG ();
284     return NULL;
285 }
286
287 /****************
288  * Make a list from all items, the end of list is indicated by a NULL
289  */
290 GCRY_SEXP
291 gcry_sexp_vlist( const GCRY_SEXP a, ... )
292 {
293     /* NYI: Implementaion should be quite easy with our new data representation */
294     BUG ();
295     return NULL;
296 }
297
298
299 /****************
300  * Append n to the list a
301  * Returns: a new ist (which maybe a)
302  */
303 GCRY_SEXP
304 gcry_sexp_append( const GCRY_SEXP a, const GCRY_SEXP n )
305 {
306     /* NYI: Implementaion should be quite easy with our new data representation */
307     BUG ();
308     return NULL;
309 }
310
311 GCRY_SEXP
312 gcry_sexp_prepend( const GCRY_SEXP a, const GCRY_SEXP n )
313 {
314     /* NYI: Implementaion should be quite easy with our new data representation */
315     BUG ();
316     return NULL;
317 }
318
319
320
321 /****************
322  * Locate token in a list. The token must be the car of a sublist.
323  * Returns: A new list with this sublist or NULL if not found.
324  */
325 GCRY_SEXP
326 gcry_sexp_find_token( const GCRY_SEXP list, const char *tok, size_t toklen )
327 {
328     const byte *p;
329     DATALEN n;
330
331     if ( !list )
332         return NULL;
333
334     if( !toklen )
335         toklen = strlen(tok);
336     p = list->d;
337     while ( *p != ST_STOP ) {
338         if ( *p == ST_OPEN && p[1] == ST_DATA ) {
339             const byte *head = p;
340
341             p += 2;
342             memcpy ( &n, p, sizeof n ); p += sizeof n;
343             if ( n == toklen && !memcmp( p, tok, toklen ) ) { /* found it */
344                 GCRY_SEXP newlist;
345                 byte *d;
346                 int level = 1;
347
348                 /* look for the end of the list */
349                 for ( p += n; level; p++ ) {
350                     if ( *p == ST_DATA ) {
351                         memcpy ( &n, ++p, sizeof n );
352                         p += sizeof n + n;
353                         p--; /* compensate for later increment */
354                     }
355                     else if ( *p == ST_OPEN ) {
356                         level++;
357                     }
358                     else if ( *p == ST_CLOSE ) {
359                         level--;
360                     }
361                     else if ( *p == ST_STOP ) {
362                         BUG ();
363                     }
364                 } while ( level );
365                 n = p - head;
366
367                 newlist = gcry_xmalloc ( sizeof *newlist + n );
368                 d = newlist->d;
369                 memcpy ( d, head, n ); d += n;
370                 *d++ = ST_STOP;
371                 return normalize ( newlist );
372             }
373             p += n;
374         }
375         else if ( *p == ST_DATA ) {
376             memcpy ( &n, ++p, sizeof n ); p += sizeof n;
377             p += n;
378         }
379         else
380             p++;
381     }
382     return NULL;
383 }
384
385 /****************
386  * return the length of the given list
387  */
388 int
389 gcry_sexp_length( const GCRY_SEXP list )
390 {
391     const byte *p;
392     DATALEN n;
393     int type;
394     int length = 0;
395     int level = 0;
396
397     if ( !list )
398         return 0;
399
400     p = list->d;
401     while ( (type=*p) != ST_STOP ) {
402         p++;
403         if ( type == ST_DATA ) {
404             memcpy ( &n, ++p, sizeof n );
405             p += sizeof n + n;
406             p--;
407             if ( !level )
408                 length++;
409         }
410         else if ( type == ST_OPEN ) {
411             if ( !level )
412                 length++;
413             level++;
414         }
415         else if ( type == ST_CLOSE ) {
416             level--;
417         }
418     }
419     return length;
420 }
421
422
423
424 /****************
425  * Extract the CAR of the given list
426  */
427 GCRY_SEXP
428 gcry_sexp_nth( const GCRY_SEXP list, int number )
429 {
430     const byte *p;
431     DATALEN n;
432     GCRY_SEXP newlist;
433     byte *d;
434     int level = 0;
435
436     if ( !list || list->d[0] != ST_OPEN )
437         return NULL;
438     p = list->d;
439
440     while ( number > 0 ) {
441         p++;
442         if ( *p == ST_DATA ) {
443             memcpy ( &n, ++p, sizeof n );
444             p += sizeof n + n;
445             p--;
446             if ( !level )
447                 number--;
448         }
449         else if ( *p == ST_OPEN ) {
450             level++;
451         }
452         else if ( *p == ST_CLOSE ) {
453             level--;
454             if ( !level )
455                 number--;
456         }
457         else if ( *p == ST_STOP ) {
458             return NULL;
459         }
460     }
461     p++;
462
463     if ( *p == ST_DATA ) {
464         memcpy ( &n, p, sizeof n ); p += sizeof n;
465         newlist = gcry_xmalloc ( sizeof *newlist + n + 1 );
466         d = newlist->d;
467         memcpy ( d, p, n ); d += n;
468         *d++ = ST_STOP;
469     }
470     else if ( *p == ST_OPEN ) {
471         const byte *head = p;
472
473         level = 1;
474         do {
475             p++;
476             if ( *p == ST_DATA ) {
477                 memcpy ( &n, ++p, sizeof n );
478                 p += sizeof n + n;
479                 p--;
480             }
481             else if ( *p == ST_OPEN ) {
482                 level++;
483             }
484             else if ( *p == ST_CLOSE ) {
485                 level--;
486             }
487             else if ( *p == ST_STOP ) {
488                 BUG ();
489             }
490         } while ( level );
491         n = p + 1 - head;
492
493         newlist = gcry_xmalloc ( sizeof *newlist + n );
494         d = newlist->d;
495         memcpy ( d, head, n ); d += n;
496         *d++ = ST_STOP;
497     }
498     else
499         newlist = NULL;
500
501     return normalize (newlist);
502 }
503
504 GCRY_SEXP
505 gcry_sexp_car( const GCRY_SEXP list )
506 {
507     return gcry_sexp_nth ( list, 0 );
508 }
509
510 /****************
511  * Get data from the car.  The returned value is valid as long as the list
512  * is not modified.
513  */
514 const char *
515 gcry_sexp_nth_data( const GCRY_SEXP list, int number, size_t *datalen )
516 {
517     const byte *p;
518     DATALEN n;
519     int level = 0;
520
521     *datalen = 0;
522     if ( !list ) {
523         return NULL;
524     }
525     p = list->d;
526     if ( *p == ST_OPEN )
527         p++;         /* yep, a list */
528     else if (number )
529         return NULL; /* not a list but an n > 0 element requested */
530
531     /* skip n elements */
532     while ( number > 0 ) {
533         if ( *p == ST_DATA ) {
534             memcpy ( &n, ++p, sizeof n );
535             p += sizeof n + n;
536             p--;
537             if ( !level )
538                 number--;
539         }
540         else if ( *p == ST_OPEN ) {
541             level++;
542         }
543         else if ( *p == ST_CLOSE ) {
544             level--;
545             if ( !level )
546                 number--;
547         }
548         else if ( *p == ST_STOP ) {
549             return NULL;
550         }
551         p++;
552     }
553
554
555     if ( *p == ST_DATA ) {
556         memcpy ( &n, ++p, sizeof n );
557         *datalen = n;
558         return p + sizeof n;
559     }
560
561     return NULL;
562 }
563
564 /****************
565  * Get a MPI from the car
566  */
567 GCRY_MPI
568 gcry_sexp_nth_mpi( GCRY_SEXP list, int number, int mpifmt )
569 {
570     const byte *p;
571     DATALEN n;
572     int level = 0;
573
574     if ( !list )
575         return NULL;
576     if ( !mpifmt )
577         mpifmt = GCRYMPI_FMT_STD;
578
579     p = list->d;
580     if ( *p == ST_OPEN )
581         p++;         /* yep, a list */
582     else if (number )
583         return NULL; /* not a list but an n > 0 element requested */
584
585     /* skip n elements */
586     while ( number > 0 ) {
587         if ( *p == ST_DATA ) {
588             memcpy ( &n, ++p, sizeof n );
589             p += sizeof n + n;
590             p--;
591             if ( !level )
592                 number--;
593         }
594         else if ( *p == ST_OPEN ) {
595             level++;
596         }
597         else if ( *p == ST_CLOSE ) {
598             level--;
599             if ( !level )
600                 number--;
601         }
602         else if ( *p == ST_STOP ) {
603             return NULL;
604         }
605         p++;
606     }
607
608     if ( *p == ST_DATA ) {
609         MPI a;
610         size_t nbytes;
611
612         memcpy ( &n, ++p, sizeof n );
613         p += sizeof n;
614         nbytes = n;
615         if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
616             return a;
617     }
618
619     return NULL;
620 }
621
622
623 /****************
624  * Get the CDR
625  */
626 GCRY_SEXP
627 gcry_sexp_cdr( const GCRY_SEXP list )
628 {
629     const byte *p;
630     const byte *head;
631     DATALEN n;
632     GCRY_SEXP newlist;
633     byte *d;
634     int level = 0;
635     int skip = 1;
636
637     if ( !list || list->d[0] != ST_OPEN )
638         return NULL;
639     p = list->d;
640
641     while ( skip > 0 ) {
642         p++;
643         if ( *p == ST_DATA ) {
644             memcpy ( &n, ++p, sizeof n );
645             p += sizeof n + n;
646             p--;
647             if ( !level )
648                 skip--;
649         }
650         else if ( *p == ST_OPEN ) {
651             level++;
652         }
653         else if ( *p == ST_CLOSE ) {
654             level--;
655             if ( !level )
656                 skip--;
657         }
658         else if ( *p == ST_STOP ) {
659             return NULL;
660         }
661     }
662     p++;
663
664     head = p;
665     level = 0;
666     do {
667         if ( *p == ST_DATA ) {
668             memcpy ( &n, ++p, sizeof n );
669             p += sizeof n + n;
670             p--;
671         }
672         else if ( *p == ST_OPEN ) {
673             level++;
674         }
675         else if ( *p == ST_CLOSE ) {
676             level--;
677         }
678         else if ( *p == ST_STOP ) {
679             return NULL;
680         }
681         p++;
682     } while ( level );
683     n = p - head;
684
685     newlist = gcry_xmalloc ( sizeof *newlist + n + 2 );
686     d = newlist->d;
687     *d++ = ST_OPEN;
688     memcpy ( d, head, n ); d += n;
689     *d++ = ST_CLOSE;
690     *d++ = ST_STOP;
691
692     return normalize (newlist);
693 }
694
695 GCRY_SEXP
696 gcry_sexp_cadr ( const GCRY_SEXP list )
697 {
698     GCRY_SEXP a, b;
699
700     a = gcry_sexp_cdr ( list );
701     b = gcry_sexp_car ( a );
702     gcry_sexp_release ( a );
703     return b;
704 }
705
706
707
708 static int
709 hextobyte( const byte *s )
710 {
711     int c=0;
712
713     if( *s >= '0' && *s <= '9' )
714         c = 16 * (*s - '0');
715     else if( *s >= 'A' && *s <= 'F' )
716         c = 16 * (10 + *s - 'A');
717     else if( *s >= 'a' && *s <= 'f' ) {
718         c = 16 * (10 + *s - 'a');
719     }
720     s++;
721     if( *s >= '0' && *s <= '9' )
722         c += *s - '0';
723     else if( *s >= 'A' && *s <= 'F' )
724         c += 10 + *s - 'A';
725     else if( *s >= 'a' && *s <= 'f' ) {
726         c += 10 + *s - 'a';
727     }
728     return c;
729 }
730
731 struct make_space_ctx {
732     GCRY_SEXP sexp;
733     size_t allocated;
734     byte *pos;
735 };
736
737 static void
738 make_space ( struct make_space_ctx *c, size_t n )
739 {
740     size_t used = c->pos - c->sexp->d;
741
742     if ( used + n + sizeof(DATALEN) + 1 >= c->allocated ) {
743         GCRY_SEXP newsexp;
744         byte *newhead;
745
746         c->allocated += 2*(n+sizeof(DATALEN)+1);
747         newsexp = gcry_xrealloc ( c->sexp, sizeof *newsexp + c->allocated - 1 );
748         newhead = newsexp->d;
749         c->pos = newhead + used;
750         c->sexp = newsexp;
751     }
752 }
753
754
755 /* Unquote STRING of LENGTH and store it into BUF.  The surrounding
756    quotes are must already be removed from STRING.  We assume that the
757    quoted string is syntacillay correct.  */
758 static size_t
759 unquote_string (const unsigned char *string, size_t length, unsigned char *buf)
760 {
761   int esc = 0;
762   const unsigned char *s = string;
763   unsigned char *d = buf;
764   size_t n = length;
765
766   for (; n; n--, s++)
767     {
768       if (esc)
769         {
770           switch (*s)
771             {
772             case 'b':  *d++ = '\b'; break;
773             case 't':  *d++ = '\t'; break;
774             case 'v':  *d++ = '\v'; break;
775             case 'n':  *d++ = '\n'; break;
776             case 'f':  *d++ = '\f'; break;
777             case 'r':  *d++ = '\r'; break;
778             case '"':  *d++ = '\"'; break;
779             case '\'': *d++ = '\''; break;
780             case '\\': *d++ = '\\'; break;
781
782             case '\r':  /* ignore CR[,LF] */
783               if (n>1 && s[1] == '\n')
784                 {
785                   s++; n--;
786                 }
787               esc = 0;
788               break;
789               
790             case '\n':  /* ignore LF[,CR] */
791               if (n>1 && s[1] == '\r')
792                 {
793                   s++; n--;
794                 }
795               break;
796
797             case 'x': /* hex value */
798               if (n>2 && hexdigitp (s+1) && hexdigitp (s+2))
799                 {
800                   s++; n--;
801                   *d++ = xtoi_2 (s);
802                   s++; n--;
803                 }
804               break;
805
806             default:
807               if (n>2 && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
808                 {
809                   *d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
810                   s += 2;
811                   n -= 2;
812                 }
813               break;
814             }
815           esc = 0;
816         }
817       else if( *s == '\\' )
818         esc = 1;
819       else
820         *d++ = *s;
821     } 
822
823   return d - buf;
824 }
825
826 /****************
827  * Scan the provided buffer and return the S expression in our internal
828  * format.  Returns a newly allocated expression.  If erroff is not NULL and
829  * a parsing error has occured, the offset into buffer will be returned.
830  * If ARGFLAG is true, the function supports some printf like
831  * expressions.
832  *  These are:
833  *      %m - MPI
834  *      %s - string (no autoswitch to secure allocation)
835  *      %d - integer stored as string (no autoswitch to secure allocation)
836  *  all other format elements are currently not defined and return an error.
837  *  this includes the "%%" sequence becauce the percent sign is not an
838  *  allowed character.
839  * FIXME: We should find a way to store the secure-MPIS not in the string
840  * but as reference to somewhere - this can help us to save huge amounts
841  * of secure memory.  The problem is, that if only one element is secure, all
842  * other elements are automagicaly copied to secure meory too, so the most
843  * common operation gcry_sexp_cdr_mpi() will always return a secure MPI
844  * regardless whether it is needed or not.
845  */
846 static int
847 sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff ,
848             const char *buffer, size_t length, va_list arg_ptr, int argflag )
849 {
850     static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz"
851                                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
852                                      "0123456789-./_:*+=";
853     const char *p;
854     size_t n;
855     const char *digptr=NULL;
856     const char *quoted=NULL;
857     const char *tokenp=NULL;
858     const char *hexfmt=NULL;
859     const char *base64=NULL;
860     const char *disphint=NULL;
861     const char *percent=NULL;
862     int hexcount=0;
863     int quoted_esc=0;
864     int datalen=0;
865     size_t dummy_erroff;
866
867     struct make_space_ctx c;
868
869     if( !erroff )
870         erroff = &dummy_erroff;
871
872     /* FIXME: replace all the returns by a jump to the leave label
873      * and invent better error codes. Make sure that everything is cleaned up*/
874   #define MAKE_SPACE(n)  do { make_space ( &c, (n) ); } while (0)
875   #define STORE_LEN(p,n) do {                                              \
876                             DATALEN ashort = (n);                          \
877                             memcpy ( (p), &ashort, sizeof(ashort) );       \
878                             (p) += sizeof (ashort);                        \
879                         } while (0)
880
881     /* We assume that the internal representation takes less memory
882      * than the provided one.  However, we add space for one extra datalen
883      * so that the code which does the ST_CLOSE can use MAKE_SPACE */
884     c.allocated = length + sizeof(DATALEN);
885     c.sexp = gcry_xmalloc ( sizeof *c.sexp + c.allocated - 1 );
886     c.pos = c.sexp->d;
887
888     for(p=buffer,n=length; n; p++, n-- ) {
889         if( tokenp && !hexfmt ) {
890             if( strchr( tokenchars, *p ) )
891                 continue;
892             datalen = p - tokenp;
893             MAKE_SPACE ( datalen );
894             *c.pos++ = ST_DATA;
895             STORE_LEN ( c.pos, datalen );
896             memcpy ( c.pos, tokenp, datalen );
897             c.pos += datalen;
898             tokenp = NULL;
899         }
900         if( quoted ) {
901             if( quoted_esc ) {
902                 switch( *p ) {
903                   case 'b': case 't': case 'v': case 'n': case 'f':
904                   case 'r': case '"': case '\'': case '\\':
905                     quoted_esc = 0;
906                     break;
907                   case '0': case '1': case '2': case '3': case '4':
908                   case '5': case '6': case '7':
909                     if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
910                                 && p[2] >= '0' && p[2] <= '7') ) {
911                         *erroff = p - buffer;
912                         return -6;   /* invalid octal value */
913                     }
914                     p += 2; n -= 2;
915                     quoted_esc = 0;
916                     break;
917                   case 'x':
918                     if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
919                         *erroff = p - buffer;
920                         return -6;   /* invalid hex value */
921                     }
922                     p += 2; n -= 2;
923                     quoted_esc = 0;
924                     break;
925                   case '\r':  /* ignore CR[,LF] */
926                     if( n && p[1] == '\n' ) {
927                         p++; n--;
928                     }
929                     quoted_esc = 0;
930                     break;
931                   case '\n':  /* ignore LF[,CR] */
932                     if( n && p[1] == '\r' ) {
933                         p++; n--;
934                     }
935                     quoted_esc = 0;
936                     break;
937                   default:
938                     *erroff = p - buffer;
939                     return -6;   /* invalid quoted string escape */
940                 }
941             }
942             else if( *p == '\\' )
943                 quoted_esc = 1;
944             else if( *p == '\"' ) {
945                 /* keep it easy - we know that the unquoted string will
946                    never be larger */
947                 char *save;
948                 size_t len;
949                 
950                 quoted++; /* skip leading quote */
951                 MAKE_SPACE (p - quoted);
952                 *c.pos++ = ST_DATA;
953                 save = c.pos;
954                 STORE_LEN (c.pos, 0); /* will be fixed up later */
955                 len = unquote_string (quoted, p - quoted, c.pos);
956                 c.pos += len;
957                 STORE_LEN (save, len);
958                 quoted = NULL;
959             }
960         }
961         else if( hexfmt ) {
962             if( isxdigit( *p ) )
963                 hexcount++;
964             else if( *p == '#' ) {
965                 if( (hexcount & 1) ) {
966                     *erroff = p - buffer;
967                     return OLDPARSECODE (ODD_HEX_NUMBERS);
968                 }
969
970                 datalen = hexcount/2;
971                 MAKE_SPACE (datalen);
972                 *c.pos++ = ST_DATA;
973                 STORE_LEN (c.pos, datalen);
974                 for( hexfmt++; hexfmt < p; hexfmt++ ) {
975                     if( isspace( *hexfmt ) )
976                         continue;
977                     *c.pos++ = hextobyte( hexfmt );
978                     hexfmt++;
979                 }
980                 hexfmt = NULL;
981             }
982             else if( !isspace( *p ) ) {
983                 *erroff = p - buffer;
984                 return OLDPARSECODE (BAD_HEX_CHAR);
985             }
986         }
987         else if( base64 ) {
988             if( *p == '|' )
989                base64 = NULL;
990         }
991         else if( digptr ) {
992             if( isdigit(*p) )
993                 ;
994             else if( *p == ':' ) {
995                 datalen = atoi( digptr ); /* fixme: check for overflow */
996                 digptr = NULL;
997                 if( datalen > n-1 ) {
998                     *erroff = p - buffer;
999                     return -2; /* buffer too short */
1000                 }
1001                 /* make a new list entry */
1002                 MAKE_SPACE (datalen);
1003                 *c.pos++ = ST_DATA;
1004                 STORE_LEN (c.pos, datalen);
1005                 memcpy (c.pos, p+1, datalen );
1006                 c.pos += datalen;
1007                 n -= datalen;
1008                 p += datalen;
1009             }
1010             else if( *p == '\"' ) {
1011                 digptr = NULL; /* we ignore the optional length */
1012                 quoted = p;
1013                 quoted_esc = 0;
1014             }
1015             else if( *p == '#' ) {
1016                 digptr = NULL; /* we ignore the optional length */
1017                 hexfmt = p;
1018                 hexcount = 0;
1019             }
1020             else if( *p == '|' ) {
1021                 digptr = NULL; /* we ignore the optional length */
1022                 base64 = p;
1023             }
1024             else {
1025                 *erroff = p - buffer;
1026                 return -1;
1027             }
1028         }
1029         else if ( percent ) {
1030             if ( *p == 'm' ) { /* insert an MPI */
1031                 GCRY_MPI m = va_arg (arg_ptr, GCRY_MPI);
1032                 size_t nm;
1033
1034                 if ( gcry_mpi_print( GCRYMPI_FMT_STD, NULL, &nm, m ) )
1035                     BUG ();
1036
1037                 MAKE_SPACE (nm);
1038                 if ( !gcry_is_secure ( c.sexp->d )
1039                      &&  gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE ) ) {
1040                     /* we have to switch to secure allocation */
1041                     GCRY_SEXP newsexp;
1042                     byte *newhead;
1043
1044                     newsexp = gcry_xmalloc_secure ( sizeof *newsexp
1045                                                    + c.allocated - 1 );
1046                     newhead = newsexp->d;
1047                     memcpy ( newhead, c.sexp->d, (c.pos - c.sexp->d) );
1048                     c.pos = newhead + ( c.pos - c.sexp->d );
1049                     gcry_free ( c.sexp );
1050                     c.sexp = newsexp;
1051                 }
1052
1053                 *c.pos++ = ST_DATA;
1054                 STORE_LEN (c.pos, nm);
1055                 if ( gcry_mpi_print( GCRYMPI_FMT_STD, c.pos, &nm, m ) )
1056                     BUG ();
1057                 c.pos += nm;
1058             }
1059             else if ( *p == 's' ) { /* insert an string */
1060                 const char *astr = va_arg (arg_ptr, const char *);
1061                 size_t alen = strlen ( astr );
1062
1063                 MAKE_SPACE (alen);
1064                 *c.pos++ = ST_DATA;
1065                 STORE_LEN (c.pos, alen);
1066                 memcpy ( c.pos, astr, alen );
1067                 c.pos += alen;
1068             }
1069             else if ( *p == 'd' ) { /* insert an integer as string */
1070                 int aint = va_arg (arg_ptr, int);
1071                 size_t alen;
1072                 char buf[20];
1073
1074                 sprintf ( buf, "%d", aint );
1075                 alen = strlen ( buf );
1076                 MAKE_SPACE (alen);
1077                 *c.pos++ = ST_DATA;
1078                 STORE_LEN (c.pos, alen);
1079                 memcpy ( c.pos, buf, alen );
1080                 c.pos += alen;
1081             }
1082             else {
1083                 *erroff = p - buffer;
1084                 return -1;  /* invalid format specifier */
1085             }
1086             percent = NULL;
1087         }
1088         else if( *p == '(' ) {
1089             if( disphint ) {
1090                 *erroff = p - buffer;
1091                 return -9; /* open display hint */
1092             }
1093             MAKE_SPACE (0);
1094             *c.pos++ = ST_OPEN;
1095         }
1096         else if( *p == ')' ) { /* walk up */
1097             if( disphint ) {
1098                 *erroff = p - buffer;
1099                 return -9; /* open display hint */
1100             }
1101             MAKE_SPACE (0);
1102             *c.pos++ = ST_CLOSE;
1103         }
1104         else if( *p == '\"' ) {
1105             quoted = p;
1106             quoted_esc = 0;
1107         }
1108         else if( *p == '#' ) {
1109             hexfmt = p;
1110             hexcount = 0;
1111         }
1112         else if( *p == '|' )
1113             base64 = p;
1114         else if( *p == '[' ) {
1115             if( disphint ) {
1116                 *erroff = p - buffer;
1117                 return -8; /* nested display hints */
1118             }
1119             disphint = p;
1120         }
1121         else if( *p == ']' ) {
1122             if( !disphint ) {
1123                 *erroff = p - buffer;
1124                 return -9; /* unmatched display hint close */
1125             }
1126             disphint = NULL;
1127         }
1128         else if( isdigit(*p) ) {
1129             if( *p == '0' ) { /* a length may not begin with zero */
1130                 *erroff = p - buffer;
1131                 return -7;
1132             }
1133             digptr = p;
1134         }
1135         else if( strchr( tokenchars, *p ) )
1136             tokenp = p;
1137         else if( isspace(*p) )
1138             ;
1139         else if( *p == '{' ) {
1140             /* fixme: handle rescanning:
1141              * we can do this by saving our current state
1142              * and start over at p+1 -- Hmmm. At this point here
1143              * we are in a well defined state, so we don't need to save
1144              * it.  Great.
1145              */
1146             *erroff = p - buffer;
1147             return -10; /* unexpected reserved punctuation */
1148         }
1149         else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
1150             *erroff = p - buffer;
1151             return -10; /* unexpected reserved punctuation */
1152         }
1153         else if( argflag && *p == '%' ) {
1154             percent = p;
1155         }
1156         else { /* bad or unavailable*/
1157             *erroff = p - buffer;
1158             return -5;
1159         }
1160
1161     }
1162     MAKE_SPACE (0);
1163     *c.pos++ = ST_STOP;
1164
1165     *retsexp = normalize ( c.sexp );
1166     return 0;
1167   #undef MAKE_SPACE
1168   #undef STORE_LEN
1169 }
1170
1171 int
1172 gcry_sexp_build( GCRY_SEXP *retsexp, size_t *erroff, const char *format, ... )
1173 {
1174     int rc;
1175     va_list arg_ptr ;
1176
1177     va_start( arg_ptr, format ) ;
1178     rc = sexp_sscan( retsexp, erroff, format, strlen(format), arg_ptr, 1 );
1179     va_end(arg_ptr);
1180
1181     return rc;
1182 }
1183
1184 int
1185 gcry_sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff,
1186                             const char *buffer, size_t length )
1187 {
1188   /* We don't need the va_list because it is controlled by the
1189      following flag, however we have to pass it but can't initialize
1190      it as there is no portable way to do so.  volatile is needed to
1191      suppress the compiler warning */
1192   volatile va_list dummy_arg_ptr;
1193
1194   return sexp_sscan( retsexp, erroff, buffer, length, dummy_arg_ptr, 0 );
1195 }
1196
1197 \f
1198 /* Figure out a suitable encoding for BUFFER of LENGTH.
1199    Returns: 0 = Binary
1200             1 = String possible
1201             2 = Token possible
1202 */
1203 static int
1204 suitable_encoding (const unsigned char *buffer, size_t length)
1205 {
1206   const unsigned char *s;
1207   int maybe_token = 1;
1208
1209   if (!length)
1210     return 1;
1211   
1212   for (s=buffer; length; s++, length--)
1213     {
1214       if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
1215            && !strchr ("\b\t\v\n\f\r\"\'\\", *s))
1216         return 0; /*binary*/
1217       if ( maybe_token
1218            && !alphap (s) && !digitp (s)  && !strchr (TOKEN_SPECIALS, *s))
1219         maybe_token = 0;
1220     }
1221   s = buffer;
1222   if ( maybe_token && !digitp (s) )
1223     return 2;
1224   return 1;
1225 }
1226
1227
1228 static int
1229 convert_to_hex (const unsigned char *src, size_t len, unsigned char *dest)
1230 {
1231   int i;
1232
1233   if (dest)
1234     {
1235       *dest++ = '#';
1236       for (i=0; i < len; i++, dest += 2 )
1237         sprintf (dest, "%02X", src[i]);
1238       *dest++ = '#';
1239     }
1240   return len*2+2;
1241 }
1242
1243 static int
1244 convert_to_string (const unsigned char *s, size_t len, unsigned char *dest)
1245 {
1246   if (dest)
1247     {
1248       unsigned char *p = dest;
1249       *p++ = '\"';
1250       for (; len; len--, s++ )
1251         {
1252           switch (*s)
1253             {
1254             case '\b': *p++ = '\\'; *p++ = 'b';  break;
1255             case '\t': *p++ = '\\'; *p++ = 't';  break;
1256             case '\v': *p++ = '\\'; *p++ = 'v';  break;
1257             case '\n': *p++ = '\\'; *p++ = 'n';  break;
1258             case '\f': *p++ = '\\'; *p++ = 'f';  break;
1259             case '\r': *p++ = '\\'; *p++ = 'r';  break;
1260             case '\"': *p++ = '\\'; *p++ = '\"';  break;
1261             case '\'': *p++ = '\\'; *p++ = '\'';  break;
1262             case '\\': *p++ = '\\'; *p++ = '\\';  break;
1263             default: 
1264               if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1265                 {
1266                   sprintf (p, "\\x%02x", *s); 
1267                   p += 4;
1268                 }
1269               else
1270                 *p++ = *s;
1271             }
1272         }
1273       *p++ = '\"';
1274       return p - dest;
1275     }
1276   else
1277     {
1278       int count = 2;
1279       for (; len; len--, s++ )
1280         {
1281           switch (*s)
1282             {
1283             case '\b': 
1284             case '\t': 
1285             case '\v': 
1286             case '\n': 
1287             case '\f': 
1288             case '\r': 
1289             case '\"':
1290             case '\'':
1291             case '\\': count += 2; break;
1292             default: 
1293               if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1294                 count += 4;
1295               else
1296                 count++;
1297             }
1298         }
1299       return count;
1300     }
1301 }
1302
1303
1304
1305 static int
1306 convert_to_token (const unsigned char *src, size_t len, unsigned char *dest)
1307 {
1308   if (dest)
1309     memcpy (dest, src, len);
1310   return len;
1311 }
1312
1313
1314 /****************
1315  * Print SEXP to buffer using the MODE.  Returns the length of the
1316  * SEXP in buffer or 0 if the buffer is too short (We have at least an
1317  * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
1318  * the required length is returned.
1319  */
1320 size_t
1321 gcry_sexp_sprint( const GCRY_SEXP list, int mode,
1322                                         char *buffer, size_t maxlength )
1323 {
1324   static byte empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
1325   const byte *s;
1326   char *d;
1327   DATALEN n;
1328   char numbuf[20];
1329   size_t len = 0;
1330   int i, indent = 0;
1331   
1332   s = list? list->d : empty;
1333   d = buffer;
1334   while ( *s != ST_STOP )
1335     {
1336       switch ( *s )
1337         {
1338         case ST_OPEN:
1339           s++;
1340           if ( mode != GCRYSEXP_FMT_CANON )
1341             {
1342               if (indent)
1343                 len++; 
1344               len += indent;
1345             }
1346           len++;
1347           if ( buffer ) 
1348             {
1349               if ( len >= maxlength )
1350                 return 0;
1351               if ( mode != GCRYSEXP_FMT_CANON )
1352                 {
1353                   if (indent)
1354                     *d++ = '\n'; 
1355                   for (i=0; i < indent; i++)
1356                     *d++ = ' ';
1357                 }
1358               *d++ = '(';
1359             }
1360           indent++;
1361           break;
1362         case ST_CLOSE:
1363           s++;
1364           len++;
1365           if ( buffer ) 
1366             {
1367               if ( len >= maxlength )
1368                 return 0;
1369               *d++ = ')';
1370             }
1371           indent--;
1372           if (*s != ST_OPEN && *s != ST_STOP && mode != GCRYSEXP_FMT_CANON)
1373             {
1374               len++;
1375               len += indent;
1376               if (buffer)
1377                 {
1378                   if (len >= maxlength)
1379                     return 0;
1380                   *d++ = '\n';
1381                   for (i=0; i < indent; i++)
1382                     *d++ = ' ';
1383                 }
1384             }
1385           break;
1386         case ST_DATA:
1387           s++;
1388           memcpy ( &n, s, sizeof n ); s += sizeof n;
1389           if (mode == GCRYSEXP_FMT_ADVANCED)
1390             {
1391               int type;
1392               size_t nn;
1393
1394               switch ( (type=suitable_encoding (s, n)))
1395                 {
1396                 case 1: nn = convert_to_string (s, n, NULL); break;
1397                 case 2: nn = convert_to_token (s, n, NULL); break;
1398                 default: nn = convert_to_hex (s, n, NULL); break;
1399                 }
1400               len += nn;
1401               if (buffer)
1402                 {
1403                   if (len >= maxlength)
1404                     return 0;
1405                   switch (type)
1406                     {
1407                     case 1: convert_to_string (s, n, d); break;
1408                     case 2: convert_to_token (s, n, d); break;
1409                     default: convert_to_hex (s, n, d); break;
1410                     }
1411                   d += nn;
1412                 }
1413               if (s[n] != ST_CLOSE)
1414                 {
1415                   len++;
1416                   if (buffer)
1417                     {
1418                       if (len >= maxlength)
1419                         return 0;
1420                       *d++ = ' ';
1421                     }
1422                 }
1423             }
1424           else
1425             {
1426               sprintf (numbuf, "%u:", (unsigned int)n );
1427               len += strlen (numbuf) + n;
1428               if ( buffer ) 
1429                 {
1430                   if ( len >= maxlength )
1431                     return 0;
1432                   d = stpcpy ( d, numbuf );
1433                   memcpy ( d, s, n ); d += n;
1434                 }
1435             }
1436           s += n;
1437           break;
1438         default:
1439           BUG ();
1440         }
1441     }
1442   if ( mode != GCRYSEXP_FMT_CANON )
1443     {
1444       len++;
1445       if (buffer)
1446         {
1447           if ( len >= maxlength )
1448             return 0;
1449           *d++ = '\n'; 
1450         }
1451     }
1452   if (buffer) 
1453     {
1454       if ( len >= maxlength )
1455         return 0;
1456       *d++ = 0; /* for convenience we make a C string */
1457     }
1458   else
1459     len++; /* we need one byte more for this */
1460
1461   return len;
1462 }
1463
1464
1465
1466
1467 /* Scan a cannocial encoded buffer with implicit length values and
1468    return the actual length this S-expression uses.  For a valid S-Exp
1469    it should never return 0.  If LENGTH is not zero, the maximum
1470    length to scan is given - this can be used for syntax checks of
1471    data passed from outside. errorcode and erroff may both be passed as
1472    NULL
1473
1474    Errorcodes (for historic reasons they are all negative):
1475     -1 := invalid length specification
1476     -2 := string too long 
1477     -3 := unmatched parenthesis
1478     -4 := not a (canonical) S-expression
1479     -5 := bad character 
1480     -6 := invalid hex octal value or bad quotation
1481     -7 := a length may not begin with zero 
1482     -8 := nested display hints 
1483     -9 := unmatched display hint close
1484    -10 := unexpected reserved punctuation          
1485
1486    Use this formula to convert the errorcodes:
1487    gcryerr = 200 - errcode;
1488  */
1489 size_t
1490 gcry_sexp_canon_len (const unsigned char *buffer, size_t length, 
1491                      size_t *erroff, int *errcode)
1492 {
1493   const unsigned char *p;
1494   const char *disphint=NULL;
1495   unsigned int datalen = 0;
1496   size_t dummy_erroff;
1497   int    dummy_errcode;
1498   size_t count = 0;
1499   int level = 0;
1500
1501   if (!erroff)
1502     erroff = &dummy_erroff;
1503   if (!errcode)
1504     errcode = &dummy_errcode;
1505
1506   *errcode = 0;
1507   *erroff = 0;
1508   if (!buffer)
1509     return 0;
1510   if (*buffer != '(')
1511     {
1512       *errcode = OLDPARSECODE (NOT_CANONICAL);
1513       return 0;
1514     }
1515
1516   for (p=buffer; ; p++, count++ )
1517     {
1518       if (length && count >= length)
1519         {
1520           *erroff = count;
1521           *errcode = OLDPARSECODE (STRING_TOO_LONG); 
1522           return 0;
1523         }
1524       
1525       if (datalen)
1526         {
1527           if (*p == ':')
1528             {
1529               if (length && (count+datalen) >= length)
1530                 {
1531                   *erroff = count;
1532                   *errcode = OLDPARSECODE (STRING_TOO_LONG);
1533                   return 0;
1534                 }
1535               count += datalen;
1536               p += datalen;
1537               datalen = 0;
1538             }
1539           else if (digitp(p))
1540             datalen = datalen*10 + atoi_1(p);
1541           else 
1542             {
1543               *erroff = count;
1544               *errcode = OLDPARSECODE (INV_LEN_SPEC);
1545               return 0;
1546             }
1547         }
1548       else if (*p == '(')
1549         {
1550           if (disphint)
1551             {
1552               *erroff = count;
1553               *errcode = OLDPARSECODE (UNMATCHED_DH);
1554               return 0;
1555             }
1556           level++;
1557         }
1558       else if (*p == ')')
1559         { /* walk up */
1560           if (!level)
1561             {
1562               *erroff = count;
1563               *errcode = OLDPARSECODE (UNMATCHED_PAREN);
1564               return 0;
1565             }
1566           if (disphint)
1567             {
1568               *erroff = count;
1569               *errcode = OLDPARSECODE (UNMATCHED_DH);
1570               return 0;
1571             }
1572           if (!--level)
1573             return ++count; /* ready */
1574         }
1575       else if (*p == '[')
1576         {
1577           if (disphint) 
1578             {
1579               *erroff = count;
1580               *errcode = OLDPARSECODE (NESTED_DH);
1581               return 0;
1582             }
1583           disphint = p;
1584         }
1585       else if (*p == ']')
1586         {
1587           if( !disphint ) 
1588             {
1589               *erroff = count;
1590               *errcode = OLDPARSECODE (UNMATCHED_DH);
1591               return 0;
1592             }
1593           disphint = NULL;
1594         }
1595       else if (digitp (p) )
1596         {
1597           if (*p == '0')
1598             { 
1599               *erroff = count;
1600               *errcode = OLDPARSECODE (ZERO_PREFIX);
1601               return 0;
1602             }
1603           datalen = atoi_1 (p);
1604         }
1605       else if (*p == '&' || *p == '\\')
1606         {
1607           *erroff = count;
1608           *errcode = OLDPARSECODE (UNEXPECTED_PUNC);
1609           return 0;
1610         }
1611       else
1612         { 
1613           *erroff = count;
1614           *errcode = OLDPARSECODE (BAD_CHARACTER);
1615           return 0;
1616         }
1617     }
1618 }