1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2011 - David Sommerseth <davids@redhat.com>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#elif defined(_MSC_VER)
28#include "config-msvc.h"
29#endif
30
31
32#ifndef HAVE_DIRNAME
33
34#include "compat.h"
35#include <string.h>
36
37/* Unoptimised version of glibc memrchr().
38 * This is considered fast enough, as only this compat
39 * version of dirname() depends on it.
40 */
41static const char *
42__memrchr(const char *str, int c, size_t n)
43{
44  const char *end = str;
45
46  end += n - 1; /* Go to the end of the string */
47  while (end >= str) {
48    if(c == *end)
49      return end;
50    else
51      end--;
52  }
53  return NULL;
54}
55
56/* Modified version based on glibc-2.14.1 by Ulrich Drepper <drepper@akkadia.org>
57 * This version is extended to handle both / and \ in path names.
58 */
59char *
60dirname (char *path)
61{
62  static const char dot[] = ".";
63  char *last_slash;
64  char separator = '/';
65
66  /* Find last '/'.  */
67  last_slash = path != NULL ? strrchr (path, '/') : NULL;
68  /* If NULL, check for \ instead ... might be Windows a path */
69  if (!last_slash) {
70    last_slash = path != NULL ? strrchr (path, '\\') : NULL;
71    separator = last_slash ? '\\' : '/';  /* Change the separator if \ was found */
72  }
73
74  if (last_slash != NULL && last_slash != path && last_slash[1] == '\0') {
75      /* Determine whether all remaining characters are slashes.  */
76      char *runp;
77
78      for (runp = last_slash; runp != path; --runp)
79	if (runp[-1] != separator)
80	  break;
81
82      /* The '/' is the last character, we have to look further.  */
83      if (runp != path)
84	last_slash = (char *) __memrchr (path, separator, runp - path);
85    }
86
87  if (last_slash != NULL) {
88      /* Determine whether all remaining characters are slashes.  */
89      char *runp;
90
91      for (runp = last_slash; runp != path; --runp)
92	if (runp[-1] != separator)
93	  break;
94
95      /* Terminate the path.  */
96      if (runp == path) {
97	  /* The last slash is the first character in the string.  We have to
98	     return "/".  As a special case we have to return "//" if there
99	     are exactly two slashes at the beginning of the string.  See
100	     XBD 4.10 Path Name Resolution for more information.  */
101	  if (last_slash == path + 1)
102	    ++last_slash;
103	  else
104	    last_slash = path + 1;
105	}
106      else
107	last_slash = runp;
108
109      last_slash[0] = '\0';
110  } else
111    /* This assignment is ill-designed but the XPG specs require to
112       return a string containing "." in any case no directory part is
113       found and so a static and constant string is required.  */
114    path = (char *) dot;
115
116  return path;
117}
118
119#endif /* HAVE_DIRNAME */
120