Compare commits

..

57 Commits

Author SHA1 Message Date
bel
72c9d79dd2 filter csv to matchies
All checks were successful
cicd / ci (push) Successful in 2m16s
2026-03-22 14:12:09 -06:00
bel
96703721e3 csv accepts depth 2026-03-22 14:11:11 -06:00
bel
7ac5c15ff8 id is val
All checks were successful
cicd / ci (push) Successful in 3m5s
2026-03-22 00:04:34 -06:00
bel
d743b6dbd0 separate unmatched list
Some checks failed
cicd / ci (push) Failing after 1m35s
2026-03-21 23:32:11 -06:00
Bel LaPointe
ca365ad39c can pass duration to period
All checks were successful
cicd / ci (push) Successful in 1m51s
2026-03-04 08:53:02 -07:00
Bel LaPointe
86b8e62862 empty string period is inf
All checks were successful
cicd / ci (push) Successful in 2m36s
2026-03-04 08:14:07 -07:00
Bel LaPointe
7262f5f69b find unique to ledger
All checks were successful
cicd / ci (push) Successful in 1m15s
2026-01-31 12:14:08 -07:00
Bel LaPointe
b2954c0461 no log confusing to read
All checks were successful
cicd / ci (push) Successful in 1m6s
2026-01-31 11:30:08 -07:00
Bel LaPointe
03b9a6d1f1 todo
All checks were successful
cicd / ci (push) Successful in 1m10s
2026-01-31 11:23:53 -07:00
Bel LaPointe
fa7bafa241 reconcile csv via --csv csv
Some checks failed
cicd / ci (push) Has been cancelled
2026-01-31 11:22:47 -07:00
Bel LaPointe
502e47d0bc ledger.Delta.OtherDates 2026-01-31 11:03:56 -07:00
Bel LaPointe
0eb0abf4a8 bpis to period as well
All checks were successful
cicd / ci (push) Successful in 2m29s
2026-01-28 09:53:04 -07:00
Bel LaPointe
49b7bd2f85 qt pay up <3
Some checks failed
cicd / ci (push) Failing after 13m10s
2026-01-21 21:00:24 -07:00
bel
045ab30dfa install script
All checks were successful
cicd / ci (push) Successful in 2m6s
2026-01-03 11:21:47 -07:00
Bel LaPointe
b1cf639f39 un-break shared
All checks were successful
cicd / ci (push) Successful in 3m5s
2025-10-31 07:28:26 -06:00
Bel LaPointe
cc546d9b2d fix
All checks were successful
cicd / ci (push) Successful in 1m14s
2025-10-26 13:11:09 -06:00
Bel LaPointe
0066a267a6 bal prints percents
All checks were successful
cicd / ci (push) Successful in 2m40s
2025-10-26 09:27:07 -06:00
Bel LaPointe
f58053ebe9 5% raise neat
All checks were successful
cicd / ci (push) Successful in 1m55s
2025-10-15 14:55:00 -06:00
Bel LaPointe
b30b1811ea shared flags
All checks were successful
cicd / ci (push) Successful in 1m53s
2025-09-04 22:18:04 -06:00
Bel LaPointe
3fb1ee4ea3 qt got a turtle rock promo~
All checks were successful
cicd / ci (push) Successful in 2m13s
2025-08-28 20:56:35 -06:00
Bel LaPointe
7a790fa31e group date
All checks were successful
cicd / ci (push) Successful in 1m51s
2025-08-23 08:25:08 -06:00
Bel LaPointe
774de58bf7 not u
All checks were successful
cicd / ci (push) Successful in 1m3s
2025-06-16 18:18:04 -06:00
Bel LaPointe
6aa549cb02 bpis predictFixedGrowth fixed
All checks were successful
cicd / ci (push) Successful in 1m15s
2025-06-16 18:12:11 -06:00
Bel LaPointe
fe7c3a9682 oop 3500 saved per mo not 3600
All checks were successful
cicd / ci (push) Successful in 2m45s
2025-06-16 17:58:38 -06:00
Bel LaPointe
36dcf70dbe from Asset to Bel:Asset
All checks were successful
cicd / ci (push) Successful in 1m1s
2025-06-16 17:57:06 -06:00
Bel LaPointe
989bc3c2ff update prediction default
All checks were successful
cicd / ci (push) Successful in 2m19s
2025-06-16 17:55:16 -06:00
Bel LaPointe
f22d7d958b WILDCARD
All checks were successful
cicd / ci (push) Successful in 1m28s
2025-05-25 13:04:27 -06:00
Bel LaPointe
6a4e10ee2b trigger on self 2025-05-25 13:04:06 -06:00
Bel LaPointe
09da985455 build on build/ 2025-05-25 13:03:36 -06:00
Bel LaPointe
f52832ee82 docker build 2025-05-25 13:02:59 -06:00
bel
0cafba0571 bel pay raise
Some checks failed
cicd / ci (push) Failing after 1m30s
2025-05-24 08:46:51 -06:00
Bel LaPointe
1a397dbf45 mmmm giving out security info wasnt great so rotate bank passwords
Some checks failed
cicd / ci (push) Failing after 15s
2025-05-23 23:36:02 -06:00
Bel LaPointe
b10283d752 multi-acc rate limited lookin pretty good~
Some checks failed
cicd / ci (push) Failing after 14s
2025-05-23 23:17:54 -06:00
Bel LaPointe
284613b5bc fix https
Some checks failed
cicd / ci (push) Failing after 14s
2025-05-23 23:01:15 -06:00
Bel LaPointe
929d15c5b7 teller accepts multi token in tokens.txt
Some checks failed
cicd / ci (push) Failing after 17s
2025-05-23 23:00:09 -06:00
Bel LaPointe
5e61378d63 resolved chase since dawn of time yay 2025-05-23 22:38:52 -06:00
Bel LaPointe
c948a32458 fix onedayoff checks day after
Some checks failed
cicd / ci (push) Failing after 15s
2025-05-23 22:24:05 -06:00
Bel LaPointe
35e2e40ce6 oooo onedayoff ok
Some checks failed
cicd / ci (push) Failing after 15s
2025-05-23 22:15:10 -06:00
Bel LaPointe
847cd736b6 at least round both wrong
Some checks failed
cicd / ci (push) Failing after 15s
2025-05-23 22:02:27 -06:00
Bel LaPointe
9cf8cb0736 rec ok with negatives/positives
Some checks failed
cicd / ci (push) Failing after 21s
2025-05-23 21:59:19 -06:00
Bel LaPointe
4997264f4c fix cache test 2025-05-23 21:56:36 -06:00
Bel LaPointe
f69a850bd8 got a silly ui that can yield a test token 2025-05-23 21:38:07 -06:00
Bel LaPointe
5a3d5e5610 stub teller.Init 2025-05-23 21:12:27 -06:00
Bel LaPointe
c38e8529af ready to get a real token 2025-05-23 21:09:26 -06:00
Bel LaPointe
7a946b7604 go run ./ cli rec to pull all from teller
Some checks failed
cicd / ci (push) Failing after 18s
2025-05-23 21:01:09 -06:00
Bel LaPointe
e0fa44eef7 test bank.cache
Some checks failed
cicd / ci (push) Failing after 17s
2025-05-23 20:32:49 -06:00
Bel LaPointe
6440b07d14 impl teller.Client returns bank.*
Some checks failed
cicd / ci (push) Failing after 14s
2025-05-23 20:15:59 -06:00
Bel LaPointe
bae33f8c60 try /transactions too
Some checks failed
cicd / ci (push) Failing after 19s
2025-05-23 19:44:24 -06:00
Bel LaPointe
daa446cc02 teller seems k so long as they accept 2025-05-23 19:41:39 -06:00
Bel LaPointe
daac3907f4 teller certs
Some checks failed
cicd / ci (push) Failing after 1m7s
2025-05-23 19:23:52 -06:00
Bel LaPointe
83305227db no more ofx 2025-05-23 19:20:52 -06:00
Bel LaPointe
f5d82fc6aa ofx died 3y ago 2025-05-23 18:59:39 -06:00
Bel LaPointe
e581b7835c DRAW
Some checks failed
cicd / ci (push) Failing after 23s
2025-05-07 15:54:58 -06:00
Bel LaPointe
19f4b614d3 insta..sh
Some checks failed
cicd / ci (push) Failing after 17s
2025-05-07 15:35:05 -06:00
Bel LaPointe
58462fb5a4 cli graph graphs
Some checks failed
cicd / ci (push) Failing after 51s
2025-05-07 15:34:31 -06:00
Bel LaPointe
2f8dba4e23 accept --cpi=FILE --cpiy=YEAR to translate money to target year
All checks were successful
cicd / ci (push) Successful in 1m30s
2025-05-07 09:55:16 -06:00
Bel LaPointe
0d91cd63db helpers 2025-05-07 09:40:53 -06:00
440 changed files with 228463 additions and 74 deletions

View File

@@ -6,6 +6,8 @@ on:
paths: paths:
- 'cmd/**' - 'cmd/**'
- 'src/**' - 'src/**'
- 'build/**'
- '.gitea/**'
jobs: jobs:
ci: ci:

View File

@@ -1,4 +1,4 @@
FROM golang:1.21.3-alpine3.18 as builder FROM golang:1.23.9-alpine3.21 as builder
COPY ./ /go/src/ana-ledger COPY ./ /go/src/ana-ledger
WORKDIR /go/src/ana-ledger WORKDIR /go/src/ana-ledger

1
cmd/cli/bpi.dat Symbolic link
View File

@@ -0,0 +1 @@
../../../../../../Sync/Core/ledger/bpi.dat

View File

@@ -3,6 +3,8 @@ package cli
type Config struct { type Config struct {
Files FileList Files FileList
BPI string BPI string
CPI string
CPIYear int
Query struct { Query struct {
Period Period Period Period
Sort string Sort string
@@ -14,4 +16,7 @@ type Config struct {
USDOnly bool USDOnly bool
} }
Compact bool Compact bool
GroupDate string
NoPercent bool
CSV string
} }

1
cmd/cli/cpi.dat Symbolic link
View File

@@ -0,0 +1 @@
../../../../../../Sync/Core/ledger/cpi.dat

View File

@@ -3,6 +3,8 @@ package cli
import ( import (
"fmt" "fmt"
"os" "os"
"regexp"
"strconv"
"strings" "strings"
"time" "time"
) )
@@ -49,20 +51,96 @@ func (period *Period) String() string {
} }
func (period *Period) Set(s string) error { func (period *Period) Set(s string) error {
if result, err := time.Parse("2006", s); err == nil { ss := strings.Split(s, "..")
period.Start = result if err := period.setStartStop(ss[0]); err != nil {
period.Stop = result.AddDate(1, 0, 0).Add(-1 * time.Minute) return err
}
if len(ss) != 2 {
} else if err := period.setStop(ss[1]); err != nil {
return err
}
return nil return nil
}
func (period *Period) setStartStop(s string) error {
stop, err := period.setT(time.Now(), s, &period.Start)
period.Stop = stop
return err
}
func (period *Period) setStop(s string) error {
_, err := period.setT(time.Now(), s, &period.Stop)
return err
}
func (*Period) setT(now time.Time, s string, t *time.Time) (time.Time, error) {
if s == "" {
*t = time.Unix(0, 0)
return time.Now().AddDate(100, 0, 0), nil
}
if submatches := regexp.MustCompile(`[+-]?(?P<years>[0-9]+y)?(?P<months>[0-9]+mo)?(?P<weeks>[0-9]+w)?(?P<days>[0-9]+d)?([0-9]+[a-z])?`).FindStringSubmatch(s); len(submatches) > 0 {
s2 := s
result := now
scalar := time.Duration(1)
if strings.HasPrefix(s2, "-") {
scalar = -1
}
for i, submatch := range submatches[1 : len(submatches)-1] {
if len(submatch) == 0 {
continue
}
unit := submatch[len(submatch)-1]
if submatch[len(submatch)-1] == 'o' { // mo
submatch = submatch[:len(submatch)-1]
}
n, err := strconv.Atoi(submatch[:len(submatch)-1])
if err != nil {
return time.Time{}, err
}
for i := 0; i < n; i++ {
switch unit {
case 'y':
result = result.AddDate(int(scalar*1), 0, 0)
case 'o':
result = result.AddDate(0, int(scalar*1), 0)
case 'w':
result = result.AddDate(0, 0, int(scalar*7))
case 'd':
result = result.AddDate(0, 0, int(scalar*1))
}
}
s2 = strings.ReplaceAll(s2, submatches[i+1], "")
}
if stdDuration := strings.TrimLeft(s2, "+-"); stdDuration != "" {
if d, err := time.ParseDuration(stdDuration); err == nil {
result = result.Add(scalar * d)
}
}
if result != now {
*t = result
return result.AddDate(100, 0, 0), nil
}
}
if result, err := time.Parse("2006", s); err == nil {
*t = result
return result.AddDate(1, 0, 0).Add(-1 * time.Minute), nil
} }
if result, err := time.Parse("2006-01", s); err == nil { if result, err := time.Parse("2006-01", s); err == nil {
period.Start = result *t = result
period.Stop = result.AddDate(0, 1, 0).Add(-1 * time.Minute) return result.AddDate(0, 1, 0).Add(-1 * time.Minute), nil
return nil
} }
if result, err := time.Parse("2006-01-02", s); err == nil { if result, err := time.Parse("2006-01-02", s); err == nil {
period.Start = result *t = result
period.Stop = result.AddDate(0, 0, 1).Add(-1 * time.Minute) return result.AddDate(0, 0, 1).Add(-1 * time.Minute), nil
return nil
} }
return fmt.Errorf("unimplemented format: %s", s) return time.Time{}, fmt.Errorf("unimplemented format: %s", s)
} }

41
cmd/cli/flag_test.go Normal file
View File

@@ -0,0 +1,41 @@
package cli
import (
"testing"
"time"
)
func TestPeriodSetT(t *testing.T) {
now := time.Date(2010, 1, 1, 0, 0, 0, 0, time.UTC)
cases := map[string]time.Time{
"2001-02-03": time.Date(2001, 2, 3, 0, 0, 0, 0, time.UTC),
"2001-02": time.Date(2001, 2, 1, 0, 0, 0, 0, time.UTC),
"2001": time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC),
"": time.Unix(0, 0),
"1m": now.Add(1 * time.Minute),
"+1m": now.Add(1 * time.Minute),
"-1m": now.Add(-1 * time.Minute),
"1h1m": now.Add(1*time.Hour + 1*time.Minute),
"1d": now.Add(24 * time.Hour),
"+1d": now.Add(24 * time.Hour),
"-1d": now.Add(-24 * time.Hour),
"1d1m": now.Add(24*time.Hour + 1*time.Minute),
"+1d1m": now.Add(24*time.Hour + 1*time.Minute),
"-1d1m": now.Add(-1*24*time.Hour + -1*1*time.Minute),
"1y1mo1w1d1h": now.AddDate(1, 1, 7+1).Add(1 * time.Hour),
}
for input, expect := range cases {
input, expect := input, expect
t.Run(input, func(t *testing.T) {
p := &Period{}
var got time.Time
if _, err := p.setT(now, input, &got); err != nil {
t.Fatal(err)
}
if got.Unix() != expect.Unix() {
t.Errorf("expected %s but got %s", expect.String(), got.String())
}
})
}
}

View File

