From 84e629ffce824e8b52fca16da9407abb98423528 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Mon, 16 Dec 2024 15:24:28 +0100 Subject: [PATCH] Replace `hocload.sh` with `std::filesystem` utils --- share/lib/hocload.sh | 48 ----------------- src/oc/fileio.cpp | 126 ++++++++++++++++++++++++++++--------------- 2 files changed, 84 insertions(+), 90 deletions(-) delete mode 100755 share/lib/hocload.sh diff --git a/share/lib/hocload.sh b/share/lib/hocload.sh deleted file mode 100755 index 1780ec626f..0000000000 --- a/share/lib/hocload.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash - -# used by the libload command in hoc to find an instance of a procedure, -# function, or template - -# uncomment following line for use with DOS -#NEURONHOME=`d2uenv NEURONHOME` - -if [ $TEMP ] ; then - tmpdir=$TEMP -else - tmpdir="/tmp" -fi -curdir=`pwd` -names=$tmpdir/oc"$3".hl - -if [ ! -f $names ] ; then - -paths=". $HOC_LIBRARY_PATH $NEURONHOME/lib/hoc" - -spaths=`echo "$paths" | sed 's/:/ /g'` - -for p in $spaths -do -#for DOS comment out the egrep and uncomment the grep line - egrep '^func|^proc|^begintemplate' $p/*.oc $p/*.hoc >> $names 2>/dev/null -# grep -s '^func|^proc|^begintemplate' $p/\*.oc $p/\*.hoc >> $names -done - -fi -if [ "$1" = "begintemplate" ] ; then -file=`sed -n "/:$1 $2\$/ { - s/:$1 $2.*//p - q - }" $names` -else -file=`sed -n "/:$1 $2 *()/ { - s/:$1 $2.*//p - q - }" $names` -fi -if [ -z "$file" ] ; then - exit 1 -fi -echo $file -exit 0 - - diff --git a/src/oc/fileio.cpp b/src/oc/fileio.cpp index 7a929f8e01..37a95cc835 100644 --- a/src/oc/fileio.cpp +++ b/src/oc/fileio.cpp @@ -4,6 +4,11 @@ #include #include #include +#include +#include +#include +#include +#include #ifdef HAVE_UNISTD_H #include #endif @@ -13,6 +18,14 @@ #include "hocparse.h" #include #include "nrnfilewrap.h" +#include + +// separator for items in env variables +#if defined(WIN32) +const auto os_pathsep = std::string(";"); +#else +const auto os_pathsep = std::string(":"); +#endif extern char* neuron_home; @@ -473,61 +486,90 @@ void hoc_sprint1(char** ppbuf, int argn) { /* convert args to right type for con *ppbuf = hs->buf; } -#if defined(WIN32) -static FILE* oc_popen(char const* const cmd, char const* const type) { - FILE* fp; - char buf[1024]; - assert(strlen(cmd) + 20 < 1024); - Sprintf(buf, "sh %s > hocload.tmp", cmd); - if (system(buf) != 0) { - return (FILE*) 0; - } else if ((fp = fopen("hocload.tmp", "r")) == (FILE*) 0) { - return (FILE*) 0; - } else { - return fp; + +// Split a string containing an env variable into multiple paths (OS-specific) +// and return a container with the results +static auto split_paths(const std::string& input) { + std::vector result; + std::size_t start = 0; + std::size_t end = 0; + + while ((end = input.find(os_pathsep, start)) != std::string::npos) { + if (end > start) { + result.push_back(input.substr(start, end - start)); + } + start = end + 1; + } + + // Add the last segment if it's non-empty + if (start < input.size()) { + result.push_back(input.substr(start)); } + + return result; } -static void oc_pclose(FILE* fp) { - fclose(fp); - unlink("hocload.tmp"); + +// return the default search paths for loading files +static auto default_search_paths() { + auto result = std::vector({"."}); + + // insert hoc paths (if any) + auto hoc_library_path = getenv("HOC_LIBRARY_PATH"); + if (hoc_library_path) { + auto paths = split_paths(std::string(hoc_library_path)); + std::copy(begin(paths), end(paths), back_inserter(result)); + } + + // insert home path + auto home_path = fmt::format("{}/lib/hoc", std::string(neuron_home)); + result.push_back(home_path); + + return result; +} + +// look for regex ``pattern`` in ``paths`` (non-recursively); +// if there is no match, return empty value +// if there is a match, return the path of the first file containing the match +static std::optional search_hoc_files_regex(const std::regex& pattern, + const std::vector& paths) { + namespace fs = std::filesystem; + for (const auto& path: paths) { + for (const auto& entry: fs::directory_iterator(path)) { + if (entry.is_regular_file() && + (entry.path().extension() == ".oc" || entry.path().extension() == ".hoc")) { + auto file = std::ifstream(entry.path()); + if (!file.is_open()) + continue; + + std::string line; + while (std::getline(file, line)) { + if (std::regex_search(line, pattern)) { + return entry.path().string(); + } + } + } + } + } + return {}; } -#else -#define oc_popen popen -#define oc_pclose pclose -#endif static int hoc_Load_file(int, const char*); static void hoc_load(const char* stype) { int i = 1; - char* s; - Symbol* sym; - char cmd[1024]; - FILE* p; - char file[1024], *f; while (ifarg(i)) { - s = gargstr(i); + const char* s = gargstr(i); ++i; - sym = hoc_lookup(s); + const Symbol* sym = hoc_lookup(s); if (!sym || sym->type == UNDEF) { - assert(strlen(stype) + strlen(s) + 50 < 1024); - Sprintf(cmd, "$NEURONHOME/lib/hocload.sh %s %s %d", stype, s, hoc_pid()); - p = oc_popen(cmd, "r"); - if (p) { - f = fgets(file, 1024, p); - if (f) { - f[strlen(f) - 1] = '\0'; - } - oc_pclose(p); - if (f) { - fprintf(stderr, "Getting %s from %s\n", s, f); - hoc_Load_file(0, f); - } else { - fprintf(stderr, "Couldn't find a file that declares %s\n", s); - } + auto file = search_hoc_files_regex(std::regex("^(func|proc|begintemplate)"), + default_search_paths()); + if (file) { + fprintf(stderr, "Getting %s from %s\n", s, file->c_str()); + hoc_Load_file(0, file->c_str()); } else { - hoc_execerror("can't run:", cmd); + fprintf(stderr, "Couldn't find a file that declares %s\n", s); } } }