Subversion Repositories SvarDOS

Rev

Rev 406 | Rev 415 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
352 mateuszvis 1
/*
2
 * a variety of helper functions
3
 * Copyright (C) 2021 Mateusz Viste
4
 */
5
 
396 mateuszvis 6
#include <i86.h>    /* MK_FP() */
7
 
352 mateuszvis 8
#include "helpers.h"
9
 
10
/* case-insensitive comparison of strings, returns non-zero on equality */
11
int imatch(const char *s1, const char *s2) {
12
  for (;;) {
13
    char c1, c2;
14
    c1 = *s1;
15
    c2 = *s2;
16
    if ((c1 >= 'a') && (c1 <= 'z')) c1 -= ('a' - 'A');
17
    if ((c2 >= 'a') && (c2 <= 'z')) c2 -= ('a' - 'A');
18
    /* */
19
    if (c1 != c2) return(0);
20
    if (c1 == 0) return(1);
21
    s1++;
22
    s2++;
23
  }
24
}
25
 
26
 
27
/* returns zero if s1 starts with s2 */
28
int strstartswith(const char *s1, const char *s2) {
29
  while (*s2 != 0) {
30
    if (*s1 != *s2) return(-1);
31
    s1++;
32
    s2++;
33
  }
34
  return(0);
35
}
369 mateuszvis 36
 
37
 
38
/* outputs a NULL-terminated string to stdout */
39
void output_internal(const char *s, unsigned short nl) {
40
  _asm {
41
    mov ah, 0x02 /* AH=9 - write character in DL to stdout */
42
    mov si, s
43
    cld          /* clear DF so lodsb increments SI */
44
    NEXTBYTE:
45
    lodsb /* load byte from DS:SI into AL, SI++ */
46
    mov dl, al
47
    or al, 0  /* is al == 0? */
48
    jz DONE
49
    int 0x21
50
    jmp NEXTBYTE
51
    DONE:
52
    or nl, 0
53
    jz FINITO
54
    /* print out a CR/LF trailer if nl set */
55
    mov dl, 0x0D /* CR */
56
    int 0x21
57
    mov dl, 0x0A /* LF */
58
    int 0x21
59
    FINITO:
60
  }
61
}
388 mateuszvis 62
 
63
 
64
/* find first matching files using a FindFirst DOS call
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) {
67
  unsigned short res = 0;
68
  _asm {
69
    /* set DTA location */
70
    mov ah, 0x1a
71
    mov dx, dta
72
    int 0x21
73
    /* */
74
    mov ah, 0x4e    /* FindFirst */
75
    mov dx, pattern
76
    mov cx, attr
77
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
78
    jnc DONE
79
    mov [res], ax
80
    DONE:
81
  }
82
  return(res);
83
}
84
 
85
 
86
/* find next matching, ie. continues an action intiated by findfirst() */
87
unsigned short findnext(struct DTA *dta) {
88
  unsigned short res = 0;
89
  _asm {
90
    mov ah, 0x4f    /* FindNext */
91
    mov dx, dta
92
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
93
    jnc DONE
94
    mov [res], ax
95
    DONE:
96
  }
97
  return(res);
98
}
392 mateuszvis 99
 
100
 
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
103
 * in string. keys in c MUST BE UPPERCASE! */
104
unsigned short askchoice(const char *s, const char *c) {
105
  unsigned short res;
106
  char key = 0;
107
 
108
  AGAIN:
109
  output(s);
110
  output(" ");
111
 
112
  _asm {
113
    push ax
114
    push dx
115
 
116
    mov ax, 0x0c01 /* clear input buffer and execute getchar (INT 21h,AH=1) */
117
    int 0x21
118
    /* if AL == 0 then this is an extended character */
119
    test al, al
120
    jnz GOTCHAR
121
    mov ah, 0x08   /* read again to flush extended char from input buffer */
122
    int 0x21
123
    xor al, al     /* all extended chars are ignored */
124
    GOTCHAR:       /* received key is in AL now */
125
    mov [key], al  /* save key */
126
 
127
    /* print a cr/lf */
128
    mov ah, 0x02
129
    mov dl, 0x0D
130
    int 0x21
131
    mov dl, 0x0A
132
    int 0x21
133
 
134
    pop dx
135
    pop ax
136
  }
137
 
138
  /* ucase() result */
139
  if ((key >= 'a') && (key <= 'z')) key -= ('a' - 'A');
140
 
141
  /* is there a match? */
142
  for (res = 0; c[res] != 0; res++) if (c[res] == key) return(res);
143
 
144
  goto AGAIN;
145
}
146
 
147
 
399 mateuszvis 148
/* converts a path to its canonic representation, returns 0 on success
149
 * or DOS err on failure (invalid drive) */
150
unsigned short file_truename(const char *src, char *dst) {
151
  unsigned short res = 0;
392 mateuszvis 152
  _asm {
399 mateuszvis 153
    push es
392 mateuszvis 154
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
155
    push ds
156
    pop es
157
    mov si, src
158
    mov di, dst
159
    int 0x21
399 mateuszvis 160
    jnc DONE
161
    mov [res], ax
162
    DONE:
163
    pop es
392 mateuszvis 164
  }
399 mateuszvis 165
  return(res);
392 mateuszvis 166
}
167
 