@@ -2,17 +2,30 @@ package cli
import ( import (
"bufio" "bufio"
"context"
"encoding/csv"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"log"
"maps"
"math" "math"
"os" "os"
"os/signal"
"slices" "slices"
"strconv"
"strings" "strings"
"syscall"
"time" "time"
"gogs.inhome.blapointe.com/ana-ledger/src/ana" "gogs.inhome.blapointe.com/ana-ledger/src/ana"
"gogs.inhome.blapointe.com/ana-ledger/src/bank"
"gogs.inhome.blapointe.com/ana-ledger/src/bank/cache"
"gogs.inhome.blapointe.com/ana-ledger/src/bank/teller"
"gogs.inhome.blapointe.com/ana-ledger/src/ledger" "gogs.inhome.blapointe.com/ana-ledger/src/ledger"
"github.com/guptarohit/asciigraph"
"golang.org/x/crypto/ssh/terminal"
) )
func Main() { func Main() {
@@ -20,43 +33,48 @@ func Main() {
fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
fs.Var(&config.Files, "f", "paths to files") fs.Var(&config.Files, "f", "paths to files")
fs.Var(&config.Query.Period, "period", "period") fs.Var(&config.Query.Period, "period", "period can be YYYY, YYYY-mm, YYYY-mm-dd, x..y")
fs.StringVar(&config.Query.Sort, "S", "", "sort ie date") fs.StringVar(&config.Query.Sort, "S", "", "sort ie date")
fs.BoolVar(&config.Query.NoRounding, "no-rounding", false, "no rounding") fs.BoolVar(&config.Query.NoRounding, "no-rounding", false, "no rounding")
fs.BoolVar(&config.Compact, "c", false, "reg entries oneline") fs.BoolVar(&config.Compact, "c", false, "reg entries oneline")
fs.StringVar(&config.Query.With, "w", "", "regexp for transactions") fs.StringVar(&config.Query.With, "w", "", "regexp for transactions")
fs.StringVar(&config.CSV, "csv", "", "if csv then the csv")
fs.IntVar(&config.Query.Depth, "depth", 0, "depth grouping") fs.IntVar(&config.Query.Depth, "depth", 0, "depth grouping")
fs.BoolVar(&config.Query.Normalize, "n", false, "normalize with default normalizer") fs.BoolVar(&config.Query.Normalize, "n", false, "normalize with default normalizer")
fs.BoolVar(&config.Query.USDOnly, "usd", false, "filter to usd") fs.BoolVar(&config.Query.USDOnly, "usd", false, "filter to usd")
fs.BoolVar(&config.Query.NoExchanging, "no-exchanging", true, "omit currency exchanges") fs.BoolVar(&config.Query.NoExchanging, "no-exchanging", true, "omit currency exchanges")
fs.StringVar(&config.BPI, "bpi", "", "path to bpi") fs.StringVar(&config.BPI, "bpi", "", "path to bpi")
fs.StringVar(&config.CPI, "cpi", "", "path to cpi")
fs.StringVar(&config.GroupDate, "group-date", "^....-..-..", "date grouping")
fs.IntVar(&config.CPIYear, "cpiy", 0, "use cpi to convert usd to this year's value")
fs.BoolVar(&config.NoPercent, "no-percent", false, "compute percent")
if err := fs.Parse(os.Args[1:]); err != nil { if err := fs.Parse(os.Args[1:]); err != nil {
panic(err) panic(err)
} }
files := config.Files.Strings() files := config.Files.Strings()
if len(files) == 0 { if len(files) == 0 {
panic("must specify at least one file") log.Fatalf("must specify at least one file")
} }
ledgerFiles, err := ledger.NewFiles(files[0], files[1:]...) ledgerFiles, err := ledger.NewFiles(files[0], files[1:]...)
if err != nil { if err != nil {
panic(err) log.Fatalf("%v", err)
} }
positional := fs.Args() positional := fs.Args()
if len(positional) == 0 || len(positional[0]) < 3 { if len(positional) == 0 || len(positional[0]) < 3 {
panic("positional arguments required, ie bal|reg PATTERN MATCHING") log.Fatalf("positional arguments required, ie bal|reg PATTERN MATCHING")
} }
cmd := positional[0] cmd := positional[0]
q, err := BuildQuery(config, positional[1:]) q, err := BuildQuery(config, positional[1:])
if err != nil { if err != nil {
panic(err) log.Fatalf("%v", err)
} }
deltas, err := ledgerFiles.Deltas() deltas, err := ledgerFiles.Deltas()
if err != nil { if err != nil {
panic(err) log.Fatalf("%v", err)
} }
if period := config.Query.Period; !period.Empty() { if period := config.Query.Period; !period.Empty() {
@@ -84,9 +102,34 @@ func Main() {
if config.BPI != "" { if config.BPI != "" {
b, err := ledger.NewBPIs(config.BPI) b, err := ledger.NewBPIs(config.BPI)
if err != nil { if err != nil {
panic(err) log.Fatalf("%v", err)
} }
bpis = b bpis = b
if period := config.Query.Period; !period.Empty() {
before := period.Stop.Format("2006-01-02")
for _, timeToValue := range bpis {
maps.DeleteFunc(timeToValue, func(k string, _ float64) bool {
return k > before
})
}
}
}
cpiNormalizer := ana.NewNormalizer()
if config.CPI != "" && config.CPIYear > 0 {
c, err := ledger.NewBPIs(config.CPI)
if err != nil {
log.Fatalf("%v", err)
}
cpi := c["CPI"]
cpiy := cpi.Lookup(fmt.Sprintf("%d-06-01", config.CPIYear))
if cpiy == nil {
log.Fatalf("no cpi for year %d", config.CPIYear)
}
for date, value := range cpi {
cpiNormalizer = cpiNormalizer.With(".*", date, value/(*cpiy))
}
} }
if config.Query.Normalize { if config.Query.Normalize {
@@ -108,18 +151,186 @@ func Main() {
} }
switch cmd[:3] { switch cmd[:3] {
case "bal": case "bal": // balances
balances := deltas.Balances(). balances := deltas.Group(ledger.GroupDate(config.GroupDate)).Balances().
WithBPIs(bpis). WithBPIs(bpis).
KindaLike(q). KindaLike(q).
KindaGroup(group). KindaGroup(group).
Nonzero() Nonzero().
FPrintBalances(w, "", balances, nil, config.Query.USDOnly, config.Query.Normalize, time.Now().Format("2006-01-02"), false, maxAccW) Normalize(cpiNormalizer, "9")
case "reg":
cumulatives := make(ledger.Balances)
cumulativesFormat := "%s%.2f"
if !config.NoPercent {
var sum float64
for key := range balances {
if _, ok := cumulatives[key]; !ok {
cumulatives[key] = make(ledger.Balance)
}
for currency, val := range balances[key] {
if currency == ledger.USD {
cumulatives[key][currency] = val
sum += val
} else {
cumulatives[key][currency] = 0
}
}
}
for key := range cumulatives {
cumulatives[key][ledger.USD] = 100 * cumulatives[key][ledger.USD] / sum
}
cumulativesFormat = "%.0f%%"
}
FPrintBalances(w, "", balances, cumulatives, config.Query.USDOnly, config.Query.Normalize, time.Now().Format("2006-01-02"), false, maxAccW, cumulativesFormat)
case "gra": // graph
dateGrouping := "^[0-9]{4}-[0-9]{2}"
if period := config.Query.Period; !period.Empty() {
day := time.Hour * 24
year := day * 365
r := period.Stop.Sub(period.Start)
if r > 10*year {
dateGrouping = "^[0-9]{4}"
} else if r > 5*year {
} else if r > year {
dateGrouping = "^[0-9]{4}-[0-9]{2}-[0-9]"
} else {
dateGrouping = "^[0-9]{4}-[0-9]{2}-[0-9]{2}"
}
}
deltas = deltas.Group(ledger.GroupDate(dateGrouping))
transactions := deltas.Transactions()
cumulative := make(ledger.Balances)
data := map[string][]float64{}
pushData := func() {
soFar := 0
for _, v := range data {
soFar = len(v)
}
for k, balance := range cumulative {
for curr, v := range balance {
if curr != ledger.USD {
continue
}
if _, ok := data[k]; !ok {
data[k] = make([]float64, soFar)
}
data[k] = append(data[k], v)
}
}
}
for i, transaction := range transactions {
if i > 0 && transactions[i-1][0].Date != transaction[0].Date {
pushData()
}
balances := ledger.Deltas(transaction).
Like(q).
Group(group).
Balances().
WithBPIsAt(bpis, transaction[0].Date).
Nonzero().
Normalize(cpiNormalizer, transaction[0].Date)
cumulative.PushAll(balances)
}
pushData()
labels := []string{}
for k := range data {
labels = append(labels, k)
}
slices.Sort(labels)
points := [][]float64{}
for _, k := range labels {
points = append(points, data[k])
}
for i := range points {
for j := range points[i] {
points[i][j] /= 1000.0
}
}
options := []asciigraph.Option{asciigraph.Precision(0)}
if _, h, err := terminal.GetSize(0); err == nil && h > 4 {
options = append(options, asciigraph.Height(h-4))
}
if len(labels) < 256 {
seriesColors := make([]asciigraph.AnsiColor, len(labels))
for i := range seriesColors {
seriesColors[i] = asciigraph.AnsiColor(i)
}
options = append(options, asciigraph.SeriesLegends(labels...))
options = append(options, asciigraph.SeriesColors(seriesColors...))
}
fmt.Println(asciigraph.PlotMany(points, options...))
case "rec": // reconcile via teller // DEAD
log.Fatalf("dead and bad")
byDate := map[string]ledger.Deltas{}
for _, delta := range deltas {
delta := delta
byDate[delta.Date] = append(byDate[delta.Date], delta)
}
ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT)
defer can()
teller, err := teller.New()
if err != nil {
log.Fatalf("%v", err)
}
client := cache.New(teller)
accounts, err := client.Accounts(ctx)
if err != nil {
log.Fatalf("%v", err)
}
inDay := func(date string, transaction bank.Transaction) bool {
return slices.ContainsFunc(byDate[date], func(d ledger.Delta) bool {
v := fmt.Sprintf("%.2f", d.Value)
nv := fmt.Sprintf("%.2f", -1.0*d.Value)
a := fmt.Sprintf("%.2f", transaction.Amount)
return v == a || nv == a
})
}
for _, acc := range accounts {
transactions, err := client.Transactions(ctx, acc)
if err != nil {
log.Fatalf("%v", err)
}
for _, transaction := range transactions {
if inDay(transaction.Date, transaction) {
continue
}
msg := "missing"
ts, err := time.ParseInLocation("2006-01-02", transaction.Date, time.Local)
if err != nil {
log.Fatalf("%v", err)
}
dayBefore := ts.Add(-24 * time.Hour).Format("2006-01-02")
dayAfter := ts.Add(24 * time.Hour).Format("2006-01-02")
if inDay(dayBefore, transaction) || inDay(dayAfter, transaction) {
msg = "1dayoff"
}
prefix := " "
if transaction.Status != "posted" {
prefix = "! "
}
fmt.Printf("[%s] %s $%7.2f %s%s (%s)\n", msg, transaction.Date, transaction.Amount, prefix, transaction.Details.CounterParty.Name, transaction.Description)
}
}
case "reg": // reg
deltas = deltas.Group(ledger.GroupDate(config.GroupDate))
transactions := deltas.Transactions() transactions := deltas.Transactions()
cumulative := make(ledger.Balances) cumulative := make(ledger.Balances)
for _, transaction := range transactions { for _, transaction := range transactions {
balances := ledger.Deltas(transaction).Like(q).Group(group).Balances().WithBPIsAt(bpis, transaction[0].Date).Nonzero() balances := ledger.Deltas(transaction).Like(q).Group(group).Balances().WithBPIsAt(bpis, transaction[0].Date).Nonzero().Normalize(cpiNormalizer, transaction[0].Date)
shouldPrint := false shouldPrint := false
shouldPrint = shouldPrint || len(balances) > 2 shouldPrint = shouldPrint || len(balances) > 2
if config.Query.NoExchanging { if config.Query.NoExchanging {
@@ -133,24 +344,206 @@ func Main() {
if shouldPrint { if shouldPrint {
cumulative.PushAll(balances) cumulative.PushAll(balances)
cumulative = cumulative.Nonzero() cumulative = cumulative.Nonzero()
FPrintBalancesFor(transaction[0].Description, w, "\t\t", balances, cumulative, config.Query.USDOnly, config.Query.Normalize, transaction[0].Date, config.Compact, maxAccW) FPrintBalancesFor(transaction[0].Description, w, "\t\t", balances, cumulative, config.Query.USDOnly, config.Query.Normalize, transaction[0].Date, config.Compact, maxAccW, "%s%.2f")
}
}
case "csv": // reconcile with given csv
deltas := deltas.Group(group)
if config.CSV == "" {
log.Fatalf("missing required -csv")
}
f, err := os.Open(config.CSV)
if err != nil {
log.Fatalf("cannot open csv %q: %v", config.CSV, err)
}
defer f.Close()
reader := csv.NewReader(f)
fields, err := reader.Read()
if err != nil {
log.Fatal(err)
}
dateIdxs := []int{}
for i := range fields {
if strings.Contains(strings.ToLower(fields[i]), "date") {
dateIdxs = append(dateIdxs, i)
}
}
descIdx := slices.IndexFunc(fields, func(field string) bool {
return strings.Contains(strings.ToLower(field), "desc")
})
amountIdx := slices.IndexFunc(fields, func(field string) bool {
return strings.Contains(strings.ToLower(field), "amount")
})
csvDeltas := make(ledger.Deltas, 0)
for {
line, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("failed to read csv line: %v", err)
}
dates := []string{}
for _, dateIdx := range dateIdxs {
dates = append(dates, normalizeDate(line[dateIdx]))
}
dates = slices.Compact(dates)
desc := line[descIdx]
amount := line[amountIdx]
amountF, err := strconv.ParseFloat(amount, 32)
if err != nil {
log.Fatalf("non-float amount %q: %v", amount, err)
}
csvDeltas = append(csvDeltas, ledger.Delta{
Date: dates[0],
OtherDates: dates[1:],
Name: desc,
Value: amountF,
Currency: ledger.USD,
Description: desc,
Payee: true,
})
}
matched := map[string]struct{}{}
matchies := func(deltas ledger.Deltas, delta ledger.Delta) (ledger.Deltas, []string) {
deltas = slices.Clone(deltas)
dates := append([]string{delta.Date}, delta.OtherDates...)
matches := deltas.Like(func(delta ledger.Delta) bool {
return delta.Date >= slices.Min(dates)
})
matches = matches.Like(func(delta ledger.Delta) bool {
return delta.Date <= slices.Max(dates)
})
matches = matches.Like(func(delta ledger.Delta) bool {
return delta.Currency == ledger.USD
})
matches = matches.Like(func(d2 ledger.Delta) bool {
return fmt.Sprintf("%.2f", d2.Value) == fmt.Sprintf("%.2f", delta.Value)
})
for _, match := range matches {
if _, ok := matched[match.ID()]; !ok {
matched[match.ID()] = struct{}{}
break
}
}
return matches, dates
}
datesMatched := []string{}
namesMatched := []string{}
nonAssetNamesMatched := []string{}
for _, csvDelta := range csvDeltas {
matches, dates := matchies(deltas, csvDelta)
if len(matches) == 0 {
fmt.Printf("unique to csv | %s %s %.2f\n", strings.Join(dates, "="), csvDelta.Name, csvDelta.Value)
}
for _, match := range matches {
datesMatched = append(datesMatched, match.Date)
datesMatched = append(datesMatched, match.OtherDates...)
namesMatched = append(namesMatched, match.Name)
}
}
nonAssetNamesMatched = slices.DeleteFunc(slices.Clone(namesMatched), func(name string) bool {
return strings.Contains(name, "Asset")
})
datesMatched = slices.DeleteFunc(datesMatched, func(a string) bool { return strings.TrimSpace(a) == "" })
datesMatched = slices.Compact(datesMatched)
namesMatched = slices.Compact(namesMatched)
transactions := deltas.Transactions()
deltas = deltas.Like(func(delta ledger.Delta) bool {
return delta.Date >= slices.Min(datesMatched)
})
deltas = deltas.Like(func(delta ledger.Delta) bool {
return delta.Date <= slices.Max(datesMatched)
})
deltas = deltas.Like(func(delta ledger.Delta) bool {
return slices.Contains(namesMatched, delta.Name)
})
deltas = deltas.Like(func(delta ledger.Delta) bool {
xaction := transactions.Lookup(delta)
if noXactionFound := len(xaction) == 0; noXactionFound {
return false
}
names := []string{}
for _, delta := range xaction.Deltas() {
names = append(names, delta.Name)
}
slices.Sort(names)
_ = names
allTheSame := true
for i := range xaction {
for j := i + 1; j < len(xaction); j++ {
allTheSame = allTheSame && (xaction[i].Name == xaction[j].Name)
}
}
if allTheSame {
return false
}
if anyNameNotRelevant := slices.ContainsFunc(xaction.Deltas(), func(some ledger.Delta) bool {
return !slices.Contains(namesMatched, delta.Name)
}); anyNameNotRelevant {
return false
}
if hasNonAssetNameMatch := slices.ContainsFunc(xaction.Deltas(), func(some ledger.Delta) bool {
return slices.Contains(nonAssetNamesMatched, delta.Name)
}); !hasNonAssetNameMatch {
return false
}
return true
})
deltasSum := deltas.Group(ledger.GroupDate(""), ledger.GroupName("")).Balances()[""][ledger.USD]
csvSum := csvDeltas.Group(ledger.GroupDate(""), ledger.GroupName("")).Balances()[""][ledger.USD]
if deltasSum != csvSum {
log.Printf("csv sum %.2f but deltas sum %.2f", csvSum, deltasSum)
}
for _, delta := range deltas {
matches, dates := matchies(csvDeltas, delta)
if len(matches) == 0 {
fmt.Printf("unique to ledger | %s %s %.2f\n", strings.Join(dates, "="), delta.Description, delta.Value)
}
}
for _, delta := range deltas {
if _, ok := matched[delta.ID()]; !ok {
fmt.Printf("unmatched ledger | %s %s %.2f\n", delta.Date, delta.Description, delta.Value)
}
}
for _, delta := range csvDeltas {
if _, ok := matched[delta.ID()]; !ok {
fmt.Printf("unmatched csv | %s %s %.2f\n", delta.Date, delta.Description, delta.Value)
} }
} }
default: default:
panic("unknown command " + positional[0]) log.Fatalf("unknown command %q", positional[0])
} }
} }
func FPrintBalancesFor(description string, w io.Writer, linePrefix string, balances, cumulatives ledger.Balances, usdOnly, normalized bool, date string, compact bool, keyW int) { func FPrintBalancesFor(description string, w io.Writer, linePrefix string, balances, cumulatives ledger.Balances, usdOnly, normalized bool, date string, compact bool, keyW int, cumulativeFormat string) {
if compact { if compact {
FPrintBalances(w, date+"\t", balances, cumulatives, usdOnly, normalized, date, compact, keyW) FPrintBalances(w, date+"\t", balances, cumulatives, usdOnly, normalized, date, compact, keyW, cumulativeFormat)
} else { } else {
fmt.Fprintf(w, "%s\t%s\n", date, description) fmt.Fprintf(w, "%s\t%s\n", date, description)
FPrintBalances(w, linePrefix, balances, cumulatives, usdOnly, normalized, date, compact, keyW) FPrintBalances(w, linePrefix, balances, cumulatives, usdOnly, normalized, date, compact, keyW, cumulativeFormat)
} }
} }
func FPrintBalances(w io.Writer, linePrefix string, balances, cumulatives ledger.Balances, usdOnly, normalized bool, date string, fullKey bool, max int) { func FPrintBalances(w io.Writer, linePrefix string, balances, cumulatives ledger.Balances, usdOnly, normalized bool, date string, fullKey bool, max int, cumulativeFormat string) {
maxes := map[ledger.Currency]float64{} maxes := map[ledger.Currency]float64{}
keys := []string{} keys := []string{}
for k, v := range balances { for k, v := range balances {
@@ -165,9 +558,10 @@ func FPrintBalances(w io.Writer, linePrefix string, balances, cumulatives ledger
normalizer := ana.NewDefaultNormalizer() normalizer := ana.NewDefaultNormalizer()
format := fmt.Sprintf("%s%%-%ds\t%%s%%.2f (%%s%%.2f)\n", linePrefix, max) cumulativeFormat = strings.ReplaceAll(cumulativeFormat, "%", "%%")
format := fmt.Sprintf("%s%%-%ds\t%%s%%.2f ("+cumulativeFormat+")\n", linePrefix, max)
if normalized { if normalized {
format = fmt.Sprintf("%s%%-%ds\t%%s%%.2f (%%s%%.2f (%%.2f @%%.2f (%%s%%.0f)))\n", linePrefix, max) format = fmt.Sprintf("%s%%-%ds\t%%s%%.2f (%%s%%.2f (%%.2f @%%.2f ("+cumulativeFormat+")))\n", linePrefix, max)
} }
for i, key := range keys { for i, key := range keys {
printableKey := key printableKey := key
@@ -217,13 +611,40 @@ func FPrintBalances(w io.Writer, linePrefix string, balances, cumulatives ledger
cumulative = value cumulative = value
} }
printingPercents := strings.Contains(cumulativeFormat, "%%%%")
if !printingPercents {
if !normalized { if !normalized {
fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative) fmt.Fprintf(w, format,
printableKey,
printableCurrency, balances[key][currency],
printableCurrency, cumulative,
)
} else { } else {
factor := normalizer.NormalizeFactor(ledger.Delta{Name: key, Date: date}) factor := normalizer.NormalizeFactor(key, date)
trailingMax := maxes[currency] - math.Abs(balances[key][currency]) trailingMax := maxes[currency] - math.Abs(balances[key][currency])
fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative, cumulative*factor, factor, printableCurrency, factor*trailingMax) fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative, cumulative*factor, factor, printableCurrency, factor*trailingMax)
} }
} else {
if !normalized {
fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], cumulative)
} else {
factor := normalizer.NormalizeFactor(key, date)
trailingMax := maxes[currency] - math.Abs(balances[key][currency])
fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative, cumulative*factor, factor, factor*trailingMax)
}
}
} }
} }
} }
func normalizeDate(date string) string {
for _, layout := range []string{
"01/02/2006",
} {
if t, err := time.Parse(layout, date); err == nil {
return t.Format("2006-01-02")
}
}
log.Fatalf("cannot normalize date %q", date)
return ""
}

12
cmd/cli/run.sh Normal file
View File

