Mercurial > hg > octave-nkf > gnulib-hg
annotate lib/filenamecat.c @ 8051:9c2b0396b27c
Stylistic change: Use '#if HAVE_*' instead of '#ifdef HAVE_*'.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Tue, 30 Jan 2007 01:07:22 +0000 |
parents | 8a1a9361108c |
children | ffc5b7a10350 |
rev | line source |
---|---|
5907 | 1 /* Concatenate two arbitrary file names. |
2 | |
6912 | 3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, |
4 2005, 2006 Free Software Foundation, Inc. | |
5907 | 5 |
6 This program is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program; if not, write to the Free Software Foundation, | |
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | |
19 | |
20 /* Written by Jim Meyering. */ | |
21 | |
7302
8a1a9361108c
* _fpending.c: Include <config.h> unconditionally, since we no
Paul Eggert <eggert@cs.ucla.edu>
parents:
6912
diff
changeset
|
22 #include <config.h> |
5907 | 23 |
24 /* Specification. */ | |
25 #include "filenamecat.h" | |
26 | |
27 #include <string.h> | |
28 | |
29 #include "dirname.h" | |
30 #include "xalloc.h" | |
31 | |
32 #if ! HAVE_MEMPCPY && ! defined mempcpy | |
33 # define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) | |
34 #endif | |
35 | |
36 /* Return the longest suffix of F that is a relative file name. | |
37 If it has no such suffix, return the empty string. */ | |
38 | |
39 static char const * | |
40 longest_relative_suffix (char const *f) | |
41 { | |
42 for (f += FILE_SYSTEM_PREFIX_LEN (f); ISSLASH (*f); f++) | |
43 continue; | |
44 return f; | |
45 } | |
46 | |
47 /* Concatenate two file name components, DIR and ABASE, in | |
48 newly-allocated storage and return the result. | |
49 The resulting file name F is such that the commands "ls F" and "(cd | |
50 DIR; ls BASE)" refer to the same file, where BASE is ABASE with any | |
51 file system prefixes and leading separators removed. | |
52 Arrange for a directory separator if necessary between DIR and BASE | |
53 in the result, removing any redundant separators. | |
54 In any case, if BASE_IN_RESULT is non-NULL, set | |
55 *BASE_IN_RESULT to point to the copy of ABASE in the returned | |
56 concatenation. However, if ABASE begins with more than one slash, | |
57 set *BASE_IN_RESULT to point to the sole corresponding slash that | |
58 is copied into the result buffer. | |
59 | |
60 Report an error if memory is exhausted. */ | |
61 | |
62 char * | |
63 file_name_concat (char const *dir, char const *abase, char **base_in_result) | |
64 { | |
6912 | 65 char const *dirbase = last_component (dir); |
5907 | 66 size_t dirbaselen = base_len (dirbase); |
67 size_t dirlen = dirbase - dir + dirbaselen; | |
68 size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1])); | |
69 | |
70 char const *base = longest_relative_suffix (abase); | |
71 size_t baselen = strlen (base); | |
72 | |
73 char *p_concat = xmalloc (dirlen + needs_separator + baselen + 1); | |
74 char *p; | |
75 | |
76 p = mempcpy (p_concat, dir, dirlen); | |
77 *p = DIRECTORY_SEPARATOR; | |
78 p += needs_separator; | |
79 | |
80 if (base_in_result) | |
81 *base_in_result = p - IS_ABSOLUTE_FILE_NAME (abase); | |
82 | |
83 p = mempcpy (p, base, baselen); | |
84 *p = '\0'; | |
85 | |
86 return p_concat; | |
87 } | |
88 | |
89 #ifdef TEST_FILE_NAME_CONCAT | |
90 # include <stdlib.h> | |
91 # include <stdio.h> | |
92 int | |
93 main () | |
94 { | |
95 static char const *const tests[][3] = | |
96 { | |
97 {"a", "b", "a/b"}, | |
98 {"a/", "b", "a/b"}, | |
99 {"a/", "/b", "a/b"}, | |
100 {"a", "/b", "a/b"}, | |
101 | |
102 {"/", "b", "/b"}, | |
103 {"/", "/b", "/b"}, | |
104 {"/", "/", "/"}, | |
105 {"a", "/", "a/"}, /* this might deserve a diagnostic */ | |
106 {"/a", "/", "/a/"}, /* this might deserve a diagnostic */ | |
107 {"a", "//b", "a/b"}, | |
108 }; | |
109 size_t i; | |
110 bool fail = false; | |
111 for (i = 0; i < sizeof tests / sizeof tests[0]; i++) | |
112 { | |
113 char *base_in_result; | |
114 char const *const *t = tests[i]; | |
115 char *res = file_name_concat (t[0], t[1], &base_in_result); | |
116 if (strcmp (res, t[2]) != 0) | |
117 { | |
118 printf ("got %s, expected %s\n", res, t[2]); | |
119 fail = true; | |
120 } | |
121 } | |
122 exit (fail ? EXIT_FAILURE : EXIT_SUCCESS); | |
123 } | |
124 #endif |