Subversion Repositories SvarDOS

Rev

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

Rev 416 Rev 420
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
#include <stdio.h>  /* sprintf() */
7
 
8
 
8
#include "helpers.h"
9
#include "helpers.h"
9
 
10
 
-
 
11
 
10
/* case-insensitive comparison of strings, returns non-zero on equality */
12
/* case-insensitive comparison of strings, returns non-zero on equality */
11
int imatch(const char *s1, const char *s2) {
13
int imatch(const char *s1, const char *s2) {
12
  for (;;) {
14
  for (;;) {
13
    char c1, c2;
15
    char c1, c2;
14
    c1 = *s1;
16
    c1 = *s1;
15
    c2 = *s2;
17
    c2 = *s2;
16
    if ((c1 >= 'a') && (c1 <= 'z')) c1 -= ('a' - 'A');
18
    if ((c1 >= 'a') && (c1 <= 'z')) c1 -= ('a' - 'A');
17
    if ((c2 >= 'a') && (c2 <= 'z')) c2 -= ('a' - 'A');
19
    if ((c2 >= 'a') && (c2 <= 'z')) c2 -= ('a' - 'A');
18
    /* */
20
    /* */
19
    if (c1 != c2) return(0);
21
    if (c1 != c2) return(0);
20
    if (c1 == 0) return(1);
22
    if (c1 == 0) return(1);
21
    s1++;
23
    s1++;
22
    s2++;
24
    s2++;
23
  }
25
  }
24
}
26
}
25
 
27
 
26
 
28
 
27
/* returns zero if s1 starts with s2 */
29
/* returns zero if s1 starts with s2 */
28
int strstartswith(const char *s1, const char *s2) {
30
int strstartswith(const char *s1, const char *s2) {
29
  while (*s2 != 0) {
31
  while (*s2 != 0) {
30
    if (*s1 != *s2) return(-1);
32
    if (*s1 != *s2) return(-1);
31
    s1++;
33
    s1++;
32
    s2++;
34
    s2++;
33
  }
35
  }
34
  return(0);
36
  return(0);
35
}
37
}
36
 
38
 
37
 
39
 
38
/* outputs a NULL-terminated string to stdout */
40
/* outputs a NULL-terminated string to stdout */
39
void output_internal(const char *s, unsigned short nl) {
41
void output_internal(const char *s, unsigned short nl) {
40
  _asm {
42
  _asm {
41
    mov ah, 0x02 /* AH=9 - write character in DL to stdout */
43
    mov ah, 0x02 /* AH=9 - write character in DL to stdout */
42
    mov si, s
44
    mov si, s
43
    cld          /* clear DF so lodsb increments SI */
45
    cld          /* clear DF so lodsb increments SI */
44
    NEXTBYTE:
46
    NEXTBYTE:
45
    lodsb /* load byte from DS:SI into AL, SI++ */
47
    lodsb /* load byte from DS:SI into AL, SI++ */
46
    mov dl, al
48
    mov dl, al
47
    or al, 0  /* is al == 0? */
49
    or al, 0  /* is al == 0? */
48
    jz DONE
50
    jz DONE
49
    int 0x21
51
    int 0x21
50
    jmp NEXTBYTE
52
    jmp NEXTBYTE
51
    DONE:
53
    DONE:
52
    or nl, 0
54
    or nl, 0
53
    jz FINITO
55
    jz FINITO
54
    /* print out a CR/LF trailer if nl set */
56
    /* print out a CR/LF trailer if nl set */
55
    mov dl, 0x0D /* CR */
57
    mov dl, 0x0D /* CR */
56
    int 0x21
58
    int 0x21
57
    mov dl, 0x0A /* LF */
59
    mov dl, 0x0A /* LF */
58
    int 0x21
60
    int 0x21
59
    FINITO:
61
    FINITO:
60
  }
62
  }
61
}
63
}
62
 
64
 
63
 
65
 