@@ -0,0 +1,12 @@
#! /bin/bash
cmd="bal"
case "$1" in
bal|reg|gra|graph|rec )
cmd="$1"
shift
;;
esac
cd "$(dirname "$(realpath "$BASH_SOURCE")")"
go run ../ cli "$@" $(printf " -f %s" $HOME/Sync/Core/ledger/eras/2022-/*.txt) "$cmd" :AssetAccount:

View File

@@ -47,7 +47,7 @@
<span> <span>
<label for="likeName">likeName</label> <label for="likeName">likeName</label>
<input name="likeName" type="text" value="AssetAccount"/> <input name="likeName" type="text" value="Bel:AssetAccount"/>
</span> </span>
<span> <span>
@@ -72,7 +72,7 @@
<span> <span>
<label for="prediction">prediction</label> <label for="prediction">prediction</label>
<input name="prediction" type="text" value="interest=AssetAccount:Cash \$ 0.02&prediction=contributions=AssetAccount:Bonds $ 1875&prediction=interest=AssetAccount:Monthly \$ 0.03&prediction=contributions=AssetAccount:Monthly $ 2500"/> <input name="prediction" type="text" value="interest=Bel:AssetAccount:Cash \$ 0.02&prediction=contributions=Bel:AssetAccount:Bonds $ 1916&prediction=interest=Bel:AssetAccount:Monthly \$ 0.03&prediction=contributions=Bel:AssetAccount:Monthly $ 3500"/>
</span> </span>
<span> <span>
@@ -82,7 +82,7 @@
<span> <span>
<label for="whatIf">whatIf</label> <label for="whatIf">whatIf</label>
<input name="whatIf" type="text" value="AssetAccount:Cash $ -.10000"/> <input name="whatIf" type="text" value="Bel:AssetAccount:Cash $ -.10000"/>
</span> </span>
<span> <span>

View File

@@ -20,7 +20,7 @@
<li><a href="/api/trends">Where does the house money go?</a></li> <li><a href="/api/trends">Where does the house money go?</a></li>
<li><a href="/explore.html">Explore Bel's Money</a></li> <li><a href="/explore.html">Explore Bel's Money</a></li>
<li><a href="/api/bal?x=y&mode=bal&likeName=AssetAccount&chart=stack&predictionMonths=120&bpi=true&zoomStart=YYYY-MM&prediction=interest=AssetAccount:Cash%20\$%200.02&prediction=contributions=AssetAccount:Bonds%20$%201875&prediction=interest=AssetAccount:Monthly%20\$%200.03&prediction=contributions=AssetAccount:Monthly%20$%202500&predictFixedGrowth=VBTLX=0.02&predictFixedGrowth=GLD=0.02&predictFixedGrowth=FXAIX=0.03&predictFixedGrowth=FSPSX=0.03&whatIf=AssetAccount:Cash%20$%20-.10000&=">Project Bel's Net Worth</a></li> <li><a href="/api/bal?x=y&mode=bal&likeName=AssetAccount&chart=stack&predictionMonths=120&bpi=true&zoomStart=YYYY-MM&prediction=interest=AssetAccount:Cash%20\$%200.02&prediction=contributions=AssetAccount:Bonds%20$%201875&prediction=interest=AssetAccount:Monthly%20\$%200.03&prediction=contributions=AssetAccount:Monthly%20$%202500&predictFixedGrowth=VBTLX=0.02&predictFixedGrowth=GLD=0.02&predictFixedGrowth=FXAIX=0.03&predictFixedGrowth=FSPSX=0.03&whatIf=AssetAccount:Cash%20$%20-.10000&=">Project Bel's Net Worth</a></li>
<li><a href="/api/reg?x=y&mode=reg&likeName=Withdrawal:&chart=stack&predictionMonths=3&bpi=false&zoomStart=YYYY-MM&prediction=autoContributions=&predictFixedGrowth=VBTLX=0&whatIf=AssetAccount:Cash%20$%20-.10000&=">Expect Bel's Expenses</a></li> <!--<li><a href="/api/reg?x=y&mode=reg&likeName=Bel:Withdrawal:&chart=stack&predictionMonths=3&bpi=false&zoomStart=YYYY-MM&prediction=autoContributions=&predictFixedGrowth=VBTLX=0&whatIf=AssetAccount:Cash%20$%20-.10000&=">Expect Bel's Expenses</a></li>-->
</ul> </ul>
</body> </body>
<footer> <footer>

View File

@@ -135,7 +135,7 @@ func (router Router) APITransactions(w http.ResponseWriter, r *http.Request) {
v := normalized[k] v := normalized[k]
if v := math.Abs(v["$"]); v < biggest { if v := math.Abs(v["$"]); v < biggest {
normalizedDelta := biggest - v normalizedDelta := biggest - v
normalizedFactor := normalizer.NormalizeFactor(ledger.Delta{Name: k, Date: time.Now().Format("2006-01-02")}) normalizedFactor := normalizer.NormalizeFactor(k, time.Now().Format("2006-01-02"))
normalized[fmt.Sprintf(`(%s trailing $)`, k)] = ledger.Balance{"$": normalizedDelta * normalizedFactor} normalized[fmt.Sprintf(`(%s trailing $)`, k)] = ledger.Balance{"$": normalizedDelta * normalizedFactor}
} }
} }
@@ -297,6 +297,11 @@ func (router Router) APIReg(w http.ResponseWriter, r *http.Request) {
register := deltas.Register() register := deltas.Register()
predicted := make(ledger.Register) predicted := make(ledger.Register)
bpis, err := router.bpis()
if err != nil {
panic(err)
}
if predictionMonths, err := strconv.ParseInt(r.URL.Query().Get("predictionMonths"), 10, 16); err == nil && predictionMonths > 0 { if predictionMonths, err := strconv.ParseInt(r.URL.Query().Get("predictionMonths"), 10, 16); err == nil && predictionMonths > 0 {
window := time.Hour * 24.0 * 365.0 / 12.0 * time.Duration(predictionMonths) window := time.Hour * 24.0 * 365.0 / 12.0 * time.Duration(predictionMonths)
// TODO whatif // TODO whatif
@@ -334,10 +339,6 @@ func (router Router) APIReg(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
bpis, err := router.bpis()
if err != nil {
panic(err)
}
bpis, err = ana.BPIsWithFixedGrowthPrediction(bpis, window, currency, rate) bpis, err = ana.BPIsWithFixedGrowthPrediction(bpis, window, currency, rate)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -346,10 +347,6 @@ func (router Router) APIReg(w http.ResponseWriter, r *http.Request) {
} }
if r.URL.Query().Get("bpi") == "true" { if r.URL.Query().Get("bpi") == "true" {
bpis, err := router.bpis()
if err != nil {
panic(err)
}
register = register.WithBPIs(bpis) register = register.WithBPIs(bpis)
predicted = predicted.WithBPIs(bpis) predicted = predicted.WithBPIs(bpis)
} }

3
cmd/install.sh Normal file
View File

@@ -0,0 +1,3 @@
#! /bin/bash
cd "$(dirname "$(realpath "$BASH_SOURCE")")"
go build -o $GOPATH/bin/ana-ledger

1
cmd/install_scratch.sh Normal file
View File

@@ -0,0 +1 @@
CGO_ENABLED=1 CC=x86_64-linux-musl-gcc go build -ldflags="-linkmode external -extldflags -static" -o $HOME/Go/bin/ana-ledger

View File

@@ -1,14 +1,33 @@
package main package main
import ( import (
"context"
"log"
"os" "os"
"os/signal"
"strings"
"syscall"
"gogs.inhome.blapointe.com/ana-ledger/cmd/cli" "gogs.inhome.blapointe.com/ana-ledger/cmd/cli"
"gogs.inhome.blapointe.com/ana-ledger/cmd/http" "gogs.inhome.blapointe.com/ana-ledger/cmd/http"
"gogs.inhome.blapointe.com/ana-ledger/src/bank/teller"
) )
func main() { func main() {
switch os.Args[1] { switch os.Args[1] {
case "tel":
ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT)
defer can()
if c, err := teller.New(); err != nil {
} else if _, err := c.Accounts(ctx); err != nil {
} else {
log.Println("teller already init")
}
if err := teller.Init(ctx); err != nil {
panic(err)
}
case "http": case "http":
os.Args = append([]string{os.Args[0]}, os.Args[2:]...) os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
http.Main() http.Main()
@@ -19,13 +38,18 @@ func main() {
files := os.Args[2:] files := os.Args[2:]
os.Args = []string{os.Args[0], "cli"} os.Args = []string{os.Args[0], "cli"}
for _, f := range files { for _, f := range files {
if strings.HasPrefix(f, "-") {
os.Args = append(os.Args, f)
} else {
os.Args = append(os.Args, "-f", f) os.Args = append(os.Args, "-f", f)
} }
}
os.Args = append(os.Args, os.Args = append(os.Args,
"-w=^Housey", "-w=^Housey",
"--depth=1", "--depth=1",
"--usd", "--usd",
"-n", "-n",
"--no-percent",
"bal", "^Bel", "^Zach", "bal", "^Bel", "^Zach",
) )
main() main()

16
go.mod
View File

@@ -1,5 +1,17 @@
module gogs.inhome.blapointe.com/ana-ledger module gogs.inhome.blapointe.com/ana-ledger
go 1.21.1 go 1.23.0
require github.com/go-echarts/go-echarts/v2 v2.3.1 toolchain go1.24.2
require (
github.com/go-echarts/go-echarts/v2 v2.3.1
github.com/guptarohit/asciigraph v0.7.3
golang.org/x/crypto v0.38.0
golang.org/x/time v0.11.0
)
require (
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
)

10
go.sum
View File

@@ -2,9 +2,19 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-echarts/go-echarts/v2 v2.3.1 h1:Yw0HVjVTxpYm48l974dMjRzx8ni2ql0kKi/kawSgxFE= github.com/go-echarts/go-echarts/v2 v2.3.1 h1:Yw0HVjVTxpYm48l974dMjRzx8ni2ql0kKi/kawSgxFE=
github.com/go-echarts/go-echarts/v2 v2.3.1/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI= github.com/go-echarts/go-echarts/v2 v2.3.1/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI=
github.com/guptarohit/asciigraph v0.7.3 h1:p05XDDn7cBTWiBqWb30mrwxd6oU0claAjqeytllnsPY=
github.com/guptarohit/asciigraph v0.7.3/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho= github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -19,11 +19,15 @@ type normalize struct {
func NewDefaultNormalizer() Normalizer { func NewDefaultNormalizer() Normalizer {
return NewNormalizer(). return NewNormalizer().
With("^Zach", "2026-01-01", 156). // turtle up again!
With("^Zach", "2025-09-01", 151). // turtle up
With("^Zach", "2023-10-05", 139). // to turtle With("^Zach", "2023-10-05", 139). // to turtle
With("^Zach", "2021-12-30", 135). // at pluralsight With("^Zach", "2021-12-30", 135). // at pluralsight
With("^Zach", "2020-07-30", 120). // to pluralsight With("^Zach", "2020-07-30", 120). // to pluralsight
With("^Zach", "2019-07-16", 77). // at fedex With("^Zach", "2019-07-16", 77). // at fedex
With("^Zach", "2017-02-16", 49). // to fedex With("^Zach", "2017-02-16", 49). // to fedex
With("^Bel", "2025-10-01", 225). // render up
With("^Bel", "2025-04-01", 214). // lc4 at render
With("^Bel", "2023-12-05", 190). // to render With("^Bel", "2023-12-05", 190). // to render
With("^Bel", "2022-12-31", 154). // at q With("^Bel", "2022-12-31", 154). // at q
With("^Bel", "2022-06-30", 148). // at q With("^Bel", "2022-06-30", 148). // at q
@@ -68,15 +72,15 @@ func (n Normalizer) Normalize(deltas ledger.Deltas) ledger.Deltas {
} }
func (n Normalizer) NormalizeDelta(delta ledger.Delta) ledger.Delta { func (n Normalizer) NormalizeDelta(delta ledger.Delta) ledger.Delta {
delta.Value /= n.NormalizeFactor(delta) delta.Value /= n.NormalizeFactor(delta.Name, delta.Date)
return delta return delta
} }
func (n Normalizer) NormalizeFactor(delta ledger.Delta) float64 { func (n Normalizer) NormalizeFactor(name, date string) float64 {
for pattern := range n.m { for pattern := range n.m {
if regexp.MustCompile(pattern).MatchString(delta.Name) { if regexp.MustCompile(pattern).MatchString(name) {
for _, normalize := range n.m[pattern] { for _, normalize := range n.m[pattern] {
if normalize.startDate < delta.Date { if normalize.startDate < date {
return normalize.factor return normalize.factor
} }
} }

107
src/bank/cache/cache.go vendored Normal file
View File

@@ -0,0 +1,107 @@
package cache
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"path"
"time"
"gogs.inhome.blapointe.com/ana-ledger/src/bank"
)
type Client struct {
Client bank.Agg
}
var _ bank.Agg = Client{}
func New(client bank.Agg) Client {
return Client{Client: client}
}
func (c Client) Accounts(ctx context.Context) ([]bank.Account, error) {
k := "accounts"
result := []bank.Account{}
if err := fromCache(k, &result); err != nil {
log.Printf("%q not in cache: %v", k, err)
} else {
return result, nil
}
result, err := c.Client.Accounts(ctx)
if err != nil {
return nil, err
}
toCache(k, result)
return result, nil
}
func (c Client) Transactions(ctx context.Context, a bank.Account) ([]bank.Transaction, error) {
k := path.Join("accounts.d", a.Account)
result := []bank.Transaction{}
if err := fromCache(k, &result); err != nil {
log.Printf("%q not in cache: %v", k, err)
} else {
return result, nil
}
result, err := c.Client.Transactions(ctx, a)
if err != nil {
return nil, err
}
toCache(k, result)
return result, nil
}
var (
d = path.Join("/tmp/ana_ledger_bank_cache.d")
)
func toCache(k string, v interface{}) {
if err := _toCache(k, v); err != nil {
log.Printf("failed to cache %s: %v", k, err)
}
}
func _toCache(k string, v interface{}) error {
b, err := json.Marshal(v)
if err != nil {
return err
}
p := path.Join(d, k)
os.MkdirAll(path.Dir(p), os.ModePerm)
if err := os.WriteFile(p, b, os.ModePerm); err != nil {
os.Remove(p)
return err
}
return nil
}
func fromCache(k string, ptr interface{}) error {
p := path.Join(d, k)
if stat, err := os.Stat(p); err != nil {
return err
} else if time.Since(stat.ModTime()) > 24*time.Hour {
return fmt.Errorf("stale")
}
b, err := os.ReadFile(p)
if err != nil {
return err
}
if err := json.Unmarshal(b, ptr); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,50 @@
//go:build integration
package cache_test
import (
"context"
"strconv"
"testing"
"gogs.inhome.blapointe.com/ana-ledger/src/bank/cache"
"gogs.inhome.blapointe.com/ana-ledger/src/bank/teller"
)
func Test(t *testing.T) {
tellerC, err := teller.New()
if err != nil {
t.Fatal(err)
}
client := cache.New(tellerC)
ctx := context.Background()
for i := 0; i < 2; i++ {
i := i
client := client
t.Run(strconv.Itoa(i), func(t *testing.T) {
accounts, err := client.Accounts(ctx)
if err != nil {
t.Fatal(err)
}
for _, account := range accounts {
account := account
t.Run(account.Account, func(t *testing.T) {
transactions, err := client.Transactions(ctx, account)
if err != nil {
t.Fatal(err)
}
for i, tr := range transactions {
t.Logf("[%d] %+v", i, tr)
}
})
break
}
})
client.Client = nil
}
}

View File

@@ -0,0 +1 @@
app_pdvv33dtmta4fema66000

View File

@@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIExjCCAq6gAwIBAgIIGEJSCPAVjIYwDQYJKoZIhvcNAQELBQAwYTELMAkGA1UE
BhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxDzANBgNVBAcMBkxvbmRvbjEPMA0GA1UE
CgwGVGVsbGVyMR4wHAYDVQQLDBVUZWxsZXIgQXBwbGljYXRpb24gQ0EwHhcNMjUw
NTI0MDEyMzIzWhcNMjgwNTIzMDEyMzIzWjAkMSIwIAYDVQQDDBlhcHBfcGR2djMz
ZHRtdGE0ZmVtYTY2MDAwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
tWbYAc2wQBBvKJhTlo5YPLqkM5GgaYaWUqJJ5bFht+U2PL0rJHbS7oRG9fXtgb12
jEzD3CUUPpCxj7oRgYdji2SH5NKmo3M85/Cry1y5pmotmqGlqrt01zStj2A+FuzR
BqdmVb1CIE2iJmttGn3C3f9OCbV5kMKreu4DhVdPW7eafpo+yIMaoJxx2CAMqw5Y
GK2NNpehMHzpL4Z0032yEQJaBblYeUT4zgMCxoupXQ7hCsyjn/ws7ocpMHXY9r08
6PjaY1j6wYwX9OUJDXz0zgoeShr2vcfkjBc1QavRLVQQUWgYJevS/8rCfo32B7ub
Ym1CmWz2cY3+4UV3uihJgQIDAQABo4G+MIG7MA4GA1UdDwEB/wQEAwIF4DATBgNV
HSUEDDAKBggrBgEFBQcDAjCBkwYDVR0jBIGLMIGIgBSEq++simSLxXkuNSUKjel6
pmhxmqFlpGMwYTELMAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxDzANBgNV
BAcMBkxvbmRvbjEPMA0GA1UECgwGVGVsbGVyMR4wHAYDVQQLDBVUZWxsZXIgQXBw
bGljYXRpb24gQ0GCCQDiNWG/vm85CTANBgkqhkiG9w0BAQsFAAOCAgEARv/Kjwcu
ppXbTf9pvsesEgo6O+OM1qW73SkmQeB5ZfF6KEOn57SujTjVQRlBGhVs//+Ezlav
GKKm4Xw0eCKUfISIgz+nY7lSlVvW2REZAdpuiY6owsqtiL/Fe/RBvkUmNSWnu8vc
OIfnpqP6flKL7KjXwQXoI/Xt9Zw6D56dHQi5hYgYtP0HqtEZn6vdtroHM3mbIL6D
Dnfdhb3ywwVZTiQE5ceQk+StDYuzTz7PNQL6IWxcH4j73dQlvFzMLSDm9yA2NguK
SEiRi4gYmluQxSiTN3gYqfOMeVv/buklHknkRHCInOTOiDWX8ku0FWwApiwsmvLS
3z/9WK4QEMLQfxBbp7UJePWx0Tq6KE61gcTgMbjqz+Xi9n2KM6RenDdMg2rQXWX4
xqC0sOOuSS19WFCGYDBRjI2JOQqfeEymq8pQsrGm+XyzCPMi+eFyLZqkRiT85MCr
IZuUWpMTcqILGP3Ar5Z0ppDI1ppVDhWMoq5EYx0iuJjNQZEtHlbu1j+cw6uVAoqJ
T/E5/qKcLRkkDKV68B+CP2z+iOXH5M1dcYFu6yEkKxVbEuTJNyN5gHhBATyIoMQ0
RdohL8F9hdOHvTLo89xrFEHiLExIT0NISjlT0M/mTqq4rbr5kp5W/ee9h5uSVUJ8
3nCv0NH3CX0Ygjzd7Czd9hWRahQz+vv55u4=
-----END CERTIFICATE-----

64
src/bank/teller/init.go Normal file
View File

@@ -0,0 +1,64 @@
package teller
import (
"context"
_ "embed"
"fmt"
"io"
"net/http"
"os"
"slices"
"text/template"
)
var (
//go:embed application_id.txt
applicationId string
//go:embed init.html
initHTML string
)
func Init(ctx context.Context) error {
environment := "development"
if sandbox := !slices.Contains(os.Args, "forreal"); sandbox {
environment = "sandbox"
}
fmt.Printf("environment=%q\n", environment)
newTokens := make(chan string)
defer close(newTokens)
s := &http.Server{
Addr: ":20000",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
b, _ := io.ReadAll(r.Body)
newTokens <- string(b)
return
}
t, err := template.New("initHTML").Parse(initHTML)
if err != nil {
panic(err)
}
if err := t.Execute(w, map[string]string{
"applicationId": applicationId,
"environment": environment,
}); err != nil {
panic(err)
}
}),
}
defer s.Close()
go s.ListenAndServe()
fmt.Println("Open http://localhost:20000")
select {
case <-ctx.Done():
case newToken := <-newTokens:
return fmt.Errorf("not impl: %q >> token.txt", newToken)
}
return ctx.Err()
}

58
src/bank/teller/init.html Normal file
View File

@@ -0,0 +1,58 @@
<html>
<head></head>
<body>
<button id="teller-connect">Connect to your bank</button>
<h3 id="log">
</h3>
<script src="https://cdn.teller.io/connect/connect.js"></script>
<script>
function logme(msg) {
document.getElementById("log").innerHTML += `<br>* ${msg}`
}
function http(method, remote, callback, body) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
callback(xmlhttp.responseText, xmlhttp.status)
}
};
xmlhttp.open(method, remote, true);
if (typeof body == "undefined") {
body = null
}
xmlhttp.send(body);
}
function callback(responseBody, responseStatus) {
}
document.addEventListener("DOMContentLoaded", function() {
var tellerConnect = TellerConnect.setup({
applicationId: "{{.applicationId}}",
environment: "{{.environment}}",
products: ["verify", "balance", "transactions"],
onInit: function() {
logme("Teller Connect has initialized")
},
onSuccess: function(enrollment) {
logme(`User enrolled successfully: ${enrollment.accessToken}`)
http("post", "/", callback, enrollment.accessToken)
},
onExit: function() {
logme("User closed Teller Connect")
},
onFailure: function(failure) {
logme(`Failed: type=${failure.type} code=${failure.code} message=${failure.message}`)
},
});
var el = document.getElementById("teller-connect");
el.addEventListener("click", function() {
tellerConnect.open();
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1ZtgBzbBAEG8o
mFOWjlg8uqQzkaBphpZSoknlsWG35TY8vSskdtLuhEb19e2BvXaMTMPcJRQ+kLGP
uhGBh2OLZIfk0qajczzn8KvLXLmmai2aoaWqu3TXNK2PYD4W7NEGp2ZVvUIgTaIm
a20afcLd/04JtXmQwqt67gOFV09bt5p+mj7IgxqgnHHYIAyrDlgYrY02l6EwfOkv
hnTTfbIRAloFuVh5RPjOAwLGi6ldDuEKzKOf/Czuhykwddj2vTzo+NpjWPrBjBf0
5QkNfPTOCh5KGva9x+SMFzVBq9EtVBBRaBgl69L/ysJ+jfYHu5tibUKZbPZxjf7h
RXe6KEmBAgMBAAECggEAExDEEyxzIciYZkPcRS6gx4E2UNU1buHeWsED00hZZOKK
WMfpCOQUN01fx+oZFFG9a/GFhFXBUvISN3Du9hYsuDHQtpQNP5CVDiuVYsJUINF4
CZCDwPYCybuXokITRIWPUou1jb1efdaq/C6+QNKG8J4srYiNRlGvhDQP2qvag2ET
YtY+6OuQPF9QSeoKLBCJJi8bP/wy3OfOQkTqvlpyEGVOUc5utGuziITShL2mLtQw
1O22r4BIFtkvnhM4kGimbSDMYwtAgMrBrktR4Xp7JICV6eZn6fJgjpYOix/4ILxS
Ri69qPLso4qF+ML/vsTHlxQj7FwZDZozT4hm3DK3gQKBgQDdnEAdQYuKIvwrHflk
Pxb9q7MjrMJMGiA9GvSVTimeWu68kH2y/dUUQyBtr8SRCScNUmhRCfaZCBakSYR0
0v+6FLXleI28dD93Qzn70G0N6kVdKLdM3Rt0r+fojPhP+8pHn74UzvcoGUDOzoax
VPvHLe19wqrbRFIU4IAE6qjmNQKBgQDRjUFjRJIh4wgrB6rROeoTtYRRyS9RLliw
dpH78Vz7OYTx7qnvtVOl8led82Ott7hEXcK9Ihobz8uPCewW/x+sPYty13shT46K
8zEj9FoP9XhAS3MOqLDNx7h5jv7nvua8aRQEPkF30SmPqb+X4nN5+JjuJiTqWgJ+
5nfnyX4PnQKBgQCE87brVmV27GJJI+R5JfiPG7GPl5fBvHLW9hMCeDAz1u4fprgi
6HIrg9IyvB67vLf3IBeBdu7BBL9AtPKIfAX8B2zRTLAL/doNnQFud67ViFUw/Lpr
nMNaECabt+dJZRAIRGfvZ/OT1QKyj+jy/r9G0eEHcAC9J5HvAHkNehL2eQKBgAU+
a6x4Qs/mRoYNIxEpSdpEaJNDXZPCfSWtUenkGFeREOqc9lOxTe6RKfAh7xShzFKp
pf3lpJGdmZJyxR2uNLSytZKiIcqrmv2PKGOl8bsEgYXaXX64afQ8Uzl3gpl6BXwh
hQa2KB0/drLJpKnAWPNsbSdIfRQAPJ/AVK/QMv9hAoGAMtmCDJK1KVZcpFJbFSMk
pPJjcp1XRWKsiBOPfUKlwbBSFDBUnhyPcsfL9ooAwzBnBcpNf6S5I+I22AdDuk8E
S3uOBBlNhoecWN1tqVlcbTR1p5kXV0WVAcQ09hGPqja5ghrTTpWbC7SviSVNa0fx
LXKvqDx5qTleSmrPwPs5TW4=
-----END PRIVATE KEY-----

95
src/bank/teller/teller.go Normal file
View File

@@ -0,0 +1,95 @@
package teller
import (
"context"
"crypto/tls"
_ "embed"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
"gogs.inhome.blapointe.com/ana-ledger/src/bank"
"golang.org/x/time/rate"
)
type Client struct {
cert tls.Certificate
}
var _ bank.Agg = Client{}
var (
//go:embed certificate.pem
certificate []byte
//go:embed private_key.pem
privateKey []byte
//go:embed token.txt
Tokens string
)
func New() (Client, error) {
cert, err := tls.X509KeyPair(certificate, privateKey)
return Client{cert: cert}, err
}
func (c Client) Accounts(ctx context.Context) ([]bank.Account, error) {
var result []bank.Account
for _, token := range strings.Fields(Tokens) {
var more []bank.Account
if err := c.get(ctx, "https://api.teller.io/accounts", token, &more); err != nil {
return nil, err
}
for i := range more {
more[i].Token = token
}
result = append(result, more...)
}
return result, nil
}
func (c Client) Transactions(ctx context.Context, a bank.Account) ([]bank.Transaction, error) {
var result []bank.Transaction
err := c.get(ctx, "https://api.teller.io/accounts/"+a.Account+"/transactions", a.Token, &result)
return result, err
}
var limiter = rate.NewLimiter(0.1, 1)
func (c Client) get(ctx context.Context, url, token string, ptr interface{}) error {
if err := limiter.Wait(ctx); err != nil {
return err
}
log.Printf("Teller.Get(%s, %s)", url, token)
httpc := &http.Client{
Timeout: time.Second,
Transport: &http.Transport{
DisableKeepAlives: true,
TLSClientConfig: &tls.Config{Certificates: []tls.Certificate{c.cert}},
},
}
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return err
}
req.SetBasicAuth(token, "")
req = req.WithContext(ctx)
resp, err := httpc.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
if err := json.Unmarshal(b, &ptr); err != nil {
return fmt.Errorf("cannot unmarshal: %w: %s", err, b)
}
return nil
}

View File

@@ -0,0 +1,41 @@
//go:build integration
package teller_test
import (
"context"
"testing"
"gogs.inhome.blapointe.com/ana-ledger/src/bank/teller"
)
func Test(t *testing.T) {
teller.Tokens = "test_token_bfu2cyvq3il6o"
c, err := teller.New()
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
accounts, err := c.Accounts(ctx)
if err != nil {
t.Fatal(err)
}
for _, account := range accounts {
account := account
t.Run(account.Account, func(t *testing.T) {
transactions, err := c.Transactions(ctx, account)
if err != nil {
t.Fatal(err)
}
for i, tr := range transactions {
t.Logf("[%d] %+v", i, tr)
}
})
break
}
}

View File

@@ -0,0 +1,59 @@
//go:build manual
package teller_test
import (
"crypto/tls"
"io"
"net/http"
"testing"
"time"
"gogs.inhome.blapointe.com/ana-ledger/src/bank/teller"
)
func TestIntegration(t *testing.T) {
teller.Tokens = "test_token_bfu2cyvq3il6o"
//curl --cert certificate.pem --cert-key private_key.pem --auth test_token_bfu2cyvq3il6o: https://api.teller.io/accounts
cert, err := tls.LoadX509KeyPair("./certificate.pem", "./private_key.pem")
if err != nil {
t.Fatal(err)
}
c := &http.Client{
Timeout: time.Second,
Transport: &http.Transport{
DisableKeepAlives: true,
TLSClientConfig: &tls.Config{Certificates: []tls.Certificate{cert}},
},
}
//curl --cert certificate.pem --cert-key private_key.pem --auth test_token_bfu2cyvq3il6o: https://api.teller.io/accounts
for _, url := range []string{
"https://api.teller.io/accounts",
"https://api.teller.io/accounts/acc_pdvv4810fi9hmrcn6g000/transactions",
} {
url := url
t.Run(url, func(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
t.Fatal(err)
}
req.SetBasicAuth("test_token_bfu2cyvq3il6o", "")
resp, err := c.Do(req)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if code := resp.StatusCode; code >= 300 {
t.Fatalf("(%d) %s", code, body)
}
t.Logf("(%d) %s", resp.StatusCode, body)
})
}
}

View File

@@ -0,0 +1,2 @@
token_2utqstwpn3pxwgvyno56hqdehq
token_vr6dnzvfv7c24wuxtmnnzyiqbm

31
src/bank/types.go Normal file
View File

@@ -0,0 +1,31 @@
package bank
import "context"
type Agg interface {
Accounts(context.Context) ([]Account, error)
Transactions(context.Context, Account) ([]Transaction, error)
}
type Account struct {
Institution struct {
Name string `json:"name"`
} `json:"institution"`
Name string `json:"last_four"`
Account string `json:"id"`
Token string `json:"__token"`
}
type Transaction struct {
Amount float64 `json:"amount,string"`
Details struct {
ProcessingStatus string `json:"processing_status"`
CounterParty struct {
Name string `json:"name"`
} `json:"counterparty"`
} `json:"details"`
Description string `json:"description"`
Date string `json:"date"`
Type string `json:"type"`
Status string `json:"status"`
}

View File

@@ -9,6 +9,10 @@ import (
"time" "time"
) )
type Normalizer interface {
NormalizeFactor(string, string) float64
}
type Balances map[string]Balance type Balances map[string]Balance
type Balance map[Currency]float64 type Balance map[Currency]float64
@@ -246,3 +250,14 @@ func (balance Balance) Debug() string {
} }
return strings.Join(result, " + ") return strings.Join(result, " + ")
} }
func (balances Balances) Normalize(n Normalizer, date string) Balances {
result := make(Balances)
for name, balance := range balances {
result[name] = make(Balance)
for currency, value := range balance {
result[name][currency] = value / n.NormalizeFactor(name, date)
}
}
return result
}

View File

@@ -10,6 +10,7 @@ const (
type Delta struct { type Delta struct {
Date string Date string
OtherDates []string
Name string Name string
Value float64 Value float64
Currency Currency Currency Currency
@@ -23,9 +24,10 @@ type Delta struct {
with []Delta with []Delta
} }
func newDelta(transaction string, payee bool, d, desc, name string, v float64, c string, isSet bool, fileName string, lineNo int) Delta { func newDelta(transaction string, payee bool, d, desc, name string, v float64, c string, isSet bool, fileName string, lineNo int, otherDates []string) Delta {
return Delta{ return Delta{
Date: d, Date: d,
OtherDates: otherDates,
Name: name, Name: name,
Value: v, Value: v,
Currency: Currency(c), Currency: Currency(c),
@@ -39,6 +41,10 @@ func newDelta(transaction string, payee bool, d, desc, name string, v float64, c
} }
} }
func (delta Delta) ID() string {
return fmt.Sprintf("%.2f", delta.Value)
}
func (delta Delta) withWith(other Delta) Delta { func (delta Delta) withWith(other Delta) Delta {
other.with = nil other.with = nil
delta.with = append(delta.with, other) delta.with = append(delta.with, other)

View File

@@ -6,7 +6,7 @@ import (
func TestDelta(t *testing.T) { func TestDelta(t *testing.T) {
d := "2099-08-07" d := "2099-08-07"
delta := newDelta("x", true, d, "", "name", 34.56, "$", false, "", 0) delta := newDelta("x", true, d, "", "name", 34.56, "$", false, "", 0, []string{"d2"})
if delta.Transaction != "x" { if delta.Transaction != "x" {
t.Error(delta.Transaction) t.Error(delta.Transaction)
@@ -17,6 +17,9 @@ func TestDelta(t *testing.T) {
if delta.Date != d { if delta.Date != d {
t.Error(delta.Date) t.Error(delta.Date)
} }
if delta.OtherDates[0] != "d2" {
t.Error(delta.OtherDates)
}
if delta.Name != "name" { if delta.Name != "name" {
t.Error(delta.Name) t.Error(delta.Name)
} }

View File

@@ -99,8 +99,12 @@ func (files Files) add(payee string, delta Delta) error {
if delta.Currency != USD { if delta.Currency != USD {
currencyValue = fmt.Sprintf("%.2f %s", delta.Value, delta.Currency) currencyValue = fmt.Sprintf("%.2f %s", delta.Value, delta.Currency)
} }
date := delta.Date
for _, otherDate := range delta.OtherDates {
date += "=" + otherDate
}
return files.append(fmt.Sprintf("%s %s\n%s%s%s%s\n%s%s", return files.append(fmt.Sprintf("%s %s\n%s%s%s%s\n%s%s",
delta.Date, delta.Description, date, delta.Description,
filesAppendDelim, delta.Name, filesAppendDelim+filesAppendDelim+filesAppendDelim, currencyValue, filesAppendDelim, delta.Name, filesAppendDelim+filesAppendDelim+filesAppendDelim, currencyValue,
filesAppendDelim, payee, filesAppendDelim, payee,
)) ))

View File

@@ -73,12 +73,13 @@ func TestFileAmend(t *testing.T) {
}, },
"payee": { "payee": {
from: ` from: `
2006-01-02 description 2006-01-02=2006-01-03 description
recipient $3.45 recipient $3.45
payee payee
`, `,
old: Delta{ old: Delta{
Date: "2006-01-02", Date: "2006-01-02",
OtherDates: []string{"2006-01-03"},
Name: "payee", Name: "payee",
Value: -3.45, Value: -3.45,
Currency: "$", Currency: "$",
@@ -86,16 +87,17 @@ func TestFileAmend(t *testing.T) {
}, },
now: Delta{ now: Delta{
Date: "2106-11-12", Date: "2106-11-12",
OtherDates: []string{"2006-01-03"},
Name: "1payee", Name: "1payee",
Value: -13.45, Value: -13.45,
Currency: "T", Currency: "T",
Description: "1description", Description: "1description",
}, },
want: ` want: `
2006-01-02 description 2006-01-02=2006-01-03 description
payee $3.45 payee $3.45
recipient recipient
2106-11-12 1description 2106-11-12=2006-01-03 1description
1payee -13.45 T 1payee -13.45 T
recipient`, recipient`,
}, },

View File

@@ -1,6 +1,8 @@
package ledger package ledger
import "regexp" import (
"regexp"
)
type Group func(Delta) Delta type Group func(Delta) Delta
@@ -17,6 +19,9 @@ func GroupDate(pattern string) Group {
p := regexp.MustCompile(pattern) p := regexp.MustCompile(pattern)
return func(d Delta) Delta { return func(d Delta) Delta {
d.Date = p.FindString(d.Date) d.Date = p.FindString(d.Date)
for i := range d.with {
d.with[i].Date = p.FindString(d.with[i].Date)
}
return d return d
} }
} }
@@ -25,6 +30,9 @@ func GroupName(pattern string) Group {
p := regexp.MustCompile(pattern) p := regexp.MustCompile(pattern)
return func(d Delta) Delta { return func(d Delta) Delta {
d.Name = p.FindString(d.Name) d.Name = p.FindString(d.Name)
for i := range d.with {
d.with[i].Name = p.FindString(d.with[i].Name)
}
return d return d
} }
} }

View File

@@ -16,8 +16,21 @@ import (
type Transaction Deltas type Transaction Deltas
func (t Transaction) Deltas() Deltas {
return Deltas(slices.Clone(t))
}
type Transactions []Transaction type Transactions []Transaction
func (transactions Transactions) Lookup(delta Delta) Transaction {
for i := range transactions {
if transactions[i][0].Transaction == delta.Transaction {
return slices.Clone(transactions[i])
}
}
return nil
}
func (transactions Transactions) Deltas() Deltas { func (transactions Transactions) Deltas() Deltas {
result := make(Deltas, 0, len(transactions)) result := make(Deltas, 0, len(transactions))
for _, transaction := range transactions { for _, transaction := range transactions {
@@ -106,6 +119,7 @@ func (transaction Transaction) Payee() string {
type transaction struct { type transaction struct {
date string date string
otherDates []string
description string description string
payee string payee string
recipients []transactionRecipient recipients []transactionRecipient
@@ -142,6 +156,7 @@ func (t transaction) deltas() Deltas {
recipient.isSet, recipient.isSet,
t.fileName, t.fileName,
t.lineNo+i, t.lineNo+i,
t.otherDates,
)) ))
} }
for currency, value := range sums { for currency, value := range sums {
@@ -162,6 +177,7 @@ func (t transaction) deltas() Deltas {
false, false,
t.fileName, t.fileName,
t.lineNo, t.lineNo,
t.otherDates,
)) ))
} }
} }
@@ -287,16 +303,17 @@ func _readTransaction(name string, r *bufio.Reader) (transaction, error) {
return transaction{}, err return transaction{}, err
} }
dateDescriptionPattern := regexp.MustCompile(`^([0-9]+-[0-9]+-[0-9]+)\s+(.*)$`) dateDescriptionPattern := regexp.MustCompile(`^([0-9]+-[0-9]+-[0-9]+)((=[0-9]+-[0-9]+-[0-9]+)*)\s+(.*)$`)
dateDescriptionMatches := dateDescriptionPattern.FindAllSubmatch(firstLine, 4) dateDescriptionMatches := dateDescriptionPattern.FindAllStringSubmatch(string(firstLine), 4)
if len(dateDescriptionMatches) != 1 { if len(dateDescriptionMatches) != 1 {
return transaction{}, fmt.Errorf("bad first line: %v matches: %q", len(dateDescriptionMatches), firstLine) return transaction{}, fmt.Errorf("bad first line: %v matches: %q", len(dateDescriptionMatches), firstLine)
} else if len(dateDescriptionMatches[0]) != 3 { } else if len(dateDescriptionMatches[0]) != 5 {
return transaction{}, fmt.Errorf("bad first line: %v submatches: %q", len(dateDescriptionMatches[0]), firstLine) return transaction{}, fmt.Errorf("bad first line: %v submatches: %q", len(dateDescriptionMatches[0]), firstLine)
} }
result := transaction{ result := transaction{
date: string(dateDescriptionMatches[0][1]), date: dateDescriptionMatches[0][1],
description: string(dateDescriptionMatches[0][2]), otherDates: strings.Split(strings.Trim(dateDescriptionMatches[0][2], "="), "="),
description: dateDescriptionMatches[0][4],
name: name, name: name,
} }

View File

@@ -58,12 +58,13 @@ func TestReadTransaction(t *testing.T) {
}, },
"verbose": { "verbose": {
input: ` input: `
2003-04-05 Reasoning here 2003-04-05=2003-04-06=2003-04-07 Reasoning here
A:B $1.00 A:B $1.00
C:D $-1.00 C:D $-1.00
`, `,
want: transaction{ want: transaction{
date: "2003-04-05", date: "2003-04-05",
otherDates: []string{"2003-04-06", "2003-04-07"},
description: "Reasoning here", description: "Reasoning here",
payee: "A:B", payee: "A:B",
recipients: []transactionRecipient{ recipients: []transactionRecipient{

18
vendor/github.com/guptarohit/asciigraph/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,18 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# ide
.idea
# build dirs
*dist*

View File

@@ -0,0 +1,74 @@
# Build customization
builds:
- env:
- CGO_ENABLED=0
main: ./cmd/asciigraph/main.go
ldflags: '-s -w'
# GOOS list to build in.
# For more info refer to https://golang.org/doc/install/source#environment
goos:
- linux
- darwin
- windows
# GOARCH to build in.
# For more info refer to https://golang.org/doc/install/source#environment
goarch:
- 386
- amd64
- arm
- arm64
ignore:
- goos: darwin
goarch: 386
checksum:
name_template: '{{ .ProjectName }}_{{ .Version }}_sha512-checksums.txt'
algorithm: sha512
# Archive customization
archives:
- id: tar
format: tar.gz
files:
- LICENSE
- README.md
name_template: >-
{{- .ProjectName }}_
{{- .Version }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end -}}
format_overrides:
- goos: windows
format: zip
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
release:
github:
owner: guptarohit
name: asciigraph
# If set to true, will not auto-publish the release.
# Default is false.
draft: true
dockers:
- image_templates:
- 'ghcr.io/guptarohit/asciigraph:{{ .Version }}'
- 'ghcr.io/guptarohit/asciigraph:{{ .Tag }}'
- 'ghcr.io/guptarohit/asciigraph:v{{ .Major }}'
- 'ghcr.io/guptarohit/asciigraph:v{{ .Major }}.{{ .Minor }}'
- 'ghcr.io/guptarohit/asciigraph:latest'
dockerfile: goreleaser.dockerfile
build_flag_templates:
- '--label=org.opencontainers.image.title={{ .ProjectName }}'
- '--label=org.opencontainers.image.name={{ .ProjectName }}'
- '--label=org.opencontainers.image.description=Go package to make lightweight line graphs ╭┈╯ in CLI'
- '--label=org.opencontainers.image.url=https://github.com/guptarohit/asciigraph'
- '--label=org.opencontainers.image.source=https://github.com/guptarohit/asciigraph'
- '--label=org.opencontainers.image.version={{ .Version }}'
- '--label=org.opencontainers.image.created={{ .Date }}'
- '--label=org.opencontainers.image.revision={{ .FullCommit }}'
- '--label=org.opencontainers.image.licenses=BSD-3-Clause'

113
vendor/github.com/guptarohit/asciigraph/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,113 @@
# Changelog
All notable changes to this project will be documented in this file.
## [0.7.3] - 2024-10-26
### Fixed
- Incorrect plot height calculation for small value ranges (#59)
## [0.7.2] - 2024-08-12
### Fixed
- Unintended modification of input data (#55)
## [0.7.1] - 2024-03-30
### Added
- CLI: Option to specify legends for series (`sl`)
## [0.7.0] - 2024-03-30
### Added
- CLI: Options to specify delimiter (`d`) and number of series (`sn`)
### Changed
- CLI: Option (`sc`) to specify series colors
## [0.6.0] - 2024-03-25
### Added
- Option to add legends for colored graphs
## [0.5.6] - 2023-06-24
### Added
- Options to set upper & lower bound of graph
## [0.5.5] - 2022-05-03
### Added
- Ansi colors support for graphs
## [0.5.4] - 2022-05-03
### Added
- Option to plot multiple series together (#34)
- Dockerfile file support (#33)
## [0.5.3] - 2022-02-20
### Fixed
- Handled NaN first value (#32)
- Fixed incorrect y-axis start value tick (#31)
## [0.5.2] - 2021-03-28
### Added
- added support to set custom precision of data point labels along the y-axis
- added go module support
### Changed
- updated README to markdown format
## [0.5.1] - 2020-09-14
### Added
- added support for NaN values in series
- added option to control fps of plot rendering via cli for real-time data
### Changed
- removed use of append() method
- make caption centered
- removed trailing spaces from plot
## [0.5.0] - 2020-06-28
### Added
- added support for the realtime plot of data points (from stdin) for CLI.
## [0.4.2] - 2020-06-07
### Fixed
- Prevent panics when data is flat. (#8)
- Prevent BADPREC issue when maximum and minimum values in a series are 0. (#10)
[0.7.2]: https://github.com/guptarohit/asciigraph/releases/tag/v0.7.2
[0.7.1]: https://github.com/guptarohit/asciigraph/releases/tag/v0.7.1
[0.7.0]: https://github.com/guptarohit/asciigraph/releases/tag/v0.7.0
[0.6.0]: https://github.com/guptarohit/asciigraph/releases/tag/v0.6.0
[0.5.6]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.6
[0.5.5]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.5
[0.5.4]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.4
[0.5.3]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.3
[0.5.2]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.2
[0.5.1]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.1
[0.5.0]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.0
[0.4.2]: https://github.com/guptarohit/asciigraph/releases/tag/v0.4.2

View File

@@ -0,0 +1,133 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
https://github.com/guptarohit.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

10
vendor/github.com/guptarohit/asciigraph/Dockerfile generated vendored Normal file
View File

@@ -0,0 +1,10 @@
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY cmd ./cmd
COPY go.mod ./
COPY *.go ./
RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /app/asciigraph ./cmd/asciigraph/main.go
FROM scratch
COPY --from=builder /app/asciigraph /asciigraph
ENTRYPOINT ["/asciigraph"]

29
vendor/github.com/guptarohit/asciigraph/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2018, Rohit Gupta
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

292
vendor/github.com/guptarohit/asciigraph/README.md generated vendored Normal file
View File

@@ -0,0 +1,292 @@
# asciigraph
[![Build status][]][1] [![Go Report Card][]][2] [![Coverage Status][]][3] [![GoDoc][]][4] [![License][]][5] [![Mentioned in Awesome Go][]][6]
Go package to make lightweight ASCII line graphs ╭┈╯.
![image][]
## Installation
```bash
go get -u github.com/guptarohit/asciigraph@latest
```
## Usage
### Basic graph
```go
package main
import (
"fmt"
"github.com/guptarohit/asciigraph"
)
func main() {
data := []float64{3, 4, 9, 6, 2, 4, 5, 8, 5, 10, 2, 7, 2, 5, 6}
graph := asciigraph.Plot(data)
fmt.Println(graph)
}
```
Running this example would render the following graph:
```bash
10.00 ┤ ╭╮
9.00 ┤ ╭╮ ││
8.00 ┤ ││ ╭╮││
7.00 ┤ ││ ││││╭╮
6.00 ┤ │╰╮ ││││││ ╭
5.00 ┤ │ │ ╭╯╰╯│││╭╯
4.00 ┤╭╯ │╭╯ ││││
3.00 ┼╯ ││ ││││
2.00 ┤ ╰╯ ╰╯╰╯
```
### Multiple Series
```go
package main
import (
"fmt"
"github.com/guptarohit/asciigraph"
)
func main() {
data := [][]float64{{0, 1, 2, 3, 3, 3, 2, 0}, {5, 4, 2, 1, 4, 6, 6}}
graph := asciigraph.PlotMany(data)
fmt.Println(graph)
}
```
Running this example would render the following graph:
```bash
6.00 ┤ ╭─
5.00 ┼╮ │
4.00 ┤╰╮ ╭╯
3.00 ┤ │╭│─╮
2.00 ┤ ╰╮│ ╰╮
1.00 ┤╭╯╰╯ │
0.00 ┼╯ ╰
```
### Colored graphs
```go
package main
import (
"fmt"
"github.com/guptarohit/asciigraph"
)
func main() {
data := make([][]float64, 4)
for i := 0; i < 4; i++ {
for x := -20; x <= 20; x++ {
v := math.NaN()
if r := 20 - i; x >= -r && x <= r {
v = math.Sqrt(math.Pow(float64(r), 2)-math.Pow(float64(x), 2)) / 2
}
data[i] = append(data[i], v)
}
}
graph := asciigraph.PlotMany(data, asciigraph.Precision(0), asciigraph.SeriesColors(
asciigraph.Red,
asciigraph.Yellow,
asciigraph.Green,
asciigraph.Blue,
))
fmt.Println(graph)
}
```
Running this example would render the following graph:
![colored_graph_image][]
### Legends for colored graphs
The graph can include legends for each series, making it easier to interpret.
```go
package main
import (
"fmt"
"github.com/guptarohit/asciigraph"
"math"
)
func main() {
data := make([][]float64, 3)
for i := 0; i < 3; i++ {
for x := -12; x <= 12; x++ {
v := math.NaN()
if r := 12 - i; x >= -r && x <= r {
v = math.Sqrt(math.Pow(float64(r), 2)-math.Pow(float64(x), 2)) / 2
}
data[i] = append(data[i], v)
}
}
graph := asciigraph.PlotMany(data,
asciigraph.Precision(0),
asciigraph.SeriesColors(asciigraph.Red, asciigraph.Green, asciigraph.Blue),
asciigraph.SeriesLegends("Red", "Green", "Blue"),
asciigraph.Caption("Series with legends"))
fmt.Println(graph)
}
```
Running this example would render the following graph:
![graph_with_legends_image][]
## CLI Installation
This package also brings a small utility for command line usage.
Assuming `$GOPATH/bin` is in your `$PATH`, install CLI with following command:
```bash
go install github.com/guptarohit/asciigraph/cmd/asciigraph@latest
```
or pull Docker image:
```bash
docker pull ghcr.io/guptarohit/asciigraph:latest
```
or download binaries from the [releases][] page.
## CLI Usage
```bash ✘ 0|125  16:19:23
> asciigraph --help
Usage of asciigraph:
asciigraph [options]
Options:
-ac axis color
y-axis color of the plot
-b buffer
data points buffer when realtime graph enabled, default equal to `width`
-c caption
caption for the graph
-cc caption color
caption color of the plot
-d delimiter
data delimiter for splitting data points in the input stream (default ",")
-f fps
set fps to control how frequently graph to be rendered when realtime graph enabled (default 24)
-h height
height in text rows, 0 for auto-scaling
-lb lower bound
lower bound set the minimum value for the vertical axis (ignored if series contains lower values) (default +Inf)
-lc label color
y-axis label color of the plot
-o offset
offset in columns, for the label (default 3)
-p precision
precision of data point labels along the y-axis (default 2)
-r realtime
enables realtime graph for data stream
-sc series colors
comma-separated series colors corresponding to each series
-sl series legends
comma-separated series legends corresponding to each series
-sn number of series
number of series (columns) in the input data (default 1)
-ub upper bound
upper bound set the maximum value for the vertical axis (ignored if series contains larger values) (default -Inf)
-w width
width in columns, 0 for auto-scaling
asciigraph expects data points from stdin. Invalid values are logged to stderr.
```
Feed it data points via stdin:
```bash
seq 1 72 | asciigraph -h 10 -c "plot data from stdin"
```
or use Docker image:
```bash
seq 1 72 | docker run -i --rm ghcr.io/guptarohit/asciigraph -h 10 -c "plot data from stdin"
```
Output:
```bash
72.00 ┤ ╭────
64.90 ┤ ╭──────╯
57.80 ┤ ╭──────╯
50.70 ┤ ╭──────╯
43.60 ┤ ╭──────╯
36.50 ┤ ╭───────╯
29.40 ┤ ╭──────╯
22.30 ┤ ╭──────╯
15.20 ┤ ╭──────╯
8.10 ┤ ╭──────╯
1.00 ┼──╯
plot data from stdin
```
Example of **real-time graph** for data points stream via stdin:
<a href="https://asciinema.org/a/382383" target="_blank"><img width="500" alt="Realtime graph for data points via stdin (google ping) using asciigraph" src="https://asciinema.org/a/382383.svg" /></a>
<details>
<summary>command for above graph</summary>
```sh
ping -i.2 google.com | grep -oP '(?<=time=).*(?=ms)' --line-buffered | asciigraph -r -h 10 -w 40 -c "realtime plot data (google ping in ms) from stdin"
```
</details>
Example of **multi-series real-time graph** for data points stream via stdin:
<a href="https://asciinema.org/a/649906" target="_blank"><img width="500" alt="Ping latency comparison: Google (Blue) vs. DuckDuckGo (Red) with asciigraph" src="https://asciinema.org/a/649906.svg" /></a>
<details>
<summary>command for above graph</summary>
```sh
{unbuffer paste -d, <(ping -i 0.4 google.com | sed -u -n -E 's/.*time=(.*)ms.*/\1/p') <(ping -i 0.4 duckduckgo.com | sed -u -n -E 's/.*time=(.*)ms.*/\1/p') } | asciigraph -r -h 15 -w 60 -sn 2 -sc "blue,red" -c "Ping Latency Comparison" -sl "Google, DuckDuckGo"
```
</details>
## Acknowledgement
This package started as golang port of [asciichart][].
## Contributing
Feel free to make a pull request! :octocat:
[Build status]: https://github.com/guptarohit/asciigraph/actions/workflows/test.yml/badge.svg
[1]: https://github.com/guptarohit/asciigraph/actions/workflows/test.yml
[Go Report Card]: https://goreportcard.com/badge/github.com/guptarohit/asciigraph
[2]: https://goreportcard.com/report/github.com/guptarohit/asciigraph
[Coverage Status]: https://coveralls.io/repos/github/guptarohit/asciigraph/badge.svg?branch=master
[3]: https://coveralls.io/github/guptarohit/asciigraph?branch=master
[GoDoc]: https://godoc.org/github.com/guptarohit/asciigraph?status.svg
[4]: https://godoc.org/github.com/guptarohit/asciigraph
[License]: https://img.shields.io/badge/licence-BSD-blue.svg
[5]: https://github.com/guptarohit/asciigraph/blob/master/LICENSE
[Mentioned in Awesome Go]: https://awesome.re/mentioned-badge-flat.svg
[6]: https://github.com/avelino/awesome-go#advanced-console-uis
[image]: https://user-images.githubusercontent.com/7895001/41509956-b1b2b3d0-7279-11e8-9d19-d7dea17d5e44.png
[colored_graph_image]: https://user-images.githubusercontent.com/7895001/166443444-40ad8113-2c0f-46d7-9c75-1cf08435ce15.png
[releases]: https://github.com/guptarohit/asciigraph/releases
[asciichart]: https://github.com/kroitor/asciichart
[graph_with_legends_image]: https://github.com/guptarohit/asciigraph/assets/7895001/4066ee95-55ca-42a4-8a03-e73ce20df5d3

265
vendor/github.com/guptarohit/asciigraph/asciigraph.go generated vendored Normal file
View File

@@ -0,0 +1,265 @@
package asciigraph
import (
"bytes"
"fmt"
"math"
"strings"
)
// Plot returns ascii graph for a series.
func Plot(series []float64, options ...Option) string {
return PlotMany([][]float64{series}, options...)
}
// PlotMany returns ascii graph for multiple series.
func PlotMany(data [][]float64, options ...Option) string {
var logMaximum float64
config := configure(config{
Offset: 3,
Precision: 2,
}, options)
// Create a deep copy of the input data
dataCopy := make([][]float64, len(data))
for i, series := range data {
dataCopy[i] = make([]float64, len(series))
copy(dataCopy[i], series)
}
data = dataCopy
lenMax := 0
for i := range data {
if l := len(data[i]); l > lenMax {
lenMax = l
}
}
if config.Width > 0 {
for i := range data {
for j := len(data[i]); j < lenMax; j++ {
data[i] = append(data[i], math.NaN())
}
data[i] = interpolateArray(data[i], config.Width)
}
lenMax = config.Width
}
minimum, maximum := math.Inf(1), math.Inf(-1)
for i := range data {
minVal, maxVal := minMaxFloat64Slice(data[i])
if minVal < minimum {
minimum = minVal
}
if maxVal > maximum {
maximum = maxVal
}
}
if config.LowerBound != nil && *config.LowerBound < minimum {
minimum = *config.LowerBound
}
if config.UpperBound != nil && *config.UpperBound > maximum {
maximum = *config.UpperBound
}
interval := math.Abs(maximum - minimum)
if config.Height <= 0 {
config.Height = calculateHeight(interval)
}
if config.Offset <= 0 {
config.Offset = 3
}
var ratio float64
if interval != 0 {
ratio = float64(config.Height) / interval
} else {
ratio = 1
}
min2 := round(minimum * ratio)
max2 := round(maximum * ratio)
intmin2 := int(min2)
intmax2 := int(max2)
rows := int(math.Abs(float64(intmax2 - intmin2)))
width := lenMax + config.Offset
type cell struct {
Text string
Color AnsiColor
}
plot := make([][]cell, rows+1)
// initialise empty 2D grid
for i := 0; i < rows+1; i++ {
line := make([]cell, width)
for j := 0; j < width; j++ {
line[j].Text = " "
line[j].Color = Default
}
plot[i] = line
}
precision := config.Precision
logMaximum = math.Log10(math.Max(math.Abs(maximum), math.Abs(minimum))) //to find number of zeros after decimal
if minimum == float64(0) && maximum == float64(0) {
logMaximum = float64(-1)
}
if logMaximum < 0 {
// negative log
if math.Mod(logMaximum, 1) != 0 {
// non-zero digits after decimal
precision += uint(math.Abs(logMaximum))
} else {
precision += uint(math.Abs(logMaximum) - 1.0)
}
} else if logMaximum > 2 {
precision = 0
}
maxNumLength := len(fmt.Sprintf("%0.*f", precision, maximum))
minNumLength := len(fmt.Sprintf("%0.*f", precision, minimum))
maxWidth := int(math.Max(float64(maxNumLength), float64(minNumLength)))
// axis and labels
for y := intmin2; y < intmax2+1; y++ {
var magnitude float64
if rows > 0 {
magnitude = maximum - (float64(y-intmin2) * interval / float64(rows))
} else {
magnitude = float64(y)
}
label := fmt.Sprintf("%*.*f", maxWidth+1, precision, magnitude)
w := y - intmin2
h := int(math.Max(float64(config.Offset)-float64(len(label)), 0))
plot[w][h].Text = label
plot[w][h].Color = config.LabelColor
plot[w][config.Offset-1].Text = "┤"
plot[w][config.Offset-1].Color = config.AxisColor
}
for i := range data {
series := data[i]
color := Default
if i < len(config.SeriesColors) {
color = config.SeriesColors[i]
}
var y0, y1 int
if !math.IsNaN(series[0]) {
y0 = int(round(series[0]*ratio) - min2)
plot[rows-y0][config.Offset-1].Text = "┼" // first value
plot[rows-y0][config.Offset-1].Color = config.AxisColor
}
for x := 0; x < len(series)-1; x++ { // plot the line
d0 := series[x]
d1 := series[x+1]
if math.IsNaN(d0) && math.IsNaN(d1) {
continue
}
if math.IsNaN(d1) && !math.IsNaN(d0) {
y0 = int(round(d0*ratio) - float64(intmin2))
plot[rows-y0][x+config.Offset].Text = "╴"
plot[rows-y0][x+config.Offset].Color = color
continue
}
if math.IsNaN(d0) && !math.IsNaN(d1) {
y1 = int(round(d1*ratio) - float64(intmin2))
plot[rows-y1][x+config.Offset].Text = "╶"
plot[rows-y1][x+config.Offset].Color = color
continue
}
y0 = int(round(d0*ratio) - float64(intmin2))
y1 = int(round(d1*ratio) - float64(intmin2))
if y0 == y1 {
plot[rows-y0][x+config.Offset].Text = "─"
} else {
if y0 > y1 {
plot[rows-y1][x+config.Offset].Text = "╰"
plot[rows-y0][x+config.Offset].Text = "╮"
} else {
plot[rows-y1][x+config.Offset].Text = "╭"
plot[rows-y0][x+config.Offset].Text = "╯"
}
start := int(math.Min(float64(y0), float64(y1))) + 1
end := int(math.Max(float64(y0), float64(y1)))
for y := start; y < end; y++ {
plot[rows-y][x+config.Offset].Text = "│"
}
}
start := int(math.Min(float64(y0), float64(y1)))
end := int(math.Max(float64(y0), float64(y1)))
for y := start; y <= end; y++ {
plot[rows-y][x+config.Offset].Color = color
}
}
}
// join columns
var lines bytes.Buffer
for h, horizontal := range plot {
if h != 0 {
lines.WriteRune('\n')
}
// remove trailing spaces
lastCharIndex := 0
for i := width - 1; i >= 0; i-- {
if horizontal[i].Text != " " {
lastCharIndex = i
break
}
}
c := Default
for _, v := range horizontal[:lastCharIndex+1] {
if v.Color != c {
c = v.Color
lines.WriteString(c.String())
}
lines.WriteString(v.Text)
}
if c != Default {
lines.WriteString(Default.String())
}
}
// add caption if not empty
if config.Caption != "" {
lines.WriteRune('\n')
lines.WriteString(strings.Repeat(" ", config.Offset+maxWidth))
if len(config.Caption) < lenMax {
lines.WriteString(strings.Repeat(" ", (lenMax-len(config.Caption))/2))
}
if config.CaptionColor != Default {
lines.WriteString(config.CaptionColor.String())
}
lines.WriteString(config.Caption)
if config.CaptionColor != Default {
lines.WriteString(Default.String())
}
}
if len(config.SeriesLegends) > 0 {
addLegends(&lines, config, lenMax, config.Offset+maxWidth)
}
return lines.String()
}

312
vendor/github.com/guptarohit/asciigraph/color.go generated vendored Normal file
View File

@@ -0,0 +1,312 @@
package asciigraph
import "fmt"
type AnsiColor byte
var (
Default AnsiColor = 0
AliceBlue AnsiColor = 255
AntiqueWhite AnsiColor = 255
Aqua AnsiColor = 14
Aquamarine AnsiColor = 122
Azure AnsiColor = 15
Beige AnsiColor = 230
Bisque AnsiColor = 224
Black AnsiColor = 188 // dummy value
BlanchedAlmond AnsiColor = 230
Blue AnsiColor = 12
BlueViolet AnsiColor = 92
Brown AnsiColor = 88
BurlyWood AnsiColor = 180
CadetBlue AnsiColor = 73
Chartreuse AnsiColor = 118
Chocolate AnsiColor = 166
Coral AnsiColor = 209
CornflowerBlue AnsiColor = 68
Cornsilk AnsiColor = 230
Crimson AnsiColor = 161
Cyan AnsiColor = 14
DarkBlue AnsiColor = 18
DarkCyan AnsiColor = 30
DarkGoldenrod AnsiColor = 136
DarkGray AnsiColor = 248
DarkGreen AnsiColor = 22
DarkKhaki AnsiColor = 143
DarkMagenta AnsiColor = 90
DarkOliveGreen AnsiColor = 59
DarkOrange AnsiColor = 208
DarkOrchid AnsiColor = 134
DarkRed AnsiColor = 88
DarkSalmon AnsiColor = 173
DarkSeaGreen AnsiColor = 108
DarkSlateBlue AnsiColor = 60
DarkSlateGray AnsiColor = 238
DarkTurquoise AnsiColor = 44
DarkViolet AnsiColor = 92
DeepPink AnsiColor = 198
DeepSkyBlue AnsiColor = 39
DimGray AnsiColor = 242
DodgerBlue AnsiColor = 33
Firebrick AnsiColor = 124
FloralWhite AnsiColor = 15
ForestGreen AnsiColor = 28
Fuchsia AnsiColor = 13
Gainsboro AnsiColor = 253
GhostWhite AnsiColor = 15
Gold AnsiColor = 220
Goldenrod AnsiColor = 178
Gray AnsiColor = 8
Green AnsiColor = 2
GreenYellow AnsiColor = 155
Honeydew AnsiColor = 15
HotPink AnsiColor = 205
IndianRed AnsiColor = 167
Indigo AnsiColor = 54
Ivory AnsiColor = 15
Khaki AnsiColor = 222
Lavender AnsiColor = 254
LavenderBlush AnsiColor = 255
LawnGreen AnsiColor = 118
LemonChiffon AnsiColor = 230
LightBlue AnsiColor = 152
LightCoral AnsiColor = 210
LightCyan AnsiColor = 195
LightGoldenrodYellow AnsiColor = 230
LightGray AnsiColor = 252
LightGreen AnsiColor = 120
LightPink AnsiColor = 217
LightSalmon AnsiColor = 216
LightSeaGreen AnsiColor = 37
LightSkyBlue AnsiColor = 117
LightSlateGray AnsiColor = 103
LightSteelBlue AnsiColor = 152
LightYellow AnsiColor = 230
Lime AnsiColor = 10
LimeGreen AnsiColor = 77
Linen AnsiColor = 255
Magenta AnsiColor = 13
Maroon AnsiColor = 1
MediumAquamarine AnsiColor = 79
MediumBlue AnsiColor = 20
MediumOrchid AnsiColor = 134
MediumPurple AnsiColor = 98
MediumSeaGreen AnsiColor = 72
MediumSlateBlue AnsiColor = 99
MediumSpringGreen AnsiColor = 48
MediumTurquoise AnsiColor = 80
MediumVioletRed AnsiColor = 162
MidnightBlue AnsiColor = 17
MintCream AnsiColor = 15
MistyRose AnsiColor = 224
Moccasin AnsiColor = 223
NavajoWhite AnsiColor = 223
Navy AnsiColor = 4
OldLace AnsiColor = 230
Olive AnsiColor = 3
OliveDrab AnsiColor = 64
Orange AnsiColor = 214
OrangeRed AnsiColor = 202
Orchid AnsiColor = 170
PaleGoldenrod AnsiColor = 223
PaleGreen AnsiColor = 120
PaleTurquoise AnsiColor = 159
PaleVioletRed AnsiColor = 168
PapayaWhip AnsiColor = 230
PeachPuff AnsiColor = 223
Peru AnsiColor = 173
Pink AnsiColor = 218
Plum AnsiColor = 182
PowderBlue AnsiColor = 152
Purple AnsiColor = 5
Red AnsiColor = 9
RosyBrown AnsiColor = 138
RoyalBlue AnsiColor = 63
SaddleBrown AnsiColor = 94
Salmon AnsiColor = 210
SandyBrown AnsiColor = 215
SeaGreen AnsiColor = 29
SeaShell AnsiColor = 15
Sienna AnsiColor = 131
Silver AnsiColor = 7
SkyBlue AnsiColor = 117
SlateBlue AnsiColor = 62
SlateGray AnsiColor = 66
Snow AnsiColor = 15
SpringGreen AnsiColor = 48
SteelBlue AnsiColor = 67
Tan AnsiColor = 180
Teal AnsiColor = 6
Thistle AnsiColor = 182
Tomato AnsiColor = 203
Turquoise AnsiColor = 80
Violet AnsiColor = 213
Wheat AnsiColor = 223
White AnsiColor = 15
WhiteSmoke AnsiColor = 255
Yellow AnsiColor = 11
YellowGreen AnsiColor = 149
)
var ColorNames = map[string]AnsiColor{
"default": Default,
"aliceblue": AliceBlue,
"antiquewhite": AntiqueWhite,
"aqua": Aqua,
"aquamarine": Aquamarine,
"azure": Azure,
"beige": Beige,
"bisque": Bisque,
"black": Black,
"blanchedalmond": BlanchedAlmond,
"blue": Blue,
"blueviolet": BlueViolet,
"brown": Brown,
"burlywood": BurlyWood,
"cadetblue": CadetBlue,
"chartreuse": Chartreuse,
"chocolate": Chocolate,
"coral": Coral,
"cornflowerblue": CornflowerBlue,
"cornsilk": Cornsilk,
"crimson": Crimson,
"cyan": Cyan,
"darkblue": DarkBlue,
"darkcyan": DarkCyan,
"darkgoldenrod": DarkGoldenrod,
"darkgray": DarkGray,
"darkgreen": DarkGreen,
"darkkhaki": DarkKhaki,
"darkmagenta": DarkMagenta,
"darkolivegreen": DarkOliveGreen,
"darkorange": DarkOrange,
"darkorchid": DarkOrchid,
"darkred": DarkRed,
"darksalmon": DarkSalmon,
"darkseagreen": DarkSeaGreen,
"darkslateblue": DarkSlateBlue,
"darkslategray": DarkSlateGray,
"darkturquoise": DarkTurquoise,
"darkviolet": DarkViolet,
"deeppink": DeepPink,
"deepskyblue": DeepSkyBlue,
"dimgray": DimGray,
"dodgerblue": DodgerBlue,
"firebrick": Firebrick,
"floralwhite": FloralWhite,
"forestgreen": ForestGreen,
"fuchsia": Fuchsia,
"gainsboro": Gainsboro,
"ghostwhite": GhostWhite,
"gold": Gold,
"goldenrod": Goldenrod,
"gray": Gray,
"green": Green,
"greenyellow": GreenYellow,
"honeydew": Honeydew,
"hotpink": HotPink,
"indianred": IndianRed,
"indigo": Indigo,
"ivory": Ivory,
"khaki": Khaki,
"lavender": Lavender,
"lavenderblush": LavenderBlush,
"lawngreen": LawnGreen,
"lemonchiffon": LemonChiffon,
"lightblue": LightBlue,
"lightcoral": LightCoral,
"lightcyan": LightCyan,
"lightgoldenrodyellow": LightGoldenrodYellow,
"lightgray": LightGray,
"lightgreen": LightGreen,
"lightpink": LightPink,
"lightsalmon": LightSalmon,
"lightseagreen": LightSeaGreen,
"lightskyblue": LightSkyBlue,
"lightslategray": LightSlateGray,
"lightsteelblue": LightSteelBlue,
"lightyellow": LightYellow,
"lime": Lime,
"limegreen": LimeGreen,
"linen": Linen,
"magenta": Magenta,
"maroon": Maroon,
"mediumaquamarine": MediumAquamarine,
"mediumblue": MediumBlue,
"mediumorchid": MediumOrchid,
"mediumpurple": MediumPurple,
"mediumseagreen": MediumSeaGreen,
"mediumslateblue": MediumSlateBlue,
"mediumspringgreen": MediumSpringGreen,
"mediumturquoise": MediumTurquoise,
"mediumvioletred": MediumVioletRed,
"midnightblue": MidnightBlue,
"mintcream": MintCream,
"mistyrose": MistyRose,
"moccasin": Moccasin,
"navajowhite": NavajoWhite,
"navy": Navy,
"oldlace": OldLace,
"olive": Olive,
"olivedrab": OliveDrab,
"orange": Orange,
"orangered": OrangeRed,
"orchid": Orchid,
"palegoldenrod": PaleGoldenrod,
"palegreen": PaleGreen,
"paleturquoise": PaleTurquoise,
"palevioletred": PaleVioletRed,
"papayawhip": PapayaWhip,
"peachpuff": PeachPuff,
"peru": Peru,
"pink": Pink,
"plum": Plum,
"powderblue": PowderBlue,
"purple": Purple,
"red": Red,
"rosybrown": RosyBrown,
"royalblue": RoyalBlue,
"saddlebrown": SaddleBrown,
"salmon": Salmon,
"sandybrown": SandyBrown,
"seagreen": SeaGreen,
"seashell": SeaShell,
"sienna": Sienna,
"silver": Silver,
"skyblue": SkyBlue,
"slateblue": SlateBlue,
"slategray": SlateGray,
"snow": Snow,
"springgreen": SpringGreen,
"steelblue": SteelBlue,
"tan": Tan,
"teal": Teal,
"thistle": Thistle,
"tomato": Tomato,
"turquoise": Turquoise,
"violet": Violet,
"wheat": Wheat,
"white": White,
"whitesmoke": WhiteSmoke,
"yellow": Yellow,
"yellowgreen": YellowGreen,
}
func (c AnsiColor) String() string {
if c == Default {
return "\x1b[0m"
}
if c == Black {
c = 0
}
if c <= Silver {
// 3-bit color
return fmt.Sprintf("\x1b[%dm", 30+byte(c))
}
if c <= White {
// 4-bit color
return fmt.Sprintf("\x1b[%dm", 82+byte(c))
}
// 8-bit color
return fmt.Sprintf("\x1b[38;5;%dm", byte(c))
}

View File

@@ -0,0 +1,3 @@
FROM scratch
COPY asciigraph /asciigraph
ENTRYPOINT ["/asciigraph"]

45
vendor/github.com/guptarohit/asciigraph/legend.go generated vendored Normal file
View File

@@ -0,0 +1,45 @@
package asciigraph
import (
"bytes"
"fmt"
"strings"
"unicode/utf8"
)
// Create legend item as a colored box and text
func createLegendItem(text string, color AnsiColor) (string, int) {
return fmt.Sprintf(
"%s■%s %s",
color.String(),
Default.String(),
text,
),
// Can't use len() because of AnsiColor, add 2 for box and space
utf8.RuneCountInString(text) + 2
}
// Add legend for each series added to the graph
func addLegends(lines *bytes.Buffer, config *config, lenMax int, leftPad int) {
lines.WriteString("\n\n")
lines.WriteString(strings.Repeat(" ", leftPad))
var legendsText string
var legendsTextLen int
rightPad := 3
for i, text := range config.SeriesLegends {
item, itemLen := createLegendItem(text, config.SeriesColors[i])
legendsText += item
legendsTextLen += itemLen
if i < len(config.SeriesLegends)-1 {
legendsText += strings.Repeat(" ", rightPad)
legendsTextLen += rightPad
}
}
if legendsTextLen < lenMax {
lines.WriteString(strings.Repeat(" ", (lenMax-legendsTextLen)/2))
}
lines.WriteString(legendsText)
}

126
vendor/github.com/guptarohit/asciigraph/options.go generated vendored Normal file
View File

@@ -0,0 +1,126 @@
package asciigraph
import (
"strings"
)
// Option represents a configuration setting.
type Option interface {
apply(c *config)
}
// config holds various graph options
type config struct {
Width, Height int
LowerBound, UpperBound *float64
Offset int
Caption string
Precision uint
CaptionColor AnsiColor
AxisColor AnsiColor
LabelColor AnsiColor
SeriesColors []AnsiColor
SeriesLegends []string
}
// An optionFunc applies an option.
type optionFunc func(*config)
// apply implements the Option interface.
func (of optionFunc) apply(c *config) { of(c) }
func configure(defaults config, options []Option) *config {
for _, o := range options {
o.apply(&defaults)
}
return &defaults
}
// Width sets the graphs width. By default, the width of the graph is
// determined by the number of data points. If the value given is a
// positive number, the data points are interpolated on the x axis.
// Values <= 0 reset the width to the default value.
func Width(w int) Option {
return optionFunc(func(c *config) {
if w > 0 {
c.Width = w
} else {
c.Width = 0
}
})
}
// Height sets the graphs height.
func Height(h int) Option {
return optionFunc(func(c *config) {
if h > 0 {
c.Height = h
} else {
c.Height = 0
}
})
}
// LowerBound sets the graph's minimum value for the vertical axis. It will be ignored
// if the series contains a lower value.
func LowerBound(min float64) Option {
return optionFunc(func(c *config) { c.LowerBound = &min })
}
// UpperBound sets the graph's maximum value for the vertical axis. It will be ignored
// if the series contains a bigger value.
func UpperBound(max float64) Option {
return optionFunc(func(c *config) { c.UpperBound = &max })
}
// Offset sets the graphs offset.
func Offset(o int) Option {
return optionFunc(func(c *config) { c.Offset = o })
}
// Precision sets the graphs precision.
func Precision(p uint) Option {
return optionFunc(func(c *config) { c.Precision = p })
}
// Caption sets the graphs caption.
func Caption(caption string) Option {
return optionFunc(func(c *config) {
c.Caption = strings.TrimSpace(caption)
})
}
// CaptionColor sets the caption color.
func CaptionColor(ac AnsiColor) Option {
return optionFunc(func(c *config) {
c.CaptionColor = ac
})
}
// AxisColor sets the axis color.
func AxisColor(ac AnsiColor) Option {
return optionFunc(func(c *config) {
c.AxisColor = ac
})
}
// LabelColor sets the axis label color.
func LabelColor(ac AnsiColor) Option {
return optionFunc(func(c *config) {
c.LabelColor = ac
})
}
// SeriesColors sets the series colors.
func SeriesColors(ac ...AnsiColor) Option {
return optionFunc(func(c *config) {
c.SeriesColors = ac
})
}
// SeriesLegends sets the legend text for the corresponding series.
func SeriesLegends(text ...string) Option {
return optionFunc(func(c *config) {
c.SeriesLegends = text
})
}

105
vendor/github.com/guptarohit/asciigraph/utils.go generated vendored Normal file
View File

@@ -0,0 +1,105 @@
package asciigraph
import (
"fmt"
"log"
"math"
"os"
"os/exec"
"runtime"
)
func minMaxFloat64Slice(v []float64) (min, max float64) {
min = math.Inf(1)
max = math.Inf(-1)
if len(v) == 0 {
panic("Empty slice")
}
for _, e := range v {
if e < min {
min = e
}
if e > max {
max = e
}
}
return
}
func round(input float64) float64 {
if math.IsNaN(input) {
return math.NaN()
}
sign := 1.0
if input < 0 {
sign = -1
input *= -1
}
_, decimal := math.Modf(input)
var rounded float64
if decimal >= 0.5 {
rounded = math.Ceil(input)
} else {
rounded = math.Floor(input)
}
return rounded * sign
}
func linearInterpolate(before, after, atPoint float64) float64 {
return before + (after-before)*atPoint
}
func interpolateArray(data []float64, fitCount int) []float64 {
var interpolatedData []float64
springFactor := float64(len(data)-1) / float64(fitCount-1)
interpolatedData = append(interpolatedData, data[0])
for i := 1; i < fitCount-1; i++ {
spring := float64(i) * springFactor
before := math.Floor(spring)
after := math.Ceil(spring)
atPoint := spring - before
interpolatedData = append(interpolatedData, linearInterpolate(data[int(before)], data[int(after)], atPoint))
}
interpolatedData = append(interpolatedData, data[len(data)-1])
return interpolatedData
}
// clear terminal screen
var Clear func()
func init() {
platform := runtime.GOOS
if platform == "windows" {
Clear = func() {
cmd := exec.Command("cmd", "/c", "cls")
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
} else {
Clear = func() {
fmt.Print("\033[2J\033[H")
}
}
}
func calculateHeight(interval float64) int {
if interval >= 1 {
return int(interval)
}
scaleFactor := math.Pow(10, math.Floor(math.Log10(interval)))
scaledDelta := interval / scaleFactor
if scaledDelta < 2 {
return int(math.Ceil(scaledDelta))
}
return int(math.Floor(scaledDelta))
}

27
vendor/golang.org/x/crypto/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/crypto/PATENTS generated vendored Normal file
View File

@@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

76
vendor/golang.org/x/crypto/ssh/terminal/terminal.go generated vendored Normal file
View File

@@ -0,0 +1,76 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Deprecated: this package moved to golang.org/x/term.
package terminal
import (
"io"
"golang.org/x/term"
)
// EscapeCodes contains escape sequences that can be written to the terminal in
// order to achieve different styles of text.
type EscapeCodes = term.EscapeCodes
// Terminal contains the state for running a VT100 terminal that is capable of
// reading lines of input.
type Terminal = term.Terminal
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
// a local terminal, that terminal must first have been put into raw mode.
// prompt is a string that is written at the start of each input line (i.e.
// "> ").
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
return term.NewTerminal(c, prompt)
}
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
// to valid line data. It indicates that bracketed paste mode is enabled and
// that the returned line consists only of pasted data. Programs may wish to
// interpret pasted data more literally than typed data.
var ErrPasteIndicator = term.ErrPasteIndicator
// State contains the state of a terminal.
type State = term.State
// IsTerminal returns whether the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
return term.IsTerminal(fd)
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
return term.ReadPassword(fd)
}
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
return term.MakeRaw(fd)
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, oldState *State) error {
return term.Restore(fd, oldState)
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
return term.GetState(fd)
}
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
return term.GetSize(fd)
}

27
vendor/golang.org/x/sys/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/sys/PATENTS generated vendored Normal file
View File

@@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

8
vendor/golang.org/x/sys/plan9/asm.s generated vendored Normal file
View File

@@ -0,0 +1,8 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
TEXT ·use(SB),NOSPLIT,$0
RET

30
vendor/golang.org/x/sys/plan9/asm_plan9_386.s generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
//
// System call support for 386, Plan 9
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-32
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-44
JMP syscall·Syscall6(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·seek(SB),NOSPLIT,$0-36
JMP syscall·seek(SB)
TEXT ·exit(SB),NOSPLIT,$4-4
JMP syscall·exit(SB)

30
vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
//
// System call support for amd64, Plan 9
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-64
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-88
JMP syscall·Syscall6(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·seek(SB),NOSPLIT,$0-56
JMP syscall·seek(SB)
TEXT ·exit(SB),NOSPLIT,$8-8
JMP syscall·exit(SB)

25
vendor/golang.org/x/sys/plan9/asm_plan9_arm.s generated vendored Normal file
View File

@@ -0,0 +1,25 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// System call support for plan9 on arm
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-32
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-44
JMP syscall·Syscall6(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·seek(SB),NOSPLIT,$0-36
JMP syscall·exit(SB)

70
vendor/golang.org/x/sys/plan9/const_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,70 @@
package plan9
// Plan 9 Constants
// Open modes
const (
O_RDONLY = 0
O_WRONLY = 1
O_RDWR = 2
O_TRUNC = 16
O_CLOEXEC = 32
O_EXCL = 0x1000
)
// Rfork flags
const (
RFNAMEG = 1 << 0
RFENVG = 1 << 1
RFFDG = 1 << 2
RFNOTEG = 1 << 3
RFPROC = 1 << 4
RFMEM = 1 << 5
RFNOWAIT = 1 << 6
RFCNAMEG = 1 << 10
RFCENVG = 1 << 11
RFCFDG = 1 << 12
RFREND = 1 << 13
RFNOMNT = 1 << 14
)
// Qid.Type bits
const (
QTDIR = 0x80
QTAPPEND = 0x40
QTEXCL = 0x20
QTMOUNT = 0x10
QTAUTH = 0x08
QTTMP = 0x04
QTFILE = 0x00
)
// Dir.Mode bits
const (
DMDIR = 0x80000000
DMAPPEND = 0x40000000
DMEXCL = 0x20000000
DMMOUNT = 0x10000000
DMAUTH = 0x08000000
DMTMP = 0x04000000
DMREAD = 0x4
DMWRITE = 0x2
DMEXEC = 0x1
)
const (
STATMAX = 65535
ERRMAX = 128
STATFIXLEN = 49
)
// Mount and bind flags
const (
MREPL = 0x0000
MBEFORE = 0x0001
MAFTER = 0x0002
MORDER = 0x0003
MCREATE = 0x0004
MCACHE = 0x0010
MMASK = 0x0017
)

212
vendor/golang.org/x/sys/plan9/dir_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,212 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Plan 9 directory marshalling. See intro(5).
package plan9
import "errors"
var (
ErrShortStat = errors.New("stat buffer too short")
ErrBadStat = errors.New("malformed stat buffer")
ErrBadName = errors.New("bad character in file name")
)
// A Qid represents a 9P server's unique identification for a file.
type Qid struct {
Path uint64 // the file server's unique identification for the file
Vers uint32 // version number for given Path
Type uint8 // the type of the file (plan9.QTDIR for example)
}
// A Dir contains the metadata for a file.
type Dir struct {
// system-modified data
Type uint16 // server type
Dev uint32 // server subtype
// file data
Qid Qid // unique id from server
Mode uint32 // permissions
Atime uint32 // last read time
Mtime uint32 // last write time
Length int64 // file length
Name string // last element of path
Uid string // owner name
Gid string // group name
Muid string // last modifier name
}
var nullDir = Dir{
Type: ^uint16(0),
Dev: ^uint32(0),
Qid: Qid{
Path: ^uint64(0),
Vers: ^uint32(0),
Type: ^uint8(0),
},
Mode: ^uint32(0),
Atime: ^uint32(0),
Mtime: ^uint32(0),
Length: ^int64(0),
}
// Null assigns special "don't touch" values to members of d to
// avoid modifying them during plan9.Wstat.
func (d *Dir) Null() { *d = nullDir }
// Marshal encodes a 9P stat message corresponding to d into b
//
// If there isn't enough space in b for a stat message, ErrShortStat is returned.
func (d *Dir) Marshal(b []byte) (n int, err error) {
n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
if n > len(b) {
return n, ErrShortStat
}
for _, c := range d.Name {
if c == '/' {
return n, ErrBadName
}
}
b = pbit16(b, uint16(n)-2)
b = pbit16(b, d.Type)
b = pbit32(b, d.Dev)
b = pbit8(b, d.Qid.Type)
b = pbit32(b, d.Qid.Vers)
b = pbit64(b, d.Qid.Path)
b = pbit32(b, d.Mode)
b = pbit32(b, d.Atime)
b = pbit32(b, d.Mtime)
b = pbit64(b, uint64(d.Length))
b = pstring(b, d.Name)
b = pstring(b, d.Uid)
b = pstring(b, d.Gid)
b = pstring(b, d.Muid)
return n, nil
}
// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
//
// If b is too small to hold a valid stat message, ErrShortStat is returned.
//
// If the stat message itself is invalid, ErrBadStat is returned.
func UnmarshalDir(b []byte) (*Dir, error) {
if len(b) < STATFIXLEN {
return nil, ErrShortStat
}
size, buf := gbit16(b)
if len(b) != int(size)+2 {
return nil, ErrBadStat
}
b = buf
var d Dir
d.Type, b = gbit16(b)
d.Dev, b = gbit32(b)
d.Qid.Type, b = gbit8(b)
d.Qid.Vers, b = gbit32(b)
d.Qid.Path, b = gbit64(b)
d.Mode, b = gbit32(b)
d.Atime, b = gbit32(b)
d.Mtime, b = gbit32(b)
n, b := gbit64(b)
d.Length = int64(n)
var ok bool
if d.Name, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
if d.Uid, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
if d.Gid, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
if d.Muid, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
return &d, nil
}
// pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
func pbit8(b []byte, v uint8) []byte {
b[0] = byte(v)
return b[1:]
}
// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
func pbit16(b []byte, v uint16) []byte {
b[0] = byte(v)
b[1] = byte(v >> 8)
return b[2:]
}
// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
func pbit32(b []byte, v uint32) []byte {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
return b[4:]
}
// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
func pbit64(b []byte, v uint64) []byte {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
b[4] = byte(v >> 32)
b[5] = byte(v >> 40)
b[6] = byte(v >> 48)
b[7] = byte(v >> 56)
return b[8:]
}
// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
// returning the remaining slice of b..
func pstring(b []byte, s string) []byte {
b = pbit16(b, uint16(len(s)))
n := copy(b, s)
return b[n:]
}
// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
func gbit8(b []byte) (uint8, []byte) {
return uint8(b[0]), b[1:]
}
// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
func gbit16(b []byte) (uint16, []byte) {
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
}
// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
func gbit32(b []byte) (uint32, []byte) {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
}
// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
func gbit64(b []byte) (uint64, []byte) {
lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
return uint64(lo) | uint64(hi)<<32, b[8:]
}
// gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
// It returns the string with the remaining slice of b and a boolean. If the length is
// greater than the number of bytes in b, the boolean will be false.
func gstring(b []byte) (string, []byte, bool) {
n, b := gbit16(b)
if int(n) > len(b) {
return "", b, false
}
return string(b[:n]), b[n:], true
}

31
vendor/golang.org/x/sys/plan9/env_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,31 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Plan 9 environment variables.
package plan9
import (
"syscall"
)
func Getenv(key string) (value string, found bool) {
return syscall.Getenv(key)
}
func Setenv(key, value string) error {
return syscall.Setenv(key, value)
}
func Clearenv() {
syscall.Clearenv()
}
func Environ() []string {
return syscall.Environ()
}
func Unsetenv(key string) error {
return syscall.Unsetenv(key)
}

50
vendor/golang.org/x/sys/plan9/errors_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,50 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package plan9
import "syscall"
// Constants
const (
// Invented values to support what package os expects.
O_CREAT = 0x02000
O_APPEND = 0x00400
O_NOCTTY = 0x00000
O_NONBLOCK = 0x00000
O_SYNC = 0x00000
O_ASYNC = 0x00000
S_IFMT = 0x1f000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
S_IFDIR = 0x4000
S_IFBLK = 0x6000
S_IFREG = 0x8000
S_IFLNK = 0xa000
S_IFSOCK = 0xc000
)
// Errors
var (
EINVAL = syscall.NewError("bad arg in system call")
ENOTDIR = syscall.NewError("not a directory")
EISDIR = syscall.NewError("file is a directory")
ENOENT = syscall.NewError("file does not exist")
EEXIST = syscall.NewError("file already exists")
EMFILE = syscall.NewError("no free file descriptors")
EIO = syscall.NewError("i/o error")
ENAMETOOLONG = syscall.NewError("file name too long")
EINTR = syscall.NewError("interrupted")
EPERM = syscall.NewError("permission denied")
EBUSY = syscall.NewError("no free devices")
ETIMEDOUT = syscall.NewError("connection timed out")
EPLAN9 = syscall.NewError("not supported by plan 9")
// The following errors do not correspond to any
// Plan 9 system messages. Invented to support
// what package os and others expect.
EACCES = syscall.NewError("access permission denied")
EAFNOSUPPORT = syscall.NewError("address family not supported by protocol")
)

150
vendor/golang.org/x/sys/plan9/mkall.sh generated vendored Normal file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# The plan9 package provides access to the raw system call
# interface of the underlying operating system. Porting Go to
# a new architecture/operating system combination requires
# some manual effort, though there are tools that automate
# much of the process. The auto-generated files have names
# beginning with z.
#
# This script runs or (given -n) prints suggested commands to generate z files
# for the current system. Running those commands is not automatic.
# This script is documentation more than anything else.
#
# * asm_${GOOS}_${GOARCH}.s
#
# This hand-written assembly file implements system call dispatch.
# There are three entry points:
#
# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
#
# The first and second are the standard ones; they differ only in
# how many arguments can be passed to the kernel.
# The third is for low-level use by the ForkExec wrapper;
# unlike the first two, it does not call into the scheduler to
# let it know that a system call is running.
#
# * syscall_${GOOS}.go
#
# This hand-written Go file implements system calls that need
# special handling and lists "//sys" comments giving prototypes
# for ones that can be auto-generated. Mksyscall reads those
# comments to generate the stubs.
#
# * syscall_${GOOS}_${GOARCH}.go
#
# Same as syscall_${GOOS}.go except that it contains code specific
# to ${GOOS} on one particular architecture.
#
# * types_${GOOS}.c
#
# This hand-written C file includes standard C headers and then
# creates typedef or enum names beginning with a dollar sign
# (use of $ in variable names is a gcc extension). The hardest
# part about preparing this file is figuring out which headers to
# include and which symbols need to be #defined to get the
# actual data structures that pass through to the kernel system calls.
# Some C libraries present alternate versions for binary compatibility
# and translate them on the way in and out of system calls, but
# there is almost always a #define that can get the real ones.
# See types_darwin.c and types_linux.c for examples.
#
# * zerror_${GOOS}_${GOARCH}.go
#
# This machine-generated file defines the system's error numbers,
# error strings, and signal numbers. The generator is "mkerrors.sh".
# Usually no arguments are needed, but mkerrors.sh will pass its
# arguments on to godefs.
#
# * zsyscall_${GOOS}_${GOARCH}.go
#
# Generated by mksyscall.pl; see syscall_${GOOS}.go above.
#
# * zsysnum_${GOOS}_${GOARCH}.go
#
# Generated by mksysnum_${GOOS}.
#
# * ztypes_${GOOS}_${GOARCH}.go
#
# Generated by godefs; see types_${GOOS}.c above.
GOOSARCH="${GOOS}_${GOARCH}"
# defaults
mksyscall="go run mksyscall.go"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
run="sh"
case "$1" in
-syscalls)
for i in zsyscall*go
do
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
rm _$i
done
exit 0
;;
-n)
run="cat"
shift
esac
case "$#" in
0)
;;
*)
echo 'usage: mkall.sh [-n]' 1>&2
exit 2
esac
case "$GOOSARCH" in
_* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
plan9_386)
mkerrors=
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,386"
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
plan9_amd64)
mkerrors=
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,amd64"
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
plan9_arm)
mkerrors=
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,arm"
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
exit 1
;;
esac
(
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
case "$GOOS" in
plan9)
syscall_goos="syscall_$GOOS.go"
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos |gofmt >zsyscall_$GOOSARCH.go"; fi
;;
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
) | $run

246
vendor/golang.org/x/sys/plan9/mkerrors.sh generated vendored Normal file
View File

@@ -0,0 +1,246 @@
#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.
unset LANG
export LC_ALL=C
export LC_CTYPE=C
CC=${CC:-gcc}
uname=$(uname)
includes='
#include <sys/types.h>
#include <sys/file.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <sys/signal.h>
#include <signal.h>
#include <sys/resource.h>
'
ccflags="$@"
# Write go tool cgo -godefs input.
(
echo package plan9
echo
echo '/*'
indirect="includes_$(uname)"
echo "${!indirect} $includes"
echo '*/'
echo 'import "C"'
echo
echo 'const ('
# The gcc command line prints all the #defines
# it encounters while processing the input
echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
awk '
$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
$2 ~ /^(SCM_SRCRT)$/ {next}
$2 ~ /^(MAP_FAILED)$/ {next}
$2 !~ /^ETH_/ &&
$2 !~ /^EPROC_/ &&
$2 !~ /^EQUIV_/ &&
$2 !~ /^EXPR_/ &&
$2 ~ /^E[A-Z0-9_]+$/ ||
$2 ~ /^B[0-9_]+$/ ||
$2 ~ /^V[A-Z0-9]+$/ ||
$2 ~ /^CS[A-Z0-9]/ ||
$2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
$2 ~ /^IGN/ ||
$2 ~ /^IX(ON|ANY|OFF)$/ ||
$2 ~ /^IN(LCR|PCK)$/ ||
$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
$2 ~ /^C(LOCAL|READ)$/ ||
$2 == "BRKINT" ||
$2 == "HUPCL" ||
$2 == "PENDIN" ||
$2 == "TOSTOP" ||
$2 ~ /^PAR/ ||
$2 ~ /^SIG[^_]/ ||
$2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ ||
$2 ~ /^IN_/ ||
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
$2 == "ICMPV6_FILTER" ||
$2 == "SOMAXCONN" ||
$2 == "NAME_MAX" ||
$2 == "IFNAMSIZ" ||
$2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ ||
$2 ~ /^SYSCTL_VERS/ ||
$2 ~ /^(MS|MNT)_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
$2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
$2 !~ "NLA_TYPE_MASK" &&
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
$2 !~ "RTF_BITS" &&
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
$2 ~ /^BIOC/ ||
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||
$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
$2 ~ /^CLONE_[A-Z_]+/ ||
$2 !~ /^(BPF_TIMEVAL)$/ &&
$2 ~ /^(BPF|DLT)_/ ||
$2 !~ "WMESGLEN" &&
$2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)}
$2 ~ /^__WCOREFLAG$/ {next}
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
{next}
' | sort
echo ')'
) >_const.go
# Pull out the error names for later.
errors=$(
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
sort
)
# Pull out the signal names for later.
signals=$(
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
sort
)
# Again, writing regexps to a file.
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
sort >_error.grep
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
sort >_signal.grep
echo '// mkerrors.sh' "$@"
echo '// Code generated by the command above; DO NOT EDIT.'
echo
go tool cgo -godefs -- "$@" _const.go >_error.out
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
echo
echo '// Errors'
echo 'const ('
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/'
echo ')'
echo
echo '// Signals'
echo 'const ('
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/'
echo ')'
# Run C program to print error and syscall strings.
(
echo -E "
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
int errors[] = {
"
for i in $errors
do
echo -E ' '$i,
done
echo -E "
};
int signals[] = {
"
for i in $signals
do
echo -E ' '$i,
done
# Use -E because on some systems bash builtin interprets \n itself.
echo -E '
};
static int
intcmp(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
int
main(void)
{
int i, j, e;
char buf[1024], *p;
printf("\n\n// Error table\n");
printf("var errors = [...]string {\n");
qsort(errors, nelem(errors), sizeof errors[0], intcmp);
for(i=0; i<nelem(errors); i++) {
e = errors[i];
if(i > 0 && errors[i-1] == e)
continue;
strcpy(buf, strerror(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
buf[0] += a - A;
printf("\t%d: \"%s\",\n", e, buf);
}
printf("}\n\n");
printf("\n\n// Signal table\n");
printf("var signals = [...]string {\n");
qsort(signals, nelem(signals), sizeof signals[0], intcmp);
for(i=0; i<nelem(signals); i++) {
e = signals[i];
if(i > 0 && signals[i-1] == e)
continue;
strcpy(buf, strsignal(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
buf[0] += a - A;
// cut trailing : number.
p = strrchr(buf, ":"[0]);
if(p)
*p = '\0';
printf("\t%d: \"%s\",\n", e, buf);
}
printf("}\n\n");
return 0;
}
'
) >_errors.c
$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out

23
vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh generated vendored Normal file
View File

@@ -0,0 +1,23 @@
#!/bin/sh
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
COMMAND="mksysnum_plan9.sh $@"
cat <<EOF
// $COMMAND
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package plan9
const(
EOF
SP='[ ]' # space or tab
sed "s/^#define${SP}\\([A-Z0-9_][A-Z0-9_]*\\)${SP}${SP}*\\([0-9][0-9]*\\)/SYS_\\1=\\2/g" \
< $1 | grep -v SYS__
cat <<EOF
)
EOF

21
vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.5
package plan9
import "syscall"
func fixwd() {
syscall.Fixwd()
}
func Getwd() (wd string, err error) {
return syscall.Getwd()
}
func Chdir(path string) error {
return syscall.Chdir(path)
}

23
vendor/golang.org/x/sys/plan9/pwd_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.5
package plan9
func fixwd() {
}
func Getwd() (wd string, err error) {
fd, err := open(".", O_RDONLY)
if err != nil {
return "", err
}
defer Close(fd)
return Fd2path(fd)
}
func Chdir(path string) error {
return chdir(path)
}

30
vendor/golang.org/x/sys/plan9/race.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build plan9 && race
package plan9
import (
"runtime"
"unsafe"
)
const raceenabled = true
func raceAcquire(addr unsafe.Pointer) {
runtime.RaceAcquire(addr)
}
func raceReleaseMerge(addr unsafe.Pointer) {
runtime.RaceReleaseMerge(addr)
}
func raceReadRange(addr unsafe.Pointer, len int) {
runtime.RaceReadRange(addr, len)
}
func raceWriteRange(addr unsafe.Pointer, len int) {
runtime.RaceWriteRange(addr, len)
}

25
vendor/golang.org/x/sys/plan9/race0.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build plan9 && !race
package plan9
import (
"unsafe"
)
const raceenabled = false
func raceAcquire(addr unsafe.Pointer) {
}
func raceReleaseMerge(addr unsafe.Pointer) {
}
func raceReadRange(addr unsafe.Pointer, len int) {
}
func raceWriteRange(addr unsafe.Pointer, len int) {
}

22
vendor/golang.org/x/sys/plan9/str.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build plan9
package plan9
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
if val < 0 {
return "-" + itoa(-val)
}
var buf [32]byte // big enough for int64
i := len(buf) - 1
for val >= 10 {
buf[i] = byte(val%10 + '0')
i--
val /= 10
}
buf[i] = byte(val + '0')
return string(buf[i:])
}

109
vendor/golang.org/x/sys/plan9/syscall.go generated vendored Normal file
View File

@@ -0,0 +1,109 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build plan9
// Package plan9 contains an interface to the low-level operating system
// primitives. OS details vary depending on the underlying system, and
// by default, godoc will display the OS-specific documentation for the current
// system. If you want godoc to display documentation for another
// system, set $GOOS and $GOARCH to the desired system. For example, if
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
// to freebsd and $GOARCH to arm.
//
// The primary use of this package is inside other packages that provide a more
// portable interface to the system, such as "os", "time" and "net". Use
// those packages rather than this one if you can.
//
// For details of the functions and data types in this package consult
// the manuals for the appropriate operating system.
//
// These calls return err == nil to indicate success; otherwise
// err represents an operating system error describing the failure and
// holds a value of type syscall.ErrorString.
package plan9 // import "golang.org/x/sys/plan9"
import (
"bytes"
"strings"
"unsafe"
)
// ByteSliceFromString returns a NUL-terminated slice of bytes
// containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func ByteSliceFromString(s string) ([]byte, error) {
if strings.IndexByte(s, 0) != -1 {
return nil, EINVAL
}
a := make([]byte, len(s)+1)
copy(a, s)
return a, nil
}
// BytePtrFromString returns a pointer to a NUL-terminated array of
// bytes containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func BytePtrFromString(s string) (*byte, error) {
a, err := ByteSliceFromString(s)
if err != nil {
return nil, err
}
return &a[0], nil
}
// ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any
// bytes after the NUL removed.
func ByteSliceToString(s []byte) string {
if i := bytes.IndexByte(s, 0); i != -1 {
s = s[:i]
}
return string(s)
}
// BytePtrToString takes a pointer to a sequence of text and returns the corresponding string.
// If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated
// at a zero byte; if the zero byte is not present, the program may crash.
func BytePtrToString(p *byte) string {
if p == nil {
return ""
}
if *p == 0 {
return ""
}
// Find NUL terminator.
n := 0
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + 1)
}
return string(unsafe.Slice(p, n))
}
// Single-word zero for use when we need a valid pointer to 0 bytes.
// See mksyscall.pl.
var _zero uintptr
func (ts *Timespec) Unix() (sec int64, nsec int64) {
return int64(ts.Sec), int64(ts.Nsec)
}
func (tv *Timeval) Unix() (sec int64, nsec int64) {
return int64(tv.Sec), int64(tv.Usec) * 1000
}
func (ts *Timespec) Nano() int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
}
func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
//
//go:noescape
func use(p unsafe.Pointer)

361
vendor/golang.org/x/sys/plan9/syscall_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,361 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Plan 9 system calls.
// This file is compiled as ordinary Go code,
// but it is also input to mksyscall,
// which parses the //sys lines and generates system call stubs.
// Note that sometimes we use a lowercase //sys name and
// wrap it in our own nicer implementation.
package plan9
import (
"bytes"
"syscall"
"unsafe"
)
// A Note is a string describing a process note.
// It implements the os.Signal interface.
type Note string
func (n Note) Signal() {}
func (n Note) String() string {
return string(n)
}
var (
Stdin = 0
Stdout = 1
Stderr = 2
)
// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func atoi(b []byte) (n uint) {
n = 0
for i := 0; i < len(b); i++ {
n = n*10 + uint(b[i]-'0')
}
return
}
func cstring(s []byte) string {
i := bytes.IndexByte(s, 0)
if i == -1 {
i = len(s)
}
return string(s[:i])
}
func errstr() string {
var buf [ERRMAX]byte
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
buf[len(buf)-1] = 0
return cstring(buf[:])
}
// Implemented in assembly to import from runtime.
func exit(code int)
func Exit(code int) { exit(code) }
func readnum(path string) (uint, error) {
var b [12]byte
fd, e := Open(path, O_RDONLY)
if e != nil {
return 0, e
}
defer Close(fd)
n, e := Pread(fd, b[:], 0)
if e != nil {
return 0, e
}
m := 0
for ; m < n && b[m] == ' '; m++ {
}
return atoi(b[m : n-1]), nil
}
func Getpid() (pid int) {
n, _ := readnum("#c/pid")
return int(n)
}
func Getppid() (ppid int) {
n, _ := readnum("#c/ppid")
return int(n)
}
func Read(fd int, p []byte) (n int, err error) {
return Pread(fd, p, -1)
}
func Write(fd int, p []byte) (n int, err error) {
return Pwrite(fd, p, -1)
}
var ioSync int64
//sys fd2path(fd int, buf []byte) (err error)
func Fd2path(fd int) (path string, err error) {
var buf [512]byte
e := fd2path(fd, buf[:])
if e != nil {
return "", e
}
return cstring(buf[:]), nil
}
//sys pipe(p *[2]int32) (err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return syscall.ErrorString("bad arg in system call")
}
var pp [2]int32
err = pipe(&pp)
if err == nil {
p[0] = int(pp[0])
p[1] = int(pp[1])
}
return
}
// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
newoffset, e := seek(0, fd, offset, whence)
if newoffset == -1 {
err = syscall.ErrorString(e)
}
return
}
func Mkdir(path string, mode uint32) (err error) {
fd, err := Create(path, O_RDONLY, DMDIR|mode)
if fd != -1 {
Close(fd)
}
return
}
type Waitmsg struct {
Pid int
Time [3]uint32
Msg string
}
func (w Waitmsg) Exited() bool { return true }
func (w Waitmsg) Signaled() bool { return false }
func (w Waitmsg) ExitStatus() int {
if len(w.Msg) == 0 {
// a normal exit returns no message
return 0
}
return 1
}
//sys await(s []byte) (n int, err error)
func Await(w *Waitmsg) (err error) {
var buf [512]byte
var f [5][]byte
n, err := await(buf[:])
if err != nil || w == nil {
return
}
nf := 0
p := 0
for i := 0; i < n && nf < len(f)-1; i++ {
if buf[i] == ' ' {
f[nf] = buf[p:i]
p = i + 1
nf++
}
}
f[nf] = buf[p:]
nf++
if nf != len(f) {
return syscall.ErrorString("invalid wait message")
}
w.Pid = int(atoi(f[0]))
w.Time[0] = uint32(atoi(f[1]))
w.Time[1] = uint32(atoi(f[2]))
w.Time[2] = uint32(atoi(f[3]))
w.Msg = cstring(f[4])
if w.Msg == "''" {
// await() returns '' for no error
w.Msg = ""
}
return
}
func Unmount(name, old string) (err error) {
fixwd()
oldp, err := BytePtrFromString(old)
if err != nil {
return err
}
oldptr := uintptr(unsafe.Pointer(oldp))
var r0 uintptr
var e syscall.ErrorString
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
if name == "" {
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
} else {
namep, err := BytePtrFromString(name)
if err != nil {
return err
}
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
}
if int32(r0) == -1 {
err = e
}
return
}
func Fchdir(fd int) (err error) {
path, err := Fd2path(fd)
if err != nil {
return
}
return Chdir(path)
}
type Timespec struct {
Sec int32
Nsec int32
}
type Timeval struct {
Sec int32
Usec int32
}
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
tv.Sec = int32(nsec / 1e9)
return
}
func nsec() int64 {
var scratch int64
r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
if r0 == 0 {
return scratch
}
return int64(r0)
}
func Gettimeofday(tv *Timeval) error {
nsec := nsec()
*tv = NsecToTimeval(nsec)
return nil
}
func Getpagesize() int { return 0x1000 }
func Getegid() (egid int) { return -1 }
func Geteuid() (euid int) { return -1 }
func Getgid() (gid int) { return -1 }
func Getuid() (uid int) { return -1 }
func Getgroups() (gids []int, err error) {
return make([]int, 0), nil
}
//sys open(path string, mode int) (fd int, err error)
func Open(path string, mode int) (fd int, err error) {
fixwd()
return open(path, mode)
}
//sys create(path string, mode int, perm uint32) (fd int, err error)
func Create(path string, mode int, perm uint32) (fd int, err error) {
fixwd()
return create(path, mode, perm)
}
//sys remove(path string) (err error)
func Remove(path string) error {
fixwd()
return remove(path)
}
//sys stat(path string, edir []byte) (n int, err error)
func Stat(path string, edir []byte) (n int, err error) {
fixwd()
return stat(path, edir)
}
//sys bind(name string, old string, flag int) (err error)
func Bind(name string, old string, flag int) (err error) {
fixwd()
return bind(name, old, flag)
}
//sys mount(fd int, afd int, old string, flag int, aname string) (err error)
func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
fixwd()
return mount(fd, afd, old, flag, aname)
}
//sys wstat(path string, edir []byte) (err error)
func Wstat(path string, edir []byte) (err error) {
fixwd()
return wstat(path, edir)
}
//sys chdir(path string) (err error)
//sys Dup(oldfd int, newfd int) (fd int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//sys Close(fd int) (err error)
//sys Fstat(fd int, edir []byte) (n int, err error)
//sys Fwstat(fd int, edir []byte) (err error)

284
vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go generated vendored Normal file
View File

@@ -0,0 +1,284 @@
// go run mksyscall.go -l32 -plan9 -tags plan9,386 syscall_plan9.go
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && 386
package plan9
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pipe(p *[2]int32) (err error) {
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func await(s []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(s) > 0 {
_p0 = unsafe.Pointer(&s[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func open(path string, mode int) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func create(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func remove(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func stat(path string, edir []byte) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func bind(name string, old string, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func mount(fd int, afd int, old string, flag int, aname string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func wstat(path string, edir []byte) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup(oldfd int, newfd int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Close(fd int) (err error) {
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fwstat(fd int, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}

284
vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go generated vendored Normal file
View File

@@ -0,0 +1,284 @@
// go run mksyscall.go -l32 -plan9 -tags plan9,amd64 syscall_plan9.go
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && amd64
package plan9
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pipe(p *[2]int32) (err error) {
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func await(s []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(s) > 0 {
_p0 = unsafe.Pointer(&s[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func open(path string, mode int) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func create(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func remove(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func stat(path string, edir []byte) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func bind(name string, old string, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func mount(fd int, afd int, old string, flag int, aname string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func wstat(path string, edir []byte) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup(oldfd int, newfd int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Close(fd int) (err error) {
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fwstat(fd int, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}

284
vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go generated vendored Normal file
View File

@@ -0,0 +1,284 @@
// go run mksyscall.go -l32 -plan9 -tags plan9,arm syscall_plan9.go
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && arm
package plan9
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pipe(p *[2]int32) (err error) {
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func await(s []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(s) > 0 {
_p0 = unsafe.Pointer(&s[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func open(path string, mode int) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func create(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func remove(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func stat(path string, edir []byte) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func bind(name string, old string, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func mount(fd int, afd int, old string, flag int, aname string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func wstat(path string, edir []byte) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup(oldfd int, newfd int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Close(fd int) (err error) {
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fwstat(fd int, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}

49
vendor/golang.org/x/sys/plan9/zsysnum_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,49 @@
// mksysnum_plan9.sh /opt/plan9/sys/src/libc/9syscall/sys.h
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package plan9
const (
SYS_SYSR1 = 0
SYS_BIND = 2
SYS_CHDIR = 3
SYS_CLOSE = 4
SYS_DUP = 5
SYS_ALARM = 6
SYS_EXEC = 7
SYS_EXITS = 8
SYS_FAUTH = 10
SYS_SEGBRK = 12
SYS_OPEN = 14
SYS_OSEEK = 16
SYS_SLEEP = 17
SYS_RFORK = 19
SYS_PIPE = 21
SYS_CREATE = 22
SYS_FD2PATH = 23
SYS_BRK_ = 24
SYS_REMOVE = 25
SYS_NOTIFY = 28
SYS_NOTED = 29
SYS_SEGATTACH = 30
SYS_SEGDETACH = 31
SYS_SEGFREE = 32
SYS_SEGFLUSH = 33
SYS_RENDEZVOUS = 34
SYS_UNMOUNT = 35
SYS_SEMACQUIRE = 37
SYS_SEMRELEASE = 38
SYS_SEEK = 39
SYS_FVERSION = 40
SYS_ERRSTR = 41
SYS_STAT = 42
SYS_FSTAT = 43
SYS_WSTAT = 44
SYS_FWSTAT = 45
SYS_MOUNT = 46
SYS_AWAIT = 47
SYS_PREAD = 50
SYS_PWRITE = 51
SYS_TSEMACQUIRE = 52
SYS_NSEC = 53
)

2
vendor/golang.org/x/sys/unix/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
_obj/
unix.test

184
vendor/golang.org/x/sys/unix/README.md generated vendored Normal file
View File

@@ -0,0 +1,184 @@
# Building `sys/unix`
The sys/unix package provides access to the raw system call interface of the
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
Porting Go to a new architecture/OS combination or adding syscalls, types, or
constants to an existing architecture/OS pair requires some manual effort;
however, there are tools that automate much of the process.
## Build Systems
There are currently two ways we generate the necessary files. We are currently
migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.
### Old Build System (currently for `GOOS != "linux"`)
The old build system generates the Go files based on the C header files
present on your system. This means that files
for a given GOOS/GOARCH pair must be generated on a system with that OS and
architecture. This also means that the generated code can differ from system
to system, based on differences in the header files.
To avoid this, if you are using the old build system, only generate the Go
files on an installation with unmodified header files. It is also important to
keep track of which version of the OS the files were generated from (ex.
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
and have each OS upgrade correspond to a single change.
To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
your specific system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, go
### New Build System (currently for `GOOS == "linux"`)
The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
that on any platform that supports Docker, all the files using the new build
system can be generated at once, and generated files will not change based on
what the person running the scripts has installed on their computer.
The OS specific files for the new build system are located in the `${GOOS}`
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
the kernel or system library updates, modify the Dockerfile at
`${GOOS}/Dockerfile` to checkout the new release of the source.
To build all the files under the new build system, you must be on an amd64/Linux
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, go, docker
## Component files
This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
if you are using the new build system, the scripts/programs cannot be called normally.
They must be called from within the docker container.
### asm files
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
call dispatch. There are three entry points:
```
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
```
The first and second are the standard ones; they differ only in how many
arguments can be passed to the kernel. The third is for low-level use by the
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
let it know that a system call is running.
When porting Go to a new architecture/OS, this file must be implemented for
each GOOS/GOARCH pair.
### mksysnum
Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
for the old system). This program takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you may need to update the
parsing in mksysnum.
### mksyscall.go
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list `//sys` comments giving prototypes for ones that can be generated.
The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
prototype can be exported (capitalized) or not.
Adding a new syscall often just requires adding a new `//sys` function prototype
with the desired arguments and a capitalized name so it is exported. However, if
you want the interface to the syscall to be different, often one will make an
unexported `//sys` prototype, and then write a custom wrapper in
`syscall_${GOOS}.go`.
### types files
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
`types_${GOOS}.go` on the old system). This file includes standard C headers and
creates Go type aliases to the corresponding C types. The file is then fed
through godef to get the Go compatible definitions. Finally, the generated code
is fed though mkpost.go to format the code correctly and remove any hidden or
private identifiers. This cleaned-up code is written to
`ztypes_${GOOS}_${GOARCH}.go`.
The hardest part about preparing this file is figuring out which headers to
include and which symbols need to be `#define`d to get the actual data
structures that pass through to the kernel system calls. Some C libraries
preset alternate versions for binary compatibility and translate them on the
way in and out of system calls, but there is almost always a `#define` that can
get the real ones.
See `types_darwin.go` and `linux/types.go` for examples.
To add a new type, add in the necessary include statement at the top of the
file (if it is not already there) and add in a type alias line. Note that if
your type is significantly different on different architectures, you may need
some `#if/#elif` macros in your include statements.
### mkerrors.sh
This script is used to generate the system's various constants. This doesn't
just include the error numbers and error strings, but also the signal numbers
and a wide variety of miscellaneous constants. The constants come from the list
of include files in the `includes_${uname}` variable. A regex then picks out
the desired `#define` statements, and generates the corresponding Go constants.
The error numbers and strings are generated from `#include <errno.h>`, and the
signal numbers and strings are generated from `#include <signal.h>`. All of
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
`_errors.c`, which prints out all the constants.
To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants.
### internal/mkmerge
This program is used to extract duplicate const, func, and type declarations
from the generated architecture-specific files listed below, and merge these
into a common file for each OS.
The merge is performed in the following steps:
1. Construct the set of common code that is identical in all architecture-specific files.
2. Write this common code to the merged file.
3. Remove the common code from all architecture-specific files.
## Generated files
### `zerrors_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above).
### `zsyscall_${GOOS}_${GOARCH}.go`
A file containing all the generated syscalls for a specific GOOS and GOARCH.
Generated by `mksyscall.go` (see above).
### `zsysnum_${GOOS}_${GOARCH}.go`
A list of numeric constants for all the syscall number of the specific GOOS
and GOARCH. Generated by mksysnum (see above).
### `ztypes_${GOOS}_${GOARCH}.go`
A file containing Go types for passing into (or returning from) syscalls.
Generated by godefs and the types file (see above).

