print.c revision a1f3da82
1a1f3da82Smrg/* $XTermId: print.c,v 1.121 2011/02/09 10:11:44 tom Exp $ */
2d522f475Smrg
3d522f475Smrg/************************************************************
4d522f475Smrg
5a1f3da82SmrgCopyright 1997-2010,2011 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>
3920d2c4d2Smrg#include <xstrings.h>
40d522f475Smrg
41d522f475Smrg#include <stdio.h>
42d522f475Smrg
43d522f475Smrg#undef  CTRL
44d522f475Smrg#define	CTRL(c)	((c) & 0x1f)
45d522f475Smrg
46d522f475Smrg#define SHIFT_IN  '\017'
47d522f475Smrg#define SHIFT_OUT '\016'
48d522f475Smrg
49d522f475Smrg#define CSET_IN   'A'
50d522f475Smrg#define CSET_OUT  '0'
51d522f475Smrg
52d522f475Smrg#define isForm(c)      ((c) == '\r' || (c) == '\n' || (c) == '\f')
53d522f475Smrg#define Strlen(a)      strlen((char *)a)
54d522f475Smrg#define Strcmp(a,b)    strcmp((char *)a,(char *)b)
55d522f475Smrg#define Strncmp(a,b,c) strncmp((char *)a,(char *)b,c)
56d522f475Smrg
57d522f475Smrg#ifdef VMS
58d522f475Smrg#define VMS_TEMP_PRINT_FILE "sys$scratch:xterm_print.txt"
59d522f475Smrg#endif
60d522f475Smrg
61956cc18dSsnjstatic void charToPrinter(XtermWidget /* xw */ ,
62956cc18dSsnj			  unsigned /* chr */ );
63956cc18dSsnjstatic void printLine(XtermWidget /* xw */ ,
64956cc18dSsnj		      int /* row */ ,
6520d2c4d2Smrg		      unsigned /* chr */ ,
6620d2c4d2Smrg		      PrinterFlags * /* p */ );
67956cc18dSsnjstatic void send_CharSet(XtermWidget /* xw */ ,
68956cc18dSsnj			 LineData * /* ld */ );
69956cc18dSsnjstatic void send_SGR(XtermWidget /* xw */ ,
70956cc18dSsnj		     unsigned /* attr */ ,
71956cc18dSsnj		     unsigned /* fg */ ,
72956cc18dSsnj		     unsigned /* bg */ );
73956cc18dSsnjstatic void stringToPrinter(XtermWidget /* xw */ ,
7420d2c4d2Smrg			    const char * /*str */ );
75d522f475Smrg
76d522f475Smrgstatic FILE *Printer;
77d522f475Smrgstatic pid_t Printer_pid;
78d522f475Smrgstatic int initialized;
79d522f475Smrg
80d522f475Smrgstatic void
81956cc18dSsnjclosePrinter(XtermWidget xw GCC_UNUSED)
82d522f475Smrg{
83956cc18dSsnj    if (xtermHasPrinter(xw) != 0) {
84d522f475Smrg#ifdef VMS
85956cc18dSsnj	TScreen *screen = TScreenOf(xw);
86d522f475Smrg
87d522f475Smrg	char pcommand[256];
88d522f475Smrg	(void) sprintf(pcommand, "%s %s;",
89d522f475Smrg		       screen->printer_command,
90d522f475Smrg		       VMS_TEMP_PRINT_FILE);
91d522f475Smrg#endif
92d522f475Smrg
93d522f475Smrg	if (Printer != 0) {
94d522f475Smrg	    fclose(Printer);
95d522f475Smrg	    TRACE(("closed printer, waiting...\n"));
96d522f475Smrg#ifdef VMS			/* This is a quick hack, really should use
97d522f475Smrg				   spawn and check status or system services
98d522f475Smrg				   and go straight to the queue */
99d522f475Smrg	    (void) system(pcommand);
100d522f475Smrg#else /* VMS */
101d522f475Smrg	    while (nonblocking_wait() > 0)
102d522f475Smrg#endif /* VMS */
103d522f475Smrg		;
104d522f475Smrg	    Printer = 0;
105d522f475Smrg	    initialized = 0;
106d522f475Smrg	    TRACE(("closed printer\n"));
107d522f475Smrg	}
108d522f475Smrg    }
109d522f475Smrg}
110d522f475Smrg
111d522f475Smrgstatic void
112956cc18dSsnjprintCursorLine(XtermWidget xw)
113d522f475Smrg{
114956cc18dSsnj    TScreen *screen = TScreenOf(xw);
115d522f475Smrg
116d522f475Smrg    TRACE(("printCursorLine\n"));
11720d2c4d2Smrg    printLine(xw, screen->cur_row, '\n', getPrinterFlags(xw, NULL, 0));
118d522f475Smrg}
119d522f475Smrg
120d522f475Smrg#define NO_COLOR	((unsigned)-1)
121d522f475Smrg
122d522f475Smrg/*
123d522f475Smrg * DEC's manual doesn't document whether trailing blanks are removed, or what
124d522f475Smrg * happens with a line that is entirely blank.  This function prints the
125d522f475Smrg * characters that xterm would allow as a selection (which may include blanks).
126d522f475Smrg */
127d522f475Smrgstatic void
12820d2c4d2SmrgprintLine(XtermWidget xw, int row, unsigned chr, PrinterFlags * p)
129d522f475Smrg{
130956cc18dSsnj    TScreen *screen = TScreenOf(xw);
131d522f475Smrg    int inx = ROW2INX(screen, row);
132956cc18dSsnj    LineData *ld;
133d522f475Smrg    Char attr = 0;
134d522f475Smrg    unsigned ch;
135d522f475Smrg    int last = MaxCols(screen);
136d522f475Smrg    int col;
137d522f475Smrg#if OPT_ISO_COLORS && OPT_PRINT_COLORS
138956cc18dSsnj#define ColorOf(ld,col) (ld->color[col])
139d522f475Smrg#endif
140d522f475Smrg    unsigned fg = NO_COLOR, last_fg = NO_COLOR;
141d522f475Smrg    unsigned bg = NO_COLOR, last_bg = NO_COLOR;
142d522f475Smrg    int cs = CSET_IN;
143d522f475Smrg    int last_cs = CSET_IN;
144d522f475Smrg
145956cc18dSsnj    ld = getLineData(screen, inx);
14620d2c4d2Smrg    if (ld == 0)
14720d2c4d2Smrg	return;
14820d2c4d2Smrg
149d522f475Smrg    TRACE(("printLine(row=%d/%d, top=%d:%d, chr=%d):%s\n",
150d522f475Smrg	   row, ROW2INX(screen, row), screen->topline, screen->max_row, chr,
151956cc18dSsnj	   visibleIChars(ld->charData, (unsigned) last)));
152956cc18dSsnj
153d522f475Smrg    while (last > 0) {
154956cc18dSsnj	if ((ld->attribs[last - 1] & CHARDRAWN) == 0)
155d522f475Smrg	    last--;
156d522f475Smrg	else
157d522f475Smrg	    break;
158d522f475Smrg    }
159d522f475Smrg    if (last) {
16020d2c4d2Smrg	if (p->print_attributes) {
161956cc18dSsnj	    send_CharSet(xw, ld);
162956cc18dSsnj	    send_SGR(xw, 0, NO_COLOR, NO_COLOR);
163d522f475Smrg	}
164d522f475Smrg	for (col = 0; col < last; col++) {
165956cc18dSsnj	    ch = ld->charData[col];
166d522f475Smrg#if OPT_PRINT_COLORS
167d522f475Smrg	    if (screen->colorMode) {
16820d2c4d2Smrg		if (p->print_attributes > 1) {
169956cc18dSsnj		    fg = (ld->attribs[col] & FG_COLOR)
170956cc18dSsnj			? extract_fg(xw, ColorOf(ld, col), ld->attribs[col])
171d522f475Smrg			: NO_COLOR;
172956cc18dSsnj		    bg = (ld->attribs[col] & BG_COLOR)
173956cc18dSsnj			? extract_bg(xw, ColorOf(ld, col), ld->attribs[col])
174d522f475Smrg			: NO_COLOR;
175d522f475Smrg		}
176d522f475Smrg	    }
177d522f475Smrg#endif
178956cc18dSsnj	    if ((((ld->attribs[col] & SGR_MASK) != attr)
179d522f475Smrg#if OPT_PRINT_COLORS
180d522f475Smrg		 || (last_fg != fg) || (last_bg != bg)
181d522f475Smrg#endif
182d522f475Smrg		)
183d522f475Smrg		&& ch) {
184956cc18dSsnj		attr = CharOf(ld->attribs[col] & SGR_MASK);
18520d2c4d2Smrg#if OPT_PRINT_COLORS
186d522f475Smrg		last_fg = fg;
187d522f475Smrg		last_bg = bg;
18820d2c4d2Smrg#endif
18920d2c4d2Smrg		if (p->print_attributes)
190956cc18dSsnj		    send_SGR(xw, attr, fg, bg);
191d522f475Smrg	    }
192d522f475Smrg
193d522f475Smrg	    if (ch == 0)
194d522f475Smrg		ch = ' ';
195d522f475Smrg
196d522f475Smrg#if OPT_WIDE_CHARS
197d522f475Smrg	    if (screen->utf8_mode)
198d522f475Smrg		cs = CSET_IN;
199d522f475Smrg	    else
200d522f475Smrg#endif
201d522f475Smrg		cs = (ch >= ' ' && ch != ANSI_DEL) ? CSET_IN : CSET_OUT;
202d522f475Smrg	    if (last_cs != cs) {
20320d2c4d2Smrg		if (p->print_attributes) {
204956cc18dSsnj		    charToPrinter(xw,
205956cc18dSsnj				  (unsigned) ((cs == CSET_OUT)
206d522f475Smrg					      ? SHIFT_OUT
207d522f475Smrg					      : SHIFT_IN));
208d522f475Smrg		}
209d522f475Smrg		last_cs = cs;
210d522f475Smrg	    }
211d522f475Smrg
212d522f475Smrg	    /* FIXME:  we shouldn't have to map back from the
213d522f475Smrg	     * alternate character set, except that the
214d522f475Smrg	     * corresponding charset information is not encoded
215d522f475Smrg	     * into the CSETS array.
216d522f475Smrg	     */
217956cc18dSsnj	    charToPrinter(xw,
218956cc18dSsnj			  ((cs == CSET_OUT)
219d522f475Smrg			   ? (ch == ANSI_DEL ? 0x5f : (ch + 0x5f))
220d522f475Smrg			   : ch));
221d522f475Smrg	    if_OPT_WIDE_CHARS(screen, {
222956cc18dSsnj		size_t off;
223956cc18dSsnj		for_each_combData(off, ld) {
224956cc18dSsnj		    ch = ld->combData[off][col];
225956cc18dSsnj		    if (ch == 0)
226d522f475Smrg			break;
227956cc18dSsnj		    charToPrinter(xw, ch);
228d522f475Smrg		}
229d522f475Smrg	    });
230d522f475Smrg	}
23120d2c4d2Smrg	if (p->print_attributes) {
232956cc18dSsnj	    send_SGR(xw, 0, NO_COLOR, NO_COLOR);
233d522f475Smrg	    if (cs != CSET_IN)
234956cc18dSsnj		charToPrinter(xw, SHIFT_IN);
235d522f475Smrg	}
236d522f475Smrg    }
23720d2c4d2Smrg
23820d2c4d2Smrg    /* finish line (protocol for attributes needs a CR */
23920d2c4d2Smrg    if (p->print_attributes)
240956cc18dSsnj	charToPrinter(xw, '\r');
24120d2c4d2Smrg
24220d2c4d2Smrg    if (chr && !(p->printer_newline)) {
24320d2c4d2Smrg	if (LineTstWrapped(ld))
24420d2c4d2Smrg	    chr = '\0';
24520d2c4d2Smrg    }
24620d2c4d2Smrg
24720d2c4d2Smrg    if (chr)
24820d2c4d2Smrg	charToPrinter(xw, chr);
249956cc18dSsnj
250956cc18dSsnj    return;
251d522f475Smrg}
252d522f475Smrg
25320d2c4d2Smrg#define PrintNewLine() (unsigned) (((top < bot) || p->printer_newline) ? '\n' : '\0')
25420d2c4d2Smrg
255d522f475Smrgvoid
25620d2c4d2SmrgxtermPrintScreen(XtermWidget xw, Bool use_DECPEX, PrinterFlags * p)
257d522f475Smrg{
258956cc18dSsnj    if (XtIsRealized((Widget) xw)) {
259956cc18dSsnj	TScreen *screen = TScreenOf(xw);
26020d2c4d2Smrg	Bool extent = (use_DECPEX && p->printer_extent);
261d522f475Smrg	int top = extent ? 0 : screen->top_marg;
262d522f475Smrg	int bot = extent ? screen->max_row : screen->bot_marg;
263d522f475Smrg	int was_open = initialized;
264d522f475Smrg
265d522f475Smrg	TRACE(("xtermPrintScreen, rows %d..%d\n", top, bot));
266d522f475Smrg
26720d2c4d2Smrg	while (top <= bot) {
26820d2c4d2Smrg	    printLine(xw, top, PrintNewLine(), p);
26920d2c4d2Smrg	    ++top;
27020d2c4d2Smrg	}
27120d2c4d2Smrg	if (p->printer_formfeed)
272956cc18dSsnj	    charToPrinter(xw, '\f');
273d522f475Smrg
274d522f475Smrg	if (!was_open || screen->printer_autoclose) {
275956cc18dSsnj	    closePrinter(xw);
276d522f475Smrg	}
277d522f475Smrg    } else {
27820d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
279d522f475Smrg    }
280d522f475Smrg}
281d522f475Smrg
282d522f475Smrg/*
283d522f475Smrg * If the alternate screen is active, we'll print only that.  Otherwise, print
284d522f475Smrg * the normal screen plus all scrolled-back lines.  The distinction is made
285d522f475Smrg * because the normal screen's buffer is part of the overall scrollback buffer.
286d522f475Smrg */
287956cc18dSsnjvoid
28820d2c4d2SmrgxtermPrintEverything(XtermWidget xw, PrinterFlags * p)
289d522f475Smrg{
290956cc18dSsnj    TScreen *screen = TScreenOf(xw);
291d522f475Smrg    int top = 0;
292d522f475Smrg    int bot = screen->max_row;
293d522f475Smrg    int was_open = initialized;
294d522f475Smrg
295956cc18dSsnj    if (!screen->whichBuf) {
296956cc18dSsnj	top = -screen->savedlines - screen->topline;
297956cc18dSsnj	bot -= screen->topline;
298956cc18dSsnj    }
299d522f475Smrg
300d522f475Smrg    TRACE(("xtermPrintEverything, rows %d..%d\n", top, bot));
30120d2c4d2Smrg    while (top <= bot) {
30220d2c4d2Smrg	printLine(xw, top, PrintNewLine(), p);
30320d2c4d2Smrg	++top;
30420d2c4d2Smrg    }
30520d2c4d2Smrg    if (p->printer_formfeed)
306956cc18dSsnj	charToPrinter(xw, '\f');
307d522f475Smrg
308d522f475Smrg    if (!was_open || screen->printer_autoclose) {
309956cc18dSsnj	closePrinter(xw);
310d522f475Smrg    }
311d522f475Smrg}
312d522f475Smrg
313d522f475Smrgstatic void
314956cc18dSsnjsend_CharSet(XtermWidget xw, LineData * ld)
315d522f475Smrg{
316d522f475Smrg#if OPT_DEC_CHRSET
31720d2c4d2Smrg    const char *msg = 0;
318d522f475Smrg
319956cc18dSsnj    switch (GetLineDblCS(ld)) {
320d522f475Smrg    case CSET_SWL:
321d522f475Smrg	msg = "\033#5";
322d522f475Smrg	break;
323d522f475Smrg    case CSET_DHL_TOP:
324d522f475Smrg	msg = "\033#3";
325d522f475Smrg	break;
326d522f475Smrg    case CSET_DHL_BOT:
327d522f475Smrg	msg = "\033#4";
328d522f475Smrg	break;
329d522f475Smrg    case CSET_DWL:
330d522f475Smrg	msg = "\033#6";
331d522f475Smrg	break;
332d522f475Smrg    }
333d522f475Smrg    if (msg != 0)
334956cc18dSsnj	stringToPrinter(xw, msg);
335d522f475Smrg#else
336956cc18dSsnj    (void) xw;
337956cc18dSsnj    (void) ld;
338d522f475Smrg#endif /* OPT_DEC_CHRSET */
339d522f475Smrg}
340d522f475Smrg
341d522f475Smrgstatic void
342956cc18dSsnjsend_SGR(XtermWidget xw, unsigned attr, unsigned fg, unsigned bg)
343d522f475Smrg{
344d522f475Smrg    char msg[80];
345d522f475Smrg    strcpy(msg, "\033[0");
346d522f475Smrg    if (attr & BOLD)
347d522f475Smrg	strcat(msg, ";1");
348d522f475Smrg    if (attr & UNDERLINE)
349d522f475Smrg	strcat(msg, ";4");	/* typo? DEC documents this as '2' */
350d522f475Smrg    if (attr & BLINK)
351d522f475Smrg	strcat(msg, ";5");
352d522f475Smrg    if (attr & INVERSE)		/* typo? DEC documents this as invisible */
353d522f475Smrg	strcat(msg, ";7");
354d522f475Smrg#if OPT_PRINT_COLORS
355d522f475Smrg    if (bg != NO_COLOR) {
356d522f475Smrg	sprintf(msg + strlen(msg), ";%u", (bg < 8) ? (40 + bg) : (92 + bg));
357d522f475Smrg    }
358d522f475Smrg    if (fg != NO_COLOR) {
359d522f475Smrg#if OPT_PC_COLORS
36020d2c4d2Smrg	if (TScreenOf(xw)->boldColors
361d522f475Smrg	    && fg > 8
362d522f475Smrg	    && (attr & BOLD) != 0)
363d522f475Smrg	    fg -= 8;
364d522f475Smrg#endif
365d522f475Smrg	sprintf(msg + strlen(msg), ";%u", (fg < 8) ? (30 + fg) : (82 + fg));
366d522f475Smrg    }
367d522f475Smrg#else
368d522f475Smrg    (void) bg;
369d522f475Smrg    (void) fg;
370d522f475Smrg#endif
371d522f475Smrg    strcat(msg, "m");
372956cc18dSsnj    stringToPrinter(xw, msg);
373d522f475Smrg}
374d522f475Smrg
375d522f475Smrg/*
376d522f475Smrg * This implementation only knows how to write to a pipe.
377d522f475Smrg */
378d522f475Smrgstatic void
379956cc18dSsnjcharToPrinter(XtermWidget xw, unsigned chr)
380d522f475Smrg{
381956cc18dSsnj    TScreen *screen = TScreenOf(xw);
382d522f475Smrg
383956cc18dSsnj    if (!initialized && xtermHasPrinter(xw)) {
384d522f475Smrg#if defined(VMS)
385d522f475Smrg	/*
386d522f475Smrg	 * This implementation only knows how to write to a file.  When the
387d522f475Smrg	 * file is closed the print command executes.  Print command must be of
388d522f475Smrg	 * the form:
389d522f475Smrg	 *   print/que=name/delete [/otherflags].
390d522f475Smrg	 */
391d522f475Smrg	Printer = fopen(VMS_TEMP_PRINT_FILE, "w");
392d522f475Smrg#else
393d522f475Smrg	/*
394d522f475Smrg	 * This implementation only knows how to write to a pipe.
395d522f475Smrg	 */
396d522f475Smrg	FILE *input;
397d522f475Smrg	int my_pipe[2];
398d522f475Smrg	int c;
399d522f475Smrg
400d522f475Smrg	if (pipe(my_pipe))
401d522f475Smrg	    SysError(ERROR_FORK);
402d522f475Smrg	if ((Printer_pid = fork()) < 0)
403d522f475Smrg	    SysError(ERROR_FORK);
404d522f475Smrg
405d522f475Smrg	if (Printer_pid == 0) {
40620d2c4d2Smrg	    TRACE_CLOSE();
407d522f475Smrg	    close(my_pipe[1]);	/* printer is silent */
408d522f475Smrg	    close(screen->respond);
409d522f475Smrg
410d522f475Smrg	    close(fileno(stdout));
411d522f475Smrg	    dup2(fileno(stderr), 1);
412d522f475Smrg
413d522f475Smrg	    if (fileno(stderr) != 2) {
414d522f475Smrg		dup2(fileno(stderr), 2);
415d522f475Smrg		close(fileno(stderr));
416d522f475Smrg	    }
417d522f475Smrg
418d522f475Smrg	    /* don't want privileges! */
419d522f475Smrg	    if (xtermResetIds(screen) < 0)
420d522f475Smrg		exit(1);
421d522f475Smrg
422d522f475Smrg	    Printer = popen(screen->printer_command, "w");
423d522f475Smrg	    input = fdopen(my_pipe[0], "r");
424d522f475Smrg	    while ((c = fgetc(input)) != EOF) {
425d522f475Smrg		fputc(c, Printer);
426d522f475Smrg		if (isForm(c))
427d522f475Smrg		    fflush(Printer);
428d522f475Smrg	    }
429d522f475Smrg	    pclose(Printer);
430d522f475Smrg	    exit(0);
431d522f475Smrg	} else {
432d522f475Smrg	    close(my_pipe[0]);	/* won't read from printer */
433d522f475Smrg	    Printer = fdopen(my_pipe[1], "w");
434d522f475Smrg	    TRACE(("opened printer from pid %d/%d\n",
43520d2c4d2Smrg		   (int) getpid(), (int) Printer_pid));
436d522f475Smrg	}
437d522f475Smrg#endif
438d522f475Smrg	initialized++;
439d522f475Smrg    }
440d522f475Smrg    if (Printer != 0) {
441d522f475Smrg#if OPT_WIDE_CHARS
442d522f475Smrg	if (chr > 127) {
443d522f475Smrg	    Char temp[10];
444d522f475Smrg	    *convertToUTF8(temp, chr) = 0;
445d522f475Smrg	    fputs((char *) temp, Printer);
446d522f475Smrg	} else
447d522f475Smrg#endif
448d522f475Smrg	    fputc((int) chr, Printer);
449d522f475Smrg	if (isForm(chr))
450d522f475Smrg	    fflush(Printer);
451d522f475Smrg    }
452d522f475Smrg}
453d522f475Smrg
454d522f475Smrgstatic void
45520d2c4d2SmrgstringToPrinter(XtermWidget xw, const char *str)
456d522f475Smrg{
457d522f475Smrg    while (*str)
458956cc18dSsnj	charToPrinter(xw, CharOf(*str++));
459d522f475Smrg}
460d522f475Smrg
461d522f475Smrg/*
462d522f475Smrg * This module implements the MC (Media Copy) and related printing control
463d522f475Smrg * sequences for VTxxx emulation.  This is based on the description in the
464d522f475Smrg * VT330/VT340 Programmer Reference Manual EK-VT3XX-TP-001 (Digital Equipment
465d522f475Smrg * Corp., March 1987).
466d522f475Smrg */
467d522f475Smrgvoid
468956cc18dSsnjxtermMediaControl(XtermWidget xw, int param, int private_seq)
469d522f475Smrg{
470d522f475Smrg    TRACE(("MediaCopy param=%d, private=%d\n", param, private_seq));
471d522f475Smrg
472d522f475Smrg    if (private_seq) {
473d522f475Smrg	switch (param) {
474d522f475Smrg	case 1:
475956cc18dSsnj	    printCursorLine(xw);
476d522f475Smrg	    break;
477d522f475Smrg	case 4:
478956cc18dSsnj	    setPrinterControlMode(xw, 0);
479d522f475Smrg	    break;
480d522f475Smrg	case 5:
481956cc18dSsnj	    setPrinterControlMode(xw, 1);
482d522f475Smrg	    break;
483d522f475Smrg	case 10:		/* VT320 */
48420d2c4d2Smrg	    xtermPrintScreen(xw, False, getPrinterFlags(xw, NULL, 0));
485d522f475Smrg	    break;
486d522f475Smrg	case 11:		/* VT320 */
48720d2c4d2Smrg	    xtermPrintEverything(xw, getPrinterFlags(xw, NULL, 0));
488d522f475Smrg	    break;
489d522f475Smrg	}
490d522f475Smrg    } else {
491d522f475Smrg	switch (param) {
492d522f475Smrg	case -1:
493d522f475Smrg	case 0:
49420d2c4d2Smrg	    xtermPrintScreen(xw, True, getPrinterFlags(xw, NULL, 0));
495d522f475Smrg	    break;
496d522f475Smrg	case 4:
497956cc18dSsnj	    setPrinterControlMode(xw, 0);
498d522f475Smrg	    break;
499d522f475Smrg	case 5:
500956cc18dSsnj	    setPrinterControlMode(xw, 2);
501d522f475Smrg	    break;
502d522f475Smrg	}
503d522f475Smrg    }
504d522f475Smrg}
505d522f475Smrg
506d522f475Smrg/*
507d522f475Smrg * When in autoprint mode, the printer prints a line from the screen when you
508d522f475Smrg * move the cursor off that line with an LF, FF, or VT character, or an
509d522f475Smrg * autowrap occurs.  The printed line ends with a CR and the character (LF, FF
510d522f475Smrg * or VT) that moved the cursor off the previous line.
511d522f475Smrg */
512d522f475Smrgvoid
513956cc18dSsnjxtermAutoPrint(XtermWidget xw, unsigned chr)
514d522f475Smrg{
515956cc18dSsnj    TScreen *screen = TScreenOf(xw);
516d522f475Smrg
517d522f475Smrg    if (screen->printer_controlmode == 1) {
518d522f475Smrg	TRACE(("AutoPrint %d\n", chr));
51920d2c4d2Smrg	printLine(xw, screen->cursorp.row, chr, getPrinterFlags(xw, NULL, 0));
520d522f475Smrg	if (Printer != 0)
521d522f475Smrg	    fflush(Printer);
522d522f475Smrg    }
523d522f475Smrg}
524d522f475Smrg
525d522f475Smrg/*
526d522f475Smrg * When in printer controller mode, the terminal sends received characters to
527d522f475Smrg * the printer without displaying them on the screen. The terminal sends all
528d522f475Smrg * characters and control sequences to the printer, except NUL, XON, XOFF, and
529d522f475Smrg * the printer controller sequences.
530d522f475Smrg *
531d522f475Smrg * This function eats characters, returning 0 as long as it must buffer or
532d522f475Smrg * divert to the printer.  We're only invoked here when in printer controller
533d522f475Smrg * mode, and handle the exit from that mode.
534d522f475Smrg */
535d522f475Smrg#define LB '['
536d522f475Smrg
537d522f475Smrgint
538956cc18dSsnjxtermPrinterControl(XtermWidget xw, int chr)
539d522f475Smrg{
540956cc18dSsnj    TScreen *screen = TScreenOf(xw);
541d522f475Smrg    /* *INDENT-OFF* */
542d522f475Smrg    static struct {
543d522f475Smrg	Char seq[5];
544d522f475Smrg	int active;
545d522f475Smrg    } tbl[] = {
546d522f475Smrg	{ { ANSI_CSI, '5', 'i'      }, 2 },
547d522f475Smrg	{ { ANSI_CSI, '4', 'i'      }, 0 },
548d522f475Smrg	{ { ANSI_ESC, LB,  '5', 'i' }, 2 },
549d522f475Smrg	{ { ANSI_ESC, LB,  '4', 'i' }, 0 },
550d522f475Smrg    };
551d522f475Smrg    /* *INDENT-ON* */
552d522f475Smrg
553d522f475Smrg    static Char bfr[10];
554d522f475Smrg    static size_t length;
555d522f475Smrg    size_t n;
556d522f475Smrg
557d522f475Smrg    TRACE(("In printer:%04X\n", chr));
558d522f475Smrg
559d522f475Smrg    switch (chr) {
560d522f475Smrg    case 0:
561d522f475Smrg    case CTRL('Q'):
562d522f475Smrg    case CTRL('S'):
563d522f475Smrg	return 0;		/* ignored by application */
564d522f475Smrg
565d522f475Smrg    case ANSI_CSI:
566d522f475Smrg    case ANSI_ESC:
567d522f475Smrg    case '[':
568d522f475Smrg    case '4':
569d522f475Smrg    case '5':
570d522f475Smrg    case 'i':
5714e40088cSchristos	bfr[length++] = CharOf(chr);
572d522f475Smrg	for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); n++) {
573d522f475Smrg	    size_t len = Strlen(tbl[n].seq);
574d522f475Smrg
575d522f475Smrg	    if (length == len
576d522f475Smrg		&& Strcmp(bfr, tbl[n].seq) == 0) {
577956cc18dSsnj		setPrinterControlMode(xw, tbl[n].active);
578d522f475Smrg		if (screen->printer_autoclose
579d522f475Smrg		    && screen->printer_controlmode == 0)
580956cc18dSsnj		    closePrinter(xw);
581d522f475Smrg		length = 0;
582d522f475Smrg		return 0;
583d522f475Smrg	    } else if (len > length
584d522f475Smrg		       && Strncmp(bfr, tbl[n].seq, length) == 0) {
585d522f475Smrg		return 0;
586d522f475Smrg	    }
587d522f475Smrg	}
588d522f475Smrg	length--;
589d522f475Smrg
590d522f475Smrg	/* FALLTHRU */
591d522f475Smrg
592d522f475Smrg    default:
593d522f475Smrg	for (n = 0; n < length; n++)
594956cc18dSsnj	    charToPrinter(xw, bfr[n]);
5954e40088cSchristos	bfr[0] = CharOf(chr);
596d522f475Smrg	length = 1;
597d522f475Smrg	return 0;
598d522f475Smrg    }
599d522f475Smrg}
600d522f475Smrg
601d522f475Smrg/*
602d522f475Smrg * If there is no printer command, we will ignore printer controls.
603d522f475Smrg */
604d522f475SmrgBool
605956cc18dSsnjxtermHasPrinter(XtermWidget xw)
606d522f475Smrg{
607956cc18dSsnj    TScreen *screen = TScreenOf(xw);
608d522f475Smrg
609d522f475Smrg    return (strlen(screen->printer_command) != 0);
610d522f475Smrg}
611d522f475Smrg
612d522f475Smrg#define showPrinterControlMode(mode) \
613d522f475Smrg		(((mode) == 0) \
614d522f475Smrg		 ? "normal" \
615d522f475Smrg		 : ((mode) == 1 \
616d522f475Smrg		    ? "autoprint" \
617d522f475Smrg		    : "printer controller"))
618d522f475Smrg
619d522f475Smrgvoid
620956cc18dSsnjsetPrinterControlMode(XtermWidget xw, int mode)
621d522f475Smrg{
62220d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
62320d2c4d2Smrg
624956cc18dSsnj    if (xtermHasPrinter(xw)
62520d2c4d2Smrg	&& screen->printer_controlmode != mode) {
626d522f475Smrg	TRACE(("%s %s mode\n",
627d522f475Smrg	       (mode
628d522f475Smrg		? "set"
629d522f475Smrg		: "reset"),
630d522f475Smrg	       (mode
631d522f475Smrg		? showPrinterControlMode(mode)
63220d2c4d2Smrg		: showPrinterControlMode(screen->printer_controlmode))));
63320d2c4d2Smrg	screen->printer_controlmode = mode;
634d522f475Smrg	update_print_redir();
635d522f475Smrg    }
636d522f475Smrg}
63720d2c4d2Smrg
63820d2c4d2SmrgPrinterFlags *
63920d2c4d2SmrggetPrinterFlags(XtermWidget xw, String * params, Cardinal *param_count)
64020d2c4d2Smrg{
64120d2c4d2Smrg    /* *INDENT-OFF* */
64220d2c4d2Smrg    static const struct {
64320d2c4d2Smrg	const char *name;
64420d2c4d2Smrg	unsigned    offset;
64520d2c4d2Smrg	int	    value;
64620d2c4d2Smrg    } table[] = {
64720d2c4d2Smrg	{ "noFormFeed", XtOffsetOf(PrinterFlags, printer_formfeed), 0 },
64820d2c4d2Smrg	{ "FormFeed",	XtOffsetOf(PrinterFlags, printer_formfeed), 1 },
64920d2c4d2Smrg	{ "noNewLine",	XtOffsetOf(PrinterFlags, printer_newline),  0 },
65020d2c4d2Smrg	{ "NewLine",	XtOffsetOf(PrinterFlags, printer_newline),  1 },
65120d2c4d2Smrg	{ "noAttrs",	XtOffsetOf(PrinterFlags, print_attributes), 0 },
65220d2c4d2Smrg	{ "monoAttrs",	XtOffsetOf(PrinterFlags, print_attributes), 1 },
65320d2c4d2Smrg	{ "colorAttrs", XtOffsetOf(PrinterFlags, print_attributes), 2 },
65420d2c4d2Smrg    };
65520d2c4d2Smrg    /* *INDENT-ON* */
65620d2c4d2Smrg
65720d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
65820d2c4d2Smrg    PrinterFlags *result = &(screen->printer_flags);
65920d2c4d2Smrg
66020d2c4d2Smrg    TRACE(("getPrinterFlags %d params\n", param_count ? *param_count : 0));
66120d2c4d2Smrg
66220d2c4d2Smrg    result->printer_extent = screen->printer_extent;
66320d2c4d2Smrg    result->printer_formfeed = screen->printer_formfeed;
66420d2c4d2Smrg    result->printer_newline = screen->printer_newline;
66520d2c4d2Smrg    result->print_attributes = screen->print_attributes;
66620d2c4d2Smrg
66720d2c4d2Smrg    if (param_count != 0 && *param_count != 0) {
66820d2c4d2Smrg	Cardinal j;
66920d2c4d2Smrg	unsigned k;
67020d2c4d2Smrg	for (j = 0; j < *param_count; ++j) {
67120d2c4d2Smrg	    TRACE(("param%d:%s\n", j, params[j]));
67220d2c4d2Smrg	    for (k = 0; k < XtNumber(table); ++k) {
67320d2c4d2Smrg		if (!x_strcasecmp(params[j], table[k].name)) {
674a1f3da82Smrg		    int *ptr = (int *) (void *) ((char *) result + table[k].offset);
67520d2c4d2Smrg		    TRACE(("...PrinterFlags(%s) %d->%d\n",
67620d2c4d2Smrg			   table[k].name,
67720d2c4d2Smrg			   *ptr,
67820d2c4d2Smrg			   table[k].value));
67920d2c4d2Smrg		    *ptr = table[k].value;
68020d2c4d2Smrg		    break;
68120d2c4d2Smrg		}
68220d2c4d2Smrg	    }
68320d2c4d2Smrg	}
68420d2c4d2Smrg    }
68520d2c4d2Smrg
68620d2c4d2Smrg    return result;
68720d2c4d2Smrg}
688