#include <xterm.h>
#include <data.h>
#include <menu.h>
#include <error.h>
#include <stdio.h>
#undef CTRL
#define CTRL(c) ((c) & 0x1f)
#define SHIFT_IN '\017'
#define SHIFT_OUT '\016'
#define CSET_IN 'A'
#define CSET_OUT '0'
#define isForm(c) ((c) == '\r' || (c) == '\n' || (c) == '\f')
#define Strlen(a) strlen((char *)a)
#define Strcmp(a,b) strcmp((char *)a,(char *)b)
#define Strncmp(a,b,c) strncmp((char *)a,(char *)b,c)
#ifdef VMS
#define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt"
#endif
static void charToPrinter(unsigned chr);
static void printLine(int row, unsigned chr);
static void send_CharSet(int row);
static void send_SGR(unsigned attr, unsigned fg, unsigned bg);
static void stringToPrinter(char *str);
static FILE *Printer;
static pid_t Printer_pid;
static int initialized;
static void
closePrinter(void)
{
if (xtermHasPrinter() != 0) {
#ifdef VMS
TScreen *screen = TScreenOf(term);
char pcommand[256];
(void) sprintf(pcommand, "%s %s;",
screen->printer_command,
VMS_TEMP_PRINT_FILE);
#endif
if (Printer != 0) {
fclose(Printer);
TRACE(("closed printer, waiting...\n"));
#ifdef VMS
(void) system(pcommand);
#else
while (nonblocking_wait() > 0)
#endif
;
Printer = 0;
initialized = 0;
TRACE(("closed printer\n"));
}
}
}
static void
printCursorLine(void)
{
TScreen *screen = TScreenOf(term);
TRACE(("printCursorLine\n"));
printLine(screen->cur_row, '\n');
}
#define NO_COLOR ((unsigned)-1)
static void
printLine(int row, unsigned chr)
{
TScreen *screen = TScreenOf(term);
int inx = ROW2INX(screen, row);
Char *c = SCRN_BUF_CHARS(screen, inx);
Char *a = SCRN_BUF_ATTRS(screen, inx);
Char attr = 0;
unsigned ch;
int last = MaxCols(screen);
int col;
#if OPT_ISO_COLORS && OPT_PRINT_COLORS
#if OPT_EXT_COLORS
Char *fbf = 0;
Char *fbb = 0;
#define ColorOf(col) (unsigned)((fbf[col] << 8) | fbb[col])
#else
Char *fb = 0;
#define ColorOf(col) (fb[col])
#endif
#endif
unsigned fg = NO_COLOR, last_fg = NO_COLOR;
unsigned bg = NO_COLOR, last_bg = NO_COLOR;
int cs = CSET_IN;
int last_cs = CSET_IN;
TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n",
row, ROW2INX(screen, row), screen->topline, screen->max_row, chr,
visibleChars(PAIRED_CHARS(c,
(screen->utf8_mode
? SCRN_BUF_WIDEC(screen, inx)
: 0)),
(unsigned) last)));
if_OPT_EXT_COLORS(screen, {
fbf = SCRN_BUF_FGRND(screen, inx);
fbb = SCRN_BUF_BGRND(screen, inx);
});
if_OPT_ISO_TRADITIONAL_COLORS(screen, {
fb = SCRN_BUF_COLOR(screen, inx);
});
while (last > 0) {
if ((a[last - 1] & CHARDRAWN) == 0)
last--;
else
break;
}
if (last) {
if (screen->print_attributes) {
send_CharSet(row);
send_SGR(0, NO_COLOR, NO_COLOR);
}
for (col = 0; col < last; col++) {
ch = c[col];
if_OPT_WIDE_CHARS(screen, {
ch = XTERM_CELL(row, col);
});
#if OPT_PRINT_COLORS
if (screen->colorMode) {
if (screen->print_attributes > 1) {
fg = (a[col] & FG_COLOR)
? extract_fg(term, ColorOf(col), a[col])
: NO_COLOR;
bg = (a[col] & BG_COLOR)
? extract_bg(term, ColorOf(col), a[col])
: NO_COLOR;
}
}
#endif
if ((((a[col] & SGR_MASK) != attr)
#if OPT_PRINT_COLORS
|| (last_fg != fg) || (last_bg != bg)
#endif
)
&& ch) {
attr = CharOf(a[col] & SGR_MASK);
last_fg = fg;
last_bg = bg;
if (screen->print_attributes)
send_SGR(attr, fg, bg);
}
if (ch == 0)
ch = ' ';
#if OPT_WIDE_CHARS
if (screen->utf8_mode)
cs = CSET_IN;
else
#endif
cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT;
if (last_cs != cs) {
if (screen->print_attributes) {
charToPrinter((unsigned) ((cs == CSET_OUT)
? SHIFT_OUT
: SHIFT_IN));
}
last_cs = cs;
}
charToPrinter(((cs == CSET_OUT)
? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f))
: ch));
if_OPT_WIDE_CHARS(screen, {
int off;
for (off = OFF_FINAL; off < MAX_PTRS; off += 2) {
if ((ch = XTERM_CELLC(row, col, off)) == 0)
break;
charToPrinter(ch);
}
});
}
if (screen->print_attributes) {
send_SGR(0, NO_COLOR, NO_COLOR);
if (cs != CSET_IN)
charToPrinter(SHIFT_IN);
}
}
if (screen->print_attributes)
charToPrinter('\r');
charToPrinter(chr);
}
void
xtermPrintScreen(Bool use_DECPEX)
{
if (XtIsRealized((Widget) term)) {
TScreen *screen = TScreenOf(term);
Bool extent = (use_DECPEX && screen->printer_extent);
int top = extent ? 0 : screen->top_marg;
int bot = extent ? screen->max_row : screen->bot_marg;
int was_open = initialized;
TRACE(("xtermPrintScreen, rows %d..%d\n", top, bot));
while (top <= bot)
printLine(top++, '\n');
if (screen->printer_formfeed)
charToPrinter('\f');
if (!was_open || screen->printer_autoclose) {
closePrinter();
}
} else {
Bell(XkbBI_MinorError, 0);
}
}
static void
xtermPrintEverything(void)
{
TScreen *screen = TScreenOf(term);
int top = 0;
int bot = screen->max_row;
int was_open = initialized;
if (!screen->altbuf)
top = -screen->savedlines;
TRACE(("xtermPrintEverything, rows %d..%d\n", top, bot));
while (top <= bot)
printLine(top++, '\n');
if (screen->printer_formfeed)
charToPrinter('\f');
if (!was_open || screen->printer_autoclose) {
closePrinter();
}
}
static void
send_CharSet(int row)
{
#if OPT_DEC_CHRSET
TScreen *screen = TScreenOf(term);
char *msg = 0;
switch (SCRN_BUF_CSETS(screen, row)[0]) {
case CSET_SWL:
msg = "\033#5";
break;
case CSET_DHL_TOP:
msg = "\033#3";
break;
case CSET_DHL_BOT:
msg = "\033#4";
break;
case CSET_DWL:
msg = "\033#6";
break;
}
if (msg != 0)
stringToPrinter(msg);
#else
(void) row;
#endif
}
static void
send_SGR(unsigned attr, unsigned fg, unsigned bg)
{
char msg[80];
strcpy(msg, "\033[0");
if (attr & BOLD)
strcat(msg, ";1");
if (attr & UNDERLINE)
strcat(msg, ";4");
if (attr & BLINK)
strcat(msg, ";5");
if (attr & INVERSE)
strcat(msg, ";7");
#if OPT_PRINT_COLORS
if (bg != NO_COLOR) {
sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg));
}
if (fg != NO_COLOR) {
#if OPT_PC_COLORS
if (term->screen.boldColors
&& fg > 8
&& (attr & BOLD) != 0)
fg -= 8;
#endif
sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg));
}
#else
(void) bg;
(void) fg;
#endif
strcat(msg, "m");
stringToPrinter(msg);
}
static void
charToPrinter(unsigned chr)
{
TScreen *screen = TScreenOf(term);
if (!initialized && xtermHasPrinter()) {
#if defined(VMS)
Printer = fopen(VMS_TEMP_PRINT_FILE, "w");
#else
FILE *input;
int my_pipe[2];
int c;
if (pipe(my_pipe))
SysError(ERROR_FORK);
if ((Printer_pid = fork()) < 0)
SysError(ERROR_FORK);
if (Printer_pid == 0) {
TRACE(((char *) 0));
close(my_pipe[1]);
close(screen->respond);
close(fileno(stdout));
dup2(fileno(stderr), 1);
if (fileno(stderr) != 2) {
dup2(fileno(stderr), 2);
close(fileno(stderr));
}
if (xtermResetIds(screen) < 0)
exit(1);
Printer = popen(screen->printer_command, "w");
input = fdopen(my_pipe[0], "r");
while ((c = fgetc(input)) != EOF) {
fputc(c, Printer);
if (isForm(c))
fflush(Printer);
}
pclose(Printer);
exit(0);
} else {
close(my_pipe[0]);
Printer = fdopen(my_pipe[1], "w");
TRACE(("opened printer from pid %d/%d\n",
(int) getpid(), Printer_pid));
}
#endif
initialized++;
}
if (Printer != 0) {
#if OPT_WIDE_CHARS
if (chr > 127) {
Char temp[10];
*convertToUTF8(temp, chr) = 0;
fputs((char *) temp, Printer);
} else
#endif
fputc((int) chr, Printer);
if (isForm(chr))
fflush(Printer);
}
}
static void
stringToPrinter(char *str)
{
while (*str)
charToPrinter(CharOf(*str++));
}
void
xtermMediaControl(int param, int private_seq)
{
TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq));
if (private_seq) {
switch (param) {
case 1:
printCursorLine();
break;
case 4:
setPrinterControlMode(0);
break;
case 5:
setPrinterControlMode(1);
break;
case 10:
xtermPrintScreen(False);
break;
case 11:
xtermPrintEverything();
break;
}
} else {
switch (param) {
case -1:
case 0:
xtermPrintScreen(True);
break;
case 4:
setPrinterControlMode(0);
break;
case 5:
setPrinterControlMode(2);
break;
}
}
}
void
xtermAutoPrint(unsigned chr)
{
TScreen *screen = TScreenOf(term);
if (screen->printer_controlmode == 1) {
TRACE(("AutoPrint %d\n", chr));
printLine(screen->cursorp.row, chr);
if (Printer != 0)
fflush(Printer);
}
}
#define LB '['
int
xtermPrinterControl(int chr)
{
TScreen *screen = TScreenOf(term);
static struct {
Char seq[5];
int active;
} tbl[] = {
{ { ANSI_CSI, '5', 'i' }, 2 },
{ { ANSI_CSI, '4', 'i' }, 0 },
{ { ANSI_ESC, LB, '5', 'i' }, 2 },
{ { ANSI_ESC, LB, '4', 'i' }, 0 },
};
static Char bfr[10];
static size_t length;
size_t n;
TRACE(("In printer:%04X\n", chr));
switch (chr) {
case 0:
case CTRL('Q'):
case CTRL('S'):
return 0;
case ANSI_CSI:
case ANSI_ESC:
case '[':
case '4':
case '5':
case 'i':
bfr[length++] = CharOf(chr);
for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) {
size_t len = Strlen(tbl[n].seq);
if (length == len
&& Strcmp(bfr, tbl[n].seq) == 0) {
setPrinterControlMode(tbl[n].active);
if (screen->printer_autoclose
&& screen->printer_controlmode == 0)
closePrinter();
length = 0;
return 0;
} else if (len > length
&& Strncmp(bfr, tbl[n].seq, length) == 0) {
return 0;
}
}
length--;
default:
for (n = 0; n < length; n++)
charToPrinter(bfr[n]);
bfr[0] = CharOf(chr);
length = 1;
return 0;
}
}
Bool
xtermHasPrinter(void)
{
TScreen *screen = TScreenOf(term);
return (strlen(screen->printer_command) != 0);
}
#define showPrinterControlMode(mode) \
(((mode) == 0) \
? "normal" \
: ((mode) == 1 \
? "autoprint" \
: "printer controller"))
void
setPrinterControlMode(int mode)
{
if (xtermHasPrinter()
&& term->screen.printer_controlmode != mode) {
TRACE(("%s %s mode\n",
(mode
? "set"
: "reset"),
(mode
? showPrinterControlMode(mode)
: showPrinterControlMode(term->screen.printer_controlmode))));
term->screen.printer_controlmode = mode;
update_print_redir();
}
}