Added support for interpreting ANSI escape sequences on behalf of
authorMichael Brown <mcb30@etherboot.org>
Mon, 18 Dec 2006 00:01:30 +0000 (00:01 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 18 Dec 2006 00:01:30 +0000 (00:01 +0000)
non-ANSI-capable consoles.

src/core/ansiesc.c [new file with mode: 0644]
src/include/gpxe/ansiesc.h [new file with mode: 0644]

diff --git a/src/core/ansiesc.c b/src/core/ansiesc.c
new file mode 100644 (file)
index 0000000..6b820ad
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <gpxe/ansiesc.h>
+
+/** @file
+ *
+ * ANSI escape sequences
+ *
+ */
+
+/**
+ * Call ANSI escape sequence handler
+ *
+ * @v handlers         List of escape sequence handlers
+ * @v function         Control function identifier
+ * @v count            Parameter count
+ * @v params           Parameter list
+ */
+static void ansiesc_call_handler ( struct ansiesc_handler *handlers,
+                                  unsigned int function, int count,
+                                  int params[] ) {
+       struct ansiesc_handler *handler;
+
+       for ( handler = handlers ; handler->function ; handler++ ) {
+               if ( handler->function == function ) {
+                       handler->handle ( count, params );
+                       break;
+               }
+       }
+}
+
+/**
+ * Process character that may be part of ANSI escape sequence
+ *
+ * @v ctx              ANSI escape sequence context
+ * @v c                        Character
+ * @ret c              Original character if not part of escape sequence
+ * @ret <0             Character was part of escape sequence
+ *
+ * ANSI escape sequences will be plucked out of the character stream
+ * and interpreted; once complete they will be passed to the
+ * appropriate handler if one exists in this ANSI escape sequence
+ * context.
+ *
+ * In the interests of code size, we are rather liberal about the
+ * sequences we are prepared to accept as valid.
+ */
+int ansiesc_process ( struct ansiesc_context *ctx, int c ) {
+       if ( ctx->count == 0 ) {
+               if ( c == ESC ) {
+                       /* First byte of CSI : begin escape sequence */
+                       ctx->count = 1;
+                       memset ( ctx->params, 0xff, sizeof ( ctx->params ) );
+                       ctx->function = 0;
+                       return -1;
+               } else {
+                       /* Normal character */
+                       return c;
+               }
+       } else {
+               if ( c == '[' ) {
+                       /* Second byte of CSI : do nothing */
+               } else if ( ( c >= '0' ) && ( c <= '9' ) ) {
+                       /* Parameter Byte : part of a parameter value */
+                       int *param = &ctx->params[ctx->count - 1];
+                       if ( *param < 0 )
+                               *param = 0;
+                       *param = ( ( *param * 10 ) + ( c - '0' ) );
+               } else if ( c == ';' ) {
+                       /* Parameter Byte : parameter delimiter */
+                       ctx->count++;
+                       if ( ctx->count > ( sizeof ( ctx->params ) /
+                                           sizeof ( ctx->params[0] ) ) ) {
+                               /* Excessive parameters : abort sequence */
+                               ctx->count = 0;
+                               DBG ( "Too many parameters in ANSI escape "
+                                     "sequence\n" );
+                       }
+               } else if ( ( c >= 0x20 ) && ( c <= 0x2f ) ) {
+                       /* Intermediate Byte */
+                       ctx->function <<= 8;
+                       ctx->function |= c;
+               } else {
+                       /* Treat as Final Byte.  Zero ctx->count before 
+                        * calling handler to avoid potential infinite loops.
+                        */
+                       int count = ctx->count;
+                       ctx->count = 0;
+                       ctx->function <<= 8;
+                       ctx->function |= c;
+                       ansiesc_call_handler ( ctx->handlers, ctx->function,
+                                              count, ctx->params );
+               }
+               return -1;
+       }
+}
diff --git a/src/include/gpxe/ansiesc.h b/src/include/gpxe/ansiesc.h
new file mode 100644 (file)
index 0000000..9848589
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _GPXE_ANSIESC_H
+#define _GPXE_ANSIESC_H
+
+/** @file
+ *
+ * ANSI escape sequences
+ *
+ * ANSI X3.64 (aka ECMA-48 or ISO/IEC 6429, available from
+ * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf)
+ * defines escape sequences consisting of:
+ *
+ *     A Control Sequence Introducer (CSI)
+ *
+ *     Zero or more Parameter Bytes (P)
+ *
+ *     Zero or more Intermediate Bytes (I)
+ *
+ *     A Final Byte (F)
+ *
+ * The CSI consists of ESC (0x1b) followed by "[" (0x5b).  The
+ * Parameter Bytes, for a standardised (i.e. not private or
+ * experimental) sequence, consist of a list of ASCII decimal integers
+ * separated by semicolons.  The Intermediate Bytes (in the range 0x20
+ * to 0x2f) and the Final Byte (in the range 0x40 to 0x4f) determine
+ * the control function.
+ * 
+ */
+
+/** A handler for an escape sequence */
+struct ansiesc_handler {
+       /** The control function identifier
+        *
+        * The control function identifier consists of the
+        * Intermediate Bytes (if any) and the Final Byte.  In
+        * practice, no more than one immediate byte is ever used, so
+        * the byte combination can be efficiently expressed as a
+        * single integer, in the obvious way (with the Final Byte
+        * being the least significant byte).
+        */
+       unsigned int function;
+       /** Handle escape sequence
+        *
+        * @v count             Parameter count
+        * @v params            Parameter list
+        *
+        * A negative parameter value indicates that the parameter was
+        * omitted and that the default value for this control
+        * function should be used.
+        *
+        * Since all parameters are optional, there is no way to
+        * distinguish between "zero parameters" and "single parameter
+        * omitted".  Consequently, the parameter list will always
+        * contain at least one item.
+        */
+       void ( * handle ) ( unsigned int count, int params[] );
+};
+
+/** Maximum number of parameters within a single escape sequence */
+#define ANSIESC_MAX_PARAMS 4
+
+/**
+ * ANSI escape sequence context
+ *
+ * This provides temporary storage for processing escape sequences,
+ * and points to the list of escape sequence handlers.
+ */
+struct ansiesc_context {
+       /** Array of handlers
+        *
+        * Must be terminated by a handler with @c function set to
+        * zero.
+        */
+       struct ansiesc_handler *handlers;
+       /** Parameter count
+        *
+        * Will be zero when not currently in an escape sequence.
+        */
+       unsigned int count;
+       /** Parameter list */ 
+       int params[ANSIESC_MAX_PARAMS];
+       /** Control function identifier */
+       unsigned int function;
+};
+
+/** Escape character */
+#define ESC 0x1b
+
+/** Control Sequence Introducer */
+#define CSI "\033["
+
+/**
+ * @defgroup ansifuncs ANSI escape sequence function identifiers
+ * @{
+ */
+
+/** Character and line position */
+#define ANSIESC_HVP 'f'
+
+/** @} */
+
+extern int ansiesc_process ( struct ansiesc_context *ctx, int c );
+
+#endif /* _GPXE_ANSIESC_H */