Skip to content

Commit dac3892

Browse files
authored
Merge pull request #46 from enzoevers/make-scripts-run-via-all-terminals
Normilize path separators
2 parents 7ada98b + 6d146da commit dac3892

File tree

4 files changed

+160
-63
lines changed

4 files changed

+160
-63
lines changed

CoDeLib/FileUtils/src/FileUtils.c

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,34 @@ int _HandleFtwCallback_Remove(const char *fpath, const struct stat *sb,
5454
// Public function implementations
5555
//=========================
5656

57+
bool IsPathNormalized(const char *const pPath) {
58+
if (pPath == NULL) {
59+
return false;
60+
}
61+
62+
for (size_t i = 0; i < strlen(pPath); ++i) {
63+
if (pPath[i] == '\\') {
64+
return false;
65+
}
66+
}
67+
68+
return true;
69+
}
70+
71+
char *NormailizePathSeparatorsInPlace(char *pPath) {
72+
if (pPath == NULL) {
73+
return NULL;
74+
}
75+
76+
for (size_t i = 0; i < strlen(pPath); ++i) {
77+
if (pPath[i] == '\\') {
78+
pPath[i] = '/';
79+
}
80+
}
81+
82+
return pPath;
83+
}
84+
5785
// Based on
5886
// https://nachtimwald.com/2019/07/10/recursive-create-directory-in-c-revisited/
5987
bool RecursiveMkdir(const char *const pDirname) {
@@ -114,9 +142,11 @@ bool RecursiveMkdir(const char *const pDirname) {
114142
// Adds null terminator after the seperator
115143
pPathToCreate[dirnamePartLength] = '\0';
116144

117-
success = _CreateDir(pPathToCreate);
118-
if (!success) {
119-
break;
145+
if (!PathExists(pPathToCreate)) {
146+
success = _CreateDir(pPathToCreate);
147+
if (!success) {
148+
break;
149+
}
120150
}
121151

122152
pTargetPath++;
@@ -171,7 +201,8 @@ bool IsAbsolutePath(const char *pPath) {
171201

172202
bool GetAbsolutePath(const char *pPath, char *const pAbsolutePath,
173203
const size_t absolutePathSize) {
174-
if (pPath == NULL || pAbsolutePath == NULL || absolutePathSize == 0) {
204+
if (pPath == NULL || pAbsolutePath == NULL || absolutePathSize == 0 ||
205+
!IsPathNormalized(pPath)) {
175206
return false;
176207
}
177208

@@ -201,6 +232,8 @@ bool GetAbsolutePath(const char *pPath, char *const pAbsolutePath,
201232
memcpy(&pAbsolutePath[0], pPath, sizeof(char) * (pathLenght + 1));
202233
}
203234

235+
NormailizePathSeparatorsInPlace(pAbsolutePath);
236+
204237
return true;
205238
}
206239

@@ -232,6 +265,8 @@ char *GetCurrentWorkingDirectory(char *pFullPath, size_t fullPathSize) {
232265
pFullPath[currentPathLength + 1] = '\0';
233266
}
234267

268+
NormailizePathSeparatorsInPlace(pFullPath);
269+
235270
return pFullPath;
236271
}
237272

CoDeLib/Test/src/TestFileUtils.c

Lines changed: 88 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,62 @@ TEST_TEAR_DOWN(TestFileUtils) {
3636
}
3737
}
3838

39+
//==============================
40+
// IsPathNormalized(...)
41+
//==============================
42+
43+
TEST(TestFileUtils, test_IsPathNormalized_ReturnsFalseIfPathIsNull) {
44+
TEST_ASSERT_FALSE(IsPathNormalized(NULL));
45+
}
46+
47+
TEST(TestFileUtils, test_IsPathNormalized_ReturnsTrueIfPathIsEmpty) {
48+
TEST_ASSERT_TRUE(IsPathNormalized(""));
49+
}
50+
51+
TEST(TestFileUtils, test_IsPathNormalized_ReturnsFalseIfPathIsNotNormalized) {
52+
TEST_ASSERT_FALSE(IsPathNormalized("a\\b/c\\d"));
53+
}
54+
55+
TEST(TestFileUtils, test_IsPathNormalized_ReturnsTrueIfPathIsNormalized) {
56+
TEST_ASSERT_TRUE(IsPathNormalized("a/b/c/d"));
57+
}
58+
59+
//==============================
60+
// NormailizePathSeparatorsInPlace(...)
61+
//==============================
62+
63+
TEST(TestFileUtils,
64+
test_NormailizePathSeparatorsInPlace_ReturnsFalseIfPathIsNull) {
65+
TEST_ASSERT_NULL(NormailizePathSeparatorsInPlace(NULL));
66+
}
67+
68+
TEST(TestFileUtils,
69+
test_NormailizePathSeparatorsInPlace_NormalizesPathSeparators) {
70+
RAII_STRING path = RaiiStringCreateFromCString("a\\b/c\\d");
71+
72+
char *pNormalizedPath = NormailizePathSeparatorsInPlace(path.pString);
73+
TEST_ASSERT_EQUAL(pNormalizedPath, path.pString);
74+
TEST_ASSERT_EQUAL_STRING("a/b/c/d", path.pString);
75+
}
76+
77+
TEST(TestFileUtils,
78+
test_NormailizePathSeparatorsInPlace_DoesNotChangeAlreadyNormalized) {
79+
RAII_STRING path = RaiiStringCreateFromCString("a/b/c/d");
80+
81+
char *pNormalizedPath = NormailizePathSeparatorsInPlace(path.pString);
82+
TEST_ASSERT_EQUAL(pNormalizedPath, path.pString);
83+
TEST_ASSERT_EQUAL_STRING("a/b/c/d", path.pString);
84+
}
85+
86+
TEST(TestFileUtils,
87+
test_NormailizePathSeparatorsInPlace_NormalizesWithWindowsStylePrefix) {
88+
RAII_STRING path = RaiiStringCreateFromCString("C:\\a\\b\\");
89+
90+
char *pNormalizedPath = NormailizePathSeparatorsInPlace(path.pString);
91+
TEST_ASSERT_EQUAL(pNormalizedPath, path.pString);
92+
TEST_ASSERT_EQUAL_STRING("C:/a/b/", path.pString);
93+
}
94+
3995
//==============================
4096
// IsAbsolutePath(...)
4197
//==============================
@@ -213,39 +269,21 @@ TEST(TestFileUtils,
213269
TEST_ASSERT_TRUE(success);
214270
}
215271

216-
TEST(
217-
TestFileUtils,
218-
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_TrailingSlash_WindowsStyle) {
219-
char localBuffer[MAX_PATH_LENGTH_WTH_TERMINATOR];
220-
char *pPath = "C:\\a\\b\\";
221-
222-
bool success =
223-
GetAbsolutePath(pPath, localBuffer, MAX_PATH_LENGTH_WTH_TERMINATOR);
224-
225-
TEST_ASSERT_TRUE(success);
226-
TEST_ASSERT_NOT_EQUAL(pPath, &localBuffer[0]);
227-
TEST_ASSERT_EQUAL_STRING(pPath, localBuffer);
228-
}
229-
230-
TEST(
231-
TestFileUtils,
232-
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_NoTrailingSlash_WindowsStyle) {
272+
TEST(TestFileUtils, test_GetAbsolutePath_ReturnsFalseIfIfIsNotNormalized) {
233273
char localBuffer[MAX_PATH_LENGTH_WTH_TERMINATOR];
234-
char *pPath = "C:\\a\\b";
274+
char *pPath = "C:\\a/b\\";
235275

236276
bool success =
237277
GetAbsolutePath(pPath, localBuffer, MAX_PATH_LENGTH_WTH_TERMINATOR);
238278

239-
TEST_ASSERT_TRUE(success);
240-
TEST_ASSERT_NOT_EQUAL(pPath, &localBuffer[0]);
241-
TEST_ASSERT_EQUAL_STRING(pPath, localBuffer);
279+
TEST_ASSERT_FALSE(success);
242280
}
243281

244282
TEST(
245283
TestFileUtils,
246-
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_FileExtention_WindowsStyle) {
284+
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_TrailingSlash_PosixStyleWindowsPrefix) {
247285
char localBuffer[MAX_PATH_LENGTH_WTH_TERMINATOR];
248-
char *pPath = "C:\\a\\b.txt";
286+
char *pPath = "C:/a/b/";
249287

250288
bool success =
251289
GetAbsolutePath(pPath, localBuffer, MAX_PATH_LENGTH_WTH_TERMINATOR);
@@ -297,28 +335,6 @@ TEST(
297335
TEST_ASSERT_EQUAL_STRING(pPath, localBuffer);
298336
}
299337

300-
TEST(
301-
TestFileUtils,
302-
test_GetAbsolutePath_ReturnsTrueIfPathIsRelativeAndCopiesItToBuffer_TrailingSlash_WindowsStyle) {
303-
char expectedAbsolutePathBuffer[MAX_PATH_LENGTH_WTH_TERMINATOR];
304-
GetCurrentWorkingDirectory(expectedAbsolutePathBuffer,
305-
MAX_PATH_LENGTH_WTH_TERMINATOR);
306-
RAII_STRING expectedAbsolutePath =
307-
RaiiStringCreateFromCString(expectedAbsolutePathBuffer);
308-
309-
char localBuffer[MAX_PATH_LENGTH_WTH_TERMINATOR];
310-
char *pPath = "b\\";
311-
312-
RaiiStringAppend_cString(&expectedAbsolutePath, pPath);
313-
314-
bool success =
315-
GetAbsolutePath(pPath, localBuffer, MAX_PATH_LENGTH_WTH_TERMINATOR);
316-
317-
TEST_ASSERT_TRUE(success);
318-
TEST_ASSERT_GREATER_THAN(strlen(pPath), strlen(&localBuffer[0]));
319-
TEST_ASSERT_EQUAL_STRING(expectedAbsolutePath.pString, localBuffer);
320-
}
321-
322338
TEST(
323339
TestFileUtils,
324340
test_GetAbsolutePath_ReturnsTrueIfPathIsRelativeAndCopiesItToBuffer_TrailingSlash_PosixStyle) {
@@ -1204,6 +1220,30 @@ TEST(TestFileUtils,
12041220
//==============================
12051221

12061222
TEST_GROUP_RUNNER(TestFileUtils) {
1223+
// IsPathNormalized(...)
1224+
RUN_TEST_CASE(TestFileUtils,
1225+
test_IsPathNormalized_ReturnsFalseIfPathIsNull);
1226+
RUN_TEST_CASE(TestFileUtils,
1227+
test_IsPathNormalized_ReturnsTrueIfPathIsEmpty);
1228+
RUN_TEST_CASE(TestFileUtils,
1229+
test_IsPathNormalized_ReturnsFalseIfPathIsNotNormalized);
1230+
RUN_TEST_CASE(TestFileUtils,
1231+
test_IsPathNormalized_ReturnsTrueIfPathIsNormalized);
1232+
1233+
// NormalizePathSeparator(...)
1234+
RUN_TEST_CASE(
1235+
TestFileUtils,
1236+
test_NormailizePathSeparatorsInPlace_ReturnsFalseIfPathIsNull);
1237+
RUN_TEST_CASE(
1238+
TestFileUtils,
1239+
test_NormailizePathSeparatorsInPlace_NormalizesPathSeparators);
1240+
RUN_TEST_CASE(
1241+
TestFileUtils,
1242+
test_NormailizePathSeparatorsInPlace_DoesNotChangeAlreadyNormalized);
1243+
RUN_TEST_CASE(
1244+
TestFileUtils,
1245+
test_NormailizePathSeparatorsInPlace_NormalizesWithWindowsStylePrefix);
1246+
12071247
// IsAbsolutePath(...)
12081248
RUN_TEST_CASE(TestFileUtils, test_IsAbsolutePath_ReturnsFalseIfPathIsNull);
12091249
RUN_TEST_CASE(TestFileUtils, test_IsAbsolutePath_ReturnsFalseIfPathIsEmpty);
@@ -1257,15 +1297,11 @@ TEST_GROUP_RUNNER(TestFileUtils) {
12571297
RUN_TEST_CASE(
12581298
TestFileUtils,
12591299
test_GetAbsolutePath_AllowsBuffersToBeBiggerThanMaxPathLength);
1300+
RUN_TEST_CASE(TestFileUtils,
1301+
test_GetAbsolutePath_ReturnsFalseIfIfIsNotNormalized);
12601302
RUN_TEST_CASE(
12611303
TestFileUtils,
1262-
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_TrailingSlash_WindowsStyle);
1263-
RUN_TEST_CASE(
1264-
TestFileUtils,
1265-
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_NoTrailingSlash_WindowsStyle);
1266-
RUN_TEST_CASE(
1267-
TestFileUtils,
1268-
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_FileExtention_WindowsStyle);
1304+
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_TrailingSlash_PosixStyleWindowsPrefix);
12691305
RUN_TEST_CASE(
12701306
TestFileUtils,
12711307
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_TrailingSlash_PosixStyle);
@@ -1275,9 +1311,6 @@ TEST_GROUP_RUNNER(TestFileUtils) {
12751311
RUN_TEST_CASE(
12761312
TestFileUtils,
12771313
test_GetAbsolutePath_ReturnsTrueIfPathIsAlreadyAbsoluteAndCopiesItToBuffer_FileExtentions_PosixStyle);
1278-
RUN_TEST_CASE(
1279-
TestFileUtils,
1280-
test_GetAbsolutePath_ReturnsTrueIfPathIsRelativeAndCopiesItToBuffer_TrailingSlash_WindowsStyle);
12811314
RUN_TEST_CASE(
12821315
TestFileUtils,
12831316
test_GetAbsolutePath_ReturnsTrueIfPathIsRelativeAndCopiesItToBuffer_TrailingSlash_PosixStyle);

CoDeLib/Test/src/main.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,29 @@ static void RunAllTests(void) {
2222
}
2323

2424
int main(int argc, const char **argv) {
25-
RAII_STRING fullPathToBenchmarkTestFiles;
25+
RAII_STRING fullPathToBenchmarkTestFiles = {NULL, 0};
2626

2727
// Should end with '/'
28-
RAII_STRING currentWorkingDirectory;
28+
RAII_STRING currentWorkingDirectory = {NULL, 0};
2929
bool runLongTests = false;
3030

3131
// TODO: use getopt(...)
3232
if (argc < 4) {
3333
printf("Not enough arguments provided\n");
3434
return 1;
3535
} else {
36-
fullPathToBenchmarkTestFiles = RaiiStringCreateFromCString(argv[1]);
37-
currentWorkingDirectory = RaiiStringCreateFromCString(argv[2]);
36+
RAII_STRING unNormalizedFullPathToBenchmarkTestFiles =
37+
RaiiStringCreateFromCString(argv[1]);
38+
fullPathToBenchmarkTestFiles =
39+
RaiiStringCreateFromCString(NormailizePathSeparatorsInPlace(
40+
unNormalizedFullPathToBenchmarkTestFiles.pString));
41+
42+
RAII_STRING unNormalizedCurrentWorkingDirectory =
43+
RaiiStringCreateFromCString(argv[2]);
44+
currentWorkingDirectory =
45+
RaiiStringCreateFromCString(NormailizePathSeparatorsInPlace(
46+
unNormalizedCurrentWorkingDirectory.pString));
47+
3848
runLongTests = strcmp(argv[3], "true") == 0;
3949
}
4050

CoDeLib/include/CoDeLib/FileUtils/FileUtils.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@
88
#define MAX_PATH_LENGTH 256
99
#define MAX_PATH_LENGTH_WTH_TERMINATOR (MAX_PATH_LENGTH + 1)
1010

11+
#define PATH_SEPARATOR '/'
12+
13+
/*!
14+
@brief Checks if a path is normalized. A normalized path has no escaped
15+
backward slashes ('\\') and uses forward slashes ('/') as path separators.
16+
@param pPath The path to check.
17+
@return true if the path is normalized, false otherwise.
18+
*/
19+
bool IsPathNormalized(const char *const pPath);
20+
21+
/*!
22+
@brief Normalizes the path separators in a path. This function replaces all
23+
escaped backward slashes ('\\') with forward slashes ('/').
24+
@param pPath The path to normalize. The path will be modified in place.
25+
@return pPath if the path was successfully normalized and placed in pDestPath,
26+
NULL otherwise
27+
*/
28+
char *NormailizePathSeparatorsInPlace(char *pPath);
29+
1130
/*!
1231
@brief Recursively creates a directory. If the directory already exists, nothing
1332
happens.

0 commit comments

Comments
 (0)