summaryrefslogtreecommitdiffhomepage
path: root/cmd
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-08-12 14:56:37 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-08-12 14:56:37 +0200
commit792b2bd299b611e378679e5a269cc249e079c60e (patch)
tree1c601d00398b79460a0f5694aad02536fec39897 /cmd
parent0003a3d51b2a7be791bf60b2cddaebb14dc65183 (diff)
Use a new mintage format
Diffstat (limited to 'cmd')
-rw-r--r--cmd/mfmt/main.go168
-rw-r--r--cmd/mfmt/main_test.go214
-rw-r--r--cmd/mfmt/util_test.go28
3 files changed, 203 insertions, 207 deletions
diff --git a/cmd/mfmt/main.go b/cmd/mfmt/main.go
index 263b258..7f7ec8b 100644
--- a/cmd/mfmt/main.go
+++ b/cmd/mfmt/main.go
@@ -1,25 +1,35 @@
+/* Simple formatter for mintage files. This is not perfect and doesn’t
+ check for syntactic correctness, it’s just to get stuff aligned
+ nicely. Maybe in the future I will construct a military-grade
+ formatter. */
+
package main
import (
+ "bufio"
"fmt"
"io"
"os"
"path/filepath"
- "unsafe"
+ "regexp"
+ "strings"
+)
- "git.thomasvoss.com/euro-cash.eu/lib/mintage"
+const (
+ ws = " \t"
+ longestNum = len("1.000.000.000")
)
-const cols = unsafe.Sizeof(mintage.Row{}.Cols) /
- unsafe.Sizeof(mintage.Row{}.Cols[0])
+var (
+ rv int
-var rv int
+ reMintageYear = regexp.MustCompile(`^\d{4}(-[^ \t]+)?`)
+ reMintageRow = regexp.MustCompile(`^(([0-9.]+|\?)[ \t]+)*([0-9.]+|\?)$`)
+)
func main() {
if len(os.Args) == 1 {
- if err := mfmt("-", os.Stdin, os.Stdout); err != nil {
- warn(err)
- }
+ mfmt("-", os.Stdin, os.Stdout)
}
for _, arg := range os.Args[1:] {
f, err := os.OpenFile(arg, os.O_RDWR, 0)
@@ -28,117 +38,70 @@ func main() {
continue
}
defer f.Close()
- if err := mfmt(arg, f, f); err != nil {
- warn(err)
- }
+ mfmt(arg, f, f)
}
os.Exit(rv)
}
-func mfmt(path string, in io.Reader, out io.Writer) error {
- data, err := mintage.Parse(in, path)
- if err != nil {
- return err
- }
-
- f, outfile := out.(*os.File)
- if outfile {
- _, err := f.Seek(0, io.SeekStart)
- if err != nil {
- return err
+func mfmt(file string, r io.Reader, w io.Writer) {
+ scanner := bufio.NewScanner(r)
+ for linenr := 1; scanner.Scan(); linenr++ {
+ line := strings.Trim(scanner.Text(), ws)
+
+ switch {
+ case len(line) == 0, line[0] == '#':
+ fmt.Fprintln(w, line)
+ case reMintageYear.MatchString(line):
+ fmtMintageYear(line, w)
+ case reMintageRow.MatchString(line):
+ fmtMintageRow(line, w)
+ default:
+ warn(fmt.Sprintf("%s:%d: potential syntax error", file, linenr))
+ fmt.Fprintln(w, line)
}
}
+}
- fmt.Fprintf(out, `BEGIN %d`, data.StartYear)
- for i, tbl := range data.Tables {
- if len(tbl) != 0 {
- var section string
- switch mintage.CoinType(i) {
- case mintage.TypeCirculated:
- section = "CIRC"
- case mintage.TypeNIFC:
- section = "BU"
- case mintage.TypeProof:
- section = "PROOF"
- }
- fmt.Fprintf(out, "\n\nBEGIN %s\n", section)
- formatSection(out, tbl)
- }
- }
- fmt.Fprintln(out, "")
-
- if outfile {
- if off, err := f.Seek(0, io.SeekCurrent); err != nil {
- return err
- } else if err = f.Truncate(off); err != nil {
- return err
- }
+func fmtMintageYear(line string, w io.Writer) {
+ switch i := strings.IndexAny(line, ws); i {
+ case -1:
+ fmt.Fprintln(w, line)
+ default:
+ fmt.Fprintf(w, "%s %s\n", line[:i], strings.TrimLeft(line[i:], ws))
}
- return nil
}
-func formatSection(out io.Writer, rows []mintage.Row) {
- var (
- longestMM int
- longestNum [cols]int
- )
+func fmtMintageRow(line string, w io.Writer) {
+ tokens := strings.FieldsFunc(line, func(r rune) bool {
+ return strings.ContainsRune(ws, r)
+ })
- for i, row := range rows {
- n := len(row.Mintmark)
- if n != 0 && i != 0 && row.Year != rows[i-1].Year {
- n++
- }
- longestMM = max(longestMM, n)
+ for i, tok := range tokens {
+ s := formatMintage(tok)
- for j, col := range row.Cols {
- n := intlen(col)
- longestNum[j] = max(longestNum[j], n+(n-1)/3)
+ if i == 0 {
+ fmt.Fprintf(w, "\t%*s", longestNum, s)
+ } else {
+ fmt.Fprintf(w, "%*s", longestNum+1, s)
}
}
- extraSpace := 0
- if longestMM != 0 {
- extraSpace = 2
- }
-
- for i, row := range rows {
- var label string
- if row.Mintmark != "" {
- if i != 0 && row.Year != rows[i-1].Year {
- label = row.Mintmark + "*: "
- } else {
- label = row.Mintmark + ": "
- }
- }
- fmt.Fprintf(out, "%-*s", longestMM+extraSpace, label)
- for j, n := range row.Cols {
- if j != 0 {
- fmt.Fprintf(out, " ")
- }
- fmt.Fprintf(out, "%*s", longestNum[j], formatInt(n))
- }
-
- if i != len(rows)-1 {
- fmt.Fprintln(out, "")
- }
- }
+ fmt.Fprintln(w)
}
-func formatInt(n int) string {
- if n <= mintage.Invalid {
- panic(fmt.Sprintf("invalid input %d", n))
- } else if n == mintage.Unknown {
- return "?"
+func formatMintage(s string) string {
+ if s == "?" {
+ return s
}
+ n := atoiWithDots(s)
digits := intlen(n)
dots := (digits - 1) / 3
out := make([]byte, digits+dots)
for i, j := len(out)-1, 0; ; i-- {
out[i] = byte(n%10) + 48
- n /= 10
- if n == 0 {
+ if n /= 10; n == 0 {
return string(out)
}
if j++; j == 3 {
@@ -150,9 +113,7 @@ func formatInt(n int) string {
func intlen(v int) int {
switch {
- case v <= mintage.Invalid:
- panic("mintage count is negative and not -1")
- case v == 0, v == mintage.Unknown:
+ case v == 0:
return 1
default:
n := 0
@@ -163,7 +124,18 @@ func intlen(v int) int {
}
}
-func warn(e error) {
+func atoiWithDots(s string) int {
+ n := 0
+ for _, ch := range s {
+ if ch == '.' {
+ continue
+ }
+ n = n*10 + int(ch) - '0'
+ }
+ return n
+}
+
+func warn(e any) {
fmt.Fprintf(os.Stderr, "%s: %s\n", filepath.Base(os.Args[0]), e)
rv = 1
}
diff --git a/cmd/mfmt/main_test.go b/cmd/mfmt/main_test.go
index 72e3665..7366ae0 100644
--- a/cmd/mfmt/main_test.go
+++ b/cmd/mfmt/main_test.go
@@ -6,103 +6,135 @@ import (
)
func runTest(t *testing.T, in, out string, nilErr bool) {
- r := bytes.NewReader([]byte(in))
- w := new(bytes.Buffer)
-
- err := mfmt("-", r, w)
- if nilErr && err != nil {
- t.Fatalf(`Expected err=nil; got "%s"`, err)
- } else if !nilErr && err == nil {
- t.Fatalf(`Expected err=Error; got nil`)
- }
-
- if nilErr && w.String() != out {
- t.Fatalf(`Expected w.String()="%s"; got "%s"`, out, w.String())
- }
-}
-
-func TestSpacing(t *testing.T) {
- in := `
- BEGIN 2002
- BEGIN CIRC
-
-
-378.383.000 326.439.000 217.031.000 441.621.000 203.388.000 169.088.000 223.544.000 196.438.000
-
-
- 10.817.950 118.526.000 ? 43.859.072 50.913.200 9.074.200 150.000 4.679.500
-`
- out := `BEGIN 2002
-
-BEGIN CIRC
-378.383.000 326.439.000 217.031.000 441.621.000 203.388.000 169.088.000 223.544.000 196.438.000
- 10.817.950 118.526.000 ? 43.859.072 50.913.200 9.074.200 150.000 4.679.500
-`
- runTest(t, in, out, true)
-}
-
-func TestAddDots(t *testing.T) {
- in := `BEGIN 2002
-
-BEGIN CIRC
-378383000 326439000 217031000 441621000 203388000 169088000 223544000 196438000
- 10817950 118526000 ? 43859072 50913200 9074200 150000 4679500
-`
- out := `BEGIN 2002
-
-BEGIN CIRC
-378.383.000 326.439.000 217.031.000 441.621.000 203.388.000 169.088.000 223.544.000 196.438.000
- 10.817.950 118.526.000 ? 43.859.072 50.913.200 9.074.200 150.000 4.679.500
-`
- runTest(t, in, out, true)
}
func TestComplete(t *testing.T) {
in := `
- BEGIN 2002
- BEGIN CIRC
-
-
-378383000 326439000 21703...1000 441621000 203388000 .1.6.9.0.8.8.0.0.0 223544000 196438000
-
-
- 10817950 118526000 ? 43859072 50913200 9074..200 150000 4679500
-
- BEGIN PROOF
-
-
-378383000 123456789 ..5 441621000 203388000 .1.6.9.0.8.8.0.0.0 223544000 196438000
-
-
- 10817950 118526000 ? 43859072 50913200 9074..200 150000 4679500
+2014
+60.000 60.000 860.000 860.000 860.000 340.000 511.843 360.000
+70.000 70.000 70.000 70.000 70.000 70.000 70.000 70.000
+3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000
+
+# Ref: https://example.com
+2015
+ 0 0 0 0 0 0 0 1.072.400
+40.000 40.000 40.000 40.000 40.000 40.000 40.000 40.000
+ ? ? ? ? ? ? ? ?
+
+2016
+ 0 0 0 0 0 0 2.339.200 0
+35.000 35.000 35.000 35.000 35.000 35.000 35.000 35.000
+ ? ? ? ? ? ? ? ?
+
+2017
+2.582.395 1.515.000 2.191.421 1.103.000 1.213.000 968.800 17.000 794.588
+22.000 22.000 22.000 22.000 22.000 22.000 22.000 22.000
+ ? ? ? ? ? ? ? ?
+
+2018
+2.430.000 2.550.000 1.800.000 980.000 1.014.000 890.000 0 868.000
+20.000 20.000 20.000 20.000 20.000 20.000 20.000 20.000
+ ? ? ? ? ? ? ? ?
+
+2019
+2.447.000 1.727.000 2.100.000 1.610.000 1.570.000 930.000 0 1.058.310
+15.000 15.000 15.000 15.000 15.000 15.000 15.000 15.000
+ ? ? ? ? ? ? ? ?
+
+2020
+ 0 0 0 860.000 175.000 740.000 0 1.500.000
+12.000 12.000 12.000 12.000 12.000 12.000 12.000 12.000
+ ? ? ? ? ? ? ? ?
+
+2021
+ 200.000 700.000 0 1.400.000 1.420.000 600.000 50.000 1.474.500
+10.500 10.500 10.500 10.500 10.500 10.500 10.500 10.500
+ ? ? ? ? ? ? ? ?
+
+2022
+ 700.000 450.000 400.000 700.000 700.000 380.000 0 1.708.000
+10.500 10.500 10.500 10.500 10.500 10.500 10.500 10.500
+ ? ? ? ? ? ? ? ?
+
+2023
+ 0 0 0 0 0 0 0 2.075.250
+10.500 10.500 10.500 10.500 10.500 10.500 10.500 10.500
+ ? ? ? ? ? ? ? ?
+
+2024
+ ? ? ? ? ? ? ? ?
+ ? ? ? ? ? ? ? ?
+ ? ? ? ? ? ? ? ?
+
+ 2014 "Council of Europe"
+ ? ? ?
`
- out := `BEGIN 2002
-
-BEGIN CIRC
-378.383.000 326.439.000 217.031.000 441.621.000 203.388.000 169.088.000 223.544.000 196.438.000
- 10.817.950 118.526.000 ? 43.859.072 50.913.200 9.074.200 150.000 4.679.500
-
-BEGIN PROOF
-378.383.000 123.456.789 5 441.621.000 203.388.000 169.088.000 223.544.000 196.438.000
- 10.817.950 118.526.000 ? 43.859.072 50.913.200 9.074.200 150.000 4.679.500
+ out := `
+2014
+ 60.000 60.000 860.000 860.000 860.000 340.000 511.843 360.000
+ 70.000 70.000 70.000 70.000 70.000 70.000 70.000 70.000
+ 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000
+
+# Ref: https://example.com
+2015
+ 0 0 0 0 0 0 0 1.072.400
+ 40.000 40.000 40.000 40.000 40.000 40.000 40.000 40.000
+ ? ? ? ? ? ? ? ?
+
+2016
+ 0 0 0 0 0 0 2.339.200 0
+ 35.000 35.000 35.000 35.000 35.000 35.000 35.000 35.000
+ ? ? ? ? ? ? ? ?
+
+2017
+ 2.582.395 1.515.000 2.191.421 1.103.000 1.213.000 968.800 17.000 794.588
+ 22.000 22.000 22.000 22.000 22.000 22.000 22.000 22.000
+ ? ? ? ? ? ? ? ?
+
+2018
+ 2.430.000 2.550.000 1.800.000 980.000 1.014.000 890.000 0 868.000
+ 20.000 20.000 20.000 20.000 20.000 20.000 20.000 20.000
+ ? ? ? ? ? ? ? ?
+
+2019
+ 2.447.000 1.727.000 2.100.000 1.610.000 1.570.000 930.000 0 1.058.310
+ 15.000 15.000 15.000 15.000 15.000 15.000 15.000 15.000
+ ? ? ? ? ? ? ? ?
+
+2020
+ 0 0 0 860.000 175.000 740.000 0 1.500.000
+ 12.000 12.000 12.000 12.000 12.000 12.000 12.000 12.000
+ ? ? ? ? ? ? ? ?
+
+2021
+ 200.000 700.000 0 1.400.000 1.420.000 600.000 50.000 1.474.500
+ 10.500 10.500 10.500 10.500 10.500 10.500 10.500 10.500
+ ? ? ? ? ? ? ? ?
+
+2022
+ 700.000 450.000 400.000 700.000 700.000 380.000 0 1.708.000
+ 10.500 10.500 10.500 10.500 10.500 10.500 10.500 10.500
+ ? ? ? ? ? ? ? ?
+
+2023
+ 0 0 0 0 0 0 0 2.075.250
+ 10.500 10.500 10.500 10.500 10.500 10.500 10.500 10.500
+ ? ? ? ? ? ? ? ?
+
+2024
+ ? ? ? ? ? ? ? ?
+ ? ? ? ? ? ? ? ?
+ ? ? ? ? ? ? ? ?
+
+2014 "Council of Europe"
+ ? ? ?
`
- runTest(t, in, out, true)
-}
-func TestLabelAlignment(t *testing.T) {
- in := `BEGIN 2002
-
-BEGIN CIRC
-378383000 326439000 217031000 441621000 203388000 169088000 223544000 196438000
-KNM*: 10817950 118526000 ? 43859072 50913200 9074200 150000 4679500
-MdP: 115.000.000 156.400.000 89.300.000 5.200.000 54.800.000 3.100.000 2.600.000 2.500.000
-`
- out := `BEGIN 2002
+ r := bytes.NewReader([]byte(in))
+ w := new(bytes.Buffer)
-BEGIN CIRC
- 378.383.000 326.439.000 217.031.000 441.621.000 203.388.000 169.088.000 223.544.000 196.438.000
-KNM*: 10.817.950 118.526.000 ? 43.859.072 50.913.200 9.074.200 150.000 4.679.500
-MdP: 115.000.000 156.400.000 89.300.000 5.200.000 54.800.000 3.100.000 2.600.000 2.500.000
-`
- runTest(t, in, out, true)
+ mfmt("-", r, w)
+ if w.String() != out {
+ t.Fatalf(`Expected w.String()="%s"; got "%s"`, out, w.String())
+ }
}
diff --git a/cmd/mfmt/util_test.go b/cmd/mfmt/util_test.go
index 1041e4f..8366a50 100644
--- a/cmd/mfmt/util_test.go
+++ b/cmd/mfmt/util_test.go
@@ -3,26 +3,19 @@
package main
-import (
- "testing"
-
- "git.thomasvoss.com/euro-cash.eu/lib/mintage"
-)
+import "testing"
func TestFormatInt(t *testing.T) {
- for _, x := range [...]struct {
- n int
- s string
- }{
- {0, "0"},
- {123, "123"},
- {81758, "81.758"},
- {752759237528, "752.759.237.528"},
- {mintage.Unknown, "?"},
+ for _, x := range [...]struct{ x, y string }{
+ {"?", "?"},
+ {"0", "0"},
+ {"123", "123"},
+ {"81758", "81.758"},
+ {"752759237528", "752.759.237.528"},
} {
- s := formatInt(x.n)
- if s != x.s {
- t.Fatalf(`Expected s="%s"; got "%s"`, x.s, s)
+ s := formatMintage(x.x)
+ if s != x.y {
+ t.Fatalf(`Expected s="%s"; got "%s"`, x.y, s)
}
}
}
@@ -33,7 +26,6 @@ func TestIntLen(t *testing.T) {
{123, len("123")},
{81758, len("81758")},
{752759237528, len("752759237528")},
- {mintage.Unknown, len("?")},
} {
n := intlen(x.x)
if n != x.y {