summaryrefslogtreecommitdiffstats
path: root/lib/isc/include/isc/lex.h
blob: 14b29cf94d977fd884c750f9a14e9ff4d9321904 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
/*
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 *
 * SPDX-License-Identifier: MPL-2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
 */

#pragma once

/*****
***** Module Info
*****/

/*! \file isc/lex.h
 * \brief The "lex" module provides a lightweight tokenizer.  It can operate
 * on files or buffers, and can handle "include".  It is designed for
 * parsing of DNS master files and the BIND configuration file, but
 * should be general enough to tokenize other things, e.g. HTTP.
 *
 * \li MP:
 *	No synchronization is provided.  Clients must ensure exclusive
 *	access.
 *
 * \li Reliability:
 *	No anticipated impact.
 *
 * \li Resources:
 *	TBS
 *
 * \li Security:
 *	No anticipated impact.
 *
 * \li Standards:
 * 	None.
 */

/***
 *** Imports
 ***/

#include <stdbool.h>
#include <stdio.h>

#include <isc/lang.h>
#include <isc/region.h>
#include <isc/types.h>

ISC_LANG_BEGINDECLS

/***
 *** Options
 ***/

/*@{*/
/*!
 * Various options for isc_lex_gettoken().
 */

#define ISC_LEXOPT_EOL	     0x0001 /*%< Want end-of-line token. */
#define ISC_LEXOPT_EOF	     0x0002 /*%< Want end-of-file token. */
#define ISC_LEXOPT_INITIALWS 0x0004 /*%< Want initial whitespace. */
#define ISC_LEXOPT_NUMBER    0x0008 /*%< Recognize numbers. */
#define ISC_LEXOPT_QSTRING   0x0010 /*%< Recognize qstrings. */
/*@}*/

/*@{*/
/*!
 * The ISC_LEXOPT_DNSMULTILINE option handles the processing of '(' and ')' in
 * the DNS master file format.  If this option is set, then the
 * ISC_LEXOPT_INITIALWS and ISC_LEXOPT_EOL options will be ignored when
 * the paren count is > 0.  To use this option, '(' and ')' must be special
 * characters.
 */
#define ISC_LEXOPT_DNSMULTILINE 0x0020 /*%< Handle '(' and ')'. */
#define ISC_LEXOPT_NOMORE	0x0040 /*%< Want "no more" token. */

#define ISC_LEXOPT_CNUMBER	    0x0080 /*%< Recognize octal and hex. */
#define ISC_LEXOPT_ESCAPE	    0x0100 /*%< Recognize escapes. */
#define ISC_LEXOPT_QSTRINGMULTILINE 0x0200 /*%< Allow multiline "" strings */
#define ISC_LEXOPT_OCTAL	    0x0400 /*%< Expect a octal number. */
#define ISC_LEXOPT_BTEXT	    0x0800 /*%< Bracketed text. */
#define ISC_LEXOPT_VPAIR	    0x1000 /*%< Recognize value pair. */
#define ISC_LEXOPT_QVPAIR	    0x2000 /*%< Recognize quoted value pair. */
/*@}*/
/*@{*/
/*!
 * Various commenting styles, which may be changed at any time with
 * isc_lex_setcomments().
 */

#define ISC_LEXCOMMENT_C	     0x01
#define ISC_LEXCOMMENT_CPLUSPLUS     0x02
#define ISC_LEXCOMMENT_SHELL	     0x04
#define ISC_LEXCOMMENT_DNSMASTERFILE 0x08
/*@}*/

/***
 *** Types
 ***/

/*! Lex */

typedef char isc_lexspecials_t[256];

/* Tokens */

typedef enum {
	isc_tokentype_unknown = 0,
	isc_tokentype_string = 1,
	isc_tokentype_number = 2,
	isc_tokentype_qstring = 3,
	isc_tokentype_eol = 4,
	isc_tokentype_eof = 5,
	isc_tokentype_initialws = 6,
	isc_tokentype_special = 7,
	isc_tokentype_nomore = 8,
	isc_tokentype_btext = 9,
	isc_tokentype_vpair = 10,
	isc_tokentype_qvpair = 11,
} isc_tokentype_t;

typedef union {
	char		 as_char;
	unsigned long	 as_ulong;
	isc_region_t	 as_region;
	isc_textregion_t as_textregion;
	void		*as_pointer;
} isc_tokenvalue_t;

typedef struct isc_token {
	isc_tokentype_t	 type;
	isc_tokenvalue_t value;
} isc_token_t;

/***
 *** Functions
 ***/

isc_result_t
isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp);
/*%<
 * Create a lexer.
 *
 * 'max_token' is a hint of the number of bytes in the largest token.
 *
 * Requires:
 *\li	'*lexp' is a valid lexer.
 *
 * Ensures:
 *\li	On success, *lexp is attached to the newly created lexer.
 *
 * Returns:
 *\li	#ISC_R_SUCCESS
 *\li	#ISC_R_NOMEMORY
 */

void
isc_lex_destroy(isc_lex_t **lexp);
/*%<
 * Destroy the lexer.
 *
 * Requires:
 *\li	'*lexp' is a valid lexer.
 *
 * Ensures:
 *\li	*lexp == NULL
 */

unsigned int
isc_lex_getcomments(isc_lex_t *lex);
/*%<
 * Return the current lexer commenting styles.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 * Returns:
 *\li	The commenting styles which are currently allowed.
 */