64
/* find first matching files using a FindFirst DOS call
66
/* find first matching files using a FindFirst DOS call
65
 * returns 0 on success or a DOS err code on failure */
67
 * returns 0 on success or a DOS err code on failure */
66
unsigned short findfirst(struct DTA *dta, const char *pattern, unsigned short attr) {
68
unsigned short findfirst(struct DTA *dta, const char *pattern, unsigned short attr) {
67
  unsigned short res = 0;
69
  unsigned short res = 0;
68
  _asm {
70
  _asm {
69
    /* set DTA location */
71
    /* set DTA location */
70
    mov ah, 0x1a
72
    mov ah, 0x1a
71
    mov dx, dta
73
    mov dx, dta
72
    int 0x21
74
    int 0x21
73
    /* */
75
    /* */
74
    mov ah, 0x4e    /* FindFirst */
76
    mov ah, 0x4e    /* FindFirst */
75
    mov dx, pattern
77
    mov dx, pattern
76
    mov cx, attr
78
    mov cx, attr
77
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
79
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
78
    jnc DONE
80
    jnc DONE
79
    mov [res], ax
81
    mov [res], ax
80
    DONE:
82
    DONE:
81
  }
83
  }
82
  return(res);
84
  return(res);
83
}
85
}
84
 
86
 
85
 
87
 
86
/* find next matching, ie. continues an action intiated by findfirst() */
88
/* find next matching, ie. continues an action intiated by findfirst() */
87
unsigned short findnext(struct DTA *dta) {
89
unsigned short findnext(struct DTA *dta) {
88
  unsigned short res = 0;
90
  unsigned short res = 0;
89
  _asm {
91
  _asm {
90
    mov ah, 0x4f    /* FindNext */
92
    mov ah, 0x4f    /* FindNext */
91
    mov dx, dta
93
    mov dx, dta
92
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
94
    int 0x21        /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
93
    jnc DONE
95
    jnc DONE
94
    mov [res], ax
96
    mov [res], ax
95
    DONE:
97
    DONE:
96
  }
98
  }
97
  return(res);
99
  return(res);
98
}
100
}
99
 
101
 
100
 
102
 
101
/* print s string and wait for a single key press from stdin. accepts only
103
/* 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
104
 * key presses defined in the c ASCIIZ string. returns offset of pressed key
103
 * in string. keys in c MUST BE UPPERCASE! */
105
 * in string. keys in c MUST BE UPPERCASE! */
104
unsigned short askchoice(const char *s, const char *c) {
106
unsigned short askchoice(const char *s, const char *c) {
105
  unsigned short res;
107
  unsigned short res;
106
  char key = 0;
108
  char key = 0;
107
 
109
 
108
  AGAIN:
110
  AGAIN:
109
  output(s);
111
  output(s);
110
  output(" ");
112
  output(" ");
111
 
113
 
112
  _asm {
114
  _asm {
113
    push ax
115
    push ax
114
    push dx
116
    push dx
115
 
117
 
116
    mov ax, 0x0c01 /* clear input buffer and execute getchar (INT 21h,AH=1) */
118
    mov ax, 0x0c01 /* clear input buffer and execute getchar (INT 21h,AH=1) */
117
    int 0x21
119
    int 0x21
118
    /* if AL == 0 then this is an extended character */
120
    /* if AL == 0 then this is an extended character */
119
    test al, al
121
    test al, al
120
    jnz GOTCHAR
122
    jnz GOTCHAR
121
    mov ah, 0x08   /* read again to flush extended char from input buffer */
123
    mov ah, 0x08   /* read again to flush extended char from input buffer */
122
    int 0x21
124
    int 0x21
123
    xor al, al     /* all extended chars are ignored */
125
    xor al, al     /* all extended chars are ignored */
124
    GOTCHAR:       /* received key is in AL now */
126
    GOTCHAR:       /* received key is in AL now */
125
    mov [key], al  /* save key */
127
    mov [key], al  /* save key */
126
 
128
 
127
    /* print a cr/lf */
129
    /* print a cr/lf */
128
    mov ah, 0x02
130
    mov ah, 0x02
129
    mov dl, 0x0D
131
    mov dl, 0x0D
130
    int 0x21
132
    int 0x21
131
    mov dl, 0x0A
133
    mov dl, 0x0A
132
    int 0x21
134
    int 0x21
133
 
135
 
134
    pop dx
136
    pop dx
135
    pop ax
137
    pop ax
136
  }
138
  }
137
 
139
 
138
  /* ucase() result */
140
  /* ucase() result */
139
  if ((key >= 'a') && (key <= 'z')) key -= ('a' - 'A');
141
  if ((key >= 'a') && (key <= 'z')) key -= ('a' - 'A');
140
 
142
 
141
  /* is there a match? */
143
  /* is there a match? */
142
  for (res = 0; c[res] != 0; res++) if (c[res] == key) return(res);
144
  for (res = 0; c[res] != 0; res++) if (c[res] == key) return(res);
143
 
145
 
144
  goto AGAIN;
146
  goto AGAIN;
145
}
147
}
146
 
