Hello, I was just building a little application that tries to mimic "touch"
behaviour in Windows, its source is attached to this message.

Since it is a command line utility I'm building it in the following way,
without specifying -mwindows:

x86_64-w64-mingw32-g++ -D_UNICODE -DUNICODE -municode touch.cpp

Which fails, it looks for wWinMain() even though it isn't an application
with a graphical interface. Specifying -mconsole leads to the same result.

I was able to build the utility, adding manually a wWinMain() and using the
CommandLineToArgvW() function because the program depends on "argc" and
"argv". I thought it was "fixed", but the built executable doesn't work,
behaves as if there were always no arguments to it (shows usage).

Finding that strange... I looked at the subsystem of the binary which is
reported as a console application:

$ x86_64-w64-mingw32-objdump.exe -x a.exe | findstr /i "^subsystem"
Subsystem               00000003        (Windows CUI)

How come the compiler expects a wWinMain() function when it is a console
application?

PS. Sources origin:
http://www.codeproject.com/Articles/3258/Touch-for-Windows
// touch.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <io.h>
#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>

// Matches the command line arguments/options
#define OPT_MODIFY_ATIME       (1 << 0)
#define OPT_MODIFY_MTIME       (1 << 1)
#define OPT_MODIFY_CTIME       (1 << 2)
#define OPT_NO_CREATE	       (1 << 3)
#define OPT_USE_TEMPLATE       (1 << 4)
#define OPT_USER_TIME          (1 << 5)
#define OPT_DIR_IF_NOT_EXIST   (1 << 6)

// The magic function which does all the touching
static DWORD touch(LPCTSTR lpszFile, FILETIME* atime, FILETIME* mtime, FILETIME* ctime, WORD wOpts)
{
	SetLastError(ERROR_SUCCESS);

	DWORD dwFileAttributes = GetFileAttributes(lpszFile);
	DWORD dwErr = GetLastError();
	if(dwFileAttributes == INVALID_FILE_ATTRIBUTES && dwErr != ERROR_FILE_NOT_FOUND)
		return dwErr;

	bool bUpdateOrCreateDirectory =
		(OPT_DIR_IF_NOT_EXIST & wOpts) && dwFileAttributes == INVALID_FILE_ATTRIBUTES ||
		dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && dwFileAttributes != INVALID_FILE_ATTRIBUTES;

	// If there is no directory, create it!
	if(bUpdateOrCreateDirectory && dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
		SetLastError(ERROR_SUCCESS);
		BOOL bResult = CreateDirectory(lpszFile, NULL);
		
		if(!bResult) {
			DWORD dwErr = GetLastError();
			if(dwErr != ERROR_ALREADY_EXISTS)
				return dwErr;
		} else {
			// We're done, because we obviously created a directory!
			return ERROR_SUCCESS;
		}
	}

	SetLastError(ERROR_SUCCESS);

	HANDLE hFile = CreateFile(
		lpszFile, 
		GENERIC_WRITE, 
		FILE_SHARE_READ | FILE_SHARE_WRITE, 
		NULL, 
		((wOpts & OPT_NO_CREATE) || bUpdateOrCreateDirectory) ? OPEN_EXISTING : OPEN_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL | (bUpdateOrCreateDirectory ? FILE_FLAG_BACKUP_SEMANTICS : 0), 
		0);

	DWORD dwRetVal = GetLastError();

	// Check for CreateFile() special cases
	if(hFile == INVALID_HANDLE_VALUE) {
		if((wOpts & OPT_NO_CREATE) && dwRetVal == ERROR_FILE_NOT_FOUND)
			return ERROR_SUCCESS; // not an error
		else if(dwRetVal == ERROR_ALREADY_EXISTS)
			dwRetVal = ERROR_SUCCESS; // not an error according to MSDN docs

		return dwRetVal;
	}

	// Is there any template timestamp?  
	if(atime || mtime || ctime) {
		BOOL bResult = SetFileTime(
			hFile, 
			(wOpts & OPT_MODIFY_CTIME) ? ctime : NULL,
			(wOpts & OPT_MODIFY_ATIME) ? atime : NULL,
			(wOpts & OPT_MODIFY_MTIME) ? mtime : NULL
		);

		if(bResult)
			dwRetVal = ERROR_SUCCESS;
		else
			dwRetVal = GetLastError();
	}

	CloseHandle(hFile);

	return dwRetVal;
}

