This is expand.c in view mode; [Download] [Up]
#include <stdio.h> /* convert a pathname to an absolute one, if it is absolute already, it is returned in the buffer unchanged, otherwise leading "./"s will be removed, and "../"s will be resolved. In a moment of weakness, I have implemented the cshell ~ filename convention. ~/foobar will have the ~ replaced by the home directory of the current user. ~user/foobar will have the ~user replaced by the home directory of the named user. This should really be in the kernel (or be replaced by a better kernel mechanism). Doing file name expansion like this in a user-level program leads to some very distasteful non-uniformities. Another fit of dementia has led me to implement the expansion of shell environment variables. $HOME/mbox is the same as ~/mbox. If the environment variable a = "foo" and b = "bar" then: $a => foo $a$b => foobar $a.c => foo.c xxx$a => xxxfoo ${a}! => foo! James Gosling @ CMU */ /* #include <sys/types.h> #include <sys/stat.h> */ #include <pwd.h> #include "ctype.h" expand_path (nm, buf) /* input name in nm, absolute pathname output to buf. returns 0 on success -1 on failure with error msg in buf */ char *nm, * buf; { register char *s, *d; char lnm[1000]; s = nm; d = lnm; while (*d++ = *s) if (*s++ == '$') { register char *start = d; register braces = *s == '{'; register char *value; while (*d++ = *s) if (braces ? *s == '}' : !(isalpha(*s) || isdigit(*s) || (*s == '_'))) break; else s++; *--d = 0; value = (char *) getenv (braces ? start + 1 : start); if (value) { for (d = start - 1; *d++ = *value++;); d--; if (braces && *s) s++; } } d = buf; nm = lnm; if (nm[0] == '~') /* prefix ~ */ if (nm[1] == '/' || nm[1] == 0)/* ~/filename */ if (s = (char *) getenv ("HOME")) { if (*++nm) nm++; } else s = ""; else { /* ~user/filename */ register char *nnm; register struct passwd *pw; for (s = nm; *s && *s != '/'; s++); nnm = *s ? s + 1 : s; *s = 0; pw = (struct passwd *) getpwnam (nm + 1); if (pw == 0) { sprintf (buf,"\"%s\" isn't a registered user.", nm+1); return -1; } else { nm = nnm; s = pw -> pw_dir; } } while (*d++ = *s++); if (buf[0] != '\0') *(d - 1) = '/'; else d--; s = nm; while (*d++ = *s++); *(d - 1) = '/'; *d = '\0'; d = buf; s = buf; while (*s) if ((*d++ = *s++) == '/' && d > buf + 1) { register char *t = d - 2; switch (*t) { case '/': /* found // in the name */ --d; break; case '.': switch (*--t) { case '/': /* found /./ in the name */ d -= 2; break; case '.': if (*--t == '/') {/* found /../ */ while (t > buf && *--t != '/'); d = t + 1; } break; } break; } } if (*(d - 1) == '/') d--; *d = '\0'; return 0; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.