print.c revision 894e0ac8
1/* $XTermId: print.c,v 1.152 2014/06/13 00:36:51 tom Exp $ */ 2 3/* 4 * Copyright 1997-2013,2014 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 IAttr attr = 0; 133 unsigned ch; 134 int last = MaxCols(screen); 135 int col; 136#if OPT_ISO_COLORS && OPT_PRINT_COLORS 137#define ColorOf(ld,col) (ld->color[col]) 138#endif 139 unsigned fg = NO_COLOR, last_fg = NO_COLOR; 140 unsigned bg = NO_COLOR, last_bg = NO_COLOR; 141 int cs = CSET_IN; 142 int last_cs = CSET_IN; 143 144 ld = getLineData(screen, inx); 145 if (ld == 0) 146 return; 147 148 TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n", 149 row, ROW2INX(screen, row), screen->topline, screen->max_row, chr, 150 visibleIChars(ld->charData, (unsigned) last))); 151 152 while (last > 0) { 153 if ((ld->attribs[last - 1] & CHARDRAWN) == 0) 154 last--; 155 else 156 break; 157 } 158 if (last) { 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 ch = ld->charData[col]; 165#if OPT_PRINT_COLORS 166 if (screen->colorMode) { 167 if (p->print_attributes > 1) { 168 fg = (ld->attribs[col] & FG_COLOR) 169 ? extract_fg(xw, ColorOf(ld, col), ld->attribs[col]) 170 : NO_COLOR; 171 bg = (ld->attribs[col] & BG_COLOR) 172 ? extract_bg(xw, ColorOf(ld, col), ld->attribs[col]) 173 : NO_COLOR; 174 } 175 } 176#endif 177 if ((((ld->attribs[col] & SGR_MASK) != attr) 178#if OPT_PRINT_COLORS 179 || (last_fg != fg) || (last_bg != bg) 180#endif 181 ) 182 && ch) { 183 attr = ld->attribs[col] & SGR_MASK; 184#if OPT_PRINT_COLORS 185 last_fg = fg; 186 last_bg = bg; 187#endif 188 if (p->print_attributes) 189 send_SGR(xw, attr, fg, bg); 190 } 191 192 if (ch == 0) 193 ch = ' '; 194 195#if OPT_WIDE_CHARS 196 if (screen->utf8_mode) 197 cs = CSET_IN; 198 else 199#endif 200 cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT; 201 if (last_cs != cs) { 202 if (p->print_attributes) { 203 charToPrinter(xw, 204 (unsigned) ((cs == CSET_OUT) 205 ? SHIFT_OUT 206 : SHIFT_IN)); 207 } 208 last_cs = cs; 209 } 210 211 /* FIXME: we shouldn't have to map back from the 212 * alternate character set, except that the 213 * corresponding charset information is not encoded 214 * into the CSETS array. 215 */ 216 charToPrinter(xw, 217 ((cs == CSET_OUT) 218 ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f)) 219 : ch)); 220 if_OPT_WIDE_CHARS(screen, { 221 size_t off; 222 for_each_combData(off, ld) { 223 ch = ld->combData[off][col]; 224 if (ch == 0) 225 break; 226 charToPrinter(xw, ch); 227 } 228 }); 229 } 230 if (p->print_attributes) { 231 send_SGR(xw, 0, NO_COLOR, NO_COLOR); 232 if (cs != CSET_IN) 233 charToPrinter(xw, SHIFT_IN); 234 } 235 } 236 237 /* finish line (protocol for attributes needs a CR */ 238 if (p->print_attributes) 239 charToPrinter(xw, '\r'); 240 241 if (chr && !(p->printer_newline)) { 242 if (LineTstWrapped(ld)) 243 chr = '\0'; 244 } 245 246 if (chr) 247 charToPrinter(xw, chr); 248 249 return; 250} 251 252#define PrintNewLine() (unsigned) (((top < bot) || p->printer_newline) ? '\n' : '\0') 253 254static void 255printLines(XtermWidget xw, int top, int bot, PrinterFlags *p) 256{ 257 TRACE(("printLines, rows %d..%d\n", top, bot)); 258 while (top <= bot) { 259 printLine(xw, top, PrintNewLine(), p); 260 ++top; 261 } 262} 263 264void 265xtermPrintScreen(XtermWidget xw, Bool use_DECPEX, PrinterFlags *p) 266{ 267 if (XtIsRealized((Widget) xw)) { 268 TScreen *screen = TScreenOf(xw); 269 Bool extent = (use_DECPEX && p->printer_extent); 270 Boolean was_open = SPS.isOpen; 271 272 printLines(xw, 273 extent ? 0 : screen->top_marg, 274 extent ? screen->max_row : screen->bot_marg, 275 p); 276 if (p->printer_formfeed) 277 charToPrinter(xw, '\f'); 278 279 if (!was_open || SPS.printer_autoclose) { 280 closePrinter(xw); 281 } 282 } else { 283 Bell(xw, XkbBI_MinorError, 0); 284 } 285} 286 287/* 288 * If p->print_everything is zero, use this behavior: 289 * If the alternate screen is active, we'll print only that. Otherwise, print 290 * the normal screen plus all scrolled-back lines. The distinction is made 291 * because the normal screen's buffer is part of the overall scrollback buffer. 292 * 293 * Otherwise, decode bits: 294 * 1 = current screen 295 * 2 = normal screen 296 * 4 = alternate screen 297 * 8 = saved lines 298 */ 299void 300xtermPrintEverything(XtermWidget xw, PrinterFlags *p) 301{ 302 TScreen *screen = TScreenOf(xw); 303 Boolean was_open = SPS.isOpen; 304 int save_which = screen->whichBuf; 305 int done_which = 0; 306 307 DEBUG_MSG("xtermPrintEverything\n"); 308 if (p->print_everything) { 309 if (p->print_everything & 8) { 310 printLines(xw, -screen->savedlines, -(screen->topline + 1), p); 311 } 312 if (p->print_everything & 4) { 313 screen->whichBuf = 1; 314 done_which |= 2; 315 printLines(xw, 0, screen->max_row, p); 316 screen->whichBuf = save_which; 317 } 318 if (p->print_everything & 2) { 319 screen->whichBuf = 0; 320 done_which |= 1; 321 printLines(xw, 0, screen->max_row, p); 322 screen->whichBuf = save_which; 323 } 324 if (p->print_everything & 1) { 325 if (!(done_which & (1 << screen->whichBuf))) { 326 printLines(xw, 0, screen->max_row, p); 327 } 328 } 329 } else { 330 int top = 0; 331 int bot = screen->max_row; 332 if (!screen->whichBuf) { 333 top = -screen->savedlines - screen->topline; 334 bot -= screen->topline; 335 } 336 printLines(xw, top, bot, p); 337 } 338 if (p->printer_formfeed) 339 charToPrinter(xw, '\f'); 340 341 if (!was_open || SPS.printer_autoclose) { 342 closePrinter(xw); 343 } 344} 345 346static void 347send_CharSet(XtermWidget xw, LineData *ld) 348{ 349#if OPT_DEC_CHRSET 350 const char *msg = 0; 351 352 switch (GetLineDblCS(ld)) { 353 case CSET_SWL: 354 msg = "\033#5"; 355 break; 356 case CSET_DHL_TOP: 357 msg = "\033#3"; 358 break; 359 case CSET_DHL_BOT: 360 msg = "\033#4"; 361 break; 362 case CSET_DWL: 363 msg = "\033#6"; 364 break; 365 } 366 if (msg != 0) 367 stringToPrinter(xw, msg); 368#else 369 (void) xw; 370 (void) ld; 371#endif /* OPT_DEC_CHRSET */ 372} 373 374static void 375send_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg) 376{ 377 char msg[80]; 378 379 strcpy(msg, "\033[0"); 380 if (attr & BOLD) 381 strcat(msg, ";1"); 382#if OPT_WIDE_ATTRS 383 if (attr & ATR_FAINT) 384 strcat(msg, ";2"); 385 if (attr & ATR_ITALIC) 386 strcat(msg, ";3"); 387#endif 388 if (attr & UNDERLINE) 389 strcat(msg, ";4"); /* typo? DEC documents this as '2' */ 390 if (attr & BLINK) 391 strcat(msg, ";5"); 392 if (attr & INVERSE) /* typo? DEC documents this as invisible */ 393 strcat(msg, ";7"); 394#if OPT_PRINT_COLORS 395 if (bg != NO_COLOR) { 396 sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg)); 397 } 398 if (fg != NO_COLOR) { 399#if OPT_PC_COLORS 400 if (TScreenOf(xw)->boldColors 401 && fg > 8 402 && (attr & BOLD) != 0) 403 fg -= 8; 404#endif 405 sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg)); 406 } 407#else 408 (void) bg; 409 (void) fg; 410#endif 411 strcat(msg, "m"); 412 stringToPrinter(xw, msg); 413} 414 415/* 416 * This implementation only knows how to write to a pipe. 417 */ 418static void 419charToPrinter(XtermWidget xw, unsigned chr) 420{ 421 TScreen *screen = TScreenOf(xw); 422 423 if (!SPS.isOpen && xtermHasPrinter(xw)) { 424 switch (SPS.toFile) { 425 /* 426 * write to a pipe. 427 */ 428 case False: 429#ifdef VMS 430 /* 431 * This implementation only knows how to write to a file. When the 432 * file is closed the print command executes. Print command must 433 * be of the form: 434 * print/que=name/delete [/otherflags]. 435 */ 436 SPS.fp = fopen(VMS_TEMP_PRINT_FILE, "w"); 437#else 438 { 439 FILE *input; 440 int my_pipe[2]; 441 int c; 442 pid_t my_pid; 443 444 if (pipe(my_pipe)) 445 SysError(ERROR_FORK); 446 if ((my_pid = fork()) < 0) 447 SysError(ERROR_FORK); 448 449 if (my_pid == 0) { 450 DEBUG_MSG("charToPrinter: subprocess for printer\n"); 451 TRACE_CLOSE(); 452 close(my_pipe[1]); /* printer is silent */ 453 close(screen->respond); 454 455 close(fileno(stdout)); 456 dup2(fileno(stderr), 1); 457 458 if (fileno(stderr) != 2) { 459 dup2(fileno(stderr), 2); 460 close(fileno(stderr)); 461 } 462 463 /* don't want privileges! */ 464 if (xtermResetIds(screen) < 0) 465 exit(1); 466 467 SPS.fp = popen(SPS.printer_command, "w"); 468 if (SPS.fp != 0) { 469 DEBUG_MSG("charToPrinter: opened pipe to printer\n"); 470 input = fdopen(my_pipe[0], "r"); 471 clearerr(input); 472 for (;;) { 473 if (ferror(input)) { 474 DEBUG_MSG("charToPrinter: break on ferror\n"); 475 break; 476 } else if (feof(input)) { 477 DEBUG_MSG("charToPrinter: break on feof\n"); 478 break; 479 } else if ((c = fgetc(input)) == EOF) { 480 DEBUG_MSG("charToPrinter: break on EOF\n"); 481 break; 482 } 483 fputc(c, SPS.fp); 484 if (isForm(c)) 485 fflush(SPS.fp); 486 } 487 DEBUG_MSG("charToPrinter: calling pclose\n"); 488 pclose(SPS.fp); 489 } 490 exit(0); 491 } else { 492 close(my_pipe[0]); /* won't read from printer */ 493 if ((SPS.fp = fdopen(my_pipe[1], "w")) != 0) { 494 DEBUG_MSG("charToPrinter: opened printer in parent\n"); 495 TRACE(("opened printer from pid %d/%d\n", 496 (int) getpid(), (int) my_pid)); 497 } else { 498 TRACE(("failed to open printer:%s\n", strerror(errno))); 499 DEBUG_MSG("charToPrinter: could not open in parent\n"); 500 } 501 } 502 } 503#endif 504 break; 505 case True: 506 TRACE(("opening \"%s\" as printer output\n", SPS.printer_command)); 507 SPS.fp = fopen(SPS.printer_command, "w"); 508 break; 509 } 510 SPS.isOpen = True; 511 } 512 if (SPS.fp != 0) { 513#if OPT_WIDE_CHARS 514 if (chr > 127) { 515 Char temp[10]; 516 *convertToUTF8(temp, chr) = 0; 517 fputs((char *) temp, SPS.fp); 518 } else 519#endif 520 fputc((int) chr, SPS.fp); 521 if (isForm(chr)) 522 fflush(SPS.fp); 523 } 524} 525 526static void 527stringToPrinter(XtermWidget xw, const char *str) 528{ 529 while (*str) 530 charToPrinter(xw, CharOf(*str++)); 531} 532 533/* 534 * This module implements the MC (Media Copy) and related printing control 535 * sequences for VTxxx emulation. This is based on the description in the 536 * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment 537 * Corp., March 1987). 538 */ 539void 540xtermMediaControl(XtermWidget xw, int param, int private_seq) 541{ 542 TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq)); 543 544 if (private_seq) { 545 switch (param) { 546 case 1: 547 printCursorLine(xw); 548 break; 549 case 4: 550 setPrinterControlMode(xw, 0); 551 break; 552 case 5: 553 setPrinterControlMode(xw, 1); 554 break; 555 case 10: /* VT320 */ 556 xtermPrintScreen(xw, False, getPrinterFlags(xw, NULL, 0)); 557 break; 558 case 11: /* VT320 */ 559 xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 560 break; 561 } 562 } else { 563 switch (param) { 564 case -1: 565 case 0: 566 xtermPrintScreen(xw, True, getPrinterFlags(xw, NULL, 0)); 567 break; 568 case 4: 569 setPrinterControlMode(xw, 0); 570 break; 571 case 5: 572 setPrinterControlMode(xw, 2); 573 break; 574 } 575 } 576} 577 578/* 579 * When in autoprint mode, the printer prints a line from the screen when you 580 * move the cursor off that line with an LF, FF, or VT character, or an 581 * autowrap occurs. The printed line ends with a CR and the character (LF, FF 582 * or VT) that moved the cursor off the previous line. 583 */ 584void 585xtermAutoPrint(XtermWidget xw, unsigned chr) 586{ 587 TScreen *screen = TScreenOf(xw); 588 589 if (SPS.printer_controlmode == 1) { 590 TRACE(("AutoPrint %d\n", chr)); 591 printLine(xw, screen->cursorp.row, chr, getPrinterFlags(xw, NULL, 0)); 592 if (SPS.fp != 0) 593 fflush(SPS.fp); 594 } 595} 596 597/* 598 * When in printer controller mode, the terminal sends received characters to 599 * the printer without displaying them on the screen. The terminal sends all 600 * characters and control sequences to the printer, except NUL, XON, XOFF, and 601 * the printer controller sequences. 602 * 603 * This function eats characters, returning 0 as long as it must buffer or 604 * divert to the printer. We're only invoked here when in printer controller 605 * mode, and handle the exit from that mode. 606 */ 607#define LB '[' 608 609int 610xtermPrinterControl(XtermWidget xw, int chr) 611{ 612 TScreen *screen = TScreenOf(xw); 613 /* *INDENT-OFF* */ 614 static const struct { 615 const Char seq[5]; 616 int active; 617 } tbl[] = { 618 { { ANSI_CSI, '5', 'i' }, 2 }, 619 { { ANSI_CSI, '4', 'i' }, 0 }, 620 { { ANSI_ESC, LB, '5', 'i' }, 2 }, 621 { { ANSI_ESC, LB, '4', 'i' }, 0 }, 622 }; 623 /* *INDENT-ON* */ 624 625 static Char bfr[10]; 626 static size_t length; 627 size_t n; 628 629 TRACE(("In printer:%04X\n", chr)); 630 631 switch (chr) { 632 case 0: 633 case CTRL('Q'): 634 case CTRL('S'): 635 return 0; /* ignored by application */ 636 637 case ANSI_CSI: 638 case ANSI_ESC: 639 case '[': 640 case '4': 641 case '5': 642 case 'i': 643 bfr[length++] = CharOf(chr); 644 for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) { 645 size_t len = Strlen(tbl[n].seq); 646 647 if (length == len 648 && Strcmp(bfr, tbl[n].seq) == 0) { 649 setPrinterControlMode(xw, tbl[n].active); 650 if (SPS.printer_autoclose 651 && SPS.printer_controlmode == 0) 652 closePrinter(xw); 653 length = 0; 654 return 0; 655 } else if (len > length 656 && Strncmp(bfr, tbl[n].seq, length) == 0) { 657 return 0; 658 } 659 } 660 length--; 661 662 /* FALLTHRU */ 663 664 default: 665 for (n = 0; n < length; n++) 666 charToPrinter(xw, bfr[n]); 667 bfr[0] = CharOf(chr); 668 length = 1; 669 return 0; 670 } 671} 672 673/* 674 * If there is no printer command, we will ignore printer controls. 675 * 676 * If we do have a printer command, we still have to verify that it will 677 * (perhaps) work if we pass it to popen(). At a minimum, the program 678 * must exist and be executable. If not, warn and disable the feature. 679 */ 680Bool 681xtermHasPrinter(XtermWidget xw) 682{ 683 TScreen *screen = TScreenOf(xw); 684 Bool result = SPS.printer_checked; 685 686 if (strlen(SPS.printer_command) != 0 && !result) { 687 char **argv = x_splitargs(SPS.printer_command); 688 if (argv) { 689 if (argv[0]) { 690 char *myShell = xtermFindShell(argv[0], False); 691 if (myShell == 0) { 692 xtermWarning("No program found for printerCommand: %s\n", SPS.printer_command); 693 SPS.printer_command = x_strdup(""); 694 } else { 695 free(myShell); 696 SPS.printer_checked = True; 697 result = True; 698 } 699 } 700 x_freeargs(argv); 701 } 702 TRACE(("xtermHasPrinter:%d\n", result)); 703 } 704 705 return result; 706} 707 708#define showPrinterControlMode(mode) \ 709 (((mode) == 0) \ 710 ? "normal" \ 711 : ((mode) == 1 \ 712 ? "autoprint" \ 713 : "printer controller")) 714 715void 716setPrinterControlMode(XtermWidget xw, int mode) 717{ 718 TScreen *screen = TScreenOf(xw); 719 720 if (xtermHasPrinter(xw) 721 && SPS.printer_controlmode != mode) { 722 TRACE(("%s %s mode\n", 723 (mode 724 ? "set" 725 : "reset"), 726 (mode 727 ? showPrinterControlMode(mode) 728 : showPrinterControlMode(SPS.printer_controlmode)))); 729 SPS.printer_controlmode = mode; 730 update_print_redir(); 731 } 732} 733 734PrinterFlags * 735getPrinterFlags(XtermWidget xw, String *params, Cardinal *param_count) 736{ 737 /* *INDENT-OFF* */ 738 static const struct { 739 const char *name; 740 unsigned offset; 741 int value; 742 } table[] = { 743 { "noFormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 0 }, 744 { "FormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 1 }, 745 { "noNewLine", XtOffsetOf(PrinterFlags, printer_newline), 0 }, 746 { "NewLine", XtOffsetOf(PrinterFlags, printer_newline), 1 }, 747 { "noAttrs", XtOffsetOf(PrinterFlags, print_attributes), 0 }, 748 { "monoAttrs", XtOffsetOf(PrinterFlags, print_attributes), 1 }, 749 { "colorAttrs", XtOffsetOf(PrinterFlags, print_attributes), 2 }, 750 }; 751 /* *INDENT-ON* */ 752 753 TScreen *screen = TScreenOf(xw); 754 PrinterFlags *result = &(screen->printer_flags); 755 756 TRACE(("getPrinterFlags %d params\n", param_count ? *param_count : 0)); 757 758 result->printer_extent = SPS.printer_extent; 759 result->printer_formfeed = SPS.printer_formfeed; 760 result->printer_newline = SPS.printer_newline; 761 result->print_attributes = SPS.print_attributes; 762 result->print_everything = SPS.print_everything; 763 764 if (param_count != 0 && *param_count != 0) { 765 Cardinal j; 766 unsigned k; 767 for (j = 0; j < *param_count; ++j) { 768 TRACE(("param%d:%s\n", j, params[j])); 769 for (k = 0; k < XtNumber(table); ++k) { 770 if (!x_strcasecmp(params[j], table[k].name)) { 771 int *ptr = (int *) (void *) ((char *) result + table[k].offset); 772 TRACE(("...PrinterFlags(%s) %d->%d\n", 773 table[k].name, 774 *ptr, 775 table[k].value)); 776 *ptr = table[k].value; 777 break; 778 } 779 } 780 } 781 } 782 783 return result; 784} 785 786/* 787 * Print a timestamped copy of everything. 788 */ 789void 790xtermPrintImmediately(XtermWidget xw, String filename, int opts, int attrs) 791{ 792 TScreen *screen = TScreenOf(xw); 793 PrinterState save_state = screen->printer_state; 794 char *my_filename = malloc(TIMESTAMP_LEN + strlen(filename)); 795 796 if (my_filename != 0) { 797 unsigned save_umask = umask(0177); 798 799 timestamp_filename(my_filename, filename); 800 SPS.fp = 0; 801 SPS.isOpen = False; 802 SPS.toFile = True; 803 SPS.printer_command = my_filename; 804 SPS.printer_autoclose = True; 805 SPS.printer_formfeed = False; 806 SPS.printer_newline = True; 807 SPS.print_attributes = attrs; 808 SPS.print_everything = opts; 809 xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0)); 810 811 umask(save_umask); 812 screen->printer_state = save_state; 813 } 814} 815 816void 817xtermPrintOnXError(XtermWidget xw, int n) 818{ 819#if OPT_PRINT_ON_EXIT 820 /* 821 * The user may have requested that the contents of the screen will be 822 * written to a file if an X error occurs. 823 */ 824 if (TScreenOf(xw)->write_error && !IsEmpty(resource.printFileOnXError)) { 825 Boolean printIt = False; 826 827 switch (n) { 828 case ERROR_XERROR: 829 /* FALLTHRU */ 830 case ERROR_XIOERROR: 831 /* FALLTHRU */ 832 case ERROR_ICEERROR: 833 printIt = True; 834 break; 835 } 836 837 if (printIt) { 838 xtermPrintImmediately(xw, 839 resource.printFileOnXError, 840 resource.printOptsOnXError, 841 resource.printModeOnXError); 842 } 843 } 844#else 845 (void) xw; 846 (void) n; 847#endif 848} 849