ftp.nice.ch/pub/next/developer/languages/T/T.3.1.N.bs.tar.gz#/T3.1/tsystem/expand.c

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.