Drop PCRE dependency.

The config file is now manually parsed instead of using regex.
While this is less beautifull, it allows us to drop PCRE
as a dependency on Windows.
This commit is contained in:
xaqq 2015-07-22 15:47:36 +02:00
parent 6be73720fa
commit 17ed36a7a5
7 changed files with 122 additions and 101 deletions

View file

@ -47,16 +47,6 @@ ENDIF(SPI_REQUIRED)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
IF(WIN32)
# Windows now requires regex, so we utilize PCRE
# since Windows doesn't get the benefit of finding in CMake
# it has to be added manually
IF(PCRE_FOUND)
INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIRS})
LINK_DIRECTORIES(${PCRE_LIBRARY_DIRS})
ENDIF(PCRE_FOUND)
ENDIF(WIN32)
IF(PCSC_FOUND)
INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS})
LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS})
@ -94,9 +84,6 @@ SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 5 VERSION 5.0.1)
IF(WIN32)
# Libraries that are windows specific
TARGET_LINK_LIBRARIES(nfc wsock32)
IF(PCRE_FOUND)
TARGET_LINK_LIBRARIES(nfc ${PCRE_LIBRARIES})
ENDIF(PCRE_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT libnfc.lib

View file

@ -33,9 +33,9 @@
#ifdef CONFFILES
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#include <regex.h>
#include <sys/stat.h>
#include <nfc/nfc.h>
@ -56,8 +56,122 @@
#define LIBNFC_CONFFILE LIBNFC_SYSCONFDIR"/libnfc.conf"
#define LIBNFC_DEVICECONFDIR LIBNFC_SYSCONFDIR"/devices.d"
static int
escaped_value(const char line[BUFSIZ], int i, char **value)
{
if (line[i] != '"')
goto FAIL;
i++;
if (line[i] == 0 || line[i] == '\n')
goto FAIL;
int c = 0;
while (line[i] && line[i] != '"') {
i++;
c++;
}
if (line[i] != '"')
goto FAIL;
*value = malloc(c + 1);
if (!*value)
goto FAIL;
memset(*value, 0, c + 1);
memcpy(*value, &line[i - c], c);
i++;
while (line[i] && isspace(line[i]))
i++;
if (line[i] != 0 && line[i] != '\n')
goto FAIL;
return 0;
FAIL:
free(*value);
*value = NULL;
return -1;
}
static int
non_escaped_value(const char line[BUFSIZ], int i, char **value)
{
int c = 0;
while (line[i] && !isspace(line[i])) {
i++;
c++;
}
*value = malloc(c + 1);
if (!*value)
goto FAIL;
memset(*value, 0, c + 1);
memcpy(*value, &line[i - c], c);
i++;
while (line[i] && isspace(line[i]))
i++;
if (line[i] != 0)
goto FAIL;
return 0;
FAIL:
free(*value);
*value = NULL;
return -1;
}
static int
parse_line(const char line[BUFSIZ], char **key, char **value)
{
*key = NULL;
*value = NULL;
int i = 0;
int c = 0;
// optional initial spaces
while (isspace(line[i]))
i++;
if (line[i] == 0 || line[i] == '\n')
return -1;
// key
while (isalnum(line[i]) || line[i] == '_' || line[i] == '.') {
i++;
c++;
}
if (c == 0 || line[i] == 0 || line[i] == '\n') // key is empty
return -1;
*key = malloc(c + 1);
if (!*key)
return -1;
memset(*key, 0, c + 1);
memcpy(*key, &line[i - c], c);
// space before '='
while (isspace(line[i]))
i++;
if (line[i] != '=')
return -1;
i++;
if (line[i] == 0 || line[i] == '\n')
return -1;
// space after '='
while (isspace(line[i]))
i++;
if (line[i] == 0 || line[i] == '\n')
return -1;
if (escaped_value(line, i, value) == 0)
return 0;
else if (non_escaped_value(line, i, value) == 0)
return 0;
// Extracting key or value failed
free(*key);
*key = NULL;
free(*value);
*value = NULL;
return -1;
}
static bool
conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const char *key, const char *value), void *data)
conf_parse_file(const char *filename,
void (*conf_keyvalue)(void *data, const char *key, const char *value),
void *data)
{
FILE *f = fopen(filename, "r");
if (!f) {
@ -65,21 +179,6 @@ conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const ch
return false;
}
char line[BUFSIZ];
const char *str_regex = "^[[:space:]]*([[:alnum:]_.]+)[[:space:]]*=[[:space:]]*(\"(.+)\"|([^[:space:]]+))[[:space:]]*$";
regex_t preg;
if (regcomp(&preg, str_regex, REG_EXTENDED | REG_NOTEOL) != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Regular expression used for configuration file parsing is not valid.");
fclose(f);
return false;
}
size_t nmatch = preg.re_nsub + 1;
regmatch_t *pmatch = malloc(sizeof(*pmatch) * nmatch);
if (!pmatch) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not enough memory: malloc failed.");
regfree(&preg);
fclose(f);
return false;
}
int lineno = 0;
while (fgets(line, BUFSIZ, f) != NULL) {
@ -89,29 +188,18 @@ conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const ch
case '\n':
break;
default: {
int match;
if ((match = regexec(&preg, line, nmatch, pmatch, 0)) == 0) {
const size_t key_size = pmatch[1].rm_eo - pmatch[1].rm_so;
const off_t value_pmatch = pmatch[3].rm_eo != -1 ? 3 : 4;
const size_t value_size = pmatch[value_pmatch].rm_eo - pmatch[value_pmatch].rm_so;
char key[key_size + 1];
char value[value_size + 1];
strncpy(key, line + (pmatch[1].rm_so), key_size);
key[key_size] = '\0';
strncpy(value, line + (pmatch[value_pmatch].rm_so), value_size);
value[value_size] = '\0';
char *key;
char *value;
if (parse_line(line, &key, &value) == 0) {
conf_keyvalue(data, key, value);
free(key);
free(value);
} else {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line);
}
}
break;
}
}
free(pmatch);
regfree(&preg);
fclose(f);
return false;
}