1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "util.h"
5
6 #include "filename.h"
7
8 #ifdef _WIN32
9 #define PATHSEP '\\'
10 #else
11 #define PATHSEP '/'
12 #endif
13
14 struct Filename
15 {
16 char *full;
17 char *dir;
18 char *base;
19 char *ext;
20 };
21
Filename_create(void)22 SOLOCAL Filename *Filename_create(void)
23 {
24 Filename *self = xmalloc(sizeof *self);
25 memset(self, 0, sizeof *self);
26 return self;
27 }
28
Filename_clone(const Filename * self)29 SOLOCAL Filename *Filename_clone(const Filename *self)
30 {
31 Filename *clone = Filename_create();
32 if (self->full) clone->full = copystr(self->full);
33 if (self->dir) clone->dir = copystr(self->dir);
34 if (self->base) clone->base = copystr(self->base);
35 if (self->ext) clone->ext = copystr(self->ext);
36 return clone;
37 }
38
Filename_full(const Filename * self)39 SOLOCAL const char *Filename_full(const Filename *self)
40 {
41 return self->full;
42 }
43
Filename_dir(const Filename * self)44 SOLOCAL const char *Filename_dir(const Filename *self)
45 {
46 return self->dir;
47 }
48
Filename_base(const Filename * self)49 SOLOCAL const char *Filename_base(const Filename *self)
50 {
51 return self->base;
52 }
53
Filename_ext(const Filename * self)54 SOLOCAL const char *Filename_ext(const Filename *self)
55 {
56 return self->ext;
57 }
58
Filename_setFull(Filename * self,const char * full)59 SOLOCAL void Filename_setFull(Filename *self, const char *full)
60 {
61 free(self->full);
62 free(self->dir);
63 free(self->base);
64 free(self->ext);
65 memset(self, 0, sizeof *self);
66 if (!full) return;
67 self->full = copystr(full);
68 #ifdef _WIN32
69 for (char *c = self->full; *c; ++c)
70 {
71 if (*c == '/') *c = PATHSEP;
72 }
73 #endif
74 const char *pathsep = strrchr(self->full, PATHSEP);
75 const char *base;
76 if (pathsep)
77 {
78 size_t dirlen = pathsep - self->full;
79 self->dir = xmalloc(dirlen + 1);
80 strncpy(self->dir, self->full, dirlen);
81 self->dir[dirlen] = 0;
82 base = pathsep+1;
83 }
84 else
85 {
86 base = self->full;
87 }
88
89 const char *extsep = *base ? strrchr(base, '.') : 0;
90 if (extsep)
91 {
92 self->ext = copystr(extsep+1);
93 size_t baselen = extsep - base;
94 self->base = xmalloc(baselen + 1);
95 strncpy(self->base, base, baselen);
96 self->base[baselen] = 0;
97 }
98 else
99 {
100 self->base = *base ? copystr(base) : 0;
101 }
102 }
103
Filename_updateFull(Filename * self)104 static void Filename_updateFull(Filename *self)
105 {
106 free(self->full);
107 if (!self->base)
108 {
109 self->full = 0;
110 return;
111 }
112 size_t fulllen = strlen(self->base);
113 if (self->dir) fulllen += strlen(self->dir) + 1;
114 if (self->ext) fulllen += strlen(self->ext) + 1;
115 self->full = xmalloc(fulllen+1);
116 char *wrptr = self->full;
117 if (self->dir)
118 {
119 strcpy(wrptr, self->dir);
120 wrptr += strlen(self->dir);
121 *wrptr++ = PATHSEP;
122 }
123 strcpy(wrptr, self->base);
124 wrptr += strlen(self->base);
125 if (self->ext)
126 {
127 *wrptr++ = '.';
128 strcpy(wrptr, self->ext);
129 }
130 }
131
Filename_setDir(Filename * self,const char * dir)132 SOLOCAL void Filename_setDir(Filename *self, const char *dir)
133 {
134 free(self->dir);
135 self->dir = copystr(dir);
136 Filename_updateFull(self);
137 }
138
Filename_setBase(Filename * self,const char * base)139 SOLOCAL void Filename_setBase(Filename *self, const char *base)
140 {
141 free(self->base);
142 self->base = copystr(base);
143 Filename_updateFull(self);
144 }
145
Filename_setExt(Filename * self,const char * ext)146 SOLOCAL void Filename_setExt(Filename *self, const char *ext)
147 {
148 free(self->ext);
149 self->ext = copystr(ext);
150 Filename_updateFull(self);
151 }
152
Filename_destroy(Filename * self)153 SOLOCAL void Filename_destroy(Filename *self)
154 {
155 if (!self) return;
156 free(self->full);
157 free(self->dir);
158 free(self->base);
159 free(self->ext);
160 free(self);
161 }
162
163