dosxtrn.c 16.5 KB
Newer Older
1
2
3
4
5
6
/* Synchronet External DOS Program Launcher (16-bit MSVC 1.52c project) */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <dos.h>			/* _dos_set/getvect() */
#include <windows.h>		/* BOOL, etc. */
#include "vdd_func.h"
#include "isvbop.h"			/* ddk\inc */
30
#include "fossdefs.h"
31
32
#include "../git_branch.h"
#include "../git_hash.h"
33

34
#define DOSXTRN_REVISION	26
rswindell's avatar
rswindell committed
35
36
#define VDD_FILENAME	"sbbsexec.dll"

37
38
39
40
41
42
#if 0
#define DEBUG_INT_CALLS
#define DEBUG_DOS_CALLS
#define DEBUG_FOSSIL_CALLS
#endif

43
44
45
46
47
48
49
/****************************************************************************/
/* Truncates white-space chars off end of 'str' and terminates at first tab */
/****************************************************************************/
static void truncsp(char *str)
{
	size_t c;

50
51
52
53
	str[strcspn(str,"\t")]=0;
	c=strlen(str);
	while(c && (unsigned char)str[c-1]<=' ') c--;
	str[c]=0;
54
55
56
}
short	vdd=0;
BYTE	node_num=0;
57
char	id_string[128];
58
59
60
61
62
63
#ifdef DEBUG_INT_CALLS
ulong	int14calls=0;
ulong	int16calls=0;
ulong	int21calls=0;
ulong	int29calls=0;
#endif
64
65
66

void (interrupt *oldint14)();
void (interrupt *oldint16)();
67
void (interrupt *oldint21)();
68
69
void (interrupt *oldint29)();

70

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
static int vdd_buf(BYTE op, int count, WORD buf_seg, WORD buf_off)
{
	int retval;

	_asm {
		push	bx
		push	cx
		push	es
		push	di
		mov		ax,	vdd
		mov		bh,	node_num
		mov		bl,	op
		mov		cx,	count
		mov		es, buf_seg
		mov		di, buf_off
	}
	DispatchCall();
	_asm {
		mov		retval, ax
		pop		di
		pop		es
		pop		cx
		pop		bx
	}
	return(retval);
}

98
99
100
101
102
103
104
105
static int vdd_str(BYTE op, char* str)
{
	WORD			buf_seg;

	_asm mov buf_seg, ss;
	return vdd_buf(op, strlen(str), buf_seg, (WORD)str);
}

106
static int vdd_op(BYTE op)
107
108
109
{
	int retval;

110
111
112
113
#if FALSE	/* disable yield? */
	if(op==VDD_YIELD)
		return(0);
#endif
114
115
116
117
118
119
120
121
122
123
124
125
126
127
	_asm {
		push	bx
		mov		ax,	vdd
		mov		bh,	node_num
		mov		bl,	op
	}
	DispatchCall();
	_asm {
		mov		retval, ax
		pop		bx
	}
	return(retval);
}

128

129
130
131
132
133
134
135
136
137
void vdd_getstatus(vdd_status_t* status)
{
	WORD			buf_seg;

	_asm mov buf_seg, ss;
	if(vdd_buf(VDD_STATUS, sizeof(vdd_status_t), buf_seg, (WORD)status)!=0)
		memset(status,0,sizeof(vdd_status_t));
}

