Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800/* * 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 * * 25-Jan-1999 (Eric Kohl) * 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. */
#include "precomp.h"
#ifdef FEATURE_UNIX_FILENAME_COMPLETION
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]; 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('\\') && 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) { /* 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); }
if (!perfectmatch) { 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); }}
/* * returns 1 if at least one match, else returns 0 */BOOL ShowCompletionMatches (LPTSTR str, INT charcount){ 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('"')) count++;
/* 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 */ GetScreenSize(&screenwidth, NULL);
/* For counting columns of output */ count = 0;
/* Increase by the number of spaces behind file name */ longestfname += 3;
/* find anything */ ConOutChar(_T('\n')); 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) ConOutChar(_T('\n')); count = 0; } } while (FindNextFile (hFile, &file));
FindClose (hFile);
if (count) ConOutChar(_T('\n')); } else { /* no match found */ MessageBeep (-1); return FALSE; }
return TRUE;}#endif
#ifdef FEATURE_4NT_FILENAME_COMPLETION
typedef struct _FileName{ TCHAR Name[MAX_PATH];} FileName;
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; 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++) { 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('\\')); szSearch3 = _tcsrchr(str, _T('/')); if ((szSearch2 != NULL) && (szSearch1 < szSearch2)) szSearch = szSearch2; else if ((szSearch3 != NULL) && (szSearch1 < szSearch3)) szSearch = szSearch3; 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; }
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('\\')); szSearch3 = _tcsrchr(str, _T('/')); if ((szSearch2 != NULL) && (szSearch1 < szSearch2)) szSearch = szSearch2; else if ((szSearch3 != NULL) && (szSearch1 < szSearch3)) 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++) { 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('\"') && 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("\\")); }}
int __cdecl compare(const void *arg1,const void *arg2){ FileName * File1; FileName * File2; INT ret;
File1 = cmd_alloc(sizeof(FileName)); if (!File1) return 0;
File2 = cmd_alloc(sizeof(FileName)); if (!File2) { 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;}
BOOLFileNameContainsSpecialCharacters(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)) // '´' { return TRUE; } }
return FALSE;}
VOID CompleteFilename (LPTSTR strIN, BOOL bNext, LPTSTR strOut, UINT cusor){ /* 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]; TCHAR szOriginal[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 original should not be */ _tcscpy(str,strIN); _tcscpy(szOriginal,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);
/* 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); }
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); if (hFile == INVALID_HANDLE_VALUE) { /* Assemble the original string and return */ _tcscpy(strOut,szOriginal); return; }
/* assemble a list of all files names */ do { FileName * oldFileList = FileList;
if (!_tcscmp (file.cFileName, _T(".")) || !_tcscmp (file.cFileName, _T(".."))) continue;
/* Don't show files when they are doing 'cd' or 'rd' */ if (!ShowAll && file.dwFileAttributes != INVALID_FILE_ATTRIBUTES && !(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { continue; }
/* Add the file to the list of files */ FileList = cmd_realloc(FileList, ++FileListSize * sizeof(FileName));
if (FileList == NULL) { /* Don't leak old buffer */ cmd_free(oldFileList); /* Assemble the original string and return */ _tcscpy(strOut,szOriginal); 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);
/* Check the size of the list to see if we found any matches */ if (FileListSize == 0) { _tcscpy(strOut,szOriginal); if (FileList != NULL) cmd_free(FileList); return;
} /* Sort the files */ qsort(FileList,FileListSize,sizeof(FileName), compare);
/* Find the next/previous */ if (_tcslen(szOriginal) && !_tcscmp(szOriginal,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');
/* 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++) { if (szPrefix[i] == _T('\"')) bInside = !bInside; if (szPrefix[i] == _T(' ') && !bInside) LastSpace = i; }
/* insert the quotation 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) { /* 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 */ if (!NeededQuote) { for(i = 0; i < _tcslen(strOut); i++) { if (strOut[i] == _T('\"')) NeededQuote = !NeededQuote; } }
if (NeededQuote || (_tcslen(szPrefix) && szPrefix[_tcslen(szPrefix) - 1] == _T('\"'))) _tcscat(strOut,_T("\""));
_tcscpy(LastReturned,strOut); //EndLength = _tcslen(strOut); //DiffLength = EndLength - StartLength; if (FileList != NULL) cmd_free(FileList);}#endif