35ba0d7a6cc9a9163adcaf0fa272e85056f49272
[strongswan.git] / src / libstrongswan / utils / lexparser.c
1 /**
2 * @file lexparser.c
3 *
4 * @brief lexical parser for text-based configuration files
5 *
6 */
7
8 /*
9 * Copyright (C) 2001-2006 Andreas Steffen, Zuercher Hochschule Winterthur
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * RCSID $Id$
22 */
23
24 /* memrchr is a GNU extension */
25 #define _GNU_SOURCE
26 #include <string.h>
27
28 #include "lexparser.h"
29
30
31 /**
32 * eat whitespace
33 */
34 bool eat_whitespace(chunk_t *src)
35 {
36 while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
37 {
38 src->ptr++; src->len--;
39 }
40 return src->len > 0 && *src->ptr != '#';
41 }
42
43 /**
44 * compare string with chunk
45 */
46 bool match(const char *pattern, const chunk_t *ch)
47 {
48 return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
49 }
50
51 /**
52 * extracts a token ending with the first occurrence of a given termination symbol
53 */
54 bool extract_token(chunk_t *token, const char termination, chunk_t *src)
55 {
56 u_char *eot = memchr(src->ptr, termination, src->len);
57
58 /* initialize empty token */
59 *token = chunk_empty;
60
61 if (eot == NULL) /* termination symbol not found */
62 {
63 return FALSE;
64 }
65
66 /* extract token */
67 token->ptr = src->ptr;
68 token->len = (u_int)(eot - src->ptr);
69
70 /* advance src pointer after termination symbol */
71 src->ptr = eot + 1;
72 src->len -= (token->len + 1);
73
74 return TRUE;
75 }
76
77 /**
78 * extracts a token ending with the last occurrence of a given termination symbol
79 */
80 bool extract_last_token(chunk_t *token, const char termination, chunk_t *src)
81 {
82 u_char *eot = memrchr(src->ptr, termination, src->len);
83
84 /* initialize empty token */
85 *token = chunk_empty;
86
87 if (eot == NULL) /* termination symbol not found */
88 {
89 return FALSE;
90 }
91
92 /* extract token */
93 token->ptr = src->ptr;
94 token->len = (u_int)(eot - src->ptr);
95
96 /* advance src pointer after termination symbol */
97 src->ptr = eot + 1;
98 src->len -= (token->len + 1);
99
100 return TRUE;
101 }
102
103 /**
104 * fetches a new line terminated by \n or \r\n
105 */
106 bool fetchline(chunk_t *src, chunk_t *line)
107 {
108 if (src->len == 0) /* end of src reached */
109 return FALSE;
110
111 if (extract_token(line, '\n', src))
112 {
113 if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
114 line->len--; /* remove optional \r */
115 }
116 else /*last line ends without newline */
117 {
118 *line = *src;
119 src->ptr += src->len;
120 src->len = 0;
121 }
122 return TRUE;
123 }
124
125 err_t extract_value(chunk_t *value, chunk_t *line)
126 {
127 char delimiter = ' ';
128
129 if (!eat_whitespace(line))
130 {
131 *value = chunk_empty;
132 return NULL;
133 }
134 if (*line->ptr == '\'' || *line->ptr == '"')
135 {
136 delimiter = *line->ptr;
137 line->ptr++; line->len--;
138 }
139 if (!extract_token(value, delimiter, line))
140 {
141 if (delimiter == ' ')
142 {
143 *value = *line;
144 line->len = 0;
145 }
146 else
147 {
148 return "missing second delimiter";
149 }
150 }
151 return NULL;
152 }
153
154 /**
155 * extracts a parameter: value pair
156 */
157 err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line)
158 {
159 /* extract name */
160 if (!extract_token(name,':', line))
161 {
162 return "missing ':'";
163 }
164
165 /* extract value */
166 return extract_value(value, line);
167 }