|
|
1.1 ! root 1: /* pc.c */ ! 2: ! 3: /* Author: ! 4: * Guntram Blohm ! 5: * Buchenstrasse 19 ! 6: * 7904 Erbach, West Germany ! 7: * Tel. ++49-7305-6997 ! 8: * sorry - no regular network connection ! 9: */ ! 10: ! 11: /* This file implements the ibm pc bios interface. See IBM documentation ! 12: * for details. ! 13: * If TERM is set upon invocation of elvis, this code is ignored completely, ! 14: * and the standard termcap functions are used, thus, even not-so-close ! 15: * compatibles can run elvis. For close compatibles however, bios output ! 16: * is much faster (and permits reverse scrolling, adding and deleting lines, ! 17: * and much more ansi.sys isn't capable of). GB. ! 18: */ ! 19: ! 20: /* The routines for setting raw mode were written by Dan Kegel. They were ! 21: * taken [with slight modifications] from the "raw.c" file that he distributes ! 22: * with his NANSI.SYS console driver. Email: [email protected] ! 23: */ ! 24: ! 25: #include "config.h" ! 26: #include "vi.h" ! 27: ! 28: #if MSDOS ! 29: ! 30: #include <dos.h> ! 31: ! 32: static void video(); ! 33: ! 34: /* vmode contains the screen attribute index and is set by attrset.*/ ! 35: ! 36: int vmode; ! 37: ! 38: /* The following array contains attribute definitions for ! 39: * color/monochrome attributes. Screen selects one of the sets. ! 40: * Maybe i'll put them into elvis options one day. ! 41: */ ! 42: ! 43: static int screen; ! 44: static char attr[2][8] = ! 45: { ! 46: /* :se: :so: :VB: :ul: :as: popup visible quit */ ! 47: { 0x1f, 0x1d, 0x1e, 0x1a, 0x1c, 0x2f, 0x3f, 0x07}, /* color */ ! 48: { 0x07, 0x70, 0x0f, 0x01, 0x0f, 0x70, 0x70, 0x07}, /* mono */ ! 49: }; ! 50: ! 51: /* ! 52: * bios interface functions for elvis - pc version ! 53: */ ! 54: ! 55: int biosquit() ! 56: { ! 57: int cx = 1; ! 58: ! 59: vmode = 7; ! 60: v_ce(); ! 61: } ! 62: ! 63: ! 64: /* This function changes the table of attribute bytes used during BIOS output. ! 65: */ ! 66: int bioscolor(mode, attrbyte) ! 67: int mode; /* e.g. A_NORMAL */ ! 68: int attrbyte;/* color code, as a PC attribute byte */ ! 69: { ! 70: attr[0][mode] = attrbyte; ! 71: return 0; ! 72: } ! 73: ! 74: /* IOCTL GETBITS/SETBITS bits. */ ! 75: #define DEVICE 0x80 ! 76: #define RAW 0x20 ! 77: ! 78: /* IOCTL operations */ ! 79: #define GETBITS 0 ! 80: #define SETBITS 1 ! 81: #define GETINSTATUS 6 ! 82: ! 83: /* DOS function numbers. */ ! 84: #define BREAKCHECK 0x33 ! 85: #define IOCTL 0x44 ! 86: ! 87: /* A nice way to call the DOS IOCTL function */ ! 88: static int ! 89: ioctl(int handle, int mode, unsigned setvalue) ! 90: { ! 91: union REGS regs; ! 92: ! 93: regs.h.ah = IOCTL; ! 94: regs.h.al = (char) mode; ! 95: regs.x.bx = handle; ! 96: regs.h.dl = (char) setvalue; ! 97: regs.h.dh = 0; /* Zero out dh */ ! 98: intdos(®s, ®s); ! 99: return (regs.x.dx); ! 100: } ! 101: ! 102: ! 103: /*-------------------------------------------------------------------------- ! 104: Call this routine to set or clear RAW mode for the device associated with ! 105: the given file. ! 106: Example: raw_set(1, TRUE); ! 107: --------------------------------------------------------------------------*/ ! 108: void raw_set(fd, rawstate) ! 109: int fd; ! 110: int rawstate; ! 111: { ! 112: int bits; ! 113: bits = ioctl(fd, GETBITS, 0); ! 114: if (DEVICE & bits) { ! 115: if (rawstate) ! 116: bits |= RAW; ! 117: else ! 118: bits &= ~RAW; ! 119: (void) ioctl(fd, SETBITS, bits); ! 120: } ! 121: } ! 122: ! 123: /* A nice way to call the DOS BREAKCHECK function */ ! 124: static int breakctl(int mode, int setvalue) ! 125: { ! 126: union REGS regs; ! 127: ! 128: regs.h.ah = BREAKCHECK; ! 129: regs.h.al = (char) mode; ! 130: regs.h.dl = (char) setvalue; ! 131: intdos(®s, ®s); ! 132: return (regs.x.dx & 0xff); ! 133: } ! 134: ! 135: /*-------------------------------------------------------------------------- ! 136: Call this routine to determine whether DOS is checking for break (Control-C) ! 137: before it executes any DOS function call. ! 138: Return value is FALSE if it only checks before console I/O function calls, ! 139: TRUE if it checks before any function call. ! 140: --------------------------------------------------------------------------*/ ! 141: int break_get(void) ! 142: { ! 143: return ( 0 != breakctl(GETBITS, 0)); ! 144: } ! 145: ! 146: /*-------------------------------------------------------------------------- ! 147: Call this routine with TRUE to tell DOS to check for break (Control-C) ! 148: before it executes any DOS function call. ! 149: Call this routine with FALSE to tell DOS to only check for break before ! 150: it executes console I/O function calls. ! 151: --------------------------------------------------------------------------*/ ! 152: void break_set(check) ! 153: int check; ! 154: { ! 155: (void) breakctl(SETBITS, check); ! 156: } ! 157: ! 158: /*-------------------------------------------------------------------------- ! 159: One routine to set (or clear) raw mode on stdin and stdout, ! 160: clear (or restore) break checking, and turn off input buffering on stdin. ! 161: This is the most common configuration; under MS-DOS, since setting raw mode ! 162: on stdout sometimes sets it on stdin, it's best to set it on both & be done ! 163: with it. ! 164: --------------------------------------------------------------------------*/ ! 165: void raw_set_stdio(rawstate) ! 166: int rawstate; /* TRUE -> set raw mode; FALSE -> clear raw mode */ ! 167: { ! 168: static int was_break_checking = 0; ! 169: ! 170: raw_set(0, rawstate); ! 171: raw_set(1, rawstate); ! 172: if (rawstate) { ! 173: was_break_checking = break_get(); ! 174: break_set(0); ! 175: } else { ! 176: break_set(was_break_checking); ! 177: } ! 178: } ! 179: ! 180: ! 181: ! 182: ! 183: ! 184: ! 185: /* cursor up: determine current position, decrement row, set position */ ! 186: ! 187: void v_up() ! 188: { ! 189: int dx; ! 190: video(0x300,(int *)0,&dx); ! 191: dx-=0x100; ! 192: video(0x200,(int *)0,&dx); ! 193: } ! 194: ! 195: #ifndef NO_CURSORSHAPE ! 196: /* cursor big: set begin scan to end scan - 4 */ ! 197: void v_cb() ! 198: { ! 199: int cx; ! 200: video(0x300, &cx, (int *)0); ! 201: cx=((cx&0xff)|(((cx&0xff)-4)<<8)); ! 202: video(0x100, &cx, (int *)0); ! 203: } ! 204: ! 205: /* cursor small: set begin scan to end scan - 1 */ ! 206: void v_cs() ! 207: { ! 208: int cx; ! 209: video(0x300, &cx, (int *)0); ! 210: cx=((cx&0xff)|(((cx&0xff)-1)<<8)); ! 211: video(0x100, &cx, (int *)0); ! 212: } ! 213: #endif ! 214: ! 215: /* clear to end: get cursor position and emit the aproppriate number ! 216: * of spaces, without moving cursor. ! 217: */ ! 218: ! 219: void v_ce() ! 220: { ! 221: int cx, dx; ! 222: video(0x300,(int *)0,&dx); ! 223: cx=COLS-(dx&0xff); ! 224: video(0x920,&cx,(int *)0); ! 225: } ! 226: ! 227: /* clear screen: clear all and set cursor home */ ! 228: ! 229: void v_cl() ! 230: { ! 231: int cx=0, dx=((LINES-1)<<8)+COLS-1; ! 232: video(0x0600,&cx,&dx); ! 233: dx=0; ! 234: video(0x0200,&cx,&dx); ! 235: } ! 236: ! 237: /* clear to bottom: get position, clear to eol, clear next line to end */ ! 238: ! 239: void v_cd() ! 240: { ! 241: int cx, dx, dxtmp; ! 242: video(0x0300,(int *)0,&dx); ! 243: dxtmp=(dx&0xff00)|(COLS-1); ! 244: cx=dx; ! 245: video(0x0600,&cx,&dxtmp); ! 246: cx=(dx&0xff00)+0x100; ! 247: dx=((LINES-1)<<8)+COLS-1; ! 248: video(0x600,&cx,&dx); ! 249: } ! 250: ! 251: /* add line: scroll rest of screen down */ ! 252: ! 253: void v_al() ! 254: { ! 255: int cx,dx; ! 256: video(0x0300,(int *)0,&dx); ! 257: cx=(dx&0xff00); ! 258: dx=((LINES-1)<<8)+COLS-1; ! 259: video(0x701,&cx,&dx); ! 260: } ! 261: ! 262: /* delete line: scroll rest up */ ! 263: ! 264: void v_dl() ! 265: { ! 266: int cx,dx; ! 267: video(0x0300,(int *)0,&dx); ! 268: cx=(dx&0xff00)/*+0x100*/; ! 269: dx=((LINES-1)<<8)+COLS-1; ! 270: video(0x601,&cx,&dx); ! 271: } ! 272: ! 273: /* scroll reverse: scroll whole screen */ ! 274: ! 275: void v_sr() ! 276: { ! 277: int cx=0, dx=((LINES-1)<<8)+COLS-1; ! 278: video(0x0701,&cx,&dx); ! 279: } ! 280: ! 281: /* set cursor */ ! 282: ! 283: void v_move(x,y) ! 284: int x, y; ! 285: { ! 286: int dx=(y<<8)+x; ! 287: video(0x200,(int *)0,&dx); ! 288: } ! 289: ! 290: /* put character: set attribute first, then execute char. ! 291: * Also remember if current line has changed. ! 292: */ ! 293: ! 294: int v_put(ch) ! 295: int ch; ! 296: { ! 297: int cx=1; ! 298: ch&=0xff; ! 299: if (ch>=' ') ! 300: video(0x900|ch,&cx,(int *)0); ! 301: video(0xe00|ch,(int *)0, (int *)0); ! 302: if (ch=='\n') ! 303: { exwrote = TRUE; ! 304: video(0xe0d, (int *)0, (int *)0); ! 305: } ! 306: return ch; ! 307: } ! 308: ! 309: /* determine number of screen columns. Also set attrset according ! 310: * to monochrome/color screen. ! 311: */ ! 312: ! 313: int v_cols() ! 314: { ! 315: union REGS regs; ! 316: regs.h.ah=0x0f; ! 317: int86(0x10, ®s, ®s); ! 318: if (regs.h.al==7) /* monochrome mode ? */ ! 319: screen=1; ! 320: else ! 321: screen=0; ! 322: return regs.h.ah; ! 323: } ! 324: ! 325: /* Getting the number of rows is hard. Most screens support 25 only, ! 326: * EGA/VGA also support 43/50 lines, and some OEM's even more. ! 327: * Unfortunately, there is no standard bios variable for the number ! 328: * of lines, and the bios screen memory size is always rounded up ! 329: * to 0x1000. So, we'll really have to cheat. ! 330: * When using the screen memory size, keep in mind that each character ! 331: * byte has an associated attribute byte. ! 332: * ! 333: * uses: word at 40:4c contains memory size ! 334: * byte at 40:84 # of rows-1 (sometimes) ! 335: * byte at 40:4a # of columns ! 336: */ ! 337: ! 338: int v_rows() ! 339: { ! 340: int line, oldline; ! 341: ! 342: /* screen size less then 4K? then we have 25 lines only */ ! 343: ! 344: if (*(int far *)(0x0040004cl)<=4096) ! 345: return 25; ! 346: ! 347: /* VEGA vga uses the bios byte at 0x40:0x84 for # of rows. ! 348: * Use that byte, if it makes sense together with memory size. ! 349: */ ! 350: ! 351: if ((((*(unsigned char far *)(0x0040004aL)*2* ! 352: (*(unsigned char far *)(0x00400084L)+1))+0xfff)&(~0xfff))== ! 353: *(unsigned int far *)(0x0040004cL)) ! 354: return *(unsigned char far *)(0x00400084L)+1; ! 355: ! 356: /* uh oh. Emit '\n's until screen starts scrolling. */ ! 357: ! 358: v_move(oldline=0, 0); ! 359: for (;;) ! 360: { ! 361: video(0xe0a,(int *)0,(int *)0); ! 362: video(0x300,(int *)0,&line); ! 363: line>>=8; ! 364: if (oldline==line) ! 365: return line+1; ! 366: oldline=line; ! 367: } ! 368: } ! 369: ! 370: /* the REAL bios interface -- used internally only. */ ! 371: ! 372: static void video(ax, cx, dx) ! 373: int ax, *cx, *dx; ! 374: { ! 375: union REGS regs; ! 376: ! 377: regs.x.ax=ax; ! 378: if ((ax&0xff00)==0x600 || (ax&0xff00)==0x700) ! 379: regs.h.bh=attr[screen][vmode]; ! 380: else ! 381: { ! 382: regs.h.bh=0; ! 383: regs.h.bl=attr[screen][vmode]; ! 384: } ! 385: if (cx) regs.x.cx=*cx; ! 386: if (dx) regs.x.dx=*dx; ! 387: int86(0x10, ®s, ®s); ! 388: if (dx) *dx=regs.x.dx; ! 389: if (cx) *cx=regs.x.cx; ! 390: } ! 391: ! 392: /* The following function determines which character is used for ! 393: * commandline-options by command.com. This system call is undocumented ! 394: * and valid for versions < 4.00 only. ! 395: */ ! 396: ! 397: int switchar() ! 398: { ! 399: union REGS regs; ! 400: regs.x.ax=0x3700; ! 401: int86(0x21, ®s, ®s); ! 402: return regs.h.dl; ! 403: } ! 404: ! 405: ! 406: /* this function returns the DOS time, as a 32-bit long int representing ! 407: * hundredths of a second since midnight. Some systems may be limited to ! 408: * a resolution of whole seconds, but the values will still represent ! 409: * hundredths. ! 410: */ ! 411: static long dostime() ! 412: { ! 413: union REGS regs; ! 414: ! 415: regs.h.ah = 0x2c; /* MS-DOS "get time" service */ ! 416: intdos(®s, ®s); ! 417: return (((regs.h.ch * 60L) + regs.h.cl) * 60L + regs.h.dh) * 100L + regs.h.dl; ! 418: } ! 419: ! 420: ! 421: /*ARGSUSED*/ ! 422: /* This function implements a raw read from the keyboard, with timeout. */ ! 423: int ttyread(buf, len, time) ! 424: char *buf; /* where to store the keystrokes */ ! 425: int len; /* maximum number of characters to get -- ignored */ ! 426: int time; /* maximum time to wait, in 1/9th second increments */ ! 427: { ! 428: long stop; ! 429: ! 430: /* are we going to timeout? */ ! 431: if (time != 0) ! 432: { ! 433: /* compute the time when we'll give up */ ! 434: stop = dostime() + time * 10L; ! 435: ! 436: /* wait for either keystroke or timeout */ ! 437: while (!kbhit()) ! 438: { ! 439: if (dostime() > stop) ! 440: { ! 441: /* we couldn't read any characters ! 442: * before timeout ! 443: */ ! 444: return 0; ! 445: } ! 446: } ! 447: } ! 448: ! 449: /* get a keystroke */ ! 450: buf[0] = getch(); ! 451: if (buf[0] == 0) /* function key? */ ! 452: { ! 453: buf[0] = '#'; ! 454: buf[1] = getch(); ! 455: return 2; ! 456: } ! 457: else ! 458: { ! 459: return 1; ! 460: } ! 461: } ! 462: ! 463: #if !TURBOC ! 464: /* Turboc provides sleep, declared as void sleep(unsigned seconds) */ ! 465: int sleep(seconds) ! 466: unsigned seconds; ! 467: { ! 468: long stop; ! 469: ! 470: stop = dostime() + 100L * seconds; ! 471: while (dostime() < stop) ! 472: { ! 473: } ! 474: return 0; ! 475: } ! 476: #endif ! 477: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.