Coverage Report

Created: 2022-03-10 07:56

/src/bind9/lib/isc/lex.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <ctype.h>
17
#include <errno.h>
18
#include <inttypes.h>
19
#include <stdbool.h>
20
#include <stdlib.h>
21
22
#include <isc/buffer.h>
23
#include <isc/file.h>
24
#include <isc/lex.h>
25
#include <isc/mem.h>
26
#include <isc/parseint.h>
27
#include <isc/print.h>
28
#include <isc/stdio.h>
29
#include <isc/string.h>
30
#include <isc/util.h>
31
32
#include "errno2result.h"
33
34
typedef struct inputsource {
35
  isc_result_t result;
36
  bool is_file;
37
  bool need_close;
38
  bool at_eof;
39
  bool last_was_eol;
40
  isc_buffer_t *pushback;
41
  unsigned int ignored;
42
  void *input;
43
  char *name;
44
  unsigned long line;
45
  unsigned long saved_line;
46
  ISC_LINK(struct inputsource) link;
47
} inputsource;
48
49
24.9k
#define LEX_MAGIC    ISC_MAGIC('L', 'e', 'x', '!')
50
#define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)
51
52
struct isc_lex {
53
  /* Unlocked. */
54
  unsigned int magic;
55
  isc_mem_t *mctx;
56
  size_t max_token;
57
  char *data;
58
  unsigned int comments;
59
  bool comment_ok;
60
  bool last_was_eol;
61
  unsigned int brace_count;
62
  unsigned int paren_count;
63
  unsigned int saved_paren_count;
64
  isc_lexspecials_t specials;
65
  LIST(struct inputsource) sources;
66
};
67
68
static inline isc_result_t
69
6.74k
grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
70
6.74k
  char *tmp;
71
72
6.74k
  tmp = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
73
6.74k
  memmove(tmp, lex->data, lex->max_token + 1);
74
6.74k
  *currp = tmp + (*currp - lex->data);
75
6.74k
  if (*prevp != NULL) {
76
404
    *prevp = tmp + (*prevp - lex->data);
77
404
  }
78
6.74k
  isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
79
6.74k
  lex->data = tmp;
80
6.74k
  *remainingp += lex->max_token;
81
6.74k
  lex->max_token *= 2;
82
6.74k
  return (ISC_R_SUCCESS);
83
6.74k
}
84
85
isc_result_t
86
24.9k
isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
87
24.9k
  isc_lex_t *lex;
88
89
  /*
90
   * Create a lexer.
91
   */
92
24.9k
  REQUIRE(lexp != NULL && *lexp == NULL);
93
94
24.9k
  if (max_token == 0U) {
95
0
    max_token = 1;
96
0
  }
97
98
24.9k
  lex = isc_mem_get(mctx, sizeof(*lex));
99
24.9k
  lex->data = isc_mem_get(mctx, max_token + 1);
100
24.9k
  lex->mctx = mctx;
101
24.9k
  lex->max_token = max_token;
102
24.9k
  lex->comments = 0;
103
24.9k
  lex->comment_ok = true;
104
24.9k
  lex->last_was_eol = true;
105
24.9k
  lex->brace_count = 0;
106
24.9k
  lex->paren_count = 0;
107
24.9k
  lex->saved_paren_count = 0;
108
24.9k
  memset(lex->specials, 0, 256);
109
24.9k
  INIT_LIST(lex->sources);
110
24.9k
  lex->magic = LEX_MAGIC;
111
112
24.9k
  *lexp = lex;
113
114
24.9k
  return (ISC_R_SUCCESS);
115
24.9k
}
116
117
void
118
24.9k
isc_lex_destroy(isc_lex_t **lexp) {
119
24.9k
  isc_lex_t *lex;
120
121
  /*
122
   * Destroy the lexer.
123
   */
124
125
24.9k
  REQUIRE(lexp != NULL);
126
0
  lex = *lexp;
127
24.9k
  *lexp = NULL;
128
24.9k
  REQUIRE(VALID_LEX(lex));
129
130
34.5k
  while (!EMPTY(lex->sources)) {
131
9.67k
    RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
132
9.67k
  }
133
24.9k
  if (lex->data != NULL) {
134
24.9k
    isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
135
24.9k
  }
136
24.9k
  lex->magic = 0;
137
24.9k
  isc_mem_put(lex->mctx, lex, sizeof(*lex));
138
24.9k
}
139
140
unsigned int
141
0
isc_lex_getcomments(isc_lex_t *lex) {
142
  /*
143
   * Return the current lexer commenting styles.
144
   */
145
146
0
  REQUIRE(VALID_LEX(lex));
147
148
0
  return (lex->comments);
149
0
}
150
151
void
152
24.9k
isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
153
  /*
154
   * Set allowed lexer commenting styles.
155
   */
156
157
24.9k
  REQUIRE(VALID_LEX(lex));
158
159
0
  lex->comments = comments;
160
24.9k
}
161
162
void
163
0
isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
164
  /*
165
   * Put the current list of specials into 'specials'.
166
   */
167
168
0
  REQUIRE(VALID_LEX(lex));
169
170
0
  memmove(specials, lex->specials, 256);
