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