version 1.19, 2015/10/10 16:15:03 |
version 1.20, 2016/01/18 17:34:26 |
|
|
|
|
#include <curses.h> |
#include <curses.h> |
#include <err.h> |
#include <err.h> |
|
#include <errno.h> |
|
#include <locale.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <term.h> |
#include <term.h> |
#include <unistd.h> |
#include <unistd.h> |
|
#include <wchar.h> |
|
|
#define IESC '\033' |
#define IESC L'\033' |
#define SO '\016' |
#define SO L'\016' |
#define SI '\017' |
#define SI L'\017' |
#define HFWD '9' |
#define HFWD '9' |
#define HREV '8' |
#define HREV '8' |
#define FREV '7' |
#define FREV '7' |
|
|
|
|
struct CHAR { |
struct CHAR { |
char c_mode; |
char c_mode; |
char c_char; |
wchar_t c_char; |
|
int c_width; |
|
int c_pos; |
} ; |
} ; |
|
|
struct CHAR obuf[MAXBUF]; |
struct CHAR obuf[MAXBUF]; |
|
|
void fwd(void); |
void fwd(void); |
void flushln(void); |
void flushln(void); |
void msetmode(int); |
void msetmode(int); |
void outc(int); |
void outc(wchar_t, int); |
void overstrike(void); |
void overstrike(void); |
void iattr(void); |
void iattr(void); |
|
|
|
|
FILE *f; |
FILE *f; |
char termcap[1024]; |
char termcap[1024]; |
|
|
|
setlocale(LC_CTYPE, ""); |
|
|
if (pledge("stdio rpath tty", NULL) == -1) |
if (pledge("stdio rpath tty", NULL) == -1) |
err(1, "pledge"); |
err(1, "pledge"); |
|
|
|
|
void |
void |
mfilter(FILE *f) |
mfilter(FILE *f) |
{ |
{ |
int c; |
struct CHAR *cp; |
|
wint_t c; |
|
int skip_bs, w, wt; |
|
|
while ((c = getc(f)) != EOF && col < MAXBUF) switch(c) { |
col = 1; |
case '\b': |
skip_bs = 0; |
if (col > 0) |
while (col < MAXBUF) { |
col--; |
switch (c = fgetwc(f)) { |
continue; |
case WEOF: |
case '\t': |
/* Discard invalid bytes. */ |
col = (col+8) & ~07; |
if (ferror(f)) { |
if (col > maxcol) |
if (errno != EILSEQ) |
maxcol = col; |
err(1, NULL); |
continue; |
clearerr(f); |
case '\r': |
break; |
col = 0; |
|
continue; |
|
case SO: |
|
mode |= ALTSET; |
|
continue; |
|
case SI: |
|
mode &= ~ALTSET; |
|
continue; |
|
case IESC: |
|
switch (c = getc(f)) { |
|
case HREV: |
|
if (halfpos == 0) { |
|
mode |= SUPERSC; |
|
halfpos--; |
|
} else if (halfpos > 0) { |
|
mode &= ~SUBSC; |
|
halfpos--; |
|
} else { |
|
halfpos = 0; |
|
reverse(); |
|
} |
} |
|
|
|
/* End of file. */ |
|
if (maxcol) |
|
flushln(); |
|
return; |
|
|
|
case L'\b': |
|
/* |
|
* Back up one character position, not one |
|
* display column, but ignore a second |
|
* backspace after a double-width character. |
|
*/ |
|
if (skip_bs > 0) |
|
skip_bs--; |
|
else if (col > 1) |
|
if (obuf[--col].c_width > 1) |
|
skip_bs = obuf[col].c_width - 1; |
continue; |
continue; |
case HFWD: |
|
if (halfpos == 0) { |
case L'\t': |
mode |= SUBSC; |
/* Calculate the target position. */ |
halfpos++; |
wt = (obuf[col - 1].c_pos + 8) & ~7; |
} else if (halfpos < 0) { |
|
mode &= ~SUPERSC; |
/* Advance past known positions. */ |
halfpos++; |
while ((w = obuf[col].c_pos) > 0 && w <= wt) |
} else { |
col++; |
halfpos = 0; |
|
fwd(); |
/* Advance beyond the end. */ |
|
if (w == 0) { |
|
w = obuf[col - 1].c_pos; |
|
while (w < wt) { |
|
obuf[col].c_width = 1; |
|
obuf[col++].c_pos = ++w; |
|
} |
} |
} |
continue; |
if (col > maxcol) |
case FREV: |
maxcol = col; |
reverse(); |
break; |
continue; |
|
|
case L'\r': |
|
col = 1; |
|
break; |
|
|
|
case SO: |
|
mode |= ALTSET; |
|
break; |
|
|
|
case SI: |
|
mode &= ~ALTSET; |
|
break; |
|
|
|
case IESC: |
|
switch (c = fgetwc(f)) { |
|
case HREV: |
|
if (halfpos == 0) { |
|
mode |= SUPERSC; |
|
halfpos--; |
|
} else if (halfpos > 0) { |
|
mode &= ~SUBSC; |
|
halfpos--; |
|
} else { |
|
halfpos = 0; |
|
reverse(); |
|
} |
|
break; |
|
case HFWD: |
|
if (halfpos == 0) { |
|
mode |= SUBSC; |
|
halfpos++; |
|
} else if (halfpos < 0) { |
|
mode &= ~SUPERSC; |
|
halfpos++; |
|
} else { |
|
halfpos = 0; |
|
fwd(); |
|
} |
|
break; |
|
case FREV: |
|
reverse(); |
|
break; |
|
default: |
|
errx(1, "0%o: unknown escape sequence", c); |
|
} |
|
break; |
|
|
|
case L'_': |
|
if (obuf[col].c_char == L'\0') { |
|
obuf[col].c_char = L'_'; |
|
obuf[col].c_width = 1; |
|
} else |
|
obuf[col].c_mode |= UNDERL | mode; |
|
/* FALLTHROUGH */ |
|
|
|
case L' ': |
|
if (obuf[col].c_pos == 0) { |
|
obuf[col].c_width = 1; |
|
obuf[col].c_pos = obuf[col - 1].c_pos + 1; |
|
} |
|
col++; |
|
if (col > maxcol) |
|
maxcol = col; |
|
break; |
|
|
|
case L'\n': |
|
flushln(); |
|
break; |
|
|
|
case L'\f': |
|
flushln(); |
|
putwchar(L'\f'); |
|
break; |
|
|
default: |
default: |
errx(1, "0%o: unknown escape sequence", c); |
/* Discard valid, but non-printable characters. */ |
/* NOTREACHED */ |
if ((w = wcwidth(c)) == -1) |
} |
break; |
continue; |
|
|
|
case '_': |
if (obuf[col].c_char == L'\0') { |
if (obuf[col].c_char) |
obuf[col].c_char = c; |
obuf[col].c_mode |= UNDERL | mode; |
obuf[col].c_mode = mode; |
else |
obuf[col].c_width = w; |
obuf[col].c_char = '_'; |
obuf[col].c_pos = obuf[col - 1].c_pos + w; |
/* FALLTHROUGH */ |
} else if (obuf[col].c_char == L'_') { |
case ' ': |
obuf[col].c_char = c; |
col++; |
obuf[col].c_mode |= UNDERL|mode; |
if (col > maxcol) |
obuf[col].c_width = w; |
maxcol = col; |
obuf[col].c_pos = obuf[col - 1].c_pos + w; |
continue; |
for (cp = obuf + col; cp[1].c_pos > 0; cp++) |
case '\n': |
cp[1].c_pos = cp[0].c_pos + |
flushln(); |
cp[1].c_width; |
continue; |
} else if (obuf[col].c_char == c) |
case '\f': |
obuf[col].c_mode |= BOLD|mode; |
flushln(); |
else |
putchar('\f'); |
obuf[col].c_mode = mode; |
continue; |
col++; |
default: |
if (col > maxcol) |
if (c < ' ') /* non printing */ |
maxcol = col; |
continue; |
break; |
if (obuf[col].c_char == '\0') { |
} |
obuf[col].c_char = c; |
skip_bs = 0; |
obuf[col].c_mode = mode; |
|
} else if (obuf[col].c_char == '_') { |
|
obuf[col].c_char = c; |
|
obuf[col].c_mode |= UNDERL|mode; |
|
} else if (obuf[col].c_char == c) |
|
obuf[col].c_mode |= BOLD|mode; |
|
else |
|
obuf[col].c_mode = mode; |
|
col++; |
|
if (col > maxcol) |
|
maxcol = col; |
|
continue; |
|
} |
} |
if (maxcol) |
|
flushln(); |
|
} |
} |
|
|
void |
void |
|
|
int hadmodes = 0; |
int hadmodes = 0; |
|
|
lastmode = NORMAL; |
lastmode = NORMAL; |
for (i=0; i < maxcol; i++) { |
for (i = 1; i < maxcol; i++) { |
if (obuf[i].c_mode != lastmode) { |
if (obuf[i].c_mode != lastmode) { |
hadmodes++; |
hadmodes = 1; |
msetmode(obuf[i].c_mode); |
msetmode(obuf[i].c_mode); |
lastmode = obuf[i].c_mode; |
lastmode = obuf[i].c_mode; |
} |
} |
if (obuf[i].c_char == '\0') { |
if (obuf[i].c_char == L'\0') { |
if (upln) |
if (upln) |
PRINT(CURS_RIGHT); |
PRINT(CURS_RIGHT); |
else |
else |
outc(' '); |
outc(L' ', 1); |
} else |
} else |
outc(obuf[i].c_char); |
outc(obuf[i].c_char, obuf[i].c_width); |
} |
} |
if (lastmode != NORMAL) { |
if (lastmode != NORMAL) |
msetmode(0); |
msetmode(0); |
} |
|
if (must_overstrike && hadmodes) |
if (must_overstrike && hadmodes) |
overstrike(); |
overstrike(); |
putchar('\n'); |
putwchar(L'\n'); |
if (iflag && hadmodes) |
if (iflag && hadmodes) |
iattr(); |
iattr(); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
void |
void |
overstrike(void) |
overstrike(void) |
{ |
{ |
int i; |
wchar_t wc; |
char *buf, *cp; |
int i, j, needspace; |
int hadbold = 0; |
|
|
|
if ((buf = malloc(maxcol + 1)) == NULL) |
putwchar(L'\r'); |
err(1, NULL); |
needspace = 0; |
cp = buf; |
for (i = 1; i < maxcol; i++) { |
|
if (obuf[i].c_mode != UNDERL && obuf[i].c_mode != BOLD) { |
|
needspace += obuf[i].c_width; |
|
continue; |
|
} |
|
while (needspace > 0) { |
|
putwchar(L' '); |
|
needspace--; |
|
} |
|
if (obuf[i].c_mode == BOLD) |
|
putwchar(obuf[i].c_char); |
|
else |
|
for (j = 0; j < obuf[i].c_width; j++) |
|
putwchar(L'_'); |
|
} |
|
} |
|
|
/* Set up overstrike buffer */ |
void |
for (i = 0; i < maxcol; i++) |
iattr(void) |
|
{ |
|
int i, j, needspace; |
|
char c; |
|
|
|
needspace = 0; |
|
for (i = 1; i < maxcol; i++) { |
switch (obuf[i].c_mode) { |
switch (obuf[i].c_mode) { |
case NORMAL: |
case NORMAL: |
default: |
needspace += obuf[i].c_width; |
*cp++ = ' '; |
continue; |
|
case ALTSET: |
|
c = 'g'; |
break; |
break; |
|
case SUPERSC: |
|
c = '^'; |
|
break; |
|
case SUBSC: |
|
c = 'v'; |
|
break; |
case UNDERL: |
case UNDERL: |
*cp++ = '_'; |
c = '_'; |
break; |
break; |
case BOLD: |
case BOLD: |
*cp++ = obuf[i].c_char; |
c = '!'; |
hadbold=1; |
|
break; |
break; |
|
default: |
|
c = 'X'; |
|
break; |
} |
} |
putchar('\r'); |
while (needspace > 0) { |
while (cp > buf && *(cp - 1) == ' ') |
putwchar(L' '); |
cp--; |
needspace--; |
*cp = '\0'; |
} |
for (cp = buf; *cp != '\0'; cp++) |
for (j = 0; j < obuf[i].c_width; j++) |
putchar(*cp); |
putwchar(c); |
if (hadbold) { |
|
putchar('\r'); |
|
for (cp = buf; *cp != '\0'; cp++) |
|
putchar(*cp=='_' ? ' ' : *cp); |
|
putchar('\r'); |
|
for (cp = buf; *cp != '\0'; cp++) |
|
putchar(*cp=='_' ? ' ' : *cp); |
|
} |
} |
free(buf); |
putwchar(L'\n'); |
} |
} |
|
|
void |
void |
iattr(void) |
|
{ |
|
int i; |
|
char *buf, *cp; |
|
|
|
if ((buf = malloc(maxcol + 1)) == NULL) |
|
err(1, NULL); |
|
cp = buf; |
|
|
|
for (i=0; i < maxcol; i++) |
|
switch (obuf[i].c_mode) { |
|
case NORMAL: *cp++ = ' '; break; |
|
case ALTSET: *cp++ = 'g'; break; |
|
case SUPERSC: *cp++ = '^'; break; |
|
case SUBSC: *cp++ = 'v'; break; |
|
case UNDERL: *cp++ = '_'; break; |
|
case BOLD: *cp++ = '!'; break; |
|
default: *cp++ = 'X'; break; |
|
} |
|
while (cp > buf && *(cp - 1) == ' ') |
|
cp--; |
|
*cp = '\0'; |
|
for (cp = buf; *cp != '\0'; cp++) |
|
putchar(*cp); |
|
free(buf); |
|
putchar('\n'); |
|
} |
|
|
|
void |
|
initbuf(void) |
initbuf(void) |
{ |
{ |
bzero(obuf, sizeof (obuf)); /* depends on NORMAL == 0 */ |
bzero(obuf, sizeof (obuf)); /* depends on NORMAL == 0 */ |
col = 0; |
col = 1; |
maxcol = 0; |
maxcol = 0; |
mode &= ALTSET; |
mode &= ALTSET; |
} |
} |
|
|
int |
int |
outchar(int c) |
outchar(int c) |
{ |
{ |
putchar(c & 0177); |
return (putwchar(c) != WEOF ? c : EOF); |
return (0); |
|
} |
} |
|
|
static int curmode = 0; |
static int curmode = 0; |
|
|
void |
void |
outc(int c) |
outc(wchar_t c, int width) |
{ |
{ |
putchar(c); |
int i; |
|
|
|
putwchar(c); |
if (must_use_uc && (curmode&UNDERL)) { |
if (must_use_uc && (curmode&UNDERL)) { |
PRINT(CURS_LEFT); |
for (i = 0; i < width; i++) |
PRINT(UNDER_CHAR); |
PRINT(CURS_LEFT); |
|
for (i = 0; i < width; i++) |
|
PRINT(UNDER_CHAR); |
} |
} |
} |
} |
|
|