parser.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package ansiterm
  2. import (
  3. "errors"
  4. "log"
  5. "os"
  6. )
  7. type AnsiParser struct {
  8. currState state
  9. eventHandler AnsiEventHandler
  10. context *ansiContext
  11. csiEntry state
  12. csiParam state
  13. dcsEntry state
  14. escape state
  15. escapeIntermediate state
  16. error state
  17. ground state
  18. oscString state
  19. stateMap []state
  20. logf func(string, ...interface{})
  21. }
  22. type Option func(*AnsiParser)
  23. func WithLogf(f func(string, ...interface{})) Option {
  24. return func(ap *AnsiParser) {
  25. ap.logf = f
  26. }
  27. }
  28. func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
  29. ap := &AnsiParser{
  30. eventHandler: evtHandler,
  31. context: &ansiContext{},
  32. }
  33. for _, o := range opts {
  34. o(ap)
  35. }
  36. if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
  37. logFile, _ := os.Create("ansiParser.log")
  38. logger := log.New(logFile, "", log.LstdFlags)
  39. if ap.logf != nil {
  40. l := ap.logf
  41. ap.logf = func(s string, v ...interface{}) {
  42. l(s, v...)
  43. logger.Printf(s, v...)
  44. }
  45. } else {
  46. ap.logf = logger.Printf
  47. }
  48. }
  49. if ap.logf == nil {
  50. ap.logf = func(string, ...interface{}) {}
  51. }
  52. ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
  53. ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
  54. ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
  55. ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
  56. ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
  57. ap.error = errorState{baseState{name: "Error", parser: ap}}
  58. ap.ground = groundState{baseState{name: "Ground", parser: ap}}
  59. ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
  60. ap.stateMap = []state{
  61. ap.csiEntry,
  62. ap.csiParam,
  63. ap.dcsEntry,
  64. ap.escape,
  65. ap.escapeIntermediate,
  66. ap.error,
  67. ap.ground,
  68. ap.oscString,
  69. }
  70. ap.currState = getState(initialState, ap.stateMap)
  71. ap.logf("CreateParser: parser %p", ap)
  72. return ap
  73. }
  74. func getState(name string, states []state) state {
  75. for _, el := range states {
  76. if el.Name() == name {
  77. return el
  78. }
  79. }
  80. return nil
  81. }
  82. func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
  83. for i, b := range bytes {
  84. if err := ap.handle(b); err != nil {
  85. return i, err
  86. }
  87. }
  88. return len(bytes), ap.eventHandler.Flush()
  89. }
  90. func (ap *AnsiParser) handle(b byte) error {
  91. ap.context.currentChar = b
  92. newState, err := ap.currState.Handle(b)
  93. if err != nil {
  94. return err
  95. }
  96. if newState == nil {
  97. ap.logf("WARNING: newState is nil")
  98. return errors.New("New state of 'nil' is invalid.")
  99. }
  100. if newState != ap.currState {
  101. if err := ap.changeState(newState); err != nil {
  102. return err
  103. }
  104. }
  105. return nil
  106. }
  107. func (ap *AnsiParser) changeState(newState state) error {
  108. ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
  109. // Exit old state
  110. if err := ap.currState.Exit(); err != nil {
  111. ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
  112. return err
  113. }
  114. // Perform transition action
  115. if err := ap.currState.Transition(newState); err != nil {
  116. ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
  117. return err
  118. }
  119. // Enter new state
  120. if err := newState.Enter(); err != nil {
  121. ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
  122. return err
  123. }
  124. ap.currState = newState
  125. return nil
  126. }