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