171
0
}
172
173
void
174
24.9k
isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
175
  /*
176
   * The characters in 'specials' are returned as tokens.  Along with
177
   * whitespace, they delimit strings and numbers.
178
   */
179
180
24.9k
  REQUIRE(VALID_LEX(lex));
181
182
0
  memmove(lex->specials, specials, 256);
183
24.9k
}
184
185
static inline isc_result_t
186
new_source(isc_lex_t *lex, bool is_file, bool need_close, void *input,
187
2.70M
     const char *name) {
188
2.70M
  inputsource *source;
189
190
2.70M
  source = isc_mem_get(lex->mctx, sizeof(*source));
191
2.70M
  source->result = ISC_R_SUCCESS;
192
2.70M
  source->is_file = is_file;
193
2.70M
  source->need_close = need_close;
194
2.70M
  source->at_eof = false;
195
2.70M
  source->last_was_eol = lex->last_was_eol;
196
2.70M
  source->input = input;
197
2.70M
  source->name = isc_mem_strdup(lex->mctx, name);
198
2.70M
  source->pushback = NULL;
199
2.70M
  isc_buffer_allocate(lex->mctx, &source->pushback,
200
2.70M
          (unsigned int)lex->max_token);
201
2.70M
  source->ignored = 0;
202
2.70M
  source->line = 1;
203
2.70M
  ISC_LIST_INITANDPREPEND(lex->sources, source, link);
204
205
2.70M
  return (ISC_R_SUCCESS);
206
2.70M
}
207
208
isc_result_t
209
11
isc_lex_openfile(isc_lex_t *lex, const char *filename) {
210
11
  isc_result_t result;
211
11
  FILE *stream = NULL;
212
213
  /*
214
   * Open 'filename' and make it the current input source for 'lex'.
215
   */
216
217
11
  REQUIRE(VALID_LEX(lex));
218
219
0
  result = isc_stdio_open(filename, "r", &stream);
220
11
  if (result != ISC_R_SUCCESS) {
221
10
    return (result);
222
10
  }
223
224
1
  result = new_source(lex, true, true, stream, filename);
225
1
  if (result != ISC_R_SUCCESS) {
226
0
    (void)fclose(stream);
227
0
  }
228
1
  return (result);
229
11
}
230
231
isc_result_t
232
0
isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
233
0
  char name[128];
234
235
  /*
236
   * Make 'stream' the current input source for 'lex'.
237
   */
238
239
0
  REQUIRE(VALID_LEX(lex));
240
241
0
  snprintf(name, sizeof(name), "stream-%p", stream);
242
243
0
  return (new_source(lex, true, false, stream, name));
244
0
}
245
246
isc_result_t
247
2.70M
isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
248
2.70M
  char name[128];
249
250
  /*
251
   * Make 'buffer' the current input source for 'lex'.
252
   */
253
254
2.70M
  REQUIRE(VALID_LEX(lex));
255
256
0
  snprintf(name, sizeof(name), "buffer-%p", buffer);
257
258
2.70M
  return (new_source(lex, false, false, buffer, name));
259
2.70M
}
260
261
isc_result_t
262
2.69M
isc_lex_close(isc_lex_t *lex) {
263
2.69M
  inputsource *source;
264
265
  /*
266
   * Close the most recently opened object (i.e. file or buffer).
267
   */
268
269
2.69M
  REQUIRE(VALID_LEX(lex));
270
271
2.69M
  source = HEAD(lex->sources);
272
2.69M
  if (source == NULL) {
273
0
    return (ISC_R_NOMORE);
274
0
  }
275
276
2.69M
  ISC_LIST_UNLINK(lex->sources, source, link);
277
0
  lex->last_was_eol = source->last_was_eol;
278
2.69M
  if (source->is_file) {
279
1
    if (source->need_close) {
280
1
      (void)fclose((FILE *)(source->input));
281
1
    }
282
1
  }
283
2.69M
  isc_mem_free(lex->mctx, source->name);
284
2.69M
  isc_buffer_free(&source->pushback);
285
2.69M
  isc_mem_put(lex->mctx, source, sizeof(*source));
286
287
2.69M
  return (ISC_R_SUCCESS);
288
2.69M
}
289
290
typedef enum {
291
  lexstate_start,
292
  lexstate_crlf,
293
  lexstate_string,
294
  lexstate_number,
295
  lexstate_maybecomment,
296
  lexstate_ccomment,
297
  lexstate_ccommentend,
298
  lexstate_eatline,
299
  lexstate_qstring,
300
  lexstate_btext,
301
  lexstate_vpair,
302
  lexstate_vpairstart,
303
  lexstate_qvpair,
304
} lexstate;
305
306
1.87M
#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
307
308
static void
309
8.99M
pushback(inputsource *source, int c) {
310
8.99M
  REQUIRE(source->pushback->current > 0);
311
8.99M
  if (c == EOF) {
312
5.31M
    source->at_eof = false;
313
5.31M
    return;
314
5.31M
  }
315
3.67M
  source->pushback->current--;
316
3.67M
  if (c == '\n') {
317
597k
    source->line--;
318
597k
  }
319
3.67M
}
320
321
static isc_result_t
322
189M
pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
323
189M
  if (isc_buffer_availablelength(source->pushback) == 0) {
324
6.88k
    isc_buffer_t *tbuf = NULL;
325
6.88k
    unsigned int oldlen;
326
6.88k
    isc_region_t used;
327
6.88k
    isc_result_t result;
328
329
6.88k
    oldlen = isc_buffer_length(source->pushback);
330
6.88k
    isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
331
6.88k
    isc_buffer_usedregion(source->pushback, &used);
332
6.88k
    result = isc_buffer_copyregion(tbuf, &used);
333
6.88k
    INSIST(result == ISC_R_SUCCESS);
334
0
    tbuf->current = source->pushback->current;
335
6.88k
    isc_buffer_free(&source->pushback);
336
6.88k
    source->pushback = tbuf;
337
6.88k
  }
