*
* 25-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
* Cleanup. Unicode safe!
- */
-
-#include "config.h"
-
-#include <windows.h>
-#include <tchar.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdio.h>
+ *
+ * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
+ * Make the file listing readable when there is a lot of long names.
+ *
-#include "cmd.h"
+ * 05-Jul-2004 (Jens Collin <jens.collin@lakhei.com>)
+ * Now expands lfn even when trailing " is omitted.
+ */
+#include <precomp.h>
+#include "cmd.h"
#ifdef FEATURE_UNIX_FILENAME_COMPLETION
-VOID CompleteFilename (LPTSTR str, INT charcount)
+VOID CompleteFilename (LPTSTR str, UINT charcount)
{
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];
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 */
- while (count > 0 && str[count] != _T(' '))
+ 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(' '))
start = count;
+ if (str[count] == _T('"'))
+ count++; /* don't increment start */
+
/* extract directory from word */
- _tcscpy (directory, &str[start]);
+ _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(':'))
{
curplace--;
}
- _tcscpy (path, &str[start]);
-
/* look for a '.' in the filename */
for (count = _tcslen (directory); path[count] != _T('\0'); count++)
{
if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
_tcscat (fname, _T("\\"));
- else
- _tcscat (fname, _T(" "));
if (!maxmatch[0] && perfectmatch)
{
break;
}
}
+
+ if (maxmatch[count] == _T('\0') &&
+ fname[count] != _T('\0'))
+ perfectmatch = FALSE;
}
}
while (FindNextFile (hFile, &file));
FindClose (hFile);
- if( perfectmatch )
- {
- str[start] = '\"';
- _tcscpy (&str[start+1], directory);
- _tcscat (&str[start], maxmatch);
- _tcscat (&str[start], "\"" );
- }
+ /* 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
-#ifdef __REACTOS__
- Beep (440, 50);
-#else
+ {
+ _tcscpy (&str[start], directory);
+ _tcscat (&str[start], maxmatch);
+ }
+
+ if(!perfectmatch)
+ {
MessageBeep (-1);
-#endif
+ }
}
else
{
}
}
-#ifdef __REACTOS__
- Beep (440, 50);
-#else
MessageBeep (-1);
-#endif
}
}
BOOL found_dot = FALSE;
INT curplace = 0;
INT start;
- INT count;
+ UINT count;
TCHAR path[MAX_PATH];
TCHAR fname[MAX_PATH];
TCHAR directory[MAX_PATH];
+ UINT longestfname = 0;
+ SHORT screenwidth;
/* expand current file name */
count = charcount - 1;
count = 0;
/* find front of word */
- while (count > 0 && str[count] != _T(' '))
+ 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(' '))
start = count;
+ if (str[count] == _T('"'))
+ count++; /* don't increment start */
+
/* extract directory from word */
- _tcscpy (directory, &str[start]);
+ _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(':'))
curplace--;
}
- _tcscpy (path, &str[start]);
-
/* look for a . in the filename */
for (count = _tcslen (directory); path[count] != _T('\0'); count++)
{
hFile = FindFirstFile (path, &file);
if (hFile != INVALID_HANDLE_VALUE)
{
+ /* 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 */
+ GetScreenSize(&screenwidth, 0);
+
+ /* For counting columns of output */
+ count = 0;
+
+ /* Increase by the number of spaces behind file name */
+ longestfname += 3;
+
/* find anything */
ConOutChar (_T('\n'));
- count = 0;
do
{
/* ignore . and .. */
- if (!_tcscmp (file.cFileName, _T(".")) ||
+ if (!_tcscmp (file.cFileName, _T(".")) ||
!_tcscmp (file.cFileName, _T("..")))
continue;
else
_tcscpy (fname, file.cFileName);
- ConOutPrintf (_T("%-14s"), fname);
- if (++count == 5)
+ ConOutPrintf (_T("%*s"), - longestfname, fname);
+ count++;
+ /* output as much columns as fits on the screen */
+ if (count >= (screenwidth / longestfname))
{
- ConOutChar (_T('\n'));
+ /* print the new line only if we aren't on the
+ * last column, in this case it wraps anyway */
+ if (count * longestfname != (UINT)screenwidth)
+ ConOutPrintf (_T("\n"));
count = 0;
}
}
else
{
/* no match found */
-#ifdef __REACTOS__
- Beep (440, 50);
-#else
MessageBeep (-1);
-#endif
return FALSE;
}
#ifdef FEATURE_4NT_FILENAME_COMPLETION
-//static VOID BuildFilenameMatchList (...)
+typedef struct _FileName
+{
+ TCHAR Name[MAX_PATH];
+} FileName;
-// VOID CompleteFilenameNext (LPTSTR, INT)
-// VOID CompleteFilenamePrev (LPTSTR, INT)
+VOID FindPrefixAndSuffix(LPTSTR strIN, LPTSTR szPrefix, LPTSTR szSuffix)
+{
+ /* String that is to be examined */
+ TCHAR str[MAX_PATH];
+ /* temp pointers to used to find needed parts */
+ TCHAR * szSearch;
+ TCHAR * szSearch1;
+ TCHAR * szSearch2;
+ /* 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++)
+ if(str[i] == _T('\"'))
+ nQuotes++;
+
+ /* Find the prefix and suffix */
+ if(nQuotes % 2 && nQuotes > 1)
+ {
+ /* 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('\\'));
+ if(szSearch2 != NULL && _tcslen(szSearch1) > _tcslen(szSearch2))
+ szSearch = szSearch2;
+ else
+ szSearch = szSearch1;
+ /* Move one char past */
+ szSearch++;
+ szSearch[0] = _T('\0');
+ _tcscpy(szPrefix,str);
+ return;
+
+ }
+
+ if(!_tcschr(str, _T(' ')))
+ {
+ /* No spaces, everything goes to Suffix */
+ _tcscpy(szSuffix,str);
+ /* look for a slash just in case */
+ szSearch = _tcsrchr(str, _T('\\'));
+ if(szSearch)
+ {
+ szSearch++;
+ szSearch[0] = _T('\0');
+ _tcscpy(szPrefix,str);
+ }
+ else
+ {
+ szPrefix[0] = _T('\0');
+ }
+ return;
+ }
-// VOID RemoveFilenameMatchList (VOID)
+ if(!nQuotes)
+ {
+ /* 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('\\'));
+ if(szSearch2 != NULL && _tcslen(szSearch1) > _tcslen(szSearch2))
+ szSearch = szSearch2;
+ 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++)
+ {
+ if(str[i] == _T('\"'))
+ bInside = !bInside;
+ if(str[i] == _T(' ') && !bInside)
+ SBreak = i;
+ if((str[i] == _T(' ') || str[i] == _T('\\')) && !bInside)
+ PBreak = i;
+ }
+ SBreak++;
+ PBreak++;
+ _tcscpy(szSuffix,&strIN[SBreak]);
+ strIN[PBreak] = _T('\0');
+ _tcscpy(szPrefix,strIN);
+ if(szPrefix[_tcslen(szPrefix) - 2] == _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("\\"));
+
+ }
+
+}
+ int __cdecl compare(const void *arg1,const void *arg2)
+ {
+ FileName * File1;
+ FileName * File2;
+ INT ret;
+
+ File1 = malloc(sizeof(FileName));
+ File2 = malloc(sizeof(FileName));
+ if(!File1 || !File2)
+ return 0;
+
+ memcpy(File1,arg1,sizeof(FileName));
+ memcpy(File2,arg2,sizeof(FileName));
+
+ /* ret = _tcsicmp(File1->Name, File2->Name); */
+ ret = lstrcmpi(File1->Name, File2->Name);
+
+ free(File1);
+ free(File2);
+ return ret;
+ }
+
+VOID CompleteFilename (LPTSTR strIN, BOOL bNext, LPTSTR strOut, UINT cusor)
+{
+ /* Length of string before we complete it */
+ INT 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];
+ TCHAR szOrginal[MAX_PATH];
+ 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++;
+ if(!_tcsnicmp (line, _T("rd "), 3) || !_tcsnicmp (line, _T("cd "), 3))
+ ShowAll = FALSE;
+
+ /* Copy the string, str can be edited and orginal should not be */
+ _tcscpy(str,strIN);
+ _tcscpy(szOrginal,strIN);
+
+ /* Look to see if the cusor is not at the end of the string */
+ if((cusor + 1) < _tcslen(str))
+ str[cusor] = _T('\0');
+
+ /* Look to see if they hit tab again, if so cut off the diff length */
+ if(_tcscmp(str,LastReturned) || !_tcslen(str))
+ {
+ /* We need to know how many chars we added from the start */
+ StartLength = _tcslen(str);
+
+ /* no string, we need all files in that directory */
+ if(!StartLength)
+ {
+ _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); )
+ {
+ if(szBaseWord[i] == _T('\"'))
+ 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);
+ if(StartLength > 0)
+ _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);
+
+ /* aseemble a list of all files names */
+ do
+ {
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ /* Assemble the orginal string and return */
+ _tcscpy(strOut,szOrginal);
+ CloseHandle(hFile);
+ if(FileList != NULL)
+ free(FileList);
+ return;
+ }
+
+ if(!_tcscmp (file.cFileName, _T(".")) ||
+ !_tcscmp (file.cFileName, _T("..")))
+ continue;
+
+ /* Don't show files when they are doing 'cd' or 'rd' */
+ if(!ShowAll)
+ {
+ DWORD attr = GetFileAttributes (file.cFileName);
+ if(attr != 0xFFFFFFFF && (!(attr & FILE_ATTRIBUTE_DIRECTORY)))
+ continue;
+ }
+
+ /* Add the file to the list of files */
+ if(FileList == NULL)
+ {
+ FileListSize = 1;
+ FileList = malloc(FileListSize * sizeof(FileName));
+ }
+ else
+ {
+ FileListSize++;
+ FileList = realloc(FileList, FileListSize * sizeof(FileName));
+ }
+
+ if(FileList == NULL)
+ {
+ /* Assemble the orginal string and return */
+ _tcscpy(strOut,szOrginal);
+ CloseHandle(hFile);
+ ConOutFormatMessage (GetLastError());
+ return;
+ }
+ /* Copies the file name into the struct */
+ _tcscpy(FileList[FileListSize-1].Name,file.cFileName);
+
+ }while(FindNextFile(hFile,&file));
+
+ /* Check the size of the list to see if we
+ found any matches */
+ if(FileListSize == 0)
+ {
+ _tcscpy(strOut,szOrginal);
+ CloseHandle(hFile);
+ if(FileList != NULL)
+ free(FileList);
+ return;
+
+ }
+ /* Sort the files */
+ qsort(FileList,FileListSize,sizeof(FileName), compare);
+
+ /* Find the next/previous */
+ if(!_tcscmp(szOrginal,LastReturned))
+ {
+ if(bNext)
+ {
+ if(FileListSize - 1 == Sel)
+ Sel = 0;
+ else
+ Sel++;
+ }
+ else
+ {
+ if(!Sel)
+ Sel = FileListSize - 1;
+ else
+ Sel--;
+ }
+ }
+ else
+ {
+ Sel = 0;
+ }
+
+ /* nothing found that matched last time
+ so return the first thing in the list */
+ strOut[0] = _T('\0');
+
+ /* space in the name */
+ if(_tcschr(FileList[Sel].Name, _T(' ')))
+ {
+ 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++)
+ {
+ if(szPrefix[i] == _T('\"'))
+ bInside = !bInside;
+ if(szPrefix[i] == _T(' ') && !bInside)
+ LastSpace = i;
+
+ }
+ /* insert the quoation and move things around */
+ if(szPrefix[LastSpace + 1] != _T('\"') && LastSpace != -1)
+ {
+ memmove ( &szPrefix[LastSpace+1], &szPrefix[LastSpace], (_tcslen(szPrefix)-LastSpace+1) * sizeof(TCHAR) );
+
+ if((UINT)(LastSpace + 1) == _tcslen(szPrefix))
+ {
+ _tcscat(szPrefix,_T("\""));
+ }
+ szPrefix[LastSpace + 1] = _T('\"');
+ }
+ else if(LastSpace == -1)
+ {
+ _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 */
+ if(!NeededQuote)
+ {
+ for(i = 0; i < _tcslen(strOut); i++)
+ if(strOut[i] == _T('\"'))
+ NeededQuote = !NeededQuote;
+ }
+
+ if(szPrefix[_tcslen(szPrefix) - 1] == _T('\"') || NeededQuote)
+ _tcscat(strOut,_T("\""));
+
+ _tcscpy(LastReturned,strOut);
+ EndLength = _tcslen(strOut);
+ DiffLength = EndLength - StartLength;
+ CloseHandle(hFile);
+ if(FileList != NULL)
+ free(FileList);
+
+}
#endif