Just use string.h, strings.h if they're available.
[screen-lua.git] / src / ansi.c
blobd6952ea6e7ab7595bcac126704df12bc1c03264d
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;
325 c = (unsigned char)*buf++;
326 #ifdef FONT
327 # ifdef DW_CHARS
328 if (!curr->w_mbcs)
329 # endif
330 curr->w_rend.font = curr->w_FontL; /* Default: GL */
331 #endif
333 /* The next part is only for speedup */
334 if (curr->w_state == LIT &&
335 #ifdef UTF8
336 curr->w_encoding != UTF8 &&
337 #endif
338 #ifdef DW_CHARS
339 !is_dw_font(curr->w_rend.font) &&
340 # ifdef ENCODINGS
341 curr->w_rend.font != KANA && !curr->w_mbcs &&
342 # endif
343 #endif
344 #ifdef FONT
345 curr->w_rend.font != '<' &&
346 #endif
347 c >= ' ' && c != 0x7f &&
348 ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) && !curr->w_ss &&
349 !curr->w_insert && curr->w_x < cols - 1)
351 register int currx = curr->w_x;
352 char *imp = buf - 1;
354 while (currx < cols - 1)
356 currx++;
357 if (--len == 0)
358 break;
359 c = (unsigned char)*buf++;
360 if (c < ' ' || c == 0x7f || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
361 break;
363 currx -= curr->w_x;
364 if (currx > 0)
366 MPutStr(curr, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
367 LPutStr(&curr->w_layer, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
368 curr->w_x += currx;
370 if (len == 0)
371 break;
373 /* end of speedup code */
375 #ifdef UTF8
376 if (curr->w_encoding == UTF8)
378 c = FromUtf8(c, &curr->w_decodestate);
379 if (c == -1)
380 continue;
381 if (c == -2)
383 c = UCS_REPL;
384 /* try char again */
385 buf--;
386 len++;
388 if (c > 0xff)
389 debug1("read UNICODE %04x\n", c);
391 #endif
393 tryagain:
394 switch (curr->w_state)
396 case PRIN:
397 switch (c)
399 case '\033':
400 curr->w_state = PRINESC;
401 break;
402 default:
403 PrintChar(c);
405 break;
406 case PRINESC:
407 switch (c)
409 case '[':
410 curr->w_state = PRINCSI;
411 break;
412 default:
413 PrintChar('\033');
414 PrintChar(c);
415 curr->w_state = PRIN;
417 break;
418 case PRINCSI:
419 switch (c)
421 case '4':
422 curr->w_state = PRIN4;
423 break;
424 default:
425 PrintChar('\033');
426 PrintChar('[');
427 PrintChar(c);
428 curr->w_state = PRIN;
430 break;
431 case PRIN4:
432 switch (c)
434 case 'i':
435 curr->w_state = LIT;
436 PrintFlush();
437 if (curr->w_pdisplay && curr->w_pdisplay->d_printfd >= 0)
439 close(curr->w_pdisplay->d_printfd);
440 curr->w_pdisplay->d_printfd = -1;
442 curr->w_pdisplay = 0;
443 break;
444 default:
445 PrintChar('\033');
446 PrintChar('[');
447 PrintChar('4');
448 PrintChar(c);
449 curr->w_state = PRIN;
451 break;
452 case ASTR:
453 if (c == 0)
454 break;
455 if (c == '\033')
457 curr->w_state = STRESC;
458 break;
460 /* special xterm hack: accept SetStatus sequence. Yucc! */
461 /* allow ^E for title escapes */
462 if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
463 if (!curr->w_c1 || c != ('\\' ^ 0xc0))
465 StringChar(c);
466 break;
468 c = '\\';
469 /* FALLTHROUGH */
470 case STRESC:
471 switch (c)
473 case '\\':
474 if (StringEnd() == 0 || len <= 1)
475 break;
476 /* check if somewhere a status is displayed */
477 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
479 display = cv->c_display;
480 if (D_status == STATUS_ON_WIN)
481 break;
483 if (cv)
485 if (len > IOSIZE + 1)
486 len = IOSIZE + 1;
487 curr->w_outlen = len - 1;
488 bcopy(buf, curr->w_outbuf, len - 1);
489 return; /* wait till status is gone */
491 break;
492 case '\033':
493 StringChar('\033');
494 break;
495 default:
496 curr->w_state = ASTR;
497 StringChar('\033');
498 StringChar(c);
499 break;
501 break;
502 case ESC:
503 switch (c)
505 case '[':
506 curr->w_NumArgs = 0;
507 curr->w_intermediate = 0;
508 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
509 curr->w_state = CSI;
510 break;
511 case ']':
512 StringStart(OSC);
513 break;
514 case '_':
515 StringStart(APC);
516 break;
517 case 'P':
518 StringStart(DCS);
519 break;
520 case '^':
521 StringStart(PM);
522 break;
523 case '!':
524 StringStart(GM);
525 break;
526 case '"':
527 case 'k':
528 StringStart(AKA);
529 break;
530 default:
531 if (Special(c))
533 curr->w_state = LIT;
534 break;
536 debug1("not special. c = %x\n", c);
537 if (c >= ' ' && c <= '/')
539 if (curr->w_intermediate)
541 #ifdef DW_CHARS
542 if (curr->w_intermediate == '$')
543 c |= '$' << 8;
544 else
545 #endif
546 c = -1;
548 curr->w_intermediate = c;
550 else if (c >= '0' && c <= '~')
552 DoESC(c, curr->w_intermediate);
553 curr->w_state = LIT;
555 else
557 curr->w_state = LIT;
558 goto tryagain;
561 break;
562 case CSI:
563 switch (c)
565 case '0': case '1': case '2': case '3': case '4':
566 case '5': case '6': case '7': case '8': case '9':
567 if (curr->w_NumArgs < MAXARGS)
569 if (curr->w_args[curr->w_NumArgs] < 100000000)
570 curr->w_args[curr->w_NumArgs] =
571 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
573 break;
574 case ';':
575 case ':':
576 if (curr->w_NumArgs < MAXARGS)
577 curr->w_NumArgs++;
578 break;
579 default:
580 if (Special(c))
581 break;
582 if (c >= '@' && c <= '~')
584 if (curr->w_NumArgs < MAXARGS)
585 curr->w_NumArgs++;
586 DoCSI(c, curr->w_intermediate);
587 if (curr->w_state != PRIN)
588 curr->w_state = LIT;
590 else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
591 curr->w_intermediate = curr->w_intermediate ? -1 : c;
592 else
594 curr->w_state = LIT;
595 goto tryagain;
598 break;
599 case LIT:
600 default:
601 #ifdef DW_CHARS
602 if (curr->w_mbcs)
603 if (c <= ' ' || c == 0x7f || (c >= 0x80 && c < 0xa0 && curr->w_c1))
604 curr->w_mbcs = 0;
605 #endif
606 if (c < ' ')
608 if (c == '\033')
610 curr->w_intermediate = 0;
611 curr->w_state = ESC;
612 if (curr->w_autoaka < 0)
613 curr->w_autoaka = 0;
615 else
616 Special(c);
617 break;
619 if (c >= 0x80 && c < 0xa0 && curr->w_c1)
620 #ifdef FONT
621 if ((curr->w_FontR & 0xf0) != 0x20
622 # ifdef UTF8
623 || curr->w_encoding == UTF8
624 # endif
626 #endif
628 switch (c)
630 case 0xc0 ^ 'D':
631 case 0xc0 ^ 'E':
632 case 0xc0 ^ 'H':
633 case 0xc0 ^ 'M':
634 case 0xc0 ^ 'N': /* SS2 */
635 case 0xc0 ^ 'O': /* SS3 */
636 DoESC(c ^ 0xc0, 0);
637 break;
638 case 0xc0 ^ '[':
639 if (curr->w_autoaka < 0)
640 curr->w_autoaka = 0;
641 curr->w_NumArgs = 0;
642 curr->w_intermediate = 0;
643 bzero((char *) curr->w_args, MAXARGS * sizeof(int));
644 curr->w_state = CSI;
645 break;
646 case 0xc0 ^ 'P':
647 StringStart(DCS);
648 break;
649 default:
650 break;
652 break;
655 #ifdef FONT
656 # ifdef DW_CHARS
657 if (!curr->w_mbcs)
659 # endif
660 if (c < 0x80 || curr->w_gr == 0)
661 curr->w_rend.font = curr->w_FontL;
662 # ifdef ENCODINGS
663 else if (curr->w_gr == 2 && !curr->w_ss)
664 curr->w_rend.font = curr->w_FontE;
665 # endif
666 else
667 curr->w_rend.font = curr->w_FontR;
668 # ifdef DW_CHARS
670 # endif
671 # ifdef UTF8
672 if (curr->w_encoding == UTF8)
674 if (curr->w_rend.font == '0')
676 struct mchar mc, *mcp;
678 debug1("SPECIAL %x\n", c);
679 mc.image = c;
680 mc.mbcs = 0;
681 mc.font = '0';
682 mcp = recode_mchar(&mc, 0, UTF8);
683 debug2("%02x %02x\n", mcp->image, mcp->font);
684 c = mcp->image | mcp->font << 8;
686 curr->w_rend.font = 0;
688 # ifdef DW_CHARS
689 if (curr->w_encoding == UTF8 && utf8_isdouble(c))
690 curr->w_mbcs = 0xff;
691 # endif
692 if (curr->w_encoding == UTF8 && c >= 0x0300 && utf8_iscomb(c))
694 int ox, oy;
695 struct mchar omc;
697 ox = curr->w_x - 1;
698 oy = curr->w_y;
699 if (ox < 0)
701 ox = curr->w_width - 1;
702 oy--;
704 if (oy < 0)
705 oy = 0;
706 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
707 if (omc.image == 0xff && omc.font == 0xff)
709 ox--;
710 if (ox >= 0)
712 copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
713 omc.mbcs = 0xff;
716 if (ox >= 0)
718 utf8_handle_comb(c, &omc);
719 MFixLine(curr, oy, &omc);
720 copy_mchar2mline(&omc, &curr->w_mlines[oy], ox);
721 LPutChar(&curr->w_layer, &omc, ox, oy);
722 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
724 break;
726 font = curr->w_rend.font;
727 # endif
728 # ifdef DW_CHARS
729 # ifdef ENCODINGS
730 if (font == KANA && curr->w_encoding == SJIS && curr->w_mbcs == 0)
732 /* Lets see if it is the first byte of a kanji */
733 debug1("%x may be first of SJIS\n", c);
734 if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
736 debug("YES!\n");
737 curr->w_mbcs = c;
738 break;
741 # endif
742 if (font == 031 && c == 0x80 && !curr->w_mbcs)
743 font = curr->w_rend.font = 0;
744 if (is_dw_font(font) && c == ' ')
745 font = curr->w_rend.font = 0;
746 if (is_dw_font(font) || curr->w_mbcs)
748 int t = c;
749 if (curr->w_mbcs == 0)
751 curr->w_mbcs = c;
752 break;
754 if (curr->w_x == cols - 1)
756 curr->w_x += curr->w_wrap ? 1 : -1;
757 debug1("Patched w_x to %d\n", curr->w_x);
759 # ifdef UTF8
760 if (curr->w_encoding != UTF8)
761 # endif
763 c = curr->w_mbcs;
764 # ifdef ENCODINGS
765 if (font == KANA && curr->w_encoding == SJIS)
767 debug2("SJIS !! %x %x\n", c, t);
769 * SJIS -> EUC mapping:
770 * First byte:
771 * 81,82...9f -> 21,23...5d
772 * e0,e1...ef -> 5f,61...7d
773 * Second byte:
774 * 40-7e -> 21-5f
775 * 80-9e -> 60-7e
776 * 9f-fc -> 21-7e (increment first byte!)
778 if (0x40 <= t && t <= 0xfc && t != 0x7f)
780 if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
781 else c = (c - 0xc1) * 2 + 0x21;
782 if (t <= 0x7e) t -= 0x1f;
783 else if (t <= 0x9e) t -= 0x20;
784 else t -= 0x7e, c++;
785 curr->w_rend.font = KANJI;
787 else
789 /* Incomplete shift-jis - skip first byte */
790 c = t;
791 t = 0;
793 debug2("SJIS after %x %x\n", c, t);
795 # endif
796 if (t && curr->w_gr && font != 030 && font != 031)
798 t &= 0x7f;
799 if (t < ' ')
800 goto tryagain;
802 if (t == '\177')
803 break;
804 curr->w_mbcs = t;
807 # endif /* DW_CHARS */
808 if (font == '<' && c >= ' ')
810 font = curr->w_rend.font = 0;
811 c |= 0x80;
813 # ifdef UTF8
814 else if (curr->w_gr && curr->w_encoding != UTF8)
815 # else
816 else if (curr->w_gr)
817 # endif
819 #ifdef ENCODINGS
820 if (c == 0x80 && font == 0 && curr->w_encoding == GBK)
821 c = 0xa4;
822 else
823 c &= 0x7f;
824 if (c < ' ' && font != 031)
825 goto tryagain;
826 #else
827 c &= 0x7f;
828 if (c < ' ') /* this is ugly but kanji support */
829 goto tryagain; /* prevents nicer programming */
830 #endif
832 #endif /* FONT */
833 if (c == '\177')
834 break;
835 curr->w_rend.image = c;
836 #ifdef UTF8
837 if (curr->w_encoding == UTF8)
838 curr->w_rend.font = c >> 8;
839 #endif
840 #ifdef DW_CHARS
841 curr->w_rend.mbcs = curr->w_mbcs;
842 #endif
843 if (curr->w_x < cols - 1)
845 if (curr->w_insert)
847 save_mline(&curr->w_mlines[curr->w_y], cols);
848 MInsChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
849 LInsChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y, &mline_old);
850 curr->w_x++;
852 else
854 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
855 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
856 curr->w_x++;
859 else if (curr->w_x == cols - 1)
861 MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
862 LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
863 if (curr->w_wrap)
864 curr->w_x++;
866 else
868 MWrapChar(curr, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
869 LWrapChar(&curr->w_layer, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
870 if (curr->w_y != curr->w_bot && curr->w_y != curr->w_height - 1)
871 curr->w_y++;
872 curr->w_x = 1;
874 #ifdef FONT
875 # ifdef DW_CHARS
876 if (curr->w_mbcs)
878 curr->w_rend.mbcs = curr->w_mbcs = 0;
879 curr->w_x++;
881 # endif
882 if (curr->w_ss)
884 curr->w_FontL = curr->w_charsets[curr->w_Charset];
885 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
886 curr->w_rend.font = curr->w_FontL;
887 LSetRendition(&curr->w_layer, &curr->w_rend);
888 curr->w_ss = 0;
890 #endif /* FONT */
891 break;
894 while (--len);
895 if (!printcmd && curr->w_state == PRIN)
896 PrintFlush();
899 static void
900 WLogString(p, buf, len)
901 struct win *p;
902 char *buf;
903 int len;
905 if (!p->w_log)
906 return;
907 if (logtstamp_on && p->w_logsilence >= logtstamp_after * 2)
909 char *t = MakeWinMsg(logtstamp_string, p, '%');
910 logfwrite(p->w_log, t, strlen(t)); /* long time no write */
912 p->w_logsilence = 0;
913 if (logfwrite(p->w_log, buf, len) < 1)
915 WMsg(p, errno, "Error writing logfile");
916 logfclose(p->w_log);
917 p->w_log = 0;
919 if (!log_flush)
920 logfflush(p->w_log);
923 static int
924 Special(c)
925 register int c;
927 switch (c)
929 case '\b':
930 BackSpace();
931 return 1;
932 case '\r':
933 Return();
934 return 1;
935 case '\n':
936 if (curr->w_autoaka)
937 FindAKA();
938 LineFeed(0);
939 return 1;
940 case '\007':
941 WBell(curr, visual_bell);
942 return 1;
943 case '\t':
944 ForwardTab();
945 return 1;
946 #ifdef FONT
947 case '\017': /* SI */
948 MapCharset(G0);
949 return 1;
950 case '\016': /* SO */
951 MapCharset(G1);
952 return 1;
953 #endif
955 return 0;
958 static void
959 DoESC(c, intermediate)
960 int c, intermediate;
962 debug2("DoESC: %x - inter = %x\n", c, intermediate);
963 switch (intermediate)
965 case 0:
966 switch (c)
968 case 'E':
969 LineFeed(1);
970 break;
971 case 'D':
972 LineFeed(0);
973 break;
974 case 'M':
975 ReverseLineFeed();
976 break;
977 case 'H':
978 curr->w_tabs[curr->w_x] = 1;
979 break;
980 case 'Z': /* jph: Identify as VT100 */
981 Report("\033[?%d;%dc", 1, 2);
982 break;
983 case '7':
984 SaveCursor();
985 break;
986 case '8':
987 RestoreCursor();
988 break;
989 case 'c':
990 ClearScreen();
991 ResetWindow(curr);
992 LKeypadMode(&curr->w_layer, 0);
993 LCursorkeysMode(&curr->w_layer, 0);
994 #ifndef TIOCPKT
995 WNewAutoFlow(curr, 1);
996 #endif
997 /* XXX
998 SetRendition(&mchar_null);
999 InsertMode(0);
1000 ChangeScrollRegion(0, rows - 1);
1002 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1003 break;
1004 case '=':
1005 LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
1006 #ifndef TIOCPKT
1007 WNewAutoFlow(curr, 0);
1008 #endif /* !TIOCPKT */
1009 break;
1010 case '>':
1011 LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
1012 #ifndef TIOCPKT
1013 WNewAutoFlow(curr, 1);
1014 #endif /* !TIOCPKT */
1015 break;
1016 #ifdef FONT
1017 case 'n': /* LS2 */
1018 MapCharset(G2);
1019 break;
1020 case 'o': /* LS3 */
1021 MapCharset(G3);
1022 break;
1023 case '~':
1024 MapCharsetR(G1); /* LS1R */
1025 break;
1026 /* { */
1027 case '}':
1028 MapCharsetR(G2); /* LS2R */
1029 break;
1030 case '|':
1031 MapCharsetR(G3); /* LS3R */
1032 break;
1033 case 'N': /* SS2 */
1034 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
1035 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
1036 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
1037 else
1038 curr->w_ss = 0;
1039 break;
1040 case 'O': /* SS3 */
1041 if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
1042 || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
1043 curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
1044 else
1045 curr->w_ss = 0;
1046 break;
1047 #endif /* FONT */
1048 case 'g': /* VBELL, private screen sequence */
1049 WBell(curr, 1);
1050 break;
1052 break;
1053 case '#':
1054 switch (c)
1056 case '8':
1057 FillWithEs();
1058 break;
1060 break;
1061 #ifdef FONT
1062 case '(':
1063 DesignateCharset(c, G0);
1064 break;
1065 case ')':
1066 DesignateCharset(c, G1);
1067 break;
1068 case '*':
1069 DesignateCharset(c, G2);
1070 break;
1071 case '+':
1072 DesignateCharset(c, G3);
1073 break;
1074 # ifdef DW_CHARS
1076 * ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
1077 * ESC $ Fn: same as above. (old sequence)
1078 * ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
1079 * ESC $ * Fn: invoke multi-byte charset, Fn, to G2
1080 * ESC $ + Fn: invoke multi-byte charset, Fn, to G3
1082 case '$':
1083 case '$'<<8 | '(':
1084 DesignateCharset(c & 037, G0);
1085 break;
1086 case '$'<<8 | ')':
1087 DesignateCharset(c & 037, G1);
1088 break;
1089 case '$'<<8 | '*':
1090 DesignateCharset(c & 037, G2);
1091 break;
1092 case '$'<<8 | '+':
1093 DesignateCharset(c & 037, G3);
1094 break;
1095 # endif
1096 #endif /* FONT */
1100 static void
1101 DoCSI(c, intermediate)
1102 int c, intermediate;
1104 register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
1106 if (curr->w_NumArgs > MAXARGS)
1107 curr->w_NumArgs = MAXARGS;
1108 switch (intermediate)
1110 case 0:
1111 switch (c)
1113 case 'H':
1114 case 'f':
1115 if (a1 < 1)
1116 a1 = 1;
1117 if (curr->w_origin)
1118 a1 += curr->w_top;
1119 if (a1 > rows)
1120 a1 = rows;
1121 if (a2 < 1)
1122 a2 = 1;
1123 if (a2 > cols)
1124 a2 = cols;
1125 LGotoPos(&curr->w_layer, --a2, --a1);
1126 curr->w_x = a2;
1127 curr->w_y = a1;
1128 if (curr->w_autoaka)
1129 curr->w_autoaka = a1 + 1;
1130 break;
1131 case 'J':
1132 if (a1 < 0 || a1 > 2)
1133 a1 = 0;
1134 switch (a1)
1136 case 0:
1137 ClearToEOS();
1138 break;
1139 case 1:
1140 ClearFromBOS();
1141 break;
1142 case 2:
1143 ClearScreen();
1144 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1145 break;
1147 break;
1148 case 'K':
1149 if (a1 < 0 || a1 > 2)
1150 a1 %= 3;
1151 switch (a1)
1153 case 0:
1154 ClearLineRegion(curr->w_x, cols - 1);
1155 break;
1156 case 1:
1157 ClearLineRegion(0, curr->w_x);
1158 break;
1159 case 2:
1160 ClearLineRegion(0, cols - 1);
1161 break;
1163 break;
1164 case 'X':
1165 a1 = curr->w_x + (a1 ? a1 - 1 : 0);
1166 ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
1167 break;
1168 case 'A':
1169 CursorUp(a1 ? a1 : 1);
1170 break;
1171 case 'B':
1172 CursorDown(a1 ? a1 : 1);
1173 break;
1174 case 'C':
1175 CursorRight(a1 ? a1 : 1);
1176 break;
1177 case 'D':
1178 CursorLeft(a1 ? a1 : 1);
1179 break;
1180 case 'E':
1181 curr->w_x = 0;
1182 CursorDown(a1 ? a1 : 1); /* positions cursor */
1183 break;
1184 case 'F':
1185 curr->w_x = 0;
1186 CursorUp(a1 ? a1 : 1); /* positions cursor */
1187 break;
1188 case 'G':
1189 case '`': /* HPA */
1190 curr->w_x = a1 ? a1 - 1 : 0;
1191 if (curr->w_x >= cols)
1192 curr->w_x = cols - 1;
1193 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1194 break;
1195 case 'd': /* VPA */
1196 curr->w_y = a1 ? a1 - 1 : 0;
1197 if (curr->w_y >= rows)
1198 curr->w_y = rows - 1;
1199 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1200 break;
1201 case 'm':
1202 SelectRendition();
1203 break;
1204 case 'g':
1205 if (a1 == 0)
1206 curr->w_tabs[curr->w_x] = 0;
1207 else if (a1 == 3)
1208 bzero(curr->w_tabs, cols);
1209 break;
1210 case 'r':
1211 if (!a1)
1212 a1 = 1;
1213 if (!a2)
1214 a2 = rows;
1215 if (a1 < 1 || a2 > rows || a1 >= a2)
1216 break;
1217 curr->w_top = a1 - 1;
1218 curr->w_bot = a2 - 1;
1219 /* ChangeScrollRegion(curr->w_top, curr->w_bot); */
1220 if (curr->w_origin)
1222 curr->w_y = curr->w_top;
1223 curr->w_x = 0;
1225 else
1226 curr->w_y = curr->w_x = 0;
1227 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1228 break;
1229 case 's':
1230 SaveCursor();
1231 break;
1232 case 't':
1233 switch(a1)
1235 case 11:
1236 if (curr->w_layer.l_cvlist)
1237 Report("\033[1t", 0, 0);
1238 else
1239 Report("\033[2t", 0, 0);
1240 break;
1241 case 7:
1242 LRefreshAll(&curr->w_layer, 0);
1243 break;
1244 case 21:
1245 a1 = strlen(curr->w_title);
1246 if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
1248 bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
1249 bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
1250 bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
1251 curr->w_inlen += 5 + a1;
1253 break;
1254 case 8:
1255 a1 = curr->w_args[2];
1256 if (a1 < 1)
1257 a1 = curr->w_width;
1258 if (a2 < 1)
1259 a2 = curr->w_height;
1260 if (a1 > 10000 || a2 > 10000)
1261 break;
1262 WChangeSize(curr, a1, a2);
1263 cols = curr->w_width;
1264 rows = curr->w_height;
1265 break;
1266 default:
1267 break;
1269 break;
1270 case 'u':
1271 RestoreCursor();
1272 break;
1273 case 'I':
1274 if (!a1)
1275 a1 = 1;
1276 while (a1--)
1277 ForwardTab();
1278 break;
1279 case 'Z':
1280 if (!a1)
1281 a1 = 1;
1282 while (a1--)
1283 BackwardTab();
1284 break;
1285 case 'L':
1286 InsertLine(a1 ? a1 : 1);
1287 break;
1288 case 'M':
1289 DeleteLine(a1 ? a1 : 1);
1290 break;
1291 case 'P':
1292 DeleteChar(a1 ? a1 : 1);
1293 break;
1294 case '@':
1295 InsertChar(a1 ? a1 : 1);
1296 break;
1297 case 'h':
1298 ASetMode(1);
1299 break;
1300 case 'l':
1301 ASetMode(0);
1302 break;
1303 case 'i': /* MC Media Control */
1304 if (a1 == 5)
1305 PrintStart();
1306 break;
1307 case 'n':
1308 if (a1 == 5) /* Report terminal status */
1309 Report("\033[0n", 0, 0);
1310 else if (a1 == 6) /* Report cursor position */
1311 Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
1312 break;
1313 case 'c': /* Identify as VT100 */
1314 if (a1 == 0)
1315 Report("\033[?%d;%dc", 1, 2);
1316 break;
1317 case 'x': /* decreqtparm */
1318 if (a1 == 0 || a1 == 1)
1319 Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
1320 break;
1321 case 'p': /* obscure code from a 97801 term */
1322 if (a1 == 6 || a1 == 7)
1324 curr->w_curinv = 7 - a1;
1325 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1327 break;
1328 case 'S': /* code from a 97801 term / DEC vt400 */
1329 ScrollRegion(a1 ? a1 : 1);
1330 break;
1331 case 'T': /* code from a 97801 term / DEC vt400 */
1332 case '^': /* SD as per ISO 6429 */
1333 ScrollRegion(a1 ? -a1 : -1);
1334 break;
1336 break;
1337 case '?':
1338 for (a2 = 0; a2 < curr->w_NumArgs; a2++)
1340 a1 = curr->w_args[a2];
1341 debug2("\\E[?%d%c\n",a1,c);
1342 if (c != 'h' && c != 'l')
1343 break;
1344 i = (c == 'h');
1345 switch (a1)
1347 case 1: /* CKM: cursor key mode */
1348 LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
1349 #ifndef TIOCPKT
1350 WNewAutoFlow(curr, !i);
1351 #endif /* !TIOCPKT */
1352 break;
1353 case 2: /* ANM: ansi/vt52 mode */
1354 if (i)
1356 #ifdef FONT
1357 # ifdef ENCODINGS
1358 if (curr->w_encoding)
1359 break;
1360 # endif
1361 curr->w_charsets[0] = curr->w_charsets[1] =
1362 curr->w_charsets[2] = curr->w_charsets[2] =
1363 curr->w_FontL = curr->w_FontR = ASCII;
1364 curr->w_Charset = 0;
1365 curr->w_CharsetR = 2;
1366 curr->w_ss = 0;
1367 #endif
1369 break;
1370 case 3: /* COLM: column mode */
1371 i = (i ? Z0width : Z1width);
1372 WChangeSize(curr, i, curr->w_height);
1373 cols = curr->w_width;
1374 rows = curr->w_height;
1375 break;
1376 /* case 4: SCLM: scrolling mode */
1377 case 5: /* SCNM: screen mode */
1378 if (i != curr->w_revvid)
1379 WReverseVideo(curr, i);
1380 curr->w_revvid = i;
1381 break;
1382 case 6: /* OM: origin mode */
1383 if ((curr->w_origin = i) != 0)
1385 curr->w_y = curr->w_top;
1386 curr->w_x = 0;
1388 else
1389 curr->w_y = curr->w_x = 0;
1390 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1391 break;
1392 case 7: /* AWM: auto wrap mode */
1393 curr->w_wrap = i;
1394 break;
1395 /* case 8: ARM: auto repeat mode */
1396 /* case 9: INLM: interlace mode */
1397 case 9: /* X10 mouse tracking */
1398 curr->w_mouse = i ? 9 : 0;
1399 LMouseMode(&curr->w_layer, curr->w_mouse);
1400 break;
1401 /* case 10: EDM: edit mode */
1402 /* case 11: LTM: line transmit mode */
1403 /* case 13: SCFDM: space compression / field delimiting */
1404 /* case 14: TEM: transmit execution mode */
1405 /* case 16: EKEM: edit key execution mode */
1406 /* case 18: PFF: Printer term form feed */
1407 /* case 19: PEX: Printer extend screen / scroll. reg */
1408 case 25: /* TCEM: text cursor enable mode */
1409 curr->w_curinv = !i;
1410 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
1411 break;
1412 /* case 34: RLM: Right to left mode */
1413 /* case 35: HEBM: hebrew keyboard map */
1414 /* case 36: HEM: hebrew encoding */
1415 /* case 38: TeK Mode */
1416 /* case 40: 132 col enable */
1417 /* case 42: NRCM: 7bit NRC character mode */
1418 /* case 44: margin bell enable */
1419 case 47: /* xterm-like alternate screen */
1420 case 1047: /* xterm-like alternate screen */
1421 case 1049: /* xterm-like alternate screen */
1422 if (use_altscreen)
1424 if (i)
1425 EnterAltScreen(curr);
1426 else
1427 LeaveAltScreen(curr);
1428 if (a1 == 47 && !i)
1429 curr->w_saved = 0;
1430 LRefreshAll(&curr->w_layer, 0);
1431 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1433 break;
1434 /* case 66: NKM: Numeric keypad appl mode */
1435 /* case 68: KBUM: Keyboard usage mode (data process) */
1436 case 1000: /* VT200 mouse tracking */
1437 case 1001: /* VT200 highlight mouse */
1438 case 1002: /* button event mouse*/
1439 case 1003: /* any event mouse*/
1440 curr->w_mouse = i ? a1 : 0;
1441 LMouseMode(&curr->w_layer, curr->w_mouse);
1442 break;
1445 break;
1446 case '>':
1447 switch (c)
1449 case 'c': /* secondary DA */
1450 if (a1 == 0)
1451 Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
1452 break;
1454 break;
1459 static void
1460 StringStart(type)
1461 enum string_t type;
1463 curr->w_StringType = type;
1464 curr->w_stringp = curr->w_string;
1465 curr->w_state = ASTR;
1468 static void
1469 StringChar(c)
1470 int c;
1472 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1473 curr->w_state = LIT;
1474 else
1475 *(curr->w_stringp)++ = c;
1479 * Do string processing. Returns -1 if output should be suspended
1480 * until status is gone.
1482 static int
1483 StringEnd()
1485 struct canvas *cv;
1486 char *p;
1487 int typ;
1489 curr->w_state = LIT;
1490 *curr->w_stringp = '\0';
1491 switch (curr->w_StringType)
1493 case OSC: /* special xterm compatibility hack */
1494 if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
1495 break;
1496 typ = atoi(curr->w_string);
1497 p++;
1498 #ifdef MULTIUSER
1499 if (typ == 83) /* 83 = 'S' */
1501 /* special execute commands sequence */
1502 char *args[MAXARGS];
1503 int argl[MAXARGS];
1504 struct acluser *windowuser;
1506 windowuser = *FindUserPtr(":window:");
1507 if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
1509 for (display = displays; display; display = display->d_next)
1510 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1511 break; /* found it */
1512 if (display == 0 && curr->w_layer.l_cvlist)
1513 display = curr->w_layer.l_cvlist->c_display;
1514 if (display == 0)
1515 display = displays;
1516 EffectiveAclUser = windowuser;
1517 fore = curr;
1518 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1519 DoCommand(args, argl);
1520 EffectiveAclUser = 0;
1521 fore = 0;
1522 flayer = 0;
1524 break;
1526 #endif
1527 #ifdef RXVT_OSC
1528 if (typ == 0 || typ == 1 || typ == 20 || typ == 39 || typ == 49)
1530 int typ2;
1531 typ2 = typ / 10;
1532 if (--typ2 < 0)
1533 typ2 = 0;
1534 if (strcmp(curr->w_xtermosc[typ2], p))
1536 strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
1537 curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
1539 for (display = displays; display; display = display->d_next)
1541 if (!D_CXT)
1542 continue;
1543 if (D_forecv->c_layer->l_bottom == &curr->w_layer)
1544 SetXtermOSC(typ2, curr->w_xtermosc[typ2]);
1545 if ((typ2 == 2 || typ2 == 3) && D_xtermosc[typ2])
1546 Redisplay(0);
1550 if (typ != 0 && typ != 2)
1551 break;
1552 #else
1553 if (typ < 0 || typ > 2)
1554 break;
1555 #endif
1557 curr->w_stringp -= p - curr->w_string;
1558 if (curr->w_stringp > curr->w_string)
1559 bcopy(p, curr->w_string, curr->w_stringp - curr->w_string);
1560 *curr->w_stringp = '\0';
1561 /* FALLTHROUGH */
1562 case APC:
1563 if (curr->w_hstatus)
1565 if (strcmp(curr->w_hstatus, curr->w_string) == 0)
1566 break; /* not changed */
1567 free(curr->w_hstatus);
1568 curr->w_hstatus = 0;
1570 if (curr->w_string != curr->w_stringp)
1571 curr->w_hstatus = SaveStr(curr->w_string);
1572 WindowChanged(curr, 'h');
1573 break;
1574 case PM:
1575 case GM:
1576 for (display = displays; display; display = display->d_next)
1578 for (cv = D_cvlist; cv; cv = cv->c_next)
1579 if (cv->c_layer->l_bottom == &curr->w_layer)
1580 break;
1581 if (cv || curr->w_StringType == GM)
1582 MakeStatus(curr->w_string);
1584 return -1;
1585 case DCS:
1586 LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
1587 break;
1588 case AKA:
1589 if (curr->w_title == curr->w_akabuf && !*curr->w_string)
1590 break;
1591 ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
1592 if (!*curr->w_string)
1593 curr->w_autoaka = curr->w_y + 1;
1594 break;
1595 default:
1596 break;
1598 return 0;
1601 static void
1602 PrintStart()
1604 curr->w_pdisplay = 0;
1606 /* find us a nice display to print on, fore prefered */
1607 display = curr->w_lastdisp;
1608 if (!(display && curr == D_fore && (printcmd || D_PO)))
1609 for (display = displays; display; display = display->d_next)
1610 if (curr == D_fore && (printcmd || D_PO))
1611 break;
1612 if (!display)
1614 struct canvas *cv;
1615 for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1617 display = cv->c_display;
1618 if (printcmd || D_PO)
1619 break;
1621 if (!cv)
1623 display = displays;
1624 if (!display || display->d_next || !(printcmd || D_PO))
1625 return;
1628 curr->w_pdisplay = display;
1629 curr->w_stringp = curr->w_string;
1630 curr->w_state = PRIN;
1631 if (printcmd && curr->w_pdisplay->d_printfd < 0)
1632 curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
1635 static void
1636 PrintChar(c)
1637 int c;
1639 if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
1640 PrintFlush();
1641 *(curr->w_stringp)++ = c;
1644 static void
1645 PrintFlush()
1647 display = curr->w_pdisplay;
1648 if (display && printcmd)
1650 char *bp = curr->w_string;
1651 int len = curr->w_stringp - curr->w_string;
1652 int r;
1653 while (len && display->d_printfd >= 0)
1655 r = write(display->d_printfd, bp, len);
1656 if (r <= 0)
1658 WMsg(curr, errno, "printing aborted");
1659 close(display->d_printfd);
1660 display->d_printfd = -1;
1661 break;
1663 bp += r;
1664 len -= r;
1667 else if (display && curr->w_stringp > curr->w_string)
1669 AddCStr(D_PO);
1670 AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
1671 AddCStr(D_PF);
1672 Flush();
1674 curr->w_stringp = curr->w_string;
1678 void
1679 WNewAutoFlow(win, on)
1680 struct win *win;
1681 int on;
1683 debug1("WNewAutoFlow: %d\n", on);
1684 if (win->w_flow & FLOW_AUTOFLAG)
1685 win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
1686 else
1687 win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
1688 LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
1692 #ifdef FONT
1694 static void
1695 DesignateCharset(c, n)
1696 int c, n;
1698 curr->w_ss = 0;
1699 # ifdef ENCODINGS
1700 if (c == ('@' & 037)) /* map JIS 6226 to 0208 */
1701 c = KANJI;
1702 # endif
1703 if (c == 'B')
1704 c = ASCII;
1705 if (curr->w_charsets[n] != c)
1707 curr->w_charsets[n] = c;
1708 if (curr->w_Charset == n)
1710 curr->w_FontL = c;
1711 curr->w_rend.font = curr->w_FontL;
1712 LSetRendition(&curr->w_layer, &curr->w_rend);
1714 if (curr->w_CharsetR == n)
1715 curr->w_FontR = c;
1719 static void
1720 MapCharset(n)
1721 int n;
1723 curr->w_ss = 0;
1724 if (curr->w_Charset != n)
1726 curr->w_Charset = n;
1727 curr->w_FontL = curr->w_charsets[n];
1728 curr->w_rend.font = curr->w_FontL;
1729 LSetRendition(&curr->w_layer, &curr->w_rend);
1733 static void
1734 MapCharsetR(n)
1735 int n;
1737 curr->w_ss = 0;
1738 if (curr->w_CharsetR != n)
1740 curr->w_CharsetR = n;
1741 curr->w_FontR = curr->w_charsets[n];
1743 curr->w_gr = 1;
1746 #endif /* FONT */
1748 static void
1749 SaveCursor()
1751 curr->w_saved = 1;
1752 curr->w_Saved_x = curr->w_x;
1753 curr->w_Saved_y = curr->w_y;
1754 curr->w_SavedRend = curr->w_rend;
1755 #ifdef FONT
1756 curr->w_SavedCharset = curr->w_Charset;
1757 curr->w_SavedCharsetR = curr->w_CharsetR;
1758 bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
1759 4 * sizeof(int));
1760 #endif
1763 static void
1764 RestoreCursor()
1766 if (!curr->w_saved)
1767 return;
1768 LGotoPos(&curr->w_layer, curr->w_Saved_x, curr->w_Saved_y);
1769 curr->w_x = curr->w_Saved_x;
1770 curr->w_y = curr->w_Saved_y;
1771 curr->w_rend = curr->w_SavedRend;
1772 #ifdef FONT
1773 bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
1774 4 * sizeof(int));
1775 curr->w_Charset = curr->w_SavedCharset;
1776 curr->w_CharsetR = curr->w_SavedCharsetR;
1777 curr->w_ss = 0;
1778 curr->w_FontL = curr->w_charsets[curr->w_Charset];
1779 curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
1780 #endif
1781 LSetRendition(&curr->w_layer, &curr->w_rend);
1784 static void
1785 BackSpace()
1787 if (curr->w_x > 0)
1789 curr->w_x--;
1791 else if (curr->w_wrap && curr->w_y > 0)
1793 curr->w_x = cols - 1;
1794 curr->w_y--;
1796 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1799 static void
1800 Return()
1802 if (curr->w_x == 0)
1803 return;
1804 curr->w_x = 0;
1805 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1808 static void
1809 LineFeed(out_mode)
1810 int out_mode;
1812 /* out_mode: 0=lf, 1=cr+lf */
1813 if (out_mode)
1814 curr->w_x = 0;
1815 if (curr->w_y != curr->w_bot) /* Don't scroll */
1817 if (curr->w_y < rows-1)
1818 curr->w_y++;
1819 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1820 return;
1822 if (curr->w_autoaka > 1)
1823 curr->w_autoaka--;
1824 MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
1825 LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
1826 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1829 static void
1830 ReverseLineFeed()
1832 if (curr->w_y == curr->w_top)
1834 MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
1835 LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
1836 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1838 else if (curr->w_y > 0)
1839 CursorUp(1);
1842 static void
1843 InsertChar(n)
1844 int n;
1846 register int y = curr->w_y, x = curr->w_x;
1848 if (n <= 0)
1849 return;
1850 if (x == cols)
1851 x--;
1852 save_mline(&curr->w_mlines[y], cols);
1853 MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
1854 LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1855 LGotoPos(&curr->w_layer, x, y);
1858 static void
1859 DeleteChar(n)
1860 int n;
1862 register int y = curr->w_y, x = curr->w_x;
1864 if (x == cols)
1865 x--;
1866 save_mline(&curr->w_mlines[y], cols);
1867 MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
1868 LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
1869 LGotoPos(&curr->w_layer, x, y);
1872 static void
1873 DeleteLine(n)
1874 int n;
1876 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1877 return;
1878 if (n > curr->w_bot - curr->w_y + 1)
1879 n = curr->w_bot - curr->w_y + 1;
1880 MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
1881 LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
1882 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1885 static void
1886 InsertLine(n)
1887 int n;
1889 if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
1890 return;
1891 if (n > curr->w_bot - curr->w_y + 1)
1892 n = curr->w_bot - curr->w_y + 1;
1893 MScrollV(curr, -n, curr->w_y, curr->w_bot, CURR_BCE);
1894 LScrollV(&curr->w_layer, -n, curr->w_y, curr->w_bot, CURR_BCE);
1895 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1898 static void
1899 ScrollRegion(n)
1900 int n;
1902 MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
1903 LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
1904 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1908 static void
1909 ForwardTab()
1911 register int x = curr->w_x;
1913 if (x == cols)
1915 LineFeed(1);
1916 x = 0;
1918 if (curr->w_tabs[x] && x < cols - 1)
1919 x++;
1920 while (x < cols - 1 && !curr->w_tabs[x])
1921 x++;
1922 curr->w_x = x;
1923 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1926 static void
1927 BackwardTab()
1929 register int x = curr->w_x;
1931 if (curr->w_tabs[x] && x > 0)
1932 x--;
1933 while (x > 0 && !curr->w_tabs[x])
1934 x--;
1935 curr->w_x = x;
1936 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
1939 static void
1940 ClearScreen()
1942 LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
1943 #ifdef COPY_PASTE
1944 MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
1945 #else
1946 MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
1947 #endif
1950 static void
1951 ClearFromBOS()
1953 register int y = curr->w_y, x = curr->w_x;
1955 LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
1956 MClearArea(curr, 0, 0, x, y, CURR_BCE);
1957 RestorePosRendition();
1960 static void
1961 ClearToEOS()
1963 register int y = curr->w_y, x = curr->w_x;
1965 if (x == 0 && y == 0)
1967 ClearScreen();
1968 RestorePosRendition();
1969 return;
1971 LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
1972 MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
1973 RestorePosRendition();
1976 static void
1977 ClearLineRegion(from, to)
1978 int from, to;
1980 register int y = curr->w_y;
1981 LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
1982 MClearArea(curr, from, y, to, y, CURR_BCE);
1983 RestorePosRendition();
1986 static void
1987 CursorRight(n)
1988 register int n;
1990 register int x = curr->w_x;
1992 if (x == cols)
1994 LineFeed(1);
1995 x = 0;
1997 if ((curr->w_x += n) >= cols)
1998 curr->w_x = cols - 1;
1999 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2002 static void
2003 CursorUp(n)
2004 register int n;
2006 if (curr->w_y < curr->w_top) /* if above scrolling rgn, */
2008 if ((curr->w_y -= n) < 0) /* ignore its limits */
2009 curr->w_y = 0;
2011 else
2012 if ((curr->w_y -= n) < curr->w_top)
2013 curr->w_y = curr->w_top;
2014 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2017 static void
2018 CursorDown(n)
2019 register int n;
2021 if (curr->w_y > curr->w_bot) /* if below scrolling rgn, */
2023 if ((curr->w_y += n) > rows - 1) /* ignore its limits */
2024 curr->w_y = rows - 1;
2026 else
2027 if ((curr->w_y += n) > curr->w_bot)
2028 curr->w_y = curr->w_bot;
2029 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2032 static void
2033 CursorLeft(n)
2034 register int n;
2036 if ((curr->w_x -= n) < 0)
2037 curr->w_x = 0;
2038 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2041 static void
2042 ASetMode(on)
2043 int on;
2045 register int i;
2047 for (i = 0; i < curr->w_NumArgs; ++i)
2049 switch (curr->w_args[i])
2051 /* case 2: KAM: Lock keyboard */
2052 case 4: /* IRM: Insert mode */
2053 curr->w_insert = on;
2054 LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
2055 break;
2056 /* case 12: SRM: Echo mode on */
2057 case 20: /* LNM: Linefeed mode */
2058 curr->w_autolf = on;
2059 break;
2060 case 34:
2061 curr->w_curvvis = !on;
2062 LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
2063 break;
2064 default:
2065 break;
2070 static char rendlist[] =
2072 ~((1 << NATTR) - 1), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
2073 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2074 0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
2077 static void
2078 SelectRendition()
2080 #ifdef COLOR
2081 register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
2082 # ifdef COLORS256
2083 int cx = curr->w_rend.colorx;
2084 # endif
2085 #else
2086 register int j, i = 0, a = curr->w_rend.attr;
2087 #endif
2091 j = curr->w_args[i];
2092 #ifdef COLOR
2093 if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
2095 int jj;
2097 i += 2;
2098 jj = curr->w_args[i];
2099 if (jj < 0 || jj > 255)
2100 continue;
2101 # ifdef COLORS256
2102 if (j == 38)
2104 c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
2105 a |= A_BFG;
2106 if (jj >= 8 && jj < 16)
2107 c |= 0x08;
2108 else
2109 a ^= A_BFG;
2110 a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
2111 cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
2113 else
2115 c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
2116 a |= A_BBG;
2117 if (jj >= 8 && jj < 16)
2118 c |= 0x80;
2119 else
2120 a ^= A_BBG;
2121 cx = (cx & 0x0f) | (jj & 0xf0);
2123 continue;
2124 # else
2125 jj = color256to16(jj) + 30;
2126 if (jj >= 38)
2127 jj += 60 - 8;
2128 j = j == 38 ? jj : jj + 10;
2129 # endif
2131 # ifdef COLORS16
2132 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2133 a &= 0xbf;
2134 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2135 a &= 0x7f;
2136 if (j >= 90 && j <= 97)
2137 a |= 0x40;
2138 if (j >= 100 && j <= 107)
2139 a |= 0x80;
2140 # endif
2141 if (j >= 90 && j <= 97)
2142 j -= 60;
2143 if (j >= 100 && j <= 107)
2144 j -= 60;
2145 if (j >= 30 && j <= 39 && j != 38)
2146 c = (c & 0xf0) | ((j - 30) ^ 9);
2147 else if (j >= 40 && j <= 49 && j != 48)
2148 c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
2149 if (j == 0)
2150 c = 0;
2151 # ifdef COLORS256
2152 if (j == 0 || (j >= 30 && j <= 39 && j != 38))
2153 cx &= 0xf0;
2154 if (j == 0 || (j >= 40 && j <= 49 && j != 48))
2155 cx &= 0x0f;
2156 # endif
2157 #endif
2158 if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
2159 continue;
2160 j = rendlist[j];
2161 if (j & (1 << NATTR))
2162 a &= j;
2163 else
2164 a |= j;
2166 while (++i < curr->w_NumArgs);
2167 curr->w_rend.attr = a;
2168 #ifdef COLOR
2169 curr->w_rend.color = c;
2170 # ifdef COLORS256
2171 curr->w_rend.colorx = cx;
2172 # endif
2173 #endif
2174 LSetRendition(&curr->w_layer, &curr->w_rend);
2177 static void
2178 FillWithEs()
2180 register int i;
2181 register unsigned char *p, *ep;
2183 LClearAll(&curr->w_layer, 1);
2184 curr->w_y = curr->w_x = 0;
2185 for (i = 0; i < rows; ++i)
2187 clear_mline(&curr->w_mlines[i], 0, cols + 1);
2188 p = curr->w_mlines[i].image;
2189 ep = p + cols;
2190 while (p < ep)
2191 *p++ = 'E';
2193 LRefreshAll(&curr->w_layer, 1);
2198 * Ugly autoaka hack support:
2199 * ChangeAKA() sets a new aka
2200 * FindAKA() searches for an autoaka match
2203 void
2204 ChangeAKA(p, s, l)
2205 struct win *p;
2206 char *s;
2207 int l;
2209 int i, c;
2211 for (i = 0; l > 0; l--)
2213 if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
2214 break;
2215 c = (unsigned char)*s++;
2216 if (c == 0)
2217 break;
2218 if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
2219 continue;
2220 p->w_akachange[i++] = c;
2222 p->w_akachange[i] = 0;
2223 p->w_title = p->w_akachange;
2224 if (p->w_akachange != p->w_akabuf)
2225 if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
2226 p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
2227 WindowChanged(p, 't');
2228 WindowChanged((struct win *)0, 'w');
2229 WindowChanged((struct win *)0, 'W');
2232 static void
2233 FindAKA()
2235 register unsigned char *cp, *line;
2236 register struct win *wp = curr;
2237 register int len = strlen(wp->w_akabuf);
2238 int y;
2240 y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
2241 cols = wp->w_width;
2242 try_line:
2243 cp = line = wp->w_mlines[y].image;
2244 if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
2246 for (;;)
2248 if (cp - line >= cols - len)
2250 if (++y == wp->w_autoaka && y < rows)
2251 goto try_line;
2252 return;
2254 if (strncmp((char *)cp, wp->w_akabuf, len) == 0)
2255 break;
2256 cp++;
2258 cp += len;
2260 for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
2262 if (len)
2264 if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
2265 wp->w_autoaka = -1;
2266 else
2267 wp->w_autoaka = 0;
2268 line = cp;
2269 while (len && *cp != ' ')
2271 if (*cp++ == '/')
2272 line = cp;
2273 len--;
2275 ChangeAKA(wp, (char *)line, cp - line);
2277 else
2278 wp->w_autoaka = 0;
2281 static void
2282 RestorePosRendition()
2284 LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
2285 LSetRendition(&curr->w_layer, &curr->w_rend);
2288 /* Send a terminal report as if it were typed. */
2289 static void
2290 Report(fmt, n1, n2)
2291 char *fmt;
2292 int n1, n2;
2294 register int len;
2295 char rbuf[40]; /* enough room for all replys */
2297 sprintf(rbuf, fmt, n1, n2);
2298 len = strlen(rbuf);
2300 #ifdef PSEUDOS
2301 if (W_UWP(curr))
2303 if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
2305 bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
2306 curr->w_pwin->p_inlen += len;
2309 else
2310 #endif
2312 if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
2314 bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
2315 curr->w_inlen += len;
2323 *====================================================================*
2324 *====================================================================*
2327 /**********************************************************************
2329 * Memory subsystem.
2333 static void
2334 MFixLine(p, y, mc)
2335 struct win *p;
2336 int y;
2337 struct mchar *mc;
2339 struct mline *ml = &p->w_mlines[y];
2340 if (mc->attr && ml->attr == null)
2342 if ((ml->attr = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2344 ml->attr = null;
2345 mc->attr = p->w_rend.attr = 0;
2346 WMsg(p, 0, "Warning: no space for attr - turned off");
2349 #ifdef FONT
2350 if (mc->font && ml->font == null)
2352 if ((ml->font = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2354 ml->font = null;
2355 p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
2356 p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
2357 mc->font = p->w_rend.font = 0;
2358 WMsg(p, 0, "Warning: no space for font - turned off");
2361 #endif
2362 #ifdef COLOR
2363 if (mc->color && ml->color == null)
2365 if ((ml->color = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2367 ml->color = null;
2368 mc->color = p->w_rend.color = 0;
2369 WMsg(p, 0, "Warning: no space for color - turned off");
2372 # ifdef COLORS256
2373 if (mc->colorx && ml->colorx == null)
2375 if ((ml->colorx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
2377 ml->colorx = null;
2378 mc->colorx = p->w_rend.colorx = 0;
2379 WMsg(p, 0, "Warning: no space for extended colors - turned off");
2382 # endif
2383 #endif
2386 /*****************************************************************/
2388 #ifdef DW_CHARS
2389 # define MKillDwRight(p, ml, x) \
2390 if (dw_right(ml, x, p->w_encoding)) \
2392 if (x > 0) \
2393 copy_mchar2mline(&mchar_blank, ml, x - 1); \
2394 copy_mchar2mline(&mchar_blank, ml, x); \
2397 # define MKillDwLeft(p, ml, x) \
2398 if (dw_left(ml, x, p->w_encoding)) \
2400 copy_mchar2mline(&mchar_blank, ml, x); \
2401 copy_mchar2mline(&mchar_blank, ml, x + 1); \
2403 #else
2404 # define MKillDwRight(p, ml, x) ;
2405 # define MKillDwLeft(p, ml, x) ;
2406 #endif
2408 static void
2409 MScrollH(p, n, y, xs, xe, bce)
2410 struct win *p;
2411 int n, y, xs, xe, bce;
2413 struct mline *ml;
2415 if (n == 0)
2416 return;
2417 ml = &p->w_mlines[y];
2418 MKillDwRight(p, ml, xs);
2419 MKillDwLeft(p, ml, xe);
2420 if (n > 0)
2422 if (xe - xs + 1 > n)
2424 MKillDwRight(p, ml, xs + n);
2425 bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
2427 else
2428 n = xe - xs + 1;
2429 clear_mline(ml, xe + 1 - n, n);
2430 #ifdef COLOR
2431 if (bce)
2432 MBceLine(p, y, xe + 1 - n, n, bce);
2433 #endif
2435 else
2437 n = -n;
2438 if (xe - xs + 1 > n)
2440 MKillDwLeft(p, ml, xe - n);
2441 bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
2443 else
2444 n = xe - xs + 1;
2445 clear_mline(ml, xs, n);
2446 #ifdef COLOR
2447 if (bce)
2448 MBceLine(p, y, xs, n, bce);
2449 #endif
2453 static void
2454 MScrollV(p, n, ys, ye, bce)
2455 struct win *p;
2456 int n, ys, ye, bce;
2458 int i, cnt1, cnt2;
2459 struct mline tmp[256];
2460 struct mline *ml;
2462 if (n == 0)
2463 return;
2464 if (n > 0)
2466 if (n > 256)
2468 MScrollV(p, n - 256, ys, ye, bce);
2469 n = 256;
2471 if (ye - ys + 1 < n)
2472 n = ye - ys + 1;
2473 #ifdef COPY_PASTE
2474 if (compacthist)
2476 ye = MFindUsedLine(p, ye, ys);
2477 if (ye - ys + 1 < n)
2478 n = ye - ys + 1;
2479 if (n <= 0)
2480 return;
2482 #endif
2483 /* Clear lines */
2484 ml = p->w_mlines + ys;
2485 for (i = ys; i < ys + n; i++, ml++)
2487 #ifdef COPY_PASTE
2488 if (ys == p->w_top)
2489 WAddLineToHist(p, ml);
2490 #endif
2491 if (ml->attr != null)
2492 free(ml->attr);
2493 ml->attr = null;
2494 #ifdef FONT
2495 if (ml->font != null)
2496 free(ml->font);
2497 ml->font = null;
2498 #endif
2499 #ifdef COLOR
2500 if (ml->color != null)
2501 free(ml->color);
2502 ml->color = null;
2503 # ifdef COLORS256
2504 if (ml->colorx != null)
2505 free(ml->colorx);
2506 ml->colorx = null;
2507 # endif
2508 #endif
2509 bclear((char *)ml->image, p->w_width + 1);
2510 #ifdef COLOR
2511 if (bce)
2512 MBceLine(p, i, 0, p->w_width, bce);
2513 #endif
2515 /* switch 'em over */
2516 cnt1 = n * sizeof(struct mline);
2517 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2518 if (cnt1 && cnt2)
2519 Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
2521 else
2523 if (n < -256)
2525 MScrollV(p, n + 256, ys, ye, bce);
2526 n = -256;
2528 n = -n;
2529 if (ye - ys + 1 < n)
2530 n = ye - ys + 1;
2532 ml = p->w_mlines + ye;
2533 /* Clear lines */
2534 for (i = ye; i > ye - n; i--, ml--)
2536 if (ml->attr != null)
2537 free(ml->attr);
2538 ml->attr = null;
2539 #ifdef FONT
2540 if (ml->font != null)
2541 free(ml->font);
2542 ml->font = null;
2543 #endif
2544 #ifdef COLOR
2545 if (ml->color != null)
2546 free(ml->color);
2547 ml->color = null;
2548 # ifdef COLORS256
2549 if (ml->colorx != null)
2550 free(ml->colorx);
2551 ml->colorx = null;
2552 # endif
2553 #endif
2554 bclear((char *)ml->image, p->w_width + 1);
2555 #ifdef COLOR
2556 if (bce)
2557 MBceLine(p, i, 0, p->w_width, bce);
2558 #endif
2560 cnt1 = n * sizeof(struct mline);
2561 cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
2562 if (cnt1 && cnt2)
2563 Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
2567 static void
2568 Scroll(cp, cnt1, cnt2, tmp)
2569 char *cp, *tmp;
2570 int cnt1, cnt2;
2572 if (!cnt1 || !cnt2)
2573 return;
2574 if (cnt1 <= cnt2)
2576 bcopy(cp, tmp, cnt1);
2577 bcopy(cp + cnt1, cp, cnt2);
2578 bcopy(tmp, cp + cnt2, cnt1);
2580 else
2582 bcopy(cp + cnt1, tmp, cnt2);
2583 bcopy(cp, cp + cnt2, cnt1);
2584 bcopy(tmp, cp, cnt2);
2588 static void
2589 MClearArea(p, xs, ys, xe, ye, bce)
2590 struct win *p;
2591 int xs, ys, xe, ye, bce;
2593 int n, y;
2594 int xxe;
2595 struct mline *ml;
2597 /* check for magic margin condition */
2598 if (xs >= p->w_width)
2599 xs = p->w_width - 1;
2600 if (xe >= p->w_width)
2601 xe = p->w_width - 1;
2603 MKillDwRight(p, p->w_mlines + ys, xs);
2604 MKillDwLeft(p, p->w_mlines + ye, xe);
2606 ml = p->w_mlines + ys;
2607 for (y = ys; y <= ye; y++, ml++)
2609 xxe = (y == ye) ? xe : p->w_width - 1;
2610 n = xxe - xs + 1;
2611 if (n > 0)
2612 clear_mline(ml, xs, n);
2613 #ifdef COLOR
2614 if (n > 0 && bce)
2615 MBceLine(p, y, xs, xs + n - 1, bce);
2616 #endif
2617 xs = 0;
2621 static void
2622 MInsChar(p, c, x, y)
2623 struct win *p;
2624 struct mchar *c;
2625 int x, y;
2627 int n;
2628 struct mline *ml;
2630 ASSERT(x >= 0 && x < p->w_width);
2631 MFixLine(p, y, c);
2632 ml = p->w_mlines + y;
2633 n = p->w_width - x - 1;
2634 MKillDwRight(p, ml, x);
2635 if (n > 0)
2637 MKillDwRight(p, ml, p->w_width - 1);
2638 bcopy_mline(ml, x, x + 1, n);
2640 copy_mchar2mline(c, ml, x);
2641 #ifdef DW_CHARS
2642 if (c->mbcs)
2644 if (--n > 0)
2646 MKillDwRight(p, ml, p->w_width - 1);
2647 bcopy_mline(ml, x + 1, x + 2, n);
2649 copy_mchar2mline(c, ml, x + 1);
2650 ml->image[x + 1] = c->mbcs;
2651 # ifdef UTF8
2652 if (p->w_encoding != UTF8)
2653 ml->font[x + 1] |= 0x80;
2654 else if (p->w_encoding == UTF8 && c->mbcs)
2655 ml->font[x + 1] = c->mbcs;
2656 # else
2657 ml->font[x + 1] |= 0x80;
2658 # endif
2660 #endif
2663 static void
2664 MPutChar(p, c, x, y)
2665 struct win *p;
2666 struct mchar *c;
2667 int x, y;
2669 struct mline *ml;
2671 MFixLine(p, y, c);
2672 ml = &p->w_mlines[y];
2673 MKillDwRight(p, ml, x);
2674 MKillDwLeft(p, ml, x);
2675 copy_mchar2mline(c, ml, x);
2676 #ifdef DW_CHARS
2677 if (c->mbcs)
2679 MKillDwLeft(p, ml, x + 1);
2680 copy_mchar2mline(c, ml, x + 1);
2681 ml->image[x + 1] = c->mbcs;
2682 # ifdef UTF8
2683 if (p->w_encoding != UTF8)
2684 ml->font[x + 1] |= 0x80;
2685 else if (p->w_encoding == UTF8 && c->mbcs)
2686 ml->font[x + 1] = c->mbcs;
2687 # else
2688 ml->font[x + 1] |= 0x80;
2689 # endif
2691 #endif
2695 static void
2696 MWrapChar(p, c, y, top, bot, ins)
2697 struct win *p;
2698 struct mchar *c;
2699 int y, top, bot;
2700 int ins;
2702 struct mline *ml;
2703 int bce;
2705 #ifdef COLOR
2706 bce = rend_getbg(c);
2707 #else
2708 bce = 0;
2709 #endif
2710 MFixLine(p, y, c);
2711 ml = &p->w_mlines[y];
2712 copy_mchar2mline(&mchar_null, ml, p->w_width);
2713 if (y == bot)
2714 MScrollV(p, 1, top, bot, bce);
2715 else if (y < p->w_height - 1)
2716 y++;
2717 if (ins)
2718 MInsChar(p, c, 0, y);
2719 else
2720 MPutChar(p, c, 0, y);
2723 static void
2724 MPutStr(p, s, n, r, x, y)
2725 struct win *p;
2726 char *s;
2727 int n;
2728 struct mchar *r;
2729 int x, y;
2731 struct mline *ml;
2732 int i;
2733 unsigned char *b;
2735 if (n <= 0)
2736 return;
2737 MFixLine(p, y, r);
2738 ml = &p->w_mlines[y];
2739 MKillDwRight(p, ml, x);
2740 MKillDwLeft(p, ml, x + n - 1);
2741 bcopy(s, (char *)ml->image + x, n);
2742 b = ml->attr + x;
2743 for (i = n; i-- > 0;)
2744 *b++ = r->attr;
2745 #ifdef FONT
2746 b = ml->font + x;
2747 for (i = n; i-- > 0;)
2748 *b++ = r->font;
2749 #endif
2750 #ifdef COLOR
2751 b = ml->color + x;
2752 for (i = n; i-- > 0;)
2753 *b++ = r->color;
2754 # ifdef COLORS256
2755 b = ml->colorx + x;
2756 for (i = n; i-- > 0;)
2757 *b++ = r->colorx;
2758 # endif
2759 #endif
2762 #ifdef COLOR
2763 static void
2764 MBceLine(p, y, xs, xe, bce)
2765 struct win *p;
2766 int y, xs, xe, bce;
2768 struct mchar mc;
2769 struct mline *ml;
2770 int x;
2772 mc = mchar_null;
2773 rend_setbg(&mc, bce);
2774 MFixLine(p, y, &mc);
2775 ml = p->w_mlines + y;
2776 # ifdef COLORS16
2777 if (mc.attr)
2778 for (x = xs; x <= xe; x++)
2779 ml->attr[x] = mc.attr;
2780 # endif
2781 if (mc.color)
2782 for (x = xs; x <= xe; x++)
2783 ml->color[x] = mc.color;
2784 # ifdef COLORS256
2785 if (mc.colorx)
2786 for (x = xs; x <= xe; x++)
2787 ml->colorx[x] = mc.colorx;
2788 # endif
2790 #endif
2793 #ifdef COPY_PASTE
2794 static void
2795 WAddLineToHist(wp, ml)
2796 struct win *wp;
2797 struct mline *ml;
2799 register unsigned char *q, *o;
2800 struct mline *hml;
2802 if (wp->w_histheight == 0)
2803 return;
2804 hml = &wp->w_hlines[wp->w_histidx];
2805 q = ml->image; ml->image = hml->image; hml->image = q;
2807 q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
2808 if (o != null)
2809 free(o);
2811 #ifdef FONT
2812 q = ml->font; o = hml->font; hml->font = q; ml->font = null;
2813 if (o != null)
2814 free(o);
2815 #endif
2817 #ifdef COLOR
2818 q = ml->color; o = hml->color; hml->color = q; ml->color = null;
2819 if (o != null)
2820 free(o);
2821 # ifdef COLORS256
2822 q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
2823 if (o != null)
2824 free(o);
2825 # endif
2826 #endif
2828 if (++wp->w_histidx >= wp->w_histheight)
2829 wp->w_histidx = 0;
2831 #endif
2834 MFindUsedLine(p, ye, ys)
2835 struct win *p;
2836 int ys, ye;
2838 int y;
2839 struct mline *ml = p->w_mlines + ye;
2841 debug2("MFindUsedLine: %d %d\n", ye, ys);
2842 for (y = ye; y >= ys; y--, ml--)
2844 if (bcmp((char*)ml->image, blank, p->w_width))
2845 break;
2846 if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
2847 break;
2848 #ifdef COLOR
2849 if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
2850 break;
2851 # ifdef COLORS256
2852 if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
2853 break;
2854 # endif
2855 #endif
2857 debug1("MFindUsedLine returning %d\n", y);
2858 return y;
2863 *====================================================================*
2864 *====================================================================*
2868 * Tricky: send only one bell even if the window is displayed
2869 * more than once.
2871 void
2872 WBell(p, visual)
2873 struct win *p;
2874 int visual;
2876 struct canvas *cv;
2877 for (display = displays; display; display = display->d_next)
2879 for (cv = D_cvlist; cv; cv = cv->c_next)
2880 if (cv->c_layer->l_bottom == &p->w_layer)
2881 break;
2882 if (cv && !visual)
2883 AddCStr(D_BL);
2884 else if (cv && D_VB)
2885 AddCStr(D_VB);
2886 else
2887 p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
2892 * This should be reverse video.
2893 * Only change video if window is fore.
2894 * Because it is used in some termcaps to emulate
2895 * a visual bell we do this hack here.
2896 * (screen uses \Eg as special vbell sequence)
2898 static void
2899 WReverseVideo(p, on)
2900 struct win *p;
2901 int on;
2903 struct canvas *cv;
2904 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2906 display = cv->c_display;
2907 if (cv != D_forecv)
2908 continue;
2909 ReverseVideo(on);
2910 if (!on && p->w_revvid && !D_CVR)
2912 if (D_VB)
2913 AddCStr(D_VB);
2914 else
2915 p->w_bell = BELL_VISUAL;
2920 void
2921 WMsg(p, err, str)
2922 struct win *p;
2923 int err;
2924 char *str;
2926 extern struct layer *flayer;
2927 struct layer *oldflayer = flayer;
2928 flayer = &p->w_layer;
2929 LMsg(err, str);
2930 flayer = oldflayer;
2933 void
2934 WChangeSize(p, w, h)
2935 struct win *p;
2936 int w, h;
2938 int wok = 0;
2939 struct canvas *cv;
2941 if (p->w_layer.l_cvlist == 0)
2943 /* window not displayed -> works always */
2944 ChangeWindowSize(p, w, h, p->w_histheight);
2945 return;
2947 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
2949 display = cv->c_display;
2950 if (p != D_fore)
2951 continue; /* change only fore */
2952 if (D_CWS)
2953 break;
2954 if (D_CZ0 && (w == Z0width || w == Z1width))
2955 wok = 1;
2957 if (cv == 0 && wok == 0) /* can't change any display */
2958 return;
2959 if (!D_CWS)
2960 h = p->w_height;
2961 ChangeWindowSize(p, w, h, p->w_histheight);
2962 for (display = displays; display; display = display->d_next)
2964 if (p == D_fore)
2966 if (D_cvlist && D_cvlist->c_next == 0)
2967 ResizeDisplay(w, h);
2968 else
2969 ResizeDisplay(w, D_height);
2970 ResizeLayersToCanvases(); /* XXX Hmm ? */
2971 continue;
2973 for (cv = D_cvlist; cv; cv = cv->c_next)
2974 if (cv->c_layer->l_bottom == &p->w_layer)
2975 break;
2976 if (cv)
2977 Redisplay(0);
2981 static int
2982 WindowChangedCheck(s, what, hp)
2983 char *s;
2984 int what;
2985 int *hp;
2987 int h = 0;
2988 int l;
2989 while(*s)
2991 if (*s++ != (hp ? '%' : '\005'))
2992 continue;
2993 l = 0;
2994 s += (*s == '+');
2995 s += (*s == '-');
2996 while (*s >= '0' && *s <= '9')
2997 s++;
2998 if (*s == 'L')
3000 s++;
3001 l = 0x100;
3003 if (*s == 'h')
3004 h = 1;
3005 if (*s == what || ((*s | l) == what) || what == 'd')
3006 break;
3007 if (*s)
3008 s++;
3010 if (hp)
3011 *hp = h;
3012 return *s ? 1 : 0;
3015 void
3016 WindowChanged(p, what)
3017 struct win *p;
3018 int what;
3020 int inwstr, inhstr, inlstr;
3021 int inwstrh = 0, inhstrh = 0, inlstrh = 0;
3022 int got, ox, oy;
3023 struct display *olddisplay = display;
3024 struct canvas *cv;
3026 inwstr = inhstr = 0;
3028 if (what == 'f')
3030 WindowChanged((struct win *)0, 'w'|0x100);
3031 WindowChanged((struct win *)0, 'W'|0x100);
3034 if (what)
3036 inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
3037 inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
3038 inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
3040 else
3042 inwstr = inhstr = 0;
3043 inlstr = 1;
3046 if (p == 0)
3048 for (display = displays; display; display = display->d_next)
3050 ox = D_x;
3051 oy = D_y;
3052 for (cv = D_cvlist; cv; cv = cv->c_next)
3054 if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3055 WListUpdatecv(cv, (struct win *)0);
3056 p = Layer2Window(cv->c_layer);
3057 if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3058 if (cv->c_ye + 1 < D_height)
3059 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3061 p = D_fore;
3062 if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
3063 RefreshHStatus();
3064 if (ox != -1 && ox != -1)
3065 GotoPos(ox, oy);
3067 display = olddisplay;
3068 return;
3071 if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
3073 inwstr |= inwstrh;
3074 inhstr |= inhstrh;
3075 inlstr |= inlstrh;
3077 if (!inwstr && !inhstr && !inlstr)
3078 return;
3079 for (display = displays; display; display = display->d_next)
3081 got = 0;
3082 ox = D_x;
3083 oy = D_y;
3084 for (cv = D_cvlist; cv; cv = cv->c_next)
3086 if (inlstr)
3087 WListUpdatecv(cv, p);
3088 if (Layer2Window(cv->c_layer) != p)
3089 continue;
3090 got = 1;
3091 if (inwstr && cv->c_ye + 1 < D_height)
3092 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3094 if (got && inhstr && p == D_fore)
3095 RefreshHStatus();
3096 if (ox != -1 && ox != -1)
3097 GotoPos(ox, oy);
3099 display = olddisplay;