From 3fea71d1e88e0a09ba260e364508187e78aab716 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Tue, 9 Feb 2016 23:50:33 -0500 Subject: [PATCH] directory -- support for MacOS pathnames. --- CMakeLists.txt | 6 +- builtins.cpp | 10 +- pathnames.rl | 267 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 pathnames.rl diff --git a/CMakeLists.txt b/CMakeLists.txt index 6776979..d5e484f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project("mpw-shell") set (PROJECT_TYPE "CXX") set (PROJECT_NAME "MPW Shell") -set(CMAKE_CXX_FLAGS "-g -Wall -Wno-unused-variable -Wno-multichar") +set(CMAKE_CXX_FLAGS "-g -Wall -Wno-unused-variable -Wno-multichar -O1") if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable ") @@ -66,6 +66,7 @@ endmacro() RAGEL_TARGET(mpw-shell-read mpw-shell-read.rl mpw-shell-read.cpp COMPILE_FLAGS "-p -G2") RAGEL_TARGET(phase1 phase1.rl phase1.cpp COMPILE_FLAGS "-p -G2") RAGEL_TARGET(phase2 phase2.rl phase2.cpp COMPILE_FLAGS "-p -G2") +RAGEL_TARGET(pathnames pathnames.rl pathnames.cpp COMPILE_FLAGS "-p -G2") # need to copy all OUTPUT file to the build dir add_custom_command( @@ -113,7 +114,8 @@ add_custom_command( # mpw-shell-execute.cpp mpw-shell-builtins.cpp mpw-shell-read.cpp add_executable(mpw-shell mpw-shell.cpp mpw-shell-token.cpp mpw-shell-expand.cpp mpw-shell-parser.cpp value.cpp mpw-shell-quote.cpp - phase1.cpp phase2.cpp phase2-parser.cpp command.cpp environment.cpp builtins.cpp mapped_file.cpp) + phase1.cpp phase2.cpp phase2-parser.cpp command.cpp environment.cpp builtins.cpp mapped_file.cpp + pathnames.cpp) target_link_libraries(mpw-shell edit) diff --git a/builtins.cpp b/builtins.cpp index 29de5f3..b55166d 100644 --- a/builtins.cpp +++ b/builtins.cpp @@ -15,6 +15,12 @@ //MAXPATHLEN #include + +namespace ToolBox { + std::string MacToUnix(const std::string path); + std::string UnixToMac(const std::string path); +} + namespace { /* @@ -46,6 +52,7 @@ namespace { } + #undef stdin #undef stdout #undef stderr @@ -330,7 +337,8 @@ int builtin_directory(Environment &env, const std::vector &tokens, } // todo -- pathname translation. - int ok = chdir(argv.front().c_str()); + std::string path = ToolBox::MacToUnix(argv.front()); + int ok = chdir(path.c_str()); if (ok < 0) { fputs("### Directory - Unable to set current directory.\n", stderr); perror("chdir: "); diff --git a/pathnames.rl b/pathnames.rl new file mode 100644 index 0000000..8220a28 --- /dev/null +++ b/pathnames.rl @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2013, Kelvin W Sherlock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include + +//#include "toolbox.h" + + + +namespace { + + + /* + * To Mac: + * file -> file + * :directory:file -> directory/file + * volume:directory -> /volume/directory + * : -> ./ + * :: -> ../ + * ::: -> ../../ + * + * To Unix: + * file -> file + * directory/file -> :directory:file + * /volume/file -> volume:file + * + */ + + + %%{ + machine mac; + + main := |* + + ':' {2,} { + + // :: = .. + // ::: = ../.. + // etc + unsigned count = te - ts; + + if (ts != begin) + { + rv.push_back('/'); + } + for (unsigned i = 1; i < count; ++i) + { + rv.append("../"); + } + }; + + ':' { + /* + if (ts == begin) + rv.append("./"); + else + rv.push_back('/'); + */ + if (ts != begin) + rv.push_back('/'); + }; + + + any { + rv.push_back(*ts); + }; + + *|; + + write data; + }%% + + %%{ + machine unix; + + main := |* + + '/' + { + // collapse multiple /s to a single ':' + if (ts != begin) + { + rv.push_back(':'); + slash = true; + } + }; + + any { + rv.push_back(*ts); + }; + + *|; + + write data; + }%% + +} + +namespace ToolBox +{ + + std::string MacToUnix(const std::string path) + { + + // todo -- Dev:Null -> lowercase it? + + int sep = 0; + bool colon = false; + + for (char c : path) + { + switch (c) + { + case ':': + colon = true; + case '/': + if (!sep) sep = c; + break; + + } + if (colon) break; + } + + // no colon - no problem. + if (!colon) return path; + + // special case ":" -> "." + if (colon && path.length() == 1) return "."; + + const char *p = path.c_str(); + const char *pe = p + path.length(); + const char *eof = pe; + const char *ts; + const char *te; + + const char *begin = p; + int cs; + int act; + + std::string rv; + + // volume:directory -> /volume + if (sep == ':' && path.front() != ':') + rv.push_back('/'); + + %%{ + machine mac; + + write init; + write exec; + }%% + + + return rv; + } + + + std::string UnixToMac(const std::string path) + { + // /volume/directory -> volume:directory + // // -> / + + + bool slash = false; + bool sep = 0; + + for (char c : path) + { + switch(c) + { + case '/': + slash = true; + case ':': + if (!sep) sep = c; + break; + } + if (slash) break; + } + + if (!slash) return path; + + const char *p = path.c_str(); + const char *pe = p + path.length(); + const char *eof = pe; + const char *ts; + const char *te; + + const char *begin = p; + int act; + int cs; + + std::string rv; + + + slash = false; + // path/file -> :path:file + if (path.front() != '/') + { + rv.push_back(':'); + slash = true; + } + %%{ + machine unix; + + write init; + write exec; + }%% + + // special check /dir -> dir: + if (path.front() == '/' && !slash) rv.push_back(':'); + + return rv; + } + + +} + + +#ifdef TESTING + +#include + +int main(int argc, char **argv) +{ + + for (int i = 1; i < argc; ++i) + { + std::string s(argv[i]); + std::string a = ToolBox::MacToUnix(s); + std::string b = ToolBox::UnixToMac(s); + + if (s != a) + printf("ToUnix: %s -> %s\n", s.c_str(), a.c_str()); + + if (s != b) + printf("ToMac: %s -> %s\n", s.c_str(), b.c_str()); + + + } + + return 0; +} + +#endif