338
189M
  isc_buffer_putuint8(source->pushback, (uint8_t)c);
339
0
  return (ISC_R_SUCCESS);
340
189M
}
341
342
isc_result_t
343
13.6M
isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
344
13.6M
  inputsource *source;
345
13.6M
  int c;
346
13.6M
  bool done = false;
347
13.6M
  bool no_comments = false;
348
13.6M
  bool escaped = false;
349
13.6M
  lexstate state = lexstate_start;
350
13.6M
  lexstate saved_state = lexstate_start;
351
13.6M
  isc_buffer_t *buffer;
352
13.6M
  FILE *stream;
353
13.6M
  char *curr, *prev;
354
13.6M
  size_t remaining;
355
13.6M
  uint32_t as_ulong;
356
13.6M
  unsigned int saved_options;
357
13.6M
  isc_result_t result;
358
359
  /*
360
   * Get the next token.
361
   */
362
363
13.6M
  REQUIRE(VALID_LEX(lex));
364
13.6M
  source = HEAD(lex->sources);
365
13.6M
  REQUIRE(tokenp != NULL);
366
367
13.6M
  if (source == NULL) {
368
0
    if ((options & ISC_LEXOPT_NOMORE) != 0) {
369
0
      tokenp->type = isc_tokentype_nomore;
370
0
      return (ISC_R_SUCCESS);
371
0
    }
372
0
    return (ISC_R_NOMORE);
373
0
  }
374
375
13.6M
  if (source->result != ISC_R_SUCCESS) {
376
0
    return (source->result);
377
0
  }
378
379
13.6M
  lex->saved_paren_count = lex->paren_count;
380
13.6M
  source->saved_line = source->line;
381
382
13.6M
  if (isc_buffer_remaininglength(source->pushback) == 0 && source->at_eof)
383
2.11k
  {
384
2.11k
    if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
385
2.11k
        lex->paren_count != 0) {
386
14
      lex->paren_count = 0;
387
14
      return (ISC_R_UNBALANCED);
388
14
    }
389
2.10k
    if ((options & ISC_LEXOPT_BTEXT) != 0 && lex->brace_count != 0)
390
0
    {
391
0
      lex->brace_count = 0;
392
0
      return (ISC_R_UNBALANCED);
393
0
    }
394
2.10k
    if ((options & ISC_LEXOPT_EOF) != 0) {
395
2.10k
      tokenp->type = isc_tokentype_eof;
396
2.10k
      return (ISC_R_SUCCESS);
397
2.10k
    }
398
0
    return (ISC_R_EOF);
399
2.10k
  }
400
401
13.6M
  isc_buffer_compact(source->pushback);
402
403
13.6M
  saved_options = options;
404
13.6M
  if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0) {
405
1.76M
    options &= ~IWSEOL;
406
1.76M
  }
407
408
13.6M
  curr = lex->data;
409
13.6M
  *curr = '\0';
410
411
13.6M
  prev = NULL;
412
13.6M
  remaining = lex->max_token;
413
414
13.6M
#ifdef HAVE_FLOCKFILE
415
13.6M
  if (source->is_file) {
416
1
    flockfile(source->input);
417
1
  }
418
13.6M
#endif /* ifdef HAVE_FLOCKFILE */
419
420
267M
  do {
421
267M
    if (isc_buffer_remaininglength(source->pushback) == 0) {
422
199M
      if (source->is_file) {
423
1
        stream = source->input;
424
425
1
#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETC_UNLOCKED)
426
1
        c = getc_unlocked(stream);
427
#else  /* if defined(HAVE_FLOCKFILE) && defined(HAVE_GETC_UNLOCKED) */
428
        c = getc(stream);
429
#endif /* if defined(HAVE_FLOCKFILE) && defined(HAVE_GETC_UNLOCKED) */
430
1
        if (c == EOF) {
431
1
          if (ferror(stream)) {
432
1
            source->result =
433
1
              isc__errno2result(
434
1
                errno);
435
1
            result = source->result;
436
1
            goto done;
437
1
          }
438
0
          source->at_eof = true;
439
0
        }
440
199M
      } else {
441
199M
        buffer = source->input;
442
443
199M
        if (buffer->current == buffer->used) {
444
9.20M
          c = EOF;
445
9.20M
          source->at_eof = true;
446
189M
        } else {
447
189M
          c = *((unsigned char *)buffer->base +
448
189M
                buffer->current);
449
189M
          buffer->current++;
450
189M
        }
451
199M
      }
452
199M
      if (c != EOF) {
453
189M
        source->result = pushandgrow(lex, source, c);
454
189M
        if (source->result != ISC_R_SUCCESS) {
455
0
          result = source->result;
456
0
          goto done;
457
0
        }
458
189M
      }
459
199M
    }
460
461
267M
    if (!source->at_eof) {
462
258M
      if (state == lexstate_start) {
463
        /* Token has not started yet. */
464
16.0M
        source->ignored = isc_buffer_consumedlength(
465
16.0M
          source->pushback);
466
16.0M
      }
467
258M
      c = isc_buffer_getuint8(source->pushback);
468
258M
    } else {
469
9.20M
      c = EOF;
470
9.20M
    }
471
472
267M
    if (c == '\n') {
473
1.43M
      source->line++;
474
1.43M
    }
475
476
267M
    if (lex->comment_ok && !no_comments) {
477
244M
      if (!escaped && c == ';' &&
478
244M
          ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE) !=
479
286k
           0))
