Allow highlighting bell/monitor windows in caption
[screen-lua.git] / src / ansi.c
bloba38bd120684545a0b24be072681ca5324642b62b
1 /* Copyright (c) 2008
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] = {6750175 /* =B dd */, 6750205 /* =u dd */};
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((void));
126 static void RestoreCursor __P((void));
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 = 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 && rows)
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 LineFeed(0);
944 return 1;
945 case '\007':
946 WBell(curr, visual_bell);
947 return 1;
948 case '\t':
949 ForwardTab();
950 return 1;
951 #ifdef FONT
952 case '\017': /* SI */
953 MapCharset(G0);
954 return 1;
955 case '\016': /* SO */
956 MapCharset(G1);
957 return 1;
958 #endif
960 return 0;
963 static void
964 DoESC(c, intermediate)
965 int c, intermediate;
967 debug2("DoESC: %x - inter = %x\n", c, intermediate);
968 switch (intermediate)
970 case 0:
971 switch (c)
973 case 'E':
974 LineFeed(1);
975 break;
976 case 'D':
977 LineFeed(0);
978 break;
979 case 'M':
980 ReverseLineFeed();
981 break;
982 case 'H':
983 curr->w_tabs[curr->w_x] = 1;
984 break;
985 case 'Z': /* jph: Identify as VT100 */
986 Report("\033[?%d;%dc", 1, 2);
987 break;
988 case '7':
989 SaveCursor();
990 break;
991 case '8':
992 RestoreCursor();
993 break;
994 case 'c':
995 ClearScreen();
996 ResetWindow(curr);
997 LKeypadMode(&curr->w_layer, 0);
998 LCursorkeysMode(&curr->w_layer, 0);
999 #ifndef TIOCPKT
1000 WNewAutoFlow(curr, 1);
1001 #endif
1002 /* XXX
1003 SetRendition(&mchar_null);
1004 InsertMode(0);
1005 ChangeScrollRegion(0, rows - 1);
1007 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1008 break;
1009 case '=':
1010 LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
1011 #ifndef TIOCPKT
1012 WNewAutoFlow(curr, 0);
1013 #endif /* !TIOCPKT */
1014 break;
1015 case '>':
1016 LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
1017 #ifndef TIOCPKT
1018 WNewAutoFlow(curr, 1);
1019 #endif /* !TIOCPKT */
1020 break;
1021 #ifdef FONT
1022 case 'n': /* LS2 */
1023 MapCharset(G2);
1024 break;
1025 case 'o': /* LS3 */
1026 MapCharset(G3);
1027 break;
1028 case '~':
1029 MapCharsetR(G1); /* LS1R */
1030 break;
1031 /* { */
1032 case '}':
1033 MapCharsetR(G2); /* LS2R */
1034 break;
1035 case '|':
1036 MapCharsetR(G3); /* LS3R */
1037 break;
1038 case 'N': /* SS2 */
1039 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
1040 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
1041 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
1042 else
1043 curr->w_ss = 0;
1044 break;
1045 case 'O': /* SS3 */
1046 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
1047 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
1048 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
1049 else
1050 curr->w_ss = 0;
1051 break;
1052 #endif /* FONT */
1053 case 'g': /* VBELL, private screen sequence */
1054 WBell(curr, 1);
1055 break;
1057 break;
1058 case '#':
1059 switch (c)
1061 case '8':
1062 FillWithEs();
1063 break;
1065 break;
1066 #ifdef FONT
1067 case '(':
1068 DesignateCharset(c, G0);
1069 break;
1070 case ')':
1071 DesignateCharset(c, G1);
1072 break;
1073 case '*':
1074 DesignateCharset(c, G2);
1075 break;
1076 case '+':
1077 DesignateCharset(c, G3);
1078 break;
1079 # ifdef DW_CHARS
1081 * ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
1082 * ESC $ Fn: same as above. (old sequence)
1083 * ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
1084 * ESC $ * Fn: invoke multi-byte charset, Fn, to G2
1085 * ESC $ + Fn: invoke multi-byte charset, Fn, to G3
1087 case '$':
1088 case '$'<<8 | '(':
1089 DesignateCharset(c & 037, G0);
1090 break;
1091 case '$'<<8 | ')':
1092 DesignateCharset(c & 037, G1);
1093 break;
1094 case '$'<<8 | '*':
1095 DesignateCharset(c & 037, G2);
1096 break;
1097 case '$'<<8 | '+':
1098 DesignateCharset(c & 037, G3);
1099 break;
1100 # endif
1101 #endif /* FONT */
1105 static void
1106 DoCSI(c, intermediate)
1107 int c, intermediate;
1109 register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
1111 if (curr->w_NumArgs > MAXARGS)
1112 curr->w_NumArgs = MAXARGS;
1113 switch (intermediate)
1115 case 0:
1116 switch (c)
1118 case 'H':
1119 case 'f':
1120 if (a1 < 1)
1121 a1 = 1;
1122 if (curr->w_origin)
1123 a1 += curr->w_top;
1124 if (a1 > rows)
1125 a1 = rows;
1126 if (a2 < 1)
1127 a2 = 1;
1128 if (a2 > cols)
1129 a2 = cols;
1130 LGotoPos(&curr->w_layer, --a2, --a1);
1131 curr->w_x = a2;
1132 curr->w_y = a1;
1133 if (curr->w_autoaka)
1134 curr->w_autoaka = a1 + 1;
1135 break;
1136 case 'J':
1137 if (a1 < 0 || a1 > 2)
1138 a1 = 0;
1139 switch (a1)
1141 case 0:
1142 ClearToEOS();
1143 break;
1144 case 1:
1145 ClearFromBOS();
1146 break;
1147 case 2:
1148 ClearScreen();
1149 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1150 break;
1152 break;
1153 case 'K':
1154 if (a1 < 0 || a1 > 2)
1155 a1 %= 3;
1156 switch (a1)
1158 case 0:
1159 ClearLineRegion(curr->w_x, cols - 1);
1160 break;
1161 case 1:
1162 ClearLineRegion(0, curr->w_x);
1163 break;
1164 case 2:
1165 ClearLineRegion(0, cols - 1);
1166 break;
1168 break;
1169 case 'X':
1170 a1 = curr->w_x + (a1 ? a1 - 1 : 0);
1171 ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
1172 break;
1173 case 'A':
1174 CursorUp(a1 ? a1 : 1);
1175 break;
1176 case 'B':
1177 CursorDown(a1 ? a1 : 1);
1178 break;
1179 case 'C':
1180 CursorRight(a1 ? a1 : 1);
1181 break;
1182 case 'D':
1183 CursorLeft(a1 ? a1 : 1);
1184 break;
1185 case 'E':
1186 curr->w_x = 0;
1187 CursorDown(a1 ? a1 : 1); /* positions cursor */
1188 break;
1189 case 'F':
1190 curr->w_x = 0;
1191 CursorUp(a1 ? a1 : 1); /* positions cursor */
1192 break;
1193 case 'G':
1194 case '`': /* HPA */
1195 curr->w_x = a1 ? a1 - 1 : 0;
1196 if (curr->w_x >= cols)
1197 curr->w_x = cols - 1;
1198 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1199 break;
1200 case 'd': /* VPA */
1201 curr->w_y = a1 ? a1 - 1 : 0;
1202 if (curr->w_y >= rows)
1203 curr->w_y = rows - 1;
1204 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1205 break;
1206 case 'm':
1207 SelectRendition();
1208 break;
1209 case 'g':
1210 if (a1 == 0)
1211 curr->w_tabs[curr->w_x] = 0;
1212 else if (a1 == 3)
1213 bzero(curr->w_tabs, cols);
1214 break;
1215 case 'r':
1216 if (!a1)
1217 a1 = 1;
1218 if (!a2)
1219 a2 = rows;
1220 if (a1 < 1 || a2 > rows || a1 >= a2)
1221 break;
1222 curr->w_top = a1 - 1;
1223 curr->w_bot = a2 - 1;
1224 /* ChangeScrollRegion(curr->w_top, curr->w_bot); */
1225 if (curr->w_origin)
1227 curr->w_y = curr->w_top;
1228 curr->w_x = 0;
1230 else
1231 curr->w_y = curr->w_x = 0;
1232 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1233 break;
1234 case 's':
1235 SaveCursor();
1236 break;
1237 case 't':
1238 switch(a1)
1240 case 11:
1241 if (curr->w_layer.l_cvlist)
1242 Report("\033[1t", 0, 0);
1243 else
1244 Report("\033[2t", 0, 0);
1245 break;
1246 case 7:
1247 LRefreshAll(&curr->w_layer, 0);
1248 break;
1249 case 21:
1250 a1 = strlen(curr->w_title);
1251 if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
1253 bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
1254 bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
1255 bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
1256 curr->w_inlen += 5 + a1;
1258 break;
1259 case 8:
1260 a1 = curr->w_args[2];
1261 if (a1 < 1)
1262 a1 = curr->w_width;
1263 if (a2 < 1)
1264 a2 = curr->w_height;
1265 if (a1 > 10000 || a2 > 10000)
1266 break;
1267 WChangeSize(curr, a1, a2);
1268 cols = curr->w_width;
1269 rows = curr->w_height;
1270 break;
1271 default:
1272 break;
1274 break;
1275 case 'u':
1276 RestoreCursor();
1277 break;
1278 case 'I':
1279 if (!a1)
1280 a1 = 1;
1281 while (a1--)
1282 ForwardTab();
1283 break;
1284 case 'Z':
1285 if (!a1)
1286 a1 = 1;
1287 while (a1--)
1288 BackwardTab();
1289 break;
1290 case 'L':
1291 InsertLine(a1 ? a1 : 1);
1292 break;
1293 case 'M':
1294 DeleteLine(a1 ? a1 : 1);
1295 break;
1296 case 'P':
1297 DeleteChar(a1 ? a1 : 1);
1298 break;
1299 case '@':
1300 InsertChar(a1 ? a1 : 1);
1301 break;
1302 case 'h':
1303 ASetMode(1);
1304 break;
1305 case 'l':
1306 ASetMode(0);
1307 break;
1308 case 'i': /* MC Media Control */
1309 if (a1 == 5)
1310 PrintStart();
1311 break;
1312 case 'n':
1313 if (a1 == 5) /* Report terminal status */
1314 Report("\033[0n", 0, 0);
1315 else if (a1 == 6) /* Report cursor position */
1316 Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
1317 break;
1318 case 'c': /* Identify as VT100 */
1319 if (a1 == 0)
1320 Report("\033[?%d;%dc", 1, 2);
1321 break;
1322 case 'x': /* decreqtparm */
1323 if (a1 == 0 || a1 == 1)
1324 Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
1325 break;
1326 case 'p': /* obscure code from a 97801 term */
1327 if (a1 == 6 || a1 == 7)
1329 curr->w_curinv = 7 - a1;
1330 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1332 break;
1333 case 'S': /* code from a 97801 term / DEC vt400 */
1334 ScrollRegion(a1 ? a1 : 1);
1335 break;
1336 case 'T': /* code from a 97801 term / DEC vt400 */
1337 case '^': /* SD as per ISO 6429 */
1338 ScrollRegion(a1 ? -a1 : -1);
1339 break;
1341 break;
1342 case '?':
1343 for (a2 = 0; a2 < curr->w_NumArgs; a2++)
1345 a1 = curr->w_args[a2];
1346 debug2("\\E[?%d%c\n",a1,c);
1347 if (c != 'h' && c != 'l')
1348 break;
1349 i = (c == 'h');
1350 switch (a1)
1352 case 1: /* CKM: cursor key mode */
1353 LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
1354 #ifndef TIOCPKT
1355 WNewAutoFlow(curr, !i);
1356 #endif /* !TIOCPKT */
1357 break;
1358 case 2: /* ANM: ansi/vt52 mode */
1359 if (i)
1361 #ifdef FONT
1362 # ifdef ENCODINGS
1363 if (curr->w_encoding)
1364 break;
1365 # endif
1366 curr->w_charsets[0] = curr->w_charsets[1] =
1367 curr->w_charsets[2] = curr->w_charsets[2] =
1368 curr->w_FontL = curr->w_FontR = ASCII;
1369 curr->w_Charset = 0;
1370 curr->w_CharsetR = 2;
1371 curr->w_ss = 0;
1372 #endif
1374 break;
1375 case 3: /* COLM: column mode */
1376 i = (i ? Z0width : Z1width);
1377 WChangeSize(curr, i, curr->w_height);
1378 cols = curr->w_width;
1379 rows = curr->w_height;
1380 break;
1381 /* case 4: SCLM: scrolling mode */
1382 case 5: /* SCNM: screen mode */
1383 if (i != curr->w_revvid)
1384 WReverseVideo(curr, i);
1385 curr->w_revvid = i;
1386 break;
1387 case 6: /* OM: origin mode */
1388 if ((curr->w_origin = i) != 0)
1390 curr->w_y = curr->w_top;
1391 curr->w_x = 0;
1393 else
1394 curr->w_y = curr->w_x = 0;
1395 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1396 break;
1397 case 7: /* AWM: auto wrap mode */
1398 curr->w_wrap = i;
1399 break;
1400 /* case 8: ARM: auto repeat mode */
1401 /* case 9: INLM: interlace mode */
1402 case 9: /* X10 mouse tracking */
1403 curr->w_mouse = i ? 9 : 0;
1404 LMouseMode(&curr->w_layer, curr->w_mouse);
1405 break;
1406 /* case 10: EDM: edit mode */
1407 /* case 11: LTM: line transmit mode */
1408 /* case 13: SCFDM: space compression / field delimiting */
1409 /* case 14: TEM: transmit execution mode */
1410 /* case 16: EKEM: edit key execution mode */
1411 /* case 18: PFF: Printer term form feed */
1412 /* case 19: PEX: Printer extend screen / scroll. reg */
1413 case 25: /* TCEM: text cursor enable mode */
1414 curr->w_curinv = !i;
1415 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1416 break;
1417 /* case 34: RLM: Right to left mode */
1418 /* case 35: HEBM: hebrew keyboard map */
1419 /* case 36: HEM: hebrew encoding */
1420 /* case 38: TeK Mode */
1421 /* case 40: 132 col enable */
1422 /* case 42: NRCM: 7bit NRC character mode */
1423 /* case 44: margin bell enable */
1424 case 47: /* xterm-like alternate screen */
1425 case 1047: /* xterm-like alternate screen */
1426 case 1049: /* xterm-like alternate screen */
1427 if (use_altscreen)
1429 if (i)
1430 EnterAltScreen(curr);
1431 else
1432 LeaveAltScreen(curr);
1433 if (a1 == 47 && !i)
1434 curr->w_saved = 0;
1435 LRefreshAll(&curr->w_layer, 0);
1436 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1438 break;
1439 /* case 66: NKM: Numeric keypad appl mode */
1440 /* case 68: KBUM: Keyboard usage mode (data process) */
1441 case 1000: /* VT200 mouse tracking */
1442 case 1001: /* VT200 highlight mouse */
1443 case 1002: /* button event mouse*/
1444 case 1003: /* any event mouse*/
1445 curr->w_mouse = i ? a1 : 0;
1446 LMouseMode(&curr->w_layer, curr->w_mouse);
1447 break;
1450 break;
1451 case '>':
1452 switch (c)
1454 case 'c': /* secondary DA */
1455 if (a1 == 0)
1456 Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
1457 break;
1459 break;
1464 static void
1465 StringStart(type)
1466 enum string_t type;
1468 curr->w_StringType = type;
1469 curr->w_stringp = curr->w_string;
1470 curr->w_state = ASTR;
1473 static void
1474 StringChar(c)
1475 int c;
1477 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1478 curr->w_state = LIT;
1479 else
1480 *(curr->w_stringp)++ = c;
1484 * Do string processing. Returns -1 if output should be suspended
1485 * until status is gone.
1487 static int
1488 StringEnd()
1490 struct canvas *cv;
1491 char *p;
1492 int typ;
1494 curr->w_state = LIT;
1495 *curr->w_stringp = '\0';
1496 switch (curr->w_StringType)
1498 case OSC: /* special xterm compatibility hack */
1499 if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
1500 break;
1501 typ = atoi(curr->w_string);
1502 p++;
1503 #ifdef MULTIUSER
1504 if (typ == 83) /* 83 = 'S' */
1506 /* special execute commands sequence */
1507 char *args[MAXARGS];
1508 int argl[MAXARGS];
1509 struct acluser *windowuser;
1511 windowuser = *FindUserPtr(":window:");
1512 if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
1514 for (display = displays; display; display = display->d_next)
1515 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1516 break; /* found it */
1517 if (display == 0 && curr->w_layer.l_cvlist)
1518 display = curr->w_layer.l_cvlist->c_display;
1519 if (display == 0)
1520 display = displays;
1521 EffectiveAclUser = windowuser;
1522 fore = curr;
1523 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1524 DoCommand(args, argl);
1525 EffectiveAclUser = 0;
1526 fore = 0;
1527 flayer = 0;
1529 break;
1531 #endif
1532 #ifdef RXVT_OSC
1533 if (typ == 0 || typ == 1 || typ == 20 || typ == 39 || typ == 49)
1535 int typ2;
1536 typ2 = typ / 10;
1537 if (--typ2 < 0)
1538 typ2 = 0;
1539 if (strcmp(curr->w_xtermosc[typ2], p))
1541 strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
1542 curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
1544 for (display = displays; display; display = display->d_next)
1546 if (!D_CXT)
1547 continue;
1548 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1549 SetXtermOSC(typ2, curr->w_xtermosc[typ2]);
1550 if ((typ2 == 2 || typ2 == 3) && D_xtermosc[typ2])
1551 Redisplay(0);
1555 if (typ != 0 && typ != 2)
1556 break;
1557 #else
1558 if (typ < 0 || typ > 2)
1559 break;
1560 #endif
1562 curr->w_stringp -= p - curr->w_string;
1563 if (curr->w_stringp > curr->w_string)
1564 bcopy(p, curr->w_string, curr->w_stringp - curr->w_string);
1565 *curr->w_stringp = '\0';
1566 /* FALLTHROUGH */
1567 case APC:
1568 if (curr->w_hstatus)
1570 if (strcmp(curr->w_hstatus, curr->w_string) == 0)
1571 break; /* not changed */
1572 free(curr->w_hstatus);
1573 curr->w_hstatus = 0;
1575 if (curr->w_string != curr->w_stringp)
1576 curr->w_hstatus = SaveStr(curr->w_string);
1577 WindowChanged(curr, 'h');
1578 break;
1579 case PM:
1580 case GM:
1581 for (display = displays; display; display = display->d_next)
1583 for (cv = D_cvlist; cv; cv = cv->c_next)
1584 if (cv->c_layer->l_bottom == &curr->w_layer)
1585 break;
1586 if (cv || curr->w_StringType == GM)
1587 MakeStatus(curr->w_string);
1589 return -1;
1590 case DCS:
1591 LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
1592 break;
1593 case AKA:
1594 if (curr->w_title == curr->w_akabuf && !*curr->w_string)
1595 break;
1596 ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
1597 if (!*curr->w_string)
1598 curr->w_autoaka = curr->w_y + 1;
1599 break;
1600 default:
1601 break;
1603 return 0;
1606 static void
1607 PrintStart()
1609 curr->w_pdisplay = 0;
1611 /* find us a nice display to print on, fore prefered */
1612 display = curr->w_lastdisp;
1613 if (!(display && curr == D_fore && (printcmd || D_PO)))
1614 for (display = displays; display; display = display->d_next)
1615 if (curr == D_fore && (printcmd || D_PO))
1616 break;
1617 if (!display)
1619 struct canvas *cv;
1620 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1622 display = cv->c_display;
1623 if (printcmd || D_PO)
1624 break;
1626 if (!cv)
1628 display = displays;
1629 if (!display || display->d_next || !(printcmd || D_PO))
1630 return;
1633 curr->w_pdisplay = display;
1634 curr->w_stringp = curr->w_string;
1635 curr->w_state = PRIN;
1636 if (printcmd && curr->w_pdisplay->d_printfd < 0)
1637 curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
1640 static void
1641 PrintChar(c)
1642 int c;
1644 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1645 PrintFlush();
1646 *(curr->w_stringp)++ = c;
1649 static void
1650 PrintFlush()
1652 display = curr->w_pdisplay;
1653 if (display && printcmd)
1655 char *bp = curr->w_string;
1656 int len = curr->w_stringp - curr->w_string;
1657 int r;
1658 while (len && display->d_printfd >= 0)
1660 r = write(display->d_printfd, bp, len);
1661 if (r <= 0)
1663 WMsg(curr, errno, "printing aborted");
1664 close(display->d_printfd);
1665 display->d_printfd = -1;
1666 break;
1668 bp += r;
1669 len -= r;
1672 else if (display && curr->w_stringp > curr->w_string)
1674 AddCStr(D_PO);
1675 AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
1676 AddCStr(D_PF);
1677 Flush();
1679 curr->w_stringp = curr->w_string;
1683 void
1684 WNewAutoFlow(win, on)
1685 struct win *win;
1686 int on;
1688 debug1("WNewAutoFlow: %d\n", on);
1689 if (win->w_flow & FLOW_AUTOFLAG)
1690 win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
1691 else
1692 win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
1693 LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
1697 #ifdef FONT
1699 static void
1700 DesignateCharset(c, n)
1701 int c, n;
1703 curr->w_ss = 0;
1704 # ifdef ENCODINGS
1705 if (c == ('@' & 037)) /* map JIS 6226 to 0208 */
1706 c = KANJI;
1707 # endif
1708 if (c == 'B')
1709 c = ASCII;
1710 if (curr->w_charsets[n] != c)
1712 curr->w_charsets[n] = c;
1713 if (curr->w_Charset == n)
1715 curr->w_FontL = c;
1716 curr->w_rend.font = curr->w_FontL;
1717 LSetRendition(&curr->w_layer, &curr->w_rend);
1719 if (curr->w_CharsetR == n)
1720 curr->w_FontR = c;
1724 static void
1725 MapCharset(n)
1726 int n;
1728 curr->w_ss = 0;
1729 if (curr->w_Charset != n)
1731 curr->w_Charset = n;
1732 curr->w_FontL = curr->w_charsets[n];
1733 curr->w_rend.font = curr->w_FontL;
1734 LSetRendition(&curr->w_layer, &curr->w_rend);
1738 static void
1739 MapCharsetR(n)
1740 int n;
1742 curr->w_ss = 0;
1743 if (curr->w_CharsetR != n)
1745 curr->w_CharsetR = n;
1746 curr->w_FontR = curr->w_charsets[n];
1748 curr->w_gr = 1;
1751 #endif /* FONT */
1753 static void
1754 SaveCursor()
1756 curr->w_saved = 1;
1757 curr->w_Saved_x = curr->w_x;
1758 curr->w_Saved_y = curr->w_y;
1759 curr->w_SavedRend = curr->w_rend;
1760 #ifdef FONT
1761 curr->w_SavedCharset = curr->w_Charset;
1762 curr->w_SavedCharsetR = curr->w_CharsetR;
1763 bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
1764 4 * sizeof(int));
1765 #endif
1768 static void
1769 RestoreCursor()
1771 if (!curr->w_saved)
1772 return;
1773 LGotoPos(&curr->w_layer, curr->w_Saved_x, curr->w_Saved_y);
1774 curr->w_x = curr->w_Saved_x;
1775 curr->w_y = curr->w_Saved_y;
1776 curr->w_rend = curr->w_SavedRend;
1777 #ifdef FONT
1778 bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
1779 4 * sizeof(int));
1780 curr->w_Charset = curr->w_SavedCharset;
1781 curr->w_CharsetR = curr->w_SavedCharsetR;
1782 curr->w_ss = 0;
1783 curr->w_FontL = curr->w_charsets[curr->w_Charset];
1784 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
1785 #endif
1786 LSetRendition(&curr->w_layer, &curr->w_rend);
1789 static void
1790 BackSpace()
1792 if (curr->w_x > 0)
1794 curr->w_x--;
1796 else if (curr->w_wrap && curr->w_y > 0)
1798 curr->w_x = cols - 1;
1799 curr->w_y--;
1801 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1804 static void
1805 Return()
1807 if (curr->w_x == 0)
1808 return;
1809 curr->w_x = 0;
1810 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1813 static void
1814 LineFeed(out_mode)
1815 int out_mode;
1817 /* out_mode: 0=lf, 1=cr+lf */
1818 if (out_mode)
1819 curr->w_x = 0;
1820 if (curr->w_y != curr->w_bot) /* Don't scroll */
1822 if (curr->w_y < rows-1)
1823 curr->w_y++;
1824 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1825 return;
1827 if (curr->w_autoaka > 1)
1828 curr->w_autoaka--;
1829 MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
1830 LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
1831 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1834 static void
1835 ReverseLineFeed()
1837 if (curr->w_y == curr->w_top)
1839 MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
1840 LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
1841 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1843 else if (curr->w_y > 0)
1844 CursorUp(1);
1847 static void
1848 InsertChar(n)
1849 int n;
1851 register int y = curr->w_y, x = curr->w_x;
1853 if (n <= 0)
1854 return;
1855 if (x == cols)
1856 x--;
1857 save_mline(&curr->w_mlines[y], cols);
1858 MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
1859 LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1860 LGotoPos(&curr->w_layer, x, y);
1863 static void
1864 DeleteChar(n)
1865 int n;
1867 register int y = curr->w_y, x = curr->w_x;
1869 if (x == cols)
1870 x--;
1871 save_mline(&curr->w_mlines[y], cols);
1872 MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
1873 LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1874 LGotoPos(&curr->w_layer, x, y);
1877 static void
1878 DeleteLine(n)
1879 int n;
1881 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1882 return;
1883 if (n > curr->w_bot - curr->w_y + 1)
1884 n = curr->w_bot - curr->w_y + 1;
1885 MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
1886 LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
1887 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1890 static void
1891 InsertLine(n)
1892 int n;
1894 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1895 return;
1896 if (n > curr->w_bot - curr->w_y + 1)
1897 n = curr->w_bot - curr->w_y + 1;
1898 MScrollV(curr, -n, curr->w_y, curr->w_bot, CURR_BCE);
1899 LScrollV(&curr->w_layer, -n, curr->w_y, curr->w_bot, CURR_BCE);
1900 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1903 static void
1904 ScrollRegion(n)
1905 int n;
1907 MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
1908 LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
1909 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1913 static void
1914 ForwardTab()
1916 register int x = curr->w_x;
1918 if (x == cols)
1920 LineFeed(1);
1921 x = 0;
1923 if (curr->w_tabs[x] && x < cols - 1)
1924 x++;
1925 while (x < cols - 1 && !curr->w_tabs[x])
1926 x++;
1927 curr->w_x = x;
1928 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1931 static void
1932 BackwardTab()
1934 register int x = curr->w_x;
1936 if (curr->w_tabs[x] && x > 0)
1937 x--;
1938 while (x > 0 && !curr->w_tabs[x])
1939 x--;
1940 curr->w_x = x;
1941 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1944 static void
1945 ClearScreen()
1947 LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
1948 #ifdef COPY_PASTE
1949 MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
1950 #else
1951 MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
1952 #endif
1955 static void
1956 ClearFromBOS()
1958 register int y = curr->w_y, x = curr->w_x;
1960 LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
1961 MClearArea(curr, 0, 0, x, y, CURR_BCE);
1962 RestorePosRendition();
1965 static void
1966 ClearToEOS()
1968 register int y = curr->w_y, x = curr->w_x;
1970 if (x == 0 && y == 0)
1972 ClearScreen();
1973 RestorePosRendition();
1974 return;
1976 LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
1977 MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
1978 RestorePosRendition();
1981 static void
1982 ClearLineRegion(from, to)
1983 int from, to;
1985 register int y = curr->w_y;
1986 LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
1987 MClearArea(curr, from, y, to, y, CURR_BCE);
1988 RestorePosRendition();
1991 static void
1992 CursorRight(n)
1993 register int n;
1995 register int x = curr->w_x;
1997 if (x == cols)
1999 LineFeed(1);
2000 x = 0;
2002 if ((curr->w_x += n) >= cols)
2003 curr->w_x = cols - 1;
2004 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2007 static void
2008 CursorUp(n)
2009 register int n;
2011 if (curr->w_y < curr->w_top) /* if above scrolling rgn, */
2013 if ((curr->w_y -= n) < 0) /* ignore its limits */
2014 curr->w_y = 0;
2016 else
2017 if ((curr->w_y -= n) < curr->w_top)
2018 curr->w_y = curr->w_top;
2019 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2022 static void
2023 CursorDown(n)
2024 register int n;
2026 if (curr->w_y > curr->w_bot) /* if below scrolling rgn, */
2028 if ((curr->w_y += n) > rows - 1) /* ignore its limits */
2029 curr->w_y = rows - 1;
2031 else
2032 if ((curr->w_y += n) > curr->w_bot)
2033 curr->w_y = curr->w_bot;
2034 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2037 static void
2038 CursorLeft(n)
2039 register int n;
2041 if ((curr->w_x -= n) < 0)
2042 curr->w_x = 0;
2043 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2046 static void
2047 ASetMode(on)
2048 int on;
2050 register int i;
2052 for (i = 0; i < curr->w_NumArgs; ++i)
2054 switch (curr->w_args[i])
2056 /* case 2: KAM: Lock keyboard */
2057 case 4: /* IRM: Insert mode */
2058 curr->w_insert = on;
2059 LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
2060 break;
2061 /* case 12: SRM: Echo mode on */
2062 case 20: /* LNM: Linefeed mode */
2063 curr->w_autolf = on;
2064 break;
2065 case 34:
2066 curr->w_curvvis = !on;
2067 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
2068 break;
2069 default:
2070 break;
2075 static char rendlist[] =
2077 ~((1 << NATTR) - 1), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
2078 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2079 0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
2082 static void
2083 SelectRendition()
2085 #ifdef COLOR
2086 register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
2087 # ifdef COLORS256
2088 int cx = curr->w_rend.colorx;
2089 # endif
2090 #else
2091 register int j, i = 0, a = curr->w_rend.attr;
2092 #endif
2096 j = curr->w_args[i];
2097 #ifdef COLOR
2098 if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
2100 int jj;
2102 i += 2;
2103 jj = curr->w_args[i];
2104 if (jj < 0 || jj > 255)
2105 continue;
2106 # ifdef COLORS256
2107 if (j == 38)
2109 c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
2110 a |= A_BFG;
2111 if (jj >= 8 && jj < 16)
2112 c |= 0x08;
2113 else
2114 a ^= A_BFG;
2115 a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
2116 cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
2118 else
2120 c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
2121 a |= A_BBG;
2122 if (jj >= 8 && jj < 16)
2123 c |= 0x80;
2124 else
2125 a ^= A_BBG;
2126 cx = (cx & 0x0f) | (jj & 0xf0);
2128 continue;
2129 # else
2130 jj = color256to16(jj) + 30;
2131 if (jj >= 38)
2132 jj += 60 - 8;
2133 j = j == 38 ? jj : jj + 10;
2134 # endif
2136 # ifdef COLORS16
2137 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2138 a &= 0xbf;
2139 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2140 a &= 0x7f;
2141 if (j >= 90 && j <= 97)
2142 a |= 0x40;
2143 if (j >= 100 && j <= 107)
2144 a |= 0x80;
2145 # endif
2146 if (j >= 90 && j <= 97)
2147 j -= 60;
2148 if (j >= 100 && j <= 107)
2149 j -= 60;
2150 if (j >= 30 && j <= 39 && j != 38)
2151 c = (c & 0xf0) | ((j - 30) ^ 9);
2152 else if (j >= 40 && j <= 49 && j != 48)
2153 c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
2154 if (j == 0)
2155 c = 0;
2156 # ifdef COLORS256
2157 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2158 cx &= 0xf0;
2159 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2160 cx &= 0x0f;
2161 # endif
2162 #endif
2163 if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
2164 continue;
2165 j = rendlist[j];
2166 if (j & (1 << NATTR))
2167 a &= j;
2168 else
2169 a |= j;
2171 while (++i < curr->w_NumArgs);
2172 curr->w_rend.attr = a;
2173 #ifdef COLOR
2174 curr->w_rend.color = c;
2175 # ifdef COLORS256
2176 curr->w_rend.colorx = cx;
2177 # endif
2178 #endif
2179 LSetRendition(&curr->w_layer, &curr->w_rend);
2182 static void
2183 FillWithEs()
2185 register int i;
2186 register unsigned char *p, *ep;
2188 LClearAll(&curr->w_layer, 1);
2189 curr->w_y = curr->w_x = 0;
2190 for (i = 0; i < rows; ++i)
2192 clear_mline(&curr->w_mlines[i], 0, cols + 1);
2193 p = curr->w_mlines[i].image;
2194 ep = p + cols;
2195 while (p < ep)
2196 *p++ = 'E';
2198 LRefreshAll(&curr->w_layer, 1);
2203 * Ugly autoaka hack support:
2204 * ChangeAKA() sets a new aka
2205 * FindAKA() searches for an autoaka match
2208 void
2209 ChangeAKA(p, s, l)
2210 struct win *p;
2211 char *s;
2212 int l;
2214 int i, c;
2216 for (i = 0; l > 0; l--)
2218 if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
2219 break;
2220 c = (unsigned char)*s++;
2221 if (c == 0)
2222 break;
2223 if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
2224 continue;
2225 p->w_akachange[i++] = c;
2227 p->w_akachange[i] = 0;
2228 p->w_title = p->w_akachange;
2229 if (p->w_akachange != p->w_akabuf)
2230 if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
2231 p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
2232 WindowChanged(p, 't');
2233 WindowChanged((struct win *)0, 'w');
2234 WindowChanged((struct win *)0, 'W');
2237 static void
2238 FindAKA()
2240 register unsigned char *cp, *line;
2241 register struct win *wp = curr;
2242 register int len = strlen(wp->w_akabuf);
2243 int y;
2245 y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
2246 cols = wp->w_width;
2247 try_line:
2248 cp = line = wp->w_mlines[y].image;
2249 if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
2251 for (;;)
2253 if (cp - line >= cols - len)
2255 if (++y == wp->w_autoaka && y < rows)
2256 goto try_line;
2257 return;
2259 if (strncmp((char *)cp, wp->w_akabuf, len) == 0)
2260 break;
2261 cp++;
2263 cp += len;
2265 for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
2267 if (len)
2269 if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
2270 wp->w_autoaka = -1;
2271 else
2272 wp->w_autoaka = 0;
2273 line = cp;
2274 while (len && *cp != ' ')
2276 if (*cp++ == '/')
2277 line = cp;
2278 len--;
2280 ChangeAKA(wp, (char *)line, cp - line);
2282 else
2283 wp->w_autoaka = 0;
2286 static void
2287 RestorePosRendition()
2289 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2290 LSetRendition(&curr->w_layer, &curr->w_rend);
2293 /* Send a terminal report as if it were typed. */
2294 static void
2295 Report(fmt, n1, n2)
2296 char *fmt;
2297 int n1, n2;
2299 register int len;
2300 char rbuf[40]; /* enough room for all replys */
2302 sprintf(rbuf, fmt, n1, n2);
2303 len = strlen(rbuf);
2305 #ifdef PSEUDOS
2306 if (W_UWP(curr))
2308 if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
2310 bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
2311 curr->w_pwin->p_inlen += len;
2314 else
2315 #endif
2317 if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
2319 bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
2320 curr->w_inlen += len;
2328 *====================================================================*
2329 *====================================================================*
2332 /**********************************************************************
2334 * Memory subsystem.
2338 static void
2339 MFixLine(p, y, mc)
2340 struct win *p;
2341 int y;
2342 struct mchar *mc;
2344 struct mline *ml = &p->w_mlines[y];
2345 if (mc->attr && ml->attr == null)
2347 if ((ml->attr = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2349 ml->attr = null;
2350 mc->attr = p->w_rend.attr = 0;
2351 WMsg(p, 0, "Warning: no space for attr - turned off");
2354 #ifdef FONT
2355 if (mc->font && ml->font == null)
2357 if ((ml->font = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2359 ml->font = null;
2360 p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
2361 p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
2362 mc->font = p->w_rend.font = 0;
2363 WMsg(p, 0, "Warning: no space for font - turned off");
2366 #endif
2367 #ifdef COLOR
2368 if (mc->color && ml->color == null)
2370 if ((ml->color = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2372 ml->color = null;
2373 mc->color = p->w_rend.color = 0;
2374 WMsg(p, 0, "Warning: no space for color - turned off");
2377 # ifdef COLORS256
2378 if (mc->colorx && ml->colorx == null)
2380 if ((ml->colorx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2382 ml->colorx = null;
2383 mc->colorx = p->w_rend.colorx = 0;
2384 WMsg(p, 0, "Warning: no space for extended colors - turned off");
2387 # endif
2388 #endif
2391 /*****************************************************************/
2393 #ifdef DW_CHARS
2394 # define MKillDwRight(p, ml, x) \
2395 if (dw_right(ml, x, p->w_encoding)) \
2397 if (x > 0) \
2398 copy_mchar2mline(&mchar_blank, ml, x - 1); \
2399 copy_mchar2mline(&mchar_blank, ml, x); \
2402 # define MKillDwLeft(p, ml, x) \
2403 if (dw_left(ml, x, p->w_encoding)) \
2405 copy_mchar2mline(&mchar_blank, ml, x); \
2406 copy_mchar2mline(&mchar_blank, ml, x + 1); \
2408 #else
2409 # define MKillDwRight(p, ml, x) ;
2410 # define MKillDwLeft(p, ml, x) ;
2411 #endif
2413 static void
2414 MScrollH(p, n, y, xs, xe, bce)
2415 struct win *p;
2416 int n, y, xs, xe, bce;
2418 struct mline *ml;
2420 if (n == 0)
2421 return;
2422 ml = &p->w_mlines[y];
2423 MKillDwRight(p, ml, xs);
2424 MKillDwLeft(p, ml, xe);
2425 if (n > 0)
2427 if (xe - xs + 1 > n)
2429 MKillDwRight(p, ml, xs + n);
2430 bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
2432 else
2433 n = xe - xs + 1;
2434 clear_mline(ml, xe + 1 - n, n);
2435 #ifdef COLOR
2436 if (bce)
2437 MBceLine(p, y, xe + 1 - n, n, bce);
2438 #endif
2440 else
2442 n = -n;
2443 if (xe - xs + 1 > n)
2445 MKillDwLeft(p, ml, xe - n);
2446 bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
2448 else
2449 n = xe - xs + 1;
2450 clear_mline(ml, xs, n);
2451 #ifdef COLOR
2452 if (bce)
2453 MBceLine(p, y, xs, n, bce);
2454 #endif
2458 static void
2459 MScrollV(p, n, ys, ye, bce)
2460 struct win *p;
2461 int n, ys, ye, bce;
2463 int i, cnt1, cnt2;
2464 struct mline tmp[256];
2465 struct mline *ml;
2467 if (n == 0)
2468 return;
2469 if (n > 0)
2471 if (n > 256)
2473 MScrollV(p, n - 256, ys, ye, bce);
2474 n = 256;
2476 if (ye - ys + 1 < n)
2477 n = ye - ys + 1;
2478 #ifdef COPY_PASTE
2479 if (compacthist)
2481 ye = MFindUsedLine(p, ye, ys);
2482 if (ye - ys + 1 < n)
2483 n = ye - ys + 1;
2484 if (n <= 0)
2485 return;
2487 #endif
2488 /* Clear lines */
2489 ml = p->w_mlines + ys;
2490 for (i = ys; i < ys + n; i++, ml++)
2492 #ifdef COPY_PASTE
2493 if (ys == p->w_top)
2494 WAddLineToHist(p, ml);
2495 #endif
2496 if (ml->attr != null)
2497 free(ml->attr);
2498 ml->attr = null;
2499 #ifdef FONT
2500 if (ml->font != null)
2501 free(ml->font);
2502 ml->font = null;
2503 #endif
2504 #ifdef COLOR
2505 if (ml->color != null)
2506 free(ml->color);
2507 ml->color = null;
2508 # ifdef COLORS256
2509 if (ml->colorx != null)
2510 free(ml->colorx);
2511 ml->colorx = null;
2512 # endif
2513 #endif
2514 bclear((char *)ml->image, p->w_width + 1);
2515 #ifdef COLOR
2516 if (bce)
2517 MBceLine(p, i, 0, p->w_width, bce);
2518 #endif
2520 /* switch 'em over */
2521 cnt1 = n * sizeof(struct mline);
2522 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2523 if (cnt1 && cnt2)
2524 Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
2526 else
2528 if (n < -256)
2530 MScrollV(p, n + 256, ys, ye, bce);
2531 n = -256;
2533 n = -n;
2534 if (ye - ys + 1 < n)
2535 n = ye - ys + 1;
2537 ml = p->w_mlines + ye;
2538 /* Clear lines */
2539 for (i = ye; i > ye - n; i--, ml--)
2541 if (ml->attr != null)
2542 free(ml->attr);
2543 ml->attr = null;
2544 #ifdef FONT
2545 if (ml->font != null)
2546 free(ml->font);
2547 ml->font = null;
2548 #endif
2549 #ifdef COLOR
2550 if (ml->color != null)
2551 free(ml->color);
2552 ml->color = null;
2553 # ifdef COLORS256
2554 if (ml->colorx != null)
2555 free(ml->colorx);
2556 ml->colorx = null;
2557 # endif
2558 #endif
2559 bclear((char *)ml->image, p->w_width + 1);
2560 #ifdef COLOR
2561 if (bce)
2562 MBceLine(p, i, 0, p->w_width, bce);
2563 #endif
2565 cnt1 = n * sizeof(struct mline);
2566 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2567 if (cnt1 && cnt2)
2568 Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
2572 static void
2573 Scroll(cp, cnt1, cnt2, tmp)
2574 char *cp, *tmp;
2575 int cnt1, cnt2;
2577 if (!cnt1 || !cnt2)
2578 return;
2579 if (cnt1 <= cnt2)
2581 bcopy(cp, tmp, cnt1);
2582 bcopy(cp + cnt1, cp, cnt2);
2583 bcopy(tmp, cp + cnt2, cnt1);
2585 else
2587 bcopy(cp + cnt1, tmp, cnt2);
2588 bcopy(cp, cp + cnt2, cnt1);
2589 bcopy(tmp, cp, cnt2);
2593 static void
2594 MClearArea(p, xs, ys, xe, ye, bce)
2595 struct win *p;
2596 int xs, ys, xe, ye, bce;
2598 int n, y;
2599 int xxe;
2600 struct mline *ml;
2602 /* Check for zero-height window */
2603 if (ys < 0 || ye < ys)
2604 return;
2606 /* check for magic margin condition */
2607 if (xs >= p->w_width)
2608 xs = p->w_width - 1;
2609 if (xe >= p->w_width)
2610 xe = p->w_width - 1;
2612 MKillDwRight(p, p->w_mlines + ys, xs);
2613 MKillDwLeft(p, p->w_mlines + ye, xe);
2615 ml = p->w_mlines + ys;
2616 for (y = ys; y <= ye; y++, ml++)
2618 xxe = (y == ye) ? xe : p->w_width - 1;
2619 n = xxe - xs + 1;
2620 if (n > 0)
2621 clear_mline(ml, xs, n);
2622 #ifdef COLOR
2623 if (n > 0 && bce)
2624 MBceLine(p, y, xs, xs + n - 1, bce);
2625 #endif
2626 xs = 0;
2630 static void
2631 MInsChar(p, c, x, y)
2632 struct win *p;
2633 struct mchar *c;
2634 int x, y;
2636 int n;
2637 struct mline *ml;
2639 ASSERT(x >= 0 && x < p->w_width);
2640 MFixLine(p, y, c);
2641 ml = p->w_mlines + y;
2642 n = p->w_width - x - 1;
2643 MKillDwRight(p, ml, x);
2644 if (n > 0)
2646 MKillDwRight(p, ml, p->w_width - 1);
2647 bcopy_mline(ml, x, x + 1, n);
2649 copy_mchar2mline(c, ml, x);
2650 #ifdef DW_CHARS
2651 if (c->mbcs)
2653 if (--n > 0)
2655 MKillDwRight(p, ml, p->w_width - 1);
2656 bcopy_mline(ml, x + 1, x + 2, n);
2658 copy_mchar2mline(c, ml, x + 1);
2659 ml->image[x + 1] = c->mbcs;
2660 # ifdef UTF8
2661 if (p->w_encoding != UTF8)
2662 ml->font[x + 1] |= 0x80;
2663 else if (p->w_encoding == UTF8 && c->mbcs)
2664 ml->font[x + 1] = c->mbcs;
2665 # else
2666 ml->font[x + 1] |= 0x80;
2667 # endif
2669 #endif
2672 static void
2673 MPutChar(p, c, x, y)
2674 struct win *p;
2675 struct mchar *c;
2676 int x, y;
2678 struct mline *ml;
2680 MFixLine(p, y, c);
2681 ml = &p->w_mlines[y];
2682 MKillDwRight(p, ml, x);
2683 MKillDwLeft(p, ml, x);
2684 copy_mchar2mline(c, ml, x);
2685 #ifdef DW_CHARS
2686 if (c->mbcs)
2688 MKillDwLeft(p, ml, x + 1);
2689 copy_mchar2mline(c, ml, x + 1);
2690 ml->image[x + 1] = c->mbcs;
2691 # ifdef UTF8
2692 if (p->w_encoding != UTF8)
2693 ml->font[x + 1] |= 0x80;
2694 else if (p->w_encoding == UTF8 && c->mbcs)
2695 ml->font[x + 1] = c->mbcs;
2696 # else
2697 ml->font[x + 1] |= 0x80;
2698 # endif
2700 #endif
2704 static void
2705 MWrapChar(p, c, y, top, bot, ins)
2706 struct win *p;
2707 struct mchar *c;
2708 int y, top, bot;
2709 int ins;
2711 struct mline *ml;
2712 int bce;
2714 #ifdef COLOR
2715 bce = rend_getbg(c);
2716 #else
2717 bce = 0;
2718 #endif
2719 MFixLine(p, y, c);
2720 ml = &p->w_mlines[y];
2721 copy_mchar2mline(&mchar_null, ml, p->w_width);
2722 if (y == bot)
2723 MScrollV(p, 1, top, bot, bce);
2724 else if (y < p->w_height - 1)
2725 y++;
2726 if (ins)
2727 MInsChar(p, c, 0, y);
2728 else
2729 MPutChar(p, c, 0, y);
2732 static void
2733 MPutStr(p, s, n, r, x, y)
2734 struct win *p;
2735 char *s;
2736 int n;
2737 struct mchar *r;
2738 int x, y;
2740 struct mline *ml;
2741 int i;
2742 unsigned char *b;
2744 if (n <= 0)
2745 return;
2746 MFixLine(p, y, r);
2747 ml = &p->w_mlines[y];
2748 MKillDwRight(p, ml, x);
2749 MKillDwLeft(p, ml, x + n - 1);
2750 bcopy(s, (char *)ml->image + x, n);
2751 b = ml->attr + x;
2752 for (i = n; i-- > 0;)
2753 *b++ = r->attr;
2754 #ifdef FONT
2755 b = ml->font + x;
2756 for (i = n; i-- > 0;)
2757 *b++ = r->font;
2758 #endif
2759 #ifdef COLOR
2760 b = ml->color + x;
2761 for (i = n; i-- > 0;)
2762 *b++ = r->color;
2763 # ifdef COLORS256
2764 b = ml->colorx + x;
2765 for (i = n; i-- > 0;)
2766 *b++ = r->colorx;
2767 # endif
2768 #endif
2771 #ifdef COLOR
2772 static void
2773 MBceLine(p, y, xs, xe, bce)
2774 struct win *p;
2775 int y, xs, xe, bce;
2777 struct mchar mc;
2778 struct mline *ml;
2779 int x;
2781 mc = mchar_null;
2782 rend_setbg(&mc, bce);
2783 MFixLine(p, y, &mc);
2784 ml = p->w_mlines + y;
2785 # ifdef COLORS16
2786 if (mc.attr)
2787 for (x = xs; x <= xe; x++)
2788 ml->attr[x] = mc.attr;
2789 # endif
2790 if (mc.color)
2791 for (x = xs; x <= xe; x++)
2792 ml->color[x] = mc.color;
2793 # ifdef COLORS256
2794 if (mc.colorx)
2795 for (x = xs; x <= xe; x++)
2796 ml->colorx[x] = mc.colorx;
2797 # endif
2799 #endif
2802 #ifdef COPY_PASTE
2803 static void
2804 WAddLineToHist(wp, ml)
2805 struct win *wp;
2806 struct mline *ml;
2808 register unsigned char *q, *o;
2809 struct mline *hml;
2811 if (wp->w_histheight == 0)
2812 return;
2813 hml = &wp->w_hlines[wp->w_histidx];
2814 q = ml->image; ml->image = hml->image; hml->image = q;
2816 q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
2817 if (o != null)
2818 free(o);
2820 #ifdef FONT
2821 q = ml->font; o = hml->font; hml->font = q; ml->font = null;
2822 if (o != null)
2823 free(o);
2824 #endif
2826 #ifdef COLOR
2827 q = ml->color; o = hml->color; hml->color = q; ml->color = null;
2828 if (o != null)
2829 free(o);
2830 # ifdef COLORS256
2831 q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
2832 if (o != null)
2833 free(o);
2834 # endif
2835 #endif
2837 if (++wp->w_histidx >= wp->w_histheight)
2838 wp->w_histidx = 0;
2840 #endif
2843 MFindUsedLine(p, ye, ys)
2844 struct win *p;
2845 int ys, ye;
2847 int y;
2848 struct mline *ml = p->w_mlines + ye;
2850 debug2("MFindUsedLine: %d %d\n", ye, ys);
2851 for (y = ye; y >= ys; y--, ml--)
2853 if (bcmp((char*)ml->image, blank, p->w_width))
2854 break;
2855 if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
2856 break;
2857 #ifdef COLOR
2858 if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
2859 break;
2860 # ifdef COLORS256
2861 if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
2862 break;
2863 # endif
2864 #endif
2866 debug1("MFindUsedLine returning %d\n", y);
2867 return y;
2872 *====================================================================*
2873 *====================================================================*
2877 * Tricky: send only one bell even if the window is displayed
2878 * more than once.
2880 void
2881 WBell(p, visual)
2882 struct win *p;
2883 int visual;
2885 struct canvas *cv;
2886 for (display = displays; display; display = display->d_next)
2888 for (cv = D_cvlist; cv; cv = cv->c_next)
2889 if (cv->c_layer->l_bottom == &p->w_layer)
2890 break;
2891 if (cv && !visual)
2892 AddCStr(D_BL);
2893 else if (cv && D_VB)
2894 AddCStr(D_VB);
2895 else
2896 p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
2901 * This should be reverse video.
2902 * Only change video if window is fore.
2903 * Because it is used in some termcaps to emulate
2904 * a visual bell we do this hack here.
2905 * (screen uses \Eg as special vbell sequence)
2907 static void
2908 WReverseVideo(p, on)
2909 struct win *p;
2910 int on;
2912 struct canvas *cv;
2913 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2915 display = cv->c_display;
2916 if (cv != D_forecv)
2917 continue;
2918 ReverseVideo(on);
2919 if (!on && p->w_revvid && !D_CVR)
2921 if (D_VB)
2922 AddCStr(D_VB);
2923 else
2924 p->w_bell = BELL_VISUAL;
2929 void
2930 WMsg(p, err, str)
2931 struct win *p;
2932 int err;
2933 char *str;
2935 extern struct layer *flayer;
2936 struct layer *oldflayer = flayer;
2937 flayer = &p->w_layer;
2938 LMsg(err, str);
2939 flayer = oldflayer;
2942 void
2943 WChangeSize(p, w, h)
2944 struct win *p;
2945 int w, h;
2947 int wok = 0;
2948 struct canvas *cv;
2950 if (p->w_layer.l_cvlist == 0)
2952 /* window not displayed -> works always */
2953 ChangeWindowSize(p, w, h, p->w_histheight);
2954 return;
2956 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2958 display = cv->c_display;
2959 if (p != D_fore)
2960 continue; /* change only fore */
2961 if (D_CWS)
2962 break;
2963 if (D_CZ0 && (w == Z0width || w == Z1width))
2964 wok = 1;
2966 if (cv == 0 && wok == 0) /* can't change any display */
2967 return;
2968 if (!D_CWS)
2969 h = p->w_height;
2970 ChangeWindowSize(p, w, h, p->w_histheight);
2971 for (display = displays; display; display = display->d_next)
2973 if (p == D_fore)
2975 if (D_cvlist && D_cvlist->c_next == 0)
2976 ResizeDisplay(w, h);
2977 else
2978 ResizeDisplay(w, D_height);
2979 ResizeLayersToCanvases(); /* XXX Hmm ? */
2980 continue;
2982 for (cv = D_cvlist; cv; cv = cv->c_next)
2983 if (cv->c_layer->l_bottom == &p->w_layer)
2984 break;
2985 if (cv)
2986 Redisplay(0);
2990 static int
2991 WindowChangedCheck(s, what, hp)
2992 char *s;
2993 int what;
2994 int *hp;
2996 int h = 0;
2997 int l;
2998 while(*s)
3000 if (*s++ != (hp ? '%' : '\005'))
3001 continue;
3002 l = 0;
3003 s += (*s == '+');
3004 s += (*s == '-');
3005 while (*s >= '0' && *s <= '9')
3006 s++;
3007 if (*s == 'L')
3009 s++;
3010 l = 0x100;
3012 if (*s == 'h')
3013 h = 1;
3014 if (*s == what || ((*s | l) == what) || what == 'd')
3015 break;
3016 if (*s)
3017 s++;
3019 if (hp)
3020 *hp = h;
3021 return *s ? 1 : 0;
3024 void
3025 WindowChanged(p, what)
3026 struct win *p;
3027 int what;
3029 int inwstr, inhstr, inlstr;
3030 int inwstrh = 0, inhstrh = 0, inlstrh = 0;
3031 int got, ox, oy;
3032 struct display *olddisplay = display;
3033 struct canvas *cv;
3035 inwstr = inhstr = 0;
3037 if (what == 'f')
3039 WindowChanged((struct win *)0, 'w'|0x100);
3040 WindowChanged((struct win *)0, 'W'|0x100);
3043 if (what)
3045 inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
3046 inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
3047 inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
3049 else
3051 inwstr = inhstr = 0;
3052 inlstr = 1;
3055 if (p == 0)
3057 for (display = displays; display; display = display->d_next)
3059 ox = D_x;
3060 oy = D_y;
3061 for (cv = D_cvlist; cv; cv = cv->c_next)
3063 if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3064 WListUpdatecv(cv, (struct win *)0);
3065 p = Layer2Window(cv->c_layer);
3066 if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3067 if (cv->c_ye + 1 < D_height)
3068 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3070 p = D_fore;
3071 if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3072 RefreshHStatus();
3073 if (ox != -1 && ox != -1)
3074 GotoPos(ox, oy);
3076 display = olddisplay;
3077 return;
3080 if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
3082 inwstr |= inwstrh;
3083 inhstr |= inhstrh;
3084 inlstr |= inlstrh;
3086 if (!inwstr && !inhstr && !inlstr)
3087 return;
3088 for (display = displays; display; display = display->d_next)
3090 got = 0;
3091 ox = D_x;
3092 oy = D_y;
3093 for (cv = D_cvlist; cv; cv = cv->c_next)
3095 if (inlstr)
3096 WListUpdatecv(cv, p);
3097 if (Layer2Window(cv->c_layer) != p)
3098 continue;
3099 got = 1;
3100 if (inwstr && cv->c_ye + 1 < D_height)
3101 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3103 if (got && inhstr && p == D_fore)
3104 RefreshHStatus();
3105 if (ox != -1 && ox != -1)
3106 GotoPos(ox, oy);
3108 display = olddisplay;