|
13 | 13 |
|
14 | 14 | static void set_parse_error(git_config_parser *reader, int col, const char *error_str) |
15 | 15 | { |
16 | | - giterr_set(GITERR_CONFIG, "failed to parse config file: %s (in %s:%d, column %d)", |
17 | | - error_str, reader->file->path, reader->line_number, col); |
| 16 | + giterr_set(GITERR_CONFIG, "failed to parse config file: %s (in %s:%"PRIuZ", column %d)", |
| 17 | + error_str, reader->file->path, reader->ctx.line_num, col); |
18 | 18 | } |
19 | 19 |
|
20 | | -static int reader_getchar_raw(git_config_parser *reader) |
21 | | -{ |
22 | | - int c; |
23 | | - |
24 | | - c = *reader->read_ptr++; |
25 | | - |
26 | | - /* |
27 | | - Win 32 line breaks: if we find a \r\n sequence, |
28 | | - return only the \n as a newline |
29 | | - */ |
30 | | - if (c == '\r' && *reader->read_ptr == '\n') { |
31 | | - reader->read_ptr++; |
32 | | - c = '\n'; |
33 | | - } |
34 | | - |
35 | | - if (c == '\n') |
36 | | - reader->line_number++; |
37 | | - |
38 | | - if (c == 0) { |
39 | | - reader->eof = 1; |
40 | | - c = '\0'; |
41 | | - } |
42 | | - |
43 | | - return c; |
44 | | -} |
45 | | - |
46 | | -#define SKIP_WHITESPACE (1 << 1) |
47 | | -#define SKIP_COMMENTS (1 << 2) |
48 | | - |
49 | | -static int reader_getchar(git_config_parser *reader, int flags) |
50 | | -{ |
51 | | - const int skip_whitespace = (flags & SKIP_WHITESPACE); |
52 | | - const int skip_comments = (flags & SKIP_COMMENTS); |
53 | | - int c; |
54 | | - |
55 | | - assert(reader->read_ptr); |
56 | | - |
57 | | - do { |
58 | | - c = reader_getchar_raw(reader); |
59 | | - } while (c != '\n' && c != '\0' && skip_whitespace && git__isspace(c)); |
60 | | - |
61 | | - if (skip_comments && (c == '#' || c == ';')) { |
62 | | - do { |
63 | | - c = reader_getchar_raw(reader); |
64 | | - } while (c != '\n' && c != '\0'); |
65 | | - } |
66 | | - |
67 | | - return c; |
68 | | -} |
69 | | - |
70 | | -/* |
71 | | - * Read the next char, but don't move the reading pointer. |
72 | | - */ |
73 | | -static int reader_peek(git_config_parser *reader, int flags) |
74 | | -{ |
75 | | - void *old_read_ptr; |
76 | | - int old_lineno, old_eof; |
77 | | - int ret; |
78 | | - |
79 | | - assert(reader->read_ptr); |
80 | | - |
81 | | - old_read_ptr = reader->read_ptr; |
82 | | - old_lineno = reader->line_number; |
83 | | - old_eof = reader->eof; |
84 | | - |
85 | | - ret = reader_getchar(reader, flags); |
86 | | - |
87 | | - reader->read_ptr = old_read_ptr; |
88 | | - reader->line_number = old_lineno; |
89 | | - reader->eof = old_eof; |
90 | | - |
91 | | - return ret; |
92 | | -} |
93 | | - |
94 | | -/* |
95 | | - * Read and consume a line, returning it in newly-allocated memory. |
96 | | - */ |
97 | | -static char *reader_readline(git_config_parser *reader, bool skip_whitespace) |
98 | | -{ |
99 | | - char *line = NULL; |
100 | | - char *line_src, *line_end; |
101 | | - size_t line_len, alloc_len; |
102 | | - |
103 | | - line_src = reader->read_ptr; |
104 | | - |
105 | | - if (skip_whitespace) { |
106 | | - /* Skip empty empty lines */ |
107 | | - while (git__isspace(*line_src)) |
108 | | - ++line_src; |
109 | | - } |
110 | | - |
111 | | - line_end = strchr(line_src, '\n'); |
112 | | - |
113 | | - /* no newline at EOF */ |
114 | | - if (line_end == NULL) |
115 | | - line_end = strchr(line_src, 0); |
116 | | - |
117 | | - line_len = line_end - line_src; |
118 | | - |
119 | | - if (GIT_ADD_SIZET_OVERFLOW(&alloc_len, line_len, 1) || |
120 | | - (line = git__malloc(alloc_len)) == NULL) { |
121 | | - return NULL; |
122 | | - } |
123 | | - |
124 | | - memcpy(line, line_src, line_len); |
125 | | - |
126 | | - do line[line_len] = '\0'; |
127 | | - while (line_len-- > 0 && git__isspace(line[line_len])); |
128 | | - |
129 | | - if (*line_end == '\n') |
130 | | - line_end++; |
131 | | - |
132 | | - if (*line_end == '\0') |
133 | | - reader->eof = 1; |
134 | | - |
135 | | - reader->line_number++; |
136 | | - reader->read_ptr = line_end; |
137 | | - |
138 | | - return line; |
139 | | -} |
140 | | - |
141 | | -/* |
142 | | - * Consume a line, without storing it anywhere |
143 | | - */ |
144 | | -static void reader_consume_line(git_config_parser *reader) |
145 | | -{ |
146 | | - char *line_start, *line_end; |
147 | | - |
148 | | - line_start = reader->read_ptr; |
149 | | - line_end = strchr(line_start, '\n'); |
150 | | - /* No newline at EOF */ |
151 | | - if(line_end == NULL){ |
152 | | - line_end = strchr(line_start, '\0'); |
153 | | - } |
154 | | - |
155 | | - if (*line_end == '\n') |
156 | | - line_end++; |
157 | | - |
158 | | - if (*line_end == '\0') |
159 | | - reader->eof = 1; |
160 | | - |
161 | | - reader->line_number++; |
162 | | - reader->read_ptr = line_end; |
163 | | -} |
164 | 20 |
|
165 | 21 | GIT_INLINE(int) config_keychar(int c) |
166 | 22 | { |
@@ -295,7 +151,8 @@ static int parse_section_header(git_config_parser *reader, char **section_out) |
295 | 151 | char *line; |
296 | 152 | size_t line_len; |
297 | 153 |
|
298 | | - line = reader_readline(reader, true); |
| 154 | + git_parse_advance_ws(&reader->ctx); |
| 155 | + line = git__strndup(reader->ctx.line, reader->ctx.line_len); |
299 | 156 | if (line == NULL) |
300 | 157 | return -1; |
301 | 158 |
|
@@ -356,14 +213,14 @@ static int parse_section_header(git_config_parser *reader, char **section_out) |
356 | 213 | return -1; |
357 | 214 | } |
358 | 215 |
|
359 | | -static int skip_bom(git_config_parser *reader) |
| 216 | +static int skip_bom(git_parse_ctx *parser) |
360 | 217 | { |
| 218 | + git_buf buf = GIT_BUF_INIT_CONST(parser->content, parser->content_len); |
361 | 219 | git_bom_t bom; |
362 | | - int bom_offset = git_buf_text_detect_bom(&bom, |
363 | | - &reader->buffer, reader->read_ptr - reader->buffer.ptr); |
| 220 | + int bom_offset = git_buf_text_detect_bom(&bom, &buf, parser->content_len); |
364 | 221 |
|
365 | 222 | if (bom == GIT_BOM_UTF8) |
366 | | - reader->read_ptr += bom_offset; |
| 223 | + git_parse_advance_chars(parser, bom_offset); |
367 | 224 |
|
368 | 225 | /* TODO: reference implementation is pretty stupid with BoM */ |
369 | 226 |
|
@@ -463,7 +320,8 @@ static int parse_multiline_variable(git_config_parser *reader, git_buf *value, i |
463 | 320 | bool multiline; |
464 | 321 |
|
465 | 322 | /* Check that the next line exists */ |
466 | | - line = reader_readline(reader, false); |
| 323 | + git_parse_advance_line(&reader->ctx); |
| 324 | + line = git__strndup(reader->ctx.line, reader->ctx.line_len); |
467 | 325 | if (line == NULL) |
468 | 326 | return -1; |
469 | 327 |
|
@@ -550,7 +408,8 @@ static int parse_variable(git_config_parser *reader, char **var_name, char **var |
550 | 408 | int quote_count; |
551 | 409 | bool multiline; |
552 | 410 |
|
553 | | - line = reader_readline(reader, true); |
| 411 | + git_parse_advance_ws(&reader->ctx); |
| 412 | + line = git__strndup(reader->ctx.line, reader->ctx.line_len); |
554 | 413 | if (line == NULL) |
555 | 414 | return -1; |
556 | 415 |
|
@@ -603,56 +462,58 @@ int git_config_parse( |
603 | 462 | git_config_parser_eof_cb on_eof, |
604 | 463 | void *data) |
605 | 464 | { |
606 | | - char *current_section = NULL, *var_name, *var_value, *line_start; |
607 | | - char c; |
608 | | - size_t line_len; |
| 465 | + git_parse_ctx *ctx; |
| 466 | + char *current_section = NULL, *var_name, *var_value; |
609 | 467 | int result = 0; |
610 | 468 |
|
611 | | - skip_bom(parser); |
| 469 | + ctx = &parser->ctx; |
612 | 470 |
|
613 | | - while (result == 0 && !parser->eof) { |
614 | | - line_start = parser->read_ptr; |
| 471 | + skip_bom(ctx); |
615 | 472 |
|
616 | | - c = reader_peek(parser, SKIP_WHITESPACE); |
| 473 | + for (; ctx->remain_len > 0; git_parse_advance_line(ctx)) { |
| 474 | + const char *line_start = parser->ctx.line; |
| 475 | + size_t line_len = parser->ctx.line_len; |
| 476 | + char c; |
617 | 477 |
|
618 | | - switch (c) { |
619 | | - case '\0': /* EOF when peeking, set EOF in the parser to exit the loop */ |
620 | | - parser->eof = 1; |
621 | | - break; |
| 478 | + if (git_parse_peek(&c, ctx, GIT_PARSE_PEEK_SKIP_WHITESPACE) < 0 && |
| 479 | + git_parse_peek(&c, ctx, 0) < 0) |
| 480 | + continue; |
622 | 481 |
|
| 482 | + switch (c) { |
623 | 483 | case '[': /* section header, new section begins */ |
624 | 484 | git__free(current_section); |
625 | 485 | current_section = NULL; |
626 | 486 |
|
627 | 487 | if ((result = parse_section_header(parser, ¤t_section)) == 0 && on_section) { |
628 | | - line_len = parser->read_ptr - line_start; |
629 | 488 | result = on_section(parser, current_section, line_start, line_len, data); |
630 | 489 | } |
631 | 490 | break; |
632 | 491 |
|
633 | 492 | case '\n': /* comment or whitespace-only */ |
| 493 | + case ' ': |
| 494 | + case '\t': |
634 | 495 | case ';': |
635 | 496 | case '#': |
636 | | - reader_consume_line(parser); |
637 | | - |
638 | 497 | if (on_comment) { |
639 | | - line_len = parser->read_ptr - line_start; |
640 | 498 | result = on_comment(parser, line_start, line_len, data); |
641 | 499 | } |
642 | 500 | break; |
643 | 501 |
|
644 | 502 | default: /* assume variable declaration */ |
645 | 503 | if ((result = parse_variable(parser, &var_name, &var_value)) == 0 && on_variable) { |
646 | | - line_len = parser->read_ptr - line_start; |
647 | 504 | result = on_variable(parser, current_section, var_name, var_value, line_start, line_len, data); |
648 | 505 | } |
649 | 506 | break; |
650 | 507 | } |
| 508 | + |
| 509 | + if (result < 0) |
| 510 | + goto out; |
651 | 511 | } |
652 | 512 |
|
653 | 513 | if (on_eof) |
654 | 514 | result = on_eof(parser, current_section, data); |
655 | 515 |
|
| 516 | +out: |
656 | 517 | git__free(current_section); |
657 | 518 | return result; |
658 | 519 | } |
0 commit comments