480
184k
      {
481
184k
        saved_state = state;
482
184k
        state = lexstate_eatline;
483
184k
        no_comments = true;
484
184k
        continue;
485
243M
      } else if (c == '/' &&
486
243M
           (lex->comments &
487
161k
            (ISC_LEXCOMMENT_C |
488
161k
             ISC_LEXCOMMENT_CPLUSPLUS)) != 0)
489
0
      {
490
0
        saved_state = state;
491
0
        state = lexstate_maybecomment;
492
0
        no_comments = true;
493
0
        continue;
494
243M
      } else if (c == '#' && ((lex->comments &
495
129k
             ISC_LEXCOMMENT_SHELL) != 0)) {
496
0
        saved_state = state;
497
0
        state = lexstate_eatline;
498
0
        no_comments = true;
499
0
        continue;
500
0
      }
501
244M
    }
502
503
276M
  no_read:
504
    /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
505
276M
    switch (state) {
506
19.9M
    case lexstate_start:
507
19.9M
      if (c == EOF) {
508
3.89M
        lex->last_was_eol = false;
509
3.89M
        if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
510
3.89M
            lex->paren_count != 0) {
511
5.26k
          lex->paren_count = 0;
512
5.26k
          result = ISC_R_UNBALANCED;
513
5.26k
          goto done;
514
5.26k
        }
515
3.88M
        if ((options & ISC_LEXOPT_BTEXT) != 0 &&
516
3.88M
            lex->brace_count != 0) {
517
0
          lex->brace_count = 0;
518
0
          result = ISC_R_UNBALANCED;
519
0
          goto done;
520
0
        }
521
3.88M
        if ((options & ISC_LEXOPT_EOF) == 0) {
522
383
          result = ISC_R_EOF;
523
383
          goto done;
524
383
        }
525
3.88M
        tokenp->type = isc_tokentype_eof;
526
3.88M
        done = true;
527
16.0M
      } else if (c == ' ' || c == '\t') {
528
3.26M
        if (lex->last_was_eol &&
529
3.26M
            (options & ISC_LEXOPT_INITIALWS) != 0) {
530
130k
          lex->last_was_eol = false;
531
130k
          tokenp->type = isc_tokentype_initialws;
532
130k
          tokenp->value.as_char = c;
533
130k
          done = true;
534
130k
        }
535
12.8M
      } else if (c == '\n') {
536
838k
        if ((options & ISC_LEXOPT_EOL) != 0) {
537
484k
          tokenp->type = isc_tokentype_eol;
538
484k
          done = true;
539
484k
        }
540
838k
        lex->last_was_eol = true;
541
11.9M
      } else if (c == '\r') {
542
284k
        if ((options & ISC_LEXOPT_EOL) != 0) {
543
161k
          state = lexstate_crlf;
544
161k
        }
545
11.7M
      } else if (c == '"' &&
546
11.7M
           (options & ISC_LEXOPT_QSTRING) != 0) {
547
64.5k
        lex->last_was_eol = false;
548
64.5k
        no_comments = true;
549
64.5k
        state = lexstate_qstring;
550
11.6M
      } else if (lex->specials[c]) {
551
2.80M
        lex->last_was_eol = false;
552
2.80M
        if ((c == '(' || c == ')') &&
553
2.80M
            (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
554
2.71M
          if (c == '(') {
555
2.54M
            if (lex->paren_count == 0) {
556
112k
              options &= ~IWSEOL;
557
112k
            }
558
2.54M
            lex->paren_count++;
559
2.54M
          } else {
560
167k
            if (lex->paren_count == 0) {
561
273
              result =
562
273
                ISC_R_UNBALANCED;
563
273
              goto done;
564
273
            }
565
167k
            lex->paren_count--;
566
167k
            if (lex->paren_count == 0) {
567
118k
              options = saved_options;
568
118k
            }
569
167k
          }
570
2.71M
          continue;
571
2.71M
        } else if (c == '{' &&
572
92.7k
             (options & ISC_LEXOPT_BTEXT) != 0) {
573
0
          if (lex->brace_count != 0) {
574
0
            result = ISC_R_UNBALANCED;
575
0
            goto done;
576
0
          }
577
0
          lex->brace_count++;
578
0
          options &= ~IWSEOL;
579
0
          state = lexstate_btext;
580
0
          no_comments = true;
581
0
          continue;
582
0
        }
583
92.7k
        tokenp->type = isc_tokentype_special;
584
92.7k
        tokenp->value.as_char = c;
585
92.7k
        done = true;
586
8.83M
      } else if (isdigit((unsigned char)c) &&
587
8.83M
           (options & ISC_LEXOPT_NUMBER) != 0) {
588
198k
        lex->last_was_eol = false;
589
198k
        if ((options & ISC_LEXOPT_OCTAL) != 0 &&
590
198k
            (c == '8' || c == '9')) {
591
2
          state = lexstate_string;
592
198k
        } else {
593
198k
          state = lexstate_number;
594
198k
        }
595
198k
        goto no_read;
596
8.63M
      } else {
597
8.63M
        lex->last_was_eol = false;
598
8.63M
        state = lexstate_string;
599
8.63M
        goto no_read;
600
8.63M
      }
601
8.42M
      break;
602
8.42M
    case lexstate_crlf:
603
161k
      if (c != '\n') {
604
158k
        pushback(source, c);
605
158k
      }
606
161k
      tokenp->type = isc_tokentype_eol;
607
161k
      done = true;
608
161k
      lex->last_was_eol = true;
609
161k
      break;
610
3.89M
    case lexstate_number:
611
3.89M
      if (c == EOF || !isdigit((unsigned char)c)) {
612
198k
        if (c == ' ' || c == '\t' || c == '\r' ||
613
198k
            c == '\n' || c == EOF || lex->specials[c])
614
197k
        {
615
197k
          int base;
616
197k
          if ((options & ISC_LEXOPT_OCTAL) != 0) {
617
110
            base = 8;
618
197k
          } else if ((options &
619
197k
                ISC_LEXOPT_CNUMBER) != 0) {
620
0
            base = 0;
621
197k
          } else {
622
197k
            base = 10;
623
197k
          }
624
197k
          pushback(source, c);
625
626
197k
          result = isc_parse_uint32(
627
197k
            &as_ulong, lex->data, base);
628
197k
          if (result == ISC_R_SUCCESS) {
629
196k
            tokenp->type =
630
196k
              isc_tokentype_number;
631
196k
            tokenp->value.as_ulong =
632
196k
              as_ulong;
633
196k
          } else if (result == ISC_R_BADNUMBER) {
634
0
            isc_tokenvalue_t *v;
635
636
0
            tokenp->type =
637
0
              isc_tokentype_string;
638
0
            v = &(tokenp->value);
639
0
            v->as_textregion.base =
640
0
              lex->data;
641
0
            v->as_textregion.length =
642
0
              (unsigned int)(lex->max_token -
643
0
                       remaining);
644
1.08k
          } else {
645
1.08k
            goto done;
646
1.08k
          }
647
196k
          done = true;
648
196k
          continue;
649
197k
        } else if ((options & ISC_LEXOPT_CNUMBER) ==
650
975
               0 ||
651
975
             ((c != 'x' && c != 'X') ||
652
0
              (curr != &lex->data[1]) ||
653
0
              (lex->data[0] != '0')))
654
975
        {
655
          /* Above test supports hex numbers */
656
975
          state = lexstate_string;
657
975
        }
658
3.70M
      } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
659
3.70M
           (c == '8' || c == '9')) {
660
2
        state = lexstate_string;
661
2
      }
