Start converting to GPL v3+ (ref: ticket #23900)
[screen-lua.git] / src / ansi.c
blobd5d1a6245e01499edeb8c50a2266566d498d52e4
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, see
18 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #ifndef sun /* we want to know about TIOCPKT. */
27 # include <sys/ioctl.h>
28 #endif
30 #include "config.h"
31 #include "screen.h"
32 #include "braille.h"
33 #include "extern.h"
34 #include "logfile.h"
36 extern struct display *display, *displays;
37 extern struct win *fore; /* for 83 escape */
38 extern struct layer *flayer; /* for 83 escape */
40 extern struct NewWindow nwin_default; /* for ResetWindow() */
41 extern int nversion; /* numerical version of screen */
42 extern int log_flush, logtstamp_on, logtstamp_after;
43 extern char *logtstamp_string;
44 extern char *captionstring;
45 extern char *hstatusstring;
46 extern char *wliststr;
47 #ifdef COPY_PASTE
48 extern int compacthist;
49 #endif
50 #ifdef MULTIUSER
51 extern struct acluser *EffectiveAclUser;
52 #endif
54 int Z0width, Z1width; /* widths for Z0/Z1 switching */
56 /* globals set in WriteString */
57 static struct win *curr; /* window we are working on */
58 static int rows, cols; /* window size of the curr window */
60 int visual_bell = 0;
61 int use_hardstatus = 1; /* display status line in hs */
62 char *printcmd = 0;
63 int use_altscreen = 0; /* enable alternate screen support? */
65 unsigned char *blank; /* line filled with spaces */
66 unsigned char *null; /* line filled with '\0' */
68 struct mline mline_old;
69 struct mline mline_blank;
70 struct mline mline_null;
72 struct mchar mchar_null;
73 struct mchar mchar_blank = {' ' /* , 0, 0, ... */};
74 struct mchar mchar_so = {' ', A_SO /* , 0, 0, ... */};
76 /* keep string_t and string_t_string in sync! */
77 static char *string_t_string[] =
79 "NONE",
80 "DCS", /* Device control string */
81 "OSC", /* Operating system command */
82 "APC", /* Application program command */
83 /* - used for status change */
84 "PM", /* Privacy message */
85 "AKA", /* title for current screen */
86 "GM", /* Global message to every display */
87 "STATUS" /* User hardstatus line */
90 /* keep state_t and state_t_string in sync! */
91 static char *state_t_string[] =
93 "LIT", /* Literal input */
94 "ESC", /* Start of escape sequence */
95 "ASTR", /* Start of control string */
96 "STRESC", /* ESC seen in control string */
97 "CSI", /* Reading arguments in "CSI Pn ;...*/
98 "PRIN", /* Printer mode */
99 "PRINESC", /* ESC seen in printer mode */
100 "PRINCSI", /* CSI seen in printer mode */
101 "PRIN4" /* CSI 4 seen in printer mode */
104 static int Special __P((int));
105 static void DoESC __P((int, int));
106 static void DoCSI __P((int, int));
107 static void StringStart __P((enum string_t));
108 static void StringChar __P((int));
109 static int StringEnd __P((void));
110 static void PrintStart __P((void));
111 static void PrintChar __P((int));
112 static void PrintFlush __P((void));
113 #ifdef FONT
114 static void DesignateCharset __P((int, int));
115 static void MapCharset __P((int));
116 static void MapCharsetR __P((int));
117 #endif
118 static void SaveCursor __P((void));
119 static void RestoreCursor __P((void));
120 static void BackSpace __P((void));
121 static void Return __P((void));
122 static void LineFeed __P((int));
123 static void ReverseLineFeed __P((void));
124 static void InsertChar __P((int));
125 static void DeleteChar __P((int));
126 static void DeleteLine __P((int));
127 static void InsertLine __P((int));
128 static void Scroll __P((char *, int, int, char *));
129 static void ForwardTab __P((void));
130 static void BackwardTab __P((void));
131 static void ClearScreen __P((void));
132 static void ClearFromBOS __P((void));
133 static void ClearToEOS __P((void));
134 static void ClearLineRegion __P((int, int));
135 static void CursorRight __P((int));
136 static void CursorUp __P((int));
137 static void CursorDown __P((int));
138 static void CursorLeft __P((int));
139 static void ASetMode __P((int));
140 static void SelectRendition __P((void));
141 static void RestorePosRendition __P((void));
142 static void FillWithEs __P((void));
143 static void FindAKA __P((void));
144 static void Report __P((char *, int, int));
145 static void ScrollRegion __P((int));
146 #ifdef COPY_PASTE
147 static void WAddLineToHist __P((struct win *, struct mline *));
148 #endif
149 static void WLogString __P((struct win *, char *, int));
150 static void WReverseVideo __P((struct win *, int));
151 static int WindowChangedCheck __P((char *, int, int *));
152 static void MFixLine __P((struct win *, int, struct mchar *));
153 static void MScrollH __P((struct win *, int, int, int, int, int));
154 static void MScrollV __P((struct win *, int, int, int, int));
155 static void MClearArea __P((struct win *, int, int, int, int, int));
156 static void MInsChar __P((struct win *, struct mchar *, int, int));
157 static void MPutChar __P((struct win *, struct mchar *, int, int));
158 static void MPutStr __P((struct win *, char *, int, struct mchar *, int, int));
159 static void MWrapChar __P((struct win *, struct mchar *, int, int, int, int));
160 #ifdef COLOR
161 static void MBceLine __P((struct win *, int, int, int, int));
162 #endif
164 #ifdef COLOR
165 # define CURR_BCE (curr->w_bce ? rend_getbg(&curr->w_rend) : 0)
166 #else
167 # define CURR_BCE 0
168 #endif
170 void
171 ResetAnsiState(p)
172 struct win *p;
174 p->w_state = LIT;
175 p->w_StringType = NONE;
178 void
179 ResetWindow(p)
180 register struct win *p;
182 register int i;
184 p->w_wrap = nwin_default.wrap;
185 p->w_origin = 0;
186 p->w_insert = 0;
187 p->w_revvid = 0;
188 p->w_mouse = 0;
189 p->w_curinv = 0;
190 p->w_curvvis = 0;
191 p->w_autolf = 0;
192 p->w_keypad = 0;
193 p->w_cursorkeys = 0;
194 p->w_top = 0;
195 p->w_bot = p->w_height - 1;
196 p->w_saved = 0;
197 p->w_x = p->w_y = 0;
198 p->w_state = LIT;
199 p->w_StringType = NONE;
200 bzero(p->w_tabs, p->w_width);
201 for (i = 8; i < p->w_width; i += 8)
202 p->w_tabs[i] = 1;
203 p->w_rend = mchar_null;
204 #ifdef FONT
205 ResetCharsets(p);
206 #endif
207 #ifdef COLOR
208 p->w_bce = nwin_default.bce;
209 #endif
212 /* adds max 22 bytes */
214 GetAnsiStatus(w, buf)
215 struct win *w;
216 char *buf;
218 char *p = buf;
220 if (w->w_state == LIT)
221 return 0;
223 strcpy(p, state_t_string[w->w_state]);
224 p += strlen(p);
225 if (w->w_intermediate)
227 *p++ = '-';
228 if (w->w_intermediate > 0xff)
229 p += AddXChar(p, w->w_intermediate >> 8);
230 p += AddXChar(p, w->w_intermediate & 0xff);
231 *p = 0;
233 if (w->w_state == ASTR || w->w_state == STRESC)
234 sprintf(p, "-%s", string_t_string[w->w_StringType]);
235 p += strlen(p);
236 return p - buf;
240 #ifdef FONT
242 void
243 ResetCharsets(p)
244 struct win *p;
246 p->w_gr = nwin_default.gr;
247 p->w_c1 = nwin_default.c1;
248 SetCharsets(p, "BBBB02");
249 if (nwin_default.charset)
250 SetCharsets(p, nwin_default.charset);
251 #ifdef ENCODINGS
252 ResetEncoding(p);
253 #endif
256 void
257 SetCharsets(p, s)
258 struct win *p;
259 char *s;
261 int i;
263 for (i = 0; i < 4 && *s; i++, s++)
264 if (*s != '.')
265 p->w_charsets[i] = ((*s == 'B') ? ASCII : *s);
266 if (*s && *s++ != '.')
267 p->w_Charset = s[-1] - '0';
268 if (*s && *s != '.')
269 p->w_CharsetR = *s - '0';
270 p->w_ss = 0;
271 p->w_FontL = p->w_charsets[p->w_Charset];
272 p->w_FontR = p->w_charsets[p->w_CharsetR];
274 #endif /* FONT */
276 /*****************************************************************/
280 * Here comes the vt100 emulator
281 * - writes logfiles,
282 * - sets timestamp and flags activity in window.
283 * - record program output in window scrollback
284 * - translate program output for the display and put it into the obuf.
287 void
288 WriteString(wp, buf, len)
289 struct win *wp;
290 register char *buf;
291 register int len;
293 register int c;
294 #ifdef FONT
295 register int font;
296 #endif
297 struct canvas *cv;
299 if (!len)
300 return;
301 if (wp->w_log)
302 WLogString(wp, buf, len);
304 /* set global variables (yuck!) */
305 curr = wp;
306 cols = curr->w_width;
307 rows = curr->w_height;
309 if (curr->w_silence)
310 SetTimeout(&curr->w_silenceev, curr->w_silencewait * 1000);
312 if (curr->w_monitor == MON_ON)
314 debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
315 curr->w_monitor = MON_FOUND;
320 c = (unsigned char)*buf++;
321 #ifdef FONT
322 # ifdef DW_CHARS
323 if (!curr->w_mbcs)
324 # endif
325 curr->w_rend.font = curr->w_FontL; /* Default: GL */
326 #endif
328 /* The next part is only for speedup */
329 if (curr->w_state == LIT &&
330 #ifdef UTF8
331 curr->w_encoding != UTF8 &&
332 #endif
333 #ifdef DW_CHARS
334 !is_dw_font(curr->w_rend.font) &&
335 # ifdef ENCODINGS
336 curr->w_rend.font != KANA && !curr->w_mbcs &&
337 # endif
338 #endif
339 #ifdef FONT
340 curr->w_rend.font != '<' &&
341 #endif
342 c >= ' ' && c != 0x7f &&
343 ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) && !curr->w_ss &&
344 !curr->w_insert && curr->w_x < cols - 1)
346 register int currx = curr->w_x;
347 char *imp = buf - 1;
349 while (currx < cols - 1)
351 currx++;
352 if (--len == 0)
353 break;
354 c = (unsigned char)*buf++;
355 if (c < ' ' || c == 0x7f || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
356 break;
358 currx -= curr->w_x;
359 if (currx > 0)
361 MPutStr(curr, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
362 LPutStr(&curr->w_layer, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
363 curr->w_x += currx;
365 if (len == 0)
366 break;
368 /* end of speedup code */
370 #ifdef UTF8
371 if (curr->w_encoding == UTF8)
373 c = FromUtf8(c, &curr->w_decodestate);
374 if (c == -1)
375 continue;
376 if (c == -2)
378 c = UCS_REPL;
379 /* try char again */
380 buf--;
381 len++;
383 if (c > 0xff)
384 debug1("read UNICODE %04x\n", c);
386 #endif
388 tryagain:
389 switch (curr->w_state)
391 case PRIN:
392 switch (c)
394 case '\033':
395 curr->w_state = PRINESC;
396 break;
397 default:
398 PrintChar(c);
400 break;
401 case PRINESC:
402 switch (c)
404 case '[':
405 curr->w_state = PRINCSI;
406 break;
407 default:
408 PrintChar('\033');
409 PrintChar(c);
410 curr->w_state = PRIN;
412 break;
413 case PRINCSI:
414 switch (c)
416 case '4':
417 curr->w_state = PRIN4;
418 break;
419 default:
420 PrintChar('\033');
421 PrintChar('[');
422 PrintChar(c);
423 curr->w_state = PRIN;
425 break;
426 case PRIN4:
427 switch (c)
429 case 'i':
430 curr->w_state = LIT;
431 PrintFlush();
432 if (curr->w_pdisplay && curr->w_pdisplay->d_printfd >= 0)
434 close(curr->w_pdisplay->d_printfd);
435 curr->w_pdisplay->d_printfd = -1;
437 curr->w_pdisplay = 0;
438 break;
439 default:
440 PrintChar('\033');
441 PrintChar('[');
442 PrintChar('4');
443 PrintChar(c);
444 curr->w_state = PRIN;
446 break;
447 case ASTR:
448 if (c == 0)
449 break;
450 if (c == '\033')
452 curr->w_state = STRESC;
453 break;
455 /* special xterm hack: accept SetStatus sequence. Yucc! */
456 /* allow ^E for title escapes */
457 if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
458 if (!curr->w_c1 || c != ('\\' ^ 0xc0))
460 StringChar(c);
461 break;
463 c = '\\';
464 /* FALLTHROUGH */
465 case STRESC:
466 switch (c)
468 case '\\':
469 if (StringEnd() == 0 || len <= 1)
470 break;
471 /* check if somewhere a status is displayed */
472 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
474 display = cv->c_display;
475 if (D_status == STATUS_ON_WIN)
476 break;
478 if (cv)
480 if (len > IOSIZE + 1)
481 len = IOSIZE + 1;
482 curr->w_outlen = len - 1;
483 bcopy(buf, curr->w_outbuf, len - 1);
484 return; /* wait till status is gone */
486 break;
487 case '\033':
488 StringChar('\033');
489 break;
490 default:
491 curr->w_state = ASTR;
492 StringChar('\033');
493 StringChar(c);
494 break;
496 break;
497 case ESC:
498 switch (c)
500 case '[':
501 curr->w_NumArgs = 0;
502 curr->w_intermediate = 0;
503 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
504 curr->w_state = CSI;
505 break;
506 case ']':
507 StringStart(OSC);
508 break;
509 case '_':
510 StringStart(APC);
511 break;
512 case 'P':
513 StringStart(DCS);
514 break;
515 case '^':
516 StringStart(PM);
517 break;
518 case '!':
519 StringStart(GM);
520 break;
521 case '"':
522 case 'k':
523 StringStart(AKA);
524 break;
525 default:
526 if (Special(c))
528 curr->w_state = LIT;
529 break;
531 debug1("not special. c = %x\n", c);
532 if (c >= ' ' && c <= '/')
534 if (curr->w_intermediate)
536 #ifdef DW_CHARS
537 if (curr->w_intermediate == '$')
538 c |= '$' << 8;
539 else
540 #endif
541 c = -1;
543 curr->w_intermediate = c;
545 else if (c >= '0' && c <= '~')
547 DoESC(c, curr->w_intermediate);
548 curr->w_state = LIT;
550 else
552 curr->w_state = LIT;
553 goto tryagain;
556 break;
557 case CSI:
558 switch (c)
560 case '0': case '1': case '2': case '3': case '4':
561 case '5': case '6': case '7': case '8': case '9':
562 if (curr->w_NumArgs < MAXARGS)
564 if (curr->w_args[curr->w_NumArgs] < 100000000)
565 curr->w_args[curr->w_NumArgs] =
566 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
568 break;
569 case ';':
570 case ':':
571 if (curr->w_NumArgs < MAXARGS)
572 curr->w_NumArgs++;
573 break;
574 default:
575 if (Special(c))
576 break;
577 if (c >= '@' && c <= '~')
579 if (curr->w_NumArgs < MAXARGS)
580 curr->w_NumArgs++;
581 DoCSI(c, curr->w_intermediate);
582 if (curr->w_state != PRIN)
583 curr->w_state = LIT;
585 else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
586 curr->w_intermediate = curr->w_intermediate ? -1 : c;
587 else
589 curr->w_state = LIT;
590 goto tryagain;
593 break;
594 case LIT:
595 default:
596 #ifdef DW_CHARS
597 if (curr->w_mbcs)
598 if (c <= ' ' || c == 0x7f || (c >= 0x80 && c < 0xa0 && curr->w_c1))
599 curr->w_mbcs = 0;
600 #endif
601 if (c < ' ')
603 if (c == '\033')
605 curr->w_intermediate = 0;
606 curr->w_state = ESC;
607 if (curr->w_autoaka < 0)
608 curr->w_autoaka = 0;
610 else
611 Special(c);
612 break;
614 if (c >= 0x80 && c < 0xa0 && curr->w_c1)
615 #ifdef FONT
616 if ((curr->w_FontR & 0xf0) != 0x20
617 # ifdef UTF8
618 || curr->w_encoding == UTF8
619 # endif
621 #endif
623 switch (c)
625 case 0xc0 ^ 'D':
626 case 0xc0 ^ 'E':
627 case 0xc0 ^ 'H':
628 case 0xc0 ^ 'M':
629 case 0xc0 ^ 'N': /* SS2 */
630 case 0xc0 ^ 'O': /* SS3 */
631 DoESC(c ^ 0xc0, 0);
632 break;
633 case 0xc0 ^ '[':
634 if (curr->w_autoaka < 0)
635 curr->w_autoaka = 0;
636 curr->w_NumArgs = 0;
637 curr->w_intermediate = 0;
638 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
639 curr->w_state = CSI;
640 break;
641 case 0xc0 ^ 'P':
642 StringStart(DCS);
643 break;
644 default:
645 break;
647 break;
650 #ifdef FONT
651 # ifdef DW_CHARS
652 if (!curr->w_mbcs)
654 # endif
655 if (c < 0x80 || curr->w_gr == 0)
656 curr->w_rend.font = curr->w_FontL;
657 # ifdef ENCODINGS
658 else if (curr->w_gr == 2 && !curr->w_ss)
659 curr->w_rend.font = curr->w_FontE;
660 # endif
661 else
662 curr->w_rend.font = curr->w_FontR;
663 # ifdef DW_CHARS
665 # endif
666 # ifdef UTF8
667 if (curr->w_encoding == UTF8)
669 if (curr->w_rend.font == '0')
671 struct mchar mc, *mcp;
673 debug1("SPECIAL %x\n", c);
674 mc.image = c;
675 mc.mbcs = 0;
676 mc.font = '0';
677 mcp = recode_mchar(&mc, 0, UTF8);
678 debug2("%02x %02x\n", mcp->image, mcp->font);
679 c = mcp->image | mcp->font << 8;
681 curr->w_rend.font = 0;
683 # ifdef DW_CHARS
684 if (curr->w_encoding == UTF8 && utf8_isdouble(c))
685 curr->w_mbcs = 0xff;
686 # endif
687 if (curr->w_encoding == UTF8 && c >= 0x0300 && utf8_iscomb(c))
689 int ox, oy;
690 struct mchar omc;
692 ox = curr->w_x - 1;
693 oy = curr->w_y;
694 if (ox < 0)
696 ox = curr->w_width - 1;
697 oy--;
699 if (oy < 0)
700 oy = 0;
701 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
702 if (omc.image == 0xff && omc.font == 0xff)
704 ox--;
705 if (ox >= 0)
707 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
708 omc.mbcs = 0xff;
711 if (ox >= 0)
713 utf8_handle_comb(c, &omc);
714 MFixLine(curr, oy, &omc);
715 copy_mchar2mline(&omc, &curr->w_mlines[oy], ox);
716 LPutChar(&curr->w_layer, &omc, ox, oy);
717 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
719 break;
721 font = curr->w_rend.font;
722 # endif
723 # ifdef DW_CHARS
724 # ifdef ENCODINGS
725 if (font == KANA && curr->w_encoding == SJIS && curr->w_mbcs == 0)
727 /* Lets see if it is the first byte of a kanji */
728 debug1("%x may be first of SJIS\n", c);
729 if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
731 debug("YES!\n");
732 curr->w_mbcs = c;
733 break;
736 # endif
737 if (font == 031 && c == 0x80 && !curr->w_mbcs)
738 font = curr->w_rend.font = 0;
739 if (is_dw_font(font) && c == ' ')
740 font = curr->w_rend.font = 0;
741 if (is_dw_font(font) || curr->w_mbcs)
743 int t = c;
744 if (curr->w_mbcs == 0)
746 curr->w_mbcs = c;
747 break;
749 if (curr->w_x == cols - 1)
751 curr->w_x += curr->w_wrap ? 1 : -1;
752 debug1("Patched w_x to %d\n", curr->w_x);
754 # ifdef UTF8
755 if (curr->w_encoding != UTF8)
756 # endif
758 c = curr->w_mbcs;
759 # ifdef ENCODINGS
760 if (font == KANA && curr->w_encoding == SJIS)
762 debug2("SJIS !! %x %x\n", c, t);
764 * SJIS -> EUC mapping:
765 * First byte:
766 * 81,82...9f -> 21,23...5d
767 * e0,e1...ef -> 5f,61...7d
768 * Second byte:
769 * 40-7e -> 21-5f
770 * 80-9e -> 60-7e
771 * 9f-fc -> 21-7e (increment first byte!)
773 if (0x40 <= t && t <= 0xfc && t != 0x7f)
775 if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
776 else c = (c - 0xc1) * 2 + 0x21;
777 if (t <= 0x7e) t -= 0x1f;
778 else if (t <= 0x9e) t -= 0x20;
779 else t -= 0x7e, c++;
780 curr->w_rend.font = KANJI;
782 else
784 /* Incomplete shift-jis - skip first byte */
785 c = t;
786 t = 0;
788 debug2("SJIS after %x %x\n", c, t);
790 # endif
791 if (t && curr->w_gr && font != 030 && font != 031)
793 t &= 0x7f;
794 if (t < ' ')
795 goto tryagain;
797 if (t == '\177')
798 break;
799 curr->w_mbcs = t;
802 # endif /* DW_CHARS */
803 if (font == '<' && c >= ' ')
805 font = curr->w_rend.font = 0;
806 c |= 0x80;
808 # ifdef UTF8
809 else if (curr->w_gr && curr->w_encoding != UTF8)
810 # else
811 else if (curr->w_gr)
812 # endif
814 #ifdef ENCODINGS
815 if (c == 0x80 && font == 0 && curr->w_encoding == GBK)
816 c = 0xa4;
817 else
818 c &= 0x7f;
819 if (c < ' ' && font != 031)
820 goto tryagain;
821 #else
822 c &= 0x7f;
823 if (c < ' ') /* this is ugly but kanji support */
824 goto tryagain; /* prevents nicer programming */
825 #endif
827 #endif /* FONT */
828 if (c == '\177')
829 break;
830 curr->w_rend.image = c;
831 #ifdef UTF8
832 if (curr->w_encoding == UTF8)
833 curr->w_rend.font = c >> 8;
834 #endif
835 #ifdef DW_CHARS
836 curr->w_rend.mbcs = curr->w_mbcs;
837 #endif
838 if (curr->w_x < cols - 1)
840 if (curr->w_insert)
842 save_mline(&curr->w_mlines[curr->w_y], cols);
843 MInsChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
844 LInsChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y, &mline_old);
845 curr->w_x++;
847 else
849 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
850 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
851 curr->w_x++;
854 else if (curr->w_x == cols - 1)
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 if (curr->w_wrap)
859 curr->w_x++;
861 else
863 MWrapChar(curr, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
864 LWrapChar(&curr->w_layer, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
865 if (curr->w_y != curr->w_bot && curr->w_y != curr->w_height - 1)
866 curr->w_y++;
867 curr->w_x = 1;
869 #ifdef FONT
870 # ifdef DW_CHARS
871 if (curr->w_mbcs)
873 curr->w_rend.mbcs = curr->w_mbcs = 0;
874 curr->w_x++;
876 # endif
877 if (curr->w_ss)
879 curr->w_FontL = curr->w_charsets[curr->w_Charset];
880 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
881 curr->w_rend.font = curr->w_FontL;
882 LSetRendition(&curr->w_layer, &curr->w_rend);
883 curr->w_ss = 0;
885 #endif /* FONT */
886 break;
889 while (--len);
890 if (!printcmd && curr->w_state == PRIN)
891 PrintFlush();
894 static void
895 WLogString(p, buf, len)
896 struct win *p;
897 char *buf;
898 int len;
900 if (!p->w_log)
901 return;
902 if (logtstamp_on && p->w_logsilence >= logtstamp_after * 2)
904 char *t = MakeWinMsg(logtstamp_string, p, '%');
905 logfwrite(p->w_log, t, strlen(t)); /* long time no write */
907 p->w_logsilence = 0;
908 if (logfwrite(p->w_log, buf, len) < 1)
910 WMsg(p, errno, "Error writing logfile");
911 logfclose(p->w_log);
912 p->w_log = 0;
914 if (!log_flush)
915 logfflush(p->w_log);
918 static int
919 Special(c)
920 register int c;
922 switch (c)
924 case '\b':
925 BackSpace();
926 return 1;
927 case '\r':
928 Return();
929 return 1;
930 case '\n':
931 if (curr->w_autoaka)
932 FindAKA();
933 LineFeed(0);
934 return 1;
935 case '\007':
936 WBell(curr, visual_bell);
937 return 1;
938 case '\t':
939 ForwardTab();
940 return 1;
941 #ifdef FONT
942 case '\017': /* SI */
943 MapCharset(G0);
944 return 1;
945 case '\016': /* SO */
946 MapCharset(G1);
947 return 1;
948 #endif
950 return 0;
953 static void
954 DoESC(c, intermediate)
955 int c, intermediate;
957 debug2("DoESC: %x - inter = %x\n", c, intermediate);
958 switch (intermediate)
960 case 0:
961 switch (c)
963 case 'E':
964 LineFeed(1);
965 break;
966 case 'D':
967 LineFeed(0);
968 break;
969 case 'M':
970 ReverseLineFeed();
971 break;
972 case 'H':
973 curr->w_tabs[curr->w_x] = 1;
974 break;
975 case 'Z': /* jph: Identify as VT100 */
976 Report("\033[?%d;%dc", 1, 2);
977 break;
978 case '7':
979 SaveCursor();
980 break;
981 case '8':
982 RestoreCursor();
983 break;
984 case 'c':
985 ClearScreen();
986 ResetWindow(curr);
987 LKeypadMode(&curr->w_layer, 0);
988 LCursorkeysMode(&curr->w_layer, 0);
989 #ifndef TIOCPKT
990 WNewAutoFlow(curr, 1);
991 #endif
992 /* XXX
993 SetRendition(&mchar_null);
994 InsertMode(0);
995 ChangeScrollRegion(0, rows - 1);
997 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
998 break;
999 case '=':
1000 LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
1001 #ifndef TIOCPKT
1002 WNewAutoFlow(curr, 0);
1003 #endif /* !TIOCPKT */
1004 break;
1005 case '>':
1006 LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
1007 #ifndef TIOCPKT
1008 WNewAutoFlow(curr, 1);
1009 #endif /* !TIOCPKT */
1010 break;
1011 #ifdef FONT
1012 case 'n': /* LS2 */
1013 MapCharset(G2);
1014 break;
1015 case 'o': /* LS3 */
1016 MapCharset(G3);
1017 break;
1018 case '~':
1019 MapCharsetR(G1); /* LS1R */
1020 break;
1021 /* { */
1022 case '}':
1023 MapCharsetR(G2); /* LS2R */
1024 break;
1025 case '|':
1026 MapCharsetR(G3); /* LS3R */
1027 break;
1028 case 'N': /* SS2 */
1029 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
1030 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
1031 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
1032 else
1033 curr->w_ss = 0;
1034 break;
1035 case 'O': /* SS3 */
1036 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
1037 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
1038 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
1039 else
1040 curr->w_ss = 0;
1041 break;
1042 #endif /* FONT */
1043 case 'g': /* VBELL, private screen sequence */
1044 WBell(curr, 1);
1045 break;
1047 break;
1048 case '#':
1049 switch (c)
1051 case '8':
1052 FillWithEs();
1053 break;
1055 break;
1056 #ifdef FONT
1057 case '(':
1058 DesignateCharset(c, G0);
1059 break;
1060 case ')':
1061 DesignateCharset(c, G1);
1062 break;
1063 case '*':
1064 DesignateCharset(c, G2);
1065 break;
1066 case '+':
1067 DesignateCharset(c, G3);
1068 break;
1069 # ifdef DW_CHARS
1071 * ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
1072 * ESC $ Fn: same as above. (old sequence)
1073 * ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
1074 * ESC $ * Fn: invoke multi-byte charset, Fn, to G2
1075 * ESC $ + Fn: invoke multi-byte charset, Fn, to G3
1077 case '$':
1078 case '$'<<8 | '(':
1079 DesignateCharset(c & 037, G0);
1080 break;
1081 case '$'<<8 | ')':
1082 DesignateCharset(c & 037, G1);
1083 break;
1084 case '$'<<8 | '*':
1085 DesignateCharset(c & 037, G2);
1086 break;
1087 case '$'<<8 | '+':
1088 DesignateCharset(c & 037, G3);
1089 break;
1090 # endif
1091 #endif /* FONT */
1095 static void
1096 DoCSI(c, intermediate)
1097 int c, intermediate;
1099 register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
1101 if (curr->w_NumArgs > MAXARGS)
1102 curr->w_NumArgs = MAXARGS;
1103 switch (intermediate)
1105 case 0:
1106 switch (c)
1108 case 'H':
1109 case 'f':
1110 if (a1 < 1)
1111 a1 = 1;
1112 if (curr->w_origin)
1113 a1 += curr->w_top;
1114 if (a1 > rows)
1115 a1 = rows;
1116 if (a2 < 1)
1117 a2 = 1;
1118 if (a2 > cols)
1119 a2 = cols;
1120 LGotoPos(&curr->w_layer, --a2, --a1);
1121 curr->w_x = a2;
1122 curr->w_y = a1;
1123 if (curr->w_autoaka)
1124 curr->w_autoaka = a1 + 1;
1125 break;
1126 case 'J':
1127 if (a1 < 0 || a1 > 2)
1128 a1 = 0;
1129 switch (a1)
1131 case 0:
1132 ClearToEOS();
1133 break;
1134 case 1:
1135 ClearFromBOS();
1136 break;
1137 case 2:
1138 ClearScreen();
1139 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1140 break;
1142 break;
1143 case 'K':
1144 if (a1 < 0 || a1 > 2)
1145 a1 %= 3;
1146 switch (a1)
1148 case 0:
1149 ClearLineRegion(curr->w_x, cols - 1);
1150 break;
1151 case 1:
1152 ClearLineRegion(0, curr->w_x);
1153 break;
1154 case 2:
1155 ClearLineRegion(0, cols - 1);
1156 break;
1158 break;
1159 case 'X':
1160 a1 = curr->w_x + (a1 ? a1 - 1 : 0);
1161 ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
1162 break;
1163 case 'A':
1164 CursorUp(a1 ? a1 : 1);
1165 break;
1166 case 'B':
1167 CursorDown(a1 ? a1 : 1);
1168 break;
1169 case 'C':
1170 CursorRight(a1 ? a1 : 1);
1171 break;
1172 case 'D':
1173 CursorLeft(a1 ? a1 : 1);
1174 break;
1175 case 'E':
1176 curr->w_x = 0;
1177 CursorDown(a1 ? a1 : 1); /* positions cursor */
1178 break;
1179 case 'F':
1180 curr->w_x = 0;
1181 CursorUp(a1 ? a1 : 1); /* positions cursor */
1182 break;
1183 case 'G':
1184 case '`': /* HPA */
1185 curr->w_x = a1 ? a1 - 1 : 0;
1186 if (curr->w_x >= cols)
1187 curr->w_x = cols - 1;
1188 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1189 break;
1190 case 'd': /* VPA */
1191 curr->w_y = a1 ? a1 - 1 : 0;
1192 if (curr->w_y >= rows)
1193 curr->w_y = rows - 1;
1194 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1195 break;
1196 case 'm':
1197 SelectRendition();
1198 break;
1199 case 'g':
1200 if (a1 == 0)
1201 curr->w_tabs[curr->w_x] = 0;
1202 else if (a1 == 3)
1203 bzero(curr->w_tabs, cols);
1204 break;
1205 case 'r':
1206 if (!a1)
1207 a1 = 1;
1208 if (!a2)
1209 a2 = rows;
1210 if (a1 < 1 || a2 > rows || a1 >= a2)
1211 break;
1212 curr->w_top = a1 - 1;
1213 curr->w_bot = a2 - 1;
1214 /* ChangeScrollRegion(curr->w_top, curr->w_bot); */
1215 if (curr->w_origin)
1217 curr->w_y = curr->w_top;
1218 curr->w_x = 0;
1220 else
1221 curr->w_y = curr->w_x = 0;
1222 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1223 break;
1224 case 's':
1225 SaveCursor();
1226 break;
1227 case 't':
1228 switch(a1)
1230 case 11:
1231 if (curr->w_layer.l_cvlist)
1232 Report("\033[1t", 0, 0);
1233 else
1234 Report("\033[2t", 0, 0);
1235 break;
1236 case 7:
1237 LRefreshAll(&curr->w_layer, 0);
1238 break;
1239 case 21:
1240 a1 = strlen(curr->w_title);
1241 if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
1243 bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
1244 bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
1245 bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
1246 curr->w_inlen += 5 + a1;
1248 break;
1249 case 8:
1250 a1 = curr->w_args[2];
1251 if (a1 < 1)
1252 a1 = curr->w_width;
1253 if (a2 < 1)
1254 a2 = curr->w_height;
1255 if (a1 > 10000 || a2 > 10000)
1256 break;
1257 WChangeSize(curr, a1, a2);
1258 cols = curr->w_width;
1259 rows = curr->w_height;
1260 break;
1261 default:
1262 break;
1264 break;
1265 case 'u':
1266 RestoreCursor();
1267 break;
1268 case 'I':
1269 if (!a1)
1270 a1 = 1;
1271 while (a1--)
1272 ForwardTab();
1273 break;
1274 case 'Z':
1275 if (!a1)
1276 a1 = 1;
1277 while (a1--)
1278 BackwardTab();
1279 break;
1280 case 'L':
1281 InsertLine(a1 ? a1 : 1);
1282 break;
1283 case 'M':
1284 DeleteLine(a1 ? a1 : 1);
1285 break;
1286 case 'P':
1287 DeleteChar(a1 ? a1 : 1);
1288 break;
1289 case '@':
1290 InsertChar(a1 ? a1 : 1);
1291 break;
1292 case 'h':
1293 ASetMode(1);
1294 break;
1295 case 'l':
1296 ASetMode(0);
1297 break;
1298 case 'i': /* MC Media Control */
1299 if (a1 == 5)
1300 PrintStart();
1301 break;
1302 case 'n':
1303 if (a1 == 5) /* Report terminal status */
1304 Report("\033[0n", 0, 0);
1305 else if (a1 == 6) /* Report cursor position */
1306 Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
1307 break;
1308 case 'c': /* Identify as VT100 */
1309 if (a1 == 0)
1310 Report("\033[?%d;%dc", 1, 2);
1311 break;
1312 case 'x': /* decreqtparm */
1313 if (a1 == 0 || a1 == 1)
1314 Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
1315 break;
1316 case 'p': /* obscure code from a 97801 term */
1317 if (a1 == 6 || a1 == 7)
1319 curr->w_curinv = 7 - a1;
1320 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1322 break;
1323 case 'S': /* code from a 97801 term / DEC vt400 */
1324 ScrollRegion(a1 ? a1 : 1);
1325 break;
1326 case 'T': /* code from a 97801 term / DEC vt400 */
1327 case '^': /* SD as per ISO 6429 */
1328 ScrollRegion(a1 ? -a1 : -1);
1329 break;
1331 break;
1332 case '?':
1333 for (a2 = 0; a2 < curr->w_NumArgs; a2++)
1335 a1 = curr->w_args[a2];
1336 debug2("\\E[?%d%c\n",a1,c);
1337 if (c != 'h' && c != 'l')
1338 break;
1339 i = (c == 'h');
1340 switch (a1)
1342 case 1: /* CKM: cursor key mode */
1343 LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
1344 #ifndef TIOCPKT
1345 WNewAutoFlow(curr, !i);
1346 #endif /* !TIOCPKT */
1347 break;
1348 case 2: /* ANM: ansi/vt52 mode */
1349 if (i)
1351 #ifdef FONT
1352 # ifdef ENCODINGS
1353 if (curr->w_encoding)
1354 break;
1355 # endif
1356 curr->w_charsets[0] = curr->w_charsets[1] =
1357 curr->w_charsets[2] = curr->w_charsets[2] =
1358 curr->w_FontL = curr->w_FontR = ASCII;
1359 curr->w_Charset = 0;
1360 curr->w_CharsetR = 2;
1361 curr->w_ss = 0;
1362 #endif
1364 break;
1365 case 3: /* COLM: column mode */
1366 i = (i ? Z0width : Z1width);
1367 WChangeSize(curr, i, curr->w_height);
1368 cols = curr->w_width;
1369 rows = curr->w_height;
1370 break;
1371 /* case 4: SCLM: scrolling mode */
1372 case 5: /* SCNM: screen mode */
1373 if (i != curr->w_revvid)
1374 WReverseVideo(curr, i);
1375 curr->w_revvid = i;
1376 break;
1377 case 6: /* OM: origin mode */
1378 if ((curr->w_origin = i) != 0)
1380 curr->w_y = curr->w_top;
1381 curr->w_x = 0;
1383 else
1384 curr->w_y = curr->w_x = 0;
1385 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1386 break;
1387 case 7: /* AWM: auto wrap mode */
1388 curr->w_wrap = i;
1389 break;
1390 /* case 8: ARM: auto repeat mode */
1391 /* case 9: INLM: interlace mode */
1392 case 9: /* X10 mouse tracking */
1393 curr->w_mouse = i ? 9 : 0;
1394 LMouseMode(&curr->w_layer, curr->w_mouse);
1395 break;
1396 /* case 10: EDM: edit mode */
1397 /* case 11: LTM: line transmit mode */
1398 /* case 13: SCFDM: space compression / field delimiting */
1399 /* case 14: TEM: transmit execution mode */
1400 /* case 16: EKEM: edit key execution mode */
1401 /* case 18: PFF: Printer term form feed */
1402 /* case 19: PEX: Printer extend screen / scroll. reg */
1403 case 25: /* TCEM: text cursor enable mode */
1404 curr->w_curinv = !i;
1405 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1406 break;
1407 /* case 34: RLM: Right to left mode */
1408 /* case 35: HEBM: hebrew keyboard map */
1409 /* case 36: HEM: hebrew encoding */
1410 /* case 38: TeK Mode */
1411 /* case 40: 132 col enable */
1412 /* case 42: NRCM: 7bit NRC character mode */
1413 /* case 44: margin bell enable */
1414 case 47: /* xterm-like alternate screen */
1415 case 1047: /* xterm-like alternate screen */
1416 case 1049: /* xterm-like alternate screen */
1417 if (use_altscreen)
1419 if (i)
1420 EnterAltScreen(curr);
1421 else
1422 LeaveAltScreen(curr);
1423 if (a1 == 47 && !i)
1424 curr->w_saved = 0;
1425 LRefreshAll(&curr->w_layer, 0);
1426 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1428 break;
1429 /* case 66: NKM: Numeric keypad appl mode */
1430 /* case 68: KBUM: Keyboard usage mode (data process) */
1431 case 1000: /* VT200 mouse tracking */
1432 case 1001: /* VT200 highlight mouse */
1433 case 1002: /* button event mouse*/
1434 case 1003: /* any event mouse*/
1435 curr->w_mouse = i ? a1 : 0;
1436 LMouseMode(&curr->w_layer, curr->w_mouse);
1437 break;
1440 break;
1441 case '>':
1442 switch (c)
1444 case 'c': /* secondary DA */
1445 if (a1 == 0)
1446 Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
1447 break;
1449 break;
1454 static void
1455 StringStart(type)
1456 enum string_t type;
1458 curr->w_StringType = type;
1459 curr->w_stringp = curr->w_string;
1460 curr->w_state = ASTR;
1463 static void
1464 StringChar(c)
1465 int c;
1467 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1468 curr->w_state = LIT;
1469 else
1470 *(curr->w_stringp)++ = c;
1474 * Do string processing. Returns -1 if output should be suspended
1475 * until status is gone.
1477 static int
1478 StringEnd()
1480 struct canvas *cv;
1481 char *p;
1482 int typ;
1484 curr->w_state = LIT;
1485 *curr->w_stringp = '\0';
1486 switch (curr->w_StringType)
1488 case OSC: /* special xterm compatibility hack */
1489 if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
1490 break;
1491 typ = atoi(curr->w_string);
1492 p++;
1493 #ifdef MULTIUSER
1494 if (typ == 83) /* 83 = 'S' */
1496 /* special execute commands sequence */
1497 char *args[MAXARGS];
1498 int argl[MAXARGS];
1499 struct acluser *windowuser;
1501 windowuser = *FindUserPtr(":window:");
1502 if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
1504 for (display = displays; display; display = display->d_next)
1505 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1506 break; /* found it */
1507 if (display == 0 && curr->w_layer.l_cvlist)
1508 display = curr->w_layer.l_cvlist->c_display;
1509 if (display == 0)
1510 display = displays;
1511 EffectiveAclUser = windowuser;
1512 fore = curr;
1513 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1514 DoCommand(args, argl);
1515 EffectiveAclUser = 0;
1516 fore = 0;
1517 flayer = 0;
1519 break;
1521 #endif
1522 #ifdef RXVT_OSC
1523 if (typ == 0 || typ == 1 || typ == 20 || typ == 39 || typ == 49)
1525 int typ2;
1526 typ2 = typ / 10;
1527 if (--typ2 < 0)
1528 typ2 = 0;
1529 if (strcmp(curr->w_xtermosc[typ2], p))
1531 strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
1532 curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
1534 for (display = displays; display; display = display->d_next)
1536 if (!D_CXT)
1537 continue;
1538 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1539 SetXtermOSC(typ2, curr->w_xtermosc[typ2]);
1540 if ((typ2 == 2 || typ2 == 3) && D_xtermosc[typ2])
1541 Redisplay(0);
1545 if (typ != 0 && typ != 2)
1546 break;
1547 #else
1548 if (typ < 0 || typ > 2)
1549 break;
1550 #endif
1552 curr->w_stringp -= p - curr->w_string;
1553 if (curr->w_stringp > curr->w_string)
1554 bcopy(p, curr->w_string, curr->w_stringp - curr->w_string);
1555 *curr->w_stringp = '\0';
1556 /* FALLTHROUGH */
1557 case APC:
1558 if (curr->w_hstatus)
1560 if (strcmp(curr->w_hstatus, curr->w_string) == 0)
1561 break; /* not changed */
1562 free(curr->w_hstatus);
1563 curr->w_hstatus = 0;
1565 if (curr->w_string != curr->w_stringp)
1566 curr->w_hstatus = SaveStr(curr->w_string);
1567 WindowChanged(curr, 'h');
1568 break;
1569 case PM:
1570 case GM:
1571 for (display = displays; display; display = display->d_next)
1573 for (cv = D_cvlist; cv; cv = cv->c_next)
1574 if (cv->c_layer->l_bottom == &curr->w_layer)
1575 break;
1576 if (cv || curr->w_StringType == GM)
1577 MakeStatus(curr->w_string);
1579 return -1;
1580 case DCS:
1581 LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
1582 break;
1583 case AKA:
1584 if (curr->w_title == curr->w_akabuf && !*curr->w_string)
1585 break;
1586 ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
1587 if (!*curr->w_string)
1588 curr->w_autoaka = curr->w_y + 1;
1589 break;
1590 default:
1591 break;
1593 return 0;
1596 static void
1597 PrintStart()
1599 curr->w_pdisplay = 0;
1601 /* find us a nice display to print on, fore prefered */
1602 display = curr->w_lastdisp;
1603 if (!(display && curr == D_fore && (printcmd || D_PO)))
1604 for (display = displays; display; display = display->d_next)
1605 if (curr == D_fore && (printcmd || D_PO))
1606 break;
1607 if (!display)
1609 struct canvas *cv;
1610 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1612 display = cv->c_display;
1613 if (printcmd || D_PO)
1614 break;
1616 if (!cv)
1618 display = displays;
1619 if (!display || display->d_next || !(printcmd || D_PO))
1620 return;
1623 curr->w_pdisplay = display;
1624 curr->w_stringp = curr->w_string;
1625 curr->w_state = PRIN;
1626 if (printcmd && curr->w_pdisplay->d_printfd < 0)
1627 curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
1630 static void
1631 PrintChar(c)
1632 int c;
1634 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1635 PrintFlush();
1636 *(curr->w_stringp)++ = c;
1639 static void
1640 PrintFlush()
1642 display = curr->w_pdisplay;
1643 if (display && printcmd)
1645 char *bp = curr->w_string;
1646 int len = curr->w_stringp - curr->w_string;
1647 int r;
1648 while (len && display->d_printfd >= 0)
1650 r = write(display->d_printfd, bp, len);
1651 if (r <= 0)
1653 WMsg(curr, errno, "printing aborted");
1654 close(display->d_printfd);
1655 display->d_printfd = -1;
1656 break;
1658 bp += r;
1659 len -= r;
1662 else if (display && curr->w_stringp > curr->w_string)
1664 AddCStr(D_PO);
1665 AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
1666 AddCStr(D_PF);
1667 Flush();
1669 curr->w_stringp = curr->w_string;
1673 void
1674 WNewAutoFlow(win, on)
1675 struct win *win;
1676 int on;
1678 debug1("WNewAutoFlow: %d\n", on);
1679 if (win->w_flow & FLOW_AUTOFLAG)
1680 win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
1681 else
1682 win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
1683 LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
1687 #ifdef FONT
1689 static void
1690 DesignateCharset(c, n)
1691 int c, n;
1693 curr->w_ss = 0;
1694 # ifdef ENCODINGS
1695 if (c == ('@' & 037)) /* map JIS 6226 to 0208 */
1696 c = KANJI;
1697 # endif
1698 if (c == 'B')
1699 c = ASCII;
1700 if (curr->w_charsets[n] != c)
1702 curr->w_charsets[n] = c;
1703 if (curr->w_Charset == n)
1705 curr->w_FontL = c;
1706 curr->w_rend.font = curr->w_FontL;
1707 LSetRendition(&curr->w_layer, &curr->w_rend);
1709 if (curr->w_CharsetR == n)
1710 curr->w_FontR = c;
1714 static void
1715 MapCharset(n)
1716 int n;
1718 curr->w_ss = 0;
1719 if (curr->w_Charset != n)
1721 curr->w_Charset = n;
1722 curr->w_FontL = curr->w_charsets[n];
1723 curr->w_rend.font = curr->w_FontL;
1724 LSetRendition(&curr->w_layer, &curr->w_rend);
1728 static void
1729 MapCharsetR(n)
1730 int n;
1732 curr->w_ss = 0;
1733 if (curr->w_CharsetR != n)
1735 curr->w_CharsetR = n;
1736 curr->w_FontR = curr->w_charsets[n];
1738 curr->w_gr = 1;
1741 #endif /* FONT */
1743 static void
1744 SaveCursor()
1746 curr->w_saved = 1;
1747 curr->w_Saved_x = curr->w_x;
1748 curr->w_Saved_y = curr->w_y;
1749 curr->w_SavedRend = curr->w_rend;
1750 #ifdef FONT
1751 curr->w_SavedCharset = curr->w_Charset;
1752 curr->w_SavedCharsetR = curr->w_CharsetR;
1753 bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
1754 4 * sizeof(int));
1755 #endif
1758 static void
1759 RestoreCursor()
1761 if (!curr->w_saved)
1762 return;
1763 LGotoPos(&curr->w_layer, curr->w_Saved_x, curr->w_Saved_y);
1764 curr->w_x = curr->w_Saved_x;
1765 curr->w_y = curr->w_Saved_y;
1766 curr->w_rend = curr->w_SavedRend;
1767 #ifdef FONT
1768 bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
1769 4 * sizeof(int));
1770 curr->w_Charset = curr->w_SavedCharset;
1771 curr->w_CharsetR = curr->w_SavedCharsetR;
1772 curr->w_ss = 0;
1773 curr->w_FontL = curr->w_charsets[curr->w_Charset];
1774 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
1775 #endif
1776 LSetRendition(&curr->w_layer, &curr->w_rend);
1779 static void
1780 BackSpace()
1782 if (curr->w_x > 0)
1784 curr->w_x--;
1786 else if (curr->w_wrap && curr->w_y > 0)
1788 curr->w_x = cols - 1;
1789 curr->w_y--;
1791 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1794 static void
1795 Return()
1797 if (curr->w_x == 0)
1798 return;
1799 curr->w_x = 0;
1800 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1803 static void
1804 LineFeed(out_mode)
1805 int out_mode;
1807 /* out_mode: 0=lf, 1=cr+lf */
1808 if (out_mode)
1809 curr->w_x = 0;
1810 if (curr->w_y != curr->w_bot) /* Don't scroll */
1812 if (curr->w_y < rows-1)
1813 curr->w_y++;
1814 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1815 return;
1817 if (curr->w_autoaka > 1)
1818 curr->w_autoaka--;
1819 MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
1820 LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
1821 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1824 static void
1825 ReverseLineFeed()
1827 if (curr->w_y == curr->w_top)
1829 MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
1830 LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
1831 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1833 else if (curr->w_y > 0)
1834 CursorUp(1);
1837 static void
1838 InsertChar(n)
1839 int n;
1841 register int y = curr->w_y, x = curr->w_x;
1843 if (n <= 0)
1844 return;
1845 if (x == cols)
1846 x--;
1847 save_mline(&curr->w_mlines[y], cols);
1848 MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
1849 LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1850 LGotoPos(&curr->w_layer, x, y);
1853 static void
1854 DeleteChar(n)
1855 int n;
1857 register int y = curr->w_y, x = curr->w_x;
1859 if (x == cols)
1860 x--;
1861 save_mline(&curr->w_mlines[y], cols);
1862 MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
1863 LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1864 LGotoPos(&curr->w_layer, x, y);
1867 static void
1868 DeleteLine(n)
1869 int n;
1871 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1872 return;
1873 if (n > curr->w_bot - curr->w_y + 1)
1874 n = curr->w_bot - curr->w_y + 1;
1875 MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
1876 LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
1877 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1880 static void
1881 InsertLine(n)
1882 int n;
1884 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1885 return;
1886 if (n > curr->w_bot - curr->w_y + 1)
1887 n = curr->w_bot - curr->w_y + 1;
1888 MScrollV(curr, -n, curr->w_y, curr->w_bot, CURR_BCE);
1889 LScrollV(&curr->w_layer, -n, curr->w_y, curr->w_bot, CURR_BCE);
1890 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1893 static void
1894 ScrollRegion(n)
1895 int n;
1897 MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
1898 LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
1899 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1903 static void
1904 ForwardTab()
1906 register int x = curr->w_x;
1908 if (x == cols)
1910 LineFeed(1);
1911 x = 0;
1913 if (curr->w_tabs[x] && x < cols - 1)
1914 x++;
1915 while (x < cols - 1 && !curr->w_tabs[x])
1916 x++;
1917 curr->w_x = x;
1918 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1921 static void
1922 BackwardTab()
1924 register int x = curr->w_x;
1926 if (curr->w_tabs[x] && x > 0)
1927 x--;
1928 while (x > 0 && !curr->w_tabs[x])
1929 x--;
1930 curr->w_x = x;
1931 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1934 static void
1935 ClearScreen()
1937 LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
1938 #ifdef COPY_PASTE
1939 MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
1940 #else
1941 MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
1942 #endif
1945 static void
1946 ClearFromBOS()
1948 register int y = curr->w_y, x = curr->w_x;
1950 LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
1951 MClearArea(curr, 0, 0, x, y, CURR_BCE);
1952 RestorePosRendition();
1955 static void
1956 ClearToEOS()
1958 register int y = curr->w_y, x = curr->w_x;
1960 if (x == 0 && y == 0)
1962 ClearScreen();
1963 RestorePosRendition();
1964 return;
1966 LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
1967 MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
1968 RestorePosRendition();
1971 static void
1972 ClearLineRegion(from, to)
1973 int from, to;
1975 register int y = curr->w_y;
1976 LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
1977 MClearArea(curr, from, y, to, y, CURR_BCE);
1978 RestorePosRendition();
1981 static void
1982 CursorRight(n)
1983 register int n;
1985 register int x = curr->w_x;
1987 if (x == cols)
1989 LineFeed(1);
1990 x = 0;
1992 if ((curr->w_x += n) >= cols)
1993 curr->w_x = cols - 1;
1994 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1997 static void
1998 CursorUp(n)
1999 register int n;
2001 if (curr->w_y < curr->w_top) /* if above scrolling rgn, */
2003 if ((curr->w_y -= n) < 0) /* ignore its limits */
2004 curr->w_y = 0;
2006 else
2007 if ((curr->w_y -= n) < curr->w_top)
2008 curr->w_y = curr->w_top;
2009 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2012 static void
2013 CursorDown(n)
2014 register int n;
2016 if (curr->w_y > curr->w_bot) /* if below scrolling rgn, */
2018 if ((curr->w_y += n) > rows - 1) /* ignore its limits */
2019 curr->w_y = rows - 1;
2021 else
2022 if ((curr->w_y += n) > curr->w_bot)
2023 curr->w_y = curr->w_bot;
2024 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2027 static void
2028 CursorLeft(n)
2029 register int n;
2031 if ((curr->w_x -= n) < 0)
2032 curr->w_x = 0;
2033 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2036 static void
2037 ASetMode(on)
2038 int on;
2040 register int i;
2042 for (i = 0; i < curr->w_NumArgs; ++i)
2044 switch (curr->w_args[i])
2046 /* case 2: KAM: Lock keyboard */
2047 case 4: /* IRM: Insert mode */
2048 curr->w_insert = on;
2049 LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
2050 break;
2051 /* case 12: SRM: Echo mode on */
2052 case 20: /* LNM: Linefeed mode */
2053 curr->w_autolf = on;
2054 break;
2055 case 34:
2056 curr->w_curvvis = !on;
2057 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
2058 break;
2059 default:
2060 break;
2065 static char rendlist[] =
2067 ~((1 << NATTR) - 1), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
2068 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2069 0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
2072 static void
2073 SelectRendition()
2075 #ifdef COLOR
2076 register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
2077 # ifdef COLORS256
2078 int cx = curr->w_rend.colorx;
2079 # endif
2080 #else
2081 register int j, i = 0, a = curr->w_rend.attr;
2082 #endif
2086 j = curr->w_args[i];
2087 #ifdef COLOR
2088 if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
2090 int jj;
2092 i += 2;
2093 jj = curr->w_args[i];
2094 if (jj < 0 || jj > 255)
2095 continue;
2096 # ifdef COLORS256
2097 if (j == 38)
2099 c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
2100 a |= A_BFG;
2101 if (jj >= 8 && jj < 16)
2102 c |= 0x08;
2103 else
2104 a ^= A_BFG;
2105 a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
2106 cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
2108 else
2110 c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
2111 a |= A_BBG;
2112 if (jj >= 8 && jj < 16)
2113 c |= 0x80;
2114 else
2115 a ^= A_BBG;
2116 cx = (cx & 0x0f) | (jj & 0xf0);
2118 continue;
2119 # else
2120 jj = color256to16(jj) + 30;
2121 if (jj >= 38)
2122 jj += 60 - 8;
2123 j = j == 38 ? jj : jj + 10;
2124 # endif
2126 # ifdef COLORS16
2127 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2128 a &= 0xbf;
2129 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2130 a &= 0x7f;
2131 if (j >= 90 && j <= 97)
2132 a |= 0x40;
2133 if (j >= 100 && j <= 107)
2134 a |= 0x80;
2135 # endif
2136 if (j >= 90 && j <= 97)
2137 j -= 60;
2138 if (j >= 100 && j <= 107)
2139 j -= 60;
2140 if (j >= 30 && j <= 39 && j != 38)
2141 c = (c & 0xf0) | ((j - 30) ^ 9);
2142 else if (j >= 40 && j <= 49 && j != 48)
2143 c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
2144 if (j == 0)
2145 c = 0;
2146 # ifdef COLORS256
2147 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2148 cx &= 0xf0;
2149 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2150 cx &= 0x0f;
2151 # endif
2152 #endif
2153 if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
2154 continue;
2155 j = rendlist[j];
2156 if (j & (1 << NATTR))
2157 a &= j;
2158 else
2159 a |= j;
2161 while (++i < curr->w_NumArgs);
2162 curr->w_rend.attr = a;
2163 #ifdef COLOR
2164 curr->w_rend.color = c;
2165 # ifdef COLORS256
2166 curr->w_rend.colorx = cx;
2167 # endif
2168 #endif
2169 LSetRendition(&curr->w_layer, &curr->w_rend);
2172 static void
2173 FillWithEs()
2175 register int i;
2176 register unsigned char *p, *ep;
2178 LClearAll(&curr->w_layer, 1);
2179 curr->w_y = curr->w_x = 0;
2180 for (i = 0; i < rows; ++i)
2182 clear_mline(&curr->w_mlines[i], 0, cols + 1);
2183 p = curr->w_mlines[i].image;
2184 ep = p + cols;
2185 while (p < ep)
2186 *p++ = 'E';
2188 LRefreshAll(&curr->w_layer, 1);
2193 * Ugly autoaka hack support:
2194 * ChangeAKA() sets a new aka
2195 * FindAKA() searches for an autoaka match
2198 void
2199 ChangeAKA(p, s, l)
2200 struct win *p;
2201 char *s;
2202 int l;
2204 int i, c;
2206 for (i = 0; l > 0; l--)
2208 if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
2209 break;
2210 c = (unsigned char)*s++;
2211 if (c == 0)
2212 break;
2213 if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
2214 continue;
2215 p->w_akachange[i++] = c;
2217 p->w_akachange[i] = 0;
2218 p->w_title = p->w_akachange;
2219 if (p->w_akachange != p->w_akabuf)
2220 if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
2221 p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
2222 WindowChanged(p, 't');
2223 WindowChanged((struct win *)0, 'w');
2224 WindowChanged((struct win *)0, 'W');
2227 static void
2228 FindAKA()
2230 register unsigned char *cp, *line;
2231 register struct win *wp = curr;
2232 register int len = strlen(wp->w_akabuf);
2233 int y;
2235 y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
2236 cols = wp->w_width;
2237 try_line:
2238 cp = line = wp->w_mlines[y].image;
2239 if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
2241 for (;;)
2243 if (cp - line >= cols - len)
2245 if (++y == wp->w_autoaka && y < rows)
2246 goto try_line;
2247 return;
2249 if (strncmp((char *)cp, wp->w_akabuf, len) == 0)
2250 break;
2251 cp++;
2253 cp += len;
2255 for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
2257 if (len)
2259 if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
2260 wp->w_autoaka = -1;
2261 else
2262 wp->w_autoaka = 0;
2263 line = cp;
2264 while (len && *cp != ' ')
2266 if (*cp++ == '/')
2267 line = cp;
2268 len--;
2270 ChangeAKA(wp, (char *)line, cp - line);
2272 else
2273 wp->w_autoaka = 0;
2276 static void
2277 RestorePosRendition()
2279 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2280 LSetRendition(&curr->w_layer, &curr->w_rend);
2283 /* Send a terminal report as if it were typed. */
2284 static void
2285 Report(fmt, n1, n2)
2286 char *fmt;
2287 int n1, n2;
2289 register int len;
2290 char rbuf[40]; /* enough room for all replys */
2292 sprintf(rbuf, fmt, n1, n2);
2293 len = strlen(rbuf);
2295 if (W_UWP(curr))
2297 if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
2299 bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
2300 curr->w_pwin->p_inlen += len;
2303 else
2305 if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
2307 bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
2308 curr->w_inlen += len;
2316 *====================================================================*
2317 *====================================================================*
2320 /**********************************************************************
2322 * Memory subsystem.
2326 static void
2327 MFixLine(p, y, mc)
2328 struct win *p;
2329 int y;
2330 struct mchar *mc;
2332 struct mline *ml = &p->w_mlines[y];
2333 if (mc->attr && ml->attr == null)
2335 if ((ml->attr = (unsigned char *)malloc(p->w_width + 1)) == 0)
2337 ml->attr = null;
2338 mc->attr = p->w_rend.attr = 0;
2339 WMsg(p, 0, "Warning: no space for attr - turned off");
2341 bzero((char *)ml->attr, p->w_width + 1);
2343 #ifdef FONT
2344 if (mc->font && ml->font == null)
2346 if ((ml->font = (unsigned char *)malloc(p->w_width + 1)) == 0)
2348 ml->font = null;
2349 p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
2350 p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
2351 mc->font = p->w_rend.font = 0;
2352 WMsg(p, 0, "Warning: no space for font - turned off");
2354 bzero((char *)ml->font, p->w_width + 1);
2356 #endif
2357 #ifdef COLOR
2358 if (mc->color && ml->color == null)
2360 if ((ml->color = (unsigned char *)malloc(p->w_width + 1)) == 0)
2362 ml->color = null;
2363 mc->color = p->w_rend.color = 0;
2364 WMsg(p, 0, "Warning: no space for color - turned off");
2366 bzero((char *)ml->color, p->w_width + 1);
2368 # ifdef COLORS256
2369 if (mc->colorx && ml->colorx == null)
2371 if ((ml->colorx = (unsigned char *)malloc(p->w_width + 1)) == 0)
2373 ml->colorx = null;
2374 mc->colorx = p->w_rend.colorx = 0;
2375 WMsg(p, 0, "Warning: no space for extended colors - turned off");
2377 bzero((char *)ml->colorx, p->w_width + 1);
2379 # endif
2380 #endif
2383 /*****************************************************************/
2385 #ifdef DW_CHARS
2386 # define MKillDwRight(p, ml, x) \
2387 if (dw_right(ml, x, p->w_encoding)) \
2389 if (x > 0) \
2390 copy_mchar2mline(&mchar_blank, ml, x - 1); \
2391 copy_mchar2mline(&mchar_blank, ml, x); \
2394 # define MKillDwLeft(p, ml, x) \
2395 if (dw_left(ml, x, p->w_encoding)) \
2397 copy_mchar2mline(&mchar_blank, ml, x); \
2398 copy_mchar2mline(&mchar_blank, ml, x + 1); \
2400 #else
2401 # define MKillDwRight(p, ml, x) ;
2402 # define MKillDwLeft(p, ml, x) ;
2403 #endif
2405 static void
2406 MScrollH(p, n, y, xs, xe, bce)
2407 struct win *p;
2408 int n, y, xs, xe, bce;
2410 struct mline *ml;
2412 if (n == 0)
2413 return;
2414 ml = &p->w_mlines[y];
2415 MKillDwRight(p, ml, xs);
2416 MKillDwLeft(p, ml, xe);
2417 if (n > 0)
2419 if (xe - xs + 1 > n)
2421 MKillDwRight(p, ml, xs + n);
2422 bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
2424 else
2425 n = xe - xs + 1;
2426 clear_mline(ml, xe + 1 - n, n);
2427 #ifdef COLOR
2428 if (bce)
2429 MBceLine(p, y, xe + 1 - n, n, bce);
2430 #endif
2432 else
2434 n = -n;
2435 if (xe - xs + 1 > n)
2437 MKillDwLeft(p, ml, xe - n);
2438 bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
2440 else
2441 n = xe - xs + 1;
2442 clear_mline(ml, xs, n);
2443 #ifdef COLOR
2444 if (bce)
2445 MBceLine(p, y, xs, n, bce);
2446 #endif
2450 static void
2451 MScrollV(p, n, ys, ye, bce)
2452 struct win *p;
2453 int n, ys, ye, bce;
2455 int i, cnt1, cnt2;
2456 struct mline tmp[256];
2457 struct mline *ml;
2459 if (n == 0)
2460 return;
2461 if (n > 0)
2463 if (n > 256)
2465 MScrollV(p, n - 256, ys, ye, bce);
2466 n = 256;
2468 if (ye - ys + 1 < n)
2469 n = ye - ys + 1;
2470 #ifdef COPY_PASTE
2471 if (compacthist)
2473 ye = MFindUsedLine(p, ye, ys);
2474 if (ye - ys + 1 < n)
2475 n = ye - ys + 1;
2476 if (n <= 0)
2477 return;
2479 #endif
2480 /* Clear lines */
2481 ml = p->w_mlines + ys;
2482 for (i = ys; i < ys + n; i++, ml++)
2484 #ifdef COPY_PASTE
2485 if (ys == p->w_top)
2486 WAddLineToHist(p, ml);
2487 #endif
2488 if (ml->attr != null)
2489 free(ml->attr);
2490 ml->attr = null;
2491 #ifdef FONT
2492 if (ml->font != null)
2493 free(ml->font);
2494 ml->font = null;
2495 #endif
2496 #ifdef COLOR
2497 if (ml->color != null)
2498 free(ml->color);
2499 ml->color = null;
2500 # ifdef COLORS256
2501 if (ml->colorx != null)
2502 free(ml->colorx);
2503 ml->colorx = null;
2504 # endif
2505 #endif
2506 bclear((char *)ml->image, p->w_width + 1);
2507 #ifdef COLOR
2508 if (bce)
2509 MBceLine(p, i, 0, p->w_width, bce);
2510 #endif
2512 /* switch 'em over */
2513 cnt1 = n * sizeof(struct mline);
2514 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2515 if (cnt1 && cnt2)
2516 Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
2518 else
2520 if (n < -256)
2522 MScrollV(p, n + 256, ys, ye, bce);
2523 n = -256;
2525 n = -n;
2526 if (ye - ys + 1 < n)
2527 n = ye - ys + 1;
2529 ml = p->w_mlines + ye;
2530 /* Clear lines */
2531 for (i = ye; i > ye - n; i--, ml--)
2533 if (ml->attr != null)
2534 free(ml->attr);
2535 ml->attr = null;
2536 #ifdef FONT
2537 if (ml->font != null)
2538 free(ml->font);
2539 ml->font = null;
2540 #endif
2541 #ifdef COLOR
2542 if (ml->color != null)
2543 free(ml->color);
2544 ml->color = null;
2545 # ifdef COLORS256
2546 if (ml->colorx != null)
2547 free(ml->colorx);
2548 ml->colorx = null;
2549 # endif
2550 #endif
2551 bclear((char *)ml->image, p->w_width + 1);
2552 #ifdef COLOR
2553 if (bce)
2554 MBceLine(p, i, 0, p->w_width, bce);
2555 #endif
2557 cnt1 = n * sizeof(struct mline);
2558 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2559 if (cnt1 && cnt2)
2560 Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
2564 static void
2565 Scroll(cp, cnt1, cnt2, tmp)
2566 char *cp, *tmp;
2567 int cnt1, cnt2;
2569 if (!cnt1 || !cnt2)
2570 return;
2571 if (cnt1 <= cnt2)
2573 bcopy(cp, tmp, cnt1);
2574 bcopy(cp + cnt1, cp, cnt2);
2575 bcopy(tmp, cp + cnt2, cnt1);
2577 else
2579 bcopy(cp + cnt1, tmp, cnt2);
2580 bcopy(cp, cp + cnt2, cnt1);
2581 bcopy(tmp, cp, cnt2);
2585 static void
2586 MClearArea(p, xs, ys, xe, ye, bce)
2587 struct win *p;
2588 int xs, ys, xe, ye, bce;
2590 int n, y;
2591 int xxe;
2592 struct mline *ml;
2594 /* check for magic margin condition */
2595 if (xs >= p->w_width)
2596 xs = p->w_width - 1;
2597 if (xe >= p->w_width)
2598 xe = p->w_width - 1;
2600 MKillDwRight(p, p->w_mlines + ys, xs);
2601 MKillDwLeft(p, p->w_mlines + ye, xe);
2603 ml = p->w_mlines + ys;
2604 for (y = ys; y <= ye; y++, ml++)
2606 xxe = (y == ye) ? xe : p->w_width - 1;
2607 n = xxe - xs + 1;
2608 if (n > 0)
2609 clear_mline(ml, xs, n);
2610 #ifdef COLOR
2611 if (n > 0 && bce)
2612 MBceLine(p, y, xs, xs + n - 1, bce);
2613 #endif
2614 xs = 0;
2618 static void
2619 MInsChar(p, c, x, y)
2620 struct win *p;
2621 struct mchar *c;
2622 int x, y;
2624 int n;
2625 struct mline *ml;
2627 ASSERT(x >= 0 && x < p->w_width);
2628 MFixLine(p, y, c);
2629 ml = p->w_mlines + y;
2630 n = p->w_width - x - 1;
2631 MKillDwRight(p, ml, x);
2632 if (n > 0)
2634 MKillDwRight(p, ml, p->w_width - 1);
2635 bcopy_mline(ml, x, x + 1, n);
2637 copy_mchar2mline(c, ml, x);
2638 #ifdef DW_CHARS
2639 if (c->mbcs)
2641 if (--n > 0)
2643 MKillDwRight(p, ml, p->w_width - 1);
2644 bcopy_mline(ml, x + 1, x + 2, n);
2646 copy_mchar2mline(c, ml, x + 1);
2647 ml->image[x + 1] = c->mbcs;
2648 # ifdef UTF8
2649 if (p->w_encoding != UTF8)
2650 ml->font[x + 1] |= 0x80;
2651 else if (p->w_encoding == UTF8 && c->mbcs)
2652 ml->font[x + 1] = c->mbcs;
2653 # else
2654 ml->font[x + 1] |= 0x80;
2655 # endif
2657 #endif
2660 static void
2661 MPutChar(p, c, x, y)
2662 struct win *p;
2663 struct mchar *c;
2664 int x, y;
2666 struct mline *ml;
2668 MFixLine(p, y, c);
2669 ml = &p->w_mlines[y];
2670 MKillDwRight(p, ml, x);
2671 MKillDwLeft(p, ml, x);
2672 copy_mchar2mline(c, ml, x);
2673 #ifdef DW_CHARS
2674 if (c->mbcs)
2676 MKillDwLeft(p, ml, x + 1);
2677 copy_mchar2mline(c, ml, x + 1);
2678 ml->image[x + 1] = c->mbcs;
2679 # ifdef UTF8
2680 if (p->w_encoding != UTF8)
2681 ml->font[x + 1] |= 0x80;
2682 else if (p->w_encoding == UTF8 && c->mbcs)
2683 ml->font[x + 1] = c->mbcs;
2684 # else
2685 ml->font[x + 1] |= 0x80;
2686 # endif
2688 #endif
2692 static void
2693 MWrapChar(p, c, y, top, bot, ins)
2694 struct win *p;
2695 struct mchar *c;
2696 int y, top, bot;
2697 int ins;
2699 struct mline *ml;
2700 int bce;
2702 #ifdef COLOR
2703 bce = rend_getbg(c);
2704 #else
2705 bce = 0;
2706 #endif
2707 MFixLine(p, y, c);
2708 ml = &p->w_mlines[y];
2709 copy_mchar2mline(&mchar_null, ml, p->w_width);
2710 if (y == bot)
2711 MScrollV(p, 1, top, bot, bce);
2712 else if (y < p->w_height - 1)
2713 y++;
2714 if (ins)
2715 MInsChar(p, c, 0, y);
2716 else
2717 MPutChar(p, c, 0, y);
2720 static void
2721 MPutStr(p, s, n, r, x, y)
2722 struct win *p;
2723 char *s;
2724 int n;
2725 struct mchar *r;
2726 int x, y;
2728 struct mline *ml;
2729 int i;
2730 unsigned char *b;
2732 if (n <= 0)
2733 return;
2734 MFixLine(p, y, r);
2735 ml = &p->w_mlines[y];
2736 MKillDwRight(p, ml, x);
2737 MKillDwLeft(p, ml, x + n - 1);
2738 bcopy(s, (char *)ml->image + x, n);
2739 b = ml->attr + x;
2740 for (i = n; i-- > 0;)
2741 *b++ = r->attr;
2742 #ifdef FONT
2743 b = ml->font + x;
2744 for (i = n; i-- > 0;)
2745 *b++ = r->font;
2746 #endif
2747 #ifdef COLOR
2748 b = ml->color + x;
2749 for (i = n; i-- > 0;)
2750 *b++ = r->color;
2751 # ifdef COLORS256
2752 b = ml->colorx + x;
2753 for (i = n; i-- > 0;)
2754 *b++ = r->colorx;
2755 # endif
2756 #endif
2759 #ifdef COLOR
2760 static void
2761 MBceLine(p, y, xs, xe, bce)
2762 struct win *p;
2763 int y, xs, xe, bce;
2765 struct mchar mc;
2766 struct mline *ml;
2767 int x;
2769 mc = mchar_null;
2770 rend_setbg(&mc, bce);
2771 MFixLine(p, y, &mc);
2772 ml = p->w_mlines + y;
2773 # ifdef COLORS16
2774 if (mc.attr)
2775 for (x = xs; x <= xe; x++)
2776 ml->attr[x] = mc.attr;
2777 # endif
2778 if (mc.color)
2779 for (x = xs; x <= xe; x++)
2780 ml->color[x] = mc.color;
2781 # ifdef COLORS256
2782 if (mc.colorx)
2783 for (x = xs; x <= xe; x++)
2784 ml->colorx[x] = mc.colorx;
2785 # endif
2787 #endif
2790 #ifdef COPY_PASTE
2791 static void
2792 WAddLineToHist(wp, ml)
2793 struct win *wp;
2794 struct mline *ml;
2796 register unsigned char *q, *o;
2797 struct mline *hml;
2799 if (wp->w_histheight == 0)
2800 return;
2801 hml = &wp->w_hlines[wp->w_histidx];
2802 q = ml->image; ml->image = hml->image; hml->image = q;
2804 q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
2805 if (o != null)
2806 free(o);
2808 #ifdef FONT
2809 q = ml->font; o = hml->font; hml->font = q; ml->font = null;
2810 if (o != null)
2811 free(o);
2812 #endif
2814 #ifdef COLOR
2815 q = ml->color; o = hml->color; hml->color = q; ml->color = null;
2816 if (o != null)
2817 free(o);
2818 # ifdef COLORS256
2819 q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
2820 if (o != null)
2821 free(o);
2822 # endif
2823 #endif
2825 if (++wp->w_histidx >= wp->w_histheight)
2826 wp->w_histidx = 0;
2828 #endif
2831 MFindUsedLine(p, ye, ys)
2832 struct win *p;
2833 int ys, ye;
2835 int y;
2836 struct mline *ml = p->w_mlines + ye;
2838 debug2("MFindUsedLine: %d %d\n", ye, ys);
2839 for (y = ye; y >= ys; y--, ml--)
2841 if (bcmp((char*)ml->image, blank, p->w_width))
2842 break;
2843 if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
2844 break;
2845 #ifdef COLOR
2846 if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
2847 break;
2848 # ifdef COLORS256
2849 if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
2850 break;
2851 # endif
2852 #endif
2854 debug1("MFindUsedLine returning %d\n", y);
2855 return y;
2860 *====================================================================*
2861 *====================================================================*
2865 * Tricky: send only one bell even if the window is displayed
2866 * more than once.
2868 void
2869 WBell(p, visual)
2870 struct win *p;
2871 int visual;
2873 struct canvas *cv;
2874 for (display = displays; display; display = display->d_next)
2876 for (cv = D_cvlist; cv; cv = cv->c_next)
2877 if (cv->c_layer->l_bottom == &p->w_layer)
2878 break;
2879 if (cv && !visual)
2880 AddCStr(D_BL);
2881 else if (cv && D_VB)
2882 AddCStr(D_VB);
2883 else
2884 p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
2889 * This should be reverse video.
2890 * Only change video if window is fore.
2891 * Because it is used in some termcaps to emulate
2892 * a visual bell we do this hack here.
2893 * (screen uses \Eg as special vbell sequence)
2895 static void
2896 WReverseVideo(p, on)
2897 struct win *p;
2898 int on;
2900 struct canvas *cv;
2901 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2903 display = cv->c_display;
2904 if (cv != D_forecv)
2905 continue;
2906 ReverseVideo(on);
2907 if (!on && p->w_revvid && !D_CVR)
2909 if (D_VB)
2910 AddCStr(D_VB);
2911 else
2912 p->w_bell = BELL_VISUAL;
2917 void
2918 WMsg(p, err, str)
2919 struct win *p;
2920 int err;
2921 char *str;
2923 extern struct layer *flayer;
2924 struct layer *oldflayer = flayer;
2925 flayer = &p->w_layer;
2926 LMsg(err, str);
2927 flayer = oldflayer;
2930 void
2931 WChangeSize(p, w, h)
2932 struct win *p;
2933 int w, h;
2935 int wok = 0;
2936 struct canvas *cv;
2938 if (p->w_layer.l_cvlist == 0)
2940 /* window not displayed -> works always */
2941 ChangeWindowSize(p, w, h, p->w_histheight);
2942 return;
2944 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2946 display = cv->c_display;
2947 if (p != D_fore)
2948 continue; /* change only fore */
2949 if (D_CWS)
2950 break;
2951 if (D_CZ0 && (w == Z0width || w == Z1width))
2952 wok = 1;
2954 if (cv == 0 && wok == 0) /* can't change any display */
2955 return;
2956 if (!D_CWS)
2957 h = p->w_height;
2958 ChangeWindowSize(p, w, h, p->w_histheight);
2959 for (display = displays; display; display = display->d_next)
2961 if (p == D_fore)
2963 if (D_cvlist && D_cvlist->c_next == 0)
2964 ResizeDisplay(w, h);
2965 else
2966 ResizeDisplay(w, D_height);
2967 ResizeLayersToCanvases(); /* XXX Hmm ? */
2968 continue;
2970 for (cv = D_cvlist; cv; cv = cv->c_next)
2971 if (cv->c_layer->l_bottom == &p->w_layer)
2972 break;
2973 if (cv)
2974 Redisplay(0);
2978 static int
2979 WindowChangedCheck(s, what, hp)
2980 char *s;
2981 int what;
2982 int *hp;
2984 int h = 0;
2985 int l;
2986 while(*s)
2988 if (*s++ != (hp ? '%' : '\005'))
2989 continue;
2990 l = 0;
2991 s += (*s == '+');
2992 s += (*s == '-');
2993 while (*s >= '0' && *s <= '9')
2994 s++;
2995 if (*s == 'L')
2997 s++;
2998 l = 0x100;
3000 if (*s == 'h')
3001 h = 1;
3002 if (*s == what || ((*s | l) == what) || what == 'd')
3003 break;
3004 if (*s)
3005 s++;
3007 if (hp)
3008 *hp = h;
3009 return *s ? 1 : 0;
3012 void
3013 WindowChanged(p, what)
3014 struct win *p;
3015 int what;
3017 int inwstr, inhstr, inlstr;
3018 int inwstrh = 0, inhstrh = 0, inlstrh = 0;
3019 int got, ox, oy;
3020 struct display *olddisplay = display;
3021 struct canvas *cv;
3023 inwstr = inhstr = 0;
3025 if (what == 'f')
3027 WindowChanged((struct win *)0, 'w'|0x100);
3028 WindowChanged((struct win *)0, 'W'|0x100);
3031 if (what)
3033 inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
3034 inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
3035 inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
3037 else
3039 inwstr = inhstr = 0;
3040 inlstr = 1;
3043 if (p == 0)
3045 for (display = displays; display; display = display->d_next)
3047 ox = D_x;
3048 oy = D_y;
3049 for (cv = D_cvlist; cv; cv = cv->c_next)
3051 if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3052 WListUpdatecv(cv, (struct win *)0);
3053 p = Layer2Window(cv->c_layer);
3054 if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3055 if (cv->c_ye + 1 < D_height)
3056 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3058 p = D_fore;
3059 if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3060 RefreshHStatus();
3061 if (ox != -1 && ox != -1)
3062 GotoPos(ox, oy);
3064 display = olddisplay;
3065 return;
3068 if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
3070 inwstr |= inwstrh;
3071 inhstr |= inhstrh;
3072 inlstr |= inlstrh;
3074 if (!inwstr && !inhstr && !inlstr)
3075 return;
3076 for (display = displays; display; display = display->d_next)
3078 got = 0;
3079 ox = D_x;
3080 oy = D_y;
3081 for (cv = D_cvlist; cv; cv = cv->c_next)
3083 if (inlstr)
3084 WListUpdatecv(cv, p);
3085 if (Layer2Window(cv->c_layer) != p)
3086 continue;
3087 got = 1;
3088 if (inwstr && cv->c_ye + 1 < D_height)
3089 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3091 if (got && inhstr && p == D_fore)
3092 RefreshHStatus();
3093 if (ox != -1 && ox != -1)
3094 GotoPos(ox, oy);
3096 display = olddisplay;