mirror of
https://github.com/bkaradzic/bx.git
synced 2026-10-05 16:35:33 +00:00
Added scanner. (#410)
This commit is contained in:
committed by
GitHub
parent
cd6720ce9a
commit
9916e720fc
@@ -18,6 +18,7 @@
|
||||
#include "mutex.cpp"
|
||||
#include "os.cpp"
|
||||
#include "process.cpp"
|
||||
#include "scanner.cpp"
|
||||
#include "semaphore.cpp"
|
||||
#include "settings.cpp"
|
||||
#include "sort.cpp"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <bx/readerwriter.h> // WriterI
|
||||
#include <bx/os.h> // exit
|
||||
#include <bx/process.h> // ProcessReader
|
||||
#include <bx/scanner.h> // Scanner
|
||||
|
||||
#include <inttypes.h> // PRIx*
|
||||
|
||||
@@ -947,22 +948,6 @@ namespace bx
|
||||
|
||||
#elif BX_CONFIG_CALLSTACK_USE_EXECINFO
|
||||
|
||||
StringView strConsumeTo(StringView& _input, const StringView& _find)
|
||||
{
|
||||
const StringView to = strFind(_input, _find);
|
||||
|
||||
if (!to.isEmpty() )
|
||||
{
|
||||
const StringView result(_input.getPtr(), to.getPtr() );
|
||||
|
||||
_input.set(to.getTerm(), _input.getTerm() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return StringView();
|
||||
}
|
||||
|
||||
int32_t writeCallstack(WriterI* _writer, const uintptr_t* _stack, uint32_t _num, Error* _err)
|
||||
{
|
||||
int32_t total = write(_writer, _err, "Callstack (%d):\n", _num);
|
||||
@@ -1126,16 +1111,18 @@ namespace bx
|
||||
{
|
||||
for (LineReader lr({atosBuffer, bytes}); !lr.isDone();)
|
||||
{
|
||||
StringView input = lr.next();
|
||||
Scanner scanner(lr.next() );
|
||||
|
||||
atosFunctionName = strConsumeTo(input, " (");
|
||||
atosFunctionName = scanner.acceptUntil(" (");
|
||||
|
||||
if (atosFunctionName.isEmpty() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
filePath = strConsumeTo(input, ":");
|
||||
scanner.accept(" (");
|
||||
|
||||
filePath = scanner.acceptUntil(":");
|
||||
|
||||
if (filePath.isEmpty() )
|
||||
{
|
||||
@@ -1143,7 +1130,9 @@ namespace bx
|
||||
break;
|
||||
}
|
||||
|
||||
const StringView lineStr = strConsumeTo(input, ")");
|
||||
scanner.accept(':');
|
||||
|
||||
const StringView lineStr = scanner.acceptUntil(")");
|
||||
|
||||
if (!lineStr.isEmpty() )
|
||||
{
|
||||
|
||||
135
src/filepath.cpp
135
src/filepath.cpp
@@ -6,6 +6,7 @@
|
||||
#include <bx/file.h>
|
||||
#include <bx/os.h>
|
||||
#include <bx/readerwriter.h>
|
||||
#include <bx/scanner.h>
|
||||
|
||||
#if BX_CRT_MSVC
|
||||
# include <direct.h> // _getcwd
|
||||
@@ -24,12 +25,9 @@ extern "C" int _NSGetExecutablePath(char* _buf, uint32_t* _bufSize);
|
||||
|
||||
namespace bx
|
||||
{
|
||||
static bool isPathSeparator(char _ch)
|
||||
static bool isNotPathSeparator(char _ch)
|
||||
{
|
||||
return false
|
||||
|| '/' == _ch
|
||||
|| '\\' == _ch
|
||||
;
|
||||
return !isPathSeparator(_ch);
|
||||
}
|
||||
|
||||
static int32_t normalizeFilePath(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
|
||||
@@ -38,9 +36,9 @@ namespace bx
|
||||
// - Lexical File Names in Plan 9 or Getting Dot-Dot Right
|
||||
// https://web.archive.org/web/20180629044444/https://9p.io/sys/doc/lexnames.html
|
||||
|
||||
const int32_t num = strLen(_src, _num);
|
||||
const StringView src(_src, strLen(_src, _num) );
|
||||
|
||||
if (0 == num)
|
||||
if (src.isEmpty() )
|
||||
{
|
||||
return strCopy(_dst, _dstSize, ".");
|
||||
}
|
||||
@@ -50,91 +48,80 @@ namespace bx
|
||||
StaticMemoryBlockWriter writer(_dst, _dstSize);
|
||||
Error err;
|
||||
|
||||
int32_t idx = 0;
|
||||
int32_t dotdot = 0;
|
||||
Scanner scanner(src);
|
||||
|
||||
if (2 <= num
|
||||
&& ':' == _src[1])
|
||||
// Everything below `dotdot` is a prefix `..` can't back out of.
|
||||
int32_t dotdot = 0;
|
||||
|
||||
if (2 <= src.getLength()
|
||||
&& ':' == src.getPtr()[1])
|
||||
{
|
||||
size += write(&writer, toUpper(_src[idx]), &err);
|
||||
size += write(&writer, toUpper(src.getPtr()[0]), &err);
|
||||
size += write(&writer, ':', &err);
|
||||
idx += 2;
|
||||
scanner.seek(2);
|
||||
dotdot = size;
|
||||
}
|
||||
|
||||
const int32_t slashIdx = idx;
|
||||
const bool rooted = !scanner.accept(isPathSeparator).isEmpty();
|
||||
|
||||
bool rooted = isPathSeparator(_src[idx]);
|
||||
if (rooted)
|
||||
{
|
||||
size += write(&writer, '/', &err);
|
||||
++idx;
|
||||
dotdot = size;
|
||||
}
|
||||
|
||||
const int32_t rootSize = size;
|
||||
|
||||
bool trailingSlash = false;
|
||||
|
||||
while (idx < num && err.isOk() )
|
||||
while (!scanner.isDone()
|
||||
&& err.isOk() )
|
||||
{
|
||||
switch (_src[idx])
|
||||
if (!scanner.acceptWhile(isPathSeparator).isEmpty() )
|
||||
{
|
||||
case '/':
|
||||
case '\\':
|
||||
++idx;
|
||||
trailingSlash = idx == num;
|
||||
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;
|
||||
}
|
||||
[[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;
|
||||
trailingSlash = scanner.isDone();
|
||||
continue;
|
||||
}
|
||||
|
||||
const StringView component = scanner.acceptWhile(isNotPathSeparator);
|
||||
|
||||
if (component == ".")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (component == "..")
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rooted ? rootSize != size : 0 != size)
|
||||
{
|
||||
size += write(&writer, '/', &err);
|
||||
}
|
||||
|
||||
size += write(&writer, component, &err);
|
||||
}
|
||||
|
||||
if (0 == size)
|
||||
|
||||
167
src/scanner.cpp
Normal file
167
src/scanner.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2010-2026 Branimir Karadzic. All rights reserved.
|
||||
* License: https://github.com/bkaradzic/bx/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
#include <bx/scanner.h>
|
||||
|
||||
namespace bx
|
||||
{
|
||||
bool Scanner::seek(const StringView& _to)
|
||||
{
|
||||
if (contain(m_input, _to) )
|
||||
{
|
||||
moveTo(_to);
|
||||
return true;
|
||||
}
|
||||
|
||||
BX_TRACE("StringView '%S' is not a view into input string!", &_to);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t Scanner::getColumn() const
|
||||
{
|
||||
return uint32_t(between(getCursor(Cursor::LineStart) ).getLength() ) + 1;
|
||||
}
|
||||
|
||||
StringView Scanner::getCursor(Cursor _which) const
|
||||
{
|
||||
const char* ptr = m_tail.getPtr();
|
||||
|
||||
if (Cursor::LineStart == _which)
|
||||
{
|
||||
while (ptr > m_input.getPtr()
|
||||
&& '\n' != ptr[-1])
|
||||
{
|
||||
--ptr;
|
||||
}
|
||||
}
|
||||
else if (Cursor::LineEnd == _which)
|
||||
{
|
||||
const char* term = m_input.getTerm();
|
||||
while (ptr < term
|
||||
&& '\n' != *ptr)
|
||||
{
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return StringView(ptr, ptr);
|
||||
}
|
||||
|
||||
StringView Scanner::moveTo(const StringView& _to)
|
||||
{
|
||||
if (BX_LIKELY(!_to.isEmpty() ) )
|
||||
{
|
||||
if (BX_LIKELY(overlap(m_tail, _to) ) )
|
||||
{
|
||||
const StringView result(m_tail.getPtr(), _to.getTerm() );
|
||||
|
||||
m_tail.set(_to.getTerm(), m_tail.getTerm() );
|
||||
m_line += countLines(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const StringView result(_to.getPtr(), m_tail.getPtr() );
|
||||
|
||||
m_tail.set(_to.getPtr(), m_tail.getTerm() );
|
||||
m_line -= countLines(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return StringView();
|
||||
}
|
||||
|
||||
StringView Scanner::strFunc(Class _class) const
|
||||
{
|
||||
switch (_class)
|
||||
{
|
||||
case Class::Space:
|
||||
return strLTrimSpace(m_tail);
|
||||
|
||||
case Class::NonSpace:
|
||||
return strLTrimNonSpace(m_tail);
|
||||
|
||||
case Class::Identifier:
|
||||
{
|
||||
const StringView word = strWord(m_tail);
|
||||
return word.isEmpty()
|
||||
? m_tail
|
||||
: StringView(word.getTerm(), m_tail.getTerm() )
|
||||
;
|
||||
}
|
||||
|
||||
case Class::EndOfLine:
|
||||
return strFindEol(m_tail);
|
||||
|
||||
case Class::NewLine:
|
||||
return strFindNl(m_tail);
|
||||
|
||||
default:
|
||||
BX_ASSERT(false, "Bug, _class can't be %d!", _class);
|
||||
BX_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
StringView Scanner::moveBy(int32_t _bytes)
|
||||
{
|
||||
const int32_t len = m_tail.getLength();
|
||||
_bytes = clamp(_bytes, len - m_input.getLength(), len);
|
||||
|
||||
if (BX_LIKELY(0 < _bytes) )
|
||||
{
|
||||
const StringView result(m_tail.getPtr(), m_tail.getPtr() + _bytes);
|
||||
|
||||
m_tail.set(result.getTerm(), m_tail.getTerm() );
|
||||
m_line += countLines(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const StringView result(m_tail.getPtr() + _bytes, m_tail.getPtr() );
|
||||
|
||||
m_tail.set(result.getPtr(), m_tail.getTerm() );
|
||||
m_line -= countLines(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t Scanner::countLines(const StringView& _str)
|
||||
{
|
||||
uint32_t line = 0;
|
||||
|
||||
StringView str = strFindEol(_str);
|
||||
|
||||
while (!str.isEmpty() )
|
||||
{
|
||||
++line;
|
||||
str = strFindEol(strFindNl(str) );
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
StringView LineReader::next()
|
||||
{
|
||||
if (!m_scanner.isDone() )
|
||||
{
|
||||
++m_line;
|
||||
|
||||
const StringView cursor = m_scanner.getCursor();
|
||||
m_scanner.acceptUntil(Scanner::Class::EndOfLine);
|
||||
|
||||
const StringView line = m_scanner.between(cursor);
|
||||
m_scanner.accept(Scanner::Class::NewLine);
|
||||
|
||||
// A line terminator is `\n` or `\r\n`, and `Class::EndOfLine` already
|
||||
// excludes it. Only malformed input (`\r` at the end of input, or
|
||||
// `\r\r\n`) can leave a trailing `\r` behind.
|
||||
return strRTrim(line, "\r");
|
||||
}
|
||||
|
||||
return m_scanner.getCursor();
|
||||
}
|
||||
|
||||
} // namespace bx
|
||||
655
src/settings.cpp
655
src/settings.cpp
@@ -4,209 +4,496 @@
|
||||
*/
|
||||
|
||||
#include <bx/settings.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
#define INI_MALLOC(_ctx, _size) (bx::alloc(reinterpret_cast<bx::AllocatorI*>(_ctx), _size) )
|
||||
#define INI_FREE(_ctx, _ptr) (bx::free(reinterpret_cast<bx::AllocatorI*>(_ctx), _ptr) )
|
||||
#define INI_MEMCPY(_dst, _src, _count) (bx::memCopy(_dst, _src, _count) )
|
||||
#define INI_STRLEN(_str) (bx::strLen(_str) )
|
||||
#define INI_STRNICMP(_s1, _s2, _len) (bx::strCmpI(_s1, _s2, _len) )
|
||||
|
||||
#define INI_IMPLEMENTATION
|
||||
|
||||
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-function");
|
||||
|
||||
BX_PRAGMA_DIAGNOSTIC_PUSH();
|
||||
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wsign-compare");
|
||||
#include <ini/ini.h>
|
||||
BX_PRAGMA_DIAGNOSTIC_POP();
|
||||
}
|
||||
#include <bx/filepath.h>
|
||||
#include <bx/scanner.h>
|
||||
|
||||
namespace bx
|
||||
{
|
||||
|
||||
Settings::Settings(AllocatorI* _allocator, const void* _data, uint32_t _len)
|
||||
: m_allocator(_allocator)
|
||||
, m_ini(NULL)
|
||||
{
|
||||
load(_data, _len);
|
||||
}
|
||||
|
||||
#define INI_T(_ptr) reinterpret_cast<ini_t*>(_ptr)
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
ini_destroy(INI_T(m_ini) );
|
||||
}
|
||||
|
||||
void Settings::clear()
|
||||
{
|
||||
load(NULL, 0);
|
||||
}
|
||||
|
||||
void Settings::load(const void* _data, uint32_t _len)
|
||||
{
|
||||
if (NULL != m_ini)
|
||||
static StringView settingsAlloc(AllocatorI* _allocator, const StringView& _str)
|
||||
{
|
||||
ini_destroy(INI_T(m_ini) );
|
||||
}
|
||||
const int32_t len = _str.getLength();
|
||||
|
||||
if (NULL == _data)
|
||||
{
|
||||
m_ini = ini_create(m_allocator);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ini = ini_load( (const char*)_data, _len, m_allocator);
|
||||
}
|
||||
}
|
||||
|
||||
StringView Settings::get(const StringView& _name) const
|
||||
{
|
||||
ini_t* ini = INI_T(m_ini);
|
||||
|
||||
FilePath uri(_name);
|
||||
const StringView path(strTrim(uri.getPath(), "/") );
|
||||
const StringView& fileName(uri.getFileName() );
|
||||
int32_t section = INI_GLOBAL_SECTION;
|
||||
|
||||
if (!path.isEmpty() )
|
||||
{
|
||||
section = ini_find_section(ini, path.getPtr(), path.getLength() );
|
||||
if (INI_NOT_FOUND == section)
|
||||
if (0 == len)
|
||||
{
|
||||
section = INI_GLOBAL_SECTION;
|
||||
return StringView();
|
||||
}
|
||||
|
||||
char* ptr = (char*)alloc(_allocator, len);
|
||||
memCopy(ptr, _str.getPtr(), len);
|
||||
|
||||
return StringView(ptr, len);
|
||||
}
|
||||
|
||||
static void settingsFree(AllocatorI* _allocator, StringView& _str)
|
||||
{
|
||||
if (!_str.isEmpty() )
|
||||
{
|
||||
free(_allocator, const_cast<char*>(_str.getPtr() ) );
|
||||
}
|
||||
|
||||
_str.clear();
|
||||
}
|
||||
|
||||
static void settingsAssign(AllocatorI* _allocator, StringView& _dst, const StringView& _src)
|
||||
{
|
||||
const StringView next = settingsAlloc(_allocator, _src);
|
||||
settingsFree(_allocator, _dst);
|
||||
_dst = next;
|
||||
}
|
||||
|
||||
struct Settings::Ini
|
||||
{
|
||||
static constexpr int32_t kGlobal = 0;
|
||||
static constexpr int32_t kInvalid = -1;
|
||||
|
||||
struct Property
|
||||
{
|
||||
StringView name;
|
||||
StringView value;
|
||||
};
|
||||
|
||||
struct Section
|
||||
{
|
||||
StringView name;
|
||||
Property* props;
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
};
|
||||
|
||||
void init(AllocatorI* _allocator)
|
||||
{
|
||||
m_allocator = _allocator;
|
||||
m_sections = NULL;
|
||||
m_count = 0;
|
||||
m_capacity = 0;
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
reset();
|
||||
|
||||
if (NULL != m_sections)
|
||||
{
|
||||
free(m_allocator, m_sections);
|
||||
m_sections = NULL;
|
||||
}
|
||||
|
||||
m_capacity = 0;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
reset();
|
||||
|
||||
addSection(StringView() );
|
||||
}
|
||||
|
||||
void load(const StringView& _data)
|
||||
{
|
||||
clear();
|
||||
|
||||
Scanner scanner(_data);
|
||||
int32_t section = kGlobal;
|
||||
|
||||
while (!scanner.isDone() )
|
||||
{
|
||||
scanner.accept(Scanner::Class::Space);
|
||||
|
||||
if (scanner.isDone() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Scanner line(scanner.acceptUntil(Scanner::Class::EndOfLine) );
|
||||
|
||||
// Line comment.
|
||||
if (!line.accept(';').isEmpty() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// [section] header.
|
||||
if (!line.accept('[').isEmpty() )
|
||||
{
|
||||
line.accept(Scanner::Class::Space);
|
||||
const StringView name = strRTrimSpace(line.acceptUntil("]") );
|
||||
|
||||
if (!line.accept(']').isEmpty()
|
||||
&& !name.isEmpty() )
|
||||
{
|
||||
const int32_t existing = findSection(name);
|
||||
section = kInvalid == existing ? addSection(name) : existing;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// name = value property.
|
||||
const StringView name = strRTrimSpace(line.acceptUntil("=") );
|
||||
|
||||
if (line.accept('=').isEmpty()
|
||||
|| name.isEmpty() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
line.accept(Scanner::Class::Space);
|
||||
setProperty(section, name, strRTrimSpace(line.acceptAll() ) );
|
||||
}
|
||||
}
|
||||
|
||||
int32_t find(const StringView& _name, StringView& _propertyName) const
|
||||
{
|
||||
const FilePath uri(_name);
|
||||
const StringView path(strTrim(uri.getPath(), "/") );
|
||||
|
||||
_propertyName = uri.getFileName();
|
||||
|
||||
if (path.isEmpty() )
|
||||
{
|
||||
return kGlobal;
|
||||
}
|
||||
|
||||
const int32_t section = findSection(path);
|
||||
|
||||
return kInvalid == section ? kGlobal : section;
|
||||
}
|
||||
|
||||
int32_t findSection(const StringView& _name) const
|
||||
{
|
||||
for (uint32_t ss = 0; ss < m_count; ++ss)
|
||||
{
|
||||
const StringView& name = m_sections[ss].name;
|
||||
|
||||
if (isEqual(name, _name, false) )
|
||||
{
|
||||
return int32_t(ss);
|
||||
}
|
||||
}
|
||||
|
||||
return kInvalid;
|
||||
}
|
||||
|
||||
int32_t addSection(const StringView& _name)
|
||||
{
|
||||
if (m_count == m_capacity)
|
||||
{
|
||||
m_capacity = 0 == m_capacity ? 8 : m_capacity * 2;
|
||||
m_sections = (Section*)realloc(m_allocator, m_sections, m_capacity * sizeof(Section) );
|
||||
}
|
||||
|
||||
Section& section = m_sections[m_count];
|
||||
section.name = settingsAlloc(m_allocator, _name);
|
||||
section.props = NULL;
|
||||
section.count = 0;
|
||||
section.capacity = 0;
|
||||
|
||||
return int32_t(m_count++);
|
||||
}
|
||||
|
||||
void removeSection(int32_t _section)
|
||||
{
|
||||
if (kGlobal >= _section
|
||||
|| uint32_t(_section) >= m_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
freeSection(m_sections[_section]);
|
||||
|
||||
for (uint32_t ss = uint32_t(_section); ss+1 < m_count; ++ss)
|
||||
{
|
||||
m_sections[ss] = m_sections[ss+1];
|
||||
}
|
||||
|
||||
--m_count;
|
||||
}
|
||||
|
||||
int32_t findProperty(int32_t _section, const StringView& _name) const
|
||||
{
|
||||
if (0 > _section
|
||||
|| uint32_t(_section) >= m_count)
|
||||
{
|
||||
return kInvalid;
|
||||
}
|
||||
|
||||
const Section& section = m_sections[_section];
|
||||
|
||||
for (uint32_t pp = 0; pp < section.count; ++pp)
|
||||
{
|
||||
const StringView& name = section.props[pp].name;
|
||||
|
||||
if (isEqual(name, _name, false) )
|
||||
{
|
||||
return int32_t(pp);
|
||||
}
|
||||
}
|
||||
|
||||
return kInvalid;
|
||||
}
|
||||
|
||||
void setProperty(int32_t _section, const StringView& _name, const StringView& _value)
|
||||
{
|
||||
if (0 > _section
|
||||
|| uint32_t(_section) >= m_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int32_t property = findProperty(_section, _name);
|
||||
|
||||
Section& section = m_sections[_section];
|
||||
|
||||
if (kInvalid != property)
|
||||
{
|
||||
settingsAssign(m_allocator, section.props[property].value, _value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (section.count == section.capacity)
|
||||
{
|
||||
section.capacity = 0 == section.capacity ? 8 : section.capacity * 2;
|
||||
section.props = (Property*)realloc(m_allocator, section.props, section.capacity * sizeof(Property) );
|
||||
}
|
||||
|
||||
Property& prop = section.props[section.count];
|
||||
prop.name = settingsAlloc(m_allocator, _name);
|
||||
prop.value = settingsAlloc(m_allocator, _value);
|
||||
|
||||
++section.count;
|
||||
}
|
||||
|
||||
void removeProperty(int32_t _section, int32_t _property)
|
||||
{
|
||||
if (0 > _section
|
||||
|| uint32_t(_section) >= m_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Section& section = m_sections[_section];
|
||||
|
||||
if (0 > _property
|
||||
|| uint32_t(_property) >= section.count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
settingsFree(m_allocator, section.props[_property].name);
|
||||
settingsFree(m_allocator, section.props[_property].value);
|
||||
|
||||
for (uint32_t pp = uint32_t(_property); pp+1 < section.count; ++pp)
|
||||
{
|
||||
section.props[pp] = section.props[pp+1];
|
||||
}
|
||||
|
||||
--section.count;
|
||||
}
|
||||
|
||||
StringView getPropertyValue(int32_t _section, int32_t _property) const
|
||||
{
|
||||
if (0 > _section
|
||||
|| uint32_t(_section) >= m_count)
|
||||
{
|
||||
return StringView();
|
||||
}
|
||||
|
||||
const Section& section = m_sections[_section];
|
||||
|
||||
return (0 <= _property && uint32_t(_property) < section.count)
|
||||
? section.props[_property].value
|
||||
: StringView()
|
||||
;
|
||||
}
|
||||
|
||||
uint32_t getPropertyCount(int32_t _section) const
|
||||
{
|
||||
return (0 <= _section && uint32_t(_section) < m_count)
|
||||
? m_sections[_section].count
|
||||
: 0
|
||||
;
|
||||
}
|
||||
|
||||
int32_t save(WriterI* _writer, Error* _err) const
|
||||
{
|
||||
int32_t total = 0;
|
||||
|
||||
for (uint32_t ss = 0; ss < m_count; ++ss)
|
||||
{
|
||||
const Section& section = m_sections[ss];
|
||||
|
||||
if (!section.name.isEmpty() )
|
||||
{
|
||||
total += bx::write(_writer, "[", _err);
|
||||
total += bx::write(_writer, section.name, _err);
|
||||
total += bx::write(_writer, "]\n", _err);
|
||||
}
|
||||
|
||||
for (uint32_t pp = 0; pp < section.count; ++pp)
|
||||
{
|
||||
total += bx::write(_writer, section.props[pp].name, _err);
|
||||
total += bx::write(_writer, "=", _err);
|
||||
total += bx::write(_writer, section.props[pp].value, _err);
|
||||
total += bx::write(_writer, "\n", _err);
|
||||
}
|
||||
|
||||
if (0 != total)
|
||||
{
|
||||
total += bx::write(_writer, "\n", _err);
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void freeSection(Section& _section)
|
||||
{
|
||||
for (uint32_t pp = 0; pp < _section.count; ++pp)
|
||||
{
|
||||
settingsFree(m_allocator, _section.props[pp].name);
|
||||
settingsFree(m_allocator, _section.props[pp].value);
|
||||
}
|
||||
|
||||
if (NULL != _section.props)
|
||||
{
|
||||
free(m_allocator, _section.props);
|
||||
}
|
||||
|
||||
settingsFree(m_allocator, _section.name);
|
||||
|
||||
_section.props = NULL;
|
||||
_section.count = 0;
|
||||
_section.capacity = 0;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
for (uint32_t ss = 0; ss < m_count; ++ss)
|
||||
{
|
||||
freeSection(m_sections[ss]);
|
||||
}
|
||||
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
AllocatorI* m_allocator;
|
||||
Section* m_sections;
|
||||
uint32_t m_count;
|
||||
uint32_t m_capacity;
|
||||
};
|
||||
|
||||
Settings::Settings(AllocatorI* _allocator, const void* _data, uint32_t _len)
|
||||
: m_allocator(_allocator)
|
||||
, m_ini(BX_NEW(_allocator, Ini) )
|
||||
{
|
||||
m_ini->init(_allocator);
|
||||
load(_data, _len);
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
m_ini->shutdown();
|
||||
deleteObject(m_allocator, m_ini);
|
||||
}
|
||||
|
||||
void Settings::clear()
|
||||
{
|
||||
m_ini->clear();
|
||||
}
|
||||
|
||||
void Settings::load(const void* _data, uint32_t _len)
|
||||
{
|
||||
if (NULL == _data
|
||||
|| 0 == _len)
|
||||
{
|
||||
m_ini->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
m_ini->load(StringView( (const char*)_data, int32_t(_len) ) );
|
||||
}
|
||||
|
||||
StringView Settings::get(const StringView& _name) const
|
||||
{
|
||||
StringView propertyName;
|
||||
const int32_t section = m_ini->find(_name, propertyName);
|
||||
|
||||
return m_ini->getPropertyValue(section, m_ini->findProperty(section, propertyName) );
|
||||
}
|
||||
|
||||
void Settings::set(const StringView& _name, const StringView& _value)
|
||||
{
|
||||
const FilePath uri(_name);
|
||||
const StringView path(strTrim(uri.getPath(), "/") );
|
||||
const StringView& fileName(uri.getFileName() );
|
||||
|
||||
int32_t section = Ini::kGlobal;
|
||||
|
||||
if (!path.isEmpty() )
|
||||
{
|
||||
section = m_ini->findSection(path);
|
||||
|
||||
if (Ini::kInvalid == section)
|
||||
{
|
||||
section = m_ini->addSection(path);
|
||||
}
|
||||
}
|
||||
|
||||
m_ini->setProperty(section, fileName, _value);
|
||||
}
|
||||
|
||||
void Settings::remove(const StringView& _name) const
|
||||
{
|
||||
StringView propertyName;
|
||||
const int32_t section = m_ini->find(_name, propertyName);
|
||||
|
||||
const int32_t property = m_ini->findProperty(section, propertyName);
|
||||
|
||||
if (Ini::kInvalid == property)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_ini->removeProperty(section, property);
|
||||
|
||||
if (Ini::kGlobal != section
|
||||
&& 0 == m_ini->getPropertyCount(section) )
|
||||
{
|
||||
m_ini->removeSection(section);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t property = ini_find_property(ini, section, fileName.getPtr(), fileName.getLength() );
|
||||
if (INI_NOT_FOUND == property)
|
||||
int32_t Settings::read(ReaderSeekerI* _reader, Error* _err)
|
||||
{
|
||||
return StringView();
|
||||
int32_t size = int32_t(getRemain(_reader) );
|
||||
|
||||
void* data = bx::alloc(m_allocator, size);
|
||||
|
||||
int32_t total = bx::read(_reader, data, size, _err);
|
||||
load(data, size);
|
||||
|
||||
bx::free(m_allocator, data);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
return ini_property_value(ini, section, property);
|
||||
}
|
||||
|
||||
void Settings::set(const StringView& _name, const StringView& _value)
|
||||
{
|
||||
ini_t* ini = INI_T(m_ini);
|
||||
|
||||
FilePath uri(_name);
|
||||
const StringView path(strTrim(uri.getPath(), "/") );
|
||||
const StringView& fileName(uri.getFileName() );
|
||||
|
||||
int32_t section = INI_GLOBAL_SECTION;
|
||||
|
||||
if (!path.isEmpty() )
|
||||
int32_t Settings::write(WriterI* _writer, Error* _err) const
|
||||
{
|
||||
section = ini_find_section(ini, path.getPtr(), path.getLength() );
|
||||
if (INI_NOT_FOUND == section)
|
||||
{
|
||||
section = ini_section_add(ini, path.getPtr(), path.getLength() );
|
||||
}
|
||||
return m_ini->save(_writer, _err);
|
||||
}
|
||||
|
||||
int32_t property = ini_find_property(ini, section, fileName.getPtr(), fileName.getLength() );
|
||||
if (INI_NOT_FOUND == property)
|
||||
int32_t read(ReaderSeekerI* _reader, Settings& _settings, Error* _err)
|
||||
{
|
||||
ini_property_add(
|
||||
ini
|
||||
, section
|
||||
, fileName.getPtr()
|
||||
, fileName.getLength()
|
||||
, _value.getPtr()
|
||||
, _value.getLength()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ini_property_value_set(
|
||||
ini
|
||||
, section
|
||||
, property
|
||||
, _value.getPtr()
|
||||
, _value.getLength()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::remove(const StringView& _name) const
|
||||
{
|
||||
ini_t* ini = INI_T(m_ini);
|
||||
|
||||
FilePath uri(_name);
|
||||
const StringView path = strTrim(uri.getPath(), "/");
|
||||
const StringView& fileName = uri.getFileName();
|
||||
|
||||
int32_t section = INI_GLOBAL_SECTION;
|
||||
|
||||
if (!path.isEmpty() )
|
||||
{
|
||||
section = ini_find_section(ini, path.getPtr(), path.getLength() );
|
||||
if (INI_NOT_FOUND == section)
|
||||
{
|
||||
section = INI_GLOBAL_SECTION;
|
||||
}
|
||||
BX_ERROR_SCOPE(_err);
|
||||
return _settings.read(_reader, _err);
|
||||
}
|
||||
|
||||
int32_t property = ini_find_property(ini, section, fileName.getPtr(), fileName.getLength() );
|
||||
if (INI_NOT_FOUND == property)
|
||||
int32_t write(WriterI* _writer, const Settings& _settings, Error* _err)
|
||||
{
|
||||
return;
|
||||
BX_ERROR_SCOPE(_err);
|
||||
return _settings.write(_writer, _err);
|
||||
}
|
||||
|
||||
ini_property_remove(ini, section, property);
|
||||
|
||||
if (INI_GLOBAL_SECTION != section
|
||||
&& 0 == ini_property_count(ini, section) )
|
||||
{
|
||||
ini_section_remove(ini, section);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Settings::read(ReaderSeekerI* _reader, Error* _err)
|
||||
{
|
||||
int32_t size = int32_t(getRemain(_reader) );
|
||||
|
||||
void* data = bx::alloc(m_allocator, size);
|
||||
|
||||
int32_t total = bx::read(_reader, data, size, _err);
|
||||
load(data, size);
|
||||
|
||||
bx::free(m_allocator, data);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int32_t Settings::write(WriterI* _writer, Error* _err) const
|
||||
{
|
||||
ini_t* ini = INI_T(m_ini);
|
||||
|
||||
int32_t size = ini_save(ini, NULL, 0);
|
||||
void* data = bx::alloc(m_allocator, size);
|
||||
|
||||
ini_save(ini, (char*)data, size);
|
||||
int32_t total = bx::write(_writer, data, size-1, _err);
|
||||
|
||||
bx::free(m_allocator, data);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
#undef INI_T
|
||||
|
||||
int32_t read(ReaderSeekerI* _reader, Settings& _settings, Error* _err)
|
||||
{
|
||||
BX_ERROR_SCOPE(_err);
|
||||
return _settings.read(_reader, _err);
|
||||
}
|
||||
|
||||
int32_t write(WriterI* _writer, const Settings& _settings, Error* _err)
|
||||
{
|
||||
BX_ERROR_SCOPE(_err);
|
||||
return _settings.write(_writer, _err);
|
||||
}
|
||||
|
||||
} // namespace bx
|
||||
|
||||
@@ -10,65 +10,6 @@
|
||||
|
||||
namespace bx
|
||||
{
|
||||
inline bool isInRange(char _ch, char _from, char _to)
|
||||
{
|
||||
return unsigned(_ch - _from) <= unsigned(_to-_from);
|
||||
}
|
||||
|
||||
bool isSpace(char _ch)
|
||||
{
|
||||
return ' ' == _ch // Space.
|
||||
|| '\t' == _ch // Horizontal tab.
|
||||
|| '\n' == _ch // Line feed / new line.
|
||||
|| '\r' == _ch // Carriage return.
|
||||
|| '\v' == _ch // Vertical tab.
|
||||
|| '\f' == _ch // Form feed / new page.
|
||||
;
|
||||
}
|
||||
|
||||
bool isUpper(char _ch)
|
||||
{
|
||||
return isInRange(_ch, 'A', 'Z');
|
||||
}
|
||||
|
||||
bool isLower(char _ch)
|
||||
{
|
||||
return isInRange(_ch, 'a', 'z');
|
||||
}
|
||||
|
||||
bool isAlpha(char _ch)
|
||||
{
|
||||
return isLower(_ch) || isUpper(_ch);
|
||||
}
|
||||
|
||||
bool isNumeric(char _ch)
|
||||
{
|
||||
return isInRange(_ch, '0', '9');
|
||||
}
|
||||
|
||||
bool isAlphaNum(char _ch)
|
||||
{
|
||||
return false
|
||||
|| isAlpha(_ch)
|
||||
|| isNumeric(_ch)
|
||||
;
|
||||
}
|
||||
|
||||
bool isHexNum(char _ch)
|
||||
{
|
||||
return false
|
||||
|| isInRange(toLower(_ch), 'a', 'f')
|
||||
|| isNumeric(_ch)
|
||||
;
|
||||
}
|
||||
|
||||
bool isPrint(char _ch)
|
||||
{
|
||||
return isInRange(_ch, ' ', '~');
|
||||
}
|
||||
|
||||
typedef bool (*CharTestFn)(char _ch);
|
||||
|
||||
template<CharTestFn fn>
|
||||
inline bool isCharTest(const StringView& _str)
|
||||
{
|
||||
@@ -125,11 +66,6 @@ namespace bx
|
||||
return isCharTest<isPrint>(_str);
|
||||
}
|
||||
|
||||
char toLower(char _ch)
|
||||
{
|
||||
return _ch + (isUpper(_ch) ? 0x20 : 0);
|
||||
}
|
||||
|
||||
void toLowerUnsafe(char* _inOutStr, int32_t _len)
|
||||
{
|
||||
for (int32_t ii = 0; ii < _len; ++ii)
|
||||
@@ -144,11 +80,6 @@ namespace bx
|
||||
toLowerUnsafe(_inOutStr, len);
|
||||
}
|
||||
|
||||
char toUpper(char _ch)
|
||||
{
|
||||
return _ch - (isLower(_ch) ? 0x20 : 0);
|
||||
}
|
||||
|
||||
void toUpperUnsafe(char* _inOutStr, int32_t _len)
|
||||
{
|
||||
for (int32_t ii = 0; ii < _len; ++ii)
|
||||
@@ -165,7 +96,7 @@ namespace bx
|
||||
|
||||
typedef char (*CharFn)(char _ch);
|
||||
|
||||
inline constexpr char toNoop(char _ch)
|
||||
inline BX_CONSTEXPR_FUNC char toNoop(char _ch)
|
||||
{
|
||||
return _ch;
|
||||
}
|
||||
@@ -560,8 +491,6 @@ namespace bx
|
||||
);
|
||||
}
|
||||
|
||||
constexpr uint32_t kFindStep = 1024;
|
||||
|
||||
StringView strFindNl(const StringView& _str)
|
||||
{
|
||||
StringView str(_str);
|
||||
@@ -578,23 +507,19 @@ namespace bx
|
||||
|
||||
StringView strFindEol(const StringView& _str)
|
||||
{
|
||||
StringView str(_str);
|
||||
const StringView eol = strFind(_str, '\n');
|
||||
|
||||
for (; str.getPtr() != _str.getTerm()
|
||||
; str = StringView(min(str.getPtr() + kFindStep, _str.getTerm() ), min(str.getPtr() + kFindStep*2, _str.getTerm() ) )
|
||||
)
|
||||
if (!eol.isEmpty() )
|
||||
{
|
||||
StringView eol = strFind(str, "\r\n");
|
||||
if (!eol.isEmpty() )
|
||||
const char* ptr = eol.getPtr();
|
||||
|
||||
if (ptr != _str.getPtr()
|
||||
&& '\r' == ptr[-1])
|
||||
{
|
||||
return StringView(eol.getPtr(), _str.getTerm() );
|
||||
--ptr;
|
||||
}
|
||||
|
||||
eol = strFind(str, '\n');
|
||||
if (!eol.isEmpty() )
|
||||
{
|
||||
return StringView(eol.getPtr(), _str.getTerm() );
|
||||
}
|
||||
return StringView(ptr, _str.getTerm() );
|
||||
}
|
||||
|
||||
return StringView(_str.getTerm(), _str.getTerm() );
|
||||
|
||||
149
src/url.cpp
149
src/url.cpp
@@ -3,10 +3,36 @@
|
||||
* License: https://github.com/bkaradzic/bnet#license-bsd-2-clause
|
||||
*/
|
||||
|
||||
#include <bx/scanner.h>
|
||||
#include <bx/url.h>
|
||||
|
||||
namespace bx
|
||||
{
|
||||
static bool isNotSlash(char _ch)
|
||||
{
|
||||
return '/' != _ch;
|
||||
}
|
||||
|
||||
static bool isNotColon(char _ch)
|
||||
{
|
||||
return ':' != _ch;
|
||||
}
|
||||
|
||||
static bool isNotQuery(char _ch)
|
||||
{
|
||||
return '?' != _ch;
|
||||
}
|
||||
|
||||
static bool isNotFragment(char _ch)
|
||||
{
|
||||
return '#' != _ch;
|
||||
}
|
||||
|
||||
static bool isNotQueryOrFragment(char _ch)
|
||||
{
|
||||
return isNotQuery(_ch) && isNotFragment(_ch);
|
||||
}
|
||||
|
||||
UrlView::UrlView()
|
||||
{
|
||||
}
|
||||
@@ -23,22 +49,16 @@ namespace bx
|
||||
{
|
||||
clear();
|
||||
|
||||
const char* term = _url.getTerm();
|
||||
StringView schemeEnd = strFind(_url, "://");
|
||||
const char* hostStart = !schemeEnd.isEmpty() ? schemeEnd.getTerm() : _url.getPtr();
|
||||
StringView path = strFind(StringView(hostStart, term), '/');
|
||||
Scanner scanner(_url);
|
||||
|
||||
if (schemeEnd.isEmpty()
|
||||
&& path.isEmpty() )
|
||||
const StringView schemeBegin = scanner.getCursor();
|
||||
scanner.acceptUntil("://");
|
||||
const StringView scheme = scanner.between(schemeBegin);
|
||||
|
||||
const bool hasScheme = !scanner.accept("://").isEmpty();
|
||||
|
||||
if (hasScheme)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!schemeEnd.isEmpty()
|
||||
&& (path.isEmpty() || path.getPtr() > schemeEnd.getPtr() ) )
|
||||
{
|
||||
const StringView scheme(_url.getPtr(), schemeEnd.getPtr() );
|
||||
|
||||
if (!isAlpha(scheme) )
|
||||
{
|
||||
return false;
|
||||
@@ -47,65 +67,72 @@ namespace bx
|
||||
m_tokens[Scheme].set(scheme);
|
||||
}
|
||||
|
||||
if (!path.isEmpty() )
|
||||
{
|
||||
path.set(path.getPtr(), term);
|
||||
const StringView query = strFind(path, '?');
|
||||
const StringView fragment = strFind(path, '#');
|
||||
const StringView authorityBegin = scanner.getCursor();
|
||||
scanner.acceptWhile(isNotSlash);
|
||||
const StringView authority = scanner.between(authorityBegin);
|
||||
|
||||
if (!fragment.isEmpty()
|
||||
&& fragment.getPtr() < query.getPtr() )
|
||||
const bool hasPath = !scanner.peek('/').isEmpty();
|
||||
|
||||
if (!hasScheme
|
||||
&& !hasPath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasPath)
|
||||
{
|
||||
const StringView pathBegin = scanner.getCursor();
|
||||
scanner.acceptWhile(isNotQueryOrFragment);
|
||||
m_tokens[Path].set(scanner.between(pathBegin) );
|
||||
|
||||
if (!scanner.accept('?').isEmpty() )
|
||||
{
|
||||
const StringView queryBegin = scanner.getCursor();
|
||||
scanner.acceptWhile(isNotFragment);
|
||||
m_tokens[Query].set(scanner.between(queryBegin) );
|
||||
}
|
||||
|
||||
if (!scanner.accept('#').isEmpty() )
|
||||
{
|
||||
const StringView fragmentBegin = scanner.getCursor();
|
||||
scanner.acceptWhile(isNotQuery);
|
||||
m_tokens[Fragment].set(scanner.between(fragmentBegin) );
|
||||
}
|
||||
|
||||
// Anything left over is a query following a fragment.
|
||||
if (!scanner.isDone() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_tokens[Path].set(path.getPtr()
|
||||
, !query.isEmpty() ? query.getPtr()
|
||||
: !fragment.isEmpty() ? fragment.getPtr()
|
||||
: term
|
||||
);
|
||||
|
||||
if (!query.isEmpty() )
|
||||
{
|
||||
m_tokens[Query].set(query.getPtr()+1
|
||||
, !fragment.isEmpty() ? fragment.getPtr()
|
||||
: term
|
||||
);
|
||||
}
|
||||
|
||||
if (!fragment.isEmpty() )
|
||||
{
|
||||
m_tokens[Fragment].set(fragment.getPtr()+1, term);
|
||||
}
|
||||
|
||||
term = path.getPtr();
|
||||
}
|
||||
|
||||
const StringView userPassEnd = strFind(StringView(hostStart, term), '@');
|
||||
const char* userPassStart = !userPassEnd.isEmpty() ? hostStart : NULL;
|
||||
hostStart = !userPassEnd.isEmpty() ? userPassEnd.getPtr()+1 : hostStart;
|
||||
const StringView portStart = strFind(StringView(hostStart, term), ':');
|
||||
Scanner authorityScanner(authority);
|
||||
|
||||
m_tokens[Host].set(hostStart, !portStart.isEmpty() ? portStart.getPtr() : term);
|
||||
const StringView userInfoBegin = authorityScanner.getCursor();
|
||||
authorityScanner.acceptUntil("@");
|
||||
const StringView userInfo = authorityScanner.between(userInfoBegin);
|
||||
|
||||
if (!portStart.isEmpty())
|
||||
if (!authorityScanner.accept('@').isEmpty() )
|
||||
{
|
||||
m_tokens[Port].set(portStart.getPtr()+1, term);
|
||||
Scanner userInfoScanner(userInfo);
|
||||
|
||||
const StringView userNameBegin = userInfoScanner.getCursor();
|
||||
userInfoScanner.acceptWhile(isNotColon);
|
||||
m_tokens[UserName].set(userInfoScanner.between(userNameBegin) );
|
||||
|
||||
if (!userInfoScanner.accept(':').isEmpty() )
|
||||
{
|
||||
m_tokens[Password].set(userInfoScanner.acceptAll() );
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != userPassStart)
|
||||
const StringView hostBegin = authorityScanner.getCursor();
|
||||
authorityScanner.acceptWhile(isNotColon);
|
||||
m_tokens[Host].set(authorityScanner.between(hostBegin) );
|
||||
|
||||
if (!authorityScanner.accept(':').isEmpty() )
|
||||
{
|
||||
StringView passStart = strFind(StringView(userPassStart, userPassEnd.getPtr() ), ':');
|
||||
|
||||
m_tokens[UserName].set(userPassStart
|
||||
, !passStart.isEmpty() ? passStart.getPtr()
|
||||
: userPassEnd.getPtr()
|
||||
);
|
||||
|
||||
if (!passStart.isEmpty() )
|
||||
{
|
||||
m_tokens[Password].set(passStart.getPtr()+1, userPassEnd.getPtr() );
|
||||
}
|
||||
m_tokens[Port].set(authorityScanner.acceptAll() );
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user