008f3f14fa8073636e4e22d7691fcb1dd5dff42b
[platform/upstream/nettle.git] / tools / parse.c
1 /* parse.c
2
3    Copyright (C) 2002, 2003, 2008 Niels Möller
4
5    This file is part of GNU Nettle.
6
7    GNU Nettle is free software: you can redistribute it and/or
8    modify it under the terms of either:
9
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at your
12        option) any later version.
13
14    or
15
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at your
18        option) any later version.
19
20    or both in parallel, as here.
21
22    GNU Nettle is distributed in the hope that it will be useful,
23    but WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see http://www.gnu.org/licenses/.
30 */
31
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <assert.h>
37 #include <stdlib.h>
38
39 #include "parse.h"
40
41 #include "input.h"
42
43 void
44 sexp_compound_token_init(struct sexp_compound_token *token)
45 {
46   token->type = 0;
47   nettle_buffer_init(&token->display);
48   nettle_buffer_init(&token->string);
49 }
50
51 void
52 sexp_compound_token_clear(struct sexp_compound_token *token)
53 {
54   nettle_buffer_clear(&token->display);
55   nettle_buffer_clear(&token->string);
56 }
57
58 void
59 sexp_parse_init(struct sexp_parser *parser,
60                 struct sexp_input *input,
61                 enum sexp_mode mode)
62 {
63   parser->input = input;
64   parser->mode = mode;
65
66   /* Start counting with 1 for the top level, to make comparisons
67    * between transport and level simpler.
68    *
69    * FIXME: Is that trick ugly? */
70   parser->level = 1;
71   parser->transport = 0;
72 }
73
74 /* Get next token, and check that it is of the expected kind. */
75 static void
76 sexp_check_token(struct sexp_parser *parser,
77                  enum sexp_token token,
78                  struct nettle_buffer *string)
79 {
80   sexp_get_token(parser->input,
81                  parser->transport ? SEXP_CANONICAL : parser->mode,
82                  string);
83
84   if (parser->input->token != token)
85     die("Syntax error.\n");
86 }
87
88 /* Performs further processing of the input, in particular display
89  * types and transport decoding.
90  *
91  * This is complicated a little by the requirement that a
92  * transport-encoded block, {xxxxx}, must include exactly one
93  * expression. We check at the end of strings and list whether or not
94  * we should expect a SEXP_CODING_END as the next token. */
95 void
96 sexp_parse(struct sexp_parser *parser,
97            struct sexp_compound_token *token)
98 {
99   for (;;)
100     {
101       sexp_get_token(parser->input,
102                      parser->transport ? SEXP_CANONICAL : parser->mode,
103                      &token->string);
104
105       switch(parser->input->token)
106         {
107         case SEXP_LIST_END:
108           if (parser->level == parser->transport)
109             die("Unmatched end of list in transport encoded data.\n");
110           parser->level--;
111
112           if (!parser->level)
113             die("Unmatched end of list.\n");
114
115           token->type = SEXP_LIST_END;
116
117         check_transport_end:
118           if (parser->level == parser->transport)
119             {
120               sexp_check_token(parser, SEXP_CODING_END, &token->string);
121               assert(parser->transport);
122               assert(parser->level == parser->transport);
123
124               parser->level--;
125               parser->transport = 0;
126             }
127           return;
128     
129         case SEXP_EOF:
130           if (parser->level > 1)
131             die("Unexpected end of file.\n");
132
133           token->type = SEXP_EOF;
134           return;
135
136         case SEXP_LIST_START:
137           parser->level++;
138           token->type = SEXP_LIST_START;
139           return;
140
141         case SEXP_DISPLAY_START:
142           sexp_check_token(parser, SEXP_STRING, &token->display);
143           sexp_check_token(parser, SEXP_DISPLAY_END, &token->display);
144           sexp_check_token(parser, SEXP_STRING, &token->string);
145
146           token->type = SEXP_DISPLAY;
147           goto check_transport_end;
148
149         case SEXP_STRING:
150           token->type = SEXP_STRING;
151           goto check_transport_end;
152
153         case SEXP_COMMENT:
154           token->type = SEXP_COMMENT;
155           return;
156
157         case SEXP_TRANSPORT_START:
158           if (parser->mode == SEXP_CANONICAL)
159             die("Base64 not allowed in canonical mode.\n");
160           parser->level++;
161           parser->transport = parser->level;
162
163           continue;
164
165         case SEXP_CODING_END:
166           die("Unexpected end of transport encoding.\n");
167           
168         default:
169           /* Internal error. */
170           abort();
171         }
172     }
173 }