Subversion Repositories SvarDOS

Rev

Rev 397 | Rev 406 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 397 Rev 399
1
/*
1
/*
2
 * a variety of helper functions
2
 * a variety of helper functions
3
 * Copyright (C) 2021 Mateusz Viste
3
 * Copyright (C) 2021 Mateusz Viste
4
 */
4
 */
5
 
5
 
6
#include <i86.h>    /* MK_FP() */
6
#include <i86.h>    /* MK_FP() */
7
 
7
 
8
#include "helpers.h"
8
#include "helpers.h"
9
 
9
 
10
/* case-insensitive comparison of strings, returns non-zero on equality */
10
/* case-insensitive comparison of strings, returns non-zero on equality */
11
int imatch(const char *s1, const char *s2) {
11
int imatch(const char *s1, const char *s2) {
12
  for (;;) {
12
  for (;;) {
13
    char c1, c2;
13
    char c1, c2;
14
    c1 = *s1;
14
    c1 = *s1;
15
    c2 = *s2;
15
    c2 = *s2;
16
    if ((c1 >= 'a') && (c1 <= 'z')) c1 -= ('a' - 'A');
16
    if ((c1 >= 'a') && (c1 <= 'z')) c1 -= ('a' - 'A');
17
    if ((c2 >= 'a') && (c2 <= 'z')) c2 -= ('a' - 'A');
17
    if ((c2 >= 'a') && (c2 <= 'z')) c2 -= ('a' - 'A');
18
    /* */
18
    /* */
19
    if (c1 != c2) return(0);
19
    if (c1 != c2) return(0);
20
    if (c1 == 0) return(1);
20
    if (c1 == 0) return(1);
21
    s1++;
21
    s1++;
22
    s2++;
22
    s2++;
23
  }
23
  }
24
}
24
}
25
 
25
 
26
 
26
 
27
/* returns zero if s1 starts with s2 */
27
/* returns zero if s1 starts with s2 */
28
int strstartswith(const char *s1, const char *s2) {
28
int strstartswith(const char *s1, const char *s2) {
29
  while (*s2 != 0) {
29
  while (*s2 != 0) {
30
    if (*s1 != *s2) return(-1);
30
    if (*s1 != *s2) return(-1);
31
    s1++;
31
    s1++;
32
    s2++;
32
    s2++;
33
  }
33
  }
34
  return(0);
34
  return(0);
35
}
35
}
36
 
36
 
37
 
37
 
38
/* outputs a NULL-terminated string to stdout */
38
/* outputs a NULL-terminated string to stdout */
39
void output_internal(const char *s, unsigned short nl) {
39
void output_internal(const char *s, unsigned short nl) {
40
  _asm {
40
  _asm {
41
    mov ah, 0x02 /* AH=9 - write character in DL to stdout */
41
    mov ah, 0x02 /* AH=9 - write character in DL to stdout */
42
    mov si, s
42
    mov si, s
43
    cld          /* clear DF so lodsb increments SI */
43
    cld          /* clear DF so lodsb increments SI */
44
    NEXTBYTE:
44
    NEXTBYTE:
45
    lodsb /* load byte from DS:SI into AL, SI++ */
45
    lodsb /* load byte from DS:SI into AL, SI++ */
46
    mov dl, al
46
    mov dl, al
47
    or al, 0  /* is al == 0? */
47
    or al, 0  /* is al == 0? */
48
    jz DONE
48
    jz DONE
49
    int 0x21
49
    int 0x21
50
    jmp NEXTBYTE
50
    jmp NEXTBYTE
51
    DONE:
51
    DONE:
52
    or nl, 0
52
    or nl, 0
53
    jz FINITO
53
    jz FINITO
54
    /* print out a CR/LF trailer if nl set */
54
    /* print out a CR/LF trailer if nl set */
55
    mov dl, 0x0D /* CR */
55
    mov dl, 0x0D /* CR */
56
    int 0x21
56
    int 0x21
57
    mov dl, 0x0A /* LF */
57
    mov dl, 0x0A /* LF */
58
    int 0x21
58
    int 0x21
59
    FINITO:
59
    FINITO:
60
  }
60
  }
61
}
61
}
62
 
62
 
63
 
63
 
64
/* find first matching files using a FindFirst DOS call
64
/* find first matching files using a FindFirst DOS call
65
 * returns 0 on success or a DOS err code on failure */
65
 * returns 0 on success or a DOS err code on failure */
66
unsigned short findfirst(struct DTA *dta, const char *pattern, unsigned short attr) {
66
unsigned short findfirst(struct DTA *dta, const char *pattern, unsigned short attr) {
67
  unsigned short res = 0;
67
  unsigned short res = 0;
68
  _asm {
68
  _asm {
69
    /* set DTA location */
69
    /* set DTA location */
70
    mov ah, 0x1a
70
    mov ah, 0x1a
71
    mov dx, dta
71
    mov dx, dta
72
    int 0x21
72
    int 0x21
73
    /* */
73
    /* */
74
    mov ah, 0x4e    /* FindFirst */
74
    mov ah, 0x4e    /* FindFirst */
75
    mov dx, pattern
75
    mov dx, pattern
76
    mov cx, attr
76
    mov cx, attr
77
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
77
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
78
    jnc DONE
78
    jnc DONE
79
    mov [res], ax
79
    mov [res], ax
80
    DONE:
80
    DONE:
81
  }
81
  }
82
  return(res);
82
  return(res);
83
}
83
}
84
 
