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 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 /* 34 * compath(pathname) 35 * 36 * This compresses pathnames. All strings of multiple slashes are 37 * changed to a single slash. All occurrences of "./" are removed. 38 * Whenever possible, strings of "/.." are removed together with 39 * the directory names that they follow. 40 * 41 * WARNING: since pathname is altered by this function, it should 42 * be located in a temporary buffer. This avoids the problem 43 * of accidently changing strings obtained from makefiles 44 * and stored in global structures. 45 */ 46 47 #include <string.h> 48 49 char * 50 compath(char *pathname) 51 { 52 char *nextchar; 53 char *lastchar; 54 char *sofar; 55 char *pnend; 56 57 int pnlen; 58 59 /* 60 * do not change the path if it has no "/" 61 */ 62 63 if (strchr(pathname, '/') == 0) 64 return (pathname); 65 66 /* 67 * find all strings consisting of more than one '/' 68 */ 69 70 for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) 71 if ((*lastchar == '/') && (*(lastchar - 1) == '/')) { 72 73 /* 74 * find the character after the last slash 75 */ 76 77 nextchar = lastchar; 78 while (*++lastchar == '/') { 79 } 80 81 /* 82 * eliminate the extra slashes by copying 83 * everything after the slashes over the slashes 84 */ 85 86 sofar = nextchar; 87 while ((*nextchar++ = *lastchar++) != '\0') 88 ; 89 lastchar = sofar; 90 } 91 92 /* 93 * find all strings of "./" 94 */ 95 96 for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) 97 if ((*lastchar == '/') && (*(lastchar - 1) == '.') && 98 ((lastchar - 1 == pathname) || (*(lastchar - 2) == '/'))) { 99 100 /* 101 * copy everything after the "./" over the "./" 102 */ 103 104 nextchar = lastchar - 1; 105 sofar = nextchar; 106 while ((*nextchar++ = *++lastchar) != '\0') 107 ; 108 lastchar = sofar; 109 } 110 111 /* 112 * find each occurrence of "/.." 113 */ 114 115 for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) 116 if ((lastchar != pathname) && (*lastchar == '/') && 117 (*(lastchar + 1) == '.') && (*(lastchar + 2) == '.') && 118 ((*(lastchar + 3) == '/') || (*(lastchar + 3) == '\0'))) { 119 120 /* 121 * find the directory name preceding the "/.." 122 */ 123 124 nextchar = lastchar - 1; 125 while ((nextchar != pathname) && 126 (*(nextchar - 1) != '/')) 127 --nextchar; 128 129 /* 130 * make sure the preceding directory's name 131 * is not "." or ".." 132 */ 133 134 if ((*nextchar == '.') && 135 (*(nextchar + 1) == '/') || 136 ((*(nextchar + 1) == '.') && 137 (*(nextchar + 2) == '/'))) { 138 /* EMPTY */; 139 } else { 140 141 /* 142 * prepare to eliminate either 143 * "dir_name/../" or "dir_name/.." 144 */ 145 146 if (*(lastchar + 3) == '/') 147 lastchar += 4; 148 else 149 lastchar += 3; 150 151 /* 152 * copy everything after the "/.." to 153 * before the preceding directory name 154 */ 155 156 sofar = nextchar - 1; 157 while ((*nextchar++ = *lastchar++) != '\0'); 158 159 lastchar = sofar; 160 161 /* 162 * if the character before what was taken 163 * out is '/', set up to check if the 164 * slash is part of "/.." 165 */ 166 167 if ((sofar + 1 != pathname) && (*sofar == '/')) 168 --lastchar; 169 } 170 } 171 172 /* 173 * if the string is more than a character long and ends 174 * in '/', eliminate the '/'. 175 */ 176 177 pnlen = strlen(pathname); 178 pnend = strchr(pathname, '\0') - 1; 179 180 if ((pnlen > 1) && (*pnend == '/')) { 181 *pnend-- = '\0'; 182 pnlen--; 183 } 184 185 /* 186 * if the string has more than two characters and ends in 187 * "/.", remove the "/.". 188 */ 189 190 if ((pnlen > 2) && (*(pnend - 1) == '/') && (*pnend == '.')) 191 *--pnend = '\0'; 192 193 /* 194 * if all characters were deleted, return "."; 195 * otherwise return pathname 196 */ 197 198 if (*pathname == '\0') 199 (void) strcpy(pathname, "."); 200 201 return (pathname); 202 } 203