fix motifless build, keep original LIBS variable
[nedit-bw.git] / relativeFileNormalization.diff
blobd5eb85a72abe0663c65ca0774baa23439cab5526
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 | 10 ++--
25 source/macro.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++--
26 source/menu.c | 7 +--
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, 164 insertions(+), 43 deletions(-)
38 diff --quilt old/source/file.c new/source/file.c
39 --- old/source/file.c
40 +++ 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))
48 return False;
50 @@ -1101,7 +1101,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 @@ -1182,8 +1182,8 @@ static int doSave(WindowInfo *window)
61 /* call pre_save_hook, and set result as path/name */
62 fileString = PreSaveHook(window);
63 - if (fileString &&
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"
69 "('%s')\n"
70 @@ -1323,7 +1323,7 @@ static int doSave(WindowInfo *window)
72 #ifdef VMS
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);
76 #endif /*VMS*/
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
83 if (w == NULL) {
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()";
90 return False;
91 @@ -2116,6 +2116,108 @@ static int clipboardToStringMS(WindowInf
92 return True;
95 +/*
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.)
98 +*/
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();
110 +#ifdef VMS
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 -)
114 + */
115 + isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
116 + !((name[0] == '[') && (name[1] != '-') &&
117 + (name[1] != '.')));
118 +#else
119 + /* UNIX-like:
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 */
126 + isRelative = True;
128 + else
129 + isRelative = (name[0] != '/');
130 +#endif
132 + if (!isRelative)
133 + return name;
135 + namelen = strlen(name);
136 + pathlen = strlen(path);
138 +#ifndef VMS
139 + needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
140 +#endif
142 + /* make sure the buffer's big enough */
143 + len = namelen + pathlen + needSlash;
145 + if (nameTextLen < len) {
146 + ptr = realloc(nameText, len + 1);
147 + if (!ptr)
148 + return NULL;
149 + nameText = ptr;
150 + nameTextLen = len;
153 + /* copy in pieces */
154 + strcpy(nameText, path);
155 + if (needSlash)
156 + nameText[pathlen] = '/';
157 + strcpy(nameText + pathlen + needSlash, name);
159 + CompressPathname(nameText);
161 + return 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;
173 + size_t len;
175 + /* Validate arguments and convert to int */
176 + if (nArgs != 1)
177 + return wrongNArgsErr(errMsg);
178 + if (!readStringArg(argList[0], &name, stringStorage, errMsg))
179 + return False;
181 + name = convFilePathToAbsolute(window->path, name);
182 + len = strlen(name);
184 + if (name) {
185 + result->tag = STRING_TAG;
186 + AllocNString(&result->val.str, len + 1);
187 + strcpy(result->val.str.rep, name);
189 + else {
190 + result->tag = STRING_TAG;
191 + result->val.str.rep = PERM_ALLOC_STR("");
192 + result->val.str.len = 0;
195 + return True;
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))
203 return False;
206 + name = convFilePathToAbsolute(window->path, name);
208 /* Read the whole file into an allocated string */
209 if ((fp = fopen(name, "r")) == NULL)
210 goto errorNoClose;
211 @@ -2215,7 +2319,9 @@ static int writeOrAppendFile(int append,
212 return False;
213 if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
214 return False;
217 + name = convFilePathToAbsolute(window->path, name);
219 /* open the file */
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
226 return;
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",
233 args[0]);
234 return;
235 @@ -5006,7 +5007,7 @@ static void updatePrevOpenMenu(WindowInf
236 XtUnmanageChild(items[n]);
237 XtDestroyWidget(items[n]);
238 } else {
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
254 --- old/source/nc.c
255 +++ 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;
264 return;
265 @@ -750,7 +750,7 @@ static void parseCommandLine(int argc, c
266 if (nameList != NULL)
267 free(nameList);
268 #else
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;
273 return;
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 */
285 if (group == 2) {
286 @@ -729,7 +729,7 @@ int main(int argc, char **argv)
287 free(nameList);
288 #else
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 */
294 if (group == 2) {
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)
301 /* Open the file */
302 - if (ParseFilename(PreOpenHook(window, nameText), filename, pathname) != 0) {
303 + if (ParseFilename(PreOpenHook(window, nameText),
304 + filename, pathname, window->path)) {
305 XBell(TheDisplay, 0);
306 return;
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);
316 return;
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);
326 else {
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);
334 else
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);
347 break;
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
352 else
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;
368 return 0;
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);
377 if (t) {
378 @@ -433,7 +433,7 @@ int AddTagsFile(const char *tagSpec, int
379 } else {
380 strcpy(pathName,filename);
382 - NormalizePathname(pathName);
383 + NormalizePathname(pathName, NULL);
385 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
386 if (t) {
387 @@ -504,7 +504,7 @@ int DeleteTagsFile(const char *tagSpec,
388 } else {
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
397 return 0;
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
424 char *message;
426 /* 1. Open the target file */
427 - NormalizePathname(tagFiles[i]);
428 + NormalizePathname(tagFiles[i], NULL);
429 fp = fopen(tagFiles[i], "r");
430 if (fp == NULL) {
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
442 #endif
444 /* Get the path to the tips file */
445 - ParseFilename(resolvedTipsFile, NULL, tipPath);
446 + ParseFilename(resolvedTipsFile, NULL, tipPath, NULL);
448 /* Open the file */
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.
457 -int
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 */
467 if(pathname) {
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 *
474 } else {
475 strcpy(pathBuf, resolveBuf);
477 - NormalizePathname(pathBuf);
478 + NormalizePathname(pathBuf, NULL);
479 pathIn=pathBuf;
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 */
492 #ifdef __EMX__
493 /* OS/2, ...: welcome to the world of drive letters ... */
494 if (!_fnisabs(pathname)) {
495 @@ -298,12 +299,13 @@ int NormalizePathname(char *pathname)
496 #endif
497 char *oldPathname;
498 size_t len;
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);
513 free(oldPathname);
514 + if (useRelpath)
516 + /* make sure our relative path wasn't relative to start with */
517 + if (CompressPathname(pathname) == 0)
518 + return NormalizePathname(pathname, NULL);
519 + else
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)
532 return 0;
534 diff --quilt old/util/fileUtils.h new/util/fileUtils.h
535 --- old/util/fileUtils.h
536 +++ new/util/fileUtils.h
537 @@ -30,11 +30,12 @@
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,
546 int noOfComponents);
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
556 selectPos = 0;
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) {
561 XtFree(itemString);
562 return;
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)
573 MV(cursor, cursor)
574 MV(line, line)
575 diff --quilt old/util/utils.c new/util/utils.c
576 --- old/util/utils.c
577 +++ 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;