summaryrefslogtreecommitdiff
path: root/app/xterm/print.c
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 11:11:55 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 11:11:55 +0000
commit145a665014b2aa230b81b582689c8ec17ef9968e (patch)
tree5ea1019527fe16cc21b9702371c72cc7f8c8090c /app/xterm/print.c
parent95c2d1cbda23a41cdf6e63520c7f0b825e63dd5b (diff)
Importing xterm 216
Diffstat (limited to 'app/xterm/print.c')
-rw-r--r--app/xterm/print.c622
1 files changed, 622 insertions, 0 deletions
diff --git a/app/xterm/print.c b/app/xterm/print.c
new file mode 100644
index 000000000..6255e8a44
--- /dev/null
+++ b/app/xterm/print.c
@@ -0,0 +1,622 @@
+/* $XTermId: print.c,v 1.77 2006/07/23 22:06:23 tom Exp $ */
+
+/*
+ * $XFree86: xc/programs/xterm/print.c,v 1.24 2006/06/19 00:36:51 dickey Exp $
+ */
+
+/************************************************************
+
+Copyright 1997-2005,2006 by Thomas E. Dickey
+
+ All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name(s) of the above copyright
+holders shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization.
+
+********************************************************/
+
+#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 = &term->screen;
+
+ 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 /* This is a quick hack, really should use
+ spawn and check status or system services
+ and go straight to the queue */
+ (void) system(pcommand);
+#else /* VMS */
+ while (nonblocking_wait() > 0)
+#endif /* VMS */
+ ;
+ Printer = 0;
+ initialized = 0;
+ TRACE(("closed printer\n"));
+ }
+ }
+}
+
+static void
+printCursorLine(void)
+{
+ TScreen *screen = &term->screen;
+
+ TRACE(("printCursorLine\n"));
+ printLine(screen->cur_row, '\n');
+}
+
+#define NO_COLOR ((unsigned)-1)
+
+/*
+ * DEC's manual doesn't document whether trailing blanks are removed, or what
+ * happens with a line that is entirely blank. This function prints the
+ * characters that xterm would allow as a selection (which may include blanks).
+ */
+static void
+printLine(int row, unsigned chr)
+{
+ TScreen *screen = &term->screen;
+ 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 = (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 != 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;
+ }
+
+ /* FIXME: we shouldn't have to map back from the
+ * alternate character set, except that the
+ * corresponding charset information is not encoded
+ * into the CSETS array.
+ */
+ charToPrinter(((cs == CSET_OUT)
+ ? (ch == 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 = &term->screen;
+ 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);
+ }
+}
+
+/*
+ * If the alternate screen is active, we'll print only that. Otherwise, print
+ * the normal screen plus all scrolled-back lines. The distinction is made
+ * because the normal screen's buffer is part of the overall scrollback buffer.
+ */
+static void
+xtermPrintEverything(void)
+{
+ TScreen *screen = &term->screen;
+ 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 = &term->screen;
+ 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 /* OPT_DEC_CHRSET */
+}
+
+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"); /* typo? DEC documents this as '2' */
+ if (attr & BLINK)
+ strcat(msg, ";5");
+ if (attr & INVERSE) /* typo? DEC documents this as invisible */
+ 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);
+}
+
+/*
+ * This implementation only knows how to write to a pipe.
+ */
+static void
+charToPrinter(unsigned chr)
+{
+ TScreen *screen = &term->screen;
+
+ if (!initialized && xtermHasPrinter()) {
+#if defined(VMS)
+ /*
+ * This implementation only knows how to write to a file. When the
+ * file is closed the print command executes. Print command must be of
+ * the form:
+ * print/que=name/delete [/otherflags].
+ */
+ Printer = fopen(VMS_TEMP_PRINT_FILE, "w");
+#else
+ /*
+ * This implementation only knows how to write to a pipe.
+ */
+ 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]); /* printer is silent */
+ close(screen->respond);
+
+ close(fileno(stdout));
+ dup2(fileno(stderr), 1);
+
+ if (fileno(stderr) != 2) {
+ dup2(fileno(stderr), 2);
+ close(fileno(stderr));
+ }
+
+ /* don't want privileges! */
+ 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]); /* won't read from printer */
+ 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++));
+}
+
+/*
+ * This module implements the MC (Media Copy) and related printing control
+ * sequences for VTxxx emulation. This is based on the description in the
+ * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment
+ * Corp., March 1987).
+ */
+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: /* VT320 */
+ xtermPrintScreen(False);
+ break;
+ case 11: /* VT320 */
+ xtermPrintEverything();
+ break;
+ }
+ } else {
+ switch (param) {
+ case -1:
+ case 0:
+ xtermPrintScreen(True);
+ break;
+ case 4:
+ setPrinterControlMode(0);
+ break;
+ case 5:
+ setPrinterControlMode(2);
+ break;
+ }
+ }
+}
+
+/*
+ * When in autoprint mode, the printer prints a line from the screen when you
+ * move the cursor off that line with an LF, FF, or VT character, or an
+ * autowrap occurs. The printed line ends with a CR and the character (LF, FF
+ * or VT) that moved the cursor off the previous line.
+ */
+void
+xtermAutoPrint(unsigned chr)
+{
+ TScreen *screen = &term->screen;
+
+ if (screen->printer_controlmode == 1) {
+ TRACE(("AutoPrint %d\n", chr));
+ printLine(screen->cursorp.row, chr);
+ if (Printer != 0)
+ fflush(Printer);
+ }
+}
+
+/*
+ * When in printer controller mode, the terminal sends received characters to
+ * the printer without displaying them on the screen. The terminal sends all
+ * characters and control sequences to the printer, except NUL, XON, XOFF, and
+ * the printer controller sequences.
+ *
+ * This function eats characters, returning 0 as long as it must buffer or
+ * divert to the printer. We're only invoked here when in printer controller
+ * mode, and handle the exit from that mode.
+ */
+#define LB '['
+
+int
+xtermPrinterControl(int chr)
+{
+ TScreen *screen = &term->screen;
+ /* *INDENT-OFF* */
+ static struct {
+ Char seq[5];
+ int active;
+ } tbl[] = {
+ { { CSI, '5', 'i' }, 2 },
+ { { CSI, '4', 'i' }, 0 },
+ { { ESC, LB, '5', 'i' }, 2 },
+ { { ESC, LB, '4', 'i' }, 0 },
+ };
+ /* *INDENT-ON* */
+
+ 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; /* ignored by application */
+
+ case CSI:
+ case ESC:
+ case '[':
+ case '4':
+ case '5':
+ case 'i':
+ bfr[length++] = 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--;
+
+ /* FALLTHRU */
+
+ default:
+ for (n = 0; n < length; n++)
+ charToPrinter(bfr[n]);
+ bfr[0] = chr;
+ length = 1;
+ return 0;
+ }
+}
+
+/*
+ * If there is no printer command, we will ignore printer controls.
+ */
+Bool
+xtermHasPrinter(void)
+{
+ TScreen *screen = &term->screen;
+
+ 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();
+ }
+}