void
isc_lex_setcomments(isc_lex_t *lex, unsigned int comments);
/*%<
 * Set allowed lexer commenting styles.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'comments' has meaningful values.
 */

void
isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials);
/*%<
 * Put the current list of specials into 'specials'.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 */

void
isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials);
/*!<
 * The characters in 'specials' are returned as tokens.  Along with
 * whitespace, they delimit strings and numbers.
 *
 * Note:
 *\li	Comment processing takes precedence over special character
 *	recognition.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 */

isc_result_t
isc_lex_openfile(isc_lex_t *lex, const char *filename);
/*%<
 * Open 'filename' and make it the current input source for 'lex'.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	filename is a valid C string.
 *
 * Returns:
 *\li	#ISC_R_SUCCESS
 *\li	#ISC_R_NOMEMORY			Out of memory
 *\li	#ISC_R_NOTFOUND			File not found
 *\li	#ISC_R_NOPERM			No permission to open file
 *\li	#ISC_R_FAILURE			Couldn't open file, not sure why
 *\li	#ISC_R_UNEXPECTED
 */

isc_result_t
isc_lex_openstream(isc_lex_t *lex, FILE *stream);
/*%<
 * Make 'stream' the current input source for 'lex'.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'stream' is a valid C stream.
 *
 * Returns:
 *\li	#ISC_R_SUCCESS
 *\li	#ISC_R_NOMEMORY			Out of memory
 */

isc_result_t
isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer);
/*%<
 * Make 'buffer' the current input source for 'lex'.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'buffer' is a valid buffer.
 *
 * Returns:
 *\li	#ISC_R_SUCCESS
 *\li	#ISC_R_NOMEMORY			Out of memory
 */

isc_result_t
isc_lex_close(isc_lex_t *lex);
/*%<
 * Close the most recently opened object (i.e. file or buffer).
 *
 * Returns:
 *\li	#ISC_R_SUCCESS
 *\li	#ISC_R_NOMORE			No more input sources
 */

isc_result_t
isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp);
/*%<
 * Get the next token.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'lex' has an input source.
 *
 *\li	'options' contains valid options.
 *
 *\li	'*tokenp' is a valid pointer.
 *
 * Returns:
 *\li	#ISC_R_SUCCESS
 *\li	#ISC_R_UNEXPECTEDEND
 *\li	#ISC_R_NOMEMORY
 *
 *	These two results are returned only if their corresponding lexer
 *	options are not set.
 *
 *\li	#ISC_R_EOF			End of input source
 *\li	#ISC_R_NOMORE			No more input sources
 */

isc_result_t
isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
		       isc_tokentype_t expect, bool eol);
/*%<
 * Get the next token from a DNS master file type stream.  This is a
 * convenience function that sets appropriate options and handles quoted
 * strings and end of line correctly for master files.  It also ungets
 * unexpected tokens.  If `eol` is set then expect end-of-line otherwise
 * eol is a error.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'token' is a valid pointer
 *
 * Returns:
 *
 * \li	any return code from isc_lex_gettoken().
 */

isc_result_t
isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, bool eol);
/*%<
 * Get the next token from a DNS master file type stream.  This is a
 * convenience function that sets appropriate options and handles end
 * of line correctly for master files.  It also ungets unexpected tokens.
 * If `eol` is set then expect end-of-line otherwise eol is a error.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'token' is a valid pointer
 *
 * Returns:
 *
 * \li	any return code from isc_lex_gettoken().
 */

void
isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp);
/*%<
 * Unget the current token.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'lex' has an input source.
 *
 *\li	'tokenp' points to a valid token.
 *
 *\li	There is no ungotten token already.
 */

void
isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r);
/*%<
 * Returns a region containing the text of the last token returned.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 *\li	'lex' has an input source.
 *
 *\li	'tokenp' points to a valid token.
 *
 *\li	A token has been gotten and not ungotten.
 */

char *
isc_lex_getsourcename(isc_lex_t *lex);
/*%<
 * Return the input source name.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 * Returns:
 * \li	source name or NULL if no current source.
 *\li	result valid while current input source exists.
 */

unsigned long
isc_lex_getsourceline(isc_lex_t *lex);
/*%<
 * Return the input source line number.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 * Returns:
 *\li 	Current line number or 0 if no current source.
 */

isc_result_t
isc_lex_setsourcename(isc_lex_t *lex, const char *name);
/*%<
 * Assigns a new name to the input source.
 *
 * Requires:
 *
 * \li	'lex' is a valid lexer.
 *
 * Returns:
 * \li	#ISC_R_SUCCESS
 * \li	#ISC_R_NOMEMORY
 * \li	#ISC_R_NOTFOUND - there are no sources.
 */

isc_result_t
isc_lex_setsourceline(isc_lex_t *lex, unsigned long line);
/*%<
 * Assigns a new line number to the input source. This can be used
 * when parsing a buffer that's been excerpted from the middle a file,
 * allowing logged messages to display the correct line number,
 * rather than the line number within the buffer.
 *
 * Requires:
 *
 * \li	'lex' is a valid lexer.
 *
 * Returns:
 * \li	#ISC_R_SUCCESS
 * \li	#ISC_R_NOTFOUND - there are no sources.
 */

bool
isc_lex_isfile(isc_lex_t *lex);
/*%<
 * Return whether the current input source is a file.
 *
 * Requires:
 *\li	'lex' is a valid lexer.
 *
 * Returns:
 * \li	#true if the current input is a file,
 *\li	#false otherwise.
 */

ISC_LANG_ENDDECLS