]> git.ipfire.org Git - thirdparty/strongswan.git/blame - programs/pluto/lex.c
- import of strongswan-2.7.0
[thirdparty/strongswan.git] / programs / pluto / lex.c
CommitLineData
997358a6
MW
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
33struct 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 */
39bool
40lexopen(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
67void
68lexclose(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
84char *tok;
85#define tokeq(s) (streq(tok, (s)))
86#define tokeqword(s) (strcasecmp(tok, (s)) == 0)
87
88bool
89shift(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
199bool
200flushline(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}