print.c revision 4e40088c
14e40088cSchristos/* $XTermId: print.c,v 1.81 2009/01/09 01:43:01 tom Exp $ */
2d522f475Smrg
3d522f475Smrg/*
4d522f475Smrg * $XFree86: xc/programs/xterm/print.c,v 1.24 2006/06/19 00:36:51 dickey Exp $
5d522f475Smrg */
6d522f475Smrg
7d522f475Smrg/************************************************************
8d522f475Smrg
94e40088cSchristosCopyright 1997-2007,2009 by Thomas E. Dickey
10d522f475Smrg
11d522f475Smrg                        All Rights Reserved
12d522f475Smrg
13d522f475SmrgPermission is hereby granted, free of charge, to any person obtaining a
14d522f475Smrgcopy of this software and associated documentation files (the
15d522f475Smrg"Software"), to deal in the Software without restriction, including
16d522f475Smrgwithout limitation the rights to use, copy, modify, merge, publish,
17d522f475Smrgdistribute, sublicense, and/or sell copies of the Software, and to
18d522f475Smrgpermit persons to whom the Software is furnished to do so, subject to
19d522f475Smrgthe following conditions:
20d522f475Smrg
21d522f475SmrgThe above copyright notice and this permission notice shall be included
22d522f475Smrgin all copies or substantial portions of the Software.
23d522f475Smrg
24d522f475SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25d522f475SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26d522f475SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27d522f475SmrgIN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
28d522f475SmrgCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29d522f475SmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30d522f475SmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31d522f475Smrg
32d522f475SmrgExcept as contained in this notice, the name(s) of the above copyright
33d522f475Smrgholders shall not be used in advertising or otherwise to promote the
34d522f475Smrgsale, use or other dealings in this Software without prior written
35d522f475Smrgauthorization.
36d522f475Smrg
37d522f475Smrg********************************************************/
38d522f475Smrg
39d522f475Smrg#include <xterm.h>
40d522f475Smrg#include <data.h>
41d522f475Smrg#include <menu.h>
42d522f475Smrg#include <error.h>
43d522f475Smrg
44d522f475Smrg#include <stdio.h>
45d522f475Smrg
46d522f475Smrg#undef  CTRL
47d522f475Smrg#define	CTRL(c)	((c) & 0x1f)
48d522f475Smrg
49d522f475Smrg#define SHIFT_IN  '\017'
50d522f475Smrg#define SHIFT_OUT '\016'
51d522f475Smrg
52d522f475Smrg#define CSET_IN   'A'
53d522f475Smrg#define CSET_OUT  '0'
54d522f475Smrg
55d522f475Smrg#define isForm(c)      ((c) == '\r' || (c) == '\n' || (c) == '\f')
56d522f475Smrg#define Strlen(a)      strlen((char *)a)
57d522f475Smrg#define Strcmp(a,b)    strcmp((char *)a,(char *)b)
58d522f475Smrg#define Strncmp(a,b,c) strncmp((char *)a,(char *)b,c)
59d522f475Smrg
60d522f475Smrg#ifdef VMS
61d522f475Smrg#define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt"
62d522f475Smrg#endif
63d522f475Smrg
64d522f475Smrgstatic void charToPrinter(unsigned chr);
65d522f475Smrgstatic void printLine(int row, unsigned chr);
66d522f475Smrgstatic void send_CharSet(int row);
67d522f475Smrgstatic void send_SGR(unsigned attr, unsigned fg, unsigned bg);
68d522f475Smrgstatic void stringToPrinter(char *str);
69d522f475Smrg
70d522f475Smrgstatic FILE *Printer;
71d522f475Smrgstatic pid_t Printer_pid;
72d522f475Smrgstatic int initialized;
73d522f475Smrg
74d522f475Smrgstatic void
75d522f475SmrgclosePrinter(void)
76d522f475Smrg{
77d522f475Smrg    if (xtermHasPrinter() != 0) {
78d522f475Smrg#ifdef VMS
79d522f475Smrg	TScreen *screen = TScreenOf(term);
80d522f475Smrg
81d522f475Smrg	char pcommand[256];
82d522f475Smrg	(void) sprintf(pcommand, "%s %s;",
83d522f475Smrg		       screen->printer_command,
84d522f475Smrg		       VMS_TEMP_PRINT_FILE);
85d522f475Smrg#endif
86d522f475Smrg
87d522f475Smrg	if (Printer != 0) {
88d522f475Smrg	    fclose(Printer);
89d522f475Smrg	    TRACE(("closed printer, waiting...\n"));
90d522f475Smrg#ifdef VMS			/* This is a quick hack, really should use
91d522f475Smrg				   spawn and check status or system services
92d522f475Smrg				   and go straight to the queue */
93d522f475Smrg	    (void) system(pcommand);
94d522f475Smrg#else /* VMS */
95d522f475Smrg	    while (nonblocking_wait() > 0)
96d522f475Smrg#endif /* VMS */
97d522f475Smrg		;
98d522f475Smrg	    Printer = 0;
99d522f475Smrg	    initialized = 0;
100d522f475Smrg	    TRACE(("closed printer\n"));
101d522f475Smrg	}
102d522f475Smrg    }
103d522f475Smrg}
104d522f475Smrg
105d522f475Smrgstatic void
106d522f475SmrgprintCursorLine(void)
107d522f475Smrg{
108d522f475Smrg    TScreen *screen = TScreenOf(term);
109d522f475Smrg
110d522f475Smrg    TRACE(("printCursorLine\n"));
111d522f475Smrg    printLine(screen->cur_row, '\n');
112d522f475Smrg}
113d522f475Smrg
114d522f475Smrg#define NO_COLOR	((unsigned)-1)
115d522f475Smrg
116d522f475Smrg/*
117d522f475Smrg * DEC's manual doesn't document whether trailing blanks are removed, or what
118d522f475Smrg * happens with a line that is entirely blank.  This function prints the
119d522f475Smrg * characters that xterm would allow as a selection (which may include blanks).
120d522f475Smrg */
121d522f475Smrgstatic void
122d522f475SmrgprintLine(int row, unsigned chr)
123d522f475Smrg{
124d522f475Smrg    TScreen *screen = TScreenOf(term);
125d522f475Smrg    int inx = ROW2INX(screen, row);
126d522f475Smrg    Char *c = SCRN_BUF_CHARS(screen, inx);
127d522f475Smrg    Char *a = SCRN_BUF_ATTRS(screen, inx);
128d522f475Smrg    Char attr = 0;
129d522f475Smrg    unsigned ch;
130d522f475Smrg    int last = MaxCols(screen);
131d522f475Smrg    int col;
132d522f475Smrg#if OPT_ISO_COLORS && OPT_PRINT_COLORS
133d522f475Smrg#if OPT_EXT_COLORS
134d522f475Smrg    Char *fbf = 0;
135d522f475Smrg    Char *fbb = 0;
136d522f475Smrg#define ColorOf(col) (unsigned)((fbf[col] << 8) | fbb[col])
137d522f475Smrg#else
138d522f475Smrg    Char *fb = 0;
139d522f475Smrg#define ColorOf(col) (fb[col])
140d522f475Smrg#endif
141d522f475Smrg#endif
142d522f475Smrg    unsigned fg = NO_COLOR, last_fg = NO_COLOR;
143d522f475Smrg    unsigned bg = NO_COLOR, last_bg = NO_COLOR;
144d522f475Smrg    int cs = CSET_IN;
145d522f475Smrg    int last_cs = CSET_IN;
146d522f475Smrg
147d522f475Smrg    TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n",
148d522f475Smrg	   row, ROW2INX(screen, row), screen->topline, screen->max_row, chr,
149d522f475Smrg	   visibleChars(PAIRED_CHARS(c,
150d522f475Smrg				     (screen->utf8_mode
151d522f475Smrg				      ? SCRN_BUF_WIDEC(screen, inx)
152d522f475Smrg				      : 0)),
153d522f475Smrg			(unsigned) last)));
154d522f475Smrg
155d522f475Smrg    if_OPT_EXT_COLORS(screen, {
156d522f475Smrg	fbf = SCRN_BUF_FGRND(screen, inx);
157d522f475Smrg	fbb = SCRN_BUF_BGRND(screen, inx);
158d522f475Smrg    });
159d522f475Smrg    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
160d522f475Smrg	fb = SCRN_BUF_COLOR(screen, inx);
161d522f475Smrg    });
162d522f475Smrg    while (last > 0) {
163d522f475Smrg	if ((a[last - 1] & CHARDRAWN) == 0)
164d522f475Smrg	    last--;
165d522f475Smrg	else
166d522f475Smrg	    break;
167d522f475Smrg    }
168d522f475Smrg    if (last) {
169d522f475Smrg	if (screen->print_attributes) {
170d522f475Smrg	    send_CharSet(row);
171d522f475Smrg	    send_SGR(0, NO_COLOR, NO_COLOR);
172d522f475Smrg	}
173d522f475Smrg	for (col = 0; col < last; col++) {
174d522f475Smrg	    ch = c[col];
175d522f475Smrg	    if_OPT_WIDE_CHARS(screen, {
176d522f475Smrg		ch = XTERM_CELL(row, col);
177d522f475Smrg	    });
178d522f475Smrg#if OPT_PRINT_COLORS
179d522f475Smrg	    if (screen->colorMode) {
180d522f475Smrg		if (screen->print_attributes > 1) {
181d522f475Smrg		    fg = (a[col] & FG_COLOR)
182d522f475Smrg			? extract_fg(term, ColorOf(col), a[col])
183d522f475Smrg			: NO_COLOR;
184d522f475Smrg		    bg = (a[col] & BG_COLOR)
185d522f475Smrg			? extract_bg(term, ColorOf(col), a[col])
186d522f475Smrg			: NO_COLOR;
187d522f475Smrg		}
188d522f475Smrg	    }
189d522f475Smrg#endif
190d522f475Smrg	    if ((((a[col] & SGR_MASK) != attr)
191d522f475Smrg#if OPT_PRINT_COLORS
192d522f475Smrg		 || (last_fg != fg) || (last_bg != bg)
193d522f475Smrg#endif
194d522f475Smrg		)
195d522f475Smrg		&& ch) {
1964e40088cSchristos		attr = CharOf(a[col] & SGR_MASK);
197d522f475Smrg		last_fg = fg;
198d522f475Smrg		last_bg = bg;
199d522f475Smrg		if (screen->print_attributes)
200d522f475Smrg		    send_SGR(attr, fg, bg);
201d522f475Smrg	    }
202d522f475Smrg
203d522f475Smrg	    if (ch == 0)
204d522f475Smrg		ch = ' ';
205d522f475Smrg
206d522f475Smrg#if OPT_WIDE_CHARS
207d522f475Smrg	    if (screen->utf8_mode)
208d522f475Smrg		cs = CSET_IN;
209d522f475Smrg	    else
210d522f475Smrg#endif
211d522f475Smrg		cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT;
212d522f475Smrg	    if (last_cs != cs) {
213d522f475Smrg		if (screen->print_attributes) {
214d522f475Smrg		    charToPrinter((unsigned) ((cs == CSET_OUT)
215d522f475Smrg					      ? SHIFT_OUT
216d522f475Smrg					      : SHIFT_IN));
217d522f475Smrg		}
218d522f475Smrg		last_cs = cs;
219d522f475Smrg	    }
220d522f475Smrg
221d522f475Smrg	    /* FIXME:  we shouldn't have to map back from the
222d522f475Smrg	     * alternate character set, except that the
223d522f475Smrg	     * corresponding charset information is not encoded
224d522f475Smrg	     * into the CSETS array.
225d522f475Smrg	     */
226d522f475Smrg	    charToPrinter(((cs == CSET_OUT)
227d522f475Smrg			   ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f))
228d522f475Smrg			   : ch));
229d522f475Smrg	    if_OPT_WIDE_CHARS(screen, {
230d522f475Smrg		int off;
231d522f475Smrg		for (off = OFF_FINAL; off < MAX_PTRS; off += 2) {
232d522f475Smrg		    if ((ch = XTERM_CELLC(row, col, off)) == 0)
233d522f475Smrg			break;
234d522f475Smrg		    charToPrinter(ch);
235d522f475Smrg		}
236d522f475Smrg	    });
237d522f475Smrg	}
238d522f475Smrg	if (screen->print_attributes) {
239d522f475Smrg	    send_SGR(0, NO_COLOR, NO_COLOR);
240d522f475Smrg	    if (cs != CSET_IN)
241d522f475Smrg		charToPrinter(SHIFT_IN);
242d522f475Smrg	}
243d522f475Smrg    }
244d522f475Smrg    if (screen->print_attributes)
245d522f475Smrg	charToPrinter('\r');
246d522f475Smrg    charToPrinter(chr);
247d522f475Smrg}
248d522f475Smrg
249d522f475Smrgvoid
250d522f475SmrgxtermPrintScreen(Bool use_DECPEX)
251d522f475Smrg{
252d522f475Smrg    if (XtIsRealized((Widget) term)) {
253d522f475Smrg	TScreen *screen = TScreenOf(term);
254d522f475Smrg	Bool extent = (use_DECPEX && screen->printer_extent);
255d522f475Smrg	int top = extent ? 0 : screen->top_marg;
256d522f475Smrg	int bot = extent ? screen->max_row : screen->bot_marg;
257d522f475Smrg	int was_open = initialized;
258d522f475Smrg
259d522f475Smrg	TRACE(("xtermPrintScreen, rows %d..%d\n", top, bot));
260d522f475Smrg
261d522f475Smrg	while (top <= bot)
262d522f475Smrg	    printLine(top++, '\n');
263d522f475Smrg	if (screen->printer_formfeed)
264d522f475Smrg	    charToPrinter('\f');
265d522f475Smrg
266d522f475Smrg	if (!was_open || screen->printer_autoclose) {
267d522f475Smrg	    closePrinter();
268d522f475Smrg	}
269d522f475Smrg    } else {
270d522f475Smrg	Bell(XkbBI_MinorError, 0);
271d522f475Smrg    }
272d522f475Smrg}
273d522f475Smrg
274d522f475Smrg/*
275d522f475Smrg * If the alternate screen is active, we'll print only that.  Otherwise, print
276d522f475Smrg * the normal screen plus all scrolled-back lines.  The distinction is made
277d522f475Smrg * because the normal screen's buffer is part of the overall scrollback buffer.
278d522f475Smrg */
279d522f475Smrgstatic void
280d522f475SmrgxtermPrintEverything(void)
281d522f475Smrg{
282d522f475Smrg    TScreen *screen = TScreenOf(term);
283d522f475Smrg    int top = 0;
284d522f475Smrg    int bot = screen->max_row;
285d522f475Smrg    int was_open = initialized;
286d522f475Smrg
287d522f475Smrg    if (!screen->altbuf)
288d522f475Smrg	top = -screen->savedlines;
289d522f475Smrg
290d522f475Smrg    TRACE(("xtermPrintEverything, rows %d..%d\n", top, bot));
291d522f475Smrg    while (top <= bot)
292d522f475Smrg	printLine(top++, '\n');
293d522f475Smrg    if (screen->printer_formfeed)
294d522f475Smrg	charToPrinter('\f');
295d522f475Smrg
296d522f475Smrg    if (!was_open || screen->printer_autoclose) {
297d522f475Smrg	closePrinter();
298d522f475Smrg    }
299d522f475Smrg}
300d522f475Smrg
301d522f475Smrgstatic void
302d522f475Smrgsend_CharSet(int row)
303d522f475Smrg{
304d522f475Smrg#if OPT_DEC_CHRSET
305d522f475Smrg    TScreen *screen = TScreenOf(term);
306d522f475Smrg    char *msg = 0;
307d522f475Smrg
308d522f475Smrg    switch (SCRN_BUF_CSETS(screen, row)[0]) {
309d522f475Smrg    case CSET_SWL:
310d522f475Smrg	msg = "\033#5";
311d522f475Smrg	break;
312d522f475Smrg    case CSET_DHL_TOP:
313d522f475Smrg	msg = "\033#3";
314d522f475Smrg	break;
315d522f475Smrg    case CSET_DHL_BOT:
316d522f475Smrg	msg = "\033#4";
317d522f475Smrg	break;
318d522f475Smrg    case CSET_DWL:
319d522f475Smrg	msg = "\033#6";
320d522f475Smrg	break;
321d522f475Smrg    }
322d522f475Smrg    if (msg != 0)
323d522f475Smrg	stringToPrinter(msg);
324d522f475Smrg#else
325d522f475Smrg    (void) row;
326d522f475Smrg#endif /* OPT_DEC_CHRSET */
327d522f475Smrg}
328d522f475Smrg
329d522f475Smrgstatic void
330d522f475Smrgsend_SGR(unsigned attr, unsigned fg, unsigned bg)
331d522f475Smrg{
332d522f475Smrg    char msg[80];
333d522f475Smrg    strcpy(msg, "\033[0");
334d522f475Smrg    if (attr & BOLD)
335d522f475Smrg	strcat(msg, ";1");
336d522f475Smrg    if (attr & UNDERLINE)
337d522f475Smrg	strcat(msg, ";4");	/* typo? DEC documents this as '2' */
338d522f475Smrg    if (attr & BLINK)
339d522f475Smrg	strcat(msg, ";5");
340d522f475Smrg    if (attr & INVERSE)		/* typo? DEC documents this as invisible */
341d522f475Smrg	strcat(msg, ";7");
342d522f475Smrg#if OPT_PRINT_COLORS
343d522f475Smrg    if (bg != NO_COLOR) {
344d522f475Smrg	sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg));
345d522f475Smrg    }
346d522f475Smrg    if (fg != NO_COLOR) {
347d522f475Smrg#if OPT_PC_COLORS
348d522f475Smrg	if (term->screen.boldColors
349d522f475Smrg	    && fg > 8
350d522f475Smrg	    && (attr & BOLD) != 0)
351d522f475Smrg	    fg -= 8;
352d522f475Smrg#endif
353d522f475Smrg	sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg));
354d522f475Smrg    }
355d522f475Smrg#else
356d522f475Smrg    (void) bg;
357d522f475Smrg    (void) fg;
358d522f475Smrg#endif
359d522f475Smrg    strcat(msg, "m");
360d522f475Smrg    stringToPrinter(msg);
361d522f475Smrg}
362d522f475Smrg
363d522f475Smrg/*
364d522f475Smrg * This implementation only knows how to write to a pipe.
365d522f475Smrg */
366d522f475Smrgstatic void
367d522f475SmrgcharToPrinter(unsigned chr)
368d522f475Smrg{
369d522f475Smrg    TScreen *screen = TScreenOf(term);
370d522f475Smrg
371d522f475Smrg    if (!initialized && xtermHasPrinter()) {
372d522f475Smrg#if defined(VMS)
373d522f475Smrg	/*
374d522f475Smrg	 * This implementation only knows how to write to a file.  When the
375d522f475Smrg	 * file is closed the print command executes.  Print command must be of
376d522f475Smrg	 * the form:
377d522f475Smrg	 *   print/que=name/delete [/otherflags].
378d522f475Smrg	 */
379d522f475Smrg	Printer = fopen(VMS_TEMP_PRINT_FILE, "w");
380d522f475Smrg#else
381d522f475Smrg	/*
382d522f475Smrg	 * This implementation only knows how to write to a pipe.
383d522f475Smrg	 */
384d522f475Smrg	FILE *input;
385d522f475Smrg	int my_pipe[2];
386d522f475Smrg	int c;
387d522f475Smrg
388d522f475Smrg	if (pipe(my_pipe))
389d522f475Smrg	    SysError(ERROR_FORK);
390d522f475Smrg	if ((Printer_pid = fork()) < 0)
391d522f475Smrg	    SysError(ERROR_FORK);
392d522f475Smrg
393d522f475Smrg	if (Printer_pid == 0) {
394d522f475Smrg	    TRACE(((char *) 0));
395d522f475Smrg	    close(my_pipe[1]);	/* printer is silent */
396d522f475Smrg	    close(screen->respond);
397d522f475Smrg
398d522f475Smrg	    close(fileno(stdout));
399d522f475Smrg	    dup2(fileno(stderr), 1);
400d522f475Smrg
401d522f475Smrg	    if (fileno(stderr) != 2) {
402d522f475Smrg		dup2(fileno(stderr), 2);
403d522f475Smrg		close(fileno(stderr));
404d522f475Smrg	    }
405d522f475Smrg
406d522f475Smrg	    /* don't want privileges! */
407d522f475Smrg	    if (xtermResetIds(screen) < 0)
408d522f475Smrg		exit(1);
409d522f475Smrg
410d522f475Smrg	    Printer = popen(screen->printer_command, "w");
411d522f475Smrg	    input = fdopen(my_pipe[0], "r");
412d522f475Smrg	    while ((c = fgetc(input)) != EOF) {
413d522f475Smrg		fputc(c, Printer);
414d522f475Smrg		if (isForm(c))
415d522f475Smrg		    fflush(Printer);
416d522f475Smrg	    }
417d522f475Smrg	    pclose(Printer);
418d522f475Smrg	    exit(0);
419d522f475Smrg	} else {
420d522f475Smrg	    close(my_pipe[0]);	/* won't read from printer */
421d522f475Smrg	    Printer = fdopen(my_pipe[1], "w");
422d522f475Smrg	    TRACE(("opened printer from pid %d/%d\n",
423d522f475Smrg		   (int) getpid(), Printer_pid));
424d522f475Smrg	}
425d522f475Smrg#endif
426d522f475Smrg	initialized++;
427d522f475Smrg    }
428d522f475Smrg    if (Printer != 0) {
429d522f475Smrg#if OPT_WIDE_CHARS
430d522f475Smrg	if (chr > 127) {
431d522f475Smrg	    Char temp[10];
432d522f475Smrg	    *convertToUTF8(temp, chr) = 0;
433d522f475Smrg	    fputs((char *) temp, Printer);
434d522f475Smrg	} else
435d522f475Smrg#endif
436d522f475Smrg	    fputc((int) chr, Printer);
437d522f475Smrg	if (isForm(chr))
438d522f475Smrg	    fflush(Printer);
439d522f475Smrg    }
440d522f475Smrg}
441d522f475Smrg
442d522f475Smrgstatic void
443d522f475SmrgstringToPrinter(char *str)
444d522f475Smrg{
445d522f475Smrg    while (*str)
446d522f475Smrg	charToPrinter(CharOf(*str++));
447d522f475Smrg}
448d522f475Smrg
449d522f475Smrg/*
450d522f475Smrg * This module implements the MC (Media Copy) and related printing control
451d522f475Smrg * sequences for VTxxx emulation.  This is based on the description in the
452d522f475Smrg * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment
453d522f475Smrg * Corp., March 1987).
454d522f475Smrg */
455d522f475Smrgvoid
456d522f475SmrgxtermMediaControl(int param, int private_seq)
457d522f475Smrg{
458d522f475Smrg    TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq));
459d522f475Smrg
460d522f475Smrg    if (private_seq) {
461d522f475Smrg	switch (param) {
462d522f475Smrg	case 1:
463d522f475Smrg	    printCursorLine();
464d522f475Smrg	    break;
465d522f475Smrg	case 4:
466d522f475Smrg	    setPrinterControlMode(0);
467d522f475Smrg	    break;
468d522f475Smrg	case 5:
469d522f475Smrg	    setPrinterControlMode(1);
470d522f475Smrg	    break;
471d522f475Smrg	case 10:		/* VT320 */
472d522f475Smrg	    xtermPrintScreen(False);
473d522f475Smrg	    break;
474d522f475Smrg	case 11:		/* VT320 */
475d522f475Smrg	    xtermPrintEverything();
476d522f475Smrg	    break;
477d522f475Smrg	}
478d522f475Smrg    } else {
479d522f475Smrg	switch (param) {
480d522f475Smrg	case -1:
481d522f475Smrg	case 0:
482d522f475Smrg	    xtermPrintScreen(True);
483d522f475Smrg	    break;
484d522f475Smrg	case 4:
485d522f475Smrg	    setPrinterControlMode(0);
486d522f475Smrg	    break;
487d522f475Smrg	case 5:
488d522f475Smrg	    setPrinterControlMode(2);
489d522f475Smrg	    break;
490d522f475Smrg	}
491d522f475Smrg    }
492d522f475Smrg}
493d522f475Smrg
494d522f475Smrg/*
495d522f475Smrg * When in autoprint mode, the printer prints a line from the screen when you
496d522f475Smrg * move the cursor off that line with an LF, FF, or VT character, or an
497d522f475Smrg * autowrap occurs.  The printed line ends with a CR and the character (LF, FF
498d522f475Smrg * or VT) that moved the cursor off the previous line.
499d522f475Smrg */
500d522f475Smrgvoid
501d522f475SmrgxtermAutoPrint(unsigned chr)
502d522f475Smrg{
503d522f475Smrg    TScreen *screen = TScreenOf(term);
504d522f475Smrg
505d522f475Smrg    if (screen->printer_controlmode == 1) {
506d522f475Smrg	TRACE(("AutoPrint %d\n", chr));
507d522f475Smrg	printLine(screen->cursorp.row, chr);
508d522f475Smrg	if (Printer != 0)
509d522f475Smrg	    fflush(Printer);
510d522f475Smrg    }
511d522f475Smrg}
512d522f475Smrg
513d522f475Smrg/*
514d522f475Smrg * When in printer controller mode, the terminal sends received characters to
515d522f475Smrg * the printer without displaying them on the screen. The terminal sends all
516d522f475Smrg * characters and control sequences to the printer, except NUL, XON, XOFF, and
517d522f475Smrg * the printer controller sequences.
518d522f475Smrg *
519d522f475Smrg * This function eats characters, returning 0 as long as it must buffer or
520d522f475Smrg * divert to the printer.  We're only invoked here when in printer controller
521d522f475Smrg * mode, and handle the exit from that mode.
522d522f475Smrg */
523d522f475Smrg#define LB '['
524d522f475Smrg
525d522f475Smrgint
526d522f475SmrgxtermPrinterControl(int chr)
527d522f475Smrg{
528d522f475Smrg    TScreen *screen = TScreenOf(term);
529d522f475Smrg    /* *INDENT-OFF* */
530d522f475Smrg    static struct {
531d522f475Smrg	Char seq[5];
532d522f475Smrg	int active;
533d522f475Smrg    } tbl[] = {
534d522f475Smrg	{ { ANSI_CSI, '5', 'i'      }, 2 },
535d522f475Smrg	{ { ANSI_CSI, '4', 'i'      }, 0 },
536d522f475Smrg	{ { ANSI_ESC, LB,  '5', 'i' }, 2 },
537d522f475Smrg	{ { ANSI_ESC, LB,  '4', 'i' }, 0 },
538d522f475Smrg    };
539d522f475Smrg    /* *INDENT-ON* */
540d522f475Smrg
541d522f475Smrg    static Char bfr[10];
542d522f475Smrg    static size_t length;
543d522f475Smrg    size_t n;
544d522f475Smrg
545d522f475Smrg    TRACE(("In printer:%04X\n", chr));
546d522f475Smrg
547d522f475Smrg    switch (chr) {
548d522f475Smrg    case 0:
549d522f475Smrg    case CTRL('Q'):
550d522f475Smrg    case CTRL('S'):
551d522f475Smrg	return 0;		/* ignored by application */
552d522f475Smrg
553d522f475Smrg    case ANSI_CSI:
554d522f475Smrg    case ANSI_ESC:
555d522f475Smrg    case '[':
556d522f475Smrg    case '4':
557d522f475Smrg    case '5':
558d522f475Smrg    case 'i':
5594e40088cSchristos	bfr[length++] = CharOf(chr);
560d522f475Smrg	for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) {
561d522f475Smrg	    size_t len = Strlen(tbl[n].seq);
562d522f475Smrg
563d522f475Smrg	    if (length == len
564d522f475Smrg		&& Strcmp(bfr, tbl[n].seq) == 0) {
565d522f475Smrg		setPrinterControlMode(tbl[n].active);
566d522f475Smrg		if (screen->printer_autoclose
567d522f475Smrg		    && screen->printer_controlmode == 0)
568d522f475Smrg		    closePrinter();
569d522f475Smrg		length = 0;
570d522f475Smrg		return 0;
571d522f475Smrg	    } else if (len > length
572d522f475Smrg		       && Strncmp(bfr, tbl[n].seq, length) == 0) {
573d522f475Smrg		return 0;
574d522f475Smrg	    }
575d522f475Smrg	}
576d522f475Smrg	length--;
577d522f475Smrg
578d522f475Smrg	/* FALLTHRU */
579d522f475Smrg
580d522f475Smrg    default:
581d522f475Smrg	for (n = 0; n < length; n++)
582d522f475Smrg	    charToPrinter(bfr[n]);
5834e40088cSchristos	bfr[0] = CharOf(chr);
584d522f475Smrg	length = 1;
585d522f475Smrg	return 0;
586d522f475Smrg    }
587d522f475Smrg}
588d522f475Smrg
589d522f475Smrg/*
590d522f475Smrg * If there is no printer command, we will ignore printer controls.
591d522f475Smrg */
592d522f475SmrgBool
593d522f475SmrgxtermHasPrinter(void)
594d522f475Smrg{
595d522f475Smrg    TScreen *screen = TScreenOf(term);
596d522f475Smrg
597d522f475Smrg    return (strlen(screen->printer_command) != 0);
598d522f475Smrg}
599d522f475Smrg
600d522f475Smrg#define showPrinterControlMode(mode) \
601d522f475Smrg		(((mode) == 0) \
602d522f475Smrg		 ? "normal" \
603d522f475Smrg		 : ((mode) == 1 \
604d522f475Smrg		    ? "autoprint" \
605d522f475Smrg		    : "printer controller"))
606d522f475Smrg
607d522f475Smrgvoid
608d522f475SmrgsetPrinterControlMode(int mode)
609d522f475Smrg{
610d522f475Smrg    if (xtermHasPrinter()
611d522f475Smrg	&& term->screen.printer_controlmode != mode) {
612d522f475Smrg	TRACE(("%s %s mode\n",
613d522f475Smrg	       (mode
614d522f475Smrg		? "set"
615d522f475Smrg		: "reset"),
616d522f475Smrg	       (mode
617d522f475Smrg		? showPrinterControlMode(mode)
618d522f475Smrg		: showPrinterControlMode(term->screen.printer_controlmode))));
619d522f475Smrg	term->screen.printer_controlmode = mode;
620d522f475Smrg	update_print_redir();
621d522f475Smrg    }
622d522f475Smrg}
623