Commit 517285a1 authored by jan.koester's avatar jan.koester
Browse files

test

parent 8c4a3c7d
Loading
Loading
Loading
Loading
+50 −30
Changes for commands/editor/sed.cpp: 50 added lines, 30 removed lines.
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ namespace fresh { namespace cmd {
            std::map<std::string,std::unique_ptr<std::ofstream>> wstreams;
            std::map<std::string,std::unique_ptr<std::ifstream>> rstreams; // R command readers
            std::ostream *out=&std::cout;
            bool missingNl=false;   // the last line written lacked its newline
            int lastRe=-1;
            std::string error;
            int status=0;
@@ -413,7 +414,7 @@ namespace fresh { namespace cmd {
                // after a command: optional spaces, then ';', newline, '}' or '#'
                s.ws();
                if(!s.end() && s.peek()!=';' && s.peek()!='\n' && s.peek()!='}' && s.peek()!='#' &&
                   c.name!='}' && c.name!='a' && c.name!='i' && c.name!='c')
                   c.name!='{' && c.name!='}' && c.name!='a' && c.name!='i' && c.name!='c')
                    return fail(r,std::string("extra characters after command"));
                r.sc.cmds.push_back(std::move(c));
            }
@@ -528,7 +529,8 @@ namespace fresh { namespace cmd {
            std::string ps,hs;
            long lineNo=0;
            bool isLast=false;
            bool lastHadNl=true;
            bool psNl=true;         // the pattern space ends a newline-terminated line
            bool hsNl=true;
            bool subst=false;       // for t/T
            std::string appendQ;    // a/r/R output after the cycle
            std::string file;
@@ -536,11 +538,6 @@ namespace fresh { namespace cmd {
            int exitCode=0;
        };

        static void writeLine(std::ostream &o,const std::string &s,bool nl,char delim){
            o << s;
            if(nl) o << delim;
        }

        bool matchRe(Run &r,int idx,const std::string &s,size_t nmatch=0,regmatch_t *m=nullptr,int eflags=0){
            if(idx<0) idx=r.lastRe;
            if(idx<0){ fail(r,"no previous regular expression"); return false; }
@@ -655,11 +652,21 @@ namespace fresh { namespace cmd {
            long count=0;
            bool did=false;
            regmatch_t m[10];
            size_t prevEnd=std::string::npos;
            while(pos<=src.size()){
                int ef=pos>0 ? REG_NOTBOL : 0;
                if(regexec(re,src.c_str()+pos,10,m,ef)!=0) break;
                ++count;
                size_t so=pos+m[0].rm_so,eo=pos+m[0].rm_eo;
                if(so==eo && so==prevEnd){
                    // an empty match right where the previous one ended
                    // doesn't count (GNU: "six" s/x*/-/g -> "-s-i-")
                    if(so>=src.size()) break;
                    out+=src[so];
                    pos=so+1;
                    continue;
                }
                prevEnd=eo;
                ++count;
                bool replaceThis=count>=c.nth && (c.global || count==c.nth);
                out.append(src,pos,so-pos);
                if(replaceThis){
@@ -721,19 +728,29 @@ namespace fresh { namespace cmd {
            return out+line+"$";
        }

        // every write to the main output: first the newline a previous,
        // unterminated last line still owes (GNU sed does the same)
        void emit(Run &r,const std::string &s){
            if(r.missingNl){ *r.out << (r.nulData ? '\0' : '\n'); r.missingNl=false; }
            *r.out << s;
        }

        void flushAppend(Run &r,State &st){
            if(!st.appendQ.empty()){
                *r.out << st.appendQ;
                emit(r,st.appendQ);
                st.appendQ.clear();
            }
        }

        void output(Run &r,State &st,const std::string &s){
            writeLine(*r.out,s,st.lastHadNl || !st.isLast,r.nulData ? '\0' : '\n');
        void output(Run &r,State &st,const std::string &s,bool terminated){
            emit(r,s);
            if(terminated) *r.out << (r.nulData ? '\0' : '\n');
            else r.missingNl=true;
            (void)st;
        }

        void writeTo(Run &r,const std::string &file,const std::string &s,char delim){
            if(file=="/dev/stdout"){ *r.out << s << delim; return; }
            if(file=="/dev/stdout"){ emit(r,s+std::string(1,delim)); return; }
            if(file=="/dev/stderr"){ std::cerr << s << delim; return; }
            std::ofstream *f=wstream(r,file);
            if(f){ *f << s << delim; f->flush(); }
@@ -757,12 +774,12 @@ namespace fresh { namespace cmd {
                }
                switch(c.name){
                    case '{': break;
                    case '=': *r.out << st.lineNo << '\n'; break;
                    case '=': emit(r,std::to_string(st.lineNo)+"\n"); break;
                    case 'a': st.appendQ+=c.text+"\n"; break;
                    case 'i': *r.out << c.text << '\n'; break;
                    case 'i': emit(r,c.text+"\n"); break;
                    case 'c':
                        // in a range: the text once, at its end
                        if(c.a2.type==Addr::None || c.negate || !c.active) *r.out << c.text << '\n';
                        if(c.a2.type==Addr::None || c.negate || !c.active) emit(r,c.text+"\n");
                        st.ps.clear();
                        autoPrint=false;
                        pc=cmds.size();
@@ -793,17 +810,19 @@ namespace fresh { namespace cmd {
                    }
                    case 'e':
                        if(c.text.empty()) st.ps=runShell(st.ps);
                        else *r.out << runShell(c.text) << '\n';
                        else emit(r,runShell(c.text)+"\n");
                        break;
                    case 'F': *r.out << (st.file.empty() ? "-" : st.file) << '\n'; break;
                    case 'g': st.ps=st.hs; break;
                    case 'G': st.ps+="\n"+st.hs; break;
                    case 'h': st.hs=st.ps; break;
                    case 'H': st.hs+="\n"+st.ps; break;
                    case 'x': std::swap(st.ps,st.hs); break;
                    case 'l': *r.out << escapeL(st.ps,c.lwidth<0 ? 70 : c.lwidth) << '\n'; break;
                    case 'F': emit(r,(st.file.empty() ? std::string("-") : st.file)+"\n"); break;
                    case 'g': st.ps=st.hs; st.psNl=st.hsNl; break;
                    // appending: the appended part decides whether the
                    // result still owes a final newline (as in GNU sed)
                    case 'G': st.ps+="\n"+st.hs; st.psNl=st.hsNl; break;
                    case 'h': st.hs=st.ps; st.hsNl=st.psNl; break;
                    case 'H': st.hs+="\n"+st.ps; st.hsNl=st.psNl; break;
                    case 'x': std::swap(st.ps,st.hs); std::swap(st.psNl,st.hsNl); break;
                    case 'l': emit(r,escapeL(st.ps,c.lwidth<0 ? 70 : c.lwidth)+"\n"); break;
                    case 'n':
                        if(r.quiet ? false : true) output(r,st,st.ps);
                        if(r.quiet ? false : true) output(r,st,st.ps,st.psNl);
                        flushAppend(r,st);
                        if(!nextLine(r,st,in,false)){ autoPrint=false; st.quit=true; continue; }
                        break;
@@ -818,10 +837,10 @@ namespace fresh { namespace cmd {
                        }
                        break;
                    }
                    case 'p': output(r,st,st.ps); break;
                    case 'p': output(r,st,st.ps,st.psNl); break;
                    case 'P': {
                        size_t p=st.ps.find('\n');
                        *r.out << st.ps.substr(0,p) << nl;
                        emit(r,st.ps.substr(0,p)+std::string(1,nl));
                        break;
                    }
                    case 'q':
@@ -851,7 +870,7 @@ namespace fresh { namespace cmd {
                    case 's':
                        if(substitute(r,c,st)){
                            st.subst=true;
                            if(c.print) output(r,st,st.ps);
                            if(c.print) output(r,st,st.ps,st.psNl);
                            if(!c.wfile.empty()) writeTo(r,c.wfile,st.ps,nl);
                        }
                        if(!r.error.empty()) return;
@@ -866,7 +885,7 @@ namespace fresh { namespace cmd {
                }
                ++pc;
            }
            if(autoPrint) output(r,st,st.ps);
            if(autoPrint) output(r,st,st.ps,st.psNl);
            flushAppend(r,st);
        }

@@ -878,7 +897,7 @@ namespace fresh { namespace cmd {
            if(!in.read(line,hadNl,isLast,sf,file)) return false;
            ++st.lineNo;
            st.isLast=isLast;
            st.lastHadNl=hadNl;
            st.psNl=hadNl;
            st.file=file;
            if(append) st.ps+="\n"+line;
            else st.ps=line;
@@ -902,7 +921,7 @@ namespace fresh { namespace cmd {
                ++st.lineNo;
                st.ps=line;
                st.isLast=isLast;
                st.lastHadNl=hadNl;
                st.psNl=hadNl;
                st.file=file;
                cycle(r,st,in);
                if(!r.error.empty()){
@@ -946,6 +965,7 @@ namespace fresh { namespace cmd {
                {
                    std::ofstream o(tmp.c_str(),std::ios::out|std::ios::trunc|std::ios::binary);
                    r.out=&o;
                    r.missingNl=false;
                    for(auto &c: r.sc.cmds) c.active=false;
                    int rc=process(r,{f});
                    o.flush();