File: ansiesc.c

package info (click to toggle)
mknbi 1.4.4-7
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 852 kB
  • ctags: 1,381
  • sloc: ansic: 3,511; asm: 2,374; perl: 1,368; makefile: 208; sh: 65; pascal: 37
file content (468 lines) | stat: -rw-r--r-- 14,040 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
#include "stddef.h"
#include "string.h"
#include "etherboot.h"
#include "ansiesc.h"

/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 */

/*
 *	Display attributes
 *
 *	Code          Effect
 *	<esc>[0m      normal text
 *	<esc>[1m      high-intensity on
 *	<esc>[21m     high-intensity off
 *	<esc>[5m      blinking on
 *	<esc>[25m     blinking off
 *	<esc>[7m      reverse video on
 *	<esc>[27m     reverse video off
 *	<esc>[3xm     set foreground color:
 *	<esc>[4xm     set background color. x can be:
 *			   0 - black                   4 - blue
 *			   1 - red                     5 - magenta
 *			   2 - green                   6 - cyan
 *			   3 - yellow                  7 - white
 *	<esc>[=xh     set video mode
 *			   0 - 40x25 mono     (text)  13 - 40x25 16colors (gfx)
 *			   1 - 40x25 16colors (text)  14 - 80x25 16colors (gfx)
 *			   2 - 80x25 mono     (text)  15 - 80x25 mono     (gfx)
 *			   3 - 80x25 16colors (text)  16 - 80x25 16colors (gfx)
 *			   4 - 40x25 4colors  (gfx)   17 - 80x30 mono     (gfx)
 *			   5 - 40x25 mono     (gfx)   18 - 80x30 16colors (gfx)
 *			   6 - 80x25 mono     (gfx)   19 - 40x25 256colors(gfx)
 *
 *
 *	Cursor control
 *
 *	Code          Effect
 *	<esc>[r;cH    move cursor to row r col c (r and c are both numbers)
 *	<esc>[r;cf    move cursor to row r col c (r and c are both numbers)
 *	<esc>[rA      move cursor up r rows
 *	<esc>[rB      move cursor down r rows
 *	<esc>[cC      move cursor right c columns
 *	<esc>[cD      move cursor left c columns
 *	<esc>[?7l     turn off line wrap
 *	<esc>[?7h     turn on line wrap
 *	<esc>[J       clear screen and home cursor
 *	<esc>[K       clear to end of line
 *	<esc>[s       save the cursor position
 *	<esc>[u       return cursor to saved position
 *
 *	Extended features
 *
 *	Code          Effect
 *      <esc>[a;b;c;d+<data>
 *                    draw pixel data; use one byte per pixel. Parameters
 *                    differ depending on the number of parameters passed:
 *                    cnt
 *                      "cnt" bytes follow; they will be drawn to the
 *                      right of the last graphics position
 *                    rle;col
 *                      the next "rle" pixels have the value "col"; they
 *                      will be drawn to the right of the last graphics
 *                      position
 *                    x;y;cnt
 *                      "cnt" bytes follow; they will be drawn relative to
 *                      the text cursor position with an offset of (x/y)
 *                    x;y;rle;col
 *                      the next "rle" pixels have the value "col"; the
 *                      will be drawn relative to the text cursor position
 *                      with an offset of (x/y)
 *      <esc>[a;b;c;d-<data>
 *                      same as above, but pack pixels into three bits.
 *
 */

#define MAXARGS		8
#define MAXSTRARGS	1
#define MAXSTRARGLEN	40

extern union {
  struct {
    unsigned char al,ah,bl,bh,cl,ch,dl,dh;
  } __attribute__ ((packed)) lh;
  struct {
    unsigned short ax,bx,cx,dx;
  } __attribute__ ((packed)) x;
  unsigned long axbx;
} __attribute__ ((packed)) int10ret;

union axbxstruct {
  struct {
    unsigned char al,ah,bl,bh;
  } __attribute__ ((packed)) lh;
  struct {
    unsigned short ax,bx;
  } __attribute__ ((packed)) x;
  unsigned long axbx;
} __attribute__ ((packed));

#define int10(a,b,c,d) _int10((unsigned long)(a)+((unsigned long)(b)<<16), \
			      (unsigned long)(c)+((unsigned long)(d)<<16))
extern unsigned long _int10(unsigned long axbx,unsigned long cxdx);

