add a compatible memrchr() function if the platform does not support it (e.g. old...
[strongswan.git] / src / libstrongswan / utils / lexparser.c
1 /*
2 * Copyright (C) 2001-2006 Andreas Steffen
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 * $Id$
15 */
16
17 /* memrchr is a GNU extension */
18 #define _GNU_SOURCE
19 #include <string.h>
20
21 #include "lexparser.h"
22
23 #ifndef HAVE_MEMRCHR
24 void *memrchr(const void *s, int c, size_t n);
25 #endif
26
27 /**
28 * eat whitespace
29 */
30 bool eat_whitespace(chunk_t *src)
31 {
32 while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
33 {
34 src->ptr++; src->len--;
35 }
36 return src->len > 0 && *src->ptr != '#';
37 }
38
39 /**
40 * compare string with chunk
41 */
42 bool match(const char *pattern, const chunk_t *ch)
43 {
44 return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
45 }
46
47 /**
48 * extracts a token ending with the first occurrence of a given termination symbol
49 */
50 bool extract_token(chunk_t *token, const char termination, chunk_t *src)
51 {
52 u_char *eot = memchr(src->ptr, termination, src->len);
53
54 if (termination == ' ')
55 {
56 u_char *eot_tab = memchr(src->ptr, '\t', src->len);
57
58 /* check if a tab instead of a space terminates the token */
59 eot = ( eot_tab == NULL || (eot && eot < eot_tab) ) ? eot : eot_tab;
60 }
61
62 /* initialize empty token */
63 *token = chunk_empty;
64
65 if (eot == NULL) /* termination symbol not found */
66 {
67 return FALSE;
68 }
69
70 /* extract token */
71 token->ptr = src->ptr;
72 token->len = (u_int)(eot - src->ptr);
73
74 /* advance src pointer after termination symbol */
75 src->ptr = eot + 1;
76 src->len -= (token->len + 1);
77
78 return TRUE;
79 }
80
81 /**
82 * extracts a token ending with the first occurrence of a given null-terminated string
83 */
84 bool extract_token_str(chunk_t *token, const char *termination, chunk_t *src)
85 {
86 u_char *eot = memstr(src->ptr, termination, src->len);
87 size_t l = strlen(termination);
88
89 /* initialize empty token */
90 *token = chunk_empty;
91
92 if (eot == NULL) /* termination string not found */
93 {
94 return FALSE;
95 }
96
97 /* extract token */
98 token->ptr = src->ptr;
99 token->len = (u_int)(eot - src->ptr);
100
101 /* advance src pointer after termination string */
102 src->ptr = eot + l;
103 src->len -= (token->len + l);
104
105 return TRUE;
106 }
107
108 /**
109 * extracts a token ending with the last occurrence of a given termination symbol
110 */
111 bool extract_last_token(chunk_t *token, const char termination, chunk_t *src)
112 {
113 u_char *eot = memrchr(src->ptr, termination, src->len);
114
115 /* initialize empty token */
116 *token = chunk_empty;
117
118 if (eot == NULL) /* termination symbol not found */
119 {
120 return FALSE;
121 }
122
123 /* extract token */
124 token->ptr = src->ptr;
125 token->len = (u_int)(eot - src->ptr);
126
127 /* advance src pointer after termination symbol */
128 src->ptr = eot + 1;
129 src->len -= (token->len + 1);
130
131 return TRUE;
132 }
133
134 /**
135 * fetches a new line terminated by \n or \r\n
136 */
137 bool fetchline(chunk_t *src, chunk_t *line)
138 {
139 if (src->len == 0) /* end of src reached */
140 return FALSE;
141
142 if (extract_token(line, '\n', src))
143 {
144 if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
145 line->len--; /* remove optional \r */
146 }
147 else /*last line ends without newline */
148 {
149 *line = *src;
150 src->ptr += src->len;
151 src->len = 0;
152 }
153 return TRUE;
154 }
155
156 err_t extract_value(chunk_t *value, chunk_t *line)
157 {
158 char delimiter = ' ';
159
160 if (!eat_whitespace(line))
161 {
162 *value = chunk_empty;
163 return NULL;
164 }
165 if (*line->ptr == '\'' || *line->ptr == '"')
166 {
167 delimiter = *line->ptr;
168 line->ptr++; line->len--;
169 }
170 if (!extract_token(value, delimiter, line))
171 {
172 if (delimiter == ' ')
173 {
174 *value = *line;
175 line->len = 0;
176 }
177 else
178 {
179 return "missing second delimiter";
180 }
181 }
182 return NULL;
183 }
184
185 /**
186 * extracts a parameter: value pair
187 */
188 err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line)
189 {
190 /* extract name */
191 if (!extract_token(name,':', line))
192 {
193 return "missing ':'";
194 }
195
196 /* extract value */
197 return extract_value(value, line);
198 }