84
 
85
 
85
 
86
/* find next matching, ie. continues an action intiated by findfirst() */
86
/* find next matching, ie. continues an action intiated by findfirst() */
87
unsigned short findnext(struct DTA *dta) {
87
unsigned short findnext(struct DTA *dta) {
88
  unsigned short res = 0;
88
  unsigned short res = 0;
89
  _asm {
89
  _asm {
90
    mov ah, 0x4f    /* FindNext */
90
    mov ah, 0x4f    /* FindNext */
91
    mov dx, dta
91
    mov dx, dta
92
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
92
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
93
    jnc DONE
93
    jnc DONE
94
    mov [res], ax
94
    mov [res], ax
95
    DONE:
95
    DONE:
96
  }
96
  }
97
  return(res);
97
  return(res);
98
}
98
}
99
 
99
 
100
 
100
 
101
/* print s string and wait for a single key press from stdin. accepts only
101
/* print s string and wait for a single key press from stdin. accepts only
102
 * key presses defined in the c ASCIIZ string. returns offset of pressed key
102
 * key presses defined in the c ASCIIZ string. returns offset of pressed key
103
 * in string. keys in c MUST BE UPPERCASE! */
103
 * in string. keys in c MUST BE UPPERCASE! */
104
unsigned short askchoice(const char *s, const char *c) {
104
unsigned short askchoice(const char *s, const char *c) {
105
  unsigned short res;
105
  unsigned short res;
106
  char key = 0;
106
  char key = 0;
107
 
107
 
108
  AGAIN:
108
  AGAIN:
109
  output(s);
109
  output(s);
110
  output(" ");
110
  output(" ");
111
 
111
 
112
  _asm {
112
  _asm {
113
    push ax
113
    push ax
114
    push dx
114
    push dx
115
 
115
 
116
    mov ax, 0x0c01 /* clear input buffer and execute getchar (INT 21h,AH=1) */
116
    mov ax, 0x0c01 /* clear input buffer and execute getchar (INT 21h,AH=1) */
117
    int 0x21
117
    int 0x21
118
    /* if AL == 0 then this is an extended character */
118
    /* if AL == 0 then this is an extended character */
119
    test al, al
119
    test al, al
120
    jnz GOTCHAR
120
    jnz GOTCHAR
121
    mov ah, 0x08   /* read again to flush extended char from input buffer */
121
    mov ah, 0x08   /* read again to flush extended char from input buffer */
122
    int 0x21
122
    int 0x21
123
    xor al, al     /* all extended chars are ignored */
123
    xor al, al     /* all extended chars are ignored */
124
    GOTCHAR:       /* received key is in AL now */
124
    GOTCHAR:       /* received key is in AL now */
125
    mov [key], al  /* save key */
125
    mov [key], al  /* save key */
126
 
126
 
127
    /* print a cr/lf */
127
    /* print a cr/lf */
128
    mov ah, 0x02
128
    mov ah, 0x02
129
    mov dl, 0x0D
129
    mov dl, 0x0D
130
    int 0x21
130
    int 0x21
131
    mov dl, 0x0A
131
    mov dl, 0x0A
132
    int 0x21
132
    int 0x21
133
 
133
 
134
    pop dx
134
    pop dx
135
    pop ax
135
    pop ax
136
  }
136
  }
137
 
137
 
138
  /* ucase() result */
138
  /* ucase() result */
139
  if ((key >= 'a') && (key <= 'z')) key -= ('a' - 'A');
139
  if ((key >= 'a') && (key <= 'z')) key -= ('a' - 'A');
140
 
140
 
141
  /* is there a match? */
141
  /* is there a match? */
142
  for (res = 0; c[res] != 0; res++) if (c[res] == key) return(res);
142
  for (res = 0; c[res] != 0; res++) if (c[res] == key) return(res);
143
 
143
 
144
  goto AGAIN;
144
  goto AGAIN;
145
}
145
}
146
 
146
 
147
 
147
 
148
/* converts a path to its canonic representation */
148
/* converts a path to its canonic representation, returns 0 on success
-
 
149
 * or DOS err on failure (invalid drive) */
149
void file_truename(const char *src, char *dst) {
150
unsigned short file_truename(const char *src, char *dst) {
-
 
151
  unsigned short res = 0;
150
  _asm {
152
  _asm {
-
 
153
    push es
151
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
154
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
152
    push ds
155
    push ds
153
    pop es
156
    pop es
154
    mov si, src
157
    mov si, src
155
    mov di, dst
158
    mov di, dst
156
    int 0x21
159
    int 0x21
-
 
160
    jnc DONE
-
 
161
    mov [res], ax
-
 
162
    DONE:
-
 
163
    pop es
157
  }
164
  }
-
 
165
  return(res);
158
}
166
}
159
 
167
 
