Skip to content

Commit

Permalink
Added FilePath.
Browse files Browse the repository at this point in the history
  • Loading branch information
bkaradzic committed Jul 14, 2017
1 parent a517e19 commit 6e252cf
Show file tree
Hide file tree
Showing 8 changed files with 451 additions and 19 deletions.
64 changes: 64 additions & 0 deletions include/bx/filepath.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2017 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bx#license-bsd-2-clause
*/

#ifndef BX_FILEPATH_H_HEADER_GUARD
#define BX_FILEPATH_H_HEADER_GUARD

#include "string.h"

namespace bx
{
const int32_t kMaxFilePath = 1024;

/// FilePath parser and helper.
///
/// /abv/gd/555/333/pod.mac
/// ppppppppppppppppbbbeeee
/// ^ ^ ^
/// +-path base-+ +-ext
/// ^^^^^^^
/// +-filename
///
class FilePath
{
public:
///
FilePath();

///
FilePath(const StringView& _str);

///
void set(const StringView& _str);

///
const StringView get() const;

/// If path is `/abv/gd/555/333/pod.mac` returns `/abv/gd/555/333/`.
///
const StringView getPath() const;

/// If path is `/abv/gd/555/333/pod.mac` returns `pod.mac`.
///
const StringView getFileName() const;

/// If path is `/abv/gd/555/333/pod.mac` returns `pod`.
///
const StringView getBaseName() const;

/// If path is `/abv/gd/555/333/pod.mac` returns `.mac`.
///
const StringView getExt() const;

///
bool isAbsolute() const;

private:
char m_filePath[kMaxFilePath];
};

} // namespace bx

#endif // BX_FILEPATH_H_HEADER_GUARD
5 changes: 5 additions & 0 deletions include/bx/inline/readerwriter.inl
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,11 @@ namespace bx
return _writer->write(_data, _size, _err);
}

inline int32_t write(WriterI* _writer, const char* _str, Error* _err)
{
return write(_writer, _str, strLen(_str), _err);
}

inline int32_t writeRep(WriterI* _writer, uint8_t _byte, int32_t _size, Error* _err)
{
BX_ERROR_SCOPE(_err);
Expand Down
10 changes: 10 additions & 0 deletions include/bx/inline/string.inl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ namespace bx
set(_ptr, _len);
}

inline StringView::StringView(const char* _ptr, const char* _term)
{
set(_ptr, _term);
}

inline void StringView::set(const char* _ptr, int32_t _len)
{
clear();
Expand All @@ -90,6 +95,11 @@ namespace bx
}
}

inline void StringView::set(const char* _ptr, const char* _term)
{
set(_ptr, int32_t(_term-_ptr) );
}

