1 Allow NormalizePathname() and ParseFilename() to use windows path
3 Various operations require the extension of an incomplete file specification
4 to a full, absolute path. Before this patch, this completion uses the
5 current directory of the NEdit process as the base for relative file lookup.
6 However, this works against NEdit's file dialogs and shell processing which
7 start off in the directory of the current document, which may well not be
8 the same as the process' directory. Using "File > Open Selected" may not, in
9 this situation, find the file you would expect.
11 This patch alters NormalizePathname() and ParseFilename(), the utility
12 functions that perform the expansion so that the base for relative file
13 specifications can be passed, then changes all relevant calls to supply the
14 current window's file path value. It includes the nmReadWriteRelToWin.diff
15 adjustments to macro file functions read_file(), write_file() and
16 append_file() for this same behaviour, and adds a new one, full_file_name(),
17 which provides the macro writer with a way of obtaining the relative file
18 name from a relative file path.
23 source/macro.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++--
27 source/selection.c | 10 ++--
29 source/tags.c | 22 +++++-----
30 util/fileUtils.c | 26 ++++++++---
31 util/fileUtils.h | 5 +-
33 11 files changed, 160 insertions(+), 38 deletions(-)
35 diff --quilt old/source/file.c new/source/file.c
38 @@ -1076,20 +1076,20 @@ int SaveWindowAs(WindowInfo *window, con
41 strcpy(fullname, newName);
44 - if (1 == NormalizePathname(fullname))
45 + if (1 == NormalizePathname(fullname, window->path))
50 /* Add newlines if requested */
52 addWrapNewlines(window);
54 - if (ParseFilename(fullname, filename, pathname) != 0) {
55 + if (ParseFilename(fullname, filename, pathname, window->path) != 0) {
59 /* If the requested file is this file, just save it and return */
60 if (!strcmp(window->filename, filename) &&
61 @@ -1279,11 +1279,11 @@ static int doSave(WindowInfo *window)
62 /* free the text buffer copy returned from XmTextGetString */
66 /* reflect the fact that NEdit is now editing a new version of the file */
67 - ParseFilename(fullname, window->filename, window->path);
68 + ParseFilename(fullname, window->filename, window->path, NULL);
71 /* success, file was written */
72 SetWindowModified(window, FALSE);
74 diff --quilt old/source/macro.c new/source/macro.c
75 --- old/source/macro.c
76 +++ new/source/macro.c
77 @@ -182,10 +182,12 @@ static int validNumberMS(WindowInfo *win
78 DataValue *result, char **errMsg);
79 static int replaceInStringMS(WindowInfo *window, DataValue *argList, int nArgs,
80 DataValue *result, char **errMsg);
81 static int replaceSubstringMS(WindowInfo *window, DataValue *argList, int nArgs,
82 DataValue *result, char **errMsg);
83 +static int fullFileNameMS(WindowInfo *window, DataValue *argList, int nArgs,
84 + DataValue *result, char **errMsg);
85 static int readFileMS(WindowInfo *window, DataValue *argList, int nArgs,
86 DataValue *result, char **errMsg);
87 static int writeFileMS(WindowInfo *window, DataValue *argList, int nArgs,
88 DataValue *result, char **errMsg);
89 static int appendFileMS(WindowInfo *window, DataValue *argList, int nArgs,
90 @@ -527,10 +529,11 @@ static const BuiltInSubrName MacroSubrs[
91 { "to_column", toColumnMS },
92 { "set_window_title", setWindowTitleMS },
93 { "timer_add", timerAddMS },
94 { "timer_remove", timerRemoveMS },
95 { "escape_literal", escapeLiteralMS },
96 + { "full_file_name", fullFileNameMS },
97 { NULL, NULL } /* sentinel */
100 static const BuiltInSubrName SpecialVars[] = {
101 { "$cursor", cursorMV },
102 @@ -2070,11 +2073,11 @@ static int focusWindowMS(WindowInfo *win
104 /* didn't work? try normalizing the string passed in */
106 strncpy(normalizedString, string, MAXPATHLEN);
107 normalizedString[MAXPATHLEN-1] = '\0';
108 - if (1 == NormalizePathname(normalizedString)) {
109 + if (1 == NormalizePathname(normalizedString, window->path)) {
110 /* Something is broken with the input pathname. */
111 *errMsg = "Pathname too long in focus_window()";
114 for (w=WindowList; w != NULL; w = w->next) {
115 @@ -2506,10 +2509,112 @@ static int clipboardToStringMS(WindowInf
116 result->val.str.len = retLength;
122 +** Resolve the partial file path in name with respect to path.
123 +** (We don't use NormalizePathname() since this modifies its path in place.)
125 +static char *convFilePathToAbsolute(const char *path, char *name)
127 + static char *nameText = NULL, *ptr;
128 + static size_t nameTextLen = 0;
129 + size_t namelen, pathlen, len;
130 + Bool isRelative = False;
131 + size_t needSlash = 0;
133 + if (!path || !path[0] || strcmp(path, ".") == 0)
134 + path = GetCurrentDir();
137 + /* If path name is relative, make it refer to current window's directory;
138 + absolute paths start with a logical name ([\w$]+) followed by a colon,
139 + or with a non-relative path in brackets (not starting with . or -)
141 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
142 + !((name[0] == '[') && (name[1] != '-') &&
143 + (name[1] != '.')));
146 + Any path starting without a "/" is considered relative; if the first
147 + character is "~", we really need the user's home directory */
148 + if (name[0] == '~' && name[1] == '/') {
149 + path = GetHomeDir();
150 + for (++name; *name == '/'; ++name)
151 + continue; /* skip slash(es) following initial tilde */
155 + isRelative = (name[0] != '/');
161 + namelen = strlen(name);
162 + pathlen = strlen(path);
165 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
168 + /* make sure the buffer's big enough */
169 + len = namelen + pathlen + needSlash;
171 + if (nameTextLen < len) {
172 + ptr = realloc(nameText, len + 1);
179 + /* copy in pieces */
180 + strcpy(nameText, path);
182 + nameText[pathlen] = '/';
183 + strcpy(nameText + pathlen + needSlash, name);
185 + CompressPathname(nameText);
191 +** Built-in macro subroutine for expanding a possibly partial file specification
192 +** to a full one, using the current window's directory as a base for relative
193 +** path specifications. It does not check for file/path validity.
195 +static int fullFileNameMS(WindowInfo *window, DataValue *argList, int nArgs,
196 + DataValue *result, char **errMsg)
198 + char stringStorage[TYPE_INT_STR_SIZE(int)], *name;
201 + /* Validate arguments and convert to int */
203 + return wrongNArgsErr(errMsg);
204 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
207 + name = convFilePathToAbsolute(window->path, name);
208 + len = strlen(name);
211 + result->tag = STRING_TAG;
212 + AllocNString(&result->val.str, len + 1);
213 + strcpy(result->val.str.rep, name);
216 + result->tag = STRING_TAG;
217 + result->val.str.rep = PERM_ALLOC_STR("");
218 + result->val.str.len = 0;
225 ** Built-in macro subroutine for reading the contents of a text file into
226 ** a string. On success, returns 1 in $readStatus, and the contents of the
227 ** file as a string in the subroutine return value. On failure, returns
228 @@ -2526,11 +2631,13 @@ static int readFileMS(WindowInfo *window
229 /* Validate arguments and convert to int */
231 return wrongNArgsErr(errMsg);
232 if (!readStringArg(argList[0], &name, stringStorage, errMsg))
236 + name = convFilePathToAbsolute(window->path, name);
238 /* Read the whole file into an allocated string */
239 if ((fp = fopen(name, "r")) == NULL)
241 if (fstat(fileno(fp), &statbuf) != 0)
243 @@ -2605,11 +2712,13 @@ static int writeOrAppendFile(int append,
244 return wrongNArgsErr(errMsg);
245 if (!readStringArg(argList[0], &string, stringStorage[1], errMsg))
247 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
251 + name = convFilePathToAbsolute(window->path, name);
254 if ((fp = fopen(name, append ? "a" : "w")) == NULL) {
255 result->tag = INT_TAG;
256 result->val.n = False;
258 diff --quilt old/source/menu.c new/source/menu.c
259 --- old/source/menu.c
260 +++ new/source/menu.c
261 @@ -2988,11 +2988,11 @@ static void openAP(Widget w, XEvent *eve
262 fileNameToOpen = resultDV.val.str.rep;
264 fileNameToOpen = args[0];
267 - if (0 != ParseFilename(fileNameToOpen, filename, pathname)
268 + if (0 != ParseFilename(fileNameToOpen, filename, pathname, window->path)
269 || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) {
270 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
274 diff --quilt old/source/nc.c new/source/nc.c
277 @@ -712,11 +712,11 @@ static void parseCommandLine(int argc, c
278 newCommandString = XtMalloc(oldLength+length+1);
279 strncpy(newCommandString, commandString, oldLength);
280 XtFree(commandString);
281 commandString = newCommandString;
282 outPtr = newCommandString + oldLength;
283 - if (ParseFilename(nameList[j], name, path) != 0) {
284 + if (ParseFilename(nameList[j], name, path, NULL) != 0) {
285 /* An Error, most likely too long paths/strings given */
286 commandLine->serverRequest = NULL;
290 @@ -748,11 +748,11 @@ static void parseCommandLine(int argc, c
293 if (nameList != NULL)
296 - if (ParseFilename(argv[i], name, path) != 0) {
297 + if (ParseFilename(argv[i], name, path, NULL) != 0) {
298 /* An Error, most likely too long paths/strings given */
299 commandLine->serverRequest = NULL;
303 diff --quilt old/source/nedit.c new/source/nedit.c
304 --- old/source/nedit.c
305 +++ new/source/nedit.c
306 @@ -664,11 +664,11 @@ int main(int argc, char **argv)
307 /* Use VMS's LIB$FILESCAN for filename in argv[i] to process */
308 /* wildcards and to obtain a full VMS file specification */
309 numFiles = VMSFileScan(argv[i], &nameList, NULL, INCLUDE_FNF);
310 /* for each expanded file name do: */
311 for (j = 0; j < numFiles; ++j) {
312 - if (ParseFilename(nameList[j], filename, pathname) == 0) {
313 + if (ParseFilename(nameList[j], filename, pathname, NULL) == 0) {
314 /* determine if file is to be openned in new tab, by
315 factoring the options -group, -tabbed & -untabbed */
317 isTabbed = 0; /* start a new window for new group */
318 group = 1; /* next file will be within group */
319 @@ -719,11 +719,11 @@ int main(int argc, char **argv)
322 if (nameList != NULL)
325 - if (ParseFilename(argv[i], filename, pathname) == 0 ) {
326 + if (ParseFilename(argv[i], filename, pathname, NULL) == 0 ) {
327 /* determine if file is to be openned in new tab, by
328 factoring the options -group, -tabbed & -untabbed */
330 isTabbed = 0; /* start a new window for new group */
331 group = 1; /* next file will be within group */
332 diff --quilt old/source/selection.c new/source/selection.c
333 --- old/source/selection.c
334 +++ new/source/selection.c
335 @@ -325,28 +325,29 @@ static void fileCB(Widget widget, Window
336 names, in these cases, either don't expand names, or try to use the
337 Motif internal parsing routine _XmOSGetDirEntries, which is not
338 guranteed to be available, but in practice is there and does work. */
339 #if defined(DONT_HAVE_GLOB) || defined(VMS)
341 - if (ParseFilename(nameText, filename, pathname) != 0) {
342 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
343 XBell(TheDisplay, 0);
346 EditExistingFile(window, filename,
347 pathname, 0, NULL, False, NULL, GetPrefOpenInTab(), False);
348 #elif defined(USE_MOTIF_GLOB)
349 { char **nameList = NULL;
350 int i, nFiles = 0, maxFiles = 30;
352 - if (ParseFilename(nameText, filename, pathname) != 0) {
353 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
354 XBell(TheDisplay, 0);
357 _XmOSGetDirEntries(pathname, filename, XmFILE_ANY_TYPE, False, True,
358 &nameList, &nFiles, &maxFiles);
359 for (i=0; i<nFiles; i++) {
360 - if (ParseFilename(nameList[i], filename, pathname) != 0) {
361 + if (ParseFilename(nameList[i], filename, pathname,
362 + window->path) != 0) {
363 XBell(TheDisplay, 0);
366 EditExistingFile(window, filename, pathname, 0,
367 NULL, False, NULL, GetPrefOpenInTab(), False);
368 @@ -378,11 +379,12 @@ static void fileCB(Widget widget, Window
369 fileNameToOpen = resultDV.val.str.rep;
371 fileNameToOpen = globbuf.gl_pathv[i];
374 - if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
375 + if (ParseFilename(fileNameToOpen, filename, pathname,
376 + window->path) != 0) {
377 XBell(TheDisplay, 0);
379 EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
380 pathname, 0, NULL, False, NULL, GetPrefOpenInTab(),
382 diff --quilt old/source/server.c new/source/server.c
383 --- old/source/server.c
384 +++ new/source/server.c
385 @@ -452,11 +452,11 @@ static void processServerCommandString(c
387 /* Process the filename by looking for the files in an
388 existing window, or opening if they don't exist */
389 editFlags = (readFlag ? PREF_READ_ONLY : 0) | CREATE |
390 (createFlag ? SUPPRESS_CREATE_WARN : 0);
391 - if (ParseFilename(fullname, filename, pathname) != 0) {
392 + if (ParseFilename(fullname, filename, pathname, NULL) != 0) {
393 fprintf(stderr, "NEdit: invalid file name\n");
394 deleteFileClosedProperty2(filename, pathname);
398 diff --quilt old/source/tags.c new/source/tags.c
399 --- old/source/tags.c
400 +++ new/source/tags.c
401 @@ -253,22 +253,22 @@ static int addTag(const char *name, cons
403 strcpy(newfile,file);
405 sprintf(newfile,"%s%s", path, file);
407 - NormalizePathname(newfile);
408 + NormalizePathname(newfile, NULL);
410 for (t = table[addr]; t; t = t->next) {
411 if (strcmp(name,t->name)) continue;
412 if (lang != t->language) continue;
413 if (strcmp(search,t->searchString)) continue;
414 if (posInf != t->posInf) continue;
415 if (*t->file == '/' && strcmp(newfile,t->file)) continue;
416 if (*t->file != '/') {
417 char tmpfile[MAXPATHLEN];
418 sprintf(tmpfile, "%s%s", t->path, t->file);
419 - NormalizePathname(tmpfile);
420 + NormalizePathname(tmpfile, NULL);
421 if (strcmp(newfile, tmpfile)) continue;
426 @@ -364,11 +364,11 @@ int AddRelTagsFile(const char *tagSpec,
428 strcpy(pathName, GetCurrentDir());
430 strcat(pathName, "/");
431 strcat(pathName, filename);
432 - NormalizePathname(pathName);
433 + NormalizePathname(pathName, NULL);
435 for (t = FileList; t && strcmp(t->filename, pathName); t = t->next);
439 @@ -432,11 +432,11 @@ int AddTagsFile(const char *tagSpec, int
440 strcat(pathName,"/");
441 strcat(pathName,filename);
443 strcpy(pathName,filename);
445 - NormalizePathname(pathName);
446 + NormalizePathname(pathName, NULL);
448 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
450 /* This file is already in the list. It's easiest to just
451 refcount all tag/tip files even though we only actually care
452 @@ -503,11 +503,11 @@ int DeleteTagsFile(const char *tagSpec,
453 strcat(pathName,"/");
454 strcat(pathName,filename);
456 strcpy(pathName,filename);
458 - NormalizePathname(pathName);
459 + NormalizePathname(pathName, NULL);
461 for (last=NULL,t = FileList; t; last = t,t = t->next) {
462 if (strcmp(t->filename, pathName))
464 /* Don't unload tips files with nonzero refcounts unless forced */
465 @@ -733,11 +733,11 @@ static int loadTagsFile(const char *tags
467 if ((fp = fopen(resolvedTagsFile, "r")) == NULL) {
471 - ParseFilename(resolvedTagsFile, NULL, tagPath);
472 + ParseFilename(resolvedTagsFile, NULL, tagPath, NULL);
474 /* Read the file and store its contents */
475 while (fgets(line, MAXLINE, fp)) {
477 /* This might take a while if you have a huge tags file (like I do)..
478 @@ -1147,11 +1147,11 @@ static int findAllMatches(WindowInfo *wi
479 strcpy(tagFiles[nMatches], fileToSearch);
481 sprintf(tagFiles[nMatches],"%s%s",tagPath,fileToSearch);
482 strcpy(tagSearch[nMatches],searchString);
483 tagPosInf[nMatches]=startPos;
484 - ParseFilename(tagFiles[nMatches], filename, pathname);
485 + ParseFilename(tagFiles[nMatches], filename, pathname, NULL);
486 /* Is this match in the current file? If so, use it! */
487 if (GetPrefSmartTags() && !strcmp(window->filename,filename)
488 && !strcmp(window->path,pathname) ) {
490 strcpy(tagFiles[0],tagFiles[nMatches]);
491 @@ -1204,11 +1204,11 @@ static int findAllMatches(WindowInfo *wi
492 XBell(TheDisplay, 0);
496 for (i=0; i<nMatches; i++) {
497 - ParseFilename(tagFiles[i], filename, pathname);
498 + ParseFilename(tagFiles[i], filename, pathname, NULL);
499 if ((i<nMatches-1 && !strcmp(tagFiles[i],tagFiles[i+1])) ||
500 (i>0 && !strcmp(tagFiles[i],tagFiles[i-1]))) {
501 if(*(tagSearch[i]) && (tagPosInf[i] != -1)) { /* etags */
502 sprintf(temp,"%2d. %s%s %8i %s", i+1, pathname,
503 filename, tagPosInf[i], tagSearch[i]);
504 @@ -1327,11 +1327,11 @@ static void showMatchingCalltip( Widget
509 /* 1. Open the target file */
510 - NormalizePathname(tagFiles[i]);
511 + NormalizePathname(tagFiles[i], NULL);
512 fp = fopen(tagFiles[i], "r");
514 DialogF(DF_ERR, parent, 1, "Error opening File", "Error opening %s",
517 @@ -1446,11 +1446,11 @@ static void editTaggedLocation( Widget p
518 int startPos, endPos, lineNum, rows;
519 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
520 WindowInfo *windowToSearch;
521 WindowInfo *parentWindow = WidgetToWindow(parent);
523 - ParseFilename(tagFiles[i],filename,pathname);
524 + ParseFilename(tagFiles[i], filename, pathname, NULL);
525 /* open the file containing the definition */
526 EditExistingFile(parentWindow, filename, pathname, 0, NULL, False,
527 NULL, GetPrefOpenInTab(), False);
528 windowToSearch = FindWindowWithFile(filename, pathname);
529 if (windowToSearch == NULL) {
530 @@ -1993,11 +1993,11 @@ static int loadTipsFile(const char *tips
531 if(!ResolvePath(tipsFile, resolvedTipsFile))
535 /* Get the path to the tips file */
536 - ParseFilename(resolvedTipsFile, NULL, tipPath);
537 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
540 if ((fp = fopen(resolvedTipsFile, "r")) == NULL)
543 diff --quilt old/util/fileUtils.c new/util/fileUtils.c
544 --- old/util/fileUtils.c
545 +++ new/util/fileUtils.c
546 @@ -86,12 +86,12 @@ static void copyThruSlash(char **toStrin
547 ** Return non-zero value if it fails, zero else.
548 ** For now we assume that filename and pathname are at
549 ** most MAXPATHLEN chars long.
550 ** To skip setting filename or pathname pass NULL for that argument.
553 -ParseFilename(const char *fullname, char *filename, char *pathname)
554 +int ParseFilename(const char *fullname, char *filename, char *pathname,
555 + const char *relpath)
557 int fullLen = strlen(fullname);
558 int i, pathLen, fileLen;
561 @@ -136,11 +136,11 @@ ParseFilename(const char *fullname, char
562 filename[fileLen] = 0;
565 #ifndef VMS /* UNIX specific... Modify at a later date for VMS */
567 - if (NormalizePathname(pathname)) {
568 + if (NormalizePathname(pathname, relpath)) {
569 return 1; /* pathname too long */
571 pathLen = strlen(pathname);
574 @@ -269,11 +269,11 @@ ResolvePath(const char * pathIn, char *
576 strcpy(pathEnd+1, resolveBuf);
578 strcpy(pathBuf, resolveBuf);
580 - NormalizePathname(pathBuf);
581 + NormalizePathname(pathBuf, NULL);
586 #endif /* NO_READLINK */
587 @@ -285,27 +285,29 @@ ResolvePath(const char * pathIn, char *
588 ** Capable to handle arbitrary path length (>MAXPATHLEN)!
590 ** FIXME: Documentation
591 ** FIXME: Change return value to False and True.
593 -int NormalizePathname(char *pathname)
594 +int NormalizePathname(char *pathname, const char *relpath)
596 - /* if this is a relative pathname, prepend current directory */
597 + /* if this is a relative pathname, prepend relpath */
598 + /* if relpath is a relative path, prepend the current directory */
600 /* OS/2, ...: welcome to the world of drive letters ... */
601 if (!_fnisabs(pathname)) {
603 if (pathname[0] != '/') {
607 + int useRelpath = (relpath && *relpath);
609 /* make a copy of pathname to work from */
610 oldPathname=(char *)malloc(strlen(pathname)+1);
611 strcpy(oldPathname, pathname);
612 /* get the working directory and prepend to the path */
613 - strcpy(pathname, GetCurrentDir());
614 + strcpy(pathname, useRelpath ? relpath : GetCurrentDir());
616 /* check for trailing slash, or pathname being root dir "/":
617 don't add a second '/' character as this may break things
618 on non-un*x systems */
619 len = strlen(pathname); /* GetCurrentDir() returns non-NULL value */
620 @@ -318,10 +320,18 @@ int NormalizePathname(char *pathname)
622 strcat(pathname, "/");
624 strcat(pathname, oldPathname);
628 + /* make sure our relative path wasn't relative to start with */
629 + if (CompressPathname(pathname) == 0)
630 + return NormalizePathname(pathname, NULL);
632 + return 1; /* some non-zero value */
636 /* compress out .. and . */
637 return CompressPathname(pathname);
639 @@ -470,11 +480,11 @@ copyThruSlash(char **toString, char **fr
643 ** Return 0 if everything's fine, 1 else.
645 -int NormalizePathname(char *pathname)
646 +int NormalizePathname(char *pathname, const char *relpath)
652 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
653 --- old/util/fileUtils.h
654 +++ new/util/fileUtils.h
656 #ifndef NEDIT_FILEUTILS_H_INCLUDED
657 #define NEDIT_FILEUTILS_H_INCLUDED
659 enum fileFormats {UNIX_FILE_FORMAT, DOS_FILE_FORMAT, MAC_FILE_FORMAT};
661 -int ParseFilename(const char *fullname, char *filename, char *pathname);
662 +int ParseFilename(const char *fullname, char *filename, char *pathname,
663 + const char *relpath);
664 int ExpandTilde(char *pathname);
665 const char* GetTrailingPathComponents(const char* path,
667 -int NormalizePathname(char *pathname);
668 +int NormalizePathname(char *pathname, const char *relpath);
669 int CompressPathname(char *pathname);
670 int ResolvePath(const char * pathIn, char * pathResolved);
672 int FormatOfFile(const char *fileString);
673 void ConvertFromDosFileString(char *inString, int *length,
674 diff --quilt old/util/getfiles.c new/util/getfiles.c
675 --- old/util/getfiles.c
676 +++ new/util/getfiles.c
677 @@ -1401,11 +1401,11 @@ static void listCharEH(Widget w, XtPoint
678 /* compare them with the accumulated user keystrokes & decide the
679 appropriate line in the list widget to select */
681 for (i=0; i<nItems; i++) {
682 XmStringGetLtoR(items[i], XmSTRING_DEFAULT_CHARSET, &itemString);
683 - if (ParseFilename(itemString, name, path) != 0) {
684 + if (ParseFilename(itemString, name, path, NULL) != 0) {
689 cmp = strncmp(name, keystrokes, nKeystrokes);