/* * @(#) winmain.c - Windows "WinMain" wrapper for C "main" entry. * Copyright (C) 2007-2009 Ivan Maidanski All rights reserved. ** * Version: 1.4 * Required: any ANSI C compiler for Windows (Win32, Win64, WinCE). */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ /* * Tested with: * Borland BCC32 (-w-par -tW), * MsDev CL (/link /subsystem:windows), * MsDev CL with MSVCRT (-MD -DWINMAIN_MSVCRT /link /subsystem:windows), * MsDev WinCE CL (-DWINMAIN_PARSECMDLINE -DWINMAIN_EMPTYENV -DUNDER_CE), * mingw32ce (-DWINMAIN_PARSECMDLINE -DWINMAIN_EMPTYENV -DWINMAIN_NOSTOREARGV). */ /* * Control macros: * UNDER_CE, WINMAIN_CALLEXIT, WINMAIN_EMPTYENV, WINMAIN_MSVCRT, * WINMAIN_NOGLOB, WINMAIN_NOSTOREARGV, WINMAIN_PARSECMDLINE, * WINMAIN_SETLOCALE, WINMAIN_TWOARGS, WINMAIN_USECRTGLOB, WINMAIN_WCHAR; * WINMAIN_CLIBDECL, WINMAIN_CONST, WINMAIN_FREE, WINMAIN_INIT, * WINMAIN_MALLOC, WINMAIN_STATIC. */ #ifndef _STDLIB_H #include /* void exit(int); */ /* void free(void *); */ /* void *malloc(size_t); */ /* int __argc; */ /* char **__argv; */ /* wchar_t **__wargv; */ /* char **_environ; */ /* wchar_t **_wenviron; */ #endif #ifndef WINMAIN_NOGLOB #ifndef _STRING_H #include /* void *memcpy(void *, const void *, size_t); */ #endif #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #ifndef _WINDOWS_H #include /* BOOL FindClose(HANDLE); */ /* HANDLE FindFirstFileA(LPCSTR, WIN32_FIND_DATAA *); */ /* HANDLE FindFirstFileW(LPCWSTR, WIN32_FIND_DATAW *); */ /* BOOL FindNextFileA(HANDLE, WIN32_FIND_DATAA *); */ /* BOOL FindNextFileW(HANDLE, WIN32_FIND_DATAW *); */ /* DWORD GetModuleFileNameA(HMODULE, LPSTR, DWORD); */ /* DWORD GetModuleFileNameW(HMODULE, LPWSTR, DWORD); */ /* LCID GetSystemDefaultLCID(void); */ /* BOOL SetThreadLocale(LCID); */ #endif #ifndef NULL #define NULL ((void *)0) #endif #ifndef WINMAIN_CLIBDECL #define WINMAIN_CLIBDECL __cdecl #endif #ifndef WINMAIN_CONST #define WINMAIN_CONST const #endif #ifndef WINMAIN_STATIC #define WINMAIN_STATIC static #endif #ifndef WINMAIN_INIT #define WINMAIN_INIT /* empty */ #endif #ifdef WINMAIN_PARSECMDLINE #ifndef WINMAIN_WCHAR #ifdef UNDER_CE #define WINMAIN_WCHAR #endif #endif #endif #ifdef WINMAIN_WCHAR #define WINMAIN_TCHAR_OF(a, w) w #else #define WINMAIN_TCHAR_OF(a, w) a #endif #define WINMAIN_CHAR_T WINMAIN_TCHAR_OF(char, wchar_t) #ifdef WINMAIN_TWOARGS #define WINMAIN_MAIN_F(ac, av, env) WINMAIN_TCHAR_OF(main, wmain)(ac, av) #else #define WINMAIN_MAIN_F(ac, av, env) WINMAIN_TCHAR_OF(main, wmain)(ac, av, env) #endif #ifdef WINMAIN_EMPTYENV #ifndef WINMAIN_TWOARGS WINMAIN_STATIC WINMAIN_CHAR_T *WINMAIN_CONST winmain_empty_environ = NULL; #endif #define WINMAIN_MAIN_ENVARG ((WINMAIN_CHAR_T **)&winmain_empty_environ) #else #define WINMAIN_MAIN_ENVARG WINMAIN_TCHAR_OF(_environ, _wenviron) #endif #ifdef WINMAIN_MSVCRT __declspec(dllimport) char **__initenv; #ifdef WINMAIN_WCHAR __declspec(dllimport) wchar_t **__winitenv; #endif #endif extern int WINMAIN_CLIBDECL WINMAIN_MAIN_F(int argc, WINMAIN_CHAR_T **targv, WINMAIN_CHAR_T **tenv); #ifdef WINMAIN_PARSECMDLINE #ifndef WINMAIN_PROGPATH_BUFSIZE #define WINMAIN_PROGPATH_BUFSIZE 512 #endif #ifndef WINMAIN_MALLOC #define WINMAIN_MALLOC malloc #endif #ifndef WINMAIN_FREE #define WINMAIN_FREE free #endif #ifndef WINMAIN_NOMEM_ABORT #define WINMAIN_NOMEM_ABORT exit(-1) #endif #ifdef WINMAIN_USECRTGLOB #ifndef WINMAIN_NOGLOB extern int _CRT_glob; #endif #endif WINMAIN_STATIC WINMAIN_CHAR_T *winmain_get_progname(void) { WINMAIN_CHAR_T *tpath = NULL; int len; WINMAIN_CHAR_T tbuf[WINMAIN_PROGPATH_BUFSIZE]; len = (int)WINMAIN_TCHAR_OF(GetModuleFileNameA, GetModuleFileNameW)(NULL, tbuf, WINMAIN_PROGPATH_BUFSIZE); if (len > 0 && (tpath = WINMAIN_MALLOC((len + 1) * sizeof(WINMAIN_CHAR_T))) != NULL) { tpath[len] = (WINMAIN_CHAR_T)0; #ifdef WINMAIN_NOGLOB while (len-- > 0) tpath[len] = tbuf[len]; #else (void)memcpy(tpath, tbuf, len * sizeof(WINMAIN_CHAR_T)); #endif } return tpath; } WINMAIN_STATIC int winmain_scan_token(int *plen, int pos, WINMAIN_CONST WINMAIN_CHAR_T *tcmdline) { int isquote = 0; if (tcmdline[pos] == '"') { isquote = 1; pos++; } for(;;) { if (tcmdline[pos] == '"') { pos++; isquote = 1 - isquote; } else { if (!tcmdline[pos] || (!isquote && (tcmdline[pos] == ' ' || tcmdline[pos] == '\t'))) break; if (tcmdline[pos] != '\\' || tcmdline[pos + 1] != '"' || ++pos == 1 || tcmdline[pos - 2] != '\\') { (*plen)++; pos++; } } } return pos; } WINMAIN_STATIC int winmain_copy_token(WINMAIN_CHAR_T *tstr, WINMAIN_CONST WINMAIN_CHAR_T *tcmdline, int pos) { int len = 0; int isquote = 0; int wildcard = 0; if (tcmdline[pos] == '"') { isquote = 1; pos++; } for(;;) { if (tcmdline[pos] == '"') { pos++; isquote = 1 - isquote; } else { if (!tcmdline[pos] || (!isquote && (tcmdline[pos] == ' ' || tcmdline[pos] == '\t'))) break; if (tcmdline[pos] != '\\') { #ifndef WINMAIN_NOGLOB if ((tcmdline[pos] == '*' || tcmdline[pos] == '?') && !isquote) wildcard = 1; #endif tstr[len++] = tcmdline[pos++]; } else if (tcmdline[pos + 1] != '"' || ++pos == 1 || tcmdline[pos - 2] != '\\') tstr[len++] = tcmdline[pos++]; } } tstr[len] = (WINMAIN_CHAR_T)0; return wildcard; } #ifndef WINMAIN_NOGLOB WINMAIN_STATIC WINMAIN_CHAR_T **winmain_grow_argv(WINMAIN_CHAR_T **targv, int *pcapacity) { int newsize = *pcapacity / 3 + *pcapacity + 3; WINMAIN_CHAR_T **tnewargv = WINMAIN_MALLOC((newsize + 1) * sizeof(void *)); if (tnewargv != NULL) { (void)memcpy(tnewargv, targv, *pcapacity * sizeof(void *)); *pcapacity = newsize; WINMAIN_FREE(targv); } return tnewargv; } WINMAIN_STATIC WINMAIN_CHAR_T **winmain_argv_adjsize(WINMAIN_CHAR_T **targv, int argc) { WINMAIN_CHAR_T **tnewargv; if ((tnewargv = WINMAIN_MALLOC((argc + 1) * sizeof(void *))) != NULL) { (void)memcpy(tnewargv, targv, argc * sizeof(void *)); WINMAIN_FREE(targv); targv = tnewargv; } return targv; } WINMAIN_STATIC WINMAIN_CHAR_T **winmain_process_wildcards( WINMAIN_CHAR_T **targv, int *pindex, int *pargc, int *pcapacity) { HANDLE handle; WINMAIN_CHAR_T *tstr = targv[*pindex]; WINMAIN_CHAR_T *tpath; int pos; int len; int found; WINMAIN_TCHAR_OF(WIN32_FIND_DATAA, WIN32_FIND_DATAW) finddata; if ((handle = WINMAIN_TCHAR_OF(FindFirstFileA, FindFirstFileW)(tstr, &finddata)) != INVALID_HANDLE_VALUE) { pos = 0; while (tstr[pos]) pos++; while (pos-- > 0) if (tstr[pos] == '\\' || tstr[pos] == '/') break; if (++pos == 0 && tstr[1] == ':' && ((tstr[0] >= 'A' && tstr[0] <= 'Z') || (tstr[0] >= 'a' && tstr[0] <= 'z'))) pos = 2; found = 0; do { if (finddata.cFileName[0] != '.' || (finddata.cFileName[1] && (finddata.cFileName[1] != '.' || finddata.cFileName[2]))) { if (*pargc > *pcapacity && (targv = winmain_grow_argv(targv, pcapacity)) == NULL) break; len = 0; while (finddata.cFileName[len]) len++; if ((tpath = WINMAIN_MALLOC((pos + len + 1) * sizeof(WINMAIN_CHAR_T))) == NULL) { targv = NULL; break; } if (pos > 0) (void)memcpy(tpath, tstr, pos * sizeof(WINMAIN_CHAR_T)); (void)memcpy(&tpath[pos], finddata.cFileName, len * sizeof(WINMAIN_CHAR_T)); tpath[pos + len] = (WINMAIN_CHAR_T)0; targv[(*pindex)++] = tpath; (*pargc)++; found = 1; } } while (WINMAIN_TCHAR_OF(FindNextFileA, FindNextFileW)(handle, &finddata)); (void)FindClose(handle); if (found) { (*pindex)--; (*pargc)--; WINMAIN_FREE(tstr); } } return targv; } #endif /* ! WINMAIN_NOGLOB */ WINMAIN_STATIC WINMAIN_CHAR_T **winmain_parse_cmdline(int *pargc, WINMAIN_CONST WINMAIN_CHAR_T *tcmdline) { WINMAIN_CHAR_T **targv; int argc = 1; int index; int start; int pos = 0; int len = 0; #ifndef WINMAIN_NOGLOB int capacity; #endif do { while (tcmdline[pos] == ' ' || tcmdline[pos] == '\t') pos++; if (!tcmdline[pos]) break; pos = winmain_scan_token(&len, pos, tcmdline); argc++; } while (tcmdline[pos++]); if ((targv = WINMAIN_MALLOC((argc + 1) * sizeof(void *))) == NULL || (targv[0] = winmain_get_progname()) == NULL) WINMAIN_NOMEM_ABORT; pos = 0; #ifndef WINMAIN_NOGLOB capacity = argc; #endif for (index = 1; index < argc; index++) { while (tcmdline[pos] == ' ' || tcmdline[pos] == '\t') pos++; start = pos; len = 0; pos = winmain_scan_token(&len, pos, tcmdline) + 1; if ((targv[index] = WINMAIN_MALLOC((len + 1) * sizeof(WINMAIN_CHAR_T))) == NULL) WINMAIN_NOMEM_ABORT; #ifdef WINMAIN_NOGLOB (void)winmain_copy_token(targv[index], tcmdline, start); #else if (winmain_copy_token(targv[index], tcmdline, start) && #ifdef WINMAIN_USECRTGLOB _CRT_glob && #endif (targv = winmain_process_wildcards(targv, &index, &argc, &capacity)) == NULL) WINMAIN_NOMEM_ABORT; #endif } #ifndef WINMAIN_NOGLOB if (argc < capacity) targv = winmain_argv_adjsize(targv, argc); #endif targv[argc] = NULL; *pargc = argc; return targv; } #endif /* WINMAIN_PARSECMDLINE */ /*ARGSUSED*/ int WINAPI /* APIENTRY */ #ifdef UNDER_CE WinMain(HINSTANCE inst, HINSTANCE previnst, LPWSTR cmdline, int cmdshow) #else WINMAIN_TCHAR_OF(WinMain, wWinMain)(HINSTANCE inst, HINSTANCE previnst, WINMAIN_TCHAR_OF(LPSTR, LPWSTR) cmdline, int cmdshow) #endif { int res; #ifdef WINMAIN_PARSECMDLINE WINMAIN_CHAR_T **targv; #endif WINMAIN_INIT; #ifdef WINMAIN_SETLOCALE SetThreadLocale(GetSystemDefaultLCID()); #endif #ifdef WINMAIN_MSVCRT __initenv = _environ; #ifdef WINMAIN_WCHAR __winitenv = _wenviron; #endif #endif #ifdef WINMAIN_PARSECMDLINE targv = winmain_parse_cmdline(&res, cmdline); #ifndef WINMAIN_NOSTOREARGV WINMAIN_TCHAR_OF(__argv, __wargv) = targv; __argc = res; #endif res = WINMAIN_MAIN_F(res, targv, WINMAIN_MAIN_ENVARG); #else res = WINMAIN_MAIN_F(__argc, WINMAIN_TCHAR_OF(__argv, __wargv), WINMAIN_MAIN_ENVARG); #endif #ifdef WINMAIN_CALLEXIT if (inst) exit(res); #endif return res; }