/* #line 1 "user/ansi_parser.rl" */ #include #include "ansi_parser.h" #include "ansi_parser_callbacks.h" #include "ascii.h" #include "apars_logging.h" #include "screen.h" /* Ragel constants block */ /* #line 13 "user/ansi_parser.c" */ static const char _ansi_actions[] ESP_CONST_DATA = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15 }; static const char _ansi_eof_actions[] ESP_CONST_DATA = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }; static const int ansi_start = 1; static const int ansi_first_final = 11; static const int ansi_error = 0; static const int ansi_en_CSI_body = 5; static const int ansi_en_STRCMD_body = 8; static const int ansi_en_charsetcmd_body = 10; static const int ansi_en_main = 1; /* #line 12 "user/ansi_parser.rl" */ static volatile int cs = -1; static volatile bool inside_string = false; // public volatile u32 ansi_parser_char_cnt = 0; volatile bool ansi_parser_inhibit = 0; void ICACHE_FLASH_ATTR ansi_parser_reset(void) { if (cs != ansi_start) { cs = ansi_start; inside_string = false; apars_reset_utf8buffer(); ansi_warn("Parser state reset (timeout?)"); } } #define HISTORY_LEN 10 #if DEBUG_ANSI static char history[HISTORY_LEN + 1]; #endif void ICACHE_FLASH_ATTR apars_show_context(void) { #if DEBUG_ANSI char buf1[HISTORY_LEN*3+2]; char buf2[HISTORY_LEN*3+2]; char *b1 = buf1; char *b2 = buf2; char c; for(int i=0;i 127) c = '.'; b2 += sprintf(b2, "%c ", c); } ansi_dbg("Context: %s", buf2); ansi_dbg(" %s", buf1); #endif } /** * \brief Linear ANSI chars stream parser * * Parses a stream of bytes using a Ragel parser. The defined * grammar does not use 'unget', so the entire buffer is * always processed in a linear manner. * * \attention -> but always check the Ragel output for 'p--' * or 'p -=', that means trouble. * * \param newdata - array of new chars to process * \param len - length of the newdata buffer */ void ICACHE_FLASH_ATTR ansi_parser(char newchar) { // The CSI code is built here static char leadchar; static char interchar; // intermediate CSI char static int arg_ni; static int arg_cnt; static int arg[CSI_N_MAX]; static char string_buffer[ANSI_STR_LEN]; static int str_ni; if (ansi_parser_inhibit) return; // This is used to detect timeout delay (time since last rx char) ansi_parser_char_cnt++; if (termconf->ascii_debug) { apars_handle_plainchar(newchar); return; } // Init Ragel on the first run if (cs == -1) { /* #line 123 "user/ansi_parser.c" */ { cs = ansi_start; } /* #line 97 "user/ansi_parser.rl" */ #if DEBUG_ANSI memset(history, 0, sizeof(history)); #endif } #if DEBUG_ANSI for(int i=1; i= ' ') { apars_handle_plainchar(newchar); return; } } // Load new data to Ragel vars const char *p = &newchar; const char *eof = NULL; const char *pe = &newchar + 1; // The parser /* #line 209 "user/ansi_parser.c" */ { const char *_acts; unsigned int _nacts; if ( p == pe ) goto _test_eof; if ( cs == 0 ) goto _out; _resume: switch ( cs ) { case 1: switch( (*p) ) { case 7: goto tr1; case 27: goto tr2; } goto tr0; case 0: goto _out; case 2: switch( (*p) ) { case 32: goto tr3; case 35: goto tr4; case 37: goto tr5; case 80: goto tr7; case 88: goto tr7; case 91: goto tr8; case 107: goto tr7; } if ( (*p) < 64 ) { if ( (*p) < 48 ) { if ( 40 <= (*p) && (*p) <= 47 ) goto tr5; } else if ( (*p) > 57 ) { if ( 60 <= (*p) && (*p) <= 62 ) goto tr6; } else goto tr6; } else if ( (*p) > 92 ) { if ( (*p) < 97 ) { if ( 93 <= (*p) && (*p) <= 95 ) goto tr7; } else if ( (*p) > 122 ) { if ( 124 <= (*p) && (*p) <= 126 ) goto tr6; } else goto tr6; } else goto tr6; goto tr1; case 3: if ( (*p) > 71 ) { if ( 76 <= (*p) && (*p) <= 78 ) goto tr9; } else if ( (*p) >= 70 ) goto tr9; goto tr1; case 11: switch( (*p) ) { case 7: goto tr1; case 27: goto tr2; } goto tr0; case 4: if ( 48 <= (*p) && (*p) <= 57 ) goto tr10; goto tr1; case 5: switch( (*p) ) { case 36: goto tr11; case 59: goto tr13; } if ( (*p) < 48 ) { if ( (*p) < 38 ) { if ( 32 <= (*p) && (*p) <= 34 ) goto tr11; } else if ( (*p) > 39 ) { if ( 41 <= (*p) && (*p) <= 45 ) goto tr11; } else goto tr11; } else if ( (*p) > 57 ) { if ( (*p) < 64 ) { if ( 61 <= (*p) && (*p) <= 63 ) goto tr14; } else if ( (*p) > 90 ) { if ( 96 <= (*p) && (*p) <= 126 ) goto tr15; } else goto tr15; } else goto tr12; goto tr1; case 6: if ( (*p) > 90 ) { if ( 96 <= (*p) && (*p) <= 126 ) goto tr15; } else if ( (*p) >= 64 ) goto tr15; goto tr1; case 12: goto tr1; case 7: switch( (*p) ) { case 36: goto tr11; case 59: goto tr13; } if ( (*p) < 41 ) { if ( (*p) > 34 ) { if ( 38 <= (*p) && (*p) <= 39 ) goto tr11; } else if ( (*p) >= 32 ) goto tr11; } else if ( (*p) > 45 ) { if ( (*p) < 64 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr12; } else if ( (*p) > 90 ) { if ( 96 <= (*p) && (*p) <= 126 ) goto tr15; } else goto tr15; } else goto tr11; goto tr1; case 8: switch( (*p) ) { case 7: goto tr17; case 27: goto tr18; } goto tr16; case 13: goto tr1; case 9: if ( (*p) == 92 ) goto tr17; goto tr1; case 10: switch( (*p) ) { case 7: goto tr1; case 27: goto tr1; } goto tr19; case 14: goto tr1; } tr1: cs = 0; goto f0; tr0: cs = 1; goto f1; tr2: cs = 2; goto _again; tr3: cs = 3; goto _again; tr4: cs = 4; goto _again; tr11: cs = 6; goto f8; tr12: cs = 7; goto f9; tr13: cs = 7; goto f10; tr14: cs = 7; goto f11; tr16: cs = 8; goto f13; tr18: cs = 9; goto _again; tr5: cs = 11; goto f2; tr6: cs = 11; goto f3; tr7: cs = 11; goto f4; tr8: cs = 11; goto f5; tr9: cs = 11; goto f6; tr10: cs = 11; goto f7; tr15: cs = 12; goto f12; tr17: cs = 13; goto f14; tr19: cs = 14; goto f15; f0: _acts = _ansi_actions + 1; goto execFuncs; f1: _acts = _ansi_actions + 3; goto execFuncs; f5: _acts = _ansi_actions + 5; goto execFuncs; f11: _acts = _ansi_actions + 7; goto execFuncs; f9: _acts = _ansi_actions + 9; goto execFuncs; f10: _acts = _ansi_actions + 11; goto execFuncs; f8: _acts = _ansi_actions + 13; goto execFuncs; f12: _acts = _ansi_actions + 15; goto execFuncs; f4: _acts = _ansi_actions + 17; goto execFuncs; f13: _acts = _ansi_actions + 19; goto execFuncs; f14: _acts = _ansi_actions + 21; goto execFuncs; f7: _acts = _ansi_actions + 23; goto execFuncs; f3: _acts = _ansi_actions + 25; goto execFuncs; f6: _acts = _ansi_actions + 27; goto execFuncs; f2: _acts = _ansi_actions + 29; goto execFuncs; f15: _acts = _ansi_actions + 31; goto execFuncs; execFuncs: _nacts = *_acts++; while ( _nacts-- > 0 ) { switch ( *_acts++ ) { case 0: /* #line 185 "user/ansi_parser.rl" */ { ansi_warn("Parser error."); apars_show_context(); inside_string = false; // no longer in string, for sure {cs = 1;goto _again;} } break; case 1: /* #line 194 "user/ansi_parser.rl" */ { if ((*p) != 0) { apars_handle_plainchar((*p)); } } break; case 2: /* #line 202 "user/ansi_parser.rl" */ { // Reset the CSI builder leadchar = NUL; interchar = NUL; arg_ni = 0; arg_cnt = 0; // Zero out digits for(int i = 0; i < CSI_N_MAX; i++) { arg[i] = 0; } {cs = 5;goto _again;} } break; case 3: /* #line 217 "user/ansi_parser.rl" */ { leadchar = (*p); } break; case 4: /* #line 221 "user/ansi_parser.rl" */ { if (arg_cnt == 0) arg_cnt = 1; // x10 + digit if (arg_ni < CSI_N_MAX) { arg[arg_ni] = arg[arg_ni]*10 + ((*p) - '0'); } } break; case 5: /* #line 229 "user/ansi_parser.rl" */ { if (arg_cnt == 0) arg_cnt = 1; // handle case when first arg is empty arg_cnt++; arg_ni++; } break; case 6: /* #line 235 "user/ansi_parser.rl" */ { interchar = (*p); } break; case 7: /* #line 239 "user/ansi_parser.rl" */ { apars_handle_csi(leadchar, arg, arg_cnt, interchar, (*p)); {cs = 1;goto _again;} } break; case 8: /* #line 251 "user/ansi_parser.rl" */ { leadchar = (*p); str_ni = 0; string_buffer[0] = '\0'; inside_string = true; {cs = 8;goto _again;} } break; case 9: /* #line 259 "user/ansi_parser.rl" */ { string_buffer[str_ni++] = (*p); } break; case 10: /* #line 263 "user/ansi_parser.rl" */ { inside_string = false; string_buffer[str_ni++] = '\0'; apars_handle_string_cmd(leadchar, string_buffer); {cs = 1;goto _again;} } break; case 11: /* #line 276 "user/ansi_parser.rl" */ { apars_handle_hash_cmd((*p)); {cs = 1;goto _again;} } break; case 12: /* #line 281 "user/ansi_parser.rl" */ { apars_handle_short_cmd((*p)); {cs = 1;goto _again;} } break; case 13: /* #line 286 "user/ansi_parser.rl" */ { apars_handle_space_cmd((*p)); {cs = 1;goto _again;} } break; case 14: /* #line 293 "user/ansi_parser.rl" */ { leadchar = (*p); {cs = 10;goto _again;} } break; case 15: /* #line 298 "user/ansi_parser.rl" */ { apars_handle_chs_designate(leadchar, (*p)); {cs = 1;goto _again;} } break; /* #line 529 "user/ansi_parser.c" */ } } goto _again; _again: if ( cs == 0 ) goto _out; if ( ++p != pe ) goto _resume; _test_eof: {} if ( p == eof ) { const char *__acts = _ansi_actions + _ansi_eof_actions[cs]; unsigned int __nacts = (unsigned int) *__acts++; while ( __nacts-- > 0 ) { switch ( *__acts++ ) { case 0: /* #line 185 "user/ansi_parser.rl" */ { ansi_warn("Parser error."); apars_show_context(); inside_string = false; // no longer in string, for sure {cs = 1; if ( p == pe ) goto _test_eof; goto _again;} } break; /* #line 557 "user/ansi_parser.c" */ } } } _out: {} } /* #line 321 "user/ansi_parser.rl" */ }