Add first implementation attempt

This commit is contained in:
RYAN 2024-08-25 23:03:25 +02:00
parent 4b5cd25293
commit da74f00f79
Signed by: RYAN
GPG Key ID: 3BD93EABD1407B82
26 changed files with 1550 additions and 0 deletions

16
.editorconfig Normal file
View File

@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
[*.md]
indent_style = space
indent_size = 4
max_line_length = off
trim_trailing_whitespace = false

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto

32
.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
.bdep/
Doxyfile
# Local default options files.
#
.build2/local/
# Compiler/linker output.
#
*.d
*.t
*.i
*.i.*
*.ii
*.ii.*
*.o
*.obj
*.gcm
*.pcm
*.ifc
*.so
*.dylib
*.dll
*.a
*.lib
*.exp
*.pdb
*.ilk
*.exe
*.exe.dlls/
*.exe.manifest
*.pc

404
Doxyfile.in Normal file
View File

@ -0,0 +1,404 @@
# Doxyfile 1.10.0
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "@project@"
PROJECT_NUMBER = "@version@"
PROJECT_BRIEF = "@SUMMARY@"
PROJECT_LOGO =
PROJECT_ICON =
OUTPUT_DIRECTORY = @out_root@/docs/api-reference
CREATE_SUBDIRS = YES
CREATE_SUBDIRS_LEVEL = 8
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = YES
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = "@src_root@"
STRIP_FROM_INC_PATH = "@src_root@"
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
PYTHON_DOCSTRING = YES
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
MARKDOWN_ID_STYLE = DOXYGEN
AUTOLINK_SUPPORT = NO
BUILTIN_STL_SUPPORT = YES
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
TIMESTAMP = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PRIV_VIRTUAL = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = NO
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = YES
RESOLVE_UNNAMED_PARAMS = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = SYSTEM
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_HEADERFILE = YES
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = NO
WARN_IF_UNDOC_ENUM_VAL = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LINE_FORMAT = "at line $line of file $file"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = @src_root@/README.md \
@src_root@/arc
INPUT_ENCODING = UTF-8
INPUT_FILE_ENCODING =
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cxxm \
*.cpp \
*.cppm \
*.ccm \
*.c++ \
*.c++m \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.ixx \
*.l \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f18 \
*.f \
*.for \
*.vhd \
*.vhdl \
*.ucf \
*.qsf \
*.txx \
*.ice
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = @src_root@/docs/introduction.md
FORTRAN_COMMENT_AFTER = 72
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE = LIGHT
#HTML_COLORSTYLE_HUE = 327
#HTML_COLORSTYLE_SAT = 89
#HTML_COLORSTYLE_GAMMA = 65
HTML_COLORSTYLE_HUE = 204
HTML_COLORSTYLE_SAT = 60
HTML_COLORSTYLE_GAMMA = 100
HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_CODE_FOLDING = YES
HTML_COPY_CLIPBOARD = YES
HTML_PROJECT_COOKIE =
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_FEEDURL =
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
SITEMAP_URL =
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
FULL_SIDEBAR = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
OBFUSCATE_EMAILS = NO
HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
FORMULA_MACROFILE =
USE_MATHJAX = NO
MATHJAX_VERSION = MathJax_2
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH =
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME =
MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
GENERATE_SQLITE3 = NO
SQLITE3_OUTPUT = sqlite3
SQLITE3_RECREATE_DB = YES
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH = "@src_root@"
INCLUDE_FILE_PATTERNS =
PREDEFINED = LIBARC_URI_SYMEXPORT
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to diagram generator tools
#---------------------------------------------------------------------------
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
DOT_NUM_THREADS = 0
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
DOT_UML_DETAILS = NO
DOT_WRAP_THRESHOLD = 17
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DIR_GRAPH_MAX_DEPTH = 1
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
DIA_PATH =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
MSCGEN_TOOL =
MSCFILE_DIRS =

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Arc Project Software License, version 1.0, June 2nd 2024
Permission to use, copy, modify, distribute, and sell this software
(the "Software") and its documentation for any purpose is hereby
granted without fee, provided that the copyright notices in the
Software and this license appear in supporting documentation.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGMENT,
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONJUNCTION WITH THE
SOFTWARE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name(s) of copyright holders
of the Software shall not be used in advertising or otherwise to
promote the sale, use or other dealing in this Software without prior
written authorization from the copyright holders.

9
arc/uri/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
# Generated version header.
#
version.hxx
# Unit test executables and Testscript output directories
# (can be symlinks).
#
*.test
test-*.test

