mtm | Ncurses-based terminal multiplexer |
| download: https://git.y1.nz/archives/mtm.tar.gz | |
| Files | Log | Refs |
vtparser.c
1 /* Copyright (c) 2017-2019 Rob King
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of the copyright holder nor the
12 * names of contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS,
19 * COPYRIGHT HOLDERS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <stdbool.h>
28 #include <string.h>
29 #include "vtparser.h"
30
31 /**** DATA TYPES */
32 #define MAXACTIONS 128
33
34 typedef struct ACTION ACTION;
35 struct ACTION{
36 wchar_t lo, hi;
37 void (*cb)(VTPARSER *p, wchar_t w);
38 STATE *next;
39 };
40
41 struct STATE{
42 void (*entry)(VTPARSER *v);
43 ACTION actions[MAXACTIONS];
44 };
45
46 /**** GLOBALS */
47 static STATE ground, escape, escape_intermediate, csi_entry,
48 csi_ignore, csi_param, csi_intermediate, osc_string;
49
50 /**** ACTION FUNCTIONS */
51 static void
52 reset(VTPARSER *v)
53 {
54 v->inter = v->narg = v->nosc = 0;
55 memset(v->args, 0, sizeof(v->args));
56 memset(v->oscbuf, 0, sizeof(v->oscbuf));
57 }
58
59 static void
60 ignore(VTPARSER *v, wchar_t w)
61 {
62 (void)v; (void)w; /* avoid warnings */
63 }
64
65 static void
66 collect(VTPARSER *v, wchar_t w)
67 {
68 v->inter = v->inter? v->inter : (int)w;
69 }
70
71 static void
72 collectosc(VTPARSER *v, wchar_t w)
73 {
74 if (v->nosc < MAXOSC)
75 v->oscbuf[v->nosc++] = w;
76 }
77
78 static void
79 param(VTPARSER *v, wchar_t w)
80 {
81 v->narg = v->narg? v->narg : 1;
82
83 if (w == L';')
84 v->args[v->narg++] = 0;
85 else if (v->narg < MAXPARAM && v->args[v->narg - 1] < 9999)
86 v->args[v->narg - 1] = v->args[v->narg - 1] * 10 + (w - 0x30);
87 }
88
89 #define DO(k, t, f, n, a) \
90 static void \
91 do ## k (VTPARSER *v, wchar_t w) \
92 { \
93 if (t) \
94 f (v, v->p, w, v->inter, n, a, v->oscbuf); \
95 }
96
97 DO(control, w < MAXCALLBACK && v->cons[w], v->cons[w], 0, NULL)
98 DO(escape, w < MAXCALLBACK && v->escs[w], v->escs[w], v->inter > 0, &v->inter)
99 DO(csi, w < MAXCALLBACK && v->csis[w], v->csis[w], v->narg, v->args)
100 DO(print, v->print, v->print, 0, NULL)
101 DO(osc, v->osc, v->osc, v->nosc, NULL)
102
103 /**** PUBLIC FUNCTIONS */
104 VTCALLBACK
105 vtonevent(VTPARSER *vp, VtEvent t, wchar_t w, VTCALLBACK cb)
106 {
107 VTCALLBACK o = NULL;
108 if (w < MAXCALLBACK) switch (t){
109 case VTPARSER_CONTROL: o = vp->cons[w]; vp->cons[w] = cb; break;
110 case VTPARSER_ESCAPE: o = vp->escs[w]; vp->escs[w] = cb; break;
111 case VTPARSER_CSI: o = vp->csis[w]; vp->csis[w] = cb; break;
112 case VTPARSER_PRINT: o = vp->print; vp->print = cb; break;
113 case VTPARSER_OSC: o = vp->osc; vp->osc = cb; break;
114 }
115
116 return o;
117 }
118
119 static void
120 handlechar(VTPARSER *vp, wchar_t w)
121 {
122 vp->s = vp->s? vp->s : &ground;
123 for (ACTION *a = vp->s->actions; a->cb; a++) if (w >= a->lo && w <= a->hi){
124 a->cb(vp, w);
125 if (a->next){
126 vp->s = a->next;
127 if (a->next->entry)
128 a->next->entry(vp);
129 }
130 return;
131 }
132 }
133
134 void
135 vtwrite(VTPARSER *vp, const char *s, size_t n)
136 {
137 wchar_t w = 0;
138 while (n){
139 size_t r = mbrtowc(&w, s, n, &vp->ms);
140 switch (r){
141 case -2: /* incomplete character, try again */
142 return;
143
144 case -1: /* invalid character, skip it */
145 w = VTPARSER_BAD_CHAR;
146 r = 1;
147 break;
148
149 case 0: /* literal zero, write it but advance */
150 r = 1;
151 break;
152 }
153
154 n -= r;
155 s += r;
156 handlechar(vp, w);
157 }
158 }
159
160 /**** STATE DEFINITIONS
161 * This was built by consulting the excellent state chart created by
162 * Paul Flo Williams: http://vt100.net/emu/dec_ansi_parser
163 * Please note that Williams does not (AFAIK) endorse this work.
164 */
165 #define MAKESTATE(name, onentry, ...) \
166 static STATE name ={ \
167 onentry , \
168 { \
169 {0x00, 0x00, ignore, NULL}, \
170 {0x7f, 0x7f, ignore, NULL}, \
171 {0x18, 0x18, docontrol, &ground}, \
172 {0x1a, 0x1a, docontrol, &ground}, \
173 {0x1b, 0x1b, ignore, &escape}, \
174 {0x01, 0x06, docontrol, NULL}, \
175 {0x08, 0x17, docontrol, NULL}, \
176 {0x19, 0x19, docontrol, NULL}, \
177 {0x1c, 0x1f, docontrol, NULL}, \
178 __VA_ARGS__ , \
179 {0x07, 0x07, docontrol, NULL}, \
180 {0x00, 0x00, NULL, NULL} \
181 } \
182 }
183
184 MAKESTATE(ground, NULL,
185 {0x20, WCHAR_MAX, doprint, NULL}
186 );
187
188 MAKESTATE(escape, reset,
189 {0x21, 0x21, ignore, &osc_string},
190 {0x20, 0x2f, collect, &escape_intermediate},
191 {0x30, 0x4f, doescape, &ground},
192 {0x51, 0x57, doescape, &ground},
193 {0x59, 0x59, doescape, &ground},
194 {0x5a, 0x5a, doescape, &ground},
195 {0x5c, 0x5c, doescape, &ground},
196 {0x6b, 0x6b, ignore, &osc_string},
197 {0x60, 0x7e, doescape, &ground},
198 {0x5b, 0x5b, ignore, &csi_entry},
199 {0x5d, 0x5d, ignore, &osc_string},
200 {0x5e, 0x5e, ignore, &osc_string},
201 {0x50, 0x50, ignore, &osc_string},
202 {0x5f, 0x5f, ignore, &osc_string}
203 );
204
205 MAKESTATE(escape_intermediate, NULL,
206 {0x20, 0x2f, collect, NULL},
207 {0x30, 0x7e, doescape, &ground}
208 );
209
210 MAKESTATE(csi_entry, reset,
211 {0x20, 0x2f, collect, &csi_intermediate},
212 {0x3a, 0x3a, ignore, &csi_ignore},
213 {0x30, 0x39, param, &csi_param},
214 {0x3b, 0x3b, param, &csi_param},
215 {0x3c, 0x3f, collect, &csi_param},
216 {0x40, 0x7e, docsi, &ground}
217 );
218
219 MAKESTATE(csi_ignore, NULL,
220 {0x20, 0x3f, ignore, NULL},
221 {0x40, 0x7e, ignore, &ground}
222 );
223
224 MAKESTATE(csi_param, NULL,
225 {0x30, 0x39, param, NULL},
226 {0x3b, 0x3b, param, NULL},
227 {0x3a, 0x3a, ignore, &csi_ignore},
228 {0x3c, 0x3f, ignore, &csi_ignore},
229 {0x20, 0x2f, collect, &csi_intermediate},
230 {0x40, 0x7e, docsi, &ground}
231 );
232
233 MAKESTATE(csi_intermediate, NULL,
234 {0x20, 0x2f, collect, NULL},
235 {0x30, 0x3f, ignore, &csi_ignore},
236 {0x40, 0x7e, docsi, &ground}
237 );
238
239 MAKESTATE(osc_string, reset,
240 {0x07, 0x07, doosc, &ground},
241 {0x20, 0x7f, collectosc, NULL}
242 );
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.