diff options
Diffstat (limited to 'btparser/lib/utils.c')
-rw-r--r-- | btparser/lib/utils.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/btparser/lib/utils.c b/btparser/lib/utils.c new file mode 100644 index 00000000..1de329a7 --- /dev/null +++ b/btparser/lib/utils.c @@ -0,0 +1,423 @@ +/* + utils.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "utils.h" +#include "location.h" +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <regex.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +bool btp_debug_parser = false; + +void * +btp_malloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr == NULL) + { + fprintf(stderr, "btp: out of memory"); + exit(1); + } + return ptr; +} + +char * +btp_vasprintf(const char *format, va_list p) +{ + int r; + char *string_ptr; + +#if 1 + // GNU extension + r = vasprintf(&string_ptr, format, p); +#else + // Bloat for systems that haven't got the GNU extension. + va_list p2; + va_copy(p2, p); + r = vsnprintf(NULL, 0, format, p); + string_ptr = xmalloc(r+1); + r = vsnprintf(string_ptr, r+1, format, p2); + va_end(p2); +#endif + + if (r < 0) + { + fprintf(stderr, "btp: out of memory"); + exit(1); + } + + return string_ptr; +} + +char * +btp_strdup(const char *s) +{ + return btp_strndup(s, strlen(s)); +} + +char * +btp_strndup(const char *s, size_t n) +{ + char *result = strndup(s, n); + if (result == NULL) + { + fprintf(stderr, "btp: out of memory"); + exit(1); + } + return result; +} + +int +btp_strcmp0(const char *s1, const char *s2) +{ + if (!s1) + { + if (s2) + return -1; + return 0; + } + else + { + if (!s2) + return 1; + /* Both are non-null. */ + return strcmp(s1, s2); + } +} + +char * +btp_strchr_location(const char *s, int c, int *line, int *column) +{ + *line = 1; + *column = 0; + + /* Scan s for the character. When this loop is finished, + s will either point to the end of the string or the + character we were looking for. */ + while (*s != '\0' && *s != (char)c) + { + btp_location_eat_char_ext(line, column, *s); + ++s; + } + return ((*s == c) ? (char*)s : NULL); +} + +char * +btp_strstr_location(const char *haystack, + const char *needle, + int *line, + int *column) +{ + *line = 1; + *column = 0; + size_t needlelen; + + /* Check for the null needle case. */ + if (*needle == '\0') + return (char*)haystack; + + needlelen = strlen(needle); + int chrline, chrcolumn; + for (;(haystack = btp_strchr_location(haystack, *needle, &chrline, &chrcolumn)) != NULL; ++haystack) + { + btp_location_add_ext(line, column, chrline, chrcolumn); + + if (strncmp(haystack, needle, needlelen) == 0) + return (char*)haystack; + + btp_location_eat_char_ext(line, column, *haystack); + } + return NULL; +} + +size_t +btp_strspn_location(const char *s, + const char *accept, + int *line, + int *column) +{ + *line = 1; + *column = 0; + const char *sc; + for (sc = s; *sc != '\0'; ++sc) + { + if (strchr(accept, *sc) == NULL) + return (sc - s); + + btp_location_eat_char_ext(line, column, *sc); + } + return sc - s; /* terminating nulls don't match */ +} + +char * +btp_file_to_string(const char *filename) +{ + /* Open input file, and parse it. */ + int fd = open(filename, O_RDONLY | O_LARGEFILE); + if (fd < 0) + { + fprintf(stderr, "Unable to open '%s': %s.\n", + filename, strerror(errno)); + return NULL; + } + + off_t size = lseek(fd, 0, SEEK_END); + if (size < 0) /* EOVERFLOW? */ + { + fprintf(stderr, "Unable to seek in '%s': %s.\n", + filename, strerror(errno)); + } + + lseek(fd, 0, SEEK_SET); /* No reason to fail. */ + + static const size_t FILE_SIZE_LIMIT = 20000000; /* ~ 20 MB */ + if (size > FILE_SIZE_LIMIT) + { + fprintf(stderr, "Input file too big (%lld). Maximum size is %zd.\n", + (long long)size, FILE_SIZE_LIMIT); + close(fd); + return NULL; + } + + char *contents = btp_malloc(size + 1); + if (size != read(fd, contents, size)) + { + fprintf(stderr, "Unable to read from '%s'.\n", filename); + close(fd); + free(contents); + return NULL; + } + + /* Just reading, so no need to check the returned value. */ + close(fd); + + contents[size] = '\0'; + return contents; +} + +bool +btp_skip_char(char **input, char c) +{ + if (**input != c) + return false; + ++*input; + return true; +} + +bool +btp_skip_char_limited(char **input, const char *allowed) +{ + if (strchr(allowed, **input) == NULL) + return false; + ++*input; + return true; +} + +bool +btp_parse_char_limited(char **input, const char *allowed, char *result) +{ + if (**input == '\0') + return false; + if (strchr(allowed, **input) == NULL) + return false; + *result = **input; + ++*input; + return true; +} + +int +btp_skip_char_sequence(char **input, char c) +{ + int count = 0; + + /* Skip all the occurences of c. */ + while (btp_skip_char(input, c)) + ++count; + + return count; +} + +int +btp_skip_char_span(char **input, const char *chars) +{ + size_t count = strspn(*input, chars); + if (0 == count) + return count; + *input += count; + return count; +} + +int +btp_skip_char_span_location(char **input, + const char *chars, + int *line, + int *column) +{ + size_t count = btp_strspn_location(*input, chars, line, column); + if (0 == count) + return count; + *input += count; + return count; +} + +int +btp_parse_char_span(char **input, const char *accept, char **result) +{ + size_t count = strspn(*input, accept); + if (count == 0) + return 0; + *result = btp_strndup(*input, count); + *input += count; + return count; +} + +bool +btp_parse_char_cspan(char **input, const char *reject, char **result) +{ + size_t count = strcspn(*input, reject); + if (count == 0) + return false; + *result = btp_strndup(*input, count); + *input += count; + return true; +} + +int +btp_skip_string(char **input, const char *string) +{ + char *local_input = *input; + const char *local_string = string; + while (*local_string && *local_input && *local_input == *local_string) + { + ++local_input; + ++local_string; + } + if (*local_string != '\0') + return 0; + int count = local_input - *input; + *input = local_input; + return count; +} + +bool +btp_parse_string(char **input, const char *string, char **result) +{ + char *local_input = *input; + const char *local_string = string; + while (*local_string && *local_input && *local_input == *local_string) + { + ++local_input; + ++local_string; + } + if (*local_string != '\0') + return false; + *result = btp_strndup(string, local_input - *input); + *input = local_input; + return true; +} + +char +btp_parse_digit(char **input) +{ + char digit = **input; + if (digit < '0' || digit > '9') + return '\0'; + ++*input; + return digit; +} + +int +btp_skip_unsigned_integer(char **input) +{ + return btp_skip_char_span(input, "0123456789"); +} + +int +btp_parse_unsigned_integer(char **input, unsigned *result) +{ + char *local_input = *input; + char *numstr; + int length = btp_parse_char_span(&local_input, + "0123456789", + &numstr); + if (0 == length) + return 0; + + char *endptr; + errno = 0; + unsigned long r = strtoul(numstr, &endptr, 10); + bool failure = (errno || numstr == endptr || *endptr != '\0' + || r > UINT_MAX); + free(numstr); + if (failure) /* number too big or some other error */ + return 0; + *result = r; + *input = local_input; + return length; +} + +int +btp_skip_hexadecimal_number(char **input) +{ + char *local_input = *input; + if (!btp_skip_char(&local_input, '0')) + return 0; + if (!btp_skip_char(&local_input, 'x')) + return 0; + int count = 2; + count += btp_skip_char_span(&local_input, "abcdef0123456789"); + if (2 == count) /* btp_skip_char_span returned 0 */ + return 0; + *input = local_input; + return count; +} + +int +btp_parse_hexadecimal_number(char **input, uint64_t *result) +{ + char *local_input = *input; + if (!btp_skip_char(&local_input, '0')) + return 0; + if (!btp_skip_char(&local_input, 'x')) + return 0; + int count = 2; + char *numstr; + count += btp_parse_char_span(&local_input, + "abcdef0123456789", + &numstr); + + if (2 == count) /* btp_parse_char_span returned 0 */ + return 0; + char *endptr; + errno = 0; + unsigned long long r = strtoull(numstr, &endptr, 16); + bool failure = (errno || numstr == endptr || *endptr != '\0'); + free(numstr); + if (failure) /* number too big or some other error */ + return 0; + *result = r; + *input = local_input; + return count; +} |