148
 
147
 
149
 
148
/* converts a path to its canonic representation, returns 0 on success
150
/* converts a path to its canonic representation, returns 0 on success
149
 * or DOS err on failure (invalid drive) */
151
 * or DOS err on failure (invalid drive) */
150
unsigned short file_truename(const char *src, char *dst) {
152
unsigned short file_truename(const char *src, char *dst) {
151
  unsigned short res = 0;
153
  unsigned short res = 0;
152
  _asm {
154
  _asm {
153
    push es
155
    push es
154
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
156
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
155
    push ds
157
    push ds
156
    pop es
158
    pop es
157
    mov si, src
159
    mov si, src
158
    mov di, dst
160
    mov di, dst
159
    int 0x21
161
    int 0x21
160
    jnc DONE
162
    jnc DONE
161
    mov [res], ax
163
    mov [res], ax
162
    DONE:
164
    DONE:
163
    pop es
165
    pop es
164
  }
166
  }
165
  return(res);
167
  return(res);
166
}
168
}
167
 
169
 
168
 
170
 
169
/* returns DOS attributes of file, or -1 on error */
171
/* returns DOS attributes of file, or -1 on error */
170
int file_getattr(const char *fname) {
172
int file_getattr(const char *fname) {
171
  int res = -1;
173
  int res = -1;
172
  _asm {
174
  _asm {
173
    mov ax, 0x4300  /* query file attributes, fname at DS:DX */
175
    mov ax, 0x4300  /* query file attributes, fname at DS:DX */
174
    mov dx, fname
176
    mov dx, fname
175
    int 0x21        /* CX=attributes if CF=0, otherwise AX=errno */
177
    int 0x21        /* CX=attributes if CF=0, otherwise AX=errno */
176
    jc DONE
178
    jc DONE
177
    mov [res], cx
179
    mov [res], cx
178
    DONE:
180
    DONE:
179
  }
181
  }
180
  return(res);
182
  return(res);
181
}
183
}
182
 
184
 
183
 
185
 
184
/* returns screen's width (in columns) */
186
/* returns screen's width (in columns) */
185
unsigned short screen_getwidth(void) {
187
unsigned short screen_getwidth(void) {
186
  /* BIOS 0040:004A = word containing screen width in text columns */
188
  /* BIOS 0040:004A = word containing screen width in text columns */
187
  unsigned short far *scrw = MK_FP(0x40, 0x4a);
189
  unsigned short far *scrw = MK_FP(0x40, 0x4a);
188
  return(*scrw);
190
  return(*scrw);
189
}
191
}
190
 
192
 
191
 
193
 
