-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
167 lines (146 loc) · 3.26 KB
/
main.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package main
import (
"bufio"
"fmt"
"os"
"github.com/jiro4989/ponpe/unicode"
)
type (
ErrorCode int
)
const (
errorCodeOk ErrorCode = iota
errorCodeFailedBinding
errorCodeFailedReadingStdin
errorCodeIllegalAlphabet
errorCodeIllegalConverter
errorCodeIllegalCommand
)
func main() {
opts, err := ParseArgs()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
return
}
os.Exit(int(Main(opts)))
}
func Main(opts *CmdArgs) ErrorCode {
if opts.Version {
fmt.Println(Version)
return errorCodeOk
}
if opts.List != "" {
return cmdList(opts)
}
// 引数未指定の時は ponponpain が自動的に設定される
if len(opts.Args) < 2 {
opts.Args = []string{"ponponpain", "haraita-i"}
}
return cmdJoin(opts)
}
// cmdJoin は2つの入力を結合し、標準出力に出す。
// 引数が'-'という指定のときは、その位置に標準入力から受け取った文字列を埋め込む
// 。'-'指定が存在しないときは標準入力を受け付けない。
func cmdJoin(opts *CmdArgs) ErrorCode {
if err := setStdinToArgs(opts); err != nil {
fmt.Fprintln(os.Stderr, err)
return errorCodeFailedReadingStdin
}
var word []rune
var marks [][]rune
for _, orgMark := range opts.Args[1:] {
// 結合文字に変換可能かチェック
mark := []rune(orgMark)
if err := unicode.ValidateCombindingCharacterMap(mark); err != nil {
fmt.Fprintln(os.Stderr, err)
return errorCodeIllegalAlphabet
}
// 結合文字に変換
mark = unicode.ToCombindingCharacterMap(mark)
// 結合先の文字よりも、結合文字が多くてはならない
w, m := deleteOverSize([]rune(opts.Args[0]), mark)
// wordは常に1つのため上書きで良い
word = w
marks = append(marks, m)
}
// 結合して出力
s := joinWords(word, marks...)
fmt.Println(s)
return errorCodeOk
}
// setStdinToArgs は標準入力を受け取る指定があるときだけハイフンの引数の位置に標
// 準入力を埋め込む。
func setStdinToArgs(opts *CmdArgs) error {
if hasStdinArgs(opts.Args) {
stdinStr, err := readStdin()
if err != nil {
return err
}
// 受け取った標準入力で上書き
if opts.Args[0] == "-" {
opts.Args[0] = stdinStr
}
for i := 1; i < len(opts.Args); i++ {
if opts.Args[i] == "-" {
opts.Args[i] = stdinStr
}
}
}
return nil
}
func hasStdinArgs(args []string) bool {
ws := args
for _, w := range ws {
if w == "-" {
return true
}
}
return false
}
func readStdin() (string, error) {
sc := bufio.NewScanner(os.Stdin)
var s string
for sc.Scan() {
s = sc.Text()
break
}
if err := sc.Err(); err != nil {
return "", err
}
return s, nil
}
func deleteOverSize(w, m []rune) ([]rune, []rune) {
if len(w) < len(m) {
m = m[:len(w)]
}
return w, m
}
func joinWords(w []rune, m ...[]rune) string {
if len(m) < 1 {
return string(w)
}
var s string
for i := 0; i < len(w); i++ {
s += string(w[i])
for _, mm := range m {
if len(mm) <= i {
continue
}
m := mm[i]
if m == ' ' {
continue
}
s += string(m)
}
}
return s
}
func cmdList(opts *CmdArgs) ErrorCode {
converter := categories[opts.List]
for k, v := range converter {
w, j := string(k), string(v)
s := fmt.Sprintf("%s %s %d u%.4x", w, j, v, v)
fmt.Println(s)
}
return errorCodeOk
}