Loading src/shell.cpp +59 −0 Changes for src/shell.cpp: 59 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1898,6 +1898,65 @@ bool fresh::extractSubshellBody(const std::string &stage,std::string &body,std:: return true; } // "{ cmds; } redirection" group as one pipeline stage -- e.g. the Linux // kernel's own scripts/syscallhdr.sh: "grep -E ... "$infile" | { echo ...; // while read ...; done; } > "$outfile"". Same job as extractSubshellBody() // just above, just for '{'/'}' instead of '('/')' -- see its own comment // for the depth-tracked, quote/backtick-aware scan this mirrors exactly. // Requires whitespace right after '{' (a bare "{foo}" is a literal word, // never a group opener), matching what the non-pipeline "{ CMDS; }" // handler in parse() already requires for the same reason. bool fresh::extractBraceGroupBody(const std::string &stage,std::string &body,std::string &suffix){ size_t i=0,n=stage.length(); while(i<n && (stage[i]==' ' || stage[i]=='\t')) ++i; if(i>=n || stage[i]!='{') return false; if(!(i+1<n && (stage[i+1]==' ' || stage[i+1]=='\t' || stage[i+1]=='\n'))) return false; size_t j=i+1; int depth=1; while(j<n && depth>0){ char c=stage[j]; if(c=='\'' || c=='"'){ char q=c; ++j; if(q=='"'){ while(j<n && stage[j]!=q){ if(stage[j]=='\\' && j+1<n && (stage[j+1]=='"' || stage[j+1]=='\\' || stage[j+1]=='$' || stage[j+1]=='`')) j+=2; else ++j; } }else{ while(j<n && stage[j]!=q) ++j; } }else if(c=='`'){ ++j; while(j<n && stage[j]!='`'){ if(stage[j]=='\\' && j+1<n && stage[j+1]=='`') ++j; ++j; } }else if(c=='{'){ ++depth; }else if(c=='}'){ --depth; } ++j; } if(depth>0) return false; // unterminated "{" -- treat as not a group at all body=stage.substr(i+1,(j-1)-(i+1)); suffix=stage.substr(j); return true; } // See shell.h's own comment for why this lives here (shared with // readLogicalLine() in fresh.cpp) instead of staying a fresh.cpp-local // static, and for the real-world case this fixes. Loading Loading
src/shell.cpp +59 −0 Changes for src/shell.cpp: 59 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1898,6 +1898,65 @@ bool fresh::extractSubshellBody(const std::string &stage,std::string &body,std:: return true; } // "{ cmds; } redirection" group as one pipeline stage -- e.g. the Linux // kernel's own scripts/syscallhdr.sh: "grep -E ... "$infile" | { echo ...; // while read ...; done; } > "$outfile"". Same job as extractSubshellBody() // just above, just for '{'/'}' instead of '('/')' -- see its own comment // for the depth-tracked, quote/backtick-aware scan this mirrors exactly. // Requires whitespace right after '{' (a bare "{foo}" is a literal word, // never a group opener), matching what the non-pipeline "{ CMDS; }" // handler in parse() already requires for the same reason. bool fresh::extractBraceGroupBody(const std::string &stage,std::string &body,std::string &suffix){ size_t i=0,n=stage.length(); while(i<n && (stage[i]==' ' || stage[i]=='\t')) ++i; if(i>=n || stage[i]!='{') return false; if(!(i+1<n && (stage[i+1]==' ' || stage[i+1]=='\t' || stage[i+1]=='\n'))) return false; size_t j=i+1; int depth=1; while(j<n && depth>0){ char c=stage[j]; if(c=='\'' || c=='"'){ char q=c; ++j; if(q=='"'){ while(j<n && stage[j]!=q){ if(stage[j]=='\\' && j+1<n && (stage[j+1]=='"' || stage[j+1]=='\\' || stage[j+1]=='$' || stage[j+1]=='`')) j+=2; else ++j; } }else{ while(j<n && stage[j]!=q) ++j; } }else if(c=='`'){ ++j; while(j<n && stage[j]!='`'){ if(stage[j]=='\\' && j+1<n && stage[j+1]=='`') ++j; ++j; } }else if(c=='{'){ ++depth; }else if(c=='}'){ --depth; } ++j; } if(depth>0) return false; // unterminated "{" -- treat as not a group at all body=stage.substr(i+1,(j-1)-(i+1)); suffix=stage.substr(j); return true; } // See shell.h's own comment for why this lives here (shared with // readLogicalLine() in fresh.cpp) instead of staying a fresh.cpp-local // static, and for the real-world case this fixes. Loading