86
vendor/golang.org/x/sys/unix/affinity_linux.go generated vendored Normal file
View File

@@ -0,0 +1,86 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// CPU affinity functions
package unix
import (
"math/bits"
"unsafe"
)
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
// CPUSet represents a CPU affinity mask.
type CPUSet [cpuSetSize]cpuMask
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
if e != 0 {
return errnoErr(e)
}
return nil
}
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedGetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
}
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedSetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
}
// Zero clears the set s, so that it contains no CPUs.
func (s *CPUSet) Zero() {
for i := range s {
s[i] = 0
}
}
func cpuBitsIndex(cpu int) int {
return cpu / _NCPUBITS
}
func cpuBitsMask(cpu int) cpuMask {
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
}
// Set adds cpu to the set s.
func (s *CPUSet) Set(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] |= cpuBitsMask(cpu)
}
}
// Clear removes cpu from the set s.
func (s *CPUSet) Clear(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] &^= cpuBitsMask(cpu)
}
}
// IsSet reports whether cpu is in the set s.
func (s *CPUSet) IsSet(cpu int) bool {
i := cpuBitsIndex(cpu)
if i < len(s) {
return s[i]&cpuBitsMask(cpu) != 0
}
return false
}
// Count returns the number of CPUs in the set s.
func (s *CPUSet) Count() int {
c := 0
for _, b := range s {
c += bits.OnesCount64(uint64(b))
}
return c
}

