Added support for interpreting ANSI escape sequences on behalf of
[people/mcb30/gpxe.git] / src / core / ansiesc.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <string.h>
20 #include <assert.h>
21 #include <gpxe/ansiesc.h>
22
23 /** @file
24  *
25  * ANSI escape sequences
26  *
27  */
28
29 /**
30  * Call ANSI escape sequence handler
31  *
32  * @v handlers          List of escape sequence handlers
33  * @v function          Control function identifier
34  * @v count             Parameter count
35  * @v params            Parameter list
36  */
37 static void ansiesc_call_handler ( struct ansiesc_handler *handlers,
38                                    unsigned int function, int count,
39                                    int params[] ) {
40         struct ansiesc_handler *handler;
41
42         for ( handler = handlers ; handler->function ; handler++ ) {
43                 if ( handler->function == function ) {
44                         handler->handle ( count, params );
45                         break;
46                 }
47         }
48 }
49
50 /**
51  * Process character that may be part of ANSI escape sequence
52  *
53  * @v ctx               ANSI escape sequence context
54  * @v c                 Character
55  * @ret c               Original character if not part of escape sequence
56  * @ret <0              Character was part of escape sequence
57  *
58  * ANSI escape sequences will be plucked out of the character stream
59  * and interpreted; once complete they will be passed to the
60  * appropriate handler if one exists in this ANSI escape sequence
61  * context.
62  *
63  * In the interests of code size, we are rather liberal about the
64  * sequences we are prepared to accept as valid.
65  */
66 int ansiesc_process ( struct ansiesc_context *ctx, int c ) {
67         if ( ctx->count == 0 ) {
68                 if ( c == ESC ) {
69                         /* First byte of CSI : begin escape sequence */
70                         ctx->count = 1;
71                         memset ( ctx->params, 0xff, sizeof ( ctx->params ) );
72                         ctx->function = 0;
73                         return -1;
74                 } else {
75                         /* Normal character */
76                         return c;
77                 }
78         } else {
79                 if ( c == '[' ) {
80                         /* Second byte of CSI : do nothing */
81                 } else if ( ( c >= '0' ) && ( c <= '9' ) ) {
82                         /* Parameter Byte : part of a parameter value */
83                         int *param = &ctx->params[ctx->count - 1];
84                         if ( *param < 0 )
85                                 *param = 0;
86                         *param = ( ( *param * 10 ) + ( c - '0' ) );
87                 } else if ( c == ';' ) {
88                         /* Parameter Byte : parameter delimiter */
89                         ctx->count++;
90                         if ( ctx->count > ( sizeof ( ctx->params ) /
91                                             sizeof ( ctx->params[0] ) ) ) {
92                                 /* Excessive parameters : abort sequence */
93                                 ctx->count = 0;
94                                 DBG ( "Too many parameters in ANSI escape "
95                                       "sequence\n" );
96                         }
97                 } else if ( ( c >= 0x20 ) && ( c <= 0x2f ) ) {
98                         /* Intermediate Byte */
99                         ctx->function <<= 8;
100                         ctx->function |= c;
101                 } else {
102                         /* Treat as Final Byte.  Zero ctx->count before 
103                          * calling handler to avoid potential infinite loops.
104                          */
105                         int count = ctx->count;
106                         ctx->count = 0;
107                         ctx->function <<= 8;
108                         ctx->function |= c;
109                         ansiesc_call_handler ( ctx->handlers, ctx->function,
110                                                count, ctx->params );
111                 }
112                 return -1;
113         }
114 }