Bring back --with-sys-screenrc configure flag.
[screen-lua.git] / src / ansi.c
blob46e3e01e082b8e9d8ee888a770dbc29a7d9aec7e
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include <fcntl.h>
31 #ifndef sun /* we want to know about TIOCPKT. */
32 # include <sys/ioctl.h>
33 #endif
35 #include "config.h"
36 #include "screen.h"
37 #include "braille.h"
38 #include "extern.h"
39 #include "logfile.h"
41 extern struct display *display, *displays;
42 extern struct win *fore; /* for 83 escape */
43 extern struct layer *flayer; /* for 83 escape */
45 extern struct NewWindow nwin_default; /* for ResetWindow() */
46 extern int nversion; /* numerical version of screen */
47 extern int log_flush, logtstamp_on, logtstamp_after;
48 extern char *logtstamp_string;
49 extern char *captionstring;
50 extern char *hstatusstring;
51 extern char *wliststr;
52 #ifdef COPY_PASTE
53 extern int compacthist;
54 #endif
55 #ifdef MULTIUSER
56 extern struct acluser *EffectiveAclUser;
57 #endif
59 int Z0width, Z1width; /* widths for Z0/Z1 switching */
61 /* globals set in WriteString */
62 static struct win *curr; /* window we are working on */
63 static int rows, cols; /* window size of the curr window */
65 int visual_bell = 0;
66 int use_hardstatus = 1; /* display status line in hs */
67 char *printcmd = 0;
68 int use_altscreen = 0; /* enable alternate screen support? */
70 unsigned char *blank; /* line filled with spaces */
71 unsigned char *null; /* line filled with '\0' */
73 struct mline mline_old;
74 struct mline mline_blank;
75 struct mline mline_null;
77 struct mchar mchar_null;
78 struct mchar mchar_blank = {' ' /* , 0, 0, ... */};
79 struct mchar mchar_so = {' ', A_SO /* , 0, 0, ... */};
81 int renditions[NUM_RENDS] = {65529 /* =ub */, 65531 /* =b */, 65533 /* =u */ };
83 /* keep string_t and string_t_string in sync! */
84 static char *string_t_string[] =
86 "NONE",
87 "DCS", /* Device control string */
88 "OSC", /* Operating system command */
89 "APC", /* Application program command */
90 /* - used for status change */
91 "PM", /* Privacy message */
92 "AKA", /* title for current screen */
93 "GM", /* Global message to every display */
94 "STATUS" /* User hardstatus line */
97 /* keep state_t and state_t_string in sync! */
98 static char *state_t_string[] =
100 "LIT", /* Literal input */
101 "ESC", /* Start of escape sequence */
102 "ASTR", /* Start of control string */
103 "STRESC", /* ESC seen in control string */
104 "CSI", /* Reading arguments in "CSI Pn ;...*/
105 "PRIN", /* Printer mode */
106 "PRINESC", /* ESC seen in printer mode */
107 "PRINCSI", /* CSI seen in printer mode */
108 "PRIN4" /* CSI 4 seen in printer mode */
111 static int Special __P((int));
112 static void DoESC __P((int, int));
113 static void DoCSI __P((int, int));
114 static void StringStart __P((enum string_t));
115 static void StringChar __P((int));
116 static int StringEnd __P((void));
117 static void PrintStart __P((void));
118 static void PrintChar __P((int));
119 static void PrintFlush __P((void));
120 #ifdef FONT
121 static void DesignateCharset __P((int, int));
122 static void MapCharset __P((int));
123 static void MapCharsetR __P((int));
124 #endif
125 static void SaveCursor __P((struct cursor *));
126 static void RestoreCursor __P((struct cursor *));
127 static void BackSpace __P((void));
128 static void Return __P((void));
129 static void LineFeed __P((int));
130 static void ReverseLineFeed __P((void));
131 static void InsertChar __P((int));
132 static void DeleteChar __P((int));
133 static void DeleteLine __P((int));
134 static void InsertLine __P((int));
135 static void Scroll __P((char *, int, int, char *));
136 static void ForwardTab __P((void));
137 static void BackwardTab __P((void));
138 static void ClearScreen __P((void));
139 static void ClearFromBOS __P((void));
140 static void ClearToEOS __P((void));
141 static void ClearLineRegion __P((int, int));
142 static void CursorRight __P((int));
143 static void CursorUp __P((int));
144 static void CursorDown __P((int));
145 static void CursorLeft __P((int));
146 static void ASetMode __P((int));
147 static void SelectRendition __P((void));
148 static void RestorePosRendition __P((void));
149 static void FillWithEs __P((void));
150 static void FindAKA __P((void));
151 static void Report __P((char *, int, int));
152 static void ScrollRegion __P((int));
153 #ifdef COPY_PASTE
154 static void WAddLineToHist __P((struct win *, struct mline *));
155 #endif
156 static void WLogString __P((struct win *, char *, int));
157 static void WReverseVideo __P((struct win *, int));
158 static int WindowChangedCheck __P((char *, int, int *));
159 static void MFixLine __P((struct win *, int, struct mchar *));
160 static void MScrollH __P((struct win *, int, int, int, int, int));
161 static void MScrollV __P((struct win *, int, int, int, int));
162 static void MClearArea __P((struct win *, int, int, int, int, int));
163 static void MInsChar __P((struct win *, struct mchar *, int, int));
164 static void MPutChar __P((struct win *, struct mchar *, int, int));
165 static void MPutStr __P((struct win *, char *, int, struct mchar *, int, int));
166 static void MWrapChar __P((struct win *, struct mchar *, int, int, int, int));
167 #ifdef COLOR
168 static void MBceLine __P((struct win *, int, int, int, int));
169 #endif
171 #ifdef COLOR
172 # define CURR_BCE (curr->w_bce ? rend_getbg(&curr->w_rend) : 0)
173 #else
174 # define CURR_BCE 0
175 #endif
177 void
178 ResetAnsiState(p)
179 struct win *p;
181 p->w_state = LIT;
182 p->w_StringType = NONE;
185 void
186 ResetWindow(p)
187 register struct win *p;
189 register int i;
191 p->w_wrap = nwin_default.wrap;
192 p->w_origin = 0;
193 p->w_insert = 0;
194 p->w_revvid = 0;
195 p->w_mouse = 0;
196 p->w_curinv = 0;
197 p->w_curvvis = 0;
198 p->w_autolf = 0;
199 p->w_keypad = 0;
200 p->w_cursorkeys = 0;
201 p->w_top = 0;
202 p->w_bot = p->w_height - 1;
203 p->w_saved.on = 0;
204 p->w_x = p->w_y = 0;
205 p->w_state = LIT;
206 p->w_StringType = NONE;
207 bzero(p->w_tabs, p->w_width);
208 for (i = 8; i < p->w_width; i += 8)
209 p->w_tabs[i] = 1;
210 p->w_rend = mchar_null;
211 #ifdef FONT
212 ResetCharsets(p);
213 #endif
214 #ifdef COLOR
215 p->w_bce = nwin_default.bce;
216 #endif
219 /* adds max 22 bytes */
221 GetAnsiStatus(w, buf)
222 struct win *w;
223 char *buf;
225 char *p = buf;
227 if (w->w_state == LIT)
228 return 0;
230 strcpy(p, state_t_string[w->w_state]);
231 p += strlen(p);
232 if (w->w_intermediate)
234 *p++ = '-';
235 if (w->w_intermediate > 0xff)
236 p += AddXChar(p, w->w_intermediate >> 8);
237 p += AddXChar(p, w->w_intermediate & 0xff);
238 *p = 0;
240 if (w->w_state == ASTR || w->w_state == STRESC)
241 sprintf(p, "-%s", string_t_string[w->w_StringType]);
242 p += strlen(p);
243 return p - buf;
247 #ifdef FONT
249 void
250 ResetCharsets(p)
251 struct win *p;
253 p->w_gr = nwin_default.gr;
254 p->w_c1 = nwin_default.c1;
255 SetCharsets(p, "BBBB02");
256 if (nwin_default.charset)
257 SetCharsets(p, nwin_default.charset);
258 #ifdef ENCODINGS
259 ResetEncoding(p);
260 #endif
263 void
264 SetCharsets(p, s)
265 struct win *p;
266 char *s;
268 int i;
270 for (i = 0; i < 4 && *s; i++, s++)
271 if (*s != '.')
272 p->w_charsets[i] = ((*s == 'B') ? ASCII : *s);
273 if (*s && *s++ != '.')
274 p->w_Charset = s[-1] - '0';
275 if (*s && *s != '.')
276 p->w_CharsetR = *s - '0';
277 p->w_ss = 0;
278 p->w_FontL = p->w_charsets[p->w_Charset];
279 p->w_FontR = p->w_charsets[p->w_CharsetR];
281 #endif /* FONT */
283 /*****************************************************************/
287 * Here comes the vt100 emulator
288 * - writes logfiles,
289 * - sets timestamp and flags activity in window.
290 * - record program output in window scrollback
291 * - translate program output for the display and put it into the obuf.
294 void
295 WriteString(wp, buf, len)
296 struct win *wp;
297 register char *buf;
298 register int len;
300 register int c;
301 #ifdef FONT
302 register int font;
303 #endif
304 struct canvas *cv;
306 if (!len)
307 return;
308 if (wp->w_log)
309 WLogString(wp, buf, len);
311 /* set global variables (yuck!) */
312 curr = wp;
313 cols = curr->w_width;
314 rows = curr->w_height;
316 if (curr->w_silence)
317 SetTimeout(&curr->w_silenceev, curr->w_silencewait * 1000);
319 if (curr->w_monitor == MON_ON)
321 debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
322 curr->w_monitor = MON_FOUND;
325 if (cols > 0 && rows > 0)
329 c = (unsigned char)*buf++;
330 #ifdef FONT
331 # ifdef DW_CHARS
332 if (!curr->w_mbcs)
333 # endif
334 curr->w_rend.font = curr->w_FontL; /* Default: GL */
335 #endif
337 /* The next part is only for speedup */
338 if (curr->w_state == LIT &&
339 #ifdef UTF8
340 curr->w_encoding != UTF8 &&
341 #endif
342 #ifdef DW_CHARS
343 !is_dw_font(curr->w_rend.font) &&
344 # ifdef ENCODINGS
345 curr->w_rend.font != KANA && !curr->w_mbcs &&
346 # endif
347 #endif
348 #ifdef FONT
349 curr->w_rend.font != '<' &&
350 #endif
351 c >= ' ' && c != 0x7f &&
352 ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) && !curr->w_ss &&
353 !curr->w_insert && curr->w_x < cols - 1)
355 register int currx = curr->w_x;
356 char *imp = buf - 1;
358 while (currx < cols - 1)
360 currx++;
361 if (--len == 0)
362 break;
363 c = (unsigned char)*buf++;
364 if (c < ' ' || c == 0x7f || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
365 break;
367 currx -= curr->w_x;
368 if (currx > 0)
370 MPutStr(curr, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
371 LPutStr(&curr->w_layer, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
372 curr->w_x += currx;
374 if (len == 0)
375 break;
377 /* end of speedup code */
379 #ifdef UTF8
380 if (curr->w_encoding == UTF8)
382 c = FromUtf8(c, &curr->w_decodestate);
383 if (c == -1)
384 continue;
385 if (c == -2)
387 c = UCS_REPL;
388 /* try char again */
389 buf--;
390 len++;
392 if (c > 0xff)
393 debug1("read UNICODE %04x\n", c);
395 #endif
397 tryagain:
398 switch (curr->w_state)
400 case PRIN:
401 switch (c)
403 case '\033':
404 curr->w_state = PRINESC;
405 break;
406 default:
407 PrintChar(c);
409 break;
410 case PRINESC:
411 switch (c)
413 case '[':
414 curr->w_state = PRINCSI;
415 break;
416 default:
417 PrintChar('\033');
418 PrintChar(c);
419 curr->w_state = PRIN;
421 break;
422 case PRINCSI:
423 switch (c)
425 case '4':
426 curr->w_state = PRIN4;
427 break;
428 default:
429 PrintChar('\033');
430 PrintChar('[');
431 PrintChar(c);
432 curr->w_state = PRIN;
434 break;
435 case PRIN4:
436 switch (c)
438 case 'i':
439 curr->w_state = LIT;
440 PrintFlush();
441 if (curr->w_pdisplay && curr->w_pdisplay->d_printfd >= 0)
443 close(curr->w_pdisplay->d_printfd);
444 curr->w_pdisplay->d_printfd = -1;
446 curr->w_pdisplay = 0;
447 break;
448 default:
449 PrintChar('\033');
450 PrintChar('[');
451 PrintChar('4');
452 PrintChar(c);
453 curr->w_state = PRIN;
455 break;
456 case ASTR:
457 if (c == 0)
458 break;
459 if (c == '\033')
461 curr->w_state = STRESC;
462 break;
464 /* special xterm hack: accept SetStatus sequence. Yucc! */
465 /* allow ^E for title escapes */
466 if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
467 if (!curr->w_c1 || c != ('\\' ^ 0xc0))
469 StringChar(c);
470 break;
472 c = '\\';
473 /* FALLTHROUGH */
474 case STRESC:
475 switch (c)
477 case '\\':
478 if (StringEnd() == 0 || len <= 1)
479 break;
480 /* check if somewhere a status is displayed */
481 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
483 display = cv->c_display;
484 if (D_status == STATUS_ON_WIN)
485 break;
487 if (cv)
489 if (len > IOSIZE + 1)
490 len = IOSIZE + 1;
491 curr->w_outlen = len - 1;
492 bcopy(buf, curr->w_outbuf, len - 1);
493 return; /* wait till status is gone */
495 break;
496 case '\033':
497 StringChar('\033');
498 break;
499 default:
500 curr->w_state = ASTR;
501 StringChar('\033');
502 StringChar(c);
503 break;
505 break;
506 case ESC:
507 switch (c)
509 case '[':
510 curr->w_NumArgs = 0;
511 curr->w_intermediate = 0;
512 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
513 curr->w_state = CSI;
514 break;
515 case ']':
516 StringStart(OSC);
517 break;
518 case '_':
519 StringStart(APC);
520 break;
521 case 'P':
522 StringStart(DCS);
523 break;
524 case '^':
525 StringStart(PM);
526 break;
527 case '!':
528 StringStart(GM);
529 break;
530 case '"':
531 case 'k':
532 StringStart(AKA);
533 break;
534 default:
535 if (Special(c))
537 curr->w_state = LIT;
538 break;
540 debug1("not special. c = %x\n", c);
541 if (c >= ' ' && c <= '/')
543 if (curr->w_intermediate)
545 #ifdef DW_CHARS
546 if (curr->w_intermediate == '$')
547 c |= '$' << 8;
548 else
549 #endif
550 c = -1;
552 curr->w_intermediate = c;
554 else if (c >= '0' && c <= '~')
556 DoESC(c, curr->w_intermediate);
557 curr->w_state = LIT;
559 else
561 curr->w_state = LIT;
562 goto tryagain;
565 break;
566 case CSI:
567 switch (c)
569 case '0': case '1': case '2': case '3': case '4':
570 case '5': case '6': case '7': case '8': case '9':
571 if (curr->w_NumArgs < MAXARGS)
573 if (curr->w_args[curr->w_NumArgs] < 100000000)
574 curr->w_args[curr->w_NumArgs] =
575 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
577 break;
578 case ';':
579 case ':':
580 if (curr->w_NumArgs < MAXARGS)
581 curr->w_NumArgs++;
582 break;
583 default:
584 if (Special(c))
585 break;
586 if (c >= '@' && c <= '~')
588 if (curr->w_NumArgs < MAXARGS)
589 curr->w_NumArgs++;
590 DoCSI(c, curr->w_intermediate);
591 if (curr->w_state != PRIN)
592 curr->w_state = LIT;
594 else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
595 curr->w_intermediate = curr->w_intermediate ? -1 : c;
596 else
598 curr->w_state = LIT;
599 goto tryagain;
602 break;
603 case LIT:
604 default:
605 #ifdef DW_CHARS
606 if (curr->w_mbcs)
607 if (c <= ' ' || c == 0x7f || (c >= 0x80 && c < 0xa0 && curr->w_c1))
608 curr->w_mbcs = 0;
609 #endif
610 if (c < ' ')
612 if (c == '\033')
614 curr->w_intermediate = 0;
615 curr->w_state = ESC;
616 if (curr->w_autoaka < 0)
617 curr->w_autoaka = 0;
619 else
620 Special(c);
621 break;
623 if (c >= 0x80 && c < 0xa0 && curr->w_c1)
624 #ifdef FONT
625 if ((curr->w_FontR & 0xf0) != 0x20
626 # ifdef UTF8
627 || curr->w_encoding == UTF8
628 # endif
630 #endif
632 switch (c)
634 case 0xc0 ^ 'D':
635 case 0xc0 ^ 'E':
636 case 0xc0 ^ 'H':
637 case 0xc0 ^ 'M':
638 case 0xc0 ^ 'N': /* SS2 */
639 case 0xc0 ^ 'O': /* SS3 */
640 DoESC(c ^ 0xc0, 0);
641 break;
642 case 0xc0 ^ '[':
643 if (curr->w_autoaka < 0)
644 curr->w_autoaka = 0;
645 curr->w_NumArgs = 0;
646 curr->w_intermediate = 0;
647 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
648 curr->w_state = CSI;
649 break;
650 case 0xc0 ^ 'P':
651 StringStart(DCS);
652 break;
653 default:
654 break;
656 break;
659 #ifdef FONT
660 # ifdef DW_CHARS
661 if (!curr->w_mbcs)
663 # endif
664 if (c < 0x80 || curr->w_gr == 0)
665 curr->w_rend.font = curr->w_FontL;
666 # ifdef ENCODINGS
667 else if (curr->w_gr == 2 && !curr->w_ss)
668 curr->w_rend.font = curr->w_FontE;
669 # endif
670 else
671 curr->w_rend.font = curr->w_FontR;
672 # ifdef DW_CHARS
674 # endif
675 # ifdef UTF8
676 if (curr->w_encoding == UTF8)
678 if (curr->w_rend.font == '0')
680 struct mchar mc, *mcp;
682 debug1("SPECIAL %x\n", c);
683 mc.image = c;
684 mc.mbcs = 0;
685 mc.font = '0';
686 mcp = recode_mchar(&mc, 0, UTF8);
687 debug2("%02x %02x\n", mcp->image, mcp->font);
688 c = mcp->image | mcp->font << 8;
690 curr->w_rend.font = 0;
692 # ifdef DW_CHARS
693 if (curr->w_encoding == UTF8 && utf8_isdouble(c))
694 curr->w_mbcs = 0xff;
695 # endif
696 if (curr->w_encoding == UTF8 && c >= 0x0300 && utf8_iscomb(c))
698 int ox, oy;
699 struct mchar omc;
701 ox = curr->w_x - 1;
702 oy = curr->w_y;
703 if (ox < 0)
705 ox = curr->w_width - 1;
706 oy--;
708 if (oy < 0)
709 oy = 0;
710 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
711 if (omc.image == 0xff && omc.font == 0xff)
713 ox--;
714 if (ox >= 0)
716 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
717 omc.mbcs = 0xff;
720 if (ox >= 0)
722 utf8_handle_comb(c, &omc);
723 MFixLine(curr, oy, &omc);
724 copy_mchar2mline(&omc, &curr->w_mlines[oy], ox);
725 LPutChar(&curr->w_layer, &omc, ox, oy);
726 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
728 break;
730 font = curr->w_rend.font;
731 # endif
732 # ifdef DW_CHARS
733 # ifdef ENCODINGS
734 if (font == KANA && curr->w_encoding == SJIS && curr->w_mbcs == 0)
736 /* Lets see if it is the first byte of a kanji */
737 debug1("%x may be first of SJIS\n", c);
738 if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
740 debug("YES!\n");
741 curr->w_mbcs = c;
742 break;
745 # endif
746 if (font == 031 && c == 0x80 && !curr->w_mbcs)
747 font = curr->w_rend.font = 0;
748 if (is_dw_font(font) && c == ' ')
749 font = curr->w_rend.font = 0;
750 if (is_dw_font(font) || curr->w_mbcs)
752 int t = c;
753 if (curr->w_mbcs == 0)
755 curr->w_mbcs = c;
756 break;
758 if (curr->w_x == cols - 1)
760 curr->w_x += curr->w_wrap ? 1 : -1;
761 debug1("Patched w_x to %d\n", curr->w_x);
763 # ifdef UTF8
764 if (curr->w_encoding != UTF8)
765 # endif
767 c = curr->w_mbcs;
768 # ifdef ENCODINGS
769 if (font == KANA && curr->w_encoding == SJIS)
771 debug2("SJIS !! %x %x\n", c, t);
773 * SJIS -> EUC mapping:
774 * First byte:
775 * 81,82...9f -> 21,23...5d
776 * e0,e1...ef -> 5f,61...7d
777 * Second byte:
778 * 40-7e -> 21-5f
779 * 80-9e -> 60-7e
780 * 9f-fc -> 21-7e (increment first byte!)
782 if (0x40 <= t && t <= 0xfc && t != 0x7f)
784 if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
785 else c = (c - 0xc1) * 2 + 0x21;
786 if (t <= 0x7e) t -= 0x1f;
787 else if (t <= 0x9e) t -= 0x20;
788 else t -= 0x7e, c++;
789 curr->w_rend.font = KANJI;
791 else
793 /* Incomplete shift-jis - skip first byte */
794 c = t;
795 t = 0;
797 debug2("SJIS after %x %x\n", c, t);
799 # endif
800 if (t && curr->w_gr && font != 030 && font != 031)
802 t &= 0x7f;
803 if (t < ' ')
804 goto tryagain;
806 if (t == '\177')
807 break;
808 curr->w_mbcs = t;
811 # endif /* DW_CHARS */
812 if (font == '<' && c >= ' ')
814 font = curr->w_rend.font = 0;
815 c |= 0x80;
817 # ifdef UTF8
818 else if (curr->w_gr && curr->w_encoding != UTF8)
819 # else
820 else if (curr->w_gr)
821 # endif
823 #ifdef ENCODINGS
824 if (c == 0x80 && font == 0 && curr->w_encoding == GBK)
825 c = 0xa4;
826 else
827 c &= 0x7f;
828 if (c < ' ' && font != 031)
829 goto tryagain;
830 #else
831 c &= 0x7f;
832 if (c < ' ') /* this is ugly but kanji support */
833 goto tryagain; /* prevents nicer programming */
834 #endif
836 #endif /* FONT */
837 if (c == '\177')
838 break;
839 curr->w_rend.image = c;
840 #ifdef UTF8
841 if (curr->w_encoding == UTF8)
842 curr->w_rend.font = c >> 8;
843 #endif
844 #ifdef DW_CHARS
845 curr->w_rend.mbcs = curr->w_mbcs;
846 #endif
847 if (curr->w_x < cols - 1)
849 if (curr->w_insert)
851 save_mline(&curr->w_mlines[curr->w_y], cols);
852 MInsChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
853 LInsChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y, &mline_old);
854 curr->w_x++;
856 else
858 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
859 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
860 curr->w_x++;
863 else if (curr->w_x == cols - 1)
865 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
866 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
867 if (curr->w_wrap)
868 curr->w_x++;
870 else
872 MWrapChar(curr, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
873 LWrapChar(&curr->w_layer, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
874 if (curr->w_y != curr->w_bot && curr->w_y != curr->w_height - 1)
875 curr->w_y++;
876 curr->w_x = 1;
878 #ifdef FONT
879 # ifdef DW_CHARS
880 if (curr->w_mbcs)
882 curr->w_rend.mbcs = curr->w_mbcs = 0;
883 curr->w_x++;
885 # endif
886 if (curr->w_ss)
888 curr->w_FontL = curr->w_charsets[curr->w_Charset];
889 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
890 curr->w_rend.font = curr->w_FontL;
891 LSetRendition(&curr->w_layer, &curr->w_rend);
892 curr->w_ss = 0;
894 #endif /* FONT */
895 break;
898 while (--len);
900 if (!printcmd && curr->w_state == PRIN)
901 PrintFlush();
904 static void
905 WLogString(p, buf, len)
906 struct win *p;
907 char *buf;
908 int len;
910 if (!p->w_log)
911 return;
912 if (logtstamp_on && p->w_logsilence >= logtstamp_after * 2)
914 char *t = MakeWinMsg(logtstamp_string, p, '%');
915 logfwrite(p->w_log, t, strlen(t)); /* long time no write */
917 p->w_logsilence = 0;
918 if (logfwrite(p->w_log, buf, len) < 1)
920 WMsg(p, errno, "Error writing logfile");
921 logfclose(p->w_log);
922 p->w_log = 0;
924 if (!log_flush)
925 logfflush(p->w_log);
928 static int
929 Special(c)
930 register int c;
932 switch (c)
934 case '\b':
935 BackSpace();
936 return 1;
937 case '\r':
938 Return();
939 return 1;
940 case '\n':
941 if (curr->w_autoaka)
942 FindAKA();
943 case '\013': /* Vertical tab is the same as Line Feed */
944 LineFeed(0);
945 return 1;
946 case '\007':
947 WBell(curr, visual_bell);
948 return 1;
949 case '\t':
950 ForwardTab();
951 return 1;
952 #ifdef FONT
953 case '\017': /* SI */
954 MapCharset(G0);
955 return 1;
956 case '\016': /* SO */
957 MapCharset(G1);
958 return 1;
959 #endif
961 return 0;
964 static void
965 DoESC(c, intermediate)
966 int c, intermediate;
968 debug2("DoESC: %x - inter = %x\n", c, intermediate);
969 switch (intermediate)
971 case 0:
972 switch (c)
974 case 'E':
975 LineFeed(1);
976 break;
977 case 'D':
978 LineFeed(0);
979 break;
980 case 'M':
981 ReverseLineFeed();
982 break;
983 case 'H':
984 curr->w_tabs[curr->w_x] = 1;
985 break;
986 case 'Z': /* jph: Identify as VT100 */
987 Report("\033[?%d;%dc", 1, 2);
988 break;
989 case '7':
990 SaveCursor(&curr->w_saved);
991 break;
992 case '8':
993 RestoreCursor(&curr->w_saved);
994 break;
995 case 'c':
996 ClearScreen();
997 ResetWindow(curr);
998 LKeypadMode(&curr->w_layer, 0);
999 LCursorkeysMode(&curr->w_layer, 0);
1000 #ifndef TIOCPKT
1001 WNewAutoFlow(curr, 1);
1002 #endif
1003 /* XXX
1004 SetRendition(&mchar_null);
1005 InsertMode(0);
1006 ChangeScrollRegion(0, rows - 1);
1008 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1009 break;
1010 case '=':
1011 LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
1012 #ifndef TIOCPKT
1013 WNewAutoFlow(curr, 0);
1014 #endif /* !TIOCPKT */
1015 break;
1016 case '>':
1017 LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
1018 #ifndef TIOCPKT
1019 WNewAutoFlow(curr, 1);
1020 #endif /* !TIOCPKT */
1021 break;
1022 #ifdef FONT
1023 case 'n': /* LS2 */
1024 MapCharset(G2);
1025 break;
1026 case 'o': /* LS3 */
1027 MapCharset(G3);
1028 break;
1029 case '~':
1030 MapCharsetR(G1); /* LS1R */
1031 break;
1032 /* { */
1033 case '}':
1034 MapCharsetR(G2); /* LS2R */
1035 break;
1036 case '|':
1037 MapCharsetR(G3); /* LS3R */
1038 break;
1039 case 'N': /* SS2 */
1040 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
1041 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
1042 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
1043 else
1044 curr->w_ss = 0;
1045 break;
1046 case 'O': /* SS3 */
1047 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
1048 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
1049 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
1050 else
1051 curr->w_ss = 0;
1052 break;
1053 #endif /* FONT */
1054 case 'g': /* VBELL, private screen sequence */
1055 WBell(curr, 1);
1056 break;
1058 break;
1059 case '#':
1060 switch (c)
1062 case '8':
1063 FillWithEs();
1064 break;
1066 break;
1067 #ifdef FONT
1068 case '(':
1069 DesignateCharset(c, G0);
1070 break;
1071 case ')':
1072 DesignateCharset(c, G1);
1073 break;
1074 case '*':
1075 DesignateCharset(c, G2);
1076 break;
1077 case '+':
1078 DesignateCharset(c, G3);
1079 break;
1080 # ifdef DW_CHARS
1082 * ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
1083 * ESC $ Fn: same as above. (old sequence)
1084 * ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
1085 * ESC $ * Fn: invoke multi-byte charset, Fn, to G2
1086 * ESC $ + Fn: invoke multi-byte charset, Fn, to G3
1088 case '$':
1089 case '$'<<8 | '(':
1090 DesignateCharset(c & 037, G0);
1091 break;
1092 case '$'<<8 | ')':
1093 DesignateCharset(c & 037, G1);
1094 break;
1095 case '$'<<8 | '*':
1096 DesignateCharset(c & 037, G2);
1097 break;
1098 case '$'<<8 | '+':
1099 DesignateCharset(c & 037, G3);
1100 break;
1101 # endif
1102 #endif /* FONT */
1106 static void
1107 DoCSI(c, intermediate)
1108 int c, intermediate;
1110 register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
1112 if (curr->w_NumArgs > MAXARGS)
1113 curr->w_NumArgs = MAXARGS;
1114 switch (intermediate)
1116 case 0:
1117 switch (c)
1119 case 'H':
1120 case 'f':
1121 if (a1 < 1)
1122 a1 = 1;
1123 if (curr->w_origin)
1124 a1 += curr->w_top;
1125 if (a1 > rows)
1126 a1 = rows;
1127 if (a2 < 1)
1128 a2 = 1;
1129 if (a2 > cols)
1130 a2 = cols;
1131 LGotoPos(&curr->w_layer, --a2, --a1);
1132 curr->w_x = a2;
1133 curr->w_y = a1;
1134 if (curr->w_autoaka)
1135 curr->w_autoaka = a1 + 1;
1136 break;
1137 case 'J':
1138 if (a1 < 0 || a1 > 2)
1139 a1 = 0;
1140 switch (a1)
1142 case 0:
1143 ClearToEOS();
1144 break;
1145 case 1:
1146 ClearFromBOS();
1147 break;
1148 case 2:
1149 ClearScreen();
1150 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1151 break;
1153 break;
1154 case 'K':
1155 if (a1 < 0 || a1 > 2)
1156 a1 %= 3;
1157 switch (a1)
1159 case 0:
1160 ClearLineRegion(curr->w_x, cols - 1);
1161 break;
1162 case 1:
1163 ClearLineRegion(0, curr->w_x);
1164 break;
1165 case 2:
1166 ClearLineRegion(0, cols - 1);
1167 break;
1169 break;
1170 case 'X':
1171 a1 = curr->w_x + (a1 ? a1 - 1 : 0);
1172 ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
1173 break;
1174 case 'A':
1175 CursorUp(a1 ? a1 : 1);
1176 break;
1177 case 'B':
1178 CursorDown(a1 ? a1 : 1);
1179 break;
1180 case 'C':
1181 CursorRight(a1 ? a1 : 1);
1182 break;
1183 case 'D':
1184 CursorLeft(a1 ? a1 : 1);
1185 break;
1186 case 'E':
1187 curr->w_x = 0;
1188 CursorDown(a1 ? a1 : 1); /* positions cursor */
1189 break;
1190 case 'F':
1191 curr->w_x = 0;
1192 CursorUp(a1 ? a1 : 1); /* positions cursor */
1193 break;
1194 case 'G':
1195 case '`': /* HPA */
1196 curr->w_x = a1 ? a1 - 1 : 0;
1197 if (curr->w_x >= cols)
1198 curr->w_x = cols - 1;
1199 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1200 break;
1201 case 'd': /* VPA */
1202 curr->w_y = a1 ? a1 - 1 : 0;
1203 if (curr->w_y >= rows)
1204 curr->w_y = rows - 1;
1205 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1206 break;
1207 case 'm':
1208 SelectRendition();
1209 break;
1210 case 'g':
1211 if (a1 == 0)
1212 curr->w_tabs[curr->w_x] = 0;
1213 else if (a1 == 3)
1214 bzero(curr->w_tabs, cols);
1215 break;
1216 case 'r':
1217 if (!a1)
1218 a1 = 1;
1219 if (!a2)
1220 a2 = rows;
1221 if (a1 < 1 || a2 > rows || a1 >= a2)
1222 break;
1223 curr->w_top = a1 - 1;
1224 curr->w_bot = a2 - 1;
1225 /* ChangeScrollRegion(curr->w_top, curr->w_bot); */
1226 if (curr->w_origin)
1228 curr->w_y = curr->w_top;
1229 curr->w_x = 0;
1231 else
1232 curr->w_y = curr->w_x = 0;
1233 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1234 break;
1235 case 's':
1236 SaveCursor(&curr->w_saved);
1237 break;
1238 case 't':
1239 switch(a1)
1241 case 11:
1242 if (curr->w_layer.l_cvlist)
1243 Report("\033[1t", 0, 0);
1244 else
1245 Report("\033[2t", 0, 0);
1246 break;
1247 case 7:
1248 LRefreshAll(&curr->w_layer, 0);
1249 break;
1250 case 21:
1251 a1 = strlen(curr->w_title);
1252 if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
1254 bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
1255 bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
1256 bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
1257 curr->w_inlen += 5 + a1;
1259 break;
1260 case 8:
1261 a1 = curr->w_args[2];
1262 if (a1 < 1)
1263 a1 = curr->w_width;
1264 if (a2 < 1)
1265 a2 = curr->w_height;
1266 if (a1 > 10000 || a2 > 10000)
1267 break;
1268 WChangeSize(curr, a1, a2);
1269 cols = curr->w_width;
1270 rows = curr->w_height;
1271 break;
1272 default:
1273 break;
1275 break;
1276 case 'u':
1277 RestoreCursor(&curr->w_saved);
1278 break;
1279 case 'I':
1280 if (!a1)
1281 a1 = 1;
1282 while (a1--)
1283 ForwardTab();
1284 break;
1285 case 'Z':
1286 if (!a1)
1287 a1 = 1;
1288 while (a1--)
1289 BackwardTab();
1290 break;
1291 case 'L':
1292 InsertLine(a1 ? a1 : 1);
1293 break;
1294 case 'M':
1295 DeleteLine(a1 ? a1 : 1);
1296 break;
1297 case 'P':
1298 DeleteChar(a1 ? a1 : 1);
1299 break;
1300 case '@':
1301 InsertChar(a1 ? a1 : 1);
1302 break;
1303 case 'h':
1304 ASetMode(1);
1305 break;
1306 case 'l':
1307 ASetMode(0);
1308 break;
1309 case 'i': /* MC Media Control */
1310 if (a1 == 5)
1311 PrintStart();
1312 break;
1313 case 'n':
1314 if (a1 == 5) /* Report terminal status */
1315 Report("\033[0n", 0, 0);
1316 else if (a1 == 6) /* Report cursor position */
1317 Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
1318 break;
1319 case 'c': /* Identify as VT100 */
1320 if (a1 == 0)
1321 Report("\033[?%d;%dc", 1, 2);
1322 break;
1323 case 'x': /* decreqtparm */
1324 if (a1 == 0 || a1 == 1)
1325 Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
1326 break;
1327 case 'p': /* obscure code from a 97801 term */
1328 if (a1 == 6 || a1 == 7)
1330 curr->w_curinv = 7 - a1;
1331 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1333 break;
1334 case 'S': /* code from a 97801 term / DEC vt400 */
1335 ScrollRegion(a1 ? a1 : 1);
1336 break;
1337 case 'T': /* code from a 97801 term / DEC vt400 */
1338 case '^': /* SD as per ISO 6429 */
1339 ScrollRegion(a1 ? -a1 : -1);
1340 break;
1342 break;
1343 case '?':
1344 for (a2 = 0; a2 < curr->w_NumArgs; a2++)
1346 a1 = curr->w_args[a2];
1347 debug2("\\E[?%d%c\n",a1,c);
1348 if (c != 'h' && c != 'l')
1349 break;
1350 i = (c == 'h');
1351 switch (a1)
1353 case 1: /* CKM: cursor key mode */
1354 LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
1355 #ifndef TIOCPKT
1356 WNewAutoFlow(curr, !i);
1357 #endif /* !TIOCPKT */
1358 break;
1359 case 2: /* ANM: ansi/vt52 mode */
1360 if (i)
1362 #ifdef FONT
1363 # ifdef ENCODINGS
1364 if (curr->w_encoding)
1365 break;
1366 # endif
1367 curr->w_charsets[0] = curr->w_charsets[1] =
1368 curr->w_charsets[2] = curr->w_charsets[2] =
1369 curr->w_FontL = curr->w_FontR = ASCII;
1370 curr->w_Charset = 0;
1371 curr->w_CharsetR = 2;
1372 curr->w_ss = 0;
1373 #endif
1375 break;
1376 case 3: /* COLM: column mode */
1377 i = (i ? Z0width : Z1width);
1378 ClearScreen();
1379 curr->w_x = 0;
1380 curr->w_y = 0;
1381 WChangeSize(curr, i, curr->w_height);
1382 cols = curr->w_width;
1383 rows = curr->w_height;
1384 break;
1385 /* case 4: SCLM: scrolling mode */
1386 case 5: /* SCNM: screen mode */
1387 if (i != curr->w_revvid)
1388 WReverseVideo(curr, i);
1389 curr->w_revvid = i;
1390 break;
1391 case 6: /* OM: origin mode */
1392 if ((curr->w_origin = i) != 0)
1394 curr->w_y = curr->w_top;
1395 curr->w_x = 0;
1397 else
1398 curr->w_y = curr->w_x = 0;
1399 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1400 break;
1401 case 7: /* AWM: auto wrap mode */
1402 curr->w_wrap = i;
1403 break;
1404 /* case 8: ARM: auto repeat mode */
1405 /* case 9: INLM: interlace mode */
1406 case 9: /* X10 mouse tracking */
1407 curr->w_mouse = i ? 9 : 0;
1408 LMouseMode(&curr->w_layer, curr->w_mouse);
1409 break;
1410 /* case 10: EDM: edit mode */
1411 /* case 11: LTM: line transmit mode */
1412 /* case 13: SCFDM: space compression / field delimiting */
1413 /* case 14: TEM: transmit execution mode */
1414 /* case 16: EKEM: edit key execution mode */
1415 /* case 18: PFF: Printer term form feed */
1416 /* case 19: PEX: Printer extend screen / scroll. reg */
1417 case 25: /* TCEM: text cursor enable mode */
1418 curr->w_curinv = !i;
1419 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1420 break;
1421 /* case 34: RLM: Right to left mode */
1422 /* case 35: HEBM: hebrew keyboard map */
1423 /* case 36: HEM: hebrew encoding */
1424 /* case 38: TeK Mode */
1425 /* case 40: 132 col enable */
1426 /* case 42: NRCM: 7bit NRC character mode */
1427 /* case 44: margin bell enable */
1428 case 47: /* xterm-like alternate screen */
1429 case 1047: /* xterm-like alternate screen */
1430 case 1049: /* xterm-like alternate screen */
1431 if (use_altscreen)
1433 if (i)
1435 if (!curr->w_alt.on)
1436 SaveCursor(&curr->w_alt.cursor);
1437 EnterAltScreen(curr);
1439 else
1441 LeaveAltScreen(curr);
1442 RestoreCursor(&curr->w_alt.cursor);
1444 if (a1 == 47 && !i)
1445 curr->w_saved.on = 0;
1446 LRefreshAll(&curr->w_layer, 0);
1447 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1449 break;
1450 case 1048:
1451 if (i)
1452 SaveCursor(&curr->w_saved);
1453 else
1454 RestoreCursor(&curr->w_saved);
1455 break;
1456 /* case 66: NKM: Numeric keypad appl mode */
1457 /* case 68: KBUM: Keyboard usage mode (data process) */
1458 case 1000: /* VT200 mouse tracking */
1459 case 1001: /* VT200 highlight mouse */
1460 case 1002: /* button event mouse*/
1461 case 1003: /* any event mouse*/
1462 curr->w_mouse = i ? a1 : 0;
1463 LMouseMode(&curr->w_layer, curr->w_mouse);
1464 break;
1467 break;
1468 case '>':
1469 switch (c)
1471 case 'c': /* secondary DA */
1472 if (a1 == 0)
1473 Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
1474 break;
1476 break;
1481 static void
1482 StringStart(type)
1483 enum string_t type;
1485 curr->w_StringType = type;
1486 curr->w_stringp = curr->w_string;
1487 curr->w_state = ASTR;
1490 static void
1491 StringChar(c)
1492 int c;
1494 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1495 curr->w_state = LIT;
1496 else
1497 *(curr->w_stringp)++ = c;
1501 * Do string processing. Returns -1 if output should be suspended
1502 * until status is gone.
1504 static int
1505 StringEnd()
1507 struct canvas *cv;
1508 char *p;
1509 int typ;
1511 curr->w_state = LIT;
1512 *curr->w_stringp = '\0';
1513 switch (curr->w_StringType)
1515 case OSC: /* special xterm compatibility hack */
1516 if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
1517 break;
1518 typ = atoi(curr->w_string);
1519 p++;
1520 #ifdef MULTIUSER
1521 if (typ == 83) /* 83 = 'S' */
1523 /* special execute commands sequence */
1524 char *args[MAXARGS];
1525 int argl[MAXARGS];
1526 struct acluser *windowuser;
1528 windowuser = *FindUserPtr(":window:");
1529 if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
1531 for (display = displays; display; display = display->d_next)
1532 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1533 break; /* found it */
1534 if (display == 0 && curr->w_layer.l_cvlist)
1535 display = curr->w_layer.l_cvlist->c_display;
1536 if (display == 0)
1537 display = displays;
1538 EffectiveAclUser = windowuser;
1539 fore = curr;
1540 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1541 DoCommand(args, argl);
1542 EffectiveAclUser = 0;
1543 fore = 0;
1544 flayer = 0;
1546 break;
1548 #endif
1549 #ifdef RXVT_OSC
1550 if (typ == 0 || typ == 1 || typ == 2 || typ == 20 || typ == 39 || typ == 49)
1552 int typ2;
1553 typ2 = typ / 10;
1554 if (--typ2 < 0)
1555 typ2 = 0;
1556 if (strcmp(curr->w_xtermosc[typ2], p))
1558 strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
1559 curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
1561 for (display = displays; display; display = display->d_next)
1563 if (!D_CXT)
1564 continue;
1565 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1566 SetXtermOSC(typ2, curr->w_xtermosc[typ2]);
1567 if ((typ2 == 2 || typ2 == 3) && D_xtermosc[typ2])
1568 Redisplay(0);
1572 if (typ != 0 && typ != 2)
1573 break;
1574 #else
1575 if (typ < 0 || typ > 2)
1576 break;
1577 #endif
1579 curr->w_stringp -= p - curr->w_string;
1580 if (curr->w_stringp > curr->w_string)
1581 bcopy(p, curr->w_string, curr->w_stringp - curr->w_string);
1582 *curr->w_stringp = '\0';
1583 /* FALLTHROUGH */
1584 case APC:
1585 if (curr->w_hstatus)
1587 if (strcmp(curr->w_hstatus, curr->w_string) == 0)
1588 break; /* not changed */
1589 free(curr->w_hstatus);
1590 curr->w_hstatus = 0;
1592 if (curr->w_string != curr->w_stringp)
1593 curr->w_hstatus = SaveStr(curr->w_string);
1594 WindowChanged(curr, 'h');
1595 break;
1596 case PM:
1597 case GM:
1598 for (display = displays; display; display = display->d_next)
1600 for (cv = D_cvlist; cv; cv = cv->c_next)
1601 if (cv->c_layer->l_bottom == &curr->w_layer)
1602 break;
1603 if (cv || curr->w_StringType == GM)
1604 MakeStatus(curr->w_string);
1606 return -1;
1607 case DCS:
1608 LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
1609 break;
1610 case AKA:
1611 if (curr->w_title == curr->w_akabuf && !*curr->w_string)
1612 break;
1613 ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
1614 if (!*curr->w_string)
1615 curr->w_autoaka = curr->w_y + 1;
1616 break;
1617 default:
1618 break;
1620 return 0;
1623 static void
1624 PrintStart()
1626 curr->w_pdisplay = 0;
1628 /* find us a nice display to print on, fore prefered */
1629 display = curr->w_lastdisp;
1630 if (!(display && curr == D_fore && (printcmd || D_PO)))
1631 for (display = displays; display; display = display->d_next)
1632 if (curr == D_fore && (printcmd || D_PO))
1633 break;
1634 if (!display)
1636 struct canvas *cv;
1637 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1639 display = cv->c_display;
1640 if (printcmd || D_PO)
1641 break;
1643 if (!cv)
1645 display = displays;
1646 if (!display || display->d_next || !(printcmd || D_PO))
1647 return;
1650 curr->w_pdisplay = display;
1651 curr->w_stringp = curr->w_string;
1652 curr->w_state = PRIN;
1653 if (printcmd && curr->w_pdisplay->d_printfd < 0)
1654 curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
1657 static void
1658 PrintChar(c)
1659 int c;
1661 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1662 PrintFlush();
1663 *(curr->w_stringp)++ = c;
1666 static void
1667 PrintFlush()
1669 display = curr->w_pdisplay;
1670 if (display && printcmd)
1672 char *bp = curr->w_string;
1673 int len = curr->w_stringp - curr->w_string;
1674 int r;
1675 while (len && display->d_printfd >= 0)
1677 r = write(display->d_printfd, bp, len);
1678 if (r <= 0)
1680 WMsg(curr, errno, "printing aborted");
1681 close(display->d_printfd);
1682 display->d_printfd = -1;
1683 break;
1685 bp += r;
1686 len -= r;
1689 else if (display && curr->w_stringp > curr->w_string)
1691 AddCStr(D_PO);
1692 AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
1693 AddCStr(D_PF);
1694 Flush(3);
1696 curr->w_stringp = curr->w_string;
1700 void
1701 WNewAutoFlow(win, on)
1702 struct win *win;
1703 int on;
1705 debug1("WNewAutoFlow: %d\n", on);
1706 if (win->w_flow & FLOW_AUTOFLAG)
1707 win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
1708 else
1709 win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
1710 LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
1714 #ifdef FONT
1716 static void
1717 DesignateCharset(c, n)
1718 int c, n;
1720 curr->w_ss = 0;
1721 # ifdef ENCODINGS
1722 if (c == ('@' & 037)) /* map JIS 6226 to 0208 */
1723 c = KANJI;
1724 # endif
1725 if (c == 'B')
1726 c = ASCII;
1727 if (curr->w_charsets[n] != c)
1729 curr->w_charsets[n] = c;
1730 if (curr->w_Charset == n)
1732 curr->w_FontL = c;
1733 curr->w_rend.font = curr->w_FontL;
1734 LSetRendition(&curr->w_layer, &curr->w_rend);
1736 if (curr->w_CharsetR == n)
1737 curr->w_FontR = c;
1741 static void
1742 MapCharset(n)
1743 int n;
1745 curr->w_ss = 0;
1746 if (curr->w_Charset != n)
1748 curr->w_Charset = n;
1749 curr->w_FontL = curr->w_charsets[n];
1750 curr->w_rend.font = curr->w_FontL;
1751 LSetRendition(&curr->w_layer, &curr->w_rend);
1755 static void
1756 MapCharsetR(n)
1757 int n;
1759 curr->w_ss = 0;
1760 if (curr->w_CharsetR != n)
1762 curr->w_CharsetR = n;
1763 curr->w_FontR = curr->w_charsets[n];
1765 curr->w_gr = 1;
1768 #endif /* FONT */
1770 static void
1771 SaveCursor(cursor)
1772 struct cursor *cursor;
1774 cursor->on = 1;
1775 cursor->x = curr->w_x;
1776 cursor->y = curr->w_y;
1777 cursor->Rend = curr->w_rend;
1778 #ifdef FONT
1779 cursor->Charset = curr->w_Charset;
1780 cursor->CharsetR = curr->w_CharsetR;
1781 bcopy((char *) curr->w_charsets, (char *) cursor->Charsets,
1782 4 * sizeof(int));
1783 #endif
1786 static void
1787 RestoreCursor(cursor)
1788 struct cursor *cursor;
1790 if (!cursor->on)
1791 return;
1792 LGotoPos(&curr->w_layer, cursor->x, cursor->y);
1793 curr->w_x = cursor->x;
1794 curr->w_y = cursor->y;
1795 curr->w_rend = cursor->Rend;
1796 #ifdef FONT
1797 bcopy((char *) cursor->Charsets, (char *) curr->w_charsets,
1798 4 * sizeof(int));
1799 curr->w_Charset = cursor->Charset;
1800 curr->w_CharsetR = cursor->CharsetR;
1801 curr->w_ss = 0;
1802 curr->w_FontL = curr->w_charsets[curr->w_Charset];
1803 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
1804 #endif
1805 LSetRendition(&curr->w_layer, &curr->w_rend);
1808 static void
1809 BackSpace()
1811 if (curr->w_x > 0)
1813 curr->w_x--;
1815 else if (curr->w_wrap && curr->w_y > 0)
1817 curr->w_x = cols - 1;
1818 curr->w_y--;
1820 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1823 static void
1824 Return()
1826 if (curr->w_x == 0)
1827 return;
1828 curr->w_x = 0;
1829 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1832 static void
1833 LineFeed(out_mode)
1834 int out_mode;
1836 /* out_mode: 0=lf, 1=cr+lf */
1837 if (out_mode)
1838 curr->w_x = 0;
1839 if (curr->w_y != curr->w_bot) /* Don't scroll */
1841 if (curr->w_y < rows-1)
1842 curr->w_y++;
1843 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1844 return;
1846 if (curr->w_autoaka > 1)
1847 curr->w_autoaka--;
1848 MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
1849 LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
1850 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1853 static void
1854 ReverseLineFeed()
1856 if (curr->w_y == curr->w_top)
1858 MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
1859 LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
1860 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1862 else if (curr->w_y > 0)
1863 CursorUp(1);
1866 static void
1867 InsertChar(n)
1868 int n;
1870 register int y = curr->w_y, x = curr->w_x;
1872 if (n <= 0)
1873 return;
1874 if (x == cols)
1875 x--;
1876 save_mline(&curr->w_mlines[y], cols);
1877 MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
1878 LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1879 LGotoPos(&curr->w_layer, x, y);
1882 static void
1883 DeleteChar(n)
1884 int n;
1886 register int y = curr->w_y, x = curr->w_x;
1888 if (x == cols)
1889 x--;
1890 save_mline(&curr->w_mlines[y], cols);
1891 MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
1892 LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1893 LGotoPos(&curr->w_layer, x, y);
1896 static void
1897 DeleteLine(n)
1898 int n;
1900 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1901 return;
1902 if (n > curr->w_bot - curr->w_y + 1)
1903 n = curr->w_bot - curr->w_y + 1;
1904 MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
1905 LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
1906 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1909 static void
1910 InsertLine(n)
1911 int n;
1913 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1914 return;
1915 if (n > curr->w_bot - curr->w_y + 1)
1916 n = curr->w_bot - curr->w_y + 1;
1917 MScrollV(curr, -n, curr->w_y, curr->w_bot, CURR_BCE);
1918 LScrollV(&curr->w_layer, -n, curr->w_y, curr->w_bot, CURR_BCE);
1919 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1922 static void
1923 ScrollRegion(n)
1924 int n;
1926 MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
1927 LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
1928 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1932 static void
1933 ForwardTab()
1935 register int x = curr->w_x;
1937 if (x == cols)
1939 LineFeed(1);
1940 x = 0;
1942 if (curr->w_tabs[x] && x < cols - 1)
1943 x++;
1944 while (x < cols - 1 && !curr->w_tabs[x])
1945 x++;
1946 curr->w_x = x;
1947 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1950 static void
1951 BackwardTab()
1953 register int x = curr->w_x;
1955 if (curr->w_tabs[x] && x > 0)
1956 x--;
1957 while (x > 0 && !curr->w_tabs[x])
1958 x--;
1959 curr->w_x = x;
1960 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1963 static void
1964 ClearScreen()
1966 LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
1967 #ifdef COPY_PASTE
1968 MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
1969 #else
1970 MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
1971 #endif
1974 static void
1975 ClearFromBOS()
1977 register int y = curr->w_y, x = curr->w_x;
1979 LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
1980 MClearArea(curr, 0, 0, x, y, CURR_BCE);
1981 RestorePosRendition();
1984 static void
1985 ClearToEOS()
1987 register int y = curr->w_y, x = curr->w_x;
1989 if (x == 0 && y == 0)
1991 ClearScreen();
1992 RestorePosRendition();
1993 return;
1995 LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
1996 MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
1997 RestorePosRendition();
2000 static void
2001 ClearLineRegion(from, to)
2002 int from, to;
2004 register int y = curr->w_y;
2005 LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
2006 MClearArea(curr, from, y, to, y, CURR_BCE);
2007 RestorePosRendition();
2010 static void
2011 CursorRight(n)
2012 register int n;
2014 register int x = curr->w_x;
2016 if (x == cols)
2018 LineFeed(1);
2019 x = 0;
2021 if ((curr->w_x += n) >= cols)
2022 curr->w_x = cols - 1;
2023 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2026 static void
2027 CursorUp(n)
2028 register int n;
2030 if (curr->w_y < curr->w_top) /* if above scrolling rgn, */
2032 if ((curr->w_y -= n) < 0) /* ignore its limits */
2033 curr->w_y = 0;
2035 else
2036 if ((curr->w_y -= n) < curr->w_top)
2037 curr->w_y = curr->w_top;
2038 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2041 static void
2042 CursorDown(n)
2043 register int n;
2045 if (curr->w_y > curr->w_bot) /* if below scrolling rgn, */
2047 if ((curr->w_y += n) > rows - 1) /* ignore its limits */
2048 curr->w_y = rows - 1;
2050 else
2051 if ((curr->w_y += n) > curr->w_bot)
2052 curr->w_y = curr->w_bot;
2053 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2056 static void
2057 CursorLeft(n)
2058 register int n;
2060 if ((curr->w_x -= n) < 0)
2061 curr->w_x = 0;
2062 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2065 static void
2066 ASetMode(on)
2067 int on;
2069 register int i;
2071 for (i = 0; i < curr->w_NumArgs; ++i)
2073 switch (curr->w_args[i])
2075 /* case 2: KAM: Lock keyboard */
2076 case 4: /* IRM: Insert mode */
2077 curr->w_insert = on;
2078 LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
2079 break;
2080 /* case 12: SRM: Echo mode on */
2081 case 20: /* LNM: Linefeed mode */
2082 curr->w_autolf = on;
2083 break;
2084 case 34:
2085 curr->w_curvvis = !on;
2086 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
2087 break;
2088 default:
2089 break;
2094 static char rendlist[] =
2096 ~((1 << NATTR) - 1), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
2097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2098 0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
2101 static void
2102 SelectRendition()
2104 #ifdef COLOR
2105 register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
2106 # ifdef COLORS256
2107 int cx = curr->w_rend.colorx;
2108 # endif
2109 #else
2110 register int j, i = 0, a = curr->w_rend.attr;
2111 #endif
2115 j = curr->w_args[i];
2116 #ifdef COLOR
2117 if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
2119 int jj;
2121 i += 2;
2122 jj = curr->w_args[i];
2123 if (jj < 0 || jj > 255)
2124 continue;
2125 # ifdef COLORS256
2126 if (j == 38)
2128 c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
2129 a |= A_BFG;
2130 if (jj >= 8 && jj < 16)
2131 c |= 0x08;
2132 else
2133 a ^= A_BFG;
2134 a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
2135 cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
2137 else
2139 c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
2140 a |= A_BBG;
2141 if (jj >= 8 && jj < 16)
2142 c |= 0x80;
2143 else
2144 a ^= A_BBG;
2145 cx = (cx & 0x0f) | (jj & 0xf0);
2147 continue;
2148 # else
2149 jj = color256to16(jj) + 30;
2150 if (jj >= 38)
2151 jj += 60 - 8;
2152 j = j == 38 ? jj : jj + 10;
2153 # endif
2155 # ifdef COLORS16
2156 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2157 a &= 0xbf;
2158 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2159 a &= 0x7f;
2160 if (j >= 90 && j <= 97)
2161 a |= 0x40;
2162 if (j >= 100 && j <= 107)
2163 a |= 0x80;
2164 # endif
2165 if (j >= 90 && j <= 97)
2166 j -= 60;
2167 if (j >= 100 && j <= 107)
2168 j -= 60;
2169 if (j >= 30 && j <= 39 && j != 38)
2170 c = (c & 0xf0) | ((j - 30) ^ 9);
2171 else if (j >= 40 && j <= 49 && j != 48)
2172 c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
2173 if (j == 0)
2174 c = 0;
2175 # ifdef COLORS256
2176 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2177 cx &= 0xf0;
2178 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2179 cx &= 0x0f;
2180 # endif
2181 #endif
2182 if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
2183 continue;
2184 j = rendlist[j];
2185 if (j & (1 << NATTR))
2186 a &= j;
2187 else
2188 a |= j;
2190 while (++i < curr->w_NumArgs);
2191 curr->w_rend.attr = a;
2192 #ifdef COLOR
2193 curr->w_rend.color = c;
2194 # ifdef COLORS256
2195 curr->w_rend.colorx = cx;
2196 # endif
2197 #endif
2198 LSetRendition(&curr->w_layer, &curr->w_rend);
2201 static void
2202 FillWithEs()
2204 register int i;
2205 register unsigned char *p, *ep;
2207 LClearAll(&curr->w_layer, 1);
2208 curr->w_y = curr->w_x = 0;
2209 for (i = 0; i < rows; ++i)
2211 clear_mline(&curr->w_mlines[i], 0, cols + 1);
2212 p = curr->w_mlines[i].image;
2213 ep = p + cols;
2214 while (p < ep)
2215 *p++ = 'E';
2217 LRefreshAll(&curr->w_layer, 1);
2222 * Ugly autoaka hack support:
2223 * ChangeAKA() sets a new aka
2224 * FindAKA() searches for an autoaka match
2227 void
2228 ChangeAKA(p, s, l)
2229 struct win *p;
2230 char *s;
2231 int l;
2233 int i, c;
2235 for (i = 0; l > 0; l--)
2237 if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
2238 break;
2239 c = (unsigned char)*s++;
2240 if (c == 0)
2241 break;
2242 if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
2243 continue;
2244 p->w_akachange[i++] = c;
2246 p->w_akachange[i] = 0;
2247 p->w_title = p->w_akachange;
2248 if (p->w_akachange != p->w_akabuf)
2249 if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
2250 p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
2251 WindowChanged(p, 't');
2252 WindowChanged((struct win *)0, 'w');
2253 WindowChanged((struct win *)0, 'W');
2256 static void
2257 FindAKA()
2259 register unsigned char *cp, *line;
2260 register struct win *wp = curr;
2261 register int len = strlen(wp->w_akabuf);
2262 int y;
2264 y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
2265 cols = wp->w_width;
2266 try_line:
2267 cp = line = wp->w_mlines[y].image;
2268 if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
2270 for (;;)
2272 if (cp - line >= cols - len)
2274 if (++y == wp->w_autoaka && y < rows)
2275 goto try_line;
2276 return;
2278 if (strncmp((char *)cp, wp->w_akabuf, len) == 0)
2279 break;
2280 cp++;
2282 cp += len;
2284 for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
2286 if (len)
2288 if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
2289 wp->w_autoaka = -1;
2290 else
2291 wp->w_autoaka = 0;
2292 line = cp;
2293 while (len && *cp != ' ')
2295 if (*cp++ == '/')
2296 line = cp;
2297 len--;
2299 ChangeAKA(wp, (char *)line, cp - line);
2301 else
2302 wp->w_autoaka = 0;
2305 static void
2306 RestorePosRendition()
2308 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2309 LSetRendition(&curr->w_layer, &curr->w_rend);
2312 /* Send a terminal report as if it were typed. */
2313 static void
2314 Report(fmt, n1, n2)
2315 char *fmt;
2316 int n1, n2;
2318 register int len;
2319 char rbuf[40]; /* enough room for all replys */
2321 sprintf(rbuf, fmt, n1, n2);
2322 len = strlen(rbuf);
2324 #ifdef PSEUDOS
2325 if (W_UWP(curr))
2327 if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
2329 bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
2330 curr->w_pwin->p_inlen += len;
2333 else
2334 #endif
2336 if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
2338 bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
2339 curr->w_inlen += len;
2347 *====================================================================*
2348 *====================================================================*
2351 /**********************************************************************
2353 * Memory subsystem.
2357 static void
2358 MFixLine(p, y, mc)
2359 struct win *p;
2360 int y;
2361 struct mchar *mc;
2363 struct mline *ml = &p->w_mlines[y];
2364 if (mc->attr && ml->attr == null)
2366 if ((ml->attr = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2368 ml->attr = null;
2369 mc->attr = p->w_rend.attr = 0;
2370 WMsg(p, 0, "Warning: no space for attr - turned off");
2373 #ifdef FONT
2374 if (mc->font && ml->font == null)
2376 if ((ml->font = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2378 ml->font = null;
2379 p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
2380 p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
2381 mc->font = p->w_rend.font = 0;
2382 WMsg(p, 0, "Warning: no space for font - turned off");
2385 #endif
2386 #ifdef COLOR
2387 if (mc->color && ml->color == null)
2389 if ((ml->color = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2391 ml->color = null;
2392 mc->color = p->w_rend.color = 0;
2393 WMsg(p, 0, "Warning: no space for color - turned off");
2396 # ifdef COLORS256
2397 if (mc->colorx && ml->colorx == null)
2399 if ((ml->colorx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2401 ml->colorx = null;
2402 mc->colorx = p->w_rend.colorx = 0;
2403 WMsg(p, 0, "Warning: no space for extended colors - turned off");
2406 # endif
2407 #endif
2410 /*****************************************************************/
2412 #ifdef DW_CHARS
2413 # define MKillDwRight(p, ml, x) \
2414 if (dw_right(ml, x, p->w_encoding)) \
2416 if (x > 0) \
2417 copy_mchar2mline(&mchar_blank, ml, x - 1); \
2418 copy_mchar2mline(&mchar_blank, ml, x); \
2421 # define MKillDwLeft(p, ml, x) \
2422 if (dw_left(ml, x, p->w_encoding)) \
2424 copy_mchar2mline(&mchar_blank, ml, x); \
2425 copy_mchar2mline(&mchar_blank, ml, x + 1); \
2427 #else
2428 # define MKillDwRight(p, ml, x) ;
2429 # define MKillDwLeft(p, ml, x) ;
2430 #endif
2432 static void
2433 MScrollH(p, n, y, xs, xe, bce)
2434 struct win *p;
2435 int n, y, xs, xe, bce;
2437 struct mline *ml;
2439 if (n == 0)
2440 return;
2441 ml = &p->w_mlines[y];
2442 MKillDwRight(p, ml, xs);
2443 MKillDwLeft(p, ml, xe);
2444 if (n > 0)
2446 if (xe - xs + 1 > n)
2448 MKillDwRight(p, ml, xs + n);
2449 bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
2451 else
2452 n = xe - xs + 1;
2453 clear_mline(ml, xe + 1 - n, n);
2454 #ifdef COLOR
2455 if (bce)
2456 MBceLine(p, y, xe + 1 - n, n, bce);
2457 #endif
2459 else
2461 n = -n;
2462 if (xe - xs + 1 > n)
2464 MKillDwLeft(p, ml, xe - n);
2465 bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
2467 else
2468 n = xe - xs + 1;
2469 clear_mline(ml, xs, n);
2470 #ifdef COLOR
2471 if (bce)
2472 MBceLine(p, y, xs, n, bce);
2473 #endif
2477 static void
2478 MScrollV(p, n, ys, ye, bce)
2479 struct win *p;
2480 int n, ys, ye, bce;
2482 int i, cnt1, cnt2;
2483 struct mline tmp[256];
2484 struct mline *ml;
2486 if (n == 0)
2487 return;
2488 if (n > 0)
2490 if (n > 256)
2492 MScrollV(p, n - 256, ys, ye, bce);
2493 n = 256;
2495 if (ye - ys + 1 < n)
2496 n = ye - ys + 1;
2497 #ifdef COPY_PASTE
2498 if (compacthist)
2500 ye = MFindUsedLine(p, ye, ys);
2501 if (ye - ys + 1 < n)
2502 n = ye - ys + 1;
2503 if (n <= 0)
2504 return;
2506 #endif
2507 /* Clear lines */
2508 ml = p->w_mlines + ys;
2509 for (i = ys; i < ys + n; i++, ml++)
2511 #ifdef COPY_PASTE
2512 if (ys == p->w_top)
2513 WAddLineToHist(p, ml);
2514 #endif
2515 if (ml->attr != null)
2516 free(ml->attr);
2517 ml->attr = null;
2518 #ifdef FONT
2519 if (ml->font != null)
2520 free(ml->font);
2521 ml->font = null;
2522 #endif
2523 #ifdef COLOR
2524 if (ml->color != null)
2525 free(ml->color);
2526 ml->color = null;
2527 # ifdef COLORS256
2528 if (ml->colorx != null)
2529 free(ml->colorx);
2530 ml->colorx = null;
2531 # endif
2532 #endif
2533 bclear((char *)ml->image, p->w_width + 1);
2534 #ifdef COLOR
2535 if (bce)
2536 MBceLine(p, i, 0, p->w_width, bce);
2537 #endif
2539 /* switch 'em over */
2540 cnt1 = n * sizeof(struct mline);
2541 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2542 if (cnt1 && cnt2)
2543 Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
2545 else
2547 if (n < -256)
2549 MScrollV(p, n + 256, ys, ye, bce);
2550 n = -256;
2552 n = -n;
2553 if (ye - ys + 1 < n)
2554 n = ye - ys + 1;
2556 ml = p->w_mlines + ye;
2557 /* Clear lines */
2558 for (i = ye; i > ye - n; i--, ml--)
2560 if (ml->attr != null)
2561 free(ml->attr);
2562 ml->attr = null;
2563 #ifdef FONT
2564 if (ml->font != null)
2565 free(ml->font);
2566 ml->font = null;
2567 #endif
2568 #ifdef COLOR
2569 if (ml->color != null)
2570 free(ml->color);
2571 ml->color = null;
2572 # ifdef COLORS256
2573 if (ml->colorx != null)
2574 free(ml->colorx);
2575 ml->colorx = null;
2576 # endif
2577 #endif
2578 bclear((char *)ml->image, p->w_width + 1);
2579 #ifdef COLOR
2580 if (bce)
2581 MBceLine(p, i, 0, p->w_width, bce);
2582 #endif
2584 cnt1 = n * sizeof(struct mline);
2585 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2586 if (cnt1 && cnt2)
2587 Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
2591 static void
2592 Scroll(cp, cnt1, cnt2, tmp)
2593 char *cp, *tmp;
2594 int cnt1, cnt2;
2596 if (!cnt1 || !cnt2)
2597 return;
2598 if (cnt1 <= cnt2)
2600 bcopy(cp, tmp, cnt1);
2601 bcopy(cp + cnt1, cp, cnt2);
2602 bcopy(tmp, cp + cnt2, cnt1);
2604 else
2606 bcopy(cp + cnt1, tmp, cnt2);
2607 bcopy(cp, cp + cnt2, cnt1);
2608 bcopy(tmp, cp, cnt2);
2612 static void
2613 MClearArea(p, xs, ys, xe, ye, bce)
2614 struct win *p;
2615 int xs, ys, xe, ye, bce;
2617 int n, y;
2618 int xxe;
2619 struct mline *ml;
2621 /* Check for zero-height window */
2622 if (ys < 0 || ye < ys)
2623 return;
2625 /* check for magic margin condition */
2626 if (xs >= p->w_width)
2627 xs = p->w_width - 1;
2628 if (xe >= p->w_width)
2629 xe = p->w_width - 1;
2631 MKillDwRight(p, p->w_mlines + ys, xs);
2632 MKillDwLeft(p, p->w_mlines + ye, xe);
2634 ml = p->w_mlines + ys;
2635 for (y = ys; y <= ye; y++, ml++)
2637 xxe = (y == ye) ? xe : p->w_width - 1;
2638 n = xxe - xs + 1;
2639 if (n > 0)
2640 clear_mline(ml, xs, n);
2641 #ifdef COLOR
2642 if (n > 0 && bce)
2643 MBceLine(p, y, xs, xs + n - 1, bce);
2644 #endif
2645 xs = 0;
2649 static void
2650 MInsChar(p, c, x, y)
2651 struct win *p;
2652 struct mchar *c;
2653 int x, y;
2655 int n;
2656 struct mline *ml;
2658 ASSERT(x >= 0 && x < p->w_width);
2659 MFixLine(p, y, c);
2660 ml = p->w_mlines + y;
2661 n = p->w_width - x - 1;
2662 MKillDwRight(p, ml, x);
2663 if (n > 0)
2665 MKillDwRight(p, ml, p->w_width - 1);
2666 bcopy_mline(ml, x, x + 1, n);
2668 copy_mchar2mline(c, ml, x);
2669 #ifdef DW_CHARS
2670 if (c->mbcs)
2672 if (--n > 0)
2674 MKillDwRight(p, ml, p->w_width - 1);
2675 bcopy_mline(ml, x + 1, x + 2, n);
2677 copy_mchar2mline(c, ml, x + 1);
2678 ml->image[x + 1] = c->mbcs;
2679 # ifdef UTF8
2680 if (p->w_encoding != UTF8)
2681 ml->font[x + 1] |= 0x80;
2682 else if (p->w_encoding == UTF8 && c->mbcs)
2683 ml->font[x + 1] = c->mbcs;
2684 # else
2685 ml->font[x + 1] |= 0x80;
2686 # endif
2688 #endif
2691 static void
2692 MPutChar(p, c, x, y)
2693 struct win *p;
2694 struct mchar *c;
2695 int x, y;
2697 struct mline *ml;
2699 MFixLine(p, y, c);
2700 ml = &p->w_mlines[y];
2701 MKillDwRight(p, ml, x);
2702 MKillDwLeft(p, ml, x);
2703 copy_mchar2mline(c, ml, x);
2704 #ifdef DW_CHARS
2705 if (c->mbcs)
2707 MKillDwLeft(p, ml, x + 1);
2708 copy_mchar2mline(c, ml, x + 1);
2709 ml->image[x + 1] = c->mbcs;
2710 # ifdef UTF8
2711 if (p->w_encoding != UTF8)
2712 ml->font[x + 1] |= 0x80;
2713 else if (p->w_encoding == UTF8 && c->mbcs)
2714 ml->font[x + 1] = c->mbcs;
2715 # else
2716 ml->font[x + 1] |= 0x80;
2717 # endif
2719 #endif
2723 static void
2724 MWrapChar(p, c, y, top, bot, ins)
2725 struct win *p;
2726 struct mchar *c;
2727 int y, top, bot;
2728 int ins;
2730 struct mline *ml;
2731 int bce;
2733 #ifdef COLOR
2734 bce = rend_getbg(c);
2735 #else
2736 bce = 0;
2737 #endif
2738 MFixLine(p, y, c);
2739 ml = &p->w_mlines[y];
2740 copy_mchar2mline(&mchar_null, ml, p->w_width);
2741 if (y == bot)
2742 MScrollV(p, 1, top, bot, bce);
2743 else if (y < p->w_height - 1)
2744 y++;
2745 if (ins)
2746 MInsChar(p, c, 0, y);
2747 else
2748 MPutChar(p, c, 0, y);
2751 static void
2752 MPutStr(p, s, n, r, x, y)
2753 struct win *p;
2754 char *s;
2755 int n;
2756 struct mchar *r;
2757 int x, y;
2759 struct mline *ml;
2760 int i;
2761 unsigned char *b;
2763 if (n <= 0)
2764 return;
2765 MFixLine(p, y, r);
2766 ml = &p->w_mlines[y];
2767 MKillDwRight(p, ml, x);
2768 MKillDwLeft(p, ml, x + n - 1);
2769 bcopy(s, (char *)ml->image + x, n);
2770 b = ml->attr + x;
2771 for (i = n; i-- > 0;)
2772 *b++ = r->attr;
2773 #ifdef FONT
2774 b = ml->font + x;
2775 for (i = n; i-- > 0;)
2776 *b++ = r->font;
2777 #endif
2778 #ifdef COLOR
2779 b = ml->color + x;
2780 for (i = n; i-- > 0;)
2781 *b++ = r->color;
2782 # ifdef COLORS256
2783 b = ml->colorx + x;
2784 for (i = n; i-- > 0;)
2785 *b++ = r->colorx;
2786 # endif
2787 #endif
2790 #ifdef COLOR
2791 static void
2792 MBceLine(p, y, xs, xe, bce)
2793 struct win *p;
2794 int y, xs, xe, bce;
2796 struct mchar mc;
2797 struct mline *ml;
2798 int x;
2800 mc = mchar_null;
2801 rend_setbg(&mc, bce);
2802 MFixLine(p, y, &mc);
2803 ml = p->w_mlines + y;
2804 # ifdef COLORS16
2805 if (mc.attr)
2806 for (x = xs; x <= xe; x++)
2807 ml->attr[x] = mc.attr;
2808 # endif
2809 if (mc.color)
2810 for (x = xs; x <= xe; x++)
2811 ml->color[x] = mc.color;
2812 # ifdef COLORS256
2813 if (mc.colorx)
2814 for (x = xs; x <= xe; x++)
2815 ml->colorx[x] = mc.colorx;
2816 # endif
2818 #endif
2821 #ifdef COPY_PASTE
2822 static void
2823 WAddLineToHist(wp, ml)
2824 struct win *wp;
2825 struct mline *ml;
2827 register unsigned char *q, *o;
2828 struct mline *hml;
2830 if (wp->w_histheight == 0)
2831 return;
2832 hml = &wp->w_hlines[wp->w_histidx];
2833 q = ml->image; ml->image = hml->image; hml->image = q;
2835 q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
2836 if (o != null)
2837 free(o);
2839 #ifdef FONT
2840 q = ml->font; o = hml->font; hml->font = q; ml->font = null;
2841 if (o != null)
2842 free(o);
2843 #endif
2845 #ifdef COLOR
2846 q = ml->color; o = hml->color; hml->color = q; ml->color = null;
2847 if (o != null)
2848 free(o);
2849 # ifdef COLORS256
2850 q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
2851 if (o != null)
2852 free(o);
2853 # endif
2854 #endif
2856 if (++wp->w_histidx >= wp->w_histheight)
2857 wp->w_histidx = 0;
2859 #endif
2862 MFindUsedLine(p, ye, ys)
2863 struct win *p;
2864 int ys, ye;
2866 int y;
2867 struct mline *ml = p->w_mlines + ye;
2869 debug2("MFindUsedLine: %d %d\n", ye, ys);
2870 for (y = ye; y >= ys; y--, ml--)
2872 if (bcmp((char*)ml->image, blank, p->w_width))
2873 break;
2874 if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
2875 break;
2876 #ifdef COLOR
2877 if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
2878 break;
2879 # ifdef COLORS256
2880 if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
2881 break;
2882 # endif
2883 #endif
2885 debug1("MFindUsedLine returning %d\n", y);
2886 return y;
2891 *====================================================================*
2892 *====================================================================*
2896 * Tricky: send only one bell even if the window is displayed
2897 * more than once.
2899 void
2900 WBell(p, visual)
2901 struct win *p;
2902 int visual;
2904 struct canvas *cv;
2905 for (display = displays; display; display = display->d_next)
2907 for (cv = D_cvlist; cv; cv = cv->c_next)
2908 if (cv->c_layer->l_bottom == &p->w_layer)
2909 break;
2910 if (cv && !visual)
2911 AddCStr(D_BL);
2912 else if (cv && D_VB)
2913 AddCStr(D_VB);
2914 else
2915 p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
2920 * This should be reverse video.
2921 * Only change video if window is fore.
2922 * Because it is used in some termcaps to emulate
2923 * a visual bell we do this hack here.
2924 * (screen uses \Eg as special vbell sequence)
2926 static void
2927 WReverseVideo(p, on)
2928 struct win *p;
2929 int on;
2931 struct canvas *cv;
2932 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2934 display = cv->c_display;
2935 if (cv != D_forecv)
2936 continue;
2937 ReverseVideo(on);
2938 if (!on && p->w_revvid && !D_CVR)
2940 if (D_VB)
2941 AddCStr(D_VB);
2942 else
2943 p->w_bell = BELL_VISUAL;
2948 void
2949 WMsg(p, err, str)
2950 struct win *p;
2951 int err;
2952 char *str;
2954 extern struct layer *flayer;
2955 struct layer *oldflayer = flayer;
2956 flayer = &p->w_layer;
2957 LMsg(err, "%s", str);
2958 flayer = oldflayer;
2961 void
2962 WChangeSize(p, w, h)
2963 struct win *p;
2964 int w, h;
2966 int wok = 0;
2967 struct canvas *cv;
2969 if (p->w_layer.l_cvlist == 0)
2971 /* window not displayed -> works always */
2972 ChangeWindowSize(p, w, h, p->w_histheight);
2973 return;
2975 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2977 display = cv->c_display;
2978 if (p != D_fore)
2979 continue; /* change only fore */
2980 if (D_CWS)
2981 break;
2982 if (D_CZ0 && (w == Z0width || w == Z1width))
2983 wok = 1;
2985 if (cv == 0 && wok == 0) /* can't change any display */
2986 return;
2987 if (!D_CWS)
2988 h = p->w_height;
2989 ChangeWindowSize(p, w, h, p->w_histheight);
2990 for (display = displays; display; display = display->d_next)
2992 if (p == D_fore)
2994 if (D_cvlist && D_cvlist->c_next == 0)
2995 ResizeDisplay(w, h);
2996 else
2997 ResizeDisplay(w, D_height);
2998 ResizeLayersToCanvases(); /* XXX Hmm ? */
2999 continue;
3001 for (cv = D_cvlist; cv; cv = cv->c_next)
3002 if (cv->c_layer->l_bottom == &p->w_layer)
3003 break;
3004 if (cv)
3005 Redisplay(0);
3009 static int
3010 WindowChangedCheck(s, what, hp)
3011 char *s;
3012 int what;
3013 int *hp;
3015 int h = 0;
3016 int l;
3017 while(*s)
3019 if (*s++ != (hp ? '%' : '\005'))
3020 continue;
3021 l = 0;
3022 s += (*s == '+');
3023 s += (*s == '-');
3024 while (*s >= '0' && *s <= '9')
3025 s++;
3026 if (*s == 'L')
3028 s++;
3029 l = 0x100;
3031 if (*s == 'h')
3032 h = 1;
3033 if (*s == what || ((*s | l) == what) || what == 'd')
3034 break;
3035 if (*s)
3036 s++;
3038 if (hp)
3039 *hp = h;
3040 return *s ? 1 : 0;
3043 void
3044 WindowChanged(p, what)
3045 struct win *p;
3046 int what;
3048 int inwstr, inhstr, inlstr;
3049 int inwstrh = 0, inhstrh = 0, inlstrh = 0;
3050 int got, ox, oy;
3051 struct display *olddisplay = display;
3052 struct canvas *cv;
3054 inwstr = inhstr = 0;
3056 if (what == 'f')
3058 WindowChanged((struct win *)0, 'w'|0x100);
3059 WindowChanged((struct win *)0, 'W'|0x100);
3062 if (what)
3064 inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
3065 inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
3066 inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
3068 else
3070 inwstr = inhstr = 0;
3071 inlstr = 1;
3074 if (p == 0)
3076 for (display = displays; display; display = display->d_next)
3078 ox = D_x;
3079 oy = D_y;
3080 for (cv = D_cvlist; cv; cv = cv->c_next)
3082 if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3083 WListUpdatecv(cv, (struct win *)0);
3084 p = Layer2Window(cv->c_layer);
3085 if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3086 if (cv->c_ye + 1 < D_height)
3087 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3089 p = D_fore;
3090 if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3091 RefreshHStatus();
3092 if (ox != -1 && oy != -1)
3093 GotoPos(ox, oy);
3095 display = olddisplay;
3096 return;
3099 if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
3101 inwstr |= inwstrh;
3102 inhstr |= inhstrh;
3103 inlstr |= inlstrh;
3105 if (!inwstr && !inhstr && !inlstr)
3106 return;
3107 for (display = displays; display; display = display->d_next)
3109 got = 0;
3110 ox = D_x;
3111 oy = D_y;
3112 for (cv = D_cvlist; cv; cv = cv->c_next)
3114 if (inlstr)
3115 WListUpdatecv(cv, p);
3116 if (Layer2Window(cv->c_layer) != p)
3117 continue;
3118 got = 1;
3119 if (inwstr && cv->c_ye + 1 < D_height)
3120 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3122 if (got && inhstr && p == D_fore)
3123 RefreshHStatus();
3124 if (ox != -1 && oy != -1)
3125 GotoPos(ox, oy);
3127 display = olddisplay;