// Prints the usage/help and an optional error message
static void ShowUsage(LPCTSTR lpszErrorMessage = NULL) 
{
	if(lpszErrorMessage)
		_tprintf(_T("Error: %s\n"), lpszErrorMessage);
	_tprintf(_T("Usage: touch [-h] [-a] [-C] [-m] [-c] [-r file] [-d] [-t [[CC]YY]MMDDhhmm[.SS]] <file> [file 2] [file 3] ... [file N]\n"));
	_tprintf(_T("   -a: Modify access time\n"));
	_tprintf(_T("   -C: Modify creation time\n"));
	_tprintf(_T("   -m: Modify modification time\n"));
	_tprintf(_T("   -c: Do not create file if not found\n"));
	_tprintf(_T("   -r: Use file or directory as time source\n"));
	_tprintf(_T("   -d: If target doesn't exist, create a directory\n"));
	_tprintf(_T("   -t: Use specified time instead of current time\n"));
	_tprintf(_T("   -h: This help text\n"));
	_tprintf(_T("\n"));
	_tprintf(_T("Options -r and -t are mutually exclusive.\n"));
	_tprintf(_T("By default, all times will be modified (access, creation and modification).\n"));
}

// Prints a message translated from a Windows Error code, then prints the usage 
static void PrintError(LPCTSTR lpszInfo, DWORD err)
{
	_tprintf(_T("Error: %s: "), lpszInfo);
	LPVOID lpMsgBuf;
    FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        err,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR) &lpMsgBuf,
        0,
        NULL);
    
	_tprintf(_T("%s\n"), (LPCTSTR)lpMsgBuf);
    LocalFree( lpMsgBuf );
}

static bool IsGlobPattern(LPCTSTR lpszGlob)
{
	return _tcschr(lpszGlob, _T('*')) != NULL || _tcschr(lpszGlob, _T('?'));
}

// Parses the command line arguments. This function expects
// that "argv[0]" is not included. (argv[0] = name of called executable)
static bool ParseOptions(int argc,  LPTSTR argv[], 
						 int&       iFileArg, 
						 LPTSTR&    lpszTemplateFile,
						 LPTSTR&    lpszTime,
						 WORD&      wOpts)
{
	lpszTime = lpszTemplateFile = NULL;
	wOpts = 0;

	if(!argc) {
		ShowUsage(_T("No file(s) specified"));
		return false;
	} else if(argc == 1) {
		if(!_tcscmp(argv[0], _T("-h"))) {
			ShowUsage(_T("Help Requested"));
			return false;
		} else if(argv[0][0] == _T('-')) {
			ShowUsage(_T("Not enough arguments"));
			return false;
		}
		iFileArg = 0;
	} else {
		int i;
		for(i = 0; i < argc; ++i) {
			LPTSTR curr_arg = argv[i];
			LPTSTR next_arg = (i + 1 < (argc - 1) ? argv[i + 1] : NULL);

			if(curr_arg[0] == '-') {
				if(!_tcscmp(curr_arg, _T("-a"))) {
					wOpts |= OPT_MODIFY_ATIME;
				} else if(!_tcscmp(curr_arg, _T("-C"))) {
					wOpts |= OPT_MODIFY_CTIME;
				} else if(!_tcscmp(curr_arg, _T("-m"))) {
					wOpts |= OPT_MODIFY_MTIME;
				} else if(!_tcscmp(curr_arg, _T("-c"))) {
					wOpts |= OPT_NO_CREATE;
				} else if(!_tcscmp(curr_arg, _T("-d"))) {
					wOpts |= OPT_DIR_IF_NOT_EXIST;
				} else if(!_tcscmp(curr_arg, _T("-r"))) {
					wOpts |= OPT_USE_TEMPLATE;
					lpszTemplateFile = next_arg;
					++i;
				} else if(!_tcscmp(curr_arg, _T("-t"))) {
					wOpts |= OPT_USER_TIME;
					lpszTime = next_arg;
					++i;
				} else if(!_tcscmp(curr_arg, _T("-h"))) {
					ShowUsage(_T("Help Requested"));
					return false;
				} else {
					ShowUsage(_T("Unknown argument"));
					return false;
				}
			} else
				break;
		}

		iFileArg = i;
	}

	if(iFileArg >= argc) {
		ShowUsage(_T("No file(s) specified!"));
		return false;
	}

	if((wOpts & OPT_USE_TEMPLATE) && (wOpts & OPT_USER_TIME)) {
		ShowUsage(_T("You may not specify both -r and -t"));
		return false;
	}
	
	if((wOpts & OPT_USE_TEMPLATE) && !lpszTemplateFile) {
		ShowUsage(_T("You must specify a file name together with -r"));
		return false;
	}

	if((wOpts & OPT_USER_TIME) && !lpszTime) {
		ShowUsage(_T("You must specify a timestamp together with -t"));
		return false;
	}

	// If -a, -C and -m wasn't specified, then all of them are implied
	if(!(wOpts & OPT_MODIFY_ATIME) && 
	   !(wOpts & OPT_MODIFY_MTIME) && 
	   !(wOpts & OPT_MODIFY_CTIME))
	   wOpts |= (OPT_MODIFY_ATIME | OPT_MODIFY_MTIME | OPT_MODIFY_CTIME);

	return true;
}

