diff options
Diffstat (limited to 'lib/cleanpath.c')
-rw-r--r-- | lib/cleanpath.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/cleanpath.c b/lib/cleanpath.c new file mode 100644 index 0000000..344c705 --- /dev/null +++ b/lib/cleanpath.c @@ -0,0 +1,110 @@ +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <regex.h> +#include "cleanpath.h" + +/** + * Split path into parts by sep + * @param path a string (e.g. "/path1:/path2:/pathN") + * @param sep a delimiter string (e.g. ":") + * @note CleanPath->data string is modified. part are pointers to addresses of path (i.e. do not free()) + * @return a pointer to a CleanPath structure + */ +struct CleanPath *cleanpath_init(const char *path, const char *sep) { + struct CleanPath *result; + char *elem; + size_t i; + + if (!path || !sep) { + return NULL; + } + + result = calloc(1, sizeof(*result)); + result->data = strndup(path, ARG_MAX); + result->data_len = strlen(result->data) + 2; // + 2 to handle an empty PATH + result->sep = strdup(sep); + + // Split string by separator + elem = strtok(result->data, sep); + for (i = 0; elem != NULL; i++) { + result->part[i] = elem; + elem = strtok(NULL, sep); + } + result->part_nelem = i; + + return result; +} + +/** + * Filter elements in CleanPath->part array by pattern + * @param path a pointer to a CleanPath structure + * @param mode an integer CLEANPATH_FILTER_EXACT, CLEANPATH_FILTER_LOOSE, or CLEANPATH_FILTER_REGEX + * @param pattern a string + * @see cleanpath_init() + * @note CLEANPATH_FILTER_EXACT is the default mode + */ +void cleanpath_filter(struct CleanPath *path, unsigned mode, const char *pattern) { + int match; + regex_t regex; + + for (size_t i = 0; path->part[i]; i++) { + match = 0; + switch(mode) { + case CLEANPATH_FILTER_LOOSE: + match = strstr(path->part[i], pattern) != NULL ? 1 : 0; + break; + case CLEANPATH_FILTER_REGEX: + if (regcomp(®ex, pattern, REG_EXTENDED | REG_NOSUB) != 0) { + return; + } + match = regexec(®ex, path->part[i], 0, NULL, 0) == 0 ? 1 : 0; + regfree(®ex); + break; + case CLEANPATH_FILTER_EXACT: + default: + match = strcmp(path->part[i], pattern) == 0 ? 1 : 0; + break; + } + + if (match) + *path->part[i] = '\0'; + } +} + +/** + * Reconstruct CleanPath->data using CleanPath->part and return a copy of the string + * @param path a pointer to a CleanPath structure + * @see cleanpath_filter() + * @return a string + */ +char *cleanpath_read(struct CleanPath *path) { + char *result; + + result = calloc(path->data_len, sizeof(char)); + for (size_t i = 0; path->part[i] != NULL; i++) { + // Ignore filtered paths + if (*path->part[i] == '\0') { + continue; + } + strcat(result, path->part[i]); + + // Do not append path separator on final element + if (path->part[i + 1] != NULL) { + strcat(result, path->sep); + } + } + + return result; +} + +/** + * Free memory allocated by cleanpath_init() + * @param path a pointer to a CleanPath structure + */ +void cleanpath_free(struct CleanPath *path) { + free(path->data); + free(path->sep); + free(path); +} + |