138
#define HAPPY_PORT_STATUS FOSSIL_MDM_STATUS_DCD_CHNG | FOSSIL_MDM_STATUS_DCD | FOSSIL_MDM_STATUS_CTS | FOSSIL_LINE_STATUS_THRE | FOSSIL_LINE_STATUS_TSRE
139
140
WORD PortStatus()
{
Rob Swindell's avatar
Rob Swindell committed
141
	WORD			status=FOSSIL_MDM_STATUS_DCD_CHNG; /* AL bit 3 (change in DCD) always set */
142
143
144
145
	vdd_status_t	vdd_status;

	vdd_getstatus(&vdd_status);

146
	if(vdd_status.online)			/* carrier detect */
Rob Swindell's avatar
Rob Swindell committed
147
		status|=FOSSIL_MDM_STATUS_DCD;
148

149
	if(vdd_status.inbuf_full)		/* receive data ready  */
Rob Swindell's avatar
Rob Swindell committed
150
		status|=FOSSIL_LINE_STATUS_RDA;
151

152
153
/*	if(vm->overrun)					/* overrun error detected */
/*		status|=0x0200;				/* OVRN */
154
155

	if(vdd_status.outbuf_full
156
		<vdd_status.outbuf_size/2)	/* room available in output buffer */
Rob Swindell's avatar
Rob Swindell committed
157
		status|=FOSSIL_LINE_STATUS_THRE;
158

159
	if(!vdd_status.outbuf_full)		/* output buffer is empty */
Rob Swindell's avatar
Rob Swindell committed
160
		status|=FOSSIL_LINE_STATUS_TSRE;
161

162
163
164
	if(vdd_status.outbuf_full < vdd_status.outbuf_size)
		status|=FOSSIL_MDM_STATUS_CTS;

165
166
167
	return(status);
}

168
169
#ifdef DEBUG_FOSSIL_CALLS
	DWORD fossil_calls[0x100];
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195

const char* fossil_func(int func)
{
	switch(func) {
		case FOSSIL_FUNC_SET_RATE:		return "set rate";
		case FOSSIL_FUNC_PUT_CHAR:		return "put char";
		case FOSSIL_FUNC_GET_CHAR:		return "get char";
		case FOSSIL_FUNC_GET_STATUS:	return "get status";
		case FOSSIL_FUNC_INIT:			return "init";
		case FOSSIL_FUNC_UNINIT:		return "uninit";
		case FOSSIL_FUNC_DTR:			return "dtr";
		case FOSSIL_FUNC_GET_TIMER:		return "get timer";
		case FOSSIL_FUNC_FLUSH_OUT:		return "flush out";
		case FOSSIL_FUNC_PURGE_OUT:		return "purge out";
		case FOSSIL_FUNC_PURGE_IN:		return "purge in";
		case FOSSIL_FUNC_WRITE_CHAR:	return "write char";
		case FOSSIL_FUNC_PEEK:			return "peek";
		case FOSSIL_FUNC_GET_KB:		return "get kb";
		case FOSSIL_FUNC_GET_KB_WAIT:	return "get kb wait";
		case FOSSIL_FUNC_FLOW_CTRL:		return "flow_ctrl";
		case FOSSIL_FUNC_CTRL_C:		return "ctrl_c";
		case FOSSIL_FUNC_BREAK:			return "break";
		case FOSSIL_FUNC_GET_INFO:		return "get info";
		default: return "unknown";
	}
}
196
197
#endif