168
 
169
/* returns DOS attributes of file, or -1 on error */
170
int file_getattr(const char *fname) {
171
  int res = -1;
172
  _asm {
173
    mov ax, 0x4300  /* query file attributes, fname at DS:DX */
174
    mov dx, fname
175
    int 0x21        /* CX=attributes if CF=0, otherwise AX=errno */
176
    jc DONE
177
    mov [res], cx
178
    DONE:
179
  }
180
  return(res);
181
}
396 mateuszvis 182
 
183
 
184
/* returns screen's width (in columns) */
185
unsigned short screen_getwidth(void) {
186
  /* BIOS 0040:004A = word containing screen width in text columns */
187
  unsigned short far *scrw = MK_FP(0x40, 0x4a);
188
  return(*scrw);
189
}
190
 
191
 
192
/* returns screen's height (in rows) */
193
unsigned short screen_getheight(void) {
194
  /* BIOS 0040:0084 = byte containing maximum valid row value (EGA ONLY) */
195
  unsigned char far *scrh = MK_FP(0x40, 0x84);
196
  if (*scrh == 0) return(25);  /* pre-EGA adapter */
197
  return(*scrh + 1);
198
}
199
 
200
 
201
/* displays the "Press any key to continue" msg and waits for a keypress */
202
void press_any_key(void) {
203
  output("Press any key to continue...");
204
  _asm {
205
    mov ah, 0x08  /* no echo console input */
206
    int 0x21      /* pressed key in AL now (0 for extended keys) */
207
    test al, al
208
    jnz DONE
209
    int 0x21      /* executed ah=8 again to read the rest of extended key */
210
    DONE:
211
    /* output CR/LF */
212
    mov ah, 0x02
213
    mov dl, 0x0D
214
    int 0x21
215
    mov dl, 0x0A
216
    int 0x21
217
  }
218
}
399 mateuszvis 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
}
406 mateuszvis 248
 
249
 
250
/* converts a 8+3 filename into 11-bytes FCB format (MYFILE  EXT) */
251
void file_fname2fcb(char *dst, const char *src) {
252
  unsigned short i;
253
 
254
  /* fill dst with 11 spaces and a NULL terminator */
255
  for (i = 0; i < 12; i++) dst[i] = ' ';
256
  dst[12] = 0;
257
 
258
  /* copy fname until dot (.) or 8 characters */
259
  for (i = 0; i < 8; i++) {
260
    if ((src[i] == '.') || (src[i] == 0)) break;
261
    dst[i] = src[i];
262
  }
263
 
264
  /* advance src until extension or end of string */
265
  src += i;
266
  for (;;) {
267
    if (*src == '.') {
268
      src++; /* next character is extension */
269
      break;
270
    }
271
    if (*src == 0) break;
272
  }
273
 
274
  /* copy extension to dst (3 chars max) */
275
  dst += 8;
276
  for (i = 0; i < 3; i++) {
277
    if (src[i] == 0) break;
278
    dst[i] = src[i];
279
  }
280
}
281
 
282
 
283
/* converts a 11-bytes FCB filename (MYFILE  EXT) into 8+3 format (MYFILE.EXT) */
284
void file_fcb2fname(char *dst, const char *src) {
285
  unsigned short i, end = 0;
286
 
287
  for (i = 0; i < 8; i++) {
288
    dst[i] = src[i];
289
    if (dst[i] != ' ') end = i + 1;
290
  }
291
 
292
  /* is there an extension? */
293
  if (src[8] == ' ') {
294
    dst[end] = 0;
295
  } else { /* found extension: copy it until first space */
296
    dst[end++] = '.';
297
    for (i = 8; i < 11; i++) {
298
      if (src[i] == ' ') break;
299
      dst[end++] = src[i];
300
    }
301
    dst[end] = 0;
302
  }
303
}
410 mateuszvis 304
 
305
 
306
/* converts an ASCIIZ string into an unsigned short. returns 0 on success. */
307
int atouns(unsigned short *r, const char *s) {
308
  int err = 0;
309
 
310
  _asm {
311
    mov si, s
312
    xor ax, ax  /* general purpose register */
313
    xor cx, cx  /* contains the result */
314
    mov bx, 10  /* used as a multiplicative step */
315
 
316
    NEXTBYTE:
317
    xchg cx, ax /* move result into cx temporarily */
318
    lodsb  /* AL = DS:[SI++] */
319
    /* is AL 0? if so we're done */
320
    test al, al
321
    jz DONE
322
    /* validate that AL is in range '0'-'9' */
323
    sub al, '0'
324
    jc FAIL   /* neg result */
325
    cmp al, 9
326
    jg FAIL
327
    /* restore result into AX (CX contains the new digit) */
328
    xchg cx, ax
329
    /* multiply result by 10 and add cl */
330
    mul bx    /* DX AX = AX * BX(10) */
331
    jc FAIL   /* overflow */
332
    add ax, cx
333
    /* if CF then overflow occured (overflow part lands in DX) */
334
    jnc NEXTBYTE
335
 
336
    FAIL:
337
    inc [err]
338
 
339
    DONE: /* save result (CX) into indirect memory address r */
340
    mov bx, [r]
341
    mov [bx], cx
342
  }
343
  return(err);
344
}