print.c revision 2e4f8982
1/* $XTermId: print.c,v 1.155 2016/05/22 16:31:59 tom Exp $ */ 2 3/* 4 * Copyright 1997-2014,2016 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 */ 32 33#include <xterm.h> 34#include <data.h> 35#include <menu.h> 36#include <error.h> 37#include <xstrings.h> 38 39#include <stdio.h> 40#include <sys/stat.h> 41 42#undef CTRL 43#define CTRL(c) ((c) & 0x1f) 44 45#define SHIFT_IN '\017' 46#define SHIFT_OUT '\016' 47 48#define CSET_IN 'A' 49#define CSET_OUT '0' 50 51#define isForm(c) ((c) == '\r' || (c) == '\n' || (c) == '\f') 52#define Strlen(a) strlen((const char *)a) 53#define Strcmp(a,b) strcmp((const char *)a,(const char *)b) 54#define Strncmp(a,b,c) strncmp((const char *)a,(const char *)b,c) 55 56#define SPS PrinterOf(screen) 57 58#ifdef VMS 59#define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt" 60#endif 61 62static void charToPrinter(XtermWidget /* xw */ , 63 unsigned /* chr */ ); 64static void printLine(XtermWidget /* xw */ , 65 int /* row */ , 66 unsigned /* chr */ , 67 PrinterFlags * /* p */ ); 68static void send_CharSet(XtermWidget /* xw */ , 69 LineData * /* ld */ ); 70static void send_SGR(XtermWidget /* xw */ , 71 unsigned /* attr */ , 72 unsigned /* fg */ , 73 unsigned /* bg */ ); 74static void stringToPrinter(XtermWidget /* xw */ , 75 const char * /*str */ ); 76 77static void 78closePrinter(XtermWidget xw GCC_UNUSED) 79{ 80 if (xtermHasPrinter(xw) != 0) { 81 TScreen *screen = TScreenOf(xw); 82#ifdef VMS 83 char pcommand[256]; 84 (void) sprintf(pcommand, "%s %s;", 85 SPS.printer_command, 86 VMS_TEMP_PRINT_FILE); 87#endif 88 89 if (SPS.fp != 0) { 90 DEBUG_MSG("closePrinter\n"); 91 pclose(SPS.fp); 92 TRACE(("closed printer, waiting...\n")); 93#ifdef VMS /* This is a quick hack, really should use 94 spawn and check status or system services 95 and go straight to the queue */ 96 (void) system(pcommand); 97#else /* VMS */ 98 while (nonblocking_wait() > 0) { 99 ; 100 } 101#endif /* VMS */ 102 SPS.fp = 0; 103 SPS.isOpen = False; 104 TRACE(("closed printer\n")); 105 DEBUG_MSG("...closePrinter (done)\n"); 106 } 107 } 108} 109 110static void 111printCursorLine(XtermWidget xw) 112{ 113 TScreen *screen = TScreenOf(xw); 114 115 TRACE(("printCursorLine\n")); 116 printLine(xw, screen->cur_row, '\n', getPrinterFlags(xw, NULL, 0)); 117} 118 119#define NO_COLOR ((unsigned)-1) 120 121/* 122 * DEC's manual doesn't document whether trailing blanks are removed, or what 123 * happens with a line that is entirely blank. This function prints the 124 * characters that xterm would allow as a selection (which may include blanks). 125 */ 126static void 127printLine(XtermWidget xw, int row, unsigned chr, PrinterFlags *p) 128{ 129 TScreen *screen = TScreenOf(xw); 130 int inx = ROW2INX(screen, row); 131 LineData *ld; 132 int last = MaxCols(screen); 133#if OPT_ISO_COLORS && OPT_PRINT_COLORS 134#define ColorOf(ld,col) (ld->color[col]) 135#endif 136 unsigned fg = NO_COLOR, last_fg = NO_COLOR; 137 unsigned bg = NO_COLOR, last_bg = NO_COLOR; 138 139 ld = getLineData(screen, inx); 140 if (ld == 0) 141 return; 142 143 TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n", 144 row, ROW2INX(screen, row), screen->topline, screen->max_row, chr, 145 visibleIChars(ld->charData, (unsigned) last))); 146 147 while (last > 0) { 148 if ((ld->attribs[last - 1] & CHARDRAWN) == 0) 149 last--; 150 else 151 break; 152 } 153 154 if (last) { 155 int col; 156 int cs = CSET_IN; 157 int last_cs = CSET_IN; 158 159 if (p->print_attributes) { 160 send_CharSet(xw, ld); 161 send_SGR(xw, 0, NO_COLOR, NO_COLOR); 162 } 163 for (col = 0; col < last; col++) { 164 IAttr attr = 0; 165 unsigned ch = ld->charData[col]; 166#if OPT_PRINT_COLORS 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]) 171 : NO_COLOR; 172 bg = (ld->attribs[col] & BG_COLOR) 173 ? extract_bg(xw, ColorOf(ld, col), ld->attribs[col]) 174 : NO_COLOR; 175 } 176 } 177#endif 178 if ((((ld->attribs[col] & SGR_MASK) != attr) 179#if OPT_PRINT_COLORS 180 || (last_fg != fg) || (last_bg != bg) 181#endif 182 ) 183 && ch) { 184 attr = ld->attribs[col] & SGR_MASK; 185#if OPT_PRINT_COLORS 186 last_fg = fg; 187 last_bg = bg; 188#endif 189 if (p->print_attributes) 190 send_SGR(xw, attr, fg, bg); 191 } 192 193 if (ch == 0) 194 ch = ' '; 195 196#if OPT_WIDE_CHARS 197 if (screen->utf8_mode) 198 cs = CSET_IN; 199 else 200#endif 201 cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT; 202 if (last_cs != cs) { 203 if (p->print_attributes) { 204 charToPrinter(xw, 205 (unsigned) ((cs == CSET_OUT) 206 ? SHIFT_OUT 207 : SHIFT_IN)); 208 } 209 last_cs = cs; 210 } 211 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. 216 */ 217 charToPrinter(xw, 218 ((cs == CSET_OUT) 219 ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f)) 220 : ch)); 221 if_OPT_WIDE_CHARS(screen, { 222 size_t off; 223 for_each_combData(off, ld) { 224 ch = ld->combData[off][col]; 225 if (ch == 0) 226 break; 227 charToPrinter(xw, ch); 228 } 229 }); 230 } 231 if (p->print_attributes) { 232 send_SGR(xw, 0, NO_COLOR, NO_COLOR); 233 if (cs != CSET_IN) 234 charToPrinter(xw, SHIFT_IN); 235 } 236 } 237 238 /* finish line (protocol for attributes needs a CR */ 239 if (p->print_attributes) 240 charToPrinter(xw, '\r'); 241 242 if (chr && !(p->printer_newline)) { 243 if (LineTstWrapped(ld)) 244 chr = '\0'; 245 } 246 247 if (chr) 248 charToPrinter(xw, chr); 249 250 return; 251} 252 253#define PrintNewLine() (unsigned) (((top < bot) || p->printer_newline) ? '\n' : '\0') 254 255static void 256printLines(XtermWidget xw, int top, int bot, PrinterFlags *p) 257{ 258 TRACE(("printLines, rows %d..%d\n", top, bot)); 259 while (top <= bot) { 260 printLine(xw, top, PrintNewLine(), p); 261 ++top; 262 } 263} 264 265void 266xtermPrintScreen(XtermWidget xw, Bool use_DECPEX, PrinterFlags *p) 267{ 268 if (XtIsRealized((Widget) xw)) { 269 TScreen *screen = TScreenOf(xw); 270 Bool extent = (use_DECPEX && p->printer_extent); 271 Boolean was_open = SPS.isOpen; 272 273 printLines(xw, 274 extent ? 0 : screen->top_marg, 275 extent ? screen->max_row : screen->bot_marg, 276 p); 277 if (p->printer_formfeed) 278 charToPrinter(xw, '\f'); 279 280 if (!was_open || SPS.printer_autoclose) { 281 closePrinter(xw); 282 } 283 } else { 284 Bell(xw, XkbBI_MinorError, 0); 285 } 286} 287 288/* 289 * If p->print_everything is zero, use this behavior: 290 * If the alternate screen is active, we'll print only that. Otherwise, print 291 * the normal screen plus all scrolled-back lines. The distinction is made 292 * because the normal screen's buffer is part of the overall scrollback buffer. 293 * 294 * Otherwise, decode bits: 295 * 1 = current screen 296 * 2 = normal screen 297 * 4 = alternate screen 298 * 8 = saved lines 299 */ 300void 301xtermPrintEverything(XtermWidget xw, PrinterFlags *p) 302{ 303 TScreen *screen = TScreenOf(xw); 304 Boolean was_open = SPS.isOpen; 305 int save_which = screen->whichBuf; 306 307 DEBUG_MSG("xtermPrintEverything\n"); 308 309 if (p->print_everything) { 310 int done_which = 0; 311 312 if (p->print_everything & 8) { 313 printLines(xw, -screen->savedlines, -(screen->topline + 1), p); 314 } 315 if (p->print_everything & 4) { 316 screen->whichBuf = 1; 317 done_which |= 2; 318 printLines(xw, 0, screen->max_row, p); 319 screen->whichBuf = save_which; 320 } 321 if (p->print_everything & 2) { 322 screen->whichBuf = 0; 323 done_which |= 1; 324 printLines(xw, 0, screen->max_row, p); 325 screen->whichBuf = save_which; 326 } 327 if (p->print_everything & 1) { 328 if (!(done_which & (1 << screen->whichBuf))) { 329 printLines(xw, 0, screen->max_row, p); 330 } 331 } 332 } else { 333 int top = 0; 334 int bot = screen->max_row; 335 if (!screen->whichBuf) { 336 top = -screen->savedlines - screen->topline; 337 bot -= screen->topline; 338 } 339 printLines(xw, top, bot, p); 340 } 341 if (p->printer_formfeed) 342 charToPrinter(xw, '\f'); 343 344 if (!was_open || SPS.printer_autoclose) { 345 closePrinter(xw); 346 } 347} 348 349static void 350send_CharSet(XtermWidget xw, LineData *ld) 351{ 352#if OPT_DEC_CHRSET 353 const char *msg = 0; 354 355 switch (GetLineDblCS(ld)) { 356 case CSET_SWL: 357 msg = "\033#5"; 358 break; 359 case CSET_DHL_TOP: 360 msg = "\033#3"; 361 break; 362 case CSET_DHL_BOT: 363 msg = "\033#4"; 364 break; 365 case CSET_DWL: 366 msg = "\033#6"; 367 break; 368 } 369 if (msg != 0) 370 stringToPrinter(xw, msg); 371#else 372 (void) xw; 373 (void) ld; 374#endif /* OPT_DEC_CHRSET */ 375} 376 377static void 378send_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg) 379{ 380 char msg[80]; 381 382 strcpy(msg, "\033[0"); 383 if (attr & BOLD) 384 strcat(msg, ";1"); 385#if OPT_WIDE_ATTRS 386 if (attr & ATR_FAINT) 387 strcat(msg, ";2"); 388 if (attr & ATR_ITALIC) 389 strcat(msg, ";3"); 390#endif 391 if (attr & UNDERLINE) 392 strcat(msg, ";4"); /* typo? DEC documents this as '2' */ 393 if (attr & BLINK) 394 strcat(msg, ";5"); 395 if (attr & INVERSE) /* typo? DEC documents this as invisible */ 396 strcat(msg, ";7"); 397#if OPT_PRINT_COLORS 398 if (bg != NO_COLOR) { 399 sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg)); 400 } 401 if (fg != NO_COLOR) { 402#if OPT_PC_COLORS 403 if (TScreenOf(xw)->boldColors 404 && fg > 8 405 && (attr & BOLD) != 0) 406 fg -= 8; 407#endif 408 sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg)); 409 } 410#else 411 (void) bg; 412 (void) fg; 413#endif 414 strcat(msg, "m"); 415 stringToPrinter(xw, msg); 416} 417 418/* 419 * This implementation only knows how to write to a pipe. 420 */ 421static void 422charToPrinter(XtermWidget xw, unsigned chr) 423{ 424 TScreen *screen = TScreenOf(xw); 425 426 if (!SPS.isOpen && xtermHasPrinter(xw)) { 427 switch (SPS.toFile) { 428 /* 429 * write to a pipe. 430 */ 431 case False: 432#ifdef VMS 433 /* 434 * This implementation only knows how to write to a file. When the 435 * file is closed the print command executes. Print command must 436 * be of the form: 437 * print/que=name/delete [/otherflags]. 438 */ 439 SPS.fp = fopen(VMS_TEMP_PRINT_FILE, "w"); 440#else 441 { 442 int my_pipe[2]; 443 pid_t my_pid; 444 445 if (pipe(my_pipe)) 446 SysError(ERROR_FORK); 447 if ((my_pid = fork()) < 0) 448 SysError(ERROR_FORK); 449 450 if (my_pid == 0) { 451 DEBUG_MSG("charToPrinter: subprocess for printer\n"); 452 TRACE_CLOSE(); 453 close(my_pipe[1]); /* printer is silent */ 454 close(screen->respond); 455 456 close(fileno(stdout)); 457 dup2(fileno(stderr), 1); 458 459 if (fileno(stderr) != 2) { 460 dup2(fileno(stderr), 2); 461 close(fileno(stderr)); 462 } 463 464 /* don't want privileges! */ 465 if (xtermResetIds(screen) < 0) 466 exit(1); 467 468 SPS.fp = popen(SPS.printer_command, "w"); 469 if (SPS.fp != 0) { 470 FILE *input; 471 DEBUG_MSG("charToPrinter: opened pipe to printer\n"); 472 input = fdopen(my_pipe[0], "r"); 473 clearerr(input); 474 475 for (;;) { 476 int c; 477 478 if (ferror(input)) { 479 DEBUG_MSG("charToPrinter: break on ferror\n"); 480 break; 481 } else if (feof(input)) { 482 DEBUG_MSG("charToPrinter: break on feof\n"); 483 break; 484 } else if ((c = fgetc(input)) == EOF) { 485 DEBUG_MSG("charToPrinter: break on EOF\n"); 486 break; 487 } 488 fputc(c, SPS.fp); 489 if (isForm(c)) 490 fflush(SPS.fp); 491 } 492 493 DEBUG_MSG("charToPrinter: calling pclose\n"); 494 pclose(SPS.fp); 495 } 496 exit(0); 497 } else { 498 close(my_pipe[0]); /* won't read from printer */ 499 if ((SPS.fp = fdopen(my_pipe[1], "w")) != 0) { 500 DEBUG_MSG("charToPrinter: opened printer in parent\n"); 501 TRACE(("opened printer from pid %d/%d\n", 502 (int) getpid(), (int) my_pid)); 503 } else { 504 TRACE(("failed to open printer:%s\n", strerror(errno))); 505 DEBUG_MSG("charToPrinter: could not open in parent\n"); 506 } 507 } 508 } 509#endif 510 break; 511 case True: 512 TRACE(("opening \"%s\" as printer output\n", SPS.printer_command)); 513 SPS.fp = fopen(SPS.printer_command, "w"); 514 break; 515 } 516 SPS.isOpen = True; 517 } 518 if (SPS.fp != 0) { 519#if OPT_WIDE_CHARS 520 if (chr > 127) { 521 Char temp[10]; 522 *convertToUTF8(temp, chr) = 0; 523 fputs((char *) temp, SPS.fp); 524 } else 525#endif 526 fputc((int) chr, SPS.fp); 527 if (isForm(chr)) 528 fflush(SPS.fp); 529 } 530} 531 532static void 533stringToPrinter(XtermWidget xw, const char *str) 534{ 535 while (*str) 536 charToPrinter(xw, CharOf(*str++)); 537} 538 539/* 540 * This module implements the MC (Media Copy) and related printing control 541 * sequences for VTxxx emulation. This is based on the description in the 542 * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment 543 * Corp., March 1987). 544 */ 545void 546xtermMediaControl(XtermWidget xw, int param, int private_seq) 547{ 548 TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq)); 549 550 if (private_seq) { 551 switch (param) { 552 case 1: 553 printCursorLine(xw); 554 break; 555 case 4: 556 setPrinterControlMode(xw, 0); 557 break; 558 case 5: 559 setPrinterControlMode(xw, 1); 560 break; 561 case 10: /* VT320 */ 562 xtermPrintScreen(xw, False, getPrinterFlags(xw, NULL, 0)); 563 break; 564 case 11: /* VT320 */ 565 xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 566 break; 567 } 568 } else { 569 switch (param) { 570 case -1: 571 case 0: 572 xtermPrintScreen(xw, True, getPrinterFlags(xw, NULL, 0)); 573 break; 574 case 4: 575 setPrinterControlMode(xw, 0); 576 break; 577 case 5: 578 setPrinterControlMode(xw, 2); 579 break; 580#if OPT_SCREEN_DUMPS 581 case 10: 582 xtermDumpHtml(xw); 583 break; 584 case 11: 585 xtermDumpSvg(xw); 586 break; 587#endif 588 } 589 } 590} 591 592/* 593 * When in autoprint mode, the printer prints a line from the screen when you 594 * move the cursor off that line with an LF, FF, or VT character, or an 595 * autowrap occurs. The printed line ends with a CR and the character (LF, FF 596 * or VT) that moved the cursor off the previous line. 597 */ 598void 599xtermAutoPrint(XtermWidget xw, unsigned chr) 600{ 601 TScreen *screen = TScreenOf(xw); 602 603 if (SPS.printer_controlmode == 1) { 604 TRACE(("AutoPrint %d\n", chr)); 605 printLine(xw, screen->cursorp.row, chr, getPrinterFlags(xw, NULL, 0)); 606 if (SPS.fp != 0) 607 fflush(SPS.fp); 608 } 609} 610 611/* 612 * When in printer controller mode, the terminal sends received characters to 613 * the printer without displaying them on the screen. The terminal sends all 614 * characters and control sequences to the printer, except NUL, XON, XOFF, and 615 * the printer controller sequences. 616 * 617 * This function eats characters, returning 0 as long as it must buffer or 618 * divert to the printer. We're only invoked here when in printer controller 619 * mode, and handle the exit from that mode. 620 */ 621#define LB '[' 622 623int 624xtermPrinterControl(XtermWidget xw, int chr) 625{ 626 TScreen *screen = TScreenOf(xw); 627 /* *INDENT-OFF* */ 628 static const struct { 629 const Char seq[5]; 630 int active; 631 } tbl[] = { 632 { { ANSI_CSI, '5', 'i' }, 2 }, 633 { { ANSI_CSI, '4', 'i' }, 0 }, 634 { { ANSI_ESC, LB, '5', 'i' }, 2 }, 635 { { ANSI_ESC, LB, '4', 'i' }, 0 }, 636 }; 637 /* *INDENT-ON* */ 638 639 static Char bfr[10]; 640 static size_t length; 641 size_t n; 642 643 TRACE(("In printer:%04X\n", chr)); 644 645 switch (chr) { 646 case 0: 647 case CTRL('Q'): 648 case CTRL('S'): 649 return 0; /* ignored by application */ 650 651 case ANSI_CSI: 652 case ANSI_ESC: 653 case '[': 654 case '4': 655 case '5': 656 case 'i': 657 bfr[length++] = CharOf(chr); 658 for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) { 659 size_t len = Strlen(tbl[n].seq); 660 661 if (length == len 662 && Strcmp(bfr, tbl[n].seq) == 0) { 663 setPrinterControlMode(xw, tbl[n].active); 664 if (SPS.printer_autoclose 665 && SPS.printer_controlmode == 0) 666 closePrinter(xw); 667 length = 0; 668 return 0; 669 } else if (len > length 670 && Strncmp(bfr, tbl[n].seq, length) == 0) { 671 return 0; 672 } 673 } 674 length--; 675 676 /* FALLTHRU */ 677 678 default: 679 for (n = 0; n < length; n++) 680 charToPrinter(xw, bfr[n]); 681 bfr[0] = CharOf(chr); 682 length = 1; 683 return 0; 684 } 685} 686 687/* 688 * If there is no printer command, we will ignore printer controls. 689 * 690 * If we do have a printer command, we still have to verify that it will 691 * (perhaps) work if we pass it to popen(). At a minimum, the program 692 * must exist and be executable. If not, warn and disable the feature. 693 */ 694Bool 695xtermHasPrinter(XtermWidget xw) 696{ 697 TScreen *screen = TScreenOf(xw); 698 Bool result = SPS.printer_checked; 699 700 if (strlen(SPS.printer_command) != 0 && !result) { 701 char **argv = x_splitargs(SPS.printer_command); 702 if (argv) { 703 if (argv[0]) { 704 char *myShell = xtermFindShell(argv[0], False); 705 if (myShell == 0) { 706 xtermWarning("No program found for printerCommand: %s\n", SPS.printer_command); 707 SPS.printer_command = x_strdup(""); 708 } else { 709 free(myShell); 710 SPS.printer_checked = True; 711 result = True; 712 } 713 } 714 x_freeargs(argv); 715 } 716 TRACE(("xtermHasPrinter:%d\n", result)); 717 } 718 719 return result; 720} 721 722#define showPrinterControlMode(mode) \ 723 (((mode) == 0) \ 724 ? "normal" \ 725 : ((mode) == 1 \ 726 ? "autoprint" \ 727 : "printer controller")) 728 729void 730setPrinterControlMode(XtermWidget xw, int mode) 731{ 732 TScreen *screen = TScreenOf(xw); 733 734 if (xtermHasPrinter(xw) 735 && SPS.printer_controlmode != mode) { 736 TRACE(("%s %s mode\n", 737 (mode 738 ? "set" 739 : "reset"), 740 (mode 741 ? showPrinterControlMode(mode) 742 : showPrinterControlMode(SPS.printer_controlmode)))); 743 SPS.printer_controlmode = mode; 744 update_print_redir(); 745 } 746} 747 748PrinterFlags * 749getPrinterFlags(XtermWidget xw, String *params, Cardinal *param_count) 750{ 751 /* *INDENT-OFF* */ 752 static const struct { 753 const char *name; 754 unsigned offset; 755 int value; 756 } table[] = { 757 { "noFormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 0 }, 758 { "FormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 1 }, 759 { "noNewLine", XtOffsetOf(PrinterFlags, printer_newline), 0 }, 760 { "NewLine", XtOffsetOf(PrinterFlags, printer_newline), 1 }, 761 { "noAttrs", XtOffsetOf(PrinterFlags, print_attributes), 0 }, 762 { "monoAttrs", XtOffsetOf(PrinterFlags, print_attributes), 1 }, 763 { "colorAttrs", XtOffsetOf(PrinterFlags, print_attributes), 2 }, 764 }; 765 /* *INDENT-ON* */ 766 767 TScreen *screen = TScreenOf(xw); 768 PrinterFlags *result = &(screen->printer_flags); 769 770 TRACE(("getPrinterFlags %d params\n", param_count ? *param_count : 0)); 771 772 result->printer_extent = SPS.printer_extent; 773 result->printer_formfeed = SPS.printer_formfeed; 774 result->printer_newline = SPS.printer_newline; 775 result->print_attributes = SPS.print_attributes; 776 result->print_everything = SPS.print_everything; 777 778 if (param_count != 0 && *param_count != 0) { 779 Cardinal j; 780 unsigned k; 781 for (j = 0; j < *param_count; ++j) { 782 TRACE(("param%d:%s\n", j, params[j])); 783 for (k = 0; k < XtNumber(table); ++k) { 784 if (!x_strcasecmp(params[j], table[k].name)) { 785 int *ptr = (int *) (void *) ((char *) result + table[k].offset); 786 TRACE(("...PrinterFlags(%s) %d->%d\n", 787 table[k].name, 788 *ptr, 789 table[k].value)); 790 *ptr = table[k].value; 791 break; 792 } 793 } 794 } 795 } 796 797 return result; 798} 799 800/* 801 * Print a timestamped copy of everything. 802 */ 803void 804xtermPrintImmediately(XtermWidget xw, String filename, int opts, int attrs) 805{ 806 TScreen *screen = TScreenOf(xw); 807 PrinterState save_state = screen->printer_state; 808 char *my_filename = malloc(TIMESTAMP_LEN + strlen(filename)); 809 810 if (my_filename != 0) { 811 unsigned save_umask = umask(0177); 812 813 timestamp_filename(my_filename, filename); 814 SPS.fp = 0; 815 SPS.isOpen = False; 816 SPS.toFile = True; 817 SPS.printer_command = my_filename; 818 SPS.printer_autoclose = True; 819 SPS.printer_formfeed = False; 820 SPS.printer_newline = True; 821 SPS.print_attributes = attrs; 822 SPS.print_everything = opts; 823 xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 824 825 umask(save_umask); 826 screen->printer_state = save_state; 827 } 828} 829 830void 831xtermPrintOnXError(XtermWidget xw, int n) 832{ 833#if OPT_PRINT_ON_EXIT 834 /* 835 * The user may have requested that the contents of the screen will be 836 * written to a file if an X error occurs. 837 */ 838 if (TScreenOf(xw)->write_error && !IsEmpty(resource.printFileOnXError)) { 839 Boolean printIt = False; 840 841 switch (n) { 842 case ERROR_XERROR: 843 /* FALLTHRU */ 844 case ERROR_XIOERROR: 845 /* FALLTHRU */ 846 case ERROR_ICEERROR: 847 printIt = True; 848 break; 849 } 850 851 if (printIt) { 852 xtermPrintImmediately(xw, 853 resource.printFileOnXError, 854 resource.printOptsOnXError, 855 resource.printModeOnXError); 856 } 857 } 858#else 859 (void) xw; 860 (void) n; 861#endif 862} 863