192
/* returns screen's height (in rows) */
194
/* returns screen's height (in rows) */
193
unsigned short screen_getheight(void) {
195
unsigned short screen_getheight(void) {
194
  /* BIOS 0040:0084 = byte containing maximum valid row value (EGA ONLY) */
196
  /* BIOS 0040:0084 = byte containing maximum valid row value (EGA ONLY) */
195
  unsigned char far *scrh = MK_FP(0x40, 0x84);
197
  unsigned char far *scrh = MK_FP(0x40, 0x84);
196
  if (*scrh == 0) return(25);  /* pre-EGA adapter */
198
  if (*scrh == 0) return(25);  /* pre-EGA adapter */
197
  return(*scrh + 1);
199
  return(*scrh + 1);
198
}
200
}
199
 
201
 
200
 
202
 
201
/* displays the "Press any key to continue" msg and waits for a keypress */
203
/* displays the "Press any key to continue" msg and waits for a keypress */
202
void press_any_key(void) {
204
void press_any_key(void) {
203
  output("Press any key to continue...");
205
  output("Press any key to continue...");
204
  _asm {
206
  _asm {
205
    mov ah, 0x08  /* no echo console input */
207
    mov ah, 0x08  /* no echo console input */
206
    int 0x21      /* pressed key in AL now (0 for extended keys) */
208
    int 0x21      /* pressed key in AL now (0 for extended keys) */
207
    test al, al
209
    test al, al
208
    jnz DONE
210
    jnz DONE
209
    int 0x21      /* executed ah=8 again to read the rest of extended key */
211
    int 0x21      /* executed ah=8 again to read the rest of extended key */
210
    DONE:
212
    DONE:
211
    /* output CR/LF */
213
    /* output CR/LF */
212
    mov ah, 0x02
214
    mov ah, 0x02
213
    mov dl, 0x0D
215
    mov dl, 0x0D
214
    int 0x21
216
    int 0x21
215
    mov dl, 0x0A
217
    mov dl, 0x0A
216
    int 0x21
218
    int 0x21
217
  }
219
  }
218
}
220
}
219
 
221
 
220
 
222
 
221
/* validate a drive (A=0, B=1, etc). returns 1 if valid, 0 otherwise */
223
/* validate a drive (A=0, B=1, etc). returns 1 if valid, 0 otherwise */
222
int isdrivevalid(unsigned char drv) {
224
int isdrivevalid(unsigned char drv) {
223
  _asm {
225
  _asm {
224
    mov ah, 0x19  /* query default (current) disk */
226
    mov ah, 0x19  /* query default (current) disk */
225
    int 0x21      /* drive in AL (0=A, 1=B, etc) */
227
    int 0x21      /* drive in AL (0=A, 1=B, etc) */
226
    mov ch, al    /* save current drive to ch */
228
    mov ch, al    /* save current drive to ch */
227
    /* try setting up the drive as current */
229
    /* try setting up the drive as current */
228
    mov ah, 0x0E   /* select default drive */
230
    mov ah, 0x0E   /* select default drive */
229
    mov dl, [drv]  /* 0=A, 1=B, etc */
231
    mov dl, [drv]  /* 0=A, 1=B, etc */
230
    int 0x21
232
    int 0x21
231
    /* this call does not set CF on error, I must check cur drive to look for success */
233
    /* 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 */
234
    mov ah, 0x19  /* query default (current) disk */
233
    int 0x21      /* drive in AL (0=A, 1=B, etc) */
235
    int 0x21      /* drive in AL (0=A, 1=B, etc) */
234
    mov [drv], 1  /* preset result as success */
236
    mov [drv], 1  /* preset result as success */
235
    cmp al, dl    /* is eq? */
237
    cmp al, dl    /* is eq? */
236
    je DONE
238
    je DONE
237
    mov [drv], 0  /* fail */
239
    mov [drv], 0  /* fail */
238
    jmp FAILED
240
    jmp FAILED
239
    DONE:
241
    DONE:
240
    /* set current drive back to what it was initially */
242
    /* set current drive back to what it was initially */
241
    mov ah, 0x0E
243
    mov ah, 0x0E
242
    mov dl, ch
244
    mov dl, ch
243
    int 0x21
245
    int 0x21
244
    FAILED:
246
    FAILED:
245
  }
247
  }
246
  return(drv);
248
  return(drv);
247
}
249
}
248
 
