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
24 source/file.c | 10 ++--
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, 164 insertions(+), 43 deletions(-)
38 diff --quilt old/source/file.c new/source/file.c
41 @@ -1092,7 +1092,7 @@ int SaveWindowAs(WindowInfo *window, con
42 strcpy(fullname, newName);
45 - if (1 == NormalizePathname(fullname))
46 + if (1 == NormalizePathname(fullname, window->path))
50 @@ -1101,7 +1101,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 @@ -1182,8 +1182,8 @@ static int doSave(WindowInfo *window)
61 /* call pre_save_hook, and set result as path/name */
62 fileString = PreSaveHook(window);
64 - ParseFilename(fileString, window->filename, window->path)) {
65 + if (fileString && ParseFilename(fileString,
66 + window->filename, window->path, window->path)) {
67 result = DialogF(DF_ERR, window->shell, 2, "Invalid Filename",
68 "The filename provided by the post_save_hook\n"
70 @@ -1323,7 +1323,7 @@ static int doSave(WindowInfo *window)
73 /* reflect the fact that NEdit is now editing a new version of the file */
74 - ParseFilename(fullname, window->filename, window->path);
75 + ParseFilename(fullname, window->filename, window->path, NULL);
78 /* success, file was written */
79 diff --quilt old/source/macro.c new/source/macro.c
80 --- old/source/macro.c
81 +++ new/source/macro.c
82 @@ -1680,7 +1680,7 @@ static int focusWindowMS(WindowInfo *win
84 strncpy(normalizedString, string, MAXPATHLEN);
85 normalizedString[MAXPATHLEN-1] = '\0';
86 - if (1 == NormalizePathname(normalizedString)) {
87 + if (1 == NormalizePathname(normalizedString, window->path)) {
88 /* Something is broken with the input pathname. */
89 *errMsg = "Pathname too long in focus_window()";
91 @@ -2116,6 +2116,108 @@ static int clipboardToStringMS(WindowInf
96 +** Resolve the partial file path in name with respect to path.
97 +** (We don't use NormalizePathname() since this modifies its path in place.)
99 +static char *convFilePathToAbsolute(const char *path, char *name)
101 + static char *nameText = NULL, *ptr;
102 + static size_t nameTextLen = 0;
103 + size_t namelen, pathlen, len;
104 + Bool isRelative = False;
105 + size_t needSlash = 0;
107 + if (!path || !path[0] || strcmp(path, ".") == 0)
108 + path = GetCurrentDir();
111 + /* If path name is relative, make it refer to current window's directory;
112 + absolute paths start with a logical name ([\w$]+) followed by a colon,
113 + or with a non-relative path in brackets (not starting with . or -)
115 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
116 + !((name[0] == '[') && (name[1] != '-') &&
117 + (name[1] != '.')));
120 + Any path starting without a "/" is considered relative; if the first
121 + character is "~", we really need the user's home directory */
122 + if (name[0] == '~' && name[1] == '/') {
123 + path = GetHomeDir();
124 + for (++name; *name == '/'; ++name)
125 + continue; /* skip slash(es) following initial tilde */
129 + isRelative = (name[0] != '/');
135 + namelen = strlen(name);
136 + pathlen = strlen(path);
139 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
142 + /* make sure the buffer's big enough */
143 + len = namelen + pathlen + needSlash;
145 + if (nameTextLen < len) {
146 + ptr = realloc(nameText, len + 1);
153 + /* copy in pieces */
154 + strcpy(nameText, path);
156 + nameText[pathlen] = '/';
157 + strcpy(nameText + pathlen + needSlash, name);
159 + CompressPathname(nameText);
165 +** Built-in macro subroutine for expanding a possibly partial file specification
166 +** to a full one, using the current window's directory as a base for relative
167 +** path specifications. It does not check for file/path validity.
169 +static int fullFileNameMS(WindowInfo *window, DataValue *argList, int nArgs,
170 + DataValue *result, char **errMsg)
172 + char stringStorage[TYPE_INT_STR_SIZE(int)], *name;
175 + /* Validate arguments and convert to int */
177 + return wrongNArgsErr(errMsg);
178 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
181 + name = convFilePathToAbsolute(window->path, name);
182 + len = strlen(name);
185 + result->tag = STRING_TAG;
186 + AllocNString(&result->val.str, len + 1);
187 + strcpy(result->val.str.rep, name);
190 + result->tag = STRING_TAG;
191 + result->val.str.rep = PERM_ALLOC_STR("");
192 + result->val.str.len = 0;
199 ** Built-in macro subroutine for reading the contents of a text file into
200 @@ -2136,7 +2238,9 @@ static int readFileMS(WindowInfo *window
201 return wrongNArgsErr(errMsg);
202 if (!readStringArg(argList[0], &name, stringStorage, errMsg))
206 + name = convFilePathToAbsolute(window->path, name);
208 /* Read the whole file into an allocated string */
209 if ((fp = fopen(name, "r")) == NULL)
211 @@ -2215,7 +2319,9 @@ static int writeOrAppendFile(int append,
213 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
217 + name = convFilePathToAbsolute(window->path, name);
220 if ((fp = fopen(name, append ? "a" : "w")) == NULL) {
221 result->tag = INT_TAG;
222 diff --quilt old/source/menu.c new/source/menu.c
223 --- old/source/menu.c
224 +++ new/source/menu.c
225 @@ -2960,7 +2960,8 @@ static void openAP(Widget w, XEvent *eve
229 - if (ParseFilename(PreOpenHook(window, args[0]), filename, pathname)) {
230 + if (ParseFilename(PreOpenHook(window, args[0]),
231 + filename, pathname, window->path)) {
232 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
235 @@ -5006,7 +5007,7 @@ static void updatePrevOpenMenu(WindowInf
236 XtUnmanageChild(items[n]);
237 XtDestroyWidget(items[n]);
239 - ParseFilename(prevOpenSorted[index], filename, pathname);
240 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
241 fileIsOpen = !!FindWindowWithFile(filename, pathname);
242 XtVaSetValues(items[n],
243 XmNlabelString, st1=XmStringCreateSimple(prevOpenSorted[index]),
244 @@ -5022,7 +5023,7 @@ static void updatePrevOpenMenu(WindowInf
246 /* Add new items for the remaining file names to the menu */
247 for (; index<NPrevOpen; index++) {
248 - ParseFilename(prevOpenSorted[index], filename, pathname);
249 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
250 fileIsOpen = !!FindWindowWithFile(filename, pathname);
251 btn = XtVaCreateManagedWidget("win", xmToggleButtonWidgetClass,
252 window->prevOpenMenuPane,
253 diff --quilt old/source/nc.c new/source/nc.c
256 @@ -714,7 +714,7 @@ static void parseCommandLine(int argc, c
257 XtFree(commandString);
258 commandString = newCommandString;
259 outPtr = newCommandString + oldLength;
260 - if (ParseFilename(nameList[j], name, path) != 0) {
261 + if (ParseFilename(nameList[j], name, path, NULL) != 0) {
262 /* An Error, most likely too long paths/strings given */
263 commandLine->serverRequest = NULL;
265 @@ -750,7 +750,7 @@ static void parseCommandLine(int argc, c
266 if (nameList != NULL)
269 - if (ParseFilename(argv[i], name, path) != 0) {
270 + if (ParseFilename(argv[i], name, path, NULL) != 0) {
271 /* An Error, most likely too long paths/strings given */
272 commandLine->serverRequest = NULL;
274 diff --quilt old/source/nedit.c new/source/nedit.c
275 --- old/source/nedit.c
276 +++ new/source/nedit.c
277 @@ -673,7 +673,7 @@ int main(int argc, char **argv)
278 /* for each expanded file name do: */
279 for (j = 0; j < numFiles; ++j) {
280 if (ParseFilename(PreOpenHook(WindowList, nameList[j]),
281 - filename, pathname) == 0) {
282 + filename, pathname, NULL) == 0) {
283 /* determine if file is to be openned in new tab, by
284 factoring the options -group, -tabbed & -untabbed */
286 @@ -729,7 +729,7 @@ int main(int argc, char **argv)
289 if (ParseFilename(PreOpenHook(WindowList, argv[i]),
290 - filename, pathname) == 0 ) {
291 + filename, pathname, NULL) == 0 ) {
292 /* determine if file is to be openned in new tab, by
293 factoring the options -group, -tabbed & -untabbed */
295 diff --quilt old/source/selection.c new/source/selection.c
296 --- old/source/selection.c
297 +++ new/source/selection.c
298 @@ -327,7 +327,8 @@ static void fileCB(Widget widget, Window
299 guranteed to be available, but in practice is there and does work. */
300 #if defined(DONT_HAVE_GLOB) || defined(VMS)
302 - if (ParseFilename(PreOpenHook(window, nameText), filename, pathname) != 0) {
303 + if (ParseFilename(PreOpenHook(window, nameText),
304 + filename, pathname, window->path)) {
305 XBell(TheDisplay, 0);
308 @@ -337,7 +338,8 @@ static void fileCB(Widget widget, Window
309 { char **nameList = NULL;
310 int i, nFiles = 0, maxFiles = 30;
312 - if (ParseFilename(PreOpenHook(window, nameText), filename, pathname)) {
313 + if (ParseFilename(PreOpenHook(window, nameText),
314 + filename, pathname, window->path)) {
315 XBell(TheDisplay, 0);
318 @@ -345,7 +347,7 @@ static void fileCB(Widget widget, Window
319 &nameList, &nFiles, &maxFiles);
320 for (i=0; i<nFiles; i++) {
321 if (ParseFilename(PreOpenHook(window, nameList[i]),
322 - filename, pathname)) {
323 + filename, pathname, window->path)) {
324 XBell(TheDisplay, 0);
327 @@ -365,7 +367,7 @@ static void fileCB(Widget widget, Window
328 glob(nameText, GLOB_NOCHECK, NULL, &globbuf);
329 for (i=0; i<(int)globbuf.gl_pathc; i++) {
330 if (ParseFilename(PreOpenHook(window, globbuf.gl_pathv[i]),
331 - filename, pathname))
332 + filename, pathname, window->path))
333 XBell(TheDisplay, 0);
335 EditExistingFile(GetPrefOpenInTab()? window : NULL,
336 diff --quilt old/source/server.c new/source/server.c
337 --- old/source/server.c
338 +++ new/source/server.c
339 @@ -450,7 +450,7 @@ static void processServerCommandString(c
340 existing window, or opening if they don't exist */
341 editFlags = (readFlag ? PREF_READ_ONLY : 0) | CREATE |
342 (createFlag ? SUPPRESS_CREATE_WARN : 0);
343 - if (ParseFilename(fullname, filename, pathname) != 0) {
344 + if (ParseFilename(fullname, filename, pathname, NULL) != 0) {
345 fprintf(stderr, "NEdit: invalid file name\n");
346 deleteFileClosedProperty2(requestname);
348 diff --quilt old/source/tags.c new/source/tags.c
349 --- old/source/tags.c
350 +++ new/source/tags.c
351 @@ -254,7 +254,7 @@ static int addTag(const char *name, cons
353 sprintf(newfile,"%s%s", path, file);
355 - NormalizePathname(newfile);
356 + NormalizePathname(newfile, NULL);
358 for (t = table[addr]; t; t = t->next) {
359 if (strcmp(name,t->name)) continue;
360 @@ -265,7 +265,7 @@ static int addTag(const char *name, cons
361 if (*t->file != '/') {
362 char tmpfile[MAXPATHLEN];
363 sprintf(tmpfile, "%s%s", t->path, t->file);
364 - NormalizePathname(tmpfile);
365 + NormalizePathname(tmpfile, NULL);
366 if (strcmp(newfile, tmpfile)) continue;
369 @@ -365,7 +365,7 @@ int AddRelTagsFile(const char *tagSpec,
371 strcat(pathName, "/");
372 strcat(pathName, filename);
373 - NormalizePathname(pathName);
374 + NormalizePathname(pathName, NULL);
376 for (t = FileList; t && strcmp(t->filename, pathName); t = t->next);
378 @@ -433,7 +433,7 @@ int AddTagsFile(const char *tagSpec, int
380 strcpy(pathName,filename);
382 - NormalizePathname(pathName);
383 + NormalizePathname(pathName, NULL);
385 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
387 @@ -504,7 +504,7 @@ int DeleteTagsFile(const char *tagSpec,
389 strcpy(pathName,filename);
391 - NormalizePathname(pathName);
392 + NormalizePathname(pathName, NULL);
394 for (last=NULL,t = FileList; t; last = t,t = t->next) {
395 if (strcmp(t->filename, pathName))
396 @@ -734,7 +734,7 @@ static int loadTagsFile(const char *tags
400 - ParseFilename(resolvedTagsFile, NULL, tagPath);
401 + ParseFilename(resolvedTagsFile, NULL, tagPath, NULL);
403 /* Read the file and store its contents */
404 while (fgets(line, MAXLINE, fp)) {
405 @@ -1147,7 +1147,7 @@ static int findAllMatches(WindowInfo *wi
406 sprintf(tagFiles[nMatches],"%s%s",tagPath,fileToSearch);
407 strcpy(tagSearch[nMatches],searchString);
408 tagPosInf[nMatches]=startPos;
409 - ParseFilename(tagFiles[nMatches], filename, pathname);
410 + ParseFilename(tagFiles[nMatches], filename, pathname, NULL);
411 /* Is this match in the current file? If so, use it! */
412 if (GetPrefSmartTags() && !strcmp(window->filename,filename)
413 && !strcmp(window->path,pathname) ) {
414 @@ -1204,7 +1204,7 @@ static int findAllMatches(WindowInfo *wi
417 for (i=0; i<nMatches; i++) {
418 - ParseFilename(tagFiles[i], filename, pathname);
419 + ParseFilename(tagFiles[i], filename, pathname, NULL);
420 if ((i<nMatches-1 && !strcmp(tagFiles[i],tagFiles[i+1])) ||
421 (i>0 && !strcmp(tagFiles[i],tagFiles[i-1]))) {
422 if(*(tagSearch[i]) && (tagPosInf[i] != -1)) { /* etags */
423 @@ -1326,7 +1326,7 @@ static void showMatchingCalltip( Widget
426 /* 1. Open the target file */
427 - NormalizePathname(tagFiles[i]);
428 + NormalizePathname(tagFiles[i], NULL);
429 fp = fopen(tagFiles[i], "r");
431 DialogF(DF_ERR, parent, 1, "Error opening File", "Error opening %s",
432 @@ -1445,7 +1445,7 @@ static void editTaggedLocation( Widget p
433 WindowInfo *windowToSearch;
434 WindowInfo *parentWindow = WidgetToWindow(parent);
436 - ParseFilename(tagFiles[i],filename,pathname);
437 + ParseFilename(tagFiles[i], filename, pathname, NULL);
438 /* open the file containing the definition */
439 EditExistingFile(parentWindow, filename, pathname, 0, NULL, False,
440 NULL, GetPrefOpenInTab(), False);
441 @@ -1992,7 +1992,7 @@ static int loadTipsFile(const char *tips
444 /* Get the path to the tips file */
445 - ParseFilename(resolvedTipsFile, NULL, tipPath);
446 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
449 if ((fp = fopen(resolvedTipsFile, "r")) == NULL)
450 diff --quilt old/util/fileUtils.c new/util/fileUtils.c
451 --- old/util/fileUtils.c
452 +++ new/util/fileUtils.c
453 @@ -88,8 +88,8 @@ static void copyThruSlash(char **toStrin
454 ** least MAXPATHLEN chars long.
455 ** To skip setting filename or pathname pass NULL for that argument.
458 -ParseFilename(const char *fullname, char *filename, char *pathname)
459 +int ParseFilename(const char *fullname, char *filename, char *pathname,
460 + const char *relpath)
462 int fullLen = strlen(fullname);
463 int i, pathLen, fileLen;
464 @@ -138,7 +138,7 @@ ParseFilename(const char *fullname, char
466 #ifndef VMS /* UNIX specific... Modify at a later date for VMS */
468 - if (NormalizePathname(pathname)) {
469 + if (NormalizePathname(pathname, relpath)) {
470 return 1; /* pathname too long */
472 pathLen = strlen(pathname);
473 @@ -271,7 +271,7 @@ ResolvePath(const char * pathIn, char *
475 strcpy(pathBuf, resolveBuf);
477 - NormalizePathname(pathBuf);
478 + NormalizePathname(pathBuf, NULL);
482 @@ -287,9 +287,10 @@ ResolvePath(const char * pathIn, char *
483 ** FIXME: Documentation
484 ** FIXME: Change return value to False and True.
486 -int NormalizePathname(char *pathname)
487 +int NormalizePathname(char *pathname, const char *relpath)
489 - /* if this is a relative pathname, prepend current directory */
490 + /* if this is a relative pathname, prepend relpath */
491 + /* if relpath is a relative path, prepend the current directory */
493 /* OS/2, ...: welcome to the world of drive letters ... */
494 if (!_fnisabs(pathname)) {
495 @@ -298,12 +299,13 @@ int NormalizePathname(char *pathname)
499 + int useRelpath = (relpath && *relpath);
501 /* make a copy of pathname to work from */
502 oldPathname=(char *)malloc(strlen(pathname)+1);
503 strcpy(oldPathname, pathname);
504 /* get the working directory and prepend to the path */
505 - strcpy(pathname, GetCurrentDir());
506 + strcpy(pathname, useRelpath ? relpath : GetCurrentDir());
508 /* check for trailing slash, or pathname being root dir "/":
509 don't add a second '/' character as this may break things
510 @@ -320,6 +322,14 @@ int NormalizePathname(char *pathname)
512 strcat(pathname, oldPathname);
516 + /* make sure our relative path wasn't relative to start with */
517 + if (CompressPathname(pathname) == 0)
518 + return NormalizePathname(pathname, NULL);
520 + return 1; /* some non-zero value */
524 /* compress out .. and . */
525 @@ -472,7 +482,7 @@ copyThruSlash(char **toString, char **fr
527 ** Return 0 if everything's fine, 1 else.
529 -int NormalizePathname(char *pathname)
530 +int NormalizePathname(char *pathname, const char *relpath)
534 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
535 --- old/util/fileUtils.h
536 +++ new/util/fileUtils.h
539 enum fileFormats {UNIX_FILE_FORMAT, DOS_FILE_FORMAT, MAC_FILE_FORMAT};
541 -int ParseFilename(const char *fullname, char *filename, char *pathname);
542 +int ParseFilename(const char *fullname, char *filename, char *pathname,
543 + const char *relpath);
544 int ExpandTilde(char *pathname);
545 const char* GetTrailingPathComponents(const char* path,
547 -int NormalizePathname(char *pathname);
548 +int NormalizePathname(char *pathname, const char *relpath);
549 int CompressPathname(char *pathname);
550 int ResolvePath(const char * pathIn, char * pathResolved);
552 diff --quilt old/util/getfiles.c new/util/getfiles.c
553 --- old/util/getfiles.c
554 +++ new/util/getfiles.c
555 @@ -1024,7 +1024,7 @@ static void listCharEH(Widget w, XtPoint
557 for (i=0; i<nItems; i++) {
558 XmStringGetLtoR(items[i], XmSTRING_DEFAULT_CHARSET, &itemString);
559 - if (ParseFilename(itemString, name, path) != 0) {
560 + if (ParseFilename(itemString, name, path, NULL) != 0) {
564 diff --quilt old/source/built-ins.h new/source/built-ins.h
565 --- old/source/built-ins.h
566 +++ new/source/built-ins.h
567 @@ -76,6 +76,7 @@ MS(set_window_title, setWindowTitle)
568 MS(timer_add, timerAdd)
569 MS(timer_remove, timerRemove)
570 MS(escape_literal, escapeLiteral)
571 +MS(full_file_name, fullFileName)
575 diff --quilt old/util/utils.c new/util/utils.c
578 @@ -324,7 +324,7 @@ const char* GetRCFileName(int type)
582 - ParseFilename(rcFiles[0], NULL, neditHome);
583 + ParseFilename(rcFiles[0], NULL, neditHome, NULL);
585 namesDetermined = True;