-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfile.c
167 lines (142 loc) · 3.57 KB
/
file.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include "file.h"
#include "util.h"
#include <dirent.h> // opendir(3)
#include <stdlib.h> // malloc(3)
#include <string.h> // strdup(3)
#include <sys/stat.h> // stat(2)
#include <sys/types.h> // stat(2)
#include <unistd.h> // stat(2)
/**
* Creates a new File object from the path string.
*
* @param path string
* @return a pointer to a File object
* @return NULL if error occured
*/
File *new_File(const char *path) {
struct stat st;
if (stat(path, &st) == -1) {
return NULL;
}
File *file = malloc(sizeof(File));
// File.path
file->path = strdup(path);
// File.ty
switch (st.st_mode & S_IFMT) {
case S_IFDIR:
file->ty = F_DIR;
break;
case S_IFREG:
file->ty = F_FILE;
break;
default:
file->ty = F_OTHER;
}
// File.len
file->len = st.st_size;
return file;
}
/**
* Destroys the File object.
*
* @param file the pointer to the File object
*/
void delete_File(File *file) {
if (file == NULL)
return;
free(file->path);
free(file);
}
/**
* Returns the path to the parent directory.
*
* caller must free the allocated memory stores the parent path.
*
* @return the path to the parent directory
* @param path string
*/
char *parent_path(const char *path) {
char *ret = strdup(path);
for (char *p = ret + strlen(ret); p >= ret; p--) {
if (*p == '/') {
*p = '\0';
return ret;
}
}
*ret = '\0';
return ret;
}
/**
* Returns the filename component of the path
*
* caller must free allocated the memory stores filename.
*
* @return filename
* @param path
*/
char *filename(const char *path) {
char *p = strrchr(path, '/');
if (p == NULL)
return strdup(path);
return strdup(p + 1);
}
/**
* Returns the extension component of the path
*
* caller must free the allocated memory stores the extension
*
* @return extension
* @param path
*/
char *extension(const char *path) {
char *fname = filename(path);
char *p = strrchr(fname, '.');
if (p == NULL)
return NULL;
return strdup(p + 1);
}
static void test_new_File() {
File *file;
// normal case
file = new_File("LICENSE");
expect(__LINE__, 1064, file->len);
expect(__LINE__, F_FILE, file->ty);
expect_str(__LINE__, "LICENSE", file->path);
delete_File(file);
// file not found
file = new_File("LICENSE.");
expect_ptr(__LINE__, NULL, file);
delete_File(file);
}
static void test_parent_path() {
// clang-format off
// absolute path
expect_str(__LINE__, "/java/net", parent_path("/java/net/URL.java"));
expect_str(__LINE__, "/java", parent_path("/java/net"));
expect_str(__LINE__, "", parent_path("/java"));
// relative path
expect_str(__LINE__, "www", parent_path("www/index.html"));
expect_str(__LINE__, "", parent_path("www"));
expect_str(__LINE__, "", parent_path(""));
// clang-format on
}
static void test_filename() {
// clang-format off
expect_str(__LINE__, "URL.java", filename("/java/net/URL.java"));
expect_str(__LINE__, "URL.java", filename("URL.java"));
expect_str(__LINE__, "", filename(""));
// clang-format on
}
static void test_extension() {
// clang-format off
expect_str(__LINE__, "ext", extension("dir/foo.ext"));
expect_str(__LINE__, "", extension("dir/foo."));
expect_ptr(__LINE__, NULL, extension("dir.name/foo"));
// clang-format on
}
void run_all_test_file() {
test_new_File();
test_parent_path();
test_filename();
test_extension();
}