Skip to content

Instantly share code, notes, and snippets.

@Orc
Created March 27, 2019 03:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Orc/e1caee6695ebd3eab5320171c7073d33 to your computer and use it in GitHub Desktop.
Save Orc/e1caee6695ebd3eab5320171c7073d33 to your computer and use it in GitHub Desktop.
A tgoto() implementation for systems that don't have termcap
/*
* 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