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