pathsub.c (3917B)
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 /* 6 ** Pathname subroutines. 7 ** 8 ** Brendan Eich, 8/29/95 9 */ 10 #include <assert.h> 11 #include <sys/types.h> 12 #include <dirent.h> 13 #include <errno.h> 14 #include <stdarg.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <unistd.h> 19 #include <sys/stat.h> 20 #include "pathsub.h" 21 22 #ifdef USE_REENTRANT_LIBC 23 # include <libc_r.h> 24 #endif 25 26 #ifdef SUNOS4 27 # include "sunos4.h" 28 #endif 29 30 char* program; 31 32 void fail(const char* format, ...) { 33 int error; 34 va_list ap; 35 36 #ifdef USE_REENTRANT_LIBC 37 R_STRERROR_INIT_R(); 38 #endif 39 40 error = errno; 41 fprintf(stderr, "%s: ", program); 42 va_start(ap, format); 43 vfprintf(stderr, format, ap); 44 va_end(ap); 45 if (error) { 46 #ifdef USE_REENTRANT_LIBC 47 R_STRERROR_R(errno); 48 fprintf(stderr, ": %s", r_strerror_r); 49 #else 50 fprintf(stderr, ": %s", strerror(errno)); 51 #endif 52 } 53 54 putc('\n', stderr); 55 exit(1); 56 } 57 58 char* getcomponent(char* path, char* name) { 59 if (*path == '\0') return 0; 60 if (*path == '/') { 61 *name++ = '/'; 62 } else { 63 do { 64 *name++ = *path++; 65 } while (*path != '/' && *path != '\0'); 66 } 67 *name = '\0'; 68 while (*path == '/') path++; 69 return path; 70 } 71 72 #ifdef LAME_READDIR 73 # include <sys/param.h> 74 /* 75 ** The static buffer in Unixware's readdir is too small. 76 */ 77 struct dirent* readdir(DIR* d) { 78 static struct dirent* buf = NULL; 79 80 if (buf == NULL) 81 buf = (struct dirent*)malloc(sizeof(struct dirent) + MAXPATHLEN); 82 return (readdir_r(d, buf)); 83 } 84 #endif 85 86 char* ino2name(ino_t ino) { 87 DIR* dp; 88 struct dirent* ep; 89 char* name; 90 91 dp = opendir(".."); 92 if (!dp) fail("cannot read parent directory"); 93 for (;;) { 94 if (!(ep = readdir(dp))) fail("cannot find current directory"); 95 if (ep->d_ino == ino) break; 96 } 97 name = xstrdup(ep->d_name); 98 closedir(dp); 99 return name; 100 } 101 102 void* xmalloc(size_t size) { 103 void* p = malloc(size); 104 if (!p) fail("cannot allocate %u bytes", size); 105 return p; 106 } 107 108 char* xstrdup(char* s) { return strcpy(xmalloc(strlen(s) + 1), s); } 109 110 char* xbasename(char* path) { 111 char* cp; 112 113 while ((cp = strrchr(path, '/')) && cp[1] == '\0') *cp = '\0'; 114 if (!cp) return path; 115 return cp + 1; 116 } 117 118 void xchdir(const char* dir) { 119 if (chdir(dir) < 0) fail("cannot change directory to %s", dir); 120 } 121 122 int relatepaths(char* from, char* to, char* outpath) { 123 char *cp, *cp2; 124 int len; 125 char buf[NAME_MAX]; 126 127 assert(*from == '/' && *to == '/'); 128 for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) 129 if (*cp == '\0') break; 130 while (cp[-1] != '/') cp--, cp2--; 131 if (cp - 1 == to) { 132 /* closest common ancestor is /, so use full pathname */ 133 len = strlen(strcpy(outpath, to)); 134 if (outpath[len] != '/') { 135 outpath[len++] = '/'; 136 outpath[len] = '\0'; 137 } 138 } else { 139 len = 0; 140 while ((cp2 = getcomponent(cp2, buf)) != 0) { 141 strcpy(outpath + len, "../"); 142 len += 3; 143 } 144 while ((cp = getcomponent(cp, buf)) != 0) { 145 sprintf(outpath + len, "%s/", buf); 146 len += strlen(outpath + len); 147 } 148 } 149 return len; 150 } 151 152 void reversepath(char* inpath, char* name, int len, char* outpath) { 153 char *cp, *cp2; 154 char buf[NAME_MAX]; 155 struct stat sb; 156 157 cp = strcpy(outpath + PATH_MAX - (len + 1), name); 158 cp2 = inpath; 159 while ((cp2 = getcomponent(cp2, buf)) != 0) { 160 if (strcmp(buf, ".") == 0) continue; 161 if (strcmp(buf, "..") == 0) { 162 if (stat(".", &sb) < 0) fail("cannot stat current directory"); 163 name = ino2name(sb.st_ino); 164 len = strlen(name); 165 cp -= len + 1; 166 strcpy(cp, name); 167 cp[len] = '/'; 168 free(name); 169 xchdir(".."); 170 } else { 171 cp -= 3; 172 strncpy(cp, "../", 3); 173 xchdir(buf); 174 } 175 } 176 strcpy(outpath, cp); 177 }