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.
23 source/built-ins.h | 1
25 source/macro.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++--
29 source/selection.c | 10 ++--
31 source/tags.c | 22 +++++-----
32 util/fileUtils.c | 26 ++++++++----
33 util/fileUtils.h | 5 +-
36 13 files changed, 162 insertions(+), 42 deletions(-)
38 diff --quilt old/source/file.c new/source/file.c
41 @@ -1091,7 +1091,7 @@ int SaveWindowAs(WindowInfo *window, con
42 strcpy(fullname, newName);
45 - if (1 == NormalizePathname(fullname))
46 + if (1 == NormalizePathname(fullname, window->path))
50 @@ -1100,7 +1100,7 @@ int SaveWindowAs(WindowInfo *window, con
52 addWrapNewlines(window);
54 - if (ParseFilename(fullname, filename, pathname) != 0) {
55 + if (ParseFilename(fullname, filename, pathname, window->path) != 0) {
59 @@ -1186,7 +1186,7 @@ static int doSave(WindowInfo *window)
60 success = MacroApplyHook(window, "pre_save_hook", 0, NULL, &hookResult);
61 if (success && hookResult.tag == STRING_TAG) {
62 if (ParseFilename(hookResult.val.str.rep,
63 - window->filename, window->path)) {
64 + window->filename, window->path, window->path)) {
68 @@ -1321,7 +1321,7 @@ static int doSave(WindowInfo *window)
71 /* reflect the fact that NEdit is now editing a new version of the file */
72 - ParseFilename(fullname, window->filename, window->path);
73 + ParseFilename(fullname, window->filename, window->path, NULL);
76 /* success, file was written */
77 diff --quilt old/source/macro.c new/source/macro.c
78 --- old/source/macro.c
79 +++ new/source/macro.c
80 @@ -1680,7 +1680,7 @@ static int focusWindowMS(WindowInfo *win
82 strncpy(normalizedString, string, MAXPATHLEN);
83 normalizedString[MAXPATHLEN-1] = '\0';
84 - if (1 == NormalizePathname(normalizedString)) {
85 + if (1 == NormalizePathname(normalizedString, window->path)) {
86 /* Something is broken with the input pathname. */
87 *errMsg = "Pathname too long in focus_window()";
89 @@ -2116,6 +2116,108 @@ static int clipboardToStringMS(WindowInf
94 +** Resolve the partial file path in name with respect to path.
95 +** (We don't use NormalizePathname() since this modifies its path in place.)
97 +static char *convFilePathToAbsolute(const char *path, char *name)
99 + static char *nameText = NULL, *ptr;
100 + static size_t nameTextLen = 0;
101 + size_t namelen, pathlen, len;
102 + Bool isRelative = False;
103 + size_t needSlash = 0;
105 + if (!path || !path[0] || strcmp(path, ".") == 0)
106 + path = GetCurrentDir();
109 + /* If path name is relative, make it refer to current window's directory;
110 + absolute paths start with a logical name ([\w$]+) followed by a colon,
111 + or with a non-relative path in brackets (not starting with . or -)
113 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
114 + !((name[0] == '[') && (name[1] != '-') &&
115 + (name[1] != '.')));
118 + Any path starting without a "/" is considered relative; if the first
119 + character is "~", we really need the user's home directory */
120 + if (name[0] == '~' && name[1] == '/') {
121 + path = GetHomeDir();
122 + for (++name; *name == '/'; ++name)
123 + continue; /* skip slash(es) following initial tilde */
127 + isRelative = (name[0] != '/');
133 + namelen = strlen(name);
134 + pathlen = strlen(path);
137 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
140 + /* make sure the buffer's big enough */
141 + len = namelen + pathlen + needSlash;
143 + if (nameTextLen < len) {
144 + ptr = realloc(nameText, len + 1);
151 + /* copy in pieces */
152 + strcpy(nameText, path);
154 + nameText[pathlen] = '/';
155 + strcpy(nameText + pathlen + needSlash, name);
157 + CompressPathname(nameText);
163 +** Built-in macro subroutine for expanding a possibly partial file specification
164 +** to a full one, using the current window's directory as a base for relative
165 +** path specifications. It does not check for file/path validity.
167 +static int fullFileNameMS(WindowInfo *window, DataValue *argList, int nArgs,
168 + DataValue *result, char **errMsg)
170 + char stringStorage[TYPE_INT_STR_SIZE(int)], *name;
173 + /* Validate arguments and convert to int */
175 + return wrongNArgsErr(errMsg);
176 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
179 + name = convFilePathToAbsolute(window->path, name);
180 + len = strlen(name);
183 + result->tag = STRING_TAG;
184 + AllocNString(&result->val.str, len + 1);
185 + strcpy(result->val.str.rep, name);
188 + result->tag = STRING_TAG;
189 + result->val.str.rep = PERM_ALLOC_STR("");
190 + result->val.str.len = 0;
197 ** Built-in macro subroutine for reading the contents of a text file into
198 @@ -2136,7 +2238,9 @@ static int readFileMS(WindowInfo *window
199 return wrongNArgsErr(errMsg);
200 if (!readStringArg(argList[0], &name, stringStorage, errMsg))
204 + name = convFilePathToAbsolute(window->path, name);
206 /* Read the whole file into an allocated string */
207 if ((fp = fopen(name, "r")) == NULL)
209 @@ -2215,7 +2319,9 @@ static int writeOrAppendFile(int append,
211 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
215 + name = convFilePathToAbsolute(window->path, name);
218 if ((fp = fopen(name, append ? "a" : "w")) == NULL) {
219 result->tag = INT_TAG;
220 diff --quilt old/source/menu.c new/source/menu.c
221 --- old/source/menu.c
222 +++ new/source/menu.c
223 @@ -2976,7 +2976,7 @@ static void openAP(Widget w, XEvent *eve
224 fileNameToOpen = args[0];
227 - if (0 != ParseFilename(fileNameToOpen, filename, pathname)
228 + if (0 != ParseFilename(fileNameToOpen, filename, pathname, window->path)
229 || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) {
230 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
232 @@ -5027,7 +5027,7 @@ static void updatePrevOpenMenu(WindowInf
233 XtUnmanageChild(items[n]);
234 XtDestroyWidget(items[n]);
236 - ParseFilename(prevOpenSorted[index], filename, pathname);
237 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
238 fileIsOpen = !!FindWindowWithFile(filename, pathname);
239 XtVaSetValues(items[n],
240 XmNlabelString, st1=XmStringCreateSimple(prevOpenSorted[index]),
241 @@ -5043,7 +5043,7 @@ static void updatePrevOpenMenu(WindowInf
243 /* Add new items for the remaining file names to the menu */
244 for (; index<NPrevOpen; index++) {
245 - ParseFilename(prevOpenSorted[index], filename, pathname);
246 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
247 fileIsOpen = !!FindWindowWithFile(filename, pathname);
248 btn = XtVaCreateManagedWidget("win", xmToggleButtonWidgetClass,
249 window->prevOpenMenuPane,
250 diff --quilt old/source/nc.c new/source/nc.c
253 @@ -714,7 +714,7 @@ static void parseCommandLine(int argc, c
254 XtFree(commandString);
255 commandString = newCommandString;
256 outPtr = newCommandString + oldLength;
257 - if (ParseFilename(nameList[j], name, path) != 0) {
258 + if (ParseFilename(nameList[j], name, path, NULL) != 0) {
259 /* An Error, most likely too long paths/strings given */
260 commandLine->serverRequest = NULL;
262 @@ -750,7 +750,7 @@ static void parseCommandLine(int argc, c
263 if (nameList != NULL)
266 - if (ParseFilename(argv[i], name, path) != 0) {
267 + if (ParseFilename(argv[i], name, path, NULL) != 0) {
268 /* An Error, most likely too long paths/strings given */
269 commandLine->serverRequest = NULL;
271 diff --quilt old/source/nedit.c new/source/nedit.c
272 --- old/source/nedit.c
273 +++ new/source/nedit.c
274 @@ -671,7 +671,7 @@ int main(int argc, char **argv)
275 numFiles = VMSFileScan(argv[i], &nameList, NULL, INCLUDE_FNF);
276 /* for each expanded file name do: */
277 for (j = 0; j < numFiles; ++j) {
278 - if (ParseFilename(nameList[j], filename, pathname) == 0) {
279 + if (ParseFilename(nameList[j], filename, pathname, NULL) == 0) {
280 /* determine if file is to be openned in new tab, by
281 factoring the options -group, -tabbed & -untabbed */
283 @@ -726,7 +726,7 @@ int main(int argc, char **argv)
284 if (nameList != NULL)
287 - if (ParseFilename(argv[i], filename, pathname) == 0 ) {
288 + if (ParseFilename(argv[i], filename, pathname, NULL) == 0 ) {
289 /* determine if file is to be openned in new tab, by
290 factoring the options -group, -tabbed & -untabbed */
292 diff --quilt old/source/selection.c new/source/selection.c
293 --- old/source/selection.c
294 +++ new/source/selection.c
295 @@ -328,7 +328,7 @@ static void fileCB(Widget widget, Window
296 guranteed to be available, but in practice is there and does work. */
297 #if defined(DONT_HAVE_GLOB) || defined(VMS)
299 - if (ParseFilename(nameText, filename, pathname) != 0) {
300 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
301 XBell(TheDisplay, 0);
304 @@ -338,7 +338,7 @@ static void fileCB(Widget widget, Window
305 { char **nameList = NULL;
306 int i, nFiles = 0, maxFiles = 30;
308 - if (ParseFilename(nameText, filename, pathname) != 0) {
309 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
310 XBell(TheDisplay, 0);
313 @@ -362,7 +362,8 @@ static void fileCB(Widget widget, Window
314 fileNameToOpen = nameList[i];
317 - if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
318 + if (ParseFilename(fileNameToOpen, filename, pathname,
319 + window->path) != 0) {
320 XBell(TheDisplay, 0);
322 EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
323 @@ -399,7 +400,8 @@ static void fileCB(Widget widget, Window
324 fileNameToOpen = globbuf.gl_pathv[i];
327 - if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
328 + if (ParseFilename(fileNameToOpen, filename, pathname,
329 + window->path) != 0) {
330 XBell(TheDisplay, 0);
332 EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
333 diff --quilt old/source/server.c new/source/server.c
334 --- old/source/server.c
335 +++ new/source/server.c
336 @@ -456,7 +456,7 @@ static void processServerCommandString(c
337 existing window, or opening if they don't exist */
338 editFlags = (readFlag ? PREF_READ_ONLY : 0) | CREATE |
339 (createFlag ? SUPPRESS_CREATE_WARN : 0);
340 - if (ParseFilename(fullname, filename, pathname) != 0) {
341 + if (ParseFilename(fullname, filename, pathname, NULL) != 0) {
342 fprintf(stderr, "NEdit: invalid file name\n");
343 deleteFileClosedProperty2(filename, pathname);
345 diff --quilt old/source/tags.c new/source/tags.c
346 --- old/source/tags.c
347 +++ new/source/tags.c
348 @@ -254,7 +254,7 @@ static int addTag(const char *name, cons
350 sprintf(newfile,"%s%s", path, file);
352 - NormalizePathname(newfile);
353 + NormalizePathname(newfile, NULL);
355 for (t = table[addr]; t; t = t->next) {
356 if (strcmp(name,t->name)) continue;
357 @@ -265,7 +265,7 @@ static int addTag(const char *name, cons
358 if (*t->file != '/') {
359 char tmpfile[MAXPATHLEN];
360 sprintf(tmpfile, "%s%s", t->path, t->file);
361 - NormalizePathname(tmpfile);
362 + NormalizePathname(tmpfile, NULL);
363 if (strcmp(newfile, tmpfile)) continue;
366 @@ -365,7 +365,7 @@ int AddRelTagsFile(const char *tagSpec,
368 strcat(pathName, "/");
369 strcat(pathName, filename);
370 - NormalizePathname(pathName);
371 + NormalizePathname(pathName, NULL);
373 for (t = FileList; t && strcmp(t->filename, pathName); t = t->next);
375 @@ -433,7 +433,7 @@ int AddTagsFile(const char *tagSpec, int
377 strcpy(pathName,filename);
379 - NormalizePathname(pathName);
380 + NormalizePathname(pathName, NULL);
382 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
384 @@ -504,7 +504,7 @@ int DeleteTagsFile(const char *tagSpec,
386 strcpy(pathName,filename);
388 - NormalizePathname(pathName);
389 + NormalizePathname(pathName, NULL);
391 for (last=NULL,t = FileList; t; last = t,t = t->next) {
392 if (strcmp(t->filename, pathName))
393 @@ -734,7 +734,7 @@ static int loadTagsFile(const char *tags
397 - ParseFilename(resolvedTagsFile, NULL, tagPath);
398 + ParseFilename(resolvedTagsFile, NULL, tagPath, NULL);
400 /* Read the file and store its contents */
401 while (fgets(line, MAXLINE, fp)) {
402 @@ -1147,7 +1147,7 @@ static int findAllMatches(WindowInfo *wi
403 sprintf(tagFiles[nMatches],"%s%s",tagPath,fileToSearch);
404 strcpy(tagSearch[nMatches],searchString);
405 tagPosInf[nMatches]=startPos;
406 - ParseFilename(tagFiles[nMatches], filename, pathname);
407 + ParseFilename(tagFiles[nMatches], filename, pathname, NULL);
408 /* Is this match in the current file? If so, use it! */
409 if (GetPrefSmartTags() && !strcmp(window->filename,filename)
410 && !strcmp(window->path,pathname) ) {
411 @@ -1204,7 +1204,7 @@ static int findAllMatches(WindowInfo *wi
414 for (i=0; i<nMatches; i++) {
415 - ParseFilename(tagFiles[i], filename, pathname);
416 + ParseFilename(tagFiles[i], filename, pathname, NULL);
417 if ((i<nMatches-1 && !strcmp(tagFiles[i],tagFiles[i+1])) ||
418 (i>0 && !strcmp(tagFiles[i],tagFiles[i-1]))) {
419 if(*(tagSearch[i]) && (tagPosInf[i] != -1)) { /* etags */
420 @@ -1326,7 +1326,7 @@ static void showMatchingCalltip( Widget
423 /* 1. Open the target file */
424 - NormalizePathname(tagFiles[i]);
425 + NormalizePathname(tagFiles[i], NULL);
426 fp = fopen(tagFiles[i], "r");
428 DialogF(DF_ERR, parent, 1, "Error opening File", "Error opening %s",
429 @@ -1445,7 +1445,7 @@ static void editTaggedLocation( Widget p
430 WindowInfo *windowToSearch;
431 WindowInfo *parentWindow = WidgetToWindow(parent);
433 - ParseFilename(tagFiles[i],filename,pathname);
434 + ParseFilename(tagFiles[i], filename, pathname, NULL);
435 /* open the file containing the definition */
436 EditExistingFile(parentWindow, filename, pathname, 0, NULL, False,
437 NULL, GetPrefOpenInTab(), False);
438 @@ -1992,7 +1992,7 @@ static int loadTipsFile(const char *tips
441 /* Get the path to the tips file */
442 - ParseFilename(resolvedTipsFile, NULL, tipPath);
443 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
446 if ((fp = fopen(resolvedTipsFile, "r")) == NULL)
447 diff --quilt old/util/fileUtils.c new/util/fileUtils.c
448 --- old/util/fileUtils.c
449 +++ new/util/fileUtils.c
450 @@ -88,8 +88,8 @@ static void copyThruSlash(char **toStrin
451 ** least MAXPATHLEN chars long.
452 ** To skip setting filename or pathname pass NULL for that argument.
455 -ParseFilename(const char *fullname, char *filename, char *pathname)
456 +int ParseFilename(const char *fullname, char *filename, char *pathname,
457 + const char *relpath)
459 int fullLen = strlen(fullname);
460 int i, pathLen, fileLen;
461 @@ -138,7 +138,7 @@ ParseFilename(const char *fullname, char
463 #ifndef VMS /* UNIX specific... Modify at a later date for VMS */
465 - if (NormalizePathname(pathname)) {
466 + if (NormalizePathname(pathname, relpath)) {
467 return 1; /* pathname too long */
469 pathLen = strlen(pathname);
470 @@ -271,7 +271,7 @@ ResolvePath(const char * pathIn, char *
472 strcpy(pathBuf, resolveBuf);
474 - NormalizePathname(pathBuf);
475 + NormalizePathname(pathBuf, NULL);
479 @@ -287,9 +287,10 @@ ResolvePath(const char * pathIn, char *
480 ** FIXME: Documentation
481 ** FIXME: Change return value to False and True.
483 -int NormalizePathname(char *pathname)
484 +int NormalizePathname(char *pathname, const char *relpath)
486 - /* if this is a relative pathname, prepend current directory */
487 + /* if this is a relative pathname, prepend relpath */
488 + /* if relpath is a relative path, prepend the current directory */
490 /* OS/2, ...: welcome to the world of drive letters ... */
491 if (!_fnisabs(pathname)) {
492 @@ -298,12 +299,13 @@ int NormalizePathname(char *pathname)
496 + int useRelpath = (relpath && *relpath);
498 /* make a copy of pathname to work from */
499 oldPathname=(char *)malloc(strlen(pathname)+1);
500 strcpy(oldPathname, pathname);
501 /* get the working directory and prepend to the path */
502 - strcpy(pathname, GetCurrentDir());
503 + strcpy(pathname, useRelpath ? relpath : GetCurrentDir());
505 /* check for trailing slash, or pathname being root dir "/":
506 don't add a second '/' character as this may break things
507 @@ -320,6 +322,14 @@ int NormalizePathname(char *pathname)
509 strcat(pathname, oldPathname);
513 + /* make sure our relative path wasn't relative to start with */
514 + if (CompressPathname(pathname) == 0)
515 + return NormalizePathname(pathname, NULL);
517 + return 1; /* some non-zero value */
521 /* compress out .. and . */
522 @@ -472,7 +482,7 @@ copyThruSlash(char **toString, char **fr
524 ** Return 0 if everything's fine, 1 else.
526 -int NormalizePathname(char *pathname)
527 +int NormalizePathname(char *pathname, const char *relpath)
531 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
532 --- old/util/fileUtils.h
533 +++ new/util/fileUtils.h
536 enum fileFormats {UNIX_FILE_FORMAT, DOS_FILE_FORMAT, MAC_FILE_FORMAT};
538 -int ParseFilename(const char *fullname, char *filename, char *pathname);
539 +int ParseFilename(const char *fullname, char *filename, char *pathname,
540 + const char *relpath);
541 int ExpandTilde(char *pathname);
542 const char* GetTrailingPathComponents(const char* path,
544 -int NormalizePathname(char *pathname);
545 +int NormalizePathname(char *pathname, const char *relpath);
546 int CompressPathname(char *pathname);
547 int ResolvePath(const char * pathIn, char * pathResolved);
549 diff --quilt old/util/getfiles.c new/util/getfiles.c
550 --- old/util/getfiles.c
551 +++ new/util/getfiles.c
552 @@ -1024,7 +1024,7 @@ static void listCharEH(Widget w, XtPoint
554 for (i=0; i<nItems; i++) {
555 XmStringGetLtoR(items[i], XmSTRING_DEFAULT_CHARSET, &itemString);
556 - if (ParseFilename(itemString, name, path) != 0) {
557 + if (ParseFilename(itemString, name, path, NULL) != 0) {
561 diff --quilt old/source/built-ins.h new/source/built-ins.h
562 --- old/source/built-ins.h
563 +++ new/source/built-ins.h
564 @@ -76,6 +76,7 @@ MS(set_window_title, setWindowTitle)
565 MS(timer_add, timerAdd)
566 MS(timer_remove, timerRemove)
567 MS(escape_literal, escapeLiteral)
568 +MS(full_file_name, fullFileName)
572 diff --quilt old/util/utils.c new/util/utils.c
575 @@ -324,7 +324,7 @@ const char* GetRCFileName(int type)
579 - ParseFilename(rcFiles[0], NULL, neditHome);
580 + ParseFilename(rcFiles[0], NULL, neditHome, NULL);
582 namesDetermined = True;