inline void StringView::clear()
{
m_ptr = "";
Expand Down
3 changes: 3 additions & 0 deletions include/bx/readerwriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ namespace bx
/// Write data.
int32_t write(WriterI* _writer, const void* _data, int32_t _size, Error* _err = NULL);

/// Writer string.
inline int32_t write(WriterI* _writer, const char* _str, Error* _err = NULL);

/// Write repeat the same value.
int32_t writeRep(WriterI* _writer, uint8_t _byte, int32_t _size, Error* _err = NULL);

Expand Down
21 changes: 18 additions & 3 deletions include/bx/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,15 @@ namespace bx
///
StringView(const char* _ptr, int32_t _len = INT32_MAX);

///
StringView(const char* _ptr, const char* _term);

///
void set(const char* _ptr, int32_t _len = INT32_MAX);

///
void set(const char* _ptr, const char* _term);

///
void clear();

Expand Down Expand Up @@ -138,19 +144,31 @@ namespace bx
/// String compare.
int32_t strCmp(const char* _lhs, const char* _rhs, int32_t _max = INT32_MAX);

/// String compare.
int32_t strCmp(const char* _lhs, const StringView& _rhs);

/// Case insensitive string compare.
int32_t strCmpI(const char* _lhs, const char* _rhs, int32_t _max = INT32_MAX);

/// Case insensitive string compare.
int32_t strCmpI(const char* _lhs, const StringView& _rhs);

/// Get string length.
int32_t strLen(const char* _str, int32_t _max = INT32_MAX);

/// Copy _num characters from string _src to _dst buffer of maximum _dstSize capacity
/// including zero terminator. Copy will be terminated with '\0'.
int32_t strCopy(char* _dst, int32_t _dstSize, const char* _src, int32_t _num = INT32_MAX);

///
int32_t strCopy(char* _dst, int32_t _dstSize, const StringView& _str);

/// Concatinate string.
int32_t strCat(char* _dst, int32_t _dstSize, const char* _src, int32_t _num = INT32_MAX);

///
int32_t strCat(char* _dst, int32_t _dstSize, const StringView& _str);

/// Find character in string. Limit search to _max characters.
const char* strFind(const char* _str, char _ch, int32_t _max = INT32_MAX);

Expand Down Expand Up @@ -218,9 +236,6 @@ namespace bx
template <typename Ty>
Ty replaceAll(const Ty& _str, const char* _from, const char* _to);

/// Extract base file name from file path.
const char* baseName(const char* _filePath);

/// Convert size in bytes to human readable string kibi units.
int32_t prettify(char* _out, int32_t _count, uint64_t _size, Units::Enum _units = Units::Kibi);

Expand Down
212 changes: 212 additions & 0 deletions src/filepath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/*
* Copyright 2010-2017 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bx#license-bsd-2-clause
*/

#include <bx/filepath.h>
#include <bx/readerwriter.h>

namespace bx
{
static bool isPathSeparator(char _ch)
{
return false
|| '/' == _ch
|| '\\' == _ch
;
}

static int32_t normalizeFilePath(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
{
// Reference: Lexical File Names in Plan 9 or Getting Dot-Dot Right
// https://9p.io/sys/doc/lexnames.html

const int32_t num = strLen(_src, _num);

if (0 == num)
{
return strCopy(_dst, _dstSize, ".");
}

int32_t size = 0;

StaticMemoryBlockWriter writer(_dst, _dstSize);
Error err;

int32_t idx = 0;
int32_t dotdot = 0;

if (2 <= num
&& ':' == _src[1])
{
size += write(&writer, toUpper(_src[idx]), &err);
size += write(&writer, ':', &err);
idx += 2;
dotdot = size;
}

const int32_t slashIdx = idx;

bool rooted = isPathSeparator(_src[idx]);
if (rooted)
{
size += write(&writer, '/', &err);
++idx;
dotdot = size;
}

while (idx < num && err.isOk() )
{
switch (_src[idx])
{
case '/':
case '\\':
++idx;
break;

case '.':
if (idx+1 == num
|| isPathSeparator(_src[idx+1]) )
{
++idx;
break;
}

if ('.' == _src[idx+1]
&& (idx+2 == num || isPathSeparator(_src[idx+2]) ) )
{
idx += 2;

if (dotdot < size)
{
for (--size
; dotdot < size && !isPathSeparator(_dst[size])
; --size)
{
}
seek(&writer, size, Whence::Begin);
}
else if (!rooted)
{
if (0 < size)
{
size += write(&writer, '/', &err);
}

size += write(&writer, "..", &err);
dotdot = size;
}

break;
}

BX_FALLTHROUGH;

default:
if ( ( rooted && slashIdx+1 != size)
|| (!rooted && 0 != size) )
{
size += write(&writer, '/', &err);
}

for (; idx < num && !isPathSeparator(_src[idx]); ++idx)
{
size += write(&writer, _src[idx], &err);
}

break;
}
}

if (0 == size)
{
size += write(&writer, '.', &err);
}

write(&writer, '\0', &err);

return size;
}

FilePath::FilePath()
{
set("");
}

FilePath::FilePath(const StringView& _filePath)
{
set(_filePath);
}

void FilePath::set(const StringView& _filePath)
{
normalizeFilePath(
m_filePath
, BX_COUNTOF(m_filePath)
, _filePath.getPtr()
, _filePath.getLength()
);
}

const StringView FilePath::get() const
{
return StringView(m_filePath);
}

const StringView FilePath::getPath() const
{
const char* end = strRFind(m_filePath, '/');
if (NULL != end)
{
return StringView(m_filePath, end+1);
}

return StringView();
}

const StringView FilePath::getFileName() const
{
const char* fileName = strRFind(m_filePath, '/');
if (NULL != fileName)
{
return StringView(fileName+1);
}

return get();
}

const StringView FilePath::getBaseName() const
{
const StringView fileName = getFileName();
if (!fileName.isEmpty() )
{
const char* ext = strFind(fileName.getPtr(), '.', fileName.getLength() );
if (ext != NULL)
{
return StringView(fileName.getPtr(), ext);
}
}

return StringView();
}

const StringView FilePath::getExt() const
{
const StringView fileName = getFileName();
if (!fileName.isEmpty() )
{
const char* ext = strFind(fileName.getPtr(), '.', fileName.getLength() );
return StringView(ext);
}

return StringView();
}

bool FilePath::isAbsolute() const
{
return '/' == m_filePath[0] // no drive letter
|| (':' == m_filePath[1] && '/' == m_filePath[2]) // with drive letter
;
}

} // namespace bx
Loading

0 comments on commit 6e252cf

Please sign in to comment.