13
vendor/golang.org/x/sys/unix/aliases.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
import "syscall"
type Signal = syscall.Signal
type Errno = syscall.Errno
type SysProcAttr = syscall.SysProcAttr

17
vendor/golang.org/x/sys/unix/asm_aix_ppc64.s generated vendored Normal file
View File

@@ -0,0 +1,17 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
//
TEXT ·syscall6(SB),NOSPLIT,$0-88
JMP syscall·syscall6(SB)
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
JMP syscall·rawSyscall6(SB)

27
vendor/golang.org/x/sys/unix/asm_bsd_386.s generated vendored Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for 386 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

27
vendor/golang.org/x/sys/unix/asm_bsd_amd64.s generated vendored Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for AMD64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

27
vendor/golang.org/x/sys/unix/asm_bsd_arm.s generated vendored Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for ARM BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)

27
vendor/golang.org/x/sys/unix/asm_bsd_arm64.s generated vendored Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for ARM64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

29
vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s generated vendored Normal file
View File

@@ -0,0 +1,29 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
//
// System call support for ppc64, BSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

27
vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s generated vendored Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for RISCV64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

65
vendor/golang.org/x/sys/unix/asm_linux_386.s generated vendored Normal file
View File

@@ -0,0 +1,65 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for 386, Linux
//
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
// instead of the glibc-specific "CALL 0x10(GS)".
#define INVOKE_SYSCALL INT $0x80
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
CALL runtime·entersyscall(SB)
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
RET
TEXT ·socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
JMP syscall·rawsocketcall(SB)
TEXT ·seek(SB),NOSPLIT,$0-28
JMP syscall·seek(SB)

