📄 execnt.c
字号:
string_copy(&cmd,*(argp++)); while( *argp != 0 ) { string_push_back(&cmd,' '); string_append(&cmd,*(argp++)); } } /* create the output buffers */ string_new( &cmdtab[ slot ].buffer_out ); string_new( &cmdtab[ slot ].buffer_err ); /* run the command, by creating a sub-process for it */ if ( ! CreateProcess( NULL, /* application name */ cmd.value, /* command line */ NULL, /* process attributes */ NULL, /* thread attributes */ TRUE, /* inherit handles */ CREATE_NEW_PROCESS_GROUP, /* create flags */ NULL, /* env vars, null inherits env */ NULL, /* current dir, null is our current dir */ &si, /* startup info */ &cmdtab[ slot ].pi /* the child process info, if created */ ) ) { perror( "CreateProcess" ); exit( EXITBAD ); } /* clean up temporary stuff */ string_free(&cmd); } /* Wait until we're under the limit of concurrent commands. */ /* Don't trust globs.jobs alone. */ while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs ) if( !execwait() ) break; if (argv != argv_static) { free_argv(argv); }}/* execwait() - wait and drive at most one execution completion * waits for one command to complete, while processing the io for all ongoing commands.*/int execwait(){ int i = -1; /* Handle naive make1() which doesn't know if cmds are running. */ if( !cmdsrunning ) return 0; /* wait for a command to complete, while snarfing up any output */ do { /* read in the output of all running commands */ read_output(); /* close out pending debug style dialogs */ close_alerts(); /* check for a complete command, briefly */ if ( i < 0 ) i = try_wait(500); /* check if a command ran out of time */ if ( i < 0 ) i = try_kill_one(); } while ( i < 0 ); /* we have a command... process it */ --cmdsrunning; { timing_info time; int rstat; /* the time data for the command */ record_times(cmdtab[i].pi.hProcess, &time); /* Clear the temp file */ if ( cmdtab[i].tempfile_bat ) { unlink( cmdtab[ i ].tempfile_bat ); BJAM_FREE(cmdtab[i].tempfile_bat); cmdtab[i].tempfile_bat = NULL; } /* the dispossition of the command */ if( intr ) rstat = EXEC_CMD_INTR; else if( cmdtab[i].exitcode != 0 ) rstat = EXEC_CMD_FAIL; else rstat = EXEC_CMD_OK; /* output the action block */ out_action( cmdtab[i].action.size > 0 ? cmdtab[i].action.value : 0, cmdtab[i].target.size > 0 ? cmdtab[i].target.value : 0, cmdtab[i].command.size > 0 ? cmdtab[i].command.value : 0, cmdtab[i].buffer_out.size > 0 ? cmdtab[i].buffer_out.value : 0, cmdtab[i].buffer_err.size > 0 ? cmdtab[i].buffer_err.value : 0, cmdtab[i].exit_reason); /* call the callback, may call back to jam rule land. assume -p0 in effect so only pass buffer containing merged output */ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time, cmdtab[i].command.value, cmdtab[i].buffer_out.value ); /* clean up the command data, process, etc. */ string_free(&cmdtab[i].action); string_new(&cmdtab[i].action); string_free(&cmdtab[i].target); string_new(&cmdtab[i].target); string_free(&cmdtab[i].command); string_new(&cmdtab[i].command); if (cmdtab[i].pi.hProcess) { CloseHandle(cmdtab[i].pi.hProcess); cmdtab[i].pi.hProcess = 0; } if (cmdtab[i].pi.hThread) { CloseHandle(cmdtab[i].pi.hThread); cmdtab[i].pi.hThread = 0; } if (cmdtab[i].pipe_out[0]) { CloseHandle(cmdtab[i].pipe_out[0]); cmdtab[i].pipe_out[0] = 0; } if (cmdtab[i].pipe_out[1]) { CloseHandle(cmdtab[i].pipe_out[1]); cmdtab[i].pipe_out[1] = 0; } if (cmdtab[i].pipe_err[0]) { CloseHandle(cmdtab[i].pipe_err[0]); cmdtab[i].pipe_err[0] = 0; } if (cmdtab[i].pipe_err[1]) { CloseHandle(cmdtab[i].pipe_err[1]); cmdtab[i].pipe_err[1] = 0; } string_free(&cmdtab[i].buffer_out); string_new(&cmdtab[i].buffer_out); string_free(&cmdtab[i].buffer_err); string_new(&cmdtab[i].buffer_err); cmdtab[i].exitcode = 0; cmdtab[i].exit_reason = EXIT_OK; } return 1;}/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */static void free_argv( char** args ){ BJAM_FREE( args[0] ); BJAM_FREE( args );}int maxline(){ OSVERSIONINFO os_info; os_info.dwOSVersionInfoSize = sizeof(os_info); GetVersionEx(&os_info); return (os_info.dwMajorVersion == 3) ? 996 /* NT 3.5.1 */ : 2047 /* NT >= 4.x */ ;}/* Convert a command string into arguments for spawnvp. The original * code, inherited from ftjam, tried to break up every argument on the * command-line, dealing with quotes, but that's really a waste of * time on Win32, at least. It turns out that all you need to do is * get the raw path to the executable in the first argument to * spawnvp, and you can pass all the rest of the command-line * arguments to spawnvp in one, un-processed string. * * New strategy: break the string in at most one place. */static char** string_to_args( const char* string ){ int src_len; int in_quote; char* line; char const* src; char* dst; char** argv; /* drop leading and trailing whitespace if any */ while (isspace(*string)) ++string; src_len = strlen( string ); while ( src_len > 0 && isspace( string[src_len - 1] ) ) --src_len; /* Copy the input string into a buffer we can modify */ line = (char*)BJAM_MALLOC_ATOMIC( src_len+1 ); if (!line) return 0; /* allocate the argv array. * element 0: stores the path to the executable * element 1: stores the command-line arguments to the executable * element 2: NULL terminator */ argv = (char**)BJAM_MALLOC( 3 * sizeof(char*) ); if (!argv) { BJAM_FREE( line ); return 0; } /* Strip quotes from the first command-line argument and find * where it ends. Quotes are illegal in Win32 pathnames, so we * don't need to worry about preserving escaped quotes here. * Spaces can't be escaped in Win32, only enclosed in quotes, so * removing backslash escapes is also a non-issue. */ in_quote = 0; for ( src = string, dst = line ; *src; src++ ) { if (*src == '"') in_quote = !in_quote; else if (!in_quote && isspace(*src)) break; else *dst++ = *src; } *dst++ = 0; argv[0] = line; /* skip whitespace in src */ while (isspace(*src)) ++src; argv[1] = dst; /* Copy the rest of the arguments verbatim */ src_len -= src - string; /* Use strncat because it appends a trailing nul */ *dst = 0; strncat(dst, src, src_len); argv[2] = 0; return argv;}static void onintr( int disp ){ intr++; printf( "...interrupted\n" );}/* * can_spawn() - If the command is suitable for execution via spawnvp, * return a number >= the number of characters it would occupy on the * command-line. Otherwise, return zero. */long can_spawn(char* command){ char *p; char inquote = 0; /* Move to the first non-whitespace */ command += strspn( command, " \t" ); p = command; /* Look for newlines and unquoted i/o redirection */ do { p += strcspn( p, "'\n\"<>|" ); switch (*p) { case '\n': /* skip over any following spaces */ while( isspace( *p ) ) ++p; /* Must use a .bat file if there is anything significant * following the newline */ if (*p) return 0; break; case '"': case '\'': if (p > command && p[-1] != '\\') { if (inquote == *p) inquote = 0; else if (inquote == 0) inquote = *p; } ++p; break; case '<': case '>': case '|': if (!inquote) return 0; ++p; break; } } while (*p); /* Return the number of characters the command will occupy */ return p - command;}/* 64-bit arithmetic helpers *//* Compute the carry bit from the addition of two 32-bit unsigned numbers */#define add_carry_bit(a, b) ( (((a) | (b)) >> 31) & (~((a) + (b)) >> 31) & 0x1 )/* Compute the high 32 bits of the addition of two 64-bit unsigned numbers, h1l1 and h2l2 */#define add_64_hi(h1, l1, h2, l2) ((h1) + (h2) + add_carry_bit(l1, l2))/* Add two 64-bit unsigned numbers, h1l1 and h2l2 */static FILETIME add_64( unsigned long h1, unsigned long l1, unsigned long h2, unsigned long l2){ FILETIME result; result.dwLowDateTime = l1 + l2; result.dwHighDateTime = add_64_hi(h1, l1, h2, l2); return result;}static FILETIME add_FILETIME(FILETIME t1, FILETIME t2){ return add_64( t1.dwHighDateTime, t1.dwLowDateTime , t2.dwHighDateTime, t2.dwLowDateTime);}static FILETIME negate_FILETIME(FILETIME t){ /* 2s complement negation */ return add_64(~t.dwHighDateTime, ~t.dwLowDateTime, 0, 1);}/* Convert a FILETIME to a number of seconds */static double filetime_seconds(FILETIME t){ return t.dwHighDateTime * ((double)(1UL << 31) * 2.0 * 1.0e-7) + t.dwLowDateTime * 1.0e-7;}/* What should be a simple conversion, turns out to be horribly complicated by the defficiencies of MSVC and the Win32 API. */static time_t filetime_dt(FILETIME t_utc){ static int calc_time_diff = 1; static double time_diff; if ( calc_time_diff ) { struct tm t0_; FILETIME f0_local,f0_; SYSTEMTIME s0_; GetSystemTime(&s0_); t0_.tm_year = s0_.wYear-1900; t0_.tm_mon = s0_.wMonth-1; t0_.tm_wday = s0_.wDayOfWeek; t0_.tm_mday = s0_.wDay; t0_.tm_hour = s0_.wHour; t0_.tm_min = s0_.wMinute; t0_.tm_sec = s0_.wSecond; t0_.tm_isdst = 0; SystemTimeToFileTime(&s0_,&f0_local); LocalFileTimeToFileTime(&f0_local,&f0_); time_diff = filetime_seconds(f0_)-((double)mktime(&t0_)); calc_time_diff = 0; } return ceil(filetime_seconds(t_utc)-time_diff);}static void record_times(HANDLE process, timing_info* time){ FILETIME creation, exit, kernel, user; if (GetProcessTimes(process, &creation, &exit, &kernel, &user)) { time->system = filetime_seconds(kernel); time->user = filetime_seconds(user); time->start = filetime_dt(creation); time->end = filetime_dt(exit); }}#define IO_BUFFER_SIZE (16*1024)static char ioBuffer[IO_BUFFER_SIZE+1];static void read_pipe( HANDLE in, /* the pipe to read from */ string * out ){ DWORD bytesInBuffer = 0; DWORD bytesAvailable = 0; do { /* check if we have any data to read */ if ( ! PeekNamedPipe( in, ioBuffer, IO_BUFFER_SIZE, &bytesInBuffer, &bytesAvailable, NULL ) ) { bytesAvailable = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -