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