250
 
249
 
251
 
250
/* converts a 8+3 filename into 11-bytes FCB format (MYFILE  EXT) */
252
/* converts a 8+3 filename into 11-bytes FCB format (MYFILE  EXT) */
251
void file_fname2fcb(char *dst, const char *src) {
253
void file_fname2fcb(char *dst, const char *src) {
252
  unsigned short i;
254
  unsigned short i;
253
 
255
 
254
  /* fill dst with 11 spaces and a NULL terminator */
256
  /* fill dst with 11 spaces and a NULL terminator */
255
  for (i = 0; i < 12; i++) dst[i] = ' ';
257
  for (i = 0; i < 11; i++) dst[i] = ' ';
256
  dst[12] = 0;
258
  dst[11] = 0;
257
 
259
 
258
  /* copy fname until dot (.) or 8 characters */
260
  /* copy fname until dot (.) or 8 characters */
259
  for (i = 0; i < 8; i++) {
261
  for (i = 0; i < 8; i++) {
260
    if ((src[i] == '.') || (src[i] == 0)) break;
262
    if ((src[i] == '.') || (src[i] == 0)) break;
261
    dst[i] = src[i];
263
    dst[i] = src[i];
262
  }
264
  }
263
 
265
 
264
  /* advance src until extension or end of string */
266
  /* advance src until extension or end of string */
265
  src += i;
267
  src += i;
266
  for (;;) {
268
  for (;;) {
267
    if (*src == '.') {
269
    if (*src == '.') {
268
      src++; /* next character is extension */
270
      src++; /* next character is extension */
269
      break;
271
      break;
270
    }
272
    }
271
    if (*src == 0) break;
273
    if (*src == 0) break;
272
  }
274
  }
273
 
275
 
274
  /* copy extension to dst (3 chars max) */
276
  /* copy extension to dst (3 chars max) */
275
  dst += 8;
277
  dst += 8;
276
  for (i = 0; i < 3; i++) {
278
  for (i = 0; i < 3; i++) {
277
    if (src[i] == 0) break;
279
    if (src[i] == 0) break;
278
    dst[i] = src[i];
280
    dst[i] = src[i];
279
  }
281
  }
280
}
282
}
281
 
283
 
282
 
284
 
283
/* converts a 11-bytes FCB filename (MYFILE  EXT) into 8+3 format (MYFILE.EXT) */
285
/* converts a 11-bytes FCB filename (MYFILE  EXT) into 8+3 format (MYFILE.EXT) */
284
void file_fcb2fname(char *dst, const char *src) {
286
void file_fcb2fname(char *dst, const char *src) {
285
  unsigned short i, end = 0;
287
  unsigned short i, end = 0;
286
 
288
 
287
  for (i = 0; i < 8; i++) {
289
  for (i = 0; i < 8; i++) {
288
    dst[i] = src[i];
290
    dst[i] = src[i];
289
    if (dst[i] != ' ') end = i + 1;
291
    if (dst[i] != ' ') end = i + 1;
290
  }
292
  }
291
 
293
 
292
  /* is there an extension? */
294
  /* is there an extension? */
293
  if (src[8] == ' ') {
295
  if (src[8] == ' ') {
294
    dst[end] = 0;
296
    dst[end] = 0;
295
  } else { /* found extension: copy it until first space */
297
  } else { /* found extension: copy it until first space */
296
    dst[end++] = '.';
298
    dst[end++] = '.';
297
    for (i = 8; i < 11; i++) {
299
    for (i = 8; i < 11; i++) {
298
      if (src[i] == ' ') break;
300
      if (src[i] == ' ') break;
299
      dst[end++] = src[i];
301
      dst[end++] = src[i];
300
    }
302
    }
301
    dst[end] = 0;
303
    dst[end] = 0;
302
  }
304
  }
303
}
305
}
304
 