static enum { esc_init, esc_std, esc_esc, esc_bracket, esc_digit,
	      esc_semicolon, esc_str, esc_quote
} esc_state = esc_init;

/* Don't declare these static, so we can access them from code in other files */
unsigned short rows,columns,attr = 7;

static unsigned short scr,cx = 0,cy = 0, scx = 0,scy = 0;
static int fg = 7, bg = 0, blink = 0,reverse = 0, bright = 0;
static int wraparound = 1;
static int argn = 0;
static int argi[MAXARGS];
static char args[MAXSTRARGS][MAXSTRARGLEN];
static const unsigned char coltable[9] = "\000\004\002\006\001\005\003\007";
#ifdef	GFX
static unsigned short gfx_rows,gfx_columns,char_width,char_height,gfx_x,gfx_y;
static int in_gfx = 0, gfx_packed,gfx_data,gfx_nbits;
static int defaultmode = -1, curmode = -1, curmodetype = 0;
#endif

void ansi_reset(void)
{
#ifdef	GFX
  /* this will not execute, when the serial console is used, because
     both curmode and defaultmode will be -1 */
  if (curmode != defaultmode) {
    in_gfx = 0;
    curmodetype = 0;
    int10(curmode = defaultmode,0,0,0);
    esc_state = esc_init;
    ansi_putc('\010'); /* force reinitialization */ }
  return;
#endif
}

void enable_cursor(int enable)
{
#ifdef	GFX
  /* this will not execute, when the serial console is used, because
     curmodetype will be 0 */
  if (curmodetype == 'G' || curmodetype == 'H') {
    if (enable)
      int10(0x09DB,7,1,0);
    else
      int10(0x0920,(attr/16)&7,1,0); }
  return;
#endif
}

static void docommand(unsigned char ch)
{
#ifdef	GFX
  if (ch == '+' || ch == '-') { /* gfx bitmap */
    int i;
    gfx_packed = ((ch == '-') ? 3 : 8);
    gfx_nbits  = 0;
    if (argn > 2) {
      gfx_x    = argi[0];
      gfx_y    = argi[1];
      if (curmodetype == 'T') {
	gfx_x += cx;
	gfx_y += cy; }
      else {
	gfx_x += cx*char_width;
	gfx_y += cy*char_height; }
      i        = 2; }
    else
      i        = 0;
    in_gfx   = argi[i+0];
    if (argn == i+2)
      while (in_gfx)
	ansi_putc(argi[i+1]); }
  else
#endif
  if (ch == 'm') { /* set attribute */
    int i,j;
    for (j = 0; (i = argi[j]), (j++ < argn); )
      if (i == 0 ||       /* reset attributes */
	  i == 20) {
	blink = reverse = bright = bg = 0; fg = 7;
	goto doattr; }
      else if (i == 1) {  /* high intensity on */
	bright = 1;
	goto doattr; }
      else if (i == 21) { /* high intensity off */
	bright = 0;
	goto doattr; }
      else if (i == 5) {  /* blinking on */
	blink = 1;
	goto doattr; }
      else if (i == 25) { /* blinking off */
	blink = 0;
	goto doattr; }
      else if (i == 7) {  /* reverse video on */
	reverse = 1;
      isreverse:
	attr =
#ifdef	GFX
	  curmodetype != 'T' ? (fg?128:0)+16*fg+(fg^(8*bright+bg)) :
#endif
	  128*blink+16*fg+8*bright+bg; }
      else if (i == 27) { /* reverse video off */
	reverse = 0;
      isnormal:
	attr =
#ifdef	GFX
	  curmodetype != 'T' ? (bg?128:0)+16*bg+(bg^(8*bright+fg)) :
#endif
	  128*blink+16*bg+8*bright+fg; }
      else if (i >= 30 && i <= 37) {
	fg = coltable[i-30];
      doattr:
	if (reverse) goto isreverse; else goto isnormal; }
      else if (i >= 40 && i <= 47) {
	bg = coltable[i-40];
	goto doattr; } }
  else if (ch == 'H' || /* set cursor position */
	   ch == 'f') { /* set cursor position */
    cy = argi[0];
    cx = argi[1];
    updatecursor:
    int10(0x0200,256*scr,0,256*cy+cx); }
  else if (ch == 'A') { /* move cursor up */
    if (cy < argi[0]) cy = 0;
    else              cy -= argi[0];
    goto updatecursor; }
  else if (ch == 'B') { /* move cursor down */
    if ((cy += argi[0]) >= rows) cy = rows-1;
    goto updatecursor; }
  else if (ch == 'C') { /* move cursor right */
    if ((cx += argi[0]) >= columns) cx = columns-1;
    goto updatecursor; }
  else if (ch == 'D') { /* move cursor left */
    if (cx < argi[0]) cx = 0;
    else              cx -= argi[0];
    goto updatecursor; }
  else if (ch == 'l') { /* turn off line wrapping or set text mode */
    if (argi[0] == 7)
      wraparound = 0;
#ifdef	GFX
    else {  /* text mode */
      curmodetype = 0;
      int10(curmode = defaultmode,0,0,0);
      esc_state = esc_init; }
#endif
  }
  else if (ch == 'h') { /* turn on line wrapping or set graphics mode */
    if (argi[0] == 7)
      wraparound = 1;
#ifdef	GFX
    else {  /* graphics mode */
      curmodetype = 0;
      int10(curmode = argi[0],0,0,0);
      esc_state = esc_init; }
#endif
  }
  else if (ch == 'J') { /* clear screen and home cursor */
#ifdef	GFX
    int10(0x0600,256*(curmodetype != 'T' ? reverse ? fg : bg : attr),0,
	  256*(rows-1)+columns-1);
#else
    int10(0x0600,256*attr,0,256*(rows-1)+columns-1);
#endif
    cx = cy = 0;
    goto updatecursor; }
  else if (ch == 'K')   /* clear to end of line */
#ifdef	GFX
    int10(curmodetype == 'T' ? 0x0920 : 0x09DB,
	  curmodetype == 'T' ? 256*scr+attr : reverse ? fg : bg,
	  columns-cx,0);
#else
    int10(0x0920,256*scr+attr,columns-cx,0);
#endif
  else if (ch == 's') { /* save cursor position */
    scx = cx; scy = cy; }
  else if (ch == 'u') { /* restore cursor position */
    cx = scx; cy = scy;
    goto updatecursor; }
  return;
}

