update
[nedit-bw.git] / relativeFileNormalization.diff
blobe3c988c9ff0c83c8beda46f30e8952a0b1d5baba
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 | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++--
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 12 files changed, 162 insertions(+), 42 deletions(-)
37 diff --quilt old/source/file.c new/source/file.c
38 --- old/source/file.c
39 +++ 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))
47 return False;
49 @@ -1100,7 +1100,7 @@ int SaveWindowAs(WindowInfo *window, con
50 if (addWrap)
51 addWrapNewlines(window);
53 - if (ParseFilename(fullname, filename, pathname) != 0) {
54 + if (ParseFilename(fullname, filename, pathname, window->path) != 0) {
55 return FALSE;
58 @@ -1186,7 +1186,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)) {
64 return FALSE;
67 @@ -1321,7 +1321,7 @@ static int doSave(WindowInfo *window)
69 #ifdef VMS
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);
73 #endif /*VMS*/
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
80 if (w == NULL) {
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()";
87 return False;
88 @@ -2116,6 +2116,108 @@ static int clipboardToStringMS(WindowInf
89 return True;
92 +/*
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.)
95 +*/
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();
107 +#ifdef VMS
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 -)
111 + */
112 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
113 + !((name[0] == '[') && (name[1] != '-') &&
114 + (name[1] != '.')));
115 +#else
116 + /* UNIX-like:
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 */
123 + isRelative = True;
125 + else
126 + isRelative = (name[0] != '/');
127 +#endif
129 + if (!isRelative)
130 + return name;
132 + namelen = strlen(name);
133 + pathlen = strlen(path);
135 +#ifndef VMS
136 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
137 +#endif
139 + /* make sure the buffer's big enough */
140 + len = namelen + pathlen + needSlash;
142 + if (nameTextLen < len) {
143 + ptr = realloc(nameText, len + 1);
144 + if (!ptr)
145 + return NULL;
146 + nameText = ptr;
147 + nameTextLen = len;
150 + /* copy in pieces */
151 + strcpy(nameText, path);
152 + if (needSlash)
153 + nameText[pathlen] = '/';
154 + strcpy(nameText + pathlen + needSlash, name);
156 + CompressPathname(nameText);
158 + return 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;
170 + size_t len;
172 + /* Validate arguments and convert to int */
173 + if (nArgs != 1)
174 + return wrongNArgsErr(errMsg);
175 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
176 + return False;
178 + name = convFilePathToAbsolute(window->path, name);
179 + len = strlen(name);
181 + if (name) {
182 + result->tag = STRING_TAG;
183 + AllocNString(&result->val.str, len + 1);
184 + strcpy(result->val.str.rep, name);
186 + else {
187 + result->tag = STRING_TAG;
188 + result->val.str.rep = PERM_ALLOC_STR("");
189 + result->val.str.len = 0;
192 + return True;
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))
200 return False;
203 + name = convFilePathToAbsolute(window->path, name);
205 /* Read the whole file into an allocated string */
206 if ((fp = fopen(name, "r")) == NULL)
207 goto errorNoClose;
208 @@ -2215,7 +2319,9 @@ static int writeOrAppendFile(int append,
209 return False;
210 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
211 return False;
214 + name = convFilePathToAbsolute(window->path, name);
216 /* open the file */
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",
239 fileNameToOpen);
240 @@ -5027,7 +5027,7 @@ static void updatePrevOpenMenu(WindowInf
241 XtUnmanageChild(items[n]);
242 XtDestroyWidget(items[n]);
243 } else {
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
259 --- old/source/nc.c
260 +++ 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;
269 return;
270 @@ -750,7 +750,7 @@ static void parseCommandLine(int argc, c
271 if (nameList != NULL)
272 free(nameList);
273 #else
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;
278 return;
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 */
290 if (group == 2) {
291 @@ -715,7 +715,7 @@ int main(int argc, char **argv)
292 if (nameList != NULL)
293 free(nameList);
294 #else
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 */
299 if (group == 2) {
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)
306 /* Open the file */
307 - if (ParseFilename(nameText, filename, pathname) != 0) {
308 + if (ParseFilename(nameText, filename, pathname, window->path) != 0) {
309 XBell(TheDisplay, 0);
310 return;
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);
319 return;
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);
329 } else {
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);
339 } else {
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);
352 break;
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
357 else
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;
373 return 0;
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);
382 if (t) {
383 @@ -433,7 +433,7 @@ int AddTagsFile(const char *tagSpec, int
384 } else {
385 strcpy(pathName,filename);
387 - NormalizePathname(pathName);
388 + NormalizePathname(pathName, NULL);
390 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
391 if (t) {
392 @@ -504,7 +504,7 @@ int DeleteTagsFile(const char *tagSpec,
393 } else {
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
402 return 0;
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
429 char *message;
431 /* 1. Open the target file */
432 - NormalizePathname(tagFiles[i]);
433 + NormalizePathname(tagFiles[i], NULL);
434 fp = fopen(tagFiles[i], "r");
435 if (fp == NULL) {
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
447 #endif
449 /* Get the path to the tips file */
450 - ParseFilename(resolvedTipsFile, NULL, tipPath);
451 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
453 /* Open the file */
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.
462 -int
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 */
472 if(pathname) {
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 *
479 } else {
480 strcpy(pathBuf, resolveBuf);
482 - NormalizePathname(pathBuf);
483 + NormalizePathname(pathBuf, NULL);
484 pathIn=pathBuf;
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 */
497 #ifdef __EMX__
498 /* OS/2, ...: welcome to the world of drive letters ... */
499 if (!_fnisabs(pathname)) {
500 @@ -298,12 +299,13 @@ int NormalizePathname(char *pathname)
501 #endif
502 char *oldPathname;
503 size_t len;
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);
518 free(oldPathname);
519 + if (useRelpath)
521 + /* make sure our relative path wasn't relative to start with */
522 + if (CompressPathname(pathname) == 0)
523 + return NormalizePathname(pathname, NULL);
524 + else
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)
537 return 0;
539 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
540 --- old/util/fileUtils.h
541 +++ new/util/fileUtils.h
542 @@ -30,11 +30,12 @@
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,
551 int noOfComponents);
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
561 selectPos = 0;
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) {
566 XtFree(itemString);
567 return;
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)
578 MV(cursor, cursor)
579 MV(line, line)