From bc3013fc68746265db78bf92623f7e6e3e469264 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 16 May 2021 21:06:48 -0400 Subject: Add default path (#6) * Add default path * Improve support/implementation logic * Fix braces in tests * Enable warnings * Emit more generalized form of windows path * Change initialization order * Add --default/-D to documentation * Fix platform detection --- CMakeLists.txt | 9 ++++++++ README.md | 1 + config.h.in | 2 +- docs/man/cleanpath.1 | 7 ++++++ include/cleanpath/cleanpath.h | 14 +++++++++--- src/main.c | 46 ++++++++++++++++++++++++++++++++++----- tests/CMakeLists.txt | 2 +- tests/test_errors.c | 6 +++-- tests/test_modes_filter_all.c | 12 +++++----- tests/test_modes_filter_general.c | 12 +++++----- 10 files changed, 86 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 604534b..823cddf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.0) project(cleanpath) include(CheckIncludeFile) +include(CheckSymbolExists) include(CTest) set(CMAKE_C_STANDARD 99) @@ -9,12 +10,20 @@ set(LIB_SOURCES lib/cleanpath.c) set(MAIN_SOURCES src/main.c) set(LIB_INCLUDES include/cleanpath/cleanpath.h) +check_symbol_exists(confstr "unistd.h" HAVE_CONFSTR) + configure_file ("${PROJECT_SOURCE_DIR}/config.h.in" "${PROJECT_BINARY_DIR}/include/config.h") include_directories(${PROJECT_BINARY_DIR}/include) include_directories(${CMAKE_SOURCE_DIR}/include) +if(MSVC) + add_compile_options(/W4) +else() + add_compile_options(-Wall -Wextra) +endif() + enable_testing() add_subdirectory(tests) diff --git a/README.md b/README.md index 9cdb00f..838a1bc 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ $ make install usage: cleanpath [-hVelrsE] [pattern ...] --help -h Displays this help message --version -V Displays the program's version + --default -D Displays default operating system PATH --list Format output as a list --exact -e Filter when pattern is an exact match (default) --loose -l Filter when any part of the pattern matches diff --git a/config.h.in b/config.h.in index 777f43c..f1292c7 100644 --- a/config.h.in +++ b/config.h.in @@ -1,6 +1,6 @@ #ifndef CLEAN_PATH_CONFIG_H #define CLEAN_PATH_CONFIG_H -// Reserved for later use +#cmakedefine HAVE_CONFSTR @HAVE_CONFSTR@ #endif \ No newline at end of file diff --git a/docs/man/cleanpath.1 b/docs/man/cleanpath.1 index ba3db63..6b3aa84 100644 --- a/docs/man/cleanpath.1 +++ b/docs/man/cleanpath.1 @@ -23,6 +23,13 @@ Prints brief usage information. \f[B]-V\f[R], \f[B]--version\f[R] Prints the current version number. .TP +\f[B]-D\f[R], \f[B]--default\f[R] +Prints the default operating system PATH +.RS +.PP +No other arguments are honored and no filtering will occur. +.RE +.TP \f[B]--list\f[R] Format output as a list .TP diff --git a/include/cleanpath/cleanpath.h b/include/cleanpath/cleanpath.h index afee624..dfb0b5f 100644 --- a/include/cleanpath/cleanpath.h +++ b/include/cleanpath/cleanpath.h @@ -38,13 +38,21 @@ #define CLEANPATH_PART_MAX 1024 #define CLEANPATH_VAR "PATH" #define CLEANPATH_SEP ":" -#define CLEANPATH_MSG_NOAVAIL "" +#define CLEANPATH_MSG_NOT_IMPLEMENTED "[not implemented]" +#define CLEANPATH_MSG_NOT_SUPPORTED "[not supported]" +#define CLEANPATH_MSG_NO_REGEX "" +#define CLEANPATH_MSG_NO_DEFAULT_PATH "" #if OS_WINDOWS #undef CLEANPATH_SEP #define CLEANPATH_SEP ";" -#undef CLEANPATH_MSG_NOAVAIL -#define CLEANPATH_MSG_NOAVAIL " [not implemented] " +#undef CLEANPATH_MSG_NO_REGEX +#define CLEANPATH_MSG_NO_REGEX CLEANPATH_MSG_NOT_IMPLEMENTED +#endif + +#if !OS_SUPPORTED +#undef CLEANPATH_MSG_NO_DEFAULT_PATH +#define CLEANPATH_MSG_NO_DEFAULT_PATH CLEANPATH_MSG_NOT_SUPPORTED #endif struct CleanPath { diff --git a/src/main.c b/src/main.c index 7b60bbe..71cc6fd 100644 --- a/src/main.c +++ b/src/main.c @@ -2,8 +2,13 @@ #include #include #include +#include "config.h" #include "cleanpath/cleanpath.h" +#if !OS_WINDOWS +#include +#endif + // Make argument parsing less wordy #define ARGM(X) strcmp(argv[i], X) == 0 @@ -51,6 +56,25 @@ void show_listing(struct CleanPath *path) { } } +static int show_default_path() { + char buf[CLEANPATH_PART_MAX]; +#if OS_WINDOWS + // I could not find anything in MSDN about dumping default path information. + // The internet agrees "this" is "it" (XP/Vista/8/10): + strncpy(buf, "%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;", sizeof(buf)); +#elif HAVE_CONFSTR // POSIX + size_t cf_status; + cf_status = confstr(_CS_PATH, buf, sizeof(buf)); + if (cf_status < 1) { // 0 and -1 are possible error codes for linux and darwin + return 1; + } +#else + *buf = '\0'; +#endif + puts(buf); + return 0; +} + void show_path(struct CleanPath *path) { char *result; @@ -71,13 +95,14 @@ static void show_usage() { char *bname; bname = strrchr(program, '/'); - printf("usage: %s [-hVelrsv] [pattern ...]\n", bname ? bname + 1 : program); + printf("usage: %s [-hVDelrsv] [pattern ...]\n", bname ? bname + 1 : program); printf(" --help -h Displays this help message\n"); printf(" --version -V Displays the program's version\n"); + printf(" --default -D Displays default operating system PATH " CLEANPATH_MSG_NO_DEFAULT_PATH "\n"); printf(" --list Format output as a list\n"); printf(" --exact -e Filter when pattern is an exact match (default)\n"); printf(" --loose -l Filter when any part of the pattern matches\n"); - printf(" --regex -r Filter matches with (Extended) Regular Expressions " CLEANPATH_MSG_NOAVAIL "\n"); + printf(" --regex -r Filter matches with (Extended) Regular Expressions " CLEANPATH_MSG_NO_REGEX "\n"); printf(" --sep [str] -s Use custom path separator (default: ':')\n"); printf(" --env [str] -E Use custom environment variable (default: PATH)\n"); } @@ -86,27 +111,28 @@ int main(int argc, char *argv[]) { struct CleanPath *path; char *sep; char *sys_var; - char *result; - size_t pattern_nelem; int do_listing; + int do_default_path; int filter_mode; int args_invalid; + size_t pattern_nelem; char *pattern[CLEANPATH_PART_MAX]; program = argv[0]; - result = NULL; sys_var = NULL; sep = CLEANPATH_SEP; do_listing = 0; + do_default_path = 0; filter_mode = CLEANPATH_FILTER_NONE; - memset(pattern, 0, sizeof(pattern) / sizeof(char *)); pattern_nelem = 0; + memset(pattern, 0, (sizeof(pattern) / sizeof(char *)) * sizeof(char *)); args_invalid = 0; char *args_valid[] = { "--help", "-h", "--version", "-V", "--list", + "--default", "-D", "--exact", "-e", "--loose", "-l", "--regex", "-r", @@ -135,6 +161,9 @@ int main(int argc, char *argv[]) { if (ARGM("--list")) { do_listing = 1; } + if (ARGM("--default") || ARGM("-D")) { + do_default_path = 1; + } if (ARGM("--exact") || ARGM("-e")) { filter_mode = CLEANPATH_FILTER_EXACT; continue; @@ -173,6 +202,11 @@ int main(int argc, char *argv[]) { pattern_nelem++; } + // Show default system path, and exit + if (do_default_path) { + exit(show_default_path()); + } + // Use default environment variable when not set by --var if (sys_var == NULL) { sys_var = getenv_ex(CLEANPATH_VAR); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7a56301..7a7d3db 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,7 +27,7 @@ endforeach() # processes. set(TEST_SETUP -E TESTVAR) -if(${CMAKE_SYSTEM_NAME} EQUAL WINDOWS) +if(WIN32) set(TEST_SETUP ${TEST_SETUP}_WIN) set(exec ${CMAKE_BINARY_DIR}/cleanpath.exe) diff --git a/tests/test_errors.c b/tests/test_errors.c index 82241ed..18c444e 100644 --- a/tests/test_errors.c +++ b/tests/test_errors.c @@ -6,6 +6,8 @@ int main() { path = NULL; //intentionally bad - myassert(cleanpath_init("good", NULL) == NULL, "cleanpath_init() returned non-NULL on NULL sep\n"); - myassert(cleanpath_init(NULL, "good") == NULL, "cleanpath_init() returned non-NULL on NULL path\n"); + myassert((path = cleanpath_init("good", NULL)) == NULL, "cleanpath_init() returned non-NULL on NULL sep\n"); + if (path) cleanpath_free(path); + myassert((path = cleanpath_init(NULL, "good")) == NULL, "cleanpath_init() returned non-NULL on NULL path\n"); + if (path) cleanpath_free(path); } diff --git a/tests/test_modes_filter_all.c b/tests/test_modes_filter_all.c index d57b418..3893be0 100644 --- a/tests/test_modes_filter_all.c +++ b/tests/test_modes_filter_all.c @@ -30,7 +30,7 @@ char *modes_str[MAX_MODE] = { const char *inputs[MAX_MODE][MAX_PART][MAX_RECORD] = { { // Filter exact - "/opt/local/bin", + {"/opt/local/bin", "/opt/local/sbin", "/usr/local/bin", "/usr/bin", @@ -39,16 +39,16 @@ const char *inputs[MAX_MODE][MAX_PART][MAX_RECORD] = { "/sbin", "/opt/X11/bin", "/Library/Apple/usr/bin", - NULL + NULL} }, { // Filter loose - "bin", - NULL + {"bin", + NULL} }, #if !OS_WINDOWS { // Filter regex - ".*", - NULL + {".*", + NULL} }, #endif }; diff --git a/tests/test_modes_filter_general.c b/tests/test_modes_filter_general.c index 45206a4..d33ebb9 100644 --- a/tests/test_modes_filter_general.c +++ b/tests/test_modes_filter_general.c @@ -29,22 +29,22 @@ char *modes_str[MAX_MODE] = { const char *inputs[MAX_MODE][MAX_PART][MAX_RECORD] = { { // Filter exact - "/opt/local/bin", + {"/opt/local/bin", "/opt/local/sbin", "intentionally bad", // test non-existent pattern in string - NULL + NULL} }, { // Filter loose - "/opt/local", + {"/opt/local", "intentionally bad", // test non-existent pattern in string - NULL + NULL} }, #if !OS_WINDOWS { // Filter regex - "^/opt/local/.*", + {"^/opt/local/.*", "intentionally bad", // test non-existent pattern in string "intentionally worse (", // cause total regex failure with unmatched parenthesis - NULL + NULL} }, #endif }; -- cgit