Initial import.
[vtparse.git] / vtparse.c
blobb24a4a481b5e4f62a5c0e629eb6b68eec28a1a7a
1 /*
2 * VTParse - an implementation of Paul Williams' DEC compatible state machine parser
4 * Author: Joshua Haberman <joshua@reverberate.org>
6 * This code is in the public domain.
7 */
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdio.h>
13 #include "vtparse.h"
15 void vtparse_init(vtparse_t *parser, vtparse_callback_t cb)
17 parser->state = VTPARSE_STATE_GROUND;
18 parser->intermediate_chars[0] = '\0';
19 parser->num_params = 0;
20 parser->ignore_flagged = 0;
21 parser->cb = cb;
24 static void do_action(vtparse_t *parser, vtparse_action_t action, char ch)
26 /* Some actions we handle internally (like parsing parameters), others
27 * we hand to our client for processing */
29 switch(action) {
30 case VTPARSE_ACTION_PRINT:
31 case VTPARSE_ACTION_EXECUTE:
32 case VTPARSE_ACTION_HOOK:
33 case VTPARSE_ACTION_PUT:
34 case VTPARSE_ACTION_OSC_START:
35 case VTPARSE_ACTION_OSC_PUT:
36 case VTPARSE_ACTION_OSC_END:
37 case VTPARSE_ACTION_UNHOOK:
38 case VTPARSE_ACTION_CSI_DISPATCH:
39 case VTPARSE_ACTION_ESC_DISPATCH:
40 parser->cb(parser, action, ch);
41 break;
43 case VTPARSE_ACTION_IGNORE:
44 /* do nothing */
45 break;
47 case VTPARSE_ACTION_COLLECT:
49 /* Append the character to the intermediate params */
50 int num_intermediate_chars = strlen((char*)parser->intermediate_chars);
52 if(num_intermediate_chars + 1 > MAX_INTERMEDIATE_CHARS)
53 parser->ignore_flagged = 1;
54 else
55 parser->intermediate_chars[num_intermediate_chars++] = ch;
57 break;
60 case VTPARSE_ACTION_PARAM:
62 /* process the param character */
63 if(ch == ';')
65 parser->num_params += 1;
66 parser->params[parser->num_params-1] = 0;
68 else
70 /* the character is a digit */
71 int current_param;
73 if(parser->num_params == 0)
75 parser->num_params = 1;
76 parser->params[0] = 0;
79 current_param = parser->num_params - 1;
80 parser->params[current_param] *= 10;
81 parser->params[current_param] += (ch - '0');
84 break;
87 case VTPARSE_ACTION_CLEAR:
88 parser->intermediate_chars[0] = '\0';
89 parser->num_params = 0;
90 parser->ignore_flagged = 0;
91 break;
93 default:
94 fprintf(stderr, "Internal error, unknown action %d", action);
98 static void do_state_change(vtparse_t *parser, state_change_t change, char ch)
100 /* A state change is an action and/or a new state to transition to. */
102 vtparse_state_t new_state = STATE(change);
103 vtparse_action_t action = ACTION(change);
106 if(new_state)
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
114 vtparse_action_t exit_action = EXIT_ACTIONS[parser->state];
115 vtparse_action_t entry_action = ENTRY_ACTIONS[new_state];
117 if(exit_action)
118 do_action(parser, exit_action, 0);
120 if(action)
121 do_action(parser, action, ch);
123 if(entry_action)
124 do_action(parser, entry_action, 0);
126 parser->state = new_state;
128 else
130 do_action(parser, action, ch);
134 void vtparse(vtparse_t *parser, unsigned char *data, int len)
136 int i;
137 for(i = 0; i < len; i++)
139 unsigned char ch = data[i];
141 /* If a transition is defined from the "anywhere" state, always
142 * use that. Otherwise use the transition from the current state. */
144 state_change_t change = STATE_TABLE[VTPARSE_STATE_ANYWHERE][ch];
146 if(!change)
147 change = STATE_TABLE[parser->state][ch];
149 do_state_change(parser, change, data[i]);