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