|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: vtrm.c,v 1.3 85/08/30 10:11:04 timo Exp $";
3:
4: /* History:
5: * 21-aug-85 GvR added support for AL and DL (parametrized al and dl).
6: * The Epoch tk created and modified.
7: */
8:
9: /*
10: * Virtual TeRMinal package.
11: *
12: * This package uses termcap to determine the terminal capabilities.
13: *
14: * The lines and columns of our virtual terminal are numbered
15: * y = {0...lines-1} from top to bottom, and
16: * x = {0...cols-1} from left to right,
17: * respectively.
18: *
19: * The Visible Procedures in this package are:
20: *
21: * trmstart(&lines, &cols, &flags)
22: * Obligatory initialization call (sets tty modes etc.),
23: * Returns the height and width of the screen to the integers
24: * whose addresses are passed as parameters, and a flag that
25: * describes some capabilities.
26: * Function return value: Yes if all went well, No if the terminal
27: * is not supported. An error message has already been displayed.
28: *
29: * trmundefined()
30: * Sets internal representation of screen and attributes to undefined.
31: * This is necessary for a hard redraw, which would get optimised to
32: * oblivion,
33: *
34: * trmsense(&y, &x)
35: * Returns the cursor position through its parameters
36: * after a possible manual change by the user.
37: *
38: * trmputdata(yfirst, ylast, indent, data)
39: * Fill lines {yfirst..ylast} with data, after skipping the initial
40: * 'indent' positions. It is assumed that these positions do not contain
41: * anything dangerous (like standout cookies or null characters).
42: *
43: * trmscrollup(yfirst, ylast, by)
44: * Shift lines {yfirst..ylast} up by lines (down |by| if by < 0).
45: *
46: * trmsync(y, x)
47: * Call to output data to the terminal and set cursor position.
48: *
49: * trmbell()
50: * Send a (possibly visible) bell, immediately (flushing stdout).
51: *
52: * trmend()
53: * Obligatory termination call (resets tty modes etc.).
54: *
55: * You may call these as one or more cycles of:
56: * + trmstart
57: * + zero or more times any of the other routines
58: * + trmend
59: * To catch interrupts and the like, you may call trmend even in the middle
60: * of trmstart.
61: */
62:
63:
64: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
65: /* Includes and data definitions. */
66: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
67:
68: #include <stdio.h>
69: #include <setjmp.h>
70: #ifndef TERMIO
71: #include <sgtty.h>
72: #else
73: #include <termio.h>
74: #endif TERMIO
75: #include <signal.h>
76: #include <ctype.h> /* for isprint() */
77:
78: #include "vtrm.h"
79:
80: #ifdef lint
81: #define VOID (void)
82: #else
83: #define VOID
84: #endif
85:
86: #define Forward
87: #define Visible
88: #define Hidden static
89: #define Procedure
90:
91: typedef short intlet;
92: typedef char *string;
93: typedef char bool;
94: #define Yes ((bool) 1)
95: #define No ((bool) 0)
96:
97: #define Min(a,b) ((a) <= (b) ? (a) : (b))
98:
99: /* tty modes */
100: #ifndef TERMIO
101: /* v7/BSD tty control */
102: Hidden struct sgttyb oldtty, newtty;
103: /* to enable type ahead for abled persons on systems that provide this: */
104: #ifdef TIOCSETN
105: #define stty(fd,bp) VOID ioctl(fd, TIOCSETN, bp)
106: #endif
107: #else
108: /* AT&T tty control */
109: Hidden struct termio oldtty, newtty;
110: #define gtty(fd,bp) ioctl(fd, TCGETA, bp)
111: #define stty(fd,bp) VOID ioctl(fd, TCSETAW, bp)
112: #endif TERMIO
113: Hidden bool know_ttys = No;
114:
115: /* visible data for termcap */
116: char PC;
117: char *BC;
118: char *UP;
119: short ospeed;
120:
121: Forward int outchar(); /* procedure for termcap's tputs */
122: #define Putstr(str) tputs((str), 1, outchar)
123: extern char *tgoto();
124:
125: /* termcap terminal capabilities */
126:
127: Hidden int lines;
128: Hidden int cols;
129:
130: Hidden bool has_am; /* has automatic margins */
131: Hidden bool has_da; /* display may be retained above screen */
132: Hidden bool has_db; /* display may be retained below screen */
133: Hidden bool has_in; /* not save to have null chars on the screen */
134: Hidden bool has_mi; /* move safely in insert (and delete?) mode */
135: Hidden bool has_ms; /* move safely in standout mode */
136: Hidden bool has_xs; /* standout not erased by overwriting */
137:
138: Hidden char *al_str; /* add new blank line */
139: Hidden char *par_al_str; /* parametrized al (AL) */
140: Hidden char *cd_str; /* clear to end of display */
141: Hidden char *ce_str; /* clear to end of line */
142: Hidden char *cl_str; /* cursor home and clear screen */
143: Hidden char *cm_str; /* cursor motion */
144: Hidden char *cr_str; /* carriage return */
145: Hidden char *cs_str; /* change scrolling region */
146: Hidden char *dc_str; /* delete character */
147: Hidden char *dl_str; /* delete line */
148: Hidden char *par_dl_str; /* parametrized dl (DL) */
149: Hidden char *do_str; /* cursor down one line */
150: Hidden char *dm_str; /* enter delete mode */
151: Hidden char *ed_str; /* end delete mode */
152: Hidden char *ei_str; /* end insert mode */
153: Hidden char *ho_str; /* cursor home */
154: Hidden char *ic_str; /* insert character (iff necessary, maybe pad) */
155: Hidden char *im_str; /* enter insert mode */
156: Hidden char *le_str; /* cursor left */
157: Hidden char *nd_str; /* cursor right (non-destructive space) */
158: Hidden char *se_str; /* end standout mode */
159: Hidden char *sf_str; /* scroll text up (from bottom of region) */
160: Hidden char *so_str; /* begin standout mode */
161: Hidden char *sr_str; /* scroll text down (from top of region) */
162: Hidden char *te_str; /* end termcap */
163: Hidden char *ti_str; /* start termcap */
164: Hidden char *up_str; /* cursor up */
165: Hidden char *vb_str; /* visible bell */
166: Hidden char *ve_str; /* make cursor visible again */
167: Hidden char *vi_str; /* make cursor invisible */
168:
169: /* sense cursor position, addition to termcap */
170: Hidden char *cp_str; /* format of returned Cursor Position string */
171: Hidden char *sp_str; /* Sense cursor Position from terminal */
172:
173: /* terminal status */
174:
175: /* calling order of Visible Procs */
176: Hidden bool started = No;
177:
178: /* to exports the capabilities mentioned in vtrm.h: */
179: Hidden int flags = 0;
180:
181: /* cost for impossible operations */
182: #define Infinity 9999
183: /* Allow for adding Infinity+Infinity within range */
184: /* (Range is assumed at least 2**15 - 1) */
185:
186: /* The following for all sorts of undefined things (except for UNKNOWN char) */
187: #define Undefined (-1)
188:
189: /* current mode of putting char's */
190: #define Normal 0
191: #define Insert 1
192: #define Delete 2
193: Hidden short mode = Normal;
194:
195: /* current standout mode */
196: #define Off 0
197: #define On 0200
198: Hidden short so_mode = Off;
199:
200: /* masks for char's and intlet's */
201: #define NULCHAR '\000'
202: #define CHAR 0177
203: #define SOBIT On
204: #define SOCHAR 0377
205: /* if (has_xs) record cookies placed on screen in extra bit */
206: /* type of cookie is determined by the SO bit */
207: #define XSBIT 0400
208: #define SOCOOK 0600
209: #define COOKBITS SOCOOK
210: #define UNKNOWN 1
211: #define NOCOOK UNKNOWN
212:
213: /* current cursor position */
214: Hidden intlet cur_y = Undefined, cur_x = Undefined;
215:
216: /* "line[y][x]" holds the char on the terminal, with the SOBIT and XSBIT.
217: * the SOBIT tells whether the character is standing out, the XSBIT whether
218: * there is a cookie on the screen at this position.
219: * In particular a standend-cookie may be recorded AFTER the line
220: * (just in case some trmputdata will write after that position).
221: * "lenline[y]" holds the length of the line.
222: * Unknown chars will be 1, so the optimising compare in putline will fail.
223: * (Partially) empty lines are distinghuished by "lenline[y] < cols".
224: */
225: Hidden intlet **line = 0, *lenline = 0;
226:
227: /* Clear the screen initially iff only memory cursor addressing available */
228: Hidden bool mustclear = No;
229:
230: /* Make the cursor invisible when trmsync() tries to move outside the screen */
231: Hidden bool no_cursor = No;
232:
233: /* Optimise cursor motion */
234: Hidden int abs_cost; /* cost of absolute cursor motion */
235: Hidden int cr_cost; /* cost of carriage return */
236: Hidden int do_cost; /* cost of down */
237: Hidden int le_cost; /* cost of left */
238: Hidden int nd_cost; /* cost of right */
239: Hidden int up_cost; /* cost of up */
240:
241: /* Optimise trailing match in put_line, iff the terminal can insert and delete
242: * characters; the cost per n characters will be:
243: * n * MultiplyFactor + OverHead
244: */
245: Hidden int ins_mf, ins_oh, del_mf, del_oh;
246: Hidden int ed_cost, ei_cost; /* used in move() */
247:
248: /* The type of scrolling possible determines which routines get used;
249: * these may be:
250: * (1) with addline and deleteline (termcap: al_str & dl_str);
251: * (2) with a settable scrolling region, like VT100 (cs_str, sr_str, sf_str);
252: * (3) no scrolling available. (NOT YET IMPLEMENTED)
253: */
254: Hidden Procedure (*scr_up)();
255: Hidden Procedure (*scr_down)();
256: Forward Procedure scr1up();
257: Forward Procedure scr1down();
258: Forward Procedure scr2up();
259: Forward Procedure scr2down();
260: /*Forward Procedure scr3up(); */
261: /*Forward Procedure scr3down(); */
262:
263: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
264: /* Starting, Ending and (fatal) Error. */
265: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
266:
267: /*
268: * Initialization call.
269: * Determine terminal capabilities from termcap.
270: * Set up tty modes.
271: * Start up terminal and internal administration.
272: * Return Yes if succeeded, No if trouble (e.g., bad terminal type).
273: */
274: Visible int
275: trmstart(plines, pcols, pflags)
276: int *plines;
277: int *pcols;
278: int *pflags;
279: {
280: #ifdef TRACE
281: fprintf(stderr, "\ttrmstart(&li, &co, &fl);\n");
282: #endif
283: if (started)
284: trmerr("trmstart called twice in succession");
285: if (!gettermcaps())
286: return No;
287: if (!setttymode())
288: return No;
289: start_trm();
290:
291: *plines = lines;
292: *pcols = cols;
293: *pflags = flags;
294:
295: started = Yes;
296: return Yes;
297: }
298:
299: /*
300: * Termination call.
301: * Reset tty modes, etc.
302: * Beware that it might be called by a catched interrupt even in the middle
303: * of trmstart()!
304: */
305: Visible Procedure
306: trmend()
307: {
308: #ifdef TRACE
309: fprintf(stderr, "\ttrmend();\n");
310: #endif
311: set_mode(Normal);
312: if (so_mode != Off)
313: standend();
314: Putstr(te_str);
315: VOID fflush(stdout);
316: resetttymode();
317:
318: started = No;
319: }
320:
321: /*
322: * Set all internal statuses to undefined, especially the contents of
323: * the screen, so a hard redraw will not be optimised to heaven.
324: */
325: Visible Procedure
326: trmundefined()
327: {
328: register int y, x;
329: #ifdef TRACE
330: fprintf(stderr, "\ttrmundefined();\n");
331: #endif
332:
333: cur_y = cur_x = Undefined;
334: mode = so_mode = Undefined;
335:
336: for (y = 0; y < lines; y++) {
337: for (x = 0; x <= cols; x++)
338: line[y][x] = 1; /* impossible char, no so bits */
339: lenline[y] = cols;
340: }
341: }
342:
343: /*
344: * Give an error message, and abort.
345: * The abort can be catched by the calling process.
346: */
347: Hidden Procedure
348: trmerr(mess)
349: string mess;
350: {
351: trmreset();
352: fprintf(stderr,
353: "*** System error in screen output module:\n*** %s\n", mess);
354: VOID fflush(stderr);
355: abort();
356: }
357:
358: /*
359: * Give an error message and reset the tty modes (but don't abort).
360: */
361: Hidden Procedure trmmess(mess)
362: string mess;
363: {
364: trmreset();
365: fprintf(stderr, "*** Fatal error: %s\n", mess);
366: VOID fflush(stderr);
367: }
368:
369: /*
370: * Complain about a missing terminal feature. Otherwise like trmmess.
371: */
372: Hidden Procedure
373: trmsorry(mess)
374: string mess;
375: {
376: trmreset();
377: fprintf(stderr, (
378: #ifdef BED
379: "*** Sorry, this terminal isn't powerful enough to run the B editor.\n"
380: #else
381: "*** Sorry, this terminal isn't powerful emough.\n"
382: #endif
383: ));
384: fprintf(stderr, "*** The problem is: %s.\n", mess);
385: #ifdef BED
386: fprintf(stderr,
387: "*** (You might try 'b -e' to use a standard editor instead.)\n");
388: #endif
389: VOID fflush(stderr);
390: }
391:
392: /*
393: * Prepare for giving a (more or less fatal) error message.
394: */
395: Hidden Procedure
396: trmreset()
397: {
398: if (started) {
399: move(lines-1, 0);
400: clear_lines(lines-1, lines-1);
401: }
402: VOID fflush(stdout);
403: resetttymode();
404: }
405:
406: Hidden Procedure
407: check_started(m)
408: char *m;
409: {
410: char s[80];
411:
412: if (!started) {
413: VOID sprintf(s, "%s called outside trmstart/trmend", m);
414: trmerr(s);
415: }
416: }
417:
418: int ccc;
419:
420: /*ARGSUSED*/
421: Hidden Procedure
422: countchar(ch)
423: char ch;
424: {
425: ccc++;
426: }
427:
428: Hidden int
429: strcost(str)
430: char *str;
431: {
432: if (str == NULL)
433: return Infinity;
434: return str0cost(str);
435: }
436:
437: Hidden int
438: str0cost(str)
439: char *str;
440: {
441: ccc = 0;
442: tputs(str, 1, countchar);
443: return ccc;
444: }
445:
446: Hidden int
447: gettermcaps() /* get terminal capabilities from termcap
448: * and related static properties
449: */
450: {
451: string trmname;
452: char tc_buf[1024];
453: static char strbuf[1024];
454: char *area = strbuf;
455: char *xPC;
456: char *getenv();
457: int tgetent();
458: int tgetnum();
459: int tgetflag();
460: char *tgetstr();
461: int sg;
462: static bool tc_initialized = No;
463: #ifdef TIOCGWINSZ
464: struct winsize win;
465: #endif
466:
467: if (tc_initialized)
468: return Yes;
469:
470: if ((trmname=getenv("TERM")) == NULL) {
471: trmmess("terminal type not exported in $TERM variable");
472: return No;
473: }
474: if (tgetent(tc_buf, trmname) != 1) {
475: trmmess("unknown terminal type in $TERM envariable");
476: return No;
477: }
478:
479: if (tgetflag("hc")) {
480: trmsorry("can't use a hardcopy terminal");
481: return No;
482: }
483:
484: BC = tgetstr("le", &area);
485: if (BC == NULL)
486: BC = tgetstr("bc", &area);
487: if (BC == NULL)
488: if (tgetflag("bs"))
489: BC="\b";
490: else {
491: trmsorry("no LEFT cursor motion");
492: return No;
493: }
494: UP = tgetstr("up", &area);
495: if (UP == NULL) {
496: trmsorry("no UP cursor motion");
497: return No;
498: }
499: xPC = tgetstr("pc", &area);
500: PC = (xPC != NULL? xPC[0] : NULCHAR);
501:
502: ho_str = tgetstr("ho", &area);
503: do_str = tgetstr("do", &area);
504: nd_str = tgetstr("nd", &area);
505: cm_str = tgetstr("cm", &area);
506: if (cm_str == NULL) {
507: cm_str = tgetstr("CM", &area);
508: if (cm_str == NULL) {
509: if (ho_str == NULL || do_str == NULL || nd_str == NULL) {
510: trmsorry("no absolute cursor motion");
511: return No;
512: }
513: }
514: else
515: mustclear = Yes;
516: }
517:
518: al_str = tgetstr("al", &area);
519: dl_str = tgetstr("dl", &area);
520: par_al_str = tgetstr("AL", &area);
521: par_dl_str = tgetstr("DL", &area);
522: if (al_str && dl_str) {
523: scr_up = scr1up;
524: scr_down = scr1down;
525: flags |= CAN_SCROLL;
526: }
527: else {
528: cs_str = tgetstr("cs", &area);
529: sf_str = tgetstr("sf", &area);
530: if (sf_str == NULL)
531: sf_str = "\n";
532: sr_str = tgetstr("sr", &area);
533: if (cs_str && sr_str) {
534: scr_up = scr2up;
535: scr_down = scr2down;
536: flags |= CAN_SCROLL;
537: }
538: else {
539: trmsorry("can't scroll");
540: return No;
541: }
542: }
543:
544: lines = tgetnum("li");
545: cols = tgetnum("co");
546: #ifdef TIOCGWINSZ
547: if (ioctl (0, TIOCGWINSZ, &win) == 0) {
548: if (win.ws_col)
549: cols = win.ws_col;
550: if (win.ws_row)
551: lines = win.ws_row;
552: }
553: #endif
554: if (lines == -1) lines = 24;
555: if (cols == -1) cols = 80;
556:
557: has_am = tgetflag("am");
558: has_db = tgetflag("db");
559: has_in = tgetflag("in");
560: has_mi = tgetflag("mi");
561: has_ms = tgetflag("ms");
562: has_xs = tgetflag("xs");
563: if ((sg=tgetnum("sg")) == 0)
564: has_xs = Yes;
565: else if (sg > 0) {
566: trmsorry("video attributes take up space on the screen");
567: return No;
568: }
569:
570: cd_str = tgetstr("cd", &area);
571: ce_str = tgetstr("ce", &area);
572: if (!ce_str) {
573: trmsorry("can't clear to end of line");
574: return No;
575: }
576: cl_str = tgetstr("cl", &area);
577: cr_str = tgetstr("cr", &area);
578: if (cr_str == NULL) cr_str = "\r";
579: dc_str = tgetstr("dc", &area);
580: dm_str = tgetstr("dm", &area);
581: if (do_str == NULL) do_str = tgetstr("nl", &area);
582: if (do_str == NULL) do_str = "\n";
583: ed_str = tgetstr("ed", &area);
584: ei_str = tgetstr("ei", &area);
585: ic_str = tgetstr("ic", &area);
586: im_str = tgetstr("im", &area);
587: le_str = BC;
588: se_str = tgetstr("se", &area);
589: so_str = tgetstr("so", &area);
590: te_str = tgetstr("te", &area);
591: ti_str = tgetstr("ti", &area);
592: up_str = UP;
593: vb_str = tgetstr("vb", &area);
594: if (vb_str == NULL) /* then we will do with the audible bell */
595: vb_str = "\007";
596: ve_str = tgetstr("ve", &area);
597: vi_str = tgetstr("vi", &area);
598:
599: /* cursor sensing (non standard) */
600: cp_str = tgetstr("cp", &area);
601: sp_str = tgetstr("sp", &area);
602: if (cp_str != NULL && sp_str != NULL)
603: flags |= CAN_SENSE;
604:
605: if (so_str != NULL && se_str != NULL)
606: flags |= HAS_STANDOUT;
607:
608: /* calculate costs of local and absolute cursor motions */
609: if (cm_str == NULL)
610: abs_cost = Infinity;
611: else
612: abs_cost = strcost(tgoto(cm_str, 0, 0));
613: cr_cost = strcost(cr_str);
614: do_cost = strcost(do_str);
615: le_cost = strcost(le_str);
616: nd_cost = strcost(nd_str);
617: up_cost = strcost(up_str);
618:
619: /* cost of leaving insert or delete mode, used in move() */
620: ei_cost = str0cost(ei_str);
621: ed_cost = str0cost(ed_str);
622:
623: /* calculate insert and delete cost multiply_factor and overhead */
624: if (((im_str && ei_str) || ic_str) && dc_str) {
625: flags |= CAN_OPTIMISE;
626: ins_mf = 1 + str0cost(ic_str);
627: ins_oh = str0cost(im_str) + ei_cost;
628: del_mf = str0cost(dc_str);
629: del_oh = str0cost(dm_str) + ed_cost;
630: }
631:
632: tc_initialized = Yes;
633: return Yes;
634: }
635:
636: Hidden int
637: setttymode()
638: {
639: if (!know_ttys) {
640: if (gtty(1, &oldtty) != 0 || gtty(1, &newtty) != 0) {
641: trmmess("can't get tty modes (output not a terminal)");
642: return No;
643: }
644: #ifndef TERMIO
645: ospeed = oldtty.sg_ospeed;
646: #ifdef PWB
647: newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
648: | RAW;
649: #else PWB
650: newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
651: | CBREAK;
652: #endif PWB
653: #else TERMIO
654: ospeed= oldtty.c_lflag & CBAUD;
655: newtty.c_iflag &= ~ICRNL; /* No CR->NL mapping on input */
656: newtty.c_oflag &= ~ONLCR; /* NL doesn't output CR */
657: newtty.c_lflag &= ~(ICANON|ECHO); /* No line editing, no echo */
658: newtty.c_cc[VMIN]= 3; /* wait for 3 characters */
659: newtty.c_cc[VTIME]= 1; /* or 0.1 sec. */
660: #endif TERMIO
661: know_ttys = Yes;
662: }
663: stty(1, &newtty);
664: return Yes;
665: }
666:
667: Hidden Procedure
668: resetttymode()
669: {
670: if (know_ttys)
671: stty(1, &oldtty);
672: }
673:
674: Hidden char*
675: lalloc(size)
676: unsigned size;
677: {
678: char *l;
679: char *malloc();
680:
681: l = malloc(size);
682: if (l == NULL)
683: trmerr("not enough memory for screen buffer");
684: return l;
685: }
686:
687: Hidden Procedure
688: start_trm()
689: {
690: register int y;
691:
692: if (line == 0) {
693: line = (intlet**) lalloc((unsigned) lines * sizeof(intlet*));
694: for (y = 0; y < lines; y++)
695: line[y] = (intlet*) lalloc((unsigned) ((cols+1)*sizeof(intlet)));
696: }
697: if (lenline == 0)
698: lenline = (intlet*) lalloc((unsigned) lines * sizeof(intlet));
699:
700:
701: trmundefined();
702:
703: Putstr(ti_str);
704: if (cs_str)
705: Putstr(tgoto(cs_str, lines-1, 0));
706: if (mustclear)
707: clear_lines(0, lines-1);
708: }
709:
710: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
711: /* Sensing and moving the cursor. */
712: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
713:
714: /*
715: * Sense the current (y, x) cursor position, after a possible manual
716: * change by the user with local cursor motions.
717: * If the terminal cannot be asked for the current cursor position,
718: * or if the string returned by the terminal is garbled,
719: * the position is made Undefined.
720: */
721: Visible Procedure
722: trmsense(py, px)
723: int *py;
724: int *px;
725: {
726: bool getpos();
727:
728: #ifdef TRACE
729: fprintf(stderr, "\ttrmsense(&yy, &xx);\n");
730: #endif
731: check_started("trmsense");
732:
733: *py = *px = Undefined;
734: set_mode(Normal);
735: if (so_mode != Off)
736: standend();
737:
738: if (flags&CAN_SENSE && getpos(py, px)) {
739: if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
740: *py = *px = Undefined;
741: }
742: cur_y = *py;
743: cur_x = *px;
744: }
745:
746: Hidden bool
747: getpos(py, px)
748: int *py, *px;
749: {
750: char *format = cp_str;
751: int fc; /* current format character */
752: int ic; /* current input character */
753: int num;
754: int on_y = 1;
755: bool incr_orig = No;
756: int i, ni;
757:
758: Putstr(sp_str);
759: VOID fflush(stdout);
760:
761: while (fc = *format++) {
762: if (fc != '%') {
763: if (getchar() != fc)
764: return No;
765: }
766: else {
767: switch (fc = *format++) {
768: case '%':
769: if (getchar() != '%')
770: return No;
771: continue;
772: case 'r':
773: on_y = 1 - on_y;
774: continue;
775: case 'i':
776: incr_orig = Yes;
777: continue;
778: case 'd':
779: ic = getchar();
780: if (!isdigit(ic))
781: return No;
782: num = ic - '0';
783: while (isdigit(ic=getchar()))
784: num = 10*num + ic - '0';
785: VOID ungetc(ic, stdin);
786: break;
787: case '2':
788: case '3':
789: ni = fc - '0';
790: num = 0;
791: for (i=0; i<ni; i++) {
792: ic = getchar();
793: if (isdigit(ic))
794: num = 10*num + ic - '0';
795: else
796: return No;
797: }
798: break;
799: case '+':
800: num = getchar() - *format++;
801: break;
802: case '-':
803: num = getchar() + *format++;
804: break;
805: default:
806: return No;
807: }
808: /* assign num to parameter */
809: if (incr_orig)
810: num--;
811: if (on_y)
812: *py = num;
813: else
814: *px = num;
815: on_y = 1 - on_y;
816: }
817: }
818:
819: return Yes;
820: }
821:
822: /*
823: * To move over characters by rewriting them, we have to check:
824: * (1) that the screen has been initialised on these positions;
825: * (2) we do not screw up characters
826: * when rewriting line[y] from x_from upto x_to
827: */
828: Hidden bool
829: rewrite_ok(y, xfrom, xto)
830: int y, xfrom, xto;
831: {
832: register intlet *plnyx, *plnyto;
833:
834: if (xto > lenline[y])
835: return No;
836:
837: plnyto = &line[y][xto];
838: for (plnyx = &line[y][xfrom]; plnyx <= plnyto; plnyx++)
839: if (*plnyx == UNKNOWN
840: ||
841: (!has_xs && (*plnyx & SOBIT) != so_mode)
842: )
843: return No;
844: return Yes;
845: }
846:
847: /*
848: * Move to position y,x on the screen
849: */
850: /* possible move types for y and x respectively: */
851: #define None 0
852: #define Down 1
853: #define Up 2
854: #define Right 1
855: #define ReWrite 2
856: #define Left 3
857: #define CrWrite 4
858:
859: Hidden Procedure
860: move(y, x)
861: int y, x;
862: {
863: int dy, dx;
864: int y_cost, x_cost, y_move, x_move;
865: int mode_cost;
866: int xi;
867:
868: if (cur_y == y && cur_x == x)
869: return;
870:
871: if (!has_mi || mode == Undefined)
872: set_mode(Normal);
873: if (!has_xs && ((!has_ms && so_mode != Off) || so_mode == Undefined))
874: standend();
875:
876: if (cur_y == Undefined || cur_x == Undefined)
877: goto absmove;
878:
879: dy = y - cur_y;
880: dx = x - cur_x;
881:
882: if (dy > 0) {
883: y_move = Down;
884: y_cost = dy * do_cost;
885: }
886: else if (dy < 0) {
887: y_move = Up;
888: y_cost = -dy * up_cost;
889: }
890: else {
891: y_move = None;
892: y_cost = 0;
893: }
894: if (y_cost < abs_cost) {
895: switch (mode) {
896: case Normal:
897: mode_cost = 0;
898: break;
899: case Insert:
900: mode_cost = ei_cost;
901: break;
902: case Delete:
903: mode_cost = ed_cost;
904: break;
905: }
906: if (dx > 0) {
907: x_cost = dx + mode_cost;
908: if (dx*nd_cost < x_cost || !rewrite_ok(y, cur_x, x)) {
909: x_cost = dx * nd_cost;
910: x_move = Right;
911: }
912: else
913: x_move = ReWrite;
914: }
915: else if (dx < 0) {
916: x_cost = -dx * le_cost;
917: x_move = Left;
918: }
919: else {
920: x_cost = 0;
921: x_move = None;
922: }
923: if (cr_cost + x + mode_cost < x_cost && rewrite_ok(y, 0, x)) {
924: x_move = CrWrite;
925: x_cost = cr_cost + x + mode_cost;
926: }
927: }
928: else
929: x_cost = abs_cost;
930:
931: if (y_cost + x_cost < abs_cost) {
932: switch (y_move) {
933: case Down:
934: while (dy-- > 0) Putstr(do_str);
935: break;
936: case Up:
937: while (dy++ < 0) Putstr(up_str);
938: break;
939: }
940: switch (x_move) {
941: case Right:
942: while (dx-- > 0) Putstr(nd_str);
943: break;
944: case Left:
945: while (dx++ < 0) Putstr(le_str);
946: break;
947: case CrWrite:
948: Putstr(cr_str);
949: cur_x = 0;
950: /* FALL THROUGH */
951: case ReWrite:
952: set_mode(Normal);
953: for (xi = cur_x; xi < x; xi++)
954: putchar(line[y][xi]);
955: break;
956: }
957: }
958: else
959: {
960: absmove:
961: if (cm_str == NULL) {
962: Putstr(ho_str);
963: for (cur_y = 0; cur_y < y; ++cur_y)
964: Putstr(do_str);
965: /* Should try to use tabs here: */
966: for (cur_x = 0; cur_x < x; ++cur_x)
967: Putstr(nd_str);
968: }
969: else
970: Putstr(tgoto(cm_str, x, y));
971: }
972:
973: cur_y = y;
974: cur_x = x;
975: }
976:
977: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
978: /* Putting data on the screen. */
979: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
980:
981: /*
982: * Fill screen area with given data.
983: * Characters with the SO-bit (0200) set are put in standout mode.
984: */
985: Visible Procedure
986: trmputdata(yfirst, ylast, indent, data)
987: int yfirst;
988: int ylast;
989: register int indent;
990: register string data;
991: {
992: register int y;
993: int x, len, lendata, space;
994:
995: #ifdef TRACE
996: fprintf(stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
997: #endif
998: check_started("trmputdata");
999:
1000: if (yfirst < 0)
1001: yfirst = 0;
1002: if (ylast >= lines)
1003: ylast = lines-1;
1004: space = cols*(ylast-yfirst+1) - indent;
1005: if (space <= 0)
1006: return;
1007: yfirst += indent/cols;
1008: indent %= cols;
1009: if (data) {
1010: x = indent;
1011: lendata = strlen(data);
1012: if (ylast == lines-1 && lendata >= space)
1013: lendata = space - 1;
1014: len = Min(lendata, cols-x);
1015: for (y = yfirst; y <= ylast; ) {
1016: put_line(y, x, data, len);
1017: y++;
1018: lendata -= len;
1019: if (lendata > 0) {
1020: x = 0;
1021: data += len;
1022: len = Min(lendata, cols);
1023: }
1024: else
1025: break;
1026: }
1027: }
1028: if (y <= ylast)
1029: clear_lines(y, ylast);
1030: }
1031:
1032: /*
1033: * We will first try to get the picture:
1034: *
1035: * op>>>>>>>>>>>op oq<<<<<<<<<<<<<<<<<<<<<<<<oq
1036: * ^ ^ ^ ^
1037: * <xskip><-----m1----><----od-----><-----------m2----------->
1038: * OLD: "You're in a maze of twisty little pieces of code, all alike"
1039: * NEW: "in a maze of little twisting pieces of code, all alike"
1040: * <-----m1----><-----nd------><-----------m2----------->
1041: * ^ ^ ^ ^
1042: * np>>>>>>>>>>>np nq<<<<<<<<<<<<<<<<<<<<<<<<nq
1043: * where
1044: * op, oq, np, nq are pointers to start and end of Old and New data,
1045: * and
1046: * xskip = length of indent to be skipped,
1047: * m1 = length of Matching part at start,
1048: * od = length of Differing mid on screen,
1049: * nd = length of Differing mid in data to be put,
1050: * m2 = length of Matching trail.
1051: *
1052: * Then we will try to find a long blank-or-cleared piece in <nd+m2>:
1053: *
1054: * <---m1---><---d1---><---nb---><---d2---><---m2--->
1055: * ^ ^ ^ ^ ^
1056: * np bp bq1 nq nend
1057: * where
1058: * bp, bq are pointers to start and AFTER end of blank piece,
1059: * and
1060: * d1 = length of differing part before blank piece,
1061: * nb = length of blank piece to be skipped,
1062: * d2 = length of differing part after blank piece.
1063: * Remarks:
1064: * d1 + nb + d2 == nd,
1065: * and
1066: * d2 maybe less than 0.
1067: */
1068: Hidden int
1069: put_line(y, xskip, data, len)
1070: int y, xskip;
1071: string data;
1072: int len;
1073: {
1074: register intlet *op, *oq;
1075: register char *np, *nq, *nend;
1076: char *bp, *bq1, *p, *q;
1077: int m1, m2, od, nd, delta, dd, d1, nb, d2;
1078: bool skipping;
1079: int cost, o_cost; /* normal and optimising cost */
1080:
1081: /* calculate the magic parameters */
1082: op = &line[y][xskip];
1083: oq = &line[y][lenline[y]-1];
1084: np = data;
1085: nq = nend = data + len - 1;
1086: m1 = m2 = 0;
1087: while ((*op&SOCHAR) == (((intlet)*np)&SOCHAR) && op <= oq && np <= nq)
1088: op++, np++, m1++;
1089: if (flags & CAN_OPTIMISE)
1090: while ((*oq&SOCHAR) == (((intlet)*nq)&SOCHAR) && op <= oq && np <= nq)
1091: oq--, nq--, m2++;
1092: od = oq - op + 1;
1093: nd = nq - np + 1;
1094: /* now we have the first picture above */
1095:
1096: if (od==0 && nd==0)
1097: return;
1098: delta = nd - od;
1099:
1100: /* find the blank piece */
1101: p = q = bp = bq1 = np;
1102: oq += m2; /* back to current eol */
1103: if (!has_in) {
1104: while (p <= nend) {
1105: while (q<=nend && *q==' ' && (op>oq || *op==' '))
1106: q++, op++;
1107: if (q - p > bq1 - bp)
1108: bp = p, bq1 = q;
1109: p = ++q;
1110: op++;
1111: }
1112: }
1113: d1 = bp - np;
1114: nb = bq1 - bp;
1115: d2 = nq - bq1 + 1;
1116:
1117: /* what is cheapest:
1118: * normal: put nd+m2; (dd = nd+m2)
1119: * skipping: put d1, skip nb, put d2+m2; (dd = d2+m2)
1120: * optimise: put dd, insert or delete delta. (dd = min(od,nd))
1121: */
1122: cost = nd + m2; /* normal cost */
1123: if (nb > abs_cost || (d1 == 0 && nb > 0)) {
1124: skipping = Yes;
1125: cost -= nb - (d1>0 ? abs_cost : 0); /* skipping cost */
1126: dd = d2;
1127: }
1128: else {
1129: skipping = No;
1130: dd = nd;
1131: }
1132:
1133: if (m2 != 0) {
1134: /* try optimising */
1135: o_cost = Min(od, nd);
1136: if (delta > 0)
1137: o_cost += delta * ins_mf + ins_oh;
1138: else if (delta < 0)
1139: o_cost += -delta * del_mf + del_oh;
1140: if (o_cost >= cost) {
1141: /* discard m2, no optimise */
1142: dd += m2;
1143: m2 = 0;
1144: }
1145: else {
1146: dd = Min(od, nd);
1147: skipping = No;
1148: }
1149: }
1150:
1151: /* and now for the real work */
1152: if (!skipping || d1 > 0)
1153: move(y, xskip + m1);
1154:
1155: if (has_xs)
1156: get_so_mode();
1157:
1158: if (skipping) {
1159: if (d1 > 0) {
1160: set_mode(Normal);
1161: put_str(np, d1, No);
1162: }
1163: if (has_xs && so_mode != Off)
1164: standend();
1165: set_blanks(y, xskip+m1+d1, xskip+m1+d1+nb);
1166: if (dd != 0 || delta < 0) {
1167: move(y, xskip+m1+d1+nb);
1168: np = bq1;
1169: }
1170: }
1171:
1172: if (dd > 0) {
1173: set_mode(Normal);
1174: put_str(np, dd, No);
1175: }
1176:
1177: if (m2 > 0) {
1178: if (delta > 0) {
1179: set_mode(Insert);
1180: ins_str(np+dd, delta);
1181: }
1182: else if (delta < 0) {
1183: set_mode(Delete);
1184: del_str(-delta);
1185: }
1186: }
1187: else {
1188: if (delta < 0) {
1189: clr_to_eol();
1190: return;
1191: }
1192: }
1193:
1194: lenline[y] = xskip + len;
1195: if (cur_x == cols) {
1196: if (!has_mi)
1197: set_mode(Normal);
1198: if (!has_ms)
1199: so_mode = Undefined;
1200: if (has_am)
1201: cur_y++;
1202: else
1203: Putstr(cr_str);
1204: cur_x = 0;
1205: }
1206: else if (has_xs) {
1207: if (m2 == 0) {
1208: if (so_mode == On)
1209: standend();
1210: }
1211: else {
1212: if (!(line[cur_y][cur_x] & XSBIT)) {
1213: if (so_mode != (line[cur_y][cur_x] & SOBIT))
1214: (so_mode ? standend() : standout());
1215: }
1216: }
1217: }
1218: }
1219:
1220: Hidden Procedure
1221: set_mode(m)
1222: int m;
1223: {
1224: if (m == mode)
1225: return;
1226: switch (mode) {
1227: case Insert:
1228: Putstr(ei_str);
1229: break;
1230: case Delete:
1231: Putstr(ed_str);
1232: break;
1233: case Undefined:
1234: Putstr(ei_str);
1235: Putstr(ed_str);
1236: break;
1237: }
1238: switch (m) {
1239: case Insert:
1240: Putstr(im_str);
1241: break;
1242: case Delete:
1243: Putstr(dm_str);
1244: break;
1245: }
1246: mode = m;
1247: }
1248:
1249: Hidden Procedure
1250: get_so_mode()
1251: {
1252: if (cur_x >= lenline[cur_y] || line[cur_y][cur_x] == UNKNOWN)
1253: so_mode = Off;
1254: else
1255: so_mode = line[cur_y][cur_x] & SOBIT;
1256: }
1257:
1258: Hidden Procedure
1259: standout()
1260: {
1261: Putstr(so_str);
1262: so_mode = On;
1263: if (has_xs)
1264: line[cur_y][cur_x] |= SOCOOK;
1265: }
1266:
1267: Hidden Procedure
1268: standend()
1269: {
1270: Putstr(se_str);
1271: so_mode = Off;
1272: if (has_xs)
1273: line[cur_y][cur_x] = (line[cur_y][cur_x] & ~SOBIT) | XSBIT;
1274: }
1275:
1276: Hidden Procedure
1277: put_str(data, n, inserting)
1278: char *data;
1279: int n;
1280: bool inserting;
1281: {
1282: register intlet c, so;
1283: intlet *ln_y_x, *ln_y_end;
1284:
1285: so = so_mode;
1286: if (has_xs) {
1287: ln_y_x = &line[cur_y][cur_x];
1288: ln_y_end = &line[cur_y][lenline[cur_y]];
1289: }
1290: while (n-- > 0) {
1291: if (has_xs && ln_y_x <= ln_y_end && ((*ln_y_x)&XSBIT))
1292: so = so_mode = (*ln_y_x)&SOBIT;
1293: /* this also checks for the standend cookie AFTER */
1294: /* the line because off the equals sign in <= */
1295: c = ((intlet)(*data++))&SOCHAR;
1296: if ((c&SOBIT) != so) {
1297: so = c&SOBIT;
1298: so ? standout() : standend();
1299: }
1300: if (inserting)
1301: Putstr(ic_str);
1302: put_c(c);
1303: if (has_xs)
1304: ln_y_x++;
1305: }
1306: }
1307:
1308: Hidden Procedure
1309: ins_str(data, n)
1310: char *data;
1311: int n;
1312: {
1313: int x;
1314:
1315: /* x will start AFTER the line, because there might be a cookie */
1316: for (x = lenline[cur_y]; x >= cur_x; x--)
1317: line[cur_y][x+n] = line[cur_y][x];
1318: put_str(data, n, Yes);
1319: }
1320:
1321: Hidden Procedure
1322: del_str(n)
1323: int n;
1324: {
1325: int x, xto;
1326:
1327: xto = lenline[cur_y] - n; /* again one too far because of cookie */
1328: if (has_xs) {
1329: for (x = cur_x + n; x >= cur_x; x--) {
1330: if (line[cur_y][x] & XSBIT)
1331: break;
1332: }
1333: if (x >= cur_x)
1334: line[cur_y][cur_x+n] =
1335: (line[cur_y][cur_x+n] & CHAR)
1336: |
1337: (line[cur_y][x] & COOKBITS);
1338: }
1339: for (x = cur_x; x <= xto; x++)
1340: line[cur_y][x] = line[cur_y][x+n];
1341: while (n-- > 0)
1342: Putstr(dc_str);
1343: }
1344:
1345: Hidden Procedure
1346: put_c(c)
1347: intlet c;
1348: {
1349: char ch;
1350: intlet xs_flag;
1351:
1352: ch = c&CHAR;
1353: if (!isprint(ch) && ch != ' ') { /* V7 isprint doesn't include blank */
1354: ch = '?';
1355: c = (c&SOBIT)|'?';
1356: }
1357: putchar(ch);
1358: if (has_xs)
1359: xs_flag = line[cur_y][cur_x]&XSBIT;
1360: else
1361: xs_flag = 0;
1362: line[cur_y][cur_x] = (c&SOCHAR)|xs_flag;
1363: cur_x++;
1364: }
1365:
1366: Hidden Procedure
1367: clear_lines(yfirst, ylast)
1368: int yfirst, ylast ;
1369: {
1370: register int y;
1371:
1372: if (!has_xs && so_mode != Off)
1373: standend();
1374: if (cl_str && yfirst == 0 && ylast == lines-1) {
1375: Putstr(cl_str);
1376: cur_y = cur_x = 0;
1377: return;
1378: }
1379: for (y = yfirst; y <= ylast; y++) {
1380: if (lenline[y] > 0) {
1381: move(y, 0);
1382: if (ylast == lines-1 && cd_str) {
1383: Putstr(cd_str);
1384: while (y <= ylast) {
1385: if (has_xs) line[y][0] = NOCOOK;
1386: lenline[y++] = 0;
1387: }
1388: break;
1389: }
1390: else {
1391: clr_to_eol();
1392: }
1393: }
1394: }
1395: }
1396:
1397: Hidden Procedure
1398: clr_to_eol()
1399: {
1400: lenline[cur_y] = cur_x;
1401: if (!has_xs && so_mode != Off)
1402: standend();
1403: Putstr(ce_str);
1404: if (has_xs) {
1405: if (cur_x == 0)
1406: line[cur_y][0] = NOCOOK;
1407: else if (line[cur_y][cur_x-1]&SOBIT)
1408: standend();
1409: }
1410: }
1411:
1412: Hidden Procedure
1413: set_blanks
1414: (y, xfrom, xto)
1415: int y, xfrom, xto;
1416: {
1417: register int x;
1418:
1419: for (x = xfrom; x < xto; x++) {
1420: line[y][x] = (line[y][x]&XSBIT) | ' ';
1421: }
1422: }
1423:
1424: /*
1425: * outchar() is used by termcap's tputs;
1426: * we can't use putchar because that's probably a macro
1427: */
1428: Hidden int
1429: outchar(ch)
1430: char ch;
1431: {
1432: putchar(ch);
1433: }
1434:
1435: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1436: /* Scrolling (part of) the screen up (or down, dy<0). */
1437: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1438:
1439: Visible Procedure
1440: trmscrollup(yfirst, ylast, by)
1441: register int yfirst;
1442: register int ylast;
1443: register int by;
1444: {
1445: #ifdef TRACE
1446: fprintf(stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
1447: #endif
1448: check_started("trmscrollup");
1449:
1450: if (yfirst < 0)
1451: yfirst = 0;
1452: if (ylast >= lines)
1453: ylast = lines-1;
1454:
1455: if (yfirst > ylast)
1456: return;
1457:
1458: if (!has_xs && so_mode != Off)
1459: standend();
1460:
1461: if (by > 0 && yfirst + by > ylast
1462: ||
1463: by < 0 && yfirst - by > ylast)
1464: {
1465: clear_lines(yfirst, ylast);
1466: return;
1467: }
1468:
1469: if (by > 0) {
1470: (*scr_up)(yfirst, ylast, by);
1471: scr_lines(yfirst, ylast, by, 1);
1472: }
1473: else if (by < 0) {
1474: (*scr_down)(yfirst, ylast, -by);
1475: scr_lines(ylast, yfirst, -by, -1);
1476: }
1477: }
1478:
1479: Hidden Procedure
1480: scr_lines(yfrom, yto, n, dy)
1481: int yfrom, yto, n, dy;
1482: {
1483: register int y;
1484: intlet *saveln;
1485:
1486: while (n-- > 0) {
1487: saveln = line[yfrom];
1488: for (y = yfrom; y != yto; y += dy) {
1489: line[y] = line[y+dy];
1490: lenline[y] = lenline[y+dy];
1491: }
1492: line[yto] = saveln;
1493: lenline[yto] = 0;
1494: if (has_xs) line[yto][0] = NOCOOK;
1495: }
1496: }
1497:
1498: Hidden Procedure
1499: scr1up(yfirst, ylast, n)
1500: int yfirst;
1501: int ylast;
1502: int n;
1503: {
1504: move(yfirst, 0);
1505: dellines(n);
1506: if (ylast < lines-1) {
1507: move(ylast-n+1, 0);
1508: addlines(n);
1509: }
1510: }
1511:
1512: Hidden Procedure
1513: scr1down(yfirst, ylast, n)
1514: int yfirst;
1515: int ylast;
1516: int n;
1517: {
1518: if (ylast == lines-1) {
1519: clear_lines(ylast-n+1, ylast);
1520: }
1521: else {
1522: move(ylast-n+1, 0);
1523: dellines(n);
1524: }
1525: move(yfirst, 0);
1526: addlines(n);
1527: }
1528:
1529: Hidden Procedure
1530: addlines(n)
1531: register int n;
1532: {
1533: if (par_al_str && n > 1)
1534: Putstr(tgoto(par_al_str, n, n));
1535: else {
1536: while (n-- > 0)
1537: Putstr(al_str);
1538: }
1539: }
1540:
1541: Hidden Procedure
1542: dellines(n)
1543: register int n;
1544: {
1545: if (par_dl_str && n > 1)
1546: Putstr(tgoto(par_dl_str, n, n));
1547: else {
1548: while (n-- > 0)
1549: Putstr(dl_str);
1550: }
1551: }
1552:
1553: Hidden Procedure
1554: scr2up(yfirst, ylast, n)
1555: int yfirst, ylast, n;
1556: {
1557: Putstr(tgoto(cs_str, ylast, yfirst));
1558: cur_y = cur_x = Undefined;
1559: move(ylast, 0);
1560: while (n-- > 0) {
1561: Putstr(sf_str);
1562: if (has_db && ylast == lines-1)
1563: clr_to_eol();
1564: }
1565: Putstr(tgoto(cs_str, lines-1, 0));
1566: cur_y = cur_x = Undefined;
1567: }
1568:
1569: Hidden Procedure
1570: scr2down(yfirst, ylast, n)
1571: int yfirst, ylast, n;
1572: {
1573: Putstr(tgoto(cs_str, ylast, yfirst));
1574: cur_y = cur_x = Undefined;
1575: move(yfirst, 0);
1576: while (n-- > 0) {
1577: Putstr(sr_str);
1578: if (has_da && yfirst == 0)
1579: clr_to_eol();
1580: }
1581: Putstr(tgoto(cs_str, lines-1, 0));
1582: cur_y = cur_x = Undefined;
1583: }
1584:
1585: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1586: /* Synchronization, move cursor to given position (or previous if < 0). */
1587: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1588:
1589: Visible Procedure
1590: trmsync(y, x)
1591: int y;
1592: int x;
1593: {
1594: #ifdef TRACE
1595: fprintf(stderr, "\ttrmsync(%d, %d);\n", y, x);
1596: #endif
1597: check_started("trmsync");
1598:
1599: if (0 <= y && y < lines && 0 <= x && x < cols) {
1600: move(y, x);
1601: if (no_cursor) {
1602: Putstr(ve_str);
1603: no_cursor = No;
1604: }
1605: }
1606: else if (no_cursor == No) {
1607: Putstr(vi_str);
1608: no_cursor = Yes;
1609: }
1610: VOID fflush(stdout);
1611: }
1612:
1613: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1614: /* Send a bell, visible if possible. */
1615: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1616:
1617: Visible Procedure
1618: trmbell()
1619: {
1620: #ifdef TRACE
1621: fprintf(stderr, "\ttrmbell();\n");
1622: #endif
1623: check_started("trmbell");
1624:
1625: Putstr(vb_str);
1626: VOID fflush(stdout);
1627: }
1628:
1629: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1630: /* Show the current internal statuses of the screen on stderr. */
1631: /* For debugging only. */
1632: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1633:
1634: #ifdef SHOW
1635: Visible Procedure
1636: trmshow(s)
1637: char *s;
1638: {
1639: int y, x;
1640:
1641: fprintf(stderr, "<<< %s >>>\n", s);
1642: for (y = 0; y < lines; y++) {
1643: for (x = 0; x <= lenline[y] /*** && x < cols-1 ***/ ; x++) {
1644: fputc(line[y][x]&CHAR, stderr);
1645: }
1646: fputc('\n', stderr);
1647: for (x = 0; x <= lenline[y] && x < cols-1; x++) {
1648: if (line[y][x]&SOBIT)
1649: fputc('-', stderr);
1650: else
1651: fputc(' ', stderr);
1652: }
1653: fputc('\n', stderr);
1654: for (x = 0; x <= lenline[y] && x < cols-1; x++) {
1655: if (line[y][x]&XSBIT)
1656: fputc('+', stderr);
1657: else
1658: fputc(' ', stderr);
1659: }
1660: fputc('\n', stderr);
1661: }
1662: fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
1663: VOID fflush(stderr);
1664: }
1665: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.