    Make read/write/append macro built-ins use paths relative to the window

    If the file name given to read_file(), write_file or append_file() is
    a relative path, the path associated with the invoking window is used
    as a base to determine the absolute path before accessing the file.

    Before, these built-ins would use the directory in which the NEdit
    program was invoked as the base. This presented many inconsistencies,
    not least with shell invocations.

diff -ur nedit_official nedit_mod
diff -ur nedit_official/source/macro.c nedit_mod/source/macro.c
--- nedit_official/source/macro.c	2006-05-31 18:39:23.000000000 +0200
+++ nedit_mod/source/macro.c	2006-08-24 01:47:22.237600000 +0200
@@ -2321,6 +2321,75 @@
 
 
 /*
+** Resolve the partial file path in name with respect to path.
+*/
+static char *convFilePathToAbsolute(const char *path, char *name)
+{
+    static char *nameText = NULL, *ptr;
+    static size_t nameTextLen = 0;
+    size_t namelen, pathlen, len;
+    Bool isRelative = False;
+    size_t needSlash = 0;
+
+    if (!path || !path[0] || strcmp(path, ".") == 0)
+        path = GetCurrentDir();
+
+#ifdef VMS
+    /* If path name is relative, make it refer to current window's directory;
+       absolute paths start with a logical name ([\w$]+) followed by a colon,
+       or with a non-relative path in brackets (not starting with . or -)
+     */
+    isRelative = ((strchr(name, ':') == NULL) && (strlen(name) > 1) &&
+                  !((name[0] == '[') && (name[1] != '-') &&
+                   (name[1] != '.')));
+#else
+    /* UNIX-like:
+       Any path starting without a "/" is considered relative; if the first
+       character is "~", we really need the user's home directory */
+    if (name[0] == '~' && name[1] == '/') {
+        path = GetHomeDir();
+        for (++name; *name == '/'; ++name)
+            continue;   /* skip slash(es) following initial tilde */
+        isRelative = True;
+    }
+    else
+        isRelative = (name[0] != '/');
+#endif
+
+    if (!isRelative)
+        return name;
+
+    namelen = strlen(name);
+    pathlen = strlen(path);
+
+#ifndef VMS
+    needSlash = (path && pathlen && path[pathlen - 1] != '/') ? 1 : 0;
+#endif
+
+    /* make sure the buffer's big enough */
+    len = namelen + pathlen + needSlash;
+
+    if (nameTextLen < len) {
+        ptr = realloc(nameText, len + 1);
+        if (!ptr)
+            return NULL;
+        nameText = ptr;
+        nameTextLen = len;
+    }
+
+    /* copy in pieces */
+    strcpy(nameText, path);
+    if (needSlash)
+        nameText[pathlen] = '/';
+    strcpy(nameText + pathlen + needSlash, name);
+
+    CompressPathname(nameText);
+
+    return nameText;
+}
+
+
+/*
 ** Built-in macro subroutine for reading the contents of a text file into
 ** a string.  On success, returns 1 in $readStatus, and the contents of the
 ** file as a string in the subroutine return value.  On failure, returns
@@ -2339,7 +2408,9 @@
     	return wrongNArgsErr(errMsg);
     if (!readStringArg(argList[0], &name, stringStorage, errMsg))
     	return False;
-    
+
+    name = convFilePathToAbsolute(window->path, name);
+
     /* Read the whole file into an allocated string */
     if ((fp = fopen(name, "r")) == NULL)
     	goto errorNoClose;
@@ -2419,6 +2490,8 @@
     if (!readStringArg(argList[1], &name, stringStorage[0], errMsg))
     	return False;
     
+    name = convFilePathToAbsolute(window->path, name);
+
     /* open the file */
     if ((fp = fopen(name, append ? "a" : "w")) == NULL) {
 	result->tag = INT_TAG;
