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