diff --git a/.zrc b/.zrc index 659d8ac..37cc945 100755 --- a/.zrc +++ b/.zrc @@ -128,17 +128,17 @@ fn extract { let s { set s = $argv(1) switch $s { - reg {.\.tar.bz2$} { tar xjf $s } - reg {.\.tar.gz$} { tar xzf $s } - reg {.\.bz2$} { bunzip2 $s } - reg {.\.rar$} { unrar e $s } - reg {.\.gz$} { gunzip $s } - reg {.\.tar$} { tar xf $s } - reg {.\.tbz2$} { tar xjf $s } - reg {.\.tgz$} { tar xzf $s } - reg {.\.zip$} { unzip $s } - reg {.\.Z$} { uncompress $s } - reg {.\.7z$} { 7z x $s } + reg {.*\.tar.bz2$} { tar xjf $s } + reg {.*\.tar.gz$} { tar xzf $s } + reg {.*\.bz2$} { bunzip2 $s } + reg {.*\.rar$} { unrar e $s } + reg {.*\.gz$} { gunzip $s } + reg {.*\.tar$} { tar xf $s } + reg {.*\.tbz2$} { tar xjf $s } + reg {.*\.tgz$} { tar xzf $s } + reg {.*\.zip$} { unzip $s } + reg {.*\.Z$} { uncompress $s } + reg {.*\.7z$} { 7z x $s } default { echo '$s could not be extracted!' >(1=2) return 1 diff --git a/doc/man1/read.1 b/doc/man1/read.1 index 0d7042c..5d386e1 100644 --- a/doc/man1/read.1 +++ b/doc/man1/read.1 @@ -2,7 +2,7 @@ .SH NAME read \- Read text from standard input .SH SYNOPSIS -.BI "read [" "-d " | "-n " "] [" "-p " "] [" " ..." ] +.BI "read [" "-d " | "-n " "] [" "-p " "] [" "-f " "] [" " ..." ] .SH DESCRIPTION .I Read is a command used to do various methods of text input. It can be used in conjunction with @@ -16,8 +16,10 @@ Choose which delimiter to use (IFS) .B n Read n characters .TP -.B d +.B p Display a prompt to the user +.B f +Read from a file descriptor .SH EXAMPLES .EX read str diff --git a/src/dispatch.hpp b/src/dispatch.hpp index 4211c5f..47fd873 100644 --- a/src/dispatch.hpp +++ b/src/dispatch.hpp @@ -279,38 +279,44 @@ Command(do) { /** Switch statement implementation **/ Command(switch) { std::string def_cmd; + std::string se = " { cmd|reg |default ...}"; WordList args; - if (argc != 3) - syntax_error(" { cmd|reg |default ...}"); - - /* empty */ { - NullFin; - args = tokenize(argv[2], fin); - } + syntax_error(se); + { NullFin; args = tokenize(argv[2], fin); } std::for_each(args.wl.begin(), args.wl.end(), &str_subst); - for (int i = 0, argc = args.size(); i < argc; i += 3) { + + for (int i = 0; i < args.size(); ) { if (args.wl[i] == "case") { - if (i >= argc-2) - syntax_error("`case` ends too early"); - if (args.wl[i+1] == argv[1]) { + if (i >= args.size()-2) + syntax_error(se); + if (argv[1] == args.wl[i+1]) { eval(args.wl[i+2]); NoReturn; } - } else if (args.wl[i] == "reg") { - if (i >= argc-2) - syntax_error("`reg` ends too early"); - std::regex sr(args.wl[i+1]); - if (std::regex_search(argv[1], sr)) { + i += 3; + } + + else if (args.wl[i] == "reg") { + if (i >= args.size()-2) + syntax_error(se); + std::regex sr{args.wl[i+1]}; + if (std::regex_match(argv[1], sr)) { eval(args.wl[i+2]); NoReturn; } - } else if (args.wl[i] == "default") { - if (i >= argc-1) - syntax_error("`default` ends too early"); - def_cmd = args.wl[1+i--]; - } else { - syntax_error("Expected `case`/`default`"); + i += 3; + } + + else if (args.wl[i] == "default") { + if (i >= args.size()-1) + syntax_error(se); + def_cmd = args.wl[i+1]; + i += 2; + } + + else { + syntax_error(se); } } eval(def_cmd); @@ -459,13 +465,14 @@ Command(echo) { /** Reads from stdin **/ Command(read) { - const char *se = "[-d |-n ] [-p ] [ ...]"; + const char *se = "[-d |-n ] [-p ] [-f ] [ ...]"; std::string buf; long n = -1, i; - char d = '\n', b; + char d = '\n'; optind = 0; int opt; - while ((opt = getopt(argc, argv, "d:n:p:")) != -1) { + int fd = STDIN_FILENO; + while ((opt = getopt(argc, argv, "d:n:p:f:")) != -1) { switch (opt) { case 'd': if (n != -1) @@ -477,6 +484,9 @@ Command(read) { syntax_error(se); n = atoi(optarg); break; + case 'f': + fd = atoi(optarg); + break; case 'p': std::cout << optarg << std::flush; break; @@ -484,23 +494,27 @@ Command(read) { syntax_error(se); } } + // buffers + char b[(n > 0) ? (n+1) : 1]; + char c; #define GET_INPUT \ buf.clear(); \ if (n == -1) { \ int ok; \ - ok = read(0, &b, 1); \ + ok = read(fd, &c, 1); \ if (ok != 1) \ return "1"; \ - buf += b; \ + buf += c; \ for ever { \ - ok = read(0, &b, 1); \ - if (ok != 1 || b == d) \ + ok = read(fd, &c, 1); \ + if (ok != 1 || c == d) \ break; \ - buf += b; \ + buf += c; \ } \ - } else for (i = 0; i < n; ++i) {\ - if (read(0, &b, 1) != 1) \ + } else { \ + if (read(fd, b, n) != n) \ return "1"; \ + b[n] = '\0'; \ buf += b; \ } @@ -525,7 +539,7 @@ Command(inc) { if (argc >= 3) val = expr(combine(argc, argv, 2)); var = getvar(argv[1]); - ret_val = expr(S("(")+var+")+("+val+")"); + ret_val = expr(zrc_fmt("(%s)+(%s)", var.data(), val.data())); setvar(argv[1], ret_val); NoReturn; } @@ -547,14 +561,10 @@ Command(set) { size_t len = strlen(argv[i]); if (argv[i][len-1] == '=') { argv[i][len-1] = '\0'; - setvar(argv[i-1], expr( - S("(") - + getvar(argv[i-1]) - + ")" - + argv[i] - + "(" - + argv[i+1] - + ")")); + setvar(argv[i-1], expr(zrc_fmt("(%s)%s(%s)", + getvar(argv[i-1]).data(), + argv[i], + argv[i+1]))); } else syntax_error(se); } } diff --git a/src/expr.cpp b/src/expr.cpp index 9ad3b23..5884672 100644 --- a/src/expr.cpp +++ b/src/expr.cpp @@ -177,6 +177,7 @@ expr(std::string e, ExprType mode) str_subst(e); if (!is_expr(e)) INVALIDSYN; + //=====functions===== =====operators===== REP("log10", LOG10); REP("&&" , AND); REP("log2" , LOG2 ); REP("||" , OR ); diff --git a/src/main.cpp b/src/main.cpp index 9359a63..95b3dcd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include +#include #include #include #include @@ -92,7 +94,7 @@ */ #define CHK_FD \ /*if (std::regex_match(*it,m,e)){ */ \ - if ((*it).length()>3&&(*it)[0]=='>'&&(*it)[1]=='('&&(*it).back()==')') [[unlikely]] {\ + if ((*it).length()>3 && (*it)[0]=='>' && (*it)[1]=='(' && (*it).back()==')') [[unlikely]] {\ sword = 1; \ size_t i = 2; \ int fd1 = 0, fd2 = 0; \ @@ -124,7 +126,7 @@ } \ } \ baks[fd1] = dup(fd1); \ - dup2(dup(fd2), fd1); \ + dup2(dup(fd2), fd1); \ } \ } else if (i == (*it).length()-1) { \ baks[fd1] = dup(fd1); \ @@ -133,7 +135,7 @@ std::cerr << errmsg << ">(..?)"; \ } \ continue; \ - } +} /** * Check if a word is an interp alias @@ -192,6 +194,7 @@ typedef int Jid; static bool die (std::string_view ); static inline bool is_number (std::string_view ); WordList glob (std::string_view ); + template std::string zrc_fmt(const char *fmt, Var... args); static std::string eval_stream (std::istream& ); template std::string eval(T const& ); // MAIN.CPP @@ -312,6 +315,23 @@ glob(std::string_view s) return wl; } +/** Formatted string support + * + * @param {const char*}fmt,... + * @return string + */ +template std::string +zrc_fmt(const char *fmt, Var... args) +{ + size_t len = snprintf(nullptr, 0, fmt, args...)+1; + char *ret = new char[len]; + snprintf(ret, len, fmt, args...); + + std::string ret_str{ret}; + delete [] ret; + return ret_str; +} + /** Evaluate a text stream. * * @param {istream&}in diff --git a/src/sighandler.hpp b/src/sighandler.hpp index bd12d99..927ad27 100644 --- a/src/sighandler.hpp +++ b/src/sighandler.hpp @@ -148,7 +148,7 @@ bg_fg(int argc, char *argv[]) { Job *j; Jid index = -1; - if (argc != 2 && (!isdigit(*argv[1]) && *argv[1] != '%')) + if (argc != 2 || (!isdigit(*argv[1]) && *argv[1] != '%')) syntax_error("|<%jid>"); if (*argv[1] == '%') { int num = atoi(&argv[1][1]);