void ansi_putc(unsigned int ch)
{
  union axbxstruct u;

#ifdef	GFX
  if (in_gfx) {
    gfx_data   = (gfx_data << 8) | ch;
    gfx_nbits += 8;
    while (gfx_nbits >= gfx_packed && in_gfx) {
      in_gfx--;
      ch = (gfx_data >> (gfx_nbits -= gfx_packed)) & ((1 << gfx_packed) - 1);
      if (curmodetype == 'T') {
	if (gfx_x < columns && gfx_y < rows*2) {
	  int pix[2];
	  int10(0x0200,256*scr,0,        /* move cursor position */
		256*(gfx_y/2)+gfx_x++);
	  u.axbx = int10(0x0800,256*scr,0,0);     /* read character/attribute */
	  if (u.lh.al == 0xDB)
	    pix[0] = pix[1] =  u.lh.ah    &0xF;
	  else if (u.lh.al == 0xDC) {
	    pix[0] =          (u.lh.ah/16)&0xF;
	    pix[1] =           u.lh.ah    &0xF; }
	  else
	    pix[0] = pix[1] = (u.lh.ah/16)&0xF;
	  pix[gfx_y&1] = coltable[ch & 0x7];
	  int10(0x0900|                  /* output char */
		(pix[0]==pix[1]?0xDB:0xDC),
		256*scr+(0x7F&(pix[0]*16+pix[1])),1,0); }
	if (!in_gfx)
	  int10(0x0200,256*scr,0,        /* restore cursor position */
		256*cy+cx); }
      else if (gfx_x < gfx_columns && gfx_y < gfx_rows)
	int10(0x0C00|                    /* write pixel */
	      (ch <= 7 ? coltable[ch] : ch),256*scr,gfx_x++,gfx_y); }
    return; }
#endif
  switch (esc_state) {
  case esc_esc:
    if (ch == '[') {
      esc_state = esc_bracket;
      argn = 0;
      memset(&argi, 0, sizeof(argi));
      memset(args, 0, MAXSTRARGS*MAXSTRARGLEN); }
    else {
      esc_state = esc_std;
      goto doputchar; }
    break;
  case esc_bracket:
  case esc_semicolon:
    if (ch == '\'') {
      esc_state = esc_str;
      break; }
    /* fall thru */
    if (ch == '=' || ch == '?')
      break;
    /* fall thru */
  case esc_digit:
    if (ch >= '0' && ch <= '9') {
      esc_state = esc_digit;
      if (argn < MAXARGS)
	argi[argn] = 10*argi[argn] + ch - '0'; }
    else
      quote:
      if (ch == ';') {
      esc_state = esc_semicolon;
      argn++; }
    else {
      if (esc_state == esc_digit || esc_state == esc_quote)
	argn++;
      esc_state = esc_std;
      docommand(ch); }
    break;
  case esc_str:
    if (ch == '\'') {
      esc_state = esc_quote;
      break; }
    { int i;
    if (argn < MAXSTRARGS && (i = strlen(args[argn])) < MAXSTRARGLEN-2)
      args[argn][i] = ch; }
    break;
  case esc_quote:
    goto quote;
  case esc_init: {
    int i;
    esc_state = esc_std;
    u.axbx = int10(0x0F00,0,0,0);                 /* get graphics mode information */
#ifdef	GFX
    if (defaultmode < 0)
      defaultmode = curmode = u.lh.al ? u.lh.al : 3;
#endif
    columns = u.lh.ah;
    scr     = u.lh.bh;
    int10(0x0200,256*scr,0,0);           /* put cursor to home position */
    for (i = 0; ++i < 100; ) {
      int10(0x0E0A,256*scr,0,0);         /* output LF */
      int10(0x0300,256*scr,0,0);         /* get cursor position */
      if (int10ret.lh.dh != i)	         /* row */
	break; }
    rows    = i;
    int10(0x0200,256*scr,0,0);           /* put cursor to home position */
#ifdef	GFX
    char_width  = 8;
    char_height = *(unsigned char *)0x485;
    if (char_height < 8 || char_height > 20)
      char_height = 8;
    gfx_columns = char_width*columns;
    gfx_rows    = char_height*rows;
    if (!curmodetype) {
      int10(0x0941,256*scr+127,1,0);     /* 'A', bright, white on white */
      u.axbx = int10(0x0800,256*scr,0,0);         /* read character/attribute */
      if (u.lh.al == 0x41 &&
	  u.lh.ah == 127)
	curmodetype = 'T';
      else {
	int10(0x0C40,256*scr,0,0);       /* write pixel */
	u.axbx = int10(0x0D00,256*scr,0,0);       /* read pixel color */
	if (u.lh.al == 0x40)
	  curmodetype = 'H';
	else
	  curmodetype = 'G'; } }
#endif
    attr = fg = 7;
    cx = cy = scx = scy = bg = blink = reverse = bright = 0;
    wraparound = 1;
#ifdef	GFX
    int10(0x0600,                        /* clear screen */
	  curmodetype != 'T' ? 0 : 7*256,0,256*(rows-1)+columns-1); }
#else
    int10(0x0600,                        /* clear screen */
	  7*256,0,256*(rows-1)+columns-1); }
#endif

    /* fall thru */
  default:
    if (ch == 0x1B)
      esc_state = esc_esc;
    else if (ch == '\t') {
      int i;
      for (i = 8-cx%8; i--; ) ansi_putc(' '); }
    else if (ch == '\r') {
      cx = 0; goto updatecursor; }
    else if (ch == '\n') {
      ansi_putc('\r'); goto newline; }
    else if (ch == '\010') {
      if (cx) {
	cx--; goto updatecursor; } }
    else {
    doputchar:
#ifdef	GFX
      if (curmodetype == 'G' && (reverse ? fg : bg))
	int10(0x09DB,(attr/16)&0x07,1,0);/* set background in gfx mode */
#endif
#ifdef	GFX
      int10(0x0900|ch,                   /* output char */
	    curmodetype == 'H' ? reverse ? fg*256+bg : bg*256+fg :
	    256*scr+attr,1,0);
#else
      int10(0x0900|ch,256*scr+attr,1,0); /* output char */
#endif
      if (++cx == columns) {
	if (!wraparound)
	  cx--;
        else {
	  cx = 0;
	newline:
	  if (++cy == rows)
#ifdef	GFX
	    int10(0x0601,                /* scroll screen */
		  256*(curmodetype != 'T' ? reverse ? fg : bg : attr),0,
		  256*--cy+columns-1); }
#else
	    int10(0x0601,256*attr,0,     /* scroll screen */
		  256*--cy+columns-1); }
#endif
      }
    updatecursor:
      int10(0x0200,256*scr,0,256*cy+cx); /* update cursor position */ } }
  return;
}