/* * 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; }%% /* * this is not quite right. dev:std* is a reference to the current output device. * need to move this logic elsewhere. * */ %%{ machine dev; main := '/dev/null'i $eof{ return "/dev/null"; } | '/dev/stderr'i $eof{ return "/dev/stderr"; } | '/dev/stdout'i $eof{ return "/dev/stdout"; } ; write data; }%% } namespace ToolBox { std::string check_dev(std::string &&str) { const char *p = str.c_str(); const char *pe = p + str.length(); const char *eof = pe; int cs; %%{ machine dev; write init; write exec; }%% return std::move(str); } 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 check_dev(std::move(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