|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)move.c 5.1 (Berkeley) 5/30/85";
9: #endif not lint
10:
11: /*************************************************************************
12: *
13: * MOVE LIBRARY
14: *
15: * This set of subroutines moves a cursor to a predefined
16: * location, independent of the terminal type. If the
17: * terminal has an addressable cursor, it uses it. If
18: * not, it optimizes for tabs (currently) even if you don't
19: * have them.
20: *
21: * At all times the current address of the cursor must be maintained,
22: * and that is available as structure cursor.
23: *
24: * The following calls are allowed:
25: * move(sp) move to point sp.
26: * up() move up one line.
27: * down() move down one line.
28: * bs() move left one space (except column 0).
29: * nd() move right one space(no write).
30: * clear() clear screen.
31: * home() home.
32: * ll() move to lower left corner of screen.
33: * cr() carriage return (no line feed).
34: * printf() just like standard printf, but keeps track
35: * of cursor position. (Uses pstring).
36: * aprintf() same as printf, but first argument is &point.
37: * (Uses pstring).
38: * pstring(s) output the string of printing characters.
39: * However, '\r' is interpreted to mean return
40: * to column of origination AND do linefeed.
41: * '\n' causes <cr><lf>.
42: * putpad(str) calls tputs to output character with proper
43: * padding.
44: * outch() the output routine for a character used by
45: * tputs. It just calls putchar.
46: * pch(ch) output character to screen and update
47: * cursor address (must be a standard
48: * printing character). WILL SCROLL.
49: * pchar(ps,ch) prints one character if it is on the
50: * screen at the specified location;
51: * otherwise, dumps it.(no wrap-around).
52: *
53: * getcap() initializes strings for later calls.
54: * cap(string) outputs the string designated in the termcap
55: * data base. (Should not move the cursor.)
56: * done(int) returns the terminal to intial state. If int
57: * is not 0, it exits.
58: *
59: * same(&p1,&p2) returns 1 if p1 and p2 are the same point.
60: * point(&p,x,y) return point set to x,y.
61: *
62: * baudrate(x) returns the baudrate of the terminal.
63: * delay(t) causes an approximately constant delay
64: * independent of baudrate.
65: * Duration is ~ t/20 seconds.
66: *
67: ******************************************************************************/
68:
69: #include "snake.h"
70:
71: int CMlength;
72: int NDlength;
73: int BSlength;
74: int delaystr[10];
75: short ospeed;
76:
77: static char str[80];
78:
79: move(sp)
80: struct point *sp;
81: {
82: int distance;
83: int tabcol,ct;
84: struct point z;
85:
86: if (sp->line <0 || sp->col <0 || sp->col > COLUMNS){
87: printf("move to [%d,%d]?",sp->line,sp->col);
88: return;
89: }
90: if (sp->line >= LINES){
91: move(point(&z,sp->col,LINES-1));
92: while(sp->line-- >= LINES)putchar('\n');
93: return;
94: }
95:
96: if (CM != 0) {
97: char *cmstr = tgoto(CM, sp->col, sp->line);
98:
99: CMlength = strlen(cmstr);
100: if(cursor.line == sp->line){
101: distance = sp->col - cursor.col;
102: if(distance == 0)return; /* Already there! */
103: if(distance > 0){ /* Moving to the right */
104: if(distance*NDlength < CMlength){
105: right(sp);
106: return;
107: }
108: if(TA){
109: ct=sp->col&7;
110: tabcol=(cursor.col|7)+1;
111: do{
112: ct++;
113: tabcol=(tabcol|7)+1;
114: }
115: while(tabcol<sp->col);
116: if(ct<CMlength){
117: right(sp);
118: return;
119: }
120: }
121: } else { /* Moving to the left */
122: if (-distance*BSlength < CMlength){
123: gto(sp);
124: return;
125: }
126: }
127: if(sp->col < CMlength){
128: cr();
129: right(sp);
130: return;
131: }
132: /* No more optimizations on same row. */
133: }
134: distance = sp->col - cursor.col;
135: distance = distance > 0 ?
136: distance*NDlength : -distance * BSlength;
137: if(distance < 0)printf("ERROR: distance is negative: %d",distance);
138: distance += abs(sp->line - cursor.line);
139: if(distance >= CMlength){
140: putpad(cmstr);
141: cursor.line = sp->line;
142: cursor.col = sp->col;
143: return;
144: }
145: }
146:
147: /*
148: * If we get here we have a terminal that can't cursor
149: * address but has local motions or one which can cursor
150: * address but can get there quicker with local motions.
151: */
152: gto(sp);
153: }
154: gto(sp)
155: struct point *sp;
156: {
157:
158: int distance,f,tfield,j;
159:
160: if (cursor.line > LINES || cursor.line <0 ||
161: cursor.col <0 || cursor.col > COLUMNS)
162: printf("ERROR: cursor is at %d,%d\n",
163: cursor.line,cursor.col);
164: if (sp->line > LINES || sp->line <0 ||
165: sp->col <0 || sp->col > COLUMNS)
166: printf("ERROR: target is %d,%d\n",sp->line,sp->col);
167: tfield = (sp->col) >> 3;
168: if (sp->line == cursor.line){
169: if (sp->col > cursor.col)right(sp);
170: else{
171: distance = (cursor.col -sp->col)*BSlength;
172: if (((TA) &&
173: (distance > tfield+((sp->col)&7)*NDlength)
174: ) ||
175: (((cursor.col)*NDlength) < distance)
176: ){
177: cr();
178: right(sp);
179: }
180: else{
181: while(cursor.col > sp->col) bs();
182: }
183: }
184: return;
185: }
186: /*must change row */
187: if (cursor.col - sp->col > (cursor.col >> 3)){
188: if (cursor.col == 0)f = 0;
189: else f = -1;
190: }
191: else f = cursor.col >> 3;
192: if (((sp->line << 1) + 1 < cursor.line - f) && (HO != 0)){
193: /*
194: * home quicker than rlf:
195: * (sp->line + f > cursor.line - sp->line)
196: */
197: putpad(HO);
198: cursor.col = cursor.line = 0;
199: gto(sp);
200: return;
201: }
202: if (((sp->line << 1) > cursor.line + LINES+1 + f) && (LL != 0)){
203: /* home,rlf quicker than lf
204: * (LINES+1 - sp->line + f < sp->line - cursor.line)
205: */
206: if (cursor.line > f + 1){
207: /* is home faster than wraparound lf?
208: * (cursor.line + 20 - sp->line > 21 - sp->line + f)
209: */
210: ll();
211: gto(sp);
212: return;
213: }
214: }
215: if ((LL != 0) && (sp->line > cursor.line + (LINES >> 1) - 1))
216: cursor.line += LINES;
217: while(sp->line > cursor.line)down();
218: while(sp->line < cursor.line)up();
219: gto(sp); /*can recurse since cursor.line = sp->line */
220: }
221:
222: right(sp)
223: struct point *sp;
224: {
225: int field,tfield;
226: int tabcol,strlength;
227:
228: if (sp->col < cursor.col)
229: printf("ERROR:right() can't move left\n");
230: if(TA){ /* If No Tabs: can't send tabs because ttydrive
231: * loses count with control characters.
232: */
233: field = cursor.col >> 3;
234: /*
235: * This code is useful for a terminal which wraps around on backspaces.
236: * (Mine does.) Unfortunately, this is not specified in termcap, and
237: * most terminals don't work that way. (Of course, most terminals
238: * have addressible cursors, too).
239: */
240: if (BW && (CM == 0) &&
241: ((sp->col << 1) - field > (COLUMNS - 8) << 1 )
242: ){
243: if (cursor.line == 0){
244: outch('\n');
245: }
246: outch('\r');
247: cursor.col = COLUMNS + 1;
248: while(cursor.col > sp->col)bs();
249: if (cursor.line != 0) outch('\n');
250: return;
251: }
252:
253: tfield = sp->col >> 3;
254:
255: while (field < tfield){
256: putpad(TA);
257: cursor.col = ++field << 3;
258: }
259: tabcol = (cursor.col|7) + 1;
260: strlength = (tabcol - sp->col)*BSlength + 1;
261: /* length of sequence to overshoot */
262: if (((sp->col - cursor.col)*NDlength > strlength) &&
263: (tabcol < COLUMNS)
264: ){
265: /*
266: * Tab past and backup
267: */
268: putpad(TA);
269: cursor.col = (cursor.col | 7) + 1;
270: while(cursor.col > sp->col)bs();
271: }
272: }
273: while (sp->col > cursor.col){
274: nd();
275: }
276: }
277:
278: cr(){
279: outch('\r');
280: cursor.col = 0;
281: }
282:
283: clear(){
284: int i;
285:
286: if (CL){
287: putpad(CL);
288: cursor.col=cursor.line=0;
289: } else {
290: for(i=0; i<LINES; i++) {
291: putchar('\n');
292: }
293: cursor.line = LINES - 1;
294: home();
295: }
296: }
297:
298: home(){
299: struct point z;
300:
301: if(HO != 0){
302: putpad(HO);
303: cursor.col = cursor.line = 0;
304: return;
305: }
306: z.col = z.line = 0;
307: move(&z);
308: }
309:
310: ll(){
311: int j,l;
312: struct point z;
313:
314: l = lcnt + 2;
315: if(LL != NULL && LINES==l){
316: putpad(LL);
317: cursor.line = LINES-1;
318: cursor.col = 0;
319: return;
320: }
321: z.col = 0;
322: z.line = l-1;
323: move(&z);
324: }
325:
326: up(){
327: putpad(UP);
328: cursor.line--;
329: }
330:
331: down(){
332: putpad(DO);
333: cursor.line++;
334: if (cursor.line >= LINES)cursor.line=LINES-1;
335: }
336: bs(){
337: if (cursor.col > 0){
338: putpad(BS);
339: cursor.col--;
340: }
341: }
342:
343: nd(){
344: putpad(ND);
345: cursor.col++;
346: if (cursor.col == COLUMNS+1){
347: cursor.line++;
348: cursor.col = 0;
349: if (cursor.line >= LINES)cursor.line=LINES-1;
350: }
351: }
352:
353: pch(c)
354: {
355: outch(c);
356: if(++cursor.col >= COLUMNS && AM) {
357: cursor.col = 0;
358: ++cursor.line;
359: }
360: }
361:
362: aprintf(ps,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9)
363: struct point *ps;
364: char *st;
365: int v0,v1,v2,v3,v4,v5,v6,v7,v8,v9;
366:
367: {
368: struct point p;
369:
370: p.line = ps->line+1; p.col = ps->col+1;
371: move(&p);
372: sprintf(str,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9);
373: pstring(str);
374: }
375:
376: printf(st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9)
377: char *st;
378: int v0,v1,v2,v3,v4,v5,v6,v7,v8,v9;
379: {
380: sprintf(str,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9);
381: pstring(str);
382: }
383:
384: pstring(s)
385: char *s;{
386: struct point z;
387: int stcol;
388:
389: stcol = cursor.col;
390: while (s[0] != '\0'){
391: switch (s[0]){
392: case '\n':
393: move(point(&z,0,cursor.line+1));
394: break;
395: case '\r':
396: move(point(&z,stcol,cursor.line+1));
397: break;
398: case '\t':
399: z.col = (((cursor.col + 8) >> 3) << 3);
400: z.line = cursor.line;
401: move(&z);
402: break;
403: case '\b':
404: bs();
405: break;
406: case CTRL(g):
407: outch(CTRL(g));
408: break;
409: default:
410: if (s[0] < ' ')break;
411: pch(s[0]);
412: }
413: s++;
414: }
415: }
416:
417: pchar(ps,ch)
418: struct point *ps;
419: char ch;{
420: struct point p;
421: p.col = ps->col + 1; p.line = ps->line + 1;
422: if (
423: (p.col >= 0) &&
424: (p.line >= 0) &&
425: (
426: (
427: (p.line < LINES) &&
428: (p.col < COLUMNS)
429: ) ||
430: (
431: (p.col == COLUMNS) &&
432: (p.line < LINES-1)
433: )
434: )
435: ){
436: move(&p);
437: pch(ch);
438: }
439: }
440:
441:
442: outch(c)
443: {
444: putchar(c);
445: }
446:
447: putpad(str)
448: char *str;
449: {
450: if (str)
451: tputs(str, 1, outch);
452: }
453: baudrate()
454: {
455:
456: switch (orig.sg_ospeed){
457: case B300:
458: return(300);
459: case B1200:
460: return(1200);
461: case B4800:
462: return(4800);
463: case B9600:
464: return(9600);
465: default:
466: return(0);
467: }
468: }
469: delay(t)
470: int t;
471: {
472: int k,j;
473:
474: k = baudrate() * t / 300;
475: for(j=0;j<k;j++){
476: putchar(PC);
477: }
478: }
479:
480: done()
481: {
482: cook();
483: exit(0);
484: }
485:
486: cook()
487: {
488: delay(1);
489: putpad(TE);
490: putpad(KE);
491: fflush(stdout);
492: stty(0, &orig);
493: #ifdef TIOCSLTC
494: ioctl(0, TIOCSLTC, &olttyc);
495: #endif
496: }
497:
498: raw()
499: {
500: stty(0, &new);
501: #ifdef TIOCSLTC
502: ioctl(0, TIOCSLTC, &nlttyc);
503: #endif
504: }
505:
506: same(sp1,sp2)
507: struct point *sp1, *sp2;
508: {
509: if ((sp1->line == sp2->line) && (sp1->col == sp2->col))return(1);
510: return(0);
511: }
512:
513: struct point *point(ps,x,y)
514: struct point *ps;
515: int x,y;
516: {
517: ps->col=x;
518: ps->line=y;
519: return(ps);
520: }
521:
522: char *ap;
523:
524: getcap()
525: {
526: char *getenv();
527: char *term;
528: char *xPC;
529: struct point z;
530: int stop();
531:
532: term = getenv("TERM");
533: if (term==0) {
534: fprintf(stderr, "No TERM in environment\n");
535: exit(1);
536: }
537:
538: switch (tgetent(tbuf, term)) {
539: case -1:
540: fprintf(stderr, "Cannot open termcap file\n");
541: exit(2);
542: case 0:
543: fprintf(stderr, "%s: unknown terminal", term);
544: exit(3);
545: }
546:
547: ap = tcapbuf;
548:
549: LINES = tgetnum("li");
550: COLUMNS = tgetnum("co");
551: lcnt = LINES;
552: ccnt = COLUMNS - 1;
553:
554: AM = tgetflag("am");
555: BW = tgetflag("bw");
556:
557: ND = tgetstr("nd", &ap);
558: UP = tgetstr("up", &ap);
559:
560: DO = tgetstr("do", &ap);
561: if (DO == 0)
562: DO = "\n";
563:
564: BS = tgetstr("bc", &ap);
565: if (BS == 0 && tgetflag("bs"))
566: BS = "\b";
567: if (BS)
568: xBC = *BS;
569:
570: TA = tgetstr("ta", &ap);
571: if (TA == 0 && tgetflag("pt"))
572: TA = "\t";
573:
574: HO = tgetstr("ho", &ap);
575: CL = tgetstr("cl", &ap);
576: CM = tgetstr("cm", &ap);
577: LL = tgetstr("ll", &ap);
578:
579: KL = tgetstr("kl", &ap);
580: KR = tgetstr("kr", &ap);
581: KU = tgetstr("ku", &ap);
582: KD = tgetstr("kd", &ap);
583: Klength = strlen(KL);
584: /* NOTE: If KL, KR, KU, and KD are not
585: * all the same length, some problems
586: * may arise, since tests are made on
587: * all of them together.
588: */
589:
590: TI = tgetstr("ti", &ap);
591: TE = tgetstr("te", &ap);
592: KS = tgetstr("ks", &ap);
593: KE = tgetstr("ke", &ap);
594:
595: xPC = tgetstr("pc", &ap);
596: if (xPC)
597: PC = *xPC;
598:
599: NDlength = strlen(ND);
600: BSlength = strlen(BS);
601: if ((CM == 0) &&
602: (HO == 0 | UP==0 || BS==0 || ND==0)) {
603: fprintf(stderr, "Terminal must have addressible ");
604: fprintf(stderr, "cursor or home + 4 local motions\n");
605: exit(5);
606: }
607: if (tgetflag("os")) {
608: fprintf(stderr, "Terminal must not overstrike\n");
609: exit(5);
610: }
611: if (LINES <= 0 || COLUMNS <= 0) {
612: fprintf(stderr, "Must know the screen size\n");
613: exit(5);
614: }
615:
616: gtty(0, &orig);
617: new=orig;
618: new.sg_flags &= ~(ECHO|CRMOD|ALLDELAY|XTABS);
619: new.sg_flags |= CBREAK;
620: signal(SIGINT,stop);
621: ospeed = orig.sg_ospeed;
622: #ifdef TIOCGLTC
623: ioctl(0, TIOCGLTC, &olttyc);
624: nlttyc = olttyc;
625: nlttyc.t_suspc = '\377';
626: nlttyc.t_dsuspc = '\377';
627: #endif
628: raw();
629:
630: if ((orig.sg_flags & XTABS) == XTABS) TA=0;
631: putpad(KS);
632: putpad(TI);
633: point(&cursor,0,LINES-1);
634: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.