diff --git a/common.go b/common.go index 784eb5f..9b7f21b 100644 --- a/common.go +++ b/common.go @@ -11,6 +11,16 @@ type JshOutput struct { StdErr interface{} } +// Size prefixes as integers, using binary representation +type Unit int +const ( + B Unit = 2 ^ 0 + KB Unit = 2 ^ 10 + MB Unit = 2 ^ 20 + GB Unit = 2 ^ 30 + TB Unit = 2 ^ 40 +) + // Converts a Jshoutput into a JSON string func (j JshOutput) ToJson() *string { jsonOut, err := json.Marshal(j) diff --git a/free.go b/free.go new file mode 100644 index 0000000..69a5a49 --- /dev/null +++ b/free.go @@ -0,0 +1,8 @@ +/* File for free-related structs and methods */ + +package jsh + +type MemStat struct { + Stat int + Units Unit +} diff --git a/free/main.go b/free/main.go new file mode 100644 index 0000000..b84ccd8 --- /dev/null +++ b/free/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "bufio" + "errors" + "flag" + "fmt" + "jsh" + "regexp" + "os" + "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 + default: + return 0, errors.New(fmt.Sprintln("Unknown unit %s", 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^[\\w()]+):\\s+(?P\\d+)(\\s+)?(?P\\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.JshOutput { + file, err := os.Open("/proc/meminfo") + if err != nil { + return jsh.JshOutput{[]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 + } + + finalOut := jsh.JshOutput{memInfo, errors} + return finalOut +} + +func runJsonMode() { + output := parseMemInfo() + fmt.Println("%s", *output.ToJson()) +} + +func main() { + jsonModePtr := flag.Bool("json", false, "whether to use json mode for output") + flag.Parse() + + if !*jsonModePtr { + fmt.Printf("%s", jsh.Fallback("/usr/bin/free")) + } else { + runJsonMode() + } +}