// Gets file times from a file
static bool GetFileTimes(LPCTSTR    lpszTemplateFileName,
						 FILETIME*  tsAtime,
						 FILETIME*  tsMtime,
						 FILETIME*  tsCtime) 
{
	HANDLE hFile = CreateFile(
		lpszTemplateFileName, 
		GENERIC_READ, 
		FILE_SHARE_READ | FILE_SHARE_WRITE, 
		NULL, 
		OPEN_EXISTING, 
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 
		0);

	if(INVALID_HANDLE_VALUE == hFile) {
		PrintError(lpszTemplateFileName, GetLastError());
		ShowUsage();
		return false;
	}

	if(!GetFileTime(hFile, tsCtime, tsAtime, tsMtime)) {
		PrintError(lpszTemplateFileName, GetLastError());
		ShowUsage();
		CloseHandle(hFile);
		return false;
	}

	CloseHandle(hFile);

	return true;
}

// Parses a date/time string into a FILETIME structure
// Parses the syntax: [[CC]YY]MMDDhhmm[.SS]
// Warning: This is no masterpiece. No regular expressions or any other
// fancy features used. 
static bool ParseTime(LPCTSTR lpszTime, FILETIME* ts) 
{
	size_t nLen = _tcslen(lpszTime);
    
	// Verify length
	if(nLen < 8 || nLen > 15) {
		ShowUsage(_T("Invalid time format"));
		return false;
	}

	// Verify format
	bool   bSeenDot = false;
	size_t nDotIndex = size_t(-1);
	for(size_t i = 0; i < nLen; ++i) {
		if(lpszTime[i] == _T('.')) {
			if(bSeenDot) {
				ShowUsage(_T("Invalid time format"));
				return false;
			} else {
				bSeenDot = true;
				nDotIndex = i;
			}
		} else if(!_istdigit(lpszTime[i])) {
			ShowUsage(_T("Invalid time format"));
			return false;
		}
	}
	
	size_t nBeforeDotLength;
	size_t nAfterDotLength;

	if(bSeenDot) {
		nBeforeDotLength = nDotIndex;
		nAfterDotLength = nLen - (nDotIndex + 1);
	} else {
		nBeforeDotLength = nLen;
		nAfterDotLength = 0;
	}

	if(bSeenDot && nAfterDotLength != 2 ||
	   nBeforeDotLength != 8 && nBeforeDotLength != 10 && nBeforeDotLength != 12) {
		ShowUsage(_T("Invalid time format"));
		return false;
	}

	WORD nCentury;
	WORD nYear;
	WORD nMonth;
	WORD nDay;
	WORD nHour;
	WORD nMinute;
	WORD nSeconds;
	int nIndex = 0;

	// First get defaults for century and year (= this year) in case uses did not specify them
	SYSTEMTIME    st;
	GetSystemTime(&st);
	nCentury = st.wYear / 100;
	nYear    = st.wYear % 100;

	switch(nBeforeDotLength) { // Cases fall through... (no typo!)
		case 12:
			nCentury  = (lpszTime[nIndex++] - _T('0')) * 10;
			nCentury += (lpszTime[nIndex++] - _T('0'));
		case 10:
			nYear     = (lpszTime[nIndex++] - _T('0')) * 10;
			nYear    += (lpszTime[nIndex++] - _T('0'));
		case 8:
			nMonth    = (lpszTime[nIndex++] - _T('0')) * 10;
			nMonth   += (lpszTime[nIndex++] - _T('0'));
			nDay      = (lpszTime[nIndex++] - _T('0')) * 10;
			nDay     += (lpszTime[nIndex++] - _T('0'));
			nHour     = (lpszTime[nIndex++] - _T('0')) * 10;
			nHour    += (lpszTime[nIndex++] - _T('0'));
			nMinute   = (lpszTime[nIndex++] - _T('0')) * 10;
			nMinute  += (lpszTime[nIndex++] - _T('0'));
			break;
		default: // Should not end up here!
			ShowUsage(_T("Invalid time format"));
			return false;
	}

	if(2 == nAfterDotLength) {
		nSeconds  = (lpszTime[nDotIndex + 1] - _T('0')) * 10;
		nSeconds += (lpszTime[nDotIndex + 2] - _T('0'));
	} else {
		nSeconds = 0;
	}

	st.wYear = nCentury * 100 + nYear;
	st.wMonth = nMonth;
	st.wDay = nDay;
	st.wHour = nHour;
	st.wMinute = nMinute;
	st.wSecond = nSeconds;
	st.wMilliseconds = 0;

	
	FILETIME ft;
	if(!SystemTimeToFileTime(&st, &ft)) {
		PrintError(_T("Specified date"), GetLastError());
		ShowUsage();
		return false;
	}

	if(!LocalFileTimeToFileTime(&ft, ts)) {
		PrintError(_T("Specified date"), GetLastError());
		ShowUsage();
		return false;
	}

	return true;
}

