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