OSDN Git Service

First commitment for the BlackTank LPC1769.
[blacktank/blacktank.git] / vtparse.c
1 /**
2  * @file vtparse.c
3  * @brief VTParse
4  * @details
5  * An implementation of Paul Williams' DEC compatible state machine parser
6  * This code is in the public domain.
7  * @author Joshua Haberman <joshua@reverberate.org>
8  */
9
10 #include "vtparse.h"
11 #include "vtparse_table.h"
12 #include "ntlibc.h"
13
14 void vtparse_init(vtparse_t *parser, vtparse_callback_t cb)
15 {
16     parser->state                 = VTPARSE_STATE_GROUND;
17     parser->intermediate_chars[0] = '\0';
18     parser->num_params            = 0;
19     parser->ignore_flagged        = 0;
20     parser->cb                    = cb;
21 }
22
23 static void do_action(vtparse_t *parser, vtparse_action_t action, char ch)
24 {
25     /* Some actions we handle internally (like parsing parameters), others
26      * we hand to our client for processing */
27
28     switch(action) {
29         case VTPARSE_ACTION_PRINT:
30         case VTPARSE_ACTION_EXECUTE:
31         case VTPARSE_ACTION_HOOK:
32         case VTPARSE_ACTION_PUT:
33         case VTPARSE_ACTION_OSC_START:
34         case VTPARSE_ACTION_OSC_PUT:
35         case VTPARSE_ACTION_OSC_END:
36         case VTPARSE_ACTION_UNHOOK:
37         case VTPARSE_ACTION_CSI_DISPATCH:
38         case VTPARSE_ACTION_ESC_DISPATCH:
39             parser->cb(parser, action, ch);
40             break;
41
42         case VTPARSE_ACTION_IGNORE:
43             /* do nothing */
44             break;
45
46         case VTPARSE_ACTION_COLLECT:
47         {
48             /* Append the character to the intermediate params */
49             int num_intermediate_chars = ntlibc_strlen((char*)parser->intermediate_chars);
50
51             if(num_intermediate_chars + 1 > MAX_INTERMEDIATE_CHARS)
52                 parser->ignore_flagged = 1;
53             else
54                 parser->intermediate_chars[num_intermediate_chars++] = ch;
55
56             break;
57         }
58
59         case VTPARSE_ACTION_PARAM:
60         {
61             /* process the param character */
62             if(ch == ';')
63             {
64                 parser->num_params += 1;
65                 parser->params[parser->num_params-1] = 0;
66             }
67             else
68             {
69                 /* the character is a digit */
70                 int current_param;
71
72                 if(parser->num_params == 0)
73                 {
74                     parser->num_params = 1;
75                     parser->params[0]  = 0;
76                 }
77
78                 current_param = parser->num_params - 1;
79                 parser->params[current_param] *= 10;
80                 parser->params[current_param] += (ch - '0');
81             }
82
83             break;
84         }
85
86         case VTPARSE_ACTION_CLEAR:
87             parser->intermediate_chars[0] = '\0';
88             parser->num_params            = 0;
89             parser->ignore_flagged        = 0;
90             break;
91
92         default:
93             // Internal error: Unknown action.
94             break;
95     }
96 }
97
98 static void do_state_change(vtparse_t *parser, state_change_t change, char ch)
99 {
100     /* A state change is an action and/or a new state to transition to. */
101
102     vtparse_state_t  new_state = STATE(change);
103     vtparse_action_t action    = ACTION(change);
104
105
106     if(new_state)
107     {
108         /* Perform up to three actions:
109          *   1. the exit action of the old state
110          *   2. the action associated with the transition
111          *   3. the entry actionk of the new action
112          */
113
114         vtparse_action_t exit_action = GET_EXIT_ACTIONS(parser->state);
115         vtparse_action_t entry_action = GET_ENTRY_ACTIONS(new_state);
116
117         if(exit_action)
118             do_action(parser, exit_action, 0);
119
120         if(action)
121             do_action(parser, action, ch);
122
123         if(entry_action)
124             do_action(parser, entry_action, 0);
125
126         parser->state = new_state;
127     }
128     else
129     {
130         do_action(parser, action, ch);
131     }
132 }
133
134 void vtparse(vtparse_t *parser, unsigned char *data, int len)
135 {
136     int i;
137     for(i = 0; i < len; i++)
138     {
139         unsigned char ch = data[i];
140
141         /* If a transition is defined from the "anywhere" state, always
142          * use that.  Otherwise use the transition from the current state. */
143
144         state_change_t change = GET_STATE_TABLE(VTPARSE_STATE_ANYWHERE, ch);
145
146         if(!change)
147             change = GET_STATE_TABLE(parser->state, ch);
148
149         do_state_change(parser, change, data[i]);
150     }
151 }
152