diff --git a/utils/ls.cpp b/utils/ls.cpp index c8975eeb..3d9bccdb 100644 --- a/utils/ls.cpp +++ b/utils/ls.cpp @@ -20,42 +20,187 @@ *******************************************************************************/ -#include -#include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include -#include -#include -#include -#include +#include + +#if defined(sortix) +#define execvp execv +#endif + +bool longformat = false; +bool showdotdot = false; +bool showdotfiles = false; + +pid_t childpid; + +void finishoutput() +{ + int status; + fflush(stdout); + if ( childpid ) { close(1); wait(&status); } + childpid = 0; +} + +int handleentry(const char* path, const char* name) +{ + bool isdotdot = strcmp(name, ".") == 0 || strcmp(name, "..") == 0; + bool isdotfile = !isdotdot && name[0] == '.'; + if ( isdotdot && !showdotdot ) { return 0; } + if ( isdotfile && !showdotfiles ) { return 0; } + if ( !longformat ) + { + printf("%s\n", name); + return 0; + } + // TODO: Use openat and fstat. + char* fullpath = new char[strlen(path) + 1 + strlen(name) + 1]; + strcpy(fullpath, path); + strcat(fullpath, "/"); + strcat(fullpath, name); + struct stat st; + if ( stat(fullpath, &st) ) + { + finishoutput(); + error(0, errno, "stat: %s", fullpath); + return 2; + } + char perms[11]; + perms[0] = '?'; + if ( S_ISREG(st.st_mode) ) { perms[0] = '-'; } + if ( S_ISDIR(st.st_mode) ) { perms[0] = 'd'; } + const char flagnames[] = { 'x', 'w', 'r' }; + for ( size_t i = 0; i < 9; i++ ) + { + bool set = st.st_mode & (1UL<d_name); + int result; + if ( (result = handleentry(path, entry->d_name)) ) { return result; } } +#if defined(sortix) if ( derror(dir) ) { - error(2, errno, "readdir: %s", path); + finishoutput(); + error(0, errno, "readdir: %s", path); + return 2; } +#endif closedir(dir); return 0; } +void usage(FILE* fp, const char* argv0) +{ + fprintf(fp, "usage: %s [-l] [-a | -A] [ ...]\n", argv0); +} + +void version(FILE* fp, const char* argv0) +{ + return usage(fp, argv0); +} + +void help(FILE* fp, const char* argv0) +{ + return usage(fp, argv0); +} + int main(int argc, char* argv[]) { - pid_t childpid = 0; - if ( isatty(1) ) + const char* argv0 = argv[0]; + for ( int i = 0; i < argc; i++ ) + { + const char* arg = argv[i]; + if ( arg[0] != '-' || !argv[1] ) { continue; } + argv[i] = NULL; + if ( !strcmp(arg, "--") ) { break; } + if ( arg[1] != '-' ) + { + char c; + while ( (c = *++arg) ) + { + switch ( c ) + { + case 'l': + longformat = true; + break; + case 'a': + showdotdot = true; + showdotfiles = true; + break; + case 'A': + showdotdot = false; + showdotfiles = true; + break; + default: + fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c); + usage(stderr, argv0); + exit(2); + } + } + } + else if ( !strcmp(arg, "--version") ) + { + version(stdout, argv0); exit(0); + } + else if ( !strcmp(arg, "--usage") ) + { + usage(stdout, argv0); exit(0); + } + else if ( !strcmp(arg, "--help") ) + { + help(stdout, argv0); exit(0); + } + else + { + fprintf(stderr, "%s: unrecognized option: %s\n", argv0, arg); + usage(stderr, argv0); + exit(2); + } + } + + childpid = 0; + bool columnable = !longformat; + if ( columnable && isatty(1) ) { int pipes[2]; if ( pipe(pipes) ) { perror("pipe"); return 1; } @@ -76,22 +221,24 @@ int main(int argc, char* argv[]) close(pipes[1]); const char* columner = "column"; const char* argv[] = { columner, NULL }; - execv(columner, (char* const*) argv); + execvp(columner, (char* const*) argv); error(127, errno, "%s", columner); } } - const size_t CWD_SIZE = 512; - char cwd[CWD_SIZE]; - const char* path = getcwd(cwd, CWD_SIZE); - if ( !path ) { path = "."; } + int result = 0; + bool anyargs = false; + for ( int i = 1; i < argc; i++ ) + { + if ( !argv[i] ) { continue; } + anyargs = true; + if ( (result = ls(argv[i])) ) { break; } + } - if ( 1 < argc ) { path = argv[1]; } + if ( !anyargs ) { result = ls("."); } - int result = ls(path); + finishoutput(); - int status; - if ( childpid ) { close(1); wait(&status); } return result; }