2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)move.c 8.1 (Berkeley) 7/19/93
34 * $FreeBSD: src/games/snake/snake/move.c,v 1.5.2.1 2000/08/17 06:21:44 jhb Exp $
35 * $DragonFly: src/games/snake/snake/Attic/move.c,v 1.2 2003/06/17 04:25:25 dillon Exp $
38 /*************************************************************************
42 * This set of subroutines moves a cursor to a predefined
43 * location, independent of the terminal type. If the
44 * terminal has an addressable cursor, it uses it. If
45 * not, it optimizes for tabs (currently) even if you don't
48 * At all times the current address of the cursor must be maintained,
49 * and that is available as structure cursor.
51 * The following calls are allowed:
52 * move(sp) move to point sp.
53 * up() move up one line.
54 * down() move down one line.
55 * bs() move left one space (except column 0).
56 * nd() move right one space(no write).
57 * clear() clear screen.
59 * ll() move to lower left corner of screen.
60 * cr() carriage return (no line feed).
61 * pr() just like standard printf, but keeps track
62 * of cursor position. (Uses pstring).
63 * apr() same as printf, but first argument is &point.
65 * pstring(s) output the string of printing characters.
66 * However, '\r' is interpreted to mean return
67 * to column of origination AND do linefeed.
68 * '\n' causes <cr><lf>.
69 * putpad(str) calls tputs to output character with proper
71 * outch() the output routine for a character used by
72 * tputs. It just calls putchar.
73 * pch(ch) output character to screen and update
74 * cursor address (must be a standard
75 * printing character). WILL SCROLL.
76 * pchar(ps,ch) prints one character if it is on the
77 * screen at the specified location;
78 * otherwise, dumps it.(no wrap-around).
80 * getcap() initializes strings for later calls.
81 * cap(string) outputs the string designated in the termcap
82 * data base. (Should not move the cursor.)
83 * done() returns the terminal to intial state and exits.
85 * point(&p,x,y) return point set to x,y.
87 * baudrate() returns the baudrate of the terminal.
88 * delay(t) causes an approximately constant delay
89 * independent of baudrate.
90 * Duration is ~ t/20 seconds.
92 ******************************************************************************/
120 if (sp->line <0 || sp->col <0 || sp->col > COLUMNS){
121 pr("move to [%d,%d]?",sp->line,sp->col);
124 if (sp->line >= LINES){
125 move(point(&z,sp->col,LINES-1));
126 while(sp->line-- >= LINES)putchar('\n');
131 char *cmstr = tgoto(CM, sp->col, sp->line);
133 CMlength = strlen(cmstr);
134 if(cursor.line == sp->line){
135 distance = sp->col - cursor.col;
136 if(distance == 0)return; /* Already there! */
137 if(distance > 0){ /* Moving to the right */
138 if(distance*NDlength < CMlength){
144 tabcol=(cursor.col|7)+1;
149 while(tabcol<sp->col);
155 } else { /* Moving to the left */
156 if (-distance*BSlength < CMlength){
161 if(sp->col < CMlength){
166 /* No more optimizations on same row. */
168 distance = sp->col - cursor.col;
169 distance = distance > 0 ?
170 distance*NDlength : -distance * BSlength;
172 pr("ERROR: distance is negative: %d",distance);
173 distance += abs(sp->line - cursor.line);
174 if(distance >= CMlength){
176 cursor.line = sp->line;
177 cursor.col = sp->col;
183 * If we get here we have a terminal that can't cursor
184 * address but has local motions or one which can cursor
185 * address but can get there quicker with local motions.
193 int distance,f,tfield;
195 if (cursor.line > LINES || cursor.line <0 ||
196 cursor.col <0 || cursor.col > COLUMNS)
197 pr("ERROR: cursor is at %d,%d\n",
198 cursor.line,cursor.col);
199 if (sp->line > LINES || sp->line <0 ||
200 sp->col <0 || sp->col > COLUMNS)
201 pr("ERROR: target is %d,%d\n",sp->line,sp->col);
202 tfield = (sp->col) >> 3;
203 if (sp->line == cursor.line){
204 if (sp->col > cursor.col)right(sp);
206 distance = (cursor.col -sp->col)*BSlength;
208 (distance > tfield+((sp->col)&7)*NDlength)
210 (((cursor.col)*NDlength) < distance)
216 while(cursor.col > sp->col) bs();
222 if (cursor.col - sp->col > (cursor.col >> 3)){
223 if (cursor.col == 0)f = 0;
226 else f = cursor.col >> 3;
227 if (((sp->line << 1) + 1 < cursor.line - f) && (HO != 0)){
229 * home quicker than rlf:
230 * (sp->line + f > cursor.line - sp->line)
233 cursor.col = cursor.line = 0;
237 if (((sp->line << 1) > cursor.line + LINES+1 + f) && (LL != 0)){
238 /* home,rlf quicker than lf
239 * (LINES+1 - sp->line + f < sp->line - cursor.line)
241 if (cursor.line > f + 1){
242 /* is home faster than wraparound lf?
243 * (cursor.line + 20 - sp->line > 21 - sp->line + f)
250 if ((LL != 0) && (sp->line > cursor.line + (LINES >> 1) - 1))
251 cursor.line += LINES;
252 while(sp->line > cursor.line)down();
253 while(sp->line < cursor.line)up();
254 gto(sp); /*can recurse since cursor.line = sp->line */
261 int tabcol,strlength;
263 if (sp->col < cursor.col)
264 pr("ERROR:right() can't move left\n");
265 if(TA){ /* If No Tabs: can't send tabs because ttydrive
266 * loses count with control characters.
268 field = cursor.col >> 3;
270 * This code is useful for a terminal which wraps around on backspaces.
271 * (Mine does.) Unfortunately, this is not specified in termcap, and
272 * most terminals don't work that way. (Of course, most terminals
273 * have addressible cursors, too).
275 if (BW && (CM == 0) &&
276 ((sp->col << 1) - field > (COLUMNS - 8) << 1 )
278 if (cursor.line == 0){
282 cursor.col = COLUMNS + 1;
283 while(cursor.col > sp->col)bs();
284 if (cursor.line != 0) outch('\n');
288 tfield = sp->col >> 3;
290 while (field < tfield){
292 cursor.col = ++field << 3;
294 tabcol = (cursor.col|7) + 1;
295 strlength = (tabcol - sp->col)*BSlength + 1;
296 /* length of sequence to overshoot */
297 if (((sp->col - cursor.col)*NDlength > strlength) &&
301 * Tab past and backup
304 cursor.col = (cursor.col | 7) + 1;
305 while(cursor.col > sp->col)bs();
308 while (sp->col > cursor.col){
323 cursor.col=cursor.line=0;
325 for(i=0; i<LINES; i++) {
328 cursor.line = LINES - 1;
338 cursor.col = cursor.line = 0;
350 if(LL != NULL && LINES==l){
352 cursor.line = LINES-1;
369 if (cursor.line >= LINES)cursor.line=LINES-1;
381 if (cursor.col == COLUMNS+1){
384 if (cursor.line >= LINES)cursor.line=LINES-1;
391 if(++cursor.col >= COLUMNS && AM) {
399 apr(struct point *ps, const char *fmt, ...)
401 apr(ps, fmt, va_alist)
410 p.line = ps->line+1; p.col = ps->col+1;
417 (void)vsprintf(str, fmt, ap);
424 pr(const char *fmt, ...)
438 (void)vsprintf(str, fmt, ap);
449 while (s[0] != '\0'){
452 move(point(&z,0,cursor.line+1));
455 move(point(&z,stcol,cursor.line+1));
458 z.col = (((cursor.col + 8) >> 3) << 3);
459 z.line = cursor.line;
469 if (s[0] < ' ')break;
480 p.col = ps->col + 1; p.line = ps->line + 1;
490 (p.col == COLUMNS) &&
510 tputs(str, 1, outch);
517 switch (orig.sg_ospeed){
535 while (usleep(t*50000U) == -1 && errno == EINTR) ;
553 ioctl(0, TIOCSLTC, &olttyc);
561 ioctl(0, TIOCSLTC, &nlttyc);
565 struct point *point(ps,x,y)
586 term = getenv("TERM");
588 fprintf(stderr, "No TERM in environment\n");
592 switch (tgetent(tbuf, term)) {
594 fprintf(stderr, "Cannot open termcap file\n");
597 fprintf(stderr, "%s: unknown terminal", term);
604 if (ioctl(0, TIOCGWINSZ, (char *) &win) < 0 ||
605 (LINES = win.ws_row) == 0 || (COLUMNS = win.ws_col) == 0) {
607 LINES = tgetnum("li");
608 COLUMNS = tgetnum("co");
620 ND = tgetstr("nd", &ap);
621 UP = tgetstr("up", &ap);
623 DO = tgetstr("do", &ap);
627 BS = tgetstr("bc", &ap);
628 if (BS == 0 && tgetflag("bs"))
633 TA = tgetstr("ta", &ap);
634 if (TA == 0 && tgetflag("pt"))
637 HO = tgetstr("ho", &ap);
638 CL = tgetstr("cl", &ap);
639 CM = tgetstr("cm", &ap);
640 LL = tgetstr("ll", &ap);
642 KL = tgetstr("kl", &ap);
643 KR = tgetstr("kr", &ap);
644 KU = tgetstr("ku", &ap);
645 KD = tgetstr("kd", &ap);
647 Klength = strlen(KL);
649 Klength = strlen(KL);
651 * NOTE: If KL, KR, KU, and KD are not
652 * all the same length, some problems
653 * may arise, since tests are made on
654 * all of them together.
657 TI = tgetstr("ti", &ap);
658 TE = tgetstr("te", &ap);
659 KS = tgetstr("ks", &ap);
660 KE = tgetstr("ke", &ap);
662 VI = tgetstr("vi", &ap);
663 VE = tgetstr("ve", &ap);
665 xPC = tgetstr("pc", &ap);
670 NDlength = strlen(ND);
675 BSlength = strlen(BS);
680 (HO == 0 || DO == 0 || UP==0 || BS==0 || ND==0))
682 /* XXX as written in rev.1.6, we can assert(DO) */
683 fprintf(stderr, "Terminal must have addressible ");
684 fprintf(stderr, "cursor or home + 4 local motions\n");
687 if (tgetflag("os")) {
688 fprintf(stderr, "Terminal must not overstrike\n");
691 if (LINES <= 0 || COLUMNS <= 0) {
692 fprintf(stderr, "Must know the screen size\n");
698 new.sg_flags &= ~(ECHO|CRMOD|ALLDELAY|XTABS);
699 new.sg_flags |= CBREAK;
701 ospeed = orig.sg_ospeed;
703 ioctl(0, TIOCGLTC, &olttyc);
705 nlttyc.t_suspc = '\377';
706 nlttyc.t_dsuspc = '\377';
710 if ((orig.sg_flags & XTABS) == XTABS) TA=0;
713 point(&cursor,0,LINES-1);