2006-04-16 05:20:20 +00:00
|
|
|
/* 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>
|
|
|
|
|
2006-08-11 03:07:32 +00:00
|
|
|
#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 */
|
2006-04-16 05:20:20 +00:00
|
|
|
|
|
|
|
#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;
|
2006-08-11 03:07:32 +00:00
|
|
|
BOOL gRxvt;
|
2006-04-16 05:20:20 +00:00
|
|
|
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;
|
2006-08-11 03:07:32 +00:00
|
|
|
char errcode[9];
|
2006-04-16 05:20:20 +00:00
|
|
|
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);
|
2006-08-11 03:07:32 +00:00
|
|
|
wsprintf(errcode, "%08x", error);
|
|
|
|
WriteFile (gStdErr, ": Error 0x", 10, &wrote, NULL);
|
|
|
|
WriteFile (gStdErr, errcode, 8, &wrote, NULL);
|
|
|
|
if(len != 0)
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
WriteFile (gStdErr, "\n", 1, &wrote, NULL);
|
2006-04-16 05:20:20 +00:00
|
|
|
WriteFile (gStdErr, buffer, len, &wrote, NULL);
|
|
|
|
LocalFree(buffer);
|
|
|
|
}
|
|
|
|
WriteFile (gStdErr, "\n", 1, &wrote, NULL);
|
2006-08-11 03:07:32 +00:00
|
|
|
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);
|
2006-04-16 05:20:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpFormattedOutput()
|
|
|
|
{
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
|
DWORD out;
|
|
|
|
WORD color;
|
|
|
|
char *cp;
|
2006-05-22 01:34:07 +00:00
|
|
|
char spaces[8 + 1];
|
2006-04-16 05:20:20 +00:00
|
|
|
char *saved;
|
|
|
|
int curcol;
|
|
|
|
int i;
|
|
|
|
|
2006-08-11 03:07:32 +00:00
|
|
|
for(i = 0; i < 8; ++i)
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
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);
|
2006-04-16 05:20:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-08-11 03:07:32 +00:00
|
|
|
if(!GetConsoleScreenBufferInfo(gStdOut, &info))
|
2006-05-26 04:38:22 +00:00
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
WriteFile(gStdOut, gBuf, lstrlen(gBuf), &out, NULL);
|
|
|
|
WriteFile(gStdOut, "\n", 1, &out, NULL);
|
|
|
|
HeapFree(gHeap, 0, gBuf);
|
|
|
|
return;
|
2006-05-26 04:38:22 +00:00
|
|
|
}
|
2006-05-22 01:34:07 +00:00
|
|
|
|
2006-04-16 05:20:20 +00:00
|
|
|
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);
|
2006-08-11 03:07:32 +00:00
|
|
|
for(i = gColumns; i > 0; i -= 7)
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
WriteConsole(gStdOut, "=======", i > 7 ? 7 : i, &out, NULL);
|
2006-04-16 05:20:20 +00:00
|
|
|
}
|
2006-08-11 03:07:32 +00:00
|
|
|
color |= COLOR_ERROROUTPUT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
color |= COLOR_WARNINGOUTPUT;
|
2006-04-16 05:20:20 +00:00
|
|
|
}
|
2006-08-11 03:07:32 +00:00
|
|
|
SetConsoleTextAttribute(gStdOut, color);
|
|
|
|
WriteConsole(gStdOut, gBuf + lstrlen(gArgsStr) + 1, lstrlen(gBuf + lstrlen(gArgsStr) + 1), &out, NULL);
|
|
|
|
SetConsoleTextAttribute(gStdOut, info.wAttributes);
|
2006-04-16 05:20:20 +00:00
|
|
|
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;
|
2006-08-10 01:17:58 +00:00
|
|
|
DWORD threadid;
|
2006-04-16 05:20:20 +00:00
|
|
|
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;
|
2006-08-10 01:17:58 +00:00
|
|
|
handles[1] = CreateThread(NULL, 0, SlurpThread, (LPVOID)fd, 0, &threadid);
|
2006-04-16 05:20:20 +00:00
|
|
|
|
|
|
|
if(handles[1] == 0)
|
|
|
|
{
|
|
|
|
perror("ccdv: CreateThread");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(hStdOut != NULL)
|
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
if(!gRxvt)
|
|
|
|
{
|
|
|
|
GetConsoleScreenBufferInfo(hStdOut, &info);
|
|
|
|
info.dwCursorPosition.X = info.dwSize.X - 9;
|
|
|
|
}
|
2006-04-16 05:20:20 +00:00
|
|
|
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)
|
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
if(!gRxvt)
|
|
|
|
{
|
|
|
|
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
|
|
|
|
WriteConsoleA(hStdOut, trailcp, 1, &out, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Writef(hStdOut, "\033[999C\033[9D%c", *trailcp);
|
|
|
|
}
|
2006-04-16 05:20:20 +00:00
|
|
|
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)
|
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
if(!gRxvt)
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
info.dwCursorPosition.X = 0;
|
2006-04-16 05:20:20 +00:00
|
|
|
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
|
2006-08-11 03:07:32 +00:00
|
|
|
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);
|
2006-04-16 05:20:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
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 */
|
|
|
|
}
|
2006-04-16 05:20:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
2006-05-25 04:32:20 +00:00
|
|
|
int gcc = 0;
|
|
|
|
int lemon = 0;
|
2006-04-16 05:20:20 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2006-08-11 03:07:32 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-16 05:20:20 +00:00
|
|
|
// "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);
|
|
|
|
|
2006-05-25 04:32:20 +00:00
|
|
|
if (extlen == 2 && lstrcmpi(gAction+8, "ar") == 0)
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
|
|
|
SetTarget(&gAr, arg, arglen);
|
|
|
|
}
|
2006-05-25 04:32:20 +00:00
|
|
|
else if((extlen == 2 &&
|
|
|
|
(lstrcmpi(gAction+8, "cc") == 0 ||
|
2006-05-26 04:38:22 +00:00
|
|
|
lstrcmpi(gAction+8, "cl") == 0 ||
|
|
|
|
lstrcmpi(gAction+8, "ld") == 0)) ||
|
|
|
|
(extlen == 3 &&
|
|
|
|
(lstrcmpi(gAction+8, "gcc") == 0 ||
|
2006-06-20 20:30:39 +00:00
|
|
|
lstrcmpi(gAction+8, "g++") == 0)) ||
|
|
|
|
(extlen == 7 && lstrcmpi(gAction+8, "windres") == 0))
|
2006-05-25 04:32:20 +00:00
|
|
|
{
|
|
|
|
gcc = 1;
|
|
|
|
}
|
|
|
|
else if(extlen == 5 && lstrcmpi(gAction+8, "lemon") == 0)
|
|
|
|
{
|
|
|
|
lemon = 1;
|
|
|
|
}
|
2006-04-16 05:20:20 +00:00
|
|
|
|
|
|
|
while(StepCmdLine(&cmdline, &arg, &arglen))
|
|
|
|
{
|
2006-05-25 04:32:20 +00:00
|
|
|
if(gcc && arglen == 2 && arg[0] == '-' && arg[1] == 'o')
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
|
|
|
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')
|
2006-05-25 04:32:20 +00:00
|
|
|
{
|
|
|
|
if(lemon)
|
|
|
|
{
|
|
|
|
lstrcpy(gAction, "Generating");
|
|
|
|
SetTarget(&gTarget, arg, arglen);
|
|
|
|
gTarget[arglen-1] = 'c';
|
|
|
|
}
|
|
|
|
yy++;
|
|
|
|
}
|
|
|
|
else if(ext[0] == '.' && ext[1] == 'r' && ext[2] == 'e')
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
|
|
|
yy++;
|
|
|
|
}
|
2006-05-26 04:38:22 +00:00
|
|
|
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'))
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!DuplicateHandle(GetCurrentProcess(), pipeRd,
|
|
|
|
GetCurrentProcess(), &pipeRdDup , 0,
|
|
|
|
FALSE,
|
|
|
|
DUPLICATE_SAME_ACCESS))
|
|
|
|
{
|
|
|
|
perror("ccdv: DuplicateHandle");
|
|
|
|
}
|
|
|
|
CloseHandle(pipeRd);
|
2006-04-16 05:20:20 +00:00
|
|
|
|
|
|
|
/* 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;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
StepCmdLine(&gArgsStr, &arg, &arglen); // Skip "ccdv"
|
2006-04-16 05:20:20 +00:00
|
|
|
while(*gArgsStr == ' ' || *gArgsStr == '\t' || *gArgsStr == '\n' || *gArgsStr == '\r')
|
|
|
|
gArgsStr++;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
extlen = lstrlen(gArgsStr);
|
|
|
|
gNBufAllocated = extlen + TEXT_BLOCK_SIZE;
|
2006-04-16 05:20:20 +00:00
|
|
|
gBuf = (char *) HeapAlloc(gHeap, 0, gNBufAllocated);
|
|
|
|
if(gBuf == NULL)
|
|
|
|
goto panic;
|
|
|
|
gNBufUsed = extlen + 1;
|
|
|
|
lstrcpy(gBuf, gArgsStr);
|
|
|
|
gBuf[extlen] = '\n';
|
|
|
|
gBuf[extlen+1] = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
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);
|
2006-04-16 05:20:20 +00:00
|
|
|
|
2006-08-11 03:07:32 +00:00
|
|
|
if(!gRxvt)
|
2006-04-16 05:20:20 +00:00
|
|
|
{
|
|
|
|
if(Slurp(pipeRdDup, gStdOut) < 0)
|
|
|
|
goto panic;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-08-11 03:07:32 +00:00
|
|
|
if(Slurp(pipeRdDup, gStdOut) < 0)
|
2006-04-16 05:20:20 +00:00
|
|
|
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 */
|