print.c revision e39b573c
1e39b573cSmrg/* $XTermId: print.c,v 1.138 2011/07/14 23:49:10 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/************************************************************ 4d522f475Smrg 5a1f3da82SmrgCopyright 1997-2010,2011 by Thomas E. Dickey 6d522f475Smrg 7d522f475Smrg All Rights Reserved 8d522f475Smrg 9d522f475SmrgPermission is hereby granted, free of charge, to any person obtaining a 10d522f475Smrgcopy of this software and associated documentation files (the 11d522f475Smrg"Software"), to deal in the Software without restriction, including 12d522f475Smrgwithout limitation the rights to use, copy, modify, merge, publish, 13d522f475Smrgdistribute, sublicense, and/or sell copies of the Software, and to 14d522f475Smrgpermit persons to whom the Software is furnished to do so, subject to 15d522f475Smrgthe following conditions: 16d522f475Smrg 17d522f475SmrgThe above copyright notice and this permission notice shall be included 18d522f475Smrgin all copies or substantial portions of the Software. 19d522f475Smrg 20d522f475SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21d522f475SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22d522f475SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23d522f475SmrgIN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 24d522f475SmrgCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25d522f475SmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26d522f475SmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27d522f475Smrg 28d522f475SmrgExcept as contained in this notice, the name(s) of the above copyright 29d522f475Smrgholders shall not be used in advertising or otherwise to promote the 30d522f475Smrgsale, use or other dealings in this Software without prior written 31d522f475Smrgauthorization. 32d522f475Smrg 33d522f475Smrg********************************************************/ 34d522f475Smrg 35d522f475Smrg#include <xterm.h> 36d522f475Smrg#include <data.h> 37d522f475Smrg#include <menu.h> 38d522f475Smrg#include <error.h> 3920d2c4d2Smrg#include <xstrings.h> 40d522f475Smrg 41d522f475Smrg#include <stdio.h> 42e39b573cSmrg#include <sys/stat.h> 43d522f475Smrg 44d522f475Smrg#undef CTRL 45d522f475Smrg#define CTRL(c) ((c) & 0x1f) 46d522f475Smrg 47d522f475Smrg#define SHIFT_IN '\017' 48d522f475Smrg#define SHIFT_OUT '\016' 49d522f475Smrg 50d522f475Smrg#define CSET_IN 'A' 51d522f475Smrg#define CSET_OUT '0' 52d522f475Smrg 53d522f475Smrg#define isForm(c) ((c) == '\r' || (c) == '\n' || (c) == '\f') 54e39b573cSmrg#define Strlen(a) strlen((const char *)a) 55e39b573cSmrg#define Strcmp(a,b) strcmp((const char *)a,(const char *)b) 56e39b573cSmrg#define Strncmp(a,b,c) strncmp((const char *)a,(const char *)b,c) 57e39b573cSmrg 58e39b573cSmrg#define SPS PrinterOf(screen) 59d522f475Smrg 60d522f475Smrg#ifdef VMS 61d522f475Smrg#define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt" 62d522f475Smrg#endif 63d522f475Smrg 64956cc18dSsnjstatic void charToPrinter(XtermWidget /* xw */ , 65956cc18dSsnj unsigned /* chr */ ); 66956cc18dSsnjstatic void printLine(XtermWidget /* xw */ , 67956cc18dSsnj int /* row */ , 6820d2c4d2Smrg unsigned /* chr */ , 6920d2c4d2Smrg PrinterFlags * /* p */ ); 70956cc18dSsnjstatic void send_CharSet(XtermWidget /* xw */ , 71956cc18dSsnj LineData * /* ld */ ); 72956cc18dSsnjstatic void send_SGR(XtermWidget /* xw */ , 73956cc18dSsnj unsigned /* attr */ , 74956cc18dSsnj unsigned /* fg */ , 75956cc18dSsnj unsigned /* bg */ ); 76956cc18dSsnjstatic void stringToPrinter(XtermWidget /* xw */ , 7720d2c4d2Smrg const char * /*str */ ); 78d522f475Smrg 79e39b573cSmrgvoid 80956cc18dSsnjclosePrinter(XtermWidget xw GCC_UNUSED) 81d522f475Smrg{ 82956cc18dSsnj if (xtermHasPrinter(xw) != 0) { 83956cc18dSsnj TScreen *screen = TScreenOf(xw); 84e39b573cSmrg#ifdef VMS 85d522f475Smrg char pcommand[256]; 86d522f475Smrg (void) sprintf(pcommand, "%s %s;", 87e39b573cSmrg SPS.printer_command, 88d522f475Smrg VMS_TEMP_PRINT_FILE); 89d522f475Smrg#endif 90d522f475Smrg 91e39b573cSmrg if (SPS.fp != 0) { 92e39b573cSmrg fclose(SPS.fp); 93d522f475Smrg TRACE(("closed printer, waiting...\n")); 94d522f475Smrg#ifdef VMS /* This is a quick hack, really should use 95d522f475Smrg spawn and check status or system services 96d522f475Smrg and go straight to the queue */ 97d522f475Smrg (void) system(pcommand); 98d522f475Smrg#else /* VMS */ 99d522f475Smrg while (nonblocking_wait() > 0) 100d522f475Smrg#endif /* VMS */ 101d522f475Smrg ; 102e39b573cSmrg SPS.fp = 0; 103e39b573cSmrg SPS.isOpen = False; 104d522f475Smrg TRACE(("closed printer\n")); 105d522f475Smrg } 106d522f475Smrg } 107d522f475Smrg} 108d522f475Smrg 109d522f475Smrgstatic void 110956cc18dSsnjprintCursorLine(XtermWidget xw) 111d522f475Smrg{ 112956cc18dSsnj TScreen *screen = TScreenOf(xw); 113d522f475Smrg 114d522f475Smrg TRACE(("printCursorLine\n")); 11520d2c4d2Smrg printLine(xw, screen->cur_row, '\n', getPrinterFlags(xw, NULL, 0)); 116d522f475Smrg} 117d522f475Smrg 118d522f475Smrg#define NO_COLOR ((unsigned)-1) 119d522f475Smrg 120d522f475Smrg/* 121d522f475Smrg * DEC's manual doesn't document whether trailing blanks are removed, or what 122d522f475Smrg * happens with a line that is entirely blank. This function prints the 123d522f475Smrg * characters that xterm would allow as a selection (which may include blanks). 124d522f475Smrg */ 125d522f475Smrgstatic void 12620d2c4d2SmrgprintLine(XtermWidget xw, int row, unsigned chr, PrinterFlags * p) 127d522f475Smrg{ 128956cc18dSsnj TScreen *screen = TScreenOf(xw); 129d522f475Smrg int inx = ROW2INX(screen, row); 130956cc18dSsnj LineData *ld; 131d522f475Smrg Char attr = 0; 132d522f475Smrg unsigned ch; 133d522f475Smrg int last = MaxCols(screen); 134d522f475Smrg int col; 135d522f475Smrg#if OPT_ISO_COLORS && OPT_PRINT_COLORS 136956cc18dSsnj#define ColorOf(ld,col) (ld->color[col]) 137d522f475Smrg#endif 138d522f475Smrg unsigned fg = NO_COLOR, last_fg = NO_COLOR; 139d522f475Smrg unsigned bg = NO_COLOR, last_bg = NO_COLOR; 140d522f475Smrg int cs = CSET_IN; 141d522f475Smrg int last_cs = CSET_IN; 142d522f475Smrg 143956cc18dSsnj ld = getLineData(screen, inx); 14420d2c4d2Smrg if (ld == 0) 14520d2c4d2Smrg return; 14620d2c4d2Smrg 147d522f475Smrg TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n", 148d522f475Smrg row, ROW2INX(screen, row), screen->topline, screen->max_row, chr, 149956cc18dSsnj visibleIChars(ld->charData, (unsigned) last))); 150956cc18dSsnj 151d522f475Smrg while (last > 0) { 152956cc18dSsnj if ((ld->attribs[last - 1] & CHARDRAWN) == 0) 153d522f475Smrg last--; 154d522f475Smrg else 155d522f475Smrg break; 156d522f475Smrg } 157d522f475Smrg if (last) { 15820d2c4d2Smrg if (p->print_attributes) { 159956cc18dSsnj send_CharSet(xw, ld); 160956cc18dSsnj send_SGR(xw, 0, NO_COLOR, NO_COLOR); 161d522f475Smrg } 162d522f475Smrg for (col = 0; col < last; col++) { 163956cc18dSsnj ch = ld->charData[col]; 164d522f475Smrg#if OPT_PRINT_COLORS 165d522f475Smrg if (screen->colorMode) { 16620d2c4d2Smrg if (p->print_attributes > 1) { 167956cc18dSsnj fg = (ld->attribs[col] & FG_COLOR) 168956cc18dSsnj ? extract_fg(xw, ColorOf(ld, col), ld->attribs[col]) 169d522f475Smrg : NO_COLOR; 170956cc18dSsnj bg = (ld->attribs[col] & BG_COLOR) 171956cc18dSsnj ? extract_bg(xw, ColorOf(ld, col), ld->attribs[col]) 172d522f475Smrg : NO_COLOR; 173d522f475Smrg } 174d522f475Smrg } 175d522f475Smrg#endif 176956cc18dSsnj if ((((ld->attribs[col] & SGR_MASK) != attr) 177d522f475Smrg#if OPT_PRINT_COLORS 178d522f475Smrg || (last_fg != fg) || (last_bg != bg) 179d522f475Smrg#endif 180d522f475Smrg ) 181d522f475Smrg && ch) { 182956cc18dSsnj attr = CharOf(ld->attribs[col] & SGR_MASK); 18320d2c4d2Smrg#if OPT_PRINT_COLORS 184d522f475Smrg last_fg = fg; 185d522f475Smrg last_bg = bg; 18620d2c4d2Smrg#endif 18720d2c4d2Smrg if (p->print_attributes) 188956cc18dSsnj send_SGR(xw, attr, fg, bg); 189d522f475Smrg } 190d522f475Smrg 191d522f475Smrg if (ch == 0) 192d522f475Smrg ch = ' '; 193d522f475Smrg 194d522f475Smrg#if OPT_WIDE_CHARS 195d522f475Smrg if (screen->utf8_mode) 196d522f475Smrg cs = CSET_IN; 197d522f475Smrg else 198d522f475Smrg#endif 199d522f475Smrg cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT; 200d522f475Smrg if (last_cs != cs) { 20120d2c4d2Smrg if (p->print_attributes) { 202956cc18dSsnj charToPrinter(xw, 203956cc18dSsnj (unsigned) ((cs == CSET_OUT) 204d522f475Smrg ? SHIFT_OUT 205d522f475Smrg : SHIFT_IN)); 206d522f475Smrg } 207d522f475Smrg last_cs = cs; 208d522f475Smrg } 209d522f475Smrg 210d522f475Smrg /* FIXME: we shouldn't have to map back from the 211d522f475Smrg * alternate character set, except that the 212d522f475Smrg * corresponding charset information is not encoded 213d522f475Smrg * into the CSETS array. 214d522f475Smrg */ 215956cc18dSsnj charToPrinter(xw, 216956cc18dSsnj ((cs == CSET_OUT) 217d522f475Smrg ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f)) 218d522f475Smrg : ch)); 219d522f475Smrg if_OPT_WIDE_CHARS(screen, { 220956cc18dSsnj size_t off; 221956cc18dSsnj for_each_combData(off, ld) { 222956cc18dSsnj ch = ld->combData[off][col]; 223956cc18dSsnj if (ch == 0) 224d522f475Smrg break; 225956cc18dSsnj charToPrinter(xw, ch); 226d522f475Smrg } 227d522f475Smrg }); 228d522f475Smrg } 22920d2c4d2Smrg if (p->print_attributes) { 230956cc18dSsnj send_SGR(xw, 0, NO_COLOR, NO_COLOR); 231d522f475Smrg if (cs != CSET_IN) 232956cc18dSsnj charToPrinter(xw, SHIFT_IN); 233d522f475Smrg } 234d522f475Smrg } 23520d2c4d2Smrg 23620d2c4d2Smrg /* finish line (protocol for attributes needs a CR */ 23720d2c4d2Smrg if (p->print_attributes) 238956cc18dSsnj charToPrinter(xw, '\r'); 23920d2c4d2Smrg 24020d2c4d2Smrg if (chr && !(p->printer_newline)) { 24120d2c4d2Smrg if (LineTstWrapped(ld)) 24220d2c4d2Smrg chr = '\0'; 24320d2c4d2Smrg } 24420d2c4d2Smrg 24520d2c4d2Smrg if (chr) 24620d2c4d2Smrg charToPrinter(xw, chr); 247956cc18dSsnj 248956cc18dSsnj return; 249d522f475Smrg} 250d522f475Smrg 25120d2c4d2Smrg#define PrintNewLine() (unsigned) (((top < bot) || p->printer_newline) ? '\n' : '\0') 25220d2c4d2Smrg 253e39b573cSmrgstatic void 254e39b573cSmrgprintLines(XtermWidget xw, int top, int bot, PrinterFlags * p) 255e39b573cSmrg{ 256e39b573cSmrg TRACE(("printLines, rows %d..%d\n", top, bot)); 257e39b573cSmrg while (top <= bot) { 258e39b573cSmrg printLine(xw, top, PrintNewLine(), p); 259e39b573cSmrg ++top; 260e39b573cSmrg } 261e39b573cSmrg} 262e39b573cSmrg 263d522f475Smrgvoid 26420d2c4d2SmrgxtermPrintScreen(XtermWidget xw, Bool use_DECPEX, PrinterFlags * p) 265d522f475Smrg{ 266956cc18dSsnj if (XtIsRealized((Widget) xw)) { 267956cc18dSsnj TScreen *screen = TScreenOf(xw); 26820d2c4d2Smrg Bool extent = (use_DECPEX && p->printer_extent); 269e39b573cSmrg Boolean was_open = SPS.isOpen; 270d522f475Smrg 271e39b573cSmrg printLines(xw, 272e39b573cSmrg extent ? 0 : screen->top_marg, 273e39b573cSmrg extent ? screen->max_row : screen->bot_marg, 274e39b573cSmrg p); 27520d2c4d2Smrg if (p->printer_formfeed) 276956cc18dSsnj charToPrinter(xw, '\f'); 277d522f475Smrg 278e39b573cSmrg if (!was_open || SPS.printer_autoclose) { 279956cc18dSsnj closePrinter(xw); 280d522f475Smrg } 281d522f475Smrg } else { 28220d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 283d522f475Smrg } 284d522f475Smrg} 285d522f475Smrg 286d522f475Smrg/* 287e39b573cSmrg * If p->print_everything is zero, use this behavior: 288d522f475Smrg * If the alternate screen is active, we'll print only that. Otherwise, print 289d522f475Smrg * the normal screen plus all scrolled-back lines. The distinction is made 290d522f475Smrg * because the normal screen's buffer is part of the overall scrollback buffer. 291e39b573cSmrg * 292e39b573cSmrg * Otherwise, decode bits: 293e39b573cSmrg * 1 = current screen 294e39b573cSmrg * 2 = normal screen 295e39b573cSmrg * 4 = alternate screen 296e39b573cSmrg * 8 = saved lines 297d522f475Smrg */ 298956cc18dSsnjvoid 29920d2c4d2SmrgxtermPrintEverything(XtermWidget xw, PrinterFlags * p) 300d522f475Smrg{ 301956cc18dSsnj TScreen *screen = TScreenOf(xw); 302e39b573cSmrg Boolean was_open = SPS.isOpen; 303e39b573cSmrg int save_which = screen->whichBuf; 304e39b573cSmrg int done_which = 0; 305d522f475Smrg 306e39b573cSmrg if (p->print_everything) { 307e39b573cSmrg if (p->print_everything & 8) { 308e39b573cSmrg printLines(xw, -screen->savedlines, -(screen->topline + 1), p); 309e39b573cSmrg } 310e39b573cSmrg if (p->print_everything & 4) { 311e39b573cSmrg screen->whichBuf = 1; 312e39b573cSmrg done_which |= 2; 313e39b573cSmrg printLines(xw, 0, screen->max_row, p); 314e39b573cSmrg screen->whichBuf = save_which; 315e39b573cSmrg } 316e39b573cSmrg if (p->print_everything & 2) { 317e39b573cSmrg screen->whichBuf = 0; 318e39b573cSmrg done_which |= 1; 319e39b573cSmrg printLines(xw, 0, screen->max_row, p); 320e39b573cSmrg screen->whichBuf = save_which; 321e39b573cSmrg } 322e39b573cSmrg if (p->print_everything & 1) { 323e39b573cSmrg if (!(done_which & (1 << screen->whichBuf))) { 324e39b573cSmrg printLines(xw, 0, screen->max_row, p); 325e39b573cSmrg } 326e39b573cSmrg } 327e39b573cSmrg } else { 328e39b573cSmrg int top = 0; 329e39b573cSmrg int bot = screen->max_row; 330e39b573cSmrg if (!screen->whichBuf) { 331e39b573cSmrg top = -screen->savedlines - screen->topline; 332e39b573cSmrg bot -= screen->topline; 333e39b573cSmrg } 334e39b573cSmrg printLines(xw, top, bot, p); 33520d2c4d2Smrg } 33620d2c4d2Smrg if (p->printer_formfeed) 337956cc18dSsnj charToPrinter(xw, '\f'); 338d522f475Smrg 339e39b573cSmrg if (!was_open || SPS.printer_autoclose) { 340956cc18dSsnj closePrinter(xw); 341d522f475Smrg } 342d522f475Smrg} 343d522f475Smrg 344d522f475Smrgstatic void 345956cc18dSsnjsend_CharSet(XtermWidget xw, LineData * ld) 346d522f475Smrg{ 347d522f475Smrg#if OPT_DEC_CHRSET 34820d2c4d2Smrg const char *msg = 0; 349d522f475Smrg 350956cc18dSsnj switch (GetLineDblCS(ld)) { 351d522f475Smrg case CSET_SWL: 352d522f475Smrg msg = "\033#5"; 353d522f475Smrg break; 354d522f475Smrg case CSET_DHL_TOP: 355d522f475Smrg msg = "\033#3"; 356d522f475Smrg break; 357d522f475Smrg case CSET_DHL_BOT: 358d522f475Smrg msg = "\033#4"; 359d522f475Smrg break; 360d522f475Smrg case CSET_DWL: 361d522f475Smrg msg = "\033#6"; 362d522f475Smrg break; 363d522f475Smrg } 364d522f475Smrg if (msg != 0) 365956cc18dSsnj stringToPrinter(xw, msg); 366d522f475Smrg#else 367956cc18dSsnj (void) xw; 368956cc18dSsnj (void) ld; 369d522f475Smrg#endif /* OPT_DEC_CHRSET */ 370d522f475Smrg} 371d522f475Smrg 372d522f475Smrgstatic void 373956cc18dSsnjsend_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg) 374d522f475Smrg{ 375d522f475Smrg char msg[80]; 376e39b573cSmrg 377d522f475Smrg strcpy(msg, "\033[0"); 378d522f475Smrg if (attr & BOLD) 379d522f475Smrg strcat(msg, ";1"); 380d522f475Smrg if (attr & UNDERLINE) 381d522f475Smrg strcat(msg, ";4"); /* typo? DEC documents this as '2' */ 382d522f475Smrg if (attr & BLINK) 383d522f475Smrg strcat(msg, ";5"); 384d522f475Smrg if (attr & INVERSE) /* typo? DEC documents this as invisible */ 385d522f475Smrg strcat(msg, ";7"); 386d522f475Smrg#if OPT_PRINT_COLORS 387d522f475Smrg if (bg != NO_COLOR) { 388d522f475Smrg sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg)); 389d522f475Smrg } 390d522f475Smrg if (fg != NO_COLOR) { 391d522f475Smrg#if OPT_PC_COLORS 39220d2c4d2Smrg if (TScreenOf(xw)->boldColors 393d522f475Smrg && fg > 8 394d522f475Smrg && (attr & BOLD) != 0) 395d522f475Smrg fg -= 8; 396d522f475Smrg#endif 397d522f475Smrg sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg)); 398d522f475Smrg } 399d522f475Smrg#else 400d522f475Smrg (void) bg; 401d522f475Smrg (void) fg; 402d522f475Smrg#endif 403d522f475Smrg strcat(msg, "m"); 404956cc18dSsnj stringToPrinter(xw, msg); 405d522f475Smrg} 406d522f475Smrg 407d522f475Smrg/* 408d522f475Smrg * This implementation only knows how to write to a pipe. 409d522f475Smrg */ 410d522f475Smrgstatic void 411956cc18dSsnjcharToPrinter(XtermWidget xw, unsigned chr) 412d522f475Smrg{ 413956cc18dSsnj TScreen *screen = TScreenOf(xw); 414d522f475Smrg 415e39b573cSmrg if (!SPS.isOpen && xtermHasPrinter(xw)) { 416e39b573cSmrg switch (SPS.toFile) { 417e39b573cSmrg /* 418e39b573cSmrg * write to a pipe. 419e39b573cSmrg */ 420e39b573cSmrg case False: 421e39b573cSmrg#ifdef VMS 422e39b573cSmrg /* 423e39b573cSmrg * This implementation only knows how to write to a file. When the 424e39b573cSmrg * file is closed the print command executes. Print command must 425e39b573cSmrg * be of the form: 426e39b573cSmrg * print/que=name/delete [/otherflags]. 427e39b573cSmrg */ 428e39b573cSmrg SPS.fp = fopen(VMS_TEMP_PRINT_FILE, "w"); 429d522f475Smrg#else 430e39b573cSmrg { 431e39b573cSmrg FILE *input; 432e39b573cSmrg int my_pipe[2]; 433e39b573cSmrg int c; 434e39b573cSmrg pid_t my_pid; 435e39b573cSmrg 436e39b573cSmrg if (pipe(my_pipe)) 437e39b573cSmrg SysError(ERROR_FORK); 438e39b573cSmrg if ((my_pid = fork()) < 0) 439e39b573cSmrg SysError(ERROR_FORK); 440e39b573cSmrg 441e39b573cSmrg if (my_pid == 0) { 442e39b573cSmrg TRACE_CLOSE(); 443e39b573cSmrg close(my_pipe[1]); /* printer is silent */ 444e39b573cSmrg close(screen->respond); 445e39b573cSmrg 446e39b573cSmrg close(fileno(stdout)); 447e39b573cSmrg dup2(fileno(stderr), 1); 448e39b573cSmrg 449e39b573cSmrg if (fileno(stderr) != 2) { 450e39b573cSmrg dup2(fileno(stderr), 2); 451e39b573cSmrg close(fileno(stderr)); 452e39b573cSmrg } 453e39b573cSmrg 454e39b573cSmrg /* don't want privileges! */ 455e39b573cSmrg if (xtermResetIds(screen) < 0) 456e39b573cSmrg exit(1); 457e39b573cSmrg 458e39b573cSmrg SPS.fp = popen(SPS.printer_command, "w"); 459e39b573cSmrg input = fdopen(my_pipe[0], "r"); 460e39b573cSmrg while ((c = fgetc(input)) != EOF) { 461e39b573cSmrg fputc(c, SPS.fp); 462e39b573cSmrg if (isForm(c)) 463e39b573cSmrg fflush(SPS.fp); 464e39b573cSmrg } 465e39b573cSmrg pclose(SPS.fp); 466e39b573cSmrg exit(0); 467e39b573cSmrg } else { 468e39b573cSmrg close(my_pipe[0]); /* won't read from printer */ 469e39b573cSmrg SPS.fp = fdopen(my_pipe[1], "w"); 470e39b573cSmrg TRACE(("opened printer from pid %d/%d\n", 471e39b573cSmrg (int) getpid(), (int) my_pid)); 472e39b573cSmrg } 473d522f475Smrg } 474d522f475Smrg#endif 475e39b573cSmrg break; 476e39b573cSmrg case True: 477e39b573cSmrg TRACE(("opening \"%s\" as printer output\n", SPS.printer_command)); 478e39b573cSmrg SPS.fp = fopen(SPS.printer_command, "w"); 479e39b573cSmrg break; 480e39b573cSmrg } 481e39b573cSmrg SPS.isOpen = True; 482d522f475Smrg } 483e39b573cSmrg if (SPS.fp != 0) { 484d522f475Smrg#if OPT_WIDE_CHARS 485d522f475Smrg if (chr > 127) { 486d522f475Smrg Char temp[10]; 487d522f475Smrg *convertToUTF8(temp, chr) = 0; 488e39b573cSmrg fputs((char *) temp, SPS.fp); 489d522f475Smrg } else 490d522f475Smrg#endif 491e39b573cSmrg fputc((int) chr, SPS.fp); 492d522f475Smrg if (isForm(chr)) 493e39b573cSmrg fflush(SPS.fp); 494d522f475Smrg } 495d522f475Smrg} 496d522f475Smrg 497d522f475Smrgstatic void 49820d2c4d2SmrgstringToPrinter(XtermWidget xw, const char *str) 499d522f475Smrg{ 500d522f475Smrg while (*str) 501956cc18dSsnj charToPrinter(xw, CharOf(*str++)); 502d522f475Smrg} 503d522f475Smrg 504d522f475Smrg/* 505d522f475Smrg * This module implements the MC (Media Copy) and related printing control 506d522f475Smrg * sequences for VTxxx emulation. This is based on the description in the 507d522f475Smrg * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment 508d522f475Smrg * Corp., March 1987). 509d522f475Smrg */ 510d522f475Smrgvoid 511956cc18dSsnjxtermMediaControl(XtermWidget xw, int param, int private_seq) 512d522f475Smrg{ 513d522f475Smrg TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq)); 514d522f475Smrg 515d522f475Smrg if (private_seq) { 516d522f475Smrg switch (param) { 517d522f475Smrg case 1: 518956cc18dSsnj printCursorLine(xw); 519d522f475Smrg break; 520d522f475Smrg case 4: 521956cc18dSsnj setPrinterControlMode(xw, 0); 522d522f475Smrg break; 523d522f475Smrg case 5: 524956cc18dSsnj setPrinterControlMode(xw, 1); 525d522f475Smrg break; 526d522f475Smrg case 10: /* VT320 */ 52720d2c4d2Smrg xtermPrintScreen(xw, False, getPrinterFlags(xw, NULL, 0)); 528d522f475Smrg break; 529d522f475Smrg case 11: /* VT320 */ 53020d2c4d2Smrg xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 531d522f475Smrg break; 532d522f475Smrg } 533d522f475Smrg } else { 534d522f475Smrg switch (param) { 535d522f475Smrg case -1: 536d522f475Smrg case 0: 53720d2c4d2Smrg xtermPrintScreen(xw, True, getPrinterFlags(xw, NULL, 0)); 538d522f475Smrg break; 539d522f475Smrg case 4: 540956cc18dSsnj setPrinterControlMode(xw, 0); 541d522f475Smrg break; 542d522f475Smrg case 5: 543956cc18dSsnj setPrinterControlMode(xw, 2); 544d522f475Smrg break; 545d522f475Smrg } 546d522f475Smrg } 547d522f475Smrg} 548d522f475Smrg 549d522f475Smrg/* 550d522f475Smrg * When in autoprint mode, the printer prints a line from the screen when you 551d522f475Smrg * move the cursor off that line with an LF, FF, or VT character, or an 552d522f475Smrg * autowrap occurs. The printed line ends with a CR and the character (LF, FF 553d522f475Smrg * or VT) that moved the cursor off the previous line. 554d522f475Smrg */ 555d522f475Smrgvoid 556956cc18dSsnjxtermAutoPrint(XtermWidget xw, unsigned chr) 557d522f475Smrg{ 558956cc18dSsnj TScreen *screen = TScreenOf(xw); 559d522f475Smrg 560e39b573cSmrg if (SPS.printer_controlmode == 1) { 561d522f475Smrg TRACE(("AutoPrint %d\n", chr)); 56220d2c4d2Smrg printLine(xw, screen->cursorp.row, chr, getPrinterFlags(xw, NULL, 0)); 563e39b573cSmrg if (SPS.fp != 0) 564e39b573cSmrg fflush(SPS.fp); 565d522f475Smrg } 566d522f475Smrg} 567d522f475Smrg 568d522f475Smrg/* 569d522f475Smrg * When in printer controller mode, the terminal sends received characters to 570d522f475Smrg * the printer without displaying them on the screen. The terminal sends all 571d522f475Smrg * characters and control sequences to the printer, except NUL, XON, XOFF, and 572d522f475Smrg * the printer controller sequences. 573d522f475Smrg * 574d522f475Smrg * This function eats characters, returning 0 as long as it must buffer or 575d522f475Smrg * divert to the printer. We're only invoked here when in printer controller 576d522f475Smrg * mode, and handle the exit from that mode. 577d522f475Smrg */ 578d522f475Smrg#define LB '[' 579d522f475Smrg 580d522f475Smrgint 581956cc18dSsnjxtermPrinterControl(XtermWidget xw, int chr) 582d522f475Smrg{ 583956cc18dSsnj TScreen *screen = TScreenOf(xw); 584d522f475Smrg /* *INDENT-OFF* */ 585e39b573cSmrg static const struct { 586e39b573cSmrg const Char seq[5]; 587d522f475Smrg int active; 588d522f475Smrg } tbl[] = { 589d522f475Smrg { { ANSI_CSI, '5', 'i' }, 2 }, 590d522f475Smrg { { ANSI_CSI, '4', 'i' }, 0 }, 591d522f475Smrg { { ANSI_ESC, LB, '5', 'i' }, 2 }, 592d522f475Smrg { { ANSI_ESC, LB, '4', 'i' }, 0 }, 593d522f475Smrg }; 594d522f475Smrg /* *INDENT-ON* */ 595d522f475Smrg 596d522f475Smrg static Char bfr[10]; 597d522f475Smrg static size_t length; 598d522f475Smrg size_t n; 599d522f475Smrg 600d522f475Smrg TRACE(("In printer:%04X\n", chr)); 601d522f475Smrg 602d522f475Smrg switch (chr) { 603d522f475Smrg case 0: 604d522f475Smrg case CTRL('Q'): 605d522f475Smrg case CTRL('S'): 606d522f475Smrg return 0; /* ignored by application */ 607d522f475Smrg 608d522f475Smrg case ANSI_CSI: 609d522f475Smrg case ANSI_ESC: 610d522f475Smrg case '[': 611d522f475Smrg case '4': 612d522f475Smrg case '5': 613d522f475Smrg case 'i': 6144e40088cSchristos bfr[length++] = CharOf(chr); 615d522f475Smrg for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) { 616d522f475Smrg size_t len = Strlen(tbl[n].seq); 617d522f475Smrg 618d522f475Smrg if (length == len 619d522f475Smrg && Strcmp(bfr, tbl[n].seq) == 0) { 620956cc18dSsnj setPrinterControlMode(xw, tbl[n].active); 621e39b573cSmrg if (SPS.printer_autoclose 622e39b573cSmrg && SPS.printer_controlmode == 0) 623956cc18dSsnj closePrinter(xw); 624d522f475Smrg length = 0; 625d522f475Smrg return 0; 626d522f475Smrg } else if (len > length 627d522f475Smrg && Strncmp(bfr, tbl[n].seq, length) == 0) { 628d522f475Smrg return 0; 629d522f475Smrg } 630d522f475Smrg } 631d522f475Smrg length--; 632d522f475Smrg 633d522f475Smrg /* FALLTHRU */ 634d522f475Smrg 635d522f475Smrg default: 636d522f475Smrg for (n = 0; n < length; n++) 637956cc18dSsnj charToPrinter(xw, bfr[n]); 6384e40088cSchristos bfr[0] = CharOf(chr); 639d522f475Smrg length = 1; 640d522f475Smrg return 0; 641d522f475Smrg } 642d522f475Smrg} 643d522f475Smrg 644d522f475Smrg/* 645d522f475Smrg * If there is no printer command, we will ignore printer controls. 646d522f475Smrg */ 647d522f475SmrgBool 648956cc18dSsnjxtermHasPrinter(XtermWidget xw) 649d522f475Smrg{ 650956cc18dSsnj TScreen *screen = TScreenOf(xw); 651d522f475Smrg 652e39b573cSmrg return (strlen(SPS.printer_command) != 0); 653d522f475Smrg} 654d522f475Smrg 655d522f475Smrg#define showPrinterControlMode(mode) \ 656d522f475Smrg (((mode) == 0) \ 657d522f475Smrg ? "normal" \ 658d522f475Smrg : ((mode) == 1 \ 659d522f475Smrg ? "autoprint" \ 660d522f475Smrg : "printer controller")) 661d522f475Smrg 662d522f475Smrgvoid 663956cc18dSsnjsetPrinterControlMode(XtermWidget xw, int mode) 664d522f475Smrg{ 66520d2c4d2Smrg TScreen *screen = TScreenOf(xw); 66620d2c4d2Smrg 667956cc18dSsnj if (xtermHasPrinter(xw) 668e39b573cSmrg && SPS.printer_controlmode != mode) { 669d522f475Smrg TRACE(("%s %s mode\n", 670d522f475Smrg (mode 671d522f475Smrg ? "set" 672d522f475Smrg : "reset"), 673d522f475Smrg (mode 674d522f475Smrg ? showPrinterControlMode(mode) 675e39b573cSmrg : showPrinterControlMode(SPS.printer_controlmode)))); 676e39b573cSmrg SPS.printer_controlmode = mode; 677d522f475Smrg update_print_redir(); 678d522f475Smrg } 679d522f475Smrg} 68020d2c4d2Smrg 68120d2c4d2SmrgPrinterFlags * 68220d2c4d2SmrggetPrinterFlags(XtermWidget xw, String * params, Cardinal *param_count) 68320d2c4d2Smrg{ 68420d2c4d2Smrg /* *INDENT-OFF* */ 68520d2c4d2Smrg static const struct { 68620d2c4d2Smrg const char *name; 68720d2c4d2Smrg unsigned offset; 68820d2c4d2Smrg int value; 68920d2c4d2Smrg } table[] = { 69020d2c4d2Smrg { "noFormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 0 }, 69120d2c4d2Smrg { "FormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 1 }, 69220d2c4d2Smrg { "noNewLine", XtOffsetOf(PrinterFlags, printer_newline), 0 }, 69320d2c4d2Smrg { "NewLine", XtOffsetOf(PrinterFlags, printer_newline), 1 }, 69420d2c4d2Smrg { "noAttrs", XtOffsetOf(PrinterFlags, print_attributes), 0 }, 69520d2c4d2Smrg { "monoAttrs", XtOffsetOf(PrinterFlags, print_attributes), 1 }, 69620d2c4d2Smrg { "colorAttrs", XtOffsetOf(PrinterFlags, print_attributes), 2 }, 69720d2c4d2Smrg }; 69820d2c4d2Smrg /* *INDENT-ON* */ 69920d2c4d2Smrg 70020d2c4d2Smrg TScreen *screen = TScreenOf(xw); 70120d2c4d2Smrg PrinterFlags *result = &(screen->printer_flags); 70220d2c4d2Smrg 70320d2c4d2Smrg TRACE(("getPrinterFlags %d params\n", param_count ? *param_count : 0)); 70420d2c4d2Smrg 705e39b573cSmrg result->printer_extent = SPS.printer_extent; 706e39b573cSmrg result->printer_formfeed = SPS.printer_formfeed; 707e39b573cSmrg result->printer_newline = SPS.printer_newline; 708e39b573cSmrg result->print_attributes = SPS.print_attributes; 709e39b573cSmrg result->print_everything = SPS.print_everything; 71020d2c4d2Smrg 71120d2c4d2Smrg if (param_count != 0 && *param_count != 0) { 71220d2c4d2Smrg Cardinal j; 71320d2c4d2Smrg unsigned k; 71420d2c4d2Smrg for (j = 0; j < *param_count; ++j) { 71520d2c4d2Smrg TRACE(("param%d:%s\n", j, params[j])); 71620d2c4d2Smrg for (k = 0; k < XtNumber(table); ++k) { 71720d2c4d2Smrg if (!x_strcasecmp(params[j], table[k].name)) { 718a1f3da82Smrg int *ptr = (int *) (void *) ((char *) result + table[k].offset); 71920d2c4d2Smrg TRACE(("...PrinterFlags(%s) %d->%d\n", 72020d2c4d2Smrg table[k].name, 72120d2c4d2Smrg *ptr, 72220d2c4d2Smrg table[k].value)); 72320d2c4d2Smrg *ptr = table[k].value; 72420d2c4d2Smrg break; 72520d2c4d2Smrg } 72620d2c4d2Smrg } 72720d2c4d2Smrg } 72820d2c4d2Smrg } 72920d2c4d2Smrg 73020d2c4d2Smrg return result; 73120d2c4d2Smrg} 732e39b573cSmrg 733e39b573cSmrg/* 734e39b573cSmrg * Print a timestamped copy of everything. 735e39b573cSmrg */ 736e39b573cSmrgvoid 737e39b573cSmrgxtermPrintImmediately(XtermWidget xw, String filename, int opts, int attrs) 738e39b573cSmrg{ 739e39b573cSmrg TScreen *screen = TScreenOf(xw); 740e39b573cSmrg PrinterState save_state = screen->printer_state; 741e39b573cSmrg char *my_filename = malloc(TIMESTAMP_LEN + strlen(filename)); 742e39b573cSmrg 743e39b573cSmrg if (my_filename != 0) { 744e39b573cSmrg unsigned save_umask = umask(0177); 745e39b573cSmrg 746e39b573cSmrg timestamp_filename(my_filename, filename); 747e39b573cSmrg SPS.fp = 0; 748e39b573cSmrg SPS.isOpen = False; 749e39b573cSmrg SPS.toFile = True; 750e39b573cSmrg SPS.printer_command = my_filename; 751e39b573cSmrg SPS.printer_autoclose = True; 752e39b573cSmrg SPS.printer_formfeed = False; 753e39b573cSmrg SPS.printer_newline = True; 754e39b573cSmrg SPS.print_attributes = attrs; 755e39b573cSmrg SPS.print_everything = opts; 756e39b573cSmrg xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 757e39b573cSmrg 758e39b573cSmrg umask(save_umask); 759e39b573cSmrg screen->printer_state = save_state; 760e39b573cSmrg } 761e39b573cSmrg} 762e39b573cSmrg 763e39b573cSmrgvoid 764e39b573cSmrgxtermPrintOnXError(XtermWidget xw, int n) 765e39b573cSmrg{ 766e39b573cSmrg#if OPT_PRINT_ON_EXIT 767e39b573cSmrg /* 768e39b573cSmrg * The user may have requested that the contents of the screen will be 769e39b573cSmrg * written to a file if an X error occurs. 770e39b573cSmrg */ 771e39b573cSmrg if (TScreenOf(xw)->write_error && !IsEmpty(resource.printFileOnXError)) { 772e39b573cSmrg Boolean printIt = False; 773e39b573cSmrg 774e39b573cSmrg switch (n) { 775e39b573cSmrg case ERROR_XERROR: 776e39b573cSmrg /* FALLTHRU */ 777e39b573cSmrg case ERROR_XIOERROR: 778e39b573cSmrg /* FALLTHRU */ 779e39b573cSmrg case ERROR_ICEERROR: 780e39b573cSmrg printIt = True; 781e39b573cSmrg break; 782e39b573cSmrg } 783e39b573cSmrg 784e39b573cSmrg if (printIt) { 785e39b573cSmrg xtermPrintImmediately(xw, 786e39b573cSmrg resource.printFileOnXError, 787e39b573cSmrg resource.printOptsOnXError, 788e39b573cSmrg resource.printModeOnXError); 789e39b573cSmrg } 790e39b573cSmrg } 791e39b573cSmrg#else 792e39b573cSmrg (void) xw; 793e39b573cSmrg (void) n; 794e39b573cSmrg#endif 795e39b573cSmrg} 796