Loading commands/filesystem/ls.cpp +221 −69 Changes for commands/filesystem/ls.cpp: 221 added lines, 69 removed lines. Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <dirent.h> #include <sys/stat.h> #include <pwd.h> #include <grp.h> #include <ctime> #include <sys/sysmacros.h> #include "shell.h" Loading @@ -46,106 +49,255 @@ namespace fresh { namespace cmd { public: LsCommand():ShellCommand("ls"){} static void printLong(const std::string &dirpath,const std::string &name){ std::string full=dirpath.empty() ? name : dirpath+"/"+name; private: struct Opts { bool all=false,almostAll=false,longFormat=false,numericIds=false,inode=false, dirItself=false,recursive=false,sortTime=false,sortSize=false,noSort=false, reverse=false,human=false,classify=false,slashDirs=false,follow=false; }; struct Item { std::string name; // as displayed std::string path; // for stat/readlink struct stat st; if(lstat(full.c_str(),&st)!=0){ std::cerr << "ls: " << full << ": " << strerror(errno) << std::endl; return; bool ok; }; static std::string modeString(mode_t m){ char p[11]; p[0]=S_ISDIR(m) ? 'd' : S_ISLNK(m) ? 'l' : S_ISCHR(m) ? 'c' : S_ISBLK(m) ? 'b' : S_ISFIFO(m) ? 'p' : S_ISSOCK(m) ? 's' : '-'; const char *rwx="rwxrwxrwx"; for(int k=0;k<9;++k) p[k+1]=(m & (0400>>k)) ? rwx[k] : '-'; if(m & S_ISUID) p[3]=(m & S_IXUSR) ? 's' : 'S'; if(m & S_ISGID) p[6]=(m & S_IXGRP) ? 's' : 'S'; if(m & S_ISVTX) p[9]=(m & S_IXOTH) ? 't' : 'T'; p[10]='\0'; return p; } char perms[11]; perms[0]=S_ISDIR(st.st_mode) ? 'd' : (S_ISLNK(st.st_mode) ? 'l' : '-'); perms[1]=(st.st_mode & S_IRUSR) ? 'r' : '-'; perms[2]=(st.st_mode & S_IWUSR) ? 'w' : '-'; perms[3]=(st.st_mode & S_IXUSR) ? 'x' : '-'; perms[4]=(st.st_mode & S_IRGRP) ? 'r' : '-'; perms[5]=(st.st_mode & S_IWGRP) ? 'w' : '-'; perms[6]=(st.st_mode & S_IXGRP) ? 'x' : '-'; perms[7]=(st.st_mode & S_IROTH) ? 'r' : '-'; perms[8]=(st.st_mode & S_IWOTH) ? 'w' : '-'; perms[9]=(st.st_mode & S_IXOTH) ? 'x' : '-'; perms[10]='\0'; static std::string humanSize(off_t sz){ const char *units="BKMGTPE"; double v=(double)sz; int u=0; while(v>=1024 && u<6){ v/=1024; ++u; } char buf[32]; if(u==0) snprintf(buf,sizeof buf,"%lld",(long long)sz); else if(v<10) snprintf(buf,sizeof buf,"%.1f%c",v,units[u]); else snprintf(buf,sizeof buf,"%.0f%c",v,units[u]); return buf; } struct passwd *pw=getpwuid(st.st_uid); std::string owner=pw ? pw->pw_name : std::to_string(st.st_uid); static char classifyChar(const struct stat &st,const Opts &o){ if(S_ISDIR(st.st_mode)) return '/'; if(!o.classify) return 0; if(S_ISLNK(st.st_mode)) return '@'; if(S_ISFIFO(st.st_mode)) return '|'; if(S_ISSOCK(st.st_mode)) return '='; if(st.st_mode & 0111) return '*'; return 0; } std::cout << perms << " " << st.st_nlink << " " << owner << " " << st.st_size << " " << name << std::endl; static void printItems(std::vector<Item> &items,const Opts &o){ // column widths for -l size_t wLinks=1,wUser=1,wGroup=1,wSize=1,wIno=1; std::vector<std::string> users(items.size()),groups(items.size()),sizes(items.size()); for(size_t k=0;k<items.size();++k){ Item &it=items[k]; if(!it.ok) continue; wIno=std::max(wIno,std::to_string((unsigned long long)it.st.st_ino).size()); if(!o.longFormat) continue; struct passwd *pw=o.numericIds ? nullptr : getpwuid(it.st.st_uid); struct group *gr=o.numericIds ? nullptr : getgrgid(it.st.st_gid); users[k]=pw ? pw->pw_name : std::to_string(it.st.st_uid); groups[k]=gr ? gr->gr_name : std::to_string(it.st.st_gid); if(S_ISCHR(it.st.st_mode) || S_ISBLK(it.st.st_mode)) sizes[k]=std::to_string(major(it.st.st_rdev))+", "+std::to_string(minor(it.st.st_rdev)); else sizes[k]=o.human ? humanSize(it.st.st_size) : std::to_string((long long)it.st.st_size); wLinks=std::max(wLinks,std::to_string((unsigned long)it.st.st_nlink).size()); wUser=std::max(wUser,users[k].size()); wGroup=std::max(wGroup,groups[k].size()); wSize=std::max(wSize,sizes[k].size()); } time_t now=time(nullptr); for(size_t k=0;k<items.size();++k){ Item &it=items[k]; if(!it.ok) continue; std::string line; if(o.inode){ std::string ino=std::to_string((unsigned long long)it.st.st_ino); line+=std::string(wIno-ino.size(),' ')+ino+" "; } if(o.longFormat){ std::string links=std::to_string((unsigned long)it.st.st_nlink); char date[32]; struct tm tmv; localtime_r(&it.st.st_mtime,&tmv); // older than ~6 months or in the future: year instead of time bool recent=it.st.st_mtime<=now && now-it.st.st_mtime<15552000; strftime(date,sizeof date,recent ? "%b %e %H:%M" : "%b %e %Y",&tmv); line+=modeString(it.st.st_mode)+" "+std::string(wLinks-links.size(),' ')+links+" "+ users[k]+std::string(wUser-users[k].size(),' ')+" "+ groups[k]+std::string(wGroup-groups[k].size(),' ')+" "+ std::string(wSize-sizes[k].size(),' ')+sizes[k]+" "+date+" "; } line+=it.name; char c=(o.classify || o.slashDirs) ? classifyChar(it.st,o) : 0; if(c && !(o.longFormat && S_ISLNK(it.st.st_mode))) line+=c; if(o.longFormat && S_ISLNK(it.st.st_mode)){ char target[4096]; ssize_t n=readlink(it.path.c_str(),target,sizeof(target)-1); if(n>=0){ target[n]='\0'; line+=" -> "; line+=target; } } std::cout << line << "\n"; } } static void listOne(const std::string &path,bool showAll,bool longFormat){ struct stat st; if(stat(path.c_str(),&st)!=0){ std::cerr << "ls: " << path << ": " << strerror(errno) << std::endl; return; static void sortItems(std::vector<Item> &items,const Opts &o){ if(o.noSort) return; std::sort(items.begin(),items.end(),[&](const Item &a,const Item &b){ if(o.sortTime && a.st.st_mtime!=b.st.st_mtime) return a.st.st_mtime>b.st.st_mtime; if(o.sortSize && a.st.st_size!=b.st.st_size) return a.st.st_size>b.st.st_size; return a.name<b.name; }); if(o.reverse) std::reverse(items.begin(),items.end()); } if(!S_ISDIR(st.st_mode)){ if(longFormat) printLong("",path); else std::cout << path << std::endl; return; bool statItem(Item &it,const Opts &o,bool commandLine){ bool follow=o.follow || (commandLine && !o.longFormat && !o.dirItself); it.ok=(follow ? stat(it.path.c_str(),&it.st) : lstat(it.path.c_str(),&it.st))==0; if(!it.ok && follow) it.ok=lstat(it.path.c_str(),&it.st)==0; return it.ok; } // lists a directory's contents; returns false on error bool listDir(const std::string &path,const Opts &o,bool header,bool &first){ DIR *dir=opendir(path.c_str()); if(!dir){ std::cerr << "ls: " << path << ": " << strerror(errno) << std::endl; return; std::cerr << "ls: cannot open directory '" << path << "': " << strerror(errno) << std::endl; return false; } std::vector<std::string> names; std::vector<Item> items; struct dirent *ent; while((ent=readdir(dir))!=NULL){ std::string name=ent->d_name; if(!showAll && !name.empty() && name[0]=='.') continue; names.push_back(name); if(!name.empty() && name[0]=='.'){ if(!o.all && !o.almostAll) continue; if(o.almostAll && !o.all && (name=="." || name=="..")) continue; } Item it; it.name=name; it.path=path+(path.back()=='/' ? "" : "/")+name; statItem(it,o,false); items.push_back(it); } closedir(dir); sortItems(items,o); std::sort(names.begin(),names.end()); if(header){ if(!first) std::cout << "\n"; std::cout << path << ":\n"; } first=false; if(o.longFormat){ long long blocks=0; for(auto &it: items) if(it.ok) blocks+=it.st.st_blocks; std::cout << "total " << blocks/2 << "\n"; } printItems(items,o); for(size_t i=0; i<names.size(); ++i){ if(longFormat) printLong(path,names[i]); else std::cout << names[i] << std::endl; bool ok=true; if(o.recursive){ for(auto &it: items){ if(!it.ok || !S_ISDIR(it.st.st_mode) || it.name=="." || it.name=="..") continue; if(!listDir(it.path,o,true,first)) ok=false; } } return ok; } public: int runCommand(int argc,const char **argv){ optind=0; opterr=0; bool showAll=false; bool longFormat=false; int opt; while((opt=getopt(argc,const_cast<char *const *>(argv),"al"))!=-1){ switch(opt){ case 'a': showAll=true; break; case 'l': longFormat=true; break; Opts o; std::vector<std::string> operands; bool endOfOpts=false; for(int i=1; i<argc; ++i){ std::string a=argv[i]; if(endOfOpts || a.size()<2 || a[0]!='-'){ operands.push_back(a); continue; } if(a=="--"){ endOfOpts=true; continue; } if(a.compare(0,2,"--")==0){ if(a=="--all") o.all=true; else if(a=="--almost-all") o.almostAll=true; else if(a=="--inode") o.inode=true; else if(a=="--directory") o.dirItself=true; else if(a=="--recursive") o.recursive=true; else if(a=="--reverse") o.reverse=true; else if(a=="--human-readable") o.human=true; else if(a=="--classify") o.classify=true; else if(a=="--numeric-uid-gid"){ o.numericIds=true; o.longFormat=true; } else if(a=="--dereference") o.follow=true; else if(a.compare(0,7,"--color")==0 || a.compare(0,8,"--colour")==0 || a=="--group-directories-first") {} else{ std::cerr << "ls: unrecognized option '" << a << "'" << std::endl; return 2; } continue; } for(size_t k=1;k<a.size();++k){ switch(a[k]){ case 'a': o.all=true; break; case 'A': o.almostAll=true; break; case 'l': o.longFormat=true; break; case 'n': o.numericIds=true; o.longFormat=true; break; case 'i': o.inode=true; break; case 'd': o.dirItself=true; break; case 'R': o.recursive=true; break; case 't': o.sortTime=true; break; case 'S': o.sortSize=true; break; case 'U': case 'f': o.noSort=true; if(a[k]=='f') o.all=true; break; case 'r': o.reverse=true; break; case 'h': o.human=true; break; case 'F': o.classify=true; break; case 'p': o.slashDirs=true; break; case 'L': o.follow=true; break; case '1': case 'C': case 'x': case 'm': break; // one entry per line default: std::cerr << "ls: invalid option" << std::endl; return 1; std::cerr << "ls: invalid option -- '" << a[k] << "'" << std::endl; return 2; } } if(optind>=argc){ listOne(".",showAll,longFormat); return 0; } if(operands.empty()) operands.push_back("."); for(int i=optind; i<argc; ++i) listOne(argv[i],showAll,longFormat); return 0; int status=0; // files first, then directories (with headers if several) std::vector<Item> files; std::vector<std::string> dirs; for(auto &op: operands){ Item it; it.name=op; it.path=op; if(!statItem(it,o,true)){ std::cerr << "ls: cannot access '" << op << "': " << strerror(errno) << std::endl; status=2; continue; } if(S_ISDIR(it.st.st_mode) && !o.dirItself) dirs.push_back(op); else files.push_back(it); } sortItems(files,o); printItems(files,o); bool first=files.empty(); bool headers=(operands.size()>1) || o.recursive; if(!o.noSort) std::sort(dirs.begin(),dirs.end()); if(o.reverse) std::reverse(dirs.begin(),dirs.end()); for(auto &d: dirs){ if(!listDir(d,o,headers,first)) status=status ? status : 1; } std::cout.flush(); return status; } }; Loading commands/filesystem/rm.cpp +43 −18 Changes for commands/filesystem/rm.cpp: 43 added lines, 18 removed lines. Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include <iostream> #include <vector> #include <string> #include <string> #include <cstring> #include <cerrno> Loading Loading @@ -87,28 +89,45 @@ namespace fresh { namespace cmd { } int runCommand(int argc,const char **argv){ optind=0; opterr=0; bool recursive=false; bool force=false; int opt; while((opt=getopt(argc,const_cast<char *const *>(argv),"rRf"))!=-1){ switch(opt){ case 'r': case 'R': recursive=true; break; case 'f': force=true; break; bool dirs=false; bool verbose=false; std::vector<const char*> operands; bool endOfOpts=false; // GNU-style: options anywhere before "--", long forms too for(int i=1; i<argc; ++i){ std::string a=argv[i]; if(endOfOpts || a.size()<2 || a[0]!='-'){ operands.push_back(argv[i]); continue; } if(a=="--"){ endOfOpts=true; continue; } if(a.compare(0,2,"--")==0){ if(a=="--force") force=true; else if(a=="--recursive") recursive=true; else if(a=="--dir") dirs=true; else if(a=="--verbose") verbose=true; else if(a=="--interactive=never" || a=="--no-preserve-root" || a=="--preserve-root" || a=="--one-file-system") {} else{ std::cerr << "rm: unrecognized option '" << a << "'" << std::endl; return 1; } continue; } for(size_t k=1;k<a.size();++k){ switch(a[k]){ case 'r': case 'R': recursive=true; break; case 'f': force=true; break; case 'd': dirs=true; break; case 'v': verbose=true; break; case 'i': case 'I': force=false; break; default: std::cerr << "rm: invalid option" << std::endl; std::cerr << "rm: invalid option -- '" << a[k] << "'" << std::endl; return 1; } } } if(optind>=argc){ if(operands.empty()){ if(force) return 0; std::cerr << "rm: missing operand" << std::endl; Loading @@ -117,8 +136,7 @@ namespace fresh { namespace cmd { int failed=0; for(int i=optind; i<argc; ++i){ const char *path=argv[i]; for(const char *path: operands){ struct stat st; if(lstat(path,&st)!=0){ Loading @@ -130,13 +148,20 @@ namespace fresh { namespace cmd { } if(S_ISDIR(st.st_mode) && !recursive){ std::cerr << "rm: " << path << ": Is a directory" << std::endl; // -d: an empty directory may go without -r if(dirs && rmdir(path)==0){ if(verbose) std::cout << "removed directory '" << path << "'" << std::endl; continue; } std::cerr << "rm: " << path << ": " << (dirs ? strerror(errno) : "Is a directory") << std::endl; failed=1; continue; } if(removeRecursive(path,force)!=0) failed=1; else if(verbose) std::cout << "removed '" << path << "'" << std::endl; } return failed; Loading commands/text/grep.cpp +340 −119 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
commands/filesystem/ls.cpp +221 −69 Changes for commands/filesystem/ls.cpp: 221 added lines, 69 removed lines. Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <dirent.h> #include <sys/stat.h> #include <pwd.h> #include <grp.h> #include <ctime> #include <sys/sysmacros.h> #include "shell.h" Loading @@ -46,106 +49,255 @@ namespace fresh { namespace cmd { public: LsCommand():ShellCommand("ls"){} static void printLong(const std::string &dirpath,const std::string &name){ std::string full=dirpath.empty() ? name : dirpath+"/"+name; private: struct Opts { bool all=false,almostAll=false,longFormat=false,numericIds=false,inode=false, dirItself=false,recursive=false,sortTime=false,sortSize=false,noSort=false, reverse=false,human=false,classify=false,slashDirs=false,follow=false; }; struct Item { std::string name; // as displayed std::string path; // for stat/readlink struct stat st; if(lstat(full.c_str(),&st)!=0){ std::cerr << "ls: " << full << ": " << strerror(errno) << std::endl; return; bool ok; }; static std::string modeString(mode_t m){ char p[11]; p[0]=S_ISDIR(m) ? 'd' : S_ISLNK(m) ? 'l' : S_ISCHR(m) ? 'c' : S_ISBLK(m) ? 'b' : S_ISFIFO(m) ? 'p' : S_ISSOCK(m) ? 's' : '-'; const char *rwx="rwxrwxrwx"; for(int k=0;k<9;++k) p[k+1]=(m & (0400>>k)) ? rwx[k] : '-'; if(m & S_ISUID) p[3]=(m & S_IXUSR) ? 's' : 'S'; if(m & S_ISGID) p[6]=(m & S_IXGRP) ? 's' : 'S'; if(m & S_ISVTX) p[9]=(m & S_IXOTH) ? 't' : 'T'; p[10]='\0'; return p; } char perms[11]; perms[0]=S_ISDIR(st.st_mode) ? 'd' : (S_ISLNK(st.st_mode) ? 'l' : '-'); perms[1]=(st.st_mode & S_IRUSR) ? 'r' : '-'; perms[2]=(st.st_mode & S_IWUSR) ? 'w' : '-'; perms[3]=(st.st_mode & S_IXUSR) ? 'x' : '-'; perms[4]=(st.st_mode & S_IRGRP) ? 'r' : '-'; perms[5]=(st.st_mode & S_IWGRP) ? 'w' : '-'; perms[6]=(st.st_mode & S_IXGRP) ? 'x' : '-'; perms[7]=(st.st_mode & S_IROTH) ? 'r' : '-'; perms[8]=(st.st_mode & S_IWOTH) ? 'w' : '-'; perms[9]=(st.st_mode & S_IXOTH) ? 'x' : '-'; perms[10]='\0'; static std::string humanSize(off_t sz){ const char *units="BKMGTPE"; double v=(double)sz; int u=0; while(v>=1024 && u<6){ v/=1024; ++u; } char buf[32]; if(u==0) snprintf(buf,sizeof buf,"%lld",(long long)sz); else if(v<10) snprintf(buf,sizeof buf,"%.1f%c",v,units[u]); else snprintf(buf,sizeof buf,"%.0f%c",v,units[u]); return buf; } struct passwd *pw=getpwuid(st.st_uid); std::string owner=pw ? pw->pw_name : std::to_string(st.st_uid); static char classifyChar(const struct stat &st,const Opts &o){ if(S_ISDIR(st.st_mode)) return '/'; if(!o.classify) return 0; if(S_ISLNK(st.st_mode)) return '@'; if(S_ISFIFO(st.st_mode)) return '|'; if(S_ISSOCK(st.st_mode)) return '='; if(st.st_mode & 0111) return '*'; return 0; } std::cout << perms << " " << st.st_nlink << " " << owner << " " << st.st_size << " " << name << std::endl; static void printItems(std::vector<Item> &items,const Opts &o){ // column widths for -l size_t wLinks=1,wUser=1,wGroup=1,wSize=1,wIno=1; std::vector<std::string> users(items.size()),groups(items.size()),sizes(items.size()); for(size_t k=0;k<items.size();++k){ Item &it=items[k]; if(!it.ok) continue; wIno=std::max(wIno,std::to_string((unsigned long long)it.st.st_ino).size()); if(!o.longFormat) continue; struct passwd *pw=o.numericIds ? nullptr : getpwuid(it.st.st_uid); struct group *gr=o.numericIds ? nullptr : getgrgid(it.st.st_gid); users[k]=pw ? pw->pw_name : std::to_string(it.st.st_uid); groups[k]=gr ? gr->gr_name : std::to_string(it.st.st_gid); if(S_ISCHR(it.st.st_mode) || S_ISBLK(it.st.st_mode)) sizes[k]=std::to_string(major(it.st.st_rdev))+", "+std::to_string(minor(it.st.st_rdev)); else sizes[k]=o.human ? humanSize(it.st.st_size) : std::to_string((long long)it.st.st_size); wLinks=std::max(wLinks,std::to_string((unsigned long)it.st.st_nlink).size()); wUser=std::max(wUser,users[k].size()); wGroup=std::max(wGroup,groups[k].size()); wSize=std::max(wSize,sizes[k].size()); } time_t now=time(nullptr); for(size_t k=0;k<items.size();++k){ Item &it=items[k]; if(!it.ok) continue; std::string line; if(o.inode){ std::string ino=std::to_string((unsigned long long)it.st.st_ino); line+=std::string(wIno-ino.size(),' ')+ino+" "; } if(o.longFormat){ std::string links=std::to_string((unsigned long)it.st.st_nlink); char date[32]; struct tm tmv; localtime_r(&it.st.st_mtime,&tmv); // older than ~6 months or in the future: year instead of time bool recent=it.st.st_mtime<=now && now-it.st.st_mtime<15552000; strftime(date,sizeof date,recent ? "%b %e %H:%M" : "%b %e %Y",&tmv); line+=modeString(it.st.st_mode)+" "+std::string(wLinks-links.size(),' ')+links+" "+ users[k]+std::string(wUser-users[k].size(),' ')+" "+ groups[k]+std::string(wGroup-groups[k].size(),' ')+" "+ std::string(wSize-sizes[k].size(),' ')+sizes[k]+" "+date+" "; } line+=it.name; char c=(o.classify || o.slashDirs) ? classifyChar(it.st,o) : 0; if(c && !(o.longFormat && S_ISLNK(it.st.st_mode))) line+=c; if(o.longFormat && S_ISLNK(it.st.st_mode)){ char target[4096]; ssize_t n=readlink(it.path.c_str(),target,sizeof(target)-1); if(n>=0){ target[n]='\0'; line+=" -> "; line+=target; } } std::cout << line << "\n"; } } static void listOne(const std::string &path,bool showAll,bool longFormat){ struct stat st; if(stat(path.c_str(),&st)!=0){ std::cerr << "ls: " << path << ": " << strerror(errno) << std::endl; return; static void sortItems(std::vector<Item> &items,const Opts &o){ if(o.noSort) return; std::sort(items.begin(),items.end(),[&](const Item &a,const Item &b){ if(o.sortTime && a.st.st_mtime!=b.st.st_mtime) return a.st.st_mtime>b.st.st_mtime; if(o.sortSize && a.st.st_size!=b.st.st_size) return a.st.st_size>b.st.st_size; return a.name<b.name; }); if(o.reverse) std::reverse(items.begin(),items.end()); } if(!S_ISDIR(st.st_mode)){ if(longFormat) printLong("",path); else std::cout << path << std::endl; return; bool statItem(Item &it,const Opts &o,bool commandLine){ bool follow=o.follow || (commandLine && !o.longFormat && !o.dirItself); it.ok=(follow ? stat(it.path.c_str(),&it.st) : lstat(it.path.c_str(),&it.st))==0; if(!it.ok && follow) it.ok=lstat(it.path.c_str(),&it.st)==0; return it.ok; } // lists a directory's contents; returns false on error bool listDir(const std::string &path,const Opts &o,bool header,bool &first){ DIR *dir=opendir(path.c_str()); if(!dir){ std::cerr << "ls: " << path << ": " << strerror(errno) << std::endl; return; std::cerr << "ls: cannot open directory '" << path << "': " << strerror(errno) << std::endl; return false; } std::vector<std::string> names; std::vector<Item> items; struct dirent *ent; while((ent=readdir(dir))!=NULL){ std::string name=ent->d_name; if(!showAll && !name.empty() && name[0]=='.') continue; names.push_back(name); if(!name.empty() && name[0]=='.'){ if(!o.all && !o.almostAll) continue; if(o.almostAll && !o.all && (name=="." || name=="..")) continue; } Item it; it.name=name; it.path=path+(path.back()=='/' ? "" : "/")+name; statItem(it,o,false); items.push_back(it); } closedir(dir); sortItems(items,o); std::sort(names.begin(),names.end()); if(header){ if(!first) std::cout << "\n"; std::cout << path << ":\n"; } first=false; if(o.longFormat){ long long blocks=0; for(auto &it: items) if(it.ok) blocks+=it.st.st_blocks; std::cout << "total " << blocks/2 << "\n"; } printItems(items,o); for(size_t i=0; i<names.size(); ++i){ if(longFormat) printLong(path,names[i]); else std::cout << names[i] << std::endl; bool ok=true; if(o.recursive){ for(auto &it: items){ if(!it.ok || !S_ISDIR(it.st.st_mode) || it.name=="." || it.name=="..") continue; if(!listDir(it.path,o,true,first)) ok=false; } } return ok; } public: int runCommand(int argc,const char **argv){ optind=0; opterr=0; bool showAll=false; bool longFormat=false; int opt; while((opt=getopt(argc,const_cast<char *const *>(argv),"al"))!=-1){ switch(opt){ case 'a': showAll=true; break; case 'l': longFormat=true; break; Opts o; std::vector<std::string> operands; bool endOfOpts=false; for(int i=1; i<argc; ++i){ std::string a=argv[i]; if(endOfOpts || a.size()<2 || a[0]!='-'){ operands.push_back(a); continue; } if(a=="--"){ endOfOpts=true; continue; } if(a.compare(0,2,"--")==0){ if(a=="--all") o.all=true; else if(a=="--almost-all") o.almostAll=true; else if(a=="--inode") o.inode=true; else if(a=="--directory") o.dirItself=true; else if(a=="--recursive") o.recursive=true; else if(a=="--reverse") o.reverse=true; else if(a=="--human-readable") o.human=true; else if(a=="--classify") o.classify=true; else if(a=="--numeric-uid-gid"){ o.numericIds=true; o.longFormat=true; } else if(a=="--dereference") o.follow=true; else if(a.compare(0,7,"--color")==0 || a.compare(0,8,"--colour")==0 || a=="--group-directories-first") {} else{ std::cerr << "ls: unrecognized option '" << a << "'" << std::endl; return 2; } continue; } for(size_t k=1;k<a.size();++k){ switch(a[k]){ case 'a': o.all=true; break; case 'A': o.almostAll=true; break; case 'l': o.longFormat=true; break; case 'n': o.numericIds=true; o.longFormat=true; break; case 'i': o.inode=true; break; case 'd': o.dirItself=true; break; case 'R': o.recursive=true; break; case 't': o.sortTime=true; break; case 'S': o.sortSize=true; break; case 'U': case 'f': o.noSort=true; if(a[k]=='f') o.all=true; break; case 'r': o.reverse=true; break; case 'h': o.human=true; break; case 'F': o.classify=true; break; case 'p': o.slashDirs=true; break; case 'L': o.follow=true; break; case '1': case 'C': case 'x': case 'm': break; // one entry per line default: std::cerr << "ls: invalid option" << std::endl; return 1; std::cerr << "ls: invalid option -- '" << a[k] << "'" << std::endl; return 2; } } if(optind>=argc){ listOne(".",showAll,longFormat); return 0; } if(operands.empty()) operands.push_back("."); for(int i=optind; i<argc; ++i) listOne(argv[i],showAll,longFormat); return 0; int status=0; // files first, then directories (with headers if several) std::vector<Item> files; std::vector<std::string> dirs; for(auto &op: operands){ Item it; it.name=op; it.path=op; if(!statItem(it,o,true)){ std::cerr << "ls: cannot access '" << op << "': " << strerror(errno) << std::endl; status=2; continue; } if(S_ISDIR(it.st.st_mode) && !o.dirItself) dirs.push_back(op); else files.push_back(it); } sortItems(files,o); printItems(files,o); bool first=files.empty(); bool headers=(operands.size()>1) || o.recursive; if(!o.noSort) std::sort(dirs.begin(),dirs.end()); if(o.reverse) std::reverse(dirs.begin(),dirs.end()); for(auto &d: dirs){ if(!listDir(d,o,headers,first)) status=status ? status : 1; } std::cout.flush(); return status; } }; Loading
commands/filesystem/rm.cpp +43 −18 Changes for commands/filesystem/rm.cpp: 43 added lines, 18 removed lines. Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include <iostream> #include <vector> #include <string> #include <string> #include <cstring> #include <cerrno> Loading Loading @@ -87,28 +89,45 @@ namespace fresh { namespace cmd { } int runCommand(int argc,const char **argv){ optind=0; opterr=0; bool recursive=false; bool force=false; int opt; while((opt=getopt(argc,const_cast<char *const *>(argv),"rRf"))!=-1){ switch(opt){ case 'r': case 'R': recursive=true; break; case 'f': force=true; break; bool dirs=false; bool verbose=false; std::vector<const char*> operands; bool endOfOpts=false; // GNU-style: options anywhere before "--", long forms too for(int i=1; i<argc; ++i){ std::string a=argv[i]; if(endOfOpts || a.size()<2 || a[0]!='-'){ operands.push_back(argv[i]); continue; } if(a=="--"){ endOfOpts=true; continue; } if(a.compare(0,2,"--")==0){ if(a=="--force") force=true; else if(a=="--recursive") recursive=true; else if(a=="--dir") dirs=true; else if(a=="--verbose") verbose=true; else if(a=="--interactive=never" || a=="--no-preserve-root" || a=="--preserve-root" || a=="--one-file-system") {} else{ std::cerr << "rm: unrecognized option '" << a << "'" << std::endl; return 1; } continue; } for(size_t k=1;k<a.size();++k){ switch(a[k]){ case 'r': case 'R': recursive=true; break; case 'f': force=true; break; case 'd': dirs=true; break; case 'v': verbose=true; break; case 'i': case 'I': force=false; break; default: std::cerr << "rm: invalid option" << std::endl; std::cerr << "rm: invalid option -- '" << a[k] << "'" << std::endl; return 1; } } } if(optind>=argc){ if(operands.empty()){ if(force) return 0; std::cerr << "rm: missing operand" << std::endl; Loading @@ -117,8 +136,7 @@ namespace fresh { namespace cmd { int failed=0; for(int i=optind; i<argc; ++i){ const char *path=argv[i]; for(const char *path: operands){ struct stat st; if(lstat(path,&st)!=0){ Loading @@ -130,13 +148,20 @@ namespace fresh { namespace cmd { } if(S_ISDIR(st.st_mode) && !recursive){ std::cerr << "rm: " << path << ": Is a directory" << std::endl; // -d: an empty directory may go without -r if(dirs && rmdir(path)==0){ if(verbose) std::cout << "removed directory '" << path << "'" << std::endl; continue; } std::cerr << "rm: " << path << ": " << (dirs ? strerror(errno) : "Is a directory") << std::endl; failed=1; continue; } if(removeRecursive(path,force)!=0) failed=1; else if(verbose) std::cout << "removed '" << path << "'" << std::endl; } return failed; Loading
commands/text/grep.cpp +340 −119 File changed.Preview size limit exceeded, changes collapsed. Show changes