662
3.70M
      if (remaining == 0U) {
663
88
        result = grow_data(lex, &remaining, &curr,
664
88
               &prev);
665
88
        if (result != ISC_R_SUCCESS) {
666
0
          goto done;
667
0
        }
668
88
      }
669
3.70M
      INSIST(remaining > 0U);
670
0
      *curr++ = c;
671
3.70M
      *curr = '\0';
672
3.70M
      remaining--;
673
3.70M
      break;
674
211M
    case lexstate_string:
675
211M
      if (!escaped && c == '=' &&
676
211M
          (options & ISC_LEXOPT_VPAIR) != 0) {
677
15.6k
        if (remaining == 0U) {
678
5
          result = grow_data(lex, &remaining,
679
5
                 &curr, &prev);
680
5
          if (result != ISC_R_SUCCESS) {
681
0
            goto done;
682
0
          }
683
5
        }
684
15.6k
        INSIST(remaining > 0U);
685
0
        *curr++ = c;
686
15.6k
        *curr = '\0';
687
15.6k
        remaining--;
688
15.6k
        state = lexstate_vpairstart;
689
15.6k
        break;
690
15.6k
      }
691
      /* FALLTHROUGH */
692
211M
    case lexstate_vpairstart:
693
211M
      if (state == lexstate_vpairstart) {
694
15.6k
        if (c == '"' &&
695
15.6k
            (options & ISC_LEXOPT_QVPAIR) != 0) {
696
1.05k
          no_comments = true;
697
1.05k
          state = lexstate_qvpair;
698
1.05k
          break;
699
1.05k
        }
700
14.5k
        state = lexstate_vpair;
701
14.5k
      }
702
      /* FALLTHROUGH */
703
228M
    case lexstate_vpair:
704
      /*
705
       * EOF needs to be checked before lex->specials[c]
706
       * as lex->specials[EOF] is not a good idea.
707
       */
708
228M
      if (c == '\r' || c == '\n' || c == EOF ||
709
228M
          (!escaped &&
710
222M
           (c == ' ' || c == '\t' || lex->specials[c])))
