qzdoom/ccdv-win32.c

743 lines
19 KiB
C
Raw Normal View History

/* ccdv.c */
/* Ported to Win32 by Randy Heit
* Maybe I got a little carried away. This is pure Win32 code without any CRT in sight.
*
* To build this, use one of these command lines:
*
* [MinGW] gcc -Os -s -nostdlib -o ccdv.exe ccdv-win32.c -lkernel32 -luser32
* [MSC] cl -O1 ccdv-win32.c -link -subsystem:console -opt:nowin98 kernel32.lib user32.lib
*
* Rewriting this to not use any global variables can save 512 bytes when compiled with MSC
* because it allows the .data section to be ommitted, which means the header can occupy
* 512 bytes rather than 1024. With GCC, it doesn't help the size any, since GCC still has
* the separate .idata and .rdata sections. Since MSC really doesn't need this tool,
* I'm not bothering with that size optimization.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define COLOR_SUCCESS (FOREGROUND_GREEN|FOREGROUND_INTENSITY) /* green */
#define COLOR_FAILURE (FOREGROUND_RED|FOREGROUND_INTENSITY) /* red */
#define COLOR_WARNING (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY) /* yellow */
#define COLOR_COMMAND (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY) /* cyan */
#define COLOR_ERROROUTPUT (FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY) /* magenta */
#define COLOR_WARNINGOUTPUT (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY) /* white */
#define SETCOLOR_SUCCESS "\033[1;32m" /* green */
#define SETCOLOR_FAILURE "\033[1;31m" /* red */
#define SETCOLOR_WARNING "\033[0;33m" /* dark yellow */
#define SETCOLOR_COMMAND "\033[1;35m" /* magenta */
#define SETCOLOR_ERROROUTPUT "\033[1;31m" /* red */
#define SETCOLOR_WARNINGOUTPUT "\033[1;39m" /* bold */
#define SETCOLOR_NORMAL "\033[0;39m" /* normal */
#define TEXT_BLOCK_SIZE 8192
#define INDENT 2
PROCESS_INFORMATION gCCP;
size_t gNBufUsed, gNBufAllocated;
char *gBuf;
char *gAction;
char *gTarget;
char *gAr;
char *gArLibraryTarget;
BOOL gDumpCmdArgs;
char *gArgsStr;
int gColumns;
BOOL gRxvt;
int gExitStatus;
HANDLE gHeap;
HANDLE gStdOut, gStdErr;
#ifdef __GNUC__
#define REGPARM(x) __attribute((regparm(x)))
#else
#define REGPARM(x)
#endif
void REGPARM(1) perror(const char *string)
{
char *buffer;
char errcode[9];
DWORD error = GetLastError();
DWORD len = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, 0, (LPTSTR)&buffer, 0, NULL);
DWORD wrote;
WriteFile (gStdErr, string, lstrlen(string), &wrote, NULL);
wsprintf(errcode, "%08x", error);
WriteFile (gStdErr, ": Error 0x", 10, &wrote, NULL);
WriteFile (gStdErr, errcode, 8, &wrote, NULL);
if(len != 0)
{
WriteFile (gStdErr, "\n", 1, &wrote, NULL);
WriteFile (gStdErr, buffer, len, &wrote, NULL);
LocalFree(buffer);
}
WriteFile (gStdErr, "\n", 1, &wrote, NULL);
gColumns = 0;
}
static int REGPARM(1) str2int(const char *string)
{
int out = 0;
while (*string >= '0' && *string <= '9')
{
out = out * 10 + *string++ - '0';
}
return out;
}
static void Writef(HANDLE hFile, const char *fmt, ...)
{
char buf[1024];
int buflen;
va_list arglist;
DWORD wrote;
va_start(arglist, fmt);
buflen = wvsprintf(buf, fmt, arglist);
va_end(arglist);
WriteFile(hFile, buf, buflen, &wrote, NULL);
}
static void DumpFormattedOutput()
{
CONSOLE_SCREEN_BUFFER_INFO info;
DWORD out;
WORD color;
char *cp;
char spaces[8 + 1];
char *saved;
int curcol;
int i;
for(i = 0; i < 8; ++i)
{
spaces[i] = ' ';
}
spaces[i] = '\0';
if(gRxvt)
{
curcol = 0;
saved = NULL;
if(gDumpCmdArgs)
{
Writef(gStdOut, SETCOLOR_COMMAND "%s" SETCOLOR_NORMAL "\n", gArgsStr);
for(i = gColumns; i > 0; i -= 7)
{
WriteFile(gStdOut, "=======", i > 7 ? 7 : i, &out, NULL);
}
WriteFile(gStdOut, SETCOLOR_ERROROUTPUT, sizeof(SETCOLOR_ERROROUTPUT), &out, NULL);
}
else
{
WriteFile(gStdOut, SETCOLOR_WARNINGOUTPUT, sizeof(SETCOLOR_WARNINGOUTPUT), &out, NULL);
}
WriteFile(gStdOut, gBuf + lstrlen(gArgsStr), lstrlen(gBuf + lstrlen(gArgsStr)), &out, NULL);
WriteFile(gStdOut, SETCOLOR_NORMAL, sizeof(SETCOLOR_NORMAL), &out, NULL);
HeapFree(gHeap, 0, gBuf);
return;
}
if(!GetConsoleScreenBufferInfo(gStdOut, &info))
{
WriteFile(gStdOut, gBuf, lstrlen(gBuf), &out, NULL);
WriteFile(gStdOut, "\n", 1, &out, NULL);
HeapFree(gHeap, 0, gBuf);
return;
}
color = info.wAttributes & ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
curcol = 0;
saved = NULL;
if(gDumpCmdArgs)
{
SetConsoleTextAttribute(gStdOut, color | COLOR_COMMAND);
WriteConsole(gStdOut, gBuf, lstrlen(gArgsStr)+1, &out, NULL);
SetConsoleTextAttribute(gStdOut, info.wAttributes);
for(i = gColumns; i > 0; i -= 7)
{
WriteConsole(gStdOut, "=======", i > 7 ? 7 : i, &out, NULL);
}
color |= COLOR_ERROROUTPUT;
}
else
{
color |= COLOR_WARNINGOUTPUT;
}
SetConsoleTextAttribute(gStdOut, color);
WriteConsole(gStdOut, gBuf + lstrlen(gArgsStr) + 1, lstrlen(gBuf + lstrlen(gArgsStr) + 1), &out, NULL);
SetConsoleTextAttribute(gStdOut, info.wAttributes);
HeapFree(gHeap, 0, gBuf);
} /* DumpFormattedOutput */
static void Wait(void)
{
DWORD exitcode;
WaitForSingleObject(gCCP.hProcess, INFINITE);
GetExitCodeProcess(gCCP.hProcess, &exitcode);
gExitStatus = (int)exitcode;
} /* Wait */
static DWORD WINAPI SlurpThread(LPVOID foo)
{
HANDLE fd = (HANDLE)foo;
char *newbuf;
DWORD ntoread;
DWORD nread;
for(;;)
{
if(gNBufUsed == (gNBufAllocated - 1))
{
if((newbuf =
(char *) HeapReAlloc(gHeap, 0, gBuf,
gNBufAllocated + TEXT_BLOCK_SIZE)) == NULL)
{
return 1;
}
gNBufAllocated += TEXT_BLOCK_SIZE;
gBuf = newbuf;
}
ntoread = (gNBufAllocated - gNBufUsed - 1);
if(!ReadFile(fd, gBuf + gNBufUsed, ntoread, &nread, NULL))
{
return 2;
}
else if(nread > 0)
{
gNBufUsed += nread;
gBuf[gNBufUsed] = '\0';
}
}
return 0;
}
static void REGPARM(2) WriteAction(HANDLE hStdOut, const char *suffix)
{
DWORD out;
WriteFile(hStdOut, gAction, lstrlen(gAction), &out, NULL);
if(gTarget != NULL)
{
WriteFile(hStdOut, " ", 1, &out, NULL);
WriteFile(hStdOut, gTarget, lstrlen(gTarget), &out, NULL);
}
WriteFile(hStdOut, suffix, 3, &out, NULL);
}
static int REGPARM(2) Slurp(HANDLE fd, HANDLE hStdOut)
{
HANDLE handles[2];
DWORD waitstate;
DWORD exitcode;
DWORD out;
DWORD threadid;
const char *trail = "/-\\|", *trailcp;
CONSOLE_SCREEN_BUFFER_INFO info;
CONSOLE_CURSOR_INFO cursorInfo;
WORD color, colors[5];
int ncells, i;
trailcp = trail;
if(hStdOut != NULL)
{
WriteAction(hStdOut, "...");
}
handles[0] = gCCP.hProcess;
handles[1] = CreateThread(NULL, 0, SlurpThread, (LPVOID)fd, 0, &threadid);
if(handles[1] == 0)
{
perror("ccdv: CreateThread");
return -1;
}
if(hStdOut != NULL)
{
if(!gRxvt)
{
GetConsoleScreenBufferInfo(hStdOut, &info);
info.dwCursorPosition.X = info.dwSize.X - 9;
}
if(GetConsoleCursorInfo(hStdOut, &cursorInfo))
{
cursorInfo.bVisible = FALSE;
SetConsoleCursorInfo(hStdOut, &cursorInfo);
}
else
{
cursorInfo.bVisible = TRUE;
}
}
gExitStatus = 0xabadcafe;
while(gExitStatus == 0xabadcafe)
{
waitstate = WaitForMultipleObjects(2, handles, FALSE, 1000);
switch(waitstate)
{
case WAIT_TIMEOUT:
if(hStdOut != NULL)
{
if(!gRxvt)
{
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
WriteConsoleA(hStdOut, trailcp, 1, &out, NULL);
}
else
{
Writef(hStdOut, "\033[999C\033[9D%c", *trailcp);
}
if(*++trailcp == '\0')
trailcp = trail;
}
break;
case WAIT_FAILED:
perror("ccdv: WaitForMultipleObjects");
CloseHandle(handles[1]);
return -1;
case WAIT_OBJECT_0:
GetExitCodeProcess(gCCP.hProcess, &exitcode);
CloseHandle(handles[1]);
gExitStatus = (int)exitcode;
break;
case WAIT_OBJECT_0+1:
GetExitCodeThread(handles[1], &exitcode);
CloseHandle(handles[1]);
if(exitcode == 1)
{
perror("ccdv: HeapReAlloc");
return -1;
}
else if(exitcode == 2)
{
perror("ccdv: ReadFile");
return -1;
}
Wait();
break;
}
}
if(hStdOut != NULL)
{
if(!gRxvt)
{
info.dwCursorPosition.X = 0;
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
WriteAction(hStdOut, ": ");
info.dwCursorPosition.X = info.dwSize.X - 10;
if(gExitStatus == 0)
{
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
WriteConsoleA(hStdOut, "[OK] ", 9, &out, NULL);
color = ((gNBufUsed - lstrlen(gArgsStr)) < 4) ? COLOR_SUCCESS : COLOR_WARNING;
ncells = 2;
}
else
{
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
WriteConsoleA(hStdOut, "[ERROR] ", 9, &out, NULL);
color = COLOR_FAILURE;
ncells = 5;
gDumpCmdArgs = 1; /* print cmd when there are errors */
}
color |= info.wAttributes & ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
for(i = 0; i < ncells; ++i)
{
colors[i] = color;
}
info.dwCursorPosition.X++;
WriteConsoleOutputAttribute(hStdOut, colors, ncells, info.dwCursorPosition, &out);
if(!cursorInfo.bVisible)
{
cursorInfo.bVisible = TRUE;
SetConsoleCursorInfo(hStdOut, &cursorInfo);
}
WriteConsole(hStdOut, "\n", 1, &out, NULL);
}
else
{
WriteFile(hStdOut, "\033[255D", 6, &out, NULL);
WriteAction(hStdOut, ": ");
if(gExitStatus == 0)
{
Writef(hStdOut, "\033[999C\033[10D[%sOK%s]",
((gNBufUsed - strlen(gArgsStr)) <
4) ? SETCOLOR_SUCCESS : SETCOLOR_WARNING, SETCOLOR_NORMAL);
}
else
{
Writef(hStdOut, "\033[999C\033[10D[%sERROR%s]\n",
SETCOLOR_FAILURE, SETCOLOR_NORMAL);
gDumpCmdArgs = 1; /* print cmd when there are errors */
}
}
}
else
{
gDumpCmdArgs = (gExitStatus != 0); /* print cmd when there are errors */
}
return (0);
} /* SlurpProgress */
static const char *REGPARM(2) Basename(const char *path, int len)
{
while(len > 0)
{
len--;
if(path[len] == '/' || path[len] == '\\')
{
return path + len + 1;
}
}
return path;
} /* Basename */
static const char *REGPARM(2) Extension(const char *path, int len)
{
while(len > 0)
{
len--;
if(path[len] == '.')
{
return path + len;
}
}
return "";
} /* Extension */
static void Usage(void)
{
static const char sUsage[] = "\
Usage: ccdv /path/to/cc CFLAGS...\n\
\n\
I wrote this to reduce the deluge Make output to make finding actual problems\n\
easier. It is intended to be invoked from Makefiles, like this. Instead of:\n\
\n\
.c.o:\n\
$(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c\n\
\n\
Rewrite your rule so it looks like:\n\
\n\
.c.o:\n\
@ccdv $(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c\n\
.cpp.o:\n\
@ccdv $(CXX) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c\n\
\n\
ccdv 1.1.0 is Free under the GNU Public License. Enjoy!\n\
-- Mike Gleason, NcFTP Software <http://www.ncftp.com>\n\
-- John F Meinel Jr, <http://ccdv.sourceforge.net>\n\
";
DWORD out;
WriteFile (gStdErr, sUsage, sizeof(sUsage)-1, &out, NULL);
ExitProcess(96);
} /* Usage */
static BOOL REGPARM(3) StepCmdLine(char **cmdline, char **arg, int *arglen)
{
char *gArgsStr = *cmdline;
// Skip whitespace
while(*gArgsStr == ' ' || *gArgsStr == '\t' || *gArgsStr == '\n' || *gArgsStr == '\r')
{
gArgsStr++;
}
if(*gArgsStr == 0)
{
*cmdline = gArgsStr;
return FALSE;
}
if(*gArgsStr == '\"')
{ // It's a quoted string
*arg = ++gArgsStr;
while(*gArgsStr && *gArgsStr != '\"')
{
gArgsStr++;
}
*arglen = gArgsStr - *arg;
if(*gArgsStr)
{ // Ends with a quote
gArgsStr++;
}
*cmdline = gArgsStr;
return TRUE;
}
// It's a whitespace-separated string
*arg = gArgsStr;
while(*gArgsStr && *gArgsStr != ' ' && *gArgsStr != '\t' && *gArgsStr != '\n' && *gArgsStr != '\r')
{
gArgsStr++;
}
*arglen = gArgsStr - *arg;
*cmdline = gArgsStr;
return TRUE;
}
static void REGPARM(3) SetTarget(char **target, const char *arg, int arglen)
{
const char *base;
if (*target) HeapFree(gHeap, 0, *target);
base = Basename(arg, arglen);
arglen = arglen - (base - arg) + 1;
*target = HeapAlloc(gHeap, 0, arglen);
lstrcpyn(*target, base, arglen);
}
void mainCRTStartup(void)
{
const char *ext;
char *cmdline, *arg;
int arglen, extlen;
SECURITY_ATTRIBUTES security;
STARTUPINFO siStartInfo;
HANDLE pipeRd, pipeWr, pipeRdDup;
char emerg[256];
DWORD nread;
int cc = 0;
int yy = 0;
int gcc = 0;
int lemon = 0;
CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
gExitStatus = 95;
gHeap = GetProcessHeap();
gArgsStr = cmdline = GetCommandLine();
gStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
gStdErr = GetStdHandle(STD_ERROR_HANDLE);
if (!StepCmdLine(&cmdline, &arg, &arglen) || // Skip ccdv.exe
!StepCmdLine(&cmdline, &arg, &arglen)) // Read name of process to run
{
Usage();
}
if(GetConsoleScreenBufferInfo(gStdOut, &bufferInfo))
{
gColumns = bufferInfo.dwSize.X;
}
else
{
char envbuf[16];
DWORD envlen;
// Check for MSYS by checking for an rxvt COLORTERM.
envlen = GetEnvironmentVariable("COLORTERM", envbuf, sizeof(envbuf));
if(envlen > 0 && envlen < sizeof(envbuf) - 1)
{
if(lstrcmp(envbuf, "rxvt") == 0)
{
gRxvt = TRUE;
// We're in an rxvt, so check the number of columns.
// Unfortunately, COLUMNS is not exported by default by MSYS.
envlen = GetEnvironmentVariable("COLUMNS", envbuf, sizeof(envbuf));
if(envlen > 0 && envlen < sizeof(envbuf) - 1)
{
gColumns = str2int(envbuf);
}
else
{
gColumns = 80;
}
}
}
}
// "Running *argv[1]*"
ext = Basename(arg, arglen);
extlen = arglen - (ext - arg);
gAction = HeapAlloc(gHeap, 0, 64+extlen);
lstrcpy(gAction, "Running ");
lstrcpyn(gAction+8, ext, extlen+1);
if (extlen == 2 && lstrcmpi(gAction+8, "ar") == 0)
{
SetTarget(&gAr, arg, arglen);
}
else if((extlen == 2 &&
(lstrcmpi(gAction+8, "cc") == 0 ||
lstrcmpi(gAction+8, "cl") == 0 ||
lstrcmpi(gAction+8, "ld") == 0)) ||
(extlen == 3 &&
(lstrcmpi(gAction+8, "gcc") == 0 ||
- Unlimited the monster pain sounds in Hexen after playing as the Cleric a while and killing centaurs with the flechette. - Fixed: Moving to an old level in a hub caused the old player's inventory to spawn owned by the current player (but still hanging off the old player), so the game would hang when trying to delete it. - Modified re2c so that it doesn't add a date to the file it generates. Thus, if it regenerates a file during a full rebuild, SVN won't see it as a change. Also updated it to 0.10.5. - Fixed: SC_GetString() did not properly terminate sc_String when the last token in the file had no white space after it. Since I could not actually find the problem (it works fine in debug mode and I saw no logic errors), I decided to take this opportunity to reimplement it using an re2c-generated scanner. Now it's 1.6x faster than before and correctness is easier to verify. - Fixed: FMODSoundRenderer::Shutdown() also needs to reset NumChannels. - Added back the Manifest to zdoom.rc for non-VC8 Windows compilers. - Fixed MinGW compilation again. Now it uses the same method as Makefile.linux to find all the source files so that it doesn't need to be manually updated each time source files are added or removed. - Added the SVN revision number to the version string. A new tool is used to obtain this information from the svnversion command and write it into a header file. If you don't have the svn command line tools installed or didn't check it out from the repository, you can still build. I added some rules for this to Makefile.linux, and I assume they work because they do for Makefile.mingw. - Fixed: MIDISong2 did not delete MusHeader in its destructor. SVN r200 (trunk)
2006-06-20 20:30:39 +00:00
lstrcmpi(gAction+8, "g++") == 0)) ||
(extlen == 7 && lstrcmpi(gAction+8, "windres") == 0))
{
gcc = 1;
}
else if(extlen == 5 && lstrcmpi(gAction+8, "lemon") == 0)
{
lemon = 1;
}
while(StepCmdLine(&cmdline, &arg, &arglen))
{
if(gcc && arglen == 2 && arg[0] == '-' && arg[1] == 'o')
{
if(StepCmdLine(&cmdline, &arg, &arglen))
{
ext = Extension(arg, arglen);
if(ext[0] != '.' || (ext[1] != 'o' && ext[1] != 'O'))
{
lstrcpy(gAction, "Linking");
SetTarget(&gTarget, arg, arglen);
}
}
continue;
}
else if(arg[0] == '-' || arg[0] == '+' || arg[0] == '/')
{
continue;
}
ext = Extension(arg, arglen);
if(ext[0] == '.' && (ext[1] == 'C' || ext[1] == 'c'))
{
cc++;
SetTarget(&gTarget, arg, arglen);
}
else if(ext[0] == '.' && ext[1] == 'y')
{
if(lemon)
{
lstrcpy(gAction, "Generating");
SetTarget(&gTarget, arg, arglen);
gTarget[arglen-1] = 'c';
}
yy++;
}
else if(ext[0] == '.' && ext[1] == 'r' && ext[2] == 'e')
{
yy++;
}
else if((ext[0] == '.' && ext[1] == 'n' && ext[2] == 'a' && ext[3] == 's') ||
(ext[0] == '.' && ext[1] == 'a' && ext[2] == 's' && ext[3] == 'm') ||
(ext[0] == '.' && ext[1] == 's'))
{
lstrcpy(gAction, "Assembling");
SetTarget(&gTarget, arg, arglen);
}
else if(gArLibraryTarget == NULL && ext[0] == '.' && ext[1] == 'a')
{
SetTarget(&gArLibraryTarget, arg, arglen);
}
}
if((gAr != NULL) && (gArLibraryTarget != NULL))
{
lstrcpy(gAction, "Creating library");
if(gTarget != NULL) HeapFree(gHeap, 0, gTarget);
gTarget = gArLibraryTarget;
gArLibraryTarget = NULL;
}
else if(cc > 0)
{
lstrcpy(gAction, yy == 0 ? "Compiling" : "Generating");
}
/* Initialize security attributes for the pipe */
security.nLength = sizeof security;
security.lpSecurityDescriptor = NULL;
security.bInheritHandle = TRUE;
if(!CreatePipe(&pipeRd, &pipeWr, &security, 0))
{
perror("ccdv: pipe");
ExitProcess(97);
}
if (!DuplicateHandle(GetCurrentProcess(), pipeRd,
GetCurrentProcess(), &pipeRdDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS))
{
perror("ccdv: DuplicateHandle");
}
CloseHandle(pipeRd);
/* Initialize startup info for the child process */
siStartInfo.cb = sizeof siStartInfo;
siStartInfo.lpReserved = NULL;
siStartInfo.lpDesktop = NULL;
siStartInfo.lpTitle = NULL;
siStartInfo.dwX = 0;
siStartInfo.dwY = 0;
siStartInfo.dwXSize = 0;
siStartInfo.dwYSize = 0;
siStartInfo.dwXCountChars = 0;
siStartInfo.dwYCountChars = 0;
siStartInfo.dwFillAttribute = 0;
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.wShowWindow = 0;
siStartInfo.cbReserved2 = 0;
siStartInfo.lpReserved2 = 0;
siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartInfo.hStdOutput = pipeWr;
siStartInfo.hStdError = pipeWr;
StepCmdLine(&gArgsStr, &arg, &arglen); // Skip "ccdv"
while(*gArgsStr == ' ' || *gArgsStr == '\t' || *gArgsStr == '\n' || *gArgsStr == '\r')
gArgsStr++;
extlen = lstrlen(gArgsStr);
gNBufAllocated = extlen + TEXT_BLOCK_SIZE;
gBuf = (char *) HeapAlloc(gHeap, 0, gNBufAllocated);
if(gBuf == NULL)
goto panic;
gNBufUsed = extlen + 1;
lstrcpy(gBuf, gArgsStr);
gBuf[extlen] = '\n';
gBuf[extlen+1] = 0;
if(!CreateProcessA(NULL,
gArgsStr, /* command gArgsStr */
NULL, /* process security attributes */
NULL, /* primary thread security attributes */
TRUE, /* handles are inherited */
0, /* creation flags */
NULL, /* use parent's environment */
NULL, /* use parent's current directory */
&siStartInfo, /* STARTUPINFO pointer */
&gCCP)) /* receives PROCESS_INFORMATION */
{
CloseHandle(pipeRdDup);
CloseHandle(pipeWr);
perror("ccdv: CreateProcess");
gExitStatus = 98;
goto panic;
}
CloseHandle(gCCP.hThread);
if(!gRxvt)
{
if(Slurp(pipeRdDup, gStdOut) < 0)
goto panic;
}
else
{
if(Slurp(pipeRdDup, gStdOut) < 0)
goto panic;
}
DumpFormattedOutput();
ExitProcess(gExitStatus);
panic:
gDumpCmdArgs = 1; /* print cmd when there are errors */
DumpFormattedOutput();
while(ReadFile(pipeRdDup, emerg, sizeof emerg, &nread, NULL) && nread > 0)
WriteFile(gStdErr, emerg, nread, &nread, NULL);
Wait();
ExitProcess(gExitStatus);
} /* main */
/* eof ccdv.c */