160
 
168
 
161
/* returns DOS attributes of file, or -1 on error */
169
/* returns DOS attributes of file, or -1 on error */
162
int file_getattr(const char *fname) {
170
int file_getattr(const char *fname) {
163
  int res = -1;
171
  int res = -1;
164
  _asm {
172
  _asm {
165
    mov ax, 0x4300  /* query file attributes, fname at DS:DX */
173
    mov ax, 0x4300  /* query file attributes, fname at DS:DX */
166
    mov dx, fname
174
    mov dx, fname
167
    int 0x21        /* CX=attributes if CF=0, otherwise AX=errno */
175
    int 0x21        /* CX=attributes if CF=0, otherwise AX=errno */
168
    jc DONE
176
    jc DONE
169
    mov [res], cx
177
    mov [res], cx
170
    DONE:
178
    DONE:
171
  }
179
  }
172
  return(res);
180
  return(res);
173
}
181
}
174
 
182
 
175
 
183
 
176
/* returns screen's width (in columns) */
184
/* returns screen's width (in columns) */
177
unsigned short screen_getwidth(void) {
185
unsigned short screen_getwidth(void) {
178
  /* BIOS 0040:004A = word containing screen width in text columns */
186
  /* BIOS 0040:004A = word containing screen width in text columns */
179
  unsigned short far *scrw = MK_FP(0x40, 0x4a);
187
  unsigned short far *scrw = MK_FP(0x40, 0x4a);
180
  return(*scrw);
188
  return(*scrw);
181
}
189
}
182
 
190
 
183
 
191
 
184
/* returns screen's height (in rows) */
192
/* returns screen's height (in rows) */
185
unsigned short screen_getheight(void) {
193
unsigned short screen_getheight(void) {
186
  /* BIOS 0040:0084 = byte containing maximum valid row value (EGA ONLY) */
194
  /* BIOS 0040:0084 = byte containing maximum valid row value (EGA ONLY) */
187
  unsigned char far *scrh = MK_FP(0x40, 0x84);
195
  unsigned char far *scrh = MK_FP(0x40, 0x84);
188
  if (*scrh == 0) return(25);  /* pre-EGA adapter */
196
  if (*scrh == 0) return(25);  /* pre-EGA adapter */
189
  return(*scrh + 1);
197
  return(*scrh + 1);
190
}
198
}
191
 
199
 
192
 
200
 
193
/* displays the "Press any key to continue" msg and waits for a keypress */
201
/* displays the "Press any key to continue" msg and waits for a keypress */
194
void press_any_key(void) {
202
void press_any_key(void) {
195
  output("Press any key to continue...");
203
  output("Press any key to continue...");
196
  _asm {
204
  _asm {
197
    mov ah, 0x08  /* no echo console input */
205
    mov ah, 0x08  /* no echo console input */
198
    int 0x21      /* pressed key in AL now (0 for extended keys) */
206
    int 0x21      /* pressed key in AL now (0 for extended keys) */
199
    test al, al
207
    test al, al
200
    jnz DONE
208
    jnz DONE
201
    int 0x21      /* executed ah=8 again to read the rest of extended key */
209
    int 0x21      /* executed ah=8 again to read the rest of extended key */
202
    DONE:
210
    DONE:
203
    /* output CR/LF */
211
    /* output CR/LF */
204
    mov ah, 0x02
212
    mov ah, 0x02
205
    mov dl, 0x0D
213
    mov dl, 0x0D
206
    int 0x21
214
    int 0x21
207
    mov dl, 0x0A
215
    mov dl, 0x0A
208
    int 0x21
216
    int 0x21
209
  }
217
  }
210
}
218
}
-
 
219
 
-
 
220
 
-
 
221
/* validate a drive (A=0, B=1, etc). returns 1 if valid, 0 otherwise */
-
 
222
int isdrivevalid(unsigned char drv) {
-
 
223
  _asm {
-
 
224
    mov ah, 0x19  /* query default (current) disk */
-
 
225
    int 0x21      /* drive in AL (0=A, 1=B, etc) */
-
 
226
    mov ch, al    /* save current drive to ch */
-
 
227
    /* try setting up the drive as current */
-
 
228
    mov ah, 0x0E   /* select default drive */
-
 
229
    mov dl, [drv]  /* 0=A, 1=B, etc */
-
 
230
    int 0x21
-
 
231
    /* this call does not set CF on error, I must check cur drive to look for success */
-
 
232
    mov ah, 0x19  /* query default (current) disk */
-
 
233
    int 0x21      /* drive in AL (0=A, 1=B, etc) */
-
 
234
    mov [drv], 1  /* preset result as success */
-
 
235
    cmp al, dl    /* is eq? */
-
 
236
    je DONE
-
 
237
    mov [drv], 0  /* fail */
-
 
238
    jmp FAILED
-
 
239
    DONE:
-
 
240
    /* set current drive back to what it was initially */
-
 
241
    mov ah, 0x0E
-
 
242
    mov dl, ch
-
 
243
    int 0x21
-
 
244
    FAILED:
-
 
245
  }
-
 
246
  return(drv);
-
 
247
}
211
 
248