format.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Copyright (c) 2014 The sortutil Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSES/STRUTIL-LICENSE file.
  4. // Copyright 2015 PingCAP, Inc.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License");
  7. // you may not use this file except in compliance with the License.
  8. // You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. package format
  17. import (
  18. "bytes"
  19. "fmt"
  20. "io"
  21. "strings"
  22. )
  23. const (
  24. st0 = iota
  25. stBOL
  26. stPERC
  27. stBOLPERC
  28. )
  29. // Formatter is an io.Writer extended formatter by a fmt.Printf like function Format.
  30. type Formatter interface {
  31. io.Writer
  32. Format(format string, args ...interface{}) (n int, errno error)
  33. }
  34. type indentFormatter struct {
  35. io.Writer
  36. indent []byte
  37. indentLevel int
  38. state int
  39. }
  40. var replace = map[rune]string{
  41. '\000': "\\0",
  42. '\'': "''",
  43. '\n': "\\n",
  44. '\r': "\\r",
  45. }
  46. // IndentFormatter returns a new Formatter which interprets %i and %u in the
  47. // Format() formats string as indent and unindent commands. The commands can
  48. // nest. The Formatter writes to io.Writer 'w' and inserts one 'indent'
  49. // string per current indent level value.
  50. // Behaviour of commands reaching negative indent levels is undefined.
  51. // IndentFormatter(os.Stdout, "\t").Format("abc%d%%e%i\nx\ny\n%uz\n", 3)
  52. // output:
  53. // abc3%e
  54. // x
  55. // y
  56. // z
  57. // The Go quoted string literal form of the above is:
  58. // "abc%%e\n\tx\n\tx\nz\n"
  59. // The commands can be scattered between separate invocations of Format(),
  60. // i.e. the formatter keeps track of the indent level and knows if it is
  61. // positioned on start of a line and should emit indentation(s).
  62. // The same output as above can be produced by e.g.:
  63. // f := IndentFormatter(os.Stdout, " ")
  64. // f.Format("abc%d%%e%i\nx\n", 3)
  65. // f.Format("y\n%uz\n")
  66. func IndentFormatter(w io.Writer, indent string) Formatter {
  67. return &indentFormatter{w, []byte(indent), 0, stBOL}
  68. }
  69. func (f *indentFormatter) format(flat bool, format string, args ...interface{}) (n int, errno error) {
  70. var buf = make([]byte, 0)
  71. for i := 0; i < len(format); i++ {
  72. c := format[i]
  73. switch f.state {
  74. case st0:
  75. switch c {
  76. case '\n':
  77. cc := c
  78. if flat && f.indentLevel != 0 {
  79. cc = ' '
  80. }
  81. buf = append(buf, cc)
  82. f.state = stBOL
  83. case '%':
  84. f.state = stPERC
  85. default:
  86. buf = append(buf, c)
  87. }
  88. case stBOL:
  89. switch c {
  90. case '\n':
  91. cc := c
  92. if flat && f.indentLevel != 0 {
  93. cc = ' '
  94. }
  95. buf = append(buf, cc)
  96. case '%':
  97. f.state = stBOLPERC
  98. default:
  99. if !flat {
  100. for i := 0; i < f.indentLevel; i++ {
  101. buf = append(buf, f.indent...)
  102. }
  103. }
  104. buf = append(buf, c)
  105. f.state = st0
  106. }
  107. case stBOLPERC:
  108. switch c {
  109. case 'i':
  110. f.indentLevel++
  111. f.state = stBOL
  112. case 'u':
  113. f.indentLevel--
  114. f.state = stBOL
  115. default:
  116. if !flat {
  117. for i := 0; i < f.indentLevel; i++ {
  118. buf = append(buf, f.indent...)
  119. }
  120. }
  121. buf = append(buf, '%', c)
  122. f.state = st0
  123. }
  124. case stPERC:
  125. switch c {
  126. case 'i':
  127. f.indentLevel++
  128. f.state = st0
  129. case 'u':
  130. f.indentLevel--
  131. f.state = st0
  132. default:
  133. buf = append(buf, '%', c)
  134. f.state = st0
  135. }
  136. default:
  137. panic("unexpected state")
  138. }
  139. }
  140. switch f.state {
  141. case stPERC, stBOLPERC:
  142. buf = append(buf, '%')
  143. }
  144. return f.Write([]byte(fmt.Sprintf(string(buf), args...)))
  145. }
  146. // Format implements Format interface.
  147. func (f *indentFormatter) Format(format string, args ...interface{}) (n int, errno error) {
  148. return f.format(false, format, args...)
  149. }
  150. type flatFormatter indentFormatter
  151. // FlatFormatter returns a newly created Formatter with the same functionality as the one returned
  152. // by IndentFormatter except it allows a newline in the 'format' string argument of Format
  153. // to pass through if the indent level is current zero.
  154. //
  155. // If the indent level is non-zero then such new lines are changed to a space character.
  156. // There is no indent string, the %i and %u format verbs are used solely to determine the indent level.
  157. //
  158. // The FlatFormatter is intended for flattening of normally nested structure textual representation to
  159. // a one top level structure per line form.
  160. // FlatFormatter(os.Stdout, " ").Format("abc%d%%e%i\nx\ny\n%uz\n", 3)
  161. // output in the form of a Go quoted string literal:
  162. // "abc3%%e x y z\n"
  163. func FlatFormatter(w io.Writer) Formatter {
  164. return (*flatFormatter)(IndentFormatter(w, "").(*indentFormatter))
  165. }
  166. // Format implements Format interface.
  167. func (f *flatFormatter) Format(format string, args ...interface{}) (n int, errno error) {
  168. return (*indentFormatter)(f).format(true, format, args...)
  169. }
  170. // OutputFormat output escape character with backslash.
  171. func OutputFormat(s string) string {
  172. var buf bytes.Buffer
  173. for _, old := range s {
  174. if newVal, ok := replace[old]; ok {
  175. buf.WriteString(newVal)
  176. continue
  177. }
  178. buf.WriteRune(old)
  179. }
  180. return buf.String()
  181. }
  182. //RestoreFlag mark the Restore format
  183. type RestoreFlags uint64
  184. // Mutually exclusive group of `RestoreFlags`:
  185. // [RestoreStringSingleQuotes, RestoreStringDoubleQuotes]
  186. // [RestoreKeyWordUppercase, RestoreKeyWordLowercase]
  187. // [RestoreNameUppercase, RestoreNameLowercase]
  188. // [RestoreNameDoubleQuotes, RestoreNameBackQuotes]
  189. // The flag with the left position in each group has a higher priority.
  190. const (
  191. RestoreStringSingleQuotes RestoreFlags = 1 << iota
  192. RestoreStringDoubleQuotes
  193. RestoreStringEscapeBackslash
  194. RestoreKeyWordUppercase
  195. RestoreKeyWordLowercase
  196. RestoreNameUppercase
  197. RestoreNameLowercase
  198. RestoreNameDoubleQuotes
  199. RestoreNameBackQuotes
  200. RestoreSpacesAroundBinaryOperation
  201. RestoreStringWithoutCharset
  202. RestoreStringWithoutDefaultCharset
  203. )
  204. const (
  205. DefaultRestoreFlags = RestoreStringSingleQuotes | RestoreKeyWordUppercase | RestoreNameBackQuotes
  206. )
  207. func (rf RestoreFlags) has(flag RestoreFlags) bool {
  208. return rf&flag != 0
  209. }
  210. // HasStringSingleQuotesFlag returns a boolean indicating when `rf` has `RestoreStringSingleQuotes` flag.
  211. func (rf RestoreFlags) HasStringSingleQuotesFlag() bool {
  212. return rf.has(RestoreStringSingleQuotes)
  213. }
  214. // HasStringDoubleQuotesFlag returns a boolean indicating whether `rf` has `RestoreStringDoubleQuotes` flag.
  215. func (rf RestoreFlags) HasStringDoubleQuotesFlag() bool {
  216. return rf.has(RestoreStringDoubleQuotes)
  217. }
  218. // HasStringEscapeBackslashFlag returns a boolean indicating whether `rf` has `RestoreStringEscapeBackslash` flag.
  219. func (rf RestoreFlags) HasStringEscapeBackslashFlag() bool {
  220. return rf.has(RestoreStringEscapeBackslash)
  221. }
  222. // HasKeyWordUppercaseFlag returns a boolean indicating whether `rf` has `RestoreKeyWordUppercase` flag.
  223. func (rf RestoreFlags) HasKeyWordUppercaseFlag() bool {
  224. return rf.has(RestoreKeyWordUppercase)
  225. }
  226. // HasKeyWordLowercaseFlag returns a boolean indicating whether `rf` has `RestoreKeyWordLowercase` flag.
  227. func (rf RestoreFlags) HasKeyWordLowercaseFlag() bool {
  228. return rf.has(RestoreKeyWordLowercase)
  229. }
  230. // HasNameUppercaseFlag returns a boolean indicating whether `rf` has `RestoreNameUppercase` flag.
  231. func (rf RestoreFlags) HasNameUppercaseFlag() bool {
  232. return rf.has(RestoreNameUppercase)
  233. }
  234. // HasNameLowercaseFlag returns a boolean indicating whether `rf` has `RestoreNameLowercase` flag.
  235. func (rf RestoreFlags) HasNameLowercaseFlag() bool {
  236. return rf.has(RestoreNameLowercase)
  237. }
  238. // HasNameDoubleQuotesFlag returns a boolean indicating whether `rf` has `RestoreNameDoubleQuotes` flag.
  239. func (rf RestoreFlags) HasNameDoubleQuotesFlag() bool {
  240. return rf.has(RestoreNameDoubleQuotes)
  241. }
  242. // HasNameBackQuotesFlag returns a boolean indicating whether `rf` has `RestoreNameBackQuotes` flag.
  243. func (rf RestoreFlags) HasNameBackQuotesFlag() bool {
  244. return rf.has(RestoreNameBackQuotes)
  245. }
  246. // HasSpacesAroundBinaryOperationFlag returns a boolean indicating whether `rf` has `RestoreSpacesAroundBinaryOperation` flag.
  247. func (rf RestoreFlags) HasSpacesAroundBinaryOperationFlag() bool {
  248. return rf.has(RestoreSpacesAroundBinaryOperation)
  249. }
  250. func (rf RestoreFlags) HasStringWithoutDefaultCharset() bool {
  251. return rf.has(RestoreStringWithoutDefaultCharset)
  252. }
  253. func (rf RestoreFlags) HasStringWithoutCharset() bool {
  254. return rf.has(RestoreStringWithoutCharset)
  255. }
  256. // RestoreCtx is `Restore` context to hold flags and writer.
  257. type RestoreCtx struct {
  258. Flags RestoreFlags
  259. In io.Writer
  260. DefaultDB string
  261. }
  262. // NewRestoreCtx returns a new `RestoreCtx`.
  263. func NewRestoreCtx(flags RestoreFlags, in io.Writer) *RestoreCtx {
  264. return &RestoreCtx{flags, in, ""}
  265. }
  266. // WriteKeyWord writes the `keyWord` into writer.
  267. // `keyWord` will be converted format(uppercase and lowercase for now) according to `RestoreFlags`.
  268. func (ctx *RestoreCtx) WriteKeyWord(keyWord string) {
  269. switch {
  270. case ctx.Flags.HasKeyWordUppercaseFlag():
  271. keyWord = strings.ToUpper(keyWord)
  272. case ctx.Flags.HasKeyWordLowercaseFlag():
  273. keyWord = strings.ToLower(keyWord)
  274. }
  275. fmt.Fprint(ctx.In, keyWord)
  276. }
  277. // WriteString writes the string into writer
  278. // `str` may be wrapped in quotes and escaped according to RestoreFlags.
  279. func (ctx *RestoreCtx) WriteString(str string) {
  280. if ctx.Flags.HasStringEscapeBackslashFlag() {
  281. str = strings.Replace(str, `\`, `\\`, -1)
  282. }
  283. quotes := ""
  284. switch {
  285. case ctx.Flags.HasStringSingleQuotesFlag():
  286. str = strings.Replace(str, `'`, `''`, -1)
  287. quotes = `'`
  288. case ctx.Flags.HasStringDoubleQuotesFlag():
  289. str = strings.Replace(str, `"`, `""`, -1)
  290. quotes = `"`
  291. }
  292. fmt.Fprint(ctx.In, quotes, str, quotes)
  293. }
  294. // WriteName writes the name into writer
  295. // `name` maybe wrapped in quotes and escaped according to RestoreFlags.
  296. func (ctx *RestoreCtx) WriteName(name string) {
  297. switch {
  298. case ctx.Flags.HasNameUppercaseFlag():
  299. name = strings.ToUpper(name)
  300. case ctx.Flags.HasNameLowercaseFlag():
  301. name = strings.ToLower(name)
  302. }
  303. quotes := ""
  304. switch {
  305. case ctx.Flags.HasNameDoubleQuotesFlag():
  306. name = strings.Replace(name, `"`, `""`, -1)
  307. quotes = `"`
  308. case ctx.Flags.HasNameBackQuotesFlag():
  309. name = strings.Replace(name, "`", "``", -1)
  310. quotes = "`"
  311. }
  312. fmt.Fprint(ctx.In, quotes, name, quotes)
  313. }
  314. // WritePlain writes the plain text into writer without any handling.
  315. func (ctx *RestoreCtx) WritePlain(plainText string) {
  316. fmt.Fprint(ctx.In, plainText)
  317. }
  318. // WritePlainf write the plain text into writer without any handling.
  319. func (ctx *RestoreCtx) WritePlainf(format string, a ...interface{}) {
  320. fmt.Fprintf(ctx.In, format, a...)
  321. }