-
Notifications
You must be signed in to change notification settings - Fork 394
/
seq.go
119 lines (105 loc) · 2.66 KB
/
seq.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright 2013-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Print a sequence of numbers.
//
// Synopsis:
// seq [-f FORMAT] [-w] [-s SEPARATOR] [START [STEP [END]]]
//
// Examples:
// % seq -s=' ' 3
// 1 2 3
// % seq -s=' ' 2 4
// 2 3 4
// % seq -s=' ' 3 2 7
// 3 5 7
//
// Options:
// -f: use printf style floating-point FORMAT (default: %v)
// -s: use STRING to separate numbers (default: \n)
// -w: equalize width by padding with leading zeroes (default: false)
package main
import (
"errors"
"flag"
"fmt"
"io"
"log"
"os"
"strings"
)
var (
flags struct {
format string
separator string
widthEqual bool
}
cmd = "seq [-f format] [-w] [-s separator] [start [step [end]]]"
)
func init() {
defUsage := flag.Usage
flag.Usage = func() {
os.Args[0] = cmd
defUsage()
}
flag.StringVar(&flags.format, "f", "%v", "use printf style floating-point FORMAT")
flag.StringVar(&flags.separator, "s", "\n", "use STRING to separate numbers")
flag.BoolVar(&flags.widthEqual, "w", false, "equalize width by padding with leading zeroes")
}
func seq(w io.Writer, args []string) error {
var (
stt = 1.0
stp = 1.0
end float64
width int
)
format := flags.format // I use that because I'll modify a global variable
argv, argc := args, len(args)
if argc < 1 || argc > 4 {
return fmt.Errorf("mismatch n args; got %v, wants 1 >= n args >= 3", argc)
}
// loading step value if args is <start> <step> <end>
if argc == 3 {
_, err := fmt.Sscanf(argv[1], "%v", &stp)
if stp-float64(int(stp)) > 0 && format == "%v" {
d := len(fmt.Sprintf("%v", stp-float64(int(stp)))) - 2 // get the nums of y.xx decimal part
format = fmt.Sprintf("%%.%df", d)
}
if stp == 0.0 {
return errors.New("step value should be != 0")
}
if err != nil {
return err
}
}
if argc >= 2 { // cases: start + end || start + step + end
if _, err := fmt.Sscanf(argv[0]+" "+argv[argc-1], "%v %v", &stt, &end); err != nil {
return err
}
} else { // only <end>
if _, err := fmt.Sscanf(argv[0], "%v", &end); err != nil {
return err
}
}
format = strings.Replace(format, "%", "%0*", 1) // support widthEqual
if flags.widthEqual {
width = len(fmt.Sprintf(format, 0, end))
}
defer fmt.Fprint(w, "\n") // last char is always '\n'
for stt <= end {
fmt.Fprintf(w, format, width, stt)
stt += stp
if stt <= end { // print only between the values
fmt.Fprint(w, flags.separator)
}
}
return nil
}
func main() {
flag.Parse()
if err := seq(os.Stdout, flag.Args()); err != nil {
log.Println(err)
flag.Usage()
os.Exit(1)
}
}