2 * This file is part of DisOrder
3 * Copyright (C) 2005, 2007 Richard Kettlewell
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 /** @file lib/filepart.c
21 * @brief Filename parsing
34 /** @brief Parse a filename
35 * @param path Filename to parse
36 * @param Where to put directory name, or NULL
37 * @param Where to put basename, or NULL
39 static void parse_filename(const char *path,
42 const char *s, *e = path + strlen(path);
44 /* Strip trailing slashes. We never take these into account. */
45 while(e > path && e[-1] == '/')
48 /* The path is empty or contains only slashes */
51 *dirnamep = xstrdup("/");
53 *basenamep = xstrdup("/");
56 *dirnamep = xstrdup("");
58 *basenamep = xstrdup("");
61 /* The path isn't empty and has more than just slashes. e therefore now
62 * points at the end of the basename. */
64 while(s > path && s[-1] != '/')
66 /* Now s points at the start of the basename */
68 *basenamep = xstrndup(s, e - s);
71 /* s must now be pointing at a '/' before the basename */
73 while(s > path && s[-1] == '/')
75 /* Now s must be pointing at the last '/' after the dirname */
78 /* If we reached the start we must be at the root */
80 *dirnamep = xstrdup("/");
82 /* There's more than just the root here */
84 *dirnamep = xstrndup(path, s - path);
87 /* There wasn't a slash */
89 *dirnamep = xstrdup(".");
94 /** @brief Return the directory part of @p path
95 * @param path Path to parse
96 * @return Directory part of @p path
98 * Extracts the directory part of @p path. This is a simple lexical
99 * transformation and no canonicalization is performed. The result will only
100 * ever end "/" if it is the root directory. The result will be "." if there
101 * is no directory part.
103 char *d_dirname(const char *path) {
106 parse_filename(path, &d, 0);
111 /** @brief Return the basename part of @p path
112 * @param Path to parse
113 * @return Base part of @p path
115 * Extracts the base part of @p path. This is a simple lexical transformation
116 * and no canonicalization is performed. The result is always newly allocated
117 * even if compares equal to @p path.
119 char *d_basename(const char *path) {
122 parse_filename(path, 0, &b);
127 /** @brief Find the extension part of @p path
128 * @param path Path to parse
129 * @return Start of extension in @p path, or NULL
131 * The return value points into @p path and points at the "." at the start of
132 * the path. If the basename has no extension the result is NULL. Extensions
133 * are assumed to only contain the ASCII digits and letters.
135 * See also extension().
137 static const char *find_extension(const char *path) {
138 const char *q = path + strlen(path);
140 while(q > path && strchr("abcdefghijklmnopqrstuvwxyz"
141 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
144 return *q == '.' ? q : 0;
147 /** @brief Strip the extension from @p path
148 * @param path Path to parse
149 * @return @p path with extension removed, or @p path
151 * The extension is defined exactly as for find_extension(). The result might
152 * or might not point into @p path.
154 const char *strip_extension(const char *path) {
155 const char *q = find_extension(path);
157 return q ? xstrndup(path, q - path) : path;
160 /** @brief Find the extension part of @p path
161 * @param path Path to parse
162 * @return Start of extension in @p path, or ""
164 * The return value may points into @p path and if so points at the "." at the
165 * start of the path. If the basename has no extension the result is "".
166 * Extensions are assumed to only contain the ASCII digits and letters.
168 * See also find_extension().
170 const char *extension(const char *path) {
171 const char *q = find_extension(path);