/* * display -- a simple program to display static text in a more(1)-like * manner. Designed to run with simple BIOS services on a i*86-PC. * * Purpose of the program: provide a simple method for pcemu to display * a text when there is no DOS boot image installed. This program will * run as the bootfile then. * * Author: Joerg Wunsch, 95/03/10 * Placed in the public domain. Neither kind of warranty applies. * * Thanks to Bruce Evans for his bcc compiler. Made my work much * easier. */ #define MAXROW 23 #define MAXCOL 79 #asm maxrow: set 23 maxcol: set 79 nl: set 10 #endasm #define WHITE 7 #define BROWN 6 #define MAGENTA 5 #define RED 4 #define CYAN 3 #define GREEN 2 #define BLUE 1 #define BLACK 0 #define HIGH 8 /* convenience: */ #define YELLOW (BROWN|HIGH) /* foreground color */ #define GRAY WHITE /* background color */ #define NOCHANGE (-1) /* do not change color; for setattrib() */ /* * We use a special highlighting scheme: embedded control characters * in the text toggle the attribute selection. * * Define attributes used for highlighting. * NB: do not parenthise the macro expansions below, they are used as * complete parameter lists for setattrib()! */ #define REGULAR BLACK, GRAY /* ^R */ #define BOLD WHITE|HIGH, RED|HIGH /* ^B */ #define EMPHS BLUE, GRAY /* ^E */ #define DOUBLE YELLOW, BLACK /* ^D */ #define C_REGULAR ('R' & 0x1f) #define C_BOLD ('B' & 0x1f) #define C_EMPHS ('E' & 0x1f) #define C_DOUBLE ('D' & 0x1f) #define K_CUP ((0x48 << 8) + 0) /* extended ASCII, cursor up */ #define K_CDN ((0x50 << 8) + 0) /* extended ASCII, cursor down */ #define K_PREV ((0x49 << 8) + 0) /* extended ASCII, page up */ #define K_NEXT ((0x51 << 8) + 0) /* extended ASCII, page down */ /* * Glue to link to the BIOS services. */ char attrib; char row, col; void scroll(nlines) int nlines; /* if nlines == 0, clear entire region */ { #asm push bp mov bp, sp xor bh, bh ; page 0 mov dx, *(maxcol + (maxrow << 8)); bottom/right corner xor cx, cx ; top/left corner mov al, 4[bp] ; nlines mov bh, _attrib mov ah, *6 ; video bios, scroll (clear) region test al, al ; scroll back? jns _scroll.1 ; positive value -> forward inc ah ; scroll backwards neg al _scroll.1: int 0x10 pop bp #endasm } void gotoxy(x, y) int x; int y; { #asm push bp mov bp, sp mov dl, 4[bp] ; x mov _col, dl mov dh, 6[bp] ; y mov _row, dh xor bh, bh ; page 0 mov ah, *2 ; video bios, set cursor int 0x10 pop bp #endasm } void putchar(c) int c; { #asm push bp mov bp, sp mov al, 4[bp] ; c mov bl, _attrib xor bh, bh ; always page 0 mov cx, *1 ; just one char mov ah, *9 ; video bios, write char int 0x10 pop bp #endasm if(col < MAXCOL) gotoxy(col + 1, row); } void cls() { scroll(0); } int getchar() { #asm xor ah, ah ; kbd bios, get keystroke int 0x16 #endasm } void setattrib(foreground, background) int foreground; int background; { int i; if(foreground == -1) i = attrib & 0xf; else i = foreground & 0xf; if(background == -1) i |= (attrib & 0xf0); else i |= ((background & 0xf) << 4); attrib = i; } /* * Some auxiliary functions */ /* * print one line of text up to a newline or a null character */ char *printline(s) char *s; { register char c; while((c = *s++) && c != '\n') switch(c) { case C_REGULAR: setattrib(REGULAR); break; case C_BOLD: setattrib(BOLD); break; case C_EMPHS: setattrib(EMPHS); break; case C_DOUBLE: setattrib(DOUBLE); break; default: putchar(c); } if(c == 0) s--; return s; } /* * display a message on the bottom line; if msg == 0, clear bottom line */ void more(msg) char *msg; { int i; gotoxy(0, MAXROW + 1); if(msg) { setattrib(YELLOW, BLUE); (void)printline(msg); setattrib(REGULAR); } else { setattrib(WHITE, BLACK); for(i = 0; i < MAXCOL; i++) putchar(' '); setattrib(REGULAR); } } /* * go back for numlines newline chars, starting at current, but not before * initial */ char *goback(initial, current, numlines) char *initial; char *current; int numlines; { current--; while(numlines && current > initial) if(*--current == '\n') numlines--; if(*current == '\n') current++; return current; } /* * the static text is maintained separately in an (automatically generated) * .S file */ extern char textstr[]; /* do not declare this "char *" - bcc breaks */ int main() { char *cp, *cp1; int c; int lineno; lineno = 0; cp = textstr; setattrib(REGULAR); cls(); for(;;) { gotoxy(0, lineno); cp = printline(cp); if(*cp == 0) break; lineno++; if(lineno == MAXROW + 1) { for(;;) { more("--More--"); c = getchar(); more(0); if(c & 0xff) /* regular ASCII */ c &= 0xff; /* strip scancode */ switch(c) { case ' ': /* page forward */ case K_NEXT: lineno = 0; cls(); goto out; case 'd': /* half page forward */ scroll((MAXROW + 1) / 2); lineno -= (MAXROW + 1) / 2; goto out; case 'b': /* page backward */ case K_PREV: cp = goback(textstr, cp, 2 * (MAXROW + 1)); lineno = 0; cls(); goto out; case '\r': /* one more line */ case '\n': case K_CDN: lineno--; scroll(1); goto out; case K_CUP: /* one line less */ cp1 = goback(textstr, cp, 2); cp = goback(textstr, cp1, MAXROW); if(cp == textstr) /* start of text, redisplay all */ { lineno = 0; cls(); } else { scroll(-1); gotoxy(0, 0); (void)printline(cp); cp = cp1; lineno--; } goto out; case '?': case 'h': more( "space: next page, d: half page, b: back page, CR, DWN: nxt line, UP: prv line" ); (void)getchar(); more(0); break; case 'q': /* quit the game */ goto done; } } } out:; } done: more("Hit any key to quit."); (void)getchar(); more(0); return 0; }