public TCL.CompletionCode CmdProc(Interp interp, TclObject[] argv) { int firstWord; /* Index to the first non-switch arg */ int argLen = argv.Length; /* No of args to copy to argStrs */ int exit; /* denotes exit status of process */ int errorBytes = 0; /* number of bytes of process stderr */ //bool background; /* Indicates a bg process */ //bool keepNewline; /* Retains newline in pipline output */ System.Diagnostics.Process p; /* The exec-ed process */ string argStr; /* Conversion of argv to a string */ StringBuilder sbuf; /* * Check for a leading "-keepnewline" argument. */ for (firstWord = 1; firstWord < argLen; firstWord++) { argStr = argv[firstWord].ToString(); if ((argStr.Length > 0) && (argStr[0] == '-')) { //if (argStr.Equals("-keepnewline")) //{ // keepNewline = true; //} //else if (argStr.Equals("--")) { firstWord++; break; } else { throw new TclException(interp, "bad switch \"" + argStr + "\": must be -keepnewline or --"); } } } if (argLen <= firstWord) { throw new TclNumArgsException(interp, 1, argv, "?switches? arg ?arg ...?"); } /* * See if the command is to be run in background. * Currently this does nothing, it is just for compatibility */ //if (argv[argLen - 1].ToString().Equals("&")) //{ // argLen--; // background = true; //} try { /* * It is necessary to perform system specific * operations before calling exec. For now Solaris * and Windows execs are somewhat supported, in all other cases * we simply call exec and give it our "best shot" */ if (execMethod != null) { p = execReflection(interp, argv, firstWord, argLen); } else if (Util.Unix) { p = execUnix(interp, argv, firstWord, argLen); } else if (Util.Windows) { p = execWin(interp, argv, firstWord, argLen); } else { p = execDefault(interp, argv, firstWord, argLen); } //note to self : buffer reading should be done in //a separate thread and not by calling waitFor() //because a process that is waited for can block //Wait for the process to finish running, try { p.Start(); p.WaitForExit(); exit = p.ExitCode; } catch (Exception e) { throw new TclException(interp, "exception in exec process: " + e.Message); } //Make buffer for the results of the subprocess execution sbuf = new StringBuilder(); //read data on stdout stream into result buffer readStreamIntoBuffer(p.StandardOutput.BaseStream, sbuf); //if there is data on the stderr stream then append //this data onto the result StringBuffer //check for the special case where there is no error //data but the process returns an error result errorBytes = readStreamIntoBuffer(p.StandardError.BaseStream, sbuf); if ((errorBytes == 0) && (exit != 0)) { sbuf.Append("child process exited abnormally"); } //If the last character of the result buffer is a newline, then //remove the newline character (the newline would just confuse //things). Finally, we set pass the result to the interpreter. // Tcl supports lots of child status conditions. // Unfortunately, we can only find the child's // exit status using the Java API if (exit != 0) { TclObject childstatus = TclList.NewInstance(); TclList.Append(interp, childstatus, TclString.NewInstance("CHILDSTATUS")); // We don't know how to find the child's pid TclList.Append(interp, childstatus, TclString.NewInstance("?PID?")); TclList.Append(interp, childstatus, TclInteger.NewInstance(exit)); interp.SetErrorCode(childstatus); } //when the subprocess writes to its stderr stream or returns //a non zero result we generate an error if ((exit != 0) || (errorBytes != 0)) { throw new TclException(interp, sbuf.ToString()); } //otherwise things went well so set the result interp.SetResult(sbuf.ToString()); } catch (IOException e) { //if exec fails we end up catching the exception here throw new TclException(interp, "couldn't execute \"" + argv[firstWord].ToString() + "\": no such file or directory"); } catch (System.Threading.ThreadInterruptedException e) { /* * Do Nothing... */ } return TCL.CompletionCode.RETURN; }