386BSD 0.1 development
[unix-history] / usr / othersrc / public / screen-3.2 / screen3.2 / ansi.c
CommitLineData
bced42fb
WJ
1/* Copyright (c) 1991
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
5 * All rights reserved. Not derived from licensed software.
6 *
7 * Permission is granted to freely use, copy, modify, and redistribute
8 * this software, provided that no attempt is made to gain profit from it,
9 * the authors are not construed to be liable for any results of using the
10 * software, alterations are clearly marked as such, and this notice is
11 * not modified.
12 *
13 * Noteworthy contributors to screen's design and implementation:
14 * Wayne Davison (davison@borland.com)
15 * Patrick Wolfe (pat@kai.com, kailand!pat)
16 * Bart Schaefer (schaefer@cse.ogi.edu)
17 * Nathan Glasser (nathan@brokaw.lcs.mit.edu)
18 * Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
19 * Howard Chu (hyc@hanauma.jpl.nasa.gov)
20 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
21 * Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
22 * Marc Boucher (marc@CAM.ORG)
23 *
24 ****************************************************************
25 */
26
27#ifndef lint
28 static char rcs_id[] = "$Id: ansi.c,v 1.2 92/02/03 02:27:30 jnweiger Exp $ FAU";
29#endif
30
31#include <stdio.h>
32#include <sys/types.h>
33#ifdef BSDI
34#include <sys/signal.h>
35#endif /* BSDI */
36#include <fcntl.h>
37#include "config.h"
38#include "screen.h"
39#include "ansi.h"
40#include "extern.h"
41#ifndef sun /* we want to know about TIOCGWINSZ. jw. */
42# include <sys/ioctl.h>
43#endif
44
45extern char *getenv(), *tgetstr(), *tgoto();
46#ifndef __STDC__
47extern char *malloc();
48#endif
49
50extern struct win *fore;
51extern int ForeNum;
52extern force_vt, assume_LP;
53extern int BellDisplayed;
54extern int MsgMinWait;
55extern int all_norefresh;
56
57int TermcapROWS, TermcapCOLS; /* defaults that we learned from termcap */
58int default_width, default_height; /* width/height a new window will get */
59
60int maxwidth;
61
62int Z0width, Z1width; /* widths for Z0/Z1 switching */
63
64char display_tty[MAXPATH];
65int screenwidth, screenheight; /* width/height of the screen */
66int screentop, screenbot; /* scrollregion start/end */
67int screenx, screeny; /* cursor position */
68char GlobalAttr; /* current attributes */
69char GlobalCharset; /* current font */
70int insert; /* insert mode */
71int keypad; /* application keypad */
72int flow = 1; /* flow control */
73
74int status; /* status is displayed */
75static int status_lastx, status_lasty;
76
77static int rows, cols; /* window size of the curr window */
78
79int default_flow = -1, wrap = 1, default_monitor = 0;
80int visual_bell = 0, termcapHS, use_hardstatus = 1;
81char *Termcap, *extra_incap, *extra_outcap;
82static int Termcaplen;
83char *blank, *null, *LastMsg;
84char Term[MAXSTR+5]; /* +5: "TERM=" */
85char screenterm[20] = "screen";
86char *Z0, *Z1;
87int ISO2022, HS;
88time_t TimeDisplayed, time();
89
90/*
91 * the termcap routines need this to work
92 */
93short ospeed;
94char *BC;
95char *UP;
96
97static void AddCap __P((char *));
98static void MakeString __P((char *, char *, int, char *));
99static int Special __P((int));
100static void DoESC __P((int, int ));
101static void DoCSI __P((int, int ));
102static void CPutStr __P((char *, int));
103static void SetChar __P(());
104static void StartString __P((enum string_t));
105static void AddChar __P((int ));
106static void PrintChar __P((int ));
107static void PrintFlush __P((void));
108static void KeypadMode __P((int));
109static void DesignateCharset __P((int, int ));
110static void MapCharset __P((int));
111static void SaveCursor __P((void));
112static void RestoreCursor __P((void));
113static void CountChars __P((int));
114static int CalcCost __P((char *));
115static int Rewrite __P((int, int, int, int));
116static void BackSpace __P((void));
117static void Return __P((void));
118static void LineFeed __P((int));
119static void ReverseLineFeed __P((void));
120static void InsertAChar __P((int));
121static void InsertChar __P((int));
122static void DeleteChar __P((int));
123static void DeleteLine __P((int));
124static void InsertLine __P((int));
125static void ScrollUpMap __P((int));
126static void ScrollDownMap __P((int));
127static void Scroll __P((char *, int, int, char *));
128static void ForwardTab __P((void));
129static void BackwardTab __P((void));
130static void ClearScreen __P((void));
131static void ClearFromBOS __P((void));
132static void ClearToEOS __P((void));
133static void ClearLine __P((void));
134static void ClearToEOL __P((void));
135static void ClearFromBOL __P((void));
136static void ClearInLine __P((int, int, int, int ));
137static void CursorRight __P(());
138static void CursorUp __P(());
139static void CursorDown __P(());
140static void CursorLeft __P(());
141static void ASetMode __P((int));
142static void SelectRendition __P((void));
143static void FillWithEs __P((void));
144static void RedisplayLine __P((char *, char *, char *, int, int, int ));
145static void FindAKA __P((void));
146static void SetCurr __P((struct win *));
147static void inpRedisplayLine __P((int, int, int, int));
148static void process_inp_input __P((char **, int *));
149static void AbortInp __P((void));
150static void AKAfin __P((char *, int));
151static void Colonfin __P((char *, int));
152static void RAW_PUTCHAR __P((int));
153static char *e_tgetstr __P((char *, char **));
154static int e_tgetflag __P((char *));
155static int e_tgetnum __P((char *));
156
157
158static char *tbuf, *tentry, *termname;
159static char *tp;
160static char *TI, *TE, *BL, *VB, *CR, *NL, *CL, *IS;
161char *WS; /* used in ResizeScreen() */
162char *CE; /* used in help.c */
163static char *CM, *US, *UE, *SO, *SE, *CD, *DO, *SR, *SF, *AL;
164static char *CS, *DL, *DC, *IC, *IM, *EI, *ND, *KS, *KE;
165static char *MB, *MD, *MH, *MR, *ME, *PO, *PF, *HO;
166static char *TS, *FS, *DS, *VI, *VE, *VS;
167static char *CDC, *CDL, *CAL, *CUP, *CDO, *CLE, *CRI, *CIC;
168static char *attrtab[NATTR];
169static AM, MS, COP;
170int LP;
171/*
172 * Do not confuse S0 (es-zero), E0 (e-zero) with SO (es-oh), PO (pe-oh),
173 * Z0 (z-zero), DO (de-oh)... :-)
174 */
175static char *C0, *S0, *E0;
176static char c0_tab[256];
177/*
178 */
179static screencap = 0;
180char *OldImage, *OldAttr, *OldFont;
181static struct win *curr;
182static display = 1;
183static StrCost;
184static UPcost, DOcost, LEcost, NDcost, CRcost, IMcost, EIcost, NLcost;
185static tcLineLen;
186static StatLen;
187static lp_missing = 0;
188
189int in_ovl;
190int ovl_blockfore;
191void (*ovl_process)();
192void (*ovl_RedisplayLine)();
193int (*ovl_Rewrite)();
194
195static char *KeyCaps[] =
196{
197 "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9",
198 "kb", "kd", "kh", "kl", "ko", "kr", "ku",
199 "K1", "K2", "K3", "K4", "K5",
200 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "l8", "l9"
201};
202#define NKEYCAPS ((int)(sizeof(KeyCaps)/sizeof(*KeyCaps)))
203static char *KeyCapsArr[NKEYCAPS];
204
205static char TermcapConst[] = "\\\n\
206\t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
207\t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
208\t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\
209\t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:xv:";
210
211void
212InitTermcap()
213{
214 register char *s;
215 int i;
216
217 screencap = 0;
218 if ((s = getenv("SCREENCAP")) != 0)
219 {
220 if ((Termcap = malloc(strlen(s) + 10)) != 0)
221 {
222 sprintf(Termcap, "TERMCAP=%s", s);
223 screencap = 1;
224 }
225 }
226 else
227 Termcap = malloc((unsigned) 1024);
228 Termcaplen = 0;
229 tbuf = malloc((unsigned) 1024);
230 tentry = tp = malloc((unsigned) 1024);
231 if (!(Termcap && tbuf && tentry))
232 Msg_nomem;
233 bzero(tbuf, 1024);
234 if ((termname = getenv("TERM")) == 0)
235 Msg(0, "No TERM in environment.");
236 debug1("InitTermcap: looking for tgetent('%s');\n", termname);
237 if (tgetent(tbuf, termname) != 1)
238 Msg(0, "Cannot find termcap entry for %s.", termname);
239 debug1("got it:\n%s\n",tbuf);
240#ifdef DEBUG
241 if (extra_incap)
242 debug1("Extra incap: %s\n", extra_incap);
243 if (extra_outcap)
244 debug1("Extra outcap: %s\n", extra_outcap);
245#endif
246
247 TermcapCOLS = TermcapROWS = 0;
248 if (s = getenv("COLUMNS"))
249 TermcapCOLS = atoi(s);
250 if (TermcapCOLS <= 0)
251 TermcapCOLS = e_tgetnum("co");
252 if (TermcapCOLS <= 0)
253 TermcapCOLS = 80;
254 if (s = getenv("LINES"))
255 TermcapROWS = atoi(s);
256 if (TermcapROWS <= 0)
257 TermcapROWS = e_tgetnum("li");
258 if (TermcapROWS <= 0)
259 TermcapROWS = 24;
260
261 if (e_tgetflag("hc"))
262 Msg(0, "You can't run screen on a hardcopy terminal.");
263 if (e_tgetflag("os"))
264 Msg(0, "You can't run screen on a terminal that overstrikes.");
265 if (e_tgetflag("ns"))
266 Msg(0, "Terminal must support scrolling.");
267 if (!(CL = e_tgetstr("cl", &tp)))
268 Msg(0, "Clear screen capability required.");
269 if (!(CM = e_tgetstr("cm", &tp)))
270 Msg(0, "Addressable cursor capability required.");
271 if (default_flow < 0)
272 default_flow = e_tgetflag("NF") ? FLOW_NOW * 0 :
273 e_tgetflag("xo") ? FLOW_NOW * 1 :
274 FLOW_AUTOFLAG;
275 AM = e_tgetflag("am");
276 LP = assume_LP || (!extra_incap && !strncmp(termname, "vt", 2))
277 || !AM || e_tgetflag("LP") || e_tgetflag("xv");
278 COP = e_tgetflag("OP");
279 HO = e_tgetstr("ho", &tp);
280 TI = e_tgetstr("ti", &tp);
281 TE = e_tgetstr("te", &tp);
282 if (!(BL = e_tgetstr("bl", &tp)))
283 BL = "\007";
284 VB = e_tgetstr("vb", &tp);
285 if (!(BC = e_tgetstr("bc", &tp)))
286 {
287 if (e_tgetflag("bs"))
288 BC = "\b";
289 else
290 BC = e_tgetstr("le", &tp);
291 }
292 if (!(CR = e_tgetstr("cr", &tp)))
293 CR = "\r";
294 if (!(NL = e_tgetstr("nl", &tp)))
295 NL = "\n";
296 IS = e_tgetstr("is", &tp);
297 MS = 1;
298 if (e_tgetnum("sg") <= 0 && e_tgetnum("ug") <= 0)
299 {
300 MS = e_tgetflag("ms");
301 attrtab[ATTR_DI] = MH = e_tgetstr("mh", &tp); /* Dim */
302 attrtab[ATTR_US] = US = e_tgetstr("us", &tp); /* Underline */
303 attrtab[ATTR_BD] = MD = e_tgetstr("md", &tp); /* Bold */
304 attrtab[ATTR_RV] = MR = e_tgetstr("mr", &tp); /* Reverse */
305 attrtab[ATTR_SO] = SO = e_tgetstr("so", &tp); /* Standout */
306 attrtab[ATTR_BL] = MB = e_tgetstr("mb", &tp); /* Blinking */
307 ME = e_tgetstr("me", &tp);
308 SE = e_tgetstr("se", &tp);
309 UE = e_tgetstr("ue", &tp);
310 /*
311 * Does ME also reverse the effect of SO and/or US? This is not
312 * clearly specified by the termcap manual. Anyway, we should at
313 * least look whether ME and SE/UE are equal:
314 */
315 if (UE && ((SE && strcmp(SE, UE) == 0) || (ME && strcmp(ME, UE) == 0)))
316 UE = 0;
317 if (SE && (ME && strcmp(ME, SE) == 0))
318 SE = 0;
319
320 /* Set up missing entries */
321 s = 0;
322 for (i = NATTR-1; i >= 0; i--)
323 if (attrtab[i])
324 s = attrtab[i];
325 for (i = 0; i < NATTR; i++)
326 {
327 if (attrtab[i] == 0)
328 attrtab[i] = s;
329 else
330 s = attrtab[i];
331 }
332 }
333 else
334 {
335 US = UE = SO = SE = MB = MD = MH = MR = ME = 0;
336 for (i = 0; i < NATTR; i++)
337 attrtab[i] = 0;
338 }
339 CE = e_tgetstr("ce", &tp);
340 CD = e_tgetstr("cd", &tp);
341 if (!(DO = e_tgetstr("do", &tp)))
342 DO = NL;
343 UP = e_tgetstr("up", &tp);
344 ND = e_tgetstr("nd", &tp);
345 SR = e_tgetstr("sr", &tp);
346 if (!(SF = e_tgetstr("sf", &tp)))
347 SF = NL;
348 AL = e_tgetstr("al", &tp);
349 DL = e_tgetstr("dl", &tp);
350 CS = e_tgetstr("cs", &tp);
351 DC = e_tgetstr("dc", &tp);
352 IC = e_tgetstr("ic", &tp);
353 CIC = e_tgetstr("IC", &tp);
354 CDC = e_tgetstr("DC", &tp);
355 CDL = e_tgetstr("DL", &tp);
356 CAL = e_tgetstr("AL", &tp);
357 CUP = e_tgetstr("UP", &tp);
358 CDO = e_tgetstr("DO", &tp);
359 CLE = e_tgetstr("LE", &tp);
360 CRI = e_tgetstr("RI", &tp);
361 IM = e_tgetstr("im", &tp);
362 EI = e_tgetstr("ei", &tp);
363 if (e_tgetflag("in"))
364 IC = IM = 0;
365 if (IC && IC[0] == '\0')
366 IC = 0;
367 if (CIC && CIC[0] == '\0')
368 CIC = 0;
369 if (IM && IM[0] == '\0')
370 IM = 0;
371 if (EI && EI[0] == '\0')
372 EI = 0;
373 if (EI == 0)
374 IM = 0;
375 if (IC && IM && strcmp(IC, IM) == 0)
376 IC = 0;
377 KS = e_tgetstr("ks", &tp);
378 KE = e_tgetstr("ke", &tp);
379 if (KE == 0)
380 KS = 0;
381 ISO2022 = e_tgetflag("G0");
382 if (ISO2022)
383 {
384 if ((S0 = e_tgetstr("S0", &tp)) == NULL)
385#ifdef TERMINFO
386 S0 = "\033(%p1%c";
387#else
388 S0 = "\033(%.";
389#endif
390 if ((E0 = e_tgetstr("E0", &tp)) == NULL)
391 E0 = "\033(B";
392 C0 = e_tgetstr("C0", &tp);
393 }
394 else if ((S0 = e_tgetstr("as", &tp)) != NULL
395 && (E0 = e_tgetstr("ae", &tp)) != NULL)
396 {
397 ISO2022 = 1;
398 C0 = e_tgetstr("ac", &tp);
399 }
400 else
401 {
402 S0 = E0 = "";
403 C0 = "g.h.i'j-k-l-m-n+o~p\"q-r-s_t+u+v+w+x|y<z>";
404 }
405 for (i = 0; i < 256; i++)
406 c0_tab[i] = i;
407 if (C0)
408 for (i = strlen(C0)&~1; i >= 0; i-=2)
409 c0_tab[C0[i]] = C0[i+1];
410 debug1("ISO2022 = %d\n", ISO2022);
411 /* WS changes the window size */
412 WS = e_tgetstr("WS", &tp);
413 VI = e_tgetstr("vi", &tp);
414 VE = e_tgetstr("ve", &tp);
415 VS = e_tgetstr("vs", &tp);
416 PO = e_tgetstr("po", &tp);
417 if (!(PF = e_tgetstr("pf", &tp)))
418 PO = 0;
419 debug2("terminal size is %d, %d (says TERMCAP)\n", TermcapCOLS, TermcapROWS);
420 /* Termcap fields Z0 & Z1 contain width-changing sequences. */
421 if ((Z0 = e_tgetstr("Z0", &tp)) != NULL
422 && (Z1 = e_tgetstr("Z1", &tp)) == NULL)
423 Z0 = NULL;
424
425 Z0width = 132;
426 Z1width = 80;
427
428 CheckScreenSize(0);
429 if ((HS = e_tgetflag("hs")) != 0)
430 {
431 debug("oy! we have a hardware status line, says termcap\n");
432 TS = e_tgetstr("ts", &tp);
433 FS = e_tgetstr("fs", &tp);
434 DS = e_tgetstr("ds", &tp);
435 if ((HS = e_tgetnum("ws")) <= 0)
436 HS = screenwidth;
437 if (!TS || !FS || !DS)
438 HS = 0;
439 }
440 termcapHS = HS;
441 if (!use_hardstatus)
442 HS = 0;
443
444 UPcost = CalcCost(UP);
445 DOcost = CalcCost(DO);
446 NLcost = CalcCost(NL);
447 LEcost = CalcCost(BC);
448 NDcost = CalcCost(ND);
449 CRcost = CalcCost(CR);
450 IMcost = CalcCost(IM);
451 EIcost = CalcCost(EI);
452 for (i = 0; i < NKEYCAPS; i++)
453 KeyCapsArr[i] = e_tgetstr(KeyCaps[i], &tp);
454 MakeTermcap(0);
455}
456
457/*
458 * if the adaptflag is on, we keep the size of this display, else
459 * we may try to restore our old window sizes.
460 */
461void
462InitTerm(adapt)
463int adapt;
464{
465 display = 1;
466 screentop = screenbot = -1;
467 PutStr(IS);
468 PutStr(TI);
469 if (IM && strcmp(IM, EI))
470 PutStr(EI);
471 insert = 0;
472 if (KS && strcmp(KS, KE))
473 PutStr(KE);
474 keypad = 0;
475 PutStr(E0);
476 GlobalCharset = ASCII;
477 ResizeScreen((struct win *)0);
478 ChangeScrollRegion(0, screenheight-1);
479 PutStr(CL);
480 screenx = screeny = 0;
481 fflush(stdout);
482 debug1("we %swant to adapt all our windows to the display\n",
483 (adapt) ? "" : "don't ");
484 /* In case the size was changed by a init sequence */
485 CheckScreenSize((adapt) ? 2 : 0);
486}
487
488void
489FinitTerm()
490{
491 display = 1;
492 InsertMode(0);
493 KeypadMode(0);
494 ResizeScreen((struct win *)0);
495 ChangeScrollRegion(0, screenheight - 1);
496 SaveSetAttr(0, ASCII);
497 screenx = screeny = -1;
498 GotoPos(0, screenheight - 1);
499 PutStr(TE);
500 fflush(stdout);
501 if (Termcap)
502 {
503 Free(Termcap);
504 debug("FinitTerm: old termcap freed\n");
505 }
506 if (tbuf)
507 {
508 Free(tbuf);
509 debug("FinitTerm: old tbuf freed\n");
510 }
511 if (tentry)
512 {
513 Free(tentry);
514 debug("FinitTerm: old tentry freed\n");
515 }
516}
517
518static void AddCap(s)
519char *s;
520{
521 register int n;
522
523 if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < 1024-4)
524 {
525 strcpy(Termcap + Termcaplen, "\\\n\t:");
526 Termcaplen += 4;
527 tcLineLen = 0;
528 }
529 if (Termcaplen + n < 1024)
530 {
531 strcpy(Termcap + Termcaplen, s);
532 Termcaplen += n;
533 tcLineLen += n;
534 }
535 else
536 Msg(0, "TERMCAP overflow - sorry.");
537}
538
539char *MakeTermcap(aflag)
540int aflag;
541{
542 char buf[1024];
543 register char *p, *cp, ch;
544 int i;
545
546 if (screencap)
547 {
548 sprintf(Term, "TERM=screen");
549 return Termcap;
550 }
551 if (screenterm == 0 || *screenterm == '\0')
552 {
553 debug("MakeTermcap sets screenterm=screen\n");
554 strcpy(screenterm, "screen");
555 }
556 for (;;)
557 {
558 sprintf(Term, "TERM=");
559 p = Term + 5;
560 if (!aflag && strlen(screenterm) + strlen(termname) < MAXSTR-1)
561 {
562 sprintf(p, "%s.%s", screenterm, termname);
563 if (tgetent(buf, p) == 1)
564 break;
565 }
566 if (screenwidth >= 132)
567 {
568 sprintf(p, "%s-w", screenterm);
569 if (tgetent(buf, p) == 1)
570 break;
571 }
572 sprintf(p, "%s", screenterm);
573 if (tgetent(buf, p) == 1)
574 break;
575 sprintf(p, "vt100");
576 break;
577 }
578 tcLineLen = 100; /* Force NL */
579 sprintf(Termcap,
580 "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal|", p);
581 Termcaplen = strlen(Termcap);
582 if (extra_outcap && *extra_outcap)
583 {
584 for (cp = extra_outcap; p = index(cp, ':'); cp = p)
585 {
586 ch = *++p;
587 *p = '\0';
588 AddCap(cp);
589 *p = ch;
590 }
591 tcLineLen = 100; /* Force NL */
592 }
593 if (Termcaplen + strlen(TermcapConst) < 1024)
594 {
595 strcpy(Termcap + Termcaplen, TermcapConst);
596 Termcaplen += strlen(TermcapConst);
597 }
598 sprintf(buf, "li#%d:co#%d:", screenheight, screenwidth);
599 AddCap(buf);
600 if ((force_vt && !COP) || LP || !AM)
601 AddCap("LP:");
602 else
603 AddCap("am:");
604 if (VB)
605 AddCap("vb=\\E[?5h\\E[?5l:");
606 if (US)
607 {
608 AddCap("us=\\E[4m:");
609 AddCap("ue=\\E[24m:");
610 }
611 if (SO)
612 {
613 AddCap("so=\\E[3m:");
614 AddCap("se=\\E[23m:");
615 }
616 if (MB)
617 AddCap("mb=\\E[5m:");
618 if (MD)
619 AddCap("md=\\E[1m:");
620 if (MH)
621 AddCap("mh=\\E[2m:");
622 if (MR)
623 AddCap("mr=\\E[7m:");
624 if (MB || MD || MH || MR)
625 AddCap("me=\\E[m:ms:");
626 if ((CS && SR) || AL || CAL || aflag)
627 {
628 AddCap("sr=\\EM:");
629 AddCap("al=\\E[L:");
630 AddCap("AL=\\E[%dL:");
631 }
632 else if (SR)
633 AddCap("sr=\\EM:");
634 if (CS || DL || CDL || aflag)
635 {
636 AddCap("dl=\\E[M:");
637 AddCap("DL=\\E[%dM:");
638 }
639 if (CS)
640 AddCap("cs=\\E[%i%d;%dr:");
641 if (DC || CDC || aflag)
642 {
643 AddCap("dc=\\E[P:");
644 AddCap("DC=\\E[%dP:");
645 }
646 if (CIC || IC || IM || aflag)
647 {
648 AddCap("im=\\E[4h:");
649 AddCap("ei=\\E[4l:");
650 AddCap("mi:");
651 AddCap("ic=\\E[@:");
652 AddCap("IC=\\E[%d@:");
653 }
654 if (KS)
655 AddCap("ks=\\E=:");
656 if (KE)
657 AddCap("ke=\\E>:");
658 if (ISO2022)
659 AddCap("G0:");
660 if (PO)
661 {
662 AddCap("po=\\E[5i:");
663 AddCap("pf=\\E[4i:");
664 }
665 if (Z0)
666 {
667 AddCap("Z0=\\E[?3h:");
668 AddCap("Z1=\\E[?3l:");
669 }
670 if (WS)
671 AddCap("WS=\\E[8;%d;%dt:");
672 for (i = 0; i < NKEYCAPS; i++)
673 {
674 if (KeyCapsArr[i] == 0)
675 continue;
676 MakeString(KeyCaps[i], buf, sizeof(buf), KeyCapsArr[i]);
677 AddCap(buf);
678 }
679 return Termcap;
680}
681
682static void MakeString(cap, buf, buflen, s)
683char *cap, *buf;
684int buflen;
685char *s;
686{
687 register char *p, *pmax;
688 register unsigned int c;
689
690 p = buf;
691 pmax = p + buflen - (3+4+2);
692 *p++ = *cap++;
693 *p++ = *cap;
694 *p++ = '=';
695 while ((c = *s++) && (p < pmax))
696 {
697 switch (c)
698 {
699 case '\033':
700 *p++ = '\\';
701 *p++ = 'E';
702 break;
703 case ':':
704 sprintf(p, "\\072");
705 p += 4;
706 break;
707 case '^':
708 case '\\':
709 *p++ = '\\';
710 *p++ = c;
711 break;
712 default:
713 if (c >= 200)
714 {
715 sprintf(p, "\\%03o", c & 0377);
716 p += 4;
717 }
718 else if (c < ' ')
719 {
720 *p++ = '^';
721 *p++ = c + '@';
722 }
723 else
724 *p++ = c;
725 }
726 }
727 *p++ = ':';
728 *p = '\0';
729}
730
731void
732Activate(norefresh)
733int norefresh;
734{
735 debug1("Activate(%d)\n", norefresh);
736 if (display)
737 RemoveStatus();
738 display = fore->active = 1;
739 ResizeScreen(fore);
740 SetCurr(fore);
741 debug3("Fore (%d) has size %dx%d", ForeNum, curr->width, curr->height);
742 debug1("(%d)\n", curr->histheight);
743 ChangeScrollRegion(curr->top, curr->bot);
744 KeypadMode(curr->keypad);
745 SetFlow(curr->flow & FLOW_NOW);
746 if (curr->monitor != MON_OFF)
747 curr->monitor = MON_ON;
748 curr->bell = BELL_OFF;
749 Redisplay(norefresh || all_norefresh);
750}
751
752void
753ResetScreen(p)
754register struct win *p;
755{
756 register int i;
757
758 p->wrap = wrap;
759 p->origin = 0;
760 p->insert = 0;
761 p->vbwait = 0;
762 p->keypad = 0;
763 p->top = 0;
764 p->bot = p->height - 1;
765 p->saved = 0;
766 p->LocalAttr = 0;
767 p->x = p->y = 0;
768 p->state = LIT;
769 p->StringType = NONE;
770 p->ss = 0;
771 p->LocalCharset = G0;
772 bzero(p->tabs, p->width);
773 for (i = 8; i < p->width; i += 8)
774 p->tabs[i] = 1;
775 for (i = G0; i <= G3; i++)
776 p->charsets[i] = ASCII;
777}
778
779void
780WriteString(wp, buf, len)
781struct win *wp;
782char *buf;
783int len;
784{
785 register int c, intermediate = 0;
786
787 if (!len)
788 return;
789 if (wp->logfp != NULL)
790 if ((int)fwrite(buf, len, 1, wp->logfp) < 1)
791 {
792 extern int errno;
793
794 Msg(errno, "Error writing logfile");
795 fclose(wp->logfp);
796 wp->logfp = NULL;
797 }
798 /*
799 * SetCurr() here may prevent output, as it may set display = 0
800 */
801 SetCurr(wp);
802 if (display)
803 {
804 if (!HS)
805 RemoveStatus();
806 }
807 else if (curr->monitor == MON_ON)
808 curr->monitor = MON_FOUND;
809
810 do
811 {
812 c = (unsigned char)*buf++;
813 if (c == '\0' || c == '\177')
814 continue;
815 NextChar:
816 switch (curr->state)
817 {
818 case PRIN:
819 switch (c)
820 {
821 case '\033':
822 curr->state = PRINESC;
823 break;
824 default:
825 PrintChar(c);
826 }
827 break;
828 case PRINESC:
829 switch (c)
830 {
831 case '[':
832 curr->state = PRINCSI;
833 break;
834 default:
835 PrintChar('\033');
836 PrintChar(c);
837 curr->state = PRIN;
838 }
839 break;
840 case PRINCSI:
841 switch (c)
842 {
843 case '4':
844 curr->state = PRIN4;
845 break;
846 default:
847 PrintChar('\033');
848 PrintChar('[');
849 PrintChar(c);
850 curr->state = PRIN;
851 }
852 break;
853 case PRIN4:
854 switch (c)
855 {
856 case 'i':
857 curr->state = LIT;
858 PrintFlush();
859 break;
860 default:
861 PrintChar('\033');
862 PrintChar('[');
863 PrintChar('4');
864 PrintChar(c);
865 curr->state = PRIN;
866 }
867 break;
868 case STRESC:
869 switch (c)
870 {
871 case '\\':
872 curr->state = LIT;
873 *(curr->stringp) = '\0';
874 switch (curr->StringType)
875 {
876 case PM:
877 if (!display)
878 break;
879 MakeStatus(curr->string);
880 if (!HS && status && len > 1)
881 {
882 curr->outlen = len - 1;
883 bcopy(buf, curr->outbuf, curr->outlen);
884 return;
885 }
886 break;
887 case DCS:
888 if (display)
889 printf("%s", curr->string);
890 break;
891 case AKA:
892 if (curr->akapos == 0 && !*curr->string)
893 break;
894 strncpy(curr->cmd + curr->akapos, curr->string, 20);
895 if (!*curr->string)
896 curr->autoaka = curr->y + 1;
897 break;
898 default:
899 break;
900 }
901 break;
902 default:
903 curr->state = ASTR;
904 AddChar('\033');
905 AddChar(c);
906 }
907 break;
908 case ASTR:
909 switch (c)
910 {
911 case '\0':
912 break;
913 case '\033':
914 curr->state = STRESC;
915 break;
916 default:
917 AddChar(c);
918 }
919 break;
920 case ESC:
921 switch (c)
922 {
923 case '[':
924 curr->NumArgs = 0;
925 intermediate = 0;
926 bzero((char *) curr->args, MAXARGS * sizeof(int));
927 curr->state = CSI;
928 break;
929 case ']':
930 StartString(OSC);
931 break;
932 case '_':
933 StartString(APC);
934 break;
935 case 'P':
936 StartString(DCS);
937 break;
938 case '^':
939 StartString(PM);
940 break;
941 case '"':
942 case 'k':
943 StartString(AKA);
944 break;
945 default:
946 if (Special(c))
947 break;
948 if (c >= ' ' && c <= '/')
949 intermediate = intermediate ? -1 : c;
950 else if (c >= '0' && c <= '~')
951 {
952 DoESC(c, intermediate);
953 curr->state = LIT;
954 }
955 else
956 {
957 curr->state = LIT;
958 goto NextChar;
959 }
960 }
961 break;
962 case CSI:
963 switch (c)
964 {
965 case '0':
966 case '1':
967 case '2':
968 case '3':
969 case '4':
970 case '5':
971 case '6':
972 case '7':
973 case '8':
974 case '9':
975 if (curr->NumArgs < MAXARGS)
976 {
977 curr->args[curr->NumArgs] =
978 10 * curr->args[curr->NumArgs] + c - '0';
979 }
980 break;
981 case ';':
982 case ':':
983 curr->NumArgs++;
984 break;
985 default:
986 if (Special(c))
987 break;
988 if (c >= '@' && c <= '~')
989 {
990 curr->NumArgs++;
991 DoCSI(c, intermediate);
992 if (curr->state != PRIN)
993 curr->state = LIT;
994 }
995 else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
996 intermediate = intermediate ? -1 : c;
997 else
998 {
999 curr->state = LIT;
1000 goto NextChar;
1001 }
1002 }
1003 break;
1004 case LIT:
1005 default:
1006 if (!Special(c))
1007 {
1008 if (c == '\033')
1009 {
1010 intermediate = 0;
1011 curr->state = ESC;
1012 if (display && lp_missing && (CIC || IC || IM))
1013 {
1014 RedisplayLine(blank, null, null, screenbot,
1015 cols - 2, cols - 1);
1016 GotoPos(curr->x, curr->y);
1017 }
1018 if (curr->autoaka < 0)
1019 curr->autoaka = 0;
1020 }
1021 else if (c < ' ')
1022 break;
1023 else
1024 {
1025 NewRendition(curr->LocalAttr);
1026 NewCharset(curr->charsets[(curr->ss) ? curr->ss :
1027 curr->LocalCharset]);
1028 if (curr->x < cols - 1)
1029 {
1030 if (curr->insert)
1031 InsertAChar(c);
1032 else
1033 {
1034 if (display)
1035 PUTCHAR(c);
1036 SetChar(c);
1037 }
1038 curr->x++;
1039 }
1040 else if (curr->x == cols - 1)
1041 {
1042 if (curr->wrap && (LP || !force_vt || COP))
1043 {
1044 if (display)
1045 RAW_PUTCHAR(c);
1046 SetChar(c);
1047 if (AM && !LP)
1048 {
1049 curr->x = 0; /* terminal auto-wrapped */
1050 LineFeed(0);
1051 }
1052 else
1053 curr->x++;
1054 }
1055 else
1056 {
1057 if (display)
1058 {
1059 if (LP || curr->y != screenbot)
1060 {
1061 RAW_PUTCHAR(c);
1062 GotoPos(curr->x, curr->y);
1063 }
1064 else
1065 CheckLP(c);
1066 }
1067 SetChar(c);
1068 if (curr->wrap)
1069 curr->x++;
1070 }
1071 }
1072 else
1073 {
1074 LineFeed(2); /* cr+lf, handle LP */
1075 if (curr->insert)
1076 InsertAChar(c);
1077 else
1078 {
1079 if (display)
1080 PUTCHAR(c);
1081 SetChar(c);
1082 }
1083 curr->x = 1;
1084 }
1085 if (curr->ss)
1086 {
1087 NewCharset(curr->charsets[curr->LocalCharset]);
1088 curr->ss = 0;
1089 }
1090 }
1091 }
1092 }
1093 } while (--len);
1094 curr->outlen = 0;
1095 if (curr->state == PRIN)
1096 PrintFlush();
1097}
1098
1099static int Special(c)
1100register int c;
1101{
1102 switch (c)
1103 {
1104 case '\b':
1105 BackSpace();
1106 return 1;
1107 case '\r':
1108 Return();
1109 return 1;
1110 case '\n':
1111 if (curr->autoaka)
1112 FindAKA();
1113 LineFeed(1);
1114 return 1;
1115 case '\007':
1116 if (!visual_bell)
1117 PutStr(BL);
1118 else
1119 {
1120 if (!VB)
1121 curr->bell = BELL_VISUAL;
1122 else
1123 PutStr(VB);
1124 }
1125 if (!display)
1126 curr->bell = BELL_ON;
1127 return 1;
1128 case '\t':
1129 ForwardTab();
1130 return 1;
1131 case '\017': /* SI */
1132 MapCharset(G0);
1133 return 1;
1134 case '\016': /* SO */
1135 MapCharset(G1);
1136 return 1;
1137 }
1138 return 0;
1139}
1140
1141static void DoESC(c, intermediate)
1142int c, intermediate;
1143{
1144 switch (intermediate)
1145 {
1146 case 0:
1147 switch (c)
1148 {
1149 case 'E':
1150 LineFeed(2);
1151 break;
1152 case 'D':
1153 LineFeed(1);
1154 break;
1155 case 'M':
1156 ReverseLineFeed();
1157 break;
1158 case 'H':
1159 curr->tabs[curr->x] = 1;
1160 break;
1161 case 'Z': /* jph: Identify as VT100 */
1162 Report(curr, "\033[?%d;%dc", 1, 2);
1163 break;
1164 case '7':
1165 SaveCursor();
1166 break;
1167 case '8':
1168 RestoreCursor();
1169 break;
1170 case 'c':
1171 ClearScreen();
1172 ResetScreen(curr);
1173 NewRendition(0);
1174 NewCharset(ASCII);
1175 InsertMode(0);
1176 KeypadMode(0);
1177 ChangeScrollRegion(0, rows-1);
1178 break;
1179 case '=':
1180 KeypadMode(curr->keypad = 1);
1181#if !defined(TIOCPKT) || defined(sgi)
1182 NewAutoFlow(curr, 0);
1183#endif /* !TIOCPKT || sgi */
1184 break;
1185 case '>':
1186 KeypadMode(curr->keypad = 0);
1187#if !defined(TIOCPKT) || defined(sgi)
1188 NewAutoFlow(curr, 1);
1189#endif /* !TIOCPKT || sgi */
1190 break;
1191 case 'n': /* LS2 */
1192 MapCharset(G2);
1193 break;
1194 case 'o': /* LS3 */
1195 MapCharset(G3);
1196 break;
1197 case 'N': /* SS2 */
1198 if (curr->charsets[curr->LocalCharset] != curr->charsets[G2])
1199 curr->ss = G2;
1200 else
1201 curr->ss = 0;
1202 break;
1203 case 'O': /* SS3 */
1204 if (curr->charsets[curr->LocalCharset] != curr->charsets[G3])
1205 curr->ss = G3;
1206 else
1207 curr->ss = 0;
1208 break;
1209 }
1210 break;
1211 case '#':
1212 switch (c)
1213 {
1214 case '8':
1215 FillWithEs();
1216 break;
1217 }
1218 break;
1219 case '(':
1220 DesignateCharset(c, G0);
1221 break;
1222 case ')':
1223 DesignateCharset(c, G1);
1224 break;
1225 case '*':
1226 DesignateCharset(c, G2);
1227 break;
1228 case '+':
1229 DesignateCharset(c, G3);
1230 break;
1231 }
1232}
1233
1234static void DoCSI(c, intermediate)
1235int c, intermediate;
1236{
1237 register int i, a1 = curr->args[0], a2 = curr->args[1];
1238
1239 if (curr->NumArgs > MAXARGS)
1240 curr->NumArgs = MAXARGS;
1241 switch (intermediate)
1242 {
1243 case 0:
1244 switch (c)
1245 {
1246 case 'H':
1247 case 'f':
1248 if (a1 < 1)
1249 a1 = 1;
1250 if (curr->origin)
1251 a1 += curr->top;
1252 if (a1 > rows)
1253 a1 = rows;
1254 if (a2 < 1)
1255 a2 = 1;
1256 if (a2 > cols)
1257 a2 = cols;
1258 GotoPos(--a2, --a1);
1259 curr->x = a2;
1260 curr->y = a1;
1261 if (curr->autoaka)
1262 curr->autoaka = a1 + 1;
1263 break;
1264 case 'J':
1265 if (a1 < 0 || a1 > 2)
1266 a1 = 0;
1267 switch (a1)
1268 {
1269 case 0:
1270 ClearToEOS();
1271 break;
1272 case 1:
1273 ClearFromBOS();
1274 break;
1275 case 2:
1276 ClearScreen();
1277 GotoPos(curr->x, curr->y);
1278 break;
1279 }
1280 break;
1281 case 'K':
1282 if (a1 < 0 || a1 > 2)
1283 a1 %= 3;
1284 switch (a1)
1285 {
1286 case 0:
1287 ClearToEOL();
1288 break;
1289 case 1:
1290 ClearFromBOL();
1291 break;
1292 case 2:
1293 ClearLine();
1294 break;
1295 }
1296 break;
1297 case 'A':
1298 CursorUp(a1 ? a1 : 1);
1299 break;
1300 case 'B':
1301 CursorDown(a1 ? a1 : 1);
1302 break;
1303 case 'C':
1304 CursorRight(a1 ? a1 : 1);
1305 break;
1306 case 'D':
1307 CursorLeft(a1 ? a1 : 1);
1308 break;
1309 case 'm':
1310 SelectRendition();
1311 break;
1312 case 'g':
1313 if (a1 == 0)
1314 curr->tabs[curr->x] = 0;
1315 else if (a1 == 3)
1316 bzero(curr->tabs, cols);
1317 break;
1318 case 'r':
1319 if (!a1)
1320 a1 = 1;
1321 if (!a2)
1322 a2 = rows;
1323 if (a1 < 1 || a2 > rows || a1 >= a2)
1324 break;
1325 curr->top = a1 - 1;
1326 curr->bot = a2 - 1;
1327 ChangeScrollRegion(curr->top, curr->bot);
1328 if (curr->origin)
1329 {
1330 GotoPos(0, curr->top);
1331 curr->y = curr->top;
1332 curr->x = 0;
1333 }
1334 else
1335 {
1336 GotoPos(0, 0);
1337 curr->y = curr->x = 0;
1338 }
1339 break;
1340 case 's':
1341 SaveCursor();
1342 break;
1343 case 't':
1344 if (a1 != 8)
1345 break;
1346 a1 = curr->args[2];
1347 if (a1 < 1)
1348 a1 = curr->width;
1349 if (a2 < 1)
1350 a2 = curr->height;
1351 if (WS == NULL)
1352 {
1353 a2 = curr->height;
1354 if (Z0 == NULL || (a1 != Z0width && a1 != Z1width))
1355 a1 = curr->width;
1356 }
1357 if (a1 == curr->width && a2 == curr->height)
1358 break;
1359 ChangeWindowSize(curr, a1, a2);
1360 SetCurr(curr);
1361 if (display)
1362 Activate(0);
1363 break;
1364 case 'u':
1365 RestoreCursor();
1366 break;
1367 case 'I':
1368 if (!a1)
1369 a1 = 1;
1370 while (a1--)
1371 ForwardTab();
1372 break;
1373 case 'Z':
1374 if (!a1)
1375 a1 = 1;
1376 while (a1--)
1377 BackwardTab();
1378 break;
1379 case 'L':
1380 InsertLine(a1 ? a1 : 1);
1381 break;
1382 case 'M':
1383 DeleteLine(a1 ? a1 : 1);
1384 break;
1385 case 'P':
1386 DeleteChar(a1 ? a1 : 1);
1387 break;
1388 case '@':
1389 InsertChar(a1 ? a1 : 1);
1390 break;
1391 case 'h':
1392 ASetMode(1);
1393 break;
1394 case 'l':
1395 ASetMode(0);
1396 break;
1397 case 'i':
1398 if (PO && a1 == 5)
1399 {
1400 curr->stringp = curr->string;
1401 curr->state = PRIN;
1402 }
1403 break;
1404 case 'n':
1405 if (a1 == 6) /* Report cursor position */
1406 Report(curr, "\033[%d;%dR", curr->y + 1, curr->x + 1);
1407 break;
1408 case 'c': /* Identify as VT100 */
1409 Report(curr, "\033[?%d;%dc", 1, 2);
1410 break;
1411 }
1412 break;
1413 case '?':
1414 debug2("\\E[?%d%c\n",a1,c);
1415 if (c != 'h' && c != 'l')
1416 break;
1417 i = (c == 'h');
1418 switch (a1)
1419 {
1420 case 3:
1421 i = (i ? Z0width : Z1width);
1422 if ((Z0 || WS) && curr->width != i)
1423 {
1424 ChangeWindowSize(curr, i, curr->height);
1425 SetCurr(curr);
1426 if (display)
1427 Activate(0);
1428 }
1429 break;
1430 case 5:
1431 if (i)
1432 curr->vbwait = 1;
1433 else
1434 {
1435 if (curr->vbwait)
1436 PutStr(VB);
1437 curr->vbwait = 0;
1438 }
1439 break;
1440 case 6:
1441 if ((curr->origin = i) != 0)
1442 {
1443 GotoPos(0, curr->top);
1444 curr->y = curr->top;
1445 curr->x = 0;
1446 }
1447 else
1448 {
1449 GotoPos(0, 0);
1450 curr->y = curr->x = 0;
1451 }
1452 break;
1453 case 7:
1454 curr->wrap = i;
1455 break;
1456 case 35:
1457 debug1("Cursor %svisible\n", i?"in":"");
1458 curr->cursor_invisible = i;
1459 break;
1460 }
1461 break;
1462 }
1463}
1464
1465void
1466INSERTCHAR(c)
1467int c;
1468{
1469 if (!insert && (IC || CIC))
1470 {
1471 if (IC)
1472 PutStr(IC);
1473 else
1474 CPutStr(CIC, 1);
1475 RAW_PUTCHAR(c);
1476 return;
1477 }
1478 InsertMode(1);
1479 if (insert)
1480 RAW_PUTCHAR(c);
1481 else
1482 RefreshLine(screeny, screenx, screenwidth-1);
1483}
1484
1485void
1486PUTCHAR(c)
1487int c;
1488{
1489 if (insert)
1490 InsertMode(0);
1491 RAW_PUTCHAR(c);
1492}
1493
1494/*
1495 * RAW_PUTCHAR() is for all text that will be displayed.
1496 * NOTE, that charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1497 */
1498
1499static void
1500RAW_PUTCHAR(c)
1501int c;
1502{
1503 if (GlobalCharset == '0')
1504 putchar(c0_tab[c]);
1505 else
1506 putchar(c);
1507 if (screenx < screenwidth - 1)
1508 screenx++;
1509 else
1510 {
1511 screenx++;
1512 if ((AM && !LP) || screenx > screenwidth)
1513 {
1514 screenx -= screenwidth;
1515 if (screeny < screenheight-1 && screeny != screenbot)
1516 screeny++;
1517 }
1518 }
1519}
1520
1521void
1522PutChar(c)
1523int c;
1524{
1525 /* this PutChar for ESC-sequences only */
1526 putchar(c);
1527}
1528
1529void
1530PutStr(s)
1531char *s;
1532{
1533 if (display && s)
1534 tputs(s, 1, PutChar);
1535}
1536
1537static void CPutStr(s, c)
1538char *s;
1539int c;
1540{
1541 if (display && s)
1542 tputs(tgoto(s, 0, c), 1, PutChar);
1543}
1544
1545static void SetChar(c)
1546register int c;
1547{
1548 register struct win *p = curr;
1549
1550 p->image[p->y][p->x] = c;
1551 p->attr[p->y][p->x] = p->LocalAttr;
1552 p->font[p->y][p->x] = p->charsets[p->ss ? p->ss : p->LocalCharset];
1553}
1554
1555static void StartString(type)
1556enum string_t type;
1557{
1558 curr->StringType = type;
1559 curr->stringp = curr->string;
1560 curr->state = ASTR;
1561}
1562
1563static void AddChar(c)
1564int c;
1565{
1566 if (curr->stringp >= curr->string + MAXSTR - 1)
1567 curr->state = LIT;
1568 else
1569 *(curr->stringp)++ = c;
1570}
1571
1572static void PrintChar(c)
1573int c;
1574{
1575 if (curr->stringp >= curr->string + MAXSTR - 1)
1576 PrintFlush();
1577 *(curr->stringp)++ = c;
1578}
1579
1580static void PrintFlush()
1581{
1582 if (curr->stringp > curr->string)
1583 {
1584 tputs(PO, 1, PutChar);
1585 (void) fflush(stdout);
1586 (void) write(1, curr->string, curr->stringp - curr->string);
1587 tputs(PF, 1, PutChar);
1588 (void) fflush(stdout);
1589 curr->stringp = curr->string;
1590 }
1591}
1592
1593/* Insert mode is a toggle on some terminals, so we need this hack:
1594 */
1595void
1596InsertMode(on)
1597int on;
1598{
1599 if (display && on != insert && IM)
1600 {
1601 insert = on;
1602 if (insert)
1603 PutStr(IM);
1604 else
1605 PutStr(EI);
1606 }
1607}
1608
1609/* ...and maybe keypad application mode is a toggle, too:
1610 */
1611static void KeypadMode(on)
1612int on;
1613{
1614 if (display && keypad != on && KS)
1615 {
1616 keypad = on;
1617 if (keypad)
1618 PutStr(KS);
1619 else
1620 PutStr(KE);
1621 }
1622}
1623
1624void
1625NewAutoFlow(win, on)
1626struct win *win;
1627int on;
1628{
1629 debug1("NewAutoFlow: %d\n", on);
1630 SetCurr(win);
1631 if (win->flow & FLOW_AUTOFLAG)
1632 win->flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
1633 else
1634 win->flow = (win->flow & ~FLOW_AUTO) | FLOW_AUTO * on;
1635 if (display)
1636 SetFlow(win->flow & FLOW_NOW);
1637}
1638
1639static void DesignateCharset(c, n)
1640int c, n;
1641{
1642 curr->ss = 0;
1643 if (c == 'B')
1644 c = ASCII;
1645 if (curr->charsets[n] != c)
1646 {
1647 curr->charsets[n] = c;
1648 if (curr->LocalCharset == n)
1649 NewCharset(c);
1650 }
1651}
1652
1653static void MapCharset(n)
1654int n;
1655{
1656 curr->ss = 0;
1657 if (curr->LocalCharset != n)
1658 {
1659 curr->LocalCharset = n;
1660 NewCharset(curr->charsets[n]);
1661 }
1662}
1663
1664void
1665NewCharset(new)
1666int new;
1667{
1668 if (!display || GlobalCharset == new)
1669 return;
1670 GlobalCharset = new;
1671 if (new == ASCII)
1672 PutStr(E0);
1673 else
1674 CPutStr(S0, new);
1675}
1676
1677static void SaveCursor()
1678{
1679 curr->saved = 1;
1680 curr->Saved_x = curr->x;
1681 curr->Saved_y = curr->y;
1682 curr->SavedLocalAttr = curr->LocalAttr;
1683 curr->SavedLocalCharset = curr->LocalCharset;
1684 bcopy((char *) curr->charsets, (char *) curr->SavedCharsets,
1685 4 * sizeof(int));
1686}
1687
1688static void RestoreCursor()
1689{
1690 if (curr->saved)
1691 {
1692 GotoPos(curr->Saved_x, curr->Saved_y);
1693 curr->x = curr->Saved_x;
1694 curr->y = curr->Saved_y;
1695 curr->LocalAttr = curr->SavedLocalAttr;
1696 NewRendition(curr->LocalAttr);
1697 bcopy((char *) curr->SavedCharsets, (char *) curr->charsets,
1698 4 * sizeof(int));
1699 curr->LocalCharset = curr->SavedLocalCharset;
1700 NewCharset(curr->charsets[curr->LocalCharset]);
1701 }
1702}
1703
1704/*ARGSUSED*/
1705static void CountChars(c)
1706int c;
1707{
1708 StrCost++;
1709}
1710
1711static int CalcCost(s)
1712register char *s;
1713{
1714 if (s)
1715 {
1716 StrCost = 0;
1717 tputs(s, 1, CountChars);
1718 return StrCost;
1719 }
1720 else
1721 return EXPENSIVE;
1722}
1723
1724void
1725GotoPos(x2, y2)
1726int x2, y2;
1727{
1728 register int dy, dx, x1, y1;
1729 register int costx, costy;
1730 register int m;
1731 register char *s;
1732 int CMcost;
1733 enum move_t xm = M_NONE, ym = M_NONE;
1734
1735 if (!display)
1736 return;
1737
1738 x1 = screenx;
1739 y1 = screeny;
1740
1741 if (x1 == screenwidth)
1742 if (LP && AM)
1743 x1 = -1; /* don't know how the terminal treats this */
1744 else
1745 x1--;
1746 if (x2 == screenwidth)
1747 x2--;
1748 dx = x2 - x1;
1749 dy = y2 - y1;
1750 if (dy == 0 && dx == 0)
1751 {
1752 return;
1753 }
1754 if (!MS && GlobalAttr) /* Safe to move in SO mode ? */
1755 NewRendition(0);
1756 if (y1 < 0 /* don't know the y position */
1757 || (y2 > screenbot && y1 <= screenbot) /* have to cross border */
1758 || (y2 < screentop && y1 >= screentop)) /* of scrollregion ? */
1759 {
1760 DoCM:
1761 if (HO && !x2 && !y2)
1762 PutStr(HO);
1763 else
1764 PutStr(tgoto(CM, x2, y2));
1765 screenx = x2;
1766 screeny = y2;
1767 return;
1768 }
1769 /* Calculate CMcost */
1770 if (HO && !x2 && !y2)
1771 s = HO;
1772 else
1773 s = tgoto(CM, x2, y2);
1774 CMcost = CalcCost(s);
1775
1776 /* Calculate the cost to move the cursor to the right x position */
1777 costx = EXPENSIVE;
1778 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1779 {
1780 if (dx > 0)
1781 {
1782 if (CRI && (dx > 1 || !ND))
1783 {
1784 costx = CalcCost(tgoto(CRI, 0, dx));
1785 xm = M_CRI;
1786 }
1787 if ((m = NDcost * dx) < costx)
1788 {
1789 costx = m;
1790 xm = M_RI;
1791 }
1792 /* Speedup: dx <= Rewrite() */
1793 if (dx < costx && (m = Rewrite(y1, x1, x2, 0)) < costx)
1794 {
1795 costx = m;
1796 xm = M_RW;
1797 }
1798 }
1799 else if (dx < 0)
1800 {
1801 if (CLE && (dx < -1 || !BC))
1802 {
1803 costx = CalcCost(tgoto(CLE, 0, -dx));
1804 xm = M_CLE;
1805 }
1806 if ((m = -dx * LEcost) < costx)
1807 {
1808 costx = m;
1809 xm = M_LE;
1810 }
1811 }
1812 else
1813 costx = 0;
1814 }
1815 /* Speedup: Rewrite() >= x2 */
1816 if (x2 + CRcost < costx && (m = Rewrite(y1, 0, x2, 0) + CRcost) < costx)
1817 {
1818 costx = m;
1819 xm = M_CR;
1820 }
1821
1822 /* Check if it is already cheaper to do CM */
1823 if (costx >= CMcost)
1824 goto DoCM;
1825
1826 /* Calculate the cost to move the cursor to the right y position */
1827 costy = EXPENSIVE;
1828 if (dy > 0)
1829 {
1830 if (CDO && dy > 1) /* DO & NL are always != 0 */
1831 {
1832 costy = CalcCost(tgoto(CDO, 0, dy));
1833 ym = M_CDO;
1834 }
1835 if ((m = dy * ((x2 == 0) ? NLcost : DOcost)) < costy)
1836 {
1837 costy = m;
1838 ym = M_DO;
1839 }
1840 }
1841 else if (dy < 0)
1842 {
1843 if (CUP && (dy < -1 || !UP))
1844 {
1845 costy = CalcCost(tgoto(CUP, 0, -dy));
1846 ym = M_CUP;
1847 }
1848 if ((m = -dy * UPcost) < costy)
1849 {
1850 costy = m;
1851 ym = M_UP;
1852 }
1853 }
1854 else
1855 costy = 0;
1856
1857 /* Finally check if it is cheaper to do CM */
1858 if (costx + costy >= CMcost)
1859 goto DoCM;
1860
1861 switch (xm)
1862 {
1863 case M_LE:
1864 while (dx++ < 0)
1865 PutStr(BC);
1866 break;
1867 case M_CLE:
1868 CPutStr(CLE, -dx);
1869 break;
1870 case M_RI:
1871 while (dx-- > 0)
1872 PutStr(ND);
1873 break;
1874 case M_CRI:
1875 CPutStr(CRI, dx);
1876 break;
1877 case M_CR:
1878 PutStr(CR);
1879 screenx = 0;
1880 x1 = 0;
1881 /* FALLTHROUGH */
1882 case M_RW:
1883 if (x1 < x2)
1884 (void) Rewrite(y1, x1, x2, 1);
1885 break;
1886 default:
1887 break;
1888 }
1889 switch (ym)
1890 {
1891 case M_UP:
1892 while (dy++ < 0)
1893 PutStr(UP);
1894 break;
1895 case M_CUP:
1896 CPutStr(CUP, -dy);
1897 break;
1898 case M_DO:
1899 s = (x2 == 0) ? NL : DO;
1900 while (dy-- > 0)
1901 PutStr(s);
1902 break;
1903 case M_CDO:
1904 CPutStr(CDO, dy);
1905 break;
1906 default:
1907 break;
1908 }
1909 screenx = x2;
1910 screeny = y2;
1911}
1912
1913static int
1914Rewrite(y, x1, x2, doit)
1915int y, x1, x2, doit;
1916{
1917 register int cost, dx;
1918 register char *p, *f, *i;
1919
1920 if (x1 == x2)
1921 return(0);
1922 if (in_ovl)
1923 {
1924 if (ovl_Rewrite == 0)
1925 return EXPENSIVE;
1926 else
1927 return ((*ovl_Rewrite)(y, x1, x2, doit));
1928 }
1929 dx = x2 - x1;
1930 if (doit)
1931 {
1932 i = curr->image[y] + x1;
1933 while (dx-- > 0)
1934 PUTCHAR(*i++);
1935 return(0);
1936 }
1937 p = curr->attr[y] + x1;
1938 f = curr->font[y] + x1;
1939
1940 cost = dx = x2 - x1;
1941 if (insert)
1942 cost += EIcost + IMcost;
1943 while(dx-- > 0)
1944 {
1945 if (*p++ != GlobalAttr || *f++ != GlobalCharset)
1946 return EXPENSIVE;
1947 }
1948 return cost;
1949}
1950
1951static void BackSpace()
1952{
1953 if (curr->x > 0)
1954 {
1955 curr->x--;
1956 }
1957 else if (curr->wrap && curr->y > 0)
1958 {
1959 curr->x = cols - 1;
1960 curr->y--;
1961 }
1962 if (display)
1963 GotoPos(curr->x, curr->y);
1964}
1965
1966static void Return()
1967{
1968 if (curr->x > 0)
1969 {
1970 curr->x = 0;
1971 if (display)
1972 GotoPos(curr->x, curr->y);
1973 }
1974}
1975
1976static void LineFeed(out_mode)
1977int out_mode;
1978{
1979 /* out_mode: 0=no-output lf, 1=lf, 2=cr+lf */
1980 if (out_mode == 2)
1981 curr->x = 0;
1982 if (curr->y != curr->bot) /* Don't scroll */
1983 {
1984 if (curr->y < rows-1)
1985 curr->y++;
1986 if (out_mode && display)
1987 GotoPos(curr->x, curr->y);
1988 return;
1989 }
1990 ScrollUpMap(1);
1991 if (curr->autoaka > 1)
1992 curr->autoaka--;
1993 if (out_mode && display)
1994 {
1995 ScrollRegion(curr->top, curr->bot, 1);
1996 GotoPos(curr->x, curr->y);
1997 }
1998}
1999
2000static void ReverseLineFeed()
2001{
2002 if (curr->y == curr->top)
2003 {
2004 ScrollDownMap(1);
2005 if (!display)
2006 return;
2007 ScrollRegion(curr->top, curr->bot, -1);
2008 GotoPos(curr->x, curr->y);
2009 }
2010 else if (curr->y > 0)
2011 CursorUp(1);
2012}
2013
2014static void InsertAChar(c)
2015int c;
2016{
2017 register int y = curr->y, x = curr->x;
2018
2019 if (x == cols)
2020 x--;
2021 bcopy(curr->image[y], OldImage, cols);
2022 bcopy(curr->attr[y], OldAttr, cols);
2023 bcopy(curr->font[y], OldFont, cols);
2024 bcopy(curr->image[y] + x, curr->image[y] + x + 1, cols - x - 1);
2025 bcopy(curr->attr[y] + x, curr->attr[y] + x + 1, cols - x - 1);
2026 bcopy(curr->font[y] + x, curr->font[y] + x + 1, cols - x - 1);
2027 SetChar(c);
2028 if (!display)
2029 return;
2030 if (CIC || IC || IM)
2031 {
2032 InsertMode(curr->insert);
2033 INSERTCHAR(c);
2034 if (y == screenbot)
2035 lp_missing = 0;
2036 }
2037 else
2038 {
2039 RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
2040 GotoPos(++x, y);
2041 }
2042}
2043
2044static void InsertChar(n)
2045int n;
2046{
2047 register int i, y = curr->y, x = curr->x;
2048
2049 if (n <= 0)
2050 return;
2051 /*
2052 * The termcap manual states that only one of IM and IC is
2053 * to be defined unless the terminal needs both sequences.
2054 * We don't like this because we think that there may be cases
2055 * where it is preferable to send IC instead of IM/EI.
2056 * The hack is to ignore the IC sequence if we are already
2057 * in insert mode, so that programs which follow the termcap
2058 * guidelines still work. (I don't believe that there are
2059 * terminals which need IC in the insert mode. Why switch to
2060 * insert mode if you must send IC before every character ?)
2061 */
2062 if (curr->insert)
2063 return;
2064 if (x == cols)
2065 --x;
2066 bcopy(curr->image[y], OldImage, cols);
2067 bcopy(curr->attr[y], OldAttr, cols);
2068 bcopy(curr->font[y], OldFont, cols);
2069 if (n > cols - x)
2070 n = cols - x;
2071 bcopy(curr->image[y] + x, curr->image[y] + x + n, cols - x - n);
2072 bcopy(curr->attr[y] + x, curr->attr[y] + x + n, cols - x - n);
2073 bcopy(curr->font[y] + x, curr->font[y] + x + n, cols - x - n);
2074 ClearInLine(0, y, x, x + n - 1);
2075 if (!display)
2076 return;
2077 if (IC || CIC || IM)
2078 {
2079 if (y == screenbot)
2080 lp_missing = 0;
2081 if (!insert)
2082 {
2083 if (n == 1 && IC)
2084 {
2085 PutStr(IC);
2086 return;
2087 }
2088 if (CIC)
2089 {
2090 CPutStr(CIC, n);
2091 return;
2092 }
2093 }
2094 InsertMode(1);
2095 for (i = n; i--; )
2096 INSERTCHAR(' ');
2097 GotoPos(x, y);
2098 }
2099 else
2100 {
2101 RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
2102 GotoPos(x, y);
2103 }
2104}
2105
2106static void DeleteChar(n)
2107int n;
2108{
2109 register int i, y = curr->y, x = curr->x;
2110
2111 if (x == cols)
2112 --x;
2113 bcopy(curr->image[y], OldImage, cols);
2114 bcopy(curr->attr[y], OldAttr, cols);
2115 bcopy(curr->font[y], OldFont, cols);
2116 if (n > cols - x)
2117 n = cols - x;
2118 bcopy(curr->image[y] + x + n, curr->image[y] + x, cols - x - n);
2119 bcopy(curr->attr[y] + x + n, curr->attr[y] + x, cols - x - n);
2120 bcopy(curr->font[y] + x + n, curr->font[y] + x, cols - x - n);
2121 ClearInLine(0, y, cols - n, cols - 1);
2122 if (!display)
2123 return;
2124 if (CDC && !(n == 1 && DC))
2125 {
2126 CPutStr(CDC, n);
2127 if (lp_missing && y == screenbot)
2128 {
2129 FixLP(cols - 1 - n, y);
2130 GotoPos(x, y);
2131 }
2132 }
2133 else if (DC)
2134 {
2135 for (i = n; i; i--)
2136 PutStr(DC);
2137 if (lp_missing && y == screenbot)
2138 {
2139 FixLP(cols - 1 - n, y);
2140 GotoPos(x, y);
2141 }
2142 }
2143 else
2144 {
2145 RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
2146 GotoPos(x, y);
2147 }
2148}
2149
2150static void DeleteLine(n)
2151int n;
2152{
2153 register int old = curr->top;
2154
2155 if (curr->y < curr->top || curr->y > curr->bot)
2156 return;
2157 if (n > curr->bot - curr->y + 1)
2158 n = curr->bot - curr->y + 1;
2159 curr->top = curr->y;
2160 ScrollUpMap(n);
2161 curr->top = old;
2162 if (!display)
2163 return;
2164 ScrollRegion(curr->y, curr->bot, n);
2165 GotoPos(curr->x, curr->y);
2166}
2167
2168static void InsertLine(n)
2169int n;
2170{
2171 register int old = curr->top;
2172
2173 if (curr->y < curr->top || curr->y > curr->bot)
2174 return;
2175 if (n > curr->bot - curr->y + 1)
2176 n = curr->bot - curr->y + 1;
2177 curr->top = curr->y;
2178 ScrollDownMap(n);
2179 curr->top = old;
2180 if (!display)
2181 return;
2182 ScrollRegion(curr->y, curr->bot, -n);
2183 GotoPos(curr->x, curr->y);
2184}
2185
2186void
2187ScrollRegion(ys, ye, n)
2188int ys, ye, n;
2189{
2190 int i;
2191 int up;
2192 int oldtop, oldbot;
2193 int alok, dlok, aldlfaster;
2194 int missy = 0;
2195
2196 if (n == 0)
2197 return;
2198 if (ys == 0 && ye == screenheight-1 &&
2199 (n >= screenheight || -n >= screenheight))
2200 {
2201 PutStr(CL);
2202 screeny = screenx = 0;
2203 lp_missing = 0;
2204 return;
2205 }
2206
2207 if (lp_missing)
2208 {
2209 if (screenbot>ye || screenbot<ys)
2210 missy = screenbot;
2211 else
2212 {
2213 missy = screenbot - n;
2214 if (missy>ye || missy<ys)
2215 lp_missing = 0;
2216 }
2217 }
2218
2219 up = 1;
2220 if (n < 0)
2221 {
2222 up = 0;
2223 n = -n;
2224 }
2225 if (n >= ye-ys+1)
2226 n = ye-ys+1;
2227
2228 oldtop = screentop;
2229 oldbot = screenbot;
2230 if (screenbot != ye)
2231 ChangeScrollRegion(ys, ye);
2232 alok = (AL || CAL || (ye == screenbot && up));
2233 dlok = (DL || CDL || (ye == screenbot && !up));
2234 if (screentop != ys && !(alok && dlok))
2235 ChangeScrollRegion(ys, ye);
2236
2237 if (lp_missing &&
2238 (oldbot != screenbot ||
2239 (oldbot == screenbot && up && screentop == ys && screenbot == ye)))
2240 {
2241 /* Can't use FixLP */
2242 GotoPos(screenwidth-1, oldbot);
2243 SaveSetAttr(curr->attr[missy][screenwidth-1], curr->font[missy][screenwidth-1]);
2244 PUTCHAR(curr->image[missy][screenwidth-1]);
2245 RestoreAttr();
2246 lp_missing = 0;
2247 if (oldbot == screenbot) /* have scrolled */
2248 {
2249 if (--n == 0)
2250 {
2251 ChangeScrollRegion(oldtop, oldbot);
2252 return;
2253 }
2254 }
2255 }
2256
2257 aldlfaster = (n > 1 && ye == screenbot && ((up && CDL) || (!up && CAL)));
2258
2259 if ((up || SR) && screentop == ys && screenbot == ye && !aldlfaster)
2260 {
2261 if (up)
2262 {
2263 GotoPos(0, ye);
2264 while (n-- > 0)
2265 PutStr(NL); /* was SF, I think NL is faster */
2266 }
2267 else
2268 {
2269 GotoPos(0, ys);
2270 while (n-- > 0)
2271 PutStr(SR);
2272 }
2273 }
2274 else if (alok && dlok)
2275 {
2276 if (up || ye != screenbot)
2277 {
2278 GotoPos(0, up ? ys : ye+1-n);
2279 if (CDL && !(n == 1 && DL))
2280 CPutStr(CDL, n);
2281 else
2282 for(i=n; i--; )
2283 PutStr(DL);
2284 }
2285 if (!up || ye != screenbot)
2286 {
2287 GotoPos(0, up ? ye+1-n : ys);
2288 if (CAL && !(n == 1 && AL))
2289 CPutStr(CAL, n);
2290 else
2291 for(i=n; i--; )
2292 PutStr(AL);
2293 }
2294 }
2295 else
2296 {
2297 Redisplay(0);
2298 return;
2299 }
2300 if (lp_missing && missy != screenbot)
2301 FixLP(screenwidth-1, missy);
2302 ChangeScrollRegion(oldtop, oldbot);
2303 if (lp_missing && missy != screenbot)
2304 FixLP(screenwidth-1, missy);
2305}
2306
2307static void ScrollUpMap(n)
2308int n;
2309{
2310 char tmp[256 * sizeof(char *)];
2311 register int ii, i, cnt1, cnt2;
2312 register char **ppi, **ppa, **ppf;
2313
2314 i = curr->top + n;
2315 cnt1 = n * sizeof(char *);
2316 cnt2 = (curr->bot - i + 1) * sizeof(char *);
2317 ppi = curr->image + i;
2318 ppa = curr->attr + i;
2319 ppf = curr->font + i;
2320 for(ii = curr->top; ii < i; ii++)
2321 AddLineToHist(curr, &curr->image[ii], &curr->attr[ii], &curr->font[ii]);
2322 for (i = n; i; --i)
2323 {
2324 bclear(*--ppi, cols);
2325 bzero(*--ppa, cols);
2326 bzero(*--ppf, cols);
2327 }
2328 Scroll((char *) ppi, cnt1, cnt2, tmp);
2329 Scroll((char *) ppa, cnt1, cnt2, tmp);
2330 Scroll((char *) ppf, cnt1, cnt2, tmp);
2331}
2332
2333static void ScrollDownMap(n)
2334int n;
2335{
2336 char tmp[256 * sizeof(char *)];
2337 register int i, cnt1, cnt2;
2338 register char **ppi, **ppa, **ppf;
2339
2340 i = curr->top;
2341 cnt1 = (curr->bot - i - n + 1) * sizeof(char *);
2342 cnt2 = n * sizeof(char *);
2343 Scroll((char *) (ppi = curr->image + i), cnt1, cnt2, tmp);
2344 Scroll((char *) (ppa = curr->attr + i), cnt1, cnt2, tmp);
2345 Scroll((char *) (ppf = curr->font + i), cnt1, cnt2, tmp);
2346 for (i = n; i; --i)
2347 {
2348 bclear(*ppi++, cols);
2349 bzero(*ppa++, cols);
2350 bzero(*ppf++, cols);
2351 }
2352}
2353
2354static void Scroll(cp, cnt1, cnt2, tmp)
2355char *cp, *tmp;
2356int cnt1, cnt2;
2357{
2358 if (!cnt1 || !cnt2)
2359 return;
2360 if (cnt1 <= cnt2)
2361 {
2362 bcopy(cp, tmp, cnt1);
2363 bcopy(cp + cnt1, cp, cnt2);
2364 bcopy(tmp, cp + cnt2, cnt1);
2365 }
2366 else
2367 {
2368 bcopy(cp + cnt1, tmp, cnt2);
2369 bcopy(cp, cp + cnt2, cnt1);
2370 bcopy(tmp, cp, cnt2);
2371 }
2372}
2373
2374static void ForwardTab()
2375{
2376 register int x = curr->x;
2377
2378 if (x == cols)
2379 {
2380 LineFeed(2);
2381 x = 0;
2382 }
2383 if (curr->tabs[x] && x < cols - 1)
2384 x++;
2385 while (x < cols - 1 && !curr->tabs[x])
2386 x++;
2387 GotoPos(x, curr->y);
2388 curr->x = x;
2389}
2390
2391static void BackwardTab()
2392{
2393 register int x = curr->x;
2394
2395 if (curr->tabs[x] && x > 0)
2396 x--;
2397 while (x > 0 && !curr->tabs[x])
2398 x--;
2399 GotoPos(x, curr->y);
2400 curr->x = x;
2401}
2402
2403static void ClearScreen()
2404{
2405 register int i;
2406 register char **ppi = curr->image, **ppa = curr->attr, **ppf = curr->font;
2407
2408 for (i = 0; i < rows; ++i)
2409 {
2410 AddLineToHist(curr, ppi, ppa, ppf);
2411 bclear(*ppi++, cols);
2412 bzero(*ppa++, cols);
2413 bzero(*ppf++, cols);
2414 }
2415 if (display)
2416 {
2417 PutStr(CL);
2418 screenx = screeny = 0;
2419 lp_missing = 0;
2420 }
2421}
2422
2423static void ClearFromBOS()
2424{
2425 register int n, y = curr->y, x = curr->x;
2426
2427 for (n = 0; n < y; ++n)
2428 ClearInLine(1, n, 0, cols - 1);
2429 ClearInLine(1, y, 0, x);
2430 GotoPos(x, y);
2431 RestoreAttr();
2432}
2433
2434static void ClearToEOS()
2435{
2436 register int n, y = curr->y, x = curr->x;
2437
2438 if (!y && !x)
2439 {
2440 ClearScreen();
2441 return;
2442 }
2443 if (display && CD)
2444 {
2445 PutStr(CD);
2446 lp_missing = 0;
2447 }
2448 ClearInLine(!CD, y, x, cols - 1);
2449 for (n = y + 1; n < rows; n++)
2450 ClearInLine(!CD, n, 0, cols - 1);
2451 GotoPos(x, y);
2452 RestoreAttr();
2453}
2454
2455static void ClearLine()
2456{
2457 register int y = curr->y, x = curr->x;
2458
2459 ClearInLine(1, y, 0, cols - 1);
2460 GotoPos(x, y);
2461 RestoreAttr();
2462}
2463
2464static void ClearToEOL()
2465{
2466 register int y = curr->y, x = curr->x;
2467
2468 ClearInLine(1, y, x, cols - 1);
2469 GotoPos(x, y);
2470 RestoreAttr();
2471}
2472
2473static void ClearFromBOL()
2474{
2475 register int y = curr->y, x = curr->x;
2476
2477 ClearInLine(1, y, 0, x);
2478 GotoPos(x, y);
2479 RestoreAttr();
2480}
2481
2482static void ClearInLine(displ, y, x1, x2)
2483int displ, y, x1, x2;
2484{
2485 register int n;
2486
2487 if (x1 == cols)
2488 x1--;
2489 if (x2 == cols)
2490 x2--;
2491 if ((n = x2 - x1 + 1) != 0)
2492 {
2493 if (displ && display)
2494 {
2495 if (x2 == cols - 1 && CE)
2496 {
2497 GotoPos(x1, y);
2498 PutStr(CE);
2499 if (y == screenbot)
2500 lp_missing = 0;
2501 }
2502 else
2503 DisplayLine(curr->image[y], curr->attr[y], curr->font[y],
2504 blank, null, null, y, x1, x2);
2505 }
2506 if (curr)
2507 {
2508 bclear(curr->image[y] + x1, n);
2509 bzero(curr->attr[y] + x1, n);
2510 bzero(curr->font[y] + x1, n);
2511 }
2512 }
2513}
2514
2515static void CursorRight(n)
2516register int n;
2517{
2518 register int x = curr->x;
2519
2520 if (x == cols)
2521 {
2522 LineFeed(2);
2523 x = 0;
2524 }
2525 if ((curr->x += n) >= cols)
2526 curr->x = cols - 1;
2527 GotoPos(curr->x, curr->y);
2528}
2529
2530static void CursorUp(n)
2531register int n;
2532{
2533 if (curr->y < curr->top) /* if above scrolling rgn, */
2534 {
2535 if ((curr->y -= n) < 0) /* ignore its limits */
2536 curr->y = 0;
2537 }
2538 else
2539 if ((curr->y -= n) < curr->top)
2540 curr->y = curr->top;
2541 GotoPos(curr->x, curr->y);
2542}
2543
2544static void CursorDown(n)
2545register int n;
2546{
2547 if (curr->y > curr->bot) /* if below scrolling rgn, */
2548 {
2549 if ((curr->y += n) > rows - 1) /* ignore its limits */
2550 curr->y = rows - 1;
2551 }
2552 else
2553 if ((curr->y += n) > curr->bot)
2554 curr->y = curr->bot;
2555 GotoPos(curr->x, curr->y);
2556}
2557
2558static void CursorLeft(n)
2559register int n;
2560{
2561 if ((curr->x -= n) < 0)
2562 curr->x = 0;
2563 GotoPos(curr->x, curr->y);
2564}
2565
2566static void ASetMode(on)
2567int on;
2568{
2569 register int i;
2570
2571 for (i = 0; i < curr->NumArgs; ++i)
2572 {
2573 switch (curr->args[i])
2574 {
2575 case 4:
2576 curr->insert = on;
2577 InsertMode(on);
2578 break;
2579 }
2580 }
2581}
2582
2583static void SelectRendition()
2584{
2585 register int i = 0, a = curr->LocalAttr;
2586
2587 do
2588 {
2589 switch (curr->args[i])
2590 {
2591 case 0:
2592 a = 0;
2593 break;
2594 case 1:
2595 a |= A_BD;
2596 break;
2597 case 2:
2598 a |= A_DI;
2599 break;
2600 case 3:
2601 a |= A_SO;
2602 break;
2603 case 4:
2604 a |= A_US;
2605 break;
2606 case 5:
2607 a |= A_BL;
2608 break;
2609 case 7:
2610 a |= A_RV;
2611 break;
2612 case 22:
2613 a &= ~(A_BD | A_SO | A_DI);
2614 break;
2615 case 23:
2616 a &= ~A_SO;
2617 break;
2618 case 24:
2619 a &= ~A_US;
2620 break;
2621 case 25:
2622 a &= ~A_BL;
2623 break;
2624 case 27:
2625 a &= ~A_RV;
2626 break;
2627 }
2628 } while (++i < curr->NumArgs);
2629 NewRendition(curr->LocalAttr = a);
2630}
2631
2632void
2633NewRendition(new)
2634register int new;
2635{
2636 register int i, old = GlobalAttr;
2637
2638 if (!display || old == new)
2639 return;
2640 GlobalAttr = new;
2641 for (i = 1; i <= A_MAX; i <<= 1)
2642 {
2643 if ((old & i) && !(new & i))
2644 {
2645 PutStr(UE);
2646 PutStr(SE);
2647 PutStr(ME);
2648 if (new & A_DI)
2649 PutStr(attrtab[ATTR_DI]);
2650 if (new & A_US)
2651 PutStr(attrtab[ATTR_US]);
2652 if (new & A_BD)
2653 PutStr(attrtab[ATTR_BD]);
2654 if (new & A_RV)
2655 PutStr(attrtab[ATTR_RV]);
2656 if (new & A_SO)
2657 PutStr(attrtab[ATTR_SO]);
2658 if (new & A_BL)
2659 PutStr(attrtab[ATTR_BL]);
2660 return;
2661 }
2662 }
2663 if ((new & A_DI) && !(old & A_DI))
2664 PutStr(attrtab[ATTR_DI]);
2665 if ((new & A_US) && !(old & A_US))
2666 PutStr(attrtab[ATTR_US]);
2667 if ((new & A_BD) && !(old & A_BD))
2668 PutStr(attrtab[ATTR_BD]);
2669 if ((new & A_RV) && !(old & A_RV))
2670 PutStr(attrtab[ATTR_RV]);
2671 if ((new & A_SO) && !(old & A_SO))
2672 PutStr(attrtab[ATTR_SO]);
2673 if ((new & A_BL) && !(old & A_BL))
2674 PutStr(attrtab[ATTR_BL]);
2675}
2676
2677void
2678SaveSetAttr(newattr, newcharset)
2679int newattr, newcharset;
2680{
2681 NewRendition(newattr);
2682 NewCharset(newcharset);
2683}
2684
2685void
2686RestoreAttr()
2687{
2688 NewRendition(curr->LocalAttr);
2689 NewCharset(curr->charsets[curr->LocalCharset]);
2690}
2691
2692static void FillWithEs()
2693{
2694 register int i;
2695 register char *p, *ep;
2696
2697 curr->y = curr->x = 0;
2698 for (i = 0; i < rows; ++i)
2699 {
2700 bzero(curr->attr[i], cols);
2701 bzero(curr->font[i], cols);
2702 p = curr->image[i];
2703 ep = p + cols;
2704 while (p < ep)
2705 *p++ = 'E';
2706 }
2707 if (display)
2708 Redisplay(0);
2709}
2710
2711/*
2712 * if cur_only, we only redisplay current line, as a full refresh is
2713 * too expensive.
2714 */
2715void Redisplay(cur_only)
2716int cur_only;
2717{
2718 register int i, stop;
2719
2720 PutStr(CL);
2721 screenx = screeny = 0;
2722 lp_missing = 0;
2723 stop = rows; i = 0;
2724 if (cur_only)
2725 {
2726 i = stop = curr->y;
2727 stop++;
2728 }
2729 for (; i < stop; ++i)
2730 {
2731 if (in_ovl)
2732 (*ovl_RedisplayLine)(i, 0, cols - 1, 1);
2733 else
2734 DisplayLine(blank, null, null, curr->image[i], curr->attr[i],
2735 curr->font[i], i, 0, cols - 1);
2736 }
2737 if (!in_ovl)
2738 {
2739 GotoPos(curr->x, curr->y);
2740 NewRendition(curr->LocalAttr);
2741 NewCharset(curr->charsets[curr->LocalCharset]);
2742 }
2743}
2744
2745void
2746DisplayLine(os, oa, of, s, as, fs, y, from, to)
2747int from, to, y;
2748register char *os, *oa, *of, *s, *as, *fs;
2749{
2750 register int x;
2751 int last2flag = 0, delete_lp = 0;
2752
2753 if (!LP && y == screenbot && to == cols - 1)
2754 if (lp_missing
2755 || s[to] != os[to] || as[to] != oa[to] || of[to] != fs[to])
2756 {
2757 if ((IC || IM) && (from < to || !in_ovl))
2758 {
2759 if ((to -= 2) < from - 1)
2760 from--;
2761 last2flag = 1;
2762 lp_missing = 0;
2763 }
2764 else
2765 {
2766 to--;
2767 delete_lp = (CE || DC || CDC);
2768 lp_missing = (s[to] != ' ' || as[to] || fs[to]);
2769 }
2770 }
2771 else
2772 to--;
2773 for (x = from; x <= to; ++x)
2774 {
2775 if (s[x] == os[x] && as[x] == oa[x] && of[x] == fs[x])
2776 continue;
2777 GotoPos(x, y);
2778 NewRendition(as[x]);
2779 NewCharset(fs[x]);
2780 PUTCHAR(s[x]);
2781 }
2782 if (last2flag)
2783 {
2784 GotoPos(x, y);
2785 NewRendition(as[x + 1]);
2786 NewCharset(fs[x + 1]);
2787 PUTCHAR(s[x + 1]);
2788 GotoPos(x, y);
2789 NewRendition(as[x]);
2790 NewCharset(fs[x]);
2791 INSERTCHAR(s[x]);
2792 }
2793 else if (delete_lp)
2794 {
2795 if (DC)
2796 PutStr(DC);
2797 else if (CDC)
2798 CPutStr(CDC, 1);
2799 else if (CE)
2800 PutStr(CE);
2801 }
2802}
2803
2804void
2805RefreshLine(y, from, to)
2806int y, from, to;
2807{
2808 char *oi = null;
2809
2810 if (CE && to == screenwidth-1)
2811 {
2812 GotoPos(from, y);
2813 PutStr(CE);
2814 oi = blank;
2815 }
2816 if (in_ovl)
2817 (*ovl_RedisplayLine)(y, from, to, (oi == blank));
2818 else
2819 DisplayLine(oi, null, null, curr->image[y], curr->attr[y],
2820 curr->font[y], y, from, to);
2821}
2822
2823static void RedisplayLine(os, oa, of, y, from, to)
2824int from, to, y;
2825char *os, *oa, *of;
2826{
2827 DisplayLine(os, oa, of, curr->image[y], curr->attr[y],
2828 curr->font[y], y, from, to);
2829 NewRendition(curr->LocalAttr);
2830 NewCharset(curr->charsets[curr->LocalCharset]);
2831}
2832
2833void
2834FixLP(x2, y2)
2835register int x2, y2;
2836{
2837 register struct win *p = curr;
2838
2839 GotoPos(x2, y2);
2840 SaveSetAttr(p->attr[y2][x2], p->font[y2][x2]);
2841 PUTCHAR(p->image[y2][x2]);
2842 RestoreAttr();
2843 lp_missing = 0;
2844}
2845
2846void
2847CheckLP(n_ch)
2848char n_ch;
2849{
2850 register int y = screenbot, x = cols - 1;
2851 register char n_at, n_fo, o_ch, o_at, o_fo;
2852
2853 o_ch = curr->image[y][x];
2854 o_at = curr->attr[y][x];
2855 o_fo = curr->font[y][x];
2856
2857 n_at = curr->LocalAttr;
2858 n_fo = curr->charsets[curr->LocalCharset];
2859
2860 lp_missing = 0;
2861 if (n_ch == o_ch && n_at == o_at && n_fo == o_fo)
2862 {
2863 return;
2864 }
2865 if (n_ch != ' ' || n_at || n_fo)
2866 lp_missing = 1;
2867 if (o_ch != ' ' || o_at || o_fo)
2868 {
2869 if (DC)
2870 PutStr(DC);
2871 else if (CDC)
2872 CPutStr(CDC, 1);
2873 else if (CE)
2874 PutStr(CE);
2875 else
2876 lp_missing = 1;
2877 }
2878}
2879
2880static void FindAKA()
2881{
2882 register char *cp, *line, ch;
2883 register struct win *wp = curr;
2884 register int len = strlen(wp->cmd);
2885 int y;
2886
2887 y = (wp->autoaka > 0 && wp->autoaka <= wp->height) ? wp->autoaka - 1 : wp->y;
2888 cols = wp->width;
2889 try_line:
2890 cp = line = wp->image[y];
2891 if (wp->autoaka > 0 && (ch = *wp->cmd) != '\0')
2892 {
2893 for (;;)
2894 {
2895 if ((cp = index(cp, ch)) != NULL
2896 && !strncmp(cp, wp->cmd, len))
2897 break;
2898 if (!cp || ++cp - line >= cols - len)
2899 {
2900 if (++y == wp->autoaka && y < rows)
2901 goto try_line;
2902 return;
2903 }
2904 }
2905 cp += len;
2906 }
2907 for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
2908 ;
2909 if (len)
2910 {
2911 if (wp->autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
2912 wp->autoaka = -1;
2913 else
2914 wp->autoaka = 0;
2915 line = wp->cmd + wp->akapos;
2916 while (len && *cp != ' ')
2917 {
2918 if ((*line++ = *cp++) == '/')
2919 line = wp->cmd + wp->akapos;
2920 len--;
2921 }
2922 *line = '\0';
2923 }
2924 else
2925 wp->autoaka = 0;
2926}
2927
2928
2929/* We dont use HS status line with Input.
2930 * If we would use it, then we should check e_tgetflag("es") if
2931 * we are allowed to use esc sequences there.
2932 * For now, we hope that Goto(,,STATLINE,0) brings us in the bottom
2933 * line. jw.
2934 */
2935
2936static char inpbuf[101];
2937static int inplen;
2938static int inpmaxlen;
2939static char *inpstring;
2940static int inpstringlen;
2941static void (*inpfinfunc)();
2942
2943void
2944Input(istr, len, finfunc)
2945char *istr;
2946int len;
2947void (*finfunc)();
2948{
2949 int maxlen;
2950
2951 inpstring = istr;
2952 inpstringlen = strlen(istr);
2953 if (len > 100)
2954 len = 100;
2955 maxlen = screenwidth - inpstringlen;
2956 if (!LP && STATLINE == screenbot)
2957 maxlen--;
2958 if (len > maxlen)
2959 len = maxlen;
2960 if (len < 2)
2961 {
2962 Msg(0, "Width too small");
2963 return;
2964 }
2965 inpmaxlen = len;
2966 inpfinfunc = finfunc;
2967 InitOverlayPage(process_inp_input, inpRedisplayLine, (int (*)())0, 1);
2968 inplen = 0;
2969 GotoPos(0, STATLINE);
2970 if (CE)
2971 PutStr(CE);
2972 else
2973 {
2974 DisplayLine(curr->image[screeny], curr->attr[screeny],
2975 curr->font[screeny],
2976 blank, null, null, screeny, 0, cols - 1);
2977 }
2978 inpRedisplayLine(STATLINE, 0, inpstringlen - 1, 0);
2979 GotoPos(inpstringlen, STATLINE);
2980}
2981
2982static void
2983process_inp_input(ppbuf, plen)
2984char **ppbuf;
2985int *plen;
2986{
2987 int len, x;
2988 char *pbuf;
2989 char ch;
2990
2991 if (ppbuf == 0)
2992 {
2993 AbortInp();
2994 return;
2995 }
2996 x = inpstringlen+inplen;
2997 len = *plen;
2998 pbuf = *ppbuf;
2999 while (len)
3000 {
3001 ch = *pbuf++;
3002 len--;
3003 if (ch >= ' ' && ch <= '~' && inplen < inpmaxlen)
3004 {
3005 inpbuf[inplen++] = ch;
3006 GotoPos(x, STATLINE);
3007 SaveSetAttr(A_SO, ASCII);
3008 PUTCHAR(ch);
3009 x++;
3010 }
3011 else if ((ch == '\b' || ch == 0177) && inplen > 0)
3012 {
3013 inplen--;
3014 x--;
3015 GotoPos(x, STATLINE);
3016 SaveSetAttr(0, ASCII);
3017 PUTCHAR(' ');
3018 GotoPos(x, STATLINE);
3019 }
3020 else if (ch == '\004' || ch == '\003' || ch == '\000' || ch == '\n' || ch == '\r')
3021 {
3022 if (ch != '\n' && ch != '\r')
3023 inplen = 0;
3024 inpbuf[inplen] = 0;
3025 AbortInp(); /* redisplays... */
3026 (*inpfinfunc)(inpbuf, inplen);
3027 break;
3028 }
3029 }
3030 *ppbuf = pbuf;
3031 *plen = len;
3032}
3033
3034static void
3035AbortInp()
3036{
3037 in_ovl = 0; /* So we can use RefreshLine() */
3038 RefreshLine(STATLINE, 0, screenwidth-1);
3039 ExitOverlayPage();
3040}
3041
3042static void
3043inpRedisplayLine(y, xs, xe, isblank)
3044int y, xs, xe, isblank;
3045{
3046 int q, r, s, l, v;
3047
3048 if (y != STATLINE)
3049 return;
3050 inpbuf[inplen] = 0;
3051 GotoPos(xs,y);
3052 q = xs;
3053 v = xe - xs + 1;
3054 s = 0;
3055 r = inpstringlen;
3056 if (v > 0 && q < r)
3057 {
3058 SaveSetAttr(A_SO, ASCII);
3059 l = v;
3060 if (l > r-q)
3061 l = r-q;
3062 printf("%-*.*s", l, l, inpstring + q - s);
3063 q += l;
3064 v -= l;
3065 }
3066 s = r;
3067 r += inplen;
3068 if (v > 0 && q < r)
3069 {
3070 SaveSetAttr(A_SO, ASCII);
3071 l = v;
3072 if (l > r-q)
3073 l = r-q;
3074 printf("%-*.*s", l, l, inpbuf + q - s);
3075 q += l;
3076 v -= l;
3077 }
3078 s = r;
3079 r = screenwidth;
3080 if (!isblank && v > 0 && q < r)
3081 {
3082 SaveSetAttr(0, ASCII);
3083 l = v;
3084 if (l > r-q)
3085 l = r-q;
3086 printf("%-*.*s", l, l, "");
3087 q += l;
3088 }
3089 SetLastPos(q, y);
3090}
3091
3092static void
3093AKAfin(buf, len)
3094char *buf;
3095int len;
3096{
3097 if (len)
3098 {
3099 strcpy(curr->cmd + curr->akapos, buf);
3100 }
3101}
3102
3103void
3104InputAKA()
3105{
3106 void Input(), AKAfin();
3107
3108 Input("Set window's a.k.a. to: ", 20, AKAfin);
3109}
3110
3111static void
3112Colonfin(buf, len)
3113char *buf;
3114int len;
3115{
3116 if (len)
3117 RcLine(buf);
3118}
3119
3120void
3121InputColon()
3122{
3123 void Input(), Colonfin();
3124
3125 Input(":", 100, Colonfin);
3126}
3127
3128void
3129MakeBlankLine(p, n)
3130register char *p;
3131register int n;
3132{
3133 while (n--)
3134 *p++ = ' ';
3135}
3136
3137void
3138MakeStatus(msg)
3139char *msg;
3140{
3141 register char *s, *t;
3142 register int max, ti;
3143
3144 SetCurr(fore);
3145 display = 1;
3146 if (!(max = HS))
3147 {
3148 max = !LP ? cols - 1 : cols;
3149 }
3150 if (status)
3151 {
3152 if (!BellDisplayed)
3153 {
3154 ti = time((time_t *) 0) - TimeDisplayed;
3155 if (ti < MsgMinWait)
3156 sleep(MsgMinWait - ti);
3157 }
3158 RemoveStatus();
3159 }
3160 for (s = t = msg; *s && t - msg < max; ++s)
3161 if (*s == BELL)
3162 PutStr(BL);
3163 else if (*s >= ' ' && *s <= '~')
3164 *t++ = *s;
3165 *t = '\0';
3166 if (t > msg)
3167 {
3168 strncpy(LastMsg, msg, maxwidth);
3169 status = 1;
3170 status_lastx = screenx;
3171 status_lasty = screeny;
3172 StatLen = t - msg;
3173 if (!HS)
3174 {
3175 GotoPos(0, STATLINE);
3176 SaveSetAttr(A_SO, ASCII);
3177 InsertMode(0);
3178 printf("%s", msg);
3179 screenx = -1;
3180 }
3181 else
3182 {
3183 debug("HS:");
3184 SaveSetAttr(0, ASCII);
3185 InsertMode(0);
3186 CPutStr(TS, 0);
3187 printf("%s", msg);
3188 PutStr(FS);
3189 }
3190 (void) fflush(stdout);
3191 (void) time(&TimeDisplayed);
3192 }
3193}
3194
3195void
3196RemoveStatus()
3197{
3198 if (!status)
3199 return;
3200 status = 0;
3201 BellDisplayed = 0;
3202 SetCurr(fore);
3203 display = 1;
3204 if (!HS)
3205 {
3206 GotoPos(0, STATLINE);
3207 if (in_ovl)
3208 (*ovl_RedisplayLine)(STATLINE, 0, StatLen - 1, 0);
3209 else
3210 RedisplayLine(null, null, null, STATLINE, 0, StatLen - 1);
3211 GotoPos(status_lastx, status_lasty);
3212 }
3213 else
3214 {
3215 SaveSetAttr(0, ASCII);
3216 PutStr(DS);
3217 }
3218}
3219
3220void
3221ClearDisplay()
3222{
3223 PutStr(CL);
3224 screeny = screenx = 0;
3225 fflush(stdout);
3226}
3227
3228static void SetCurr(wp)
3229struct win *wp;
3230{
3231 curr = wp;
3232 cols = curr->width;
3233 rows = curr->height;
3234 display = curr->active;
3235}
3236
3237void
3238InitOverlayPage(pro, red, rewrite, blockfore)
3239void (*pro)();
3240void (*red)();
3241int (*rewrite)();
3242int blockfore;
3243{
3244 RemoveStatus();
3245 SetOvlCurr();
3246 ChangeScrollRegion(0, screenheight - 1);
3247 SetFlow(1);
3248 ovl_process = pro;
3249 ovl_RedisplayLine = red;
3250 ovl_Rewrite = rewrite;
3251 ovl_blockfore = blockfore;
3252 curr->active = 0;
3253 in_ovl = 1;
3254}
3255
3256void
3257ExitOverlayPage()
3258{
3259 ChangeScrollRegion(curr->top, curr->bot);
3260 GotoPos(curr->x, curr->y);
3261 RestoreAttr();
3262 SetFlow(curr->flow & FLOW_NOW);
3263 curr->active = 1;
3264 in_ovl = 0;
3265}
3266
3267void
3268SetOvlCurr()
3269{
3270 SetCurr(fore);
3271 SaveSetAttr(0, ASCII);
3272 InsertMode(0);
3273 display = 1;
3274}
3275
3276void
3277SetLastPos(x,y)
3278int x,y;
3279{
3280 screenx = x;
3281 screeny = y;
3282}
3283
3284void
3285WSresize(width, height)
3286int width, height;
3287{
3288 debug2("(display=%d:WSresize says:'%s'\n", display, tgoto(WS, width, height));
3289 PutStr(tgoto(WS, width, height));
3290}
3291
3292void
3293ChangeScrollRegion(top, bot)
3294int top, bot;
3295{
3296 if (display == 0)
3297 return;
3298 if (CS == 0)
3299 {
3300 screentop = 0;
3301 screenbot = screenheight - 1;
3302 return;
3303 }
3304 if (top == screentop && bot == screenbot)
3305 return;
3306 debug2("ChangeScrollRegion: (%d - %d)\n", top, bot);
3307 PutStr(tgoto(CS, bot, top));
3308 screentop = top;
3309 screenbot = bot;
3310 screeny = screenx = -1; /* Just in case... */
3311}
3312
3313
3314void AddLineToHist(wp, pi, pa, pf)
3315struct win *wp;
3316char **pi, **pa, **pf;
3317{
3318 register char *q;
3319
3320 if (wp->histheight == 0)
3321 return;
3322 q = *pi; *pi = wp->ihist[wp->histidx]; wp->ihist[wp->histidx] = q;
3323 q = *pa; *pa = wp->ahist[wp->histidx]; wp->ahist[wp->histidx] = q;
3324 q = *pf; *pf = wp->fhist[wp->histidx]; wp->fhist[wp->histidx] = q;
3325 if (++wp->histidx >= wp->histheight)
3326 wp->histidx = 0;
3327}
3328
3329
3330/*
3331 *
3332 * Termcap routines that use our extra_incap
3333 *
3334 */
3335
3336/* findcap:
3337 * cap = capability we are looking for
3338 * tepp = pointer to bufferpointer
3339 * n = size of buffer (0 = infinity)
3340 */
3341
3342char *
3343findcap(cap, tepp, n)
3344char *cap;
3345char **tepp;
3346int n;
3347{
3348 char *tep;
3349 char c, *p, *cp;
3350 int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */
3351 int num = 0, capl;
3352
3353 if (!extra_incap)
3354 return (0);
3355 tep = *tepp;
3356 capl = strlen(cap);
3357 cp = 0;
3358 mode = 0;
3359 for (p = extra_incap; *p; )
3360 {
3361 if (strncmp(p, cap, capl) == 0)
3362 {
3363 p+=capl;
3364 c = *p;
3365 if (c && c != ':' && c != '@')
3366 p++;
3367 if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
3368 cp = tep;
3369 }
3370 while (c = *p)
3371 {
3372 p++;
3373 if (mode == 0)
3374 {
3375 if (c == ':')
3376 break;
3377 if (c == '^')
3378 mode = 1;
3379 if (c == '\\')
3380 mode = 2;
3381 }
3382 else if (mode == 1)
3383 {
3384 c = c & 0x1f;
3385 mode = 0;
3386 }
3387 else if (mode == 2)
3388 {
3389 switch(c)
3390 {
3391 case '0':
3392 case '1':
3393 case '2':
3394 case '3':
3395 case '4':
3396 case '5':
3397 case '6':
3398 case '7':
3399 case '8':
3400 case '9':
3401 mode = 3;
3402 num = 0;
3403 break;
3404 case 'E':
3405 c = 27;
3406 break;
3407 case 'n':
3408 c = '\n';
3409 break;
3410 case 'r':
3411 c = '\r';
3412 break;
3413 case 't':
3414 c = '\t';
3415 break;
3416 case 'b':
3417 c = '\b';
3418 break;
3419 case 'f':
3420 c = '\f';
3421 break;
3422 }
3423 if (mode == 2)
3424 mode = 0;
3425 }
3426 if (mode > 2)
3427 {
3428 num = num * 8 + (c - '0');
3429 if (mode++ == 5 || (*p < '0' || *p > '9'))
3430 {
3431 c = num;
3432 mode = 0;
3433 }
3434 }
3435 if (mode)
3436 continue;
3437
3438 if (cp && n != 1)
3439 {
3440 *cp++ = c;
3441 n--;
3442 }
3443 }
3444 if (cp)
3445 {
3446 *cp++ = 0;
3447 *tepp = cp;
3448 debug2("'%s' found in extra_incap -> %s\n", cap, tep);
3449 return(tep);
3450 }
3451 }
3452 return(0);
3453}
3454
3455static char *
3456e_tgetstr(cap, tepp)
3457char *cap;
3458char **tepp;
3459{
3460 char *tep;
3461 if (tep = findcap(cap, tepp, 0))
3462 return((*tep == '@') ? 0 : tep);
3463 return (tgetstr(cap, tepp));
3464}
3465
3466static int
3467e_tgetflag(cap)
3468char *cap;
3469{
3470 char buf[2], *bufp;
3471 char *tep;
3472 bufp = buf;
3473 if (tep = findcap(cap, &bufp, 2))
3474 return((*tep == '@') ? 0 : 1);
3475 return (tgetflag(cap));
3476}
3477
3478static int
3479e_tgetnum(cap)
3480char *cap;
3481{
3482 char buf[20], *bufp;
3483 char *tep, c;
3484 int res, base = 10;
3485
3486 bufp = buf;
3487 if (tep = findcap(cap, &bufp, 20))
3488 {
3489 c = *tep;
3490 if (c == '@')
3491 return(-1);
3492 if (c == '0')
3493 base = 8;
3494 res = 0;
3495 while ((c = *tep++) >= '0' && c <= '9')
3496 res = res * base + (c - '0');
3497 return(res);
3498 }
3499 return (tgetnum(cap));
3500}