1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)spintc.c	4.1 (Berkeley) 12/04/88";
20 #endif /* not lint */
21 
22 #include <stdio.h>
23 #include <dos.h>
24 #include <stdlib.h>
25 
26 #include "../general/general.h"
27 #include "spint.h"
28 
29 #define	PSP_ENVIRONMENT		0x2c
30 #define	PSP_FCB1		0x5c
31 #define	PSP_FCB2		0x6c
32 
33 typedef struct {
34     int
35 	environment,		/* Segment address of environment */
36 	cmd_ptr_offset,		/* Offset of command to execute */
37 	cmd_ptr_segment,	/* Segment where command lives */
38 	fcb1_ptr_offset,	/* Offset of FCB 1 */
39 	fcb1_ptr_segment,	/* Segment of FCB 1 */
40 	fcb2_ptr_offset,	/* Offset of FCB 2 */
41 	fcb2_ptr_segment;	/* Segment of FCB 2 */
42 } ExecList;
43 
44 
45 static int int_offset, int_segment;
46 
47 
48 void
49 spint_finish(spint)
50 Spint *spint;
51 {
52     union REGS regs;
53     struct SREGS sregs;
54 
55     if (spint->done == 0) {
56 	return;				/* Not done yet */
57     }
58 
59     /*
60      * Restore old interrupt handler.
61      */
62 
63     regs.h.ah = 0x25;
64     regs.h.al = spint->int_no;
65     regs.x.dx = int_offset;
66     sregs.ds = int_segment;
67     intdosx(&regs, &regs, &sregs);
68 
69     if (spint->regs.x.cflag) {
70 	fprintf(stderr, "0x%x return code from EXEC.\n", spint->regs.x.ax);
71 	spint->done = 1;
72 	spint->rc = 99;
73 	return;
74     }
75 
76     regs.h.ah = 0x4d;			/* Get return code */
77 
78     intdos(&regs, &regs);
79 
80     spint->rc = regs.x.ax;
81 }
82 
83 void
84 spint_continue(spint)
85 Spint *spint;
86 {
87     _spint_continue(spint);		/* Return to caller */
88     spint_finish(spint);
89 }
90 
91 
92 void
93 spint_start(command, spint)
94 char *command;
95 Spint *spint;
96 {
97     ExecList mylist;
98     char *comspec;
99     void _spint_int();
100     union REGS regs;
101     struct SREGS sregs;
102 
103     /*
104      * Get comspec.
105      */
106     comspec = getenv("COMSPEC");
107     if (comspec == 0) {			/* Can't find where command.com is */
108 	fprintf(stderr, "Unable to find COMSPEC in the environment.");
109 	spint->done = 1;
110 	spint->rc = 99;	/* XXX */
111 	return;
112     }
113 
114     /*
115      * Now, hook up our interrupt routine.
116      */
117 
118     regs.h.ah = 0x35;
119     regs.h.al = spint->int_no;
120     intdosx(&regs, &regs, &sregs);
121 
122     /* Save old routine */
123     int_offset = regs.x.bx;
124     int_segment = sregs.es;
125 
126     regs.h.ah = 0x25;
127     regs.h.al = spint->int_no;
128     regs.x.dx = (int) _spint_int;
129     segread(&sregs);
130     sregs.ds = sregs.cs;
131     intdosx(&regs, &regs, &sregs);
132 
133     /*
134      * Read in segment registers.
135      */
136 
137     segread(&spint->sregs);
138 
139     /*
140      * Set up registers for the EXEC call.
141      */
142 
143     spint->regs.h.ah = 0x4b;
144     spint->regs.h.al = 0;
145     spint->regs.x.dx = (int) comspec;
146     spint->sregs.es = spint->sregs.ds;		/* Superfluous, probably */
147     spint->regs.x.bx = (int) &mylist;
148 
149     /*
150      * Set up EXEC parameter list.
151      */
152 
153     ClearElement(mylist);
154     mylist.cmd_ptr_offset = (int) command;
155     mylist.cmd_ptr_segment = spint->sregs.ds;
156     mylist.fcb1_ptr_offset = PSP_FCB1;
157     mylist.fcb1_ptr_segment = _psp;
158     mylist.fcb2_ptr_offset = PSP_FCB2;
159     mylist.fcb2_ptr_segment = _psp;
160     mylist.environment = *((int far *)(((long)_psp<<16)|PSP_ENVIRONMENT));
161 
162     /*
163      * Call to assembly language routine to actually set up for
164      * the spint.
165      */
166 
167     _spint_start(spint);
168 
169     spint_finish(spint);
170 }
171