711
8.63M
      {
712
8.63M
        pushback(source, c);
713
8.63M
        if (source->result != ISC_R_SUCCESS) {
714
0
          result = source->result;
715
0
          goto done;
716
0
        }
717
8.63M
        if (escaped && c == EOF) {
718
62
          result = ISC_R_UNEXPECTEDEND;
719
62
          goto done;
720
62
        }
721
8.63M
        tokenp->type = (state == lexstate_string)
722
8.63M
                   ? isc_tokentype_string
723
8.63M
                   : isc_tokentype_vpair;
724
8.63M
        tokenp->value.as_textregion.base = lex->data;
725
8.63M
        tokenp->value.as_textregion.length =
726
8.63M
          (unsigned int)(lex->max_token -
727
8.63M
                   remaining);
728
8.63M
        done = true;
729
8.63M
        continue;
730
8.63M
      }
731
220M
      if ((options & ISC_LEXOPT_ESCAPE) != 0) {
732
156M
        escaped = (!escaped && c == '\\') ? true
733
156M
                  : false;
734
156M
      }
735
220M
      if (remaining == 0U) {
736
6.25k
        result = grow_data(lex, &remaining, &curr,
737
6.25k
               &prev);
738
6.25k
        if (result != ISC_R_SUCCESS) {
739
0
          goto done;
740
0
        }
741
6.25k
      }
742
220M
      INSIST(remaining > 0U);
743
0
      *curr++ = c;
744
220M
      *curr = '\0';
745
220M
      remaining--;
746
220M
      break;
747
0
    case lexstate_maybecomment:
748
0
      if (c == '*' && (lex->comments & ISC_LEXCOMMENT_C) != 0)
749
0
      {
750
0
        state = lexstate_ccomment;
751
0
        continue;
752
0
      } else if (c == '/' && (lex->comments &
753
0
            ISC_LEXCOMMENT_CPLUSPLUS) != 0)
754
0
      {
755
0
        state = lexstate_eatline;
756
0
        continue;
757
0
      }
758
0
      pushback(source, c);
759
0
      c = '/';
760
0
      no_comments = false;
761
0
      state = saved_state;
762
0
      goto no_read;
763
0
    case lexstate_ccomment:
764
0
      if (c == EOF) {
765
0
        result = ISC_R_UNEXPECTEDEND;
766
0
        goto done;
767
0
      }
768
0
      if (c == '*') {
769
0
        state = lexstate_ccommentend;
770
0
      }
771
0
      break;
772
0
    case lexstate_ccommentend:
773
0
      if (c == EOF) {
774
0
        result = ISC_R_UNEXPECTEDEND;
775
0
        goto done;
776
0
      }
777
0
      if (c == '/') {
778
        /*
779
         * C-style comments become a single space.
780
         * We do this to ensure that a comment will
781
         * act as a delimiter for strings and
782
         * numbers.
783
         */
784
0
        c = ' ';
785
0
        no_comments = false;
786
0
        state = saved_state;
787
0
        goto no_read;
788
0
      } else if (c != '*') {
789
0
        state = lexstate_ccomment;
790
0
      }
791
0
      break;
792
8.61M
    case lexstate_eatline:
793
8.61M
      if ((c == '\n') || (c == EOF)) {
794
184k
        no_comments = false;
795
184k
        state = saved_state;
796
184k
        goto no_read;
797
184k
      }
798
8.43M
      break;
799
8.43M
    case lexstate_qstring:
800
14.9M
    case lexstate_qvpair:
801
14.9M
      if (c == EOF) {
802
215
        result = ISC_R_UNEXPECTEDEND;
803
215
        goto done;
804
215
      }
805
14.9M
      if (c == '"') {
806
75.2k
        if (escaped) {
807
9.91k
          escaped = false;
808
          /*
809
           * Overwrite the preceding backslash.
810
           */
811
9.91k
          INSIST(prev != NULL);
812
0
          *prev = '"';
813
65.3k
        } else {
814
65.3k
          tokenp->type =
815
65.3k
            (state == lexstate_qstring)
816
65.3k
              ? isc_tokentype_qstring
817
65.3k
              : isc_tokentype_qvpair;
818
65.3k
          tokenp->value.as_textregion.base =
819
65.3k
            lex->data;
820
65.3k
          tokenp->value.as_textregion.length =
821
65.3k
            (unsigned int)(lex->max_token -
822
65.3k
                     remaining);
823
65.3k
          no_comments = false;
824
65.3k
          done = true;
825
65.3k
        }
826
14.8M
      } else {
827
14.8M
        if (c == '\n' && !escaped &&
828
14.8M
            (options & ISC_LEXOPT_QSTRINGMULTILINE) ==
829
46
              0) {
830
46
          pushback(source, c);
831
46
          result = ISC_R_UNBALANCEDQUOTES;
832
46
          goto done;
833
46
        }
834
14.8M
        if (c == '\\' && !escaped) {
835
535k
          escaped = true;
836
14.3M
        } else {
837
14.3M
          escaped = false;
838
14.3M
        }
839
14.8M
        if (remaining == 0U) {
840
405
          result = grow_data(lex, &remaining,
841
405
                 &curr, &prev);
842
405
          if (result != ISC_R_SUCCESS) {
843
0
            goto done;
844
0
          }
845
405
        }
846
14.8M
        INSIST(remaining > 0U);
847
0
        prev = curr;
848
14.8M
        *curr++ = c;
849
14.8M
        *curr = '\0';
850
14.8M
        remaining--;
851
14.8M
      }
