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