1 /*-
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)spintc.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 #include <stdio.h>
13 #include <dos.h>
14 #include <stdlib.h>
15 
16 #include "../general/general.h"
17 #include "spint.h"
18 
19 #define	PSP_ENVIRONMENT		0x2c
20 #define	PSP_FCB1		0x5c
21 #define	PSP_FCB2		0x6c
22 
23 typedef struct {
24     int
25 	environment,		/* Segment address of environment */
26 	cmd_ptr_offset,		/* Offset of command to execute */
27 	cmd_ptr_segment,	/* Segment where command lives */
28 	fcb1_ptr_offset,	/* Offset of FCB 1 */
29 	fcb1_ptr_segment,	/* Segment of FCB 1 */
30 	fcb2_ptr_offset,	/* Offset of FCB 2 */
31 	fcb2_ptr_segment;	/* Segment of FCB 2 */
32 } ExecList;
33 
34 
35 static int int_offset, int_segment;
36 
37 
38 void
39 spint_finish(spint)
40 Spint *spint;
41 {
42     union REGS regs;
43     struct SREGS sregs;
44 
45     if (spint->done == 0) {
46 	return;				/* Not done yet */
47     }
48 
49     /*
50      * Restore old interrupt handler.
51      */
52 
53     regs.h.ah = 0x25;
54     regs.h.al = spint->int_no;
55     regs.x.dx = int_offset;
56     sregs.ds = int_segment;
57     intdosx(&regs, &regs, &sregs);
58 
59     if (spint->regs.x.cflag) {
60 	fprintf(stderr, "0x%x return code from EXEC.\n", spint->regs.x.ax);
61 	spint->done = 1;
62 	spint->rc = 99;
63 	return;
64     }
65 
66     regs.h.ah = 0x4d;			/* Get return code */
67 
68     intdos(&regs, &regs);
69 
70     spint->rc = regs.x.ax;
71 }
72 
73 void
74 spint_continue(spint)
75 Spint *spint;
76 {
77     _spint_continue(spint);		/* Return to caller */
78     spint_finish(spint);
79 }
80 
81 
82 void
83 spint_start(command, spint)
84 char *command;
85 Spint *spint;
86 {
87     ExecList mylist;
88     char *comspec;
89     void _spint_int();
90     union REGS regs;
91     struct SREGS sregs;
92 
93     /*
94      * Get comspec.
95      */
96     comspec = getenv("COMSPEC");
97     if (comspec == 0) {			/* Can't find where command.com is */
98 	fprintf(stderr, "Unable to find COMSPEC in the environment.");
99 	spint->done = 1;
100 	spint->rc = 99;	/* XXX */
101 	return;
102     }
103 
104     /*
105      * Now, hook up our interrupt routine.
106      */
107 
108     regs.h.ah = 0x35;
109     regs.h.al = spint->int_no;
110     intdosx(&regs, &regs, &sregs);
111 
112     /* Save old routine */
113     int_offset = regs.x.bx;
114     int_segment = sregs.es;
115 
116     regs.h.ah = 0x25;
117     regs.h.al = spint->int_no;
118     regs.x.dx = (int) _spint_int;
119     segread(&sregs);
120     sregs.ds = sregs.cs;
121     intdosx(&regs, &regs, &sregs);
122 
123     /*
124      * Read in segment registers.
125      */
126 
127     segread(&spint->sregs);
128 
129     /*
130      * Set up registers for the EXEC call.
131      */
132 
133     spint->regs.h.ah = 0x4b;
134     spint->regs.h.al = 0;
135     spint->regs.x.dx = (int) comspec;
136     spint->sregs.es = spint->sregs.ds;		/* Superfluous, probably */
137     spint->regs.x.bx = (int) &mylist;
138 
139     /*
140      * Set up EXEC parameter list.
141      */
142 
143     ClearElement(mylist);
144     mylist.cmd_ptr_offset = (int) command;
145     mylist.cmd_ptr_segment = spint->sregs.ds;
146     mylist.fcb1_ptr_offset = PSP_FCB1;
147     mylist.fcb1_ptr_segment = _psp;
148     mylist.fcb2_ptr_offset = PSP_FCB2;
149     mylist.fcb2_ptr_segment = _psp;
150     mylist.environment = *((int far *)(((long)_psp<<16)|PSP_ENVIRONMENT));
151 
152     /*
153      * Call to assembly language routine to actually set up for
154      * the spint.
155      */
156 
157     _spint_start(spint);
158 
159     spint_finish(spint);
160 }
161