github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqlparse/tidbparser/dependency/util/format/format.go (about) 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 5 // Copyright 2015 PingCAP, Inc. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package format 19 20 import ( 21 "bytes" 22 "fmt" 23 "io" 24 ) 25 26 const ( 27 st0 = iota 28 stBOL 29 stPERC 30 stBOLPERC 31 ) 32 33 // Formatter is an io.Writer extended formatter by a fmt.Printf like function Format. 34 type Formatter interface { 35 io.Writer 36 Format(format string, args ...interface{}) (n int, errno error) 37 } 38 39 type indentFormatter struct { 40 io.Writer 41 indent []byte 42 indentLevel int 43 state int 44 } 45 46 var replace = map[rune]string{ 47 '\000': "\\0", 48 '\'': "''", 49 '\n': "\\n", 50 '\r': "\\r", 51 } 52 53 // IndentFormatter returns a new Formatter which interprets %i and %u in the 54 // Format() formats string as indent and unindent commands. The commands can 55 // nest. The Formatter writes to io.Writer 'w' and inserts one 'indent' 56 // string per current indent level value. 57 // Behaviour of commands reaching negative indent levels is undefined. 58 // 59 // IndentFormatter(os.Stdout, "\t").Format("abc%d%%e%i\nx\ny\n%uz\n", 3) 60 // 61 // output: 62 // 63 // abc3%e 64 // x 65 // y 66 // z 67 // 68 // The Go quoted string literal form of the above is: 69 // 70 // "abc%%e\n\tx\n\tx\nz\n" 71 // 72 // The commands can be scattered between separate invocations of Format(), 73 // i.e. the formatter keeps track of the indent level and knows if it is 74 // positioned on start of a line and should emit indentation(s). 75 // The same output as above can be produced by e.g.: 76 // 77 // f := IndentFormatter(os.Stdout, " ") 78 // f.Format("abc%d%%e%i\nx\n", 3) 79 // f.Format("y\n%uz\n") 80 func IndentFormatter(w io.Writer, indent string) Formatter { 81 return &indentFormatter{w, []byte(indent), 0, stBOL} 82 } 83 84 func (f *indentFormatter) format(flat bool, format string, args ...interface{}) (n int, errno error) { 85 buf := make([]byte, 0) 86 for i := 0; i < len(format); i++ { 87 c := format[i] 88 switch f.state { 89 case st0: 90 switch c { 91 case '\n': 92 cc := c 93 if flat && f.indentLevel != 0 { 94 cc = ' ' 95 } 96 buf = append(buf, cc) 97 f.state = stBOL 98 case '%': 99 f.state = stPERC 100 default: 101 buf = append(buf, c) 102 } 103 case stBOL: 104 switch c { 105 case '\n': 106 cc := c 107 if flat && f.indentLevel != 0 { 108 cc = ' ' 109 } 110 buf = append(buf, cc) 111 case '%': 112 f.state = stBOLPERC 113 default: 114 if !flat { 115 for i := 0; i < f.indentLevel; i++ { 116 buf = append(buf, f.indent...) 117 } 118 } 119 buf = append(buf, c) 120 f.state = st0 121 } 122 case stBOLPERC: 123 switch c { 124 case 'i': 125 f.indentLevel++ 126 f.state = stBOL 127 case 'u': 128 f.indentLevel-- 129 f.state = stBOL 130 default: 131 if !flat { 132 for i := 0; i < f.indentLevel; i++ { 133 buf = append(buf, f.indent...) 134 } 135 } 136 buf = append(buf, '%', c) 137 f.state = st0 138 } 139 case stPERC: 140 switch c { 141 case 'i': 142 f.indentLevel++ 143 f.state = st0 144 case 'u': 145 f.indentLevel-- 146 f.state = st0 147 default: 148 buf = append(buf, '%', c) 149 f.state = st0 150 } 151 default: 152 panic("unexpected state") 153 } 154 } 155 switch f.state { 156 case stPERC, stBOLPERC: 157 buf = append(buf, '%') 158 } 159 return f.Write([]byte(fmt.Sprintf(string(buf), args...))) 160 } 161 162 // Format implements Format interface. 163 func (f *indentFormatter) Format(format string, args ...interface{}) (n int, errno error) { 164 return f.format(false, format, args...) 165 } 166 167 type flatFormatter indentFormatter 168 169 // FlatFormatter returns a newly created Formatter with the same functionality as the one returned 170 // by IndentFormatter except it allows a newline in the 'format' string argument of Format 171 // to pass through if the indent level is current zero. 172 // 173 // If the indent level is non-zero then such new lines are changed to a space character. 174 // There is no indent string, the %i and %u format verbs are used solely to determine the indent level. 175 // 176 // The FlatFormatter is intended for flattening of normally nested structure textual representation to 177 // a one top level structure per line form. 178 // 179 // FlatFormatter(os.Stdout, " ").Format("abc%d%%e%i\nx\ny\n%uz\n", 3) 180 // 181 // output in the form of a Go quoted string literal: 182 // 183 // "abc3%%e x y z\n" 184 func FlatFormatter(w io.Writer) Formatter { 185 return (*flatFormatter)(IndentFormatter(w, "").(*indentFormatter)) 186 } 187 188 // Format implements Format interface. 189 func (f *flatFormatter) Format(format string, args ...interface{}) (n int, errno error) { 190 return (*indentFormatter)(f).format(true, format, args...) 191 } 192 193 // OutputFormat output escape character with backslash. 194 func OutputFormat(s string) string { 195 var buf bytes.Buffer 196 for _, old := range s { 197 if newVal, ok := replace[old]; ok { 198 buf.WriteString(newVal) 199 continue 200 } 201 buf.WriteRune(old) 202 } 203 204 return buf.String() 205 }