print.c revision 956cc18d
1956cc18dSsnj/* $XTermId: print.c,v 1.109 2009/09/10 09:06:30 tom Exp $ */
2d522f475Smrg
3d522f475Smrg/************************************************************
4d522f475Smrg
54e40088cSchristosCopyright 1997-2007,2009 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>
39d522f475Smrg
40d522f475Smrg#include <stdio.h>
41d522f475Smrg
42d522f475Smrg#undef  CTRL
43d522f475Smrg#define	CTRL(c)	((c) & 0x1f)
44d522f475Smrg
45d522f475Smrg#define SHIFT_IN  '\017'
46d522f475Smrg#define SHIFT_OUT '\016'
47d522f475Smrg
48d522f475Smrg#define CSET_IN   'A'
49d522f475Smrg#define CSET_OUT  '0'
50d522f475Smrg
51d522f475Smrg#define isForm(c)      ((c) == '\r' || (c) == '\n' || (c) == '\f')
52d522f475Smrg#define Strlen(a)      strlen((char *)a)
53d522f475Smrg#define Strcmp(a,b)    strcmp((char *)a,(char *)b)
54d522f475Smrg#define Strncmp(a,b,c) strncmp((char *)a,(char *)b,c)
55d522f475Smrg
56d522f475Smrg#ifdef VMS
57d522f475Smrg#define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt"
58d522f475Smrg#endif
59d522f475Smrg
60956cc18dSsnjstatic void charToPrinter(XtermWidget /* xw */ ,
61956cc18dSsnj			  unsigned /* chr */ );
62956cc18dSsnjstatic void printLine(XtermWidget /* xw */ ,
63956cc18dSsnj		      int /* row */ ,
64956cc18dSsnj		      unsigned /* chr */ );
65956cc18dSsnjstatic void send_CharSet(XtermWidget /* xw */ ,
66956cc18dSsnj			 LineData * /* ld */ );
67956cc18dSsnjstatic void send_SGR(XtermWidget /* xw */ ,
68956cc18dSsnj		     unsigned /* attr */ ,
69956cc18dSsnj		     unsigned /* fg */ ,
70956cc18dSsnj		     unsigned /* bg */ );
71956cc18dSsnjstatic void stringToPrinter(XtermWidget /* xw */ ,
72956cc18dSsnj			    char * /*str */ );
73d522f475Smrg
74d522f475Smrgstatic FILE *Printer;
75d522f475Smrgstatic pid_t Printer_pid;
76d522f475Smrgstatic int initialized;
77d522f475Smrg
78d522f475Smrgstatic void
79956cc18dSsnjclosePrinter(XtermWidget xw GCC_UNUSED)
80d522f475Smrg{
81956cc18dSsnj    if (xtermHasPrinter(xw) != 0) {
82d522f475Smrg#ifdef VMS
83956cc18dSsnj	TScreen *screen = TScreenOf(xw);
84d522f475Smrg
85d522f475Smrg	char pcommand[256];
86d522f475Smrg	(void) sprintf(pcommand, "%s %s;",
87d522f475Smrg		       screen->printer_command,
88d522f475Smrg		       VMS_TEMP_PRINT_FILE);
89d522f475Smrg#endif
90d522f475Smrg
91d522f475Smrg	if (Printer != 0) {
92d522f475Smrg	    fclose(Printer);
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		;
102d522f475Smrg	    Printer = 0;
103d522f475Smrg	    initialized = 0;
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"));
115956cc18dSsnj    printLine(xw, screen->cur_row, '\n');
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
126956cc18dSsnjprintLine(XtermWidget xw, int row, unsigned chr)
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    CellColor *fb = 0;
137956cc18dSsnj#define ColorOf(ld,col) (ld->color[col])
138d522f475Smrg#endif
139d522f475Smrg    unsigned fg = NO_COLOR, last_fg = NO_COLOR;
140d522f475Smrg    unsigned bg = NO_COLOR, last_bg = NO_COLOR;
141d522f475Smrg    int cs = CSET_IN;
142d522f475Smrg    int last_cs = CSET_IN;
143d522f475Smrg
144956cc18dSsnj    ld = getLineData(screen, inx);
145d522f475Smrg    TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n",
146d522f475Smrg	   row, ROW2INX(screen, row), screen->topline, screen->max_row, chr,
147956cc18dSsnj	   visibleIChars(ld->charData, (unsigned) last)));
148956cc18dSsnj
149956cc18dSsnj    if_OPT_ISO_COLORS(screen, {
150956cc18dSsnj	fb = ld->color;
151d522f475Smrg    });
152d522f475Smrg    while (last > 0) {
153956cc18dSsnj	if ((ld->attribs[last - 1] & CHARDRAWN) == 0)
154d522f475Smrg	    last--;
155d522f475Smrg	else
156d522f475Smrg	    break;
157d522f475Smrg    }
158d522f475Smrg    if (last) {
159d522f475Smrg	if (screen->print_attributes) {
160956cc18dSsnj	    send_CharSet(xw, ld);
161956cc18dSsnj	    send_SGR(xw, 0, NO_COLOR, NO_COLOR);
162d522f475Smrg	}
163d522f475Smrg	for (col = 0; col < last; col++) {
164956cc18dSsnj	    ch = ld->charData[col];
165d522f475Smrg#if OPT_PRINT_COLORS
166d522f475Smrg	    if (screen->colorMode) {
167d522f475Smrg		if (screen->print_attributes > 1) {
168956cc18dSsnj		    fg = (ld->attribs[col] & FG_COLOR)
169956cc18dSsnj			? extract_fg(xw, ColorOf(ld, col), ld->attribs[col])
170d522f475Smrg			: NO_COLOR;
171956cc18dSsnj		    bg = (ld->attribs[col] & BG_COLOR)
172956cc18dSsnj			? extract_bg(xw, ColorOf(ld, col), ld->attribs[col])
173d522f475Smrg			: NO_COLOR;
174d522f475Smrg		}
175d522f475Smrg	    }
176d522f475Smrg#endif
177956cc18dSsnj	    if ((((ld->attribs[col] & SGR_MASK) != attr)
178d522f475Smrg#if OPT_PRINT_COLORS
179d522f475Smrg		 || (last_fg != fg) || (last_bg != bg)
180d522f475Smrg#endif
181d522f475Smrg		)
182d522f475Smrg		&& ch) {
183956cc18dSsnj		attr = CharOf(ld->attribs[col] & SGR_MASK);
184d522f475Smrg		last_fg = fg;
185d522f475Smrg		last_bg = bg;
186d522f475Smrg		if (screen->print_attributes)
187956cc18dSsnj		    send_SGR(xw, attr, fg, bg);
188d522f475Smrg	    }
189d522f475Smrg
190d522f475Smrg	    if (ch == 0)
191d522f475Smrg		ch = ' ';
192d522f475Smrg
193d522f475Smrg#if OPT_WIDE_CHARS
194d522f475Smrg	    if (screen->utf8_mode)
195d522f475Smrg		cs = CSET_IN;
196d522f475Smrg	    else
197d522f475Smrg#endif
198d522f475Smrg		cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT;
199d522f475Smrg	    if (last_cs != cs) {
200d522f475Smrg		if (screen->print_attributes) {
201956cc18dSsnj		    charToPrinter(xw,
202956cc18dSsnj				  (unsigned) ((cs == CSET_OUT)
203d522f475Smrg					      ? SHIFT_OUT
204d522f475Smrg					      : SHIFT_IN));
205d522f475Smrg		}
206d522f475Smrg		last_cs = cs;
207d522f475Smrg	    }
208d522f475Smrg
209d522f475Smrg	    /* FIXME:  we shouldn't have to map back from the
210d522f475Smrg	     * alternate character set, except that the
211d522f475Smrg	     * corresponding charset information is not encoded
212d522f475Smrg	     * into the CSETS array.
213d522f475Smrg	     */
214956cc18dSsnj	    charToPrinter(xw,
215956cc18dSsnj			  ((cs == CSET_OUT)
216d522f475Smrg			   ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f))
217d522f475Smrg			   : ch));
218d522f475Smrg	    if_OPT_WIDE_CHARS(screen, {
219956cc18dSsnj		size_t off;
220956cc18dSsnj		for_each_combData(off, ld) {
221956cc18dSsnj		    ch = ld->combData[off][col];
222956cc18dSsnj		    if (ch == 0)
223d522f475Smrg			break;
224956cc18dSsnj		    charToPrinter(xw, ch);
225d522f475Smrg		}
226d522f475Smrg	    });
227d522f475Smrg	}
228d522f475Smrg	if (screen->print_attributes) {
229956cc18dSsnj	    send_SGR(xw, 0, NO_COLOR, NO_COLOR);
230d522f475Smrg	    if (cs != CSET_IN)
231956cc18dSsnj		charToPrinter(xw, SHIFT_IN);
232d522f475Smrg	}
233d522f475Smrg    }
234d522f475Smrg    if (screen->print_attributes)
235956cc18dSsnj	charToPrinter(xw, '\r');
236956cc18dSsnj    charToPrinter(xw, chr);
237956cc18dSsnj
238956cc18dSsnj    return;
239d522f475Smrg}
240d522f475Smrg
241d522f475Smrgvoid
242956cc18dSsnjxtermPrintScreen(XtermWidget xw, Bool use_DECPEX)
243d522f475Smrg{
244956cc18dSsnj    if (XtIsRealized((Widget) xw)) {
245956cc18dSsnj	TScreen *screen = TScreenOf(xw);
246d522f475Smrg	Bool extent = (use_DECPEX && screen->printer_extent);
247d522f475Smrg	int top = extent ? 0 : screen->top_marg;
248d522f475Smrg	int bot = extent ? screen->max_row : screen->bot_marg;
249d522f475Smrg	int was_open = initialized;
250d522f475Smrg
251d522f475Smrg	TRACE(("xtermPrintScreen, rows %d..%d\n", top, bot));
252d522f475Smrg
253d522f475Smrg	while (top <= bot)
254956cc18dSsnj	    printLine(xw, top++, '\n');
255d522f475Smrg	if (screen->printer_formfeed)
256956cc18dSsnj	    charToPrinter(xw, '\f');
257d522f475Smrg
258d522f475Smrg	if (!was_open || screen->printer_autoclose) {
259956cc18dSsnj	    closePrinter(xw);
260d522f475Smrg	}
261d522f475Smrg    } else {
262d522f475Smrg	Bell(XkbBI_MinorError, 0);
263d522f475Smrg    }
264d522f475Smrg}
265d522f475Smrg
266d522f475Smrg/*
267d522f475Smrg * If the alternate screen is active, we'll print only that.  Otherwise, print
268d522f475Smrg * the normal screen plus all scrolled-back lines.  The distinction is made
269d522f475Smrg * because the normal screen's buffer is part of the overall scrollback buffer.
270d522f475Smrg */
271956cc18dSsnjvoid
272956cc18dSsnjxtermPrintEverything(XtermWidget xw)
273d522f475Smrg{
274956cc18dSsnj    TScreen *screen = TScreenOf(xw);
275d522f475Smrg    int top = 0;
276d522f475Smrg    int bot = screen->max_row;
277d522f475Smrg    int was_open = initialized;
278d522f475Smrg
279956cc18dSsnj    if (!screen->whichBuf) {
280956cc18dSsnj	top = -screen->savedlines - screen->topline;
281956cc18dSsnj	bot -= screen->topline;
282956cc18dSsnj    }
283d522f475Smrg
284d522f475Smrg    TRACE(("xtermPrintEverything, rows %d..%d\n", top, bot));
285d522f475Smrg    while (top <= bot)
286956cc18dSsnj	printLine(xw, top++, '\n');
287d522f475Smrg    if (screen->printer_formfeed)
288956cc18dSsnj	charToPrinter(xw, '\f');
289d522f475Smrg
290d522f475Smrg    if (!was_open || screen->printer_autoclose) {
291956cc18dSsnj	closePrinter(xw);
292d522f475Smrg    }
293d522f475Smrg}
294d522f475Smrg
295d522f475Smrgstatic void
296956cc18dSsnjsend_CharSet(XtermWidget xw, LineData * ld)
297d522f475Smrg{
298d522f475Smrg#if OPT_DEC_CHRSET
299d522f475Smrg    char *msg = 0;
300d522f475Smrg
301956cc18dSsnj    switch (GetLineDblCS(ld)) {
302d522f475Smrg    case CSET_SWL:
303d522f475Smrg	msg = "\033#5";
304d522f475Smrg	break;
305d522f475Smrg    case CSET_DHL_TOP:
306d522f475Smrg	msg = "\033#3";
307d522f475Smrg	break;
308d522f475Smrg    case CSET_DHL_BOT:
309d522f475Smrg	msg = "\033#4";
310d522f475Smrg	break;
311d522f475Smrg    case CSET_DWL:
312d522f475Smrg	msg = "\033#6";
313d522f475Smrg	break;
314d522f475Smrg    }
315d522f475Smrg    if (msg != 0)
316956cc18dSsnj	stringToPrinter(xw, msg);
317d522f475Smrg#else
318956cc18dSsnj    (void) xw;
319956cc18dSsnj    (void) ld;
320d522f475Smrg#endif /* OPT_DEC_CHRSET */
321d522f475Smrg}
322d522f475Smrg
323d522f475Smrgstatic void
324956cc18dSsnjsend_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg)
325d522f475Smrg{
326d522f475Smrg    char msg[80];
327d522f475Smrg    strcpy(msg, "\033[0");
328d522f475Smrg    if (attr & BOLD)
329d522f475Smrg	strcat(msg, ";1");
330d522f475Smrg    if (attr & UNDERLINE)
331d522f475Smrg	strcat(msg, ";4");	/* typo? DEC documents this as '2' */
332d522f475Smrg    if (attr & BLINK)
333d522f475Smrg	strcat(msg, ";5");
334d522f475Smrg    if (attr & INVERSE)		/* typo? DEC documents this as invisible */
335d522f475Smrg	strcat(msg, ";7");
336d522f475Smrg#if OPT_PRINT_COLORS
337d522f475Smrg    if (bg != NO_COLOR) {
338d522f475Smrg	sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg));
339d522f475Smrg    }
340d522f475Smrg    if (fg != NO_COLOR) {
341d522f475Smrg#if OPT_PC_COLORS
342956cc18dSsnj	if (xw->screen.boldColors
343d522f475Smrg	    && fg > 8
344d522f475Smrg	    && (attr & BOLD) != 0)
345d522f475Smrg	    fg -= 8;
346d522f475Smrg#endif
347d522f475Smrg	sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg));
348d522f475Smrg    }
349d522f475Smrg#else
350d522f475Smrg    (void) bg;
351d522f475Smrg    (void) fg;
352d522f475Smrg#endif
353d522f475Smrg    strcat(msg, "m");
354956cc18dSsnj    stringToPrinter(xw, msg);
355d522f475Smrg}
356d522f475Smrg
357d522f475Smrg/*
358d522f475Smrg * This implementation only knows how to write to a pipe.
359d522f475Smrg */
360d522f475Smrgstatic void
361956cc18dSsnjcharToPrinter(XtermWidget xw, unsigned chr)
362d522f475Smrg{
363956cc18dSsnj    TScreen *screen = TScreenOf(xw);
364d522f475Smrg
365956cc18dSsnj    if (!initialized && xtermHasPrinter(xw)) {
366d522f475Smrg#if defined(VMS)
367d522f475Smrg	/*
368d522f475Smrg	 * This implementation only knows how to write to a file.  When the
369d522f475Smrg	 * file is closed the print command executes.  Print command must be of
370d522f475Smrg	 * the form:
371d522f475Smrg	 *   print/que=name/delete [/otherflags].
372d522f475Smrg	 */
373d522f475Smrg	Printer = fopen(VMS_TEMP_PRINT_FILE, "w");
374d522f475Smrg#else
375d522f475Smrg	/*
376d522f475Smrg	 * This implementation only knows how to write to a pipe.
377d522f475Smrg	 */
378d522f475Smrg	FILE *input;
379d522f475Smrg	int my_pipe[2];
380d522f475Smrg	int c;
381d522f475Smrg
382d522f475Smrg	if (pipe(my_pipe))
383d522f475Smrg	    SysError(ERROR_FORK);
384d522f475Smrg	if ((Printer_pid = fork()) < 0)
385d522f475Smrg	    SysError(ERROR_FORK);
386d522f475Smrg
387d522f475Smrg	if (Printer_pid == 0) {
388d522f475Smrg	    TRACE(((char *) 0));
389d522f475Smrg	    close(my_pipe[1]);	/* printer is silent */
390d522f475Smrg	    close(screen->respond);
391d522f475Smrg
392d522f475Smrg	    close(fileno(stdout));
393d522f475Smrg	    dup2(fileno(stderr), 1);
394d522f475Smrg
395d522f475Smrg	    if (fileno(stderr) != 2) {
396d522f475Smrg		dup2(fileno(stderr), 2);
397d522f475Smrg		close(fileno(stderr));
398d522f475Smrg	    }
399d522f475Smrg
400d522f475Smrg	    /* don't want privileges! */
401d522f475Smrg	    if (xtermResetIds(screen) < 0)
402d522f475Smrg		exit(1);
403d522f475Smrg
404d522f475Smrg	    Printer = popen(screen->printer_command, "w");
405d522f475Smrg	    input = fdopen(my_pipe[0], "r");
406d522f475Smrg	    while ((c = fgetc(input)) != EOF) {
407d522f475Smrg		fputc(c, Printer);
408d522f475Smrg		if (isForm(c))
409d522f475Smrg		    fflush(Printer);
410d522f475Smrg	    }
411d522f475Smrg	    pclose(Printer);
412d522f475Smrg	    exit(0);
413d522f475Smrg	} else {
414d522f475Smrg	    close(my_pipe[0]);	/* won't read from printer */
415d522f475Smrg	    Printer = fdopen(my_pipe[1], "w");
416d522f475Smrg	    TRACE(("opened printer from pid %d/%d\n",
417d522f475Smrg		   (int) getpid(), Printer_pid));
418d522f475Smrg	}
419d522f475Smrg#endif
420d522f475Smrg	initialized++;
421d522f475Smrg    }
422d522f475Smrg    if (Printer != 0) {
423d522f475Smrg#if OPT_WIDE_CHARS
424d522f475Smrg	if (chr > 127) {
425d522f475Smrg	    Char temp[10];
426d522f475Smrg	    *convertToUTF8(temp, chr) = 0;
427d522f475Smrg	    fputs((char *) temp, Printer);
428d522f475Smrg	} else
429d522f475Smrg#endif
430d522f475Smrg	    fputc((int) chr, Printer);
431d522f475Smrg	if (isForm(chr))
432d522f475Smrg	    fflush(Printer);
433d522f475Smrg    }
434d522f475Smrg}
435d522f475Smrg
436d522f475Smrgstatic void
437956cc18dSsnjstringToPrinter(XtermWidget xw, char *str)
438d522f475Smrg{
439d522f475Smrg    while (*str)
440956cc18dSsnj	charToPrinter(xw, CharOf(*str++));
441d522f475Smrg}
442d522f475Smrg
443d522f475Smrg/*
444d522f475Smrg * This module implements the MC (Media Copy) and related printing control
445d522f475Smrg * sequences for VTxxx emulation.  This is based on the description in the
446d522f475Smrg * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment
447d522f475Smrg * Corp., March 1987).
448d522f475Smrg */
449d522f475Smrgvoid
450956cc18dSsnjxtermMediaControl(XtermWidget xw, int param, int private_seq)
451d522f475Smrg{
452d522f475Smrg    TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq));
453d522f475Smrg
454d522f475Smrg    if (private_seq) {
455d522f475Smrg	switch (param) {
456d522f475Smrg	case 1:
457956cc18dSsnj	    printCursorLine(xw);
458d522f475Smrg	    break;
459d522f475Smrg	case 4:
460956cc18dSsnj	    setPrinterControlMode(xw, 0);
461d522f475Smrg	    break;
462d522f475Smrg	case 5:
463956cc18dSsnj	    setPrinterControlMode(xw, 1);
464d522f475Smrg	    break;
465d522f475Smrg	case 10:		/* VT320 */
466956cc18dSsnj	    xtermPrintScreen(xw, False);
467d522f475Smrg	    break;
468d522f475Smrg	case 11:		/* VT320 */
469956cc18dSsnj	    xtermPrintEverything(xw);
470d522f475Smrg	    break;
471d522f475Smrg	}
472d522f475Smrg    } else {
473d522f475Smrg	switch (param) {
474d522f475Smrg	case -1:
475d522f475Smrg	case 0:
476956cc18dSsnj	    xtermPrintScreen(xw, True);
477d522f475Smrg	    break;
478d522f475Smrg	case 4:
479956cc18dSsnj	    setPrinterControlMode(xw, 0);
480d522f475Smrg	    break;
481d522f475Smrg	case 5:
482956cc18dSsnj	    setPrinterControlMode(xw, 2);
483d522f475Smrg	    break;
484d522f475Smrg	}
485d522f475Smrg    }
486d522f475Smrg}
487d522f475Smrg
488d522f475Smrg/*
489d522f475Smrg * When in autoprint mode, the printer prints a line from the screen when you
490d522f475Smrg * move the cursor off that line with an LF, FF, or VT character, or an
491d522f475Smrg * autowrap occurs.  The printed line ends with a CR and the character (LF, FF
492d522f475Smrg * or VT) that moved the cursor off the previous line.
493d522f475Smrg */
494d522f475Smrgvoid
495956cc18dSsnjxtermAutoPrint(XtermWidget xw, unsigned chr)
496d522f475Smrg{
497956cc18dSsnj    TScreen *screen = TScreenOf(xw);
498d522f475Smrg
499d522f475Smrg    if (screen->printer_controlmode == 1) {
500d522f475Smrg	TRACE(("AutoPrint %d\n", chr));
501956cc18dSsnj	printLine(xw, screen->cursorp.row, chr);
502d522f475Smrg	if (Printer != 0)
503d522f475Smrg	    fflush(Printer);
504d522f475Smrg    }
505d522f475Smrg}
506d522f475Smrg
507d522f475Smrg/*
508d522f475Smrg * When in printer controller mode, the terminal sends received characters to
509d522f475Smrg * the printer without displaying them on the screen. The terminal sends all
510d522f475Smrg * characters and control sequences to the printer, except NUL, XON, XOFF, and
511d522f475Smrg * the printer controller sequences.
512d522f475Smrg *
513d522f475Smrg * This function eats characters, returning 0 as long as it must buffer or
514d522f475Smrg * divert to the printer.  We're only invoked here when in printer controller
515d522f475Smrg * mode, and handle the exit from that mode.
516d522f475Smrg */
517d522f475Smrg#define LB '['
518d522f475Smrg
519d522f475Smrgint
520956cc18dSsnjxtermPrinterControl(XtermWidget xw, int chr)
521d522f475Smrg{
522956cc18dSsnj    TScreen *screen = TScreenOf(xw);
523d522f475Smrg    /* *INDENT-OFF* */
524d522f475Smrg    static struct {
525d522f475Smrg	Char seq[5];
526d522f475Smrg	int active;
527d522f475Smrg    } tbl[] = {
528d522f475Smrg	{ { ANSI_CSI, '5', 'i'      }, 2 },
529d522f475Smrg	{ { ANSI_CSI, '4', 'i'      }, 0 },
530d522f475Smrg	{ { ANSI_ESC, LB,  '5', 'i' }, 2 },
531d522f475Smrg	{ { ANSI_ESC, LB,  '4', 'i' }, 0 },
532d522f475Smrg    };
533d522f475Smrg    /* *INDENT-ON* */
534d522f475Smrg
535d522f475Smrg    static Char bfr[10];
536d522f475Smrg    static size_t length;
537d522f475Smrg    size_t n;
538d522f475Smrg
539d522f475Smrg    TRACE(("In printer:%04X\n", chr));
540d522f475Smrg
541d522f475Smrg    switch (chr) {
542d522f475Smrg    case 0:
543d522f475Smrg    case CTRL('Q'):
544d522f475Smrg    case CTRL('S'):
545d522f475Smrg	return 0;		/* ignored by application */
546d522f475Smrg
547d522f475Smrg    case ANSI_CSI:
548d522f475Smrg    case ANSI_ESC:
549d522f475Smrg    case '[':
550d522f475Smrg    case '4':
551d522f475Smrg    case '5':
552d522f475Smrg    case 'i':
5534e40088cSchristos	bfr[length++] = CharOf(chr);
554d522f475Smrg	for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) {
555d522f475Smrg	    size_t len = Strlen(tbl[n].seq);
556d522f475Smrg
557d522f475Smrg	    if (length == len
558d522f475Smrg		&& Strcmp(bfr, tbl[n].seq) == 0) {
559956cc18dSsnj		setPrinterControlMode(xw, tbl[n].active);
560d522f475Smrg		if (screen->printer_autoclose
561d522f475Smrg		    && screen->printer_controlmode == 0)
562956cc18dSsnj		    closePrinter(xw);
563d522f475Smrg		length = 0;
564d522f475Smrg		return 0;
565d522f475Smrg	    } else if (len > length
566d522f475Smrg		       && Strncmp(bfr, tbl[n].seq, length) == 0) {
567d522f475Smrg		return 0;
568d522f475Smrg	    }
569d522f475Smrg	}
570d522f475Smrg	length--;
571d522f475Smrg
572d522f475Smrg	/* FALLTHRU */
573d522f475Smrg
574d522f475Smrg    default:
575d522f475Smrg	for (n = 0; n < length; n++)
576956cc18dSsnj	    charToPrinter(xw, bfr[n]);
5774e40088cSchristos	bfr[0] = CharOf(chr);
578d522f475Smrg	length = 1;
579d522f475Smrg	return 0;
580d522f475Smrg    }
581d522f475Smrg}
582d522f475Smrg
583d522f475Smrg/*
584d522f475Smrg * If there is no printer command, we will ignore printer controls.
585d522f475Smrg */
586d522f475SmrgBool
587956cc18dSsnjxtermHasPrinter(XtermWidget xw)
588d522f475Smrg{
589956cc18dSsnj    TScreen *screen = TScreenOf(xw);
590d522f475Smrg
591d522f475Smrg    return (strlen(screen->printer_command) != 0);
592d522f475Smrg}
593d522f475Smrg
594d522f475Smrg#define showPrinterControlMode(mode) \
595d522f475Smrg		(((mode) == 0) \
596d522f475Smrg		 ? "normal" \
597d522f475Smrg		 : ((mode) == 1 \
598d522f475Smrg		    ? "autoprint" \
599d522f475Smrg		    : "printer controller"))
600d522f475Smrg
601d522f475Smrgvoid
602956cc18dSsnjsetPrinterControlMode(XtermWidget xw, int mode)
603d522f475Smrg{
604956cc18dSsnj    if (xtermHasPrinter(xw)
605956cc18dSsnj	&& xw->screen.printer_controlmode != mode) {
606d522f475Smrg	TRACE(("%s %s mode\n",
607d522f475Smrg	       (mode
608d522f475Smrg		? "set"
609d522f475Smrg		: "reset"),
610d522f475Smrg	       (mode
611d522f475Smrg		? showPrinterControlMode(mode)
612956cc18dSsnj		: showPrinterControlMode(xw->screen.printer_controlmode))));
613956cc18dSsnj	xw->screen.printer_controlmode = mode;
614d522f475Smrg	update_print_redir();
615d522f475Smrg    }
616d522f475Smrg}
617