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 | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++--
29 source/selection.c | 10 ++--
31 source/tags.c | 22 +++++-----
32 util/fileUtils.c | 26 ++++++++----
33 util/fileUtils.h | 5 +-
35 12 files changed, 162 insertions(+), 42 deletions(-)
37 diff --quilt old/source/file.c new/source/file.c
40 @@ -1091,7 +1091,7 @@ int SaveWindowAs(WindowInfo *window, con
41 strcpy(fullname, newName);
44 - if (1 == NormalizePathname(fullname))
45 + if (1 == NormalizePathname(fullname, window->path))
49 @@ -1100,7 +1100,7 @@ int SaveWindowAs(WindowInfo *window, con
51 addWrapNewlines(window);
53 - if (ParseFilename(fullname, filename, pathname) != 0) {
54 + if (ParseFilename(fullname, filename, pathname, window->path) != 0) {
58 @@ -1185,7 +1185,7 @@ static int doSave(WindowInfo *window)
59 success = MacroApplyHook(window, "pre_save_hook", 0, NULL, &hookResult);
60 if (success && hookResult.tag == STRING_TAG) {
61 if (ParseFilename(hookResult.val.str.rep,
62 - window->filename, window->path)) {
63 + window->filename, window->path, window->path)) {
67 @@ -1305,7 +1305,7 @@ static int doSave(WindowInfo *window)
70 /* reflect the fact that NEdit is now editing a new version of the file */
71 - ParseFilename(fullname, window->filename, window->path);
72 + ParseFilename(fullname, window->filename, window->path, NULL);
75 /* success, file was written */
76 diff --quilt old/source/macro.c new/source/macro.c
77 --- old/source/macro.c
78 +++ new/source/macro.c
79 @@ -1680,7 +1680,7 @@ static int focusWindowMS(WindowInfo *win
81 strncpy(normalizedString, string, MAXPATHLEN);
82 normalizedString[MAXPATHLEN-1] = '\0';
83 - if (1 == NormalizePathname(normalizedString)) {
84 + if (1 == NormalizePathname(normalizedString, window->path)) {
85 /* Something is broken with the input pathname. */
86 *errMsg = "Pathname too long in focus_window()";
88 @@ -2116,6 +2116,108 @@ static int clipboardToStringMS(WindowInf
93 +** Resolve the partial file path in name with respect to path.
94 +** (We don't use NormalizePathname() since this modifies its path in place.)
96 +static char *convFilePathToAbsolute(const char *path, char *name)
98 + static char *nameText = NULL, *ptr;
99 + static size_t nameTextLen = 0;
100 + size_t namelen, pathlen, len;
101 + Bool isRelative = False;
102 + size_t needSlash = 0;
104 + if (!path || !path[0] || strcmp(path, ".") == 0)
105 + path = GetCurrentDir();
108 + /* If path name is relative, make it refer to current window's directory;
109 + absolute paths start with a logical name ([\w$]+) followed by a colon,
110 + or with a non-relative path in brackets (not starting with . or -)
112 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
113 + !((name[0] == '[') && (name[1] != '-') &&
114 + (name[1] != '.')));
117 + Any path starting without a "/" is considered relative; if the first
118 + character is "~", we really need the user's home directory */
119 + if (name[0] == '~' && name[1] == '/') {
120 + path = GetHomeDir();
121 + for (++name; *name == '/'; ++name)
122 + continue; /* skip slash(es) following initial tilde */
126 + isRelative = (name[0] != '/');
132 + namelen = strlen(name);
133 + pathlen = strlen(path);
136 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
139 + /* make sure the buffer's big enough */
140 + len = namelen + pathlen + needSlash;
142 + if (nameTextLen < len) {
143 + ptr = realloc(nameText, len + 1);
150 + /* copy in pieces */
151 + strcpy(nameText, path);
153 + nameText[pathlen] = '/';
154 + strcpy(nameText + pathlen + needSlash, name);
156 + CompressPathname(nameText);
162 +** Built-in macro subroutine for expanding a possibly partial file specification
163 +** to a full one, using the current window's directory as a base for relative
164 +** path specifications. It does not check for file/path validity.
166 +static int fullFileNameMS(WindowInfo *window, DataValue *argList, int nArgs,
167 + DataValue *result, char **errMsg)
169 + char stringStorage[TYPE_INT_STR_SIZE(int)], *name;
172 + /* Validate arguments and convert to int */
174 + return wrongNArgsErr(errMsg);
175 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
178 + name = convFilePathToAbsolute(window->path, name);
179 + len = strlen(name);
182 + result->tag = STRING_TAG;
183 + AllocNString(&result->val.str, len + 1);
184 + strcpy(result->val.str.rep, name);
187 + result->tag = STRING_TAG;
188 + result->val.str.rep = PERM_ALLOC_STR("");
189 + result->val.str.len = 0;
196 ** Built-in macro subroutine for reading the contents of a text file into
197 @@ -2136,7 +2238,9 @@ static int readFileMS(WindowInfo *window
198 return wrongNArgsErr(errMsg);
199 if (!readStringArg(argList[0], &name, stringStorage, errMsg))
203 + name = convFilePathToAbsolute(window->path, name);
205 /* Read the whole file into an allocated string */
206 if ((fp = fopen(name, "r")) == NULL)
208 @@ -2215,7 +2319,9 @@ static int writeOrAppendFile(int append,
210 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
214 + name = convFilePathToAbsolute(window->path, name);
217 if ((fp = fopen(name, append ? "a" : "w")) == NULL) {
218 result->tag = INT_TAG;
219 @@ -4891,7 +4997,7 @@ static int neditHomeMV(WindowInfo *windo
220 const char *neditRCName = GetRCFileName(NEDIT_RC);
221 char neditHome[MAXPATHLEN];
223 - if (0 != ParseFilename(neditRCName, NULL, neditHome)) {
224 + if (0 != ParseFilename(neditRCName, NULL, neditHome, NULL)) {
225 M_FAILURE("Unable to parse path of nedit.rc in %s");
228 diff --quilt old/source/menu.c new/source/menu.c
229 --- old/source/menu.c
230 +++ new/source/menu.c
231 @@ -2976,7 +2976,7 @@ static void openAP(Widget w, XEvent *eve
232 fileNameToOpen = args[0];
235 - if (0 != ParseFilename(fileNameToOpen, filename, pathname)
236 + if (0 != ParseFilename(fileNameToOpen, filename, pathname, window->path)
237 || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) {
238 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
240 @@ -5027,7 +5027,7 @@ static void updatePrevOpenMenu(WindowInf
241 XtUnmanageChild(items[n]);
242 XtDestroyWidget(items[n]);
244 - ParseFilename(prevOpenSorted[index], filename, pathname);
245 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
246 fileIsOpen = !!FindWindowWithFile(filename, pathname);
247 XtVaSetValues(items[n],
248 XmNlabelString, st1=XmStringCreateSimple(prevOpenSorted[index]),
249 @@ -5043,7 +5043,7 @@ static void updatePrevOpenMenu(WindowInf
251 /* Add new items for the remaining file names to the menu */
252 for (; index<NPrevOpen; index++) {
253 - ParseFilename(prevOpenSorted[index], filename, pathname);
254 + ParseFilename(prevOpenSorted[index], filename, pathname, NULL);
255 fileIsOpen = !!FindWindowWithFile(filename, pathname);
256 btn = XtVaCreateManagedWidget("win", xmToggleButtonWidgetClass,
257 window->prevOpenMenuPane,
258 diff --quilt old/source/nc.c new/source/nc.c
261 @@ -714,7 +714,7 @@ static void parseCommandLine(int argc, c
262 XtFree(commandString);
263 commandString = newCommandString;
264 outPtr = newCommandString + oldLength;
265 - if (ParseFilename(nameList[j], name, path) != 0) {
266 + if (ParseFilename(nameList[j], name, path, NULL) != 0) {
267 /* An Error, most likely too long paths/strings given */
268 commandLine->serverRequest = NULL;
270 @@ -750,7 +750,7 @@ static void parseCommandLine(int argc, c
271 if (nameList != NULL)
274 - if (ParseFilename(argv[i], name, path) != 0) {
275 + if (ParseFilename(argv[i], name, path, NULL) != 0) {
276 /* An Error, most likely too long paths/strings given */
277 commandLine->serverRequest = NULL;
279 diff --quilt old/source/nedit.c new/source/nedit.c
280 --- old/source/nedit.c
281 +++ new/source/nedit.c
282 @@ -660,7 +660,7 @@ int main(int argc, char **argv)
283 numFiles = VMSFileScan(argv[i], &nameList, NULL, INCLUDE_FNF);
284 /* for each expanded file name do: */
285 for (j = 0; j < numFiles; ++j) {
286 - if (ParseFilename(nameList[j], filename, pathname) == 0) {
287 + if (ParseFilename(nameList[j], filename, pathname, NULL) == 0) {
288 /* determine if file is to be openned in new tab, by
289 factoring the options -group, -tabbed & -untabbed */
291 @@ -715,7 +715,7 @@ int main(int argc, char **argv)
292 if (nameList != NULL)
295 - if (ParseFilename(argv[i], filename, pathname) == 0 ) {
296 + if (ParseFilename(argv[i], filename, pathname, NULL) == 0 ) {
297 /* determine if file is to be openned in new tab, by
298 factoring the options -group, -tabbed & -untabbed */
300 diff --quilt old/source/selection.c new/source/selection.c
301 --- old/source/selection.c
302 +++ new/source/selection.c
303 @@ -328,7 +328,7 @@ static void fileCB(Widget widget, Window
304 guranteed to be available, but in practice is there and does work. */
305 #if defined(DONT_HAVE_GLOB) || defined(VMS)
307 - if (ParseFilename(nameText, filename, pathname) != 0) {
308 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
309 XBell(TheDisplay, 0);
312 @@ -338,7 +338,7 @@ static void fileCB(Widget widget, Window
313 { char **nameList = NULL;
314 int i, nFiles = 0, maxFiles = 30;
316 - if (ParseFilename(nameText, filename, pathname) != 0) {
317 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
318 XBell(TheDisplay, 0);
321 @@ -362,7 +362,8 @@ static void fileCB(Widget widget, Window
322 fileNameToOpen = nameList[i];
325 - if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
326 + if (ParseFilename(fileNameToOpen, filename, pathname,
327 + window->path) != 0) {
328 XBell(TheDisplay, 0);
330 EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
331 @@ -399,7 +400,8 @@ static void fileCB(Widget widget, Window
332 fileNameToOpen = globbuf.gl_pathv[i];
335 - if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
336 + if (ParseFilename(fileNameToOpen, filename, pathname,
337 + window->path) != 0) {
338 XBell(TheDisplay, 0);
340 EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
341 diff --quilt old/source/server.c new/source/server.c
342 --- old/source/server.c
343 +++ new/source/server.c
344 @@ -456,7 +456,7 @@ static void processServerCommandString(c
345 existing window, or opening if they don't exist */
346 editFlags = (readFlag ? PREF_READ_ONLY : 0) | CREATE |
347 (createFlag ? SUPPRESS_CREATE_WARN : 0);
348 - if (ParseFilename(fullname, filename, pathname) != 0) {
349 + if (ParseFilename(fullname, filename, pathname, NULL) != 0) {
350 fprintf(stderr, "NEdit: invalid file name\n");
351 deleteFileClosedProperty2(filename, pathname);
353 diff --quilt old/source/tags.c new/source/tags.c
354 --- old/source/tags.c
355 +++ new/source/tags.c
356 @@ -254,7 +254,7 @@ static int addTag(const char *name, cons
358 sprintf(newfile,"%s%s", path, file);
360 - NormalizePathname(newfile);
361 + NormalizePathname(newfile, NULL);
363 for (t = table[addr]; t; t = t->next) {
364 if (strcmp(name,t->name)) continue;
365 @@ -265,7 +265,7 @@ static int addTag(const char *name, cons
366 if (*t->file != '/') {
367 char tmpfile[MAXPATHLEN];
368 sprintf(tmpfile, "%s%s", t->path, t->file);
369 - NormalizePathname(tmpfile);
370 + NormalizePathname(tmpfile, NULL);
371 if (strcmp(newfile, tmpfile)) continue;
374 @@ -365,7 +365,7 @@ int AddRelTagsFile(const char *tagSpec,
376 strcat(pathName, "/");
377 strcat(pathName, filename);
378 - NormalizePathname(pathName);
379 + NormalizePathname(pathName, NULL);
381 for (t = FileList; t && strcmp(t->filename, pathName); t = t->next);
383 @@ -433,7 +433,7 @@ int AddTagsFile(const char *tagSpec, int
385 strcpy(pathName,filename);
387 - NormalizePathname(pathName);
388 + NormalizePathname(pathName, NULL);
390 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
392 @@ -504,7 +504,7 @@ int DeleteTagsFile(const char *tagSpec,
394 strcpy(pathName,filename);
396 - NormalizePathname(pathName);
397 + NormalizePathname(pathName, NULL);
399 for (last=NULL,t = FileList; t; last = t,t = t->next) {
400 if (strcmp(t->filename, pathName))
401 @@ -734,7 +734,7 @@ static int loadTagsFile(const char *tags
405 - ParseFilename(resolvedTagsFile, NULL, tagPath);
406 + ParseFilename(resolvedTagsFile, NULL, tagPath, NULL);
408 /* Read the file and store its contents */
409 while (fgets(line, MAXLINE, fp)) {
410 @@ -1147,7 +1147,7 @@ static int findAllMatches(WindowInfo *wi
411 sprintf(tagFiles[nMatches],"%s%s",tagPath,fileToSearch);
412 strcpy(tagSearch[nMatches],searchString);
413 tagPosInf[nMatches]=startPos;
414 - ParseFilename(tagFiles[nMatches], filename, pathname);
415 + ParseFilename(tagFiles[nMatches], filename, pathname, NULL);
416 /* Is this match in the current file? If so, use it! */
417 if (GetPrefSmartTags() && !strcmp(window->filename,filename)
418 && !strcmp(window->path,pathname) ) {
419 @@ -1204,7 +1204,7 @@ static int findAllMatches(WindowInfo *wi
422 for (i=0; i<nMatches; i++) {
423 - ParseFilename(tagFiles[i], filename, pathname);
424 + ParseFilename(tagFiles[i], filename, pathname, NULL);
425 if ((i<nMatches-1 && !strcmp(tagFiles[i],tagFiles[i+1])) ||
426 (i>0 && !strcmp(tagFiles[i],tagFiles[i-1]))) {
427 if(*(tagSearch[i]) && (tagPosInf[i] != -1)) { /* etags */
428 @@ -1326,7 +1326,7 @@ static void showMatchingCalltip( Widget
431 /* 1. Open the target file */
432 - NormalizePathname(tagFiles[i]);
433 + NormalizePathname(tagFiles[i], NULL);
434 fp = fopen(tagFiles[i], "r");
436 DialogF(DF_ERR, parent, 1, "Error opening File", "Error opening %s",
437 @@ -1445,7 +1445,7 @@ static void editTaggedLocation( Widget p
438 WindowInfo *windowToSearch;
439 WindowInfo *parentWindow = WidgetToWindow(parent);
441 - ParseFilename(tagFiles[i],filename,pathname);
442 + ParseFilename(tagFiles[i], filename, pathname, NULL);
443 /* open the file containing the definition */
444 EditExistingFile(parentWindow, filename, pathname, 0, NULL, False,
445 NULL, GetPrefOpenInTab(), False);
446 @@ -1992,7 +1992,7 @@ static int loadTipsFile(const char *tips
449 /* Get the path to the tips file */
450 - ParseFilename(resolvedTipsFile, NULL, tipPath);
451 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
454 if ((fp = fopen(resolvedTipsFile, "r")) == NULL)
455 diff --quilt old/util/fileUtils.c new/util/fileUtils.c
456 --- old/util/fileUtils.c
457 +++ new/util/fileUtils.c
458 @@ -88,8 +88,8 @@ static void copyThruSlash(char **toStrin
459 ** least MAXPATHLEN chars long.
460 ** To skip setting filename or pathname pass NULL for that argument.
463 -ParseFilename(const char *fullname, char *filename, char *pathname)
464 +int ParseFilename(const char *fullname, char *filename, char *pathname,
465 + const char *relpath)
467 int fullLen = strlen(fullname);
468 int i, pathLen, fileLen;
469 @@ -138,7 +138,7 @@ ParseFilename(const char *fullname, char
471 #ifndef VMS /* UNIX specific... Modify at a later date for VMS */
473 - if (NormalizePathname(pathname)) {
474 + if (NormalizePathname(pathname, relpath)) {
475 return 1; /* pathname too long */
477 pathLen = strlen(pathname);
478 @@ -271,7 +271,7 @@ ResolvePath(const char * pathIn, char *
480 strcpy(pathBuf, resolveBuf);
482 - NormalizePathname(pathBuf);
483 + NormalizePathname(pathBuf, NULL);
487 @@ -287,9 +287,10 @@ ResolvePath(const char * pathIn, char *
488 ** FIXME: Documentation
489 ** FIXME: Change return value to False and True.
491 -int NormalizePathname(char *pathname)
492 +int NormalizePathname(char *pathname, const char *relpath)
494 - /* if this is a relative pathname, prepend current directory */
495 + /* if this is a relative pathname, prepend relpath */
496 + /* if relpath is a relative path, prepend the current directory */
498 /* OS/2, ...: welcome to the world of drive letters ... */
499 if (!_fnisabs(pathname)) {
500 @@ -298,12 +299,13 @@ int NormalizePathname(char *pathname)
504 + int useRelpath = (relpath && *relpath);
506 /* make a copy of pathname to work from */
507 oldPathname=(char *)malloc(strlen(pathname)+1);
508 strcpy(oldPathname, pathname);
509 /* get the working directory and prepend to the path */
510 - strcpy(pathname, GetCurrentDir());
511 + strcpy(pathname, useRelpath ? relpath : GetCurrentDir());
513 /* check for trailing slash, or pathname being root dir "/":
514 don't add a second '/' character as this may break things
515 @@ -320,6 +322,14 @@ int NormalizePathname(char *pathname)
517 strcat(pathname, oldPathname);
521 + /* make sure our relative path wasn't relative to start with */
522 + if (CompressPathname(pathname) == 0)
523 + return NormalizePathname(pathname, NULL);
525 + return 1; /* some non-zero value */
529 /* compress out .. and . */
530 @@ -472,7 +482,7 @@ copyThruSlash(char **toString, char **fr
532 ** Return 0 if everything's fine, 1 else.
534 -int NormalizePathname(char *pathname)
535 +int NormalizePathname(char *pathname, const char *relpath)
539 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
540 --- old/util/fileUtils.h
541 +++ new/util/fileUtils.h
544 enum fileFormats {UNIX_FILE_FORMAT, DOS_FILE_FORMAT, MAC_FILE_FORMAT};
546 -int ParseFilename(const char *fullname, char *filename, char *pathname);
547 +int ParseFilename(const char *fullname, char *filename, char *pathname,
548 + const char *relpath);
549 int ExpandTilde(char *pathname);
550 const char* GetTrailingPathComponents(const char* path,
552 -int NormalizePathname(char *pathname);
553 +int NormalizePathname(char *pathname, const char *relpath);
554 int CompressPathname(char *pathname);
555 int ResolvePath(const char * pathIn, char * pathResolved);
557 diff --quilt old/util/getfiles.c new/util/getfiles.c
558 --- old/util/getfiles.c
559 +++ new/util/getfiles.c
560 @@ -1024,7 +1024,7 @@ static void listCharEH(Widget w, XtPoint
562 for (i=0; i<nItems; i++) {
563 XmStringGetLtoR(items[i], XmSTRING_DEFAULT_CHARSET, &itemString);
564 - if (ParseFilename(itemString, name, path) != 0) {
565 + if (ParseFilename(itemString, name, path, NULL) != 0) {
569 diff --quilt old/source/built-ins.h new/source/built-ins.h
570 --- old/source/built-ins.h
571 +++ new/source/built-ins.h
572 @@ -76,6 +76,7 @@ MS(set_window_title, setWindowTitle)
573 MS(timer_add, timerAdd)
574 MS(timer_remove, timerRemove)
575 MS(escape_literal, escapeLiteral)
576 +MS(full_file_name, fullFileName)