198
199
200
201
202
203
204
205
206
207
208
void interrupt winNTint14(
	unsigned _es, unsigned _ds,
	unsigned _di, unsigned _si,
	unsigned _bp, unsigned _sp,
	unsigned _bx, unsigned _dx,
	unsigned _cx, unsigned _ax,
	)
{
	BYTE			ch;
	BYTE far*		p;
	WORD			buf_seg;
Rob Swindell's avatar
Rob Swindell committed
209
	int				rd;
210
211
	int				wr;
	vdd_status_t	vdd_status;
212
213
214
    fossil_info_t info = { 
		 sizeof(info)
		,FOSSIL_REVISION
215
		,DOSXTRN_REVISION	/* driver revision */
216
217
218
		,0			/* ID string pointer */	
		,0,0		/* receive buffer size/free (overwritten later) */
		,0,0		/* transmit buffer size/free (overwritten later) */
219
        ,80,25		/* screen dimensions (cols, rows) */
220
					/* port settings (i.e. 38400 N-8-1): */
221
222
223
224
        ,FOSSIL_BAUD_RATE_38400
		|FOSSIL_PARITY_NONE
		|FOSSIL_DATA_BITS_8
		|FOSSIL_STOP_BITS_1
225
	};
226

227
228
229
230
#ifdef DEBUG_INT_CALLS
	int14calls++;
#endif

231
232
233
234
#ifdef DEBUG_FOSSIL_CALLS
	fossil_calls[_ax>>8]++;
#endif

235
	switch(_ax>>8) {
236
		case FOSSIL_FUNC_SET_RATE:	/* Initialize/Set baud rate */
237
238
			_ax = PortStatus();
			break;
239
		case FOSSIL_FUNC_PUT_CHAR: /* write char to com port, with wait */
240
241
			ch=_ax&0xff;
			_asm mov buf_seg, ss;
Rob Swindell's avatar
Rob Swindell committed
242
			wr = vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
243
			_ax = PortStatus();
Rob Swindell's avatar
Rob Swindell committed
244
245
			if(wr != 1)
				_ax |= FOSSIL_LINE_STATUS_TIMEOUT;
246
			break;
247
		case FOSSIL_FUNC_GET_CHAR: /* read char from com port, with wait */
248
			_asm mov buf_seg, ss;
Rob Swindell's avatar
Rob Swindell committed
249
250
251
			rd = vdd_buf(VDD_READ, 1, buf_seg, (WORD)&ch);
			_ax = ch;
			if(rd != 1) {
252
				vdd_op(VDD_YIELD);
Rob Swindell's avatar
Rob Swindell committed
253
				_ax = FOSSIL_LINE_STATUS_TIMEOUT;
254
			}
255
			break;
256
		case FOSSIL_FUNC_GET_STATUS:	/* request status */
257
			_ax=PortStatus();
258
			if(_ax == HAPPY_PORT_STATUS)
259
				vdd_op(VDD_MAYBE_YIELD);
260
			break;
261
		case FOSSIL_FUNC_INIT:	/* initialize */
262
263
			_ax=FOSSIL_SIGNATURE;	/* magic number = success */
			_bx=FOSSIL_REVISION<<8 | FOSSIL_FUNC_HIGHEST;	/* FOSSIL rev/maximum FOSSIL func supported */
264
			break;
265
266
267
		case FOSSIL_FUNC_DTR:
			if((_ax&0xff)==0)	/* Lower DTR */
				vdd_op(VDD_HANGUP);
268
			break;
269
270
271
        case FOSSIL_FUNC_FLUSH_OUT:	/* flush output buffer	*/
			break;
        case FOSSIL_FUNC_PURGE_OUT:	/* purge output buffer	*/
272
			vdd_op(VDD_OUTBUF_PURGE);
273
			break;
274
        case FOSSIL_FUNC_PURGE_IN:	/* purge input buffer	*/
275
			vdd_op(VDD_INBUF_PURGE);
276
			break;
277
		case FOSSIL_FUNC_WRITE_CHAR:	/* write char to com port, no wait */
278
279
280
			ch=_ax&0xff;
			_asm mov buf_seg, ss;
			_ax = vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
Rob Swindell's avatar
Rob Swindell committed
281
282
			if(_ax != 1)
				vdd_op(VDD_YIELD);
283
			break;
284
        case FOSSIL_FUNC_PEEK:	/* non-destructive read-ahead */
285
			_asm mov buf_seg, ss;
Rob Swindell's avatar
Rob Swindell committed
286
287
288
			rd = vdd_buf(VDD_PEEK, 1, buf_seg, (WORD)&ch);
			_ax = ch;
			if(rd == 0) {
289
				vdd_op(VDD_YIELD);
Rob Swindell's avatar
Rob Swindell committed
290
291
				_ax = FOSSIL_CHAR_NOT_AVAILABLE;
			}
292
			break;
293
        case FOSSIL_FUNC_READ_BLOCK:	/* read block, no wait */
Rob Swindell's avatar
Rob Swindell committed
294
			_ax = vdd_buf(VDD_READ, _cx, _es, _di);
295
			if(_ax == 0)
296
				vdd_op(VDD_YIELD);
297
			break;
298
        case FOSSIL_FUNC_WRITE_BLOCK:	/* write block, no wait */
299
300
			_ax = vdd_buf(VDD_WRITE, _cx, _es, _di);
			break;
301
        case FOSSIL_FUNC_GET_INFO:	/* driver info */
302
303
304
305
306
			vdd_getstatus(&vdd_status);
			info.inbuf_size=vdd_status.inbuf_size;
			info.inbuf_free=info.inbuf_size-vdd_status.inbuf_full;
			info.outbuf_size=vdd_status.outbuf_size;
			info.outbuf_free=info.outbuf_size-vdd_status.outbuf_full;
307
			info.id_string = id_string;
308

309
310
			if(vdd_status.inbuf_full==vdd_status.outbuf_full==0)
				vdd_op(VDD_MAYBE_YIELD);
311

312
313
314
315
316
317
318
			p = _MK_FP(_es,_di);
            wr=sizeof(info);
            if(wr>_cx)
            	wr=_cx;
            _fmemcpy(p, &info, wr);
        	_ax=wr;
            break;
319
		case FOSSIL_FUNC_GET_KB:
Rob Swindell's avatar
Rob Swindell committed
320
			_ax = FOSSIL_CHAR_NOT_AVAILABLE;
321
			break;
322
323
324
	}
}

