/*************************************************************************** * Module name : realpath.c * Module type : CMDFILE source file * Environment(s): n/a * * Description: realpath resolves all links and references to '.' and .' in "file_name" and stores it in "resolved_name". It can handle both relative and absolute path names. For absolute path names and relative path whose resolved name cannot be expressed relatively (for example, ../../reldir), it returns the resolved absolute name. For other relative names, it returns the resolved relative name. resolved name must be be big enough (MAXPATHLEN) to contain the fully resolved path name. Returns: The realpath function returns the address of the string containing the name of the resolved directory, unless an error occurs, in which case NULL is returned. * * Version Who Date Description APY 02/03/00 Created * * $Source: /cvsroot/device/DEVL/UTILS/CMDFILE/realpath.c,v $ * $Revision: 1.5 $ $Date: 2004/10/08 03:07:37 $ $State: Exp $ * $Author: ayoung $ $Locker: $ *.........................................................................*/ /* * Include Files * --------------- */ #include #include #if defined(WIN32) #include #endif #include "cmdfile.h" const char * Realpath( const char *name, char *buf ); #if defined(MSDOS) static void dos_realpath( const char *in, char *out, char sep ); #endif int do_realpath( String_t *str, const char *s ) { char name[ PATH_MAX ], buf[ PATH_MAX ]; int len; if (expected(s++, ',') > 0 && (len = pathargument(s, name, PATH_MAX)) > 0) { const char *p; p = Realpath( name, buf ); verbose( " realpath(%s) = %s", name, p ); StringPath( str, p ); return (1+len); } return (-1); } const char * Realpath(const char *name, char *buf) { #if defined(unix) const char *p; memset(buf, 0, PATH_MAX); /* PURIFY - solaris realpath illuse of 'buf'*/ if ((p = realpath(name, buf)) == name && name != NULL) if (buf == NULL) { /* NULL output buffer */ errno = EFAULT; p = NULL; } else { /* 'abs' match, copy to dest */ (void) strcpy(buf, name); p = buf; } return (p); #elif defined(WIN32) const char *p; /* restore full path */ if ((p = _fullpath(buf, name, PATH_MAX)) == NULL && name != NULL) if (buf == NULL) { /* NULL output buffer */ errno = EFAULT; p = NULL; } else { /* 'abs' match, copy to dest */ (void) strcpy(buf, name); p = buf; } return (p); #elif defined(MSDOS) char sep; sep = strchr(name, '/') ? '/' : '\\'; /* handle UNIX, default MSDOS */ (void) dos_realpath(name, buf, sep); return (buf); #else #error Unknown target OS ... #endif } #if defined(MSDOS) /* realpath --- * * Takes as input an arbitrary path. Fixes up the path by: * 1. Convert relative path to absolute * 2. Removing consecutive slashes * 3. Removing trailing slashes * 4. Making the path absolute if it wasn't already * 5. Removing "." in the path * 6. Removing ".." entries in the path (and the directory above them) */ static char *get_cwd(char *out, int drive, char sep); static void dos_realpath( const char *in, char *out, char sep ) { register const char *i = in; register char *o = out; /* Convert relative path to absolute */ { int drive; if (*(i+1) == ':' && ((*i >= 'a' && *i <= 'z') || (*i >= 'A' && *i <= 'Z'))) { if (*i >= 'a' && *i <= 'z') drive = *i - 'a'; else drive = *i - 'A'; *o++ = *i++; *o++ = *i++; } else { drive = GetDisk(); *o++ = drive + 'A'; *o++ = ':'; } if (!is_slash(*i)) o = get_cwd(o, drive, sep); } /* Step through the input path */ while (*i != '\0') { /* Skip input slashes */ if (is_slash(*i)) { i++; continue; } /* Skip "." and output nothing */ if (*i == '.' && is_term(*(i + 1))) { i++; continue; } /* Skip ".." and remove previous output directory */ if (*i == '.' && *(i + 1) == '.' && is_term(*(i + 2))) { /* Don't back up over drive spec or consume ../.. */ if (o > out+2 && strncmp(o-2, "..", 2) != 0) { /* Consume .. and parent directory */ i += 2; while (--o > out+2 && !is_slash(*o)) ; continue; } } /* Copy path component from in to p */ *o++ = sep; /* Copy next filename/directory */ while (!is_term(*i)) *o++ = *i++; } *o = '\0'; } static int get_disk(void) { #ifdef __WATCOMC__ unsigned drive; _dos_getdrive(&drive); return 0; #else union REGS regs; regs.h.ah = 0x19; /* DOS Get Default Drive call */ regs.h.al = 0; (void) intdos(®s, ®s); return regs.h.al; #endif } static char * get_cwd(char *out, int drive, char sep) { char cwd[ PATH_MAX ]; register char *p, *o; /* Get current work directory */ { union REGS regs; regs.h.ah = 0x47; regs.h.dl = drive + 1; #ifdef __386__ regs.x.esi = (unsigned long) cwd; #else regs.x.si = (unsigned long) cwd; #endif (void) intdos(®s, ®s); #ifdef __WATCOMC__ if (regs.w.cflag != 0) { errno = regs.w.ax; return out; } #else if (regs.x.cflag != 0) { errno = regs.x.ax; return out; } #endif } /* Copy and convert path */ for (p = cwd, o = out+1; *p; p++) *o++ = is_slash(*p) ? sep : *p; *o = '\0'; /* Root path, don't insert "/", it'll be added later */ if (*(out+1) != '\0') *out = sep; else *out = '\0'; return (out + strlen(out)); } #endif /*MSDOS*/