57
vendor/golang.org/x/sys/unix/asm_linux_amd64.s generated vendored Normal file
View File

@@ -0,0 +1,57 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for AMD64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
RET
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
JMP syscall·gettimeofday(SB)

56
vendor/golang.org/x/sys/unix/asm_linux_arm.s generated vendored Normal file
View File

@@ -0,0 +1,56 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for arm, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
BL runtime·entersyscall(SB)
MOVW trap+0(FP), R7
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
MOVW $0, R3
MOVW $0, R4
MOVW $0, R5
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW trap+0(FP), R7 // syscall entry
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
RET
TEXT ·seek(SB),NOSPLIT,$0-28
B syscall·seek(SB)

50
vendor/golang.org/x/sys/unix/asm_linux_arm64.s generated vendored Normal file
View File

@@ -0,0 +1,50 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && arm64 && gc
#include "textflag.h"
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP) // r1
MOVD R1, r2+40(FP) // r2
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP)
MOVD R1, r2+40(FP)
RET

51
vendor/golang.org/x/sys/unix/asm_linux_loong64.s generated vendored Normal file
View File

@@ -0,0 +1,51 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && loong64 && gc
#include "textflag.h"
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
JAL runtime·entersyscall(SB)
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R11 // syscall entry
SYSCALL
MOVV R4, r1+32(FP)
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R11 // syscall entry
SYSCALL
MOVV R4, r1+32(FP)
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
RET

