text.cpp revision 275988
1// Copyright (c) 2007 The NetBSD Foundation, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1. Redistributions of source code must retain the above copyright
8//    notice, this list of conditions and the following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright
10//    notice, this list of conditions and the following disclaimer in the
11//    documentation and/or other materials provided with the distribution.
12//
13// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26#include "atf-c++/detail/text.hpp"
27
28extern "C" {
29#include <regex.h>
30}
31
32#include <cctype>
33#include <cstring>
34
35extern "C" {
36#include "atf-c/detail/text.h"
37#include "atf-c/error.h"
38}
39
40#include "atf-c++/detail/exceptions.hpp"
41
42namespace impl = atf::text;
43#define IMPL_NAME "atf::text"
44
45char*
46impl::duplicate(const char* str)
47{
48    char* copy = new char[std::strlen(str) + 1];
49    std::strcpy(copy, str);
50    return copy;
51}
52
53bool
54impl::match(const std::string& str, const std::string& regex)
55{
56    bool found;
57
58    // Special case: regcomp does not like empty regular expressions.
59    if (regex.empty()) {
60        found = str.empty();
61    } else {
62        ::regex_t preg;
63
64        if (::regcomp(&preg, regex.c_str(), REG_EXTENDED) != 0)
65            throw std::runtime_error("Invalid regular expression '" + regex +
66                                     "'");
67
68        const int res = ::regexec(&preg, str.c_str(), 0, NULL, 0);
69        regfree(&preg);
70        if (res != 0 && res != REG_NOMATCH)
71            throw std::runtime_error("Invalid regular expression " + regex);
72
73        found = res == 0;
74    }
75
76    return found;
77}
78
79std::string
80impl::to_lower(const std::string& str)
81{
82    std::string lc;
83    for (std::string::const_iterator iter = str.begin(); iter != str.end();
84         iter++)
85        lc += std::tolower(*iter);
86    return lc;
87}
88
89std::vector< std::string >
90impl::split(const std::string& str, const std::string& delim)
91{
92    std::vector< std::string > words;
93
94    std::string::size_type pos = 0, newpos = 0;
95    while (pos < str.length() && newpos != std::string::npos) {
96        newpos = str.find(delim, pos);
97        if (newpos != pos)
98            words.push_back(str.substr(pos, newpos - pos));
99        pos = newpos + delim.length();
100    }
101
102    return words;
103}
104
105std::string
106impl::trim(const std::string& str)
107{
108    std::string::size_type pos1 = str.find_first_not_of(" \t");
109    std::string::size_type pos2 = str.find_last_not_of(" \t");
110
111    if (pos1 == std::string::npos && pos2 == std::string::npos)
112        return "";
113    else if (pos1 == std::string::npos)
114        return str.substr(0, str.length() - pos2);
115    else if (pos2 == std::string::npos)
116        return str.substr(pos1);
117    else
118        return str.substr(pos1, pos2 - pos1 + 1);
119}
120
121bool
122impl::to_bool(const std::string& str)
123{
124    bool b;
125
126    atf_error_t err = atf_text_to_bool(str.c_str(), &b);
127    if (atf_is_error(err))
128        throw_atf_error(err);
129
130    return b;
131}
132
133int64_t
134impl::to_bytes(std::string str)
135{
136    if (str.empty())
137        throw std::runtime_error("Empty value");
138
139    const char unit = str[str.length() - 1];
140    int64_t multiplier;
141    switch (unit) {
142    case 'k': case 'K': multiplier = 1 << 10; break;
143    case 'm': case 'M': multiplier = 1 << 20; break;
144    case 'g': case 'G': multiplier = 1 << 30; break;
145    case 't': case 'T': multiplier = int64_t(1) << 40; break;
146    default:
147        if (!std::isdigit(unit))
148            throw std::runtime_error(std::string("Unknown size unit '") + unit
149                                     + "'");
150        multiplier = 1;
151    }
152    if (multiplier != 1)
153        str.erase(str.length() - 1);
154
155    return to_type< int64_t >(str) * multiplier;
156}
157