852
14.9M
      break;
853
14.9M
    case lexstate_btext:
854
0
      if (c == EOF) {
855
0
        result = ISC_R_UNEXPECTEDEND;
856
0
        goto done;
857
0
      }
858
0
      if (c == '{') {
859
0
        if (escaped) {
860
0
          escaped = false;
861
0
        } else {
862
0
          lex->brace_count++;
863
0
        }
864
0
      } else if (c == '}') {
865
0
        if (escaped) {
866
0
          escaped = false;
867
0
        } else {
868
0
          INSIST(lex->brace_count > 0);
869
0
          lex->brace_count--;
870
0
        }
871
872
0
        if (lex->brace_count == 0) {
873
0
          tokenp->type = isc_tokentype_btext;
874
0
          tokenp->value.as_textregion.base =
875
0
            lex->data;
876
0
          tokenp->value.as_textregion.length =
877
0
            (unsigned int)(lex->max_token -
878
0
                     remaining);
879
0
          no_comments = false;
880
0
          done = true;
881
0
          break;
882
0
        }
883
0
      }
884
885
0
      if (c == '\\' && !escaped) {
886
0
        escaped = true;
887
0
      } else {
888
0
        escaped = false;
889
0
      }
890
891
0
      if (remaining == 0U) {
892
0
        result = grow_data(lex, &remaining, &curr,
893
0
               &prev);
894
0
        if (result != ISC_R_SUCCESS) {
895
0
          goto done;
896
0
        }
897
0
      }
898
0
      INSIST(remaining > 0U);
899
0
      prev = curr;
900
0
      *curr++ = c;
901
0
      *curr = '\0';
902
0
      remaining--;
903
0
      break;
904
0
    default:
905
0
      FATAL_ERROR(__FILE__, __LINE__, "Unexpected state %d",
906
0
            state);
907
276M
    }
908
276M
  } while (!done);
909
910
13.6M
  result = ISC_R_SUCCESS;
911
13.6M
done:
912
13.6M
#ifdef HAVE_FLOCKFILE
913
13.6M
  if (source->is_file) {
914
1
    funlockfile(source->input);
915
1
  }
916
13.6M
#endif /* ifdef HAVE_FLOCKFILE */
917
13.6M
  return (result);
918
13.6M
}
919
920
isc_result_t
921
isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
922
9.23M
           isc_tokentype_t expect, bool eol) {
923
9.23M
  unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
924
9.23M
             ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
925
9.23M
  isc_result_t result;
926
927
9.23M
  if (expect == isc_tokentype_vpair) {
928
1.17k
    options |= ISC_LEXOPT_VPAIR;
929
9.23M
  } else if (expect == isc_tokentype_qvpair) {
930
28.4k
    options |= ISC_LEXOPT_VPAIR;
931
28.4k
    options |= ISC_LEXOPT_QVPAIR;
932
9.20M
  } else if (expect == isc_tokentype_qstring) {
933
4.09M
    options |= ISC_LEXOPT_QSTRING;
934
5.11M
  } else if (expect == isc_tokentype_number) {
935
180k
    options |= ISC_LEXOPT_NUMBER;
936
180k
  }
937
9.23M
  result = isc_lex_gettoken(lex, options, token);
938
9.23M
  if (result == ISC_R_RANGE) {
939
991
    isc_lex_ungettoken(lex, token);
940
991
  }
941
9.23M
  if (result != ISC_R_SUCCESS) {
942
2.93k
    return (result);
943
2.93k
  }
944
945
9.23M
  if (eol && ((token->type == isc_tokentype_eol) ||
946
6.05M
        (token->type == isc_tokentype_eof)))
947
1.36M
  {
948
1.36M
    return (ISC_R_SUCCESS);
949
1.36M
  }
950
7.87M
  if (token->type == isc_tokentype_string &&
951
7.87M
      (expect == isc_tokentype_qstring || expect == isc_tokentype_qvpair))
952
3.75M
  {
953
3.75M
    return (ISC_R_SUCCESS);
954
3.75M
  }
955
4.11M
  if (token->type == isc_tokentype_vpair &&
956
4.11M
      expect == isc_tokentype_qvpair) {
957
14.0k
    return (ISC_R_SUCCESS);
958
14.0k
  }
959
4.10M
  if (token->type != expect) {
960
8.89k
    isc_lex_ungettoken(lex, token);
961
8.89k
    if (token->type == isc_tokentype_eol ||
962
8.89k
        token->type == isc_tokentype_eof) {
963
7.63k
      return (ISC_R_UNEXPECTEDEND);
964
7.63k
    }
965
1.26k
    if (expect == isc_tokentype_number) {
966
885
      return (ISC_R_BADNUMBER);
967
885
    }
968
376
    return (ISC_R_UNEXPECTEDTOKEN);
969
1.26k
  }
970
4.09M
  return (ISC_R_SUCCESS);
971
4.10M
}
972
973
isc_result_t
974
126
isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, bool eol) {
975
126
  unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
976
126
             ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE |
977
126
             ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
978
126
  isc_result_t result;
979
980
126
  result = isc_lex_gettoken(lex, options, token);
981
126
  if (result == ISC_R_RANGE) {
982
6
    isc_lex_ungettoken(lex, token);
983
6
  }
984
126
  if (result != ISC_R_SUCCESS) {
985
8
    return (result);
986
8
  }
987
988
118
  if (eol && ((token->type == isc_tokentype_eol) ||
989
0
        (token->type == isc_tokentype_eof)))
990
0
  {
991
0
    return (ISC_R_SUCCESS);
992
0
  }
993
118
  if (token->type != isc_tokentype_number) {
994
14
    isc_lex_ungettoken(lex, token);
995
14
    if (token->type == isc_tokentype_eol ||
996
14
        token->type == isc_tokentype_eof) {
997
9
      return (ISC_R_UNEXPECTEDEND);
998
9
    }
999
5
    return (ISC_R_BADNUMBER);
1000
14
  }
1001
104
  return (ISC_R_SUCCESS);
1002
118
}
1003
1004
void
1005
4.32M
isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
1006
4.32M
  inputsource *source;