65
arc/uri/buildfile Normal file
View File

@ -0,0 +1,65 @@
intf_libs = # Interface dependencies.
impl_libs = # Implementation dependencies.
./: lib{arc-uri}: libul{arc-uri}
libul{arc-uri}: {hxx ixx txx cxx}{** -**.test... -version} \
{hxx }{ version}
libul{arc-uri}: $impl_libs $intf_libs
# Unit tests.
#
exe{*.test}:
{
test = true
install = false
}
for t: cxx{**.test...}
{
d = $directory($t)
n = $name($t)...
./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n}
$d/exe{$n}: libul{arc-uri}: bin.whole = false
}
hxx{version}: in{version} $src_root/manifest
# Build options.
#
cxx.poptions =+ "-I$out_root" "-I$src_root"
cxx.coptions =+ -fvisibility=hidden
obja{*}: cxx.poptions += -DLIBARC_URI_STATIC_BUILD
objs{*}: cxx.poptions += -DLIBARC_URI_SHARED_BUILD
# Export options.
#
lib{arc-uri}:
{
cxx.export.poptions = "-I$out_root" "-I$src_root"
cxx.export.libs = $intf_libs
}
liba{arc-uri}: cxx.export.poptions += -DLIBARC_URI_STATIC
libs{arc-uri}: cxx.export.poptions += -DLIBARC_URI_SHARED
# For pre-releases use the complete version to make sure they cannot
# be used in place of another pre-release or the final version. See
# the version module for details on the version.* variable values.
#
if $version.pre_release
lib{arc-uri}: bin.lib.version = "-$version.project_id"
else
lib{arc-uri}: bin.lib.version = "-$version.major.$version.minor"
# Install into the arc/uri/ subdirectory of, say, /usr/include/
# recreating subdirectories.
#
{hxx ixx txx}{*}:
{
install = include/arc/uri/
install.subdirs = true
}

32
arc/uri/export.hxx Normal file
View File

@ -0,0 +1,32 @@
#ifndef arc__uri__export_hxx_
#define arc__uri__export_hxx_
#if defined _WIN32 || defined __CYGWIN__
# define LIBARC_URI_SO_IMPORT __declspec(dllimport)
# define LIBARC_URI_SO_EXPORT __declspec(dllexport)
# define LIBARC_URI_SO_LOCAL
#else
# if __GNUC__ >= 4
# define LIBARC_URI_SO_IMPORT __attribute__ ((visibility ("default")))
# define LIBARC_URI_SO_EXPORT __attribute__ ((visibility ("default")))
# define LIBARC_URI_SO_LOCAL __attribute__ ((visibility ("hidden")))
# else
# define LIBARC_URI_SO_IMPORT
# define LIBARC_URI_SO_EXPORT
# define LIBARC_URI_SO_LOCAL
# endif
#endif
#if defined(LIBARC_URI_STATIC) // Using static.
# define LIBARC_URI_SYMEXPORT
#elif defined(LIBARC_URI_STATIC_BUILD) // Building static.
# define LIBARC_URI_SYMEXPORT
#elif defined(LIBARC_URI_SHARED) // Using shared.
# define LIBARC_URI_SYMEXPORT LIBARC_URI_SO_IMPORT
#elif defined(LIBARC_URI_SHARED_BUILD) // Building shared.
# define LIBARC_URI_SYMEXPORT LIBARC_URI_SO_EXPORT
#else
# error define LIBARC_URI_STATIC or LIBARC_URI_SHARED
#endif
#endif

133
arc/uri/grammar.hxx Normal file
View File