325
326
327
328
329
void int14stub(void)
{
	/* This function will be overwritten later (during runtime) with FOSSIL signature */
}

330
331
332
333
334
335
336
337
338
339
340
341
342
void interrupt winNTint16(
	unsigned _es, unsigned _ds,
	unsigned _di, unsigned _si,
	unsigned _bp, unsigned _sp,
	unsigned _bx, unsigned _dx,
	unsigned _cx, unsigned _ax,
	unsigned _ip, unsigned _cs,
    unsigned flags )
{
	BYTE			ch;
	WORD			buf_seg;
	vdd_status_t	status;

343
344
345
346
#ifdef DEBUG_INT_CALLS
	int16calls++;
#endif

347
348
	vdd_getstatus(&status);
 	switch(_ax>>8) {
349
350
    	case 0x00:	/* Read char from keyboard */
        case 0x10:	/* Read char from enhanced keyboard */
351
352
353
354
355
			if(status.inbuf_full) {
				_asm mov buf_seg, ss;
				vdd_buf(VDD_READ, 1, buf_seg, (WORD)&ch);
				_ax=ch;
				return;
356
			} 
357
			vdd_op(VDD_MAYBE_YIELD);
358
			break;
359
360
    	case 0x01:	/* Get keyboard status */
        case 0x11:	/* Get enhanced keyboard status */
361
362
363
			if(status.inbuf_full) {
				_asm mov buf_seg, ss;
				vdd_buf(VDD_PEEK, 1, buf_seg, (WORD)&ch);
364
                flags&=~(1<<6);	/* clear zero flag */
365
366
                _ax=ch;
				return;
367
			}
368
			vdd_op(VDD_MAYBE_YIELD);
369
370
371
372
373
374
	        break;
	}

	_chain_intr(oldint16);		
}

375
376
#ifdef DEBUG_DOS_CALLS
	DWORD dos_calls[0x100];
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
#endif

