+BOOL
+GrowIfNecessary ( UINT needed, LPTSTR* ret, UINT* retlen )
+{
+ if ( *ret && needed < *retlen )
+ return TRUE;
+ *retlen = needed;
+ if ( *ret )
+ free ( *ret );
+ *ret = (LPTSTR)malloc ( *retlen * sizeof(TCHAR) );
+ if ( !*ret )
+ SetLastError ( ERROR_OUTOFMEMORY );
+ return *ret != NULL;
+}
+
+LPCTSTR
+GetEnvVarOrSpecial ( LPCTSTR varName )
+{
+ static LPTSTR ret = NULL;
+ static UINT retlen = 0;
+ UINT size;
+
+ size = GetEnvironmentVariable ( varName, ret, retlen );
+ if ( size > retlen )
+ {
+ if ( !GrowIfNecessary ( size, &ret, &retlen ) )
+ return NULL;
+ size = GetEnvironmentVariable ( varName, ret, retlen );
+ }
+ if ( size )
+ return ret;
+
+ /* env var doesn't exist, look for a "special" one */
+ /* %CD% */
+ if (_tcsicmp(varName,_T("cd")) ==0)
+ {
+ size = GetCurrentDirectory ( retlen, ret );
+ if ( size > retlen )
+ {
+ if ( !GrowIfNecessary ( size, &ret, &retlen ) )
+ return NULL;
+ size = GetCurrentDirectory ( retlen, ret );
+ }
+ if ( !size )
+ return NULL;
+ return ret;
+ }
+ /* %TIME% */
+ else if (_tcsicmp(varName,_T("time")) ==0)
+ {
+ SYSTEMTIME t;
+ if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
+ return NULL;
+ GetSystemTime(&t);
+ _sntprintf ( ret, retlen, _T("%02d%c%02d%c%02d%c%02d"),
+ t.wHour, cTimeSeparator, t.wMinute, cTimeSeparator,
+ t.wSecond, cDecimalSeparator, t.wMilliseconds );
+ return ret;
+ }
+ /* %DATE% */
+ else if (_tcsicmp(varName,_T("date")) ==0)
+ {
+ LPTSTR tmp;
+
+ if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
+ return NULL;
+ size = GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, _T("ddd"), ret, retlen );
+ /* TODO FIXME - test whether GetDateFormat() can return a value indicating the buffer wasn't big enough */
+ if ( !size )
+ return NULL;
+ tmp = ret + _tcslen(ret);
+ *tmp++ = _T(' ');
+ size = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, tmp, retlen-(tmp-ret));
+ /* TODO FIXME - test whether GetDateFormat() can return a value indicating the buffer wasn't big enough */
+ if ( !size )
+ return NULL;
+ return ret;
+ }
+
+ /* %RANDOM% */
+ else if (_tcsicmp(varName,_T("random")) ==0)
+ {
+ if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
+ return NULL;
+ /* Get random number */
+ _itot(rand(),ret,10);
+ return ret;
+ }
+
+ /* %CMDCMDLINE% */
+ else if (_tcsicmp(varName,_T("cmdcmdline")) ==0)
+ {
+ return GetCommandLine();
+ }
+
+ /* %CMDEXTVERSION% */
+ else if (_tcsicmp(varName,_T("cmdextversion")) ==0)
+ {
+ if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
+ return NULL;
+ /* Set version number to 2 */
+ _itot(2,ret,10);
+ return ret;
+ }
+
+ /* %ERRORLEVEL% */
+ else if (_tcsicmp(varName,_T("errorlevel")) ==0)
+ {
+ if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
+ return NULL;
+ _itot(nErrorLevel,ret,10);
+ return ret;
+ }
+
+ GrowIfNecessary(_tcslen(varName) + 2, &ret, &retlen);
+ _stprintf(ret,_T("%%%s%%"),varName);
+ return ret; /* not found - return orginal string */
+}
+
+LPCTSTR
+GetParsedEnvVar ( LPCTSTR varName, UINT* varNameLen, BOOL ModeSetA )
+{
+ static LPTSTR ret = NULL;
+ static UINT retlen = 0;
+ LPTSTR p, tmp;
+ UINT size;
+
+ if ( varNameLen )
+ *varNameLen = 0;
+ SetLastError(0);
+ if ( *varName++ != '%' )
+ return NULL;
+ switch ( *varName )
+ {
+ case _T('0'):
+ case _T('1'):
+ case _T('2'):
+ case _T('3'):
+ case _T('4'):
+ case _T('5'):
+ case _T('6'):
+ case _T('7'):
+ case _T('8'):
+ case _T('9'):
+ if ((tmp = FindArg (*varName - _T('0'))))
+ {
+ if ( varNameLen )
+ *varNameLen = 2;
+ if ( !*tmp )
+ return _T("");
+ if ( !GrowIfNecessary ( _tcslen(tmp)+1, &ret, &retlen ) )
+ return NULL;
+ _tcscpy ( ret, tmp );
+ return ret;
+ }
+ if ( !GrowIfNecessary ( 3, &ret, &retlen ) )
+ return NULL;
+ ret[0] = _T('%');
+ ret[1] = *varName;
+ ret[2] = 0;
+ if ( varNameLen )
+ *varNameLen = 2;
+ return ret;
+
+ case _T('%'):
+ if ( !GrowIfNecessary ( 2, &ret, &retlen ) )
+ return NULL;
+ ret[0] = _T('%');
+ ret[1] = 0;
+ if ( varNameLen )
+ *varNameLen = 2;
+ return ret;
+
+ case _T('?'):
+ /* TODO FIXME 10 is only max size for 32-bit */
+ if ( !GrowIfNecessary ( 11, &ret, &retlen ) )
+ return NULL;
+ _sntprintf ( ret, retlen, _T("%u"), nErrorLevel);
+ ret[retlen-1] = 0;
+ if ( varNameLen )
+ *varNameLen = 2;
+ return ret;
+ }
+ if ( ModeSetA )
+ {
+ /* HACK for set/a */
+ if ( !GrowIfNecessary ( 2, &ret, &retlen ) )
+ return NULL;
+ ret[0] = _T('%');
+ ret[1] = 0;
+ if ( varNameLen )
+ *varNameLen = 1;
+ return ret;
+ }
+ p = _tcschr ( varName, _T('%') );
+ if ( !p )
+ {
+ SetLastError ( ERROR_INVALID_PARAMETER );
+ return NULL;
+ }
+ size = p-varName;
+ if ( varNameLen )
+ *varNameLen = size + 2;
+ p = alloca ( (size+1) * sizeof(TCHAR) );
+ memmove ( p, varName, size * sizeof(TCHAR) );
+ p[size] = 0;
+ varName = p;
+ return GetEnvVarOrSpecial ( varName );
+}
+