@ -0,0 +1,133 @@
#ifndef arc__uri__grammar_hxx_
#define arc__uri__grammar_hxx_
namespace arc::uri::grammar
{
inline
bool
is_alpha(char c)
{
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
inline
bool
is_digit(char c)
{
return '0' <= c && c <= '9';
}
inline
bool
is_unreserved(char c)
{
if (is_alpha(c) || is_digit(c)) {
return true;
}
switch (c) {
case '-':
case '.':
case '_':
case '~':
return true;
}
return false;
}
inline
bool
is_subdelim(char c)
{
switch (c) {
case '!':
case '$':
case '&':
case '(':
case ')':
case '*':
case '+':
case ',':
case ';':
case '=':
case '\'':
return true;
}
return false;
}
inline
bool
is_scheme_start(char c)
{
return is_alpha(c);
}
inline
bool
is_scheme(char c)
{
return is_alpha(c) || is_digit(c) || c == '+' || c == '-' || c == '.';
}
inline
bool
is_userinfo(char c)
{
return is_unreserved(c) || is_subdelim(c) || c == ':' || c == '%';
}
inline
bool
is_regname(char c)
{
return is_unreserved(c) || is_subdelim(c);
}
inline
bool
is_host(char c)
{
return is_regname(c);
}
inline
bool
is_port(char c)
{
return is_digit(c);
}
inline
bool
is_pchar(char c)
{
return is_unreserved(c) || is_subdelim(c) || c == ':' || c == '@' || c == '%';
}
inline
bool
is_segment_nc(char c)
{
return is_pchar(c) && c != ':';
}
inline
bool
is_query(char c)
{
return is_pchar(c) || c == '/' || c == '?';
}
inline
bool
is_fragment(char c)
{
return is_pchar(c) || c == '/' || c == '?';
}
} // namespace arc::uri::grammar
#endif

284
arc/uri/uri.cxx Normal file
View File

@ -0,0 +1,284 @@
#include <arc/uri/uri.hxx>
#include <sstream>
#include <vector>
#include <iostream>
namespace arc::uri
{
uri_t::
uri_t()
{}
uri_t::
uri_t(std::string scheme, std::string host, std::string path)
: scheme_{std::move(scheme)},
host_{std::move(host)},
path_{std::move(path)}
{}
uri_t::
uri_t(std::string scheme,
std::string host,
std::string port,
std::string path)
: scheme_{std::move(scheme)},
host_{std::move(host)},
port_{std::move(port)},
path_{std::move(path)}
{}
uri_t::
uri_t(std::string scheme,
std::string host,
std::string port,
std::string path,
std::string query)
: scheme_{std::move(scheme)},
host_{std::move(host)},
port_{std::move(port)},
path_{std::move(path)},
query_{std::move(query)}
{}
uri_t::
uri_t(std::string scheme,
std::string host,
std::string port,
std::string path,
std::string query,
std::string fragment)
: scheme_{std::move(scheme)},
host_{std::move(host)},
port_{std::move(port)},
path_{std::move(path)},
query_{std::move(query)},
fragment_{std::move(fragment)}
{}
uri_t::
uri_t(std::string scheme,
std::string userinfo,
std::string host,
std::string port,
std::string path,
std::string query,
std::string fragment)
: scheme_{std::move(scheme)},
userinfo_{std::move(userinfo)},
host_{std::move(host)},
port_{std::move(port)},
path_{std::move(path)},
query_{std::move(query)},
fragment_{std::move(fragment)}
{}
uri_t::
uri_t(std::optional<std::string> scheme,
std::optional<std::string> userinfo,
std::optional<std::string> host,
std::optional<std::string> port,
std::string path,
std::optional<std::string> query,
std::optional<std::string> fragment)
: scheme_{std::move(scheme)},
userinfo_{std::move(userinfo)},
host_{std::move(host)},
port_{std::move(port)},
path_{std::move(path)},
query_{std::move(query)},
fragment_{std::move(fragment)}
{}
std::optional<std::string> const&
uri_t::
scheme() const
{
return scheme_;
}
std::string
uri_t::
scheme_str() const
{
return scheme().value_or(std::string{});
}
std::optional<std::string> const&
uri_t::
userinfo() const
{
return userinfo_;
}
std::string
uri_t::
userinfo_str() const
{
return userinfo().value_or(std::string{});
}
std::optional<std::string> const&
uri_t::
host() const
{
return host_;
}
std::string
uri_t::
host_str() const
{
return host().value_or(std::string{});
}
std::optional<std::string> const&
uri_t::
port() const
{
return port_;
}
std::string
uri_t::
port_str() const
{
return port().value_or(std::string{});
}
std::string
uri_t::
path_str() const
{
return path_;
}
std::optional<std::string> const&
uri_t::
query() const
{
return query_;
}
std::string
uri_t::
query_str() const
{
return query().value_or(std::string{});
}
std::optional<std::string> const&
uri_t::
fragment() const
{
return fragment_;
}
std::string
uri_t::
fragment_str() const
{
return fragment().value_or(std::string{});
}
std::string
to_string(uri_t const& uri)
{
std::ostringstream str;
// Scheme
//
if (auto scheme = uri.scheme(); scheme) {
str <<*scheme <<':';
}
// Authority
//
if (auto host = uri.host(); host) {
str <<"//";
// Userinfo
//
if (auto userinfo = uri.userinfo(); userinfo) {
str <<*userinfo <<'@';
}
// Host
//
str <<*host;
// Port
if (auto port = uri.port(); port) {
str <<':' <<*port;
}
}
// Path
//
str <<uri.path_str();
// Query
//
if (auto query = uri.query(); query) {
str <<'?' <<*query;
}
// Fragment
//
if (auto fragment = uri.fragment(); fragment) {
str <<'#' <<*fragment;
}
return str.str();
}
uri_t
normalize_path(uri_t const& uri)
{
std::stringstream path{uri.path_str()};
std::vector<std::string> segments;
for (std::string segment; std::getline(path, segment, '/');) {
std::cout << "found segment: " << segment << '\n';
if (segment.empty()) {
continue;
}
if (segment == ".") {
continue;
}
if (segment == "..") {
if (!segments.empty()) {
segments.pop_back();
}
continue;
}
segments.push_back(segment);
}
std::string normalized;
for (auto const& j : segments) {
normalized += '/';
normalized += j;
}
return uri_t{
uri.scheme(),
uri.userinfo(),
uri.host(),
uri.port(),
normalized.empty() ? "/" : normalized,
uri.query(),
uri.fragment()
};
}
std::optional<uri_t>
try_parse(std::string const& str)
{
return try_parse(str.begin(), str.end());
}
} // namespace uri

122
arc/uri/uri.hxx Normal file
View File

@ -0,0 +1,122 @@
#ifndef arc__uri__uri_hxx_
#define arc__uri__uri_hxx_
#include <arc/uri/export.hxx>
#include <arc/uri/grammar.hxx>
#include <optional>
#include <stdexcept>
#include <string>
namespace arc::uri
{
class LIBARC_URI_SYMEXPORT uri_t
{
public:
uri_t();
uri_t(std::string, std::string, std::string);
uri_t(std::string, std::string, std::string, std::string);
uri_t(std::string,
std::string,
std::string,
std::string,
std::string);
uri_t(std::string,
std::string,
std::string,
std::string,
std::string,
std::string);
uri_t(std::string,
std::string,
std::string,
std::string,
std::string,
std::string,
std::string);
uri_t(std::optional<std::string>,
std::optional<std::string>,
std::optional<std::string>,
std::optional<std::string>,
std::string,
std::optional<std::string>,
std::optional<std::string>);
std::optional<std::string> const&
scheme() const;
std::string
scheme_str() const;
std::optional<std::string> const&
userinfo() const;
std::string
userinfo_str() const;
std::optional<std::string> const&
host() const;
std::string
host_str() const;
std::optional<std::string> const&
port() const;
std::string
port_str() const;
std::string
path_str() const;
std::optional<std::string> const&
query() const;
std::string
query_str() const;
std::optional<std::string> const&
fragment() const;
std::string
fragment_str() const;
private:
std::optional<std::string> scheme_;
std::optional<std::string> userinfo_;
std::optional<std::string> host_;
std::optional<std::string> port_;
std::string path_;
std::optional<std::string> query_;
std::optional<std::string> fragment_;
};
LIBARC_URI_SYMEXPORT
std::string
to_string(uri_t const&);
LIBARC_URI_SYMEXPORT
uri_t
normalize_path(uri_t const&);
template<typename Iterator>
std::optional<uri_t>
try_parse(Iterator first, Iterator last);
LIBARC_URI_SYMEXPORT
std::optional<uri_t>
try_parse(std::string const&);
} // namespace arc::uri
#include <arc/uri/uri.txx>
#endif

242
arc/uri/uri.txx Normal file
View File

@ -0,0 +1,242 @@
namespace arc::uri
{
template<typename Iterator>
std::optional<uri_t>
try_parse(Iterator first, Iterator last)
{
std::optional<std::string> opt_scheme;
std::optional<std::string> opt_userinfo;
std::optional<std::string> opt_host;
std::optional<std::string> opt_port;
std::string path;
std::optional<std::string> opt_query;
std::optional<std::string> opt_fragment;
auto try_parse_scheme = [&](auto init)
{
auto c = init;
std::string scheme;
while (c != last && grammar::is_scheme(*c)) {
scheme += *c++;
}
if (c != last && *c == ':') {
++c; // skips ':'
opt_scheme = std::move(scheme);
return c;
}
return init;
};
auto try_parse_userinfo = [&](auto init)
{
auto c = init;
std::string userinfo;
while (c != last && grammar::is_userinfo(*c)) {
userinfo += *c++;
}
if (c != last && *c == '@') {
++c; // skips '@'
opt_userinfo = std::move(userinfo);
return c;
}
return init;
};
auto try_parse_host = [&](auto init)
{
auto c = init;
opt_host = std::string{};
while (c != last && grammar::is_host(*c)) {
*opt_host += *c++;
}
return c;
};
auto try_parse_port = [&](auto init)
{
auto c = init;
if (c != last && *c == ':') {
++c; // skips ':'
opt_port = std::string{};
while (c != last && grammar::is_digit(*c)) {
*opt_port += *c++;
}
return c;
}
return init;
};
auto try_parse_authority = [&](auto init)
{
auto c = init;
if (c == last || *c != '/') {
return init;
}
++c; // skips first '/'
if (c == last || *c != '/') {
return init;
}
++c; // skips second '/'
c = try_parse_userinfo(c);
c = try_parse_host(c);
c = try_parse_port(c);
return c;
};
auto try_parse_path = [&](auto init)
{
auto c = init;
while (c != last && (grammar::is_pchar(*c) || *c == '/')) {
path += *c++;
}
return c;
};
auto try_parse_query = [&](auto init)
{
auto c = init;
if (c != last && *c == '?') {
++c; // skips '?'
opt_query = std::string{};
while (c != last && grammar::is_query(*c)) {
*opt_query += *c++;
}
return c;
}
return init;
};
auto try_parse_fragment = [&](auto init)
{
auto c = init;
if (c != last && *c == '#') {
++c; // skips '?#'
opt_fragment = std::string{};
while (c != last && grammar::is_fragment(*c)) {
*opt_fragment += *c++;
}
return c;
}
return init;
};
first = try_parse_scheme(first);
first = try_parse_authority(first);
first = try_parse_path(first);
first = try_parse_query(first);
first = try_parse_fragment(first);
if (first != last) {
return std::nullopt;
}
auto percent_decode = [](std::string const& input)
{
auto hex_to_char = [](char c)
{
if (c>= '0' && c <= '9')
return c - '0';
if (c>= 'a' && c <= 'f')
return c - 'a' + 10;
if (c>= 'A' && c <= 'F')
return c - 'A' + 10;
throw std::invalid_argument{"invalid hex character"};
};
auto make_byte = [&](char a, char b)
{
return hex_to_char(a) << 4 | hex_to_char(b);
};
std::string str;
auto j = input.begin();
while (j != input.end()) {
if ('%' == *j) {
++j;
if (j == input.end()) {
break;
}
char one = *j++;
if (j == input.end()) {
break;
}
char two = *j++;
str += make_byte(one, two);
continue;
}
str += *j;
++j;
}
return str;
};
if (opt_userinfo) {
opt_userinfo = percent_decode(*opt_userinfo);
}
path = percent_decode(path);
if (opt_query) {
opt_query = percent_decode(*opt_query);
}
if (opt_fragment) {
opt_fragment = percent_decode(*opt_fragment);
}
return uri_t{opt_scheme,
opt_userinfo,
opt_host,
opt_port,
path,
opt_query,
opt_fragment};
}
} // namespace arc::uri

37
arc/uri/version.hxx.in Normal file
View File

@ -0,0 +1,37 @@
#ifndef arc__uri__export_hxx_
#define arc__uri__export_hxx_
// The numeric version format is AAAAABBBBBCCCCCDDDE where:
//
// AAAAA - major version number
// BBBBB - minor version number
// CCCCC - bugfix version number
// DDD - alpha / beta (DDD + 500) version number
// E - final (0) / snapshot (1)
//
// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example:
//
// Version AAAAABBBBBCCCCCDDDE
//
// 0.1.0 0000000001000000000
// 0.1.2 0000000001000020000
// 1.2.3 0000100002000030000
// 2.2.0-a.1 0000200001999990010
// 3.0.0-b.2 0000299999999995020
// 2.2.0-a.1.z 0000200001999990011
//
#define LIBARC_URI_VERSION $libarc_uri.version.project_number$ULL
#define LIBARC_URI_VERSION_STR "$libarc_uri.version.project$"
#define LIBARC_URI_VERSION_ID "$libarc_uri.version.project_id$"
#define LIBARC_URI_VERSION_FULL "$libarc_uri.version$"
#define LIBARC_URI_VERSION_MAJOR $libarc_uri.version.major$
#define LIBARC_URI_VERSION_MINOR $libarc_uri.version.minor$
#define LIBARC_URI_VERSION_PATCH $libarc_uri.version.patch$
#define LIBARC_URI_PRE_RELEASE $libarc_uri.version.pre_release$
#define LIBARC_URI_SNAPSHOT_SN $libarc_uri.version.snapshot_sn$ULL
#define LIBARC_URI_SNAPSHOT_ID "$libarc_uri.version.snapshot_id$"
#endif

4
build/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/config.build
/root/
/bootstrap/
build/

7
build/bootstrap.build Normal file
View File

@ -0,0 +1,7 @@
project = libarc-uri
using version
using config
using test
using install
using dist

6
build/export.build Normal file
View File

@ -0,0 +1,6 @@
$out_root/
{
include arc/uri/
}
export $out_root/arc/uri/$import.target

16
build/root.build Normal file
View File

@ -0,0 +1,16 @@
# Uncomment to suppress warnings coming from external libraries.
#
#cxx.internal.scope = current
cxx.std = latest
using cxx
hxx{*}: extension = hxx
ixx{*}: extension = ixx
txx{*}: extension = txx
cxx{*}: extension = cxx
# The test target for cross-testing (running tests under Wine, etc).
#
test.target = $cxx.target

30
buildfile Normal file
View File

@ -0,0 +1,30 @@
./: {arc/} doc{README.md} legal{LICENSE} manifest
import? doxygen = doxygen%exe{doxygen}
alias{all}: arc/
if ($doxygen != [null])
{
./: file{Doxyfile}: in{Doxyfile} $src_root/manifest
{
in.symbol = '@'
in.mode = lax
backlink = copy
SUMMARY = $project.summary
}
alias{api-reference}: file{Doxyfile} $doxygen fsdir{docs/api-reference}
{{
i = $path($<[0])
diag doxygen $i
env --cwd $directory($i) -- $doxygen $leaf($i)
}}
alias{all}: alias{api-reference}
}
# Don't install tests.
#
tests/: install = false

39
docs/introduction.md Normal file
View File

@ -0,0 +1,39 @@
# Introduction
[TOC]
libarc-uri is a library for parsing and manipulating Unique Resource Identifiers.
## Getting Started
libarc-uri uses the [build2][build2] build system, which is also the
only officially supported build system.
### 1. repositories.manifest
To get started, first add the libarc-uri repository to your
`repositories.manifest` file:
```
:
role: prerequisite
location: https://code.helloryan.se/arc/libarc-uri.git##HEAD
```
### 2. manifest
Then add `libarc-uri` as a dependency to your `manifest`-file:
```
depends: libarc-uri ^0.1.0-
```
### 3. buildfile
Finally, import and link your binaries with `libarc-uri`:
```
import libs =+ libarc-uri%lib{arc-uri}
```
[build2]: https://build2.org/

11
manifest Normal file
View File

@ -0,0 +1,11 @@
: 1
name: libarc-uri
version: 0.1.0-a.0.z
language: c++
summary: arc-uri C++ library
license: APSL-1.0 ; Arc Project Software License version 1.0
description-file: README.md
url: https://www.helloryan.se/arc-project/
email: arc-project@helloryan.se
depends: * build2 >= 0.17.0
depends: * bpkg >= 0.17.0

7
repositories.manifest Normal file
View File

@ -0,0 +1,7 @@
: 1
summary: libarc-uri project repository
:
role: prerequisite
location: https://pkg.cppget.org/1/beta
trust: 70:64:FE:E4:E0:F3:60:F1:B4:51:E1:FA:12:5C:E0:B3:DB:DF:96:33:39:B9:2E:E5:C2:68:63:4C:A6:47:39:43

8
tests/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Test executables.
#
driver
# Testscript output directories (can be symlinks).
#
test
test-*

4
tests/build/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/config.build
/root/
/bootstrap/
build/

View File

@ -0,0 +1,5 @@
project = # Unnamed tests subproject.
using config
using test
using dist

16
tests/build/root.build Normal file
View File

@ -0,0 +1,16 @@
cxx.std = latest
using cxx
hxx{*}: extension = hxx
ixx{*}: extension = ixx
txx{*}: extension = txx
cxx{*}: extension = cxx
# Every exe{} in this subproject is by default a test.
#
exe{*}: test = true
# The test target for cross-testing (running tests under Wine, etc).
#
test.target = $cxx.target

1
tests/buildfile Normal file
View File

@ -0,0 +1 @@
./: {*/ -build/}