Commit 724c090d authored by jan.koester's avatar jan.koester
Browse files

test

parent 9ce54615
Loading
Loading
Loading
Loading
+23 −2
Changes for commands/editor/sed.cpp: 23 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -157,14 +157,34 @@ namespace fresh { namespace cmd {
            return (int)r.sc.regexes.size()-1;
        }

        // GNU sed's escapes for control characters, which regcomp() doesn't
        // know: \t, \f, \v, \r, \a; 0 for any other character
        static char controlEscape(char e){
            switch(e){
                case 't': return '\t';
                case 'f': return '\f';
                case 'v': return '\v';
                case 'r': return '\r';
                case 'a': return '\a';
            }
            return 0;
        }

        // text up to an unescaped delim; "\delim" becomes delim, "\n" a
        // newline, other escapes are kept for the regex engine. A delimiter
        // inside a bracket expression doesn't end the regex.
        // newline, "\t" and the other control escapes (also inside a
        // bracket expression, as in GNU sed) the character, other escapes
        // are kept for the regex engine. A delimiter inside a bracket
        // expression doesn't end the regex.
        static bool readDelimited(Src &s,char delim,std::string &out,bool isRegex){
            bool inBracket=false;
            while(!s.end()){
                char c=s.get();
                if(isRegex && inBracket){
                    if(c=='\\' && !s.end() && (controlEscape(s.peek()) || s.peek()=='n')){
                        char e=s.get();
                        out+= e=='n' ? '\n' : controlEscape(e);
                        continue;
                    }
                    out+=c;
                    if(c==']' && !(out.size()>=2 && (out[out.size()-2]=='[' || (out.size()>=3 && out[out.size()-2]=='^' && out[out.size()-3]=='['))))
                        inBracket=false;
@@ -176,6 +196,7 @@ namespace fresh { namespace cmd {
                    if(e==delim && delim!='\n') out+=delim;
                    else if(e=='n') out+='\n';
                    else if(e=='\n') out+='\n';
                    else if(isRegex && controlEscape(e)) out+=controlEscape(e);
                    else { out+='\\'; out+=e; }
                    continue;
                }
+79 −17
Changes for commands/system/kill.cpp: 79 added lines, 17 removed lines.
Original line number Diff line number Diff line
@@ -30,49 +30,111 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream>

#include <signal.h>
#include <strings.h>
#include <sys/types.h>

#include "shell.h"

namespace fresh { namespace cmd {

    struct SignalName { const char *name; int sig; };

    static const SignalName signalNames[]={
        {"HUP",SIGHUP},{"INT",SIGINT},{"QUIT",SIGQUIT},{"ILL",SIGILL},
        {"TRAP",SIGTRAP},{"ABRT",SIGABRT},{"IOT",SIGABRT},{"BUS",SIGBUS},
        {"FPE",SIGFPE},{"KILL",SIGKILL},{"USR1",SIGUSR1},{"SEGV",SIGSEGV},
        {"USR2",SIGUSR2},{"PIPE",SIGPIPE},{"ALRM",SIGALRM},{"TERM",SIGTERM},
#ifdef SIGSTKFLT
        {"STKFLT",SIGSTKFLT},
#endif
        {"CHLD",SIGCHLD},{"CLD",SIGCHLD},{"CONT",SIGCONT},{"STOP",SIGSTOP},
        {"TSTP",SIGTSTP},{"TTIN",SIGTTIN},{"TTOU",SIGTTOU},{"URG",SIGURG},
        {"XCPU",SIGXCPU},{"XFSZ",SIGXFSZ},{"VTALRM",SIGVTALRM},{"PROF",SIGPROF},
        {"WINCH",SIGWINCH},{"IO",SIGIO},{"POLL",SIGIO},
#ifdef SIGPWR
        {"PWR",SIGPWR},
#endif
        {"SYS",SIGSYS},
    };

    // a signal name (with or without SIG, any case) or number; -1 if unknown
    static int parseSignal(const char *spec){
        if(*spec>='0' && *spec<='9'){
            for(const char *p=spec; *p; ++p)
                if(*p<'0' || *p>'9') return -1;
            int n=atoi(spec);
            return n>=0 && n<NSIG ? n : -1;
        }
        if(strncasecmp(spec,"SIG",3)==0) spec+=3;
        for(const SignalName &s: signalNames)
            if(strcasecmp(spec,s.name)==0) return s.sig;
        return -1;
    }

    static const char *signalName(int sig){
        for(const SignalName &s: signalNames)
            if(s.sig==sig) return s.name;
        return nullptr;
    }

    class KillCommand : public ShellCommand {
    public:
        KillCommand():ShellCommand("kill"){}

        int runCommand(int argc,const char **argv){
            if(argc<2){
                std::cerr << "kill: usage: kill [-SIGNAL|-SIGNUM] pid..." << std::endl;
                std::cerr << "kill: usage: kill [-s SIGNAL | -SIGNAL | -n NUM] pid... | kill -l [status]" << std::endl;
                return 1;
            }

            int sig=SIGTERM;
            int firstpid=1;

            if(argv[1][0]=='-' && argv[1][1]!='\0'){
                const char *spec=argv[1]+1;

                if(strcmp(spec,"TERM")==0) sig=SIGTERM;
                else if(strcmp(spec,"KILL")==0) sig=SIGKILL;
                else if(strcmp(spec,"HUP")==0) sig=SIGHUP;
                else if(strcmp(spec,"INT")==0) sig=SIGINT;
                else{
                    bool numeric=true;
                    for(const char *p=spec; *p; ++p){
                        if(*p<'0' || *p>'9'){
                            numeric=false;
                            break;
            // kill -l [exit status]: the signal names, or the one of a status
            if(strcmp(argv[1],"-l")==0 || strcmp(argv[1],"-L")==0){
                if(argc>2){
                    int n=atoi(argv[2]);
                    if(n>128) n-=128;
                    const char *name=signalName(n);
                    if(!name){
                        std::cerr << "kill: unknown signal: " << argv[2] << std::endl;
                        return 1;
                    }
                    std::cout << name << std::endl;
                    return 0;
                }
                    if(!numeric){
                        std::cerr << "kill: unknown signal: " << spec << std::endl;
                for(int n=1; n<NSIG; ++n){
                    const char *name=signalName(n);
                    if(name) std::cout << n << ") SIG" << name << std::endl;
                }
                return 0;
            }

            if(strcmp(argv[1],"-s")==0 || strcmp(argv[1],"-n")==0){
                if(argc<3){
                    std::cerr << "kill: " << argv[1] << " needs a signal" << std::endl;
                    return 1;
                }
                    sig=atoi(spec);
                sig=parseSignal(argv[2]);
                if(sig<0){
                    std::cerr << "kill: unknown signal: " << argv[2] << std::endl;
                    return 1;
                }
                firstpid=3;
            }else if(strcmp(argv[1],"--")==0){
                firstpid=2;
            }else if(argv[1][0]=='-' && argv[1][1]!='\0'){
                const char *spec=argv[1]+1;

                sig=parseSignal(spec);
                if(sig<0){
                    std::cerr << "kill: unknown signal: " << spec << std::endl;
                    return 1;
                }
                firstpid=2;
            }
            if(firstpid<argc && strcmp(argv[firstpid],"--")==0)
                ++firstpid;

            if(firstpid>=argc){
                std::cerr << "kill: no pid specified" << std::endl;
+15 −6
Changes for commands/text/textutil.h: 15 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -44,22 +44,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

namespace fresh { namespace text {

    inline bool readFd(int fd,std::string &out){
    // appends fd's data up to EOF, or up to max bytes if max>=0 (endless
    // inputs such as /dev/urandom need the limit)
    inline bool readFd(int fd,std::string &out,long long max=-1){
        char buf[65536];
        for(;;){
            ssize_t r=::read(fd,buf,sizeof buf);
            size_t want=sizeof buf;
            if(max>=0){
                if(max==0) return true;
                if((long long)want>max) want=(size_t)max;
            }
            ssize_t r=::read(fd,buf,want);
            if(r<0){ if(errno==EINTR) continue; return false; }
            if(r==0) return true;
            out.append(buf,(size_t)r);
            if(max>=0) max-=r;
        }
    }

    // the whole of path ("-": stdin); false with errno set on failure
    inline bool readInput(const std::string &path,std::string &out){
        if(path=="-") return readFd(0,out);
    // the whole of path ("-": stdin), or its first max bytes if max>=0;
    // false with errno set on failure
    inline bool readInput(const std::string &path,std::string &out,long long max=-1){
        if(path=="-") return readFd(0,out,max);
        int fd=open(path.c_str(),O_RDONLY);
        if(fd<0) return false;
        bool ok=readFd(fd,out);
        bool ok=readFd(fd,out,max);
        int e=errno;
        close(fd);
        errno=e;
+5 −1
Changes for commands/text/textutils.cpp: 5 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -133,9 +133,13 @@ namespace fresh { namespace cmd {
            if(!o.ok) return 1;
            if(types.empty()) types.push_back({'o',2});
            if(o.operands.empty()) o.operands.push_back("-");
            // with -N read no more than needed: inputs like /dev/urandom never end
            long long want=limit>=0 ? skip+limit : -1;
            std::string data;
            for(auto &f: o.operands){
                if(!text::readInput(f,data)){ std::cerr << "od: " << f << ": " << strerror(errno) << std::endl; return 1; }
                long long left=want>=0 ? want-(long long)data.size() : -1;
                if(left==0) break;
                if(!text::readInput(f,data,left)){ std::cerr << "od: " << f << ": " << strerror(errno) << std::endl; return 1; }
            }
            if(skip>0) data=skip<(long long)data.size() ? data.substr((size_t)skip) : std::string();
            if(limit>=0 && limit<(long long)data.size()) data.resize((size_t)limit);