int _tmain(int argc, LPTSTR argv[])
{
	LPTSTR    lpszTemplateFile;
	LPTSTR    lpszTime;
	int       iFileArg;
	WORD      wOpts;
	FILETIME  tsUserTime;
	FILETIME  tsATime;
	FILETIME  tsMTime;
	FILETIME  tsCTime;

	if(!ParseOptions(argc - 1, argv + 1, iFileArg, lpszTemplateFile, lpszTime, wOpts))
		return -1;

	++iFileArg; // Adjust for executable
	
	if(wOpts & OPT_USER_TIME) {
		if(!ParseTime(lpszTime, &tsUserTime)) 
			return -1;

		tsATime = tsMTime = tsCTime = tsUserTime;
	} else if(wOpts & OPT_USE_TEMPLATE) {
		if(!GetFileTimes(lpszTemplateFile, &tsATime, &tsMTime, &tsCTime))
			return -1;
	} else {
		SYSTEMTIME  now;

		GetSystemTime(&now);
		if(!SystemTimeToFileTime(&now, &tsUserTime)) {
			PrintError(_T("SystemTimeToFileTime()"), GetLastError());
			ShowUsage();
			return -1;
		}

		tsATime = tsMTime = tsCTime = tsUserTime;
	}

	for(int i = iFileArg; i < argc; ++i) {
		LPCTSTR lpszFile = argv[i];

		TCHAR szPath[_MAX_PATH];
		TCHAR szDrive[_MAX_DRIVE];
		TCHAR szDir[_MAX_DIR];
		TCHAR szFname[_MAX_FNAME];
		TCHAR szExt[_MAX_EXT];
#ifdef _UNICODE
		struct _wfinddata_t sFile;
#else
		struct _finddata_t sFile;
#endif

		if(IsGlobPattern(lpszFile)) {
			_tfullpath(szPath, lpszFile, _MAX_PATH);
			_tsplitpath(szPath, szDrive, szDir, szFname, szExt);
			intptr_t hFile = _tfindfirst(szPath, &sFile);
			if(hFile != -1L) {
				do {
					if(sFile.attrib & _A_SUBDIR) continue;
					TCHAR szIterPath[_MAX_PATH];
					TCHAR szIterFname[_MAX_FNAME];
					TCHAR szIterExt[_MAX_EXT];

					_tsplitpath(sFile.name, NULL, NULL, szIterFname, szIterExt);
					_tmakepath(szIterPath, szDrive, szDir, szIterFname, szIterExt);
					DWORD dwResult = touch(
						szIterPath,
						(wOpts & OPT_MODIFY_ATIME) ? &tsATime : NULL,
						(wOpts & OPT_MODIFY_MTIME) ? &tsMTime : NULL,
						(wOpts & OPT_MODIFY_CTIME) ? &tsCTime : NULL,
						wOpts
					);

					if(ERROR_SUCCESS != dwResult) {
						PrintError(szIterPath, dwResult);
					}
				} while(_tfindnext(hFile, &sFile) == 0);
				_findclose(hFile);
			}
		} else {
			DWORD dwResult = touch(
				lpszFile,
				(wOpts & OPT_MODIFY_ATIME) ? &tsATime : NULL,
				(wOpts & OPT_MODIFY_MTIME) ? &tsMTime : NULL,
				(wOpts & OPT_MODIFY_CTIME) ? &tsCTime : NULL,
				wOpts
			);

			if(ERROR_SUCCESS != dwResult) {
				PrintError(lpszFile, dwResult);
			}
		}
	}

	return 0;
}

