Created
March 27, 2019 03:21
-
-
Save Orc/e1caee6695ebd3eab5320171c7073d33 to your computer and use it in GitHub Desktop.
A tgoto() implementation for systems that don't have termcap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* partial implementation of termlib's tgoto() function, with | |
* the optimization of caching compiled strings so they don't | |
* need to be recompiled evey time tgoto is called. | |
* | |
* "partial implementation" because I've got yet implemented %<xy | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <ctype.h> | |
static struct _jit { | |
char *src; /* pointer to the source tgoto string */ | |
char *compiled; /* the compiled-to-printf-format tgoto string */ | |
int xfirst; /* does the string go x/y or y/x */ | |
int offset[2]; /* offset to add to x/y coordinates */ | |
int bcd[2]; /* 0: not bcd, 1: regular bcd, 2: reverse bcd */ | |
} *jit; | |
int nrjit = 0; | |
static void | |
tc_compile(char *cm, struct _jit *dest, int allocate) | |
{ | |
char printfmt[80]; | |
int sp,dp; | |
int argno=1; | |
memset(dest, 0, sizeof dest[0]); | |
for (sp=dp=0; cm[sp]; sp++ ) { | |
if ( cm[sp] == '%' ) { | |
sp++; | |
switch (cm[sp]) { | |
case '%': | |
printfmt[dp++] = '%'; | |
printfmt[dp++] = '%'; | |
break; | |
case 'i': | |
dest->offset[0]++; | |
dest->offset[1]++; | |
break; | |
case 'd': | |
printfmt[dp++] = '%'; | |
printfmt[dp++] = 'd'; | |
argno++; | |
break; | |
case '2': | |
case '3': | |
printfmt[dp++] = '%'; | |
printfmt[dp++] = cm[sp]; | |
printfmt[dp++] = 'd'; | |
argno++; | |
break; | |
case '+': | |
if ( argno < 2 ) | |
dest->offset[argno] += cm[++sp]; | |
/* fall through into 'c' */ | |
case 'c': | |
printfmt[dp++] = '%'; | |
printfmt[dp++] = 'c'; | |
argno++; | |
break; | |
case 'B': | |
case 'D': | |
printfmt[dp++] = '%'; | |
printfmt[dp++] = 'c'; | |
dest->bcd[argno] = (cm[sp] == 'B') ? 1 : 2; | |
argno++; | |
break; | |
case 'r': | |
dest->xfirst = 1; | |
break; | |
} | |
} | |
else if ( cm[sp] == '\\' ) { | |
int escaped = 0; | |
int base=10; | |
char *loc; | |
static char hexdig[] = "0123456789abcdef"; | |
sp++; | |
if (cm[sp] == '0') { | |
if (cm[sp+1] == 'x' || cm[sp+1] == 'X') { | |
sp+=2; | |
base=16; | |
} | |
else { | |
sp++; | |
base=8; | |
} | |
} | |
else if (!isdigit(cm[sp])) { | |
printfmt[dp++] = '\\'; | |
printfmt[dp++] = cm[sp]; | |
continue; | |
} | |
while (( loc=memchr(hexdig, cm[sp], base) )) { | |
escaped = (escaped*base) + (loc-hexdig); | |
sp++; | |
} | |
printfmt[dp++] = escaped; | |
--sp; | |
} | |
else { | |
printfmt[dp++] = cm[sp]; | |
} | |
} | |
printfmt[dp] = 0; | |
dest->src = cm; | |
dest->compiled = allocate ? strdup(printfmt) : printfmt; | |
} | |
static char | |
charformat(bcdflag, c) | |
{ | |
switch (bcdflag) { | |
case 1: return ((c/10 << 4) + c % 10); | |
case 2: return (c - 2 * (c%16)); | |
default: return c; | |
} | |
} | |
static char * | |
tc_printf(char dest[], int size, struct _jit *fmt, int y, int x) | |
{ | |
if (fmt->xfirst) | |
snprintf(dest, size, fmt->compiled, | |
charformat(fmt->bcd[0], x+fmt->offset[0]), | |
charformat(fmt->bcd[1], y+fmt->offset[1]) ); | |
else | |
snprintf(dest, size, fmt->compiled, | |
charformat(fmt->bcd[0], y+fmt->offset[0]), | |
charformat(fmt->bcd[1], x+fmt->offset[1]) ); | |
return dest; | |
} | |
char * | |
tgoto(cm,y,x) | |
char *cm; | |
{ | |
static char bfr[40]; | |
struct _jit *newalloc; | |
struct _jit nomem; | |
char *fmt; | |
int i; | |
for (i=0; i<nrjit; i++) | |
if (jit[i].src == cm) { | |
#if DEBUG | |
printf("tgoto: [%s] cached at [%d]\n", cm, i); | |
#endif | |
break; | |
} | |
if ( i >= nrjit ) { | |
#if DEBUG | |
printf("tgoto: compiling [%s]\n", cm); | |
#endif | |
newalloc = nrjit ? realloc(jit, (1+nrjit)*sizeof jit[0]) | |
: malloc(sizeof jit[0]); | |
if (newalloc) { | |
jit = newalloc; | |
tc_compile(cm, &jit[nrjit], 1); | |
++nrjit; | |
} | |
else { | |
tc_compile(cm, &nomem, 0); | |
return tc_printf(bfr, sizeof bfr, &nomem, y, x); | |
} | |
} | |
return tc_printf(bfr, sizeof bfr, &jit[i], y, x); | |
} | |
#if DEBUG | |
int | |
main(argc, argv) | |
char **argv; | |
{ | |
int i, loop; | |
int x = 0; | |
int y = 0; | |
char *result; | |
if ( argc < 2 ) { | |
fprintf(stderr, "usage: my_tgoto cm-string [x [y]]\n"); | |
exit(1); | |
} | |
if (argc > 2) { | |
x = atoi(argv[2]); | |
if ( argc > 3) | |
y = atoi(argv[3]); | |
} | |
for (loop=0; loop<2; loop++) { | |
result = tgoto(argv[1], y, x); | |
printf("%s + (%d,%d) -> ", argv[1], x, y); | |
for (i=0; result[i]; i++) { | |
if ( result[i] >= ' ' && result[i] < 127 ) | |
putchar(result[i]); | |
else | |
printf("%%%02x", (unsigned char)result[i]); | |
} | |
putchar('\n'); | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment