wasCSharpSQLite – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * ExecCmd.java --
3 *
4 * This file contains the Jacl implementation of the built-in Tcl "exec"
5 * command. The exec command is not available on the Mac.
6 *
7 * Copyright (c) 1997 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and
10 * redistribution of this file, and for a DISCLAIMER OF ALL
11 * WARRANTIES.
12 *
13 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
14 *
15 * RCS @(#) $Id: ExecCmd.java,v 1.8 2002/01/19 00:15:01 mdejong Exp $
16 */
17 using System;
18 using System.Diagnostics;
19 using System.IO;
20 using System.Text;
21  
22 namespace tcl.lang
23 {
24  
25  
26 /*
27 * This class implements the built-in "exec" command in Tcl.
28 */
29  
30 class ExecCmd : Command
31 {
32  
33 /// <summary> Reference to Runtime.exec, null when JDK < 1.3</summary>
34 private static System.Reflection.MethodInfo execMethod;
35  
36 public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
37 {
38 int firstWord; /* Index to the first non-switch arg */
39 int argLen = argv.Length; /* No of args to copy to argStrs */
40 int exit; /* denotes exit status of process */
41 int errorBytes = 0; /* number of bytes of process stderr */
42 //bool background; /* Indicates a bg process */
43 //bool keepNewline; /* Retains newline in pipline output */
44 System.Diagnostics.Process p; /* The exec-ed process */
45 string argStr; /* Conversion of argv to a string */
46 StringBuilder sbuf;
47  
48 /*
49 * Check for a leading "-keepnewline" argument.
50 */
51  
52 for ( firstWord = 1; firstWord < argLen; firstWord++ )
53 {
54 argStr = argv[firstWord].ToString();
55 if ( ( argStr.Length > 0 ) && ( argStr[0] == '-' ) )
56 {
57 //if (argStr.Equals("-keepnewline"))
58 //{
59 // keepNewline = true;
60 //}
61 //else
62 if ( argStr.Equals( "--" ) )
63 {
64 firstWord++;
65 break;
66 }
67 else
68 {
69 throw new TclException( interp, "bad switch \"" + argStr + "\": must be -keepnewline or --" );
70 }
71 }
72 }
73  
74 if ( argLen <= firstWord )
75 {
76 throw new TclNumArgsException( interp, 1, argv, "?switches? arg ?arg ...?" );
77 }
78  
79  
80 /*
81 * See if the command is to be run in background.
82 * Currently this does nothing, it is just for compatibility
83 */
84  
85  
86 //if (argv[argLen - 1].ToString().Equals("&"))
87 //{
88 // argLen--;
89 // background = true;
90 //}
91  
92 try
93 {
94 /*
95 * It is necessary to perform system specific
96 * operations before calling exec. For now Solaris
97 * and Windows execs are somewhat supported, in all other cases
98 * we simply call exec and give it our "best shot"
99 */
100  
101 if ( execMethod != null )
102 {
103 p = execReflection( interp, argv, firstWord, argLen );
104 }
105 else if ( Util.Unix )
106 {
107 p = execUnix( interp, argv, firstWord, argLen );
108 }
109 else if ( Util.Windows )
110 {
111 p = execWin( interp, argv, firstWord, argLen );
112 }
113 else
114 {
115 p = execDefault( interp, argv, firstWord, argLen );
116 }
117  
118  
119 //note to self : buffer reading should be done in
120 //a separate thread and not by calling waitFor()
121 //because a process that is waited for can block
122  
123  
124 //Wait for the process to finish running,
125 try
126 {
127 p.Start();
128 p.WaitForExit();
129 exit = p.ExitCode;
130 }
131 catch ( Exception e )
132 {
133 throw new TclException( interp, "exception in exec process: " + e.Message );
134 }
135  
136  
137 //Make buffer for the results of the subprocess execution
138 sbuf = new StringBuilder();
139  
140 //read data on stdout stream into result buffer
141 readStreamIntoBuffer( p.StandardOutput.BaseStream, sbuf );
142  
143 //if there is data on the stderr stream then append
144 //this data onto the result StringBuffer
145 //check for the special case where there is no error
146 //data but the process returns an error result
147  
148 errorBytes = readStreamIntoBuffer( p.StandardError.BaseStream, sbuf );
149  
150 if ( ( errorBytes == 0 ) && ( exit != 0 ) )
151 {
152 sbuf.Append( "child process exited abnormally" );
153 }
154  
155 //If the last character of the result buffer is a newline, then
156 //remove the newline character (the newline would just confuse
157 //things). Finally, we set pass the result to the interpreter.
158  
159  
160  
161 // Tcl supports lots of child status conditions.
162 // Unfortunately, we can only find the child's
163 // exit status using the Java API
164  
165 if ( exit != 0 )
166 {
167 TclObject childstatus = TclList.newInstance();
168 TclList.append( interp, childstatus, TclString.newInstance( "CHILDSTATUS" ) );
169  
170 // We don't know how to find the child's pid
171 TclList.append( interp, childstatus, TclString.newInstance( "?PID?" ) );
172  
173 TclList.append( interp, childstatus, TclInteger.newInstance( exit ) );
174  
175 interp.setErrorCode( childstatus );
176 }
177  
178 //when the subprocess writes to its stderr stream or returns
179 //a non zero result we generate an error
180 if ( ( exit != 0 ) || ( errorBytes != 0 ) )
181 {
182 throw new TclException( interp, sbuf.ToString() );
183 }
184  
185 //otherwise things went well so set the result
186 interp.setResult( sbuf.ToString() );
187 }
188 catch ( IOException e )
189 {
190 //if exec fails we end up catching the exception here
191  
192  
193 throw new TclException( interp, "couldn't execute \"" + argv[firstWord].ToString() + "\": no such file or directory" );
194 }
195 catch ( System.Threading.ThreadInterruptedException e )
196 {
197 /*
198 * Do Nothing...
199 */
200 }
201 return TCL.CompletionCode.RETURN;
202 }
203  
204  
205 internal static int readStreamIntoBuffer( Stream in_Renamed, StringBuilder sbuf )
206 {
207 int numRead = 0;
208 StreamReader br = new StreamReader( new StreamReader( in_Renamed ).BaseStream, System.Text.Encoding.UTF7 );
209  
210 try
211 {
212 string line = br.ReadLine();
213  
214 while ( (System.Object)line != null )
215 {
216 sbuf.Append( line );
217 numRead += line.Length;
218 sbuf.Append( '\n' );
219 numRead++;
220 line = br.ReadLine();
221 }
222 }
223 catch ( IOException e )
224 {
225 //do nothing just return numRead
226 }
227 finally
228 {
229 try
230 {
231 br.Close();
232 }
233 catch ( IOException e )
234 {
235 } //ignore IO error
236 }
237  
238 return numRead;
239 }
240  
241  
242 internal static string escapeWinString( string str )
243 {
244 if ( str.IndexOf( (System.Char)'%' ) == -1 )
245 return str;
246  
247 char[] arr = str.ToCharArray();
248 StringBuilder sb = new StringBuilder( 50 );
249  
250 for ( int i = 0; i < arr.Length; i++ )
251 {
252 if ( arr[i] == '%' )
253 {
254 sb.Append( '%' );
255 }
256 sb.Append( arr[i] );
257 }
258  
259 return sb.ToString();
260 }
261  
262  
263 private System.Diagnostics.Process execUnix( Interp interp, TclObject[] argv, int first, int last )
264 {
265 return execWin( interp, argv, first, last );
266 }
267  
268 private System.Diagnostics.Process execWin( Interp interp, TclObject[] argv, int first, int last )
269 {
270 StringBuilder sb = new StringBuilder();
271 for ( int i = ( first + 1 ); i < last; i++ )
272 {
273 sb.Append( '"' );
274 sb.Append( escapeWinString( argv[i].ToString() ) );
275 sb.Append( '"' );
276 sb.Append( ' ' );
277 }
278  
279 Process proc = new Process();
280 proc.StartInfo.UseShellExecute = false;
281 proc.StartInfo.RedirectStandardOutput = true;
282 proc.StartInfo.RedirectStandardError = true;
283 proc.StartInfo.RedirectStandardInput = true;
284 proc.StartInfo.WorkingDirectory = interp.getWorkingDir().FullName;
285 proc.StartInfo.FileName = argv[first].ToString();
286 proc.StartInfo.Arguments = sb.ToString();
287 return proc;
288 }
289  
290 private System.Diagnostics.Process execDefault( Interp interp, TclObject[] argv, int first, int last )
291 {
292 return execWin( interp, argv, first, last );
293 }
294  
295 private System.Diagnostics.Process execReflection( Interp interp, TclObject[] argv, int first, int last )
296 {
297  
298 string[] strv = new string[last - first];
299  
300 for ( int i = first, j = 0; i < last; j++, i++ )
301 {
302  
303 strv[j] = argv[i].ToString();
304 }
305  
306 Object[] methodArgs = new Object[3];
307 methodArgs[0] = strv; // exec command arguments
308 methodArgs[1] = null; // inherit all environment variables
309 methodArgs[2] = interp.getWorkingDir();
310  
311 try
312 {
313 return (System.Diagnostics.Process)execMethod.Invoke( System.Diagnostics.Process.GetCurrentProcess(), (System.Object[])methodArgs );
314 }
315 catch ( System.UnauthorizedAccessException ex )
316 {
317 throw new TclRuntimeError( "IllegalAccessException in execReflection" );
318 }
319 catch ( System.ArgumentException ex )
320 {
321 throw new TclRuntimeError( "IllegalArgumentException in execReflection" );
322 }
323 catch ( System.Reflection.TargetInvocationException ex )
324 {
325 System.Exception t = ex.GetBaseException();
326  
327 if ( t is System.ApplicationException )
328 {
329 throw (System.ApplicationException)t;
330 }
331 else if ( t is IOException )
332 {
333 throw (IOException)t;
334 }
335 else
336 {
337 throw new TclRuntimeError( "unexected exception in execReflection" );
338 }
339 }
340 }
341 static ExecCmd()
342 {
343 {
344 // Runtime.exec(String[] cmdArr, String[] envArr, File currDir)
345 Type[] parameterTypes = new Type[] { typeof( string[] ), typeof( string[] ), typeof( FileInfo ) };
346 try
347 {
348 execMethod = System.Diagnostics.Process.GetCurrentProcess().GetType().GetMethod( "exec", (System.Type[])parameterTypes );
349 }
350 catch ( System.MethodAccessException e )
351 {
352 execMethod = null;
353 }
354 }
355 }
356 } // end ExecCmd
357 }