parser.go 3.2 KB

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