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