Rev 396 | Rev 399 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* a variety of helper functions
* Copyright (C) 2021 Mateusz Viste
*/
#include <i86.h> /* MK_FP() */
#include "helpers.h"
/* case-insensitive comparison of strings, returns non-zero on equality */
int imatch(const char *s1, const char *s2) {
for (;;) {
char c1, c2;
c1 = *s1;
c2 = *s2;
if ((c1 >= 'a') && (c1 <= 'z')) c1 -= ('a' - 'A');
if ((c2 >= 'a') && (c2 <= 'z')) c2 -= ('a' - 'A');
/* */
if (c1 != c2) return(0);
if (c1 == 0) return(1);
s1++;
s2++;
}
}
/* returns zero if s1 starts with s2 */
int strstartswith(const char *s1, const char *s2) {
while (*s2 != 0) {
if (*s1 != *s2) return(-1);
s1++;
s2++;
}
return(0);
}
/* outputs a NULL-terminated string to stdout */
void output_internal(const char *s, unsigned short nl) {
_asm {
mov ah, 0x02 /* AH=9 - write character in DL to stdout */
mov si, s
cld /* clear DF so lodsb increments SI */
NEXTBYTE:
lodsb /* load byte from DS:SI into AL, SI++ */
mov dl, al
or al, 0 /* is al == 0? */
jz DONE
int 0x21
jmp NEXTBYTE
DONE:
or nl, 0
jz FINITO
/* print out a CR/LF trailer if nl set */
mov dl, 0x0D /* CR */
int 0x21
mov dl, 0x0A /* LF */
int 0x21
FINITO:
}
}
/* find first matching files using a FindFirst DOS call
* returns 0 on success or a DOS err code on failure */
unsigned short findfirst(struct DTA *dta, const char *pattern, unsigned short attr) {
unsigned short res = 0;
_asm {
/* set DTA location */
mov ah, 0x1a
mov dx, dta
int 0x21
/* */
mov ah, 0x4e /* FindFirst */
mov dx, pattern
mov cx, attr
int 0x21 /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
jnc DONE
mov [res], ax
DONE:
}
return(res);
}
/* find next matching, ie. continues an action intiated by findfirst() */
unsigned short findnext(struct DTA *dta) {
unsigned short res = 0;
_asm {
mov ah, 0x4f /* FindNext */
mov dx, dta
int 0x21 /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
jnc DONE
mov [res], ax
DONE:
}
return(res);
}
/* print s string and wait for a single key press from stdin. accepts only
* key presses defined in the c ASCIIZ string. returns offset of pressed key
* in string. keys in c MUST BE UPPERCASE! */
unsigned short askchoice(const char *s, const char *c) {
unsigned short res;
char key = 0;
AGAIN:
output(s);
output(" ");
_asm {
push ax
push dx
mov ax, 0x0c01 /* clear input buffer and execute getchar (INT 21h,AH=1) */
int 0x21
/* if AL == 0 then this is an extended character */
test al, al
jnz GOTCHAR
mov ah, 0x08 /* read again to flush extended char from input buffer */
int 0x21
xor al, al /* all extended chars are ignored */
GOTCHAR: /* received key is in AL now */
mov [key], al /* save key */
/* print a cr/lf */
mov ah, 0x02
mov dl, 0x0D
int 0x21
mov dl, 0x0A
int 0x21
pop dx
pop ax
}
/* ucase() result */
if ((key >= 'a') && (key <= 'z')) key -= ('a' - 'A');
/* is there a match? */
for (res = 0; c[res] != 0; res++) if (c[res] == key) return(res);
goto AGAIN;
}
/* converts a path to its canonic representation */
void file_truename(const char *src, char *dst) {
_asm {
mov ah, 0x60 /* query truename, DS:SI=src, ES:DI=dst */
push ds
pop es
mov si, src
mov di, dst
int 0x21
}
}
/* returns DOS attributes of file, or -1 on error */
int file_getattr(const char *fname) {
int res = -1;
_asm {
mov ax, 0x4300 /* query file attributes, fname at DS:DX */
mov dx, fname
int 0x21 /* CX=attributes if CF=0, otherwise AX=errno */
jc DONE
mov [res], cx
DONE:
}
return(res);
}
/* returns screen's width (in columns) */
unsigned short screen_getwidth(void) {
/* BIOS 0040:004A = word containing screen width in text columns */
unsigned short far *scrw = MK_FP(0x40, 0x4a);
return(*scrw);
}
/* returns screen's height (in rows) */
unsigned short screen_getheight(void) {
/* BIOS 0040:0084 = byte containing maximum valid row value (EGA ONLY) */
unsigned char far *scrh = MK_FP(0x40, 0x84);
if (*scrh == 0) return(25); /* pre-EGA adapter */
return(*scrh + 1);
}
/* displays the "Press any key to continue" msg and waits for a keypress */
void press_any_key(void) {
output("Press any key to continue...");
_asm {
mov ah, 0x08 /* no echo console input */
int 0x21 /* pressed key in AL now (0 for extended keys) */
test al, al
jnz DONE
int 0x21 /* executed ah=8 again to read the rest of extended key */
DONE:
/* output CR/LF */
mov ah, 0x02
mov dl, 0x0D
int 0x21
mov dl, 0x0A
int 0x21
}
}