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