2 // utils.c - Some helper code for debugging and error logging.
15 // Helper function to skip past all spaces (and comments)
16 // Returns a pointer to the first non-space character.
19 const char *after_spaces(const char *str, bool skip_nl, const char *end) {
20 // Skip whitespace and comments:
22 if (str >= end) return str;
27 __attribute__((fallthrough));
34 while (str < end && *str != '\n')
44 // Return the first character after a valid BP name, or NULL if none is
48 const char *after_name(const char *str, const char *end) {
49 if (str >= end) return end;
50 if (*str == '|') return &str[1];
51 if (*str == '^' || *str == '_' || *str == '$') {
52 return (&str[1] < end && str[1] == *str) ? &str[2] : &str[1];
54 if (!isalpha(*str)) return NULL;
55 for (++str; str < end; ++str) {
56 if (!(isalnum(*str) || *str == '-')) break;
62 // Check if a character is found and if so, move past it.
65 bool matchchar(const char **str, char c, bool skip_nl, const char *end) {
66 const char *next = after_spaces(*str, skip_nl, end);
67 if (next >= end) return false;
76 // Check if a string is found and if so, move past it.
79 bool matchstr(const char **str, const char *target, bool skip_nl, const char *end) {
80 const char *next = after_spaces(*str, skip_nl, end);
81 if (next + strlen(target) > end) return false;
82 if (strncmp(next, target, strlen(target)) == 0) {
83 *str = &next[strlen(target)];
90 // Process a string escape sequence for a character and return the
91 // character that was escaped.
92 // Set *end = the first character past the end of the escape sequence.
95 char unescapechar(const char *escaped, const char **after, const char *end) {
97 unsigned char ret = '\\';
98 if (escaped >= end) goto finished;
99 ret = (unsigned char)*escaped;
102 case 'a': ret = '\a'; break;
103 case 'b': ret = '\b'; break;
104 case 'n': ret = '\n'; break;
105 case 'r': ret = '\r'; break;
106 case 't': ret = '\t'; break;
107 case 'v': ret = '\v'; break;
108 case 'e': ret = '\033'; break;
109 case '\\': ret = '\\'; break;
111 static const unsigned char hextable[255] = {
112 ['0'] = 0x10, ['1'] = 0x1, ['2'] = 0x2, ['3'] = 0x3, ['4'] = 0x4, ['5'] = 0x5, ['6'] = 0x6, ['7'] = 0x7,
113 ['8'] = 0x8, ['9'] = 0x9, ['a'] = 0xa, ['b'] = 0xb, ['c'] = 0xc, ['d'] = 0xd, ['e'] = 0xe, ['f'] = 0xf,
114 ['A'] = 0xa, ['B'] = 0xb, ['C'] = 0xc, ['D'] = 0xd, ['E'] = 0xe, ['F'] = 0xf,
116 if (escaped + 2 >= end) {
119 } else if (hextable[(int)escaped[1]] && hextable[(int)escaped[2]]) {
120 ret = (hextable[(int)escaped[1]] << 4) | (hextable[(int)escaped[2]] & 0xF);
133 ret = (unsigned char)(escaped[0] - '0');
134 if (escaped + 2 >= end) {
137 } else if ('0' <= escaped[1] && escaped[1] <= '7') {
139 ret = (ret << 3) | (escaped[1] - '0');
140 if ('0' <= escaped[2] && escaped[2] <= '7') {
142 ret = (ret << 3) | (escaped[2] - '0');
147 default: len = 0; goto finished;
150 if (after) *after = &escaped[len];
155 // Free memory, but also set the pointer to NULL for safety
158 void delete(void *p) {
159 if (*(void **)p == NULL) errx(EXIT_FAILURE, "attempt to free(NULL)");
161 *((void **)p) = NULL;
164 // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0