// touch.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <io.h>
#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <shellapi.h>

// Matches the command line arguments/options
#define OPT_MODIFY_ATIME       (1 << 0)
#define OPT_MODIFY_MTIME       (1 << 1)
#define OPT_MODIFY_CTIME       (1 << 2)
#define OPT_NO_CREATE	       (1 << 3)
#define OPT_USE_TEMPLATE       (1 << 4)
#define OPT_USER_TIME          (1 << 5)
#define OPT_DIR_IF_NOT_EXIST   (1 << 6)

// The magic function which does all the touching
static DWORD touch(LPCTSTR lpszFile, FILETIME* atime, FILETIME* mtime, FILETIME* ctime, WORD wOpts)
{
	SetLastError(ERROR_SUCCESS);

	DWORD dwFileAttributes = GetFileAttributes(lpszFile);
	DWORD dwErr = GetLastError();
	if(dwFileAttributes == INVALID_FILE_ATTRIBUTES && dwErr != ERROR_FILE_NOT_FOUND)
		return dwErr;

	bool bUpdateOrCreateDirectory =
		(OPT_DIR_IF_NOT_EXIST & wOpts) && dwFileAttributes == INVALID_FILE_ATTRIBUTES ||
		dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && dwFileAttributes != INVALID_FILE_ATTRIBUTES;

	// If there is no directory, create it!
	if(bUpdateOrCreateDirectory && dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
		SetLastError(ERROR_SUCCESS);
		BOOL bResult = CreateDirectory(lpszFile, NULL);
		
		if(!bResult) {
			DWORD dwErr = GetLastError();
			if(dwErr != ERROR_ALREADY_EXISTS)
				return dwErr;
		} else {
			// We're done, because we obviously created a directory!
			return ERROR_SUCCESS;
		}
	}

	SetLastError(ERROR_SUCCESS);

	HANDLE hFile = CreateFile(
		lpszFile, 
		GENERIC_WRITE, 
		FILE_SHARE_READ | FILE_SHARE_WRITE, 
		NULL, 
		((wOpts & OPT_NO_CREATE) || bUpdateOrCreateDirectory) ? OPEN_EXISTING : OPEN_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL | (bUpdateOrCreateDirectory ? FILE_FLAG_BACKUP_SEMANTICS : 0), 
		0);

	DWORD dwRetVal = GetLastError();

	// Check for CreateFile() special cases
	if(hFile == INVALID_HANDLE_VALUE) {
		if((wOpts & OPT_NO_CREATE) && dwRetVal == ERROR_FILE_NOT_FOUND)
			return ERROR_SUCCESS; // not an error
		else if(dwRetVal == ERROR_ALREADY_EXISTS)
			dwRetVal = ERROR_SUCCESS; // not an error according to MSDN docs

		return dwRetVal;
	}

	// Is there any template timestamp?  
	if(atime || mtime || ctime) {
		BOOL bResult = SetFileTime(
			hFile, 
			(wOpts & OPT_MODIFY_CTIME) ? ctime : NULL,
			(wOpts & OPT_MODIFY_ATIME) ? atime : NULL,
			(wOpts & OPT_MODIFY_MTIME) ? mtime : NULL
		);

		if(bResult)
			dwRetVal = ERROR_SUCCESS;
		else
			dwRetVal = GetLastError();
	}

	CloseHandle(hFile);

	return dwRetVal;
}

// Prints the usage/help and an optional error message
static void ShowUsage(LPCTSTR lpszErrorMessage = NULL) 
{
	if(lpszErrorMessage)
		_tprintf(_T("Error: %s\n"), lpszErrorMessage);
	_tprintf(_T("Usage: touch [-h] [-a] [-C] [-m] [-c] [-r file] [-d] [-t [[CC]YY]MMDDhhmm[.SS]] <file> [file 2] [file 3] ... [file N]\n"));
	_tprintf(_T("   -a: Modify access time\n"));
	_tprintf(_T("   -C: Modify creation time\n"));
	_tprintf(_T("   -m: Modify modification time\n"));
	_tprintf(_T("   -c: Do not create file if not found\n"));
	_tprintf(_T("   -r: Use file or directory as time source\n"));
	_tprintf(_T("   -d: If target doesn't exist, create a directory\n"));
	_tprintf(_T("   -t: Use specified time instead of current time\n"));
	_tprintf(_T("   -h: This help text\n"));
	_tprintf(_T("\n"));
	_tprintf(_T("Options -r and -t are mutually exclusive.\n"));
	_tprintf(_T("By default, all times will be modified (access, creation and modification).\n"));
}

