Crossfire Server, Trunk  R20513
path.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include <assert.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <global.h>
23 
24 #include "define.h"
25 #include "path.h"
26 
27 #if 0
28 
31 #define DEBUG_PATH
32 #endif
33 
51 char *path_combine(const char *src, const char *dst, char *path, size_t size) {
52  char *p;
53 
54  if (*dst == '/') {
55  /* absolute destination path => ignore source path */
56  snprintf(path, size, "%s", dst);
57  } else {
58  /* relative destination path => add after last '/' of source */
59  snprintf(path, size, "%s", src);
60  p = strrchr(path, '/');
61  if (p != NULL) {
62  p++;
63  } else {
64  p = path;
65  if (*src == '/')
66  *p++ = '/';
67  }
68  snprintf(p, size-(p-path), "%s", dst);
69  }
70 
71 #if defined(DEBUG_PATH)
72  LOG(llevDebug, "path_combine(%s, %s) = %s\n", src, dst, path);
73 #endif
74  return(path);
75 }
76 
85 void path_normalize(char *path) {
86  char *p; /* points to the beginning of the path not yet processed; this is
87  either a path component or a path separator character */
88  char *q; /* points to the end of the path component p points to */
89  char *w; /* points to the end of the already normalized path; w <= p is
90  maintained */
91  size_t len; /* length of current component (which p points to) */
92 
93 #if defined(DEBUG_PATH)
94  LOG(llevDebug, "path_normalize: input '%s'\n", path);
95 #endif
96 
97  p = path;
98  w = p;
99  while (*p != '\0') {
100  if (*p == '/') {
101  if ((w == path && *path == '/') || (w > path && w[-1] != '/'))
102  *w++ = '/';
103  p++;
104  continue;
105  }
106 
107  q = strchr(p, '/');
108  if (q == NULL)
109  q = p+strlen(p);
110  len = q-p;
111  assert(len > 0);
112 
113 #if defined(DEBUG_PATH)
114  LOG(llevDebug, "path_normalize: checking '%.*s'\n", (int)len, p);
115 #endif
116 
117  if (len == 1 && *p == '.') {
118  /* remove current component */
119  } else if (len == 2 && memcmp(p, "..", 2) == 0) {
120  if (w == path || (w == path+3 && memcmp(path, "../", 3) == 0)) {
121  /* keep ".." at beginning of relative path ("../x" => "../x") */
122  memmove(w, p, len);
123  w += len;
124  } else if (w == path+1 && *path == '/') {
125  /* remove ".." at beginning of absolute path ("/../x" => "/x") */
126  } else {
127  /* remove both current component ".." and preceding one */
128  if (w > path && w[-1] == '/')
129  w--;
130  while (w > path && w[-1] != '/')
131  w--;
132  }
133  } else {
134  /* normal component ==> add it */
135  memmove(w, p, len);
136  w += len;
137  }
138 
139  p = q;
140 
141 #if defined(DEBUG_PATH)
142  LOG(llevDebug, "path_normalize: so far '%.*s'\n", (int)(w-path), path);
143 #endif
144  }
145 
146  /* remove trailing slashes, but keep the one at the start of the path */
147  while (w > path+1 && w[-1] == '/') {
148  w--;
149  }
150 
151  *w = '\0';
152 
153 #if defined(DEBUG_PATH)
154  LOG(llevDebug, "path_normalize: result '%s'\n", path);
155 #endif
156 }
157 
172 char *path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size) {
173  path_combine(src, dst, path, size);
174  path_normalize(path);
175  return(path);
176 }
Global type definitions and header inclusions.
#define snprintf
Definition: win32.h:46
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Combines the 2 paths.
Definition: path.c:172
void path_normalize(char *path)
Cleans specified path.
Definition: path.c:85
Path-related function prototypes.
Only for debugging purposes.
Definition: logger.h:13
char * path_combine(const char *src, const char *dst, char *path, size_t size)
Combines 2 paths, which can be relative.
Definition: path.c:51
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
Core defines: object types, flags, etc.