Commit f3e26f8d authored by jan.koester's avatar jan.koester
Browse files

test

parent ce14fa50
Loading
Loading
Loading
Loading
+75 −18
Changes for src/shell.cpp: 75 added lines, 18 removed lines.
Original line number Diff line number Diff line
@@ -159,6 +159,62 @@ static size_t dqEnd(const std::string &s,size_t from){
    return i;
}


// One past the "))" closing a "$((" at `at` (s.size() if unterminated).
static size_t arithEnd(const std::string &s,size_t at){
    size_t n=s.size(),j=at+3;
    int depth=0;
    while(j<n){
        if(s[j]=='$' && j+1<n && s[j+1]=='(' && !(j+2<n && s[j+2]=='(')){
            size_t c=cmdSubstClose(s,j+2);
            j=(c<n) ? c+1 : n;
            continue;
        }
        if(s[j]=='('){ ++depth; ++j; }
        else if(s[j]==')'){
            if(depth==0){
                ++j;
                if(j<n && s[j]==')') ++j;
                break;
            }
            --depth; ++j;
        }else ++j;
    }
    return j;
}

// "$((expr))": command substitutions inside expr run first (the kernel's
// mkcapflags.sh: $(( ( 5*8 - ($PFX_SZ + 1) - $(echo "$NAME" | wc -c) ) / 8 ))),
// then the arithmetic is evaluated
static std::string expandArith(const std::string &span){
    std::string out;
    size_t n=span.size(),i=0;
    // keep the leading "$((" and trailing "))" around the substituted body
    while(i<n){
        if(i>0 && span[i]=='$' && i+1<n && span[i+1]=='(' && !(i+2<n && span[i+2]=='(')){
            size_t c=cmdSubstClose(span,i+2);
            std::string r=fresh::Shell::instance().runCaptured(span.substr(i+2,c-(i+2)));
            while(!r.empty() && (r.back()=='\n' || r.back()==' ' || r.back()=='\t')) r.pop_back();
            size_t b=0;
            while(b<r.size() && (r[b]==' ' || r[b]=='\t')) ++b;
            out+=r.substr(b);
            i=(c<n) ? c+1 : n;
            continue;
        }
        if(span[i]=='`'){
            size_t e=span.find('`',i+1);
            if(e==std::string::npos) e=n;
            std::string r=fresh::Shell::instance().runCaptured(span.substr(i+1,e-i-1));
            while(!r.empty() && (r.back()=='\n' || r.back()==' ')) r.pop_back();
            out+=r;
            i=(e<n) ? e+1 : n;
            continue;
        }
        out+=span[i++];
    }
    return fresh::Environment::instance().expand(out);
}

static void pushGlobExpanded(std::vector<std::string> &tokens,const std::string &word){
    if(word.find_first_of("*?[")==std::string::npos){
        tokens.push_back(word);
@@ -644,25 +700,9 @@ std::vector<std::string> fresh::tokenizeShellArgs(const std::string &segment){
        // text accumulated just before this substitution resolves (in the
        // right order) ahead of it.
        if(c=='$' && i+2<n && segment[i+1]=='(' && segment[i+2]=='('){
            size_t j=i+3;
            int depth=0;
            while(j<n){
                if(segment[j]=='('){
                    ++depth; ++j;
                }else if(segment[j]==')'){
                    if(depth==0){
                        ++j;
                        if(j<n && segment[j]==')')
                            ++j;
                        break;
                    }
                    --depth; ++j;
                }else{
                    ++j;
                }
            }
            size_t j=arithEnd(segment,i);
            flushPending();
            current+=fresh::Environment::instance().expand(segment.substr(i,j-i));
            current+=expandArith(segment.substr(i,j-i));
            have=true;
            i=j;
            continue;
@@ -886,6 +926,13 @@ std::vector<std::string> fresh::tokenizeShellArgs(const std::string &segment){
                // sees it intact). Paren-depth tracked only (no quote-
                // awareness inside the substitution itself) -- same scope
                // limit the top-level "$(...)" handling already has.
                if(segment[i]=='$' && i+2<n && segment[i+1]=='(' && segment[i+2]=='('){
                    size_t j=arithEnd(segment,i);
                    flushRaw();
                    dqResult+=expandArith(segment.substr(i,j-i));
                    i=j;
                    continue;
                }
                if(segment[i]=='$' && i+1<n && segment[i+1]=='(' &&
                   !(i+2<n && segment[i+2]=='(')){
                    size_t j=cmdSubstClose(segment,i+2);
@@ -2040,6 +2087,16 @@ std::vector<std::string> fresh::splitPipelineStages(const std::string &segment,
            i=j;
            continue;
        }
        // a "( ... )" subshell group is one pipeline stage: a '|' inside it
        // belongs to the subshell (the kernel's net/wireless Makefile:
        // "(echo ...; echo | cat - $^ ; echo ...) > $@")
        if(c=='('){
            size_t j=cmdSubstClose(segment,i+1);
            if(j<n) ++j;
            current+=segment.substr(i,j-i);
            i=j;
            continue;
        }

        // "`cmd | filter`" -- same reasoning as "$(...)" above, just for
        // the older backtick spelling. Backticks don't nest (no depth to