and search the PATH for that location. If found, it will search all remaining elements for the requested program. If the location is not found on the PATH, then it will search the entire PATH for the requested program. If found, it returns the absolute path to the program. If not, err.
103 lines
2.3 KiB
Go
103 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"jsh"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
)
|
|
|
|
func ConvertUnit(stringUnit string) (jsh.Unit, error) {
|
|
switch stringUnit {
|
|
case "B":
|
|
return jsh.B, nil
|
|
case "kB":
|
|
return jsh.KB, nil
|
|
case "mB":
|
|
return jsh.MB, nil
|
|
case "gB":
|
|
return jsh.GB, nil
|
|
case "tB":
|
|
return jsh.TB, nil
|
|
case "": // On some systems (Arch, for example) bytes are just the empty string
|
|
return jsh.B, nil
|
|
default:
|
|
return 0, errors.New(fmt.Sprintf("Unknown unit: %s\n", stringUnit))
|
|
}
|
|
}
|
|
|
|
func ParseLine(line string) (string, jsh.MemStat, error) {
|
|
// Recognizes a alphanumeric or () word, the : character, whitespace, the number we're looking for,
|
|
// more whitespace, and possibly the unit
|
|
lineRegex := regexp.MustCompile("(?P<key>^[\\w()]+):\\s+(?P<val>\\d+)(\\s+)?(?P<unit>\\w+)?")
|
|
|
|
// Parse the line, and construct a map of the valid matches
|
|
parsedLine := lineRegex.FindStringSubmatch(line)
|
|
names := lineRegex.SubexpNames()
|
|
matchedVals := map[string]string{}
|
|
for i, n := range parsedLine {
|
|
matchedVals[names[i]] = n
|
|
}
|
|
|
|
key := matchedVals["key"]
|
|
val, err := strconv.Atoi(matchedVals["val"])
|
|
if err != nil {
|
|
return "", jsh.MemStat{}, err
|
|
}
|
|
unit, err := ConvertUnit(matchedVals["unit"])
|
|
if err != nil {
|
|
return "", jsh.MemStat{}, err
|
|
}
|
|
return key, jsh.MemStat{val, unit}, nil
|
|
}
|
|
|
|
func parseMemInfo() jsh.JshFrame {
|
|
file, err := os.Open("/proc/meminfo")
|
|
if err != nil {
|
|
return jsh.JshFrame{[]string{}, []error{err}}
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
memInfo := make(map[string]jsh.MemStat)
|
|
errors := []error{}
|
|
// Read in each line of the meminfo file, and place it in the map
|
|
for scanner.Scan() {
|
|
key, val, err := ParseLine(scanner.Text())
|
|
if err != nil {
|
|
errors = append(errors, err)
|
|
}
|
|
memInfo[key] = val
|
|
}
|
|
|
|
// Wrap with array
|
|
stdOut := []map[string]jsh.MemStat{memInfo}
|
|
finalOut := jsh.JshFrame{stdOut, errors}
|
|
return finalOut
|
|
}
|
|
|
|
func runJsonMode() {
|
|
output := parseMemInfo()
|
|
queue := make(chan *jsh.JshFrame)
|
|
done := make(chan bool)
|
|
go jsh.OutputFrames(queue, done)
|
|
queue <- &output
|
|
close(queue)
|
|
<-done
|
|
}
|
|
|
|
func main() {
|
|
jsonModePtr := flag.Bool("json", false, "whether to use json mode for output")
|
|
flag.Parse()
|
|
|
|
if !*jsonModePtr {
|
|
fmt.Printf("%s", jsh.Fallback("free"))
|
|
} else {
|
|
runJsonMode()
|
|
}
|
|
}
|