print.c revision 894e0ac8
1894e0ac8Smrg/* $XTermId: print.c,v 1.152 2014/06/13 00:36:51 tom Exp $ */ 2d522f475Smrg 30bd37d32Smrg/* 4894e0ac8Smrg * Copyright 1997-2013,2014 by Thomas E. Dickey 50bd37d32Smrg * 60bd37d32Smrg * All Rights Reserved 70bd37d32Smrg * 80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a 90bd37d32Smrg * copy of this software and associated documentation files (the 100bd37d32Smrg * "Software"), to deal in the Software without restriction, including 110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish, 120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to 130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to 140bd37d32Smrg * the following conditions: 150bd37d32Smrg * 160bd37d32Smrg * The above copyright notice and this permission notice shall be included 170bd37d32Smrg * in all copies or substantial portions of the Software. 180bd37d32Smrg * 190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 260bd37d32Smrg * 270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright 280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the 290bd37d32Smrg * sale, use or other dealings in this Software without prior written 300bd37d32Smrg * authorization. 310bd37d32Smrg */ 32d522f475Smrg 33d522f475Smrg#include <xterm.h> 34d522f475Smrg#include <data.h> 35d522f475Smrg#include <menu.h> 36d522f475Smrg#include <error.h> 3720d2c4d2Smrg#include <xstrings.h> 38d522f475Smrg 39d522f475Smrg#include <stdio.h> 40e39b573cSmrg#include <sys/stat.h> 41d522f475Smrg 42d522f475Smrg#undef CTRL 43d522f475Smrg#define CTRL(c) ((c) & 0x1f) 44d522f475Smrg 45d522f475Smrg#define SHIFT_IN '\017' 46d522f475Smrg#define SHIFT_OUT '\016' 47d522f475Smrg 48d522f475Smrg#define CSET_IN 'A' 49d522f475Smrg#define CSET_OUT '0' 50d522f475Smrg 51d522f475Smrg#define isForm(c) ((c) == '\r' || (c) == '\n' || (c) == '\f') 52e39b573cSmrg#define Strlen(a) strlen((const char *)a) 53e39b573cSmrg#define Strcmp(a,b) strcmp((const char *)a,(const char *)b) 54e39b573cSmrg#define Strncmp(a,b,c) strncmp((const char *)a,(const char *)b,c) 55e39b573cSmrg 56e39b573cSmrg#define SPS PrinterOf(screen) 57d522f475Smrg 58d522f475Smrg#ifdef VMS 59d522f475Smrg#define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt" 60d522f475Smrg#endif 61d522f475Smrg 62956cc18dSsnjstatic void charToPrinter(XtermWidget /* xw */ , 63956cc18dSsnj unsigned /* chr */ ); 64956cc18dSsnjstatic void printLine(XtermWidget /* xw */ , 65956cc18dSsnj int /* row */ , 6620d2c4d2Smrg unsigned /* chr */ , 6720d2c4d2Smrg PrinterFlags * /* p */ ); 68956cc18dSsnjstatic void send_CharSet(XtermWidget /* xw */ , 69956cc18dSsnj LineData * /* ld */ ); 70956cc18dSsnjstatic void send_SGR(XtermWidget /* xw */ , 71956cc18dSsnj unsigned /* attr */ , 72956cc18dSsnj unsigned /* fg */ , 73956cc18dSsnj unsigned /* bg */ ); 74956cc18dSsnjstatic void stringToPrinter(XtermWidget /* xw */ , 7520d2c4d2Smrg const char * /*str */ ); 76d522f475Smrg 770bd37d32Smrgstatic void 78956cc18dSsnjclosePrinter(XtermWidget xw GCC_UNUSED) 79d522f475Smrg{ 80956cc18dSsnj if (xtermHasPrinter(xw) != 0) { 81956cc18dSsnj TScreen *screen = TScreenOf(xw); 82e39b573cSmrg#ifdef VMS 83d522f475Smrg char pcommand[256]; 84d522f475Smrg (void) sprintf(pcommand, "%s %s;", 85e39b573cSmrg SPS.printer_command, 86d522f475Smrg VMS_TEMP_PRINT_FILE); 87d522f475Smrg#endif 88d522f475Smrg 89e39b573cSmrg if (SPS.fp != 0) { 900bd37d32Smrg DEBUG_MSG("closePrinter\n"); 910bd37d32Smrg pclose(SPS.fp); 92d522f475Smrg TRACE(("closed printer, waiting...\n")); 93d522f475Smrg#ifdef VMS /* This is a quick hack, really should use 94d522f475Smrg spawn and check status or system services 95d522f475Smrg and go straight to the queue */ 96d522f475Smrg (void) system(pcommand); 97d522f475Smrg#else /* VMS */ 980bd37d32Smrg while (nonblocking_wait() > 0) { 99d522f475Smrg ; 1000bd37d32Smrg } 1010bd37d32Smrg#endif /* VMS */ 102e39b573cSmrg SPS.fp = 0; 103e39b573cSmrg SPS.isOpen = False; 104d522f475Smrg TRACE(("closed printer\n")); 1050bd37d32Smrg DEBUG_MSG("...closePrinter (done)\n"); 106d522f475Smrg } 107d522f475Smrg } 108d522f475Smrg} 109d522f475Smrg 110d522f475Smrgstatic void 111956cc18dSsnjprintCursorLine(XtermWidget xw) 112d522f475Smrg{ 113956cc18dSsnj TScreen *screen = TScreenOf(xw); 114d522f475Smrg 115d522f475Smrg TRACE(("printCursorLine\n")); 11620d2c4d2Smrg printLine(xw, screen->cur_row, '\n', getPrinterFlags(xw, NULL, 0)); 117d522f475Smrg} 118d522f475Smrg 119d522f475Smrg#define NO_COLOR ((unsigned)-1) 120d522f475Smrg 121d522f475Smrg/* 122d522f475Smrg * DEC's manual doesn't document whether trailing blanks are removed, or what 123d522f475Smrg * happens with a line that is entirely blank. This function prints the 124d522f475Smrg * characters that xterm would allow as a selection (which may include blanks). 125d522f475Smrg */ 126d522f475Smrgstatic void 127894e0ac8SmrgprintLine(XtermWidget xw, int row, unsigned chr, PrinterFlags *p) 128d522f475Smrg{ 129956cc18dSsnj TScreen *screen = TScreenOf(xw); 130d522f475Smrg int inx = ROW2INX(screen, row); 131956cc18dSsnj LineData *ld; 132894e0ac8Smrg IAttr attr = 0; 133d522f475Smrg unsigned ch; 134d522f475Smrg int last = MaxCols(screen); 135d522f475Smrg int col; 136d522f475Smrg#if OPT_ISO_COLORS && OPT_PRINT_COLORS 137956cc18dSsnj#define ColorOf(ld,col) (ld->color[col]) 138d522f475Smrg#endif 139d522f475Smrg unsigned fg = NO_COLOR, last_fg = NO_COLOR; 140d522f475Smrg unsigned bg = NO_COLOR, last_bg = NO_COLOR; 141d522f475Smrg int cs = CSET_IN; 142d522f475Smrg int last_cs = CSET_IN; 143d522f475Smrg 144956cc18dSsnj ld = getLineData(screen, inx); 14520d2c4d2Smrg if (ld == 0) 14620d2c4d2Smrg return; 14720d2c4d2Smrg 148d522f475Smrg TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n", 149d522f475Smrg row, ROW2INX(screen, row), screen->topline, screen->max_row, chr, 150956cc18dSsnj visibleIChars(ld->charData, (unsigned) last))); 151956cc18dSsnj 152d522f475Smrg while (last > 0) { 153956cc18dSsnj if ((ld->attribs[last - 1] & CHARDRAWN) == 0) 154d522f475Smrg last--; 155d522f475Smrg else 156d522f475Smrg break; 157d522f475Smrg } 158d522f475Smrg if (last) { 15920d2c4d2Smrg if (p->print_attributes) { 160956cc18dSsnj send_CharSet(xw, ld); 161956cc18dSsnj send_SGR(xw, 0, NO_COLOR, NO_COLOR); 162d522f475Smrg } 163d522f475Smrg for (col = 0; col < last; col++) { 164956cc18dSsnj ch = ld->charData[col]; 165d522f475Smrg#if OPT_PRINT_COLORS 166d522f475Smrg if (screen->colorMode) { 16720d2c4d2Smrg if (p->print_attributes > 1) { 168956cc18dSsnj fg = (ld->attribs[col] & FG_COLOR) 169956cc18dSsnj ? extract_fg(xw, ColorOf(ld, col), ld->attribs[col]) 170d522f475Smrg : NO_COLOR; 171956cc18dSsnj bg = (ld->attribs[col] & BG_COLOR) 172956cc18dSsnj ? extract_bg(xw, ColorOf(ld, col), ld->attribs[col]) 173d522f475Smrg : NO_COLOR; 174d522f475Smrg } 175d522f475Smrg } 176d522f475Smrg#endif 177956cc18dSsnj if ((((ld->attribs[col] & SGR_MASK) != attr) 178d522f475Smrg#if OPT_PRINT_COLORS 179d522f475Smrg || (last_fg != fg) || (last_bg != bg) 180d522f475Smrg#endif 181d522f475Smrg ) 182d522f475Smrg && ch) { 183894e0ac8Smrg attr = ld->attribs[col] & SGR_MASK; 18420d2c4d2Smrg#if OPT_PRINT_COLORS 185d522f475Smrg last_fg = fg; 186d522f475Smrg last_bg = bg; 18720d2c4d2Smrg#endif 18820d2c4d2Smrg if (p->print_attributes) 189956cc18dSsnj send_SGR(xw, attr, fg, bg); 190d522f475Smrg } 191d522f475Smrg 192d522f475Smrg if (ch == 0) 193d522f475Smrg ch = ' '; 194d522f475Smrg 195d522f475Smrg#if OPT_WIDE_CHARS 196d522f475Smrg if (screen->utf8_mode) 197d522f475Smrg cs = CSET_IN; 198d522f475Smrg else 199d522f475Smrg#endif 200d522f475Smrg cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT; 201d522f475Smrg if (last_cs != cs) { 20220d2c4d2Smrg if (p->print_attributes) { 203956cc18dSsnj charToPrinter(xw, 204956cc18dSsnj (unsigned) ((cs == CSET_OUT) 205d522f475Smrg ? SHIFT_OUT 206d522f475Smrg : SHIFT_IN)); 207d522f475Smrg } 208d522f475Smrg last_cs = cs; 209d522f475Smrg } 210d522f475Smrg 211d522f475Smrg /* FIXME: we shouldn't have to map back from the 212d522f475Smrg * alternate character set, except that the 213d522f475Smrg * corresponding charset information is not encoded 214d522f475Smrg * into the CSETS array. 215d522f475Smrg */ 216956cc18dSsnj charToPrinter(xw, 217956cc18dSsnj ((cs == CSET_OUT) 218d522f475Smrg ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f)) 219d522f475Smrg : ch)); 220d522f475Smrg if_OPT_WIDE_CHARS(screen, { 221956cc18dSsnj size_t off; 222956cc18dSsnj for_each_combData(off, ld) { 223956cc18dSsnj ch = ld->combData[off][col]; 224956cc18dSsnj if (ch == 0) 225d522f475Smrg break; 226956cc18dSsnj charToPrinter(xw, ch); 227d522f475Smrg } 228d522f475Smrg }); 229d522f475Smrg } 23020d2c4d2Smrg if (p->print_attributes) { 231956cc18dSsnj send_SGR(xw, 0, NO_COLOR, NO_COLOR); 232d522f475Smrg if (cs != CSET_IN) 233956cc18dSsnj charToPrinter(xw, SHIFT_IN); 234d522f475Smrg } 235d522f475Smrg } 23620d2c4d2Smrg 23720d2c4d2Smrg /* finish line (protocol for attributes needs a CR */ 23820d2c4d2Smrg if (p->print_attributes) 239956cc18dSsnj charToPrinter(xw, '\r'); 24020d2c4d2Smrg 24120d2c4d2Smrg if (chr && !(p->printer_newline)) { 24220d2c4d2Smrg if (LineTstWrapped(ld)) 24320d2c4d2Smrg chr = '\0'; 24420d2c4d2Smrg } 24520d2c4d2Smrg 24620d2c4d2Smrg if (chr) 24720d2c4d2Smrg charToPrinter(xw, chr); 248956cc18dSsnj 249956cc18dSsnj return; 250d522f475Smrg} 251d522f475Smrg 25220d2c4d2Smrg#define PrintNewLine() (unsigned) (((top < bot) || p->printer_newline) ? '\n' : '\0') 25320d2c4d2Smrg 254e39b573cSmrgstatic void 255894e0ac8SmrgprintLines(XtermWidget xw, int top, int bot, PrinterFlags *p) 256e39b573cSmrg{ 257e39b573cSmrg TRACE(("printLines, rows %d..%d\n", top, bot)); 258e39b573cSmrg while (top <= bot) { 259e39b573cSmrg printLine(xw, top, PrintNewLine(), p); 260e39b573cSmrg ++top; 261e39b573cSmrg } 262e39b573cSmrg} 263e39b573cSmrg 264d522f475Smrgvoid 265894e0ac8SmrgxtermPrintScreen(XtermWidget xw, Bool use_DECPEX, PrinterFlags *p) 266d522f475Smrg{ 267956cc18dSsnj if (XtIsRealized((Widget) xw)) { 268956cc18dSsnj TScreen *screen = TScreenOf(xw); 26920d2c4d2Smrg Bool extent = (use_DECPEX && p->printer_extent); 270e39b573cSmrg Boolean was_open = SPS.isOpen; 271d522f475Smrg 272e39b573cSmrg printLines(xw, 273e39b573cSmrg extent ? 0 : screen->top_marg, 274e39b573cSmrg extent ? screen->max_row : screen->bot_marg, 275e39b573cSmrg p); 27620d2c4d2Smrg if (p->printer_formfeed) 277956cc18dSsnj charToPrinter(xw, '\f'); 278d522f475Smrg 279e39b573cSmrg if (!was_open || SPS.printer_autoclose) { 280956cc18dSsnj closePrinter(xw); 281d522f475Smrg } 282d522f475Smrg } else { 28320d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 284d522f475Smrg } 285d522f475Smrg} 286d522f475Smrg 287d522f475Smrg/* 288e39b573cSmrg * If p->print_everything is zero, use this behavior: 289d522f475Smrg * If the alternate screen is active, we'll print only that. Otherwise, print 290d522f475Smrg * the normal screen plus all scrolled-back lines. The distinction is made 291d522f475Smrg * because the normal screen's buffer is part of the overall scrollback buffer. 292e39b573cSmrg * 293e39b573cSmrg * Otherwise, decode bits: 294e39b573cSmrg * 1 = current screen 295e39b573cSmrg * 2 = normal screen 296e39b573cSmrg * 4 = alternate screen 297e39b573cSmrg * 8 = saved lines 298d522f475Smrg */ 299956cc18dSsnjvoid 300894e0ac8SmrgxtermPrintEverything(XtermWidget xw, PrinterFlags *p) 301d522f475Smrg{ 302956cc18dSsnj TScreen *screen = TScreenOf(xw); 303e39b573cSmrg Boolean was_open = SPS.isOpen; 304e39b573cSmrg int save_which = screen->whichBuf; 305e39b573cSmrg int done_which = 0; 306d522f475Smrg 3070bd37d32Smrg DEBUG_MSG("xtermPrintEverything\n"); 308e39b573cSmrg if (p->print_everything) { 309e39b573cSmrg if (p->print_everything & 8) { 310e39b573cSmrg printLines(xw, -screen->savedlines, -(screen->topline + 1), p); 311e39b573cSmrg } 312e39b573cSmrg if (p->print_everything & 4) { 313e39b573cSmrg screen->whichBuf = 1; 314e39b573cSmrg done_which |= 2; 315e39b573cSmrg printLines(xw, 0, screen->max_row, p); 316e39b573cSmrg screen->whichBuf = save_which; 317e39b573cSmrg } 318e39b573cSmrg if (p->print_everything & 2) { 319e39b573cSmrg screen->whichBuf = 0; 320e39b573cSmrg done_which |= 1; 321e39b573cSmrg printLines(xw, 0, screen->max_row, p); 322e39b573cSmrg screen->whichBuf = save_which; 323e39b573cSmrg } 324e39b573cSmrg if (p->print_everything & 1) { 325e39b573cSmrg if (!(done_which & (1 << screen->whichBuf))) { 326e39b573cSmrg printLines(xw, 0, screen->max_row, p); 327e39b573cSmrg } 328e39b573cSmrg } 329e39b573cSmrg } else { 330e39b573cSmrg int top = 0; 331e39b573cSmrg int bot = screen->max_row; 332e39b573cSmrg if (!screen->whichBuf) { 333e39b573cSmrg top = -screen->savedlines - screen->topline; 334e39b573cSmrg bot -= screen->topline; 335e39b573cSmrg } 336e39b573cSmrg printLines(xw, top, bot, p); 33720d2c4d2Smrg } 33820d2c4d2Smrg if (p->printer_formfeed) 339956cc18dSsnj charToPrinter(xw, '\f'); 340d522f475Smrg 341e39b573cSmrg if (!was_open || SPS.printer_autoclose) { 342956cc18dSsnj closePrinter(xw); 343d522f475Smrg } 344d522f475Smrg} 345d522f475Smrg 346d522f475Smrgstatic void 347894e0ac8Smrgsend_CharSet(XtermWidget xw, LineData *ld) 348d522f475Smrg{ 349d522f475Smrg#if OPT_DEC_CHRSET 35020d2c4d2Smrg const char *msg = 0; 351d522f475Smrg 352956cc18dSsnj switch (GetLineDblCS(ld)) { 353d522f475Smrg case CSET_SWL: 354d522f475Smrg msg = "\033#5"; 355d522f475Smrg break; 356d522f475Smrg case CSET_DHL_TOP: 357d522f475Smrg msg = "\033#3"; 358d522f475Smrg break; 359d522f475Smrg case CSET_DHL_BOT: 360d522f475Smrg msg = "\033#4"; 361d522f475Smrg break; 362d522f475Smrg case CSET_DWL: 363d522f475Smrg msg = "\033#6"; 364d522f475Smrg break; 365d522f475Smrg } 366d522f475Smrg if (msg != 0) 367956cc18dSsnj stringToPrinter(xw, msg); 368d522f475Smrg#else 369956cc18dSsnj (void) xw; 370956cc18dSsnj (void) ld; 371d522f475Smrg#endif /* OPT_DEC_CHRSET */ 372d522f475Smrg} 373d522f475Smrg 374d522f475Smrgstatic void 375956cc18dSsnjsend_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg) 376d522f475Smrg{ 377d522f475Smrg char msg[80]; 378e39b573cSmrg 379d522f475Smrg strcpy(msg, "\033[0"); 380d522f475Smrg if (attr & BOLD) 381d522f475Smrg strcat(msg, ";1"); 382894e0ac8Smrg#if OPT_WIDE_ATTRS 383894e0ac8Smrg if (attr & ATR_FAINT) 384894e0ac8Smrg strcat(msg, ";2"); 385894e0ac8Smrg if (attr & ATR_ITALIC) 386894e0ac8Smrg strcat(msg, ";3"); 387894e0ac8Smrg#endif 388d522f475Smrg if (attr & UNDERLINE) 389d522f475Smrg strcat(msg, ";4"); /* typo? DEC documents this as '2' */ 390d522f475Smrg if (attr & BLINK) 391d522f475Smrg strcat(msg, ";5"); 392d522f475Smrg if (attr & INVERSE) /* typo? DEC documents this as invisible */ 393d522f475Smrg strcat(msg, ";7"); 394d522f475Smrg#if OPT_PRINT_COLORS 395d522f475Smrg if (bg != NO_COLOR) { 396d522f475Smrg sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg)); 397d522f475Smrg } 398d522f475Smrg if (fg != NO_COLOR) { 399d522f475Smrg#if OPT_PC_COLORS 40020d2c4d2Smrg if (TScreenOf(xw)->boldColors 401d522f475Smrg && fg > 8 402d522f475Smrg && (attr & BOLD) != 0) 403d522f475Smrg fg -= 8; 404d522f475Smrg#endif 405d522f475Smrg sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg)); 406d522f475Smrg } 407d522f475Smrg#else 408d522f475Smrg (void) bg; 409d522f475Smrg (void) fg; 410d522f475Smrg#endif 411d522f475Smrg strcat(msg, "m"); 412956cc18dSsnj stringToPrinter(xw, msg); 413d522f475Smrg} 414d522f475Smrg 415d522f475Smrg/* 416d522f475Smrg * This implementation only knows how to write to a pipe. 417d522f475Smrg */ 418d522f475Smrgstatic void 419956cc18dSsnjcharToPrinter(XtermWidget xw, unsigned chr) 420d522f475Smrg{ 421956cc18dSsnj TScreen *screen = TScreenOf(xw); 422d522f475Smrg 423e39b573cSmrg if (!SPS.isOpen && xtermHasPrinter(xw)) { 424e39b573cSmrg switch (SPS.toFile) { 425e39b573cSmrg /* 426e39b573cSmrg * write to a pipe. 427e39b573cSmrg */ 428e39b573cSmrg case False: 429e39b573cSmrg#ifdef VMS 430e39b573cSmrg /* 431e39b573cSmrg * This implementation only knows how to write to a file. When the 432e39b573cSmrg * file is closed the print command executes. Print command must 433e39b573cSmrg * be of the form: 434e39b573cSmrg * print/que=name/delete [/otherflags]. 435e39b573cSmrg */ 436e39b573cSmrg SPS.fp = fopen(VMS_TEMP_PRINT_FILE, "w"); 437d522f475Smrg#else 438e39b573cSmrg { 439e39b573cSmrg FILE *input; 440e39b573cSmrg int my_pipe[2]; 441e39b573cSmrg int c; 442e39b573cSmrg pid_t my_pid; 443e39b573cSmrg 444e39b573cSmrg if (pipe(my_pipe)) 445e39b573cSmrg SysError(ERROR_FORK); 446e39b573cSmrg if ((my_pid = fork()) < 0) 447e39b573cSmrg SysError(ERROR_FORK); 448e39b573cSmrg 449e39b573cSmrg if (my_pid == 0) { 4500bd37d32Smrg DEBUG_MSG("charToPrinter: subprocess for printer\n"); 451e39b573cSmrg TRACE_CLOSE(); 452e39b573cSmrg close(my_pipe[1]); /* printer is silent */ 453e39b573cSmrg close(screen->respond); 454e39b573cSmrg 455e39b573cSmrg close(fileno(stdout)); 456e39b573cSmrg dup2(fileno(stderr), 1); 457e39b573cSmrg 458e39b573cSmrg if (fileno(stderr) != 2) { 459e39b573cSmrg dup2(fileno(stderr), 2); 460e39b573cSmrg close(fileno(stderr)); 461e39b573cSmrg } 462e39b573cSmrg 463e39b573cSmrg /* don't want privileges! */ 464e39b573cSmrg if (xtermResetIds(screen) < 0) 465e39b573cSmrg exit(1); 466e39b573cSmrg 467e39b573cSmrg SPS.fp = popen(SPS.printer_command, "w"); 4680bd37d32Smrg if (SPS.fp != 0) { 4690bd37d32Smrg DEBUG_MSG("charToPrinter: opened pipe to printer\n"); 4700bd37d32Smrg input = fdopen(my_pipe[0], "r"); 4710bd37d32Smrg clearerr(input); 4720bd37d32Smrg for (;;) { 4730bd37d32Smrg if (ferror(input)) { 4740bd37d32Smrg DEBUG_MSG("charToPrinter: break on ferror\n"); 4750bd37d32Smrg break; 4760bd37d32Smrg } else if (feof(input)) { 4770bd37d32Smrg DEBUG_MSG("charToPrinter: break on feof\n"); 4780bd37d32Smrg break; 4790bd37d32Smrg } else if ((c = fgetc(input)) == EOF) { 4800bd37d32Smrg DEBUG_MSG("charToPrinter: break on EOF\n"); 4810bd37d32Smrg break; 4820bd37d32Smrg } 4830bd37d32Smrg fputc(c, SPS.fp); 4840bd37d32Smrg if (isForm(c)) 4850bd37d32Smrg fflush(SPS.fp); 4860bd37d32Smrg } 4870bd37d32Smrg DEBUG_MSG("charToPrinter: calling pclose\n"); 4880bd37d32Smrg pclose(SPS.fp); 489e39b573cSmrg } 490e39b573cSmrg exit(0); 491e39b573cSmrg } else { 492e39b573cSmrg close(my_pipe[0]); /* won't read from printer */ 4930bd37d32Smrg if ((SPS.fp = fdopen(my_pipe[1], "w")) != 0) { 4940bd37d32Smrg DEBUG_MSG("charToPrinter: opened printer in parent\n"); 4950bd37d32Smrg TRACE(("opened printer from pid %d/%d\n", 4960bd37d32Smrg (int) getpid(), (int) my_pid)); 4970bd37d32Smrg } else { 4980bd37d32Smrg TRACE(("failed to open printer:%s\n", strerror(errno))); 4990bd37d32Smrg DEBUG_MSG("charToPrinter: could not open in parent\n"); 5000bd37d32Smrg } 501e39b573cSmrg } 502d522f475Smrg } 503d522f475Smrg#endif 504e39b573cSmrg break; 505e39b573cSmrg case True: 506e39b573cSmrg TRACE(("opening \"%s\" as printer output\n", SPS.printer_command)); 507e39b573cSmrg SPS.fp = fopen(SPS.printer_command, "w"); 508e39b573cSmrg break; 509e39b573cSmrg } 510e39b573cSmrg SPS.isOpen = True; 511d522f475Smrg } 512e39b573cSmrg if (SPS.fp != 0) { 513d522f475Smrg#if OPT_WIDE_CHARS 514d522f475Smrg if (chr > 127) { 515d522f475Smrg Char temp[10]; 516d522f475Smrg *convertToUTF8(temp, chr) = 0; 517e39b573cSmrg fputs((char *) temp, SPS.fp); 518d522f475Smrg } else 519d522f475Smrg#endif 520e39b573cSmrg fputc((int) chr, SPS.fp); 521d522f475Smrg if (isForm(chr)) 522e39b573cSmrg fflush(SPS.fp); 523d522f475Smrg } 524d522f475Smrg} 525d522f475Smrg 526d522f475Smrgstatic void 52720d2c4d2SmrgstringToPrinter(XtermWidget xw, const char *str) 528d522f475Smrg{ 529d522f475Smrg while (*str) 530956cc18dSsnj charToPrinter(xw, CharOf(*str++)); 531d522f475Smrg} 532d522f475Smrg 533d522f475Smrg/* 534d522f475Smrg * This module implements the MC (Media Copy) and related printing control 535d522f475Smrg * sequences for VTxxx emulation. This is based on the description in the 536d522f475Smrg * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment 537d522f475Smrg * Corp., March 1987). 538d522f475Smrg */ 539d522f475Smrgvoid 540956cc18dSsnjxtermMediaControl(XtermWidget xw, int param, int private_seq) 541d522f475Smrg{ 542d522f475Smrg TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq)); 543d522f475Smrg 544d522f475Smrg if (private_seq) { 545d522f475Smrg switch (param) { 546d522f475Smrg case 1: 547956cc18dSsnj printCursorLine(xw); 548d522f475Smrg break; 549d522f475Smrg case 4: 550956cc18dSsnj setPrinterControlMode(xw, 0); 551d522f475Smrg break; 552d522f475Smrg case 5: 553956cc18dSsnj setPrinterControlMode(xw, 1); 554d522f475Smrg break; 555d522f475Smrg case 10: /* VT320 */ 55620d2c4d2Smrg xtermPrintScreen(xw, False, getPrinterFlags(xw, NULL, 0)); 557d522f475Smrg break; 558d522f475Smrg case 11: /* VT320 */ 55920d2c4d2Smrg xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 560d522f475Smrg break; 561d522f475Smrg } 562d522f475Smrg } else { 563d522f475Smrg switch (param) { 564d522f475Smrg case -1: 565d522f475Smrg case 0: 56620d2c4d2Smrg xtermPrintScreen(xw, True, getPrinterFlags(xw, NULL, 0)); 567d522f475Smrg break; 568d522f475Smrg case 4: 569956cc18dSsnj setPrinterControlMode(xw, 0); 570d522f475Smrg break; 571d522f475Smrg case 5: 572956cc18dSsnj setPrinterControlMode(xw, 2); 573d522f475Smrg break; 574d522f475Smrg } 575d522f475Smrg } 576d522f475Smrg} 577d522f475Smrg 578d522f475Smrg/* 579d522f475Smrg * When in autoprint mode, the printer prints a line from the screen when you 580d522f475Smrg * move the cursor off that line with an LF, FF, or VT character, or an 581d522f475Smrg * autowrap occurs. The printed line ends with a CR and the character (LF, FF 582d522f475Smrg * or VT) that moved the cursor off the previous line. 583d522f475Smrg */ 584d522f475Smrgvoid 585956cc18dSsnjxtermAutoPrint(XtermWidget xw, unsigned chr) 586d522f475Smrg{ 587956cc18dSsnj TScreen *screen = TScreenOf(xw); 588d522f475Smrg 589e39b573cSmrg if (SPS.printer_controlmode == 1) { 590d522f475Smrg TRACE(("AutoPrint %d\n", chr)); 59120d2c4d2Smrg printLine(xw, screen->cursorp.row, chr, getPrinterFlags(xw, NULL, 0)); 592e39b573cSmrg if (SPS.fp != 0) 593e39b573cSmrg fflush(SPS.fp); 594d522f475Smrg } 595d522f475Smrg} 596d522f475Smrg 597d522f475Smrg/* 598d522f475Smrg * When in printer controller mode, the terminal sends received characters to 599d522f475Smrg * the printer without displaying them on the screen. The terminal sends all 600d522f475Smrg * characters and control sequences to the printer, except NUL, XON, XOFF, and 601d522f475Smrg * the printer controller sequences. 602d522f475Smrg * 603d522f475Smrg * This function eats characters, returning 0 as long as it must buffer or 604d522f475Smrg * divert to the printer. We're only invoked here when in printer controller 605d522f475Smrg * mode, and handle the exit from that mode. 606d522f475Smrg */ 607d522f475Smrg#define LB '[' 608d522f475Smrg 609d522f475Smrgint 610956cc18dSsnjxtermPrinterControl(XtermWidget xw, int chr) 611d522f475Smrg{ 612956cc18dSsnj TScreen *screen = TScreenOf(xw); 613d522f475Smrg /* *INDENT-OFF* */ 614e39b573cSmrg static const struct { 615e39b573cSmrg const Char seq[5]; 616d522f475Smrg int active; 617d522f475Smrg } tbl[] = { 618d522f475Smrg { { ANSI_CSI, '5', 'i' }, 2 }, 619d522f475Smrg { { ANSI_CSI, '4', 'i' }, 0 }, 620d522f475Smrg { { ANSI_ESC, LB, '5', 'i' }, 2 }, 621d522f475Smrg { { ANSI_ESC, LB, '4', 'i' }, 0 }, 622d522f475Smrg }; 623d522f475Smrg /* *INDENT-ON* */ 624d522f475Smrg 625d522f475Smrg static Char bfr[10]; 626d522f475Smrg static size_t length; 627d522f475Smrg size_t n; 628d522f475Smrg 629d522f475Smrg TRACE(("In printer:%04X\n", chr)); 630d522f475Smrg 631d522f475Smrg switch (chr) { 632d522f475Smrg case 0: 633d522f475Smrg case CTRL('Q'): 634d522f475Smrg case CTRL('S'): 635d522f475Smrg return 0; /* ignored by application */ 636d522f475Smrg 637d522f475Smrg case ANSI_CSI: 638d522f475Smrg case ANSI_ESC: 639d522f475Smrg case '[': 640d522f475Smrg case '4': 641d522f475Smrg case '5': 642d522f475Smrg case 'i': 6434e40088cSchristos bfr[length++] = CharOf(chr); 644d522f475Smrg for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) { 645d522f475Smrg size_t len = Strlen(tbl[n].seq); 646d522f475Smrg 647d522f475Smrg if (length == len 648d522f475Smrg && Strcmp(bfr, tbl[n].seq) == 0) { 649956cc18dSsnj setPrinterControlMode(xw, tbl[n].active); 650e39b573cSmrg if (SPS.printer_autoclose 651e39b573cSmrg && SPS.printer_controlmode == 0) 652956cc18dSsnj closePrinter(xw); 653d522f475Smrg length = 0; 654d522f475Smrg return 0; 655d522f475Smrg } else if (len > length 656d522f475Smrg && Strncmp(bfr, tbl[n].seq, length) == 0) { 657d522f475Smrg return 0; 658d522f475Smrg } 659d522f475Smrg } 660d522f475Smrg length--; 661d522f475Smrg 662d522f475Smrg /* FALLTHRU */ 663d522f475Smrg 664d522f475Smrg default: 665d522f475Smrg for (n = 0; n < length; n++) 666956cc18dSsnj charToPrinter(xw, bfr[n]); 6674e40088cSchristos bfr[0] = CharOf(chr); 668d522f475Smrg length = 1; 669d522f475Smrg return 0; 670d522f475Smrg } 671d522f475Smrg} 672d522f475Smrg 673d522f475Smrg/* 674d522f475Smrg * If there is no printer command, we will ignore printer controls. 6750bd37d32Smrg * 6760bd37d32Smrg * If we do have a printer command, we still have to verify that it will 6770bd37d32Smrg * (perhaps) work if we pass it to popen(). At a minimum, the program 6780bd37d32Smrg * must exist and be executable. If not, warn and disable the feature. 679d522f475Smrg */ 680d522f475SmrgBool 681956cc18dSsnjxtermHasPrinter(XtermWidget xw) 682d522f475Smrg{ 683956cc18dSsnj TScreen *screen = TScreenOf(xw); 6840bd37d32Smrg Bool result = SPS.printer_checked; 6850bd37d32Smrg 6860bd37d32Smrg if (strlen(SPS.printer_command) != 0 && !result) { 6870bd37d32Smrg char **argv = x_splitargs(SPS.printer_command); 6880bd37d32Smrg if (argv) { 6890bd37d32Smrg if (argv[0]) { 6900bd37d32Smrg char *myShell = xtermFindShell(argv[0], False); 6910bd37d32Smrg if (myShell == 0) { 6920bd37d32Smrg xtermWarning("No program found for printerCommand: %s\n", SPS.printer_command); 6930bd37d32Smrg SPS.printer_command = x_strdup(""); 6940bd37d32Smrg } else { 6950bd37d32Smrg free(myShell); 6960bd37d32Smrg SPS.printer_checked = True; 6970bd37d32Smrg result = True; 6980bd37d32Smrg } 6990bd37d32Smrg } 7000bd37d32Smrg x_freeargs(argv); 7010bd37d32Smrg } 7020bd37d32Smrg TRACE(("xtermHasPrinter:%d\n", result)); 7030bd37d32Smrg } 704d522f475Smrg 7050bd37d32Smrg return result; 706d522f475Smrg} 707d522f475Smrg 708d522f475Smrg#define showPrinterControlMode(mode) \ 709d522f475Smrg (((mode) == 0) \ 710d522f475Smrg ? "normal" \ 711d522f475Smrg : ((mode) == 1 \ 712d522f475Smrg ? "autoprint" \ 713d522f475Smrg : "printer controller")) 714d522f475Smrg 715d522f475Smrgvoid 716956cc18dSsnjsetPrinterControlMode(XtermWidget xw, int mode) 717d522f475Smrg{ 71820d2c4d2Smrg TScreen *screen = TScreenOf(xw); 71920d2c4d2Smrg 720956cc18dSsnj if (xtermHasPrinter(xw) 721e39b573cSmrg && SPS.printer_controlmode != mode) { 722d522f475Smrg TRACE(("%s %s mode\n", 723d522f475Smrg (mode 724d522f475Smrg ? "set" 725d522f475Smrg : "reset"), 726d522f475Smrg (mode 727d522f475Smrg ? showPrinterControlMode(mode) 728e39b573cSmrg : showPrinterControlMode(SPS.printer_controlmode)))); 729e39b573cSmrg SPS.printer_controlmode = mode; 730d522f475Smrg update_print_redir(); 731d522f475Smrg } 732d522f475Smrg} 73320d2c4d2Smrg 73420d2c4d2SmrgPrinterFlags * 735894e0ac8SmrggetPrinterFlags(XtermWidget xw, String *params, Cardinal *param_count) 73620d2c4d2Smrg{ 73720d2c4d2Smrg /* *INDENT-OFF* */ 73820d2c4d2Smrg static const struct { 73920d2c4d2Smrg const char *name; 74020d2c4d2Smrg unsigned offset; 74120d2c4d2Smrg int value; 74220d2c4d2Smrg } table[] = { 74320d2c4d2Smrg { "noFormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 0 }, 74420d2c4d2Smrg { "FormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 1 }, 74520d2c4d2Smrg { "noNewLine", XtOffsetOf(PrinterFlags, printer_newline), 0 }, 74620d2c4d2Smrg { "NewLine", XtOffsetOf(PrinterFlags, printer_newline), 1 }, 74720d2c4d2Smrg { "noAttrs", XtOffsetOf(PrinterFlags, print_attributes), 0 }, 74820d2c4d2Smrg { "monoAttrs", XtOffsetOf(PrinterFlags, print_attributes), 1 }, 74920d2c4d2Smrg { "colorAttrs", XtOffsetOf(PrinterFlags, print_attributes), 2 }, 75020d2c4d2Smrg }; 75120d2c4d2Smrg /* *INDENT-ON* */ 75220d2c4d2Smrg 75320d2c4d2Smrg TScreen *screen = TScreenOf(xw); 75420d2c4d2Smrg PrinterFlags *result = &(screen->printer_flags); 75520d2c4d2Smrg 75620d2c4d2Smrg TRACE(("getPrinterFlags %d params\n", param_count ? *param_count : 0)); 75720d2c4d2Smrg 758e39b573cSmrg result->printer_extent = SPS.printer_extent; 759e39b573cSmrg result->printer_formfeed = SPS.printer_formfeed; 760e39b573cSmrg result->printer_newline = SPS.printer_newline; 761e39b573cSmrg result->print_attributes = SPS.print_attributes; 762e39b573cSmrg result->print_everything = SPS.print_everything; 76320d2c4d2Smrg 76420d2c4d2Smrg if (param_count != 0 && *param_count != 0) { 76520d2c4d2Smrg Cardinal j; 76620d2c4d2Smrg unsigned k; 76720d2c4d2Smrg for (j = 0; j < *param_count; ++j) { 76820d2c4d2Smrg TRACE(("param%d:%s\n", j, params[j])); 76920d2c4d2Smrg for (k = 0; k < XtNumber(table); ++k) { 77020d2c4d2Smrg if (!x_strcasecmp(params[j], table[k].name)) { 771a1f3da82Smrg int *ptr = (int *) (void *) ((char *) result + table[k].offset); 77220d2c4d2Smrg TRACE(("...PrinterFlags(%s) %d->%d\n", 77320d2c4d2Smrg table[k].name, 77420d2c4d2Smrg *ptr, 77520d2c4d2Smrg table[k].value)); 77620d2c4d2Smrg *ptr = table[k].value; 77720d2c4d2Smrg break; 77820d2c4d2Smrg } 77920d2c4d2Smrg } 78020d2c4d2Smrg } 78120d2c4d2Smrg } 78220d2c4d2Smrg 78320d2c4d2Smrg return result; 78420d2c4d2Smrg} 785e39b573cSmrg 786e39b573cSmrg/* 787e39b573cSmrg * Print a timestamped copy of everything. 788e39b573cSmrg */ 789e39b573cSmrgvoid 790e39b573cSmrgxtermPrintImmediately(XtermWidget xw, String filename, int opts, int attrs) 791e39b573cSmrg{ 792e39b573cSmrg TScreen *screen = TScreenOf(xw); 793e39b573cSmrg PrinterState save_state = screen->printer_state; 794e39b573cSmrg char *my_filename = malloc(TIMESTAMP_LEN + strlen(filename)); 795e39b573cSmrg 796e39b573cSmrg if (my_filename != 0) { 797e39b573cSmrg unsigned save_umask = umask(0177); 798e39b573cSmrg 799e39b573cSmrg timestamp_filename(my_filename, filename); 800e39b573cSmrg SPS.fp = 0; 801e39b573cSmrg SPS.isOpen = False; 802e39b573cSmrg SPS.toFile = True; 803e39b573cSmrg SPS.printer_command = my_filename; 804e39b573cSmrg SPS.printer_autoclose = True; 805e39b573cSmrg SPS.printer_formfeed = False; 806e39b573cSmrg SPS.printer_newline = True; 807e39b573cSmrg SPS.print_attributes = attrs; 808e39b573cSmrg SPS.print_everything = opts; 809e39b573cSmrg xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 810e39b573cSmrg 811e39b573cSmrg umask(save_umask); 812e39b573cSmrg screen->printer_state = save_state; 813e39b573cSmrg } 814e39b573cSmrg} 815e39b573cSmrg 816e39b573cSmrgvoid 817e39b573cSmrgxtermPrintOnXError(XtermWidget xw, int n) 818e39b573cSmrg{ 819e39b573cSmrg#if OPT_PRINT_ON_EXIT 820e39b573cSmrg /* 821e39b573cSmrg * The user may have requested that the contents of the screen will be 822e39b573cSmrg * written to a file if an X error occurs. 823e39b573cSmrg */ 824e39b573cSmrg if (TScreenOf(xw)->write_error && !IsEmpty(resource.printFileOnXError)) { 825e39b573cSmrg Boolean printIt = False; 826e39b573cSmrg 827e39b573cSmrg switch (n) { 828e39b573cSmrg case ERROR_XERROR: 829e39b573cSmrg /* FALLTHRU */ 830e39b573cSmrg case ERROR_XIOERROR: 831e39b573cSmrg /* FALLTHRU */ 832e39b573cSmrg case ERROR_ICEERROR: 833e39b573cSmrg printIt = True; 834e39b573cSmrg break; 835e39b573cSmrg } 836e39b573cSmrg 837e39b573cSmrg if (printIt) { 838e39b573cSmrg xtermPrintImmediately(xw, 839e39b573cSmrg resource.printFileOnXError, 840e39b573cSmrg resource.printOptsOnXError, 841e39b573cSmrg resource.printModeOnXError); 842e39b573cSmrg } 843e39b573cSmrg } 844e39b573cSmrg#else 845e39b573cSmrg (void) xw; 846e39b573cSmrg (void) n; 847e39b573cSmrg#endif 848e39b573cSmrg} 849