2006-02-16 23:23:37 +00:00
|
|
|
|
/*
|
|
|
|
|
* FILECOMP.C - handles filename completion.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Comments:
|
|
|
|
|
*
|
|
|
|
|
* 30-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
|
|
|
|
* moved from command.c file
|
|
|
|
|
* made second TAB display list of filename matches
|
|
|
|
|
* made filename be lower case if last character typed is lower case
|
|
|
|
|
*
|
2007-05-05 11:32:25 +00:00
|
|
|
|
* 25-Jan-1999 (Eric Kohl)
|
2006-02-16 23:23:37 +00:00
|
|
|
|
* Cleanup. Unicode safe!
|
|
|
|
|
*
|
|
|
|
|
* 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
|
|
|
|
|
* Make the file listing readable when there is a lot of long names.
|
|
|
|
|
*
|
|
|
|
|
|
|
|
|
|
* 05-Jul-2004 (Jens Collin <jens.collin@lakhei.com>)
|
|
|
|
|
* Now expands lfn even when trailing " is omitted.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-01-24 23:00:42 +00:00
|
|
|
|
#include "precomp.h"
|
2006-02-16 23:23:37 +00:00
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_UNIX_FILENAME_COMPLETION
|
|
|
|
|
|
|
|
|
|
VOID CompleteFilename (LPTSTR str, UINT charcount)
|
|
|
|
|
{
|
2013-06-30 12:27:18 +00:00
|
|
|
|
WIN32_FIND_DATA file;
|
|
|
|
|
HANDLE hFile;
|
|
|
|
|
INT curplace = 0;
|
|
|
|
|
INT start;
|
|
|
|
|
INT count;
|
|
|
|
|
INT step;
|
|
|
|
|
INT c = 0;
|
|
|
|
|
BOOL found_dot = FALSE;
|
|
|
|
|
BOOL perfectmatch = TRUE;
|
|
|
|
|
TCHAR path[MAX_PATH];
|
|
|
|
|
TCHAR fname[MAX_PATH];
|
|
|
|
|
TCHAR maxmatch[MAX_PATH] = _T("");
|
|
|
|
|
TCHAR directory[MAX_PATH];
|
|
|
|
|
LPCOMMAND cmds_ptr;
|
|
|
|
|
|
|
|
|
|
/* expand current file name */
|
|
|
|
|
count = charcount - 1;
|
|
|
|
|
if (count < 0)
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
/* find how many '"'s there is typed already. */
|
|
|
|
|
step = count;
|
|
|
|
|
while (step > 0)
|
|
|
|
|
{
|
|
|
|
|
if (str[step] == _T('"'))
|
|
|
|
|
c++;
|
|
|
|
|
step--;
|
|
|
|
|
}
|
|
|
|
|
/* if c is odd, then user typed " before name, else not. */
|
|
|
|
|
|
|
|
|
|
/* find front of word */
|
|
|
|
|
if (str[count] == _T('"') || (c % 2))
|
|
|
|
|
{
|
|
|
|
|
count--;
|
|
|
|
|
while (count > 0 && str[count] != _T('"'))
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (count > 0 && str[count] != _T(' '))
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if not at beginning, go forward 1 */
|
|
|
|
|
if (str[count] == _T(' '))
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
|
|
start = count;
|
|
|
|
|
|
|
|
|
|
if (str[count] == _T('"'))
|
|
|
|
|
count++; /* don't increment start */
|
|
|
|
|
|
|
|
|
|
/* extract directory from word */
|
|
|
|
|
_tcscpy (directory, &str[count]);
|
|
|
|
|
curplace = _tcslen (directory) - 1;
|
|
|
|
|
|
|
|
|
|
if (curplace >= 0 && directory[curplace] == _T('"'))
|
|
|
|
|
directory[curplace--] = _T('\0');
|
|
|
|
|
|
|
|
|
|
_tcscpy (path, directory);
|
|
|
|
|
|
|
|
|
|
while (curplace >= 0 && directory[curplace] != _T('\\') &&
|
2007-02-23 20:05:39 +00:00
|
|
|
|
directory[curplace] != _T('/') &&
|
2013-06-30 12:27:18 +00:00
|
|
|
|
directory[curplace] != _T(':'))
|
|
|
|
|
{
|
|
|
|
|
directory[curplace] = 0;
|
|
|
|
|
curplace--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* look for a '.' in the filename */
|
|
|
|
|
for (count = _tcslen (directory); path[count] != _T('\0'); count++)
|
|
|
|
|
{
|
|
|
|
|
if (path[count] == _T('.'))
|
|
|
|
|
{
|
|
|
|
|
found_dot = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found_dot)
|
|
|
|
|
_tcscat (path, _T("*"));
|
|
|
|
|
else
|
|
|
|
|
_tcscat (path, _T("*.*"));
|
|
|
|
|
|
|
|
|
|
/* current fname */
|
|
|
|
|
curplace = 0;
|
|
|
|
|
|
|
|
|
|
hFile = FindFirstFile (path, &file);
|
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
/* find anything */
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
/* ignore "." and ".." */
|
|
|
|
|
if (!_tcscmp (file.cFileName, _T(".")) ||
|
|
|
|
|
!_tcscmp (file.cFileName, _T("..")))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
_tcscpy (fname, file.cFileName);
|
|
|
|
|
|
|
|
|
|
if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
|
_tcscat (fname, _T("\\"));
|
|
|
|
|
|
|
|
|
|
if (!maxmatch[0] && perfectmatch)
|
|
|
|
|
{
|
|
|
|
|
_tcscpy(maxmatch, fname);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (count = 0; maxmatch[count] && fname[count]; count++)
|
|
|
|
|
{
|
|
|
|
|
if (tolower(maxmatch[count]) != tolower(fname[count]))
|
|
|
|
|
{
|
|
|
|
|
perfectmatch = FALSE;
|
|
|
|
|
maxmatch[count] = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (maxmatch[count] == _T('\0') &&
|
|
|
|
|
fname[count] != _T('\0'))
|
|
|
|
|
perfectmatch = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (FindNextFile (hFile, &file));
|
|
|
|
|
|
|
|
|
|
FindClose (hFile);
|
|
|
|
|
|
|
|
|
|
/* only quote if the filename contains spaces */
|
|
|
|
|
if (_tcschr(directory, _T(' ')) ||
|
|
|
|
|
_tcschr(maxmatch, _T(' ')))
|
|
|
|
|
{
|
|
|
|
|
str[start] = _T('\"');
|
|
|
|
|
_tcscpy (&str[start+1], directory);
|
|
|
|
|
_tcscat (&str[start], maxmatch);
|
|
|
|
|
_tcscat (&str[start], _T("\"") );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_tcscpy (&str[start], directory);
|
|
|
|
|
_tcscat (&str[start], maxmatch);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!perfectmatch)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
MessageBeep (-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* no match found - search for internal command */
|
|
|
|
|
for (cmds_ptr = cmds; cmds_ptr->name; cmds_ptr++)
|
|
|
|
|
{
|
|
|
|
|
if (!_tcsnicmp (&str[start], cmds_ptr->name,
|
|
|
|
|
_tcslen (&str[start])))
|
|
|
|
|
{
|
|
|
|
|
/* return the mach only if it is unique */
|
|
|
|
|
if (_tcsnicmp (&str[start], (cmds_ptr+1)->name, _tcslen (&str[start])))
|
|
|
|
|
_tcscpy (&str[start], cmds_ptr->name);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MessageBeep (-1);
|
|
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* returns 1 if at least one match, else returns 0
|
|
|
|
|
*/
|
|
|
|
|
BOOL ShowCompletionMatches (LPTSTR str, INT charcount)
|
|
|
|
|
{
|
2013-06-30 12:27:18 +00:00
|
|
|
|
WIN32_FIND_DATA file;
|
|
|
|
|
HANDLE hFile;
|
|
|
|
|
BOOL found_dot = FALSE;
|
|
|
|
|
INT curplace = 0;
|
|
|
|
|
INT count;
|
|
|
|
|
TCHAR path[MAX_PATH];
|
|
|
|
|
TCHAR fname[MAX_PATH];
|
|
|
|
|
TCHAR directory[MAX_PATH];
|
|
|
|
|
SHORT screenwidth;
|
|
|
|
|
|
|
|
|
|
/* expand current file name */
|
|
|
|
|
count = charcount - 1;
|
|
|
|
|
if (count < 0)
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
/* find front of word */
|
|
|
|
|
if (str[count] == _T('"'))
|
|
|
|
|
{
|
|
|
|
|
count--;
|
|
|
|
|
while (count > 0 && str[count] != _T('"'))
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (count > 0 && str[count] != _T(' '))
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if not at beginning, go forward 1 */
|
|
|
|
|
if (str[count] == _T(' '))
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
|
|
if (str[count] == _T('"'))
|
2015-07-19 08:21:58 +00:00
|
|
|
|
count++;
|
2013-06-30 12:27:18 +00:00
|
|
|
|
|
|
|
|
|
/* extract directory from word */
|
|
|
|
|
_tcscpy (directory, &str[count]);
|
|
|
|
|
curplace = _tcslen (directory) - 1;
|
|
|
|
|
|
|
|
|
|
if (curplace >= 0 && directory[curplace] == _T('"'))
|
|
|
|
|
directory[curplace--] = _T('\0');
|
|
|
|
|
|
|
|
|
|
_tcscpy (path, directory);
|
|
|
|
|
|
|
|
|
|
while (curplace >= 0 &&
|
|
|
|
|
directory[curplace] != _T('\\') &&
|
|
|
|
|
directory[curplace] != _T(':'))
|
|
|
|
|
{
|
|
|
|
|
directory[curplace] = 0;
|
|
|
|
|
curplace--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* look for a . in the filename */
|
|
|
|
|
for (count = _tcslen (directory); path[count] != _T('\0'); count++)
|
|
|
|
|
{
|
|
|
|
|
if (path[count] == _T('.'))
|
|
|
|
|
{
|
|
|
|
|
found_dot = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found_dot)
|
|
|
|
|
_tcscat (path, _T("*"));
|
|
|
|
|
else
|
|
|
|
|
_tcscat (path, _T("*.*"));
|
|
|
|
|
|
|
|
|
|
/* current fname */
|
|
|
|
|
curplace = 0;
|
|
|
|
|
|
|
|
|
|
hFile = FindFirstFile (path, &file);
|
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
UINT longestfname = 0;
|
|
|
|
|
/* Get the size of longest filename first. */
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (_tcslen(file.cFileName) > longestfname)
|
|
|
|
|
{
|
|
|
|
|
longestfname = _tcslen(file.cFileName);
|
|
|
|
|
/* Directories get extra brackets around them. */
|
|
|
|
|
if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
|
longestfname += 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (FindNextFile (hFile, &file));
|
|
|
|
|
FindClose (hFile);
|
|
|
|
|
|
|
|
|
|
hFile = FindFirstFile (path, &file);
|
|
|
|
|
|
|
|
|
|
/* Count the highest number of columns */
|
2016-10-10 19:15:07 +00:00
|
|
|
|
GetScreenSize(&screenwidth, NULL);
|
2013-06-30 12:27:18 +00:00
|
|
|
|
|
|
|
|
|
/* For counting columns of output */
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
/* Increase by the number of spaces behind file name */
|
|
|
|
|
longestfname += 3;
|
|
|
|
|
|
|
|
|
|
/* find anything */
|
2013-07-02 23:07:15 +00:00
|
|
|
|
ConOutChar(_T('\n'));
|
2013-06-30 12:27:18 +00:00
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
/* ignore . and .. */
|
|
|
|
|
if (!_tcscmp (file.cFileName, _T(".")) ||
|
|
|
|
|
!_tcscmp (file.cFileName, _T("..")))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
|
_stprintf (fname, _T("[%s]"), file.cFileName);
|
|
|
|
|
else
|
|
|
|
|
_tcscpy (fname, file.cFileName);
|
|
|
|
|
|
|
|
|
|
ConOutPrintf (_T("%*s"), - longestfname, fname);
|
|
|
|
|
count++;
|
|
|
|
|
/* output as much columns as fits on the screen */
|
|
|
|
|
if (count >= (screenwidth / longestfname))
|
|
|
|
|
{
|
|
|
|
|
/* print the new line only if we aren't on the
|
|
|
|
|
* last column, in this case it wraps anyway */
|
|
|
|
|
if (count * longestfname != (UINT)screenwidth)
|
2013-07-02 23:07:15 +00:00
|
|
|
|
ConOutChar(_T('\n'));
|
2013-06-30 12:27:18 +00:00
|
|
|
|
count = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (FindNextFile (hFile, &file));
|
|
|
|
|
|
|
|
|
|
FindClose (hFile);
|
|
|
|
|
|
|
|
|
|
if (count)
|
2013-07-02 23:07:15 +00:00
|
|
|
|
ConOutChar(_T('\n'));
|
2013-06-30 12:27:18 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* no match found */
|
|
|
|
|
MessageBeep (-1);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
2006-02-16 23:23:37 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_4NT_FILENAME_COMPLETION
|
|
|
|
|
|
|
|
|
|
typedef struct _FileName
|
|
|
|
|
{
|
2013-06-30 12:27:18 +00:00
|
|
|
|
TCHAR Name[MAX_PATH];
|
2006-02-16 23:23:37 +00:00
|
|
|
|
} FileName;
|
|
|
|
|
|
|
|
|
|
VOID FindPrefixAndSuffix(LPTSTR strIN, LPTSTR szPrefix, LPTSTR szSuffix)
|
|
|
|
|
{
|
2013-06-30 12:27:18 +00:00
|
|
|
|
/* String that is to be examined */
|
|
|
|
|
TCHAR str[MAX_PATH];
|
|
|
|
|
/* temp pointers to used to find needed parts */
|
|
|
|
|
TCHAR * szSearch;
|
|
|
|
|
TCHAR * szSearch1;
|
|
|
|
|
TCHAR * szSearch2;
|
|
|
|
|
TCHAR * szSearch3;
|
|
|
|
|
/* number of quotes in the string */
|
|
|
|
|
INT nQuotes = 0;
|
|
|
|
|
/* used in for loops */
|
|
|
|
|
UINT i;
|
|
|
|
|
/* Char number to break the string at */
|
|
|
|
|
INT PBreak = 0;
|
|
|
|
|
INT SBreak = 0;
|
|
|
|
|
/* when phrasing a string, this tells weather
|
|
|
|
|
you are inside quotes ot not. */
|
|
|
|
|
BOOL bInside = FALSE;
|
|
|
|
|
|
|
|
|
|
szPrefix[0] = _T('\0');
|
|
|
|
|
szSuffix[0] = _T('\0');
|
|
|
|
|
|
|
|
|
|
/* Copy over the string to later be edited */
|
|
|
|
|
_tcscpy(str,strIN);
|
|
|
|
|
|
|
|
|
|
/* Count number of " */
|
|
|
|
|
for(i = 0; i < _tcslen(str); i++)
|
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (str[i] == _T('\"'))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
nQuotes++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find the prefix and suffix */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (nQuotes % 2 && nQuotes >= 1)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
/* Odd number of quotes. Just start from the last " */
|
|
|
|
|
/* THis is the way MS does it, and is an easy way out */
|
|
|
|
|
szSearch = _tcsrchr(str, _T('\"'));
|
|
|
|
|
/* Move to the next char past the " */
|
|
|
|
|
szSearch++;
|
|
|
|
|
_tcscpy(szSuffix,szSearch);
|
|
|
|
|
/* Find the one closest to end */
|
|
|
|
|
szSearch1 = _tcsrchr(str, _T('\"'));
|
|
|
|
|
szSearch2 = _tcsrchr(str, _T('\\'));
|
|
|
|
|
szSearch3 = _tcsrchr(str, _T('.'));
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (szSearch2 != NULL && _tcslen(szSearch1) > _tcslen(szSearch2))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
szSearch = szSearch2;
|
2013-06-30 16:10:54 +00:00
|
|
|
|
else if (szSearch3 != NULL && _tcslen(szSearch1) > _tcslen(szSearch3))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
szSearch = szSearch3;
|
|
|
|
|
else
|
|
|
|
|
szSearch = szSearch1;
|
|
|
|
|
/* Move one char past */
|
|
|
|
|
szSearch++;
|
|
|
|
|
szSearch[0] = _T('\0');
|
|
|
|
|
_tcscpy(szPrefix,str);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!_tcschr(str, _T(' ')))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
/* No spaces, everything goes to Suffix */
|
|
|
|
|
_tcscpy(szSuffix,str);
|
|
|
|
|
/* look for a slash just in case */
|
|
|
|
|
szSearch = _tcsrchr(str, _T('\\'));
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (szSearch)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
szSearch++;
|
|
|
|
|
szSearch[0] = _T('\0');
|
|
|
|
|
_tcscpy(szPrefix,str);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
szPrefix[0] = _T('\0');
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!nQuotes)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
/* No quotes, and there is a space*/
|
|
|
|
|
/* Take it after the last space */
|
|
|
|
|
szSearch = _tcsrchr(str, _T(' '));
|
|
|
|
|
szSearch++;
|
|
|
|
|
_tcscpy(szSuffix,szSearch);
|
|
|
|
|
/* Find the closest to the end space or \ */
|
|
|
|
|
_tcscpy(str,strIN);
|
|
|
|
|
szSearch1 = _tcsrchr(str, _T(' '));
|
|
|
|
|
szSearch2 = _tcsrchr(str, _T('\\'));
|
|
|
|
|
szSearch3 = _tcsrchr(str, _T('/'));
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (szSearch2 != NULL && _tcslen(szSearch1) > _tcslen(szSearch2))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
szSearch = szSearch2;
|
2013-06-30 16:10:54 +00:00
|
|
|
|
else if (szSearch3 != NULL && _tcslen(szSearch1) > _tcslen(szSearch3))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
szSearch = szSearch3;
|
|
|
|
|
else
|
|
|
|
|
szSearch = szSearch1;
|
|
|
|
|
szSearch++;
|
|
|
|
|
szSearch[0] = _T('\0');
|
|
|
|
|
_tcscpy(szPrefix,str);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* All else fails and there is a lot of quotes, spaces and |
|
|
|
|
|
Then we search through and find the last space or \ that is
|
|
|
|
|
not inside a quotes */
|
|
|
|
|
for(i = 0; i < _tcslen(str); i++)
|
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (str[i] == _T('\"'))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
bInside = !bInside;
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (str[i] == _T(' ') && !bInside)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
SBreak = i;
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if ((str[i] == _T(' ') || str[i] == _T('\\')) && !bInside)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
PBreak = i;
|
|
|
|
|
}
|
|
|
|
|
SBreak++;
|
|
|
|
|
PBreak++;
|
|
|
|
|
_tcscpy(szSuffix,&strIN[SBreak]);
|
|
|
|
|
strIN[PBreak] = _T('\0');
|
|
|
|
|
_tcscpy(szPrefix,strIN);
|
|
|
|
|
if (szPrefix[_tcslen(szPrefix) - 2] == _T('\"') &&
|
|
|
|
|
szPrefix[_tcslen(szPrefix) - 1] != _T(' '))
|
|
|
|
|
{
|
|
|
|
|
/* need to remove the " right before a \ at the end to
|
|
|
|
|
allow the next stuff to stay inside one set of quotes
|
|
|
|
|
otherwise you would have multiple sets of quotes*/
|
|
|
|
|
_tcscpy(&szPrefix[_tcslen(szPrefix) - 2],_T("\\"));
|
|
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
}
|
2008-05-17 08:49:39 +00:00
|
|
|
|
|
|
|
|
|
int __cdecl compare(const void *arg1,const void *arg2)
|
|
|
|
|
{
|
2013-06-30 12:27:18 +00:00
|
|
|
|
FileName * File1;
|
|
|
|
|
FileName * File2;
|
|
|
|
|
INT ret;
|
|
|
|
|
|
|
|
|
|
File1 = cmd_alloc(sizeof(FileName));
|
|
|
|
|
if (!File1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
File2 = cmd_alloc(sizeof(FileName));
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!File2)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
cmd_free(File1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(File1,arg1,sizeof(FileName));
|
|
|
|
|
memcpy(File2,arg2,sizeof(FileName));
|
|
|
|
|
|
|
|
|
|
/* ret = _tcsicmp(File1->Name, File2->Name); */
|
|
|
|
|
ret = lstrcmpi(File1->Name, File2->Name);
|
|
|
|
|
|
|
|
|
|
cmd_free(File1);
|
|
|
|
|
cmd_free(File2);
|
|
|
|
|
return ret;
|
2008-05-17 08:49:39 +00:00
|
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
|
2012-04-14 22:22:20 +00:00
|
|
|
|
BOOL
|
|
|
|
|
FileNameContainsSpecialCharacters(LPTSTR pszFileName)
|
|
|
|
|
{
|
|
|
|
|
TCHAR chr;
|
|
|
|
|
|
|
|
|
|
while ((chr = *pszFileName++) != _T('\0'))
|
|
|
|
|
{
|
|
|
|
|
if ((chr == _T(' ')) ||
|
|
|
|
|
(chr == _T('!')) ||
|
|
|
|
|
(chr == _T('%')) ||
|
|
|
|
|
(chr == _T('&')) ||
|
|
|
|
|
(chr == _T('(')) ||
|
|
|
|
|
(chr == _T(')')) ||
|
|
|
|
|
(chr == _T('{')) ||
|
|
|
|
|
(chr == _T('}')) ||
|
|
|
|
|
(chr == _T('[')) ||
|
|
|
|
|
(chr == _T(']')) ||
|
|
|
|
|
(chr == _T('=')) ||
|
|
|
|
|
(chr == _T('\'')) ||
|
|
|
|
|
(chr == _T('`')) ||
|
|
|
|
|
(chr == _T(',')) ||
|
|
|
|
|
(chr == _T(';')) ||
|
|
|
|
|
(chr == _T('^')) ||
|
|
|
|
|
(chr == _T('~')) ||
|
|
|
|
|
(chr == _T('+')) ||
|
|
|
|
|
(chr == 0xB4)) // '<27>'
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-02-16 23:23:37 +00:00
|
|
|
|
VOID CompleteFilename (LPTSTR strIN, BOOL bNext, LPTSTR strOut, UINT cusor)
|
|
|
|
|
{
|
2013-06-30 12:27:18 +00:00
|
|
|
|
/* Length of string before we complete it */
|
|
|
|
|
INT_PTR StartLength;
|
|
|
|
|
/* Length of string after completed */
|
|
|
|
|
//INT EndLength;
|
|
|
|
|
/* The number of chars added too it */
|
|
|
|
|
//static INT DiffLength = 0;
|
|
|
|
|
/* Used to find and assemble the string that is returned */
|
|
|
|
|
TCHAR szBaseWord[MAX_PATH];
|
|
|
|
|
TCHAR szPrefix[MAX_PATH];
|
2014-10-17 16:39:54 +00:00
|
|
|
|
TCHAR szOriginal[MAX_PATH];
|
2013-06-30 12:27:18 +00:00
|
|
|
|
TCHAR szSearchPath[MAX_PATH];
|
|
|
|
|
/* Save the strings used last time, so if they hit tab again */
|
|
|
|
|
static TCHAR LastReturned[MAX_PATH];
|
|
|
|
|
static TCHAR LastSearch[MAX_PATH];
|
|
|
|
|
static TCHAR LastPrefix[MAX_PATH];
|
|
|
|
|
/* Used to search for files */
|
|
|
|
|
HANDLE hFile;
|
|
|
|
|
WIN32_FIND_DATA file;
|
|
|
|
|
/* List of all the files */
|
|
|
|
|
FileName * FileList = NULL;
|
|
|
|
|
/* Number of files */
|
|
|
|
|
INT FileListSize = 0;
|
|
|
|
|
/* Used for loops */
|
|
|
|
|
UINT i;
|
|
|
|
|
/* Editable string of what was passed in */
|
|
|
|
|
TCHAR str[MAX_PATH];
|
|
|
|
|
/* Keeps track of what element was last selected */
|
|
|
|
|
static INT Sel;
|
|
|
|
|
BOOL NeededQuote = FALSE;
|
|
|
|
|
BOOL ShowAll = TRUE;
|
|
|
|
|
TCHAR * line = strIN;
|
|
|
|
|
|
|
|
|
|
strOut[0] = _T('\0');
|
|
|
|
|
|
|
|
|
|
while (_istspace (*line))
|
|
|
|
|
line++;
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!_tcsnicmp (line, _T("rd "), 3) || !_tcsnicmp (line, _T("cd "), 3))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
ShowAll = FALSE;
|
|
|
|
|
|
2014-10-17 16:39:54 +00:00
|
|
|
|
/* Copy the string, str can be edited and original should not be */
|
2013-06-30 12:27:18 +00:00
|
|
|
|
_tcscpy(str,strIN);
|
2014-10-17 16:39:54 +00:00
|
|
|
|
_tcscpy(szOriginal,strIN);
|
2013-06-30 12:27:18 +00:00
|
|
|
|
|
|
|
|
|
/* Look to see if the cusor is not at the end of the string */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if ((cusor + 1) < _tcslen(str))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
str[cusor] = _T('\0');
|
|
|
|
|
|
|
|
|
|
/* Look to see if they hit tab again, if so cut off the diff length */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (_tcscmp(str,LastReturned) || !_tcslen(str))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
/* We need to know how many chars we added from the start */
|
|
|
|
|
StartLength = _tcslen(str);
|
|
|
|
|
|
|
|
|
|
/* no string, we need all files in that directory */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!StartLength)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
_tcscat(str,_T("*"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Zero it out first */
|
|
|
|
|
szBaseWord[0] = _T('\0');
|
|
|
|
|
szPrefix[0] = _T('\0');
|
|
|
|
|
|
|
|
|
|
/*What comes out of this needs to be:
|
|
|
|
|
szBaseWord = path no quotes to the object
|
|
|
|
|
szPrefix = what leads up to the filename
|
|
|
|
|
no quote at the END of the full name */
|
|
|
|
|
FindPrefixAndSuffix(str,szPrefix,szBaseWord);
|
|
|
|
|
/* Strip quotes */
|
|
|
|
|
for(i = 0; i < _tcslen(szBaseWord); )
|
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (szBaseWord[i] == _T('\"'))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
memmove(&szBaseWord[i],&szBaseWord[i + 1], _tcslen(&szBaseWord[i]) * sizeof(TCHAR));
|
|
|
|
|
else
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* clear it out */
|
|
|
|
|
memset(szSearchPath, 0, sizeof(szSearchPath));
|
|
|
|
|
|
|
|
|
|
/* Start the search for all the files */
|
|
|
|
|
GetFullPathName(szBaseWord, MAX_PATH, szSearchPath, NULL);
|
|
|
|
|
|
|
|
|
|
/* Got a device path? Fallback to the the current dir plus the short path */
|
|
|
|
|
if (szSearchPath[0] == _T('\\') && szSearchPath[1] == _T('\\') &&
|
|
|
|
|
szSearchPath[2] == _T('.') && szSearchPath[3] == _T('\\'))
|
|
|
|
|
{
|
|
|
|
|
GetCurrentDirectory(MAX_PATH, szSearchPath);
|
|
|
|
|
_tcscat(szSearchPath, _T("\\"));
|
|
|
|
|
_tcscat(szSearchPath, szBaseWord);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (StartLength > 0)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
_tcscat(szSearchPath,_T("*"));
|
|
|
|
|
}
|
|
|
|
|
_tcscpy(LastSearch,szSearchPath);
|
|
|
|
|
_tcscpy(LastPrefix,szPrefix);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_tcscpy(szSearchPath, LastSearch);
|
|
|
|
|
_tcscpy(szPrefix, LastPrefix);
|
|
|
|
|
StartLength = 0;
|
|
|
|
|
}
|
|
|
|
|
/* search for the files it might be */
|
|
|
|
|
hFile = FindFirstFile (szSearchPath, &file);
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
2014-10-17 16:39:54 +00:00
|
|
|
|
/* Assemble the original string and return */
|
|
|
|
|
_tcscpy(strOut,szOriginal);
|
2013-06-30 12:27:18 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-05 14:55:55 +00:00
|
|
|
|
/* assemble a list of all files names */
|
2013-06-30 12:27:18 +00:00
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
FileName * oldFileList = FileList;
|
|
|
|
|
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!_tcscmp (file.cFileName, _T(".")) ||
|
2013-06-30 12:27:18 +00:00
|
|
|
|
!_tcscmp (file.cFileName, _T("..")))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Don't show files when they are doing 'cd' or 'rd' */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!ShowAll &&
|
2013-06-30 12:27:18 +00:00
|
|
|
|
file.dwFileAttributes != 0xFFFFFFFF &&
|
|
|
|
|
!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add the file to the list of files */
|
|
|
|
|
FileList = cmd_realloc(FileList, ++FileListSize * sizeof(FileName));
|
|
|
|
|
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (FileList == NULL)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
/* Don't leak old buffer */
|
|
|
|
|
cmd_free(oldFileList);
|
2014-10-17 16:39:54 +00:00
|
|
|
|
/* Assemble the original string and return */
|
|
|
|
|
_tcscpy(strOut,szOriginal);
|
2013-06-30 12:27:18 +00:00
|
|
|
|
FindClose(hFile);
|
|
|
|
|
ConOutFormatMessage (GetLastError());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Copies the file name into the struct */
|
|
|
|
|
_tcscpy(FileList[FileListSize-1].Name,file.cFileName);
|
|
|
|
|
|
|
|
|
|
} while(FindNextFile(hFile,&file));
|
|
|
|
|
|
|
|
|
|
FindClose(hFile);
|
|
|
|
|
|
2014-10-17 16:39:54 +00:00
|
|
|
|
/* Check the size of the list to see if we found any matches */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (FileListSize == 0)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
2014-10-17 16:39:54 +00:00
|
|
|
|
_tcscpy(strOut,szOriginal);
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (FileList != NULL)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
cmd_free(FileList);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/* Sort the files */
|
|
|
|
|
qsort(FileList,FileListSize,sizeof(FileName), compare);
|
|
|
|
|
|
|
|
|
|
/* Find the next/previous */
|
2014-10-17 16:39:54 +00:00
|
|
|
|
if (_tcslen(szOriginal) && !_tcscmp(szOriginal,LastReturned))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (bNext)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (FileListSize - 1 == Sel)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
Sel = 0;
|
|
|
|
|
else
|
|
|
|
|
Sel++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!Sel)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
Sel = FileListSize - 1;
|
|
|
|
|
else
|
|
|
|
|
Sel--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Sel = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-17 16:39:54 +00:00
|
|
|
|
/* nothing found that matched last time so return the first thing in the list */
|
2013-06-30 12:27:18 +00:00
|
|
|
|
strOut[0] = _T('\0');
|
|
|
|
|
|
|
|
|
|
/* Special character in the name */
|
|
|
|
|
if (FileNameContainsSpecialCharacters(FileList[Sel].Name))
|
|
|
|
|
{
|
|
|
|
|
INT LastSpace;
|
|
|
|
|
BOOL bInside;
|
|
|
|
|
/* It needs a " at the end */
|
|
|
|
|
NeededQuote = TRUE;
|
|
|
|
|
LastSpace = -1;
|
|
|
|
|
bInside = FALSE;
|
|
|
|
|
/* Find the place to put the " at the start */
|
|
|
|
|
for(i = 0; i < _tcslen(szPrefix); i++)
|
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (szPrefix[i] == _T('\"'))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
bInside = !bInside;
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (szPrefix[i] == _T(' ') && !bInside)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
LastSpace = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* insert the quotation and move things around */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (szPrefix[LastSpace + 1] != _T('\"') && LastSpace != -1)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
memmove ( &szPrefix[LastSpace+1], &szPrefix[LastSpace], (_tcslen(szPrefix)-LastSpace+1) * sizeof(TCHAR) );
|
|
|
|
|
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if ((UINT)(LastSpace + 1) == _tcslen(szPrefix))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
_tcscat(szPrefix,_T("\""));
|
|
|
|
|
}
|
|
|
|
|
szPrefix[LastSpace + 1] = _T('\"');
|
|
|
|
|
}
|
2013-06-30 16:10:54 +00:00
|
|
|
|
else if (LastSpace == -1)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
/* Add quotation only if none exists already */
|
|
|
|
|
if (szPrefix[0] != _T('\"'))
|
|
|
|
|
{
|
|
|
|
|
_tcscpy(szBaseWord,_T("\""));
|
|
|
|
|
_tcscat(szBaseWord,szPrefix);
|
|
|
|
|
_tcscpy(szPrefix,szBaseWord);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_tcscpy(strOut,szPrefix);
|
|
|
|
|
_tcscat(strOut,FileList[Sel].Name);
|
|
|
|
|
|
|
|
|
|
/* check for odd number of quotes means we need to close them */
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (!NeededQuote)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
{
|
|
|
|
|
for(i = 0; i < _tcslen(strOut); i++)
|
|
|
|
|
{
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (strOut[i] == _T('\"'))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
NeededQuote = !NeededQuote;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-17 16:39:54 +00:00
|
|
|
|
if (NeededQuote || (_tcslen(szPrefix) && szPrefix[_tcslen(szPrefix) - 1] == _T('\"')))
|
2013-06-30 12:27:18 +00:00
|
|
|
|
_tcscat(strOut,_T("\""));
|
2007-10-19 23:21:45 +00:00
|
|
|
|
|
2013-06-30 12:27:18 +00:00
|
|
|
|
_tcscpy(LastReturned,strOut);
|
|
|
|
|
//EndLength = _tcslen(strOut);
|
|
|
|
|
//DiffLength = EndLength - StartLength;
|
2013-06-30 16:10:54 +00:00
|
|
|
|
if (FileList != NULL)
|
2013-06-30 12:27:18 +00:00
|
|
|
|
cmd_free(FileList);
|
2006-02-16 23:23:37 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|