add newTabTab.patch
[nedit-bw.git] / relativeFileNormalization.diff
blob8d2ff99183b4753b4b46d6e9fe9a69cb1eb4eea0
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.
21 ---
23 source/built-ins.h | 1
24 source/file.c | 8 +--
25 source/macro.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++--
26 source/menu.c | 6 +-
27 source/nc.c | 4 -
28 source/nedit.c | 4 -
29 source/selection.c | 10 ++--
30 source/server.c | 2
31 source/tags.c | 22 +++++-----
32 util/fileUtils.c | 26 ++++++++----
33 util/fileUtils.h | 5 +-
34 util/getfiles.c | 2
35 util/utils.c | 2
36 13 files changed, 162 insertions(+), 42 deletions(-)
38 diff --quilt old/source/file.c new/source/file.c
39 --- old/source/file.c
40 +++ 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))
48 return False;
50 @@ -1100,7 +1100,7 @@ int SaveWindowAs(WindowInfo *window, con
51 if (addWrap)
52 addWrapNewlines(window);
54 - if (ParseFilename(fullname, filename, pathname) != 0) {
55 + if (ParseFilename(fullname, filename, pathname, window->path) != 0) {
56 return FALSE;
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)) {
65 return FALSE;
68 @@ -1321,7 +1321,7 @@ static int doSave(WindowInfo *window)
70 #ifdef VMS
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);
74 #endif /*VMS*/
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
81 if (w == NULL) {
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()";
88 return False;
89 @@ -2116,6 +2116,108 @@ static int clipboardToStringMS(WindowInf
90 return True;
93 +/*
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.)
96 +*/
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();
108 +#ifdef VMS
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 -)
112 + */
113 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
114 + !((name[0] == '[') && (name[1] != '-') &&
115 + (name[1] != '.')));
116 +#else
117 + /* UNIX-like:
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 */
124 + isRelative = True;
126 + else
127 + isRelative = (name[0] != '/');
128 +#endif
130 + if (!isRelative)
131 + return name;
133 + namelen = strlen(name);
134 + pathlen = strlen(path);
136 +#ifndef VMS
137 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
138 +#endif
140 + /* make sure the buffer's big enough */
141 + len = namelen + pathlen + needSlash;
143 + if (nameTextLen < len) {
144 + ptr = realloc(nameText, len + 1);
145 + if (!ptr)
146 + return NULL;
147 + nameText = ptr;
148 + nameTextLen = len;
151 + /* copy in pieces */
152 + strcpy(nameText, path);
153 + if (needSlash)
154 + nameText[pathlen] = '/';
155 + strcpy(nameText + pathlen + needSlash, name);
157 + CompressPathname(nameText);
159 + return 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;
171 + size_t len;
173 + /* Validate arguments and convert to int */
174 + if (nArgs != 1)
175 + return wrongNArgsErr(errMsg);
176 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
177 + return False;
179 + name = convFilePathToAbsolute(window->path, name);
180 + len = strlen(name);
182 + if (name) {
183 + result->tag = STRING_TAG;
184 + AllocNString(&result->val.str, len + 1);
185 + strcpy(result->val.str.rep, name);
187 + else {
188 + result->tag = STRING_TAG;
189 + result->val.str.rep = PERM_ALLOC_STR("");
190 + result->val.str.len = 0;
193 + return True;
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))
201 return False;
204 + name = convFilePathToAbsolute(window->path, name);
206 /* Read the whole file into an allocated string */
207 if ((fp = fopen(name, "r")) == NULL)
208 goto errorNoClose;
209 @@ -2215,7 +2319,9 @@ static int writeOrAppendFile(int append,
210 return False;
211 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
212 return False;
215 + name = convFilePathToAbsolute(window->path, name);
217 /* open the file */
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",
231 fileNameToOpen);
232 @@ -5027,7 +5027,7 @@ static void updatePrevOpenMenu(WindowInf
233 XtUnmanageChild(items[n]);
234 XtDestroyWidget(items[n]);
235 } else {
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
251 --- old/source/nc.c
252 +++ 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;
261 return;
262 @@ -750,7 +750,7 @@ static void parseCommandLine(int argc, c
263 if (nameList != NULL)
264 free(nameList);
265 #else
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;
270 return;
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 */
282 if (group == 2) {
283 @@ -726,7 +726,7 @@ int main(int argc, char **argv)
284 if (nameList != NULL)
285 free(nameList);
286 #else
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 */
291 if (group == 2) {
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)
298 /* Open the file */
299 - if (ParseFilename(nameText, filename, pathname) != 0) {
300 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
301 XBell(TheDisplay, 0);
302 return;
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);
311 return;
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);
321 } else {
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);
331 } else {
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);
344 break;
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
349 else
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;
365 return 0;
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);
374 if (t) {
375 @@ -433,7 +433,7 @@ int AddTagsFile(const char *tagSpec, int
376 } else {
377 strcpy(pathName,filename);
379 - NormalizePathname(pathName);
380 + NormalizePathname(pathName, NULL);
382 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
383 if (t) {
384 @@ -504,7 +504,7 @@ int DeleteTagsFile(const char *tagSpec,
385 } else {
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
394 return 0;
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
421 char *message;
423 /* 1. Open the target file */
424 - NormalizePathname(tagFiles[i]);
425 + NormalizePathname(tagFiles[i], NULL);
426 fp = fopen(tagFiles[i], "r");
427 if (fp == NULL) {
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
439 #endif
441 /* Get the path to the tips file */
442 - ParseFilename(resolvedTipsFile, NULL, tipPath);
443 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
445 /* Open the file */
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.
454 -int
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 */
464 if(pathname) {
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 *
471 } else {
472 strcpy(pathBuf, resolveBuf);
474 - NormalizePathname(pathBuf);
475 + NormalizePathname(pathBuf, NULL);
476 pathIn=pathBuf;
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 */
489 #ifdef __EMX__
490 /* OS/2, ...: welcome to the world of drive letters ... */
491 if (!_fnisabs(pathname)) {
492 @@ -298,12 +299,13 @@ int NormalizePathname(char *pathname)
493 #endif
494 char *oldPathname;
495 size_t len;
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);
510 free(oldPathname);
511 + if (useRelpath)
513 + /* make sure our relative path wasn't relative to start with */
514 + if (CompressPathname(pathname) == 0)
515 + return NormalizePathname(pathname, NULL);
516 + else
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)
529 return 0;
531 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
532 --- old/util/fileUtils.h
533 +++ new/util/fileUtils.h
534 @@ -30,11 +30,12 @@
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,
543 int noOfComponents);
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
553 selectPos = 0;
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) {
558 XtFree(itemString);
559 return;
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)
570 MV(cursor, cursor)
571 MV(line, line)
572 diff --quilt old/util/utils.c new/util/utils.c
573 --- old/util/utils.c
574 +++ 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;