param.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. package terminfo
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "strconv"
  7. "strings"
  8. "sync"
  9. )
  10. // parametizer represents the a scan state for a parameterized string.
  11. type parametizer struct {
  12. // z is the string to parameterize
  13. z []byte
  14. // pos is the current position in s.
  15. pos int
  16. // nest is the current nest level.
  17. nest int
  18. // s is the variable stack.
  19. s stack
  20. // skipElse keeps the state of skipping else.
  21. skipElse bool
  22. // buf is the result buffer.
  23. buf *bytes.Buffer
  24. // params are the parameters to interpolate.
  25. params [9]interface{}
  26. // vars are dynamic variables.
  27. vars [26]interface{}
  28. }
  29. // staticVars are the static, global variables.
  30. var staticVars = struct {
  31. vars [26]interface{}
  32. sync.Mutex
  33. }{}
  34. var parametizerPool = sync.Pool{
  35. New: func() interface{} {
  36. p := new(parametizer)
  37. p.buf = bytes.NewBuffer(make([]byte, 0, 45))
  38. return p
  39. },
  40. }
  41. // newParametizer returns a new initialized parametizer from the pool.
  42. func newParametizer(z []byte) *parametizer {
  43. p := parametizerPool.Get().(*parametizer)
  44. p.z = z
  45. return p
  46. }
  47. // reset resets the parametizer.
  48. func (p *parametizer) reset() {
  49. p.pos, p.nest = 0, 0
  50. p.s.reset()
  51. p.buf.Reset()
  52. p.params, p.vars = [9]interface{}{}, [26]interface{}{}
  53. parametizerPool.Put(p)
  54. }
  55. // stateFn represents the state of the scanner as a function that returns the
  56. // next state.
  57. type stateFn func() stateFn
  58. // exec executes the parameterizer, interpolating the supplied parameters.
  59. func (p *parametizer) exec() string {
  60. for state := p.scanTextFn; state != nil; {
  61. state = state()
  62. }
  63. return p.buf.String()
  64. }
  65. // peek returns the next byte.
  66. func (p *parametizer) peek() (byte, error) {
  67. if p.pos >= len(p.z) {
  68. return 0, io.EOF
  69. }
  70. return p.z[p.pos], nil
  71. }
  72. // writeFrom writes the characters from ppos to pos to the buffer.
  73. func (p *parametizer) writeFrom(ppos int) {
  74. if p.pos > ppos {
  75. // append remaining characters.
  76. p.buf.Write(p.z[ppos:p.pos])
  77. }
  78. }
  79. func (p *parametizer) scanTextFn() stateFn {
  80. ppos := p.pos
  81. for {
  82. ch, err := p.peek()
  83. if err != nil {
  84. p.writeFrom(ppos)
  85. return nil
  86. }
  87. if ch == '%' {
  88. p.writeFrom(ppos)
  89. p.pos++
  90. return p.scanCodeFn
  91. }
  92. p.pos++
  93. }
  94. }
  95. func (p *parametizer) scanCodeFn() stateFn {
  96. ch, err := p.peek()
  97. if err != nil {
  98. return nil
  99. }
  100. switch ch {
  101. case '%':
  102. p.buf.WriteByte('%')
  103. case ':':
  104. // this character is used to avoid interpreting "%-" and "%+" as operators.
  105. // the next character is where the format really begins.
  106. p.pos++
  107. _, err = p.peek()
  108. if err != nil {
  109. return nil
  110. }
  111. return p.scanFormatFn
  112. case '#', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
  113. return p.scanFormatFn
  114. case 'o':
  115. p.buf.WriteString(strconv.FormatInt(int64(p.s.popInt()), 8))
  116. case 'd':
  117. p.buf.WriteString(strconv.Itoa(p.s.popInt()))
  118. case 'x':
  119. p.buf.WriteString(strconv.FormatInt(int64(p.s.popInt()), 16))
  120. case 'X':
  121. p.buf.WriteString(strings.ToUpper(strconv.FormatInt(int64(p.s.popInt()), 16)))
  122. case 's':
  123. p.buf.WriteString(p.s.popString())
  124. case 'c':
  125. p.buf.WriteByte(p.s.popByte())
  126. case 'p':
  127. p.pos++
  128. return p.pushParamFn
  129. case 'P':
  130. p.pos++
  131. return p.setDsVarFn
  132. case 'g':
  133. p.pos++
  134. return p.getDsVarFn
  135. case '\'':
  136. p.pos++
  137. ch, err = p.peek()
  138. if err != nil {
  139. return nil
  140. }
  141. p.s.push(ch)
  142. // skip the '\''
  143. p.pos++
  144. case '{':
  145. p.pos++
  146. return p.pushIntfn
  147. case 'l':
  148. p.s.push(len(p.s.popString()))
  149. case '+':
  150. bi, ai := p.s.popInt(), p.s.popInt()
  151. p.s.push(ai + bi)
  152. case '-':
  153. bi, ai := p.s.popInt(), p.s.popInt()
  154. p.s.push(ai - bi)
  155. case '*':
  156. bi, ai := p.s.popInt(), p.s.popInt()
  157. p.s.push(ai * bi)
  158. case '/':
  159. bi, ai := p.s.popInt(), p.s.popInt()
  160. if bi != 0 {
  161. p.s.push(ai / bi)
  162. } else {
  163. p.s.push(0)
  164. }
  165. case 'm':
  166. bi, ai := p.s.popInt(), p.s.popInt()
  167. if bi != 0 {
  168. p.s.push(ai % bi)
  169. } else {
  170. p.s.push(0)
  171. }
  172. case '&':
  173. bi, ai := p.s.popInt(), p.s.popInt()
  174. p.s.push(ai & bi)
  175. case '|':
  176. bi, ai := p.s.popInt(), p.s.popInt()
  177. p.s.push(ai | bi)
  178. case '^':
  179. bi, ai := p.s.popInt(), p.s.popInt()
  180. p.s.push(ai ^ bi)
  181. case '=':
  182. bi, ai := p.s.popInt(), p.s.popInt()
  183. p.s.push(ai == bi)
  184. case '>':
  185. bi, ai := p.s.popInt(), p.s.popInt()
  186. p.s.push(ai > bi)
  187. case '<':
  188. bi, ai := p.s.popInt(), p.s.popInt()
  189. p.s.push(ai < bi)
  190. case 'A':
  191. bi, ai := p.s.popBool(), p.s.popBool()
  192. p.s.push(ai && bi)
  193. case 'O':
  194. bi, ai := p.s.popBool(), p.s.popBool()
  195. p.s.push(ai || bi)
  196. case '!':
  197. p.s.push(!p.s.popBool())
  198. case '~':
  199. p.s.push(^p.s.popInt())
  200. case 'i':
  201. for i := range p.params[:2] {
  202. if n, ok := p.params[i].(int); ok {
  203. p.params[i] = n + 1
  204. }
  205. }
  206. case '?', ';':
  207. case 't':
  208. return p.scanThenFn
  209. case 'e':
  210. p.skipElse = true
  211. return p.skipTextFn
  212. }
  213. p.pos++
  214. return p.scanTextFn
  215. }
  216. func (p *parametizer) scanFormatFn() stateFn {
  217. // the character was already read, so no need to check the error.
  218. ch, _ := p.peek()
  219. // 6 should be the maximum length of a format string, for example "%:-9.9d".
  220. f := []byte{'%', ch, 0, 0, 0, 0}
  221. var err error
  222. for {
  223. p.pos++
  224. ch, err = p.peek()
  225. if err != nil {
  226. return nil
  227. }
  228. f = append(f, ch)
  229. switch ch {
  230. case 'o', 'd', 'x', 'X':
  231. fmt.Fprintf(p.buf, string(f), p.s.popInt())
  232. break
  233. case 's':
  234. fmt.Fprintf(p.buf, string(f), p.s.popString())
  235. break
  236. case 'c':
  237. fmt.Fprintf(p.buf, string(f), p.s.popByte())
  238. break
  239. }
  240. }
  241. p.pos++
  242. return p.scanTextFn
  243. }
  244. func (p *parametizer) pushParamFn() stateFn {
  245. ch, err := p.peek()
  246. if err != nil {
  247. return nil
  248. }
  249. if ai := int(ch - '1'); ai >= 0 && ai < len(p.params) {
  250. p.s.push(p.params[ai])
  251. } else {
  252. p.s.push(0)
  253. }
  254. // skip the '}'
  255. p.pos++
  256. return p.scanTextFn
  257. }
  258. func (p *parametizer) setDsVarFn() stateFn {
  259. ch, err := p.peek()
  260. if err != nil {
  261. return nil
  262. }
  263. if ch >= 'A' && ch <= 'Z' {
  264. staticVars.Lock()
  265. staticVars.vars[int(ch-'A')] = p.s.pop()
  266. staticVars.Unlock()
  267. } else if ch >= 'a' && ch <= 'z' {
  268. p.vars[int(ch-'a')] = p.s.pop()
  269. }
  270. p.pos++
  271. return p.scanTextFn
  272. }
  273. func (p *parametizer) getDsVarFn() stateFn {
  274. ch, err := p.peek()
  275. if err != nil {
  276. return nil
  277. }
  278. var a byte
  279. if ch >= 'A' && ch <= 'Z' {
  280. a = 'A'
  281. } else if ch >= 'a' && ch <= 'z' {
  282. a = 'a'
  283. }
  284. staticVars.Lock()
  285. p.s.push(staticVars.vars[int(ch-a)])
  286. staticVars.Unlock()
  287. p.pos++
  288. return p.scanTextFn
  289. }
  290. func (p *parametizer) pushIntfn() stateFn {
  291. var ai int
  292. for {
  293. ch, err := p.peek()
  294. if err != nil {
  295. return nil
  296. }
  297. p.pos++
  298. if ch < '0' || ch > '9' {
  299. p.s.push(ai)
  300. return p.scanTextFn
  301. }
  302. ai = (ai * 10) + int(ch-'0')
  303. }
  304. }
  305. func (p *parametizer) scanThenFn() stateFn {
  306. p.pos++
  307. if p.s.popBool() {
  308. return p.scanTextFn
  309. }
  310. p.skipElse = false
  311. return p.skipTextFn
  312. }
  313. func (p *parametizer) skipTextFn() stateFn {
  314. for {
  315. ch, err := p.peek()
  316. if err != nil {
  317. return nil
  318. }
  319. p.pos++
  320. if ch == '%' {
  321. break
  322. }
  323. }
  324. if p.skipElse {
  325. return p.skipElseFn
  326. }
  327. return p.skipThenFn
  328. }
  329. func (p *parametizer) skipThenFn() stateFn {
  330. ch, err := p.peek()
  331. if err != nil {
  332. return nil
  333. }
  334. p.pos++
  335. switch ch {
  336. case ';':
  337. if p.nest == 0 {
  338. return p.scanTextFn
  339. }
  340. p.nest--
  341. case '?':
  342. p.nest++
  343. case 'e':
  344. if p.nest == 0 {
  345. return p.scanTextFn
  346. }
  347. }
  348. return p.skipTextFn
  349. }
  350. func (p *parametizer) skipElseFn() stateFn {
  351. ch, err := p.peek()
  352. if err != nil {
  353. return nil
  354. }
  355. p.pos++
  356. switch ch {
  357. case ';':
  358. if p.nest == 0 {
  359. return p.scanTextFn
  360. }
  361. p.nest--
  362. case '?':
  363. p.nest++
  364. }
  365. return p.skipTextFn
  366. }
  367. // Printf evaluates a parameterized terminfo value z, interpolating params.
  368. func Printf(z []byte, params ...interface{}) string {
  369. p := newParametizer(z)
  370. defer p.reset()
  371. // make sure we always have 9 parameters -- makes it easier
  372. // later to skip checks and its faster
  373. for i := 0; i < len(p.params) && i < len(params); i++ {
  374. p.params[i] = params[i]
  375. }
  376. return p.exec()
  377. }
  378. // Fprintf evaluates a parameterized terminfo value z, interpolating params and
  379. // writing to w.
  380. func Fprintf(w io.Writer, z []byte, params ...interface{}) {
  381. w.Write([]byte(Printf(z, params...)))
  382. }