1240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc.
2240116Smarcel// All rights reserved.
3240116Smarcel//
4240116Smarcel// Redistribution and use in source and binary forms, with or without
5240116Smarcel// modification, are permitted provided that the following conditions
6240116Smarcel// are met:
7240116Smarcel// 1. Redistributions of source code must retain the above copyright
8240116Smarcel//    notice, this list of conditions and the following disclaimer.
9240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel//    notice, this list of conditions and the following disclaimer in the
11240116Smarcel//    documentation and/or other materials provided with the distribution.
12240116Smarcel//
13240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25240116Smarcel
26275988Sngie#include "atf-c++/detail/text.hpp"
27275988Sngie
28240116Smarcelextern "C" {
29240116Smarcel#include <regex.h>
30240116Smarcel}
31240116Smarcel
32240116Smarcel#include <cctype>
33240116Smarcel#include <cstring>
34240116Smarcel
35240116Smarcelextern "C" {
36275988Sngie#include "atf-c/detail/text.h"
37275988Sngie#include "atf-c/error.h"
38240116Smarcel}
39240116Smarcel
40275988Sngie#include "atf-c++/detail/exceptions.hpp"
41240116Smarcel
42240116Smarcelnamespace impl = atf::text;
43240116Smarcel#define IMPL_NAME "atf::text"
44240116Smarcel
45240116Smarcelchar*
46240116Smarcelimpl::duplicate(const char* str)
47240116Smarcel{
48240116Smarcel    char* copy = new char[std::strlen(str) + 1];
49240116Smarcel    std::strcpy(copy, str);
50240116Smarcel    return copy;
51240116Smarcel}
52240116Smarcel
53240116Smarcelbool
54240116Smarcelimpl::match(const std::string& str, const std::string& regex)
55240116Smarcel{
56240116Smarcel    bool found;
57240116Smarcel
58240116Smarcel    // Special case: regcomp does not like empty regular expressions.
59240116Smarcel    if (regex.empty()) {
60240116Smarcel        found = str.empty();
61240116Smarcel    } else {
62240116Smarcel        ::regex_t preg;
63240116Smarcel
64240116Smarcel        if (::regcomp(&preg, regex.c_str(), REG_EXTENDED) != 0)
65240116Smarcel            throw std::runtime_error("Invalid regular expression '" + regex +
66240116Smarcel                                     "'");
67240116Smarcel
68240116Smarcel        const int res = ::regexec(&preg, str.c_str(), 0, NULL, 0);
69240116Smarcel        regfree(&preg);
70240116Smarcel        if (res != 0 && res != REG_NOMATCH)
71240116Smarcel            throw std::runtime_error("Invalid regular expression " + regex);
72240116Smarcel
73240116Smarcel        found = res == 0;
74240116Smarcel    }
75240116Smarcel
76240116Smarcel    return found;
77240116Smarcel}
78240116Smarcel
79240116Smarcelstd::string
80240116Smarcelimpl::to_lower(const std::string& str)
81240116Smarcel{
82240116Smarcel    std::string lc;
83240116Smarcel    for (std::string::const_iterator iter = str.begin(); iter != str.end();
84240116Smarcel         iter++)
85240116Smarcel        lc += std::tolower(*iter);
86240116Smarcel    return lc;
87240116Smarcel}
88240116Smarcel
89240116Smarcelstd::vector< std::string >
90240116Smarcelimpl::split(const std::string& str, const std::string& delim)
91240116Smarcel{
92240116Smarcel    std::vector< std::string > words;
93240116Smarcel
94240116Smarcel    std::string::size_type pos = 0, newpos = 0;
95240116Smarcel    while (pos < str.length() && newpos != std::string::npos) {
96240116Smarcel        newpos = str.find(delim, pos);
97240116Smarcel        if (newpos != pos)
98240116Smarcel            words.push_back(str.substr(pos, newpos - pos));
99240116Smarcel        pos = newpos + delim.length();
100240116Smarcel    }
101240116Smarcel
102240116Smarcel    return words;
103240116Smarcel}
104240116Smarcel
105240116Smarcelstd::string
106240116Smarcelimpl::trim(const std::string& str)
107240116Smarcel{
108240116Smarcel    std::string::size_type pos1 = str.find_first_not_of(" \t");
109240116Smarcel    std::string::size_type pos2 = str.find_last_not_of(" \t");
110240116Smarcel
111240116Smarcel    if (pos1 == std::string::npos && pos2 == std::string::npos)
112240116Smarcel        return "";
113240116Smarcel    else if (pos1 == std::string::npos)
114240116Smarcel        return str.substr(0, str.length() - pos2);
115240116Smarcel    else if (pos2 == std::string::npos)
116240116Smarcel        return str.substr(pos1);
117240116Smarcel    else
118240116Smarcel        return str.substr(pos1, pos2 - pos1 + 1);
119240116Smarcel}
120240116Smarcel
121240116Smarcelbool
122240116Smarcelimpl::to_bool(const std::string& str)
123240116Smarcel{
124240116Smarcel    bool b;
125240116Smarcel
126240116Smarcel    atf_error_t err = atf_text_to_bool(str.c_str(), &b);
127240116Smarcel    if (atf_is_error(err))
128240116Smarcel        throw_atf_error(err);
129240116Smarcel
130240116Smarcel    return b;
131240116Smarcel}
132240116Smarcel
133240116Smarcelint64_t
134240116Smarcelimpl::to_bytes(std::string str)
135240116Smarcel{
136240116Smarcel    if (str.empty())
137240116Smarcel        throw std::runtime_error("Empty value");
138240116Smarcel
139240116Smarcel    const char unit = str[str.length() - 1];
140240116Smarcel    int64_t multiplier;
141240116Smarcel    switch (unit) {
142240116Smarcel    case 'k': case 'K': multiplier = 1 << 10; break;
143240116Smarcel    case 'm': case 'M': multiplier = 1 << 20; break;
144240116Smarcel    case 'g': case 'G': multiplier = 1 << 30; break;
145240116Smarcel    case 't': case 'T': multiplier = int64_t(1) << 40; break;
146240116Smarcel    default:
147240116Smarcel        if (!std::isdigit(unit))
148240116Smarcel            throw std::runtime_error(std::string("Unknown size unit '") + unit
149240116Smarcel                                     + "'");
150240116Smarcel        multiplier = 1;
151240116Smarcel    }
152240116Smarcel    if (multiplier != 1)
153240116Smarcel        str.erase(str.length() - 1);
154240116Smarcel
155240116Smarcel    return to_type< int64_t >(str) * multiplier;
156240116Smarcel}
157