commit 99edda3865bd2e6dd4f1d079e044e09d46b3849d
parent ab3cc58956427af1fb831bf0378cf6b061d1bc9f
Author: Frederic Cambus <fred@statdns.com>
Date: Fri, 25 Sep 2020 22:43:31 +0200
Refactor the ANSI loader to use a state machine.
Diffstat:
M | src/loaders/ansi.c | | | 545 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
1 file changed, 282 insertions(+), 263 deletions(-)
diff --git a/src/loaders/ansi.c b/src/loaders/ansi.c
@@ -30,6 +30,10 @@
#define ANSI_SEQUENCE_MAX_LENGTH 14
#define ANSI_BUFFER_SIZE 65536
+#define STATE_TEXT 0
+#define STATE_SEQUENCE 1
+#define STATE_END 2
+
/* Character structure */
struct ansiChar {
int32_t column;
@@ -83,6 +87,7 @@ ansilove_ansi(struct ansilove_ctx *ctx, struct ansilove_options *options)
/* character definitions */
uint8_t current_character, character;
+ uint8_t *cursor, state = STATE_TEXT;
uint8_t ansi_sequence_character;
/* default color values */
@@ -97,6 +102,7 @@ ansilove_ansi(struct ansilove_ctx *ctx, struct ansilove_options *options)
int32_t saved_row = 0, saved_column = 0;
/* sequence parsing variables */
+ uint32_t maxlength;
uint32_t seqValue, seq_line, seq_column;
char *seqGrab = NULL;
char *seqTok = NULL;
@@ -113,336 +119,349 @@ ansilove_ansi(struct ansilove_ctx *ctx, struct ansilove_options *options)
/* ANSi interpreter */
while (loop < ctx->length) {
current_character = ctx->buffer[loop];
+ cursor = &ctx->buffer[loop];
if (column == options->columns) {
row++;
column = 0;
}
- switch (current_character) {
- case LF:
- row++;
- column = 0;
- break;
- case CR:
- break;
- case TAB:
- column += 8;
- break;
- case SUB:
- loop = ctx->length;
- break;
- case ESC: /* ANSi sequence */
- if ((loop+1 < ctx->length) && ctx->buffer[loop + 1] == 91) {
-
- uint32_t maxlength = fmin(ctx->length - loop + 1, ANSI_SEQUENCE_MAX_LENGTH);
- for (ansi_sequence_loop = 0; ansi_sequence_loop < maxlength; ansi_sequence_loop++) {
- ansi_sequence_character = ctx->buffer[loop + 2 + ansi_sequence_loop];
-
- /* cursor position */
- if (ansi_sequence_character == 'H' || ansi_sequence_character == 'f') {
- /* create substring from the sequence's content */
- seq_line = 1;
- seq_column = 1;
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
-
- if (!strncmp(seqGrab, ";", 1)) {
- seq_line = 1;
- seqTok = strtok(seqGrab, ";");
-
- if (seqTok)
- seq_column = strtonum(seqTok, 0, UINT32_MAX, &errstr);
+ switch (state) {
+ case STATE_TEXT:
+ switch (*cursor) {
+ case LF:
+ row++;
+ column = 0;
+ break;
+ case CR:
+ break;
+ case TAB:
+ column += 8;
+ break;
+ case SUB:
+ state = STATE_END;
+ break;
+ case ESC:
+ /* ANSi sequence */
+ if ((loop+1 < ctx->length) && ctx->buffer[loop + 1] == 91) {
+ state = STATE_SEQUENCE;
+ loop++;
+ }
+ break;
+ default:
+ /* record number of columns and lines used */
+ if (column > columnMax)
+ columnMax = column;
+
+ if (row > rowMax)
+ rowMax = row;
+
+ /* write current character in ansiChar structure */
+ if (!fontData.isAmigaFont || (current_character != 12 && current_character != 13)) {
+ /* reallocate structure array memory */
+ if (structIndex == ansi_buffer_size) {
+ ansi_buffer_size += ANSI_BUFFER_SIZE;
+
+ ptr = realloc(ansi_buffer, ansi_buffer_size * sizeof(struct ansiChar));
+
+ if (ptr == NULL) {
+ ctx->error = ANSILOVE_MEMORY_ERROR;
+ free(ansi_buffer);
+ return -1;
} else {
- seqTok = strtok(seqGrab, ";");
- if (seqTok)
- seq_line = strtonum(seqTok, 0, UINT32_MAX, &errstr);
-
- seqTok = strtok(NULL, ";");
- if (seqTok)
- seq_column = strtonum(seqTok, 0, UINT32_MAX, &errstr);
+ ansi_buffer = ptr;
}
-
- /* set the positions */
- row = seq_line-1;
- column = seq_column-1;
-
- loop += ansi_sequence_loop+2;
- free(seqGrab);
- break;
}
- /* cursor up */
- if (ansi_sequence_character == 'A') {
- /* create substring from the sequence's content */
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
+ if (invert) {
+ ansi_buffer[structIndex].background = foreground % 8;
+ ansi_buffer[structIndex].foreground = background + (foreground & 8);
+ } else {
+ ansi_buffer[structIndex].background =
+ background24 ? background24 : background;
- /* now get escape sequence's position value */
- uint32_t seq_line = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
- free(seqGrab);
+ ansi_buffer[structIndex].foreground =
+ foreground24 ? foreground24 : foreground;
+ }
+ ansi_buffer[structIndex].character = current_character;
+ ansi_buffer[structIndex].column = column;
+ ansi_buffer[structIndex].row = row;
- row -= seq_line ? seq_line : 1;
+ structIndex++;
+ column++;
+ }
+ }
+ break;
+ case STATE_SEQUENCE:
+ maxlength = fmin(ctx->length - loop, ANSI_SEQUENCE_MAX_LENGTH);
+ for (ansi_sequence_loop = 0; ansi_sequence_loop < maxlength; ansi_sequence_loop++) {
+ ansi_sequence_character = ctx->buffer[loop + ansi_sequence_loop];
+
+ /* cursor position */
+ if (ansi_sequence_character == 'H' || ansi_sequence_character == 'f') {
+ /* create substring from the sequence's content */
+ seq_line = 1;
+ seq_column = 1;
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
+
+ if (!strncmp(seqGrab, ";", 1)) {
+ seq_line = 1;
+ seqTok = strtok(seqGrab, ";");
- if (row < 0)
- row = 0;
+ if (seqTok)
+ seq_column = strtonum(seqTok, 0, UINT32_MAX, &errstr);
+ } else {
+ seqTok = strtok(seqGrab, ";");
+ if (seqTok)
+ seq_line = strtonum(seqTok, 0, UINT32_MAX, &errstr);
- loop += ansi_sequence_loop+2;
- break;
+ seqTok = strtok(NULL, ";");
+ if (seqTok)
+ seq_column = strtonum(seqTok, 0, UINT32_MAX, &errstr);
}
- /* cursor down */
- if (ansi_sequence_character == 'B') {
- /* create substring from the sequence's content */
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
-
- /* now get escape sequence's position value */
- uint32_t seq_line = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
- free(seqGrab);
-
- row += seq_line ? seq_line : 1;
+ /* set the positions */
+ row = seq_line-1;
+ column = seq_column-1;
- loop += ansi_sequence_loop+2;
- break;
- }
+ loop += ansi_sequence_loop;
+ free(seqGrab);
+ break;
+ }
- /* cursor forward */
- if (ansi_sequence_character == 'C') {
- /* create substring from the sequence's content */
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
+ /* cursor up */
+ if (ansi_sequence_character == 'A') {
+ /* create substring from the sequence's content */
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
- /* now get escape sequence's position value */
- uint32_t seq_column = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
- free(seqGrab);
+ /* now get escape sequence's position value */
+ uint32_t seq_line = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
+ free(seqGrab);
- column += seq_column ? seq_column : 1;
+ row -= seq_line ? seq_line : 1;
- if (column > options->columns)
- column = options->columns;
+ if (row < 0)
+ row = 0;
- loop += ansi_sequence_loop+2;
- break;
- }
+ loop += ansi_sequence_loop;
+ break;
+ }
- /* cursor backward */
- if (ansi_sequence_character == 'D') {
- /* create substring from the sequence's content */
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
+ /* cursor down */
+ if (ansi_sequence_character == 'B') {
+ /* create substring from the sequence's content */
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
- /* now get escape sequence's content length */
- uint32_t seq_column = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
- free(seqGrab);
+ /* now get escape sequence's position value */
+ uint32_t seq_line = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
+ free(seqGrab);
- column -= seq_column ? seq_column : 1;
+ row += seq_line ? seq_line : 1;
- if (column < 0)
- column = 0;
+ loop += ansi_sequence_loop;
+ break;
+ }
- loop += ansi_sequence_loop+2;
- break;
- }
+ /* cursor forward */
+ if (ansi_sequence_character == 'C') {
+ /* create substring from the sequence's content */
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
- /* save cursor position */
- if (ansi_sequence_character == 's') {
- saved_row = row;
- saved_column = column;
+ /* now get escape sequence's position value */
+ uint32_t seq_column = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
+ free(seqGrab);
- loop += ansi_sequence_loop+2;
- break;
- }
+ column += seq_column ? seq_column : 1;
- /* restore cursor position */
- if (ansi_sequence_character == 'u') {
- row = saved_row;
- column = saved_column;
+ if (column > options->columns)
+ column = options->columns;
- loop += ansi_sequence_loop+2;
- break;
- }
+ loop += ansi_sequence_loop;
+ break;
+ }
- /* erase display */
- if (ansi_sequence_character == 'J') {
- /* create substring from the sequence's content */
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
+ /* cursor backward */
+ if (ansi_sequence_character == 'D') {
+ /* create substring from the sequence's content */
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
- /* convert grab to an integer */
- uint32_t eraseDisplayInt = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
- free(seqGrab);
+ /* now get escape sequence's content length */
+ uint32_t seq_column = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
+ free(seqGrab);
- if (eraseDisplayInt == 2) {
- column = 0;
- row = 0;
+ column -= seq_column ? seq_column : 1;
- columnMax = 0;
- rowMax = 0;
+ if (column < 0)
+ column = 0;
- /* reset ansi buffer */
- structIndex = 0;
- }
- loop += ansi_sequence_loop+2;
- break;
- }
+ loop += ansi_sequence_loop;
+ break;
+ }
- /* set graphics mode */
- if (ansi_sequence_character == 'm') {
- /* create substring from the sequence's content */
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
+ /* save cursor position */
+ if (ansi_sequence_character == 's') {
+ saved_row = row;
+ saved_column = column;
- seqTok = strtok(seqGrab, ";");
- while (seqTok) {
- seqValue = strtonum(seqTok, 0, UINT32_MAX, &errstr);
-
- if (seqValue == 0) {
- background = 0;
- background24 = 0;
- foreground = 7;
- foreground24 = 0;
- bold = false;
- blink = false;
- invert = false;
- }
+ loop += ansi_sequence_loop;
+ break;
+ }
- if (seqValue == 1) {
- if (!workbench) {
- foreground += 8;
- }
- bold = true;
- foreground24 = 0;
- }
+ /* restore cursor position */
+ if (ansi_sequence_character == 'u') {
+ row = saved_row;
+ column = saved_column;
- if (seqValue == 5) {
- if (!workbench && options->icecolors)
- background += 8;
+ loop += ansi_sequence_loop;
+ break;
+ }
- blink = true;
- background24 = 0;
- }
+ /* erase display */
+ if (ansi_sequence_character == 'J') {
+ /* create substring from the sequence's content */
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
- if (seqValue == 7)
- invert = true;
+ /* convert grab to an integer */
+ uint32_t eraseDisplayInt = strtonum(seqGrab, 0, UINT32_MAX, &errstr);
+ free(seqGrab);
- if (seqValue == 27)
- invert = false;
+ if (eraseDisplayInt == 2) {
+ column = 0;
+ row = 0;
- if (seqValue > 29 && seqValue < 38) {
- foreground = seqValue - 30;
- foreground24 = 0;
+ columnMax = 0;
+ rowMax = 0;
- if (bold)
- foreground += 8;
- }
+ /* reset ansi buffer */
+ structIndex = 0;
+ }
+ loop += ansi_sequence_loop;
+ break;
+ }
- if (seqValue > 39 && seqValue < 48) {
- background = seqValue - 40;
- background24 = 0;
+ /* set graphics mode */
+ if (ansi_sequence_character == 'm') {
+ /* create substring from the sequence's content */
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
+
+ seqTok = strtok(seqGrab, ";");
+ while (seqTok) {
+ seqValue = strtonum(seqTok, 0, UINT32_MAX, &errstr);
+
+ if (seqValue == 0) {
+ background = 0;
+ background24 = 0;
+ foreground = 7;
+ foreground24 = 0;
+ bold = false;
+ blink = false;
+ invert = false;
+ }
- if (blink && options->icecolors)
- background += 8;
+ if (seqValue == 1) {
+ if (!workbench) {
+ foreground += 8;
}
-
- seqTok = strtok(NULL, ";");
+ bold = true;
+ foreground24 = 0;
}
- loop += ansi_sequence_loop+2;
- free(seqGrab);
- break;
- }
+ if (seqValue == 5) {
+ if (!workbench && options->icecolors)
+ background += 8;
- /* cursor (de)activation (Amiga ANSi) */
- if (ansi_sequence_character == 'p') {
- loop += ansi_sequence_loop+2;
- break;
- }
+ blink = true;
+ background24 = 0;
+ }
- /* skipping set mode and reset mode sequences */
- if (ansi_sequence_character == 'h' || ansi_sequence_character == 'l') {
- loop += ansi_sequence_loop+2;
- break;
- }
+ if (seqValue == 7)
+ invert = true;
- /* skipping erase in line (EL) sequences */
- if (ansi_sequence_character == 'K') {
- loop += ansi_sequence_loop+2;
- break;
- }
+ if (seqValue == 27)
+ invert = false;
- /* PabloDraw 24-bit ANSI sequences */
- if (ansi_sequence_character == 't') {
- uint32_t color_R = 0, color_G = 0, color_B = 0;
+ if (seqValue > 29 && seqValue < 38) {
+ foreground = seqValue - 30;
+ foreground24 = 0;
- /* create substring from the sequence's content */
- seqGrab = strndup((char *)ctx->buffer + loop + 2, ansi_sequence_loop);
+ if (bold)
+ foreground += 8;
+ }
- seqTok = strtok(seqGrab, ";");
- if (seqTok) {
- seqValue = strtonum(seqTok, 0, UCHAR_MAX, &errstr);
-
- seqTok = strtok(NULL, ";");
- color_R = seqTok ? strtonum(seqTok, 0, UCHAR_MAX, &errstr) & 0xff : 0;
- seqTok = strtok(NULL, ";");
- color_G = seqTok ? strtonum(seqTok, 0, UCHAR_MAX, &errstr) & 0xff : 0;
- seqTok = strtok(NULL, ";");
- color_B = seqTok ? strtonum(seqTok, 0, UCHAR_MAX, &errstr) & 0xff : 0;
-
- switch (seqValue) {
- case 0:
- background24 = color_R << 16 | color_G << 8 | color_B;
- break;
- case 1:
- foreground24 = color_R << 16 | color_G << 8 | color_B;
- break;
- }
+ if (seqValue > 39 && seqValue < 48) {
+ background = seqValue - 40;
+ background24 = 0;
- options->truecolor = true;
+ if (blink && options->icecolors)
+ background += 8;
}
- loop += ansi_sequence_loop+2;
- free(seqGrab);
- break;
+ seqTok = strtok(NULL, ";");
}
+
+ loop += ansi_sequence_loop;
+ free(seqGrab);
+ break;
}
- }
- break;
- default:
- /* record number of columns and lines used */
- if (column > columnMax)
- columnMax = column;
-
- if (row > rowMax)
- rowMax = row;
-
- /* write current character in ansiChar structure */
- if (!fontData.isAmigaFont || (current_character != 12 && current_character != 13)) {
- /* reallocate structure array memory */
- if (structIndex == ansi_buffer_size) {
- ansi_buffer_size += ANSI_BUFFER_SIZE;
-
- ptr = realloc(ansi_buffer, ansi_buffer_size * sizeof(struct ansiChar));
-
- if (ptr == NULL) {
- ctx->error = ANSILOVE_MEMORY_ERROR;
- free(ansi_buffer);
- return -1;
- } else {
- ansi_buffer = ptr;
- }
+
+ /* cursor (de)activation (Amiga ANSi) */
+ if (ansi_sequence_character == 'p') {
+ loop += ansi_sequence_loop;
+ break;
}
- if (invert) {
- ansi_buffer[structIndex].background = foreground % 8;
- ansi_buffer[structIndex].foreground = background + (foreground & 8);
- } else {
- ansi_buffer[structIndex].background =
- background24 ? background24 : background;
+ /* skipping set mode and reset mode sequences */
+ if (ansi_sequence_character == 'h' || ansi_sequence_character == 'l') {
+ loop += ansi_sequence_loop;
+ break;
+ }
- ansi_buffer[structIndex].foreground =
- foreground24 ? foreground24 : foreground;
+ /* skipping erase in line (EL) sequences */
+ if (ansi_sequence_character == 'K') {
+ loop += ansi_sequence_loop;
+ break;
}
- ansi_buffer[structIndex].character = current_character;
- ansi_buffer[structIndex].column = column;
- ansi_buffer[structIndex].row = row;
- structIndex++;
- column++;
+ /* PabloDraw 24-bit ANSI sequences */
+ if (ansi_sequence_character == 't') {
+ uint32_t color_R = 0, color_G = 0, color_B = 0;
+
+ /* create substring from the sequence's content */
+ seqGrab = strndup((char *)ctx->buffer + loop, ansi_sequence_loop);
+
+ seqTok = strtok(seqGrab, ";");
+ if (seqTok) {
+ seqValue = strtonum(seqTok, 0, UCHAR_MAX, &errstr);
+
+ seqTok = strtok(NULL, ";");
+ color_R = seqTok ? strtonum(seqTok, 0, UCHAR_MAX, &errstr) & 0xff : 0;
+ seqTok = strtok(NULL, ";");
+ color_G = seqTok ? strtonum(seqTok, 0, UCHAR_MAX, &errstr) & 0xff : 0;
+ seqTok = strtok(NULL, ";");
+ color_B = seqTok ? strtonum(seqTok, 0, UCHAR_MAX, &errstr) & 0xff : 0;
+
+ switch (seqValue) {
+ case 0:
+ background24 = color_R << 16 | color_G << 8 | color_B;
+ break;
+ case 1:
+ foreground24 = color_R << 16 | color_G << 8 | color_B;
+ break;
+ }
+
+ options->truecolor = true;
+ }
+
+ loop += ansi_sequence_loop;
+ free(seqGrab);
+ break;
+ }
}
+ state = STATE_TEXT;
+ break;
+ case STATE_END:
+ loop = ctx->length;
+ break;
}
loop++;