1 /*
2 * port.c: portable versions of often-used calls
3 * =================================================
4 * (C)1996 by F.Jalvingh; Public domain.
5 * (C)1997 by Markus F.X.J. Oberhumer; Public domain.
6 *
7 * $Header: /cvsroot/fte/fte/src/port.c,v 1.1.1.1 2000/01/30 17:23:32 captnmark Exp $
8 *
9 * $Log: port.c,v $
10 * Revision 1.1.1.1 2000/01/30 17:23:32 captnmark
11 * initial import
12 *
13 */
14
15 #include "port.h"
16
17 #ifndef MAXPATH
18 # define MAXPATH 256
19 #endif
20
21
22 /****************************************************************************/
23 /* */
24 /* CODING: Windows NT portable calls. */
25 /* */
26 /****************************************************************************/
27 #if defined(NT)
28
29
30 #define WIN32_LEAN_AND_MEAN
31 #include <windows.h>
32
33 #include <port/port.h>
34 #include <string.h>
35 #include <assert.h>
36
37
38 /*
39 * plGetcurdir() returns the current directory for the drive specified. Drive
40 * 0=current, 1=a, 2=B etc.
41 */
plGetcurdir(int drive,char * dir)42 int plGetcurdir(int drive, char *dir)
43 {
44 char tmp[256], t2[6], org[6];
45 int rv;
46
47 //** For NT: get current disk; then change to the requested one, and rest.
48 rv = -1;
49 GetCurrentDirectory(sizeof(tmp), tmp); // Get current disk & dir;
50 assert(tmp[1] == ':');
51 if(drive == 0) // Is current drive?
52 {
53 strcpy(dir, tmp+3); // Copy all after C:\ to dir,
54 rv = 0;
55 }
56 else
57 {
58 strncpy(org, tmp, 2); // Copy <drive>:
59 org[2] = 0;
60
61 //** Move to the required drive,
62 *t2 = drive + 'A'-1; // Form drive letter.
63 strcpy(t2+1, ":");
64 if(! SetCurrentDirectory(t2)) return -1;// Try to move there;
65 if(GetCurrentDirectory(sizeof(tmp), tmp))
66 {
67 strcpy(dir, tmp+3); // Copy to result,
68 rv = 0;
69 }
70
71 SetCurrentDirectory(org); // Move back to original..
72 }
73 return rv;
74 }
75
76
plGetdisk(void)77 int plGetdisk(void)
78 {
79 char buf[256];
80 int d;
81
82 GetCurrentDirectory(sizeof(buf), buf);
83 d = toupper(*buf) - 'A'; // 0=A, 1=B, etc.
84 if(d < 0 || d > 25) return -1;
85 return d;
86 }
87
plSetdisk(int drive)88 int plSetdisk(int drive)
89 {
90 char buf[30];
91
92 if( drive < 0 || drive > 25) return -1;
93 *buf = drive + 'A';
94 strcpy(buf+1, ":");
95 return SetCurrentDirectory(buf) ? 0 : -1;
96 }
97
98
99 /****************************************************************************/
100 /* */
101 /* CODING: OS/2 portable calls. */
102 /* */
103 /****************************************************************************/
104 #elif defined(OS2)
105 #define __32BIT__ 1
106
107 #define INCL_BASE
108 #define INCL_DOSMISC
109 #define INCL_DOS
110 #define INCL_SUB
111 #define INCL_DOSERRORS
112 #define INCL_DOSFILEMGR
113 #define INCL_NOPMAPI
114 #include <os2.h>
115
116
117 /*
118 * plGetcurdir() returns the current directory for the drive specified.
119 */
plGetcurdir(int drive,char * dir)120 int plGetcurdir(int drive, char *dir)
121 {
122 #ifdef __32BIT__
123 ULONG bytes;
124
125 bytes = 0;
126 DosQueryCurrentDir(drive, NULL, &bytes);
127 if(bytes > MAXPATH) return -1;
128 DosQueryCurrentDir(drive, dir, &bytes);
129 return 0;
130 #else
131 USHORT bytes;
132
133 bytes = 0;
134 DosQCurDir(drive, NULL, &bytes);
135 if(bytes > MAXPATH) return -1;
136 DosQCurDir(drive, dir, &bytes);
137 return 0;
138 #endif
139 }
140
141
142 /*
143 * plGetdisk() returns the current disk's number. A=0, B=1 etc.
144 */
plGetdisk(void)145 int plGetdisk(void)
146 {
147 #ifdef __32BIT__
148 ULONG drive, numdrives;
149
150 DosQueryCurrentDisk(&drive, &numdrives);
151 #else
152 USHORT drive;
153 ULONG numdrives;
154
155 DosQCurDisk(&drive, &numdrives);
156 #endif
157 return (int)drive - 1;
158
159 }
160
161
162 /*
163 * plSetdisk() makes another drive the current drive. Use A=0, B=1 etc. It
164 * returns 0 on succes.
165 */
plSetdisk(int drive)166 int plSetdisk(int drive)
167 {
168 #if defined(__32BIT__)
169 return (int)DosSetDefaultDisk((ULONG)drive + 1);
170 #else
171 return (int)DosSelectDisk((USHORT)drive + 1); /* Bcc getdisk: 'A' = 0; MSC DosSelectdisk: 'A' = 1 */
172 #endif
173 }
174
175
176 /****************************************************************************/
177 /* */
178 /* CODING: DOS Extender code - basic functionality & interrupt calls.
179 */ /* */
180 /****************************************************************************/
181 #elif defined(DOSP32)
182
183 /*
184 * The following code is used to handle DOS-specific calls and memory from
185 * within several DOS extender(s), or from plain DOS. To compile for other
186 * DOS extenders simply recode the base calls; the extended calls are defined
187 * in terms of the base calls.
188 *
189 * Currently the following implementations exist:
190 * - Dos4GW i.c.m. the Watcom C compiler
191 * - djgpp v2
192 */
193
194 /*--------------------------------------------------------------------------*/
195 /* CODING: 32-bits protected mode DOS with DOS4GW and Watcom C++. */
196 /*--------------------------------------------------------------------------*/
197 #if defined(__DOS4G__) // Defined when compiled with Watcom for Dos4GW
198 #include <i86.h>
199
200 #define HIWORD(x) ( (UWORD) ((x) >> 16))
201 #define LOWORD(x) ( (UWORD) (x))
202
203
204 /*
205 * dosxIntr() does a 16-bit interrupt with translation for the extender. It
206 * is used to call DOS and BIOS interrupts from within C.
207 */
dosxIntr(int inr,union dosxReg * r)208 void dosxIntr(int inr, union dosxReg* r)
209 {
210 union REGPACK rp;
211
212 //** Convert the parameters to a REGPACK structure,
213 rp.x.eax = r->x.eax; rp.x.ebx = r->x.ebx; rp.x.ecx = r->x.ecx;
214 rp.x.edx = r->x.edx; rp.x.esi = r->x.esi; rp.x.edi = r->x.edi;
215 rp.x.ds = r->x.ds; rp.x.es = r->x.es; rp.x.fs = r->x.fs; rp.x.gs = r->x.gs;
216 rp.x.flags = r->x.flags;
217 intr(inr, &rp);
218
219 //** And translate back..
220 r->x.eax = rp.x.eax; r->x.ebx = rp.x.ebx; r->x.ecx = rp.x.ecx;
221 r->x.edx = rp.x.edx; r->x.esi = rp.x.esi; r->x.edi = rp.x.edi;
222 r->x.ds = rp.x.ds; r->x.es = rp.x.es; r->x.fs = rp.x.fs; r->x.gs = rp.x.gs;
223 r->x.flags = rp.x.flags;
224 }
225
226
227 /*
228 * The Dos4GW extender maps the DOS memory arena (the 1st 1Mb of physical
229 * memory) to the 1st MB of extender memory. So, to access 0040:0087 in the
230 * BIOS data segment we use the linear address 0x487.
231 *
232 * The memory routines translate the seg:off address passed to a linear
233 * address.
234 */
235
236
237 /*
238 * SegToPhys() converts an address in seg:off format to a physical address.
239 */
SegToPhys(ULONG ra)240 static void* SegToPhys(ULONG ra)
241 {
242 return (void*) ( ((ULONG) HIWORD(ra) << 4) + (ULONG)LOWORD(ra)); }
243
244
245 /*
246 * dosxMemRead() reads the specified #bytes from the DOS real memory to the
247 * buffer specified. The address <ra> is specified as a seg:off address (even
248 * in extended mode); it is translated to the appropriate physical address.
249 */
dosxMemRead(void * dest,ULONG ra,unsigned nbytes)250 void dosxMemRead(void* dest, ULONG ra, unsigned nbytes)
251 {
252 memcpy(dest, SegToPhys(ra), nbytes);
253 }
254
255
256 /*
257 * dosxMemWrite() writes the specified #bytes to DOS real memory. <ra> is in
258 * seg:off format.
259 */
dosxMemWrite(ULONG ra,void * src,unsigned nbytes)260 void dosxMemWrite(ULONG ra, void* src, unsigned nbytes)
261 {
262 memcpy(SegToPhys(ra), src, nbytes);
263 }
264
265
266 /*
267 * dosxPMemRead() reads the specified #bytes from physical memory to the
268 * buffer specified. The physical address is the linear address, not a
269 * segmented one!
270 */
dosxPMemRead(void * dest,ULONG pa,unsigned nbytes)271 void dosxPMemRead(void* dest, ULONG pa, unsigned nbytes)
272 {
273 memcpy(dest, (void*) pa, nbytes);
274 }
275
276
277 /*
278 * dosxPMemWrite() writes the specified #bytes to physical memory.
279 */
dosxPMemWrite(ULONG pa,void * src,unsigned nbytes)280 void dosxPMemWrite(ULONG pa, void* src, unsigned nbytes)
281 {
282 memcpy((void*) pa, src, nbytes);
283 }
284
285
286 #elif defined(__DJGPP__)
287
288 #include <assert.h>
289 #include <dos.h>
290 #include <dpmi.h>
291 #include <go32.h>
292 #include <string.h>
293 #include <sys/movedata.h>
294
295 /*
296 * dosxIntr() does a 16-bit interrupt with translation for the extender. It
297 * is used to call DOS and BIOS interrupts from within C.
298 */
dosxIntr(int inr,union dosxReg * r)299 void dosxIntr(int inr, union dosxReg* r)
300 {
301 __dpmi_regs rp;
302
303 //** Convert the parameters to a REGPACK structure,
304 rp.d.eax = r->x.eax; rp.d.ebx = r->x.ebx; rp.d.ecx = r->x.ecx;
305 rp.d.edx = r->x.edx; rp.d.esi = r->x.esi; rp.d.edi = r->x.edi;
306 rp.x.ds = r->x.ds; rp.x.es = r->x.es; rp.x.fs = r->x.fs; rp.x.gs = r->x.gs;
307 rp.x.flags = r->x.flags;
308 __dpmi_int(inr, &rp);
309
310 //** And translate back..
311 r->x.eax = rp.d.eax; r->x.ebx = rp.d.ebx; r->x.ecx = rp.d.ecx;
312 r->x.edx = rp.d.edx; r->x.esi = rp.d.esi; r->x.edi = rp.d.edi;
313 r->x.ds = rp.x.ds; r->x.es = rp.x.es; r->x.fs = rp.x.fs; r->x.gs = rp.x.gs;
314 r->x.flags = rp.x.flags;
315 }
316
317
318 /*
319 * dosxMemRead() reads the specified #bytes from the DOS real memory to the
320 * buffer specified. The address <ra> is specified as a seg:off address (even
321 * in extended mode); it is translated to the appropriate physical address.
322 */
dosxMemRead(void * dest,ULONG ra,unsigned nbytes)323 void dosxMemRead(void* dest, ULONG ra, unsigned nbytes)
324 {
325 unsigned x = ((ra & 0xffff0000) >> 12) + (ra & 0xffff);
326 movedata(_dos_ds, x, _my_ds(), (unsigned) dest, nbytes);
327 }
328
329
330 /*
331 * dosxMemWrite() writes the specified #bytes to DOS real memory. <ra> is in
332 * seg:off format.
333 */
dosxMemWrite(ULONG ra,void * src,unsigned nbytes)334 void dosxMemWrite(ULONG ra, void* src, unsigned nbytes)
335 {
336 unsigned x = ((ra & 0xffff0000) >> 12) + (ra & 0xffff);
337 movedata(_my_ds(), (unsigned) src, _dos_ds, x, nbytes);
338 }
339
340
341 /*
342 * dosxPMemRead() reads the specified #bytes from physical memory to the
343 * buffer specified. The physical address is the linear address, not a
344 * segmented one!
345 */
dosxPMemRead(void * dest,ULONG pa,unsigned nbytes)346 void dosxPMemRead(void* dest, ULONG pa, unsigned nbytes)
347 {
348 assert(0); /* not used */
349 }
350
351
352 /*
353 * dosxPMemWrite() writes the specified #bytes to physical memory.
354 */
dosxPMemWrite(ULONG pa,void * src,unsigned nbytes)355 void dosxPMemWrite(ULONG pa, void* src, unsigned nbytes)
356 {
357 assert(0); /* not used */
358 }
359
360
361
362 #else // Not Dos4GW or djgpp
363 # error "Extender type not defined/illegal extender type."
364 #endif
365
366
367 /*
368 * dosxDisable() disables interrupts.
369 */
dosxDisable(void)370 void dosxDisable(void)
371 {
372 #if defined(__WATCOMC__) || defined(__MSC__)
373 _disable();
374 #elif defined(__DJGPP__)
375 __asm__ __volatile__("cli \n");
376 #else
377 disable();
378 #endif
379 }
380
381 /*
382 * dosxEnable() enables interrupts.
383 */
dosxEnable(void)384 void dosxEnable(void)
385 {
386 #if defined(__WATCOMC__) || defined(__MSC__)
387 _enable();
388 #elif defined(__DJGPP__)
389 __asm__ __volatile__("sti \n");
390 #else
391 enable();
392 #endif
393 }
394
395
396 /****************************************************************************/
397 /* */
398 /* CODING: DOS-based portability calls. */
399 /* */
400 /****************************************************************************/
401 #ifdef __WATCOMC__
402 #include <i86.h>
403 #endif
404 #include <dos.h>
405
406
407 /*
408 * plGetcurdir() returns the current directory for the drive specified. Drive
409 * 0=a, 1=B etc.
410 */
plGetcurdir(int drive,char * dir)411 int plGetcurdir(int drive, char *dir)
412 {
413 union dosxReg r;
414
415 #if defined(__32BIT__) && !defined(__DJGPP__)
416 void far *ptr;
417 #endif
418
419 memset(&r, 0, sizeof(r));
420 r.w.ax = 0x4700; // Get current directory
421 r.h.dl = drive; // Get drive (0=current, 1=a etc)!!
422 #if defined(__DJGPP__)
423 r.w.ds = _my_ds();
424 r.x.esi = (unsigned) dir; // Pass the address of the buffer.
425 #elif defined(__32BIT__)
426 ptr = dir; // Get full 16:32 address of dir,
427 r.w.ds = FP_SEG(ptr);
428 r.x.esi = FP_OFF(dir); // Pass the address of the buffer.
429 #else
430 r.w.ds = FP_SEG(dir);
431 r.w.si = FP_OFF(dir);
432 #endif
433 dosxIntr(0x21, &r);
434 return r.x.flags & 0x80 ? -1 : 0; // Carry flag is set?
435 }
436
437
438 #if defined(__WATCOMC__) || defined(__DJGPP__)
439
plSetdisk(int drive)440 int plSetdisk(int drive)
441 {
442 unsigned ndr;
443
444 _dos_setdrive(drive +1, &ndr);
445 return 0;
446 }
447
plGetdisk(void)448 int plGetdisk(void)
449 {
450 unsigned drv;
451
452 _dos_getdrive(&drv);
453 return drv - 1;
454 }
455
456 #elif defined(__BORLANDC__)
plSetdisk(int drive)457 int plSetdisk(int drive)
458 {
459 return setdisk(drive);
460 }
461
plGetdisk(void)462 int plGetdisk(void)
463 {
464 return getdisk();
465 }
466
467 #else
468 # error "Undefined compiler for DOS/Extended DOS"
469 #endif
470
471
472
473 #else
474 # error "Platform not supported."
475 #endif
476
477
478 /****************************************************************************/
479 /* */
480 /* CODING: an implementation of fnmatch(), when needed... */
481 /* */
482 /****************************************************************************/
483 #if (defined(NT) || defined(DOSP32)) && !defined(__DJGPP__)
484 /*
485 * Wildcard spec's:
486 * ================
487 *
488 * * matches 0-n characters, so * only removes all.
489 * ? matches any character on that position.
490 * #c matches 0-n occurences of the character c. Note: #? is the same
491 * as *.
492 * a+b Matches either a or b. a and b may be complex expressions.
493 * () Keep expressions together,
494 *
495 * Examples:
496 * ---------
497 * *.(obj+lib+exe) Matches *.exe, *.lib and *.exe.
498 * t#a.* Matches t.*, ta.* taa.* etc
499 *
500 * Small grammar:
501 * ==============
502 * pattern:
503 */
504 #define ENDCH(x) ((x) == '+' || (x) == ')' || (x) == 0)
505
506 static int wcMatch(char **pval, char **pw);
507
508 /*
509 * Next() moves to the next <ch> in the pattern, taking care of ( and ).
510 * It returns a nonzero value in case of error (bad match).
511 */
Next(char ** pptr,char ch)512 static int Next(char **pptr, char ch)
513 {
514 int braces;
515
516 braces = 0;
517 for(;;)
518 {
519 switch(**pptr)
520 {
521 case 0:
522 if(braces == 0)
523 return 0; /* 0 always allowed if not in () */
524 else
525 return ')'; /* Missing close brace! */
526
527 case '(':
528 braces++;
529 break;
530
531 case ')':
532 if(braces == 0)
533 {
534 if(ch == ')' || ch == '+')
535 return 0;
536 else
537 return '('; /* Missing open brace */
538 }
539 braces--;
540 break;
541
542 default:
543 if(**pptr == ch && braces == 0) return 0;
544 }
545 *pptr += 1;
546 }
547 }
548
549
550 /*
551 * wcOrs() traverses <pattern> + <pattern> + <pattern>..
552 */
wcOrs(char ** pval,char ** pw)553 static int wcOrs(char **pval, char **pw)
554 {
555 char *vsave;
556 int res;
557
558 for(;;) /* For each orred part, */
559 {
560 vsave = *pval; /* Save current string, */
561 res = wcMatch(pval, pw); /* Match part, */
562 if(res != 0) return res; /* Exit if OK or error. */
563 *pval = vsave; /* Back to start of string to match */
564
565 /**** Match not found. Find next ORred item, ****/
566 res = Next(pw, '+');
567 if(res > 0) return res;
568 if(**pw == 0 || **pw == ')') return 0; /* Exit if at eo$ */
569 if(**pw != '+') return '+'; /* Expected | ?? */
570 *pw += 1;
571 }
572 }
573
574
575
576
577 /*
578 * wcMatch() compares the string to match in *pval with the wildcard
579 * part in *pw. It returns True as soon as a match is found, and False
580 * if a match could not be found.
581 */
wcMatch(char ** pval,char ** pw)582 static int wcMatch(char **pval, char **pw)
583 {
584 char *vsave, *wsave;
585 int res;
586
587 for(;;)
588 {
589 vsave = *pval; /* Saved string, */
590 switch(*(*pw)++)
591 {
592 case '+':
593 case ')':
594 case 0:
595 /**** End of wildcarded string. If string is at end too ****/
596 /**** match is found... ****/
597 *pw -= 1; /* Back to terminator, */
598 return **pval == 0;
599
600 case '?':
601 /**** Match-anything.. ****/
602 if(**pval == 0) return FALSE; /* Exhausted! No match */
603 *pval += 1; /* Match one character, */
604 break; /* And loop, */
605
606 case '(':
607 res = wcOrs(pval, pw); /* OR sequence valid? */
608 if(res == 1) /* 1 -> Matched! */
609 {
610 /**** OR sequence valid! Move to closing ) ****/
611 res = Next(pw, ')'); /* Move past OR-sequence */
612 if(res) return res; /* If error return, */
613 if(**pw != ')') return ')'; /* Missing ')' !! */
614 *pw += 1; /* Past ), */
615 }
616 else
617 return res; /* Not found or Error!! */
618 break;
619
620 case '*':
621 /**** 0-n (kleene closure) any-character matches.. ****/
622 while(**pval != 0) /* While not at end of user $ */
623 {
624 /**** Compare current part of user string with what's ****/
625 /**** left of the wildcards... ****/
626 wsave = *pw; /* Get current wildcard ptr, after * */
627 vsave = *pval; /* And to current part of $ */
628 res = wcMatch(pval, pw); /* Check if $ matches, */
629 if(res != 0) return res; /* Exit if matches or error, */
630 *pw = wsave; /* Back wildcards, */
631 *pval = vsave+1; /* Back user $ one pos further, */
632 }
633 return ENDCH(**pw); /* No match. */
634
635 default:
636 if(toupper(**pval) != toupper(*(*pw - 1)))
637 {
638 *pw -= 1;
639 return 0;
640 }
641 *pval += 1;
642 break;
643 }
644 }
645 }
646
647
648 /*
649 * strCmpWild() returns -1 on wildcard error, 0 on match and 1 on no
650 match.
651 */
strCmpWild(char * val,char * wild)652 int strCmpWild(char *val, char *wild)
653 {
654 return wcOrs(&val, &wild);
655 }
656
657
658 /*
659 * fnmatch() does a wildcarded match.
660 */
fnmatch(char * pat,char * in,int vv)661 int fnmatch(char* pat, char* in, int vv)
662 {
663 return strCmpWild(in, pat) == 1 ? 0 : 1;
664 }
665 #endif // fnmatch()
666
667
668
669