void interrupt winNTint21(
	unsigned _es, unsigned _ds,
	unsigned _di, unsigned _si,
	unsigned _bp, unsigned _sp,
	unsigned _bx, unsigned _dx,
	unsigned _cx, unsigned _ax,
	)
{
#ifdef DEBUG_INT_CALLS
	int21calls++;
#endif
	if(_ax>>8 == 0x2c)	/* GET_SYSTEM_TIME */
		vdd_op(VDD_MAYBE_YIELD);
392
393
#ifdef DEBUG_DOS_CALLS
	dos_calls[_ax>>8]++;
394
395
396
397
#endif
	_chain_intr(oldint21);
}

398
399
400
401
402
403
404
405
406
407
void interrupt winNTint29(
	unsigned _es, unsigned _ds,
	unsigned _di, unsigned _si,
	unsigned _bp, unsigned _sp,
	unsigned _bx, unsigned _dx,
	unsigned _cx, unsigned _ax,
	)
{
	char	ch;
	WORD	buf_seg;
408
409
410
#ifdef DEBUG_INT_CALLS
	int29calls++;
#endif
411
412
413
414
415
416
417
418

	ch=_ax&0xff;
	_asm mov buf_seg, ss
	vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);

	_chain_intr(oldint29);
}

419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
/****************************************************************************/
/* Return the filename portion of a full pathname							*/
/****************************************************************************/
char* getfname(const char* path)
{
	const char* fname;
	const char* bslash;

	fname=strrchr(path,'/');
	bslash=strrchr(path,'\\');
	if(bslash>fname)
		fname=bslash;
	if(fname!=NULL) 
		fname++;
	else 
		fname=(char*)path;
	return((char*)fname);
}

rswindell's avatar
rswindell committed
438
char *	DllName		=VDD_FILENAME;
439
440
char *	InitFunc	="VDDInitialize";
char *	DispFunc	="VDDDispatch";
441
442
#define MAX_ENVVARS 32
#define MAX_ARGS	32
443
444
445
446
447

