int builtin_catenate(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { if (tokens.size() == 1) { int rv = cat_helper(stdin, stdout); if (rv) fdputs("### Catenate - I/O Error\n", stderr); return rv; } for (const auto &s : make_offset_range(tokens, 1)) { std::string path = ToolBox::MacToUnix(s); int fd = open(path.c_str(), O_RDONLY); if (fd < 0) { fdprintf(stderr, "### Catenate - Unable to open \"%s\".\n", path.c_str()); return 1; } int rv = cat_helper(fd, stdout); close(fd); if (rv) { fdputs("### Catenate - I/O Error\n", stderr); return rv; } } return 0; }
int builtin_set(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { // set var name -- set // set var -- just print the value // 3.5 supports -e to also export it. //io_helper io(fds); if (tokens.size() == 1) { for (const auto &kv : env) { std::string name = quote(kv.first); std::string value = quote(kv.second); fdprintf(stdout, "Set %s%s %s\n", bool(kv.second) ? "-e " : "", name.c_str(), value.c_str()); } return 0; } if (tokens.size() == 2) { std::string name = tokens[1]; auto iter = env.find(name); if (iter == env.end()) { fdprintf(stderr, "### Set - No variable definition exists for %s.\n", name.c_str()); return 2; } name = quote(name); std::string value = quote(iter->second); fdprintf(stdout, "Set %s%s %s\n", bool(iter->second) ? "-e " : "", name.c_str(), value.c_str()); return 0; } bool exported = false; if (tokens.size() == 4 && tokens[1] == "-e") { exported = true; } if (tokens.size() > 3 && !exported) { fdputs("### Set - Too many parameters were specified.\n", stderr); fdputs("# Usage - set [name [value]]\n", stderr); return 1; } std::string name = tokens[1+exported]; std::string value = tokens[2+exported]; env.set(name, value, exported); return 0; }
static int outspkr(const char *s) { int err = -1, fd = open("/dev/speaker", O_WRONLY); if (fd >= 0) { fdputs(initcmd, fd, 0); err = fdputs(s, fd, verbose); close(fd); } return err; }/* outspkr */
bool help_helper(const mapped_file &f, const fdmask &fds, const std::string &cmd) { /* * format is: * -\n * name whitespace * .... * -\n */ if (f.size() < 2) return false; auto iter = f.begin(); auto end = f.end(); if (iter[0] != '-' && iter[1] != '\n') { iter = find_entry(iter, end); } if (cmd.empty()) { // print first entry write(stdout, f.begin(), std::distance(f.begin(), iter)); fdputs("\n", stdout); return true; } for(;;) { if (iter == end) return false; iter += 2; auto next = find_entry(iter, end); auto l = std::distance(iter, end); if (help_name_match(cmd.begin(), cmd.end(), iter, next)) { write(stdout, iter, std::distance(iter, next)); fdputs("\n", stdout); return true; } iter = next; } }
int builtin_echo(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { //io_helper io(fds); bool space = false; bool n = false; for (const auto &s : make_offset_range(tokens, 1)) { if (s == "-n" || s == "-N") { n = true; continue; } if (space) { fdputs(" ", stdout); } fdputs(s.c_str(), stdout); space = true; } if (!n) fdputs("\n", stdout); return 0; }
inline int fdprintf(int fd, const char *format, ...) { char *cp = nullptr; va_list ap; va_start(ap, format); int len = vasprintf(&cp, format, ap); va_end(ap); fdputs(cp, fd); free(cp); return len; }
int builtin_version(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { bool _v = false; bool error = false; auto argv = getopt(tokens, [&](char c){ switch(tolower(c)) { case 'v': _v = true; break; default: fdprintf(stderr, "### Version - \"-%c\" is not an option.\n", c); error = true; break; } }); if (argv.size() != 0) { fdprintf(stderr, "### Version - Too many parameters were specified.\n"); error = true; } if (error) { fdprintf(stderr, "# Usage - Version [-v]\n"); return 1; } //fdputs("MPW Shell 3.5, Copyright Apple Computer, Inc. 1985-99. All rights reserved.\n", stdout); fdputs("MPW Shell " VERSION ", Copyright Kelvin W Sherlock 2016. All rights reserved.\n", stdout); fdputs("based on MPW Shell 3.5, Copyright Apple Computer, Inc. 1985-99. All rights reserved.\n", stdout); if (_v) { fdputs("This version built on " __DATE__ " at " __TIME__ ".\n", stdout); } return 0; }
int builtin_shift(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { int n = 1; if (tokens.size() > 3) { fdputs("### Shift - Too many parameters were specified.\n", stderr); fdputs("# Usage - Shift [number]\n", stderr); return 1; } if (tokens.size() == 2) { value v(tokens[1]); if (v.is_number() && v.number >= 0) n = v.number; else { fdputs("### Shift - The parameter must be a positive number.\n", stderr); fdputs("# Usage - Shift [number]\n", stderr); return 1; } } if (n == 0) return 0; auto argv = load_argv(env); if (argv.empty()) return 0; std::move(argv.begin() + n , argv.end(), argv.begin()); do { env.unset(std::to_string(argv.size())); argv.pop_back(); } while (--n); env.set_argv(argv); return 0; }
int builtin_aboutbox(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { // the most important command of all! if (tokens.size() == 2 && tokens[1] == "--moof") { fdputs( "\n" " ## \n" " ## ## #### \n" " ## #### ## \n" " ## ## \n" " ## ## ## ## \n" " ## ## #### \n" " ## ## ## ## \n" " ######## #### ## ## \n" " ## #################### ## \n" " ## ############## ## \n" " #### ############ ## \n" " ###### ###### ## \n" " ###### ## \n" " #### ## \n" " ## ## \n" " ## ################ ## \n" " ## ## ## ## \n" " ## ## ## ## \n" " ## ## ## ## \n" " ## ## ## ## \n" " ## ## ## ## \n" " ###### ###### \n" "\n" ,stdout); return 0; } fdprintf(stdout, "+--------------------------------------+\n" "| MPW Shell %-4s |\n" "| |\n" "| |\n" "| (c) 2016 Kelvin W Sherlock |\n" "+--------------------------------------+\n" , VERSION); return 0; }
void cmd_index(int clientsock) { send_200_ok(clientsock); send_header_textplain(clientsock); fdputs(clientsock, "\nHi from mptsd.\n"); }
//! Print the current error void err_print(int fd, err_desc_t* err) { char pbuf[32]; fdputs(fd,"Error Description:\n"); /* Print internal error into */ if( err->status ) { fdputs(fd,"Internal Error: "); sprintf(pbuf,"%d ",err->status); fdputs(fd,pbuf); sprintf(pbuf,"(%dx)\n",_err_counts[err->status]); fdputs(fd,pbuf); if(_err_msgs[err->status]) { fdputs(fd,_err_msgs[err->status]); fdputs(fd,"\n"); } if(err->details) { fdputs(fd,err->details); fdputs(fd,"\n"); } } /* Print errno */ if( err->errno ) { // If errno is recorded: fdputs(fd,"Errno: "); sprintf(pbuf,"%d\n",err->errno); fdputs(fd,pbuf); fdputs(fd,strerror(err->errno)); fdputs(fd,"\n"); } }
int builtin_evaluate(Environment &env, std::vector<token> &&tokens, const fdmask &fds) { // evaluate expression // evaluate variable = expression // evaluate variable += expression // evaluate variable -= expression // flags -- -h -o -b -- print in hex, octal, or binary // convert the arguments to a stack. int output = 'd'; //io_helper io(fds); std::reverse(tokens.begin(), tokens.end()); // remove 'Evaluate' tokens.pop_back(); // check for -h -x -o if (tokens.size() >= 2 && tokens.back().type == '-') { const token &t = tokens[tokens.size() - 2]; if (t.type == token::text && t.string.length() == 1) { int flag = tolower(t.string[0]); switch(flag) { case 'o': case 'h': case 'b': output = flag; tokens.pop_back(); tokens.pop_back(); } } } if (tokens.size() >= 2 && tokens.back().type == token::text) { int type = tokens[tokens.size() -2].type; if (is_assignment(type)) { std::string name = tokens.back().string; tokens.pop_back(); tokens.pop_back(); int32_t i = evaluate_expression("Evaluate", std::move(tokens)); switch(type) { case '=': env.set(name, i); break; case '+=': case '-=': { value old; auto iter = env.find(name); if (iter != env.end()) old = (const std::string &)iter->second; switch(type) { case '+=': i = old.to_number() + i; break; case '-=': i = old.to_number() - i; break; } env.set(name, i); } break; } return 0; } } int32_t i = evaluate_expression("Evaluate", std::move(tokens)); if (output == 'h') { fdprintf(stdout, "0x%08x\n", i); return 0; } if (output == 'b') { std::string tmp("0b"); for (int j = 0; j < 32; ++j) { tmp.push_back(i & 0x80000000 ? '1' : '0'); i <<= 1; } tmp.push_back('\n'); fdputs(tmp.c_str(), stdout); return 0; } if (output == 'o') { // octal. fdprintf(stdout, "0%o\n", i); return 0; } fdprintf(stdout, "%d\n", i); return 0; }
int builtin_exists(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { bool _a = false; // print if alias/symlink bool _d = false; // print if directory bool _f = false; // print if normal file bool _n = false; // don't follow alias bool _w = false; // print if normal file + writable bool _q = false; // don't quote names bool error = false; std::vector<std::string> argv = getopt(tokens, [&](char c){ switch(tolower(c)) { case 'a': _a = true; break; case 'd': _d = true; break; case 'f': _f = true; break; case 'n': _n = true; break; case 'q': _q = true; break; case 'w': _w = true; break; default: fdprintf(stderr, "### Exists - \"-%c\" is not an option.\n", c); error = true; break; } }); if (_w) _f = false; if (_a + _d + _f + _w > 1) { fdputs("### Exists - Conflicting options were specified.\n", stderr); error = true; } if (argv.size() < 1) { fdputs("### Exists - Not enough parameters were specified.\n", stderr); error = true; } if (error) { fdputs("# Usage - Exists [-a | -d | -f | -w] [-n] [-q] name...\n", stderr); return 1; } for (auto &s : argv) { std::string path = ToolBox::MacToUnix(s); std::error_code ec; fs::file_status st = _n ? fs::symlink_status(path, ec) : fs::status(path, ec); if (ec) continue; if (_d && !fs::is_directory(st)) continue; if (_a && !fs::is_symlink(st)) continue; if (_f && !fs::is_regular_file(st)) continue; if (_w && !fs::is_regular_file(st)) continue; if (_w && (access(path.c_str(), W_OK | F_OK) < 0)) continue; if (!_q) s = quote(std::move(s)); fdprintf(stdout, "%s\n", s.c_str()); } return 0; }
int builtin_directory(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { // directory [-q] // directory path // for relative names, uses {DirectoryPath} (if set) rather than . // set DirectoryPath ":,{MPW},{MPW}Projects:" /* * Parameters: * ---------- * directory * Sets the default directory to directory. If you specify directory * as a leafname (that is, the final portion of a full pathname), the * MPW Shell searches for the directory in the current directory path * (for example, searching "{MPW}Examples:" for CExamples). However, if * the MPW Shell fails to find the directory in the current directory * path, it searches the directories listed in the {DirectoryPath} MPW * Shell variable, which contains a list of directories to be searched * in order of precedence. The last example illustrates how to do this. * * Options: * ------- * -q * Inhibits quoting the directory pathname written to standard * output. This option applies only if you omit the directory * parameter Normally the MPW Shell quotes the current default * directory name if it contains spaces or other special characters * * Status: * ------ * Directory can return the following status codes: * * 0 no errors * 1 directory not found; command aborted; or parameter error * */ //io_helper io(fds); bool q = false; bool error = false; std::vector<std::string> argv = getopt(tokens, [&](char c){ switch(tolower(c)) { case 'q': q = true; break; default: fdprintf(stderr, "### Directory - \"-%c\" is not an option.\n", c); error = true; break; } }); if (error) { fdputs("# Usage - Directory [-q | directory]\n", stderr); return 1; } if (argv.size() > 1) { fdputs("### Directory - Too many parameters were specified.\n", stderr); fdputs("# Usage - Directory [-q | directory]\n", stderr); return 1; } if (argv.size() == 1) { //cd if (q) { fdputs("### Directory - Conflicting options or parameters were specified.\n", stderr); return 1; } // todo -- if relative path does not exist, check {DirectoryPath} fs::path path = ToolBox::MacToUnix(argv.front()); std::error_code ec; current_path(path, ec); if (ec) { fdputs("### Directory - Unable to set current directory.\n", stderr); fdprintf(stderr, "# %s\n", ec.message().c_str()); return 1; } } else { // pwd std::error_code ec; fs::path path = fs::current_path(ec); if (ec) { fdputs("### Directory - Unable to get current directory.\n", stderr); fdprintf(stderr, "# %s\n", ec.message().c_str()); return 1; } // todo -- pathname translation? std::string s = path; if (!q) s = quote(std::move(s)); fdprintf(stdout, "%s\n", s.c_str()); } return 0; }
int builtin_help(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) { bool error = false; filesystem::path _f; // todo -- -f to specify help file. auto argv = getopt(tokens, [&](char c){ switch(tolower(c)) { default: fdprintf(stderr, "### Help - \"-%c\" is not an option.\n", c); error = true; break; } }); if (error) { fdputs("# Usage - Help [-f helpfile] command...\n", stderr); return 1; } const filesystem::path sd(ToolBox::MacToUnix(env.get("shelldirectory"))); const filesystem::path hd = sd / "Help"; filesystem::path mono; mapped_file mono_file; std::error_code ec; if (_f.empty()) { mono = sd / "MPW.Help"; mono_file = mapped_file(mono, mapped_file::priv, ec); } else { mono = _f; mono_file = mapped_file(mono, mapped_file::priv, ec); if (!mono_file && !_f.is_absolute()) { mono = sd / _f; mono_file = mapped_file(mono, mapped_file::priv, ec); } if (!mono_file) { fdprintf(stderr, "### Help: Unable to open %s\n", _f.c_str()); fdprintf(stderr, "# %s\n", ec.message().c_str()); return 3; } } if (mono_file) { std::replace(mono_file.begin(), mono_file.end(), '\r', '\n'); } if (argv.empty()) { help_helper(mono_file, fds, ""); return 0; } int rv = 0; for (const auto &cmd : argv) { // 1. check for $MPW:Help:command filesystem::path p(hd); p /= cmd; mapped_file f(p, mapped_file::priv, ec); if (!ec) { std::replace(f.begin(), f.end(), '\r', '\n'); write(stdout, f.data(), f.size()); fdputs("\n", stdout); continue; } if (mono_file) { bool ok = help_helper(mono_file, fds, cmd); if (ok) break; } fdprintf(stderr, "### Help - \"%s\" was not found.\n", cmd.c_str()); rv = 2; } return rv; }