Commit 3c8769c3 authored by jan.koester's avatar jan.koester
Browse files

test

parent 157d58c6
Loading
Loading
Loading
Loading
+54 −2
Changes for lib/awk/awk.cpp: 54 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -930,7 +930,7 @@ static std::vector<std::string> splitByFS(const std::string &s,const std::string
        if(s.empty()) out.clear();
    }else{
        try{
            std::regex re(fs,std::regex::extended);
            const std::regex &re=compileRegex(fs);
            size_t start=0;
            std::sregex_iterator it(s.begin(),s.end(),re), end;
            if(s.empty()){ /* no fields */ }
@@ -1121,11 +1121,63 @@ Value Interp::doCompoundAssign(NodeP n){
    return v;
}

// awk EREs as awks read them: a '{' that doesn't open a valid interval
// ({n}, {n,}, {n,m}) and a '}' that doesn't close one are plain
// characters (the kernel's orc_hash.sh matches /^struct orc_entry {$/),
// where std::regex's extended grammar rejects both.
static std::string awkEre(const std::string &pat){
    std::string out;
    out.reserve(pat.size()+8);
    size_t i=0,n=pat.size();
    while(i<n){
        char c=pat[i];
        if(c=='\\' && i+1<n){ out+=c; out+=pat[i+1]; i+=2; continue; }
        if(c=='['){
            // copy a bracket expression whole: ']' first is literal, and
            // "[:class:]" parts may contain ']'
            size_t j=i+1;
            if(j<n && pat[j]=='^') j++;
            if(j<n && pat[j]==']') j++;
            while(j<n && pat[j]!=']'){
                if(pat[j]=='[' && j+1<n && (pat[j+1]==':' || pat[j+1]=='.' || pat[j+1]=='=')){
                    char kind=pat[j+1];
                    size_t e=pat.find(std::string(1,kind)+"]",j+2);
                    j=(e==std::string::npos) ? n : e+2;
                    continue;
                }
                j++;
            }
            if(j>=n){ out+="\\["; i++; continue; }   // unterminated: literal '['
            out.append(pat,i,j-i+1);
            i=j+1;
            continue;
        }
        if(c=='{'){
            size_t j=i+1;
            bool digits=false;
            while(j<n && isdigit((unsigned char)pat[j])){ j++; digits=true; }
            if(digits && j<n && pat[j]==','){
                j++;
                while(j<n && isdigit((unsigned char)pat[j])) j++;
            }
            bool interval=digits && j<n && pat[j]=='}' && !out.empty();
            if(interval){ out.append(pat,i,j-i+1); i=j+1; continue; }
            out+="\\{";
            i++;
            continue;
        }
        if(c=='}'){ out+="\\}"; i++; continue; }
        out+=c;
        i++;
    }
    return out;
}

const std::regex &Interp::compileRegex(const std::string &pat){
    auto it=regexCache_.find(pat);
    if(it!=regexCache_.end()) return it->second;
    std::regex re;
    try{ re=std::regex(pat,std::regex::extended); }
    try{ re=std::regex(awkEre(pat),std::regex::extended); }
    catch(...){ try{ re=std::regex(pat); }catch(...){ re=std::regex(""); } }
    return regexCache_.emplace(pat,std::move(re)).first->second;
}