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