util.c (3375B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <stdint.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <errno.h> 7 8 #include "util.h" 9 10 void 11 parse_input(int (*process_line)(char **, size_t, char *)) 12 { 13 char *line = NULL, **field = NULL, *comment; 14 size_t linebufsize = 0, i, fieldbufsize = 0, j, nfields; 15 ssize_t len; 16 17 while ((len = getline(&line, &linebufsize, stdin)) >= 0) { 18 /* remove trailing newline */ 19 if (len > 0 && line[len - 1] == '\n') { 20 line[len - 1] = '\0'; 21 len--; 22 } 23 24 /* skip empty lines and comment lines */ 25 if (len == 0 || line[0] == '#') { 26 continue; 27 } 28 29 /* tokenize line into fields */ 30 for (i = 0, nfields = 0, comment = NULL; i < (size_t)len; i++) { 31 /* extend field buffer, if necessary */ 32 if (++nfields > fieldbufsize) { 33 if ((field = realloc(field, nfields * 34 sizeof(*field))) == NULL) { 35 fprintf(stderr, "realloc: %s\n", strerror(errno)); 36 exit(1); 37 } 38 fieldbufsize = nfields; 39 } 40 41 /* skip leading whitespace */ 42 while (line[i] == ' ') { 43 i++; 44 } 45 46 /* set current position as field start */ 47 field[nfields - 1] = &line[i]; 48 49 /* continue until we reach ';' or '#' or end */ 50 while (line[i] != ';' && line[i] != '#' && 51 line[i] != '\0') { 52 i++; 53 } 54 if (line [i] == '#') { 55 /* set comment-variable for later */ 56 comment = &line[i + 1]; 57 } 58 59 /* go back whitespace and terminate field there */ 60 if (i > 0) { 61 for (j = i - 1; line[j] == ' '; j--) 62 ; 63 line[j + 1] = '\0'; 64 } else { 65 line[i] = '\0'; 66 } 67 68 /* if comment is set, we are done */ 69 if (comment != NULL) { 70 break; 71 } 72 } 73 74 /* skip leading whitespace in comment */ 75 while (comment != NULL && comment[0] == ' ') { 76 comment++; 77 } 78 79 /* call line processing function */ 80 if (process_line(field, nfields, comment)) { 81 exit(1); 82 } 83 } 84 85 free(line); 86 free(field); 87 } 88 89 static int 90 valid_hexstring(const char *str) 91 { 92 const char *p = str; 93 94 while ((*p >= '0' && *p <= '9') || 95 (*p >= 'a' && *p <= 'f') || 96 (*p >= 'A' && *p <= 'F')) { 97 p++; 98 } 99 100 if (*p != '\0') { 101 fprintf(stderr, "invalid code point range '%s'\n", str); 102 return 0; 103 } 104 105 return 1; 106 } 107 108 int 109 cp_parse(const char *str, uint32_t *cp) 110 { 111 if (!valid_hexstring(str)) { 112 return 1; 113 } 114 *cp = strtol(str, NULL, 16); 115 116 return 0; 117 } 118 119 int 120 range_parse(const char *str, struct range *range) 121 { 122 char *p; 123 124 if ((p = strstr(str, "..")) == NULL) { 125 /* input has the form "XXXXXX" */ 126 if (!valid_hexstring(str)) { 127 return 1; 128 } 129 range->lower = range->upper = strtol(str, NULL, 16); 130 } else { 131 /* input has the form "XXXXXX..XXXXXX" */ 132 *p = '\0'; 133 p += 2; 134 if (!valid_hexstring(str) || !valid_hexstring(p)) { 135 return 1; 136 } 137 range->lower = strtol(str, NULL, 16); 138 range->upper = strtol(p, NULL, 16); 139 } 140 141 return 0; 142 } 143 144 void 145 range_list_append(struct range **range, size_t *nranges, const struct range *new) 146 { 147 if (*nranges > 0 && (*range)[*nranges - 1].upper == new->lower) { 148 /* we can merge with previous entry */ 149 (*range)[*nranges - 1].upper = new->upper; 150 } else { 151 /* need to append new entry */ 152 if ((*range = realloc(*range, (++(*nranges)) * sizeof(**range))) == NULL) { 153 fprintf(stderr, "realloc: %s\n", strerror(errno)); 154 exit(1); 155 } 156 (*range)[*nranges - 1].lower = new->lower; 157 (*range)[*nranges - 1].upper = new->upper; 158 } 159 }