306
 
305
 
307
 
306
/* converts an ASCIIZ string into an unsigned short. returns 0 on success. */
308
/* converts an ASCIIZ string into an unsigned short. returns 0 on success. */
307
int atouns(unsigned short *r, const char *s) {
309
int atouns(unsigned short *r, const char *s) {
308
  int err = 0;
310
  int err = 0;
309
 
311
 
310
  _asm {
312
  _asm {
311
    mov si, s
313
    mov si, s
312
    xor ax, ax  /* general purpose register */
314
    xor ax, ax  /* general purpose register */
313
    xor cx, cx  /* contains the result */
315
    xor cx, cx  /* contains the result */
314
    mov bx, 10  /* used as a multiplicative step */
316
    mov bx, 10  /* used as a multiplicative step */
315
 
317
 
316
    NEXTBYTE:
318
    NEXTBYTE:
317
    xchg cx, ax /* move result into cx temporarily */
319
    xchg cx, ax /* move result into cx temporarily */
318
    lodsb  /* AL = DS:[SI++] */
320
    lodsb  /* AL = DS:[SI++] */
319
    /* is AL 0? if so we're done */
321
    /* is AL 0? if so we're done */
320
    test al, al
322
    test al, al
321
    jz DONE
323
    jz DONE
322
    /* validate that AL is in range '0'-'9' */
324
    /* validate that AL is in range '0'-'9' */
323
    sub al, '0'
325
    sub al, '0'
324
    jc FAIL   /* neg result */
326
    jc FAIL   /* neg result */
325
    cmp al, 9
327
    cmp al, 9
326
    jg FAIL
328
    jg FAIL
327
    /* restore result into AX (CX contains the new digit) */
329
    /* restore result into AX (CX contains the new digit) */
328
    xchg cx, ax
330
    xchg cx, ax
329
    /* multiply result by 10 and add cl */
331
    /* multiply result by 10 and add cl */
330
    mul bx    /* DX AX = AX * BX(10) */
332
    mul bx    /* DX AX = AX * BX(10) */
331
    jc FAIL   /* overflow */
333
    jc FAIL   /* overflow */
332
    add ax, cx
334
    add ax, cx
333
    /* if CF then overflow occured (overflow part lands in DX) */
335
    /* if CF then overflow occured (overflow part lands in DX) */
334
    jnc NEXTBYTE
336
    jnc NEXTBYTE
335
 
337
 
336
    FAIL:
338
    FAIL:
337
    inc [err]
339
    inc [err]
338
 
340
 
339
    DONE: /* save result (CX) into indirect memory address r */
341
    DONE: /* save result (CX) into indirect memory address r */
340
    mov bx, [r]
342
    mov bx, [r]
341
    mov [bx], cx
343
    mov [bx], cx
342
  }
344
  }
343
  return(err);
345
  return(err);
344
}
346
}
345
 
347
 
346
 
348
 
347
/* appends a backslash if path is a directory
349
/* appends a backslash if path is a directory
348
 * returns the (possibly updated) length of path */
350
 * returns the (possibly updated) length of path */
349
unsigned short path_appendbkslash_if_dir(char *path) {
351
unsigned short path_appendbkslash_if_dir(char *path) {
350
  unsigned short len;
352
  unsigned short len;
351
  int attr;
353
  int attr;
352
  for (len = 0; path[len] != 0; len++);
354
  for (len = 0; path[len] != 0; len++);
353
  if (len == 0) return(0);
355
  if (len == 0) return(0);
354
  if (path[len - 1] == '\\') return(len);
356
  if (path[len - 1] == '\\') return(len);
355
  /* */
357
  /* */
356
  attr = file_getattr(path);
358
  attr = file_getattr(path);
357
  if ((attr > 0) && (attr & DOS_ATTR_DIR)) {
359
  if ((attr > 0) && (attr & DOS_ATTR_DIR)) {
358
    path[len++] = '\\';
360
    path[len++] = '\\';
359
    path[len] = 0;
361
    path[len] = 0;
360
  }
362
  }
361
  return(len);
363
  return(len);
362
}
364
}
363
 
