19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
1 /* Proxy shell designed for use with Emacs on Windows 95 and NT.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
2 Copyright (C) 1997 Free Software Foundation, Inc.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
3
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
4 Accepts subset of Unix sh(1) command-line options, for compatability
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
5 with elisp code written for Unix. When possible, executes external
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
6 programs directly (a common use of /bin/sh by Emacs), otherwise
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
7 invokes the user-specified command processor to handle built-in shell
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
8 commands, batch files and interactive mode.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
9
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
10 The main function is simply to process the "-c string" option in the
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
11 way /bin/sh does, since the standard Windows command shells use the
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
12 convention that everything after "/c" (the Windows equivalent of
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
13 "-c") is the input string.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
14
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
15 This file is part of GNU Emacs.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
16
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
17 GNU Emacs is free software; you can redistribute it and/or modify
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
18 it under the terms of the GNU General Public License as published by
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
19 the Free Software Foundation; either version 2, or (at your option)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
20 any later version.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
21
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
22 GNU Emacs is distributed in the hope that it will be useful,
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
25 GNU General Public License for more details.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
26
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
27 You should have received a copy of the GNU General Public License
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
28 along with GNU Emacs; see the file COPYING. If not, write to
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
29 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
30 Boston, MA 02111-1307, USA. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
31
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
32 #include <windows.h>
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
33
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
34 #include <stdarg.h> /* va_args */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
35 #include <malloc.h> /* alloca */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
36 #include <stdlib.h> /* getenv */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
37 #include <string.h> /* strlen */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
38
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
39
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
40 /******* Mock C library routines *********************************/
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
41
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
42 /* These routines are used primarily to minimize the executable size. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
43
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
44 #define stdin GetStdHandle (STD_INPUT_HANDLE)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
45 #define stdout GetStdHandle (STD_OUTPUT_HANDLE)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
46 #define stderr GetStdHandle (STD_ERROR_HANDLE)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
47
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
48 int
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
49 vfprintf(HANDLE hnd, char * msg, va_list args)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
50 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
51 DWORD bytes_written;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
52 char buf[1024];
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
53
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
54 wvsprintf (buf, msg, args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
55 return WriteFile (hnd, buf, strlen (buf), &bytes_written, NULL);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
56 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
57
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
58 int
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
59 fprintf(HANDLE hnd, char * msg, ...)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
60 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
61 va_list args;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
62 int rc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
63
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
64 va_start (args, msg);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
65 rc = vfprintf (hnd, msg, args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
66 va_end (args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
67
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
68 return rc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
69 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
70
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
71 int
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
72 printf(char * msg, ...)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
73 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
74 va_list args;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
75 int rc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
76
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
77 va_start (args, msg);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
78 rc = vfprintf (stdout, msg, args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
79 va_end (args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
80
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
81 return rc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
82 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
83
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
84 void
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
85 fail (char * msg, ...)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
86 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
87 va_list args;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
88
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
89 va_start (args, msg);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
90 vfprintf (stderr, msg, args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
91 va_end (args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
92
|
21598
|
93 exit (-1);
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
94 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
95
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
96 void
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
97 warn (char * msg, ...)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
98 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
99 va_list args;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
100
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
101 va_start (args, msg);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
102 vfprintf (stderr, msg, args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
103 va_end (args);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
104 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
105
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
106 /******************************************************************/
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
107
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
108 char *
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
109 canon_filename (char *fname)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
110 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
111 char *p = fname;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
112
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
113 while (*p)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
114 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
115 if (*p == '/')
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
116 *p = '\\';
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
117 p++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
118 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
119
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
120 return fname;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
121 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
122
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
123 char *
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
124 skip_space (char *str)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
125 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
126 while (isspace (*str)) str++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
127 return str;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
128 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
129
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
130 char *
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
131 skip_nonspace (char *str)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
132 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
133 while (*str && !isspace (*str)) str++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
134 return str;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
135 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
136
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
137 int escape_char = '\\';
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
138
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
139 /* Get next token from input, advancing pointer. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
140 int
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
141 get_next_token (char * buf, char ** pSrc)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
142 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
143 char * p = *pSrc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
144 char * o = buf;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
145
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
146 p = skip_space (p);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
147 if (*p == '"')
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
148 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
149 int escape_char_run = 0;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
150
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
151 /* Go through src until an ending quote is found, unescaping
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
152 quotes along the way. If the escape char is not quote, then do
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
153 special handling of multiple escape chars preceding a quote
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
154 char (ie. the reverse of what Emacs does to escape quotes). */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
155 p++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
156 while (1)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
157 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
158 if (p[0] == escape_char && escape_char != '"')
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
159 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
160 escape_char_run++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
161 continue;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
162 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
163 else if (p[0] == '"')
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
164 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
165 while (escape_char_run > 1)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
166 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
167 *o++ = escape_char;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
168 escape_char_run -= 2;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
169 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
170
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
171 if (escape_char_run > 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
172 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
173 /* escaped quote */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
174 *o++ = *p++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
175 escape_char_run = 0;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
176 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
177 else if (p[1] == escape_char && escape_char == '"')
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
178 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
179 /* quote escaped by doubling */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
180 *o++ = *p;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
181 p += 2;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
182 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
183 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
184 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
185 /* The ending quote. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
186 *o = '\0';
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
187 /* Leave input pointer after token. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
188 p++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
189 break;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
190 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
191 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
192 else if (p[0] == '\0')
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
193 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
194 /* End of string, but no ending quote found. We might want to
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
195 flag this as an error, but for now will consider the end as
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
196 the end of the token. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
197 *o = '\0';
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
198 break;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
199 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
200 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
201 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
202 *o++ = *p++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
203 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
204 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
205 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
206 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
207 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
208 /* Next token is delimited by whitespace. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
209 char * p1 = skip_nonspace (p);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
210 memcpy (o, p, p1 - p);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
211 o += (p1 - p);
|
19718
|
212 *o = '\0';
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
213 p = p1;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
214 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
215
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
216 *pSrc = p;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
217
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
218 return o - buf;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
219 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
220
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
221 /* Search for EXEC file in DIR. If EXEC does not have an extension,
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
222 DIR is searched for EXEC with the standard extensions appended. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
223 int
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
224 search_dir (char *dir, char *exec, int bufsize, char *buffer)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
225 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
226 char *exts[] = {".bat", ".cmd", ".exe", ".com"};
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
227 int n_exts = sizeof (exts) / sizeof (char *);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
228 char *dummy;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
229 int i, rc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
230
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
231 /* Search the directory for the program. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
232 for (i = 0; i < n_exts; i++)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
233 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
234 rc = SearchPath (dir, exec, exts[i], bufsize, buffer, &dummy);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
235 if (rc > 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
236 return rc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
237 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
238
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
239 return 0;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
240 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
241
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
242 /* Return the absolute name of executable file PROG, including
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
243 any file extensions. If an absolute name for PROG cannot be found,
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
244 return NULL. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
245 char *
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
246 make_absolute (char *prog)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
247 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
248 char absname[MAX_PATH];
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
249 char dir[MAX_PATH];
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
250 char curdir[MAX_PATH];
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
251 char *p, *fname;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
252 char *path;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
253 int i;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
254
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
255 /* At least partial absolute path specified; search there. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
256 if ((isalpha (prog[0]) && prog[1] == ':') ||
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
257 (prog[0] == '\\'))
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
258 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
259 /* Split the directory from the filename. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
260 fname = strrchr (prog, '\\');
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
261 if (!fname)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
262 /* Only a drive specifier is given. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
263 fname = prog + 2;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
264 strncpy (dir, prog, fname - prog);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
265 dir[fname - prog] = '\0';
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
266
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
267 /* Search the directory for the program. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
268 if (search_dir (dir, prog, MAX_PATH, absname) > 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
269 return strdup (absname);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
270 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
271 return NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
272 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
273
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
274 if (GetCurrentDirectory (MAX_PATH, curdir) <= 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
275 return NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
276
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
277 /* Relative path; search in current dir. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
278 if (strpbrk (prog, "\\"))
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
279 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
280 if (search_dir (curdir, prog, MAX_PATH, absname) > 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
281 return strdup (absname);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
282 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
283 return NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
284 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
285
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
286 /* Just filename; search current directory then PATH. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
287 path = alloca (strlen (getenv ("PATH")) + strlen (curdir) + 2);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
288 strcpy (path, curdir);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
289 strcat (path, ";");
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
290 strcat (path, getenv ("PATH"));
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
291
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
292 while (*path)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
293 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
294 /* Get next directory from path. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
295 p = path;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
296 while (*p && *p != ';') p++;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
297 strncpy (dir, path, p - path);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
298 dir[p - path] = '\0';
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
299
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
300 /* Search the directory for the program. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
301 if (search_dir (dir, prog, MAX_PATH, absname) > 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
302 return strdup (absname);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
303
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
304 /* Move to the next directory. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
305 path = p + 1;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
306 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
307
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
308 return NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
309 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
310
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
311 /*****************************************************************/
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
312
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
313 #if 0
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
314 char ** _argv;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
315 int _argc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
316
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
317 /* Parse commandline into argv array, allowing proper quoting of args. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
318 void
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
319 setup_argv (void)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
320 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
321 char * cmdline = GetCommandLine ();
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
322 int arg_bytes = 0;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
323
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
324
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
325 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
326 #endif
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
327
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
328 /* Information about child proc is global, to allow for automatic
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
329 termination when interrupted. At the moment, only one child process
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
330 can be running at any one time. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
331
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
332 PROCESS_INFORMATION child;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
333 int interactive = TRUE;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
334
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
335 BOOL
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
336 console_event_handler (DWORD event)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
337 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
338 switch (event)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
339 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
340 case CTRL_C_EVENT:
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
341 case CTRL_BREAK_EVENT:
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
342 if (!interactive)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
343 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
344 /* Both command.com and cmd.exe have the annoying behaviour of
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
345 prompting "Terminate batch job (y/n)?" when interrupted
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
346 while running a batch file, even if running in
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
347 non-interactive (-c) mode. Try to make up for this
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
348 deficiency by forcibly terminating the subprocess if
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
349 running non-interactively. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
350 if (child.hProcess &&
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
351 WaitForSingleObject (child.hProcess, 500) != WAIT_OBJECT_0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
352 TerminateProcess (child.hProcess, 0);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
353 exit (STATUS_CONTROL_C_EXIT);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
354 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
355 break;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
356
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
357 #if 0
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
358 default:
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
359 /* CLOSE, LOGOFF and SHUTDOWN events - actually we don't get these
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
360 under Windows 95. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
361 fail ("cmdproxy: received %d event\n", event);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
362 if (child.hProcess)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
363 TerminateProcess (child.hProcess, 0);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
364 #endif
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
365 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
366 return TRUE;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
367 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
368
|
21598
|
369 /* Change from normal usage; return value indicates whether spawn
|
|
370 succeeded or failed - program return code is returned separately. */
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
371 int
|
23947
|
372 spawn (char * progname, char * cmdline, char * dir, int * retcode)
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
373 {
|
21598
|
374 BOOL success = FALSE;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
375 SECURITY_ATTRIBUTES sec_attrs;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
376 STARTUPINFO start;
|
21598
|
377 /* In theory, passing NULL for the environment block to CreateProcess
|
|
378 is the same as passing the value of GetEnvironmentStrings, but
|
|
379 doing this explicitly seems to cure problems running DOS programs
|
|
380 in some cases. */
|
19718
|
381 char * envblock = GetEnvironmentStrings ();
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
382
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
383 sec_attrs.nLength = sizeof (sec_attrs);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
384 sec_attrs.lpSecurityDescriptor = NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
385 sec_attrs.bInheritHandle = FALSE;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
386
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
387 memset (&start, 0, sizeof (start));
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
388 start.cb = sizeof (start);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
389
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
390 if (CreateProcess (progname, cmdline, &sec_attrs, NULL, TRUE,
|
23947
|
391 0, envblock, dir, &start, &child))
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
392 {
|
21598
|
393 success = TRUE;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
394 /* wait for completion and pass on return code */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
395 WaitForSingleObject (child.hProcess, INFINITE);
|
21598
|
396 if (retcode)
|
|
397 GetExitCodeProcess (child.hProcess, (DWORD *)retcode);
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
398 CloseHandle (child.hThread);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
399 CloseHandle (child.hProcess);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
400 child.hProcess = NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
401 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
402
|
19718
|
403 FreeEnvironmentStrings (envblock);
|
|
404
|
21598
|
405 return success;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
406 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
407
|
19718
|
408 /* Return size of current environment block. */
|
|
409 int
|
|
410 get_env_size ()
|
|
411 {
|
|
412 char * start = GetEnvironmentStrings ();
|
|
413 char * tmp = start;
|
|
414
|
|
415 while (tmp[0] || tmp[1])
|
|
416 ++tmp;
|
|
417 FreeEnvironmentStrings (start);
|
|
418 return tmp + 2 - start;
|
|
419 }
|
|
420
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
421 /******* Main program ********************************************/
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
422
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
423 int
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
424 main (int argc, char ** argv)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
425 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
426 int rc;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
427 int need_shell;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
428 char * cmdline;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
429 char * progname;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
430 int envsize;
|
19718
|
431 char **pass_through_args;
|
|
432 int num_pass_through_args;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
433 char modname[MAX_PATH];
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
434 char path[MAX_PATH];
|
23947
|
435 char dir[MAX_PATH];
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
436
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
437
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
438 interactive = TRUE;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
439
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
440 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) console_event_handler, TRUE);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
441
|
23947
|
442 if (!GetCurrentDirectory (sizeof (dir), dir))
|
|
443 fail ("error: GetCurrentDirectory failed\n");
|
|
444
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
445 /* We serve double duty: we can be called either as a proxy for the
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
446 real shell (that is, because we are defined to be the user shell),
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
447 or in our role as a helper application for running DOS programs.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
448 In the former case, we interpret the command line options as if we
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
449 were a Unix shell, but in the latter case we simply pass our
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
450 command line to CreateProcess. We know which case we are dealing
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
451 with by whether argv[0] refers to ourself or to some other program.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
452 (This relies on an arcane feature of CreateProcess, where we can
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
453 specify cmdproxy as the module to run, but specify a different
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
454 program in the command line - the MSVC startup code sets argv[0]
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
455 from the command line.) */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
456
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
457 if (!GetModuleFileName (NULL, modname, sizeof (modname)))
|
19718
|
458 fail ("error: GetModuleFileName failed\n");
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
459
|
23947
|
460 /* Change directory to location of .exe so startup directory can be
|
|
461 deleted. */
|
|
462 progname = strrchr (modname, '\\');
|
|
463 *progname = '\0';
|
|
464 SetCurrentDirectory (modname);
|
|
465 *progname = '\\';
|
|
466
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
467 /* Although Emacs always sets argv[0] to an absolute pathname, we
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
468 might get run in other ways as well, so convert argv[0] to an
|
24516
|
469 absolute name before comparing to the module name. Don't get
|
|
470 caught out by mixed short and long names. */
|
|
471 GetShortPathName (modname, modname, sizeof (modname));
|
|
472 path[0] = '\0';
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
473 if (!SearchPath (NULL, argv[0], ".exe", sizeof (path), path, &progname)
|
24516
|
474 || !GetShortPathName (path, path, sizeof (path))
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
475 || stricmp (modname, path) != 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
476 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
477 /* We are being used as a helper to run a DOS app; just pass
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
478 command line to DOS app without change. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
479 /* TODO: fill in progname. */
|
23947
|
480 if (spawn (NULL, GetCommandLine (), dir, &rc))
|
21598
|
481 return rc;
|
|
482 fail ("Could not run %s\n", GetCommandLine ());
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
483 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
484
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
485 /* Process command line. If running interactively (-c or /c not
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
486 specified) then spawn a real command shell, passing it the command
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
487 line arguments.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
488
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
489 If not running interactively, then attempt to execute the specified
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
490 command directly. If necessary, spawn a real shell to execute the
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
491 command.
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
492
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
493 */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
494
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
495 progname = NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
496 cmdline = NULL;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
497 /* If no args, spawn real shell for interactive use. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
498 need_shell = TRUE;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
499 interactive = TRUE;
|
19718
|
500 /* Ask command.com to create an environment block with a reasonable
|
|
501 amount of free space. */
|
|
502 envsize = get_env_size () + 300;
|
|
503 pass_through_args = (char **) alloca (argc * sizeof(char *));
|
|
504 num_pass_through_args = 0;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
505
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
506 while (--argc > 0)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
507 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
508 ++argv;
|
19718
|
509 /* Act on switches we recognize (mostly single letter switches,
|
|
510 except for -e); all unrecognised switches and extra args are
|
|
511 passed on to real shell if used (only really of benefit for
|
|
512 interactive use, but allow for batch use as well). Accept / as
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
513 switch char for compatability with cmd.exe. */
|
23374
0110032de8b3
(main): Treat command line options as case-insensitive.
Geoff Voelker <voelker@cs.washington.edu>
diff
changeset
|
514 if (((*argv)[0] == '-' || (*argv)[0] == '/') && (*argv)[1] != '\0')
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
515 {
|
23374
0110032de8b3
(main): Treat command line options as case-insensitive.
Geoff Voelker <voelker@cs.washington.edu>
diff
changeset
|
516 if (((*argv)[1] == 'c' || (*argv)[1] == 'C') && ((*argv)[2] == '\0'))
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
517 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
518 if (--argc == 0)
|
19718
|
519 fail ("error: expecting arg for %s\n", *argv);
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
520 cmdline = *(++argv);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
521 interactive = FALSE;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
522 }
|
23374
0110032de8b3
(main): Treat command line options as case-insensitive.
Geoff Voelker <voelker@cs.washington.edu>
diff
changeset
|
523 else if (((*argv)[1] == 'i' || (*argv)[1] == 'I') && ((*argv)[2] == '\0'))
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
524 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
525 if (cmdline)
|
19718
|
526 warn ("warning: %s ignored because of -c\n", *argv);
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
527 }
|
24555
|
528 else if (((*argv)[1] == 'e' || (*argv)[1] == 'E') && ((*argv)[2] == ':'))
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
529 {
|
19718
|
530 int requested_envsize = atoi (*argv + 3);
|
|
531 /* Enforce a reasonable minimum size, as above. */
|
|
532 if (requested_envsize > envsize)
|
|
533 envsize = requested_envsize;
|
|
534 /* For sanity, enforce a reasonable maximum. */
|
|
535 if (envsize > 32768)
|
|
536 envsize = 32768;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
537 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
538 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
539 {
|
19718
|
540 /* warn ("warning: unknown option %s ignored", *argv); */
|
|
541 pass_through_args[num_pass_through_args++] = *argv;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
542 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
543 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
544 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
545 break;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
546 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
547
|
19718
|
548 #if 0
|
|
549 /* I think this is probably not useful - cmd.exe ignores extra
|
|
550 (non-switch) args in interactive mode, and they cannot be passed on
|
|
551 when -c was given. */
|
|
552
|
|
553 /* Collect any remaining args after (initial) switches. */
|
|
554 while (argc-- > 0)
|
|
555 {
|
|
556 pass_through_args[num_pass_through_args++] = *argv++;
|
|
557 }
|
|
558 #else
|
|
559 /* Probably a mistake for there to be extra args; not fatal. */
|
|
560 if (argc > 0)
|
21733
|
561 warn ("warning: extra args ignored after '%s'\n", argv[-1]);
|
19718
|
562 #endif
|
|
563
|
|
564 pass_through_args[num_pass_through_args] = NULL;
|
|
565
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
566 /* If -c option, determine if we must spawn a real shell, or if we can
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
567 execute the command directly ourself. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
568 if (cmdline)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
569 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
570 /* If no redirection or piping, and if program can be found, then
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
571 run program directly. Otherwise invoke a real shell. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
572
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
573 static char copout_chars[] = "|<>&";
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
574
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
575 if (strpbrk (cmdline, copout_chars) == NULL)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
576 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
577 char *args;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
578
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
579 /* The program name is the first token of cmdline. Since
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
580 filenames cannot legally contain embedded quotes, the value
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
581 of escape_char doesn't matter. */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
582 args = cmdline;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
583 if (!get_next_token (path, &args))
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
584 fail ("error: no program name specified.\n");
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
585
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
586 canon_filename (path);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
587 progname = make_absolute (path);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
588
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
589 /* If we found the program, run it directly (if not found it
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
590 might be an internal shell command, so don't fail). */
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
591 if (progname != NULL)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
592 need_shell = FALSE;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
593 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
594 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
595
|
21733
|
596 pass_to_shell:
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
597 if (need_shell)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
598 {
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
599 char * p;
|
19718
|
600 int extra_arg_space = 0;
|
23683
|
601 int run_command_dot_com;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
602
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
603 progname = getenv ("COMSPEC");
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
604 if (!progname)
|
19718
|
605 fail ("error: COMSPEC is not set\n");
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
606
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
607 canon_filename (progname);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
608 progname = make_absolute (progname);
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
609
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
610 if (progname == NULL || strchr (progname, '\\') == NULL)
|
19718
|
611 fail ("error: the program %s could not be found.\n", getenv ("COMSPEC"));
|
|
612
|
23683
|
613 /* Need to set environment size when running command.com. */
|
|
614 run_command_dot_com =
|
|
615 (stricmp (strrchr (progname, '\\'), "command.com") == 0);
|
|
616
|
19718
|
617 /* Work out how much extra space is required for
|
|
618 pass_through_args. */
|
|
619 for (argv = pass_through_args; *argv != NULL; ++argv)
|
|
620 /* We don't expect to have to quote switches. */
|
|
621 extra_arg_space += strlen (*argv) + 2;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
622
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
623 if (cmdline)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
624 {
|
19718
|
625 char * buf;
|
|
626
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
627 /* Convert to syntax expected by cmd.exe/command.com for
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
628 running non-interactively. Always quote program name in
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
629 case path contains spaces (fortunately it can't contain
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
630 quotes, since they are illegal in path names). */
|
19718
|
631
|
|
632 buf = p = alloca (strlen (progname) + extra_arg_space +
|
|
633 strlen (cmdline) + 16);
|
|
634
|
|
635 /* Quote progname in case it contains spaces. */
|
|
636 p += wsprintf (p, "\"%s\"", progname);
|
|
637
|
|
638 /* Include pass_through_args verbatim; these are just switches
|
|
639 so should not need quoting. */
|
|
640 for (argv = pass_through_args; *argv != NULL; ++argv)
|
|
641 p += wsprintf (p, " %s", *argv);
|
|
642
|
23683
|
643 if (run_command_dot_com)
|
21733
|
644 wsprintf(p, " /e:%d /c %s", envsize, cmdline);
|
|
645 else
|
|
646 wsprintf(p, " /c %s", cmdline);
|
19718
|
647 cmdline = buf;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
648 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
649 else
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
650 {
|
23683
|
651 if (run_command_dot_com)
|
21733
|
652 {
|
|
653 /* Provide dir arg expected by command.com when first
|
23683
|
654 started interactively (the "command search path"). To
|
21733
|
655 avoid potential problems with spaces in command dir
|
|
656 (which cannot be quoted - command.com doesn't like it),
|
|
657 we always use the 8.3 form. */
|
|
658 GetShortPathName (progname, path, sizeof (path));
|
|
659 p = strrchr (path, '\\');
|
|
660 /* Trailing slash is acceptable, so always leave it. */
|
|
661 *(++p) = '\0';
|
|
662 }
|
|
663 else
|
|
664 path[0] = '\0';
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
665
|
19718
|
666 cmdline = p = alloca (strlen (progname) + extra_arg_space +
|
|
667 strlen (path) + 13);
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
668
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
669 /* Quote progname in case it contains spaces. */
|
19718
|
670 p += wsprintf (p, "\"%s\" %s", progname, path);
|
|
671
|
|
672 /* Include pass_through_args verbatim; these are just switches
|
|
673 so should not need quoting. */
|
|
674 for (argv = pass_through_args; *argv != NULL; ++argv)
|
|
675 p += wsprintf (p, " %s", *argv);
|
|
676
|
23683
|
677 if (run_command_dot_com)
|
21733
|
678 wsprintf (p, " /e:%d", envsize);
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
679 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
680 }
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
681
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
682 if (!progname)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
683 fail ("Internal error: program name not defined\n");
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
684
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
685 if (!cmdline)
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
686 cmdline = progname;
|
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
687
|
23947
|
688 if (spawn (progname, cmdline, dir, &rc))
|
21598
|
689 return rc;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
690
|
21598
|
691 if (!need_shell)
|
|
692 {
|
|
693 need_shell = TRUE;
|
|
694 goto pass_to_shell;
|
|
695 }
|
|
696
|
|
697 fail ("Could not run %s\n", progname);
|
|
698
|
|
699 return 0;
|
19236
Geoff Voelker <voelker@cs.washington.edu>
parents:
diff
changeset
|
700 }
|