announce: module-init-tools to be replaced with new library-based tools
[module-init-tools.git] / util.c
blob59db9cb9b8af9f8b51589006849a1f292f9d0477
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <elf.h>
7 #include <sys/types.h>
8 #include <regex.h>
9 #include "logging.h"
10 #include "util.h"
13 * Read one logical line from a configuration file.
15 * Line endings may be escaped with backslashes, to form one logical line from
16 * several physical lines. No end of line character(s) are included in the
17 * result.
19 * If linenum is not NULL, it is incremented by the number of physical lines
20 * which have been read.
22 char *getline_wrapped(FILE *file, unsigned int *linenum)
24 int size = 256;
25 int i = 0;
26 char *buf = NOFAIL(malloc(size));
27 for(;;) {
28 int ch = getc_unlocked(file);
30 switch(ch) {
31 case EOF:
32 if (i == 0) {
33 free(buf);
34 return NULL;
36 /* else fall through */
38 case '\n':
39 if (linenum)
40 (*linenum)++;
41 if (i == size)
42 buf = NOFAIL(realloc(buf, size + 1));
43 buf[i] = '\0';
44 return buf;
46 case '\\':
47 ch = getc_unlocked(file);
49 if (ch == '\n') {
50 if (linenum)
51 (*linenum)++;
52 continue;
54 /* else fall through */
56 default:
57 buf[i++] = ch;
59 if (i == size) {
60 size *= 2;
61 buf = NOFAIL(realloc(buf, size));
68 * Convert filename to the module name. Works if filename == modname, too.
70 void filename2modname(char *modname, const char *filename)
72 const char *afterslash;
73 unsigned int i;
75 afterslash = my_basename(filename);
77 /* Convert to underscores, stop at first . */
78 for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) {
79 if (afterslash[i] == '-')
80 modname[i] = '_';
81 else
82 modname[i] = afterslash[i];
84 modname[i] = '\0';
88 * Replace dashes with underscores.
89 * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
91 char *underscores(char *string)
93 unsigned int i;
95 if (!string)
96 return NULL;
98 for (i = 0; string[i]; i++) {
99 switch (string[i]) {
100 case '-':
101 string[i] = '_';
102 break;
104 case ']':
105 warn("Unmatched bracket in %s\n", string);
106 break;
108 case '[':
109 i += strcspn(&string[i], "]");
110 if (!string[i])
111 warn("Unmatched bracket in %s\n", string);
112 break;
115 return string;
119 * strtbl_add - add a string to a string table.
121 * @str: string to add
122 * @tbl: current string table. NULL = allocate new table
124 * Allocates an array of pointers to strings.
125 * The strings themselves are not actually kept in the table.
127 * Returns reallocated and updated string table. NULL = out of memory.
129 * Implementation note: The string table is designed to be lighter-weight
130 * and faster than a more conventional linked list that stores the strings
131 * in the list elements, as it does far fewer malloc/realloc calls
132 * and avoids copying entirely.
134 struct string_table *strtbl_add(const char *str, struct string_table *tbl)
136 if (tbl == NULL) {
137 const char max = 100;
138 tbl = malloc(sizeof(*tbl) + sizeof(char *) * max);
139 if (!tbl)
140 return NULL;
141 tbl->max = max;
142 tbl->cnt = 0;
144 if (tbl->cnt >= tbl->max) {
145 tbl->max *= 2;
146 tbl = realloc(tbl, sizeof(*tbl) + sizeof(char *) * tbl->max);
147 if (!tbl)
148 return NULL;
150 tbl->str[tbl->cnt] = str;
151 tbl->cnt += 1;
153 return tbl;
157 * strtbl_free - string table destructor
159 void strtbl_free(struct string_table *tbl)
161 free(tbl);
165 * Get the basename in a pathname.
166 * Unlike the standard implementation, this does not copy the string.
168 char *my_basename(const char *path)
170 const char *base = strrchr(path, '/');
171 if (base)
172 return (char *) base + 1;
173 return (char *) path;
177 * Find the next string in an ELF section.
179 const char *next_string(const char *string, unsigned long *secsize)
181 /* Skip non-zero chars */
182 while (string[0]) {
183 string++;
184 if ((*secsize)-- <= 1)
185 return NULL;
188 /* Skip any zero padding. */
189 while (!string[0]) {
190 string++;
191 if ((*secsize)-- <= 1)
192 return NULL;
194 return string;
198 * Get CPU endianness. 0 = unknown, 1 = ELFDATA2LSB = little, 2 = ELFDATA2MSB = big
200 int __attribute__ ((pure)) native_endianness()
202 /* Encoding the endianness enums in a string and then reading that
203 * string as a 32-bit int, returns the correct endianness automagically.
205 return (char) *((uint32_t*)("\1\0\0\2"));
209 * Compare "string" with extended regex "pattern". Include backward compatible
210 * matching of "*" as a wildcard by replacing it with ".*" automatically.
212 int regex_match(const char *string, const char *pattern)
214 int status;
215 regex_t re;
216 char *fix_pattern;
218 /* backward compatibility with old "match" code */
219 if (strncmp("*", pattern, 1) != 0)
220 fix_pattern = (char *)pattern;
221 else
222 fix_pattern = ".*"; /* match everything */
224 if (regcomp(&re, fix_pattern, REG_EXTENDED|REG_NOSUB) != 0)
225 return 0; /* alloc failure */
227 status = regexec(&re, string, (size_t) 0, NULL, 0);
228 regfree(&re);
230 if (status != 0)
231 return 0; /* no match */
233 return 1; /* match */