365
 
364
 
366
 
365
/* get current path drive d (A=1, B=2, etc - 0 is "current drive")
367
/* get current path drive d (A=1, B=2, etc - 0 is "current drive")
366
 * returns 0 on success, doserr otherwise */
368
 * returns 0 on success, doserr otherwise */
367
unsigned short curpathfordrv(char *buff, unsigned char d) {
369
unsigned short curpathfordrv(char *buff, unsigned char d) {
368
  unsigned short r = 0;
370
  unsigned short r = 0;
369
 
371
 
370
  _asm {
372
  _asm {
371
    /* is d == 0? then I need to resolve current drive */
373
    /* is d == 0? then I need to resolve current drive */
372
    cmp byte ptr [d], 0
374
    cmp byte ptr [d], 0
373
    jne GETCWD
375
    jne GETCWD
374
    /* resolve cur drive */
376
    /* resolve cur drive */
375
    mov ah, 0x19  /* get current default drive */
377
    mov ah, 0x19  /* get current default drive */
376
    int 0x21      /* al = drive (00h = A:, 01h = B:, etc) */
378
    int 0x21      /* al = drive (00h = A:, 01h = B:, etc) */
377
    inc al        /* convert to 1=A, 2=B, etc */
379
    inc al        /* convert to 1=A, 2=B, etc */
378
    mov [d], al
380
    mov [d], al
379
 
381
 
380
    GETCWD:
382
    GETCWD:
381
    /* prepend buff with drive:\ */
383
    /* prepend buff with drive:\ */
382
    mov si, buff
384
    mov si, buff
383
    mov dl, [d]
385
    mov dl, [d]
384
    mov [si], dl
386
    mov [si], dl
385
    add byte ptr [si], 'A' - 1
387
    add byte ptr [si], 'A' - 1
386
    inc si
388
    inc si
387
    mov [si], ':'
389
    mov [si], ':'
388
    inc si
390
    inc si
389
    mov [si], '\\'
391
    mov [si], '\\'
390
    inc si
392
    inc si
391
 
393
 
392
    mov ah, 0x47      /* get current directory of drv DL into DS:SI */
394
    mov ah, 0x47      /* get current directory of drv DL into DS:SI */
393
    int 0x21
395
    int 0x21
394
    jnc DONE
396
    jnc DONE
395
    mov [r], ax       /* copy result from ax */
397
    mov [r], ax       /* copy result from ax */
396
 
398
 
397
    DONE:
399
    DONE:
398
  }
400
  }
399
 
401
 
400
  return(r);
402
  return(r);
401
}
403
}
-
 
404
 
-
 
405
 
-
 
406
/* fills a nls_patterns struct with current NLS patterns, returns 0 on success, DOS errcode otherwise */
-
 
407
unsigned short nls_getpatterns(struct nls_patterns *p) {
-
 
408
  unsigned short r = 0;
-
 
409
 
-
 
410
  _asm {
-
 
411
    mov ax, 0x3800  /* DOS 2+ -- Get Country Info for current country */
-
 
412
    mov dx, p       /* DS:DX points to the CountryInfoRec buffer */
-
 
413
    int 0x21
-
 
414
    jnc DONE
-
 
415
    mov [r], ax     /* copy DOS err code to r */
-
 
416
    DONE:
-
 
417
  }
-
 
418
 
-
 
419
  return(r);
-
 
420
}
-
 
421
 
-
 
422
 
-
 
423
/* computes a formatted date based on NLS patterns found in p
-
 
424
 * returns length of result */
-
 
