xref: /reactos/base/shell/cmd/filecomp.c (revision a91a709a)
1 /*
2  *  FILECOMP.C - handles filename completion.
3  *
4  *
5  *  Comments:
6  *
7  *    30-Jul-1998 (John P Price <linux-guru@gcfl.net>)
8  *       moved from command.c file
9  *       made second TAB display list of filename matches
10  *       made filename be lower case if last character typed is lower case
11  *
12  *    25-Jan-1999 (Eric Kohl)
13  *       Cleanup. Unicode safe!
14  *
15  *    30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
16  *       Make the file listing readable when there is a lot of long names.
17  *
18 
19  *    05-Jul-2004 (Jens Collin <jens.collin@lakhei.com>)
20  *       Now expands lfn even when trailing " is omitted.
21  */
22 
23 #include "precomp.h"
24 
25 #ifdef FEATURE_UNIX_FILENAME_COMPLETION
26 
CompleteFilename(LPTSTR str,UINT charcount)27 VOID CompleteFilename (LPTSTR str, UINT charcount)
28 {
29     WIN32_FIND_DATA file;
30     HANDLE hFile;
31     INT   curplace = 0;
32     INT   start;
33     INT   count;
34     INT step;
35     INT c = 0;
36     BOOL  found_dot = FALSE;
37     BOOL  perfectmatch = TRUE;
38     TCHAR path[MAX_PATH];
39     TCHAR fname[MAX_PATH];
40     TCHAR maxmatch[MAX_PATH] = _T("");
41     TCHAR directory[MAX_PATH];
42     LPCOMMAND cmds_ptr;
43 
44     /* expand current file name */
45     count = charcount - 1;
46     if (count < 0)
47         count = 0;
48 
49     /* find how many '"'s there is typed already. */
50     step = count;
51     while (step > 0)
52     {
53         if (str[step] == _T('"'))
54             c++;
55         step--;
56     }
57     /* if c is odd, then user typed " before name, else not. */
58 
59     /* find front of word */
60     if (str[count] == _T('"') || (c % 2))
61     {
62         count--;
63         while (count > 0 && str[count] != _T('"'))
64             count--;
65     }
66     else
67     {
68         while (count > 0 && str[count] != _T(' '))
69             count--;
70     }
71 
72     /* if not at beginning, go forward 1 */
73     if (str[count] == _T(' '))
74         count++;
75 
76     start = count;
77 
78     if (str[count] == _T('"'))
79         count++;	/* don't increment start */
80 
81     /* extract directory from word */
82     _tcscpy (directory, &str[count]);
83     curplace = _tcslen (directory) - 1;
84 
85     if (curplace >= 0 && directory[curplace] == _T('"'))
86         directory[curplace--] = _T('\0');
87 
88     _tcscpy (path, directory);
89 
90     while (curplace >= 0 && directory[curplace] != _T('\\') &&
91                    directory[curplace] != _T('/') &&
92            directory[curplace] != _T(':'))
93     {
94         directory[curplace] = 0;
95         curplace--;
96     }
97 
98     /* look for a '.' in the filename */
99     for (count = _tcslen (directory); path[count] != _T('\0'); count++)
100     {
101         if (path[count] == _T('.'))
102         {
103             found_dot = TRUE;
104             break;
105         }
106     }
107 
108     if (found_dot)
109         _tcscat (path, _T("*"));
110     else
111         _tcscat (path, _T("*.*"));
112 
113     /* current fname */
114     curplace = 0;
115 
116     hFile = FindFirstFile (path, &file);
117     if (hFile != INVALID_HANDLE_VALUE)
118     {
119         /* find anything */
120         do
121         {
122             /* ignore "." and ".." */
123             if (!_tcscmp (file.cFileName, _T(".")) ||
124                 !_tcscmp (file.cFileName, _T("..")))
125                 continue;
126 
127             _tcscpy (fname, file.cFileName);
128 
129             if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
130                 _tcscat (fname, _T("\\"));
131 
132             if (!maxmatch[0] && perfectmatch)
133             {
134                 _tcscpy(maxmatch, fname);
135             }
136             else
137             {
138                 for (count = 0; maxmatch[count] && fname[count]; count++)
139                 {
140                     if (tolower(maxmatch[count]) != tolower(fname[count]))
141                     {
142                         perfectmatch = FALSE;
143                         maxmatch[count] = 0;
144                         break;
145                     }
146                 }
147 
148                 if (maxmatch[count] == _T('\0') &&
149                     fname[count] != _T('\0'))
150                     perfectmatch = FALSE;
151             }
152         }
153         while (FindNextFile (hFile, &file));
154 
155         FindClose (hFile);
156 
157         /* only quote if the filename contains spaces */
158         if (_tcschr(directory, _T(' ')) ||
159             _tcschr(maxmatch, _T(' ')))
160         {
161             str[start] = _T('\"');
162             _tcscpy (&str[start+1], directory);
163             _tcscat (&str[start], maxmatch);
164             _tcscat (&str[start], _T("\"") );
165         }
166         else
167         {
168             _tcscpy (&str[start], directory);
169             _tcscat (&str[start], maxmatch);
170         }
171 
172         if (!perfectmatch)
173         {
174             MessageBeep (-1);
175         }
176     }
177     else
178     {
179         /* no match found - search for internal command */
180         for (cmds_ptr = cmds; cmds_ptr->name; cmds_ptr++)
181         {
182             if (!_tcsnicmp (&str[start], cmds_ptr->name,
183                 _tcslen (&str[start])))
184             {
185                 /* return the mach only if it is unique */
186                 if (_tcsnicmp (&str[start], (cmds_ptr+1)->name, _tcslen (&str[start])))
187                     _tcscpy (&str[start], cmds_ptr->name);
188                 break;
189             }
190         }
191 
192         MessageBeep (-1);
193     }
194 }
195 
196 
197 /*
198  * returns 1 if at least one match, else returns 0
199  */
ShowCompletionMatches(LPTSTR str,INT charcount)200 BOOL ShowCompletionMatches (LPTSTR str, INT charcount)
201 {
202     WIN32_FIND_DATA file;
203     HANDLE hFile;
204     BOOL  found_dot = FALSE;
205     INT   curplace = 0;
206     INT   count;
207     TCHAR path[MAX_PATH];
208     TCHAR fname[MAX_PATH];
209     TCHAR directory[MAX_PATH];
210     SHORT screenwidth;
211 
212     /* expand current file name */
213     count = charcount - 1;
214     if (count < 0)
215         count = 0;
216 
217     /* find front of word */
218     if (str[count] == _T('"'))
219     {
220         count--;
221         while (count > 0 && str[count] != _T('"'))
222             count--;
223     }
224     else
225     {
226         while (count > 0 && str[count] != _T(' '))
227             count--;
228     }
229 
230     /* if not at beginning, go forward 1 */
231     if (str[count] == _T(' '))
232         count++;
233 
234     if (str[count] == _T('"'))
235         count++;
236 
237     /* extract directory from word */
238     _tcscpy (directory, &str[count]);
239     curplace = _tcslen (directory) - 1;
240 
241     if (curplace >= 0 && directory[curplace] == _T('"'))
242         directory[curplace--] = _T('\0');
243 
244     _tcscpy (path, directory);
245 
246     while (curplace >= 0 &&
247            directory[curplace] != _T('\\') &&
248            directory[curplace] != _T(':'))
249     {
250         directory[curplace] = 0;
251         curplace--;
252     }
253 
254     /* look for a . in the filename */
255     for (count = _tcslen (directory); path[count] != _T('\0'); count++)
256     {
257         if (path[count] == _T('.'))
258         {
259             found_dot = TRUE;
260             break;
261         }
262     }
263 
264     if (found_dot)
265         _tcscat (path, _T("*"));
266     else
267         _tcscat (path, _T("*.*"));
268 
269     /* current fname */
270     curplace = 0;
271 
272     hFile = FindFirstFile (path, &file);
273     if (hFile != INVALID_HANDLE_VALUE)
274     {
275         UINT longestfname = 0;
276         /* Get the size of longest filename first. */
277         do
278         {
279             if (_tcslen(file.cFileName) > longestfname)
280             {
281                 longestfname = _tcslen(file.cFileName);
282                 /* Directories get extra brackets around them. */
283                 if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
284                     longestfname += 2;
285             }
286         }
287         while (FindNextFile (hFile, &file));
288         FindClose (hFile);
289 
290         hFile = FindFirstFile (path, &file);
291 
292         /* Count the highest number of columns */
293         GetScreenSize(&screenwidth, NULL);
294 
295         /* For counting columns of output */
296         count = 0;
297 
298         /* Increase by the number of spaces behind file name */
299         longestfname += 3;
300 
301         /* find anything */
302         ConOutChar(_T('\n'));
303         do
304         {
305             /* ignore . and .. */
306             if (!_tcscmp (file.cFileName, _T(".")) ||
307                 !_tcscmp (file.cFileName, _T("..")))
308                 continue;
309 
310             if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
311                 _stprintf (fname, _T("[%s]"), file.cFileName);
312             else
313                 _tcscpy (fname, file.cFileName);
314 
315             ConOutPrintf (_T("%*s"), - longestfname, fname);
316             count++;
317             /* output as much columns as fits on the screen */
318             if (count >= (screenwidth / longestfname))
319             {
320                 /* print the new line only if we aren't on the
321                  * last column, in this case it wraps anyway */
322                 if (count * longestfname != (UINT)screenwidth)
323                     ConOutChar(_T('\n'));
324                 count = 0;
325             }
326         }
327         while (FindNextFile (hFile, &file));
328 
329         FindClose (hFile);
330 
331         if (count)
332             ConOutChar(_T('\n'));
333     }
334     else
335     {
336         /* no match found */
337         MessageBeep (-1);
338         return FALSE;
339     }
340 
341     return TRUE;
342 }
343 #endif
344 
345 #ifdef FEATURE_4NT_FILENAME_COMPLETION
346 
347 typedef struct _FileName
348 {
349     TCHAR Name[MAX_PATH];
350 } FileName;
351 
FindPrefixAndSuffix(LPTSTR strIN,LPTSTR szPrefix,LPTSTR szSuffix)352 VOID FindPrefixAndSuffix(LPTSTR strIN, LPTSTR szPrefix, LPTSTR szSuffix)
353 {
354     /* String that is to be examined */
355     TCHAR str[MAX_PATH];
356     /* temp pointers to used to find needed parts */
357     TCHAR * szSearch;
358     TCHAR * szSearch1;
359     TCHAR * szSearch2;
360     TCHAR * szSearch3;
361     /* number of quotes in the string */
362     INT nQuotes = 0;
363     /* used in for loops */
364     UINT i;
365     /* Char number to break the string at */
366     INT PBreak = 0;
367     INT SBreak = 0;
368     /* when phrasing a string, this tells weather
369        you are inside quotes ot not. */
370     BOOL bInside = FALSE;
371 
372     szPrefix[0] = _T('\0');
373     szSuffix[0] = _T('\0');
374 
375     /* Copy over the string to later be edited */
376     _tcscpy(str,strIN);
377 
378     /* Count number of " */
379     for(i = 0; i < _tcslen(str); i++)
380     {
381         if (str[i] == _T('\"'))
382             nQuotes++;
383     }
384 
385     /* Find the prefix and suffix */
386     if (nQuotes % 2 && nQuotes >= 1)
387     {
388         /* Odd number of quotes.  Just start from the last " */
389         /* THis is the way MS does it, and is an easy way out */
390         szSearch = _tcsrchr(str, _T('\"'));
391         /* Move to the next char past the " */
392         szSearch++;
393         _tcscpy(szSuffix,szSearch);
394         /* Find the one closest to end */
395         szSearch1 = _tcsrchr(str, _T('\"'));
396         szSearch2 = _tcsrchr(str, _T('\\'));
397         szSearch3 = _tcsrchr(str, _T('/'));
398         if ((szSearch2 != NULL) && (szSearch1 < szSearch2))
399             szSearch = szSearch2;
400         else if ((szSearch3 != NULL) && (szSearch1 < szSearch3))
401             szSearch = szSearch3;
402         else
403             szSearch = szSearch1;
404         /* Move one char past */
405         szSearch++;
406         szSearch[0] = _T('\0');
407         _tcscpy(szPrefix,str);
408         return;
409 
410     }
411 
412     if (!_tcschr(str, _T(' ')))
413     {
414         /* No spaces, everything goes to Suffix */
415         _tcscpy(szSuffix,str);
416         /* look for a slash just in case */
417         szSearch = _tcsrchr(str, _T('\\'));
418         if (szSearch)
419         {
420             szSearch++;
421             szSearch[0] = _T('\0');
422             _tcscpy(szPrefix,str);
423         }
424         else
425         {
426             szPrefix[0] = _T('\0');
427         }
428         return;
429     }
430 
431     if (!nQuotes)
432     {
433         /* No quotes, and there is a space*/
434         /* Take it after the last space */
435         szSearch = _tcsrchr(str, _T(' '));
436         szSearch++;
437         _tcscpy(szSuffix,szSearch);
438         /* Find the closest to the end space or \ */
439         _tcscpy(str,strIN);
440         szSearch1 = _tcsrchr(str, _T(' '));
441         szSearch2 = _tcsrchr(str, _T('\\'));
442         szSearch3 = _tcsrchr(str, _T('/'));
443         if ((szSearch2 != NULL) && (szSearch1 < szSearch2))
444             szSearch = szSearch2;
445         else if ((szSearch3 != NULL) && (szSearch1 < szSearch3))
446             szSearch = szSearch3;
447         else
448             szSearch = szSearch1;
449         szSearch++;
450         szSearch[0] = _T('\0');
451         _tcscpy(szPrefix,str);
452         return;
453     }
454 
455     /* All else fails and there is a lot of quotes, spaces and |
456        Then we search through and find the last space or \ that is
457         not inside a quotes */
458     for(i = 0; i < _tcslen(str); i++)
459     {
460         if (str[i] == _T('\"'))
461             bInside = !bInside;
462         if (str[i] == _T(' ') && !bInside)
463             SBreak = i;
464         if ((str[i] == _T(' ') || str[i] == _T('\\')) && !bInside)
465             PBreak = i;
466     }
467     SBreak++;
468     PBreak++;
469     _tcscpy(szSuffix,&strIN[SBreak]);
470     strIN[PBreak] = _T('\0');
471     _tcscpy(szPrefix,strIN);
472     if (szPrefix[_tcslen(szPrefix) - 2] == _T('\"') &&
473         szPrefix[_tcslen(szPrefix) - 1] != _T(' '))
474     {
475         /* need to remove the " right before a \ at the end to
476            allow the next stuff to stay inside one set of quotes
477             otherwise you would have multiple sets of quotes*/
478         _tcscpy(&szPrefix[_tcslen(szPrefix) - 2],_T("\\"));
479     }
480 }
481 
compare(const void * arg1,const void * arg2)482 int __cdecl compare(const void *arg1,const void *arg2)
483 {
484     FileName * File1;
485     FileName * File2;
486     INT ret;
487 
488     File1 = cmd_alloc(sizeof(FileName));
489     if (!File1)
490         return 0;
491 
492     File2 = cmd_alloc(sizeof(FileName));
493     if (!File2)
494     {
495         cmd_free(File1);
496         return 0;
497     }
498 
499     memcpy(File1,arg1,sizeof(FileName));
500     memcpy(File2,arg2,sizeof(FileName));
501 
502      /* ret = _tcsicmp(File1->Name, File2->Name); */
503      ret = lstrcmpi(File1->Name, File2->Name);
504 
505     cmd_free(File1);
506     cmd_free(File2);
507     return ret;
508 }
509 
510 BOOL
FileNameContainsSpecialCharacters(LPTSTR pszFileName)511 FileNameContainsSpecialCharacters(LPTSTR pszFileName)
512 {
513     TCHAR chr;
514 
515     while ((chr = *pszFileName++) != _T('\0'))
516     {
517         if ((chr == _T(' ')) ||
518             (chr == _T('!')) ||
519             (chr == _T('%')) ||
520             (chr == _T('&')) ||
521             (chr == _T('(')) ||
522             (chr == _T(')')) ||
523             (chr == _T('{')) ||
524             (chr == _T('}')) ||
525             (chr == _T('[')) ||
526             (chr == _T(']')) ||
527             (chr == _T('=')) ||
528             (chr == _T('\'')) ||
529             (chr == _T('`')) ||
530             (chr == _T(',')) ||
531             (chr == _T(';')) ||
532             (chr == _T('^')) ||
533             (chr == _T('~')) ||
534             (chr == _T('+')) ||
535             (chr == 0xB4)) // '´'
536         {
537             return TRUE;
538         }
539     }
540 
541     return FALSE;
542 }
543 
544 
CompleteFilename(LPTSTR strIN,BOOL bNext,LPTSTR strOut,UINT cusor)545 VOID CompleteFilename (LPTSTR strIN, BOOL bNext, LPTSTR strOut, UINT cusor)
546 {
547     /* Length of string before we complete it */
548     INT_PTR StartLength;
549     /* Length of string after completed */
550     //INT EndLength;
551     /* The number of chars added too it */
552     //static INT DiffLength = 0;
553     /* Used to find and assemble the string that is returned */
554     TCHAR szBaseWord[MAX_PATH];
555     TCHAR szPrefix[MAX_PATH];
556     TCHAR szOriginal[MAX_PATH];
557     TCHAR szSearchPath[MAX_PATH];
558     /* Save the strings used last time, so if they hit tab again */
559     static TCHAR LastReturned[MAX_PATH];
560     static TCHAR LastSearch[MAX_PATH];
561     static TCHAR LastPrefix[MAX_PATH];
562     /* Used to search for files */
563     HANDLE hFile;
564     WIN32_FIND_DATA file;
565     /* List of all the files */
566     FileName * FileList = NULL;
567     /* Number of files */
568     INT FileListSize = 0;
569     /* Used for loops */
570     UINT i;
571     /* Editable string of what was passed in */
572     TCHAR str[MAX_PATH];
573     /* Keeps track of what element was last selected */
574     static INT Sel;
575     BOOL NeededQuote = FALSE;
576     BOOL ShowAll = TRUE;
577     TCHAR * line = strIN;
578 
579     strOut[0] = _T('\0');
580 
581     while (_istspace (*line))
582         line++;
583     if (!_tcsnicmp (line, _T("rd "), 3) || !_tcsnicmp (line, _T("cd "), 3))
584         ShowAll = FALSE;
585 
586     /* Copy the string, str can be edited and original should not be */
587     _tcscpy(str,strIN);
588     _tcscpy(szOriginal,strIN);
589 
590     /* Look to see if the cusor is not at the end of the string */
591     if ((cusor + 1) < _tcslen(str))
592         str[cusor] = _T('\0');
593 
594     /* Look to see if they hit tab again, if so cut off the diff length */
595     if (_tcscmp(str,LastReturned) || !_tcslen(str))
596     {
597         /* We need to know how many chars we added from the start */
598         StartLength = _tcslen(str);
599 
600         /* no string, we need all files in that directory */
601         if (!StartLength)
602         {
603             _tcscat(str,_T("*"));
604         }
605 
606         /* Zero it out first */
607         szBaseWord[0] = _T('\0');
608         szPrefix[0] = _T('\0');
609 
610         /*What comes out of this needs to be:
611             szBaseWord =  path no quotes to the object
612             szPrefix = what leads up to the filename
613             no quote at the END of the full name */
614         FindPrefixAndSuffix(str,szPrefix,szBaseWord);
615         /* Strip quotes */
616         for(i = 0; i < _tcslen(szBaseWord); )
617         {
618             if (szBaseWord[i] == _T('\"'))
619                 memmove(&szBaseWord[i],&szBaseWord[i + 1], _tcslen(&szBaseWord[i]) * sizeof(TCHAR));
620             else
621                 i++;
622         }
623 
624         /* clear it out */
625         memset(szSearchPath, 0, sizeof(szSearchPath));
626 
627         /* Start the search for all the files */
628         GetFullPathName(szBaseWord, MAX_PATH, szSearchPath, NULL);
629 
630         /* Got a device path? Fallback to the the current dir plus the short path */
631         if (szSearchPath[0] == _T('\\') && szSearchPath[1] == _T('\\') &&
632             szSearchPath[2] == _T('.') && szSearchPath[3] == _T('\\'))
633         {
634             GetCurrentDirectory(MAX_PATH, szSearchPath);
635             _tcscat(szSearchPath, _T("\\"));
636             _tcscat(szSearchPath, szBaseWord);
637         }
638 
639         if (StartLength > 0)
640         {
641             _tcscat(szSearchPath,_T("*"));
642         }
643         _tcscpy(LastSearch,szSearchPath);
644         _tcscpy(LastPrefix,szPrefix);
645     }
646     else
647     {
648         _tcscpy(szSearchPath, LastSearch);
649         _tcscpy(szPrefix, LastPrefix);
650         StartLength = 0;
651     }
652     /* search for the files it might be */
653     hFile = FindFirstFile (szSearchPath, &file);
654     if (hFile == INVALID_HANDLE_VALUE)
655     {
656         /* Assemble the original string and return */
657         _tcscpy(strOut,szOriginal);
658         return;
659     }
660 
661     /* assemble a list of all files names */
662     do
663     {
664         FileName * oldFileList = FileList;
665 
666         if (!_tcscmp (file.cFileName, _T(".")) ||
667             !_tcscmp (file.cFileName, _T("..")))
668             continue;
669 
670         /* Don't show files when they are doing 'cd' or 'rd' */
671         if (!ShowAll &&
672             file.dwFileAttributes != INVALID_FILE_ATTRIBUTES &&
673             !(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
674         {
675                 continue;
676         }
677 
678         /* Add the file to the list of files */
679         FileList = cmd_realloc(FileList, ++FileListSize * sizeof(FileName));
680 
681         if (FileList == NULL)
682         {
683             /* Don't leak old buffer */
684             cmd_free(oldFileList);
685             /* Assemble the original string and return */
686             _tcscpy(strOut,szOriginal);
687             FindClose(hFile);
688             ConOutFormatMessage (GetLastError());
689             return;
690         }
691         /* Copies the file name into the struct */
692         _tcscpy(FileList[FileListSize-1].Name,file.cFileName);
693 
694     } while(FindNextFile(hFile,&file));
695 
696     FindClose(hFile);
697 
698     /* Check the size of the list to see if we found any matches */
699     if (FileListSize == 0)
700     {
701         _tcscpy(strOut,szOriginal);
702         if (FileList != NULL)
703             cmd_free(FileList);
704         return;
705 
706     }
707     /* Sort the files */
708     qsort(FileList,FileListSize,sizeof(FileName), compare);
709 
710     /* Find the next/previous */
711     if (_tcslen(szOriginal) && !_tcscmp(szOriginal,LastReturned))
712     {
713         if (bNext)
714         {
715             if (FileListSize - 1 == Sel)
716                 Sel = 0;
717             else
718                 Sel++;
719         }
720         else
721         {
722             if (!Sel)
723                 Sel = FileListSize - 1;
724             else
725                 Sel--;
726         }
727     }
728     else
729     {
730         Sel = 0;
731     }
732 
733     /* nothing found that matched last time so return the first thing in the list */
734     strOut[0] = _T('\0');
735 
736     /* Special character in the name */
737     if (FileNameContainsSpecialCharacters(FileList[Sel].Name))
738     {
739         INT LastSpace;
740         BOOL bInside;
741         /* It needs a " at the end */
742         NeededQuote = TRUE;
743         LastSpace = -1;
744         bInside = FALSE;
745         /* Find the place to put the " at the start */
746         for(i = 0; i < _tcslen(szPrefix); i++)
747         {
748             if (szPrefix[i] == _T('\"'))
749                 bInside = !bInside;
750             if (szPrefix[i] == _T(' ') && !bInside)
751                 LastSpace = i;
752         }
753 
754         /* insert the quotation and move things around */
755         if (szPrefix[LastSpace + 1] != _T('\"') && LastSpace != -1)
756         {
757             memmove ( &szPrefix[LastSpace+1], &szPrefix[LastSpace], (_tcslen(szPrefix)-LastSpace+1) * sizeof(TCHAR) );
758 
759             if ((UINT)(LastSpace + 1) == _tcslen(szPrefix))
760             {
761                 _tcscat(szPrefix,_T("\""));
762             }
763             szPrefix[LastSpace + 1] = _T('\"');
764         }
765         else if (LastSpace == -1)
766         {
767             /* Add quotation only if none exists already */
768             if (szPrefix[0] != _T('\"'))
769             {
770                 _tcscpy(szBaseWord,_T("\""));
771                 _tcscat(szBaseWord,szPrefix);
772                 _tcscpy(szPrefix,szBaseWord);
773             }
774         }
775     }
776 
777     _tcscpy(strOut,szPrefix);
778     _tcscat(strOut,FileList[Sel].Name);
779 
780     /* check for odd number of quotes means we need to close them */
781     if (!NeededQuote)
782     {
783         for(i = 0; i < _tcslen(strOut); i++)
784         {
785             if (strOut[i] == _T('\"'))
786                 NeededQuote = !NeededQuote;
787         }
788     }
789 
790     if (NeededQuote || (_tcslen(szPrefix) && szPrefix[_tcslen(szPrefix) - 1] == _T('\"')))
791         _tcscat(strOut,_T("\""));
792 
793     _tcscpy(LastReturned,strOut);
794     //EndLength = _tcslen(strOut);
795     //DiffLength = EndLength - StartLength;
796     if (FileList != NULL)
797         cmd_free(FileList);
798 }
799 #endif
800