diff --git a/HELP.md b/HELP.md index a9ac7c0..8134332 100644 --- a/HELP.md +++ b/HELP.md @@ -1,5 +1,5 @@ ```txt -Usage: logo-ls [-1?aAdgGhlorSstUvVX] [files ...] +Usage: logo-ls [-1?aAdgGhloRrSstUvVX] [files ...] -1 list one file per line. -? display this help and exit -a, --all do not ignore entries starting with . @@ -11,6 +11,7 @@ Usage: logo-ls [-1?aAdgGhlorSstUvVX] [files ...] with -l and -s, print sizes like 1K 234M 2G etc. -l use a long listing format -o like -l, but do not list group information + -R, --recursive list subdirectories recursively -r, --reverse reverse order while sorting -S sort by file size, largest first -s, --size print the allocated size of each file, in blocks diff --git a/dir.go b/dir.go index 46f51ae..54c9f1a 100644 --- a/dir.go +++ b/dir.go @@ -4,6 +4,8 @@ package main import ( "bytes" "fmt" + "io" + "log" "os" "path/filepath" "sort" @@ -28,8 +30,8 @@ type file struct { type dir struct { info *file parent *file - files []*file // all child files and dirs - dirs []*file // for recursion contain only child dirs + files []*file // all child files and dirs + dirs []string // for recursion contain only child dirs less func(int, int) bool } @@ -94,7 +96,7 @@ func newDir(d *os.File) (*dir, error) { } t.files = append(t.files, f) if v.IsDir() { - t.dirs = append(t.dirs, f) + t.dirs = append(t.dirs, name+"/") } } @@ -162,6 +164,37 @@ func newDir_ArgFiles(files []os.FileInfo) *dir { return t } +func newDirs_Recussion(d *os.File) { + dd, err := newDir(d) + d.Close() + if err != nil { + log.Printf("partial access to %q: %v\n", d.Name(), err) + _ = set_osExitCode(code_Minor) + } + // print the info of the files of the directory + io.Copy(os.Stdout, dd.print()) + if len(dd.dirs) == 0 { + return + } + // at this point dd.print has sorted the children files + // but not using it instead printing children in directory order + temp := make([]string, len(dd.dirs)) + for i, v := range dd.dirs { + temp[i] = filepath.Join(d.Name(), v) + } + for _, v := range temp { + fmt.Printf("\n%s:\n", v) + f, err := os.Open(v) + if err != nil { + log.Printf("cannot access %q: %v\n", v, err) + f.Close() + _ = set_osExitCode(code_Minor) + continue + } + newDirs_Recussion(f) + } +} + func (d *dir) print() *bytes.Buffer { // take care of printing, extending symbolic links in long forms diff --git a/main.go b/main.go index 773ea5d..401888f 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ const ( flag_alpha // sort in alphabetic order (default) flag_A flag_h + flag_R flag_r flag_S flag_t @@ -40,6 +41,26 @@ var flagVector uint // terminal width for formatting var terminalWidth int +const ( + code_OK int = iota + code_Minor + code_Serious +) + +// os exit code (do not update manually) +var osExitCode int = code_OK + +// only use set_osExitCode to update the value of osExitCode +func set_osExitCode(c int) int { + switch { + case c == code_Serious: + osExitCode = code_Serious + case c == code_Minor && osExitCode != code_Serious: + osExitCode = code_Minor + } + return osExitCode +} + func main() { // content flags f_a := getopt.BoolLong("all", 'a', "do not ignore entries starting with .") @@ -63,6 +84,7 @@ func main() { f_t := getopt.Bool('t', "sort by modification time, newest first") f_r := getopt.BoolLong("reverse", 'r', "reverse order while sorting") + f_R := getopt.BoolLong("recursive", 'R', "list subdirectories recursively") f_help := getopt.Bool('?', "display this help and exit") f_V := getopt.BoolLong("version", 'V', "output version information and exit") @@ -72,19 +94,19 @@ func main() { if err != nil { // code to handle error log.Printf("%v\nTry 'logo-ls -?' for more information.", err) - os.Exit(2) + os.Exit(set_osExitCode(code_Serious)) } // if f_help is provided print help and exit(0) if *f_help { getopt.PrintUsage(os.Stdout) - os.Exit(0) + os.Exit(osExitCode) } // if f_V is provided version will be printed and exit(0) if *f_V { - fmt.Printf("logo-ls %s\nCopyright (c) 2020 Yash Handa\nLicense MIT .\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n", "v0.0.0") - os.Exit(0) + fmt.Printf("logo-ls %s\nCopyright (c) 2020 Yash Handa\nLicense MIT .\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n", "v0.2.0") + os.Exit(osExitCode) } // set one of -A and -a priority -A > -a @@ -116,6 +138,11 @@ func main() { flagVector |= flag_r } + // set recursion (-R) flag + if *f_R { + flagVector |= flag_R + } + // set -1 flag if *f_1 { flagVector |= flag_1 @@ -179,14 +206,14 @@ func main() { if err != nil { log.Printf("cannot access %q: %v\n", v, err) d.Close() - defer os.Exit(2) + _ = set_osExitCode(code_Serious) continue } ds, err := d.Stat() if err != nil { log.Printf("cannot access %q: %v\n", v, err) d.Close() - defer os.Exit(2) + _ = set_osExitCode(code_Serious) continue } if ds.IsDir() { @@ -203,24 +230,36 @@ func main() { } // process and display all the dirs in arg - pName := len(dirs) > 1 - for i, v := range args.dirs { - if pName { + if flagVector&flag_R > 0 { + // use recursive func + for i, v := range args.dirs { + if i > 0 { + fmt.Println() + } fmt.Printf("%s:\n", v.Name()) + newDirs_Recussion(v) } - d, err := newDir(v) - v.Close() - if err != nil { - log.Printf("partial access to %q: %v\n", v.Name(), err) - defer os.Exit(2) - } - // print the info of the files of the directory - io.Copy(os.Stdout, d.print()) - if i < len(args.dirs)-1 { - fmt.Println() + } else { + pName := len(dirs) > 1 + for i, v := range args.dirs { + if pName { + fmt.Printf("%s:\n", v.Name()) + } + d, err := newDir(v) + v.Close() + if err != nil { + log.Printf("partial access to %q: %v\n", v.Name(), err) + _ = set_osExitCode(code_Serious) + } + // print the info of the files of the directory + io.Copy(os.Stdout, d.print()) + if i < len(args.dirs)-1 { + fmt.Println() + } } } + os.Exit(osExitCode) } func init() {