]> git.ipfire.org Git - thirdparty/strongswan.git/blob - programs/pluto/lex.c
- import of strongswan-2.7.0
[thirdparty/strongswan.git] / programs / pluto / lex.c
1 /* lexer (lexical analyzer) for control files
2 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * RCSID $Id: lex.c,v 1.1 2004/03/15 20:35:28 as Exp $
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 #include <freeswan.h>
26
27 #include "constants.h"
28 #include "defs.h"
29 #include "log.h"
30 #include "whack.h" /* for RC_LOG_SERIOUS */
31 #include "lex.h"
32
33 struct file_lex_position *flp = NULL;
34
35 /* Open a file for lexical processing.
36 * new_flp and name must point into storage with will live
37 * at least until the file is closed.
38 */
39 bool
40 lexopen(struct file_lex_position *new_flp, const char *name, bool optional)
41 {
42 FILE *f = fopen(name, "r");
43
44 if (f == NULL)
45 {
46 if (!optional || errno != ENOENT)
47 log_errno((e, "could not open \"%s\"", name));
48 return FALSE;
49 }
50 else
51 {
52 new_flp->previous = flp;
53 flp = new_flp;
54 flp->filename = name;
55 flp->fp = f;
56 flp->lino = 0;
57 flp->bdry = B_none;
58
59 flp->cur = flp->buffer; /* nothing loaded yet */
60 flp->under = *flp->cur = '\0';
61
62 (void) shift(); /* prime tok */
63 return TRUE;
64 }
65 }
66
67 void
68 lexclose(void)
69 {
70 fclose(flp->fp);
71 flp = flp->previous;
72 }
73
74 /* Token decoding: shift() loads the next token into tok.
75 * Iff a token starts at the left margin, it is considered
76 * to be the first in a record. We create a special condition,
77 * Record Boundary (analogous to EOF), just before such a token.
78 * We are unwilling to shift through a record boundary:
79 * it must be overridden first.
80 * Returns FALSE iff Record Boundary or EOF (i.e. no token);
81 * tok will then be NULL.
82 */
83
84 char *tok;
85 #define tokeq(s) (streq(tok, (s)))
86 #define tokeqword(s) (strcasecmp(tok, (s)) == 0)
87
88 bool
89 shift(void)
90 {
91 char *p = flp->cur;
92 char *sor = NULL; /* start of record for any new lines */
93
94 passert(flp->bdry == B_none);
95
96 *p = flp->under;
97 flp->under = '\0';
98
99 for (;;)
100 {
101 switch (*p)
102 {
103 case '\0': /* end of line */
104 case '#': /* comment to end of line: treat as end of line */
105 /* get the next line */
106 if (fgets(flp->buffer, sizeof(flp->buffer)-1, flp->fp) == NULL)
107 {
108 flp->bdry = B_file;
109 tok = flp->cur = NULL;
110 return FALSE;
111 }
112 else
113 {
114 /* strip trailing whitespace, including \n */
115
116 for (p = flp->buffer+strlen(flp->buffer)-1
117 ; p>flp->buffer && isspace(p[-1]); p--)
118 ;
119 *p = '\0';
120
121 flp->lino++;
122 sor = p = flp->buffer;
123 }
124 break; /* try again for a token */
125
126 case ' ': /* whitespace */
127 case '\t':
128 p++;
129 break; /* try again for a token */
130
131 case '"': /* quoted token */
132 case '\'':
133 if (p != sor)
134 {
135 /* we have a quoted token: note and advance to its end */
136 tok = p;
137 p = strchr(p+1, *p);
138 if (p == NULL)
139 {
140 loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unterminated string"
141 , flp->filename, flp->lino);
142 p = tok + strlen(tok);
143 }
144 else
145 {
146 p++; /* include delimiter in token */
147 }
148
149 /* remember token delimiter and replace with '\0' */
150 flp->under = *p;
151 *p = '\0';
152 flp->cur = p;
153 return TRUE;
154 }
155 /* FALL THROUGH */
156 default:
157 if (p != sor)
158 {
159 /* we seem to have a token: note and advance to its end */
160 tok = p;
161
162 if (p[0] == '0' && p[1] == 't')
163 {
164 /* 0t... token goes to end of line */
165 p += strlen(p);
166 }
167 else
168 {
169 /* "ordinary" token: up to whitespace or end of line */
170 do {
171 p++;
172 } while (*p != '\0' && !isspace(*p))
173 ;
174
175 /* fudge to separate ':' from a preceding adjacent token */
176 if (p-1 > tok && p[-1] == ':')
177 p--;
178 }
179
180 /* remember token delimiter and replace with '\0' */
181 flp->under = *p;
182 *p = '\0';
183 flp->cur = p;
184 return TRUE;
185 }
186
187 /* we have a start-of-record: return it, deferring "real" token */
188 flp->bdry = B_record;
189 tok = NULL;
190 flp->under = *p;
191 flp->cur = p;
192 return FALSE;
193 }
194 }
195 }
196
197 /* ensures we are at a Record (or File) boundary, optionally warning if not */
198
199 bool
200 flushline(const char *m)
201 {
202 if (flp->bdry != B_none)
203 {
204 return TRUE;
205 }
206 else
207 {
208 if (m != NULL)
209 loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s", flp->filename, flp->lino, m);
210 do ; while (shift());
211 return FALSE;
212 }
213 }