#include #include "ansi_decls.h" #include "ansi.h" struct intermediate { unsigned char buf[2]; int count; }; struct param { unsigned char buf[128]; int buf_count; unsigned int params[16]; int count; }; struct ansi_context { struct sm_context base_context; struct intermediate i_ctx; struct param p_ctx; unsigned char private; struct ansi_actions cbs; put_handler put_cb; void *put_ctx; osc_handler osc_put_cb; void *osc_put_ctx; }; /* Ground State (start state) */ static struct sm_transition ground_transitions[] = { { ground_execute_pred, do_execute, NULL }, { ground_print_pred, do_print, NULL }, {} }; static struct sm_state ground = { .name = "Ground", .entry_action = NULL, .exit_action = NULL, .transitions = ground_transitions }; /* Escape State */ static struct sm_transition escape_transitions[] = { { escape_execute_pred, do_execute, NULL }, { escape_ignore_pred, do_ignore, NULL }, { escape_to_ground_pred, do_esc_dispatch, &ground }, { escape_to_escape_intermediate_pred, do_collect, &escape_intermediate }, { escape_to_string_pred, NULL, &sos_pm_apc_string }, { escape_to_dcs_entry_pred, NULL, &dcs_entry }, { escape_to_osc_string_pred, NULL, &osc_string }, { escape_to_csi_entry_pred, NULL, &csi_entry }, {} }; static struct sm_state escape = { .name = "Escape", .entry_action = do_clear, .exit_action = NULL, .transitions = escape_transitions }; /* Escape Intermediate State */ static struct sm_transition escape_intermediate_transitions[] = { { escape_intermediate_execute_pred, do_execute, NULL }, { escape_intermediate_collect_pred, do_collect, NULL }, { escape_intermediate_ignore_pred, do_ignore, NULL }, { escape_intermediate_to_ground_pred, do_esc_dispatch, &ground }, {} }; static struct sm_state escape_intermediate = { .name = "Escape Intermediate", .entry_action = NULL, .exit_action = NULL, .transitions = escape_intermediate_transitions }; /* CSI Entry State */ static struct sm_transition csi_entry_transitions[] = { { csi_entry_execute_pred, do_execute, NULL }, { csi_entry_ignore_pred, do_ignore, NULL }, { csi_entry_to_ground_pred, do_csi_dispatch, &ground }, { csi_entry_to_param_pred, do_param, &csi_param }, { csi_entry_to_param_collect_pred, do_collect, &csi_param }, { csi_entry_to_intermediate_pred, do_collect, &csi_intermediate }, { csi_entry_to_ignore_pred, NULL, &csi_ignore }, {} }; static struct sm_state csi_entry = { .name = "CSI Entry", .entry_action = do_clear, .exit_action = NULL, .transitions = csi_entry_transitions }; /* CSI Param State */ static struct sm_transition csi_param_transitions[] = { { csi_param_execute_pred, do_execute, NULL }, { csi_param_param_pred, do_param, NULL }, { csi_param_ignore_pred, do_ignore, NULL }, { csi_param_to_ground_pred, do_csi_dispatch, &ground }, { csi_param_to_intermediate_pred, do_collect, &csi_intermediate }, { csi_param_to_ignore_pred, NULL, &csi_ignore }, {} }; static struct sm_state csi_param = { .name = "CSI Param", .entry_action = NULL, .exit_action = NULL, .transitions = csi_param_transitions }; /* CSI Intermediate State */ static struct sm_transition csi_intermediate_transitions[] = { { csi_intermediate_execute_pred, do_execute, NULL }, { csi_intermediate_collect_pred, do_collect, NULL }, { csi_intermediate_ignore_pred, do_ignore, NULL }, { csi_intermediate_to_ground_pred, do_csi_dispatch, &ground }, { csi_intermediate_to_ignore_pred, NULL, &csi_ignore }, {} }; static struct sm_state csi_intermediate = { .name = "CSI Intermediate", .entry_action = NULL, .exit_action = NULL, .transitions = csi_intermediate_transitions }; /* CSI Ignore State */ static struct sm_transition csi_ignore_transitions[] = { { csi_ignore_execute_pred, do_execute, NULL }, { csi_ignore_ignore_pred, do_ignore, NULL }, { csi_ignore_to_ground_pred, NULL, &ground }, {} }; static struct sm_state csi_ignore = { .name = "CSI Ignore", .entry_action = NULL, .exit_action = NULL, .transitions = csi_ignore_transitions }; /* DCS Entry State */ static struct sm_transition dcs_entry_transitions[] = { { dcs_entry_ignore_pred, do_ignore, NULL }, { dcs_entry_to_intermediate_pred, do_collect, &dcs_intermediate }, { dcs_entry_to_ignore_pred, NULL, &dcs_ignore }, { dcs_entry_to_param_pred, do_param, &dcs_param }, { dcs_entry_to_param_collect_pred, do_collect, &dcs_param }, { dcs_entry_to_passthrough_pred, NULL, &dcs_passthrough }, {} }; static struct sm_state dcs_entry = { .name = "DCS Entry", .entry_action = do_clear, .exit_action = NULL, .transitions = dcs_entry_transitions }; /* DCS Param State */ static struct sm_transition dcs_param_transitions[] = { { dcs_param_ignore_pred, do_ignore, NULL }, { dcs_param_param_pred, do_param, NULL }, { dcs_param_to_ignore_pred, NULL , &dcs_ignore }, { dcs_param_to_intermediate_pred, do_collect, &dcs_intermediate }, { dcs_param_to_passthrough_pred, NULL, &dcs_passthrough }, {} }; static struct sm_state dcs_param = { .name = "DCS Param", .entry_action = NULL, .exit_action = NULL, .transitions = dcs_param_transitions }; /* DCS Intermediate State */ static struct sm_transition dcs_intermediate_transitions[] = { { dcs_intermediate_ignore_pred, do_ignore, NULL }, { dcs_intermediate_collect_pred, do_collect, NULL }, { dcs_intermediate_to_passthrough_pred, NULL, &dcs_passthrough }, { dcs_intermediate_to_ignore_pred, NULL, &dcs_ignore }, {} }; static struct sm_state dcs_intermediate = { .name = "DCS Intermediate", .entry_action = NULL, .exit_action = NULL, .transitions = dcs_intermediate_transitions }; /* DCS Passthrough State */ static struct sm_transition dcs_passthrough_transitions[] = { { dcs_passthrough_ignore_pred, do_ignore, NULL }, { dcs_passthrough_put_pred, do_put, NULL }, { dcs_passthrough_to_ground_pred, NULL, &ground }, {} }; static struct sm_state dcs_passthrough = { .name = "DCS Passthrough", .entry_action = do_hook, .exit_action = do_unhook, .transitions = dcs_passthrough_transitions }; /* DCS Ignore State */ static struct sm_transition dcs_ignore_transitions[] = { { dcs_ignore_ignore_pred, do_ignore, NULL }, { dcs_ignore_to_ground_pred, NULL, &ground }, {} }; static struct sm_state dcs_ignore = { .name = "DCS Ignore", .entry_action = NULL, .exit_action = NULL, .transitions = dcs_ignore_transitions }; /* OSC String State */ static struct sm_transition osc_string_transitions[] = { { osc_string_ignore_pred, do_ignore, NULL }, { osc_string_put_pred, do_osc_put, NULL }, { osc_string_to_ground_pred, NULL, &ground }, {} }; static struct sm_state osc_string = { .name = "OSC String", .entry_action = do_osc_start, .exit_action = do_osc_end, .transitions = osc_string_transitions }; /* SOS/PM/APC String State */ static struct sm_transition sos_pm_apc_string_transitions[] = { { sos_pm_apc_string_ignore_pred, do_ignore, NULL }, { sos_pm_apc_string_to_ground_pred, NULL, &ground }, {} }; static struct sm_state sos_pm_apc_string = { .name = "SOS/PM/APC String", .entry_action = NULL, .exit_action = NULL, .transitions = sos_pm_apc_string_transitions }; /* Global Transitions - Active at all states */ static struct sm_transition global_transitions[] = { { global_execute_pred, do_execute, &ground }, { global_to_escape_pred, NULL, &escape }, { global_to_string_pred, NULL, &sos_pm_apc_string }, { global_to_dcs_pred, NULL, &dcs_entry }, { global_to_osc_pred, NULL, &osc_string }, {} }; /* * Single global machine definition, for now */ struct ansi_context ansi_machine = { .base_context = { .current_state = &ground, .global_transitions = global_transitions }, .i_ctx = { .buf = {0, 0}, .count = 0 }, .p_ctx = { .buf = {0}, .buf_count = 0, .params = {0}, .count = 0 }, .private = 0, .cbs = { .graphic_cb = NULL, .control_cb = NULL, .esc_cb = NULL, .csi_cb = NULL, .str_cb = NULL, .osc_cb = NULL }, .put_cb = NULL, .put_ctx = NULL, .osc_put_cb = NULL, .osc_put_ctx = NULL }; /* * Predicates */ /* Global State */ static int global_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode == 0x18) || (keycode == 0x1A) || ((keycode & 0xF0) == 0x80) || ((keycode >= 0x91) && (keycode <= 0x97)) || (keycode == 0x99) || (keycode == 0x9A) ); } static int global_to_escape_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x1B); } static int global_to_string_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode == 0x98) || (keycode == 0x9E) || (keycode == 0x9F) ); } static int global_to_dcs_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x90); } static int global_to_osc_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x9D); } /* Ground State */ static int ground_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; if (code >= 0xA0) code = code & 0x7F; return ( (keycode < 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int ground_print_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; if (code >= 0xA0) code = code & 0x7F; return ( (keycode >= 0x20) && (keycode <= 0x7F) ); } /* SOS/PM/APC String State */ static int sos_pm_apc_string_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; unsigned char keycode7 = keycode & 0x7F; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) || ( (keycode7 >= 0x20) && (keycode7 <= 0x7F) ) ); } static int sos_pm_apc_string_to_ground_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x9C); } /* Escape State */ static int escape_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int escape_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x7F); } static int escape_to_ground_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( ((keycode >= 0x30) && (keycode <= 0x4F)) || ((keycode >= 0x51) && (keycode <= 0x57)) || ( keycode == 0x59) || ( keycode == 0x5A) || ( keycode == 0x5C) || ((keycode >= 0x60) && (keycode <= 0x7E)) ); } static int escape_to_escape_intermediate_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x20) && (keycode7 <= 0x2F)); } static int escape_to_string_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode == 0x58) || (keycode == 0x5E) || (keycode == 0x5F) ); } static int escape_to_dcs_entry_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x50); } static int escape_to_osc_string_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x5D); } static int escape_to_csi_entry_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x5B); } /* Escape Intermediate State */ static int escape_intermediate_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int escape_intermediate_collect_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x20) && (keycode7 <= 0x2F)); } static int escape_intermediate_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x7F); } static int escape_intermediate_to_ground_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x30) && (keycode7 <= 0x7E)); } /* CSI Entry State */ static int csi_entry_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int csi_entry_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x7F); } static int csi_entry_to_ground_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x40) && (keycode7 <= 0x7E)); } static int csi_entry_to_param_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x30) && (keycode7 <= 0x39)) || ( keycode7 == 0x3B) ); } static int csi_entry_to_param_collect_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x3C) && (keycode7 <= 0x3F)) ); } static int csi_entry_to_intermediate_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x20) && (keycode7 <= 0x2F)) ); } static int csi_entry_to_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x3A); } /* CSI Param State */ static int csi_param_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int csi_param_param_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x30) && (keycode7 <= 0x39)) || ( keycode7 == 0x3B) ); } static int csi_param_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x7F); } static int csi_param_to_ground_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x40) && (keycode7 <= 0x7E)); } static int csi_param_to_intermediate_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x20) && (keycode7 <= 0x2F)) ); } static int csi_param_to_ignore_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x3C) && (keycode7 <= 0x3F)) || (keycode7 == 0x3A) ); } /* CSI Intermediate State */ static int csi_intermediate_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int csi_intermediate_collect_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x20) && (keycode7 <= 0x2F)) ); } static int csi_intermediate_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x7F); } static int csi_intermediate_to_ground_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x40) && (keycode7 <= 0x7E)); } static int csi_intermediate_to_ignore_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x30) && (keycode7 <= 0x3F)) ); } /* CSI Ignore State */ static int csi_ignore_execute_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int csi_ignore_ignore_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x20) && (keycode7 <= 0x3F)) || ( keycode7 == 0x7F) ); } static int csi_ignore_to_ground_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x40) && (keycode7 <= 0x7E)); } /* DCS Entry State */ static int dcs_entry_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) || ((keycode & 0x7F) == 0x7F) ); } static int dcs_entry_to_intermediate_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x20) && (keycode7 <= 0x2F)); } static int dcs_entry_to_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x3A); } static int dcs_entry_to_param_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x30) && (keycode7 <= 0x39)) || ( keycode7 == 0x3B) ); } static int dcs_entry_to_param_collect_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x3C) && (keycode7 <= 0x3F)) ); } static int dcs_entry_to_passthrough_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ((keycode7 >= 0x40) && (keycode7 <= 0x7E)); } /* DCS Param State */ static int dcs_param_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) || ((keycode & 0x7F) == 0x7F) ); } static int dcs_param_param_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x30) && (keycode7 <= 0x39)) || ( keycode7 == 0x3B) ); } static int dcs_param_to_ignore_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x3C) && (keycode7 <= 0x3F)) || ( keycode7 == 0x3A) ); } static int dcs_param_to_intermediate_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x20) && (keycode7 <= 0x2F)) ); } static int dcs_param_to_passthrough_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x40) && (keycode7 <= 0x7E)) ); } /* DCS Intermediate State */ static int dcs_intermediate_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) || ((keycode & 0x7F) == 0x7F) ); } static int dcs_intermediate_collect_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x20) && (keycode7 <= 0x2F)) ); } static int dcs_intermediate_to_passthrough_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x40) && (keycode7 <= 0x7E)) ); } static int dcs_intermediate_to_ignore_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x30) && (keycode7 <= 0x3F)) ); } /* DCS Passthrough State */ static int dcs_passthrough_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ((keycode & 0x7F) == 0x7F); } static int dcs_passthrough_put_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; unsigned char keycode7 = keycode & 0x7F; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) || ( (keycode7 >= 0x20) && (keycode7 <= 0x7E) ) ); } static int dcs_passthrough_to_ground_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x9C); } /* DCS Ignore State */ static int dcs_ignore_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; unsigned char keycode7 = keycode & 0x7F; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) || ( (keycode7 >= 0x20) && (keycode7 <= 0x7F) ) ); } static int dcs_ignore_to_ground_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x9C); } /* OSC String State */ static int osc_string_ignore_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return ( (keycode <= 0x17) || (keycode == 0x19) || ( (keycode >= 0x1C) && (keycode <= 0x1F) ) ); } static int osc_string_put_pred(sm_event_id code) { unsigned char keycode7 = (unsigned char)(code & 0x7F); return ( ((keycode7 >= 0x20) && (keycode7 <= 0x7F)) ); } static int osc_string_to_ground_pred(sm_event_id code) { unsigned char keycode = (unsigned char)code; return (keycode == 0x9C); } /* * Actions */ #define LOG_ACTIONS 0 #if LOG_ACTIONS #include #define LOG_ACTION(state, action, event) printf("ANSI: In %s, took act %s on char 0x%02x\n", state, action, (unsigned char)event) #define DUMP_STATE(state_) dump_state(state_) void dump_state(struct ansi_context *actx) { int i; printf("Parser Context:\n"); printf(" Current State: %s\n", actx->base_context.current_state->name); printf(" Private marker: %c\n", actx->private ? actx->private : ' '); printf(" Intermediates (%d): ", actx->i_ctx.count); for (i = 0; i < actx->i_ctx.count; i++) { printf("%c ", actx->i_ctx.buf[i]); } printf("\n"); printf(" Parameters (%d): ", actx->p_ctx.count); for (i = 0; i < actx->p_ctx.count; i++) { printf("%d ", actx->p_ctx.params[i]); } printf("\n"); if (actx->p_ctx.buf_count > 0) { printf(" In-progress: "); for (i = 0; i < actx->p_ctx.buf_count; i++) { printf("%d", actx->p_ctx.buf[i]); } printf("\n"); } } #else #define LOG_ACTION(state, action, event) #define DUMP_STATE(state_) #endif /* Do nothing */ static void do_ignore(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "IGNORE", code); (void)actx; (void)code; return; } /* Map code to a glyph according to current character set mappings and shift states and display it. */ static void do_print(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "PRINT", code); actx->cbs.graphic_cb(code); return; } /* Immediately execute a C0 or C1 control function */ static void do_execute(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "EXECUTE", code); actx->cbs.control_cb(code); return; } /* Forget current private flag, intermediate characters, final character, and parameters */ static void do_clear(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "CLEAR", code); (void)code; actx->private = '\0'; actx->i_ctx.count = 0; actx->p_ctx.buf_count = 0; actx->p_ctx.count = 0; return; } /* Collect private flag or intermediate character for later processing */ static void do_collect(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "COLLECT", code); if (code == '?') { actx->private = code; } else { int idx = actx->i_ctx.count; if (idx < 2) { actx->i_ctx.buf[idx] = code; } actx->i_ctx.count++; } return; } static void finish_param(struct ansi_context *actx, unsigned char in) { int pow, digit, number; /* parameter separator with empty buffer indicates default */ if (actx->p_ctx.buf_count == 0 && in != ';') { return; } pow = 1; digit = 0; number = 0; while (actx->p_ctx.buf_count > 0) { digit = actx->p_ctx.buf[--actx->p_ctx.buf_count]; number += digit * pow; pow = pow * 10; } if (actx->p_ctx.count < 16) { actx->p_ctx.params[actx->p_ctx.count++] = number; } } /* Build a list of parameters from collected characters */ static void do_param(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "PARAM", code); if (code == ';') { finish_param(actx, (unsigned char)code); } else { actx->p_ctx.buf[actx->p_ctx.buf_count++] = code - '0'; } return; } /* Determine control function from intermediate characters and final character and execute it */ static void do_esc_dispatch(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; struct function_id esc_id; int i; LOG_ACTION(ctx->current_state->name, "ESC_DISPATCH", code); finish_param(actx, 0); DUMP_STATE(actx); esc_id.i_count_priv = actx->i_ctx.count; for (i = 0; i < esc_id.i_count_priv; i++) { esc_id.intermediates[i] = actx->i_ctx.buf[i]; } esc_id.final = code; actx->cbs.esc_cb(esc_id); return; } /* Determine control function from private marker, intermediate characters, and final character; execute it, passing the parameter list */ static void do_csi_dispatch(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; struct function_id csi_id; int i; LOG_ACTION(ctx->current_state->name, "CSI_DISPATCH", code); finish_param(actx, 0); DUMP_STATE(actx); csi_id.i_count_priv = actx->i_ctx.count; for (i = 0; i < csi_id.i_count_priv; i++) { csi_id.intermediates[i] = actx->i_ctx.buf[i]; } if (actx->private) { csi_id.i_count_priv |= 0x80; } csi_id.final = code; actx->cbs.csi_cb(csi_id, actx->p_ctx.count, actx->p_ctx.params); return; } /* Determine control function from private marker, intermediate characters, and final character; execute it, passing the parameter list. Also install a handler for PUT for the rest of the control string. */ static void do_hook(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; struct function_id str_id; struct str_hook hook; int i; LOG_ACTION(ctx->current_state->name, "HOOK", code); finish_param(actx, 0); DUMP_STATE(actx); str_id.i_count_priv = actx->i_ctx.count; for (i = 0; i < str_id.i_count_priv; i++) { str_id.intermediates[i] = actx->i_ctx.buf[i]; } if (actx->private) { str_id.i_count_priv |= 0x80; } str_id.final = code; actx->cbs.str_cb(&hook, str_id, actx->p_ctx.count, actx->p_ctx.params); actx->put_cb = hook.handler_fn; actx->put_ctx = hook.user_ctx; return; } /* Pass the codes to the PUT handler installed by HOOK */ static void do_put(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "PUT", code); if (actx->put_cb) { actx->put_cb(actx->put_ctx, code); } return; } /* Call PUT handler with end of data code, then uninstall it */ static void do_unhook(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "UNHOOK", code); if (actx->put_cb) { actx->put_cb(actx->put_ctx, code); actx->put_cb = NULL; actx->put_ctx = NULL; } return; } /* Initialize OSC Handler */ static void do_osc_start(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; struct osc_hook hook; (void)code; LOG_ACTION(ctx->current_state->name, "OSC_START", code); actx->cbs.osc_cb(&hook); actx->osc_put_cb = hook.handler_fn; actx->osc_put_ctx = hook.user_ctx; return; } /* Pass the code to the OSC Handler */ static void do_osc_put(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "OSC_PUT", code); if (actx->osc_put_cb) { actx->osc_put_cb(actx->osc_put_ctx, code); } return; } /* Clean up the OSC Handler state */ static void do_osc_end(struct sm_context *ctx, sm_event_id code) { struct ansi_context *actx = (struct ansi_context *)ctx; LOG_ACTION(ctx->current_state->name, "OSC_END", code); if (actx->osc_put_cb) { actx->osc_put_cb(actx->osc_put_ctx, code); actx->osc_put_cb = NULL; actx->osc_put_ctx = NULL; } return; } /* * External API Functions */ struct ansi_context *new_ansi_context(struct ansi_actions *actions) { ansi_machine.cbs.graphic_cb = actions->graphic_cb; ansi_machine.cbs.control_cb = actions->control_cb; ansi_machine.cbs.esc_cb = actions->esc_cb; ansi_machine.cbs.csi_cb = actions->csi_cb; ansi_machine.cbs.str_cb = actions->str_cb; ansi_machine.cbs.osc_cb = actions->osc_cb; return &ansi_machine; } void ansi_context_put(struct ansi_context *ctx, unsigned char code) { sm_put_event((struct sm_context *)ctx, code); }