Koji Hamada / NaturalTinyShell

Fork of NaturalTinyShell by Shinichiro Nakamura

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers vtparse.cpp Source File

vtparse.cpp

Go to the documentation of this file.
00001 /**
00002  * @file vtparse.cpp
00003  * @brief VTParse
00004  * @details
00005  * An implementation of Paul Williams' DEC compatible state machine parser
00006  * This code is in the public domain.
00007  * @author Joshua Haberman <joshua@reverberate.org>
00008  */
00009 
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <stdio.h>
00013 
00014 #include "vtparse.h"
00015 #include "vtparse_table.h"
00016 #include "ntlibc.h"
00017 
00018 void vtparse_init(vtparse_t *parser, vtparse_callback_t cb)
00019 {
00020     parser->state                 = VTPARSE_STATE_GROUND;
00021     parser->intermediate_chars[0] = '\0';
00022     parser->num_params            = 0;
00023     parser->ignore_flagged        = 0;
00024     parser->cb                    = cb;
00025 }
00026 
00027 static void do_action(vtparse_t *parser, vtparse_action_t action, char ch)
00028 {
00029     /* Some actions we handle internally (like parsing parameters), others
00030      * we hand to our client for processing */
00031 
00032     switch(action) {
00033         case VTPARSE_ACTION_PRINT:
00034         case VTPARSE_ACTION_EXECUTE:
00035         case VTPARSE_ACTION_HOOK:
00036         case VTPARSE_ACTION_PUT:
00037         case VTPARSE_ACTION_OSC_START:
00038         case VTPARSE_ACTION_OSC_PUT:
00039         case VTPARSE_ACTION_OSC_END:
00040         case VTPARSE_ACTION_UNHOOK:
00041         case VTPARSE_ACTION_CSI_DISPATCH:
00042         case VTPARSE_ACTION_ESC_DISPATCH:
00043             parser->cb(parser, action, ch);
00044             break;
00045 
00046         case VTPARSE_ACTION_IGNORE:
00047             /* do nothing */
00048             break;
00049 
00050         case VTPARSE_ACTION_COLLECT:
00051         {
00052             /* Append the character to the intermediate params */
00053             int num_intermediate_chars = ntlibc_strlen((char*)parser->intermediate_chars);
00054 
00055             if(num_intermediate_chars + 1 > MAX_INTERMEDIATE_CHARS)
00056                 parser->ignore_flagged = 1;
00057             else
00058                 parser->intermediate_chars[num_intermediate_chars++] = ch;
00059 
00060             break;
00061         }
00062 
00063         case VTPARSE_ACTION_PARAM:
00064         {
00065             /* process the param character */
00066             if(ch == ';')
00067             {
00068                 parser->num_params += 1;
00069                 parser->params[parser->num_params-1] = 0;
00070             }
00071             else
00072             {
00073                 /* the character is a digit */
00074                 int current_param;
00075 
00076                 if(parser->num_params == 0)
00077                 {
00078                     parser->num_params = 1;
00079                     parser->params[0]  = 0;
00080                 }
00081 
00082                 current_param = parser->num_params - 1;
00083                 parser->params[current_param] *= 10;
00084                 parser->params[current_param] += (ch - '0');
00085             }
00086 
00087             break;
00088         }
00089 
00090         case VTPARSE_ACTION_CLEAR:
00091             parser->intermediate_chars[0] = '\0';
00092             parser->num_params            = 0;
00093             parser->ignore_flagged        = 0;
00094             break;
00095 
00096         default:
00097             // Internal error: Unknown action.
00098             break;
00099     }
00100 }
00101 
00102 static void do_state_change(vtparse_t *parser, state_change_t change, char ch)
00103 {
00104     /* A state change is an action and/or a new state to transition to. */
00105 
00106     vtparse_state_t  new_state = STATE(change);
00107     vtparse_action_t action    = ACTION(change);
00108 
00109 
00110     if(new_state)
00111     {
00112         /* Perform up to three actions:
00113          *   1. the exit action of the old state
00114          *   2. the action associated with the transition
00115          *   3. the entry actionk of the new action
00116          */
00117 
00118         vtparse_action_t exit_action = GET_EXIT_ACTIONS(parser->state);
00119         vtparse_action_t entry_action = GET_ENTRY_ACTIONS(new_state);
00120 
00121         if(exit_action)
00122             do_action(parser, exit_action, 0);
00123 
00124         if(action)
00125             do_action(parser, action, ch);
00126 
00127         if(entry_action)
00128             do_action(parser, entry_action, 0);
00129 
00130         parser->state = new_state;
00131     }
00132     else
00133     {
00134         do_action(parser, action, ch);
00135     }
00136 }
00137 
00138 void vtparse(vtparse_t *parser, unsigned char *data, int len)
00139 {
00140     int i;
00141     for(i = 0; i < len; i++)
00142     {
00143         unsigned char ch = data[i];
00144 
00145         /* If a transition is defined from the "anywhere" state, always
00146          * use that.  Otherwise use the transition from the current state. */
00147 
00148         state_change_t change = GET_STATE_TABLE(VTPARSE_STATE_ANYWHERE, ch);
00149 
00150         if(!change)
00151             change = GET_STATE_TABLE(parser->state, ch);
00152 
00153         do_state_change(parser, change, data[i]);
00154     }
00155 }
00156