54
vendor/golang.org/x/sys/unix/asm_linux_mips64x.s generated vendored Normal file
View File

@@ -0,0 +1,54 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (mips64 || mips64le) && gc
#include "textflag.h"
//
// System calls for mips64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
JAL runtime·entersyscall(SB)
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
RET

52
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s generated vendored Normal file
View File

@@ -0,0 +1,52 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (mips || mipsle) && gc
#include "textflag.h"
//
// System calls for mips, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
JAL runtime·entersyscall(SB)
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW R0, R7
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP) // r1
MOVW R3, r2+20(FP) // r2
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP)
MOVW R3, r2+20(FP)
RET

42
vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s generated vendored Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (ppc64 || ppc64le) && gc
#include "textflag.h"
//
// System calls for ppc64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
RET

47
vendor/golang.org/x/sys/unix/asm_linux_riscv64.s generated vendored Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build riscv64 && gc
#include "textflag.h"
//
// System calls for linux/riscv64.
//
// Where available, just jump to package syscall's implementation of
// these functions.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP) // r1
MOV A1, r2+40(FP) // r2
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP)
MOV A1, r2+40(FP)
RET

54
vendor/golang.org/x/sys/unix/asm_linux_s390x.s generated vendored Normal file
View File

@@ -0,0 +1,54 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && s390x && gc
#include "textflag.h"
//
// System calls for s390x, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
BR syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
RET

29
vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s generated vendored Normal file
View File

@@ -0,0 +1,29 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System call support for mips64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

Some files were not shown because too many files have changed in this diff Show More