Commit | Line | Data |
---|---|---|
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 | 9 | static 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 | ||
70 | int CMlength; | |
71 | int NDlength; | |
72 | int BSlength; | |
73 | int delaystr[10]; | |
74 | short ospeed; | |
75 | ||
76 | static char str[80]; | |
77 | ||
78 | move(sp) | |
79 | struct 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; | |
136 | if(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 | } | |
153 | gto(sp) | |
154 | struct 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 | ||
221 | right(sp) | |
222 | struct 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 | ||
277 | cr(){ | |
278 | outch('\r'); | |
279 | cursor.col = 0; | |
280 | } | |
281 | ||
282 | clear(){ | |
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 | ||
297 | home(){ | |
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 | ||
309 | ll(){ | |
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 | ||
325 | up(){ | |
326 | putpad(UP); | |
327 | cursor.line--; | |
328 | } | |
329 | ||
330 | down(){ | |
331 | putpad(DO); | |
332 | cursor.line++; | |
333 | if (cursor.line >= LINES)cursor.line=LINES-1; | |
334 | } | |
335 | bs(){ | |
336 | if (cursor.col > 0){ | |
337 | putpad(BS); | |
338 | cursor.col--; | |
339 | } | |
340 | } | |
341 | ||
342 | nd(){ | |
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 | ||
352 | pch(c) | |
353 | { | |
354 | outch(c); | |
355 | if(++cursor.col >= COLUMNS && AM) { | |
356 | cursor.col = 0; | |
357 | ++cursor.line; | |
358 | } | |
359 | } | |
360 | ||
361 | aprintf(ps,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9) | |
362 | struct point *ps; | |
363 | char *st; | |
364 | int 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 | ||
375 | printf(st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9) | |
376 | char *st; | |
377 | int 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 | ||
383 | pstring(s) | |
384 | char *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 | ||
416 | pchar(ps,ch) | |
417 | struct point *ps; | |
418 | char 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 | ||
441 | outch(c) | |
442 | { | |
443 | putchar(c); | |
444 | } | |
445 | ||
446 | putpad(str) | |
447 | char *str; | |
448 | { | |
449 | if (str) | |
450 | tputs(str, 1, outch); | |
451 | } | |
452 | baudrate() | |
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 | } | |
468 | delay(t) | |
469 | int 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 | ||
479 | done() | |
480 | { | |
481 | cook(); | |
482 | exit(0); | |
483 | } | |
484 | ||
485 | cook() | |
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 | ||
497 | raw() | |
498 | { | |
499 | stty(0, &new); | |
500 | #ifdef TIOCSLTC | |
501 | ioctl(0, TIOCSLTC, &nlttyc); | |
502 | #endif | |
503 | } | |
504 | ||
c44a1e93 SL |
505 | struct point *point(ps,x,y) |
506 | struct point *ps; | |
507 | int x,y; | |
508 | { | |
509 | ps->col=x; | |
510 | ps->line=y; | |
511 | return(ps); | |
512 | } | |
513 | ||
514 | char *ap; | |
515 | ||
516 | getcap() | |
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 | } |