int main(int argc, char **argv)
{
	char	str[128];
	char	cmdline[128],*p;
448
449
	char	dll[256];
	char	exec_dir[128];
450
451
	char*	envvar[MAX_ENVVARS];
	char*	arg[MAX_ARGS];
452
	char*	ini_fname = exec_dir;
453
	int		i,c,d,envnum=0;
454
	int		mode = SBBSEXEC_MODE_UNSPECIFIED;
455
	int		argn;
456
	FILE*	fp;
Rob Swindell's avatar
Rob Swindell committed
457
	BOOL	x64=FALSE;
458
	BOOL	success=FALSE;
459
	WORD	buf_seg;
460
	WORD	w;
461

462
	sprintf(id_string,"Synchronet FOSSIL Driver (DOSXTRN) revision %u %s/%s", DOSXTRN_REVISION, GIT_BRANCH, GIT_HASH);
463
464
	if(argc<2) {
		fprintf(stderr
465
466
			,"%s - Copyright %s Rob Swindell\n"
			,id_string, __DATE__+7);
467
		fprintf(stderr
468
			,"usage: dosxtrn <path/dosxtrn.env> [NT|x64] [node_num] [mode] [ini_file]\n");
469
470
		return(1);
	}
471

472
473
474
	sprintf(exec_dir,"%.*s",sizeof(exec_dir)-1,argv[0]);
	p=getfname(exec_dir);
	*p=0;
rswindell's avatar
rswindell committed
475
	sprintf(dll,"%s%s",exec_dir,VDD_FILENAME);
476
477
	DllName=dll;

478
479
480
	argn = 2;
	if(argn < argc) {
		if(strcmp(argv[argn],"x64") == 0)
481
			x64=TRUE;
482
483
484
485
486
487
488
489
490
491
492
493
494
		argn++;
	}
	if(argn < argc && IS_DIGIT(argv[argn][0])) {
		node_num=atoi(argv[argn]);
		argn++;
	}
	if(argn < argc && IS_DIGIT(argv[argn][0])) {
		mode = atoi(argv[argn]);
		argn++;
	}
	if(argn < argc) {
		ini_fname = argv[argn];
		argn++;
Rob Swindell's avatar
Rob Swindell committed
495
	}
496

497
498
499
	if(mode == SBBSEXEC_MODE_UNSPECIFIED)
		mode = SBBSEXEC_MODE_DEFAULT;

500
501
502
503
504
505
506
507
508
	if((fp=fopen(argv[1],"r"))==NULL) {
		fprintf(stderr,"!Error opening %s\n",argv[1]);
		return(2);
	}

	fgets(cmdline, sizeof(cmdline), fp);
	truncsp(cmdline);

	arg[0]=cmdline;	/* point to the beginning of the string */
509
	for(c=0,d=1;cmdline[c] && d < (MAX_ARGS - 1);c++)	/* Break up command line */
510
511
		if(cmdline[c]==' ') {
			cmdline[c]=0;			/* insert nulls */
512
513
			arg[d++]=cmdline+c+1;	/* point to the beginning of the next arg */
		}
514
515
	arg[d]=0;

516
	while(!feof(fp) && envnum < MAX_ENVVARS) {
517
518
519
		if(!fgets(str, sizeof(str), fp))
			break;
		truncsp(str);
520
		if((envvar[envnum]=strdup(str))==NULL) {
521
522
523
524
525
526
527
528
529
530
			fprintf(stderr,"!MALLOC ERROR\n");
			return(4);
		}
		_putenv(envvar[envnum++]);
	}
	fclose(fp);

	/* Save int14 handler */
	oldint14=_dos_getvect(0x14);

531
532
533
534
535
	/* Overwrite stub function */
	((BYTE*)int14stub)[0] = 0xe9;	/* jump (relative) */
	((BYTE*)int14stub)[3] = 0x90;	/* NOP */
	((BYTE*)int14stub)[4] = 0x90;	/* NOP */
	((BYTE*)int14stub)[5] = 0x90;	/* NOP */
536
537
538
	((BYTE*)int14stub)[6] = FOSSIL_SIGNATURE&0xff;	/* FOSSIL sig (LSB) */
	((BYTE*)int14stub)[7] = FOSSIL_SIGNATURE>>8;	/* FOSSIL sig (MSB) */
	((BYTE*)int14stub)[8] = FOSSIL_FUNC_HIGHEST;	/* FOSSIL highest func supported */
539

540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
	for(i=0;i<2;i++) {

		/* Register VDD */
       	_asm {
			push	es
			push	ds
			pop		es
			mov     si, DllName		; ds:si = dll name
			mov     di, InitFunc    ; es:di = init routine
			mov     bx, DispFunc    ; ds:bx = dispatch routine
		};
		if(!x64) {	// NTVDMx64 (based on an older Windows NTVDM) requires an init routine
			_asm {	/* Vista work-around, apparently doesn't support an InitFunc (RegisterModule fails with AX=1) */
				xor		di,di
				mov		es,di
rswindell's avatar
rswindell committed
555
			};
556
		}
557
558
559
560
561
562
563
		RegisterModule();
		_asm {
			mov		vdd, ax
			jc		err
			mov		success, TRUE
			err:
			pop		es
564
		}
565
566
567
568
569
570
571
572
		if(success)
			break;
		DllName=VDD_FILENAME;	/* try again with no path (for Windows Vista) */
	}
	if(!success) {
		fprintf(stderr,"Error %d loading %s\n",vdd,DllName);
		return(-1);
	}
573

574
#if 0
575
576
	fprintf(stderr,"vdd handle=%d\n",vdd);
	fprintf(stderr,"mode=%d\n",mode);
577
#endif
578
	vdd_str(VDD_LOAD_INI_FILE, ini_fname);
579

580
	vdd_str(VDD_LOAD_INI_SECTION, getfname(arg[0]));
581

582
583
	sprintf(str,"%s, rev %u %s/%s, %s %s mode=%u", __FILE__, DOSXTRN_REVISION, GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, mode);
	vdd_str(VDD_DEBUG_OUTPUT, str);
584

585
586
587
588
589
590
591
	if(mode & SBBSEXEC_MODE_UART)
		vdd_op(VDD_VIRTUALIZE_UART);
	i=vdd_op(VDD_OPEN);
	if(i) {
		fprintf(stderr,"!VDD_OPEN ERROR: %d\n",i);
		UnRegisterModule();
		return(-1);
592
	}
593
594
595
596
597
	oldint16=_dos_getvect(0x16);
	oldint21=_dos_getvect(0x21);
	oldint29=_dos_getvect(0x29);
	if(mode & SBBSEXEC_MODE_FOSSIL) {
		*(WORD*)((BYTE*)int14stub+1) = (WORD)winNTint14 - (WORD)&int14stub - 3;	/* jmp offset */
598
		_dos_setvect(0x14,(void(interrupt *)())int14stub); 
599
	}
600
601
602
603
604
	_dos_setvect(0x21,winNTint21); 
	if(mode&SBBSEXEC_MODE_DOS_IN)
		_dos_setvect(0x16,winNTint16); 
	if(mode&SBBSEXEC_MODE_DOS_OUT) 
		_dos_setvect(0x29,winNTint29); 
605
606
607
608
609
610
611
612

	_heapmin();
	i=_spawnvp(_P_WAIT, arg[0], arg);

	p=argv[1]+(strlen(argv[1])-3);
	strcpy(p,"RET");
	if((fp=fopen(argv[1],"w+"))==NULL) {
		fprintf(stderr,"!Error opening %s\n",argv[1]);
613
614
615
	} else {
		fprintf(fp,"%d",i);
		fclose(fp);
616
	}
617
618
619
620
621
622
623
624
625
626
	strcpy(p,"ERR");
	if(i == -1) {
		if((fp=fopen(argv[1],"w+"))==NULL) {
			fprintf(stderr,"!Error opening %s\n",argv[1]);
		} else {
			fprintf(fp,"%d\n%s\n", errno, strerror(errno));
			fclose(fp);
		}
	} else
		remove(argv[1]);
627
628
629
630

	/* Restore original ISRs */
	_dos_setvect(0x14,oldint14);

631
	vdd_op(VDD_CLOSE);
632

633
634
635
	_dos_setvect(0x16,oldint16);
	_dos_setvect(0x21,oldint21);
	_dos_setvect(0x29,oldint29);
636

637
638
	sprintf(str,"%s returned %d", arg[0], i);
	vdd_str(VDD_DEBUG_OUTPUT, str);
639

640
#ifdef DEBUG_INT_CALLS
641
642
643
644
	sprintf(str,"int14h calls: %lu", int14calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
	sprintf(str,"int16h calls: %lu", int16calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
	sprintf(str,"int21h calls: %lu", int21calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
	sprintf(str,"int29h calls: %lu", int29calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
645
#endif
646
#ifdef DEBUG_DOS_CALLS
647
648
649
650
651
	for(i=0;i<0x100;i++) {
		if(dos_calls[i]>100) {
			sprintf(str,"int21h function %02X calls: %u"
				,i, dos_calls[i]);
			vdd_str(VDD_DEBUG_OUTPUT, str);
652
		}
653
	}
654
#endif
655
#ifdef DEBUG_FOSSIL_CALLS
656
657
658
659
660
	for(i=0;i<0x100;i++) {
		if(fossil_calls[i]>0) {
			sprintf(str,"int14h function %02X (%-10s) calls: %lu"
				,i, fossil_func(i), fossil_calls[i]);
			vdd_str(VDD_DEBUG_OUTPUT, str);
661
		}
662
	}
663
664
#endif

665
666
667
	/* Unregister VDD */
	_asm mov ax, vdd;
	UnRegisterModule();
rswindell's avatar
rswindell committed
668

669
670
	return(i);
}