// Prints a message translated from a Windows Error code, then prints the usage 
static void PrintError(LPCTSTR lpszInfo, DWORD err)
{
	_tprintf(_T("Error: %s: "), lpszInfo);
	LPVOID lpMsgBuf;
    FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        err,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR) &lpMsgBuf,
        0,
        NULL);
    
	_tprintf(_T("%s\n"), (LPCTSTR)lpMsgBuf);
    LocalFree( lpMsgBuf );
}

static bool IsGlobPattern(LPCTSTR lpszGlob)
{
	return _tcschr(lpszGlob, _T('*')) != NULL || _tcschr(lpszGlob, _T('?'));
}

// Parses the command line arguments. This function expects
// that "argv[0]" is not included. (argv[0] = name of called executable)
static bool ParseOptions(int argc,  LPTSTR argv[], 
						 int&       iFileArg, 
						 LPTSTR&    lpszTemplateFile,
						 LPTSTR&    lpszTime,
						 WORD&      wOpts)
{
	lpszTime = lpszTemplateFile = NULL;
	wOpts = 0;

	if(!argc) {
		ShowUsage(_T("No file(s) specified"));
		return false;
	} else if(argc == 1) {
		if(!_tcscmp(argv[0], _T("-h"))) {
			ShowUsage(_T("Help Requested"));
			return false;
		} else if(argv[0][0] == _T('-')) {
			ShowUsage(_T("Not enough arguments"));
			return false;
		}
		iFileArg = 0;
	} else {
		int i;
		for(i = 0; i < argc; ++i) {
			LPTSTR curr_arg = argv[i];
			LPTSTR next_arg = (i + 1 < (argc - 1) ? argv[i + 1] : NULL);

			if(curr_arg[0] == '-') {
				if(!_tcscmp(curr_arg, _T("-a"))) {
					wOpts |= OPT_MODIFY_ATIME;
				} else if(!_tcscmp(curr_arg, _T("-C"))) {
					wOpts |= OPT_MODIFY_CTIME;
				} else if(!_tcscmp(curr_arg, _T("-m"))) {
					wOpts |= OPT_MODIFY_MTIME;
				} else if(!_tcscmp(curr_arg, _T("-c"))) {
					wOpts |= OPT_NO_CREATE;
				} else if(!_tcscmp(curr_arg, _T("-d"))) {
					wOpts |= OPT_DIR_IF_NOT_EXIST;
				} else if(!_tcscmp(curr_arg, _T("-r"))) {
					wOpts |= OPT_USE_TEMPLATE;
					lpszTemplateFile = next_arg;
					++i;
				} else if(!_tcscmp(curr_arg, _T("-t"))) {
					wOpts |= OPT_USER_TIME;
					lpszTime = next_arg;
					++i;
				} else if(!_tcscmp(curr_arg, _T("-h"))) {
					ShowUsage(_T("Help Requested"));
					return false;
				} else {
					ShowUsage(_T("Unknown argument"));
					return false;
				}
			} else
				break;
		}

		iFileArg = i;
	}

	if(iFileArg >= argc) {
		ShowUsage(_T("No file(s) specified!"));
		return false;
	}

	if((wOpts & OPT_USE_TEMPLATE) && (wOpts & OPT_USER_TIME)) {
		ShowUsage(_T("You may not specify both -r and -t"));
		return false;
	}
	
	if((wOpts & OPT_USE_TEMPLATE) && !lpszTemplateFile) {
		ShowUsage(_T("You must specify a file name together with -r"));
		return false;
	}

	if((wOpts & OPT_USER_TIME) && !lpszTime) {
		ShowUsage(_T("You must specify a timestamp together with -t"));
		return false;
	}

	// If -a, -C and -m wasn't specified, then all of them are implied
	if(!(wOpts & OPT_MODIFY_ATIME) && 
	   !(wOpts & OPT_MODIFY_MTIME) && 
	   !(wOpts & OPT_MODIFY_CTIME))
	   wOpts |= (OPT_MODIFY_ATIME | OPT_MODIFY_MTIME | OPT_MODIFY_CTIME);

	return true;
}

