add
This commit is contained in:
commit
a2ed5b669d
2 changed files with 381 additions and 0 deletions
3
go.mod
Normal file
3
go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module yuvia/gols
|
||||
|
||||
go 1.23.9
|
378
gols.go
Normal file
378
gols.go
Normal file
|
@ -0,0 +1,378 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
gols
|
||||
|
||||
Throughout the program, the simple approach (the braindead one), was the most taken one.
|
||||
*/
|
||||
|
||||
var modes = map[uint32]string{
|
||||
0: "---",
|
||||
1: "--x",
|
||||
2: "-w-",
|
||||
3: "-wx",
|
||||
4: "r--",
|
||||
5: "r-x",
|
||||
6: "rw-",
|
||||
7: "rwx",
|
||||
}
|
||||
|
||||
var vwidth int = 1
|
||||
var uwidth int = 1
|
||||
var gwidth int = 1
|
||||
var lwidth int = 1
|
||||
var swidth int = 1
|
||||
var mwidth int = 1
|
||||
var qwidth int = 1
|
||||
var now int64
|
||||
var dflag bool = false
|
||||
var lflag bool = false
|
||||
var mflag bool = false
|
||||
var nflag bool = false
|
||||
var pflag bool = false
|
||||
var qflag bool = false
|
||||
var Qflag bool = false
|
||||
var rflag bool = false
|
||||
var sflag bool = false
|
||||
var tflag bool = false
|
||||
var Tflag bool = false
|
||||
var uflag bool = false
|
||||
var Fflag bool = false
|
||||
|
||||
// there is an objectively better way to do this.
|
||||
// i wont do it though, not feeling like it XXX
|
||||
func parseargs(args []string) int {
|
||||
var i int
|
||||
var j int
|
||||
|
||||
if len(args) == 0 {
|
||||
return 0
|
||||
} else if args[0][0] != '-' {
|
||||
return 0
|
||||
}
|
||||
|
||||
for i = 0; i < len(args); i++ {
|
||||
if args[i][0] != '-' {
|
||||
break
|
||||
}
|
||||
if args[i] == "-" || args[i] == "--" { // the people are dumb
|
||||
break
|
||||
}
|
||||
for j = 1; j < len(args[i]); j++ {
|
||||
switch args[i][j] {
|
||||
case 'F':
|
||||
Fflag = true
|
||||
case 'd':
|
||||
dflag = true
|
||||
case 'l':
|
||||
lflag = true
|
||||
case 'm':
|
||||
mflag = true
|
||||
case 'n':
|
||||
nflag = true
|
||||
case 'p':
|
||||
pflag = true
|
||||
case 'q':
|
||||
qflag = true
|
||||
case 'Q':
|
||||
Qflag = true
|
||||
case 'r':
|
||||
rflag = true
|
||||
case 's':
|
||||
sflag = true
|
||||
case 't':
|
||||
tflag = true
|
||||
case 'T':
|
||||
Tflag = true
|
||||
case 'u':
|
||||
uflag = true
|
||||
default:
|
||||
fmt.Println(args[i], args[i][j])
|
||||
fmt.Fprintln(os.Stderr, "usage: gls [-dlmnpqrstuFQT] [file ...]")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := os.Args[1:]
|
||||
flag := false
|
||||
optind := parseargs(args)
|
||||
if pflag {
|
||||
flag = true
|
||||
}
|
||||
if lflag {
|
||||
now = time.Now().Unix()
|
||||
}
|
||||
if len(args[optind:]) == 0 {
|
||||
widths([]string{"."})
|
||||
err := ls(".", true)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
widths(args[optind:])
|
||||
for _, arg := range args[optind:] {
|
||||
err := ls(arg, flag)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func widths(args []string) {
|
||||
for _, a := range args {
|
||||
st, err := os.Lstat(a)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if st.IsDir() && !dflag {
|
||||
d, err := os.ReadDir(a)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, ent := range d {
|
||||
dowidths(ent)
|
||||
}
|
||||
} else {
|
||||
dowidths(fs.FileInfoToDirEntry(st))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func compar(a os.DirEntry, b os.DirEntry) int {
|
||||
if tflag {
|
||||
if uflag {
|
||||
ai, _ := a.Info()
|
||||
as := ai.Sys().(*syscall.Dir)
|
||||
bi, _ := b.Info()
|
||||
bs := bi.Sys().(*syscall.Dir)
|
||||
if as.Atime-bs.Atime > 0 {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
} else {
|
||||
ai, _ := a.Info()
|
||||
bi, _ := b.Info()
|
||||
if ai.ModTime().Unix()-bi.ModTime().Unix() > 0 {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return strings.Compare(a.Name(), b.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func ls(p string, flag bool) error {
|
||||
st, err := os.Lstat(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if st.IsDir() && !dflag {
|
||||
d, err := os.ReadDir(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !nflag {
|
||||
slices.SortFunc(d, compar)
|
||||
if rflag {
|
||||
slices.Reverse(d)
|
||||
}
|
||||
}
|
||||
for _, ent := range d {
|
||||
i, err := ent.Info()
|
||||
if err != nil {
|
||||
log.Fatalf("the fuck?: %s\n", err)
|
||||
}
|
||||
output(i, p, flag)
|
||||
}
|
||||
} else {
|
||||
output(st, p, flag)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
as seen from /sys/src/cmd/ls.c, in xcleanname:
|
||||
Compress slashes, remove trailing slash. Don't worry about . and ..
|
||||
*/
|
||||
func cleanname(s string) string {
|
||||
if len(s) == 1 {
|
||||
return s
|
||||
}
|
||||
b := new(strings.Builder)
|
||||
prev := ' ' // ;)
|
||||
for _, c := range s {
|
||||
if c == '/' && prev == '/' {
|
||||
prev = c
|
||||
continue
|
||||
}
|
||||
prev = c
|
||||
b.WriteRune(c)
|
||||
}
|
||||
ret := b.String()
|
||||
if ret[len(ret)-1] == '/' {
|
||||
return ret[:len(ret)-2]
|
||||
} else {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
func getpropername(p, f string, flag bool) string {
|
||||
var c string
|
||||
|
||||
quot := false
|
||||
quoters := "# '"
|
||||
if !flag {
|
||||
if p == "/" {
|
||||
p = ""
|
||||
}
|
||||
c = p + "/" + f
|
||||
} else {
|
||||
c = f
|
||||
}
|
||||
quot = strings.ContainsAny(c, quoters)
|
||||
if quot {
|
||||
b := new(strings.Builder)
|
||||
b.WriteByte('\'')
|
||||
for _, e := range c {
|
||||
b.WriteRune(e)
|
||||
if e == '\'' {
|
||||
b.WriteRune(e)
|
||||
}
|
||||
}
|
||||
b.WriteByte('\'')
|
||||
return b.String()
|
||||
} else {
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
func fileflag(s *syscall.Dir) string {
|
||||
if !Fflag {
|
||||
return ""
|
||||
}
|
||||
if s.Qid.Type&syscall.QTDIR == syscall.QTDIR {
|
||||
return "/"
|
||||
}
|
||||
if s.Mode&0111 > 0 {
|
||||
return "*"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func output(i os.FileInfo, p string, flag bool) {
|
||||
p = cleanname(p)
|
||||
s := (i.Sys().(*syscall.Dir))
|
||||
if sflag {
|
||||
fmt.Printf("%*d ", swidth, (i.Size()+1023)/1024)
|
||||
}
|
||||
if mflag {
|
||||
m := getpropername("", s.Muid, true)
|
||||
fmt.Printf("[%*s] ", mwidth, m)
|
||||
}
|
||||
if qflag {
|
||||
fmt.Printf("(%.16x %*d %.2x) ", s.Qid.Path, qwidth, s.Qid.Vers, s.Qid.Type)
|
||||
}
|
||||
if Tflag {
|
||||
if s.Mode&syscall.DMTMP == syscall.DMTMP {
|
||||
fmt.Print("t ")
|
||||
} else {
|
||||
fmt.Print("- ")
|
||||
}
|
||||
}
|
||||
if lflag {
|
||||
t := time.Unix(int64(s.Mtime), 0)
|
||||
fmt.Printf("%s %c %*d %-*s %-*s %*d ", modestr(s.Mode), s.Type, vwidth, s.Dev, uwidth, s.Uid, gwidth, s.Gid, lwidth, i.Size())
|
||||
if uflag {
|
||||
t = time.Unix(int64(s.Atime), 0)
|
||||
}
|
||||
if t.Unix() < now-180*24*60*60 || t.Unix() > now+24*60*60 {
|
||||
fmt.Printf("%s %5s ", t.Format("Jan _2"), t.Format("2006"))
|
||||
} else {
|
||||
fmt.Printf("%s ", t.Format("Jan _2 15:04"))
|
||||
}
|
||||
}
|
||||
name := getpropername(p, i.Name(), flag)
|
||||
fmt.Printf("%s%s\n", name, fileflag(s))
|
||||
}
|
||||
|
||||
func modestr(m uint32) string {
|
||||
b := new(strings.Builder)
|
||||
if m&syscall.DMDIR == syscall.DMDIR {
|
||||
b.WriteByte('d')
|
||||
} else if m&syscall.DMAPPEND == syscall.DMAPPEND {
|
||||
b.WriteByte('a')
|
||||
} else if m&syscall.DMAUTH == syscall.DMAUTH {
|
||||
b.WriteByte('A')
|
||||
} else {
|
||||
b.WriteByte('-')
|
||||
}
|
||||
if m&syscall.DMEXCL == syscall.DMEXCL {
|
||||
b.WriteByte('l')
|
||||
} else {
|
||||
b.WriteByte('-')
|
||||
}
|
||||
b.WriteString(modes[m>>6&7])
|
||||
b.WriteString(modes[m>>3&7])
|
||||
b.WriteString(modes[m&7])
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func dowidths(d os.DirEntry) {
|
||||
i, _ := d.Info()
|
||||
y := (i.Sys().(*syscall.Dir))
|
||||
if sflag {
|
||||
s := fmt.Sprint((i.Size() + 1023) / 1024)
|
||||
if len(s) > swidth {
|
||||
swidth = len(s)
|
||||
}
|
||||
}
|
||||
if qflag {
|
||||
s := fmt.Sprint(y.Qid.Vers)
|
||||
if len(s) > qwidth {
|
||||
qwidth = len(s)
|
||||
}
|
||||
}
|
||||
if mflag {
|
||||
s := fmt.Sprint(y.Muid)
|
||||
if len(s) > mwidth {
|
||||
mwidth = len(s)
|
||||
}
|
||||
}
|
||||
if lflag {
|
||||
s := fmt.Sprint(y.Dev)
|
||||
if len(s) > vwidth {
|
||||
vwidth = len(s)
|
||||
}
|
||||
s = fmt.Sprint(y.Uid)
|
||||
if len(s) > uwidth {
|
||||
uwidth = len(s)
|
||||
}
|
||||
s = fmt.Sprint(y.Gid)
|
||||
if len(s) > gwidth {
|
||||
gwidth = len(s)
|
||||
}
|
||||
s = fmt.Sprint(i.Size())
|
||||
if len(s) > lwidth {
|
||||
lwidth = len(s)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue