|
|
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.