tizen 2.0
[external/module-init-tools.git] / util.c
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"
11
12 /*
13  * Read one logical line from a configuration file.
14  *
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.
18  *
19  * If linenum is not NULL, it is incremented by the number of physical lines
20  * which have been read.
21  */
22 char *getline_wrapped(FILE *file, unsigned int *linenum)
23 {
24         int size = 256;
25         int i = 0;
26         char *buf = NOFAIL(malloc(size));
27         for(;;) {
28                 int ch = getc_unlocked(file);
29
30                 switch(ch) {
31                 case EOF:
32                         if (i == 0) {
33                                 free(buf);
34                                 return NULL;
35                         }
36                         /* else fall through */
37
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;
45
46                 case '\\':
47                         ch = getc_unlocked(file);
48
49                         if (ch == '\n') {
50                                 if (linenum)
51                                         (*linenum)++;
52                                 continue;
53                         }
54                         /* else fall through */
55
56                 default:
57                         buf[i++] = ch;
58
59                         if (i == size) {
60                                 size *= 2;
61                                 buf = NOFAIL(realloc(buf, size));
62                         }
63                 }
64         }
65 }
66
67 /*
68  * Convert filename to the module name.  Works if filename == modname, too.
69  */
70 void filename2modname(char *modname, const char *filename)
71 {
72         const char *afterslash;
73         unsigned int i;
74
75         afterslash = my_basename(filename);
76
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];
83         }
84         modname[i] = '\0';
85 }
86
87 /*
88  * Replace dashes with underscores.
89  * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
90  */
91 char *underscores(char *string)
92 {
93         unsigned int i;
94
95         if (!string)
96                 return NULL;
97
98         for (i = 0; string[i]; i++) {
99                 switch (string[i]) {
100                 case '-':
101                         string[i] = '_';
102                         break;
103
104                 case ']':
105                         warn("Unmatched bracket in %s\n", string);
106                         break;
107
108                 case '[':
109                         i += strcspn(&string[i], "]");
110                         if (!string[i])
111                                 warn("Unmatched bracket in %s\n", string);
112                         break;
113                 }
114         }
115         return string;
116 }
117
118 /*
119  * strtbl_add - add a string to a string table.
120  *
121  * @str: string to add
122  * @tbl: current string table. NULL = allocate new table
123  *
124  * Allocates an array of pointers to strings.
125  * The strings themselves are not actually kept in the table.
126  *
127  * Returns reallocated and updated string table. NULL = out of memory.
128  *
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.
133  */
134 struct string_table *strtbl_add(const char *str, struct string_table *tbl)
135 {
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;
143         }
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;
149         }
150         tbl->str[tbl->cnt] = str;
151         tbl->cnt += 1;
152
153         return tbl;
154 }
155
156 /*
157  * strtbl_free - string table destructor
158  */
159 void strtbl_free(struct string_table *tbl)
160 {
161         free(tbl);
162 }
163
164 /*
165  * Get the basename in a pathname.
166  * Unlike the standard implementation, this does not copy the string.
167  */
168 char *my_basename(const char *path)
169 {
170         const char *base = strrchr(path, '/');
171         if (base)
172                 return (char *) base + 1;
173         return (char *) path;
174 }
175
176 /*
177  * Find the next string in an ELF section.
178  */
179 const char *next_string(const char *string, unsigned long *secsize)
180 {
181         /* Skip non-zero chars */
182         while (string[0]) {
183                 string++;
184                 if ((*secsize)-- <= 1)
185                         return NULL;
186         }
187
188         /* Skip any zero padding. */
189         while (!string[0]) {
190                 string++;
191                 if ((*secsize)-- <= 1)
192                         return NULL;
193         }
194         return string;
195 }
196
197 /*
198  * Get CPU endianness. 0 = unknown, 1 = ELFDATA2LSB = little, 2 = ELFDATA2MSB = big
199  */
200 int __attribute__ ((pure)) native_endianness()
201 {
202         /* Encoding the endianness enums in a string and then reading that
203          * string as a 32-bit int, returns the correct endianness automagically.
204          */
205         return (char) *((uint32_t*)("\1\0\0\2"));
206 }
207
208 /*
209  * Compare "string" with extended regex "pattern". Include backward compatible
210  * matching of "*" as a wildcard by replacing it with ".*" automatically.
211  */
212 int regex_match(const char *string, const char *pattern)
213 {
214         int status;
215         regex_t re;
216         char *fix_pattern;
217
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 */
223
224         if (regcomp(&re, fix_pattern, REG_EXTENDED|REG_NOSUB) != 0)
225                 return 0;       /* alloc failure */
226
227         status = regexec(&re, string, (size_t) 0, NULL, 0);
228         regfree(&re);
229
230         if (status != 0)
231                 return 0;       /* no match */
232
233         return 1;       /* match */
234 }