Add two events
[screen-lua.git] / src / ansi.c
blob93701601444061db173a206c2af51cddb7ac4df8
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 */};
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);
310 #ifdef SCRIPT
311 /*May it cause buffer overrun?*/
312 if (buf[len])
313 buf[len]=0;
314 trigger_sevent(&wp->w_sev.onoutput, wp, buf);
315 #endif
317 /* set global variables (yuck!) */
318 curr = wp;
319 cols = curr->w_width;
320 rows = curr->w_height;
322 if (curr->w_silence)
323 SetTimeout(&curr->w_silenceev, curr->w_silencewait * 1000);
325 if (curr->w_monitor == MON_ON)
327 debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
328 curr->w_monitor = MON_FOUND;
331 if (cols && rows)
335 c = (unsigned char)*buf++;
336 #ifdef FONT
337 # ifdef DW_CHARS
338 if (!curr->w_mbcs)
339 # endif
340 curr->w_rend.font = curr->w_FontL; /* Default: GL */
341 #endif
343 /* The next part is only for speedup */
344 if (curr->w_state == LIT &&
345 #ifdef UTF8
346 curr->w_encoding != UTF8 &&
347 #endif
348 #ifdef DW_CHARS
349 !is_dw_font(curr->w_rend.font) &&
350 # ifdef ENCODINGS
351 curr->w_rend.font != KANA && !curr->w_mbcs &&
352 # endif
353 #endif
354 #ifdef FONT
355 curr->w_rend.font != '<' &&
356 #endif
357 c >= ' ' && c != 0x7f &&
358 ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) && !curr->w_ss &&
359 !curr->w_insert && curr->w_x < cols - 1)
361 register int currx = curr->w_x;
362 char *imp = buf - 1;
364 while (currx < cols - 1)
366 currx++;
367 if (--len == 0)
368 break;
369 c = (unsigned char)*buf++;
370 if (c < ' ' || c == 0x7f || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
371 break;
373 currx -= curr->w_x;
374 if (currx > 0)
376 MPutStr(curr, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
377 LPutStr(&curr->w_layer, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
378 curr->w_x += currx;
380 if (len == 0)
381 break;
383 /* end of speedup code */
385 #ifdef UTF8
386 if (curr->w_encoding == UTF8)
388 c = FromUtf8(c, &curr->w_decodestate);
389 if (c == -1)
390 continue;
391 if (c == -2)
393 c = UCS_REPL;
394 /* try char again */
395 buf--;
396 len++;
398 if (c > 0xff)
399 debug1("read UNICODE %04x\n", c);
401 #endif
403 tryagain:
404 switch (curr->w_state)
406 case PRIN:
407 switch (c)
409 case '\033':
410 curr->w_state = PRINESC;
411 break;
412 default:
413 PrintChar(c);
415 break;
416 case PRINESC:
417 switch (c)
419 case '[':
420 curr->w_state = PRINCSI;
421 break;
422 default:
423 PrintChar('\033');
424 PrintChar(c);
425 curr->w_state = PRIN;
427 break;
428 case PRINCSI:
429 switch (c)
431 case '4':
432 curr->w_state = PRIN4;
433 break;
434 default:
435 PrintChar('\033');
436 PrintChar('[');
437 PrintChar(c);
438 curr->w_state = PRIN;
440 break;
441 case PRIN4:
442 switch (c)
444 case 'i':
445 curr->w_state = LIT;
446 PrintFlush();
447 if (curr->w_pdisplay && curr->w_pdisplay->d_printfd >= 0)
449 close(curr->w_pdisplay->d_printfd);
450 curr->w_pdisplay->d_printfd = -1;
452 curr->w_pdisplay = 0;
453 break;
454 default:
455 PrintChar('\033');
456 PrintChar('[');
457 PrintChar('4');
458 PrintChar(c);
459 curr->w_state = PRIN;
461 break;
462 case ASTR:
463 if (c == 0)
464 break;
465 if (c == '\033')
467 curr->w_state = STRESC;
468 break;
470 /* special xterm hack: accept SetStatus sequence. Yucc! */
471 /* allow ^E for title escapes */
472 if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
473 if (!curr->w_c1 || c != ('\\' ^ 0xc0))
475 StringChar(c);
476 break;
478 c = '\\';
479 /* FALLTHROUGH */
480 case STRESC:
481 switch (c)
483 case '\\':
484 if (StringEnd() == 0 || len <= 1)
485 break;
486 /* check if somewhere a status is displayed */
487 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
489 display = cv->c_display;
490 if (D_status == STATUS_ON_WIN)
491 break;
493 if (cv)
495 if (len > IOSIZE + 1)
496 len = IOSIZE + 1;
497 curr->w_outlen = len - 1;
498 bcopy(buf, curr->w_outbuf, len - 1);
499 return; /* wait till status is gone */
501 break;
502 case '\033':
503 StringChar('\033');
504 break;
505 default:
506 curr->w_state = ASTR;
507 StringChar('\033');
508 StringChar(c);
509 break;
511 break;
512 case ESC:
513 switch (c)
515 case '[':
516 curr->w_NumArgs = 0;
517 curr->w_intermediate = 0;
518 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
519 curr->w_state = CSI;
520 break;
521 case ']':
522 StringStart(OSC);
523 break;
524 case '_':
525 StringStart(APC);
526 break;
527 case 'P':
528 StringStart(DCS);
529 break;
530 case '^':
531 StringStart(PM);
532 break;
533 case '!':
534 StringStart(GM);
535 break;
536 case '"':
537 case 'k':
538 StringStart(AKA);
539 break;
540 default:
541 if (Special(c))
543 curr->w_state = LIT;
544 break;
546 debug1("not special. c = %x\n", c);
547 if (c >= ' ' && c <= '/')
549 if (curr->w_intermediate)
551 #ifdef DW_CHARS
552 if (curr->w_intermediate == '$')
553 c |= '$' << 8;
554 else
555 #endif
556 c = -1;
558 curr->w_intermediate = c;
560 else if (c >= '0' && c <= '~')
562 DoESC(c, curr->w_intermediate);
563 curr->w_state = LIT;
565 else
567 curr->w_state = LIT;
568 goto tryagain;
571 break;
572 case CSI:
573 switch (c)
575 case '0': case '1': case '2': case '3': case '4':
576 case '5': case '6': case '7': case '8': case '9':
577 if (curr->w_NumArgs < MAXARGS)
579 if (curr->w_args[curr->w_NumArgs] < 100000000)
580 curr->w_args[curr->w_NumArgs] =
581 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
583 break;
584 case ';':
585 case ':':
586 if (curr->w_NumArgs < MAXARGS)
587 curr->w_NumArgs++;
588 break;
589 default:
590 if (Special(c))
591 break;
592 if (c >= '@' && c <= '~')
594 if (curr->w_NumArgs < MAXARGS)
595 curr->w_NumArgs++;
596 DoCSI(c, curr->w_intermediate);
597 if (curr->w_state != PRIN)
598 curr->w_state = LIT;
600 else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
601 curr->w_intermediate = curr->w_intermediate ? -1 : c;
602 else
604 curr->w_state = LIT;
605 goto tryagain;
608 break;
609 case LIT:
610 default:
611 #ifdef DW_CHARS
612 if (curr->w_mbcs)
613 if (c <= ' ' || c == 0x7f || (c >= 0x80 && c < 0xa0 && curr->w_c1))
614 curr->w_mbcs = 0;
615 #endif
616 if (c < ' ')
618 if (c == '\033')
620 curr->w_intermediate = 0;
621 curr->w_state = ESC;
622 if (curr->w_autoaka < 0)
623 curr->w_autoaka = 0;
625 else
626 Special(c);
627 break;
629 if (c >= 0x80 && c < 0xa0 && curr->w_c1)
630 #ifdef FONT
631 if ((curr->w_FontR & 0xf0) != 0x20
632 # ifdef UTF8
633 || curr->w_encoding == UTF8
634 # endif
636 #endif
638 switch (c)
640 case 0xc0 ^ 'D':
641 case 0xc0 ^ 'E':
642 case 0xc0 ^ 'H':
643 case 0xc0 ^ 'M':
644 case 0xc0 ^ 'N': /* SS2 */
645 case 0xc0 ^ 'O': /* SS3 */
646 DoESC(c ^ 0xc0, 0);
647 break;
648 case 0xc0 ^ '[':
649 if (curr->w_autoaka < 0)
650 curr->w_autoaka = 0;
651 curr->w_NumArgs = 0;
652 curr->w_intermediate = 0;
653 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
654 curr->w_state = CSI;
655 break;
656 case 0xc0 ^ 'P':
657 StringStart(DCS);
658 break;
659 default:
660 break;
662 break;
665 #ifdef FONT
666 # ifdef DW_CHARS
667 if (!curr->w_mbcs)
669 # endif
670 if (c < 0x80 || curr->w_gr == 0)
671 curr->w_rend.font = curr->w_FontL;
672 # ifdef ENCODINGS
673 else if (curr->w_gr == 2 && !curr->w_ss)
674 curr->w_rend.font = curr->w_FontE;
675 # endif
676 else
677 curr->w_rend.font = curr->w_FontR;
678 # ifdef DW_CHARS
680 # endif
681 # ifdef UTF8
682 if (curr->w_encoding == UTF8)
684 if (curr->w_rend.font == '0')
686 struct mchar mc, *mcp;
688 debug1("SPECIAL %x\n", c);
689 mc.image = c;
690 mc.mbcs = 0;
691 mc.font = '0';
692 mcp = recode_mchar(&mc, 0, UTF8);
693 debug2("%02x %02x\n", mcp->image, mcp->font);
694 c = mcp->image | mcp->font << 8;
696 curr->w_rend.font = 0;
698 # ifdef DW_CHARS
699 if (curr->w_encoding == UTF8 && utf8_isdouble(c))
700 curr->w_mbcs = 0xff;
701 # endif
702 if (curr->w_encoding == UTF8 && c >= 0x0300 && utf8_iscomb(c))
704 int ox, oy;
705 struct mchar omc;
707 ox = curr->w_x - 1;
708 oy = curr->w_y;
709 if (ox < 0)
711 ox = curr->w_width - 1;
712 oy--;
714 if (oy < 0)
715 oy = 0;
716 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
717 if (omc.image == 0xff && omc.font == 0xff)
719 ox--;
720 if (ox >= 0)
722 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
723 omc.mbcs = 0xff;
726 if (ox >= 0)
728 utf8_handle_comb(c, &omc);
729 MFixLine(curr, oy, &omc);
730 copy_mchar2mline(&omc, &curr->w_mlines[oy], ox);
731 LPutChar(&curr->w_layer, &omc, ox, oy);
732 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
734 break;
736 font = curr->w_rend.font;
737 # endif
738 # ifdef DW_CHARS
739 # ifdef ENCODINGS
740 if (font == KANA && curr->w_encoding == SJIS && curr->w_mbcs == 0)
742 /* Lets see if it is the first byte of a kanji */
743 debug1("%x may be first of SJIS\n", c);
744 if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
746 debug("YES!\n");
747 curr->w_mbcs = c;
748 break;
751 # endif
752 if (font == 031 && c == 0x80 && !curr->w_mbcs)
753 font = curr->w_rend.font = 0;
754 if (is_dw_font(font) && c == ' ')
755 font = curr->w_rend.font = 0;
756 if (is_dw_font(font) || curr->w_mbcs)
758 int t = c;
759 if (curr->w_mbcs == 0)
761 curr->w_mbcs = c;
762 break;
764 if (curr->w_x == cols - 1)
766 curr->w_x += curr->w_wrap ? 1 : -1;
767 debug1("Patched w_x to %d\n", curr->w_x);
769 # ifdef UTF8
770 if (curr->w_encoding != UTF8)
771 # endif
773 c = curr->w_mbcs;
774 # ifdef ENCODINGS
775 if (font == KANA && curr->w_encoding == SJIS)
777 debug2("SJIS !! %x %x\n", c, t);
779 * SJIS -> EUC mapping:
780 * First byte:
781 * 81,82...9f -> 21,23...5d
782 * e0,e1...ef -> 5f,61...7d
783 * Second byte:
784 * 40-7e -> 21-5f
785 * 80-9e -> 60-7e
786 * 9f-fc -> 21-7e (increment first byte!)
788 if (0x40 <= t && t <= 0xfc && t != 0x7f)
790 if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
791 else c = (c - 0xc1) * 2 + 0x21;
792 if (t <= 0x7e) t -= 0x1f;
793 else if (t <= 0x9e) t -= 0x20;
794 else t -= 0x7e, c++;
795 curr->w_rend.font = KANJI;
797 else
799 /* Incomplete shift-jis - skip first byte */
800 c = t;
801 t = 0;
803 debug2("SJIS after %x %x\n", c, t);
805 # endif
806 if (t && curr->w_gr && font != 030 && font != 031)
808 t &= 0x7f;
809 if (t < ' ')
810 goto tryagain;
812 if (t == '\177')
813 break;
814 curr->w_mbcs = t;
817 # endif /* DW_CHARS */
818 if (font == '<' && c >= ' ')
820 font = curr->w_rend.font = 0;
821 c |= 0x80;
823 # ifdef UTF8
824 else if (curr->w_gr && curr->w_encoding != UTF8)
825 # else
826 else if (curr->w_gr)
827 # endif
829 #ifdef ENCODINGS
830 if (c == 0x80 && font == 0 && curr->w_encoding == GBK)
831 c = 0xa4;
832 else
833 c &= 0x7f;
834 if (c < ' ' && font != 031)
835 goto tryagain;
836 #else
837 c &= 0x7f;
838 if (c < ' ') /* this is ugly but kanji support */
839 goto tryagain; /* prevents nicer programming */
840 #endif
842 #endif /* FONT */
843 if (c == '\177')
844 break;
845 curr->w_rend.image = c;
846 #ifdef UTF8
847 if (curr->w_encoding == UTF8)
848 curr->w_rend.font = c >> 8;
849 #endif
850 #ifdef DW_CHARS
851 curr->w_rend.mbcs = curr->w_mbcs;
852 #endif
853 if (curr->w_x < cols - 1)
855 if (curr->w_insert)
857 save_mline(&curr->w_mlines[curr->w_y], cols);
858 MInsChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
859 LInsChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y, &mline_old);
860 curr->w_x++;
862 else
864 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
865 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
866 curr->w_x++;
869 else if (curr->w_x == cols - 1)
871 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
872 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
873 if (curr->w_wrap)
874 curr->w_x++;
876 else
878 MWrapChar(curr, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
879 LWrapChar(&curr->w_layer, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
880 if (curr->w_y != curr->w_bot && curr->w_y != curr->w_height - 1)
881 curr->w_y++;
882 curr->w_x = 1;
884 #ifdef FONT
885 # ifdef DW_CHARS
886 if (curr->w_mbcs)
888 curr->w_rend.mbcs = curr->w_mbcs = 0;
889 curr->w_x++;
891 # endif
892 if (curr->w_ss)
894 curr->w_FontL = curr->w_charsets[curr->w_Charset];
895 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
896 curr->w_rend.font = curr->w_FontL;
897 LSetRendition(&curr->w_layer, &curr->w_rend);
898 curr->w_ss = 0;
900 #endif /* FONT */
901 break;
904 while (--len);
906 if (!printcmd && curr->w_state == PRIN)
907 PrintFlush();
910 static void
911 WLogString(p, buf, len)
912 struct win *p;
913 char *buf;
914 int len;
916 if (!p->w_log)
917 return;
918 if (logtstamp_on && p->w_logsilence >= logtstamp_after * 2)
920 char *t = MakeWinMsg(logtstamp_string, p, '%');
921 logfwrite(p->w_log, t, strlen(t)); /* long time no write */
923 p->w_logsilence = 0;
924 if (logfwrite(p->w_log, buf, len) < 1)
926 WMsg(p, errno, "Error writing logfile");
927 logfclose(p->w_log);
928 p->w_log = 0;
930 if (!log_flush)
931 logfflush(p->w_log);
934 static int
935 Special(c)
936 register int c;
938 switch (c)
940 case '\b':
941 BackSpace();
942 return 1;
943 case '\r':
944 Return();
945 return 1;
946 case '\n':
947 if (curr->w_autoaka)
948 FindAKA();
949 LineFeed(0);
950 return 1;
951 case '\007':
952 WBell(curr, visual_bell);
953 return 1;
954 case '\t':
955 ForwardTab();
956 return 1;
957 #ifdef FONT
958 case '\017': /* SI */
959 MapCharset(G0);
960 return 1;
961 case '\016': /* SO */
962 MapCharset(G1);
963 return 1;
964 #endif
966 return 0;
969 static void
970 DoESC(c, intermediate)
971 int c, intermediate;
973 debug2("DoESC: %x - inter = %x\n", c, intermediate);
974 switch (intermediate)
976 case 0:
977 switch (c)
979 case 'E':
980 LineFeed(1);
981 break;
982 case 'D':
983 LineFeed(0);
984 break;
985 case 'M':
986 ReverseLineFeed();
987 break;
988 case 'H':
989 curr->w_tabs[curr->w_x] = 1;
990 break;
991 case 'Z': /* jph: Identify as VT100 */
992 Report("\033[?%d;%dc", 1, 2);
993 break;
994 case '7':
995 SaveCursor();
996 break;
997 case '8':
998 RestoreCursor();
999 break;
1000 case 'c':
1001 ClearScreen();
1002 ResetWindow(curr);
1003 LKeypadMode(&curr->w_layer, 0);
1004 LCursorkeysMode(&curr->w_layer, 0);
1005 #ifndef TIOCPKT
1006 WNewAutoFlow(curr, 1);
1007 #endif
1008 /* XXX
1009 SetRendition(&mchar_null);
1010 InsertMode(0);
1011 ChangeScrollRegion(0, rows - 1);
1013 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1014 break;
1015 case '=':
1016 LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
1017 #ifndef TIOCPKT
1018 WNewAutoFlow(curr, 0);
1019 #endif /* !TIOCPKT */
1020 break;
1021 case '>':
1022 LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
1023 #ifndef TIOCPKT
1024 WNewAutoFlow(curr, 1);
1025 #endif /* !TIOCPKT */
1026 break;
1027 #ifdef FONT
1028 case 'n': /* LS2 */
1029 MapCharset(G2);
1030 break;
1031 case 'o': /* LS3 */
1032 MapCharset(G3);
1033 break;
1034 case '~':
1035 MapCharsetR(G1); /* LS1R */
1036 break;
1037 /* { */
1038 case '}':
1039 MapCharsetR(G2); /* LS2R */
1040 break;
1041 case '|':
1042 MapCharsetR(G3); /* LS3R */
1043 break;
1044 case 'N': /* SS2 */
1045 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
1046 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
1047 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
1048 else
1049 curr->w_ss = 0;
1050 break;
1051 case 'O': /* SS3 */
1052 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
1053 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
1054 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
1055 else
1056 curr->w_ss = 0;
1057 break;
1058 #endif /* FONT */
1059 case 'g': /* VBELL, private screen sequence */
1060 WBell(curr, 1);
1061 break;
1063 break;
1064 case '#':
1065 switch (c)
1067 case '8':
1068 FillWithEs();
1069 break;
1071 break;
1072 #ifdef FONT
1073 case '(':
1074 DesignateCharset(c, G0);
1075 break;
1076 case ')':
1077 DesignateCharset(c, G1);
1078 break;
1079 case '*':
1080 DesignateCharset(c, G2);
1081 break;
1082 case '+':
1083 DesignateCharset(c, G3);
1084 break;
1085 # ifdef DW_CHARS
1087 * ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
1088 * ESC $ Fn: same as above. (old sequence)
1089 * ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
1090 * ESC $ * Fn: invoke multi-byte charset, Fn, to G2
1091 * ESC $ + Fn: invoke multi-byte charset, Fn, to G3
1093 case '$':
1094 case '$'<<8 | '(':
1095 DesignateCharset(c & 037, G0);
1096 break;
1097 case '$'<<8 | ')':
1098 DesignateCharset(c & 037, G1);
1099 break;
1100 case '$'<<8 | '*':
1101 DesignateCharset(c & 037, G2);
1102 break;
1103 case '$'<<8 | '+':
1104 DesignateCharset(c & 037, G3);
1105 break;
1106 # endif
1107 #endif /* FONT */
1111 static void
1112 DoCSI(c, intermediate)
1113 int c, intermediate;
1115 register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
1117 if (curr->w_NumArgs > MAXARGS)
1118 curr->w_NumArgs = MAXARGS;
1119 switch (intermediate)
1121 case 0:
1122 switch (c)
1124 case 'H':
1125 case 'f':
1126 if (a1 < 1)
1127 a1 = 1;
1128 if (curr->w_origin)
1129 a1 += curr->w_top;
1130 if (a1 > rows)
1131 a1 = rows;
1132 if (a2 < 1)
1133 a2 = 1;
1134 if (a2 > cols)
1135 a2 = cols;
1136 LGotoPos(&curr->w_layer, --a2, --a1);
1137 curr->w_x = a2;
1138 curr->w_y = a1;
1139 if (curr->w_autoaka)
1140 curr->w_autoaka = a1 + 1;
1141 break;
1142 case 'J':
1143 if (a1 < 0 || a1 > 2)
1144 a1 = 0;
1145 switch (a1)
1147 case 0:
1148 ClearToEOS();
1149 break;
1150 case 1:
1151 ClearFromBOS();
1152 break;
1153 case 2:
1154 ClearScreen();
1155 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1156 break;
1158 break;
1159 case 'K':
1160 if (a1 < 0 || a1 > 2)
1161 a1 %= 3;
1162 switch (a1)
1164 case 0:
1165 ClearLineRegion(curr->w_x, cols - 1);
1166 break;
1167 case 1:
1168 ClearLineRegion(0, curr->w_x);
1169 break;
1170 case 2:
1171 ClearLineRegion(0, cols - 1);
1172 break;
1174 break;
1175 case 'X':
1176 a1 = curr->w_x + (a1 ? a1 - 1 : 0);
1177 ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
1178 break;
1179 case 'A':
1180 CursorUp(a1 ? a1 : 1);
1181 break;
1182 case 'B':
1183 CursorDown(a1 ? a1 : 1);
1184 break;
1185 case 'C':
1186 CursorRight(a1 ? a1 : 1);
1187 break;
1188 case 'D':
1189 CursorLeft(a1 ? a1 : 1);
1190 break;
1191 case 'E':
1192 curr->w_x = 0;
1193 CursorDown(a1 ? a1 : 1); /* positions cursor */
1194 break;
1195 case 'F':
1196 curr->w_x = 0;
1197 CursorUp(a1 ? a1 : 1); /* positions cursor */
1198 break;
1199 case 'G':
1200 case '`': /* HPA */
1201 curr->w_x = a1 ? a1 - 1 : 0;
1202 if (curr->w_x >= cols)
1203 curr->w_x = cols - 1;
1204 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1205 break;
1206 case 'd': /* VPA */
1207 curr->w_y = a1 ? a1 - 1 : 0;
1208 if (curr->w_y >= rows)
1209 curr->w_y = rows - 1;
1210 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1211 break;
1212 case 'm':
1213 SelectRendition();
1214 break;
1215 case 'g':
1216 if (a1 == 0)
1217 curr->w_tabs[curr->w_x] = 0;
1218 else if (a1 == 3)
1219 bzero(curr->w_tabs, cols);
1220 break;
1221 case 'r':
1222 if (!a1)
1223 a1 = 1;
1224 if (!a2)
1225 a2 = rows;
1226 if (a1 < 1 || a2 > rows || a1 >= a2)
1227 break;
1228 curr->w_top = a1 - 1;
1229 curr->w_bot = a2 - 1;
1230 /* ChangeScrollRegion(curr->w_top, curr->w_bot); */
1231 if (curr->w_origin)
1233 curr->w_y = curr->w_top;
1234 curr->w_x = 0;
1236 else
1237 curr->w_y = curr->w_x = 0;
1238 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1239 break;
1240 case 's':
1241 SaveCursor();
1242 break;
1243 case 't':
1244 switch(a1)
1246 case 11:
1247 if (curr->w_layer.l_cvlist)
1248 Report("\033[1t", 0, 0);
1249 else
1250 Report("\033[2t", 0, 0);
1251 break;
1252 case 7:
1253 LRefreshAll(&curr->w_layer, 0);
1254 break;
1255 case 21:
1256 a1 = strlen(curr->w_title);
1257 if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
1259 bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
1260 bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
1261 bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
1262 curr->w_inlen += 5 + a1;
1264 break;
1265 case 8:
1266 a1 = curr->w_args[2];
1267 if (a1 < 1)
1268 a1 = curr->w_width;
1269 if (a2 < 1)
1270 a2 = curr->w_height;
1271 if (a1 > 10000 || a2 > 10000)
1272 break;
1273 WChangeSize(curr, a1, a2);
1274 cols = curr->w_width;
1275 rows = curr->w_height;
1276 break;
1277 default:
1278 break;
1280 break;
1281 case 'u':
1282 RestoreCursor();
1283 break;
1284 case 'I':
1285 if (!a1)
1286 a1 = 1;
1287 while (a1--)
1288 ForwardTab();
1289 break;
1290 case 'Z':
1291 if (!a1)
1292 a1 = 1;
1293 while (a1--)
1294 BackwardTab();
1295 break;
1296 case 'L':
1297 InsertLine(a1 ? a1 : 1);
1298 break;
1299 case 'M':
1300 DeleteLine(a1 ? a1 : 1);
1301 break;
1302 case 'P':
1303 DeleteChar(a1 ? a1 : 1);
1304 break;
1305 case '@':
1306 InsertChar(a1 ? a1 : 1);
1307 break;
1308 case 'h':
1309 ASetMode(1);
1310 break;
1311 case 'l':
1312 ASetMode(0);
1313 break;
1314 case 'i': /* MC Media Control */
1315 if (a1 == 5)
1316 PrintStart();
1317 break;
1318 case 'n':
1319 if (a1 == 5) /* Report terminal status */
1320 Report("\033[0n", 0, 0);
1321 else if (a1 == 6) /* Report cursor position */
1322 Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
1323 break;
1324 case 'c': /* Identify as VT100 */
1325 if (a1 == 0)
1326 Report("\033[?%d;%dc", 1, 2);
1327 break;
1328 case 'x': /* decreqtparm */
1329 if (a1 == 0 || a1 == 1)
1330 Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
1331 break;
1332 case 'p': /* obscure code from a 97801 term */
1333 if (a1 == 6 || a1 == 7)
1335 curr->w_curinv = 7 - a1;
1336 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1338 break;
1339 case 'S': /* code from a 97801 term / DEC vt400 */
1340 ScrollRegion(a1 ? a1 : 1);
1341 break;
1342 case 'T': /* code from a 97801 term / DEC vt400 */
1343 case '^': /* SD as per ISO 6429 */
1344 ScrollRegion(a1 ? -a1 : -1);
1345 break;
1347 break;
1348 case '?':
1349 for (a2 = 0; a2 < curr->w_NumArgs; a2++)
1351 a1 = curr->w_args[a2];
1352 debug2("\\E[?%d%c\n",a1,c);
1353 if (c != 'h' && c != 'l')
1354 break;
1355 i = (c == 'h');
1356 switch (a1)
1358 case 1: /* CKM: cursor key mode */
1359 LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
1360 #ifndef TIOCPKT
1361 WNewAutoFlow(curr, !i);
1362 #endif /* !TIOCPKT */
1363 break;
1364 case 2: /* ANM: ansi/vt52 mode */
1365 if (i)
1367 #ifdef FONT
1368 # ifdef ENCODINGS
1369 if (curr->w_encoding)
1370 break;
1371 # endif
1372 curr->w_charsets[0] = curr->w_charsets[1] =
1373 curr->w_charsets[2] = curr->w_charsets[2] =
1374 curr->w_FontL = curr->w_FontR = ASCII;
1375 curr->w_Charset = 0;
1376 curr->w_CharsetR = 2;
1377 curr->w_ss = 0;
1378 #endif
1380 break;
1381 case 3: /* COLM: column mode */
1382 i = (i ? Z0width : Z1width);
1383 WChangeSize(curr, i, curr->w_height);
1384 cols = curr->w_width;
1385 rows = curr->w_height;
1386 break;
1387 /* case 4: SCLM: scrolling mode */
1388 case 5: /* SCNM: screen mode */
1389 if (i != curr->w_revvid)
1390 WReverseVideo(curr, i);
1391 curr->w_revvid = i;
1392 break;
1393 case 6: /* OM: origin mode */
1394 if ((curr->w_origin = i) != 0)
1396 curr->w_y = curr->w_top;
1397 curr->w_x = 0;
1399 else
1400 curr->w_y = curr->w_x = 0;
1401 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1402 break;
1403 case 7: /* AWM: auto wrap mode */
1404 curr->w_wrap = i;
1405 break;
1406 /* case 8: ARM: auto repeat mode */
1407 /* case 9: INLM: interlace mode */
1408 case 9: /* X10 mouse tracking */
1409 curr->w_mouse = i ? 9 : 0;
1410 LMouseMode(&curr->w_layer, curr->w_mouse);
1411 break;
1412 /* case 10: EDM: edit mode */
1413 /* case 11: LTM: line transmit mode */
1414 /* case 13: SCFDM: space compression / field delimiting */
1415 /* case 14: TEM: transmit execution mode */
1416 /* case 16: EKEM: edit key execution mode */
1417 /* case 18: PFF: Printer term form feed */
1418 /* case 19: PEX: Printer extend screen / scroll. reg */
1419 case 25: /* TCEM: text cursor enable mode */
1420 curr->w_curinv = !i;
1421 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1422 break;
1423 /* case 34: RLM: Right to left mode */
1424 /* case 35: HEBM: hebrew keyboard map */
1425 /* case 36: HEM: hebrew encoding */
1426 /* case 38: TeK Mode */
1427 /* case 40: 132 col enable */
1428 /* case 42: NRCM: 7bit NRC character mode */
1429 /* case 44: margin bell enable */
1430 case 47: /* xterm-like alternate screen */
1431 case 1047: /* xterm-like alternate screen */
1432 case 1049: /* xterm-like alternate screen */
1433 if (use_altscreen)
1435 if (i)
1436 EnterAltScreen(curr);
1437 else
1438 LeaveAltScreen(curr);
1439 if (a1 == 47 && !i)
1440 curr->w_saved = 0;
1441 LRefreshAll(&curr->w_layer, 0);
1442 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1444 break;
1445 /* case 66: NKM: Numeric keypad appl mode */
1446 /* case 68: KBUM: Keyboard usage mode (data process) */
1447 case 1000: /* VT200 mouse tracking */
1448 case 1001: /* VT200 highlight mouse */
1449 case 1002: /* button event mouse*/
1450 case 1003: /* any event mouse*/
1451 curr->w_mouse = i ? a1 : 0;
1452 LMouseMode(&curr->w_layer, curr->w_mouse);
1453 break;
1456 break;
1457 case '>':
1458 switch (c)
1460 case 'c': /* secondary DA */
1461 if (a1 == 0)
1462 Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
1463 break;
1465 break;
1470 static void
1471 StringStart(type)
1472 enum string_t type;
1474 curr->w_StringType = type;
1475 curr->w_stringp = curr->w_string;
1476 curr->w_state = ASTR;
1479 static void
1480 StringChar(c)
1481 int c;
1483 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1484 curr->w_state = LIT;
1485 else
1486 *(curr->w_stringp)++ = c;
1490 * Do string processing. Returns -1 if output should be suspended
1491 * until status is gone.
1493 static int
1494 StringEnd()
1496 struct canvas *cv;
1497 char *p;
1498 int typ;
1500 curr->w_state = LIT;
1501 *curr->w_stringp = '\0';
1502 switch (curr->w_StringType)
1504 case OSC: /* special xterm compatibility hack */
1505 if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
1506 break;
1507 typ = atoi(curr->w_string);
1508 p++;
1509 #ifdef MULTIUSER
1510 if (typ == 83) /* 83 = 'S' */
1512 /* special execute commands sequence */
1513 char *args[MAXARGS];
1514 int argl[MAXARGS];
1515 struct acluser *windowuser;
1517 windowuser = *FindUserPtr(":window:");
1518 if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
1520 for (display = displays; display; display = display->d_next)
1521 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1522 break; /* found it */
1523 if (display == 0 && curr->w_layer.l_cvlist)
1524 display = curr->w_layer.l_cvlist->c_display;
1525 if (display == 0)
1526 display = displays;
1527 EffectiveAclUser = windowuser;
1528 fore = curr;
1529 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1530 DoCommand(args, argl);
1531 EffectiveAclUser = 0;
1532 fore = 0;
1533 flayer = 0;
1535 break;
1537 #endif
1538 #ifdef RXVT_OSC
1539 if (typ == 0 || typ == 1 || typ == 20 || typ == 39 || typ == 49)
1541 int typ2;
1542 typ2 = typ / 10;
1543 if (--typ2 < 0)
1544 typ2 = 0;
1545 if (strcmp(curr->w_xtermosc[typ2], p))
1547 strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
1548 curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
1550 for (display = displays; display; display = display->d_next)
1552 if (!D_CXT)
1553 continue;
1554 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1555 SetXtermOSC(typ2, curr->w_xtermosc[typ2]);
1556 if ((typ2 == 2 || typ2 == 3) && D_xtermosc[typ2])
1557 Redisplay(0);
1561 if (typ != 0 && typ != 2)
1562 break;
1563 #else
1564 if (typ < 0 || typ > 2)
1565 break;
1566 #endif
1568 curr->w_stringp -= p - curr->w_string;
1569 if (curr->w_stringp > curr->w_string)
1570 bcopy(p, curr->w_string, curr->w_stringp - curr->w_string);
1571 *curr->w_stringp = '\0';
1572 /* FALLTHROUGH */
1573 case APC:
1574 if (curr->w_hstatus)
1576 if (strcmp(curr->w_hstatus, curr->w_string) == 0)
1577 break; /* not changed */
1578 free(curr->w_hstatus);
1579 curr->w_hstatus = 0;
1581 if (curr->w_string != curr->w_stringp)
1582 curr->w_hstatus = SaveStr(curr->w_string);
1583 WindowChanged(curr, 'h');
1584 break;
1585 case PM:
1586 case GM:
1587 for (display = displays; display; display = display->d_next)
1589 for (cv = D_cvlist; cv; cv = cv->c_next)
1590 if (cv->c_layer->l_bottom == &curr->w_layer)
1591 break;
1592 if (cv || curr->w_StringType == GM)
1593 MakeStatus(curr->w_string);
1595 return -1;
1596 case DCS:
1597 LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
1598 break;
1599 case AKA:
1600 if (curr->w_title == curr->w_akabuf && !*curr->w_string)
1601 break;
1602 ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
1603 if (!*curr->w_string)
1604 curr->w_autoaka = curr->w_y + 1;
1605 break;
1606 default:
1607 break;
1609 return 0;
1612 static void
1613 PrintStart()
1615 curr->w_pdisplay = 0;
1617 /* find us a nice display to print on, fore prefered */
1618 display = curr->w_lastdisp;
1619 if (!(display && curr == D_fore && (printcmd || D_PO)))
1620 for (display = displays; display; display = display->d_next)
1621 if (curr == D_fore && (printcmd || D_PO))
1622 break;
1623 if (!display)
1625 struct canvas *cv;
1626 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1628 display = cv->c_display;
1629 if (printcmd || D_PO)
1630 break;
1632 if (!cv)
1634 display = displays;
1635 if (!display || display->d_next || !(printcmd || D_PO))
1636 return;
1639 curr->w_pdisplay = display;
1640 curr->w_stringp = curr->w_string;
1641 curr->w_state = PRIN;
1642 if (printcmd && curr->w_pdisplay->d_printfd < 0)
1643 curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
1646 static void
1647 PrintChar(c)
1648 int c;
1650 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1651 PrintFlush();
1652 *(curr->w_stringp)++ = c;
1655 static void
1656 PrintFlush()
1658 display = curr->w_pdisplay;
1659 if (display && printcmd)
1661 char *bp = curr->w_string;
1662 int len = curr->w_stringp - curr->w_string;
1663 int r;
1664 while (len && display->d_printfd >= 0)
1666 r = write(display->d_printfd, bp, len);
1667 if (r <= 0)
1669 WMsg(curr, errno, "printing aborted");
1670 close(display->d_printfd);
1671 display->d_printfd = -1;
1672 break;
1674 bp += r;
1675 len -= r;
1678 else if (display && curr->w_stringp > curr->w_string)
1680 AddCStr(D_PO);
1681 AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
1682 AddCStr(D_PF);
1683 Flush();
1685 curr->w_stringp = curr->w_string;
1689 void
1690 WNewAutoFlow(win, on)
1691 struct win *win;
1692 int on;
1694 debug1("WNewAutoFlow: %d\n", on);
1695 if (win->w_flow & FLOW_AUTOFLAG)
1696 win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
1697 else
1698 win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
1699 LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
1703 #ifdef FONT
1705 static void
1706 DesignateCharset(c, n)
1707 int c, n;
1709 curr->w_ss = 0;
1710 # ifdef ENCODINGS
1711 if (c == ('@' & 037)) /* map JIS 6226 to 0208 */
1712 c = KANJI;
1713 # endif
1714 if (c == 'B')
1715 c = ASCII;
1716 if (curr->w_charsets[n] != c)
1718 curr->w_charsets[n] = c;
1719 if (curr->w_Charset == n)
1721 curr->w_FontL = c;
1722 curr->w_rend.font = curr->w_FontL;
1723 LSetRendition(&curr->w_layer, &curr->w_rend);
1725 if (curr->w_CharsetR == n)
1726 curr->w_FontR = c;
1730 static void
1731 MapCharset(n)
1732 int n;
1734 curr->w_ss = 0;
1735 if (curr->w_Charset != n)
1737 curr->w_Charset = n;
1738 curr->w_FontL = curr->w_charsets[n];
1739 curr->w_rend.font = curr->w_FontL;
1740 LSetRendition(&curr->w_layer, &curr->w_rend);
1744 static void
1745 MapCharsetR(n)
1746 int n;
1748 curr->w_ss = 0;
1749 if (curr->w_CharsetR != n)
1751 curr->w_CharsetR = n;
1752 curr->w_FontR = curr->w_charsets[n];
1754 curr->w_gr = 1;
1757 #endif /* FONT */
1759 static void
1760 SaveCursor()
1762 curr->w_saved = 1;
1763 curr->w_Saved_x = curr->w_x;
1764 curr->w_Saved_y = curr->w_y;
1765 curr->w_SavedRend = curr->w_rend;
1766 #ifdef FONT
1767 curr->w_SavedCharset = curr->w_Charset;
1768 curr->w_SavedCharsetR = curr->w_CharsetR;
1769 bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
1770 4 * sizeof(int));
1771 #endif
1774 static void
1775 RestoreCursor()
1777 if (!curr->w_saved)
1778 return;
1779 LGotoPos(&curr->w_layer, curr->w_Saved_x, curr->w_Saved_y);
1780 curr->w_x = curr->w_Saved_x;
1781 curr->w_y = curr->w_Saved_y;
1782 curr->w_rend = curr->w_SavedRend;
1783 #ifdef FONT
1784 bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
1785 4 * sizeof(int));
1786 curr->w_Charset = curr->w_SavedCharset;
1787 curr->w_CharsetR = curr->w_SavedCharsetR;
1788 curr->w_ss = 0;
1789 curr->w_FontL = curr->w_charsets[curr->w_Charset];
1790 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
1791 #endif
1792 LSetRendition(&curr->w_layer, &curr->w_rend);
1795 static void
1796 BackSpace()
1798 if (curr->w_x > 0)
1800 curr->w_x--;
1802 else if (curr->w_wrap && curr->w_y > 0)
1804 curr->w_x = cols - 1;
1805 curr->w_y--;
1807 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1810 static void
1811 Return()
1813 if (curr->w_x == 0)
1814 return;
1815 curr->w_x = 0;
1816 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1819 static void
1820 LineFeed(out_mode)
1821 int out_mode;
1823 /* out_mode: 0=lf, 1=cr+lf */
1824 if (out_mode)
1825 curr->w_x = 0;
1826 if (curr->w_y != curr->w_bot) /* Don't scroll */
1828 if (curr->w_y < rows-1)
1829 curr->w_y++;
1830 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1831 return;
1833 if (curr->w_autoaka > 1)
1834 curr->w_autoaka--;
1835 MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
1836 LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
1837 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1840 static void
1841 ReverseLineFeed()
1843 if (curr->w_y == curr->w_top)
1845 MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
1846 LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
1847 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1849 else if (curr->w_y > 0)
1850 CursorUp(1);
1853 static void
1854 InsertChar(n)
1855 int n;
1857 register int y = curr->w_y, x = curr->w_x;
1859 if (n <= 0)
1860 return;
1861 if (x == cols)
1862 x--;
1863 save_mline(&curr->w_mlines[y], cols);
1864 MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
1865 LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1866 LGotoPos(&curr->w_layer, x, y);
1869 static void
1870 DeleteChar(n)
1871 int n;
1873 register int y = curr->w_y, x = curr->w_x;
1875 if (x == cols)
1876 x--;
1877 save_mline(&curr->w_mlines[y], cols);
1878 MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
1879 LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1880 LGotoPos(&curr->w_layer, x, y);
1883 static void
1884 DeleteLine(n)
1885 int n;
1887 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1888 return;
1889 if (n > curr->w_bot - curr->w_y + 1)
1890 n = curr->w_bot - curr->w_y + 1;
1891 MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
1892 LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
1893 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1896 static void
1897 InsertLine(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 ScrollRegion(n)
1911 int n;
1913 MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
1914 LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
1915 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1919 static void
1920 ForwardTab()
1922 register int x = curr->w_x;
1924 if (x == cols)
1926 LineFeed(1);
1927 x = 0;
1929 if (curr->w_tabs[x] && x < cols - 1)
1930 x++;
1931 while (x < cols - 1 && !curr->w_tabs[x])
1932 x++;
1933 curr->w_x = x;
1934 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1937 static void
1938 BackwardTab()
1940 register int x = curr->w_x;
1942 if (curr->w_tabs[x] && x > 0)
1943 x--;
1944 while (x > 0 && !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 ClearScreen()
1953 LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
1954 #ifdef COPY_PASTE
1955 MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
1956 #else
1957 MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
1958 #endif
1961 static void
1962 ClearFromBOS()
1964 register int y = curr->w_y, x = curr->w_x;
1966 LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
1967 MClearArea(curr, 0, 0, x, y, CURR_BCE);
1968 RestorePosRendition();
1971 static void
1972 ClearToEOS()
1974 register int y = curr->w_y, x = curr->w_x;
1976 if (x == 0 && y == 0)
1978 ClearScreen();
1979 RestorePosRendition();
1980 return;
1982 LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
1983 MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
1984 RestorePosRendition();
1987 static void
1988 ClearLineRegion(from, to)
1989 int from, to;
1991 register int y = curr->w_y;
1992 LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
1993 MClearArea(curr, from, y, to, y, CURR_BCE);
1994 RestorePosRendition();
1997 static void
1998 CursorRight(n)
1999 register int n;
2001 register int x = curr->w_x;
2003 if (x == cols)
2005 LineFeed(1);
2006 x = 0;
2008 if ((curr->w_x += n) >= cols)
2009 curr->w_x = cols - 1;
2010 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2013 static void
2014 CursorUp(n)
2015 register int n;
2017 if (curr->w_y < curr->w_top) /* if above scrolling rgn, */
2019 if ((curr->w_y -= n) < 0) /* ignore its limits */
2020 curr->w_y = 0;
2022 else
2023 if ((curr->w_y -= n) < curr->w_top)
2024 curr->w_y = curr->w_top;
2025 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2028 static void
2029 CursorDown(n)
2030 register int n;
2032 if (curr->w_y > curr->w_bot) /* if below scrolling rgn, */
2034 if ((curr->w_y += n) > rows - 1) /* ignore its limits */
2035 curr->w_y = rows - 1;
2037 else
2038 if ((curr->w_y += n) > curr->w_bot)
2039 curr->w_y = curr->w_bot;
2040 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2043 static void
2044 CursorLeft(n)
2045 register int n;
2047 if ((curr->w_x -= n) < 0)
2048 curr->w_x = 0;
2049 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2052 static void
2053 ASetMode(on)
2054 int on;
2056 register int i;
2058 for (i = 0; i < curr->w_NumArgs; ++i)
2060 switch (curr->w_args[i])
2062 /* case 2: KAM: Lock keyboard */
2063 case 4: /* IRM: Insert mode */
2064 curr->w_insert = on;
2065 LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
2066 break;
2067 /* case 12: SRM: Echo mode on */
2068 case 20: /* LNM: Linefeed mode */
2069 curr->w_autolf = on;
2070 break;
2071 case 34:
2072 curr->w_curvvis = !on;
2073 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
2074 break;
2075 default:
2076 break;
2081 static char rendlist[] =
2083 ~((1 << NATTR) - 1), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
2084 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2085 0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
2088 static void
2089 SelectRendition()
2091 #ifdef COLOR
2092 register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
2093 # ifdef COLORS256
2094 int cx = curr->w_rend.colorx;
2095 # endif
2096 #else
2097 register int j, i = 0, a = curr->w_rend.attr;
2098 #endif
2102 j = curr->w_args[i];
2103 #ifdef COLOR
2104 if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
2106 int jj;
2108 i += 2;
2109 jj = curr->w_args[i];
2110 if (jj < 0 || jj > 255)
2111 continue;
2112 # ifdef COLORS256
2113 if (j == 38)
2115 c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
2116 a |= A_BFG;
2117 if (jj >= 8 && jj < 16)
2118 c |= 0x08;
2119 else
2120 a ^= A_BFG;
2121 a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
2122 cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
2124 else
2126 c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
2127 a |= A_BBG;
2128 if (jj >= 8 && jj < 16)
2129 c |= 0x80;
2130 else
2131 a ^= A_BBG;
2132 cx = (cx & 0x0f) | (jj & 0xf0);
2134 continue;
2135 # else
2136 jj = color256to16(jj) + 30;
2137 if (jj >= 38)
2138 jj += 60 - 8;
2139 j = j == 38 ? jj : jj + 10;
2140 # endif
2142 # ifdef COLORS16
2143 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2144 a &= 0xbf;
2145 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2146 a &= 0x7f;
2147 if (j >= 90 && j <= 97)
2148 a |= 0x40;
2149 if (j >= 100 && j <= 107)
2150 a |= 0x80;
2151 # endif
2152 if (j >= 90 && j <= 97)
2153 j -= 60;
2154 if (j >= 100 && j <= 107)
2155 j -= 60;
2156 if (j >= 30 && j <= 39 && j != 38)
2157 c = (c & 0xf0) | ((j - 30) ^ 9);
2158 else if (j >= 40 && j <= 49 && j != 48)
2159 c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
2160 if (j == 0)
2161 c = 0;
2162 # ifdef COLORS256
2163 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2164 cx &= 0xf0;
2165 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2166 cx &= 0x0f;
2167 # endif
2168 #endif
2169 if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
2170 continue;
2171 j = rendlist[j];
2172 if (j & (1 << NATTR))
2173 a &= j;
2174 else
2175 a |= j;
2177 while (++i < curr->w_NumArgs);
2178 curr->w_rend.attr = a;
2179 #ifdef COLOR
2180 curr->w_rend.color = c;
2181 # ifdef COLORS256
2182 curr->w_rend.colorx = cx;
2183 # endif
2184 #endif
2185 LSetRendition(&curr->w_layer, &curr->w_rend);
2188 static void
2189 FillWithEs()
2191 register int i;
2192 register unsigned char *p, *ep;
2194 LClearAll(&curr->w_layer, 1);
2195 curr->w_y = curr->w_x = 0;
2196 for (i = 0; i < rows; ++i)
2198 clear_mline(&curr->w_mlines[i], 0, cols + 1);
2199 p = curr->w_mlines[i].image;
2200 ep = p + cols;
2201 while (p < ep)
2202 *p++ = 'E';
2204 LRefreshAll(&curr->w_layer, 1);
2209 * Ugly autoaka hack support:
2210 * ChangeAKA() sets a new aka
2211 * FindAKA() searches for an autoaka match
2214 void
2215 ChangeAKA(p, s, l)
2216 struct win *p;
2217 char *s;
2218 int l;
2220 int i, c;
2222 for (i = 0; l > 0; l--)
2224 if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
2225 break;
2226 c = (unsigned char)*s++;
2227 if (c == 0)
2228 break;
2229 if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
2230 continue;
2231 p->w_akachange[i++] = c;
2233 p->w_akachange[i] = 0;
2234 p->w_title = p->w_akachange;
2235 if (p->w_akachange != p->w_akabuf)
2236 if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
2237 p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
2238 WindowChanged(p, 't');
2239 WindowChanged((struct win *)0, 'w');
2240 WindowChanged((struct win *)0, 'W');
2243 static void
2244 FindAKA()
2246 register unsigned char *cp, *line;
2247 register struct win *wp = curr;
2248 register int len = strlen(wp->w_akabuf);
2249 int y;
2251 y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
2252 cols = wp->w_width;
2253 try_line:
2254 cp = line = wp->w_mlines[y].image;
2255 if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
2257 for (;;)
2259 if (cp - line >= cols - len)
2261 if (++y == wp->w_autoaka && y < rows)
2262 goto try_line;
2263 return;
2265 if (strncmp((char *)cp, wp->w_akabuf, len) == 0)
2266 break;
2267 cp++;
2269 cp += len;
2271 for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
2273 if (len)
2275 if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
2276 wp->w_autoaka = -1;
2277 else
2278 wp->w_autoaka = 0;
2279 line = cp;
2280 while (len && *cp != ' ')
2282 if (*cp++ == '/')
2283 line = cp;
2284 len--;
2286 ChangeAKA(wp, (char *)line, cp - line);
2288 else
2289 wp->w_autoaka = 0;
2292 static void
2293 RestorePosRendition()
2295 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2296 LSetRendition(&curr->w_layer, &curr->w_rend);
2299 /* Send a terminal report as if it were typed. */
2300 static void
2301 Report(fmt, n1, n2)
2302 char *fmt;
2303 int n1, n2;
2305 register int len;
2306 char rbuf[40]; /* enough room for all replys */
2308 sprintf(rbuf, fmt, n1, n2);
2309 len = strlen(rbuf);
2311 #ifdef PSEUDOS
2312 if (W_UWP(curr))
2314 if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
2316 bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
2317 curr->w_pwin->p_inlen += len;
2320 else
2321 #endif
2323 if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
2325 bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
2326 curr->w_inlen += len;
2334 *====================================================================*
2335 *====================================================================*
2338 /**********************************************************************
2340 * Memory subsystem.
2344 static void
2345 MFixLine(p, y, mc)
2346 struct win *p;
2347 int y;
2348 struct mchar *mc;
2350 struct mline *ml = &p->w_mlines[y];
2351 if (mc->attr && ml->attr == null)
2353 if ((ml->attr = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2355 ml->attr = null;
2356 mc->attr = p->w_rend.attr = 0;
2357 WMsg(p, 0, "Warning: no space for attr - turned off");
2360 #ifdef FONT
2361 if (mc->font && ml->font == null)
2363 if ((ml->font = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2365 ml->font = null;
2366 p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
2367 p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
2368 mc->font = p->w_rend.font = 0;
2369 WMsg(p, 0, "Warning: no space for font - turned off");
2372 #endif
2373 #ifdef COLOR
2374 if (mc->color && ml->color == null)
2376 if ((ml->color = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2378 ml->color = null;
2379 mc->color = p->w_rend.color = 0;
2380 WMsg(p, 0, "Warning: no space for color - turned off");
2383 # ifdef COLORS256
2384 if (mc->colorx && ml->colorx == null)
2386 if ((ml->colorx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2388 ml->colorx = null;
2389 mc->colorx = p->w_rend.colorx = 0;
2390 WMsg(p, 0, "Warning: no space for extended colors - turned off");
2393 # endif
2394 #endif
2397 /*****************************************************************/
2399 #ifdef DW_CHARS
2400 # define MKillDwRight(p, ml, x) \
2401 if (dw_right(ml, x, p->w_encoding)) \
2403 if (x > 0) \
2404 copy_mchar2mline(&mchar_blank, ml, x - 1); \
2405 copy_mchar2mline(&mchar_blank, ml, x); \
2408 # define MKillDwLeft(p, ml, x) \
2409 if (dw_left(ml, x, p->w_encoding)) \
2411 copy_mchar2mline(&mchar_blank, ml, x); \
2412 copy_mchar2mline(&mchar_blank, ml, x + 1); \
2414 #else
2415 # define MKillDwRight(p, ml, x) ;
2416 # define MKillDwLeft(p, ml, x) ;
2417 #endif
2419 static void
2420 MScrollH(p, n, y, xs, xe, bce)
2421 struct win *p;
2422 int n, y, xs, xe, bce;
2424 struct mline *ml;
2426 if (n == 0)
2427 return;
2428 ml = &p->w_mlines[y];
2429 MKillDwRight(p, ml, xs);
2430 MKillDwLeft(p, ml, xe);
2431 if (n > 0)
2433 if (xe - xs + 1 > n)
2435 MKillDwRight(p, ml, xs + n);
2436 bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
2438 else
2439 n = xe - xs + 1;
2440 clear_mline(ml, xe + 1 - n, n);
2441 #ifdef COLOR
2442 if (bce)
2443 MBceLine(p, y, xe + 1 - n, n, bce);
2444 #endif
2446 else
2448 n = -n;
2449 if (xe - xs + 1 > n)
2451 MKillDwLeft(p, ml, xe - n);
2452 bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
2454 else
2455 n = xe - xs + 1;
2456 clear_mline(ml, xs, n);
2457 #ifdef COLOR
2458 if (bce)
2459 MBceLine(p, y, xs, n, bce);
2460 #endif
2464 static void
2465 MScrollV(p, n, ys, ye, bce)
2466 struct win *p;
2467 int n, ys, ye, bce;
2469 int i, cnt1, cnt2;
2470 struct mline tmp[256];
2471 struct mline *ml;
2473 if (n == 0)
2474 return;
2475 if (n > 0)
2477 if (n > 256)
2479 MScrollV(p, n - 256, ys, ye, bce);
2480 n = 256;
2482 if (ye - ys + 1 < n)
2483 n = ye - ys + 1;
2484 #ifdef COPY_PASTE
2485 if (compacthist)
2487 ye = MFindUsedLine(p, ye, ys);
2488 if (ye - ys + 1 < n)
2489 n = ye - ys + 1;
2490 if (n <= 0)
2491 return;
2493 #endif
2494 /* Clear lines */
2495 ml = p->w_mlines + ys;
2496 for (i = ys; i < ys + n; i++, ml++)
2498 #ifdef COPY_PASTE
2499 if (ys == p->w_top)
2500 WAddLineToHist(p, ml);
2501 #endif
2502 if (ml->attr != null)
2503 free(ml->attr);
2504 ml->attr = null;
2505 #ifdef FONT
2506 if (ml->font != null)
2507 free(ml->font);
2508 ml->font = null;
2509 #endif
2510 #ifdef COLOR
2511 if (ml->color != null)
2512 free(ml->color);
2513 ml->color = null;
2514 # ifdef COLORS256
2515 if (ml->colorx != null)
2516 free(ml->colorx);
2517 ml->colorx = null;
2518 # endif
2519 #endif
2520 bclear((char *)ml->image, p->w_width + 1);
2521 #ifdef COLOR
2522 if (bce)
2523 MBceLine(p, i, 0, p->w_width, bce);
2524 #endif
2526 /* switch 'em over */
2527 cnt1 = n * sizeof(struct mline);
2528 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2529 if (cnt1 && cnt2)
2530 Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
2532 else
2534 if (n < -256)
2536 MScrollV(p, n + 256, ys, ye, bce);
2537 n = -256;
2539 n = -n;
2540 if (ye - ys + 1 < n)
2541 n = ye - ys + 1;
2543 ml = p->w_mlines + ye;
2544 /* Clear lines */
2545 for (i = ye; i > ye - n; i--, ml--)
2547 if (ml->attr != null)
2548 free(ml->attr);
2549 ml->attr = null;
2550 #ifdef FONT
2551 if (ml->font != null)
2552 free(ml->font);
2553 ml->font = null;
2554 #endif
2555 #ifdef COLOR
2556 if (ml->color != null)
2557 free(ml->color);
2558 ml->color = null;
2559 # ifdef COLORS256
2560 if (ml->colorx != null)
2561 free(ml->colorx);
2562 ml->colorx = null;
2563 # endif
2564 #endif
2565 bclear((char *)ml->image, p->w_width + 1);
2566 #ifdef COLOR
2567 if (bce)
2568 MBceLine(p, i, 0, p->w_width, bce);
2569 #endif
2571 cnt1 = n * sizeof(struct mline);
2572 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2573 if (cnt1 && cnt2)
2574 Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
2578 static void
2579 Scroll(cp, cnt1, cnt2, tmp)
2580 char *cp, *tmp;
2581 int cnt1, cnt2;
2583 if (!cnt1 || !cnt2)
2584 return;
2585 if (cnt1 <= cnt2)
2587 bcopy(cp, tmp, cnt1);
2588 bcopy(cp + cnt1, cp, cnt2);
2589 bcopy(tmp, cp + cnt2, cnt1);
2591 else
2593 bcopy(cp + cnt1, tmp, cnt2);
2594 bcopy(cp, cp + cnt2, cnt1);
2595 bcopy(tmp, cp, cnt2);
2599 static void
2600 MClearArea(p, xs, ys, xe, ye, bce)
2601 struct win *p;
2602 int xs, ys, xe, ye, bce;
2604 int n, y;
2605 int xxe;
2606 struct mline *ml;
2608 /* Check for zero-height window */
2609 if (ys < 0 || ye < ys)
2610 return;
2612 /* check for magic margin condition */
2613 if (xs >= p->w_width)
2614 xs = p->w_width - 1;
2615 if (xe >= p->w_width)
2616 xe = p->w_width - 1;
2618 MKillDwRight(p, p->w_mlines + ys, xs);
2619 MKillDwLeft(p, p->w_mlines + ye, xe);
2621 ml = p->w_mlines + ys;
2622 for (y = ys; y <= ye; y++, ml++)
2624 xxe = (y == ye) ? xe : p->w_width - 1;
2625 n = xxe - xs + 1;
2626 if (n > 0)
2627 clear_mline(ml, xs, n);
2628 #ifdef COLOR
2629 if (n > 0 && bce)
2630 MBceLine(p, y, xs, xs + n - 1, bce);
2631 #endif
2632 xs = 0;
2636 static void
2637 MInsChar(p, c, x, y)
2638 struct win *p;
2639 struct mchar *c;
2640 int x, y;
2642 int n;
2643 struct mline *ml;
2645 ASSERT(x >= 0 && x < p->w_width);
2646 MFixLine(p, y, c);
2647 ml = p->w_mlines + y;
2648 n = p->w_width - x - 1;
2649 MKillDwRight(p, ml, x);
2650 if (n > 0)
2652 MKillDwRight(p, ml, p->w_width - 1);
2653 bcopy_mline(ml, x, x + 1, n);
2655 copy_mchar2mline(c, ml, x);
2656 #ifdef DW_CHARS
2657 if (c->mbcs)
2659 if (--n > 0)
2661 MKillDwRight(p, ml, p->w_width - 1);
2662 bcopy_mline(ml, x + 1, x + 2, n);
2664 copy_mchar2mline(c, ml, x + 1);
2665 ml->image[x + 1] = c->mbcs;
2666 # ifdef UTF8
2667 if (p->w_encoding != UTF8)
2668 ml->font[x + 1] |= 0x80;
2669 else if (p->w_encoding == UTF8 && c->mbcs)
2670 ml->font[x + 1] = c->mbcs;
2671 # else
2672 ml->font[x + 1] |= 0x80;
2673 # endif
2675 #endif
2678 static void
2679 MPutChar(p, c, x, y)
2680 struct win *p;
2681 struct mchar *c;
2682 int x, y;
2684 struct mline *ml;
2686 MFixLine(p, y, c);
2687 ml = &p->w_mlines[y];
2688 MKillDwRight(p, ml, x);
2689 MKillDwLeft(p, ml, x);
2690 copy_mchar2mline(c, ml, x);
2691 #ifdef DW_CHARS
2692 if (c->mbcs)
2694 MKillDwLeft(p, ml, x + 1);
2695 copy_mchar2mline(c, ml, x + 1);
2696 ml->image[x + 1] = c->mbcs;
2697 # ifdef UTF8
2698 if (p->w_encoding != UTF8)
2699 ml->font[x + 1] |= 0x80;
2700 else if (p->w_encoding == UTF8 && c->mbcs)
2701 ml->font[x + 1] = c->mbcs;
2702 # else
2703 ml->font[x + 1] |= 0x80;
2704 # endif
2706 #endif
2710 static void
2711 MWrapChar(p, c, y, top, bot, ins)
2712 struct win *p;
2713 struct mchar *c;
2714 int y, top, bot;
2715 int ins;
2717 struct mline *ml;
2718 int bce;
2720 #ifdef COLOR
2721 bce = rend_getbg(c);
2722 #else
2723 bce = 0;
2724 #endif
2725 MFixLine(p, y, c);
2726 ml = &p->w_mlines[y];
2727 copy_mchar2mline(&mchar_null, ml, p->w_width);
2728 if (y == bot)
2729 MScrollV(p, 1, top, bot, bce);
2730 else if (y < p->w_height - 1)
2731 y++;
2732 if (ins)
2733 MInsChar(p, c, 0, y);
2734 else
2735 MPutChar(p, c, 0, y);
2738 static void
2739 MPutStr(p, s, n, r, x, y)
2740 struct win *p;
2741 char *s;
2742 int n;
2743 struct mchar *r;
2744 int x, y;
2746 struct mline *ml;
2747 int i;
2748 unsigned char *b;
2750 if (n <= 0)
2751 return;
2752 MFixLine(p, y, r);
2753 ml = &p->w_mlines[y];
2754 MKillDwRight(p, ml, x);
2755 MKillDwLeft(p, ml, x + n - 1);
2756 bcopy(s, (char *)ml->image + x, n);
2757 b = ml->attr + x;
2758 for (i = n; i-- > 0;)
2759 *b++ = r->attr;
2760 #ifdef FONT
2761 b = ml->font + x;
2762 for (i = n; i-- > 0;)
2763 *b++ = r->font;
2764 #endif
2765 #ifdef COLOR
2766 b = ml->color + x;
2767 for (i = n; i-- > 0;)
2768 *b++ = r->color;
2769 # ifdef COLORS256
2770 b = ml->colorx + x;
2771 for (i = n; i-- > 0;)
2772 *b++ = r->colorx;
2773 # endif
2774 #endif
2777 #ifdef COLOR
2778 static void
2779 MBceLine(p, y, xs, xe, bce)
2780 struct win *p;
2781 int y, xs, xe, bce;
2783 struct mchar mc;
2784 struct mline *ml;
2785 int x;
2787 mc = mchar_null;
2788 rend_setbg(&mc, bce);
2789 MFixLine(p, y, &mc);
2790 ml = p->w_mlines + y;
2791 # ifdef COLORS16
2792 if (mc.attr)
2793 for (x = xs; x <= xe; x++)
2794 ml->attr[x] = mc.attr;
2795 # endif
2796 if (mc.color)
2797 for (x = xs; x <= xe; x++)
2798 ml->color[x] = mc.color;
2799 # ifdef COLORS256
2800 if (mc.colorx)
2801 for (x = xs; x <= xe; x++)
2802 ml->colorx[x] = mc.colorx;
2803 # endif
2805 #endif
2808 #ifdef COPY_PASTE
2809 static void
2810 WAddLineToHist(wp, ml)
2811 struct win *wp;
2812 struct mline *ml;
2814 register unsigned char *q, *o;
2815 struct mline *hml;
2817 if (wp->w_histheight == 0)
2818 return;
2819 hml = &wp->w_hlines[wp->w_histidx];
2820 q = ml->image; ml->image = hml->image; hml->image = q;
2822 q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
2823 if (o != null)
2824 free(o);
2826 #ifdef FONT
2827 q = ml->font; o = hml->font; hml->font = q; ml->font = null;
2828 if (o != null)
2829 free(o);
2830 #endif
2832 #ifdef COLOR
2833 q = ml->color; o = hml->color; hml->color = q; ml->color = null;
2834 if (o != null)
2835 free(o);
2836 # ifdef COLORS256
2837 q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
2838 if (o != null)
2839 free(o);
2840 # endif
2841 #endif
2843 if (++wp->w_histidx >= wp->w_histheight)
2844 wp->w_histidx = 0;
2846 #endif
2849 MFindUsedLine(p, ye, ys)
2850 struct win *p;
2851 int ys, ye;
2853 int y;
2854 struct mline *ml = p->w_mlines + ye;
2856 debug2("MFindUsedLine: %d %d\n", ye, ys);
2857 for (y = ye; y >= ys; y--, ml--)
2859 if (bcmp((char*)ml->image, blank, p->w_width))
2860 break;
2861 if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
2862 break;
2863 #ifdef COLOR
2864 if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
2865 break;
2866 # ifdef COLORS256
2867 if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
2868 break;
2869 # endif
2870 #endif
2872 debug1("MFindUsedLine returning %d\n", y);
2873 return y;
2878 *====================================================================*
2879 *====================================================================*
2883 * Tricky: send only one bell even if the window is displayed
2884 * more than once.
2886 void
2887 WBell(p, visual)
2888 struct win *p;
2889 int visual;
2891 struct canvas *cv;
2892 for (display = displays; display; display = display->d_next)
2894 for (cv = D_cvlist; cv; cv = cv->c_next)
2895 if (cv->c_layer->l_bottom == &p->w_layer)
2896 break;
2897 if (cv && !visual)
2898 AddCStr(D_BL);
2899 else if (cv && D_VB)
2900 AddCStr(D_VB);
2901 else
2902 p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
2907 * This should be reverse video.
2908 * Only change video if window is fore.
2909 * Because it is used in some termcaps to emulate
2910 * a visual bell we do this hack here.
2911 * (screen uses \Eg as special vbell sequence)
2913 static void
2914 WReverseVideo(p, on)
2915 struct win *p;
2916 int on;
2918 struct canvas *cv;
2919 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2921 display = cv->c_display;
2922 if (cv != D_forecv)
2923 continue;
2924 ReverseVideo(on);
2925 if (!on && p->w_revvid && !D_CVR)
2927 if (D_VB)
2928 AddCStr(D_VB);
2929 else
2930 p->w_bell = BELL_VISUAL;
2935 void
2936 WMsg(p, err, str)
2937 struct win *p;
2938 int err;
2939 char *str;
2941 extern struct layer *flayer;
2942 struct layer *oldflayer = flayer;
2943 flayer = &p->w_layer;
2944 LMsg(err, str);
2945 flayer = oldflayer;
2948 void
2949 WChangeSize(p, w, h)
2950 struct win *p;
2951 int w, h;
2953 int wok = 0;
2954 struct canvas *cv;
2956 if (p->w_layer.l_cvlist == 0)
2958 /* window not displayed -> works always */
2959 ChangeWindowSize(p, w, h, p->w_histheight);
2960 return;
2962 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2964 display = cv->c_display;
2965 if (p != D_fore)
2966 continue; /* change only fore */
2967 if (D_CWS)
2968 break;
2969 if (D_CZ0 && (w == Z0width || w == Z1width))
2970 wok = 1;
2972 if (cv == 0 && wok == 0) /* can't change any display */
2973 return;
2974 if (!D_CWS)
2975 h = p->w_height;
2976 ChangeWindowSize(p, w, h, p->w_histheight);
2977 for (display = displays; display; display = display->d_next)
2979 if (p == D_fore)
2981 if (D_cvlist && D_cvlist->c_next == 0)
2982 ResizeDisplay(w, h);
2983 else
2984 ResizeDisplay(w, D_height);
2985 ResizeLayersToCanvases(); /* XXX Hmm ? */
2986 continue;
2988 for (cv = D_cvlist; cv; cv = cv->c_next)
2989 if (cv->c_layer->l_bottom == &p->w_layer)
2990 break;
2991 if (cv)
2992 Redisplay(0);
2996 static int
2997 WindowChangedCheck(s, what, hp)
2998 char *s;
2999 int what;
3000 int *hp;
3002 int h = 0;
3003 int l;
3004 while(*s)
3006 if (*s++ != (hp ? '%' : '\005'))
3007 continue;
3008 l = 0;
3009 s += (*s == '+');
3010 s += (*s == '-');
3011 while (*s >= '0' && *s <= '9')
3012 s++;
3013 if (*s == 'L')
3015 s++;
3016 l = 0x100;
3018 if (*s == 'h')
3019 h = 1;
3020 if (*s == what || ((*s | l) == what) || what == 'd')
3021 break;
3022 if (*s)
3023 s++;
3025 if (hp)
3026 *hp = h;
3027 return *s ? 1 : 0;
3030 void
3031 WindowChanged(p, what)
3032 struct win *p;
3033 int what;
3035 int inwstr, inhstr, inlstr;
3036 int inwstrh = 0, inhstrh = 0, inlstrh = 0;
3037 int got, ox, oy;
3038 struct display *olddisplay = display;
3039 struct canvas *cv;
3041 inwstr = inhstr = 0;
3043 if (what == 'f')
3045 WindowChanged((struct win *)0, 'w'|0x100);
3046 WindowChanged((struct win *)0, 'W'|0x100);
3049 if (what)
3051 inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
3052 inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
3053 inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
3055 else
3057 inwstr = inhstr = 0;
3058 inlstr = 1;
3061 if (p == 0)
3063 for (display = displays; display; display = display->d_next)
3065 ox = D_x;
3066 oy = D_y;
3067 for (cv = D_cvlist; cv; cv = cv->c_next)
3069 if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3070 WListUpdatecv(cv, (struct win *)0);
3071 p = Layer2Window(cv->c_layer);
3072 if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3073 if (cv->c_ye + 1 < D_height)
3074 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3076 p = D_fore;
3077 if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3078 RefreshHStatus();
3079 if (ox != -1 && ox != -1)
3080 GotoPos(ox, oy);
3082 display = olddisplay;
3083 return;
3086 if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
3088 inwstr |= inwstrh;
3089 inhstr |= inhstrh;
3090 inlstr |= inlstrh;
3092 if (!inwstr && !inhstr && !inlstr)
3093 return;
3094 for (display = displays; display; display = display->d_next)
3096 got = 0;
3097 ox = D_x;
3098 oy = D_y;
3099 for (cv = D_cvlist; cv; cv = cv->c_next)
3101 if (inlstr)
3102 WListUpdatecv(cv, p);
3103 if (Layer2Window(cv->c_layer) != p)
3104 continue;
3105 got = 1;
3106 if (inwstr && cv->c_ye + 1 < D_height)
3107 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3109 if (got && inhstr && p == D_fore)
3110 RefreshHStatus();
3111 if (ox != -1 && ox != -1)
3112 GotoPos(ox, oy);
3114 display = olddisplay;