1 /* filename.c: Function manipulate file names
2    Was: find-suffix, extend-fname, make-suffix, remove-suffx
3    substring, concat3 */
4 
5 /* remove-suffx.c: remove any suffix.
6 
7 Copyright (C) 1999 Free Software Foundation, Inc.
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
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; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif /* Def: HAVE_CONFIG_H */
26 
27 #include "filename.h"
28 #include "xstd.h"
29 #include <string.h>
30 
31 /* Return a fresh copy of SOURCE[START..LIMIT], or NULL if LIMIT<START.
32    If LIMIT>strlen(START), it is reassigned. */
33 static at_string substring (at_string source, const unsigned start, const unsigned limit);
34 
35 /* Return a fresh copy of S1 followed by S2, et al.  */
36 static at_string concat3 (at_string, at_string, at_string);
37 
38 at_string
find_suffix(at_string name)39 find_suffix (at_string name)
40 {
41   at_string dot_pos = strrchr (name, '.');
42 #ifdef WIN32
43   at_string slash_pos = strrchr (name, '\\');
44 #else
45   at_string slash_pos = strrchr (name, '/');
46 #endif
47 
48   /* If the name is `foo' or `/foo.bar/baz', we have no extension.  */
49   return
50     dot_pos == NULL || dot_pos < slash_pos
51     ? NULL
52     : dot_pos + 1;
53 }
54 
55 at_string
extend_filename(at_string name,at_string default_suffix)56 extend_filename (at_string name, at_string default_suffix)
57 {
58   at_string new_s;
59   at_string suffix = find_suffix (name);
60 
61   new_s = suffix == NULL
62           ? concat3 (name, ".", default_suffix) : name;
63   return new_s;
64 }
65 
66 at_string
make_suffix(at_string s,at_string new_suffix)67 make_suffix (at_string s, at_string new_suffix)
68 {
69   at_string new_s;
70   at_string old_suffix = find_suffix (s);
71 
72   if (old_suffix == NULL)
73     new_s = concat3 (s, ".", new_suffix);
74   else
75     {
76       size_t length_through_dot = old_suffix - s;
77 
78       XMALLOC (new_s, length_through_dot + strlen (new_suffix) + 1);
79       strncpy (new_s, s, length_through_dot);
80       strcpy (new_s + length_through_dot, new_suffix);
81     }
82 
83   return new_s;
84 }
85 
86 at_string
remove_suffix(at_string s)87 remove_suffix (at_string s)
88 {
89   at_string suffix = find_suffix (s);
90 
91   return suffix == NULL ? s : suffix - 2 - s < 0 ? NULL : substring (s, 0, (unsigned)(suffix - 2 - s));
92 }
93 
94 /* From substring.c */
95 static at_string
substring(at_string source,const unsigned start,const unsigned limit)96 substring (at_string source, const unsigned start, const unsigned limit)
97 {
98   at_string result;
99   unsigned this_char;
100   size_t length = strlen (source);
101   size_t lim = limit;
102 
103   /* Upper bound out of range? */
104   if (lim >= length)
105     lim = length - 1;
106 
107   /* Null substring? */
108   if (start > lim)
109     return "";
110 
111   /* The `2' here is one for the null and one for limit - start inclusive. */
112   XMALLOC (result, lim - start + 2);
113 
114   for (this_char = start; this_char <= lim; this_char++)
115     result[this_char - start] = source[this_char];
116 
117   result[this_char - start] = 0;
118 
119   return result;
120 }
121 
122 static at_string
concat3(at_string s1,at_string s2,at_string s3)123 concat3 (at_string s1, at_string s2, at_string s3)
124 {
125   at_string answer;
126   XMALLOC (answer, strlen (s1) + strlen (s2) + strlen (s3) + 1);
127   strcpy (answer, s1);
128   strcat (answer, s2);
129   strcat (answer, s3);
130 
131   return answer;
132 }
133