blob: 59db9cb9b8af9f8b51589006849a1f292f9d0477 [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <elf.h>
#include <sys/types.h>
#include <regex.h>
#include "logging.h"
#include "util.h"
/*
* Read one logical line from a configuration file.
*
* Line endings may be escaped with backslashes, to form one logical line from
* several physical lines. No end of line character(s) are included in the
* result.
*
* If linenum is not NULL, it is incremented by the number of physical lines
* which have been read.
*/
char *getline_wrapped(FILE *file, unsigned int *linenum)
{
int size = 256;
int i = 0;
char *buf = NOFAIL(malloc(size));
for(;;) {
int ch = getc_unlocked(file);
switch(ch) {
case EOF:
if (i == 0) {
free(buf);
return NULL;
}
/* else fall through */
case '\n':
if (linenum)
(*linenum)++;
if (i == size)
buf = NOFAIL(realloc(buf, size + 1));
buf[i] = '\0';
return buf;
case '\\':
ch = getc_unlocked(file);
if (ch == '\n') {
if (linenum)
(*linenum)++;
continue;
}
/* else fall through */
default:
buf[i++] = ch;
if (i == size) {
size *= 2;
buf = NOFAIL(realloc(buf, size));
}
}
}
}
/*
* Convert filename to the module name. Works if filename == modname, too.
*/
void filename2modname(char *modname, const char *filename)
{
const char *afterslash;
unsigned int i;
afterslash = my_basename(filename);
/* Convert to underscores, stop at first . */
for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) {
if (afterslash[i] == '-')
modname[i] = '_';
else
modname[i] = afterslash[i];
}
modname[i] = '\0';
}
/*
* Replace dashes with underscores.
* Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
*/
char *underscores(char *string)
{
unsigned int i;
if (!string)
return NULL;
for (i = 0; string[i]; i++) {
switch (string[i]) {
case '-':
string[i] = '_';
break;
case ']':
warn("Unmatched bracket in %s\n", string);
break;
case '[':
i += strcspn(&string[i], "]");
if (!string[i])
warn("Unmatched bracket in %s\n", string);
break;
}
}
return string;
}
/*
* strtbl_add - add a string to a string table.
*
* @str: string to add
* @tbl: current string table. NULL = allocate new table
*
* Allocates an array of pointers to strings.
* The strings themselves are not actually kept in the table.
*
* Returns reallocated and updated string table. NULL = out of memory.
*
* Implementation note: The string table is designed to be lighter-weight
* and faster than a more conventional linked list that stores the strings
* in the list elements, as it does far fewer malloc/realloc calls
* and avoids copying entirely.
*/
struct string_table *strtbl_add(const char *str, struct string_table *tbl)
{
if (tbl == NULL) {
const char max = 100;
tbl = malloc(sizeof(*tbl) + sizeof(char *) * max);
if (!tbl)
return NULL;
tbl->max = max;
tbl->cnt = 0;
}
if (tbl->cnt >= tbl->max) {
tbl->max *= 2;
tbl = realloc(tbl, sizeof(*tbl) + sizeof(char *) * tbl->max);
if (!tbl)
return NULL;
}
tbl->str[tbl->cnt] = str;
tbl->cnt += 1;
return tbl;
}
/*
* strtbl_free - string table destructor
*/
void strtbl_free(struct string_table *tbl)
{
free(tbl);
}
/*
* Get the basename in a pathname.
* Unlike the standard implementation, this does not copy the string.
*/
char *my_basename(const char *path)
{
const char *base = strrchr(path, '/');
if (base)
return (char *) base + 1;
return (char *) path;
}
/*
* Find the next string in an ELF section.
*/
const char *next_string(const char *string, unsigned long *secsize)
{
/* Skip non-zero chars */
while (string[0]) {
string++;
if ((*secsize)-- <= 1)
return NULL;
}
/* Skip any zero padding. */
while (!string[0]) {
string++;
if ((*secsize)-- <= 1)
return NULL;
}
return string;
}
/*
* Get CPU endianness. 0 = unknown, 1 = ELFDATA2LSB = little, 2 = ELFDATA2MSB = big
*/
int __attribute__ ((pure)) native_endianness()
{
/* Encoding the endianness enums in a string and then reading that
* string as a 32-bit int, returns the correct endianness automagically.
*/
return (char) *((uint32_t*)("\1\0\0\2"));
}
/*
* Compare "string" with extended regex "pattern". Include backward compatible
* matching of "*" as a wildcard by replacing it with ".*" automatically.
*/
int regex_match(const char *string, const char *pattern)
{
int status;
regex_t re;
char *fix_pattern;
/* backward compatibility with old "match" code */
if (strncmp("*", pattern, 1) != 0)
fix_pattern = (char *)pattern;
else
fix_pattern = ".*"; /* match everything */
if (regcomp(&re, fix_pattern, REG_EXTENDED|REG_NOSUB) != 0)
return 0; /* alloc failure */
status = regexec(&re, string, (size_t) 0, NULL, 0);
regfree(&re);
if (status != 0)
return 0; /* no match */
return 1; /* match */
}