Do not crash when terminal height is zero.
[screen-lua.git] / src / ansi.c
blob2ac0f60d68479884542cca12023381eb9864cd51
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 /* keep string_t and string_t_string in sync! */
82 static char *string_t_string[] =
84 "NONE",
85 "DCS", /* Device control string */
86 "OSC", /* Operating system command */
87 "APC", /* Application program command */
88 /* - used for status change */
89 "PM", /* Privacy message */
90 "AKA", /* title for current screen */
91 "GM", /* Global message to every display */
92 "STATUS" /* User hardstatus line */
95 /* keep state_t and state_t_string in sync! */
96 static char *state_t_string[] =
98 "LIT", /* Literal input */
99 "ESC", /* Start of escape sequence */
100 "ASTR", /* Start of control string */
101 "STRESC", /* ESC seen in control string */
102 "CSI", /* Reading arguments in "CSI Pn ;...*/
103 "PRIN", /* Printer mode */
104 "PRINESC", /* ESC seen in printer mode */
105 "PRINCSI", /* CSI seen in printer mode */
106 "PRIN4" /* CSI 4 seen in printer mode */
109 static int Special __P((int));
110 static void DoESC __P((int, int));
111 static void DoCSI __P((int, int));
112 static void StringStart __P((enum string_t));
113 static void StringChar __P((int));
114 static int StringEnd __P((void));
115 static void PrintStart __P((void));
116 static void PrintChar __P((int));
117 static void PrintFlush __P((void));
118 #ifdef FONT
119 static void DesignateCharset __P((int, int));
120 static void MapCharset __P((int));
121 static void MapCharsetR __P((int));
122 #endif
123 static void SaveCursor __P((void));
124 static void RestoreCursor __P((void));
125 static void BackSpace __P((void));
126 static void Return __P((void));
127 static void LineFeed __P((int));
128 static void ReverseLineFeed __P((void));
129 static void InsertChar __P((int));
130 static void DeleteChar __P((int));
131 static void DeleteLine __P((int));
132 static void InsertLine __P((int));
133 static void Scroll __P((char *, int, int, char *));
134 static void ForwardTab __P((void));
135 static void BackwardTab __P((void));
136 static void ClearScreen __P((void));
137 static void ClearFromBOS __P((void));
138 static void ClearToEOS __P((void));
139 static void ClearLineRegion __P((int, int));
140 static void CursorRight __P((int));
141 static void CursorUp __P((int));
142 static void CursorDown __P((int));
143 static void CursorLeft __P((int));
144 static void ASetMode __P((int));
145 static void SelectRendition __P((void));
146 static void RestorePosRendition __P((void));
147 static void FillWithEs __P((void));
148 static void FindAKA __P((void));
149 static void Report __P((char *, int, int));
150 static void ScrollRegion __P((int));
151 #ifdef COPY_PASTE
152 static void WAddLineToHist __P((struct win *, struct mline *));
153 #endif
154 static void WLogString __P((struct win *, char *, int));
155 static void WReverseVideo __P((struct win *, int));
156 static int WindowChangedCheck __P((char *, int, int *));
157 static void MFixLine __P((struct win *, int, struct mchar *));
158 static void MScrollH __P((struct win *, int, int, int, int, int));
159 static void MScrollV __P((struct win *, int, int, int, int));
160 static void MClearArea __P((struct win *, int, int, int, int, int));
161 static void MInsChar __P((struct win *, struct mchar *, int, int));
162 static void MPutChar __P((struct win *, struct mchar *, int, int));
163 static void MPutStr __P((struct win *, char *, int, struct mchar *, int, int));
164 static void MWrapChar __P((struct win *, struct mchar *, int, int, int, int));
165 #ifdef COLOR
166 static void MBceLine __P((struct win *, int, int, int, int));
167 #endif
169 #ifdef COLOR
170 # define CURR_BCE (curr->w_bce ? rend_getbg(&curr->w_rend) : 0)
171 #else
172 # define CURR_BCE 0
173 #endif
175 void
176 ResetAnsiState(p)
177 struct win *p;
179 p->w_state = LIT;
180 p->w_StringType = NONE;
183 void
184 ResetWindow(p)
185 register struct win *p;
187 register int i;
189 p->w_wrap = nwin_default.wrap;
190 p->w_origin = 0;
191 p->w_insert = 0;
192 p->w_revvid = 0;
193 p->w_mouse = 0;
194 p->w_curinv = 0;
195 p->w_curvvis = 0;
196 p->w_autolf = 0;
197 p->w_keypad = 0;
198 p->w_cursorkeys = 0;
199 p->w_top = 0;
200 p->w_bot = p->w_height - 1;
201 p->w_saved = 0;
202 p->w_x = p->w_y = 0;
203 p->w_state = LIT;
204 p->w_StringType = NONE;
205 bzero(p->w_tabs, p->w_width);
206 for (i = 8; i < p->w_width; i += 8)
207 p->w_tabs[i] = 1;
208 p->w_rend = mchar_null;
209 #ifdef FONT
210 ResetCharsets(p);
211 #endif
212 #ifdef COLOR
213 p->w_bce = nwin_default.bce;
214 #endif
217 /* adds max 22 bytes */
219 GetAnsiStatus(w, buf)
220 struct win *w;
221 char *buf;
223 char *p = buf;
225 if (w->w_state == LIT)
226 return 0;
228 strcpy(p, state_t_string[w->w_state]);
229 p += strlen(p);
230 if (w->w_intermediate)
232 *p++ = '-';
233 if (w->w_intermediate > 0xff)
234 p += AddXChar(p, w->w_intermediate >> 8);
235 p += AddXChar(p, w->w_intermediate & 0xff);
236 *p = 0;
238 if (w->w_state == ASTR || w->w_state == STRESC)
239 sprintf(p, "-%s", string_t_string[w->w_StringType]);
240 p += strlen(p);
241 return p - buf;
245 #ifdef FONT
247 void
248 ResetCharsets(p)
249 struct win *p;
251 p->w_gr = nwin_default.gr;
252 p->w_c1 = nwin_default.c1;
253 SetCharsets(p, "BBBB02");
254 if (nwin_default.charset)
255 SetCharsets(p, nwin_default.charset);
256 #ifdef ENCODINGS
257 ResetEncoding(p);
258 #endif
261 void
262 SetCharsets(p, s)
263 struct win *p;
264 char *s;
266 int i;
268 for (i = 0; i < 4 && *s; i++, s++)
269 if (*s != '.')
270 p->w_charsets[i] = ((*s == 'B') ? ASCII : *s);
271 if (*s && *s++ != '.')
272 p->w_Charset = s[-1] - '0';
273 if (*s && *s != '.')
274 p->w_CharsetR = *s - '0';
275 p->w_ss = 0;
276 p->w_FontL = p->w_charsets[p->w_Charset];
277 p->w_FontR = p->w_charsets[p->w_CharsetR];
279 #endif /* FONT */
281 /*****************************************************************/
285 * Here comes the vt100 emulator
286 * - writes logfiles,
287 * - sets timestamp and flags activity in window.
288 * - record program output in window scrollback
289 * - translate program output for the display and put it into the obuf.
292 void
293 WriteString(wp, buf, len)
294 struct win *wp;
295 register char *buf;
296 register int len;
298 register int c;
299 #ifdef FONT
300 register int font;
301 #endif
302 struct canvas *cv;
304 if (!len)
305 return;
306 if (wp->w_log)
307 WLogString(wp, buf, len);
309 /* set global variables (yuck!) */
310 curr = wp;
311 cols = curr->w_width;
312 rows = curr->w_height;
314 if (curr->w_silence)
315 SetTimeout(&curr->w_silenceev, curr->w_silencewait * 1000);
317 if (curr->w_monitor == MON_ON)
319 debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
320 curr->w_monitor = MON_FOUND;
323 if (cols && rows)
327 c = (unsigned char)*buf++;
328 #ifdef FONT
329 # ifdef DW_CHARS
330 if (!curr->w_mbcs)
331 # endif
332 curr->w_rend.font = curr->w_FontL; /* Default: GL */
333 #endif
335 /* The next part is only for speedup */
336 if (curr->w_state == LIT &&
337 #ifdef UTF8
338 curr->w_encoding != UTF8 &&
339 #endif
340 #ifdef DW_CHARS
341 !is_dw_font(curr->w_rend.font) &&
342 # ifdef ENCODINGS
343 curr->w_rend.font != KANA && !curr->w_mbcs &&
344 # endif
345 #endif
346 #ifdef FONT
347 curr->w_rend.font != '<' &&
348 #endif
349 c >= ' ' && c != 0x7f &&
350 ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) && !curr->w_ss &&
351 !curr->w_insert && curr->w_x < cols - 1)
353 register int currx = curr->w_x;
354 char *imp = buf - 1;
356 while (currx < cols - 1)
358 currx++;
359 if (--len == 0)
360 break;
361 c = (unsigned char)*buf++;
362 if (c < ' ' || c == 0x7f || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
363 break;
365 currx -= curr->w_x;
366 if (currx > 0)
368 MPutStr(curr, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
369 LPutStr(&curr->w_layer, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
370 curr->w_x += currx;
372 if (len == 0)
373 break;
375 /* end of speedup code */
377 #ifdef UTF8
378 if (curr->w_encoding == UTF8)
380 c = FromUtf8(c, &curr->w_decodestate);
381 if (c == -1)
382 continue;
383 if (c == -2)
385 c = UCS_REPL;
386 /* try char again */
387 buf--;
388 len++;
390 if (c > 0xff)
391 debug1("read UNICODE %04x\n", c);
393 #endif
395 tryagain:
396 switch (curr->w_state)
398 case PRIN:
399 switch (c)
401 case '\033':
402 curr->w_state = PRINESC;
403 break;
404 default:
405 PrintChar(c);
407 break;
408 case PRINESC:
409 switch (c)
411 case '[':
412 curr->w_state = PRINCSI;
413 break;
414 default:
415 PrintChar('\033');
416 PrintChar(c);
417 curr->w_state = PRIN;
419 break;
420 case PRINCSI:
421 switch (c)
423 case '4':
424 curr->w_state = PRIN4;
425 break;
426 default:
427 PrintChar('\033');
428 PrintChar('[');
429 PrintChar(c);
430 curr->w_state = PRIN;
432 break;
433 case PRIN4:
434 switch (c)
436 case 'i':
437 curr->w_state = LIT;
438 PrintFlush();
439 if (curr->w_pdisplay && curr->w_pdisplay->d_printfd >= 0)
441 close(curr->w_pdisplay->d_printfd);
442 curr->w_pdisplay->d_printfd = -1;
444 curr->w_pdisplay = 0;
445 break;
446 default:
447 PrintChar('\033');
448 PrintChar('[');
449 PrintChar('4');
450 PrintChar(c);
451 curr->w_state = PRIN;
453 break;
454 case ASTR:
455 if (c == 0)
456 break;
457 if (c == '\033')
459 curr->w_state = STRESC;
460 break;
462 /* special xterm hack: accept SetStatus sequence. Yucc! */
463 /* allow ^E for title escapes */
464 if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
465 if (!curr->w_c1 || c != ('\\' ^ 0xc0))
467 StringChar(c);
468 break;
470 c = '\\';
471 /* FALLTHROUGH */
472 case STRESC:
473 switch (c)
475 case '\\':
476 if (StringEnd() == 0 || len <= 1)
477 break;
478 /* check if somewhere a status is displayed */
479 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
481 display = cv->c_display;
482 if (D_status == STATUS_ON_WIN)
483 break;
485 if (cv)
487 if (len > IOSIZE + 1)
488 len = IOSIZE + 1;
489 curr->w_outlen = len - 1;
490 bcopy(buf, curr->w_outbuf, len - 1);
491 return; /* wait till status is gone */
493 break;
494 case '\033':
495 StringChar('\033');
496 break;
497 default:
498 curr->w_state = ASTR;
499 StringChar('\033');
500 StringChar(c);
501 break;
503 break;
504 case ESC:
505 switch (c)
507 case '[':
508 curr->w_NumArgs = 0;
509 curr->w_intermediate = 0;
510 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
511 curr->w_state = CSI;
512 break;
513 case ']':
514 StringStart(OSC);
515 break;
516 case '_':
517 StringStart(APC);
518 break;
519 case 'P':
520 StringStart(DCS);
521 break;
522 case '^':
523 StringStart(PM);
524 break;
525 case '!':
526 StringStart(GM);
527 break;
528 case '"':
529 case 'k':
530 StringStart(AKA);
531 break;
532 default:
533 if (Special(c))
535 curr->w_state = LIT;
536 break;
538 debug1("not special. c = %x\n", c);
539 if (c >= ' ' && c <= '/')
541 if (curr->w_intermediate)
543 #ifdef DW_CHARS
544 if (curr->w_intermediate == '$')
545 c |= '$' << 8;
546 else
547 #endif
548 c = -1;
550 curr->w_intermediate = c;
552 else if (c >= '0' && c <= '~')
554 DoESC(c, curr->w_intermediate);
555 curr->w_state = LIT;
557 else
559 curr->w_state = LIT;
560 goto tryagain;
563 break;
564 case CSI:
565 switch (c)
567 case '0': case '1': case '2': case '3': case '4':
568 case '5': case '6': case '7': case '8': case '9':
569 if (curr->w_NumArgs < MAXARGS)
571 if (curr->w_args[curr->w_NumArgs] < 100000000)
572 curr->w_args[curr->w_NumArgs] =
573 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
575 break;
576 case ';':
577 case ':':
578 if (curr->w_NumArgs < MAXARGS)
579 curr->w_NumArgs++;
580 break;
581 default:
582 if (Special(c))
583 break;
584 if (c >= '@' && c <= '~')
586 if (curr->w_NumArgs < MAXARGS)
587 curr->w_NumArgs++;
588 DoCSI(c, curr->w_intermediate);
589 if (curr->w_state != PRIN)
590 curr->w_state = LIT;
592 else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
593 curr->w_intermediate = curr->w_intermediate ? -1 : c;
594 else
596 curr->w_state = LIT;
597 goto tryagain;
600 break;
601 case LIT:
602 default:
603 #ifdef DW_CHARS
604 if (curr->w_mbcs)
605 if (c <= ' ' || c == 0x7f || (c >= 0x80 && c < 0xa0 && curr->w_c1))
606 curr->w_mbcs = 0;
607 #endif
608 if (c < ' ')
610 if (c == '\033')
612 curr->w_intermediate = 0;
613 curr->w_state = ESC;
614 if (curr->w_autoaka < 0)
615 curr->w_autoaka = 0;
617 else
618 Special(c);
619 break;
621 if (c >= 0x80 && c < 0xa0 && curr->w_c1)
622 #ifdef FONT
623 if ((curr->w_FontR & 0xf0) != 0x20
624 # ifdef UTF8
625 || curr->w_encoding == UTF8
626 # endif
628 #endif
630 switch (c)
632 case 0xc0 ^ 'D':
633 case 0xc0 ^ 'E':
634 case 0xc0 ^ 'H':
635 case 0xc0 ^ 'M':
636 case 0xc0 ^ 'N': /* SS2 */
637 case 0xc0 ^ 'O': /* SS3 */
638 DoESC(c ^ 0xc0, 0);
639 break;
640 case 0xc0 ^ '[':
641 if (curr->w_autoaka < 0)
642 curr->w_autoaka = 0;
643 curr->w_NumArgs = 0;
644 curr->w_intermediate = 0;
645 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
646 curr->w_state = CSI;
647 break;
648 case 0xc0 ^ 'P':
649 StringStart(DCS);
650 break;
651 default:
652 break;
654 break;
657 #ifdef FONT
658 # ifdef DW_CHARS
659 if (!curr->w_mbcs)
661 # endif
662 if (c < 0x80 || curr->w_gr == 0)
663 curr->w_rend.font = curr->w_FontL;
664 # ifdef ENCODINGS
665 else if (curr->w_gr == 2 && !curr->w_ss)
666 curr->w_rend.font = curr->w_FontE;
667 # endif
668 else
669 curr->w_rend.font = curr->w_FontR;
670 # ifdef DW_CHARS
672 # endif
673 # ifdef UTF8
674 if (curr->w_encoding == UTF8)
676 if (curr->w_rend.font == '0')
678 struct mchar mc, *mcp;
680 debug1("SPECIAL %x\n", c);
681 mc.image = c;
682 mc.mbcs = 0;
683 mc.font = '0';
684 mcp = recode_mchar(&mc, 0, UTF8);
685 debug2("%02x %02x\n", mcp->image, mcp->font);
686 c = mcp->image | mcp->font << 8;
688 curr->w_rend.font = 0;
690 # ifdef DW_CHARS
691 if (curr->w_encoding == UTF8 && utf8_isdouble(c))
692 curr->w_mbcs = 0xff;
693 # endif
694 if (curr->w_encoding == UTF8 && c >= 0x0300 && utf8_iscomb(c))
696 int ox, oy;
697 struct mchar omc;
699 ox = curr->w_x - 1;
700 oy = curr->w_y;
701 if (ox < 0)
703 ox = curr->w_width - 1;
704 oy--;
706 if (oy < 0)
707 oy = 0;
708 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
709 if (omc.image == 0xff && omc.font == 0xff)
711 ox--;
712 if (ox >= 0)
714 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
715 omc.mbcs = 0xff;
718 if (ox >= 0)
720 utf8_handle_comb(c, &omc);
721 MFixLine(curr, oy, &omc);
722 copy_mchar2mline(&omc, &curr->w_mlines[oy], ox);
723 LPutChar(&curr->w_layer, &omc, ox, oy);
724 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
726 break;
728 font = curr->w_rend.font;
729 # endif
730 # ifdef DW_CHARS
731 # ifdef ENCODINGS
732 if (font == KANA && curr->w_encoding == SJIS && curr->w_mbcs == 0)
734 /* Lets see if it is the first byte of a kanji */
735 debug1("%x may be first of SJIS\n", c);
736 if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
738 debug("YES!\n");
739 curr->w_mbcs = c;
740 break;
743 # endif
744 if (font == 031 && c == 0x80 && !curr->w_mbcs)
745 font = curr->w_rend.font = 0;
746 if (is_dw_font(font) && c == ' ')
747 font = curr->w_rend.font = 0;
748 if (is_dw_font(font) || curr->w_mbcs)
750 int t = c;
751 if (curr->w_mbcs == 0)
753 curr->w_mbcs = c;
754 break;
756 if (curr->w_x == cols - 1)
758 curr->w_x += curr->w_wrap ? 1 : -1;
759 debug1("Patched w_x to %d\n", curr->w_x);
761 # ifdef UTF8
762 if (curr->w_encoding != UTF8)
763 # endif
765 c = curr->w_mbcs;
766 # ifdef ENCODINGS
767 if (font == KANA && curr->w_encoding == SJIS)
769 debug2("SJIS !! %x %x\n", c, t);
771 * SJIS -> EUC mapping:
772 * First byte:
773 * 81,82...9f -> 21,23...5d
774 * e0,e1...ef -> 5f,61...7d
775 * Second byte:
776 * 40-7e -> 21-5f
777 * 80-9e -> 60-7e
778 * 9f-fc -> 21-7e (increment first byte!)
780 if (0x40 <= t && t <= 0xfc && t != 0x7f)
782 if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
783 else c = (c - 0xc1) * 2 + 0x21;
784 if (t <= 0x7e) t -= 0x1f;
785 else if (t <= 0x9e) t -= 0x20;
786 else t -= 0x7e, c++;
787 curr->w_rend.font = KANJI;
789 else
791 /* Incomplete shift-jis - skip first byte */
792 c = t;
793 t = 0;
795 debug2("SJIS after %x %x\n", c, t);
797 # endif
798 if (t && curr->w_gr && font != 030 && font != 031)
800 t &= 0x7f;
801 if (t < ' ')
802 goto tryagain;
804 if (t == '\177')
805 break;
806 curr->w_mbcs = t;
809 # endif /* DW_CHARS */
810 if (font == '<' && c >= ' ')
812 font = curr->w_rend.font = 0;
813 c |= 0x80;
815 # ifdef UTF8
816 else if (curr->w_gr && curr->w_encoding != UTF8)
817 # else
818 else if (curr->w_gr)
819 # endif
821 #ifdef ENCODINGS
822 if (c == 0x80 && font == 0 && curr->w_encoding == GBK)
823 c = 0xa4;
824 else
825 c &= 0x7f;
826 if (c < ' ' && font != 031)
827 goto tryagain;
828 #else
829 c &= 0x7f;
830 if (c < ' ') /* this is ugly but kanji support */
831 goto tryagain; /* prevents nicer programming */
832 #endif
834 #endif /* FONT */
835 if (c == '\177')
836 break;
837 curr->w_rend.image = c;
838 #ifdef UTF8
839 if (curr->w_encoding == UTF8)
840 curr->w_rend.font = c >> 8;
841 #endif
842 #ifdef DW_CHARS
843 curr->w_rend.mbcs = curr->w_mbcs;
844 #endif
845 if (curr->w_x < cols - 1)
847 if (curr->w_insert)
849 save_mline(&curr->w_mlines[curr->w_y], cols);
850 MInsChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
851 LInsChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y, &mline_old);
852 curr->w_x++;
854 else
856 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
857 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
858 curr->w_x++;
861 else if (curr->w_x == cols - 1)
863 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
864 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
865 if (curr->w_wrap)
866 curr->w_x++;
868 else
870 MWrapChar(curr, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
871 LWrapChar(&curr->w_layer, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
872 if (curr->w_y != curr->w_bot && curr->w_y != curr->w_height - 1)
873 curr->w_y++;
874 curr->w_x = 1;
876 #ifdef FONT
877 # ifdef DW_CHARS
878 if (curr->w_mbcs)
880 curr->w_rend.mbcs = curr->w_mbcs = 0;
881 curr->w_x++;
883 # endif
884 if (curr->w_ss)
886 curr->w_FontL = curr->w_charsets[curr->w_Charset];
887 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
888 curr->w_rend.font = curr->w_FontL;
889 LSetRendition(&curr->w_layer, &curr->w_rend);
890 curr->w_ss = 0;
892 #endif /* FONT */
893 break;
896 while (--len);
898 if (!printcmd && curr->w_state == PRIN)
899 PrintFlush();
902 static void
903 WLogString(p, buf, len)
904 struct win *p;
905 char *buf;
906 int len;
908 if (!p->w_log)
909 return;
910 if (logtstamp_on && p->w_logsilence >= logtstamp_after * 2)
912 char *t = MakeWinMsg(logtstamp_string, p, '%');
913 logfwrite(p->w_log, t, strlen(t)); /* long time no write */
915 p->w_logsilence = 0;
916 if (logfwrite(p->w_log, buf, len) < 1)
918 WMsg(p, errno, "Error writing logfile");
919 logfclose(p->w_log);
920 p->w_log = 0;
922 if (!log_flush)
923 logfflush(p->w_log);
926 static int
927 Special(c)
928 register int c;
930 switch (c)
932 case '\b':
933 BackSpace();
934 return 1;
935 case '\r':
936 Return();
937 return 1;
938 case '\n':
939 if (curr->w_autoaka)
940 FindAKA();
941 LineFeed(0);
942 return 1;
943 case '\007':
944 WBell(curr, visual_bell);
945 return 1;
946 case '\t':
947 ForwardTab();
948 return 1;
949 #ifdef FONT
950 case '\017': /* SI */
951 MapCharset(G0);
952 return 1;
953 case '\016': /* SO */
954 MapCharset(G1);
955 return 1;
956 #endif
958 return 0;
961 static void
962 DoESC(c, intermediate)
963 int c, intermediate;
965 debug2("DoESC: %x - inter = %x\n", c, intermediate);
966 switch (intermediate)
968 case 0:
969 switch (c)
971 case 'E':
972 LineFeed(1);
973 break;
974 case 'D':
975 LineFeed(0);
976 break;
977 case 'M':
978 ReverseLineFeed();
979 break;
980 case 'H':
981 curr->w_tabs[curr->w_x] = 1;
982 break;
983 case 'Z': /* jph: Identify as VT100 */
984 Report("\033[?%d;%dc", 1, 2);
985 break;
986 case '7':
987 SaveCursor();
988 break;
989 case '8':
990 RestoreCursor();
991 break;
992 case 'c':
993 ClearScreen();
994 ResetWindow(curr);
995 LKeypadMode(&curr->w_layer, 0);
996 LCursorkeysMode(&curr->w_layer, 0);
997 #ifndef TIOCPKT
998 WNewAutoFlow(curr, 1);
999 #endif
1000 /* XXX
1001 SetRendition(&mchar_null);
1002 InsertMode(0);
1003 ChangeScrollRegion(0, rows - 1);
1005 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1006 break;
1007 case '=':
1008 LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
1009 #ifndef TIOCPKT
1010 WNewAutoFlow(curr, 0);
1011 #endif /* !TIOCPKT */
1012 break;
1013 case '>':
1014 LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
1015 #ifndef TIOCPKT
1016 WNewAutoFlow(curr, 1);
1017 #endif /* !TIOCPKT */
1018 break;
1019 #ifdef FONT
1020 case 'n': /* LS2 */
1021 MapCharset(G2);
1022 break;
1023 case 'o': /* LS3 */
1024 MapCharset(G3);
1025 break;
1026 case '~':
1027 MapCharsetR(G1); /* LS1R */
1028 break;
1029 /* { */
1030 case '}':
1031 MapCharsetR(G2); /* LS2R */
1032 break;
1033 case '|':
1034 MapCharsetR(G3); /* LS3R */
1035 break;
1036 case 'N': /* SS2 */
1037 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
1038 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
1039 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
1040 else
1041 curr->w_ss = 0;
1042 break;
1043 case 'O': /* SS3 */
1044 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
1045 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
1046 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
1047 else
1048 curr->w_ss = 0;
1049 break;
1050 #endif /* FONT */
1051 case 'g': /* VBELL, private screen sequence */
1052 WBell(curr, 1);
1053 break;
1055 break;
1056 case '#':
1057 switch (c)
1059 case '8':
1060 FillWithEs();
1061 break;
1063 break;
1064 #ifdef FONT
1065 case '(':
1066 DesignateCharset(c, G0);
1067 break;
1068 case ')':
1069 DesignateCharset(c, G1);
1070 break;
1071 case '*':
1072 DesignateCharset(c, G2);
1073 break;
1074 case '+':
1075 DesignateCharset(c, G3);
1076 break;
1077 # ifdef DW_CHARS
1079 * ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
1080 * ESC $ Fn: same as above. (old sequence)
1081 * ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
1082 * ESC $ * Fn: invoke multi-byte charset, Fn, to G2
1083 * ESC $ + Fn: invoke multi-byte charset, Fn, to G3
1085 case '$':
1086 case '$'<<8 | '(':
1087 DesignateCharset(c & 037, G0);
1088 break;
1089 case '$'<<8 | ')':
1090 DesignateCharset(c & 037, G1);
1091 break;
1092 case '$'<<8 | '*':
1093 DesignateCharset(c & 037, G2);
1094 break;
1095 case '$'<<8 | '+':
1096 DesignateCharset(c & 037, G3);
1097 break;
1098 # endif
1099 #endif /* FONT */
1103 static void
1104 DoCSI(c, intermediate)
1105 int c, intermediate;
1107 register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
1109 if (curr->w_NumArgs > MAXARGS)
1110 curr->w_NumArgs = MAXARGS;
1111 switch (intermediate)
1113 case 0:
1114 switch (c)
1116 case 'H':
1117 case 'f':
1118 if (a1 < 1)
1119 a1 = 1;
1120 if (curr->w_origin)
1121 a1 += curr->w_top;
1122 if (a1 > rows)
1123 a1 = rows;
1124 if (a2 < 1)
1125 a2 = 1;
1126 if (a2 > cols)
1127 a2 = cols;
1128 LGotoPos(&curr->w_layer, --a2, --a1);
1129 curr->w_x = a2;
1130 curr->w_y = a1;
1131 if (curr->w_autoaka)
1132 curr->w_autoaka = a1 + 1;
1133 break;
1134 case 'J':
1135 if (a1 < 0 || a1 > 2)
1136 a1 = 0;
1137 switch (a1)
1139 case 0:
1140 ClearToEOS();
1141 break;
1142 case 1:
1143 ClearFromBOS();
1144 break;
1145 case 2:
1146 ClearScreen();
1147 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1148 break;
1150 break;
1151 case 'K':
1152 if (a1 < 0 || a1 > 2)
1153 a1 %= 3;
1154 switch (a1)
1156 case 0:
1157 ClearLineRegion(curr->w_x, cols - 1);
1158 break;
1159 case 1:
1160 ClearLineRegion(0, curr->w_x);
1161 break;
1162 case 2:
1163 ClearLineRegion(0, cols - 1);
1164 break;
1166 break;
1167 case 'X':
1168 a1 = curr->w_x + (a1 ? a1 - 1 : 0);
1169 ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
1170 break;
1171 case 'A':
1172 CursorUp(a1 ? a1 : 1);
1173 break;
1174 case 'B':
1175 CursorDown(a1 ? a1 : 1);
1176 break;
1177 case 'C':
1178 CursorRight(a1 ? a1 : 1);
1179 break;
1180 case 'D':
1181 CursorLeft(a1 ? a1 : 1);
1182 break;
1183 case 'E':
1184 curr->w_x = 0;
1185 CursorDown(a1 ? a1 : 1); /* positions cursor */
1186 break;
1187 case 'F':
1188 curr->w_x = 0;
1189 CursorUp(a1 ? a1 : 1); /* positions cursor */
1190 break;
1191 case 'G':
1192 case '`': /* HPA */
1193 curr->w_x = a1 ? a1 - 1 : 0;
1194 if (curr->w_x >= cols)
1195 curr->w_x = cols - 1;
1196 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1197 break;
1198 case 'd': /* VPA */
1199 curr->w_y = a1 ? a1 - 1 : 0;
1200 if (curr->w_y >= rows)
1201 curr->w_y = rows - 1;
1202 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1203 break;
1204 case 'm':
1205 SelectRendition();
1206 break;
1207 case 'g':
1208 if (a1 == 0)
1209 curr->w_tabs[curr->w_x] = 0;
1210 else if (a1 == 3)
1211 bzero(curr->w_tabs, cols);
1212 break;
1213 case 'r':
1214 if (!a1)
1215 a1 = 1;
1216 if (!a2)
1217 a2 = rows;
1218 if (a1 < 1 || a2 > rows || a1 >= a2)
1219 break;
1220 curr->w_top = a1 - 1;
1221 curr->w_bot = a2 - 1;
1222 /* ChangeScrollRegion(curr->w_top, curr->w_bot); */
1223 if (curr->w_origin)
1225 curr->w_y = curr->w_top;
1226 curr->w_x = 0;
1228 else
1229 curr->w_y = curr->w_x = 0;
1230 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1231 break;
1232 case 's':
1233 SaveCursor();
1234 break;
1235 case 't':
1236 switch(a1)
1238 case 11:
1239 if (curr->w_layer.l_cvlist)
1240 Report("\033[1t", 0, 0);
1241 else
1242 Report("\033[2t", 0, 0);
1243 break;
1244 case 7:
1245 LRefreshAll(&curr->w_layer, 0);
1246 break;
1247 case 21:
1248 a1 = strlen(curr->w_title);
1249 if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
1251 bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
1252 bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
1253 bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
1254 curr->w_inlen += 5 + a1;
1256 break;
1257 case 8:
1258 a1 = curr->w_args[2];
1259 if (a1 < 1)
1260 a1 = curr->w_width;
1261 if (a2 < 1)
1262 a2 = curr->w_height;
1263 if (a1 > 10000 || a2 > 10000)
1264 break;
1265 WChangeSize(curr, a1, a2);
1266 cols = curr->w_width;
1267 rows = curr->w_height;
1268 break;
1269 default:
1270 break;
1272 break;
1273 case 'u':
1274 RestoreCursor();
1275 break;
1276 case 'I':
1277 if (!a1)
1278 a1 = 1;
1279 while (a1--)
1280 ForwardTab();
1281 break;
1282 case 'Z':
1283 if (!a1)
1284 a1 = 1;
1285 while (a1--)
1286 BackwardTab();
1287 break;
1288 case 'L':
1289 InsertLine(a1 ? a1 : 1);
1290 break;
1291 case 'M':
1292 DeleteLine(a1 ? a1 : 1);
1293 break;
1294 case 'P':
1295 DeleteChar(a1 ? a1 : 1);
1296 break;
1297 case '@':
1298 InsertChar(a1 ? a1 : 1);
1299 break;
1300 case 'h':
1301 ASetMode(1);
1302 break;
1303 case 'l':
1304 ASetMode(0);
1305 break;
1306 case 'i': /* MC Media Control */
1307 if (a1 == 5)
1308 PrintStart();
1309 break;
1310 case 'n':
1311 if (a1 == 5) /* Report terminal status */
1312 Report("\033[0n", 0, 0);
1313 else if (a1 == 6) /* Report cursor position */
1314 Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
1315 break;
1316 case 'c': /* Identify as VT100 */
1317 if (a1 == 0)
1318 Report("\033[?%d;%dc", 1, 2);
1319 break;
1320 case 'x': /* decreqtparm */
1321 if (a1 == 0 || a1 == 1)
1322 Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
1323 break;
1324 case 'p': /* obscure code from a 97801 term */
1325 if (a1 == 6 || a1 == 7)
1327 curr->w_curinv = 7 - a1;
1328 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1330 break;
1331 case 'S': /* code from a 97801 term / DEC vt400 */
1332 ScrollRegion(a1 ? a1 : 1);
1333 break;
1334 case 'T': /* code from a 97801 term / DEC vt400 */
1335 case '^': /* SD as per ISO 6429 */
1336 ScrollRegion(a1 ? -a1 : -1);
1337 break;
1339 break;
1340 case '?':
1341 for (a2 = 0; a2 < curr->w_NumArgs; a2++)
1343 a1 = curr->w_args[a2];
1344 debug2("\\E[?%d%c\n",a1,c);
1345 if (c != 'h' && c != 'l')
1346 break;
1347 i = (c == 'h');
1348 switch (a1)
1350 case 1: /* CKM: cursor key mode */
1351 LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
1352 #ifndef TIOCPKT
1353 WNewAutoFlow(curr, !i);
1354 #endif /* !TIOCPKT */
1355 break;
1356 case 2: /* ANM: ansi/vt52 mode */
1357 if (i)
1359 #ifdef FONT
1360 # ifdef ENCODINGS
1361 if (curr->w_encoding)
1362 break;
1363 # endif
1364 curr->w_charsets[0] = curr->w_charsets[1] =
1365 curr->w_charsets[2] = curr->w_charsets[2] =
1366 curr->w_FontL = curr->w_FontR = ASCII;
1367 curr->w_Charset = 0;
1368 curr->w_CharsetR = 2;
1369 curr->w_ss = 0;
1370 #endif
1372 break;
1373 case 3: /* COLM: column mode */
1374 i = (i ? Z0width : Z1width);
1375 WChangeSize(curr, i, curr->w_height);
1376 cols = curr->w_width;
1377 rows = curr->w_height;
1378 break;
1379 /* case 4: SCLM: scrolling mode */
1380 case 5: /* SCNM: screen mode */
1381 if (i != curr->w_revvid)
1382 WReverseVideo(curr, i);
1383 curr->w_revvid = i;
1384 break;
1385 case 6: /* OM: origin mode */
1386 if ((curr->w_origin = i) != 0)
1388 curr->w_y = curr->w_top;
1389 curr->w_x = 0;
1391 else
1392 curr->w_y = curr->w_x = 0;
1393 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1394 break;
1395 case 7: /* AWM: auto wrap mode */
1396 curr->w_wrap = i;
1397 break;
1398 /* case 8: ARM: auto repeat mode */
1399 /* case 9: INLM: interlace mode */
1400 case 9: /* X10 mouse tracking */
1401 curr->w_mouse = i ? 9 : 0;
1402 LMouseMode(&curr->w_layer, curr->w_mouse);
1403 break;
1404 /* case 10: EDM: edit mode */
1405 /* case 11: LTM: line transmit mode */
1406 /* case 13: SCFDM: space compression / field delimiting */
1407 /* case 14: TEM: transmit execution mode */
1408 /* case 16: EKEM: edit key execution mode */
1409 /* case 18: PFF: Printer term form feed */
1410 /* case 19: PEX: Printer extend screen / scroll. reg */
1411 case 25: /* TCEM: text cursor enable mode */
1412 curr->w_curinv = !i;
1413 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1414 break;
1415 /* case 34: RLM: Right to left mode */
1416 /* case 35: HEBM: hebrew keyboard map */
1417 /* case 36: HEM: hebrew encoding */
1418 /* case 38: TeK Mode */
1419 /* case 40: 132 col enable */
1420 /* case 42: NRCM: 7bit NRC character mode */
1421 /* case 44: margin bell enable */
1422 case 47: /* xterm-like alternate screen */
1423 case 1047: /* xterm-like alternate screen */
1424 case 1049: /* xterm-like alternate screen */
1425 if (use_altscreen)
1427 if (i)
1428 EnterAltScreen(curr);
1429 else
1430 LeaveAltScreen(curr);
1431 if (a1 == 47 && !i)
1432 curr->w_saved = 0;
1433 LRefreshAll(&curr->w_layer, 0);
1434 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1436 break;
1437 /* case 66: NKM: Numeric keypad appl mode */
1438 /* case 68: KBUM: Keyboard usage mode (data process) */
1439 case 1000: /* VT200 mouse tracking */
1440 case 1001: /* VT200 highlight mouse */
1441 case 1002: /* button event mouse*/
1442 case 1003: /* any event mouse*/
1443 curr->w_mouse = i ? a1 : 0;
1444 LMouseMode(&curr->w_layer, curr->w_mouse);
1445 break;
1448 break;
1449 case '>':
1450 switch (c)
1452 case 'c': /* secondary DA */
1453 if (a1 == 0)
1454 Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
1455 break;
1457 break;
1462 static void
1463 StringStart(type)
1464 enum string_t type;
1466 curr->w_StringType = type;
1467 curr->w_stringp = curr->w_string;
1468 curr->w_state = ASTR;
1471 static void
1472 StringChar(c)
1473 int c;
1475 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1476 curr->w_state = LIT;
1477 else
1478 *(curr->w_stringp)++ = c;
1482 * Do string processing. Returns -1 if output should be suspended
1483 * until status is gone.
1485 static int
1486 StringEnd()
1488 struct canvas *cv;
1489 char *p;
1490 int typ;
1492 curr->w_state = LIT;
1493 *curr->w_stringp = '\0';
1494 switch (curr->w_StringType)
1496 case OSC: /* special xterm compatibility hack */
1497 if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
1498 break;
1499 typ = atoi(curr->w_string);
1500 p++;
1501 #ifdef MULTIUSER
1502 if (typ == 83) /* 83 = 'S' */
1504 /* special execute commands sequence */
1505 char *args[MAXARGS];
1506 int argl[MAXARGS];
1507 struct acluser *windowuser;
1509 windowuser = *FindUserPtr(":window:");
1510 if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
1512 for (display = displays; display; display = display->d_next)
1513 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1514 break; /* found it */
1515 if (display == 0 && curr->w_layer.l_cvlist)
1516 display = curr->w_layer.l_cvlist->c_display;
1517 if (display == 0)
1518 display = displays;
1519 EffectiveAclUser = windowuser;
1520 fore = curr;
1521 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1522 DoCommand(args, argl);
1523 EffectiveAclUser = 0;
1524 fore = 0;
1525 flayer = 0;
1527 break;
1529 #endif
1530 #ifdef RXVT_OSC
1531 if (typ == 0 || typ == 1 || typ == 20 || typ == 39 || typ == 49)
1533 int typ2;
1534 typ2 = typ / 10;
1535 if (--typ2 < 0)
1536 typ2 = 0;
1537 if (strcmp(curr->w_xtermosc[typ2], p))
1539 strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
1540 curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
1542 for (display = displays; display; display = display->d_next)
1544 if (!D_CXT)
1545 continue;
1546 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1547 SetXtermOSC(typ2, curr->w_xtermosc[typ2]);
1548 if ((typ2 == 2 || typ2 == 3) && D_xtermosc[typ2])
1549 Redisplay(0);
1553 if (typ != 0 && typ != 2)
1554 break;
1555 #else
1556 if (typ < 0 || typ > 2)
1557 break;
1558 #endif
1560 curr->w_stringp -= p - curr->w_string;
1561 if (curr->w_stringp > curr->w_string)
1562 bcopy(p, curr->w_string, curr->w_stringp - curr->w_string);
1563 *curr->w_stringp = '\0';
1564 /* FALLTHROUGH */
1565 case APC:
1566 if (curr->w_hstatus)
1568 if (strcmp(curr->w_hstatus, curr->w_string) == 0)
1569 break; /* not changed */
1570 free(curr->w_hstatus);
1571 curr->w_hstatus = 0;
1573 if (curr->w_string != curr->w_stringp)
1574 curr->w_hstatus = SaveStr(curr->w_string);
1575 WindowChanged(curr, 'h');
1576 break;
1577 case PM:
1578 case GM:
1579 for (display = displays; display; display = display->d_next)
1581 for (cv = D_cvlist; cv; cv = cv->c_next)
1582 if (cv->c_layer->l_bottom == &curr->w_layer)
1583 break;
1584 if (cv || curr->w_StringType == GM)
1585 MakeStatus(curr->w_string);
1587 return -1;
1588 case DCS:
1589 LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
1590 break;
1591 case AKA:
1592 if (curr->w_title == curr->w_akabuf && !*curr->w_string)
1593 break;
1594 ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
1595 if (!*curr->w_string)
1596 curr->w_autoaka = curr->w_y + 1;
1597 break;
1598 default:
1599 break;
1601 return 0;
1604 static void
1605 PrintStart()
1607 curr->w_pdisplay = 0;
1609 /* find us a nice display to print on, fore prefered */
1610 display = curr->w_lastdisp;
1611 if (!(display && curr == D_fore && (printcmd || D_PO)))
1612 for (display = displays; display; display = display->d_next)
1613 if (curr == D_fore && (printcmd || D_PO))
1614 break;
1615 if (!display)
1617 struct canvas *cv;
1618 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1620 display = cv->c_display;
1621 if (printcmd || D_PO)
1622 break;
1624 if (!cv)
1626 display = displays;
1627 if (!display || display->d_next || !(printcmd || D_PO))
1628 return;
1631 curr->w_pdisplay = display;
1632 curr->w_stringp = curr->w_string;
1633 curr->w_state = PRIN;
1634 if (printcmd && curr->w_pdisplay->d_printfd < 0)
1635 curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
1638 static void
1639 PrintChar(c)
1640 int c;
1642 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1643 PrintFlush();
1644 *(curr->w_stringp)++ = c;
1647 static void
1648 PrintFlush()
1650 display = curr->w_pdisplay;
1651 if (display && printcmd)
1653 char *bp = curr->w_string;
1654 int len = curr->w_stringp - curr->w_string;
1655 int r;
1656 while (len && display->d_printfd >= 0)
1658 r = write(display->d_printfd, bp, len);
1659 if (r <= 0)
1661 WMsg(curr, errno, "printing aborted");
1662 close(display->d_printfd);
1663 display->d_printfd = -1;
1664 break;
1666 bp += r;
1667 len -= r;
1670 else if (display && curr->w_stringp > curr->w_string)
1672 AddCStr(D_PO);
1673 AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
1674 AddCStr(D_PF);
1675 Flush();
1677 curr->w_stringp = curr->w_string;
1681 void
1682 WNewAutoFlow(win, on)
1683 struct win *win;
1684 int on;
1686 debug1("WNewAutoFlow: %d\n", on);
1687 if (win->w_flow & FLOW_AUTOFLAG)
1688 win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
1689 else
1690 win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
1691 LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
1695 #ifdef FONT
1697 static void
1698 DesignateCharset(c, n)
1699 int c, n;
1701 curr->w_ss = 0;
1702 # ifdef ENCODINGS
1703 if (c == ('@' & 037)) /* map JIS 6226 to 0208 */
1704 c = KANJI;
1705 # endif
1706 if (c == 'B')
1707 c = ASCII;
1708 if (curr->w_charsets[n] != c)
1710 curr->w_charsets[n] = c;
1711 if (curr->w_Charset == n)
1713 curr->w_FontL = c;
1714 curr->w_rend.font = curr->w_FontL;
1715 LSetRendition(&curr->w_layer, &curr->w_rend);
1717 if (curr->w_CharsetR == n)
1718 curr->w_FontR = c;
1722 static void
1723 MapCharset(n)
1724 int n;
1726 curr->w_ss = 0;
1727 if (curr->w_Charset != n)
1729 curr->w_Charset = n;
1730 curr->w_FontL = curr->w_charsets[n];
1731 curr->w_rend.font = curr->w_FontL;
1732 LSetRendition(&curr->w_layer, &curr->w_rend);
1736 static void
1737 MapCharsetR(n)
1738 int n;
1740 curr->w_ss = 0;
1741 if (curr->w_CharsetR != n)
1743 curr->w_CharsetR = n;
1744 curr->w_FontR = curr->w_charsets[n];
1746 curr->w_gr = 1;
1749 #endif /* FONT */
1751 static void
1752 SaveCursor()
1754 curr->w_saved = 1;
1755 curr->w_Saved_x = curr->w_x;
1756 curr->w_Saved_y = curr->w_y;
1757 curr->w_SavedRend = curr->w_rend;
1758 #ifdef FONT
1759 curr->w_SavedCharset = curr->w_Charset;
1760 curr->w_SavedCharsetR = curr->w_CharsetR;
1761 bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
1762 4 * sizeof(int));
1763 #endif
1766 static void
1767 RestoreCursor()
1769 if (!curr->w_saved)
1770 return;
1771 LGotoPos(&curr->w_layer, curr->w_Saved_x, curr->w_Saved_y);
1772 curr->w_x = curr->w_Saved_x;
1773 curr->w_y = curr->w_Saved_y;
1774 curr->w_rend = curr->w_SavedRend;
1775 #ifdef FONT
1776 bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
1777 4 * sizeof(int));
1778 curr->w_Charset = curr->w_SavedCharset;
1779 curr->w_CharsetR = curr->w_SavedCharsetR;
1780 curr->w_ss = 0;
1781 curr->w_FontL = curr->w_charsets[curr->w_Charset];
1782 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
1783 #endif
1784 LSetRendition(&curr->w_layer, &curr->w_rend);
1787 static void
1788 BackSpace()
1790 if (curr->w_x > 0)
1792 curr->w_x--;
1794 else if (curr->w_wrap && curr->w_y > 0)
1796 curr->w_x = cols - 1;
1797 curr->w_y--;
1799 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1802 static void
1803 Return()
1805 if (curr->w_x == 0)
1806 return;
1807 curr->w_x = 0;
1808 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1811 static void
1812 LineFeed(out_mode)
1813 int out_mode;
1815 /* out_mode: 0=lf, 1=cr+lf */
1816 if (out_mode)
1817 curr->w_x = 0;
1818 if (curr->w_y != curr->w_bot) /* Don't scroll */
1820 if (curr->w_y < rows-1)
1821 curr->w_y++;
1822 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1823 return;
1825 if (curr->w_autoaka > 1)
1826 curr->w_autoaka--;
1827 MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
1828 LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
1829 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1832 static void
1833 ReverseLineFeed()
1835 if (curr->w_y == curr->w_top)
1837 MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
1838 LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
1839 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1841 else if (curr->w_y > 0)
1842 CursorUp(1);
1845 static void
1846 InsertChar(n)
1847 int n;
1849 register int y = curr->w_y, x = curr->w_x;
1851 if (n <= 0)
1852 return;
1853 if (x == cols)
1854 x--;
1855 save_mline(&curr->w_mlines[y], cols);
1856 MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
1857 LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1858 LGotoPos(&curr->w_layer, x, y);
1861 static void
1862 DeleteChar(n)
1863 int n;
1865 register int y = curr->w_y, x = curr->w_x;
1867 if (x == cols)
1868 x--;
1869 save_mline(&curr->w_mlines[y], cols);
1870 MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
1871 LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1872 LGotoPos(&curr->w_layer, x, y);
1875 static void
1876 DeleteLine(n)
1877 int n;
1879 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1880 return;
1881 if (n > curr->w_bot - curr->w_y + 1)
1882 n = curr->w_bot - curr->w_y + 1;
1883 MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
1884 LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
1885 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1888 static void
1889 InsertLine(n)
1890 int n;
1892 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1893 return;
1894 if (n > curr->w_bot - curr->w_y + 1)
1895 n = curr->w_bot - curr->w_y + 1;
1896 MScrollV(curr, -n, curr->w_y, curr->w_bot, CURR_BCE);
1897 LScrollV(&curr->w_layer, -n, curr->w_y, curr->w_bot, CURR_BCE);
1898 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1901 static void
1902 ScrollRegion(n)
1903 int n;
1905 MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
1906 LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
1907 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1911 static void
1912 ForwardTab()
1914 register int x = curr->w_x;
1916 if (x == cols)
1918 LineFeed(1);
1919 x = 0;
1921 if (curr->w_tabs[x] && x < cols - 1)
1922 x++;
1923 while (x < cols - 1 && !curr->w_tabs[x])
1924 x++;
1925 curr->w_x = x;
1926 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1929 static void
1930 BackwardTab()
1932 register int x = curr->w_x;
1934 if (curr->w_tabs[x] && x > 0)
1935 x--;
1936 while (x > 0 && !curr->w_tabs[x])
1937 x--;
1938 curr->w_x = x;
1939 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1942 static void
1943 ClearScreen()
1945 LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
1946 #ifdef COPY_PASTE
1947 MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
1948 #else
1949 MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
1950 #endif
1953 static void
1954 ClearFromBOS()
1956 register int y = curr->w_y, x = curr->w_x;
1958 LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
1959 MClearArea(curr, 0, 0, x, y, CURR_BCE);
1960 RestorePosRendition();
1963 static void
1964 ClearToEOS()
1966 register int y = curr->w_y, x = curr->w_x;
1968 if (x == 0 && y == 0)
1970 ClearScreen();
1971 RestorePosRendition();
1972 return;
1974 LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
1975 MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
1976 RestorePosRendition();
1979 static void
1980 ClearLineRegion(from, to)
1981 int from, to;
1983 register int y = curr->w_y;
1984 LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
1985 MClearArea(curr, from, y, to, y, CURR_BCE);
1986 RestorePosRendition();
1989 static void
1990 CursorRight(n)
1991 register int n;
1993 register int x = curr->w_x;
1995 if (x == cols)
1997 LineFeed(1);
1998 x = 0;
2000 if ((curr->w_x += n) >= cols)
2001 curr->w_x = cols - 1;
2002 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2005 static void
2006 CursorUp(n)
2007 register int n;
2009 if (curr->w_y < curr->w_top) /* if above scrolling rgn, */
2011 if ((curr->w_y -= n) < 0) /* ignore its limits */
2012 curr->w_y = 0;
2014 else
2015 if ((curr->w_y -= n) < curr->w_top)
2016 curr->w_y = curr->w_top;
2017 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2020 static void
2021 CursorDown(n)
2022 register int n;
2024 if (curr->w_y > curr->w_bot) /* if below scrolling rgn, */
2026 if ((curr->w_y += n) > rows - 1) /* ignore its limits */
2027 curr->w_y = rows - 1;
2029 else
2030 if ((curr->w_y += n) > curr->w_bot)
2031 curr->w_y = curr->w_bot;
2032 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2035 static void
2036 CursorLeft(n)
2037 register int n;
2039 if ((curr->w_x -= n) < 0)
2040 curr->w_x = 0;
2041 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2044 static void
2045 ASetMode(on)
2046 int on;
2048 register int i;
2050 for (i = 0; i < curr->w_NumArgs; ++i)
2052 switch (curr->w_args[i])
2054 /* case 2: KAM: Lock keyboard */
2055 case 4: /* IRM: Insert mode */
2056 curr->w_insert = on;
2057 LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
2058 break;
2059 /* case 12: SRM: Echo mode on */
2060 case 20: /* LNM: Linefeed mode */
2061 curr->w_autolf = on;
2062 break;
2063 case 34:
2064 curr->w_curvvis = !on;
2065 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
2066 break;
2067 default:
2068 break;
2073 static char rendlist[] =
2075 ~((1 << NATTR) - 1), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
2076 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2077 0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
2080 static void
2081 SelectRendition()
2083 #ifdef COLOR
2084 register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
2085 # ifdef COLORS256
2086 int cx = curr->w_rend.colorx;
2087 # endif
2088 #else
2089 register int j, i = 0, a = curr->w_rend.attr;
2090 #endif
2094 j = curr->w_args[i];
2095 #ifdef COLOR
2096 if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
2098 int jj;
2100 i += 2;
2101 jj = curr->w_args[i];
2102 if (jj < 0 || jj > 255)
2103 continue;
2104 # ifdef COLORS256
2105 if (j == 38)
2107 c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
2108 a |= A_BFG;
2109 if (jj >= 8 && jj < 16)
2110 c |= 0x08;
2111 else
2112 a ^= A_BFG;
2113 a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
2114 cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
2116 else
2118 c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
2119 a |= A_BBG;
2120 if (jj >= 8 && jj < 16)
2121 c |= 0x80;
2122 else
2123 a ^= A_BBG;
2124 cx = (cx & 0x0f) | (jj & 0xf0);
2126 continue;
2127 # else
2128 jj = color256to16(jj) + 30;
2129 if (jj >= 38)
2130 jj += 60 - 8;
2131 j = j == 38 ? jj : jj + 10;
2132 # endif
2134 # ifdef COLORS16
2135 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2136 a &= 0xbf;
2137 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2138 a &= 0x7f;
2139 if (j >= 90 && j <= 97)
2140 a |= 0x40;
2141 if (j >= 100 && j <= 107)
2142 a |= 0x80;
2143 # endif
2144 if (j >= 90 && j <= 97)
2145 j -= 60;
2146 if (j >= 100 && j <= 107)
2147 j -= 60;
2148 if (j >= 30 && j <= 39 && j != 38)
2149 c = (c & 0xf0) | ((j - 30) ^ 9);
2150 else if (j >= 40 && j <= 49 && j != 48)
2151 c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
2152 if (j == 0)
2153 c = 0;
2154 # ifdef COLORS256
2155 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2156 cx &= 0xf0;
2157 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2158 cx &= 0x0f;
2159 # endif
2160 #endif
2161 if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
2162 continue;
2163 j = rendlist[j];
2164 if (j & (1 << NATTR))
2165 a &= j;
2166 else
2167 a |= j;
2169 while (++i < curr->w_NumArgs);
2170 curr->w_rend.attr = a;
2171 #ifdef COLOR
2172 curr->w_rend.color = c;
2173 # ifdef COLORS256
2174 curr->w_rend.colorx = cx;
2175 # endif
2176 #endif
2177 LSetRendition(&curr->w_layer, &curr->w_rend);
2180 static void
2181 FillWithEs()
2183 register int i;
2184 register unsigned char *p, *ep;
2186 LClearAll(&curr->w_layer, 1);
2187 curr->w_y = curr->w_x = 0;
2188 for (i = 0; i < rows; ++i)
2190 clear_mline(&curr->w_mlines[i], 0, cols + 1);
2191 p = curr->w_mlines[i].image;
2192 ep = p + cols;
2193 while (p < ep)
2194 *p++ = 'E';
2196 LRefreshAll(&curr->w_layer, 1);
2201 * Ugly autoaka hack support:
2202 * ChangeAKA() sets a new aka
2203 * FindAKA() searches for an autoaka match
2206 void
2207 ChangeAKA(p, s, l)
2208 struct win *p;
2209 char *s;
2210 int l;
2212 int i, c;
2214 for (i = 0; l > 0; l--)
2216 if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
2217 break;
2218 c = (unsigned char)*s++;
2219 if (c == 0)
2220 break;
2221 if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
2222 continue;
2223 p->w_akachange[i++] = c;
2225 p->w_akachange[i] = 0;
2226 p->w_title = p->w_akachange;
2227 if (p->w_akachange != p->w_akabuf)
2228 if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
2229 p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
2230 WindowChanged(p, 't');
2231 WindowChanged((struct win *)0, 'w');
2232 WindowChanged((struct win *)0, 'W');
2235 static void
2236 FindAKA()
2238 register unsigned char *cp, *line;
2239 register struct win *wp = curr;
2240 register int len = strlen(wp->w_akabuf);
2241 int y;
2243 y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
2244 cols = wp->w_width;
2245 try_line:
2246 cp = line = wp->w_mlines[y].image;
2247 if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
2249 for (;;)
2251 if (cp - line >= cols - len)
2253 if (++y == wp->w_autoaka && y < rows)
2254 goto try_line;
2255 return;
2257 if (strncmp((char *)cp, wp->w_akabuf, len) == 0)
2258 break;
2259 cp++;
2261 cp += len;
2263 for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
2265 if (len)
2267 if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
2268 wp->w_autoaka = -1;
2269 else
2270 wp->w_autoaka = 0;
2271 line = cp;
2272 while (len && *cp != ' ')
2274 if (*cp++ == '/')
2275 line = cp;
2276 len--;
2278 ChangeAKA(wp, (char *)line, cp - line);
2280 else
2281 wp->w_autoaka = 0;
2284 static void
2285 RestorePosRendition()
2287 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2288 LSetRendition(&curr->w_layer, &curr->w_rend);
2291 /* Send a terminal report as if it were typed. */
2292 static void
2293 Report(fmt, n1, n2)
2294 char *fmt;
2295 int n1, n2;
2297 register int len;
2298 char rbuf[40]; /* enough room for all replys */
2300 sprintf(rbuf, fmt, n1, n2);
2301 len = strlen(rbuf);
2303 #ifdef PSEUDOS
2304 if (W_UWP(curr))
2306 if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
2308 bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
2309 curr->w_pwin->p_inlen += len;
2312 else
2313 #endif
2315 if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
2317 bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
2318 curr->w_inlen += len;
2326 *====================================================================*
2327 *====================================================================*
2330 /**********************************************************************
2332 * Memory subsystem.
2336 static void
2337 MFixLine(p, y, mc)
2338 struct win *p;
2339 int y;
2340 struct mchar *mc;
2342 struct mline *ml = &p->w_mlines[y];
2343 if (mc->attr && ml->attr == null)
2345 if ((ml->attr = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2347 ml->attr = null;
2348 mc->attr = p->w_rend.attr = 0;
2349 WMsg(p, 0, "Warning: no space for attr - turned off");
2352 #ifdef FONT
2353 if (mc->font && ml->font == null)
2355 if ((ml->font = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2357 ml->font = null;
2358 p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
2359 p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
2360 mc->font = p->w_rend.font = 0;
2361 WMsg(p, 0, "Warning: no space for font - turned off");
2364 #endif
2365 #ifdef COLOR
2366 if (mc->color && ml->color == null)
2368 if ((ml->color = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2370 ml->color = null;
2371 mc->color = p->w_rend.color = 0;
2372 WMsg(p, 0, "Warning: no space for color - turned off");
2375 # ifdef COLORS256
2376 if (mc->colorx && ml->colorx == null)
2378 if ((ml->colorx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2380 ml->colorx = null;
2381 mc->colorx = p->w_rend.colorx = 0;
2382 WMsg(p, 0, "Warning: no space for extended colors - turned off");
2385 # endif
2386 #endif
2389 /*****************************************************************/
2391 #ifdef DW_CHARS
2392 # define MKillDwRight(p, ml, x) \
2393 if (dw_right(ml, x, p->w_encoding)) \
2395 if (x > 0) \
2396 copy_mchar2mline(&mchar_blank, ml, x - 1); \
2397 copy_mchar2mline(&mchar_blank, ml, x); \
2400 # define MKillDwLeft(p, ml, x) \
2401 if (dw_left(ml, x, p->w_encoding)) \
2403 copy_mchar2mline(&mchar_blank, ml, x); \
2404 copy_mchar2mline(&mchar_blank, ml, x + 1); \
2406 #else
2407 # define MKillDwRight(p, ml, x) ;
2408 # define MKillDwLeft(p, ml, x) ;
2409 #endif
2411 static void
2412 MScrollH(p, n, y, xs, xe, bce)
2413 struct win *p;
2414 int n, y, xs, xe, bce;
2416 struct mline *ml;
2418 if (n == 0)
2419 return;
2420 ml = &p->w_mlines[y];
2421 MKillDwRight(p, ml, xs);
2422 MKillDwLeft(p, ml, xe);
2423 if (n > 0)
2425 if (xe - xs + 1 > n)
2427 MKillDwRight(p, ml, xs + n);
2428 bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
2430 else
2431 n = xe - xs + 1;
2432 clear_mline(ml, xe + 1 - n, n);
2433 #ifdef COLOR
2434 if (bce)
2435 MBceLine(p, y, xe + 1 - n, n, bce);
2436 #endif
2438 else
2440 n = -n;
2441 if (xe - xs + 1 > n)
2443 MKillDwLeft(p, ml, xe - n);
2444 bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
2446 else
2447 n = xe - xs + 1;
2448 clear_mline(ml, xs, n);
2449 #ifdef COLOR
2450 if (bce)
2451 MBceLine(p, y, xs, n, bce);
2452 #endif
2456 static void
2457 MScrollV(p, n, ys, ye, bce)
2458 struct win *p;
2459 int n, ys, ye, bce;
2461 int i, cnt1, cnt2;
2462 struct mline tmp[256];
2463 struct mline *ml;
2465 if (n == 0)
2466 return;
2467 if (n > 0)
2469 if (n > 256)
2471 MScrollV(p, n - 256, ys, ye, bce);
2472 n = 256;
2474 if (ye - ys + 1 < n)
2475 n = ye - ys + 1;
2476 #ifdef COPY_PASTE
2477 if (compacthist)
2479 ye = MFindUsedLine(p, ye, ys);
2480 if (ye - ys + 1 < n)
2481 n = ye - ys + 1;
2482 if (n <= 0)
2483 return;
2485 #endif
2486 /* Clear lines */
2487 ml = p->w_mlines + ys;
2488 for (i = ys; i < ys + n; i++, ml++)
2490 #ifdef COPY_PASTE
2491 if (ys == p->w_top)
2492 WAddLineToHist(p, ml);
2493 #endif
2494 if (ml->attr != null)
2495 free(ml->attr);
2496 ml->attr = null;
2497 #ifdef FONT
2498 if (ml->font != null)
2499 free(ml->font);
2500 ml->font = null;
2501 #endif
2502 #ifdef COLOR
2503 if (ml->color != null)
2504 free(ml->color);
2505 ml->color = null;
2506 # ifdef COLORS256
2507 if (ml->colorx != null)
2508 free(ml->colorx);
2509 ml->colorx = null;
2510 # endif
2511 #endif
2512 bclear((char *)ml->image, p->w_width + 1);
2513 #ifdef COLOR
2514 if (bce)
2515 MBceLine(p, i, 0, p->w_width, bce);
2516 #endif
2518 /* switch 'em over */
2519 cnt1 = n * sizeof(struct mline);
2520 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2521 if (cnt1 && cnt2)
2522 Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
2524 else
2526 if (n < -256)
2528 MScrollV(p, n + 256, ys, ye, bce);
2529 n = -256;
2531 n = -n;
2532 if (ye - ys + 1 < n)
2533 n = ye - ys + 1;
2535 ml = p->w_mlines + ye;
2536 /* Clear lines */
2537 for (i = ye; i > ye - n; i--, ml--)
2539 if (ml->attr != null)
2540 free(ml->attr);
2541 ml->attr = null;
2542 #ifdef FONT
2543 if (ml->font != null)
2544 free(ml->font);
2545 ml->font = null;
2546 #endif
2547 #ifdef COLOR
2548 if (ml->color != null)
2549 free(ml->color);
2550 ml->color = null;
2551 # ifdef COLORS256
2552 if (ml->colorx != null)
2553 free(ml->colorx);
2554 ml->colorx = null;
2555 # endif
2556 #endif
2557 bclear((char *)ml->image, p->w_width + 1);
2558 #ifdef COLOR
2559 if (bce)
2560 MBceLine(p, i, 0, p->w_width, bce);
2561 #endif
2563 cnt1 = n * sizeof(struct mline);
2564 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2565 if (cnt1 && cnt2)
2566 Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
2570 static void
2571 Scroll(cp, cnt1, cnt2, tmp)
2572 char *cp, *tmp;
2573 int cnt1, cnt2;
2575 if (!cnt1 || !cnt2)
2576 return;
2577 if (cnt1 <= cnt2)
2579 bcopy(cp, tmp, cnt1);
2580 bcopy(cp + cnt1, cp, cnt2);
2581 bcopy(tmp, cp + cnt2, cnt1);
2583 else
2585 bcopy(cp + cnt1, tmp, cnt2);
2586 bcopy(cp, cp + cnt2, cnt1);
2587 bcopy(tmp, cp, cnt2);
2591 static void
2592 MClearArea(p, xs, ys, xe, ye, bce)
2593 struct win *p;
2594 int xs, ys, xe, ye, bce;
2596 int n, y;
2597 int xxe;
2598 struct mline *ml;
2600 /* Check for zero-height window */
2601 if (ys < 0 || ye < ys)
2602 return;
2604 /* check for magic margin condition */
2605 if (xs >= p->w_width)
2606 xs = p->w_width - 1;
2607 if (xe >= p->w_width)
2608 xe = p->w_width - 1;
2610 MKillDwRight(p, p->w_mlines + ys, xs);
2611 MKillDwLeft(p, p->w_mlines + ye, xe);
2613 ml = p->w_mlines + ys;
2614 for (y = ys; y <= ye; y++, ml++)
2616 xxe = (y == ye) ? xe : p->w_width - 1;
2617 n = xxe - xs + 1;
2618 if (n > 0)
2619 clear_mline(ml, xs, n);
2620 #ifdef COLOR
2621 if (n > 0 && bce)
2622 MBceLine(p, y, xs, xs + n - 1, bce);
2623 #endif
2624 xs = 0;
2628 static void
2629 MInsChar(p, c, x, y)
2630 struct win *p;
2631 struct mchar *c;
2632 int x, y;
2634 int n;
2635 struct mline *ml;
2637 ASSERT(x >= 0 && x < p->w_width);
2638 MFixLine(p, y, c);
2639 ml = p->w_mlines + y;
2640 n = p->w_width - x - 1;
2641 MKillDwRight(p, ml, x);
2642 if (n > 0)
2644 MKillDwRight(p, ml, p->w_width - 1);
2645 bcopy_mline(ml, x, x + 1, n);
2647 copy_mchar2mline(c, ml, x);
2648 #ifdef DW_CHARS
2649 if (c->mbcs)
2651 if (--n > 0)
2653 MKillDwRight(p, ml, p->w_width - 1);
2654 bcopy_mline(ml, x + 1, x + 2, n);
2656 copy_mchar2mline(c, ml, x + 1);
2657 ml->image[x + 1] = c->mbcs;
2658 # ifdef UTF8
2659 if (p->w_encoding != UTF8)
2660 ml->font[x + 1] |= 0x80;
2661 else if (p->w_encoding == UTF8 && c->mbcs)
2662 ml->font[x + 1] = c->mbcs;
2663 # else
2664 ml->font[x + 1] |= 0x80;
2665 # endif
2667 #endif
2670 static void
2671 MPutChar(p, c, x, y)
2672 struct win *p;
2673 struct mchar *c;
2674 int x, y;
2676 struct mline *ml;
2678 MFixLine(p, y, c);
2679 ml = &p->w_mlines[y];
2680 MKillDwRight(p, ml, x);
2681 MKillDwLeft(p, ml, x);
2682 copy_mchar2mline(c, ml, x);
2683 #ifdef DW_CHARS
2684 if (c->mbcs)
2686 MKillDwLeft(p, ml, x + 1);
2687 copy_mchar2mline(c, ml, x + 1);
2688 ml->image[x + 1] = c->mbcs;
2689 # ifdef UTF8
2690 if (p->w_encoding != UTF8)
2691 ml->font[x + 1] |= 0x80;
2692 else if (p->w_encoding == UTF8 && c->mbcs)
2693 ml->font[x + 1] = c->mbcs;
2694 # else
2695 ml->font[x + 1] |= 0x80;
2696 # endif
2698 #endif
2702 static void
2703 MWrapChar(p, c, y, top, bot, ins)
2704 struct win *p;
2705 struct mchar *c;
2706 int y, top, bot;
2707 int ins;
2709 struct mline *ml;
2710 int bce;
2712 #ifdef COLOR
2713 bce = rend_getbg(c);
2714 #else
2715 bce = 0;
2716 #endif
2717 MFixLine(p, y, c);
2718 ml = &p->w_mlines[y];
2719 copy_mchar2mline(&mchar_null, ml, p->w_width);
2720 if (y == bot)
2721 MScrollV(p, 1, top, bot, bce);
2722 else if (y < p->w_height - 1)
2723 y++;
2724 if (ins)
2725 MInsChar(p, c, 0, y);
2726 else
2727 MPutChar(p, c, 0, y);
2730 static void
2731 MPutStr(p, s, n, r, x, y)
2732 struct win *p;
2733 char *s;
2734 int n;
2735 struct mchar *r;
2736 int x, y;
2738 struct mline *ml;
2739 int i;
2740 unsigned char *b;
2742 if (n <= 0)
2743 return;
2744 MFixLine(p, y, r);
2745 ml = &p->w_mlines[y];
2746 MKillDwRight(p, ml, x);
2747 MKillDwLeft(p, ml, x + n - 1);
2748 bcopy(s, (char *)ml->image + x, n);
2749 b = ml->attr + x;
2750 for (i = n; i-- > 0;)
2751 *b++ = r->attr;
2752 #ifdef FONT
2753 b = ml->font + x;
2754 for (i = n; i-- > 0;)
2755 *b++ = r->font;
2756 #endif
2757 #ifdef COLOR
2758 b = ml->color + x;
2759 for (i = n; i-- > 0;)
2760 *b++ = r->color;
2761 # ifdef COLORS256
2762 b = ml->colorx + x;
2763 for (i = n; i-- > 0;)
2764 *b++ = r->colorx;
2765 # endif
2766 #endif
2769 #ifdef COLOR
2770 static void
2771 MBceLine(p, y, xs, xe, bce)
2772 struct win *p;
2773 int y, xs, xe, bce;
2775 struct mchar mc;
2776 struct mline *ml;
2777 int x;
2779 mc = mchar_null;
2780 rend_setbg(&mc, bce);
2781 MFixLine(p, y, &mc);
2782 ml = p->w_mlines + y;
2783 # ifdef COLORS16
2784 if (mc.attr)
2785 for (x = xs; x <= xe; x++)
2786 ml->attr[x] = mc.attr;
2787 # endif
2788 if (mc.color)
2789 for (x = xs; x <= xe; x++)
2790 ml->color[x] = mc.color;
2791 # ifdef COLORS256
2792 if (mc.colorx)
2793 for (x = xs; x <= xe; x++)
2794 ml->colorx[x] = mc.colorx;
2795 # endif
2797 #endif
2800 #ifdef COPY_PASTE
2801 static void
2802 WAddLineToHist(wp, ml)
2803 struct win *wp;
2804 struct mline *ml;
2806 register unsigned char *q, *o;
2807 struct mline *hml;
2809 if (wp->w_histheight == 0)
2810 return;
2811 hml = &wp->w_hlines[wp->w_histidx];
2812 q = ml->image; ml->image = hml->image; hml->image = q;
2814 q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
2815 if (o != null)
2816 free(o);
2818 #ifdef FONT
2819 q = ml->font; o = hml->font; hml->font = q; ml->font = null;
2820 if (o != null)
2821 free(o);
2822 #endif
2824 #ifdef COLOR
2825 q = ml->color; o = hml->color; hml->color = q; ml->color = null;
2826 if (o != null)
2827 free(o);
2828 # ifdef COLORS256
2829 q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
2830 if (o != null)
2831 free(o);
2832 # endif
2833 #endif
2835 if (++wp->w_histidx >= wp->w_histheight)
2836 wp->w_histidx = 0;
2838 #endif
2841 MFindUsedLine(p, ye, ys)
2842 struct win *p;
2843 int ys, ye;
2845 int y;
2846 struct mline *ml = p->w_mlines + ye;
2848 debug2("MFindUsedLine: %d %d\n", ye, ys);
2849 for (y = ye; y >= ys; y--, ml--)
2851 if (bcmp((char*)ml->image, blank, p->w_width))
2852 break;
2853 if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
2854 break;
2855 #ifdef COLOR
2856 if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
2857 break;
2858 # ifdef COLORS256
2859 if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
2860 break;
2861 # endif
2862 #endif
2864 debug1("MFindUsedLine returning %d\n", y);
2865 return y;
2870 *====================================================================*
2871 *====================================================================*
2875 * Tricky: send only one bell even if the window is displayed
2876 * more than once.
2878 void
2879 WBell(p, visual)
2880 struct win *p;
2881 int visual;
2883 struct canvas *cv;
2884 for (display = displays; display; display = display->d_next)
2886 for (cv = D_cvlist; cv; cv = cv->c_next)
2887 if (cv->c_layer->l_bottom == &p->w_layer)
2888 break;
2889 if (cv && !visual)
2890 AddCStr(D_BL);
2891 else if (cv && D_VB)
2892 AddCStr(D_VB);
2893 else
2894 p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
2899 * This should be reverse video.
2900 * Only change video if window is fore.
2901 * Because it is used in some termcaps to emulate
2902 * a visual bell we do this hack here.
2903 * (screen uses \Eg as special vbell sequence)
2905 static void
2906 WReverseVideo(p, on)
2907 struct win *p;
2908 int on;
2910 struct canvas *cv;
2911 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2913 display = cv->c_display;
2914 if (cv != D_forecv)
2915 continue;
2916 ReverseVideo(on);
2917 if (!on && p->w_revvid && !D_CVR)
2919 if (D_VB)
2920 AddCStr(D_VB);
2921 else
2922 p->w_bell = BELL_VISUAL;
2927 void
2928 WMsg(p, err, str)
2929 struct win *p;
2930 int err;
2931 char *str;
2933 extern struct layer *flayer;
2934 struct layer *oldflayer = flayer;
2935 flayer = &p->w_layer;
2936 LMsg(err, str);
2937 flayer = oldflayer;
2940 void
2941 WChangeSize(p, w, h)
2942 struct win *p;
2943 int w, h;
2945 int wok = 0;
2946 struct canvas *cv;
2948 if (p->w_layer.l_cvlist == 0)
2950 /* window not displayed -> works always */
2951 ChangeWindowSize(p, w, h, p->w_histheight);
2952 return;
2954 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2956 display = cv->c_display;
2957 if (p != D_fore)
2958 continue; /* change only fore */
2959 if (D_CWS)
2960 break;
2961 if (D_CZ0 && (w == Z0width || w == Z1width))
2962 wok = 1;
2964 if (cv == 0 && wok == 0) /* can't change any display */
2965 return;
2966 if (!D_CWS)
2967 h = p->w_height;
2968 ChangeWindowSize(p, w, h, p->w_histheight);
2969 for (display = displays; display; display = display->d_next)
2971 if (p == D_fore)
2973 if (D_cvlist && D_cvlist->c_next == 0)
2974 ResizeDisplay(w, h);
2975 else
2976 ResizeDisplay(w, D_height);
2977 ResizeLayersToCanvases(); /* XXX Hmm ? */
2978 continue;
2980 for (cv = D_cvlist; cv; cv = cv->c_next)
2981 if (cv->c_layer->l_bottom == &p->w_layer)
2982 break;
2983 if (cv)
2984 Redisplay(0);
2988 static int
2989 WindowChangedCheck(s, what, hp)
2990 char *s;
2991 int what;
2992 int *hp;
2994 int h = 0;
2995 int l;
2996 while(*s)
2998 if (*s++ != (hp ? '%' : '\005'))
2999 continue;
3000 l = 0;
3001 s += (*s == '+');
3002 s += (*s == '-');
3003 while (*s >= '0' && *s <= '9')
3004 s++;
3005 if (*s == 'L')
3007 s++;
3008 l = 0x100;
3010 if (*s == 'h')
3011 h = 1;
3012 if (*s == what || ((*s | l) == what) || what == 'd')
3013 break;
3014 if (*s)
3015 s++;
3017 if (hp)
3018 *hp = h;
3019 return *s ? 1 : 0;
3022 void
3023 WindowChanged(p, what)
3024 struct win *p;
3025 int what;
3027 int inwstr, inhstr, inlstr;
3028 int inwstrh = 0, inhstrh = 0, inlstrh = 0;
3029 int got, ox, oy;
3030 struct display *olddisplay = display;
3031 struct canvas *cv;
3033 inwstr = inhstr = 0;
3035 if (what == 'f')
3037 WindowChanged((struct win *)0, 'w'|0x100);
3038 WindowChanged((struct win *)0, 'W'|0x100);
3041 if (what)
3043 inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
3044 inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
3045 inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
3047 else
3049 inwstr = inhstr = 0;
3050 inlstr = 1;
3053 if (p == 0)
3055 for (display = displays; display; display = display->d_next)
3057 ox = D_x;
3058 oy = D_y;
3059 for (cv = D_cvlist; cv; cv = cv->c_next)
3061 if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3062 WListUpdatecv(cv, (struct win *)0);
3063 p = Layer2Window(cv->c_layer);
3064 if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3065 if (cv->c_ye + 1 < D_height)
3066 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3068 p = D_fore;
3069 if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3070 RefreshHStatus();
3071 if (ox != -1 && ox != -1)
3072 GotoPos(ox, oy);
3074 display = olddisplay;
3075 return;
3078 if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
3080 inwstr |= inwstrh;
3081 inhstr |= inhstrh;
3082 inlstr |= inlstrh;
3084 if (!inwstr && !inhstr && !inlstr)
3085 return;
3086 for (display = displays; display; display = display->d_next)
3088 got = 0;
3089 ox = D_x;
3090 oy = D_y;
3091 for (cv = D_cvlist; cv; cv = cv->c_next)
3093 if (inlstr)
3094 WListUpdatecv(cv, p);
3095 if (Layer2Window(cv->c_layer) != p)
3096 continue;
3097 got = 1;
3098 if (inwstr && cv->c_ye + 1 < D_height)
3099 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3101 if (got && inhstr && p == D_fore)
3102 RefreshHStatus();
3103 if (ox != -1 && ox != -1)
3104 GotoPos(ox, oy);
3106 display = olddisplay;