1007
  /*
1008
   * Unget the current token.
1009
   */
1010
1011
4.32M
  REQUIRE(VALID_LEX(lex));
1012
4.32M
  source = HEAD(lex->sources);
1013
4.32M
  REQUIRE(source != NULL);
1014
4.32M
  REQUIRE(tokenp != NULL);
1015
4.32M
  REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
1016
0
    tokenp->type == isc_tokentype_eof);
1017
1018
4.32M
  UNUSED(tokenp);
1019
1020
4.32M
  isc_buffer_first(source->pushback);
1021
4.32M
  lex->paren_count = lex->saved_paren_count;
1022
4.32M
  source->line = source->saved_line;
1023
4.32M
  source->at_eof = false;
1024
4.32M
}
1025
1026
void
1027
0
isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r) {
1028
0
  inputsource *source;
1029
1030
0
  REQUIRE(VALID_LEX(lex));
1031
0
  source = HEAD(lex->sources);
1032
0
  REQUIRE(source != NULL);
1033
0
  REQUIRE(tokenp != NULL);
1034
0
  REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
1035
0
    tokenp->type == isc_tokentype_eof);
1036
1037
0
  UNUSED(tokenp);
1038
1039
0
  INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
1040
0
  r->base = (unsigned char *)isc_buffer_base(source->pushback) +
1041
0
      source->ignored;
1042
0
  r->length = isc_buffer_consumedlength(source->pushback) -
1043
0
        source->ignored;
1044
0
}
1045
1046
char *
1047
3.54M
isc_lex_getsourcename(isc_lex_t *lex) {
1048
3.54M
  inputsource *source;
1049
1050
3.54M
  REQUIRE(VALID_LEX(lex));
1051
3.54M
  source = HEAD(lex->sources);
1052
1053
3.54M
  if (source == NULL) {
1054
0
    return (NULL);
1055
0
  }
1056
1057
3.54M
  return (source->name);
1058
3.54M
}
1059
1060
unsigned long
1061
4.50M
isc_lex_getsourceline(isc_lex_t *lex) {
1062
4.50M
  inputsource *source;
1063
1064
4.50M
  REQUIRE(VALID_LEX(lex));
1065
4.50M
  source = HEAD(lex->sources);
1066
1067
4.50M
  if (source == NULL) {
1068
0
    return (0);
1069
0
  }
1070
1071
4.50M
  return (source->line);
1072
4.50M
}
1073
1074
isc_result_t
1075
0
isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
1076
0
  inputsource *source;
1077
0
  char *newname;
1078
1079
0
  REQUIRE(VALID_LEX(lex));
1080
0
  source = HEAD(lex->sources);
1081
1082
0
  if (source == NULL) {
1083
0
    return (ISC_R_NOTFOUND);
1084
0
  }
1085
0
  newname = isc_mem_strdup(lex->mctx, name);
1086
0
  isc_mem_free(lex->mctx, source->name);
1087
0
  source->name = newname;
1088
0
  return (ISC_R_SUCCESS);
1089
0
}
1090
1091
isc_result_t
1092
0
isc_lex_setsourceline(isc_lex_t *lex, unsigned long line) {
1093
0
  inputsource *source;
1094
1095
0
  REQUIRE(VALID_LEX(lex));
1096
0
  source = HEAD(lex->sources);
1097
1098
0
  if (source == NULL) {
1099
0
    return (ISC_R_NOTFOUND);
1100
0
  }
1101
1102
0
  source->line = line;
1103
0
  return (ISC_R_SUCCESS);
1104
0
}
1105
1106
bool
1107
2.67M
isc_lex_isfile(isc_lex_t *lex) {
1108
2.67M
  inputsource *source;
1109
1110
2.67M
  REQUIRE(VALID_LEX(lex));
1111
1112
2.67M
  source = HEAD(lex->sources);
1113
1114
2.67M
  if (source == NULL) {
1115
0
    return (false);
1116
0
  }
1117
1118
2.67M
  return (source->is_file);
1119
2.67M
}