// Gets file times from a file
static bool GetFileTimes(LPCTSTR    lpszTemplateFileName,
						 FILETIME*  tsAtime,
						 FILETIME*  tsMtime,
						 FILETIME*  tsCtime) 
{
	HANDLE hFile = CreateFile(
		lpszTemplateFileName, 
		GENERIC_READ, 
		FILE_SHARE_READ | FILE_SHARE_WRITE, 
		NULL, 
		OPEN_EXISTING, 
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 
		0);

	if(INVALID_HANDLE_VALUE == hFile) {
		PrintError(lpszTemplateFileName, GetLastError());
		ShowUsage();
		return false;
	}

	if(!GetFileTime(hFile, tsCtime, tsAtime, tsMtime)) {
		PrintError(lpszTemplateFileName, GetLastError());
		ShowUsage();
		CloseHandle(hFile);
		return false;
	}

	CloseHandle(hFile);

	return true;
}

// Parses a date/time string into a FILETIME structure
// Parses the syntax: [[CC]YY]MMDDhhmm[.SS]
// Warning: This is no masterpiece. No regular expressions or any other
// fancy features used. 
static bool ParseTime(LPCTSTR lpszTime, FILETIME* ts) 
{
	size_t nLen = _tcslen(lpszTime);
    
	// Verify length
	if(nLen < 8 || nLen > 15) {
		ShowUsage(_T("Invalid time format"));
		return false;
	}

	// Verify format
	bool   bSeenDot = false;
	size_t nDotIndex = size_t(-1);
	for(size_t i = 0; i < nLen; ++i) {
		if(lpszTime[i] == _T('.')) {
			if(bSeenDot) {
				ShowUsage(_T("Invalid time format"));
				return false;
			} else {
				bSeenDot = true;
				nDotIndex = i;
			}
		} else if(!_istdigit(lpszTime[i])) {
			ShowUsage(_T("Invalid time format"));
			return false;
		}
	}
	
	size_t nBeforeDotLength;
	size_t nAfterDotLength;

	if(bSeenDot) {
		nBeforeDotLength = nDotIndex;
		nAfterDotLength = nLen - (nDotIndex + 1);
	} else {
		nBeforeDotLength = nLen;
		nAfterDotLength = 0;
	}

	if(bSeenDot && nAfterDotLength != 2 ||
	   nBeforeDotLength != 8 && nBeforeDotLength != 10 && nBeforeDotLength != 12) {
		ShowUsage(_T("Invalid time format"));
		return false;
	}

	WORD nCentury;
	WORD nYear;
	WORD nMonth;
	WORD nDay;
	WORD nHour;
	WORD nMinute;
	WORD nSeconds;
	int nIndex = 0;

	// First get defaults for century and year (= this year) in case uses did not specify them
	SYSTEMTIME    st;
	GetSystemTime(&st);
	nCentury = st.wYear / 100;
	nYear    = st.wYear % 100;

	switch(nBeforeDotLength) { // Cases fall through... (no typo!)
		case 12:
			nCentury  = (lpszTime[nIndex++] - _T('0')) * 10;
			nCentury += (lpszTime[nIndex++] - _T('0'));
		case 10:
			nYear     = (lpszTime[nIndex++] - _T('0')) * 10;
			nYear    += (lpszTime[nIndex++] - _T('0'));
		case 8:
			nMonth    = (lpszTime[nIndex++] - _T('0')) * 10;
			nMonth   += (lpszTime[nIndex++] - _T('0'));
			nDay      = (lpszTime[nIndex++] - _T('0')) * 10;
			nDay     += (lpszTime[nIndex++] - _T('0'));
			nHour     = (lpszTime[nIndex++] - _T('0')) * 10;
			nHour    += (lpszTime[nIndex++] - _T('0'));
			nMinute   = (lpszTime[nIndex++] - _T('0')) * 10;
			nMinute  += (lpszTime[nIndex++] - _T('0'));
			break;
		default: // Should not end up here!
			ShowUsage(_T("Invalid time format"));
			return false;
	}

	if(2 == nAfterDotLength) {
		nSeconds  = (lpszTime[nDotIndex + 1] - _T('0')) * 10;
		nSeconds += (lpszTime[nDotIndex + 2] - _T('0'));
	} else {
		nSeconds = 0;
	}

	st.wYear = nCentury * 100 + nYear;
	st.wMonth = nMonth;
	st.wDay = nDay;
	st.wHour = nHour;
	st.wMinute = nMinute;
	st.wSecond = nSeconds;
	st.wMilliseconds = 0;

	
	FILETIME ft;
	if(!SystemTimeToFileTime(&st, &ft)) {
		PrintError(_T("Specified date"), GetLastError());
		ShowUsage();
		return false;
	}

	if(!LocalFileTimeToFileTime(&ft, ts)) {
		PrintError(_T("Specified date"), GetLastError());
		ShowUsage();
		return false;
	}

	return true;
}