425
unsigned short nls_format_date(char *s, unsigned short yr, unsigned char mo, unsigned char dy, const struct nls_patterns *p) {
-
 
426
  unsigned short items[3];
-
 
427
  /* preset date/month/year in proper order depending on date format */
-
 
428
  switch (p->dateformat) {
-
 
429
    case 0:  /* USA style: m d y */
-
 
430
      items[0] = mo;
-
 
431
      items[1] = dy;
-
 
432
      items[2] = yr;
-
 
433
      break;
-
 
434
    case 1:  /* EU style: d m y */
-
 
435
      items[0] = dy;
-
 
436
      items[1] = mo;
-
 
437
      items[2] = yr;
-
 
438
      break;
-
 
439
    case 2:  /* Japan-style: y m d */
-
 
440
    default:
-
 
441
      items[0] = yr;
-
 
442
      items[1] = mo;
-
 
443
      items[2] = dy;
-
 
444
      break;
-
 
445
  }
-
 
446
  /* compute the string */
-
 
447
  return(sprintf(s, "%02u%s%02u%s%02u", items[0], p->datesep, items[1], p->datesep, items[2]));
-
 
448
}
-
 
449
 
-
 
450
 
-
 
451
/* computes a formatted time based on NLS patterns found in p
-
 
452
 * returns length of result */
-
 
453
unsigned short nls_format_time(char *s, unsigned char ho, unsigned char mn, const struct nls_patterns *p) {
-
 
454
  char ampm[2] = {0, 0};
-
 
455
  const char *fmt = "%02u%s%02u%s";
-
 
456
  if (p->timefmt == 0) {
-
 
457
    if (ho == 12) {
-
 
458
      ampm[0] = 'p';
-
 
459
    } else if (ho > 12) {
-
 
460
      ho -= 12;
-
 
461
      ampm[0] = 'p';
-
 
462
    } else { /* ho < 12 */
-
 
463
      if (ho == 0) ho = 12;
-
 
464
      ampm[0] = 'a';
-
 
465
    }
-
 
466
    fmt = "%2u%s%02u%s";
-
 
467
  }
-
 
468
  return(sprintf(s, fmt, ho, p->timesep, mn, ampm));
-
 
469
}
-
 
470
 
-
 
471
 
-
 
472
/* computes a formatted integer number based on NLS patterns found in p
-
 
473
 * returns length of result */
-
 
474
unsigned short nls_format_number(char *s, long num, const struct nls_patterns *p) {
-
 
475
  unsigned short sl = 0, res, i;
-
 
476
  unsigned char thcount = 0;
-
 
477
 
-
 
478
  /* handle negative values */
-
 
479
  if (num < 0) {
-
 
480
    s[sl++] = '-';
-
 
481
    num = 0 - num;
-
 
482
  }
-
 
483
 
-
 
484
  /* write the absolute value now */
-
 
485
  do {
-
 
486
    if ((thcount == 3) && (p->thousep[0] != 0)) {
-
 
487
      s[sl++] = p->thousep[0];
-
 
488
      thcount = 0;
-
 
489
    }
-
 
490
    s[sl++] = '0' + num % 10;
-
 
491
    num /= 10;
-
 
492
    thcount++;
-
 
493
  } while (num > 0);
-
 
494
 
-
 
495
  /* terminate the string and remember its size */
-
 
496
  s[sl] = 0;
-
 
497
  res = sl;
-
 
498
 
-
 
499
  /* reverse the string now (it has been build in reverse) */
-
 
500
  if (s[0] == '-') {
-
 
501
    sl--;
-
 
502
    s++;
-
 
503
  }
-
 
504
  for (i = 0; i <= (sl / 2); i++) {
-
 
505
    thcount = s[i];
-
 
506
    s[i] = s[sl - (i + 1)];
-
 
507
    s[sl - (i + 1)] = thcount;
-
 
508
  }
-
 
509
 
-
 
510
  return(res);
-
 
511
}
402
 
512