diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index aa38c38..45bcef6 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - name: "Checkout repository" + - name: checkout uses: actions/checkout@v3 with: submodules: 'true' diff --git a/include/SOM/Glob.h b/include/SOM/Glob.h new file mode 100644 index 0000000..dd91ef6 --- /dev/null +++ b/include/SOM/Glob.h @@ -0,0 +1,58 @@ +#pragma once +#ifndef GLOB_H +#define GLOB_H + +#include +#include +#include + +#include +#include +#include +#include + +class I_GlobProcessor +{ +public: + virtual void process(const std::string& fpath) = 0; + virtual ~I_GlobProcessor() = default; +}; + + +class Glob +{ +public: + Glob(I_GlobProcessor& proc, bool onlyFiles=false, bool onlyDirs=false); + void glob(const std::string& fpath); + +private: + using strVec = std::vector; + struct pathVec : strVec + { + void add(const std::string& s); + pathVec& operator << (const std::filesystem::directory_entry& e); + }; + + using ffunc = std::function; + static const ffunc fd; + static const ffunc ff; + static const ffunc fx; + static bool isGlob(const std::string& token); + static void tokenize(strVec& tokens, const std::string& fpath); + + const bool onlyDirs; + I_GlobProcessor& proc; + const ffunc filter; + pathVec buffs[2]; + UINT8 pSrc = 0; + UINT8 pTrg = 1; + inline pathVec& getSrc() { return buffs[pSrc]; } + inline pathVec& getTrg() { return buffs[pTrg]; } + void getAll(); + void getDirs(const pathVec& src, bool recursive=false); + void getGlob(const std::string& token, bool dirs=false); + void swap(); + + NOCOPY(Glob) +}; +#endif // _H diff --git a/include/SOM/GlobProcessors.h b/include/SOM/GlobProcessors.h new file mode 100644 index 0000000..b7b356e --- /dev/null +++ b/include/SOM/GlobProcessors.h @@ -0,0 +1,37 @@ +#pragma once +#ifndef GLOBPROCESSORS_H +#define GLOBPROCESSORS_H + +#include "Glob.h" +#include +#include + +#include + +class GlobTrace : public I_GlobProcessor +{ +public: + void process(const std::string& fpath) override; +}; + +class GlobXargs : public I_GlobProcessor +{ +public: + GlobXargs(CONST_C_STRING cmd, CONST_C_STRING placeholder=nullptr); + void process(const std::string& fpath) override; +private: + const std::string cmd; + const std::regex re; + NODEF(GlobXargs) + NOCOPY(GlobXargs) +}; + +class GlobArgs : public I_GlobProcessor +{ +public: + GlobArgs(); + ~GlobArgs(); + void process(const std::string& fpath) override; +}; + +#endif // _H diff --git a/include/SOM/docopts.h b/include/SOM/docopts.h index 4162e6c..813db09 100644 --- a/include/SOM/docopts.h +++ b/include/SOM/docopts.h @@ -10,7 +10,6 @@ class DocOpts { public: inline DocOpts() = default; - inline ~DocOpts() { rmArgs(); } bool process(CONST_C_STRING help, INT32 argc, const CONST_C_STRING* argv, INT32 start = 1); bool getValue(CONST_C_STRING& value, CHAR key) const; inline bool isSet(CHAR key) const @@ -18,7 +17,7 @@ class DocOpts return mSwitches.find(key) != mSwitches.end(); } void reset(); - CONST_C_STRING* args() const { return mArgs; } + const CONST_C_STRING* args() const { return mArgs; } INT32 argc() const { return mArgc; } void toShell() const; const std::set& activeSwitches() const { return mSwitches; } @@ -28,9 +27,8 @@ class DocOpts std::setmValueKeys; std::setmSwitchKeys; bool mOk = false; - CONST_C_STRING* mArgs = nullptr; + const CONST_C_STRING* mArgs = nullptr; INT32 mArgc = 0; - void rmArgs(); NOCOPY(DocOpts) }; diff --git a/include/SOM/fglob.h b/include/SOM/fglob.h index 60ee14a..72bbad1 100644 --- a/include/SOM/fglob.h +++ b/include/SOM/fglob.h @@ -11,20 +11,21 @@ #define FGLOB_H #include +#include class I_FglobProcessor { public: - virtual void process(CONST_C_STRING fpath) = 0; + virtual void process(const std::string& fpath) = 0; }; //! glob files //! @param item file, or directory with file glob pattern -//! @param proc I_FglobProcessor +//! @param proc I_GlobProcessor #ifdef _WIN32 -void fglob(CONST_C_STRING item, I_FglobProcessor& proc); +void fglob(const std::string& item, I_FglobProcessor& proc); #else -inline void fglob(CONST_C_STRING item, I_FglobProcessor& proc) +inline void fglob(const std::string& item, I_FglobProcessor& proc) { proc.process(item); } diff --git a/make/Makefile b/make/Makefile index 90d1f2a..538e1e6 100644 --- a/make/Makefile +++ b/make/Makefile @@ -11,23 +11,26 @@ endif ifeq ($(config),ci) docopts_config = ci fglob_config = ci - lib_config = ci + glob_config = ci + somcpp_config = ci else ifeq ($(config),trace_on) docopts_config = trace_on fglob_config = trace_on - lib_config = trace_on + glob_config = trace_on + somcpp_config = trace_on else ifeq ($(config),trace_all) docopts_config = trace_all fglob_config = trace_all - lib_config = trace_all + glob_config = trace_all + somcpp_config = trace_all else $(error "invalid configuration $(config)") endif -PROJECTS := docopts fglob lib +PROJECTS := docopts fglob glob somcpp .PHONY: all clean help $(PROJECTS) @@ -45,16 +48,23 @@ ifneq (,$(fglob_config)) @${MAKE} --no-print-directory -C . -f fglob.make config=$(fglob_config) endif -lib: -ifneq (,$(lib_config)) - @echo "==== Building lib ($(lib_config)) ====" - @${MAKE} --no-print-directory -C . -f lib.make config=$(lib_config) +glob: +ifneq (,$(glob_config)) + @echo "==== Building glob ($(glob_config)) ====" + @${MAKE} --no-print-directory -C . -f glob.make config=$(glob_config) +endif + +somcpp: +ifneq (,$(somcpp_config)) + @echo "==== Building somcpp ($(somcpp_config)) ====" + @${MAKE} --no-print-directory -C . -f somcpp.make config=$(somcpp_config) endif clean: @${MAKE} --no-print-directory -C . -f docopts.make clean @${MAKE} --no-print-directory -C . -f fglob.make clean - @${MAKE} --no-print-directory -C . -f lib.make clean + @${MAKE} --no-print-directory -C . -f glob.make clean + @${MAKE} --no-print-directory -C . -f somcpp.make clean help: @echo "Usage: make [config=name] [target]" @@ -69,6 +79,7 @@ help: @echo " clean" @echo " docopts" @echo " fglob" - @echo " lib" + @echo " glob" + @echo " somcpp" @echo "" @echo "For more information, see https://github.com/premake/premake-core/wiki" \ No newline at end of file diff --git a/make/docopts.make b/make/docopts.make index 0e89c77..458f03b 100644 --- a/make/docopts.make +++ b/make/docopts.make @@ -39,15 +39,15 @@ define POSTBUILDCMDS endef ifeq ($(config),ci) -OBJDIR = ../build/linux/ci/ci/docopts +OBJDIR = ../build/linux/ci/docopts DEFINES += -DNDEBUG else ifeq ($(config),trace_on) -OBJDIR = ../build/linux/trace_on/trace_on/docopts +OBJDIR = ../build/linux/trace_on/docopts DEFINES += -DNDEBUG -DTRACE_ON else ifeq ($(config),trace_all) -OBJDIR = ../build/linux/trace_all/trace_all/docopts +OBJDIR = ../build/linux/trace_all/docopts DEFINES += -DNDEBUG -DTRACE_ALL endif diff --git a/make/fglob.make b/make/fglob.make index 783d725..273a47e 100644 --- a/make/fglob.make +++ b/make/fglob.make @@ -39,15 +39,15 @@ define POSTBUILDCMDS endef ifeq ($(config),ci) -OBJDIR = ../build/linux/ci/ci/fglob +OBJDIR = ../build/linux/ci/fglob DEFINES += -DNDEBUG else ifeq ($(config),trace_on) -OBJDIR = ../build/linux/trace_on/trace_on/fglob +OBJDIR = ../build/linux/trace_on/fglob DEFINES += -DNDEBUG -DTRACE_ON else ifeq ($(config),trace_all) -OBJDIR = ../build/linux/trace_all/trace_all/fglob +OBJDIR = ../build/linux/trace_all/fglob DEFINES += -DNDEBUG -DTRACE_ALL endif diff --git a/make/glob.make b/make/glob.make new file mode 100644 index 0000000..f5ad7e0 --- /dev/null +++ b/make/glob.make @@ -0,0 +1,152 @@ +# Alternative GNU Make project makefile autogenerated by Premake + +ifndef config + config=ci +endif + +ifndef verbose + SILENT = @ +endif + +.PHONY: clean prebuild + +SHELLTYPE := posix +ifeq ($(shell echo "test"), "test") + SHELLTYPE := msdos +endif + +# Configurations +# ############################################# + +RESCOMP = windres +TARGETDIR = ../build +TARGET = $(TARGETDIR)/glob +INCLUDES += -I../include +FORCE_INCLUDE += +ALL_CPPFLAGS += $(CPPFLAGS) -MD -MP $(DEFINES) $(INCLUDES) +ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -Os -std=c++17 -O3 -pedantic-errors -Wall +ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -Os -std=c++17 -O3 -pedantic-errors -Wall +ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) +LIBS += +LDDEPS += +ALL_LDFLAGS += $(LDFLAGS) -s +LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) +define PREBUILDCMDS +endef +define PRELINKCMDS +endef +define POSTBUILDCMDS +endef + +ifeq ($(config),ci) +OBJDIR = ../build/linux/ci/glob +DEFINES += -DNDEBUG + +else ifeq ($(config),trace_on) +OBJDIR = ../build/linux/trace_on/glob +DEFINES += -DNDEBUG -DTRACE_ON + +else ifeq ($(config),trace_all) +OBJDIR = ../build/linux/trace_all/glob +DEFINES += -DNDEBUG -DTRACE_ALL + +endif + +# Per File Configurations +# ############################################# + + +# File sets +# ############################################# + +GENERATED := +OBJECTS := + +GENERATED += $(OBJDIR)/Glob.o +GENERATED += $(OBJDIR)/GlobProcessors.o +GENERATED += $(OBJDIR)/docopts.o +GENERATED += $(OBJDIR)/globMain.o +OBJECTS += $(OBJDIR)/Glob.o +OBJECTS += $(OBJDIR)/GlobProcessors.o +OBJECTS += $(OBJDIR)/docopts.o +OBJECTS += $(OBJDIR)/globMain.o + +# Rules +# ############################################# + +all: $(TARGET) + @: + +$(TARGET): $(GENERATED) $(OBJECTS) $(LDDEPS) | $(TARGETDIR) + $(PRELINKCMDS) + @echo Linking glob + $(SILENT) $(LINKCMD) + $(POSTBUILDCMDS) + +$(TARGETDIR): + @echo Creating $(TARGETDIR) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(TARGETDIR) +else + $(SILENT) mkdir $(subst /,\\,$(TARGETDIR)) +endif + +$(OBJDIR): + @echo Creating $(OBJDIR) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + +clean: + @echo Cleaning glob +ifeq (posix,$(SHELLTYPE)) + $(SILENT) rm -f $(TARGET) + $(SILENT) rm -rf $(GENERATED) + $(SILENT) rm -rf $(OBJDIR) +else + $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) + $(SILENT) if exist $(subst /,\\,$(GENERATED)) del /s /q $(subst /,\\,$(GENERATED)) + $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) +endif + +prebuild: | $(OBJDIR) + $(PREBUILDCMDS) + +ifneq (,$(PCH)) +$(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER) +$(GCH): $(PCH) | prebuild + @echo $(notdir $<) + $(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<" +$(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) touch "$@" +else + $(SILENT) echo $null >> "$@" +endif +else +$(OBJECTS): | prebuild +endif + + +# File Rules +# ############################################# + +$(OBJDIR)/globMain.o: ../runtime/globMain.cpp + @echo "$(notdir $<)" + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/Glob.o: ../src/Glob.cpp + @echo "$(notdir $<)" + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/GlobProcessors.o: ../src/GlobProcessors.cpp + @echo "$(notdir $<)" + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/docopts.o: ../src/docopts.cpp + @echo "$(notdir $<)" + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" + +-include $(OBJECTS:%.o=%.d) +ifneq (,$(PCH)) + -include $(PCH_PLACEHOLDER).d +endif \ No newline at end of file diff --git a/make/premake5.lua b/make/premake5.lua index ca85915..72a233f 100644 --- a/make/premake5.lua +++ b/make/premake5.lua @@ -12,6 +12,7 @@ workspace 'somcpp' language 'C++' targetdir '../build' objdir '../build/%{_TARGET_OS}' + kind 'consoleapp' defines { 'NDEBUG' } optimize 'Size' @@ -33,13 +34,18 @@ workspace 'somcpp' defines { 'TRACE_ALL' } project 'docopts' - kind 'consoleapp' files { '../src/fio.cpp', '../src/docopts.cpp', '../runtime/docoptsMain.cpp' } project 'fglob' - kind 'consoleapp' files { '../src/fglob.cpp', '../runtime/fglobMain.cpp' } - project 'lib' + project 'glob' + files { '../src/Glob.cpp', '../src/GlobProcessors.cpp', '../src/docopts.cpp', '../runtime/globMain.cpp' } + + -- project 'lab' + -- files { '../lab/*.cpp', '../src/*.cpp' } + -- includedirs { '../lab' } + + project 'somcpp' kind 'staticlib' files { '../src/*.cpp' } diff --git a/make/lib.make b/make/somcpp.make similarity index 83% rename from make/lib.make rename to make/somcpp.make index c4cc744..e64c9f8 100644 --- a/make/lib.make +++ b/make/somcpp.make @@ -20,7 +20,7 @@ endif RESCOMP = windres TARGETDIR = ../build -TARGET = $(TARGETDIR)/liblib.a +TARGET = $(TARGETDIR)/libsomcpp.a INCLUDES += -I../include FORCE_INCLUDE += ALL_CPPFLAGS += $(CPPFLAGS) -MD -MP $(DEFINES) $(INCLUDES) @@ -39,15 +39,15 @@ define POSTBUILDCMDS endef ifeq ($(config),ci) -OBJDIR = ../build/linux/ci/ci/lib +OBJDIR = ../build/linux/ci/somcpp DEFINES += -DNDEBUG else ifeq ($(config),trace_on) -OBJDIR = ../build/linux/trace_on/trace_on/lib +OBJDIR = ../build/linux/trace_on/somcpp DEFINES += -DNDEBUG -DTRACE_ON else ifeq ($(config),trace_all) -OBJDIR = ../build/linux/trace_all/trace_all/lib +OBJDIR = ../build/linux/trace_all/somcpp DEFINES += -DNDEBUG -DTRACE_ALL endif @@ -62,9 +62,13 @@ endif GENERATED := OBJECTS := +GENERATED += $(OBJDIR)/Glob.o +GENERATED += $(OBJDIR)/GlobProcessors.o GENERATED += $(OBJDIR)/docopts.o GENERATED += $(OBJDIR)/fglob.o GENERATED += $(OBJDIR)/fio.o +OBJECTS += $(OBJDIR)/Glob.o +OBJECTS += $(OBJDIR)/GlobProcessors.o OBJECTS += $(OBJDIR)/docopts.o OBJECTS += $(OBJDIR)/fglob.o OBJECTS += $(OBJDIR)/fio.o @@ -77,7 +81,7 @@ all: $(TARGET) $(TARGET): $(GENERATED) $(OBJECTS) $(LDDEPS) | $(TARGETDIR) $(PRELINKCMDS) - @echo Linking lib + @echo Linking somcpp $(SILENT) $(LINKCMD) $(POSTBUILDCMDS) @@ -98,7 +102,7 @@ else endif clean: - @echo Cleaning lib + @echo Cleaning somcpp ifeq (posix,$(SHELLTYPE)) $(SILENT) rm -f $(TARGET) $(SILENT) rm -rf $(GENERATED) @@ -131,6 +135,12 @@ endif # File Rules # ############################################# +$(OBJDIR)/Glob.o: ../src/Glob.cpp + @echo "$(notdir $<)" + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/GlobProcessors.o: ../src/GlobProcessors.cpp + @echo "$(notdir $<)" + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" $(OBJDIR)/docopts.o: ../src/docopts.cpp @echo "$(notdir $<)" $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" diff --git a/runtime/fglobMain.cpp b/runtime/fglobMain.cpp index d341e69..f8cae41 100644 --- a/runtime/fglobMain.cpp +++ b/runtime/fglobMain.cpp @@ -21,7 +21,7 @@ class GlobOut : public I_FglobProcessor cout << '\n'; } - void process(CONST_C_STRING item) override + void process(const std::string& item) override { cout << item << ' '; } diff --git a/runtime/globMain.cpp b/runtime/globMain.cpp new file mode 100644 index 0000000..f1297a7 --- /dev/null +++ b/runtime/globMain.cpp @@ -0,0 +1,61 @@ +#include +#include +#include + +#include +#include +#include + +const CONST_C_STRING cOpts = + "options:\n" + "-x command to execute with each arg\n" + "-p placeholder for command\n" + " default: \n" + "-f files only\n" + "-d directories only\n" + "-h this help\n" +; + +void help(const CONST_C_STRING arg) +{ + std::cout + << "\nglob\n\n" + << "usage: " << std::filesystem::path(arg).filename().string() << " [options] args\n" + << cOpts; + ; +} + +INT32 main(const INT32 argc, const CONST_C_STRING* const argv) +{ + auto ret = 1; + DocOpts opts; + if (opts.process(cOpts, argc, argv)) + { + if (opts.isSet('h')) + { + help(argv[0]); + } + else + { + ret = 0; + std::unique_ptr proc; + CONST_C_STRING cmd = nullptr; + if (opts.getValue(cmd, 'x')) + { + CONST_C_STRING placeholder = nullptr; + opts.getValue(placeholder, 'p'); + proc = std::make_unique(cmd, placeholder); + } + else + { + proc = std::make_unique(); + } + Glob glob(*proc, opts.isSet('f'), opts.isSet('d')); + for (auto i = 0; i < opts.argc(); ++i) + { + glob.glob(opts.args()[i]); + } + } + } + return ret; +} diff --git a/shell/demo.cmd b/shell/demo.cmd index ffacc1f..e1352a4 100644 --- a/shell/demo.cmd +++ b/shell/demo.cmd @@ -1,12 +1,14 @@ @ECHO OFF SETLOCAL +set cDir=%CD% cd /d %~dp0 +set helpTxt=%CD%\demo_options.txt -set docopts=..\build\docopts.exe -set fglob=..\build\fglob.exe -set helpTxt=demo_options.txt -set tmpCmd=..\build\tmp.cmd +cd .. +set docopts=%CD%\build\docopts.exe +set glob=%CD%\build\glob.exe +set tmpCmd=%CD%\build\tmp.cmd echo. echo - docopts @@ -15,7 +17,7 @@ if not exist %docopts% ( exit /b 1 ) -call %docopts% %helpTxt% %* > %tmpCmd% +%docopts% %helpTxt% %* > %tmpCmd% if %errorlevel% NEQ 0 exit /b %errorlevel% call %tmpCmd% @@ -28,17 +30,17 @@ if %_h% ( echo options: -c: %_c% -t: %_t% -H %_Hu% -o: %_o% echo args: %_args% +cd %cDir% echo. -echo - fglob -if not exist %fglob% ( - echo first build %fglob% to proceed +echo - glob +if not exist %glob% ( + echo first build %glob% to proceed exit /b 1 ) -call %fglob% %_args% > %tmpCmd% -call %tmpCmd% +%glob% -p "" -x "echo " %_args% > %tmpCmd% echo args: -for %%a in (%_args%) do echo %%a +call %tmpCmd% ENDLOCAL diff --git a/src/Glob.cpp b/src/Glob.cpp new file mode 100644 index 0000000..c2a9fd8 --- /dev/null +++ b/src/Glob.cpp @@ -0,0 +1,184 @@ +#include +#include +#include + +#include +#include + +using + py::repl, + std::filesystem::exists, + std::filesystem::is_directory, + std::filesystem::is_regular_file, + std::filesystem::directory_iterator, + std::regex_match, + std::regex_search, + std::regex, + std::string, + std::vector +; +using fspath = std::filesystem::path; + +Glob::Glob(I_GlobProcessor& proc, const bool onlyFiles, const bool onlyDirs): + onlyDirs(onlyDirs), + proc(proc), + filter(onlyFiles ? ff : onlyDirs ? fd : fx) +{} + +const Glob::ffunc Glob::fd = [](const string& s) { return is_directory(s); }; +const Glob::ffunc Glob::ff = [](const string& s) { return is_regular_file(s); }; +const Glob::ffunc Glob::fx = [](const string& s) { return exists(s); }; + +void Glob::pathVec::add(const string& s) +{ + if (empty()) push_back(s); + else + { + for (auto& str: *this) + { + str += '/' + s; + } + } +} + +Glob::pathVec& Glob::pathVec::operator << (const std::filesystem::directory_entry& e) +{ + push_back(e.path().string()); + // TRACE_VAR(e.path().string()) + return *this; +} + +bool Glob::isGlob(const string& token) +{ + static const regex reGlob("\\[.*\\]|[?*]"); + return regex_search(token, reGlob); +} + +void Glob::tokenize(strVec& v, const string& path) +{ + static const regex rxTok("[/\\\\]"); + string s = path; + std::smatch sm; + while (regex_search(s, sm, rxTok)) + { + v.push_back(s.substr(0, sm.position())); + s = s.substr(sm.position() + 1); + } + if (not s.empty()) v.push_back(s); +} + +void Glob::getAll() +{ + TRACE_FUNC() + const pathVec& src = getSrc(); + pathVec& trg = getTrg(); + for (const auto& path: src) + { + if (is_directory(path)) + { + for (const auto& e : directory_iterator(fspath(path))) + { + trg << e; + } + } + } +} + +void Glob::getDirs(const pathVec& src, const bool recursive) +{ + TRACE_FUNC() + TRACE_VAR(recursive) + pathVec next; + pathVec& trg = getTrg(); + for (const auto& path: src) + { + if (is_directory(path)) + { + for (const auto& e : directory_iterator(fspath(path))) + { + if (is_directory(e)) + { + trg << e; + if (recursive) next << e; + } + } + } + } + if (recursive and not next.empty()) getDirs(next, true); +} + +void Glob::getGlob(const string& token, const bool dirs) +{ + TRACE_FUNC() + TRACE_VAR(dirs) + static const regex reAst("[*]"); + static const regex reDot("[.]"); + static const regex reQue("[?]"); + const regex re(repl(reQue, ".", repl(reAst, ".*", repl(reDot, "\\.", token)))); + const pathVec& src = getSrc(); + pathVec& trg = getTrg(); + for (const auto& path: src) + { + if (is_directory(path)) + { + for (const auto& e : directory_iterator(fspath(path))) + { + if ( + ((not dirs) or is_directory(e)) and + regex_match(e.path().filename().string(), re) + ) + { + trg << e; + } + } + } + } +} + +void Glob::swap() +{ + std::swap(pSrc, pTrg); + getTrg().clear(); +} + +void Glob::glob(const string& fpath) +{ + TRACE_FUNC() + strVec tokens; + tokenize(tokens, fpath); + size_t n = 0; + const size_t sz = tokens.size(); + for (const auto& token : tokens) + { + ++n; + TRACE_VAR(sz) + TRACE_VAR(n) + TRACE_VAR(token) + if (token == "**") + { + getDirs(getSrc(), true); + swap(); + } + else if (token == "*") + { + if (onlyDirs or n < sz) + getDirs(getSrc(), false); + else + getAll(); + swap(); + } + else if (isGlob(token)) + { + getGlob(token, onlyDirs or n < sz); + swap(); + } + else + { + getSrc().add(token); + } + } + for (const string& s: getSrc()) + { + if (filter(s)) proc.process(s); + } +} diff --git a/src/GlobProcessors.cpp b/src/GlobProcessors.cpp new file mode 100644 index 0000000..4a1b2c7 --- /dev/null +++ b/src/GlobProcessors.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include +using std::cout; + +void GlobTrace::process(const std::string& fpath) +{ + TRACE_VAR(fpath) +} + +GlobXargs::GlobXargs(CONST_C_STRING cmd, CONST_C_STRING placeholder): + cmd(cmd), + re(placeholder ? placeholder : "") +{} + +void GlobXargs::process(const std::string& fpath) +{ + cout << std::regex_replace(cmd, re, fpath) << '\n'; +} + +GlobArgs::GlobArgs() +{ +#ifdef _WIN32 + cout << "set _args="; +#else + cout << "export _args=\""; +#endif +} + +GlobArgs::~GlobArgs() +{ + TRACE_FUNC() +#ifndef _WIN32 + cout << '"'; +#endif + cout << '\n'; +} + +void GlobArgs::process(const std::string& fpath) +{ + cout << fpath << ' '; +} diff --git a/src/docopts.cpp b/src/docopts.cpp index a40200c..b144d7d 100644 --- a/src/docopts.cpp +++ b/src/docopts.cpp @@ -35,9 +35,9 @@ bool DocOpts::process(const CONST_C_STRING help, const INT32 argc, const CONST_C } if (mOk and argc > start) { - mArgs = new CONST_C_STRING[argc - start]; std::set doneValues; - for (INT32 n = start; mOk and n < argc; ++n) + INT32 n = start; + while (mOk and n < argc) { if (std::regex_match(argv[n], cm, reOpt)) { @@ -69,8 +69,14 @@ bool DocOpts::process(const CONST_C_STRING help, const INT32 argc, const CONST_C } else mSwitches.insert(c); } + ++n; + } + else + { + mArgs = argv + n; + mArgc = argc - n; + break; } - else mArgs[mArgc++] = argv[n]; } } if (not mOk) reset(); @@ -119,7 +125,8 @@ void DocOpts::toShell() const void DocOpts::reset() { - rmArgs(); + mArgs = nullptr; + mArgc = 0; mValues.clear(); mSwitches.clear(); mValueKeys.clear(); @@ -137,13 +144,3 @@ bool DocOpts::getValue(CONST_C_STRING& value, CHAR key) const } return ok; } - -void DocOpts::rmArgs() -{ - if (mArgs != nullptr) - { - delete[] mArgs; - mArgs = nullptr; - } - mArgc = 0; -} diff --git a/src/fglob.cpp b/src/fglob.cpp index bc24aa0..86135fe 100644 --- a/src/fglob.cpp +++ b/src/fglob.cpp @@ -1,50 +1,47 @@ #ifdef _WIN32 #include #include +#include -#include +// #include #include #include using py::repl; using fp = std::filesystem::path; -using std::regex, std::regex_replace, std::regex_match, std::regex_search; +using std::regex, std::regex_replace, std::regex_match; using std::string; -void fglob(const CONST_C_STRING item, I_FglobProcessor& proc) +void fglob(const string& item, I_FglobProcessor& proc) { // any posix system has expanded globbing if (std::filesystem::is_regular_file(item)) { proc.process(item); } - // windows shell has no globbing + // windows crap shell has no globbing // therefore at least apply simple file globbing by regex - else + else if (string(item).find('*') != string::npos) { - static const regex reGlob("\\[.*\\]|[?*]"); - const auto fname = fp(item).filename().string(); - if (regex_search(fname, reGlob)) - { - // simple globbing: - // abc*[0-9]?.txt -> abc.*[0-9].\.txt - // . -> \. - // * -> .* - // ? -> . - static const regex reAst("[*]"); - static const regex reDot("[.]"); - static const regex reQue("[?]"); + // simple globbing: + // abc*[0-9]?.txt -> abc.*[0-9].\.txt + // . -> \. + // * -> .* + // ? -> . + static const regex reAst("[*]"); + static const regex reDot("[.]"); + static const regex reQue("[?]"); - const regex re(repl(reQue, ".", repl(reAst, ".*", repl(reDot, "\\.", fname)))); - for (const auto& entry : std::filesystem::directory_iterator(fp(item).parent_path())) + const string restr = repl(reQue, ".", repl(reAst, ".*", repl(reDot, "\\.", fp(item).filename().string()))); + const regex re(restr); + for (const auto& entry : std::filesystem::directory_iterator(fp(item).parent_path())) + { + if ( + entry.is_regular_file() and + regex_match(entry.path().filename().string(), re) + ) { - if ( - entry.is_regular_file() and - regex_match(entry.path().filename().string(), re) - ) - { - proc.process(entry.path().string().c_str()); - } + proc.process(entry.path().string().c_str()); } } }