//int _tmain(int argc, LPTSTR argv[])
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
	LPTSTR    lpszTemplateFile;
	LPTSTR    lpszTime;
	int       iFileArg;
	WORD      wOpts;
	FILETIME  tsUserTime;
	FILETIME  tsATime;
	FILETIME  tsMTime;
	FILETIME  tsCTime;
	int       argc;
	LPTSTR   *argv = CommandLineToArgvW(lpCmdLine, &argc);

	if(!ParseOptions(argc - 1, argv + 1, iFileArg, lpszTemplateFile, lpszTime, wOpts))
		return -1;

	++iFileArg; // Adjust for executable
	
	if(wOpts & OPT_USER_TIME) {
		if(!ParseTime(lpszTime, &tsUserTime)) 
			return -1;

		tsATime = tsMTime = tsCTime = tsUserTime;
	} else if(wOpts & OPT_USE_TEMPLATE) {
		if(!GetFileTimes(lpszTemplateFile, &tsATime, &tsMTime, &tsCTime))
			return -1;
	} else {
		SYSTEMTIME  now;

		GetSystemTime(&now);
		if(!SystemTimeToFileTime(&now, &tsUserTime)) {
			PrintError(_T("SystemTimeToFileTime()"), GetLastError());
			ShowUsage();
			return -1;
		}

		tsATime = tsMTime = tsCTime = tsUserTime;
	}

	for(int i = iFileArg; i < argc; ++i) {
		LPCTSTR lpszFile = argv[i];

		TCHAR szPath[_MAX_PATH];
		TCHAR szDrive[_MAX_DRIVE];
		TCHAR szDir[_MAX_DIR];
		TCHAR szFname[_MAX_FNAME];
		TCHAR szExt[_MAX_EXT];
#ifdef _UNICODE
		struct _wfinddata_t sFile;
#else
		struct _finddata_t sFile;
#endif

		if(IsGlobPattern(lpszFile)) {
			_tfullpath(szPath, lpszFile, _MAX_PATH);
			_tsplitpath(szPath, szDrive, szDir, szFname, szExt);
			intptr_t hFile = _tfindfirst(szPath, &sFile);
			if(hFile != -1L) {
				do {
					if(sFile.attrib & _A_SUBDIR) continue;
					TCHAR szIterPath[_MAX_PATH];
					TCHAR szIterFname[_MAX_FNAME];
					TCHAR szIterExt[_MAX_EXT];

					_tsplitpath(sFile.name, NULL, NULL, szIterFname, szIterExt);
					_tmakepath(szIterPath, szDrive, szDir, szIterFname, szIterExt);
					DWORD dwResult = touch(
						szIterPath,
						(wOpts & OPT_MODIFY_ATIME) ? &tsATime : NULL,
						(wOpts & OPT_MODIFY_MTIME) ? &tsMTime : NULL,
						(wOpts & OPT_MODIFY_CTIME) ? &tsCTime : NULL,
						wOpts
					);

					if(ERROR_SUCCESS != dwResult) {
						PrintError(szIterPath, dwResult);
					}
				} while(_tfindnext(hFile, &sFile) == 0);
				_findclose(hFile);
			}
		} else {
			DWORD dwResult = touch(
				lpszFile,
				(wOpts & OPT_MODIFY_ATIME) ? &tsATime : NULL,
				(wOpts & OPT_MODIFY_MTIME) ? &tsMTime : NULL,
				(wOpts & OPT_MODIFY_CTIME) ? &tsCTime : NULL,
				wOpts
			);

			if(ERROR_SUCCESS != dwResult) {
				PrintError(lpszFile, dwResult);
			}
		}
	}

	return 0;
}

------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.
Get unparalleled scalability from the best Selenium testing platform available
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to