Mercurial > vim
view src/libvterm/src/parser.c @ 13472:f6a4614edea4 v8.0.1610
patch 8.0.1610: cannot build without GUI
commit https://github.com/vim/vim/commit/4ac31eeff0409de0b1fe2d9e9f678859656ac4ae
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Mar 16 21:34:25 2018 +0100
patch 8.0.1610: cannot build without GUI
Problem: Cannot build without GUI.
Solution: Add #ifdef.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 16 Mar 2018 21:45:06 +0100 |
parents | 7846efd291d7 |
children | 9f857e6310b6 |
line wrap: on
line source
#include "vterm_internal.h" #include <stdio.h> #include <string.h> #define CSI_ARGS_MAX 16 #define CSI_LEADER_MAX 16 #define CSI_INTERMED_MAX 16 static void do_control(VTerm *vt, unsigned char control) { if(vt->parser_callbacks && vt->parser_callbacks->control) if((*vt->parser_callbacks->control)(control, vt->cbdata)) return; DEBUG_LOG1("libvterm: Unhandled control 0x%02x\n", control); } static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char command) { int i = 0; int leaderlen = 0; char leader[CSI_LEADER_MAX]; int argcount = 1; /* Always at least 1 arg */ long csi_args[CSI_ARGS_MAX]; int argi; int intermedlen = 0; char intermed[CSI_INTERMED_MAX]; /* Extract leader bytes 0x3c to 0x3f */ for( ; i < (int)arglen; i++) { if(args[i] < 0x3c || args[i] > 0x3f) break; if(leaderlen < CSI_LEADER_MAX-1) leader[leaderlen++] = args[i]; } leader[leaderlen] = 0; for( ; i < (int)arglen; i++) if(args[i] == 0x3b || args[i] == 0x3a) /* ; or : */ argcount++; /* TODO: Consider if these buffers should live in the VTerm struct itself */ if(argcount > CSI_ARGS_MAX) argcount = CSI_ARGS_MAX; for(argi = 0; argi < argcount; argi++) csi_args[argi] = CSI_ARG_MISSING; argi = 0; for(i = leaderlen; i < (int)arglen && argi < argcount; i++) { switch(args[i]) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: if(csi_args[argi] == CSI_ARG_MISSING) csi_args[argi] = 0; csi_args[argi] *= 10; csi_args[argi] += args[i] - '0'; break; case 0x3a: csi_args[argi] |= CSI_ARG_FLAG_MORE; /* FALLTHROUGH */ case 0x3b: argi++; break; default: goto done_leader; } } done_leader: ; for( ; i < (int)arglen; i++) { if((args[i] & 0xf0) != 0x20) break; if(intermedlen < CSI_INTERMED_MAX-1) intermed[intermedlen++] = args[i]; } intermed[intermedlen] = 0; if(i < (int)arglen) { DEBUG_LOG2("libvterm: TODO unhandled CSI bytes \"%.*s\"\n", (int)(arglen - i), args + i); } #if 0 printf("Parsed CSI args %.*s as:\n", arglen, args); printf(" leader: %s\n", leader); for(argi = 0; argi < argcount; argi++) { printf(" %lu", CSI_ARG(csi_args[argi])); if(!CSI_ARG_HAS_MORE(csi_args[argi])) printf("\n"); printf(" intermed: %s\n", intermed); } #endif if(vt->parser_callbacks && vt->parser_callbacks->csi) if((*vt->parser_callbacks->csi)(leaderlen ? leader : NULL, csi_args, argcount, intermedlen ? intermed : NULL, command, vt->cbdata)) return; DEBUG_LOG3("libvterm: Unhandled CSI %.*s %c\n", (int)arglen, args, command); } static void append_strbuffer(VTerm *vt, const char *str, size_t len) { if(len > vt->strbuffer_len - vt->strbuffer_cur) { len = vt->strbuffer_len - vt->strbuffer_cur; DEBUG_LOG1("Truncating strbuffer preserve to %zd bytes\n", len); } if(len > 0) { strncpy(vt->strbuffer + vt->strbuffer_cur, str, len); vt->strbuffer_cur += len; } } static size_t do_string(VTerm *vt, const char *str_frag, size_t len) { size_t eaten; if(vt->strbuffer_cur) { if(str_frag) append_strbuffer(vt, str_frag, len); str_frag = vt->strbuffer; len = vt->strbuffer_cur; } else if(!str_frag) { DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n"); len = 0; } vt->strbuffer_cur = 0; switch(vt->parser_state) { case NORMAL: if(vt->parser_callbacks && vt->parser_callbacks->text) if((eaten = (*vt->parser_callbacks->text)(str_frag, len, vt->cbdata))) return eaten; DEBUG_LOG1("libvterm: Unhandled text (%zu chars)\n", len); return 0; case ESC: if(len == 1 && str_frag[0] >= 0x40 && str_frag[0] < 0x60) { /* C1 emulations using 7bit clean */ /* ESC 0x40 == 0x80 */ do_control(vt, str_frag[0] + 0x40); return 0; } if(vt->parser_callbacks && vt->parser_callbacks->escape) if((*vt->parser_callbacks->escape)(str_frag, len, vt->cbdata)) return 0; DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", str_frag[len-1]); return 0; case CSI: do_string_csi(vt, str_frag, len - 1, str_frag[len - 1]); return 0; case OSC: if(vt->parser_callbacks && vt->parser_callbacks->osc) if((*vt->parser_callbacks->osc)(str_frag, len, vt->cbdata)) return 0; DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str_frag); return 0; case DCS: if(vt->parser_callbacks && vt->parser_callbacks->dcs) if((*vt->parser_callbacks->dcs)(str_frag, len, vt->cbdata)) return 0; DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str_frag); return 0; case ESC_IN_OSC: case ESC_IN_DCS: DEBUG_LOG("libvterm: ARGH! Should never do_string() in ESC_IN_{OSC,DCS}\n"); return 0; } return 0; } size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) { size_t pos = 0; const char *string_start = NULL; /* init to avoid gcc warning */ switch(vt->parser_state) { case NORMAL: string_start = NULL; break; case ESC: case ESC_IN_OSC: case ESC_IN_DCS: case CSI: case OSC: case DCS: string_start = bytes; break; } #define ENTER_STRING_STATE(st) do { vt->parser_state = st; string_start = bytes + pos + 1; } while(0) #define ENTER_NORMAL_STATE() do { vt->parser_state = NORMAL; string_start = NULL; } while(0) for( ; pos < len; pos++) { unsigned char c = bytes[pos]; if(c == 0x00 || c == 0x7f) { /* NUL, DEL */ if(vt->parser_state != NORMAL) { append_strbuffer(vt, string_start, bytes + pos - string_start); string_start = bytes + pos + 1; } continue; } if(c == 0x18 || c == 0x1a) { /* CAN, SUB */ ENTER_NORMAL_STATE(); continue; } else if(c == 0x1b) { /* ESC */ if(vt->parser_state == OSC) vt->parser_state = ESC_IN_OSC; else if(vt->parser_state == DCS) vt->parser_state = ESC_IN_DCS; else ENTER_STRING_STATE(ESC); continue; } else if(c == 0x07 && /* BEL, can stand for ST in OSC or DCS state */ (vt->parser_state == OSC || vt->parser_state == DCS)) { /* fallthrough */ } else if(c < 0x20) { /* other C0 */ if(vt->parser_state != NORMAL) append_strbuffer(vt, string_start, bytes + pos - string_start); do_control(vt, c); if(vt->parser_state != NORMAL) string_start = bytes + pos + 1; continue; } /* else fallthrough */ switch(vt->parser_state) { case ESC_IN_OSC: case ESC_IN_DCS: if(c == 0x5c) { /* ST */ switch(vt->parser_state) { case ESC_IN_OSC: vt->parser_state = OSC; break; case ESC_IN_DCS: vt->parser_state = DCS; break; default: break; } do_string(vt, string_start, bytes + pos - string_start - 1); ENTER_NORMAL_STATE(); break; } vt->parser_state = ESC; string_start = bytes + pos; /* else fallthrough */ case ESC: switch(c) { case 0x50: /* DCS */ ENTER_STRING_STATE(DCS); break; case 0x5b: /* CSI */ ENTER_STRING_STATE(CSI); break; case 0x5d: /* OSC */ ENTER_STRING_STATE(OSC); break; default: if(c >= 0x30 && c < 0x7f) { /* +1 to pos because we want to include this command byte as well */ do_string(vt, string_start, bytes + pos - string_start + 1); ENTER_NORMAL_STATE(); } else if(c >= 0x20 && c < 0x30) { /* intermediate byte */ } else { DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c); } } break; case CSI: if(c >= 0x40 && c <= 0x7f) { /* +1 to pos because we want to include this command byte as well */ do_string(vt, string_start, bytes + pos - string_start + 1); ENTER_NORMAL_STATE(); } break; case OSC: case DCS: if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) { do_string(vt, string_start, bytes + pos - string_start); ENTER_NORMAL_STATE(); } break; case NORMAL: if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) { switch(c) { case 0x90: /* DCS */ ENTER_STRING_STATE(DCS); break; case 0x9b: /* CSI */ ENTER_STRING_STATE(CSI); break; case 0x9d: /* OSC */ ENTER_STRING_STATE(OSC); break; default: do_control(vt, c); break; } } else { size_t text_eaten = do_string(vt, bytes + pos, len - pos); if(text_eaten == 0) { string_start = bytes + pos; goto pause; } pos += (text_eaten - 1); /* we'll ++ it again in a moment */ } break; } } pause: if(string_start && string_start < len + bytes) { size_t remaining = len - (string_start - bytes); append_strbuffer(vt, string_start, remaining); } return len; }