Edit

IABSD.fr/xenocara/app/xterm/print.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2013-03-09 14:45:38
    Hash : a232c777
    Message : Update to xterm 291. Tested by many.

  • app/xterm/print.c
  • /* $XTermId: print.c,v 1.149 2012/12/31 13:58:16 tom Exp $ */
    
    /*
     * Copyright 1997-2011,2012 by Thomas E. Dickey
     *
     *                         All Rights Reserved
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the
     * "Software"), to deal in the Software without restriction, including
     * without limitation the rights to use, copy, modify, merge, publish,
     * distribute, sublicense, and/or sell copies of the Software, and to
     * permit persons to whom the Software is furnished to do so, subject to
     * the following conditions:
     *
     * The above copyright notice and this permission notice shall be included
     * in all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
     * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     *
     * Except as contained in this notice, the name(s) of the above copyright
     * holders shall not be used in advertising or otherwise to promote the
     * sale, use or other dealings in this Software without prior written
     * authorization.
     */
    
    #include <xterm.h>
    #include <data.h>
    #include <menu.h>
    #include <error.h>
    #include <xstrings.h>
    
    #include <stdio.h>
    #include <sys/stat.h>
    
    #undef  CTRL
    #define	CTRL(c)	((c) & 0x1f)
    
    #define SHIFT_IN  '\017'
    #define SHIFT_OUT '\016'
    
    #define CSET_IN   'A'
    #define CSET_OUT  '0'
    
    #define isForm(c)      ((c) == '\r' || (c) == '\n' || (c) == '\f')
    #define Strlen(a)      strlen((const char *)a)
    #define Strcmp(a,b)    strcmp((const char *)a,(const char *)b)
    #define Strncmp(a,b,c) strncmp((const char *)a,(const char *)b,c)
    
    #define SPS PrinterOf(screen)
    
    #ifdef VMS
    #define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt"
    #endif
    
    static void charToPrinter(XtermWidget /* xw */ ,
    			  unsigned /* chr */ );
    static void printLine(XtermWidget /* xw */ ,
    		      int /* row */ ,
    		      unsigned /* chr */ ,
    		      PrinterFlags * /* p */ );
    static void send_CharSet(XtermWidget /* xw */ ,
    			 LineData * /* ld */ );
    static void send_SGR(XtermWidget /* xw */ ,
    		     unsigned /* attr */ ,
    		     unsigned /* fg */ ,
    		     unsigned /* bg */ );
    static void stringToPrinter(XtermWidget /* xw */ ,
    			    const char * /*str */ );
    
    static void
    closePrinter(XtermWidget xw GCC_UNUSED)
    {
        if (xtermHasPrinter(xw) != 0) {
    	TScreen *screen = TScreenOf(xw);
    #ifdef VMS
    	char pcommand[256];
    	(void) sprintf(pcommand, "%s %s;",
    		       SPS.printer_command,
    		       VMS_TEMP_PRINT_FILE);
    #endif
    
    	if (SPS.fp != 0) {
    	    pclose(SPS.fp);
    	    TRACE(("closed printer, waiting...\n"));
    #ifdef VMS			/* This is a quick hack, really should use
    				   spawn and check status or system services
    				   and go straight to the queue */
    	    (void) system(pcommand);
    #else /* VMS */
    	    while (nonblocking_wait() > 0) ;
    #endif /* VMS */
    	    SPS.fp = 0;
    	    SPS.isOpen = False;
    	    TRACE(("closed printer\n"));
    	}
        }
    }
    
    static void
    printCursorLine(XtermWidget xw)
    {
        TScreen *screen = TScreenOf(xw);
    
        TRACE(("printCursorLine\n"));
        printLine(xw, screen->cur_row, '\n', getPrinterFlags(xw, NULL, 0));
    }
    
    #define NO_COLOR	((unsigned)-1)
    
    /*
     * DEC's manual doesn't document whether trailing blanks are removed, or what
     * happens with a line that is entirely blank.  This function prints the
     * characters that xterm would allow as a selection (which may include blanks).
     */
    static void
    printLine(XtermWidget xw, int row, unsigned chr, PrinterFlags * p)
    {
        TScreen *screen = TScreenOf(xw);
        int inx = ROW2INX(screen, row);
        LineData *ld;
        Char attr = 0;
        unsigned ch;
        int last = MaxCols(screen);
        int col;
    #if OPT_ISO_COLORS && OPT_PRINT_COLORS
    #define ColorOf(ld,col) (ld->color[col])
    #endif
        unsigned fg = NO_COLOR, last_fg = NO_COLOR;
        unsigned bg = NO_COLOR, last_bg = NO_COLOR;
        int cs = CSET_IN;
        int last_cs = CSET_IN;
    
        ld = getLineData(screen, inx);
        if (ld == 0)
    	return;
    
        TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n",
    	   row, ROW2INX(screen, row), screen->topline, screen->max_row, chr,
    	   visibleIChars(ld->charData, (unsigned) last)));
    
        while (last > 0) {
    	if ((ld->attribs[last - 1] & CHARDRAWN) == 0)
    	    last--;
    	else
    	    break;
        }
        if (last) {
    	if (p->print_attributes) {
    	    send_CharSet(xw, ld);
    	    send_SGR(xw, 0, NO_COLOR, NO_COLOR);
    	}
    	for (col = 0; col < last; col++) {
    	    ch = ld->charData[col];
    #if OPT_PRINT_COLORS
    	    if (screen->colorMode) {
    		if (p->print_attributes > 1) {
    		    fg = (ld->attribs[col] & FG_COLOR)
    			? extract_fg(xw, ColorOf(ld, col), ld->attribs[col])
    			: NO_COLOR;
    		    bg = (ld->attribs[col] & BG_COLOR)
    			? extract_bg(xw, ColorOf(ld, col), ld->attribs[col])
    			: NO_COLOR;
    		}
    	    }
    #endif
    	    if ((((ld->attribs[col] & SGR_MASK) != attr)
    #if OPT_PRINT_COLORS
    		 || (last_fg != fg) || (last_bg != bg)
    #endif
    		)
    		&& ch) {
    		attr = CharOf(ld->attribs[col] & SGR_MASK);
    #if OPT_PRINT_COLORS
    		last_fg = fg;
    		last_bg = bg;
    #endif
    		if (p->print_attributes)
    		    send_SGR(xw, attr, fg, bg);
    	    }
    
    	    if (ch == 0)
    		ch = ' ';
    
    #if OPT_WIDE_CHARS
    	    if (screen->utf8_mode)
    		cs = CSET_IN;
    	    else
    #endif
    		cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT;
    	    if (last_cs != cs) {
    		if (p->print_attributes) {
    		    charToPrinter(xw,
    				  (unsigned) ((cs == CSET_OUT)
    					      ? SHIFT_OUT
    					      : SHIFT_IN));
    		}
    		last_cs = cs;
    	    }
    
    	    /* FIXME:  we shouldn't have to map back from the
    	     * alternate character set, except that the
    	     * corresponding charset information is not encoded
    	     * into the CSETS array.
    	     */
    	    charToPrinter(xw,
    			  ((cs == CSET_OUT)
    			   ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f))
    			   : ch));
    	    if_OPT_WIDE_CHARS(screen, {
    		size_t off;
    		for_each_combData(off, ld) {
    		    ch = ld->combData[off][col];
    		    if (ch == 0)
    			break;
    		    charToPrinter(xw, ch);
    		}
    	    });
    	}
    	if (p->print_attributes) {
    	    send_SGR(xw, 0, NO_COLOR, NO_COLOR);
    	    if (cs != CSET_IN)
    		charToPrinter(xw, SHIFT_IN);
    	}
        }
    
        /* finish line (protocol for attributes needs a CR */
        if (p->print_attributes)
    	charToPrinter(xw, '\r');
    
        if (chr && !(p->printer_newline)) {
    	if (LineTstWrapped(ld))
    	    chr = '\0';
        }
    
        if (chr)
    	charToPrinter(xw, chr);
    
        return;
    }
    
    #define PrintNewLine() (unsigned) (((top < bot) || p->printer_newline) ? '\n' : '\0')
    
    static void
    printLines(XtermWidget xw, int top, int bot, PrinterFlags * p)
    {
        TRACE(("printLines, rows %d..%d\n", top, bot));
        while (top <= bot) {
    	printLine(xw, top, PrintNewLine(), p);
    	++top;
        }
    }
    
    void
    xtermPrintScreen(XtermWidget xw, Bool use_DECPEX, PrinterFlags * p)
    {
        if (XtIsRealized((Widget) xw)) {
    	TScreen *screen = TScreenOf(xw);
    	Bool extent = (use_DECPEX && p->printer_extent);
    	Boolean was_open = SPS.isOpen;
    
    	printLines(xw,
    		   extent ? 0 : screen->top_marg,
    		   extent ? screen->max_row : screen->bot_marg,
    		   p);
    	if (p->printer_formfeed)
    	    charToPrinter(xw, '\f');
    
    	if (!was_open || SPS.printer_autoclose) {
    	    closePrinter(xw);
    	}
        } else {
    	Bell(xw, XkbBI_MinorError, 0);
        }
    }
    
    /*
     * If p->print_everything is zero, use this behavior:
     * If the alternate screen is active, we'll print only that.  Otherwise, print
     * the normal screen plus all scrolled-back lines.  The distinction is made
     * because the normal screen's buffer is part of the overall scrollback buffer.
     *
     * Otherwise, decode bits:
     *	1 = current screen
     *	2 = normal screen
     *	4 = alternate screen
     *	8 = saved lines
     */
    void
    xtermPrintEverything(XtermWidget xw, PrinterFlags * p)
    {
        TScreen *screen = TScreenOf(xw);
        Boolean was_open = SPS.isOpen;
        int save_which = screen->whichBuf;
        int done_which = 0;
    
        if (p->print_everything) {
    	if (p->print_everything & 8) {
    	    printLines(xw, -screen->savedlines, -(screen->topline + 1), p);
    	}
    	if (p->print_everything & 4) {
    	    screen->whichBuf = 1;
    	    done_which |= 2;
    	    printLines(xw, 0, screen->max_row, p);
    	    screen->whichBuf = save_which;
    	}
    	if (p->print_everything & 2) {
    	    screen->whichBuf = 0;
    	    done_which |= 1;
    	    printLines(xw, 0, screen->max_row, p);
    	    screen->whichBuf = save_which;
    	}
    	if (p->print_everything & 1) {
    	    if (!(done_which & (1 << screen->whichBuf))) {
    		printLines(xw, 0, screen->max_row, p);
    	    }
    	}
        } else {
    	int top = 0;
    	int bot = screen->max_row;
    	if (!screen->whichBuf) {
    	    top = -screen->savedlines - screen->topline;
    	    bot -= screen->topline;
    	}
    	printLines(xw, top, bot, p);
        }
        if (p->printer_formfeed)
    	charToPrinter(xw, '\f');
    
        if (!was_open || SPS.printer_autoclose) {
    	closePrinter(xw);
        }
    }
    
    static void
    send_CharSet(XtermWidget xw, LineData * ld)
    {
    #if OPT_DEC_CHRSET
        const char *msg = 0;
    
        switch (GetLineDblCS(ld)) {
        case CSET_SWL:
    	msg = "\033#5";
    	break;
        case CSET_DHL_TOP:
    	msg = "\033#3";
    	break;
        case CSET_DHL_BOT:
    	msg = "\033#4";
    	break;
        case CSET_DWL:
    	msg = "\033#6";
    	break;
        }
        if (msg != 0)
    	stringToPrinter(xw, msg);
    #else
        (void) xw;
        (void) ld;
    #endif /* OPT_DEC_CHRSET */
    }
    
    static void
    send_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg)
    {
        char msg[80];
    
        strcpy(msg, "\033[0");
        if (attr & BOLD)
    	strcat(msg, ";1");
        if (attr & UNDERLINE)
    	strcat(msg, ";4");	/* typo? DEC documents this as '2' */
        if (attr & BLINK)
    	strcat(msg, ";5");
        if (attr & INVERSE)		/* typo? DEC documents this as invisible */
    	strcat(msg, ";7");
    #if OPT_PRINT_COLORS
        if (bg != NO_COLOR) {
    	sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg));
        }
        if (fg != NO_COLOR) {
    #if OPT_PC_COLORS
    	if (TScreenOf(xw)->boldColors
    	    && fg > 8
    	    && (attr & BOLD) != 0)
    	    fg -= 8;
    #endif
    	sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg));
        }
    #else
        (void) bg;
        (void) fg;
    #endif
        strcat(msg, "m");
        stringToPrinter(xw, msg);
    }
    
    /*
     * This implementation only knows how to write to a pipe.
     */
    static void
    charToPrinter(XtermWidget xw, unsigned chr)
    {
        TScreen *screen = TScreenOf(xw);
    
        if (!SPS.isOpen && xtermHasPrinter(xw)) {
    	switch (SPS.toFile) {
    	    /*
    	     * write to a pipe.
    	     */
    	case False:
    #ifdef VMS
    	    /*
    	     * This implementation only knows how to write to a file.  When the
    	     * file is closed the print command executes.  Print command must
    	     * be of the form:
    	     *   print/que=name/delete [/otherflags].
    	     */
    	    SPS.fp = fopen(VMS_TEMP_PRINT_FILE, "w");
    #else
    	    {
    		FILE *input;
    		int my_pipe[2];
    		int c;
    		pid_t my_pid;
    
    		if (pipe(my_pipe))
    		    SysError(ERROR_FORK);
    		if ((my_pid = fork()) < 0)
    		    SysError(ERROR_FORK);
    
    		if (my_pid == 0) {
    		    TRACE_CLOSE();
    		    (void) signal(SIGCHLD, SIG_DFL);	/* no reapchild! */
    		    close(my_pipe[1]);	/* printer is silent */
    		    close(screen->respond);
    
    		    close(fileno(stdout));
    		    dup2(fileno(stderr), 1);
    
    		    if (fileno(stderr) != 2) {
    			dup2(fileno(stderr), 2);
    			close(fileno(stderr));
    		    }
    
    		    /* don't want privileges! */
    		    if (xtermResetIds(screen) < 0)
    			exit(1);
    
    		    SPS.fp = popen(SPS.printer_command, "w");
    		    if (SPS.fp != 0) {
    			input = fdopen(my_pipe[0], "r");
    			clearerr(input);
    			while (!ferror(input) && !feof(input)) {
    			    if ((c = fgetc(input)) == EOF)
    				break;
    			    fputc(c, SPS.fp);
    			    if (isForm(c))
    				fflush(SPS.fp);
    			}
    			pclose(SPS.fp);
    		    }
    		    exit(0);
    		} else {
    		    close(my_pipe[0]);	/* won't read from printer */
    		    SPS.fp = fdopen(my_pipe[1], "w");
    		    TRACE(("opened printer from pid %d/%d\n",
    			   (int) getpid(), (int) my_pid));
    		}
    	    }
    #endif
    	    break;
    	case True:
    	    TRACE(("opening \"%s\" as printer output\n", SPS.printer_command));
    	    SPS.fp = fopen(SPS.printer_command, "w");
    	    break;
    	}
    	SPS.isOpen = True;
        }
        if (SPS.fp != 0) {
    #if OPT_WIDE_CHARS
    	if (chr > 127) {
    	    Char temp[10];
    	    *convertToUTF8(temp, chr) = 0;
    	    fputs((char *) temp, SPS.fp);
    	} else
    #endif
    	    fputc((int) chr, SPS.fp);
    	if (isForm(chr))
    	    fflush(SPS.fp);
        }
    }
    
    static void
    stringToPrinter(XtermWidget xw, const char *str)
    {
        while (*str)
    	charToPrinter(xw, CharOf(*str++));
    }
    
    /*
     * This module implements the MC (Media Copy) and related printing control
     * sequences for VTxxx emulation.  This is based on the description in the
     * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment
     * Corp., March 1987).
     */
    void
    xtermMediaControl(XtermWidget xw, int param, int private_seq)
    {
        TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq));
    
        if (private_seq) {
    	switch (param) {
    	case 1:
    	    printCursorLine(xw);
    	    break;
    	case 4:
    	    setPrinterControlMode(xw, 0);
    	    break;
    	case 5:
    	    setPrinterControlMode(xw, 1);
    	    break;
    	case 10:		/* VT320 */
    	    xtermPrintScreen(xw, False, getPrinterFlags(xw, NULL, 0));
    	    break;
    	case 11:		/* VT320 */
    	    xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0));
    	    break;
    	}
        } else {
    	switch (param) {
    	case -1:
    	case 0:
    	    xtermPrintScreen(xw, True, getPrinterFlags(xw, NULL, 0));
    	    break;
    	case 4:
    	    setPrinterControlMode(xw, 0);
    	    break;
    	case 5:
    	    setPrinterControlMode(xw, 2);
    	    break;
    	}
        }
    }
    
    /*
     * When in autoprint mode, the printer prints a line from the screen when you
     * move the cursor off that line with an LF, FF, or VT character, or an
     * autowrap occurs.  The printed line ends with a CR and the character (LF, FF
     * or VT) that moved the cursor off the previous line.
     */
    void
    xtermAutoPrint(XtermWidget xw, unsigned chr)
    {
        TScreen *screen = TScreenOf(xw);
    
        if (SPS.printer_controlmode == 1) {
    	TRACE(("AutoPrint %d\n", chr));
    	printLine(xw, screen->cursorp.row, chr, getPrinterFlags(xw, NULL, 0));
    	if (SPS.fp != 0)
    	    fflush(SPS.fp);
        }
    }
    
    /*
     * When in printer controller mode, the terminal sends received characters to
     * the printer without displaying them on the screen. The terminal sends all
     * characters and control sequences to the printer, except NUL, XON, XOFF, and
     * the printer controller sequences.
     *
     * This function eats characters, returning 0 as long as it must buffer or
     * divert to the printer.  We're only invoked here when in printer controller
     * mode, and handle the exit from that mode.
     */
    #define LB '['
    
    int
    xtermPrinterControl(XtermWidget xw, int chr)
    {
        TScreen *screen = TScreenOf(xw);
        /* *INDENT-OFF* */
        static const struct {
    	const Char seq[5];
    	int active;
        } tbl[] = {
    	{ { ANSI_CSI, '5', 'i'      }, 2 },
    	{ { ANSI_CSI, '4', 'i'      }, 0 },
    	{ { ANSI_ESC, LB,  '5', 'i' }, 2 },
    	{ { ANSI_ESC, LB,  '4', 'i' }, 0 },
        };
        /* *INDENT-ON* */
    
        static Char bfr[10];
        static size_t length;
        size_t n;
    
        TRACE(("In printer:%04X\n", chr));
    
        switch (chr) {
        case 0:
        case CTRL('Q'):
        case CTRL('S'):
    	return 0;		/* ignored by application */
    
        case ANSI_CSI:
        case ANSI_ESC:
        case '[':
        case '4':
        case '5':
        case 'i':
    	bfr[length++] = CharOf(chr);
    	for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) {
    	    size_t len = Strlen(tbl[n].seq);
    
    	    if (length == len
    		&& Strcmp(bfr, tbl[n].seq) == 0) {
    		setPrinterControlMode(xw, tbl[n].active);
    		if (SPS.printer_autoclose
    		    && SPS.printer_controlmode == 0)
    		    closePrinter(xw);
    		length = 0;
    		return 0;
    	    } else if (len > length
    		       && Strncmp(bfr, tbl[n].seq, length) == 0) {
    		return 0;
    	    }
    	}
    	length--;
    
    	/* FALLTHRU */
    
        default:
    	for (n = 0; n < length; n++)
    	    charToPrinter(xw, bfr[n]);
    	bfr[0] = CharOf(chr);
    	length = 1;
    	return 0;
        }
    }
    
    /*
     * If there is no printer command, we will ignore printer controls.
     *
     * If we do have a printer command, we still have to verify that it will
     * (perhaps) work if we pass it to popen().  At a minimum, the program
     * must exist and be executable.  If not, warn and disable the feature.
     */
    Bool
    xtermHasPrinter(XtermWidget xw)
    {
        TScreen *screen = TScreenOf(xw);
        Bool result = SPS.printer_checked;
    
        if (strlen(SPS.printer_command) != 0 && !result) {
    	char **argv = x_splitargs(SPS.printer_command);
    	if (argv) {
    	    if (argv[0]) {
    		char *myShell = xtermFindShell(argv[0], False);
    		if (myShell == 0) {
    		    xtermWarning("No program found for printerCommand: %s\n", SPS.printer_command);
    		    SPS.printer_command = x_strdup("");
    		} else {
    		    free(myShell);
    		    SPS.printer_checked = True;
    		    result = True;
    		}
    	    }
    	    x_freeargs(argv);
    	}
    	TRACE(("xtermHasPrinter:%d\n", result));
        }
    
        return result;
    }
    
    #define showPrinterControlMode(mode) \
    		(((mode) == 0) \
    		 ? "normal" \
    		 : ((mode) == 1 \
    		    ? "autoprint" \
    		    : "printer controller"))
    
    void
    setPrinterControlMode(XtermWidget xw, int mode)
    {
        TScreen *screen = TScreenOf(xw);
    
        if (xtermHasPrinter(xw)
    	&& SPS.printer_controlmode != mode) {
    	TRACE(("%s %s mode\n",
    	       (mode
    		? "set"
    		: "reset"),
    	       (mode
    		? showPrinterControlMode(mode)
    		: showPrinterControlMode(SPS.printer_controlmode))));
    	SPS.printer_controlmode = mode;
    	update_print_redir();
        }
    }
    
    PrinterFlags *
    getPrinterFlags(XtermWidget xw, String * params, Cardinal *param_count)
    {
        /* *INDENT-OFF* */
        static const struct {
    	const char *name;
    	unsigned    offset;
    	int	    value;
        } table[] = {
    	{ "noFormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 0 },
    	{ "FormFeed",	XtOffsetOf(PrinterFlags, printer_formfeed), 1 },
    	{ "noNewLine",	XtOffsetOf(PrinterFlags, printer_newline),  0 },
    	{ "NewLine",	XtOffsetOf(PrinterFlags, printer_newline),  1 },
    	{ "noAttrs",	XtOffsetOf(PrinterFlags, print_attributes), 0 },
    	{ "monoAttrs",	XtOffsetOf(PrinterFlags, print_attributes), 1 },
    	{ "colorAttrs", XtOffsetOf(PrinterFlags, print_attributes), 2 },
        };
        /* *INDENT-ON* */
    
        TScreen *screen = TScreenOf(xw);
        PrinterFlags *result = &(screen->printer_flags);
    
        TRACE(("getPrinterFlags %d params\n", param_count ? *param_count : 0));
    
        result->printer_extent = SPS.printer_extent;
        result->printer_formfeed = SPS.printer_formfeed;
        result->printer_newline = SPS.printer_newline;
        result->print_attributes = SPS.print_attributes;
        result->print_everything = SPS.print_everything;
    
        if (param_count != 0 && *param_count != 0) {
    	Cardinal j;
    	unsigned k;
    	for (j = 0; j < *param_count; ++j) {
    	    TRACE(("param%d:%s\n", j, params[j]));
    	    for (k = 0; k < XtNumber(table); ++k) {
    		if (!x_strcasecmp(params[j], table[k].name)) {
    		    int *ptr = (int *) (void *) ((char *) result + table[k].offset);
    		    TRACE(("...PrinterFlags(%s) %d->%d\n",
    			   table[k].name,
    			   *ptr,
    			   table[k].value));
    		    *ptr = table[k].value;
    		    break;
    		}
    	    }
    	}
        }
    
        return result;
    }
    
    /*
     * Print a timestamped copy of everything.
     */
    void
    xtermPrintImmediately(XtermWidget xw, String filename, int opts, int attrs)
    {
        TScreen *screen = TScreenOf(xw);
        PrinterState save_state = screen->printer_state;
        char *my_filename = malloc(TIMESTAMP_LEN + strlen(filename));
    
        if (my_filename != 0) {
    	unsigned save_umask = umask(0177);
    
    	timestamp_filename(my_filename, filename);
    	SPS.fp = 0;
    	SPS.isOpen = False;
    	SPS.toFile = True;
    	SPS.printer_command = my_filename;
    	SPS.printer_autoclose = True;
    	SPS.printer_formfeed = False;
    	SPS.printer_newline = True;
    	SPS.print_attributes = attrs;
    	SPS.print_everything = opts;
    	xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0));
    
    	umask(save_umask);
    	screen->printer_state = save_state;
        }
    }
    
    void
    xtermPrintOnXError(XtermWidget xw, int n)
    {
    #if OPT_PRINT_ON_EXIT
        /*
         * The user may have requested that the contents of the screen will be
         * written to a file if an X error occurs.
         */
        if (TScreenOf(xw)->write_error && !IsEmpty(resource.printFileOnXError)) {
    	Boolean printIt = False;
    
    	switch (n) {
    	case ERROR_XERROR:
    	    /* FALLTHRU */
    	case ERROR_XIOERROR:
    	    /* FALLTHRU */
    	case ERROR_ICEERROR:
    	    printIt = True;
    	    break;
    	}
    
    	if (printIt) {
    	    xtermPrintImmediately(xw,
    				  resource.printFileOnXError,
    				  resource.printOptsOnXError,
    				  resource.printModeOnXError);
    	}
        }
    #else
        (void) xw;
        (void) n;
    #endif
    }