1 /* $XTermId: print.c,v 1.121 2011/02/09 10:11:44 tom Exp $ */
3 /************************************************************
5 Copyright 1997-2010,2011 by Thomas E. Dickey
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
24 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 Except as contained in this notice, the name(s) of the above copyright
29 holders shall not be used in advertising or otherwise to promote the
30 sale, use or other dealings in this Software without prior written
33 ********************************************************/
44 #define CTRL(c) ((c) & 0x1f)
46 #define SHIFT_IN '\017'
47 #define SHIFT_OUT '\016'
52 #define isForm(c) ((c) == '\r' || (c) == '\n' || (c) == '\f')
53 #define Strlen(a) strlen((char *)a)
54 #define Strcmp(a,b) strcmp((char *)a,(char *)b)
55 #define Strncmp(a,b,c) strncmp((char *)a,(char *)b,c)
58 #define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt"
61 static void charToPrinter(XtermWidget /* xw */ ,
63 static void printLine(XtermWidget /* xw */ ,
66 PrinterFlags * /* p */ );
67 static void send_CharSet(XtermWidget /* xw */ ,
68 LineData * /* ld */ );
69 static void send_SGR(XtermWidget /* xw */ ,
73 static void stringToPrinter(XtermWidget /* xw */ ,
74 const char * /*str */ );
77 static pid_t Printer_pid;
78 static int initialized;
81 closePrinter(XtermWidget xw GCC_UNUSED)
83 if (xtermHasPrinter(xw) != 0) {
85 TScreen *screen = TScreenOf(xw);
88 (void) sprintf(pcommand, "%s %s;",
89 screen->printer_command,
95 TRACE(("closed printer, waiting...\n"));
96 #ifdef VMS /* This is a quick hack, really should use
97 spawn and check status or system services
98 and go straight to the queue */
99 (void) system(pcommand);
101 while (nonblocking_wait() > 0)
106 TRACE(("closed printer\n"));
112 printCursorLine(XtermWidget xw)
114 TScreen *screen = TScreenOf(xw);
116 TRACE(("printCursorLine\n"));
117 printLine(xw, screen->cur_row, '\n', getPrinterFlags(xw, NULL, 0));
120 #define NO_COLOR ((unsigned)-1)
123 * DEC's manual doesn't document whether trailing blanks are removed, or what
124 * happens with a line that is entirely blank. This function prints the
125 * characters that xterm would allow as a selection (which may include blanks).
128 printLine(XtermWidget xw, int row, unsigned chr, PrinterFlags * p)
130 TScreen *screen = TScreenOf(xw);
131 int inx = ROW2INX(screen, row);
135 int last = MaxCols(screen);
137 #if OPT_ISO_COLORS && OPT_PRINT_COLORS
138 #define ColorOf(ld,col) (ld->color[col])
140 unsigned fg = NO_COLOR, last_fg = NO_COLOR;
141 unsigned bg = NO_COLOR, last_bg = NO_COLOR;
143 int last_cs = CSET_IN;
145 ld = getLineData(screen, inx);
149 TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n",
150 row, ROW2INX(screen, row), screen->topline, screen->max_row, chr,
151 visibleIChars(ld->charData, (unsigned) last)));
154 if ((ld->attribs[last - 1] & CHARDRAWN) == 0)
160 if (p->print_attributes) {
161 send_CharSet(xw, ld);
162 send_SGR(xw, 0, NO_COLOR, NO_COLOR);
164 for (col = 0; col < last; col++) {
165 ch = ld->charData[col];
167 if (screen->colorMode) {
168 if (p->print_attributes > 1) {
169 fg = (ld->attribs[col] & FG_COLOR)
170 ? extract_fg(xw, ColorOf(ld, col), ld->attribs[col])
172 bg = (ld->attribs[col] & BG_COLOR)
173 ? extract_bg(xw, ColorOf(ld, col), ld->attribs[col])
178 if ((((ld->attribs[col] & SGR_MASK) != attr)
180 || (last_fg != fg) || (last_bg != bg)
184 attr = CharOf(ld->attribs[col] & SGR_MASK);
189 if (p->print_attributes)
190 send_SGR(xw, attr, fg, bg);
197 if (screen->utf8_mode)
201 cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT;
203 if (p->print_attributes) {
205 (unsigned) ((cs == CSET_OUT)
212 /* FIXME: we shouldn't have to map back from the
213 * alternate character set, except that the
214 * corresponding charset information is not encoded
215 * into the CSETS array.
219 ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f))
221 if_OPT_WIDE_CHARS(screen, {
223 for_each_combData(off, ld) {
224 ch = ld->combData[off][col];
227 charToPrinter(xw, ch);
231 if (p->print_attributes) {
232 send_SGR(xw, 0, NO_COLOR, NO_COLOR);
234 charToPrinter(xw, SHIFT_IN);
238 /* finish line (protocol for attributes needs a CR */
239 if (p->print_attributes)
240 charToPrinter(xw, '\r');
242 if (chr && !(p->printer_newline)) {
243 if (LineTstWrapped(ld))
248 charToPrinter(xw, chr);
253 #define PrintNewLine() (unsigned) (((top < bot) || p->printer_newline) ? '\n' : '\0')
256 xtermPrintScreen(XtermWidget xw, Bool use_DECPEX, PrinterFlags * p)
258 if (XtIsRealized((Widget) xw)) {
259 TScreen *screen = TScreenOf(xw);
260 Bool extent = (use_DECPEX && p->printer_extent);
261 int top = extent ? 0 : screen->top_marg;
262 int bot = extent ? screen->max_row : screen->bot_marg;
263 int was_open = initialized;
265 TRACE(("xtermPrintScreen, rows %d..%d\n", top, bot));
268 printLine(xw, top, PrintNewLine(), p);
271 if (p->printer_formfeed)
272 charToPrinter(xw, '\f');
274 if (!was_open || screen->printer_autoclose) {
278 Bell(xw, XkbBI_MinorError, 0);
283 * If the alternate screen is active, we'll print only that. Otherwise, print
284 * the normal screen plus all scrolled-back lines. The distinction is made
285 * because the normal screen's buffer is part of the overall scrollback buffer.
288 xtermPrintEverything(XtermWidget xw, PrinterFlags * p)
290 TScreen *screen = TScreenOf(xw);
292 int bot = screen->max_row;
293 int was_open = initialized;
295 if (!screen->whichBuf) {
296 top = -screen->savedlines - screen->topline;
297 bot -= screen->topline;
300 TRACE(("xtermPrintEverything, rows %d..%d\n", top, bot));
302 printLine(xw, top, PrintNewLine(), p);
305 if (p->printer_formfeed)
306 charToPrinter(xw, '\f');
308 if (!was_open || screen->printer_autoclose) {
314 send_CharSet(XtermWidget xw, LineData * ld)
319 switch (GetLineDblCS(ld)) {
334 stringToPrinter(xw, msg);
338 #endif /* OPT_DEC_CHRSET */
342 send_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg)
345 strcpy(msg, "\033[0");
348 if (attr & UNDERLINE)
349 strcat(msg, ";4"); /* typo? DEC documents this as '2' */
352 if (attr & INVERSE) /* typo? DEC documents this as invisible */
355 if (bg != NO_COLOR) {
356 sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg));
358 if (fg != NO_COLOR) {
360 if (TScreenOf(xw)->boldColors
362 && (attr & BOLD) != 0)
365 sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg));
372 stringToPrinter(xw, msg);
376 * This implementation only knows how to write to a pipe.
379 charToPrinter(XtermWidget xw, unsigned chr)
381 TScreen *screen = TScreenOf(xw);
383 if (!initialized && xtermHasPrinter(xw)) {
386 * This implementation only knows how to write to a file. When the
387 * file is closed the print command executes. Print command must be of
389 * print/que=name/delete [/otherflags].
391 Printer = fopen(VMS_TEMP_PRINT_FILE, "w");
394 * This implementation only knows how to write to a pipe.
401 SysError(ERROR_FORK);
402 if ((Printer_pid = fork()) < 0)
403 SysError(ERROR_FORK);
405 if (Printer_pid == 0) {
407 close(my_pipe[1]); /* printer is silent */
408 close(screen->respond);
410 close(fileno(stdout));
411 dup2(fileno(stderr), 1);
413 if (fileno(stderr) != 2) {
414 dup2(fileno(stderr), 2);
415 close(fileno(stderr));
418 /* don't want privileges! */
419 if (xtermResetIds(screen) < 0)
422 Printer = popen(screen->printer_command, "w");
423 input = fdopen(my_pipe[0], "r");
424 while ((c = fgetc(input)) != EOF) {
432 close(my_pipe[0]); /* won't read from printer */
433 Printer = fdopen(my_pipe[1], "w");
434 TRACE(("opened printer from pid %d/%d\n",
435 (int) getpid(), (int) Printer_pid));
444 *convertToUTF8(temp, chr) = 0;
445 fputs((char *) temp, Printer);
448 fputc((int) chr, Printer);
455 stringToPrinter(XtermWidget xw, const char *str)
458 charToPrinter(xw, CharOf(*str++));
462 * This module implements the MC (Media Copy) and related printing control
463 * sequences for VTxxx emulation. This is based on the description in the
464 * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment
465 * Corp., March 1987).
468 xtermMediaControl(XtermWidget xw, int param, int private_seq)
470 TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq));
478 setPrinterControlMode(xw, 0);
481 setPrinterControlMode(xw, 1);
484 xtermPrintScreen(xw, False, getPrinterFlags(xw, NULL, 0));
487 xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0));
494 xtermPrintScreen(xw, True, getPrinterFlags(xw, NULL, 0));
497 setPrinterControlMode(xw, 0);
500 setPrinterControlMode(xw, 2);
507 * When in autoprint mode, the printer prints a line from the screen when you
508 * move the cursor off that line with an LF, FF, or VT character, or an
509 * autowrap occurs. The printed line ends with a CR and the character (LF, FF
510 * or VT) that moved the cursor off the previous line.
513 xtermAutoPrint(XtermWidget xw, unsigned chr)
515 TScreen *screen = TScreenOf(xw);
517 if (screen->printer_controlmode == 1) {
518 TRACE(("AutoPrint %d\n", chr));
519 printLine(xw, screen->cursorp.row, chr, getPrinterFlags(xw, NULL, 0));
526 * When in printer controller mode, the terminal sends received characters to
527 * the printer without displaying them on the screen. The terminal sends all
528 * characters and control sequences to the printer, except NUL, XON, XOFF, and
529 * the printer controller sequences.
531 * This function eats characters, returning 0 as long as it must buffer or
532 * divert to the printer. We're only invoked here when in printer controller
533 * mode, and handle the exit from that mode.
538 xtermPrinterControl(XtermWidget xw, int chr)
540 TScreen *screen = TScreenOf(xw);
546 { { ANSI_CSI, '5', 'i' }, 2 },
547 { { ANSI_CSI, '4', 'i' }, 0 },
548 { { ANSI_ESC, LB, '5', 'i' }, 2 },
549 { { ANSI_ESC, LB, '4', 'i' }, 0 },
554 static size_t length;
557 TRACE(("In printer:%04X\n", chr));
563 return 0; /* ignored by application */
571 bfr[length++] = CharOf(chr);
572 for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) {
573 size_t len = Strlen(tbl[n].seq);
576 && Strcmp(bfr, tbl[n].seq) == 0) {
577 setPrinterControlMode(xw, tbl[n].active);
578 if (screen->printer_autoclose
579 && screen->printer_controlmode == 0)
583 } else if (len > length
584 && Strncmp(bfr, tbl[n].seq, length) == 0) {
593 for (n = 0; n < length; n++)
594 charToPrinter(xw, bfr[n]);
595 bfr[0] = CharOf(chr);
602 * If there is no printer command, we will ignore printer controls.
605 xtermHasPrinter(XtermWidget xw)
607 TScreen *screen = TScreenOf(xw);
609 return (strlen(screen->printer_command) != 0);
612 #define showPrinterControlMode(mode) \
617 : "printer controller"))
620 setPrinterControlMode(XtermWidget xw, int mode)
622 TScreen *screen = TScreenOf(xw);
624 if (xtermHasPrinter(xw)
625 && screen->printer_controlmode != mode) {
626 TRACE(("%s %s mode\n",
631 ? showPrinterControlMode(mode)
632 : showPrinterControlMode(screen->printer_controlmode))));
633 screen->printer_controlmode = mode;
634 update_print_redir();
639 getPrinterFlags(XtermWidget xw, String * params, Cardinal *param_count)
642 static const struct {
647 { "noFormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 0 },
648 { "FormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 1 },
649 { "noNewLine", XtOffsetOf(PrinterFlags, printer_newline), 0 },
650 { "NewLine", XtOffsetOf(PrinterFlags, printer_newline), 1 },
651 { "noAttrs", XtOffsetOf(PrinterFlags, print_attributes), 0 },
652 { "monoAttrs", XtOffsetOf(PrinterFlags, print_attributes), 1 },
653 { "colorAttrs", XtOffsetOf(PrinterFlags, print_attributes), 2 },
657 TScreen *screen = TScreenOf(xw);
658 PrinterFlags *result = &(screen->printer_flags);
660 TRACE(("getPrinterFlags %d params\n", param_count ? *param_count : 0));
662 result->printer_extent = screen->printer_extent;
663 result->printer_formfeed = screen->printer_formfeed;
664 result->printer_newline = screen->printer_newline;
665 result->print_attributes = screen->print_attributes;
667 if (param_count != 0 && *param_count != 0) {
670 for (j = 0; j < *param_count; ++j) {
671 TRACE(("param%d:%s\n", j, params[j]));
672 for (k = 0; k < XtNumber(table); ++k) {
673 if (!x_strcasecmp(params[j], table[k].name)) {
674 int *ptr = (int *) (void *) ((char *) result + table[k].offset);
675 TRACE(("...PrinterFlags(%s) %d->%d\n",
679 *ptr = table[k].value;