Crossfire Server, Branch 1.12
R12190
|
00001 /* $Id: path.c 11578 2009-02-23 22:02:27Z lalo $ */ 00002 00003 /* 00004 CrossFire, A Multiplayer game for X-windows 00005 00006 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00007 Copyright (C) 1992 Frank Tore Johansen 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program; if not, write to the Free Software 00021 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00022 00023 The authors can be reached via e-mail at crossfire-devel@real-time.com 00024 */ 00025 00031 #include <assert.h> 00032 #include <stdio.h> 00033 #include <string.h> 00034 #include <global.h> 00035 00036 #include "define.h" 00037 #include "path.h" 00038 00039 #if 0 00040 00043 #define DEBUG_PATH 00044 #endif 00045 00063 char *path_combine(const char *src, const char *dst, char *path, size_t size) { 00064 char *p; 00065 00066 if (*dst == '/') { 00067 /* absolute destination path => ignore source path */ 00068 snprintf(path, size, "%s", dst); 00069 } else { 00070 /* relative destination path => add after last '/' of source */ 00071 snprintf(path, size, "%s", src); 00072 p = strrchr(path, '/'); 00073 if (p != NULL) { 00074 p++; 00075 } else { 00076 p = path; 00077 if (*src == '/') 00078 *p++ = '/'; 00079 } 00080 snprintf(p, size-(p-path), "%s", dst); 00081 } 00082 00083 #if defined(DEBUG_PATH) 00084 LOG(llevDebug, "path_combine(%s, %s) = %s\n", src, dst, path); 00085 #endif 00086 return(path); 00087 } 00088 00097 void path_normalize(char *path) { 00098 char *p; /* points to the beginning of the path not yet processed; this is 00099 either a path component or a path separator character */ 00100 char *q; /* points to the end of the path component p points to */ 00101 char *w; /* points to the end of the already normalized path; w <= p is 00102 maintained */ 00103 size_t len; /* length of current component (which p points to) */ 00104 00105 #if defined(DEBUG_PATH) 00106 LOG(llevDebug, "path_normalize: input '%s'\n", path); 00107 #endif 00108 00109 p = path; 00110 w = p; 00111 while (*p != '\0') { 00112 if (*p == '/') { 00113 if ((w == path && *path == '/') || (w > path && w[-1] != '/')) 00114 *w++ = '/'; 00115 p++; 00116 continue; 00117 } 00118 00119 q = strchr(p, '/'); 00120 if (q == NULL) 00121 q = p+strlen(p); 00122 len = q-p; 00123 assert(len > 0); 00124 00125 #if defined(DEBUG_PATH) 00126 LOG(llevDebug, "path_normalize: checking '%.*s'\n", (int)len, p); 00127 #endif 00128 00129 if (len == 1 && *p == '.') { 00130 /* remove current component */ 00131 } else if (len == 2 && memcmp(p, "..", 2) == 0) { 00132 if (w == path || (w == path+3 && memcmp(path, "../", 3) == 0)) { 00133 /* keep ".." at beginning of relative path ("../x" => "../x") */ 00134 memmove(w, p, len); 00135 w += len; 00136 } else if (w == path+1 && *path == '/') { 00137 /* remove ".." at beginning of absolute path ("/../x" => "/x") */ 00138 } else { 00139 /* remove both current component ".." and preceding one */ 00140 if (w > path && w[-1] == '/') 00141 w--; 00142 while (w > path && w[-1] != '/') 00143 w--; 00144 } 00145 } else { 00146 /* normal component ==> add it */ 00147 memmove(w, p, len); 00148 w += len; 00149 } 00150 00151 p = q; 00152 00153 #if defined(DEBUG_PATH) 00154 LOG(llevDebug, "path_normalize: so far '%.*s'\n", (int)(w-path), path); 00155 #endif 00156 } 00157 00158 /* remove trailing slashes, but keep the one at the start of the path */ 00159 while (w > path+1 && w[-1] == '/') { 00160 w--; 00161 } 00162 00163 *w = '\0'; 00164 00165 #if defined(DEBUG_PATH) 00166 LOG(llevDebug, "path_normalize: result '%s'\n", path); 00167 #endif 00168 } 00169 00184 char *path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size) { 00185 path_combine(src, dst, path, size); 00186 path_normalize(path); 00187 return(path); 00188 }