1/* $XFree86: xc/programs/xtrap/chparse.c,v 1.3tsi Exp $ */ 2/***************************************************************************** 3Copyright 1987, 1988, 1989, 1990, 1991 by Digital Equipment Corp., Maynard, MA 4 5Permission to use, copy, modify, and distribute this software and its 6documentation for any purpose and without fee is hereby granted, 7provided that the above copyright notice appear in all copies and that 8both that copyright notice and this permission notice appear in 9supporting documentation, and that the name of Digital not be 10used in advertising or publicity pertaining to distribution of the 11software without specific, written prior permission. 12 13DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 14ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 15DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 16ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 17WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 18ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 19SOFTWARE. 20 21*****************************************************************************/ 22/* 23**++ 24** FACILITY: chparse - ASCII ESC & CSI parser 25** 26** MODULE DESCRIPTION: 27** 28** This module accepts single character I/O from 29** stdin and returns a parsed character or sequence 30** of characters. This is to be used in conjunction 31** with passing data from dragon-speak to XTrap. 32** 33** AUTHORS: 34** 35** Roy Lomicka (revised by Martin Minow & later Kenneth B. Miller) 36** 37** CREATION DATE: March 26, 1991 38** 39** DESIGN ISSUES: 40** 41** The algorithm is rather obscure. However, it was decided 42** that it should be left in its original condition since it 43** closely depicts the state transition diagram for ASCII 44** sequences (about the only good thing goto's are for;) . 45** The old-fashioned bracketing and tabbing schemed were 46** also preserved for posterity. 47** 48**-- 49*/ 50 51#include <stdio.h> 52#include <ctype.h> 53#ifdef vms 54#include <ssdef.h> 55#include <stsdef.h> 56#include <iodef.h> 57#include <descrip.h> 58#else 59#include <sys/types.h> 60#include <sys/time.h> 61#endif 62#include <string.h> 63#include <unistd.h> 64#include "chparse.h" 65 66#ifdef __QNX__ 67#include <sys/select.h> 68#endif 69 70#ifndef VERBOSE 71#define VERBOSE 0 72#endif 73 74#ifndef FALSE 75#define FALSE 0 76#define TRUE 1 77#endif 78#define EOS '\0' 79#define ERROR (-1) 80#define TIMEOUT (-2) 81#define NPARAM 8 82#define NINTER 8 83#define BUFFLEN 10 /* Size of typeahead buffer */ 84#ifndef EXIT_SUCCESS 85#ifdef vms 86#define EXIT_SUCCESS (SS$_NORMAL | STS$M_INHIB_MSG) 87#define EXIT_FAILURE (SS$_ABORT) 88#else 89#define EXIT_SUCCESS 0 90#define EXIT_FAILURE 1 91#endif 92#endif 93 94#define NUL 0x00 95#define CAN 0x18 96#define SUB 0x1A 97#define ESC 0x1B 98#define DEL 0x7F 99#define SS3 0x8f 100#define DCS 0x90 101#define CSI 0x9B 102#define ST 0x9C 103#define OSC 0x9D 104#define PM 0x9E 105#define APC 0x9F 106 107static int kbinr(int max_delay); 108 109/* 110 * Escape sequence parser, obscure but useful. 111 */ 112int chparse( 113int max_delay, 114int rest_delay, 115int *state, /* Parser state (n.z. if incomplete) */ 116int *private, /* Sequence private char, 'X' if error */ 117int param[], /* numeric param, starting at param[1] */ 118int *nparam, /* Number of parameters */ 119int inter[], /* intermediate char, starting at [1] */ 120int *ninter, /* Number of intermediates */ 121int *final) /* Sequence terminator */ 122{ 123 register int c; 124 register int i; 125 126 if (*state == 0) 127 *private = 0; 128label1: c = kbinr(max_delay); 129#if 0 130 printf("c %02x, *state %02x, *nparam %d\n", c, *state, *nparam); 131#endif 132 max_delay = rest_delay; 133label2: switch (c) { 134 case NUL: 135 case DEL: 136 goto label5; 137 case ESC: 138 case CSI: 139 case SS3: 140 case DCS: 141 case OSC: 142 case PM: 143 case APC: 144 *state = c; 145 *private = 0; 146 for (i = 0; i < NPARAM; i++) 147 param[i] = 0; 148 for (i = 0; i < NINTER; i++) 149 inter[i] = EOS; 150 *nparam = *ninter = 0; 151 goto label1; 152 } 153 if (*state == 0) 154 goto label5; 155 if ((c >= 0x80 && c < 0xA0) 156 || c == TIMEOUT 157 || c == ERROR 158 || c == CAN 159 || c == SUB) { 160 *state = 0; 161 goto label5; 162 } 163 if (c < 0x20) /* Doesn't stop seq. */ 164 goto label5; 165 if (c <= 0x2F) { 166 if (*ninter < 7) 167 inter[++*ninter] = c; 168 goto label1; 169 } 170 if (*state == ESC) { 171 if (*ninter == 0 172 && (c & 0x3F) < 0x20) { 173 c = (c & 0x3F) + 0x80; 174 goto label2; 175 } 176 goto label4; 177 } 178 if (c >= 0x40) 179 goto label3; 180 else if (c >= 0x3C) { /* Private introducer */ 181 if (*nparam != 0) 182 *private = 'X'; 183 else { 184 *private = c; 185 *nparam = 1; 186 } 187 goto label1; 188 } 189 if (*nparam == 0) 190 *nparam = 1; 191 if (*ninter != 0) { 192 *ninter = 0; 193 *private = 'X'; 194 } 195 if (c == ';') { 196 if (*nparam >= (NPARAM - 1)) 197 *private = 'X'; 198 else { 199 ++*nparam; 200 } 201 goto label1; 202 } 203 if (c > '9') { 204 *private = 'X'; 205 goto label1; 206 } 207 param[*nparam] = (param[*nparam] * 10) + (c - '0'); 208 goto label1; 209label3: if (*nparam == 0) 210 *nparam = 1; 211label4: *final = c; 212 c = *state; 213 *state = 0; 214label5: return (c); 215} 216 217void dumpsequence( 218int state, 219int c, 220int private, /* Sequence private char, 'X' if error */ 221int param[], /* numeric param, starting at param[1] */ 222int nparam, /* Number of parameters */ 223int inter[], /* intermediate char, starting at [1] */ 224int ninter, /* Number of intermediates */ 225int final, /* Sequence terminator */ 226short *column) /* column display count */ 227{ 228 register int i; 229 230 if (isascii(c) && isprint(c)) { 231 *column +=2; 232 if (*column >= 79) { 233 printf("\n"); 234 *column = 2; 235 } 236 printf("%c ", c); 237 } 238 else if (private == 'X') { 239 *column += strlen("bad sequence "); 240 if (*column >= 79) { 241 printf("\n"); 242 *column = strlen("bad sequence "); 243 } 244 printf("bad sequence "); 245 } 246 else if (state != NUL) { 247 *column += 32; 248 if (*column >= 79) { 249 printf("\n"); 250 *column = 32; 251 } 252 printf("incomplete sequence (type <%02x>) ", state); 253 } 254 else { 255 *column += 5; /* update total chars printed */ 256 if (*column >= 79) { 257 printf("\n"); 258 *column = 6; 259 } 260 switch (c) { 261 case ESC: printf("<ESC>"); break; 262 case DCS: printf("<DCS>"); break; 263 case CSI: printf("<CSI>"); break; 264 case SS3: printf("<SS3>"); break; 265 default: printf("<%02x>", c & 0xFF); 266 } 267 if (c == ESC || c == DCS || c == CSI || c == SS3) { 268 *column += 1 + nparam*2 + ninter + 1; /* total chars printed */ 269 if (*column >= 79) { 270 printf("\n"); 271 *column = 1 + nparam*2 + ninter + 1; 272 } 273 if (private != NUL && private != 'X') 274 printf("%c", private); 275 for (i = 1; i <= nparam; i++) 276 printf("%s%d", (i > 1) ? "," : " ", param[i]); 277 for (i = 1; i <= ninter; i++) 278 printf("%c", inter[i]); 279 printf("%c", final); 280 } 281 (*column)++; 282 if (*column >= 79) { 283 printf("\n"); 284 *column = 1; 285 } 286 printf(" "); 287 } 288} 289 290#ifdef vms 291/* 292 * Read a character from the terminal (with selectable timeout) 293 */ 294 295int 296kbinr(timeout) 297int timeout; /* In seconds, 0 == immediately */ 298/* 299 * Get one byte without echoing, if available. Returns 300 * ERROR Something is dwrong 301 * TIMEOUT Nothing read within limit. 302 * Note: 303 * timeout = 0 return immediately if nothing is present 304 * timeout = 1 Indeterminate, do not use 305 * timeout = 2 Wait at least one second. 306 */ 307{ 308 register int incount; 309 static char buffer[BUFFLEN]; 310 static char *bufptr = buffer; 311 static char *bufend = buffer; 312 313 if (bufptr >= bufend) { 314 bufptr = bufend = buffer; 315 incount = vmsread(buffer, BUFFLEN, 0); 316 if (incount == TIMEOUT) 317 incount = vmsread(buffer, 1, timeout); 318 if (incount <= 0) 319 return (incount); 320 bufend = &buffer[incount]; 321 } 322 return (*bufptr++ & 0xFF); 323} 324 325static int tt_channel; /* Gets channel number */ 326typedef struct { 327 short int status; 328 short int term_offset; 329 short int terminator; 330 short int term_size; 331} IOSTAB; 332 333int 334vmsread(buffer, size, timeout) 335char *buffer; 336int size; 337int timeout; 338{ 339 register int status; 340 IOSTAB iostab; 341 static $DESCRIPTOR(tt_device, "SYS$COMMAND"); 342 static long termset[2] = { 0, 0 }; /* No terminator */ 343 static short opened = FALSE; /* TRUE when opened */ 344 345 if (!opened) { 346 status = sys$assign(&tt_device, &tt_channel, 0, 0); 347 if (status != SS$_NORMAL) 348 lib$stop(status); 349 opened = TRUE; 350 } 351 status = sys$qiow( 352 0, /* Event flag */ 353 tt_channel, /* Input channel */ 354 IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED, 355 /* Read, no echo, no translate */ 356 &iostab, /* I/O status block */ 357 NULL, /* AST block (none) */ 358 0, /* AST parameter */ 359 buffer, /* P1 - input buffer */ 360 size, /* P2 - buffer length */ 361 timeout, /* P3 - timeout */ 362 &termset, /* P4 - terminator set */ 363 NULL, /* P5 - ignored (prompt buffer) */ 364 0 /* P6 - ignored (prompt size) */ 365 ); 366 if (status == SS$_TIMEOUT) 367 return (TIMEOUT); 368 else if (status != SS$_NORMAL) 369 return (ERROR); 370 else { 371 if ((status = iostab.term_offset + iostab.term_size) > 0) 372 return (status); 373 return (TIMEOUT); 374 } 375} 376#else 377static int 378kbinr(int max_delay) 379{ 380 auto int fdmask; 381 struct timeval timeout; 382 int count; 383 static unsigned char buffer[80]; 384 static unsigned char *bend; 385 static unsigned char *bptr; 386 387 if (bptr >= bend) { 388 fdmask = 1 << fileno(stdin); 389 timeout.tv_usec = 0; 390 timeout.tv_sec = max_delay; 391 count = select(fileno(stdin) + 1, (fd_set *)&fdmask, NULL, NULL, &timeout); 392 if (count < 0) 393 return (ERROR); 394 else if (count == 0) 395 return (TIMEOUT); 396 if (count >= sizeof buffer) 397 count = sizeof buffer; 398 count = read(fileno(stdin), buffer, count); 399 if (count <= 0) 400 return (ERROR); 401 bptr = buffer; 402 bend = buffer + count; 403 } 404 return (*bptr++); 405} 406#endif 407