|
|
1.1 root 1: /* dosxtrn.c */
2:
3: /* Synchronet External DOS Program Launcher (16-bit MSVC 1.52c project) */
4:
5: /* $Id: dosxtrn.c,v 1.23 2006/10/28 03:54:09 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include <stdio.h>
39: #include <stdlib.h>
40: #include <string.h>
41: #include <process.h>
42: #include <dos.h> /* _dos_set/getvect() */
43: #include <windows.h> /* BOOL, etc. */
44: #include "vdd_func.h"
45: #include "execvxd.h"
46: #include "isvbop.h" /* ddk\inc */
47: #include "fossdefs.h"
48:
49: #define VDD_FILENAME "sbbsexec.dll"
50:
51: /****************************************************************************/
52: /* Truncates white-space chars off end of 'str' and terminates at first tab */
53: /****************************************************************************/
54: static void truncsp(char *str)
55: {
56: size_t c;
57:
58: str[strcspn(str,"\t")]=0;
59: c=strlen(str);
60: while(c && (unsigned char)str[c-1]<=' ') c--;
61: str[c]=0;
62: }
63: short vdd=0;
64: BYTE node_num=0;
65: int mode=0;
66: int revision;
67: char id_string[128];
68: #ifdef DEBUG_INT_CALLS
69: ulong int14calls=0;
70: ulong int16calls=0;
71: ulong int21calls=0;
72: ulong int29calls=0;
73: #endif
74:
75: void (interrupt *oldint14)();
76: void (interrupt *oldint16)();
77: void (interrupt *oldint21)();
78: void (interrupt *oldint29)();
79:
80:
81: static int vdd_buf(BYTE op, int count, WORD buf_seg, WORD buf_off)
82: {
83: int retval;
84:
85: _asm {
86: push bx
87: push cx
88: push es
89: push di
90: mov ax, vdd
91: mov bh, node_num
92: mov bl, op
93: mov cx, count
94: mov es, buf_seg
95: mov di, buf_off
96: }
97: DispatchCall();
98: _asm {
99: mov retval, ax
100: pop di
101: pop es
102: pop cx
103: pop bx
104: }
105: return(retval);
106: }
107:
108: static int vdd_str(BYTE op, char* str)
109: {
110: WORD buf_seg;
111:
112: _asm mov buf_seg, ss;
113: return vdd_buf(op, strlen(str), buf_seg, (WORD)str);
114: }
115:
116: static int vdd_op(BYTE op)
117: {
118: int retval;
119:
120: #if FALSE /* disable yield? */
121: if(op==VDD_YIELD)
122: return(0);
123: #endif
124: _asm {
125: push bx
126: mov ax, vdd
127: mov bh, node_num
128: mov bl, op
129: }
130: DispatchCall();
131: _asm {
132: mov retval, ax
133: pop bx
134: }
135: return(retval);
136: }
137:
138: union REGS inregs;
139: struct SREGS sregs;
140: BOOL inside_int14=FALSE;
141:
142: /* This function is only necessary for naughty programs that call the vector
143: directly instead of issuing an interrupt
144: */
145: void interrupt win95int14(
146: unsigned _es, unsigned _ds,
147: unsigned _di, unsigned _si,
148: unsigned _bp, unsigned _sp,
149: unsigned _bx, unsigned _dx,
150: unsigned _cx, unsigned _ax,
151: unsigned flags )
152: {
153: union REGS outregs;
154:
155: /* prevent recursion, just incase the VXD isn't handling int14h */
156: if(inside_int14)
157: return;
158:
159: inside_int14=TRUE;
160:
161: inregs.x.ax=_ax;
162: inregs.x.bx=_bx;
163: inregs.x.cx=_cx;
164: inregs.x.dx=_dx;
165: inregs.x.si=_si;
166: inregs.x.di=_di;
167: inregs.x.cflag=flags;
168:
169: sregs.es=_es;
170: sregs.ds=_ds;
171:
172: int86x(0x14,&inregs,&outregs,&sregs);
173:
174: /* FOSSIL driver only touches these AX and BX */
175: _ax= outregs.x.ax;
176: _bx= outregs.x.bx;
177:
178: inside_int14=FALSE;
179: }
180:
181: void vdd_getstatus(vdd_status_t* status)
182: {
183: WORD buf_seg;
184:
185: _asm mov buf_seg, ss;
186: if(vdd_buf(VDD_STATUS, sizeof(vdd_status_t), buf_seg, (WORD)status)!=0)
187: memset(status,0,sizeof(vdd_status_t));
188: }
189:
190: WORD PortStatus()
191: {
192: WORD status=0x0008; /* AL bit 3 (change in DCD) always set */
193: vdd_status_t vdd_status;
194:
195: vdd_getstatus(&vdd_status);
196:
197: if(vdd_status.online) /* carrier detect */
198: status|=0x0080; /* DCD */
199:
200: if(vdd_status.inbuf_full) /* receive data ready */
201: status|=0x0100; /* RDA */
202:
203: /* if(vm->overrun) /* overrun error detected */
204: /* status|=0x0200; /* OVRN */
205:
206: if(vdd_status.outbuf_full
207: <vdd_status.outbuf_size/2) /* room available in output buffer */
208: status|=0x2000; /* THRE */
209:
210: if(!vdd_status.outbuf_full) /* output buffer is empty */
211: status|=0x4000; /* TSRE */
212:
213: return(status);
214: }
215:
216: #ifdef DEBUG_FOSSIL_CALLS
217: DWORD fossil_calls[0x100];
218: #endif
219:
220: void interrupt winNTint14(
221: unsigned _es, unsigned _ds,
222: unsigned _di, unsigned _si,
223: unsigned _bp, unsigned _sp,
224: unsigned _bx, unsigned _dx,
225: unsigned _cx, unsigned _ax,
226: )
227: {
228: BYTE ch;
229: BYTE far* p;
230: WORD buf_seg;
231: int wr;
232: vdd_status_t vdd_status;
233: fossil_info_t info = {
234: sizeof(info)
235: ,FOSSIL_REVISION
236: ,revision /* driver revision */
237: ,0 /* ID string pointer */
238: ,0,0 /* receive buffer size/free (overwritten later) */
239: ,0,0 /* transmit buffer size/free (overwritten later) */
240: ,80,25 /* screen dimensions (cols, rows) */
241: /* port settings (i.e. 38400 N-8-1): */
242: ,FOSSIL_BAUD_RATE_38400
243: |FOSSIL_PARITY_NONE
244: |FOSSIL_DATA_BITS_8
245: |FOSSIL_STOP_BITS_1
246: };
247:
248: #ifdef DEBUG_INT_CALLS
249: int14calls++;
250: #endif
251:
252: #ifdef DEBUG_FOSSIL_CALLS
253: fossil_calls[_ax>>8]++;
254: #endif
255:
256: switch(_ax>>8) {
257: case FOSSIL_FUNC_SET_RATE: /* Initialize/Set baud rate */
258: _ax = PortStatus();
259: break;
260: case FOSSIL_FUNC_PUT_CHAR: /* write char to com port, with wait */
261: ch=_ax&0xff;
262: _asm mov buf_seg, ss;
263: vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
264: _ax = PortStatus();
265: break;
266: case FOSSIL_FUNC_GET_CHAR: /* read char from com port, with wait */
267: _asm mov buf_seg, ss;
268: _ax = vdd_buf(VDD_READ, 1, buf_seg, (WORD)&ch);
269: if(!_ax) {
270: _ax = 0x8000; /* timed-out */
271: vdd_op(VDD_YIELD);
272: } else {
273: _ax = ch;
274: }
275: break;
276: case FOSSIL_FUNC_GET_STATUS: /* request status */
277: _ax=PortStatus();
278: if(_ax==0x6088)
279: vdd_op(VDD_MAYBE_YIELD);
280: break;
281: case FOSSIL_FUNC_INIT: /* initialize */
282: _ax=FOSSIL_SIGNATURE; /* magic number = success */
283: _bx=FOSSIL_REVISION<<8 | FOSSIL_FUNC_HIGHEST; /* FOSSIL rev/maximum FOSSIL func supported */
284: break;
285: case FOSSIL_FUNC_DTR:
286: if((_ax&0xff)==0) /* Lower DTR */
287: vdd_op(VDD_HANGUP);
288: break;
289: case FOSSIL_FUNC_FLUSH_OUT: /* flush output buffer */
290: break;
291: case FOSSIL_FUNC_PURGE_OUT: /* purge output buffer */
292: vdd_op(VDD_OUTBUF_PURGE);
293: break;
294: case FOSSIL_FUNC_PURGE_IN: /* purge input buffer */
295: vdd_op(VDD_INBUF_PURGE);
296: break;
297: case FOSSIL_FUNC_WRITE_CHAR: /* write char to com port, no wait */
298: if(0 /*RingBufFree(&vm->out)<2 */) {
299: _ax=0; /* char was not accepted */
300: break;
301: }
302: ch=_ax&0xff;
303: _asm mov buf_seg, ss;
304: _ax = vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
305: break;
306: case FOSSIL_FUNC_PEEK: /* non-destructive read-ahead */
307: vdd_getstatus(&vdd_status);
308: if(!vdd_status.inbuf_full) {
309: _ax=0xffff; /* no char available */
310: vdd_op(VDD_YIELD);
311: break;
312: }
313: _asm mov buf_seg, ss;
314: _ax = vdd_buf(VDD_PEEK, 1, buf_seg, (WORD)&ch);
315: if(_ax == 0)
316: vdd_op(VDD_YIELD);
317: break;
318: case FOSSIL_FUNC_READ_BLOCK: /* read block, no wait */
319: vdd_getstatus(&vdd_status);
320: if(!vdd_status.inbuf_full)
321: _ax = 0; /* no data available */
322: else
323: _ax = vdd_buf(VDD_READ, _cx, _es, _di);
324: if(_ax == 0)
325: vdd_op(VDD_YIELD);
326: break;
327: case FOSSIL_FUNC_WRITE_BLOCK: /* write block, no wait */
328: _ax = vdd_buf(VDD_WRITE, _cx, _es, _di);
329: break;
330: case FOSSIL_FUNC_GET_INFO: /* driver info */
331: vdd_getstatus(&vdd_status);
332: info.inbuf_size=vdd_status.inbuf_size;
333: info.inbuf_free=info.inbuf_size-vdd_status.inbuf_full;
334: info.outbuf_size=vdd_status.outbuf_size;
335: info.outbuf_free=info.outbuf_size-vdd_status.outbuf_full;
336: info.id_string = id_string;
337:
338: if(vdd_status.inbuf_full==vdd_status.outbuf_full==0)
339: vdd_op(VDD_MAYBE_YIELD);
340:
341: p = _MK_FP(_es,_di);
342: wr=sizeof(info);
343: if(wr>_cx)
344: wr=_cx;
345: _fmemcpy(p, &info, wr);
346: _ax=wr;
347: break;
348: }
349: }
350:
351: void int14stub(void)
352: {
353: /* This function will be overwritten later (during runtime) with FOSSIL signature */
354: }
355:
356: void interrupt winNTint16(
357: unsigned _es, unsigned _ds,
358: unsigned _di, unsigned _si,
359: unsigned _bp, unsigned _sp,
360: unsigned _bx, unsigned _dx,
361: unsigned _cx, unsigned _ax,
362: unsigned _ip, unsigned _cs,
363: unsigned flags )
364: {
365: BYTE ch;
366: WORD buf_seg;
367: vdd_status_t status;
368:
369: #ifdef DEBUG_INT_CALLS
370: int16calls++;
371: #endif
372:
373: vdd_getstatus(&status);
374: switch(_ax>>8) {
375: case 0x00: /* Read char from keyboard */
376: case 0x10: /* Read char from enhanced keyboard */
377: if(status.inbuf_full) {
378: _asm mov buf_seg, ss;
379: vdd_buf(VDD_READ, 1, buf_seg, (WORD)&ch);
380: _ax=ch;
381: return;
382: }
383: vdd_op(VDD_MAYBE_YIELD);
384: break;
385: case 0x01: /* Get keyboard status */
386: case 0x11: /* Get enhanced keyboard status */
387: if(status.inbuf_full) {
388: _asm mov buf_seg, ss;
389: vdd_buf(VDD_PEEK, 1, buf_seg, (WORD)&ch);
390: flags&=~(1<<6); /* clear zero flag */
391: _ax=ch;
392: return;
393: }
394: vdd_op(VDD_MAYBE_YIELD);
395: break;
396: }
397:
398: _chain_intr(oldint16);
399: }
400:
401: #ifdef DEBUG_DOS_CALLS
402: DWORD dos_calls[0x100];
403: #endif
404:
405: void interrupt winNTint21(
406: unsigned _es, unsigned _ds,
407: unsigned _di, unsigned _si,
408: unsigned _bp, unsigned _sp,
409: unsigned _bx, unsigned _dx,
410: unsigned _cx, unsigned _ax,
411: )
412: {
413: #ifdef DEBUG_INT_CALLS
414: int21calls++;
415: #endif
416: if(_ax>>8 == 0x2c) /* GET_SYSTEM_TIME */
417: vdd_op(VDD_MAYBE_YIELD);
418: #ifdef DEBUG_DOS_CALLS
419: dos_calls[_ax>>8]++;
420: #endif
421: _chain_intr(oldint21);
422: }
423:
424: void interrupt winNTint29(
425: unsigned _es, unsigned _ds,
426: unsigned _di, unsigned _si,
427: unsigned _bp, unsigned _sp,
428: unsigned _bx, unsigned _dx,
429: unsigned _cx, unsigned _ax,
430: )
431: {
432: char ch;
433: WORD buf_seg;
434: #ifdef DEBUG_INT_CALLS
435: int29calls++;
436: #endif
437:
438: ch=_ax&0xff;
439: _asm mov buf_seg, ss
440: vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
441:
442: _chain_intr(oldint29);
443: }
444:
445: /****************************************************************************/
446: /* Return the filename portion of a full pathname */
447: /****************************************************************************/
448: char* getfname(const char* path)
449: {
450: const char* fname;
451: const char* bslash;
452:
453: fname=strrchr(path,'/');
454: bslash=strrchr(path,'\\');
455: if(bslash>fname)
456: fname=bslash;
457: if(fname!=NULL)
458: fname++;
459: else
460: fname=(char*)path;
461: return((char*)fname);
462: }
463:
464: char * DllName =VDD_FILENAME;
465: char * InitFunc ="VDDInitialize";
466: char * DispFunc ="VDDDispatch";
467:
468: int main(int argc, char **argv)
469: {
470: char str[128];
471: char cmdline[128],*p;
472: char dll[256];
473: char exec_dir[128];
474: char* envvar[10];
475: char* arg[16];
476: int i,c,d,envnum=0;
477: FILE* fp;
478: BOOL NT=FALSE;
479: BOOL success=FALSE;
480: WORD buf_seg;
481: WORD w;
482:
483: sscanf("$Revision: 1.23 $", "%*s 1.%u", &revision);
484:
485: sprintf(id_string,"Synchronet FOSSIL Driver (DOSXTRN) revision %u", revision);
486: if(argc<2) {
487: fprintf(stderr
488: ,"%s - Copyright %s Rob Swindell\n"
489: ,id_string, __DATE__+7);
490: fprintf(stderr
491: ,"usage: dosxtrn <path/dosxtrn.env> [NT|95] [node_num] [mode]\n");
492: return(1);
493: }
494:
495: sprintf(exec_dir,"%.*s",sizeof(exec_dir)-1,argv[0]);
496: p=getfname(exec_dir);
497: *p=0;
498: sprintf(dll,"%s%s",exec_dir,VDD_FILENAME);
499: DllName=dll;
500:
501: if(argc>2 && !strcmp(argv[2],"NT"))
502: NT=TRUE;
503: if(argc>3)
504: node_num=atoi(argv[3]);
505: if(argc>4)
506: mode=atoi(argv[4]);
507:
508: if((fp=fopen(argv[1],"r"))==NULL) {
509: fprintf(stderr,"!Error opening %s\n",argv[1]);
510: return(2);
511: }
512:
513: fgets(cmdline, sizeof(cmdline), fp);
514: truncsp(cmdline);
515:
516: arg[0]=cmdline; /* point to the beginning of the string */
517: for(c=0,d=1;cmdline[c];c++) /* Break up command line */
518: if(cmdline[c]==' ') {
519: cmdline[c]=0; /* insert nulls */
520: arg[d++]=cmdline+c+1; /* point to the beginning of the next arg */
521: }
522: arg[d]=0;
523:
524: while(!feof(fp)) {
525: if(!fgets(str, sizeof(str), fp))
526: break;
527: truncsp(str);
528: if((envvar[envnum]=strdup(str))==NULL) {
529: fprintf(stderr,"!MALLOC ERROR\n");
530: return(4);
531: }
532: _putenv(envvar[envnum++]);
533: }
534: fclose(fp);
535:
536: /* Save int14 handler */
537: oldint14=_dos_getvect(0x14);
538:
539: /* Overwrite stub function */
540: ((BYTE*)int14stub)[0] = 0xe9; /* jump (relative) */
541: ((BYTE*)int14stub)[3] = 0x90; /* NOP */
542: ((BYTE*)int14stub)[4] = 0x90; /* NOP */
543: ((BYTE*)int14stub)[5] = 0x90; /* NOP */
544: ((BYTE*)int14stub)[6] = FOSSIL_SIGNATURE&0xff; /* FOSSIL sig (LSB) */
545: ((BYTE*)int14stub)[7] = FOSSIL_SIGNATURE>>8; /* FOSSIL sig (MSB) */
546: ((BYTE*)int14stub)[8] = FOSSIL_FUNC_HIGHEST; /* FOSSIL highest func supported */
547:
548: if(NT) { /* Windows NT/2000 */
549:
550: for(i=0;i<2;i++) {
551:
552: /* Register VDD */
553: _asm {
554: push es
555: push ds
556: pop es
557: mov si, DllName ; ds:si = dll name
558: mov di, InitFunc ; es:di = init routine
559: mov bx, DispFunc ; ds:bx = dispatch routine
560: #if 1 /* Vista work-around, apparently doesn't support an InitFunc (RegisterModule fails with AX=1) */
561: xor di,di
562: mov es,di
563: #endif
564:
565: };
566: RegisterModule();
567: _asm {
568: mov vdd, ax
569: jc err
570: mov success, TRUE
571: err:
572: pop es
573: }
574: if(success)
575: break;
576: DllName=VDD_FILENAME; /* try again with no path (for Windows Vista) */
577: }
578: if(!success) {
579: fprintf(stderr,"Error %d loading %s\n",vdd,DllName);
580: return(-1);
581: }
582:
583: #if 0
584: fprintf(stderr,"vdd handle=%d\n",vdd);
585: fprintf(stderr,"mode=%d\n",mode);
586: #endif
587: vdd_str(VDD_LOAD_INI_FILE, exec_dir);
588:
589: vdd_str(VDD_LOAD_INI_SECTION, getfname(arg[0]));
590:
591: sprintf(str,"%s, rev %u, %s %s", __FILE__, revision, __DATE__, __TIME__);
592: vdd_str(VDD_DEBUG_OUTPUT, str);
593:
594: i=vdd_op(VDD_OPEN);
595: if(i) {
596: fprintf(stderr,"!VDD_OPEN ERROR: %d\n",i);
597: UnRegisterModule();
598: return(-1);
599: }
600: oldint16=_dos_getvect(0x16);
601: oldint21=_dos_getvect(0x21);
602: oldint29=_dos_getvect(0x29);
603: if(mode==SBBSEXEC_MODE_FOSSIL) {
604: *(WORD*)((BYTE*)int14stub+1) = (WORD)winNTint14 - (WORD)&int14stub - 3; /* jmp offset */
605: _dos_setvect(0x14,(void(interrupt *)())int14stub);
606: }
607: _dos_setvect(0x21,winNTint21);
608: if(mode&SBBSEXEC_MODE_DOS_IN)
609: _dos_setvect(0x16,winNTint16);
610: if(mode&SBBSEXEC_MODE_DOS_OUT)
611: _dos_setvect(0x29,winNTint29);
612: }
613: else if(mode==SBBSEXEC_MODE_FOSSIL) { /* Windows 95/98/Millennium */
614: *(WORD*)((BYTE*)int14stub+1) = (WORD)win95int14 - (WORD)&int14stub - 3; /* jmp offset */
615: _dos_setvect(0x14,(void(interrupt *)())int14stub);
616: }
617:
618: _heapmin();
619: i=_spawnvp(_P_WAIT, arg[0], arg);
620:
621: p=argv[1]+(strlen(argv[1])-3);
622: strcpy(p,"RET");
623: if((fp=fopen(argv[1],"w+"))==NULL) {
624: fprintf(stderr,"!Error opening %s\n",argv[1]);
625: return(3);
626: }
627: fprintf(fp,"%d",i);
628:
629: /* Restore original ISRs */
630: _dos_setvect(0x14,oldint14);
631:
632: if(NT) {
633: vdd_op(VDD_CLOSE);
634:
635: _dos_setvect(0x16,oldint16);
636: _dos_setvect(0x21,oldint21);
637: _dos_setvect(0x29,oldint29);
638:
639: sprintf(str,"%s returned %d", arg[0], i);
640: vdd_str(VDD_DEBUG_OUTPUT, str);
641:
642: #ifdef DEBUG_INT_CALLS
643: sprintf(str,"int14h calls: %u", int14calls); vdd_str(VDD_DEBUG_OUTPUT, str);
644: sprintf(str,"int16h calls: %u", int16calls); vdd_str(VDD_DEBUG_OUTPUT, str);
645: sprintf(str,"int21h calls: %u", int21calls); vdd_str(VDD_DEBUG_OUTPUT, str);
646: sprintf(str,"int29h calls: %u", int29calls); vdd_str(VDD_DEBUG_OUTPUT, str);
647: #endif
648: #ifdef DEBUG_DOS_CALLS
649: for(i=0;i<0x100;i++) {
650: if(dos_calls[i]>100) {
651: sprintf(str,"int21h function %02X calls: %u\n"
652: ,i, dos_calls[i]);
653: vdd_str(VDD_DEBUG_OUTPUT, str);
654: }
655: }
656: #endif
657: #ifdef DEBUG_FOSSIL_CALLS
658: for(i=0;i<0x100;i++) {
659: if(fossil_calls[i]>0) {
660: sprintf(str,"int14h function %02X calls: %u"
661: ,i, fossil_calls[i]);
662: vdd_str(VDD_DEBUG_OUTPUT, str); }
663: }
664: #endif
665:
666: /* Unregister VDD */
667: _asm mov ax, vdd;
668: UnRegisterModule();
669:
670: }
671:
672: return(i);
673: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.