1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1988 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1999 by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 /* 32 * compath(pathname) 33 * 34 * This compresses pathnames. All strings of multiple slashes are 35 * changed to a single slash. All occurrences of "./" are removed. 36 * Whenever possible, strings of "/.." are removed together with 37 * the directory names that they follow. 38 * 39 * WARNING: since pathname is altered by this function, it should 40 * be located in a temporary buffer. This avoids the problem 41 * of accidently changing strings obtained from makefiles 42 * and stored in global structures. 43 */ 44 45 #include <string.h> 46 47 char * 48 compath(char *pathname) 49 { 50 char *nextchar; 51 char *lastchar; 52 char *sofar; 53 char *pnend; 54 55 int pnlen; 56 57 /* 58 * do not change the path if it has no "/" 59 */ 60 61 if (strchr(pathname, '/') == 0) 62 return (pathname); 63 64 /* 65 * find all strings consisting of more than one '/' 66 */ 67 68 for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) 69 if ((*lastchar == '/') && (*(lastchar - 1) == '/')) { 70 71 /* 72 * find the character after the last slash 73 */ 74 75 nextchar = lastchar; 76 while (*++lastchar == '/') { 77 } 78 79 /* 80 * eliminate the extra slashes by copying 81 * everything after the slashes over the slashes 82 */ 83 84 sofar = nextchar; 85 while ((*nextchar++ = *lastchar++) != '\0') 86 ; 87 lastchar = sofar; 88 } 89 90 /* 91 * find all strings of "./" 92 */ 93 94 for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) 95 if ((*lastchar == '/') && (*(lastchar - 1) == '.') && 96 ((lastchar - 1 == pathname) || (*(lastchar - 2) == '/'))) { 97 98 /* 99 * copy everything after the "./" over the "./" 100 */ 101 102 nextchar = lastchar - 1; 103 sofar = nextchar; 104 while ((*nextchar++ = *++lastchar) != '\0') 105 ; 106 lastchar = sofar; 107 } 108 109 /* 110 * find each occurrence of "/.." 111 */ 112 113 for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) 114 if ((lastchar != pathname) && (*lastchar == '/') && 115 (*(lastchar + 1) == '.') && (*(lastchar + 2) == '.') && 116 ((*(lastchar + 3) == '/') || (*(lastchar + 3) == '\0'))) { 117 118 /* 119 * find the directory name preceding the "/.." 120 */ 121 122 nextchar = lastchar - 1; 123 while ((nextchar != pathname) && 124 (*(nextchar - 1) != '/')) 125 --nextchar; 126 127 /* 128 * make sure the preceding directory's name 129 * is not "." or ".." 130 */ 131 132 if ((*nextchar == '.') && 133 (*(nextchar + 1) == '/') || 134 ((*(nextchar + 1) == '.') && 135 (*(nextchar + 2) == '/'))) { 136 /* EMPTY */; 137 } else { 138 139 /* 140 * prepare to eliminate either 141 * "dir_name/../" or "dir_name/.." 142 */ 143 144 if (*(lastchar + 3) == '/') 145 lastchar += 4; 146 else 147 lastchar += 3; 148 149 /* 150 * copy everything after the "/.." to 151 * before the preceding directory name 152 */ 153 154 sofar = nextchar - 1; 155 while ((*nextchar++ = *lastchar++) != '\0'); 156 157 lastchar = sofar; 158 159 /* 160 * if the character before what was taken 161 * out is '/', set up to check if the 162 * slash is part of "/.." 163 */ 164 165 if ((sofar + 1 != pathname) && (*sofar == '/')) 166 --lastchar; 167 } 168 } 169 170 /* 171 * if the string is more than a character long and ends 172 * in '/', eliminate the '/'. 173 */ 174 175 pnlen = strlen(pathname); 176 pnend = strchr(pathname, '\0') - 1; 177 178 if ((pnlen > 1) && (*pnend == '/')) { 179 *pnend-- = '\0'; 180 pnlen--; 181 } 182 183 /* 184 * if the string has more than two characters and ends in 185 * "/.", remove the "/.". 186 */ 187 188 if ((pnlen > 2) && (*(pnend - 1) == '/') && (*pnend == '.')) 189 *--pnend = '\0'; 190 191 /* 192 * if all characters were deleted, return "."; 193 * otherwise return pathname 194 */ 195 196 if (*pathname == '\0') 197 (void) strcpy(pathname, "."); 198 199 return (pathname); 200 } 201