1 From: Tony Balinski <ajbj@free.fr>
2 Subject: Allow NormalizePathname() and ParseFilename() to use windows path
4 Various operations require the extension of an incomplete file specification
5 to a full, absolute path. Before this patch, this completion uses the
6 current directory of the NEdit process as the base for relative file lookup.
7 However, this works against NEdit's file dialogs and shell processing which
8 start off in the directory of the current document, which may well not be
9 the same as the process' directory. Using "File > Open Selected" may not, in
10 this situation, find the file you would expect.
12 This patch alters NormalizePathname() and ParseFilename(), the utility
13 functions that perform the expansion so that the base for relative file
14 specifications can be passed, then changes all relevant calls to supply the
15 current window's file path value. It includes the nmReadWriteRelToWin.diff
16 adjustments to macro file functions read_file(), write_file() and
17 append_file() for this same behaviour, and adds a new one, full_file_name(),
18 which provides the macro writer with a way of obtaining the relative file
19 name from a relative file path.
24 source/macro.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++--
28 source/selection.c | 10 ++--
30 source/tags.c | 22 ++++-----
31 util/fileUtils.c | 26 ++++++++---
32 util/fileUtils.h | 5 +-
34 11 files changed, 164 insertions(+), 42 deletions(-)
36 diff --quilt old/source/file.c new/source/file.c
39 @@ -1089,20 +1089,20 @@ int SaveWindowAs(WindowInfo *window, con
42 strcpy(fullname, newName);
45 - if (1 == NormalizePathname(fullname))
46 + if (1 == NormalizePathname(fullname, window->path))
51 /* Add newlines if requested */
53 addWrapNewlines(window);
55 - if (ParseFilename(fullname, filename, pathname) != 0) {
56 + if (ParseFilename(fullname, filename, pathname, window->path) != 0) {
60 /* If the requested file is this file, just save it and return */
61 if (!strcmp(window->filename, filename) &&
62 @@ -1183,11 +1183,11 @@ static int doSave(WindowInfo *window)
63 /* call the "pre_save_hook", if the macro returns a string, interpret this
64 as the new filename */
65 success = MacroApplyHook(window, "pre_save_hook", 0, NULL, &hookResult);
66 if (success && hookResult.tag == STRING_TAG) {
67 if (ParseFilename(hookResult.val.str.rep,
68 - window->filename, window->path)) {
69 + window->filename, window->path, window->path)) {
74 /* Get the full name of the file */
75 @@ -1303,11 +1303,11 @@ static int doSave(WindowInfo *window)
76 /* free the text buffer copy returned from XmTextGetString */
80 /* reflect the fact that NEdit is now editing a new version of the file */
81 - ParseFilename(fullname, window->filename, window->path);
82 + ParseFilename(fullname, window->filename, window->path, NULL);
85 /* success, file was written */
86 SetWindowModified(window, FALSE);
88 diff --quilt old/source/macro.c new/source/macro.c
89 --- old/source/macro.c
90 +++ new/source/macro.c
91 @@ -192,10 +192,12 @@ static int validNumberMS(WindowInfo *win
92 DataValue *result, char **errMsg);
93 static int replaceInStringMS(WindowInfo *window, DataValue *argList, int nArgs,
94 DataValue *result, char **errMsg);
95 static int replaceSubstringMS(WindowInfo *window, DataValue *argList, int nArgs,
96 DataValue *result, char **errMsg);
97 +static int fullFileNameMS(WindowInfo *window, DataValue *argList, int nArgs,
98 + DataValue *result, char **errMsg);
99 static int readFileMS(WindowInfo *window, DataValue *argList, int nArgs,
100 DataValue *result, char **errMsg);
101 static int writeFileMS(WindowInfo *window, DataValue *argList, int nArgs,
102 DataValue *result, char **errMsg);
103 static int appendFileMS(WindowInfo *window, DataValue *argList, int nArgs,
104 @@ -537,10 +539,11 @@ static const BuiltInSubrName MacroSubrs[
105 { "to_column", toColumnMS },
106 { "set_window_title", setWindowTitleMS },
107 { "timer_add", timerAddMS },
108 { "timer_remove", timerRemoveMS },
109 { "escape_literal", escapeLiteralMS },
110 + { "full_file_name", fullFileNameMS },
111 { NULL, NULL } /* sentinel */
114 static const BuiltInSubrName SpecialVars[] = {
115 { "$cursor", cursorMV },
116 @@ -1969,11 +1972,11 @@ static int focusWindowMS(WindowInfo *win
118 /* didn't work? try normalizing the string passed in */
120 strncpy(normalizedString, string, MAXPATHLEN);
121 normalizedString[MAXPATHLEN-1] = '\0';
122 - if (1 == NormalizePathname(normalizedString)) {
123 + if (1 == NormalizePathname(normalizedString, window->path)) {
124 /* Something is broken with the input pathname. */
125 *errMsg = "Pathname too long in focus_window()";
128 for (w=WindowList; w != NULL; w = w->next) {
129 @@ -2405,10 +2408,112 @@ static int clipboardToStringMS(WindowInf
130 result->val.str.len = retLength;
136 +** Resolve the partial file path in name with respect to path.
137 +** (We don't use NormalizePathname() since this modifies its path in place.)
139 +static char *convFilePathToAbsolute(const char *path, char *name)
141 + static char *nameText = NULL, *ptr;
142 + static size_t nameTextLen = 0;
143 + size_t namelen, pathlen, len;
144 + Bool isRelative = False;
145 + size_t needSlash = 0;
147 + if (!path || !path[0] || strcmp(path, ".") == 0)
148 + path = GetCurrentDir();
151 + /* If path name is relative, make it refer to current window's directory;
152 + absolute paths start with a logical name ([\w$]+) followed by a colon,
153 + or with a non-relative path in brackets (not starting with . or -)
155 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
156 + !((name[0] == '[') && (name[1] != '-') &&
157 + (name[1] != '.')));
160 + Any path starting without a "/" is considered relative; if the first
161 + character is "~", we really need the user's home directory */
162 + if (name[0] == '~' && name[1] == '/') {
163 + path = GetHomeDir();
164 + for (++name; *name == '/'; ++name)
165 + continue; /* skip slash(es) following initial tilde */
169 + isRelative = (name[0] != '/');
175 + namelen = strlen(name);
176 + pathlen = strlen(path);
179 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
182 + /* make sure the buffer's big enough */
183 + len = namelen + pathlen + needSlash;
185 + if (nameTextLen < len) {
186 + ptr = realloc(nameText, len + 1);
193 + /* copy in pieces */
194 + strcpy(nameText, path);
196 + nameText[pathlen] = '/';
197 + strcpy(nameText + pathlen + needSlash, name);
199 + CompressPathname(nameText);
205 +** Built-in macro subroutine for expanding a possibly partial file specification
206 +** to a full one, using the current window's directory as a base for relative
207 +** path specifications. It does not check for file/path validity.
209 +static int fullFileNameMS(WindowInfo *window, DataValue *argList, int nArgs,
210 + DataValue *result, char **errMsg)
212 + char stringStorage[TYPE_INT_STR_SIZE(int)], *name;
215 + /* Validate arguments and convert to int */
217 + return wrongNArgsErr(errMsg);
218 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
221 + name = convFilePathToAbsolute(window->path, name);
222 + len = strlen(name);
225 + result->tag = STRING_TAG;
226 + AllocNString(&result->val.str, len + 1);
227 + strcpy(result->val.str.rep, name);
230 + result->tag = STRING_TAG;
231 + result->val.str.rep = PERM_ALLOC_STR("");
232 + result->val.str.len = 0;
239 ** Built-in macro subroutine for reading the contents of a text file into
240 ** a string. On success, returns 1 in $readStatus, and the contents of the
241 ** file as a string in the subroutine return value. On failure, returns
242 @@ -2425,11 +2530,13 @@ static int readFileMS(WindowInfo *window
243 /* Validate arguments and convert to int */
245 return wrongNArgsErr(errMsg);
246 if (!readStringArg(argList[0], &name, stringStorage, errMsg))
250 + name = convFilePathToAbsolute(window->path, name);
252 /* Read the whole file into an allocated string */
253 if ((fp = fopen(name, "r")) == NULL)
255 if (fstat(fileno(fp), &statbuf) != 0)
257 @@ -2504,11 +2611,13 @@ static int writeOrAppendFile(int append,
258 return wrongNArgsErr(errMsg);
259 if (!readStringArg(argList[0], &string, stringStorage[1], errMsg))
261 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
265 + name = convFilePathToAbsolute(window->path, name);
268 if ((fp = fopen(name, append ? "a" : "w")) == NULL) {
269 result->tag = INT_TAG;
270 result->val.n = False;
272 @@ -5180,11 +5289,11 @@ static int neditHomeMV(WindowInfo *windo
273 DataValue *result, char **errMsg)
275 const char *neditRCName = GetRCFileName(NEDIT_RC);
276 char neditHome[MAXPATHLEN];
278 - if (0 != ParseFilename(neditRCName, NULL, neditHome)) {
279 + if (0 != ParseFilename(neditRCName, NULL, neditHome, NULL)) {
280 M_FAILURE("Unable to parse path of nedit.rc in %s");
283 result->tag = STRING_TAG;
284 AllocNStringCpy(&result->val.str, neditHome);
285 diff --quilt old/source/menu.c new/source/menu.c
286 --- old/source/menu.c
287 +++ new/source/menu.c
288 @@ -2974,11 +2974,11 @@ static void openAP(Widget w, XEvent *eve
289 fileNameToOpen = resultDV.val.str.rep;
291 fileNameToOpen = args[0];
294 - if (0 != ParseFilename(fileNameToOpen, filename, pathname)
295 + if (0 != ParseFilename(fileNameToOpen, filename, pathname, window->path)
296 || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) {
297 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
301 @@ -5025,11 +5025,11 @@ static void updatePrevOpenMenu(WindowInf
302 if (index >= NPrevOpen) {
303 /* unmanaging before destroying stops parent from displaying */
304 XtUnmanageChild(items[n]);
305 XtDestroyWidget(items[n]);
307 - ParseFilename(prevOpenSorted[index], filename, pathname);
308 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
309 fileIsOpen = !!FindWindowWithFile(filename, pathname);
310 XtVaSetValues(items[n],
311 XmNlabelString, st1=XmStringCreateSimple(prevOpenSorted[index]),
314 @@ -5041,11 +5041,11 @@ static void updatePrevOpenMenu(WindowInf
318 /* Add new items for the remaining file names to the menu */
319 for (; index<NPrevOpen; index++) {
320 - ParseFilename(prevOpenSorted[index], filename, pathname);
321 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
322 fileIsOpen = !!FindWindowWithFile(filename, pathname);
323 btn = XtVaCreateManagedWidget("win", xmToggleButtonWidgetClass,
324 window->prevOpenMenuPane,
325 XmNlabelString, st1=XmStringCreateSimple(prevOpenSorted[index]),
327 diff --quilt old/source/nc.c new/source/nc.c
330 @@ -712,11 +712,11 @@ static void parseCommandLine(int argc, c
331 newCommandString = XtMalloc(oldLength+length+1);
332 strncpy(newCommandString, commandString, oldLength);
333 XtFree(commandString);
334 commandString = newCommandString;
335 outPtr = newCommandString + oldLength;
336 - if (ParseFilename(nameList[j], name, path) != 0) {
337 + if (ParseFilename(nameList[j], name, path, NULL) != 0) {
338 /* An Error, most likely too long paths/strings given */
339 commandLine->serverRequest = NULL;
343 @@ -748,11 +748,11 @@ static void parseCommandLine(int argc, c
346 if (nameList != NULL)
349 - if (ParseFilename(argv[i], name, path) != 0) {
350 + if (ParseFilename(argv[i], name, path, NULL) != 0) {
351 /* An Error, most likely too long paths/strings given */
352 commandLine->serverRequest = NULL;
356 diff --quilt old/source/nedit.c new/source/nedit.c
357 --- old/source/nedit.c
358 +++ new/source/nedit.c
359 @@ -658,11 +658,11 @@ int main(int argc, char **argv)
360 /* Use VMS's LIB$FILESCAN for filename in argv[i] to process */
361 /* wildcards and to obtain a full VMS file specification */
362 numFiles = VMSFileScan(argv[i], &nameList, NULL, INCLUDE_FNF);
363 /* for each expanded file name do: */
364 for (j = 0; j < numFiles; ++j) {
365 - if (ParseFilename(nameList[j], filename, pathname) == 0) {
366 + if (ParseFilename(nameList[j], filename, pathname, NULL) == 0) {
367 /* determine if file is to be openned in new tab, by
368 factoring the options -group, -tabbed & -untabbed */
370 isTabbed = 0; /* start a new window for new group */
371 group = 1; /* next file will be within group */
372 @@ -713,11 +713,11 @@ int main(int argc, char **argv)
375 if (nameList != NULL)
378 - if (ParseFilename(argv[i], filename, pathname) == 0 ) {
379 + if (ParseFilename(argv[i], filename, pathname, NULL) == 0 ) {
380 /* determine if file is to be openned in new tab, by
381 factoring the options -group, -tabbed & -untabbed */
383 isTabbed = 0; /* start a new window for new group */
384 group = 1; /* next file will be within group */
385 diff --quilt old/source/selection.c new/source/selection.c
386 --- old/source/selection.c
387 +++ new/source/selection.c
388 @@ -326,21 +326,21 @@ static void fileCB(Widget widget, Window
389 names, in these cases, either don't expand names, or try to use the
390 Motif internal parsing routine _XmOSGetDirEntries, which is not
391 guranteed to be available, but in practice is there and does work. */
392 #if defined(DONT_HAVE_GLOB) || defined(VMS)
394 - if (ParseFilename(nameText, filename, pathname) != 0) {
395 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
396 XBell(TheDisplay, 0);
399 EditExistingFile(window, filename,
400 pathname, 0, NULL, False, NULL, GetPrefOpenInTab(), False);
401 #elif defined(USE_MOTIF_GLOB)
402 { char **nameList = NULL;
403 int i, nFiles = 0, maxFiles = 30;
405 - if (ParseFilename(nameText, filename, pathname) != 0) {
406 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
407 XBell(TheDisplay, 0);
410 _XmOSGetDirEntries(pathname, filename, XmFILE_ANY_TYPE, False, True,
411 &nameList, &nFiles, &maxFiles);
412 @@ -360,11 +360,12 @@ static void fileCB(Widget widget, Window
413 fileNameToOpen = resultDV.val.str.rep;
415 fileNameToOpen = nameList[i];
418 - if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
419 + if (ParseFilename(fileNameToOpen, filename, pathname,
420 + window->path) != 0) {
421 XBell(TheDisplay, 0);
423 EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
424 pathname, 0, NULL, False, NULL, GetPrefOpenInTab(),
426 @@ -397,11 +398,12 @@ static void fileCB(Widget widget, Window
427 fileNameToOpen = resultDV.val.str.rep;
429 fileNameToOpen = globbuf.gl_pathv[i];
432 - if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
433 + if (ParseFilename(fileNameToOpen, filename, pathname,
434 + window->path) != 0) {
435 XBell(TheDisplay, 0);
437 EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
438 pathname, 0, NULL, False, NULL, GetPrefOpenInTab(),
440 diff --quilt old/source/server.c new/source/server.c
441 --- old/source/server.c
442 +++ new/source/server.c
443 @@ -454,11 +454,11 @@ static void processServerCommandString(c
445 /* Process the filename by looking for the files in an
446 existing window, or opening if they don't exist */
447 editFlags = (readFlag ? PREF_READ_ONLY : 0) | CREATE |
448 (createFlag ? SUPPRESS_CREATE_WARN : 0);
449 - if (ParseFilename(fullname, filename, pathname) != 0) {
450 + if (ParseFilename(fullname, filename, pathname, NULL) != 0) {
451 fprintf(stderr, "NEdit: invalid file name\n");
452 deleteFileClosedProperty2(filename, pathname);
456 diff --quilt old/source/tags.c new/source/tags.c
457 --- old/source/tags.c
458 +++ new/source/tags.c
459 @@ -252,22 +252,22 @@ static int addTag(const char *name, cons
461 strcpy(newfile,file);
463 sprintf(newfile,"%s%s", path, file);
465 - NormalizePathname(newfile);
466 + NormalizePathname(newfile, NULL);
468 for (t = table[addr]; t; t = t->next) {
469 if (strcmp(name,t->name)) continue;
470 if (lang != t->language) continue;
471 if (strcmp(search,t->searchString)) continue;
472 if (posInf != t->posInf) continue;
473 if (*t->file == '/' && strcmp(newfile,t->file)) continue;
474 if (*t->file != '/') {
475 char tmpfile[MAXPATHLEN];
476 sprintf(tmpfile, "%s%s", t->path, t->file);
477 - NormalizePathname(tmpfile);
478 + NormalizePathname(tmpfile, NULL);
479 if (strcmp(newfile, tmpfile)) continue;
484 @@ -363,11 +363,11 @@ int AddRelTagsFile(const char *tagSpec,
486 strcpy(pathName, GetCurrentDir());
488 strcat(pathName, "/");
489 strcat(pathName, filename);
490 - NormalizePathname(pathName);
491 + NormalizePathname(pathName, NULL);
493 for (t = FileList; t && strcmp(t->filename, pathName); t = t->next);
497 @@ -431,11 +431,11 @@ int AddTagsFile(const char *tagSpec, int
498 strcat(pathName,"/");
499 strcat(pathName,filename);
501 strcpy(pathName,filename);
503 - NormalizePathname(pathName);
504 + NormalizePathname(pathName, NULL);
506 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
508 /* This file is already in the list. It's easiest to just
509 refcount all tag/tip files even though we only actually care
510 @@ -502,11 +502,11 @@ int DeleteTagsFile(const char *tagSpec,
511 strcat(pathName,"/");
512 strcat(pathName,filename);
514 strcpy(pathName,filename);
516 - NormalizePathname(pathName);
517 + NormalizePathname(pathName, NULL);
519 for (last=NULL,t = FileList; t; last = t,t = t->next) {
520 if (strcmp(t->filename, pathName))
522 /* Don't unload tips files with nonzero refcounts unless forced */
523 @@ -732,11 +732,11 @@ static int loadTagsFile(const char *tags
525 if ((fp = fopen(resolvedTagsFile, "r")) == NULL) {
529 - ParseFilename(resolvedTagsFile, NULL, tagPath);
530 + ParseFilename(resolvedTagsFile, NULL, tagPath, NULL);
532 /* Read the file and store its contents */
533 while (fgets(line, MAXLINE, fp)) {
535 /* This might take a while if you have a huge tags file (like I do)..
536 @@ -1145,11 +1145,11 @@ static int findAllMatches(WindowInfo *wi
537 strcpy(tagFiles[nMatches], fileToSearch);
539 sprintf(tagFiles[nMatches],"%s%s",tagPath,fileToSearch);
540 strcpy(tagSearch[nMatches],searchString);
541 tagPosInf[nMatches]=startPos;
542 - ParseFilename(tagFiles[nMatches], filename, pathname);
543 + ParseFilename(tagFiles[nMatches], filename, pathname, NULL);
544 /* Is this match in the current file? If so, use it! */
545 if (GetPrefSmartTags() && !strcmp(window->filename,filename)
546 && !strcmp(window->path,pathname) ) {
548 strcpy(tagFiles[0],tagFiles[nMatches]);
549 @@ -1202,11 +1202,11 @@ static int findAllMatches(WindowInfo *wi
550 XBell(TheDisplay, 0);
554 for (i=0; i<nMatches; i++) {
555 - ParseFilename(tagFiles[i], filename, pathname);
556 + ParseFilename(tagFiles[i], filename, pathname, NULL);
557 if ((i<nMatches-1 && !strcmp(tagFiles[i],tagFiles[i+1])) ||
558 (i>0 && !strcmp(tagFiles[i],tagFiles[i-1]))) {
559 if(*(tagSearch[i]) && (tagPosInf[i] != -1)) { /* etags */
560 sprintf(temp,"%2d. %s%s %8i %s", i+1, pathname,
561 filename, tagPosInf[i], tagSearch[i]);
562 @@ -1324,11 +1324,11 @@ static void showMatchingCalltip( Widget
567 /* 1. Open the target file */
568 - NormalizePathname(tagFiles[i]);
569 + NormalizePathname(tagFiles[i], NULL);
570 fp = fopen(tagFiles[i], "r");
572 DialogF(DF_ERR, parent, 1, "Error opening File", "Error opening %s",
575 @@ -1443,11 +1443,11 @@ static void editTaggedLocation( Widget p
576 int startPos, endPos, lineNum, rows;
577 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
578 WindowInfo *windowToSearch;
579 WindowInfo *parentWindow = WidgetToWindow(parent);
581 - ParseFilename(tagFiles[i],filename,pathname);
582 + ParseFilename(tagFiles[i], filename, pathname, NULL);
583 /* open the file containing the definition */
584 EditExistingFile(parentWindow, filename, pathname, 0, NULL, False,
585 NULL, GetPrefOpenInTab(), False);
586 windowToSearch = FindWindowWithFile(filename, pathname);
587 if (windowToSearch == NULL) {
588 @@ -1990,11 +1990,11 @@ static int loadTipsFile(const char *tips
589 if(!ResolvePath(tipsFile, resolvedTipsFile))
593 /* Get the path to the tips file */
594 - ParseFilename(resolvedTipsFile, NULL, tipPath);
595 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
598 if ((fp = fopen(resolvedTipsFile, "r")) == NULL)
601 diff --quilt old/util/fileUtils.c new/util/fileUtils.c
602 --- old/util/fileUtils.c
603 +++ new/util/fileUtils.c
604 @@ -86,12 +86,12 @@ static void copyThruSlash(char **toStrin
605 ** Return non-zero value if it fails, zero else.
606 ** For now we assume that filename and pathname are at
607 ** least MAXPATHLEN chars long.
608 ** To skip setting filename or pathname pass NULL for that argument.
611 -ParseFilename(const char *fullname, char *filename, char *pathname)
612 +int ParseFilename(const char *fullname, char *filename, char *pathname,
613 + const char *relpath)
615 int fullLen = strlen(fullname);
616 int i, pathLen, fileLen;
619 @@ -136,11 +136,11 @@ ParseFilename(const char *fullname, char
620 filename[fileLen] = 0;
623 #ifndef VMS /* UNIX specific... Modify at a later date for VMS */
625 - if (NormalizePathname(pathname)) {
626 + if (NormalizePathname(pathname, relpath)) {
627 return 1; /* pathname too long */
629 pathLen = strlen(pathname);
632 @@ -269,11 +269,11 @@ ResolvePath(const char * pathIn, char *
634 strcpy(pathEnd+1, resolveBuf);
636 strcpy(pathBuf, resolveBuf);
638 - NormalizePathname(pathBuf);
639 + NormalizePathname(pathBuf, NULL);
644 #endif /* NO_READLINK */
645 @@ -285,27 +285,29 @@ ResolvePath(const char * pathIn, char *
646 ** Capable to handle arbitrary path length (>MAXPATHLEN)!
648 ** FIXME: Documentation
649 ** FIXME: Change return value to False and True.
651 -int NormalizePathname(char *pathname)
652 +int NormalizePathname(char *pathname, const char *relpath)
654 - /* if this is a relative pathname, prepend current directory */
655 + /* if this is a relative pathname, prepend relpath */
656 + /* if relpath is a relative path, prepend the current directory */
658 /* OS/2, ...: welcome to the world of drive letters ... */
659 if (!_fnisabs(pathname)) {
661 if (pathname[0] != '/') {
665 + int useRelpath = (relpath && *relpath);
667 /* make a copy of pathname to work from */
668 oldPathname=(char *)malloc(strlen(pathname)+1);
669 strcpy(oldPathname, pathname);
670 /* get the working directory and prepend to the path */
671 - strcpy(pathname, GetCurrentDir());
672 + strcpy(pathname, useRelpath ? relpath : GetCurrentDir());
674 /* check for trailing slash, or pathname being root dir "/":
675 don't add a second '/' character as this may break things
676 on non-un*x systems */
677 len = strlen(pathname); /* GetCurrentDir() returns non-NULL value */
678 @@ -318,10 +320,18 @@ int NormalizePathname(char *pathname)
680 strcat(pathname, "/");
682 strcat(pathname, oldPathname);
686 + /* make sure our relative path wasn't relative to start with */
687 + if (CompressPathname(pathname) == 0)
688 + return NormalizePathname(pathname, NULL);
690 + return 1; /* some non-zero value */
694 /* compress out .. and . */
695 return CompressPathname(pathname);
697 @@ -470,11 +480,11 @@ copyThruSlash(char **toString, char **fr
701 ** Return 0 if everything's fine, 1 else.
703 -int NormalizePathname(char *pathname)
704 +int NormalizePathname(char *pathname, const char *relpath)
710 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
711 --- old/util/fileUtils.h
712 +++ new/util/fileUtils.h
714 #ifndef NEDIT_FILEUTILS_H_INCLUDED
715 #define NEDIT_FILEUTILS_H_INCLUDED
717 enum fileFormats {UNIX_FILE_FORMAT, DOS_FILE_FORMAT, MAC_FILE_FORMAT};
719 -int ParseFilename(const char *fullname, char *filename, char *pathname);
720 +int ParseFilename(const char *fullname, char *filename, char *pathname,
721 + const char *relpath);
722 int ExpandTilde(char *pathname);
723 const char* GetTrailingPathComponents(const char* path,
725 -int NormalizePathname(char *pathname);
726 +int NormalizePathname(char *pathname, const char *relpath);
727 int CompressPathname(char *pathname);
728 int ResolvePath(const char * pathIn, char * pathResolved);
730 int FormatOfFile(const char *fileString);
731 void ConvertFromDosFileString(char *inString, int *length,
732 diff --quilt old/util/getfiles.c new/util/getfiles.c
733 --- old/util/getfiles.c
734 +++ new/util/getfiles.c
735 @@ -1022,11 +1022,11 @@ static void listCharEH(Widget w, XtPoint
736 /* compare them with the accumulated user keystrokes & decide the
737 appropriate line in the list widget to select */
739 for (i=0; i<nItems; i++) {
740 XmStringGetLtoR(items[i], XmSTRING_DEFAULT_CHARSET, &itemString);
741 - if (ParseFilename(itemString, name, path) != 0) {
742 + if (ParseFilename(itemString, name, path, NULL) != 0) {
747 cmp = strncmp(name, keystrokes, nKeystrokes);