+#include <pwd.h>
+#include <unistd.h>
+
+
+/*
+** Find the location of a format or configuration
+** file, and return its absolute pathname.
+**
+** 1) If it begins with ~user, then expand it.
+** 2) Next, if already absolute pathname, then leave unchanged.
+** 3) Next, check in mmh directory.
+** 4) Next, check in mmh `etc' directory.
+** 5) As fall-back, return `file' unchanged.
+*/
+char *
+etcpath(char *file)
+{
+ static char epath[PATH_MAX];
+ char *cp;
+ char *pp;
+ struct passwd *pw;
+
+ /* XXX: here was: ``context_read();'' -- why? */
+ if (*file == '~') {
+ /* Expand `~user' */
+ if ((cp = strchr(pp = file + 1, '/')))
+ *cp++ = '\0';
+ if (*pp == '\0') {
+ pp = mypath;
+ } else {
+ if ((pw = getpwnam(pp)))
+ pp = pw->pw_dir;
+ else {
+ if (cp)
+ *--cp = '/';
+ goto try_it;
+ }
+ }
+
+ snprintf(epath, sizeof epath, "%s/%s", pp, cp ? cp : "");
+ if (cp)
+ *--cp = '/';
+
+ if (access(epath, R_OK) != NOTOK)
+ return epath; /* else fall */
+ }
+
+try_it:
+ if (*file == '/') {
+ /* absolute pathname, return it */
+ return file;
+ }
+
+ /* Check mmh directory */
+ snprintf(epath, sizeof epath, "%s/%s", mmhpath, file);
+ if (access(epath, R_OK) != NOTOK)
+ return epath;
+
+ /* Check nmh `etc' directory */
+ snprintf(epath, sizeof epath, "%s/%s", mhetcdir, file);
+ if (access(epath, R_OK) != NOTOK)
+ return epath;
+
+ /* The fall-back */
+ return file;
+}
+
+
+/*
+** Compactify a path name by removing unneccessary parts.
+** Removes trailing slashes. Cares to never remove all characters.
+** Modifies f (never enlarges it).
+**
+** FIXME: Cannot use strcpy() as the areas overlap!
+*/
+static void
+packpath(char *f)
+{
+ char *cp, *dp;
+ int abspath;
+
+ if (!f || !*f) {
+ return;
+ }
+ abspath = (*f == '/');
+
+ for (cp=f; *cp; ) {
+ if (*cp != '/') {
+ /* Skip. Interesting places are only after slashes. */
+ /* We don't care about "./" beginnings */
+ cp++;
+ continue;
+ }
+
+ /* Let's see what follows the slash ... */
+ switch (*++cp) {
+ case '\0':
+ *--cp = '\0';
+ continue; /* ... and thus exit the loop */
+
+ case '/':
+ /* reduce subsequent slashes to one */
+ for (dp = cp; *dp == '/'; dp++) {
+ continue;
+ }
+ strcpy(cp, dp);
+ cp--;
+ continue; /* ... at the slash */
+
+ case '.':
+ if (cp[1] == '/' || cp[1] == '\0') {
+ /* one-dot element */
+ strcpy(cp-1, cp+1);
+ cp--;
+ continue;
+ } else if ((strncmp(cp, "../", 3) == 0) ||
+ (strcmp(cp, "..") == 0)) {
+ /* dot-dot element */
+ /* crop out previous path element */
+ for (dp=cp-2; dp>f && *dp!='/'; dp--) {
+ continue;
+ }
+ if (dp < f) {
+ /* path starts with "/.." */
+ dp = f;
+ }
+ strcpy(dp, cp+2);
+ cp = dp;
+ continue;
+ } else {
+ /* a normal hidden file */
+ cp++;
+ continue;
+ }
+
+ default:
+ /* nothing special */
+ cp++;
+ continue;
+ }
+ }