mirror of https://github.com/trapexit/mergerfs.git
Browse Source
config: rework global config, remove rwlock, make branches RCU like
config: rework global config, remove rwlock, make branches RCU like
Also added unit tests. Should have done separately but found a number of bugs.pull/865/head
Antonio SJ Musumeci
4 years ago
327 changed files with 6646 additions and 2991 deletions
-
2LICENSE
-
32Makefile
-
366src/branch.cpp
-
67src/branch.hpp
-
429src/branches.cpp
-
94src/branches.hpp
-
49src/category.cpp
-
93src/category.hpp
-
228src/config.cpp
-
98src/config.hpp
-
1src/config_cachefiles.hpp
-
1src/config_inodecalc.cpp
-
5src/config_inodecalc.hpp
-
9src/config_moveonenospc.cpp
-
14src/config_moveonenospc.hpp
-
1src/config_nfsopenhack.cpp
-
1src/config_nfsopenhack.hpp
-
1src/config_readdir.cpp
-
1src/config_readdir.hpp
-
1src/config_statfs.cpp
-
1src/config_statfs.hpp
-
1src/config_statfsignore.cpp
-
1src/config_xattr.cpp
-
1src/config_xattr.hpp
-
1src/dirinfo.hpp
-
1src/endian.hpp
-
1src/enum.hpp
-
1src/fh.hpp
-
1src/fileinfo.hpp
-
4src/fixed_mem_pool.hpp
-
17src/from_string.cpp
-
2src/from_string.hpp
-
1src/fs_acl.cpp
-
1src/fs_acl.hpp
-
1src/fs_attr.hpp
-
1src/fs_attr_linux.icpp
-
1src/fs_attr_unsupported.icpp
-
1src/fs_clonefile.cpp
-
1src/fs_clonefile.hpp
-
5src/fs_clonepath.cpp
-
1src/fs_clonepath.hpp
-
1src/fs_close.hpp
-
1src/fs_closedir.hpp
-
4src/fs_copy_file_range.hpp
-
4src/fs_copy_file_range_linux.icpp
-
4src/fs_copy_file_range_unsupported.icpp
-
1src/fs_copydata.cpp
-
1src/fs_copydata.hpp
-
3src/fs_copydata_copy_file_range.cpp
-
3src/fs_copydata_copy_file_range.hpp
-
1src/fs_copydata_readwrite.cpp
-
1src/fs_copydata_readwrite.hpp
-
1src/fs_cow.cpp
-
1src/fs_cow.hpp
-
1src/fs_devid.hpp
-
1src/fs_dirfd.hpp
-
1src/fs_dup.hpp
-
1src/fs_eaccess.hpp
-
1src/fs_exists.hpp
-
1src/fs_faccessat.hpp
-
1src/fs_fadvise.hpp
-
1src/fs_fadvise_posix.icpp
-
1src/fs_fadvise_unsupported.icpp
-
1src/fs_fallocate.hpp
-
1src/fs_fallocate_linux.icpp
-
3src/fs_fallocate_osx.icpp
-
1src/fs_fallocate_posix.icpp
-
1src/fs_fallocate_unsupported.icpp
-
1src/fs_fchmod.hpp
-
1src/fs_fchmodat.hpp
-
1src/fs_fchown.hpp
-
1src/fs_fdatasync.hpp
-
1src/fs_fgetxattr.hpp
-
1src/fs_ficlone.hpp
-
1src/fs_ficlone_linux.icpp
-
1src/fs_ficlone_unsupported.icpp
-
3src/fs_file_size.cpp
-
3src/fs_file_size.hpp
-
1src/fs_findallfiles.cpp
-
9src/fs_findallfiles.hpp
-
32src/fs_findonfs.cpp
-
11src/fs_findonfs.hpp
-
1src/fs_flistxattr.hpp
-
1src/fs_flock.hpp
-
1src/fs_fsetxattr.hpp
-
1src/fs_fstat.hpp
-
1src/fs_fstatat.hpp
-
1src/fs_fsync.hpp
-
1src/fs_ftruncate.hpp
-
1src/fs_futimens.hpp
-
1src/fs_futimens_freebsd_11.hpp
-
1src/fs_futimens_generic.hpp
-
1src/fs_futimens_linux.hpp
-
1src/fs_futimesat.hpp
-
1src/fs_futimesat_generic.icpp
-
1src/fs_futimesat_osx.icpp
-
1src/fs_getdents64.cpp
-
1src/fs_getdents64.hpp
-
1src/fs_getfl.cpp
-
1src/fs_getfl.hpp
@ -0,0 +1,429 @@ |
|||||
|
/*
|
||||
|
ISC License |
||||
|
|
||||
|
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "branches.hpp"
|
||||
|
#include "ef.hpp"
|
||||
|
#include "errno.hpp"
|
||||
|
#include "from_string.hpp"
|
||||
|
#include "fs_glob.hpp"
|
||||
|
#include "fs_realpathize.hpp"
|
||||
|
#include "nonstd/optional.hpp"
|
||||
|
#include "num.hpp"
|
||||
|
#include "str.hpp"
|
||||
|
|
||||
|
#include <string>
|
||||
|
|
||||
|
#include <fnmatch.h>
|
||||
|
|
||||
|
using std::string; |
||||
|
using std::vector; |
||||
|
using nonstd::optional; |
||||
|
|
||||
|
|
||||
|
Branches::Impl::Impl(const uint64_t &default_minfreespace_) |
||||
|
: _default_minfreespace(default_minfreespace_) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
Branches::Impl& |
||||
|
Branches::Impl::operator=(Branches::Impl &rval_) |
||||
|
{ |
||||
|
auto this_base = dynamic_cast<Branch::Vector*>(this); |
||||
|
auto rval_base = dynamic_cast<Branch::Vector*>(&rval_); |
||||
|
|
||||
|
*this_base = *rval_base; |
||||
|
|
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
Branches::Impl& |
||||
|
Branches::Impl::operator=(Branches::Impl &&rval_) |
||||
|
{ |
||||
|
auto this_base = dynamic_cast<Branch::Vector*>(this); |
||||
|
auto rval_base = dynamic_cast<Branch::Vector*>(&rval_); |
||||
|
|
||||
|
*this_base = std::move(*rval_base); |
||||
|
|
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
const |
||||
|
uint64_t& |
||||
|
Branches::Impl::minfreespace(void) const |
||||
|
{ |
||||
|
return _default_minfreespace; |
||||
|
} |
||||
|
|
||||
|
namespace l |
||||
|
{ |
||||
|
static |
||||
|
void |
||||
|
split(const std::string &s_, |
||||
|
std::string *instr_, |
||||
|
std::string *values_) |
||||
|
{ |
||||
|
uint64_t offset; |
||||
|
|
||||
|
offset = s_.find_first_of('/'); |
||||
|
*instr_ = s_.substr(0,offset); |
||||
|
if(offset != std::string::npos) |
||||
|
*values_ = s_.substr(offset); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
parse_mode(const string &str_, |
||||
|
Branch::Mode *mode_) |
||||
|
{ |
||||
|
if(str_ == "RW") |
||||
|
*mode_ = Branch::Mode::RW; |
||||
|
ef(str_ == "RO") |
||||
|
*mode_ = Branch::Mode::RO; |
||||
|
ef(str_ == "NC") |
||||
|
*mode_ = Branch::Mode::NC; |
||||
|
else |
||||
|
return -EINVAL; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
parse_minfreespace(const string &str_, |
||||
|
optional<uint64_t> *minfreespace_) |
||||
|
{ |
||||
|
int rv; |
||||
|
uint64_t uint64; |
||||
|
|
||||
|
rv = str::from(str_,&uint64); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
*minfreespace_ = uint64; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
parse_branch(const string &str_, |
||||
|
string *glob_, |
||||
|
Branch::Mode *mode_, |
||||
|
optional<uint64_t> *minfreespace_) |
||||
|
{ |
||||
|
int rv; |
||||
|
string options; |
||||
|
vector<string> v; |
||||
|
|
||||
|
str::rsplit1(str_,'=',&v); |
||||
|
switch(v.size()) |
||||
|
{ |
||||
|
case 1: |
||||
|
*glob_ = v[0]; |
||||
|
*mode_ = Branch::Mode::RW; |
||||
|
break; |
||||
|
case 2: |
||||
|
*glob_ = v[0]; |
||||
|
options = v[1]; |
||||
|
v.clear(); |
||||
|
str::split(options,',',&v); |
||||
|
switch(v.size()) |
||||
|
{ |
||||
|
case 2: |
||||
|
rv = l::parse_minfreespace(v[1],minfreespace_); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
case 1: |
||||
|
rv = l::parse_mode(v[0],mode_); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
break; |
||||
|
case 0: |
||||
|
return -EINVAL; |
||||
|
} |
||||
|
break; |
||||
|
default: |
||||
|
return -EINVAL; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
parse(const string &str_, |
||||
|
Branches::Impl *branches_) |
||||
|
{ |
||||
|
int rv; |
||||
|
string glob; |
||||
|
StrVec paths; |
||||
|
optional<uint64_t> minfreespace; |
||||
|
Branch branch(branches_->minfreespace()); |
||||
|
|
||||
|
rv = l::parse_branch(str_,&glob,&branch.mode,&minfreespace); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
if(minfreespace.has_value()) |
||||
|
branch.set_minfreespace(minfreespace.value()); |
||||
|
|
||||
|
fs::glob(glob,&paths); |
||||
|
fs::realpathize(&paths); |
||||
|
for(auto &path : paths) |
||||
|
{ |
||||
|
branch.path = path; |
||||
|
branches_->push_back(branch); |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
set(const std::string &str_, |
||||
|
Branches::Impl *branches_) |
||||
|
{ |
||||
|
int rv; |
||||
|
StrVec paths; |
||||
|
Branches::Impl tmp_branches(branches_->minfreespace()); |
||||
|
|
||||
|
str::split(str_,':',&paths); |
||||
|
for(auto &path : paths) |
||||
|
{ |
||||
|
rv = l::parse(path,&tmp_branches); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
} |
||||
|
|
||||
|
*branches_ = std::move(tmp_branches); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
add_begin(const std::string &str_, |
||||
|
Branches::Impl *branches_) |
||||
|
{ |
||||
|
int rv; |
||||
|
vector<string> paths; |
||||
|
Branches::Impl tmp_branches(branches_->minfreespace()); |
||||
|
|
||||
|
str::split(str_,':',&paths); |
||||
|
for(auto &path : paths) |
||||
|
{ |
||||
|
rv = l::parse(path,&tmp_branches); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
} |
||||
|
|
||||
|
branches_->insert(branches_->begin(), |
||||
|
tmp_branches.begin(), |
||||
|
tmp_branches.end()); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
add_end(const std::string &str_, |
||||
|
Branches::Impl *branches_) |
||||
|
{ |
||||
|
int rv; |
||||
|
StrVec paths; |
||||
|
Branches::Impl tmp_branches(branches_->minfreespace()); |
||||
|
|
||||
|
str::split(str_,':',&paths); |
||||
|
for(auto &path : paths) |
||||
|
{ |
||||
|
rv = l::parse(path,&tmp_branches); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
} |
||||
|
|
||||
|
branches_->insert(branches_->end(), |
||||
|
tmp_branches.begin(), |
||||
|
tmp_branches.end()); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
erase_begin(Branches::Impl *branches_) |
||||
|
{ |
||||
|
branches_->erase(branches_->begin()); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
erase_end(Branches::Impl *branches_) |
||||
|
{ |
||||
|
branches_->pop_back(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
erase_fnmatch(const std::string &str_, |
||||
|
Branches::Impl *branches_) |
||||
|
{ |
||||
|
StrVec patterns; |
||||
|
|
||||
|
str::split(str_,':',&patterns); |
||||
|
for(auto i = branches_->begin(); i != branches_->end();) |
||||
|
{ |
||||
|
int match = FNM_NOMATCH; |
||||
|
|
||||
|
for(auto pi = patterns.cbegin(); pi != patterns.cend() && match != 0; ++pi) |
||||
|
{ |
||||
|
match = ::fnmatch(pi->c_str(),i->path.c_str(),0); |
||||
|
} |
||||
|
|
||||
|
i = ((match == 0) ? branches_->erase(i) : (i+1)); |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
Branches::Impl::from_string(const std::string &s_) |
||||
|
{ |
||||
|
std::string instr; |
||||
|
std::string values; |
||||
|
|
||||
|
l::split(s_,&instr,&values); |
||||
|
|
||||
|
if(instr == "+") |
||||
|
return l::add_end(values,this); |
||||
|
if(instr == "+<") |
||||
|
return l::add_begin(values,this); |
||||
|
if(instr == "+>") |
||||
|
return l::add_end(values,this); |
||||
|
if(instr == "-") |
||||
|
return l::erase_fnmatch(values,this); |
||||
|
if(instr == "-<") |
||||
|
return l::erase_begin(this); |
||||
|
if(instr == "->") |
||||
|
return l::erase_end(this); |
||||
|
if(instr == "=") |
||||
|
return l::set(values,this); |
||||
|
if(instr.empty()) |
||||
|
return l::set(values,this); |
||||
|
|
||||
|
return -EINVAL; |
||||
|
} |
||||
|
|
||||
|
std::string |
||||
|
Branches::Impl::to_string(void) const |
||||
|
{ |
||||
|
string tmp; |
||||
|
|
||||
|
if(empty()) |
||||
|
return tmp; |
||||
|
|
||||
|
for(auto &branch : *this) |
||||
|
{ |
||||
|
tmp += branch.to_string(); |
||||
|
tmp += ':'; |
||||
|
} |
||||
|
|
||||
|
tmp.pop_back(); |
||||
|
|
||||
|
return tmp; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Branches::Impl::to_paths(StrVec &paths_) const |
||||
|
{ |
||||
|
for(auto &branch : *this) |
||||
|
{ |
||||
|
paths_.push_back(branch.path); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
Branches::from_string(const std::string &str_) |
||||
|
{ |
||||
|
int rv; |
||||
|
Branches::Ptr impl; |
||||
|
Branches::Ptr new_impl; |
||||
|
|
||||
|
{ |
||||
|
std::lock_guard<std::mutex> lock_guard(_mutex); |
||||
|
impl = _impl; |
||||
|
} |
||||
|
|
||||
|
new_impl = std::make_shared<Branches::Impl>(impl->minfreespace()); |
||||
|
*new_impl = *impl; |
||||
|
|
||||
|
rv = new_impl->from_string(str_); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
{ |
||||
|
std::lock_guard<std::mutex> lock_guard(_mutex); |
||||
|
_impl = new_impl; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
string |
||||
|
Branches::to_string(void) const |
||||
|
{ |
||||
|
std::lock_guard<std::mutex> lock_guard(_mutex); |
||||
|
|
||||
|
return _impl->to_string(); |
||||
|
} |
||||
|
|
||||
|
SrcMounts::SrcMounts(Branches &b_) |
||||
|
: _branches(b_) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
int |
||||
|
SrcMounts::from_string(const std::string &s_) |
||||
|
{ |
||||
|
return _branches.from_string(s_); |
||||
|
} |
||||
|
|
||||
|
std::string |
||||
|
SrcMounts::to_string(void) const |
||||
|
{ |
||||
|
std::string rv; |
||||
|
Branches::CPtr branches = _branches; |
||||
|
|
||||
|
if(branches->empty()) |
||||
|
return rv; |
||||
|
|
||||
|
for(const auto &branch : *branches) |
||||
|
{ |
||||
|
rv += branch.path; |
||||
|
rv += ':'; |
||||
|
} |
||||
|
|
||||
|
rv.pop_back(); |
||||
|
|
||||
|
return rv; |
||||
|
} |
@ -0,0 +1,94 @@ |
|||||
|
/*
|
||||
|
ISC License |
||||
|
|
||||
|
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once
|
||||
|
|
||||
|
#include "branch.hpp"
|
||||
|
#include "nonstd/optional.hpp"
|
||||
|
#include "strvec.hpp"
|
||||
|
#include "tofrom_string.hpp"
|
||||
|
|
||||
|
#include <cstdint>
|
||||
|
#include <memory>
|
||||
|
#include <mutex>
|
||||
|
#include <string>
|
||||
|
#include <vector>
|
||||
|
|
||||
|
|
||||
|
class Branches final : public ToFromString |
||||
|
{ |
||||
|
public: |
||||
|
class Impl final : public ToFromString, public Branch::Vector |
||||
|
{ |
||||
|
public: |
||||
|
typedef std::shared_ptr<Impl> Ptr; |
||||
|
typedef std::shared_ptr<const Impl> CPtr; |
||||
|
|
||||
|
public: |
||||
|
Impl(const uint64_t &default_minfreespace_); |
||||
|
|
||||
|
public: |
||||
|
int from_string(const std::string &str) final; |
||||
|
std::string to_string(void) const final; |
||||
|
|
||||
|
public: |
||||
|
const uint64_t& minfreespace(void) const; |
||||
|
void to_paths(StrVec &strvec) const; |
||||
|
|
||||
|
public: |
||||
|
Impl& operator=(Impl &impl_); |
||||
|
Impl& operator=(Impl &&impl_); |
||||
|
|
||||
|
private: |
||||
|
const uint64_t &_default_minfreespace; |
||||
|
}; |
||||
|
|
||||
|
public: |
||||
|
typedef Branches::Impl::Ptr Ptr; |
||||
|
typedef Branches::Impl::CPtr CPtr; |
||||
|
|
||||
|
public: |
||||
|
Branches(const uint64_t &default_minfreespace_) |
||||
|
: _impl(std::make_shared<Impl>(default_minfreespace_)) |
||||
|
{} |
||||
|
|
||||
|
public: |
||||
|
int from_string(const std::string &str) final; |
||||
|
std::string to_string(void) const final; |
||||
|
|
||||
|
public: |
||||
|
operator CPtr() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; } |
||||
|
CPtr operator->() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; } |
||||
|
|
||||
|
private: |
||||
|
mutable std::mutex _mutex; |
||||
|
Ptr _impl; |
||||
|
}; |
||||
|
|
||||
|
class SrcMounts : public ToFromString |
||||
|
{ |
||||
|
public: |
||||
|
SrcMounts(Branches &b_); |
||||
|
|
||||
|
public: |
||||
|
int from_string(const std::string &str) final; |
||||
|
std::string to_string(void) const final; |
||||
|
|
||||
|
private: |
||||
|
Branches &_branches; |
||||
|
}; |
@ -0,0 +1,49 @@ |
|||||
|
/*
|
||||
|
ISC License |
||||
|
|
||||
|
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "category.hpp"
|
||||
|
#include "errno.hpp"
|
||||
|
#include "str.hpp"
|
||||
|
|
||||
|
#include <string>
|
||||
|
|
||||
|
int |
||||
|
Category::Base::from_string(const std::string &s_) |
||||
|
{ |
||||
|
int rv; |
||||
|
|
||||
|
for(auto func : funcs) |
||||
|
{ |
||||
|
rv = func->from_string(s_); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
std::string |
||||
|
Category::Base::to_string(void) const |
||||
|
{ |
||||
|
std::set<std::string> rv; |
||||
|
|
||||
|
for(auto func : funcs) |
||||
|
rv.insert(func->to_string()); |
||||
|
|
||||
|
return str::join(rv,','); |
||||
|
} |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue