mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-06-26 10:54:28 +02:00
Common: Removed src/common
- This code is now relocated to common.git, and included via CMake's ExternalProject command.
This commit is contained in:
parent
77f51a41bd
commit
2d420397f9
20 changed files with 0 additions and 3690 deletions
1
src/common/.gitignore
vendored
1
src/common/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
libcommon.a
|
|
@ -1,21 +0,0 @@
|
|||
cmake_minimum_required (VERSION 2.8)
|
||||
include_directories (${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src/common
|
||||
${TIMEW_INCLUDE_DIRS})
|
||||
|
||||
set (common_SRCS Color.cpp Color.h
|
||||
FS.cpp FS.h
|
||||
RX.cpp RX.h
|
||||
Table.cpp Table.h
|
||||
Timer.cpp Timer.h
|
||||
text.cpp text.h
|
||||
unicode.cpp unicode.h
|
||||
utf8.cpp utf8.h
|
||||
wcwidth6.cpp)
|
||||
|
||||
add_library (common STATIC ${common_SRCS})
|
||||
|
||||
#SET(CMAKE_BUILD_TYPE gcov)
|
||||
#SET(CMAKE_CXX_FLAGS_GCOV "--coverage")
|
||||
#SET(CMAKE_C_FLAGS_GCOV "--coverage")
|
||||
#SET(CMAKE_EXE_LINKER_FLAGS_GCOV "--coverage")
|
|
@ -1,599 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <Color.h>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
//#include <Lexer.h>
|
||||
#include <text.h>
|
||||
|
||||
// uint to string lookup table for Color::_colorize()
|
||||
// _colorize() gets called _a lot_, having this lookup table is a cheap
|
||||
// performance optimization.
|
||||
const char *colorstring[] = {
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
|
||||
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
|
||||
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
|
||||
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
|
||||
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
|
||||
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
|
||||
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
|
||||
"100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
|
||||
"110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
|
||||
"120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
|
||||
"130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
|
||||
"140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
|
||||
"150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
|
||||
"160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
|
||||
"170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
|
||||
"180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
|
||||
"190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
|
||||
"200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
|
||||
"210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
|
||||
"220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
|
||||
"230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
|
||||
"240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
|
||||
"250", "251", "252", "253", "254", "255"
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static struct
|
||||
{
|
||||
Color::color_id id;
|
||||
std::string english_name;
|
||||
int index; // offset red=3 (therefore fg=33, bg=43)
|
||||
} allColors[] =
|
||||
{
|
||||
// Color.h enum English Index
|
||||
{ Color::nocolor, "none", 0},
|
||||
{ Color::black, "black", 1}, // fg 29+0 bg 39+0
|
||||
{ Color::red, "red", 2},
|
||||
{ Color::green, "green", 3},
|
||||
{ Color::yellow, "yellow", 4},
|
||||
{ Color::blue, "blue", 5},
|
||||
{ Color::magenta, "magenta", 6},
|
||||
{ Color::cyan, "cyan", 7},
|
||||
{ Color::white, "white", 8},
|
||||
|
||||
};
|
||||
|
||||
#define NUM_COLORS (sizeof (allColors) / sizeof (allColors[0]))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color::Color ()
|
||||
: _value (0)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color::Color (const Color& other)
|
||||
{
|
||||
_value = other._value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color::Color (unsigned int c)
|
||||
: _value (0)
|
||||
{
|
||||
if (!(c & _COLOR_HASFG)) _value &= ~_COLOR_FG;
|
||||
if (!(c & _COLOR_HASBG)) _value &= ~_COLOR_BG;
|
||||
|
||||
_value = c & (_COLOR_256 | _COLOR_HASBG | _COLOR_HASFG |_COLOR_UNDERLINE |
|
||||
_COLOR_INVERSE | _COLOR_BOLD | _COLOR_BRIGHT | _COLOR_BG |
|
||||
_COLOR_FG);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Supports the following constructs:
|
||||
// [bright] [color] [on color] [bright] [underline]
|
||||
//
|
||||
// Where [color] is one of:
|
||||
// black
|
||||
// red
|
||||
// ...
|
||||
// grayN 0 <= N <= 23 fg 38;5;232 + N bg 48;5;232 + N
|
||||
// greyN 0 <= N <= 23 fg 38;5;232 + N bg 48;5;232 + N
|
||||
// colorN 0 <= N <= 255 fg 38;5;N bg 48;5;N
|
||||
// rgbRGB 0 <= R,G,B <= 5 fg 38;5;16 + R*36 + G*6 + B bg 48;5;16 + R*36 + G*6 + B
|
||||
Color::Color (const std::string& spec)
|
||||
: _value (0)
|
||||
{
|
||||
// Split spec into words.
|
||||
auto words = split (spec, ' ');
|
||||
|
||||
// Construct the color as two separate colors, then blend them later. This
|
||||
// make it possible to declare a color such as "color1 on black", and have
|
||||
// the upgrade work properly.
|
||||
unsigned int fg_value = 0;
|
||||
unsigned int bg_value = 0;
|
||||
|
||||
bool bg = false;
|
||||
int index;
|
||||
for (auto& word : words)
|
||||
{
|
||||
// word = Lexer::lowerCase (Lexer::trim (word));
|
||||
|
||||
if (word == "bold") fg_value |= _COLOR_BOLD;
|
||||
else if (word == "bright") bg_value |= _COLOR_BRIGHT;
|
||||
else if (word == "underline") fg_value |= _COLOR_UNDERLINE;
|
||||
else if (word == "inverse") fg_value |= _COLOR_INVERSE;
|
||||
else if (word == "on") bg = true;
|
||||
|
||||
// X where X is one of black, red, blue ...
|
||||
else if ((index = find (word)) != -1)
|
||||
{
|
||||
if (index)
|
||||
{
|
||||
if (bg)
|
||||
{
|
||||
bg_value |= _COLOR_HASBG;
|
||||
bg_value |= index << 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg_value |= _COLOR_HASFG;
|
||||
fg_value |= index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// greyN/grayN, where 0 <= N <= 23.
|
||||
else if (! word.compare (0, 4, "grey", 4) ||
|
||||
! word.compare (0, 4, "gray", 4))
|
||||
{
|
||||
index = strtol (word.substr (4).c_str (), NULL, 10);
|
||||
if (index < 0 || index > 23)
|
||||
throw format ("The color '{1}' is not recognized.", word);
|
||||
|
||||
if (bg)
|
||||
{
|
||||
bg_value |= _COLOR_HASBG;
|
||||
bg_value |= (index + 232) << 8;
|
||||
bg_value |= _COLOR_256;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg_value |= _COLOR_HASFG;
|
||||
fg_value |= index + 232;
|
||||
fg_value |= _COLOR_256;
|
||||
}
|
||||
}
|
||||
|
||||
// rgbRGB, where 0 <= R,G,B <= 5.
|
||||
else if (! word.compare (0, 3, "rgb", 3))
|
||||
{
|
||||
index = strtol (word.substr (3).c_str (), NULL, 10);
|
||||
if (word.length () != 6 ||
|
||||
index < 0 || index > 555)
|
||||
throw format ("The color '{1}' is not recognized.", word);
|
||||
|
||||
int r = strtol (word.substr (3, 1).c_str (), NULL, 10);
|
||||
int g = strtol (word.substr (4, 1).c_str (), NULL, 10);
|
||||
int b = strtol (word.substr (5, 1).c_str (), NULL, 10);
|
||||
if (r < 0 || r > 5 ||
|
||||
g < 0 || g > 5 ||
|
||||
b < 0 || b > 5)
|
||||
throw format ("The color '{1}' is not recognized.", word);
|
||||
|
||||
index = 16 + r*36 + g*6 + b;
|
||||
|
||||
if (bg)
|
||||
{
|
||||
bg_value |= _COLOR_HASBG;
|
||||
bg_value |= index << 8;
|
||||
bg_value |= _COLOR_256;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg_value |= _COLOR_HASFG;
|
||||
fg_value |= index;
|
||||
fg_value |= _COLOR_256;
|
||||
}
|
||||
}
|
||||
|
||||
// colorN, where 0 <= N <= 255.
|
||||
else if (! word.compare (0, 5, "color", 5))
|
||||
{
|
||||
index = strtol (word.substr (5).c_str (), NULL, 10);
|
||||
if (index < 0 || index > 255)
|
||||
throw format ("The color '{1}' is not recognized.", word);
|
||||
|
||||
upgrade ();
|
||||
|
||||
if (bg)
|
||||
{
|
||||
bg_value |= _COLOR_HASBG;
|
||||
bg_value |= index << 8;
|
||||
bg_value |= _COLOR_256;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg_value |= _COLOR_HASFG;
|
||||
fg_value |= index;
|
||||
fg_value |= _COLOR_256;
|
||||
}
|
||||
}
|
||||
else if (word != "")
|
||||
throw format ("The color '{1}' is not recognized.", word);
|
||||
}
|
||||
|
||||
// Now combine the fg and bg into a single color.
|
||||
_value = fg_value;
|
||||
blend (Color (bg_value));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color::Color (color_id fg)
|
||||
: _value (0)
|
||||
{
|
||||
if (fg != Color::nocolor)
|
||||
{
|
||||
_value |= _COLOR_HASFG;
|
||||
_value |= fg;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color::Color (color_id fg, color_id bg, bool underline, bool bold, bool bright)
|
||||
: _value (0)
|
||||
{
|
||||
_value |= ((underline ? 1 : 0) << 18)
|
||||
| ((bold ? 1 : 0) << 17)
|
||||
| ((bright ? 1 : 0) << 16);
|
||||
|
||||
if (bg != Color::nocolor)
|
||||
{
|
||||
_value |= _COLOR_HASBG;
|
||||
_value |= (bg << 8);
|
||||
}
|
||||
|
||||
if (fg != Color::nocolor)
|
||||
{
|
||||
_value |= _COLOR_HASFG;
|
||||
_value |= fg;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color::operator std::string () const
|
||||
{
|
||||
std::string description;
|
||||
if (_value & _COLOR_BOLD) description += "bold";
|
||||
|
||||
if (_value & _COLOR_UNDERLINE)
|
||||
description += std::string (description.length () ? " " : "") + "underline";
|
||||
|
||||
if (_value & _COLOR_INVERSE)
|
||||
description += std::string (description.length () ? " " : "") + "inverse";
|
||||
|
||||
if (_value & _COLOR_HASFG)
|
||||
description += std::string (description.length () ? " " : "") + fg ();
|
||||
|
||||
if (_value & _COLOR_HASBG)
|
||||
{
|
||||
description += std::string (description.length () ? " " : "") + "on";
|
||||
|
||||
if (_value & _COLOR_BRIGHT)
|
||||
description += std::string (description.length () ? " " : "") + "bright";
|
||||
|
||||
description += " " + bg ();
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color::operator int () const
|
||||
{
|
||||
return (int) _value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// If 'other' has styles that are compatible, merge them into this. Colors in
|
||||
// other take precedence.
|
||||
void Color::blend (const Color& other)
|
||||
{
|
||||
if (!other.nontrivial ())
|
||||
return;
|
||||
|
||||
Color c (other);
|
||||
_value |= (c._value & _COLOR_UNDERLINE); // Always inherit underline.
|
||||
_value |= (c._value & _COLOR_INVERSE); // Always inherit inverse.
|
||||
|
||||
// 16 <-- 16.
|
||||
if (!(_value & _COLOR_256) &&
|
||||
!(c._value & _COLOR_256))
|
||||
{
|
||||
_value |= (c._value & _COLOR_BOLD); // Inherit bold.
|
||||
_value |= (c._value & _COLOR_BRIGHT); // Inherit bright.
|
||||
|
||||
if (c._value & _COLOR_HASFG)
|
||||
{
|
||||
_value |= _COLOR_HASFG; // There is now a color.
|
||||
_value &= ~_COLOR_FG; // Remove previous color.
|
||||
_value |= (c._value & _COLOR_FG); // Apply other color.
|
||||
}
|
||||
|
||||
if (c._value & _COLOR_HASBG)
|
||||
{
|
||||
_value |= _COLOR_HASBG; // There is now a color.
|
||||
_value &= ~_COLOR_BG; // Remove previous color.
|
||||
_value |= (c._value & _COLOR_BG); // Apply other color.
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Upgrade either color, if necessary.
|
||||
if (!(_value & _COLOR_256)) upgrade ();
|
||||
if (!(c._value & _COLOR_256)) c.upgrade ();
|
||||
|
||||
// 256 <-- 256.
|
||||
if (c._value & _COLOR_HASFG)
|
||||
{
|
||||
_value |= _COLOR_HASFG; // There is now a color.
|
||||
_value &= ~_COLOR_FG; // Remove previous color.
|
||||
_value |= (c._value & _COLOR_FG); // Apply other color.
|
||||
}
|
||||
|
||||
if (c._value & _COLOR_HASBG)
|
||||
{
|
||||
_value |= _COLOR_HASBG; // There is now a color.
|
||||
_value &= ~_COLOR_BG; // Remove previous color.
|
||||
_value |= (c._value & _COLOR_BG); // Apply other color.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Color::upgrade ()
|
||||
{
|
||||
if (!(_value & _COLOR_256))
|
||||
{
|
||||
if (_value & _COLOR_HASFG)
|
||||
{
|
||||
bool bold = _value & _COLOR_BOLD;
|
||||
unsigned int fg = _value & _COLOR_FG;
|
||||
_value &= ~_COLOR_FG;
|
||||
_value &= ~_COLOR_BOLD;
|
||||
_value |= (bold ? fg + 7 : fg - 1);
|
||||
}
|
||||
|
||||
if (_value & _COLOR_HASBG)
|
||||
{
|
||||
bool bright = _value & _COLOR_BRIGHT;
|
||||
unsigned int bg = (_value & _COLOR_BG) >> 8;
|
||||
_value &= ~_COLOR_BG;
|
||||
_value &= ~_COLOR_BRIGHT;
|
||||
_value |= (bright ? bg + 7 : bg - 1) << 8;
|
||||
}
|
||||
|
||||
_value |= _COLOR_256;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Color::colorize (const std::string& input) const
|
||||
{
|
||||
std::string result;
|
||||
_colorize (result, input);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Sample color codes:
|
||||
// red \033[31m
|
||||
// bold red \033[91m
|
||||
// underline red \033[4;31m
|
||||
// bold underline red \033[1;4;31m
|
||||
//
|
||||
// on red \033[41m
|
||||
// on bright red \033[101m
|
||||
//
|
||||
// 256 fg \033[38;5;Nm
|
||||
// 256 bg \033[48;5;Nm
|
||||
void Color::_colorize (std::string &result, const std::string& input) const
|
||||
{
|
||||
if (!nontrivial ())
|
||||
{
|
||||
result += input;
|
||||
return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
// 256 color
|
||||
if (_value & _COLOR_256)
|
||||
{
|
||||
if (_value & _COLOR_UNDERLINE)
|
||||
result += "\033[4m";
|
||||
|
||||
if (_value & _COLOR_INVERSE)
|
||||
result += "\033[7m";
|
||||
|
||||
if (_value & _COLOR_HASFG)
|
||||
{
|
||||
result += "\033[38;5;";
|
||||
result += colorstring[(_value & _COLOR_FG)];
|
||||
result += "m";
|
||||
}
|
||||
|
||||
if (_value & _COLOR_HASBG)
|
||||
{
|
||||
result += "\033[48;5;";
|
||||
result += colorstring[((_value & _COLOR_BG) >> 8)];
|
||||
result += "m";
|
||||
}
|
||||
|
||||
result += input;
|
||||
result += "\033[0m";
|
||||
}
|
||||
|
||||
// 16 color
|
||||
else
|
||||
{
|
||||
result += "\033[";
|
||||
|
||||
if (_value & _COLOR_BOLD)
|
||||
{
|
||||
if (count++) result += ";";
|
||||
result += "1";
|
||||
}
|
||||
|
||||
if (_value & _COLOR_UNDERLINE)
|
||||
{
|
||||
if (count++) result += ";";
|
||||
result += "4";
|
||||
}
|
||||
|
||||
if (_value & _COLOR_INVERSE)
|
||||
{
|
||||
if (count++) result += ";";
|
||||
result += "7";
|
||||
}
|
||||
|
||||
if (_value & _COLOR_HASFG)
|
||||
{
|
||||
if (count++) result += ";";
|
||||
result += colorstring[(29 + (_value & _COLOR_FG))];
|
||||
}
|
||||
|
||||
if (_value & _COLOR_HASBG)
|
||||
{
|
||||
if (count++) result += ";";
|
||||
result += colorstring[((_value & _COLOR_BRIGHT ? 99 : 39) + ((_value & _COLOR_BG) >> 8))];
|
||||
}
|
||||
|
||||
result += "m";
|
||||
result += input;
|
||||
result += "\033[0m";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Remove color codes from a string.
|
||||
std::string Color::strip (const std::string& input)
|
||||
{
|
||||
int length = input.length ();
|
||||
bool inside = false;
|
||||
std::string output;
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
if (inside)
|
||||
{
|
||||
if (input[i] == 'm')
|
||||
inside = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (input[i] == 033)
|
||||
inside = true;
|
||||
else
|
||||
output += input[i];
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Color::colorize (const std::string& input, const std::string& spec)
|
||||
{
|
||||
Color c (spec);
|
||||
return c.colorize (input);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Color::nontrivial () const
|
||||
{
|
||||
return _value != 0 ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int Color::find (const std::string& input)
|
||||
{
|
||||
for (unsigned int i = 0; i < NUM_COLORS; ++i)
|
||||
if (allColors[i].english_name == input)
|
||||
return (int) i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Color::fg () const
|
||||
{
|
||||
int index = _value & _COLOR_FG;
|
||||
|
||||
if (_value & _COLOR_256)
|
||||
{
|
||||
if (_value & _COLOR_HASFG)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "color" << (_value & _COLOR_FG);
|
||||
return s.str ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < NUM_COLORS; ++i)
|
||||
if (allColors[i].index == index)
|
||||
return allColors[i].english_name;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Color::bg () const
|
||||
{
|
||||
int index = (_value & _COLOR_BG) >> 8;
|
||||
|
||||
if (_value & _COLOR_256)
|
||||
{
|
||||
if (_value & _COLOR_HASBG)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "color" << ((_value & _COLOR_BG) >> 8);
|
||||
return s.str ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < NUM_COLORS; ++i)
|
||||
if (allColors[i].index == index)
|
||||
return allColors[i].english_name;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,77 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_COLOR
|
||||
#define INCLUDED_COLOR
|
||||
|
||||
#include <string>
|
||||
|
||||
#define _COLOR_INVERSE 0x00400000 // Inverse attribute.
|
||||
#define _COLOR_256 0x00200000 // 256-color mode.
|
||||
#define _COLOR_HASBG 0x00100000 // Has background color (all values taken).
|
||||
#define _COLOR_HASFG 0x00080000 // Has foreground color (all values taken).
|
||||
#define _COLOR_UNDERLINE 0x00040000 // General underline attribute.
|
||||
#define _COLOR_BOLD 0x00020000 // 16-color bold attribute.
|
||||
#define _COLOR_BRIGHT 0x00010000 // 16-color bright background attribute.
|
||||
#define _COLOR_BG 0x0000FF00 // 8-bit background color index.
|
||||
#define _COLOR_FG 0x000000FF // 8-bit foreground color index.
|
||||
|
||||
class Color
|
||||
{
|
||||
public:
|
||||
enum color_id {nocolor = 0, black, red, green, yellow, blue, magenta, cyan, white};
|
||||
|
||||
Color ();
|
||||
Color (const Color&);
|
||||
Color (unsigned int); // 256 | INVERSE | UNDERLINE | BOLD | BRIGHT | (BG << 8) | FG
|
||||
Color (const std::string&); // "red on bright black"
|
||||
Color (color_id); // fg.
|
||||
Color (color_id, color_id, bool, bool, bool); // fg, bg, underline, bold, bright
|
||||
operator std::string () const;
|
||||
operator int () const;
|
||||
|
||||
void upgrade ();
|
||||
void blend (const Color&);
|
||||
|
||||
std::string colorize (const std::string&) const;
|
||||
static std::string colorize (const std::string&, const std::string&);
|
||||
void _colorize (std::string&, const std::string&) const;
|
||||
static std::string strip (const std::string&);
|
||||
|
||||
bool nontrivial () const;
|
||||
|
||||
private:
|
||||
int find (const std::string&);
|
||||
std::string fg () const;
|
||||
std::string bg () const;
|
||||
|
||||
private:
|
||||
unsigned int _value;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,892 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <FS.h>
|
||||
#include <fstream>
|
||||
#include <glob.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <text.h>
|
||||
|
||||
#if defined SOLARIS || defined NETBSD || defined FREEBSD
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
// Fixes build with musl libc.
|
||||
#ifndef GLOB_TILDE
|
||||
#define GLOB_TILDE 0
|
||||
#endif
|
||||
|
||||
#ifndef GLOB_BRACE
|
||||
#define GLOB_BRACE 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Path::Path ()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Path::Path (const Path& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
_original = other._original;
|
||||
_data = other._data;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Path::Path (const std::string& in)
|
||||
{
|
||||
_original = in;
|
||||
_data = expand (in);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Path& Path::operator= (const Path& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
this->_original = other._original;
|
||||
this->_data = other._data;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::operator== (const Path& other)
|
||||
{
|
||||
return _data == other._data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Path& Path::operator+= (const std::string& dir)
|
||||
{
|
||||
_data += "/" + dir;
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Path::operator std::string () const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Path::name () const
|
||||
{
|
||||
if (_data.length ())
|
||||
{
|
||||
auto slash = _data.rfind ('/');
|
||||
if (slash != std::string::npos)
|
||||
return _data.substr (slash + 1, std::string::npos);
|
||||
}
|
||||
|
||||
return _data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Path::parent () const
|
||||
{
|
||||
if (_data.length ())
|
||||
{
|
||||
auto slash = _data.rfind ('/');
|
||||
if (slash != std::string::npos)
|
||||
return _data.substr (0, slash);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Path::extension () const
|
||||
{
|
||||
if (_data.length ())
|
||||
{
|
||||
auto dot = _data.rfind ('.');
|
||||
if (dot != std::string::npos)
|
||||
return _data.substr (dot + 1, std::string::npos);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::exists () const
|
||||
{
|
||||
return access (_data.c_str (), F_OK) ? false : true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::is_directory () const
|
||||
{
|
||||
struct stat s {};
|
||||
if (! stat (_data.c_str (), &s) &&
|
||||
S_ISDIR (s.st_mode))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::is_absolute () const
|
||||
{
|
||||
if (_data.length () && _data[0] == '/')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::is_link () const
|
||||
{
|
||||
struct stat s {};
|
||||
if (! lstat (_data.c_str (), &s) &&
|
||||
S_ISLNK (s.st_mode))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::readable () const
|
||||
{
|
||||
return access (_data.c_str (), R_OK) ? false : true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::writable () const
|
||||
{
|
||||
return access (_data.c_str (), W_OK) ? false : true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::executable () const
|
||||
{
|
||||
return access (_data.c_str (), X_OK) ? false : true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::rename (const std::string& new_name)
|
||||
{
|
||||
std::string expanded = expand (new_name);
|
||||
if (_data != expanded)
|
||||
{
|
||||
if (::rename (_data.c_str (), expanded.c_str ()) == 0)
|
||||
{
|
||||
_data = expanded;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ~ --> /home/user
|
||||
// ~foo/x --> /home/foo/s
|
||||
// ~/x --> /home/foo/x
|
||||
// ./x --> $PWD/x
|
||||
// x --> $PWD/x
|
||||
std::string Path::expand (const std::string& in)
|
||||
{
|
||||
std::string copy = in;
|
||||
|
||||
auto tilde = copy.find ("~");
|
||||
std::string::size_type slash;
|
||||
|
||||
if (tilde != std::string::npos)
|
||||
{
|
||||
const char *home = getenv("HOME");
|
||||
if (home == NULL)
|
||||
{
|
||||
struct passwd* pw = getpwuid (getuid ());
|
||||
home = pw->pw_dir;
|
||||
}
|
||||
|
||||
// Convert: ~ --> /home/user
|
||||
if (copy.length () == 1)
|
||||
copy = home;
|
||||
|
||||
// Convert: ~/x --> /home/user/x
|
||||
else if (copy.length () > tilde + 1 &&
|
||||
copy[tilde + 1] == '/')
|
||||
{
|
||||
copy.replace (tilde, 1, home);
|
||||
}
|
||||
|
||||
// Convert: ~foo/x --> /home/foo/x
|
||||
else if ((slash = copy.find ("/", tilde)) != std::string::npos)
|
||||
{
|
||||
std::string name = copy.substr (tilde + 1, slash - tilde - 1);
|
||||
struct passwd* pw = getpwnam (name.c_str ());
|
||||
if (pw)
|
||||
copy.replace (tilde, slash - tilde, pw->pw_dir);
|
||||
}
|
||||
}
|
||||
|
||||
// Relative paths
|
||||
else if (in.length () > 2 &&
|
||||
in.substr (0, 2) == "./")
|
||||
{
|
||||
copy = Directory::cwd () + "/" + in.substr (2);
|
||||
}
|
||||
else if (in.length () > 1 &&
|
||||
in[0] != '.' &&
|
||||
in[0] != '/')
|
||||
{
|
||||
copy = Directory::cwd () + "/" + in;
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string> Path::glob (const std::string& pattern)
|
||||
{
|
||||
std::vector <std::string> results;
|
||||
|
||||
glob_t g;
|
||||
#ifdef SOLARIS
|
||||
if (!::glob (pattern.c_str (), GLOB_ERR, NULL, &g))
|
||||
#else
|
||||
if (!::glob (pattern.c_str (), GLOB_ERR | GLOB_BRACE | GLOB_TILDE, NULL, &g))
|
||||
#endif
|
||||
for (int i = 0; i < (int) g.gl_pathc; ++i)
|
||||
results.push_back (g.gl_pathv[i]);
|
||||
|
||||
globfree (&g);
|
||||
return results;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
File::File ()
|
||||
: Path::Path ()
|
||||
, _fh (NULL)
|
||||
, _h (-1)
|
||||
, _locked (false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
File::File (const Path& other)
|
||||
: Path::Path (other)
|
||||
, _fh (NULL)
|
||||
, _h (-1)
|
||||
, _locked (false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
File::File (const File& other)
|
||||
: Path::Path (other)
|
||||
, _fh (NULL)
|
||||
, _h (-1)
|
||||
, _locked (false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
File::File (const std::string& in)
|
||||
: Path::Path (in)
|
||||
, _fh (NULL)
|
||||
, _h (-1)
|
||||
, _locked (false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
File::~File ()
|
||||
{
|
||||
if (_fh)
|
||||
close ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
File& File::operator= (const File& other)
|
||||
{
|
||||
if (this != &other)
|
||||
Path::operator= (other);
|
||||
|
||||
_locked = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::create (int mode /* = 0640 */)
|
||||
{
|
||||
if (open ())
|
||||
{
|
||||
fchmod (_h, mode);
|
||||
close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::remove () const
|
||||
{
|
||||
return unlink (_data.c_str ()) == 0 ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::open ()
|
||||
{
|
||||
if (_data != "")
|
||||
{
|
||||
if (! _fh)
|
||||
{
|
||||
bool already_exists = exists ();
|
||||
if (already_exists)
|
||||
if (!readable () || !writable ())
|
||||
throw std::string (format ("Insufficient permissions for '{1}'.", _data));
|
||||
|
||||
_fh = fopen (_data.c_str (), (already_exists ? "r+" : "w+"));
|
||||
if (_fh)
|
||||
{
|
||||
_h = fileno (_fh);
|
||||
_locked = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void File::close ()
|
||||
{
|
||||
if (_fh)
|
||||
{
|
||||
if (_locked)
|
||||
unlock ();
|
||||
|
||||
fclose (_fh);
|
||||
_fh = NULL;
|
||||
_h = -1;
|
||||
_locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::lock ()
|
||||
{
|
||||
_locked = false;
|
||||
if (_fh && _h != -1)
|
||||
{
|
||||
// l_type l_whence l_start l_len l_pid
|
||||
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
|
||||
fl.l_pid = getpid ();
|
||||
if (fcntl (_h, F_SETLKW, &fl) == 0)
|
||||
_locked = true;
|
||||
}
|
||||
|
||||
return _locked;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void File::unlock ()
|
||||
{
|
||||
if (_locked)
|
||||
{
|
||||
// l_type l_whence l_start l_len l_pid
|
||||
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0 };
|
||||
fl.l_pid = getpid ();
|
||||
|
||||
fcntl (_h, F_SETLK, &fl);
|
||||
_locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Opens if necessary.
|
||||
void File::read (std::string& contents)
|
||||
{
|
||||
contents = "";
|
||||
contents.reserve (size ());
|
||||
|
||||
std::ifstream in (_data.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
line.reserve (512 * 1024);
|
||||
while (getline (in, line))
|
||||
contents += line + "\n";
|
||||
|
||||
in.close ();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Opens if necessary.
|
||||
void File::read (std::vector <std::string>& contents)
|
||||
{
|
||||
contents.clear ();
|
||||
|
||||
std::ifstream in (_data.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
line.reserve (512 * 1024);
|
||||
while (getline (in, line))
|
||||
contents.push_back (line);
|
||||
|
||||
in.close ();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Opens if necessary.
|
||||
void File::append (const std::string& line)
|
||||
{
|
||||
if (!_fh)
|
||||
open ();
|
||||
|
||||
if (_fh)
|
||||
{
|
||||
fseek (_fh, 0, SEEK_END);
|
||||
fputs (line.c_str (), _fh);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Opens if necessary.
|
||||
void File::append (const std::vector <std::string>& lines)
|
||||
{
|
||||
if (!_fh)
|
||||
open ();
|
||||
|
||||
if (_fh)
|
||||
{
|
||||
fseek (_fh, 0, SEEK_END);
|
||||
for (auto& line : lines)
|
||||
fputs (line.c_str (), _fh);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void File::write_raw (const std::string& line)
|
||||
{
|
||||
if (!_fh)
|
||||
open ();
|
||||
|
||||
if (_fh)
|
||||
{
|
||||
fputs (line.c_str (), _fh);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void File::truncate ()
|
||||
{
|
||||
if (!_fh)
|
||||
open ();
|
||||
|
||||
if (_fh)
|
||||
(void) ftruncate (_h, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// S_IFMT 0170000 type of file
|
||||
// S_IFIFO 0010000 named pipe (fifo)
|
||||
// S_IFCHR 0020000 character special
|
||||
// S_IFDIR 0040000 directory
|
||||
// S_IFBLK 0060000 block special
|
||||
// S_IFREG 0100000 regular
|
||||
// S_IFLNK 0120000 symbolic link
|
||||
// S_IFSOCK 0140000 socket
|
||||
// S_IFWHT 0160000 whiteout
|
||||
// S_ISUID 0004000 set user id on execution
|
||||
// S_ISGID 0002000 set group id on execution
|
||||
// S_ISVTX 0001000 save swapped text even after use
|
||||
// S_IRUSR 0000400 read permission, owner
|
||||
// S_IWUSR 0000200 write permission, owner
|
||||
// S_IXUSR 0000100 execute/search permission, owner
|
||||
mode_t File::mode ()
|
||||
{
|
||||
struct stat s;
|
||||
if (!stat (_data.c_str (), &s))
|
||||
return s.st_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
size_t File::size () const
|
||||
{
|
||||
struct stat s;
|
||||
if (!stat (_data.c_str (), &s))
|
||||
return s.st_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
time_t File::mtime () const
|
||||
{
|
||||
struct stat s;
|
||||
if (!stat (_data.c_str (), &s))
|
||||
return s.st_mtime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
time_t File::ctime () const
|
||||
{
|
||||
struct stat s;
|
||||
if (!stat (_data.c_str (), &s))
|
||||
return s.st_ctime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
time_t File::btime () const
|
||||
{
|
||||
struct stat s;
|
||||
if (!stat (_data.c_str (), &s))
|
||||
#ifdef HAVE_ST_BIRTHTIME
|
||||
return s.st_birthtime;
|
||||
#else
|
||||
return s.st_ctime;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::create (const std::string& name, int mode /* = 0640 */)
|
||||
{
|
||||
std::string full_name = expand (name);
|
||||
std::ofstream out (full_name.c_str ());
|
||||
if (out.good ())
|
||||
{
|
||||
out.close ();
|
||||
chmod (full_name.c_str (), mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::read (const std::string& name, std::string& contents)
|
||||
{
|
||||
contents = "";
|
||||
|
||||
std::ifstream in (name.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
line.reserve (1024);
|
||||
while (getline (in, line))
|
||||
contents += line + "\n";
|
||||
|
||||
in.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::read (const std::string& name, std::vector <std::string>& contents)
|
||||
{
|
||||
contents.clear ();
|
||||
|
||||
std::ifstream in (name.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
line.reserve (1024);
|
||||
while (getline (in, line))
|
||||
contents.push_back (line);
|
||||
|
||||
in.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::write (const std::string& name, const std::string& contents)
|
||||
{
|
||||
std::ofstream out (expand (name).c_str (),
|
||||
std::ios_base::out | std::ios_base::trunc);
|
||||
if (out.good ())
|
||||
{
|
||||
out << contents;
|
||||
out.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::write (
|
||||
const std::string& name,
|
||||
const std::vector <std::string>& lines,
|
||||
bool addNewlines /* = true */)
|
||||
{
|
||||
std::ofstream out (expand (name).c_str (),
|
||||
std::ios_base::out | std::ios_base::trunc);
|
||||
if (out.good ())
|
||||
{
|
||||
for (auto& line : lines)
|
||||
{
|
||||
out << line;
|
||||
|
||||
if (addNewlines)
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
out.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::remove (const std::string& name)
|
||||
{
|
||||
return unlink (expand (name).c_str ()) == 0 ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Directory::Directory ()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Directory::Directory (const Directory& other)
|
||||
: File::File (other)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Directory::Directory (const File& other)
|
||||
: File::File (other)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Directory::Directory (const Path& other)
|
||||
: File::File (other)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Directory::Directory (const std::string& in)
|
||||
: File::File (in)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Directory& Directory::operator= (const Directory& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
File::operator= (other);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Directory::create (int mode /* = 0755 */)
|
||||
{
|
||||
return mkdir (_data.c_str (), mode) == 0 ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Directory::remove () const
|
||||
{
|
||||
return remove_directory (_data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Directory::remove_directory (const std::string& dir) const
|
||||
{
|
||||
DIR* dp = opendir (dir.c_str ());
|
||||
if (dp != NULL)
|
||||
{
|
||||
struct dirent* de;
|
||||
while ((de = readdir (dp)) != NULL)
|
||||
{
|
||||
if (!strcmp (de->d_name, ".") ||
|
||||
!strcmp (de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
#if defined (SOLARIS) || defined (HAIKU)
|
||||
struct stat s;
|
||||
lstat ((dir + "/" + de->d_name).c_str (), &s);
|
||||
if (S_ISDIR (s.st_mode))
|
||||
remove_directory (dir + "/" + de->d_name);
|
||||
else
|
||||
unlink ((dir + "/" + de->d_name).c_str ());
|
||||
#else
|
||||
if (de->d_type == DT_UNKNOWN)
|
||||
{
|
||||
struct stat s;
|
||||
lstat ((dir + "/" + de->d_name).c_str (), &s);
|
||||
if (S_ISDIR (s.st_mode))
|
||||
de->d_type = DT_DIR;
|
||||
}
|
||||
if (de->d_type == DT_DIR)
|
||||
remove_directory (dir + "/" + de->d_name);
|
||||
else
|
||||
unlink ((dir + "/" + de->d_name).c_str ());
|
||||
#endif
|
||||
}
|
||||
|
||||
closedir (dp);
|
||||
}
|
||||
|
||||
return rmdir (dir.c_str ()) ? false : true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string> Directory::list ()
|
||||
{
|
||||
std::vector <std::string> files;
|
||||
list (_data, files, false);
|
||||
return files;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string> Directory::listRecursive ()
|
||||
{
|
||||
std::vector <std::string> files;
|
||||
list (_data, files, true);
|
||||
return files;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Directory::cwd ()
|
||||
{
|
||||
#ifdef HAVE_GET_CURRENT_DIR_NAME
|
||||
char *buf = get_current_dir_name ();
|
||||
if (buf == NULL)
|
||||
throw std::bad_alloc ();
|
||||
std::string result (buf);
|
||||
free (buf);
|
||||
return result;
|
||||
#else
|
||||
char buf[PATH_MAX];
|
||||
getcwd (buf, PATH_MAX - 1);
|
||||
return std::string (buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Directory::up ()
|
||||
{
|
||||
if (_data == "/")
|
||||
return false;
|
||||
|
||||
auto slash = _data.rfind ('/');
|
||||
if (slash == 0)
|
||||
{
|
||||
_data = "/"; // Root dir should retain the slash.
|
||||
return true;
|
||||
}
|
||||
else if (slash != std::string::npos)
|
||||
{
|
||||
_data = _data.substr (0, slash);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Directory::cd () const
|
||||
{
|
||||
return chdir (_data.c_str ()) == 0 ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Directory::list (
|
||||
const std::string& base,
|
||||
std::vector <std::string>& results,
|
||||
bool recursive)
|
||||
{
|
||||
DIR* dp = opendir (base.c_str ());
|
||||
if (dp != NULL)
|
||||
{
|
||||
struct dirent* de;
|
||||
while ((de = readdir (dp)) != NULL)
|
||||
{
|
||||
if (!strcmp (de->d_name, ".") ||
|
||||
!strcmp (de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
#if defined (SOLARIS) || defined (HAIKU)
|
||||
struct stat s;
|
||||
stat ((base + "/" + de->d_name).c_str (), &s);
|
||||
if (recursive && S_ISDIR (s.st_mode))
|
||||
list (base + "/" + de->d_name, results, recursive);
|
||||
else
|
||||
results.push_back (base + "/" + de->d_name);
|
||||
#else
|
||||
if (recursive && de->d_type == DT_UNKNOWN)
|
||||
{
|
||||
struct stat s;
|
||||
lstat ((base + "/" + de->d_name).c_str (), &s);
|
||||
if (S_ISDIR (s.st_mode))
|
||||
de->d_type = DT_DIR;
|
||||
}
|
||||
if (recursive && de->d_type == DT_DIR)
|
||||
list (base + "/" + de->d_name, results, recursive);
|
||||
else
|
||||
results.push_back (base + "/" + de->d_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
closedir (dp);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
144
src/common/FS.h
144
src/common/FS.h
|
@ -1,144 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_FS
|
||||
#define INCLUDED_FS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
|
||||
class Path
|
||||
{
|
||||
public:
|
||||
Path ();
|
||||
Path (const Path&);
|
||||
Path (const std::string&);
|
||||
|
||||
Path& operator= (const Path&);
|
||||
bool operator== (const Path&);
|
||||
Path& operator+= (const std::string&);
|
||||
operator std::string () const;
|
||||
|
||||
std::string name () const;
|
||||
std::string parent () const;
|
||||
std::string extension () const;
|
||||
bool exists () const;
|
||||
bool is_directory () const;
|
||||
bool is_absolute () const;
|
||||
bool is_link () const;
|
||||
bool readable () const;
|
||||
bool writable () const;
|
||||
bool executable () const;
|
||||
bool rename (const std::string&);
|
||||
|
||||
// Statics
|
||||
static std::string expand (const std::string&);
|
||||
static std::vector<std::string> glob (const std::string&);
|
||||
|
||||
public:
|
||||
std::string _original;
|
||||
std::string _data;
|
||||
};
|
||||
|
||||
class File : public Path
|
||||
{
|
||||
public:
|
||||
File ();
|
||||
File (const Path&);
|
||||
File (const File&);
|
||||
File (const std::string&);
|
||||
virtual ~File ();
|
||||
|
||||
File& operator= (const File&);
|
||||
|
||||
virtual bool create (int mode = 0640);
|
||||
virtual bool remove () const;
|
||||
|
||||
bool open ();
|
||||
void close ();
|
||||
|
||||
bool lock ();
|
||||
void unlock ();
|
||||
|
||||
void read (std::string&);
|
||||
void read (std::vector <std::string>&);
|
||||
|
||||
void append (const std::string&);
|
||||
void append (const std::vector <std::string>&);
|
||||
void write_raw (const std::string&);
|
||||
|
||||
void truncate ();
|
||||
|
||||
virtual mode_t mode ();
|
||||
virtual size_t size () const;
|
||||
virtual time_t mtime () const;
|
||||
virtual time_t ctime () const;
|
||||
virtual time_t btime () const;
|
||||
|
||||
static bool create (const std::string&, int mode = 0640);
|
||||
static bool read (const std::string&, std::string&);
|
||||
static bool read (const std::string&, std::vector <std::string>&);
|
||||
static bool write (const std::string&, const std::string&);
|
||||
static bool write (const std::string&, const std::vector <std::string>&, bool addNewlines = true);
|
||||
static bool remove (const std::string&);
|
||||
|
||||
private:
|
||||
FILE* _fh;
|
||||
int _h;
|
||||
bool _locked;
|
||||
};
|
||||
|
||||
class Directory : public File
|
||||
{
|
||||
public:
|
||||
Directory ();
|
||||
Directory (const Directory&);
|
||||
Directory (const File&);
|
||||
Directory (const Path&);
|
||||
Directory (const std::string&);
|
||||
|
||||
Directory& operator= (const Directory&);
|
||||
|
||||
virtual bool create (int mode = 0755);
|
||||
virtual bool remove () const;
|
||||
|
||||
std::vector <std::string> list ();
|
||||
std::vector <std::string> listRecursive ();
|
||||
|
||||
static std::string cwd ();
|
||||
bool up ();
|
||||
bool cd () const;
|
||||
|
||||
private:
|
||||
void list (const std::string&, std::vector <std::string>&, bool);
|
||||
bool remove_directory (const std::string&) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
Common
|
||||
======
|
||||
|
||||
The 'common' library is a set of reusable objects to be shared as-is between
|
||||
various programs, including Taskwarrior, Taskserver, Tasksh and Timewarrior.
|
||||
|
||||
In order to be reusable, and therefore a member of libcommon, rules must be
|
||||
followed:
|
||||
|
||||
- Common objects may only make use of other common objects, or external
|
||||
dependencies (libuuid, gettext, readline etc), but no objects from the
|
||||
parent directories.
|
||||
|
||||
- Common objects can assume only an external 'cmake.h' that defines
|
||||
platform/portability constants.
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <RX.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
RX::RX ()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
RX::RX (
|
||||
const std::string& pattern,
|
||||
bool case_sensitive /* = true */)
|
||||
: _compiled (false)
|
||||
, _pattern (pattern)
|
||||
, _case_sensitive (case_sensitive)
|
||||
{
|
||||
compile ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
RX::RX (const RX& other)
|
||||
{
|
||||
_compiled = false;
|
||||
_pattern = other._pattern;
|
||||
_case_sensitive = other._case_sensitive;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
RX::~RX ()
|
||||
{
|
||||
if (_compiled)
|
||||
regfree (&_regex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
RX& RX::operator= (const RX& other)
|
||||
{
|
||||
_compiled = false;
|
||||
_pattern = other._pattern;
|
||||
_case_sensitive = other._case_sensitive;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void RX::compile ()
|
||||
{
|
||||
if (! _compiled)
|
||||
{
|
||||
memset (&_regex, 0, sizeof (regex_t));
|
||||
|
||||
int result;
|
||||
if ((result = regcomp (&_regex, _pattern.c_str (),
|
||||
#if defined REG_ENHANCED
|
||||
REG_ENHANCED | REG_EXTENDED | REG_NEWLINE |
|
||||
#else
|
||||
REG_EXTENDED | REG_NEWLINE |
|
||||
#endif
|
||||
(_case_sensitive ? 0 : REG_ICASE))) != 0)
|
||||
{
|
||||
char message[256];
|
||||
regerror (result, &_regex, message, 256);
|
||||
throw std::string (message);
|
||||
}
|
||||
|
||||
_compiled = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool RX::match (const std::string& in)
|
||||
{
|
||||
if (! _compiled)
|
||||
compile ();
|
||||
|
||||
return regexec (&_regex, in.c_str (), 0, NULL, 0) == 0 ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool RX::match (
|
||||
std::vector<std::string>& matches,
|
||||
const std::string& in)
|
||||
{
|
||||
if (! _compiled)
|
||||
compile ();
|
||||
|
||||
regmatch_t rm[2];
|
||||
int offset = 0;
|
||||
int length = in.length ();
|
||||
while (regexec (&_regex, in.c_str () + offset, 2, &rm[0], 0) == 0 &&
|
||||
offset < length)
|
||||
{
|
||||
matches.push_back (in.substr (rm[0].rm_so + offset, rm[0].rm_eo - rm[0].rm_so));
|
||||
offset += rm[0].rm_eo;
|
||||
|
||||
// Protection against zero-width patterns causing infinite loops.
|
||||
if (rm[0].rm_so == rm[0].rm_eo)
|
||||
++offset;
|
||||
}
|
||||
|
||||
return matches.size () ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool RX::match (
|
||||
std::vector <int>& start,
|
||||
std::vector <int>& end,
|
||||
const std::string& in)
|
||||
{
|
||||
if (! _compiled)
|
||||
compile ();
|
||||
|
||||
regmatch_t rm[2];
|
||||
int offset = 0;
|
||||
int length = in.length ();
|
||||
while (regexec (&_regex, in.c_str () + offset, 2, &rm[0], 0) == 0 &&
|
||||
offset < length)
|
||||
{
|
||||
start.push_back (rm[0].rm_so + offset);
|
||||
end.push_back (rm[0].rm_eo + offset);
|
||||
offset += rm[0].rm_eo;
|
||||
|
||||
// Protection against zero-width patterns causing infinite loops.
|
||||
if (rm[0].rm_so == rm[0].rm_eo)
|
||||
++offset;
|
||||
}
|
||||
|
||||
return start.size () ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,58 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_RX
|
||||
#define INCLUDED_RX
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <regex.h>
|
||||
|
||||
class RX
|
||||
{
|
||||
public:
|
||||
RX ();
|
||||
RX (const std::string&, bool caseSensitive = true);
|
||||
RX (const RX&);
|
||||
~RX ();
|
||||
RX& operator= (const RX&);
|
||||
|
||||
bool match (const std::string&);
|
||||
bool match (std::vector<std::string>&, const std::string&);
|
||||
bool match (std::vector <int>&, std::vector <int>&, const std::string&);
|
||||
|
||||
private:
|
||||
void compile ();
|
||||
|
||||
private:
|
||||
bool _compiled {false};
|
||||
std::string _pattern {};
|
||||
bool _case_sensitive {false};
|
||||
regex_t _regex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,312 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <Table.h>
|
||||
#include <text.h>
|
||||
#include <utf8.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Table::Table ()
|
||||
: _width (0)
|
||||
, _left_margin (0)
|
||||
, _header (0)
|
||||
, _odd (0)
|
||||
, _even (0)
|
||||
, _intra_padding (1)
|
||||
, _intra_odd (0)
|
||||
, _intra_even (0)
|
||||
, _extra_padding (0)
|
||||
, _extra_odd (0)
|
||||
, _extra_even (0)
|
||||
, _truncate_lines (0)
|
||||
, _truncate_rows (0)
|
||||
, _lines (0)
|
||||
, _rows (0)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int Table::addRow ()
|
||||
{
|
||||
_data.push_back (std::vector <std::string> (_columns.size (), ""));
|
||||
_color.push_back (std::vector <Color> (_columns.size (), Color::nocolor));
|
||||
return _data.size () - 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::set (int row, int col, const std::string& value, const Color color)
|
||||
{
|
||||
_data[row][col] = value;
|
||||
|
||||
if (color.nontrivial ())
|
||||
_color[row][col] = color;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::set (int row, int col, int value, const Color color)
|
||||
{
|
||||
std::string string_value = format (value);
|
||||
_data[row][col] = string_value;
|
||||
|
||||
if (color.nontrivial ())
|
||||
_color[row][col] = color;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::set (int row, int col, const Color color)
|
||||
{
|
||||
if (color.nontrivial ())
|
||||
_color[row][col] = color;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Table::render ()
|
||||
{
|
||||
// Determine minimal, ideal column widths.
|
||||
std::vector <int> minimal;
|
||||
std::vector <int> ideal;
|
||||
for (unsigned int col = 0; col < _columns.size (); ++col)
|
||||
{
|
||||
// Headers factor in to width calculations.
|
||||
unsigned int global_min = utf8_width (_columns[col]);
|
||||
unsigned int global_ideal = global_min;
|
||||
|
||||
for (unsigned int row = 0; row < _data.size (); ++row)
|
||||
{
|
||||
// Determine minimum and ideal width for this column.
|
||||
unsigned int min = 0;
|
||||
unsigned int ideal = 0;
|
||||
measureCell (_data[row][col], min, ideal);
|
||||
|
||||
if (min > global_min) global_min = min;
|
||||
if (ideal > global_ideal) global_ideal = ideal;
|
||||
}
|
||||
|
||||
minimal.push_back (global_min);
|
||||
ideal.push_back (global_ideal);
|
||||
}
|
||||
|
||||
// Sum the minimal widths.
|
||||
int sum_minimal = 0;
|
||||
for (auto& c : minimal)
|
||||
sum_minimal += c;
|
||||
|
||||
// Sum the ideal widths.
|
||||
int sum_ideal = 0;
|
||||
for (auto& c : ideal)
|
||||
sum_ideal += c;
|
||||
|
||||
// Calculate final column widths.
|
||||
int overage = _width
|
||||
- _left_margin
|
||||
- (2 * _extra_padding)
|
||||
- ((_columns.size () - 1) * _intra_padding);
|
||||
|
||||
std::vector <int> widths;
|
||||
if (sum_ideal <= overage)
|
||||
widths = ideal;
|
||||
else if (sum_minimal > overage || overage < 0)
|
||||
widths = minimal;
|
||||
else if (overage > 0)
|
||||
{
|
||||
widths = minimal;
|
||||
overage -= sum_minimal;
|
||||
|
||||
// Spread 'overage' among columns where width[i] < ideal[i]
|
||||
while (overage)
|
||||
{
|
||||
for (unsigned int i = 0; i < _columns.size () && overage; ++i)
|
||||
{
|
||||
if (widths[i] < ideal[i])
|
||||
{
|
||||
++widths[i];
|
||||
--overage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compose column headers.
|
||||
unsigned int max_lines = 0;
|
||||
std::vector <std::vector <std::string>> headers;
|
||||
for (unsigned int c = 0; c < _columns.size (); ++c)
|
||||
{
|
||||
headers.push_back ({});
|
||||
renderCell (headers[c], _columns[c], widths[c], _align[c], _header);
|
||||
|
||||
if (headers[c].size () > max_lines)
|
||||
max_lines = headers[c].size ();
|
||||
}
|
||||
|
||||
// Output string.
|
||||
std::string out;
|
||||
_lines = 0;
|
||||
|
||||
// Render column headers.
|
||||
std::string left_margin = std::string (_left_margin, ' ');
|
||||
std::string extra = std::string (_extra_padding, ' ');
|
||||
std::string intra = std::string (_intra_padding, ' ');
|
||||
|
||||
std::string extra_odd = _extra_odd.colorize (extra);
|
||||
std::string extra_even = _extra_even.colorize (extra);
|
||||
std::string intra_odd = _intra_odd.colorize (intra);
|
||||
std::string intra_even = _intra_even.colorize (intra);
|
||||
|
||||
for (unsigned int i = 0; i < max_lines; ++i)
|
||||
{
|
||||
out += left_margin + extra;
|
||||
|
||||
for (unsigned int c = 0; c < _columns.size (); ++c)
|
||||
{
|
||||
if (c)
|
||||
out += intra;
|
||||
|
||||
if (headers[c].size () < max_lines - i)
|
||||
out += _header.colorize (std::string (widths[c], ' '));
|
||||
else
|
||||
out += headers[c][i];
|
||||
}
|
||||
|
||||
out += extra;
|
||||
|
||||
// Trim right.
|
||||
out.erase (out.find_last_not_of (" ") + 1);
|
||||
out += "\n";
|
||||
|
||||
// Stop if the line limit is exceeded.
|
||||
if (++_lines >= _truncate_lines && _truncate_lines != 0)
|
||||
return out;
|
||||
}
|
||||
|
||||
// Compose, render columns, in sequence.
|
||||
_rows = 0;
|
||||
std::vector <std::vector <std::string>> cells;
|
||||
for (unsigned int row = 0; row < _data.size (); ++row)
|
||||
{
|
||||
max_lines = 0;
|
||||
|
||||
// Alternate rows based on |s % 2|
|
||||
bool odd = (row % 2) ? true : false;
|
||||
Color row_color = odd ? _odd : _even;
|
||||
|
||||
// TODO row_color.blend (provided color);
|
||||
// TODO Problem: colors for columns are specified, not rows,
|
||||
// therefore there are only cell colors, not intra colors.
|
||||
|
||||
Color cell_color;
|
||||
for (unsigned int col = 0; col < _columns.size (); ++col)
|
||||
{
|
||||
cell_color = row_color;
|
||||
cell_color.blend (_color[row][col]);
|
||||
|
||||
cells.push_back (std::vector <std::string> ());
|
||||
renderCell (cells[col], _data[row][col], widths[col], _align[col], cell_color);
|
||||
|
||||
if (cells[col].size () > max_lines)
|
||||
max_lines = cells[col].size ();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < max_lines; ++i)
|
||||
{
|
||||
out += left_margin + (odd ? extra_odd : extra_even);
|
||||
|
||||
for (unsigned int col = 0; col < _columns.size (); ++col)
|
||||
{
|
||||
if (col)
|
||||
{
|
||||
if (row_color.nontrivial ())
|
||||
out += row_color.colorize (intra);
|
||||
else
|
||||
out += (odd ? intra_odd : intra_even);
|
||||
}
|
||||
|
||||
if (i < cells[col].size ())
|
||||
out += cells[col][i];
|
||||
else
|
||||
{
|
||||
cell_color = row_color;
|
||||
cell_color.blend (_color[row][col]);
|
||||
out += cell_color.colorize (std::string (widths[col], ' '));
|
||||
}
|
||||
}
|
||||
|
||||
out += (odd ? extra_odd : extra_even);
|
||||
|
||||
// Trim right.
|
||||
out.erase (out.find_last_not_of (" ") + 1);
|
||||
out += "\n";
|
||||
|
||||
// Stop if the line limit is exceeded.
|
||||
if (++_lines >= _truncate_lines && _truncate_lines != 0)
|
||||
return out;
|
||||
}
|
||||
|
||||
cells.clear ();
|
||||
|
||||
// Stop if the row limit is exceeded.
|
||||
if (++_rows >= _truncate_rows && _truncate_rows != 0)
|
||||
return out;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::measureCell (
|
||||
const std::string& data,
|
||||
unsigned int& minimum,
|
||||
unsigned int& maximum) const
|
||||
{
|
||||
std::string stripped = Color::strip (data);
|
||||
maximum = longestLine (stripped);
|
||||
minimum = longestWord (stripped);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::renderCell (
|
||||
std::vector <std::string>& lines,
|
||||
const std::string& value,
|
||||
int width,
|
||||
bool alignLeft,
|
||||
const Color& color) const
|
||||
{
|
||||
std::vector <std::string> raw;
|
||||
wrapText (raw, value, width, false);
|
||||
|
||||
for (auto& line : raw)
|
||||
if (alignLeft)
|
||||
lines.push_back (
|
||||
color.colorize (
|
||||
leftJustify (line, width)));
|
||||
else
|
||||
lines.push_back (
|
||||
color.colorize (
|
||||
rightJustify (line, width)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_VIEWTEXT
|
||||
#define INCLUDED_VIEWTEXT
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <Color.h>
|
||||
|
||||
class Table
|
||||
{
|
||||
public:
|
||||
Table ();
|
||||
|
||||
// View specifications.
|
||||
void add (const std::string& col, bool alignLeft = true) { _columns.push_back (col); _align.push_back (alignLeft); }
|
||||
void width (int width) { _width = width; }
|
||||
void leftMargin (int margin) { _left_margin = margin; }
|
||||
void colorHeader (const Color& c) { _header = c; }
|
||||
void colorOdd (const Color& c) { _odd = c; }
|
||||
void colorEven (const Color& c) { _even = c; }
|
||||
void intraPadding (int padding) { _intra_padding = padding; }
|
||||
void intraColorOdd (const Color& c) { _intra_odd = c; }
|
||||
void intraColorEven (const Color& c) { _intra_even = c; }
|
||||
void extraPadding (int padding) { _extra_padding = padding; }
|
||||
void extraColorOdd (const Color& c) { _extra_odd = c; }
|
||||
void extraColorEven (const Color& c) { _extra_even = c; }
|
||||
void truncateLines (int n) { _truncate_lines = n; }
|
||||
void truncateRows (int n) { _truncate_rows = n; }
|
||||
int lines () { return _lines; }
|
||||
int rows () { return (int) _data.size (); }
|
||||
|
||||
// Data provision.
|
||||
int addRow ();
|
||||
void set (int, int, const std::string&, const Color color = Color::nocolor);
|
||||
void set (int, int, int, const Color color = Color::nocolor);
|
||||
void set (int, int, const Color);
|
||||
|
||||
// View rendering.
|
||||
std::string render ();
|
||||
|
||||
private:
|
||||
void measureCell (const std::string&, unsigned int&, unsigned int&) const;
|
||||
void renderCell (std::vector <std::string>&, const std::string&, int, bool, const Color&) const;
|
||||
|
||||
private:
|
||||
std::vector <std::vector <std::string>> _data;
|
||||
std::vector <std::vector <Color>> _color;
|
||||
std::vector <std::string> _columns;
|
||||
std::vector <bool> _align;
|
||||
int _width;
|
||||
int _left_margin;
|
||||
Color _header;
|
||||
Color _odd;
|
||||
Color _even;
|
||||
int _intra_padding;
|
||||
Color _intra_odd;
|
||||
Color _intra_even;
|
||||
int _extra_padding;
|
||||
Color _extra_odd;
|
||||
Color _extra_even;
|
||||
int _truncate_lines;
|
||||
int _truncate_rows;
|
||||
int _lines;
|
||||
int _rows;
|
||||
};
|
||||
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <Timer.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Timer starts when the object is constructed.
|
||||
Timer::Timer ()
|
||||
: _description ("-")
|
||||
, _running (false)
|
||||
, _total (0)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Timer starts when the object is constructed with a description.
|
||||
Timer::Timer (const std::string& description)
|
||||
: _description (description)
|
||||
, _running (false)
|
||||
, _total (0)
|
||||
{
|
||||
start ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Timer stops when the object is destructed.
|
||||
Timer::~Timer ()
|
||||
{
|
||||
stop ();
|
||||
|
||||
std::stringstream s;
|
||||
s << "Timer " // No i18n
|
||||
<< _description
|
||||
<< " "
|
||||
<< std::setprecision (6)
|
||||
#ifndef HAIKU
|
||||
// Haiku fails on this - don't know why.
|
||||
<< std::fixed
|
||||
#endif
|
||||
<< _total / 1000000.0
|
||||
<< " sec\n";
|
||||
|
||||
std::cerr << s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Timer::start ()
|
||||
{
|
||||
if (!_running)
|
||||
{
|
||||
gettimeofday (&_start, NULL);
|
||||
_running = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Timer::stop ()
|
||||
{
|
||||
if (_running)
|
||||
{
|
||||
struct timeval end;
|
||||
gettimeofday (&end, NULL);
|
||||
_running = false;
|
||||
_total += (end.tv_sec - _start.tv_sec) * 1000000
|
||||
+ (end.tv_usec - _start.tv_usec);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
unsigned long Timer::total () const
|
||||
{
|
||||
return _total;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Timer::subtract (unsigned long value)
|
||||
{
|
||||
if (value > _total)
|
||||
_total = 0;
|
||||
else
|
||||
_total -= value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
unsigned long Timer::now ()
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday (&now, NULL);
|
||||
return now.tv_sec * 1000000 + now.tv_usec;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,59 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_TIMER
|
||||
#define INCLUDED_TIMER
|
||||
|
||||
#include <string>
|
||||
#include <sys/time.h>
|
||||
|
||||
// Timer is a scope-activated timer that dumps to std::cout at end of scope.
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer ();
|
||||
Timer (const std::string&);
|
||||
~Timer ();
|
||||
Timer (const Timer&);
|
||||
Timer& operator= (const Timer&);
|
||||
|
||||
void start ();
|
||||
void stop ();
|
||||
unsigned long total () const;
|
||||
void subtract (unsigned long);
|
||||
|
||||
static unsigned long now ();
|
||||
|
||||
private:
|
||||
std::string _description;
|
||||
bool _running;
|
||||
struct timeval _start;
|
||||
unsigned long _total;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,354 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <text.h>
|
||||
#include <utf8.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <math.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void wrapText (
|
||||
std::vector <std::string>& lines,
|
||||
const std::string& text,
|
||||
const int width,
|
||||
bool hyphenate)
|
||||
{
|
||||
std::string line;
|
||||
unsigned int offset = 0;
|
||||
while (extractLine (line, text, width, hyphenate, offset))
|
||||
lines.push_back (line);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string> split (const std::string& input, const char delimiter)
|
||||
{
|
||||
std::vector <std::string> results;
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type i;
|
||||
while ((i = input.find (delimiter, start)) != std::string::npos)
|
||||
{
|
||||
results.push_back (input.substr (start, i - start));
|
||||
start = i + 1;
|
||||
}
|
||||
|
||||
if (input.length ())
|
||||
results.push_back (input.substr (start));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int longestWord (const std::string& input)
|
||||
{
|
||||
int longest = 0;
|
||||
int length = 0;
|
||||
std::string::size_type i = 0;
|
||||
int character;
|
||||
|
||||
while ((character = utf8_next_char (input, i)))
|
||||
{
|
||||
if (character == ' ')
|
||||
{
|
||||
if (length > longest)
|
||||
longest = length;
|
||||
|
||||
length = 0;
|
||||
}
|
||||
else
|
||||
length += mk_wcwidth (character);
|
||||
}
|
||||
|
||||
if (length > longest)
|
||||
longest = length;
|
||||
|
||||
return longest;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int longestLine (const std::string& input)
|
||||
{
|
||||
int longest = 0;
|
||||
int length = 0;
|
||||
std::string::size_type i = 0;
|
||||
int character;
|
||||
|
||||
while ((character = utf8_next_char (input, i)))
|
||||
{
|
||||
if (character == '\n')
|
||||
{
|
||||
if (length > longest)
|
||||
longest = length;
|
||||
|
||||
length = 0;
|
||||
}
|
||||
else
|
||||
length += mk_wcwidth (character);
|
||||
}
|
||||
|
||||
if (length > longest)
|
||||
longest = length;
|
||||
|
||||
return longest;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Walk the input text looking for a break point. A break point is one of:
|
||||
// - EOS
|
||||
// - \n
|
||||
// - last space before 'length' characters
|
||||
// - last punctuation (, ; . :) before 'length' characters, even if not
|
||||
// followed by a space
|
||||
// - first 'length' characters
|
||||
//
|
||||
// text "one two three\n four"
|
||||
// bytes 0123456789012 3456789
|
||||
// characters 1234567890a23 4567890
|
||||
//
|
||||
// leading_ws
|
||||
// ws ^ ^ ^^
|
||||
// punct
|
||||
// break ^
|
||||
bool extractLine (
|
||||
std::string& line,
|
||||
const std::string& text,
|
||||
int width,
|
||||
bool hyphenate,
|
||||
unsigned int& offset)
|
||||
{
|
||||
// Terminate processing.
|
||||
// Note: bytes vs bytes.
|
||||
if (offset >= text.length ())
|
||||
return false;
|
||||
|
||||
std::string::size_type last_last_bytes = offset;
|
||||
std::string::size_type last_bytes = offset;
|
||||
std::string::size_type bytes = offset;
|
||||
unsigned int last_ws = 0;
|
||||
int character;
|
||||
int char_width = 0;
|
||||
int line_width = 0;
|
||||
while (1)
|
||||
{
|
||||
last_last_bytes = last_bytes;
|
||||
last_bytes = bytes;
|
||||
character = utf8_next_char (text, bytes);
|
||||
|
||||
if (character == 0 ||
|
||||
character == '\n')
|
||||
{
|
||||
line = text.substr (offset, last_bytes - offset);
|
||||
offset = bytes;
|
||||
break;
|
||||
}
|
||||
else if (character == ' ')
|
||||
last_ws = last_bytes;
|
||||
|
||||
char_width = mk_wcwidth (character);
|
||||
if (line_width + char_width > width)
|
||||
{
|
||||
int last_last_character = text[last_last_bytes];
|
||||
int last_character = text[last_bytes];
|
||||
|
||||
// [case 1] one| two --> last_last != 32, last == 32, ws == 0
|
||||
if (last_last_character != ' ' &&
|
||||
last_character == ' ')
|
||||
{
|
||||
line = text.substr (offset, last_bytes - offset);
|
||||
offset = last_bytes + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// [case 2] one |two --> last_last == 32, last != 32, ws != 0
|
||||
else if (last_last_character == ' ' &&
|
||||
last_character != ' ' &&
|
||||
last_ws != 0)
|
||||
{
|
||||
line = text.substr (offset, last_bytes - offset - 1);
|
||||
offset = last_bytes;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (last_last_character != ' ' &&
|
||||
last_character != ' ')
|
||||
{
|
||||
// [case 3] one t|wo --> last_last != 32, last != 32, ws != 0
|
||||
if (last_ws != 0)
|
||||
{
|
||||
line = text.substr (offset, last_ws - offset);
|
||||
offset = last_ws + 1;
|
||||
break;
|
||||
}
|
||||
// [case 4] on|e two --> last_last != 32, last != 32, ws == 0
|
||||
else
|
||||
{
|
||||
if (hyphenate)
|
||||
{
|
||||
line = text.substr (offset, last_bytes - offset - 1) + "-";
|
||||
offset = last_last_bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = text.substr (offset, last_bytes - offset);
|
||||
offset = last_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
line_width += char_width;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string format (std::string& value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string format (const char* value)
|
||||
{
|
||||
std::string s (value);
|
||||
return s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string formatHex (int value)
|
||||
{
|
||||
std::stringstream s;
|
||||
s.setf (std::ios::hex, std::ios::basefield);
|
||||
s << value;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string format (float value, int width, int precision)
|
||||
{
|
||||
std::stringstream s;
|
||||
s.width (width);
|
||||
s.precision (precision);
|
||||
if (0 < value && value < 1)
|
||||
{
|
||||
// For value close to zero, width - 2 (2 accounts for the first zero and
|
||||
// the dot) is the number of digits after zero that are significant
|
||||
double factor = 1;
|
||||
for (int i = 2; i < width; i++)
|
||||
factor *= 10;
|
||||
value = roundf (value * factor) / factor;
|
||||
}
|
||||
s << value;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string format (double value, int width, int precision)
|
||||
{
|
||||
std::stringstream s;
|
||||
s.width (width);
|
||||
s.precision (precision);
|
||||
if (0 < value && value < 1)
|
||||
{
|
||||
// For value close to zero, width - 2 (2 accounts for the first zero and
|
||||
// the dot) is the number of digits after zero that are significant
|
||||
double factor = 1;
|
||||
for (int i = 2; i < width; i++)
|
||||
factor *= 10;
|
||||
value = round (value * factor) / factor;
|
||||
}
|
||||
s << value;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string format (double value)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << std::fixed << value;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void replace_positional (
|
||||
std::string& fmt,
|
||||
const std::string& from,
|
||||
const std::string& to)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
while ((pos = fmt.find (from, pos)) != std::string::npos)
|
||||
{
|
||||
fmt.replace (pos, from.length (), to);
|
||||
pos += to.length ();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string leftJustify (const int input, const int width)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << input;
|
||||
std::string output = s.str ();
|
||||
return output + std::string (width - output.length (), ' ');
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string leftJustify (const std::string& input, const int width)
|
||||
{
|
||||
return input + std::string (width - utf8_text_width (input), ' ');
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string rightJustifyZero (const int input, const int width)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << std::setw (width) << std::setfill ('0') << input;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string rightJustify (const int input, const int width)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << std::setw (width) << std::setfill (' ') << input;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string rightJustify (const std::string& input, const int width)
|
||||
{
|
||||
unsigned int len = utf8_text_width (input);
|
||||
return (((unsigned int) width > len)
|
||||
? std::string (width - len, ' ')
|
||||
: "")
|
||||
+ input;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,100 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_TEXT
|
||||
#define INCLUDED_TEXT
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// text.cpp, Non-UTF-8 aware.
|
||||
void wrapText (std::vector <std::string>&, const std::string&, const int, bool);
|
||||
int longestWord (const std::string&);
|
||||
int longestLine (const std::string&);
|
||||
bool extractLine (std::string&, const std::string&, int, bool, unsigned int&);
|
||||
std::vector <std::string> split (const std::string&, const char);
|
||||
const std::string format (std::string&);
|
||||
const std::string format (const char*);
|
||||
const std::string formatHex (int);
|
||||
const std::string format (float, int, int);
|
||||
const std::string format (double, int, int);
|
||||
const std::string format (double);
|
||||
void replace_positional (std::string&, const std::string&, const std::string&);
|
||||
|
||||
template<typename T>
|
||||
const std::string format (T value)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << value;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const std::string format (int fmt_num, const std::string& fmt, T arg)
|
||||
{
|
||||
std::string output = fmt;
|
||||
replace_positional (output, "{" + format (fmt_num) + "}", format (arg));
|
||||
return output;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
const std::string format (int fmt_num, const std::string& fmt, T arg, Args... args)
|
||||
{
|
||||
const std::string fmt_replaced (format (fmt_num, fmt, arg));
|
||||
return format (fmt_num+1, fmt_replaced, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
const std::string format (const std::string& fmt, Args... args)
|
||||
{
|
||||
return format (1, fmt, args...);
|
||||
}
|
||||
|
||||
std::string leftJustify (const int, const int);
|
||||
std::string leftJustify (const std::string&, const int);
|
||||
std::string rightJustifyZero (const int, const int);
|
||||
std::string rightJustify (const int, const int);
|
||||
std::string rightJustify (const std::string&, const int);
|
||||
|
||||
// List operations.
|
||||
template <class T> void listDiff (
|
||||
const T& left, const T& right, T& leftOnly, T& rightOnly)
|
||||
{
|
||||
leftOnly.clear ();
|
||||
for (auto& l : left)
|
||||
if (std::find (right.begin (), right.end (), l) == right.end ())
|
||||
leftOnly.push_back (l);
|
||||
|
||||
rightOnly.clear ();
|
||||
for (auto& r : right)
|
||||
if (std::find (left.begin (), left.end (), r) == left.end ())
|
||||
rightOnly.push_back (r);
|
||||
}
|
||||
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,98 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <unicode.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Complete Unicode whitespace list.
|
||||
//
|
||||
// http://en.wikipedia.org/wiki/Whitespace_character
|
||||
// Updated 2015-09-13
|
||||
// Static
|
||||
//
|
||||
// TODO This list should be derived from the Unicode database.
|
||||
bool unicodeWhitespace (unsigned int c)
|
||||
{
|
||||
return (c == 0x0020 || // space Common Separator, space
|
||||
c == 0x0009 || // Common Other, control HT, Horizontal Tab
|
||||
c == 0x000A || // Common Other, control LF, Line feed
|
||||
c == 0x000B || // Common Other, control VT, Vertical Tab
|
||||
c == 0x000C || // Common Other, control FF, Form feed
|
||||
c == 0x000D || // Common Other, control CR, Carriage return
|
||||
c == 0x0085 || // Common Other, control NEL, Next line
|
||||
c == 0x00A0 || // no-break space Common Separator, space
|
||||
c == 0x1680 || // ogham space mark Ogham Separator, space
|
||||
c == 0x180E || // mongolian vowel separator Mongolian Separator, space
|
||||
c == 0x2000 || // en quad Common Separator, space
|
||||
c == 0x2001 || // em quad Common Separator, space
|
||||
c == 0x2002 || // en space Common Separator, space
|
||||
c == 0x2003 || // em space Common Separator, space
|
||||
c == 0x2004 || // three-per-em space Common Separator, space
|
||||
c == 0x2005 || // four-per-em space Common Separator, space
|
||||
c == 0x2006 || // six-per-em space Common Separator, space
|
||||
c == 0x2007 || // figure space Common Separator, space
|
||||
c == 0x2008 || // punctuation space Common Separator, space
|
||||
c == 0x2009 || // thin space Common Separator, space
|
||||
c == 0x200A || // hair space Common Separator, space
|
||||
c == 0x200B || // zero width space
|
||||
c == 0x200C || // zero width non-joiner
|
||||
c == 0x200D || // zero width joiner
|
||||
c == 0x2028 || // line separator Common Separator, line
|
||||
c == 0x2029 || // paragraph separator Common Separator, paragraph
|
||||
c == 0x202F || // narrow no-break space Common Separator, space
|
||||
c == 0x205F || // medium mathematical space Common Separator, space
|
||||
c == 0x2060 || // word joiner
|
||||
c == 0x3000); // ideographic space Common Separator, space
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TODO Needs better definition.
|
||||
bool unicodeLatinAlpha (unsigned int c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z');
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Digits 0-9.
|
||||
//
|
||||
// TODO This list should be derived from the Unicode database.
|
||||
bool unicodeLatinDigit (unsigned int c)
|
||||
{
|
||||
return c >= 0x30 && c <= 0x39;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Digits 0-9 a-f A-F.
|
||||
bool unicodeHexDigit (unsigned int c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,36 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_UNICODE
|
||||
#define INCLUDED_UNICODE
|
||||
|
||||
bool unicodeWhitespace (unsigned int);
|
||||
bool unicodeLatinAlpha (unsigned int);
|
||||
bool unicodeLatinDigit (unsigned int);
|
||||
bool unicodeHexDigit (unsigned int);
|
||||
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,295 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2013 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <utf8.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Converts '0' -> 0
|
||||
// '9' -> 9
|
||||
// 'a'/'A' -> 10
|
||||
// 'f'/'F' -> 15
|
||||
#define XDIGIT(x) ((x) >= '0' && (x) <= '9' ? ((x) - '0') : \
|
||||
(x) >= 'a' && (x) <= 'f' ? ((x) + 10 - 'a') : \
|
||||
(x) >= 'A' && (x) <= 'F' ? ((x) + 10 - 'A') : 0)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Note: Assumes 4-digit hex codepoints:
|
||||
// xxxx
|
||||
// \uxxxx
|
||||
// U+xxxx
|
||||
unsigned int utf8_codepoint (const std::string& input)
|
||||
{
|
||||
unsigned int codepoint = 0;
|
||||
int length = input.length ();
|
||||
|
||||
// U+xxxx, \uxxxx
|
||||
if (length >= 6 &&
|
||||
((input[0] == 'U' && input[1] == '+') ||
|
||||
(input[0] == '\\' && input[1] == 'u')))
|
||||
{
|
||||
codepoint = XDIGIT (input[2]) << 12 |
|
||||
XDIGIT (input[3]) << 8 |
|
||||
XDIGIT (input[4]) << 4 |
|
||||
XDIGIT (input[5]);
|
||||
}
|
||||
else if (length >= 4)
|
||||
{
|
||||
codepoint = XDIGIT (input[0]) << 12 |
|
||||
XDIGIT (input[1]) << 8 |
|
||||
XDIGIT (input[2]) << 4 |
|
||||
XDIGIT (input[3]);
|
||||
}
|
||||
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Iterates along a UTF8 string.
|
||||
// - argument i counts bytes advanced through the string
|
||||
// - returns the next character
|
||||
unsigned int utf8_next_char (const std::string& input, std::string::size_type& i)
|
||||
{
|
||||
if (input[i] == '\0')
|
||||
return 0;
|
||||
|
||||
// How many bytes in the sequence?
|
||||
int length = utf8_sequence (input[i]);
|
||||
i += length;
|
||||
|
||||
// 0xxxxxxx -> 0xxxxxxx
|
||||
if (length == 1)
|
||||
return input[i - 1];
|
||||
|
||||
// 110yyyyy 10xxxxxx -> 00000yyy yyxxxxxx
|
||||
if (length == 2)
|
||||
return ((input[i - 2] & 0x1F) << 6) +
|
||||
(input[i - 1] & 0x3F);
|
||||
|
||||
// 1110zzzz 10yyyyyy 10xxxxxx -> zzzzyyyy yyxxxxxx
|
||||
if (length == 3)
|
||||
return ((input[i - 3] & 0xF) << 12) +
|
||||
((input[i - 2] & 0x3F) << 6) +
|
||||
(input[i - 1] & 0x3F);
|
||||
|
||||
// 11110www 10zzzzzz 10yyyyyy 10xxxxxx -> 000wwwzz zzzzyyyy yyxxxxxx
|
||||
if (length == 4)
|
||||
return ((input[i - 4] & 0x7) << 18) +
|
||||
((input[i - 3] & 0x3F) << 12) +
|
||||
((input[i - 2] & 0x3F) << 6) +
|
||||
(input[i - 1] & 0x3F);
|
||||
|
||||
// Default: pretend as though it's a single character.
|
||||
// TODO Or should this throw?
|
||||
return input[i - 1];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://en.wikipedia.org/wiki/UTF-8
|
||||
std::string utf8_character (unsigned int codepoint)
|
||||
{
|
||||
char sequence[5] {};
|
||||
|
||||
// 0xxxxxxx -> 0xxxxxxx
|
||||
if (codepoint < 0x80)
|
||||
{
|
||||
sequence[0] = codepoint;
|
||||
}
|
||||
|
||||
// 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx
|
||||
else if (codepoint < 0x800)
|
||||
{
|
||||
sequence[0] = 0xC0 | (codepoint & 0x7C0) >> 6;
|
||||
sequence[1] = 0x80 | (codepoint & 0x3F);
|
||||
}
|
||||
|
||||
// zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx
|
||||
else if (codepoint < 0x10000)
|
||||
{
|
||||
sequence[0] = 0xE0 | (codepoint & 0xF000) >> 12;
|
||||
sequence[1] = 0x80 | (codepoint & 0xFC0) >> 6;
|
||||
sequence[2] = 0x80 | (codepoint & 0x3F);
|
||||
}
|
||||
|
||||
// 000wwwzz zzzzyyyy yyxxxxxx -> 11110www 10zzzzzz 10yyyyyy 10xxxxxx
|
||||
else if (codepoint < 0x110000)
|
||||
{
|
||||
sequence[0] = 0xF0 | (codepoint & 0x1C0000) >> 18;
|
||||
sequence[1] = 0x80 | (codepoint & 0x03F000) >> 12;
|
||||
sequence[2] = 0x80 | (codepoint & 0x0FC0) >> 6;
|
||||
sequence[3] = 0x80 | (codepoint & 0x3F);
|
||||
}
|
||||
|
||||
return std::string (sequence);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int utf8_sequence (unsigned int character)
|
||||
{
|
||||
if ((character & 0xE0) == 0xC0)
|
||||
return 2;
|
||||
|
||||
if ((character & 0xF0) == 0xE0)
|
||||
return 3;
|
||||
|
||||
if ((character & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Length of a string in characters.
|
||||
unsigned int utf8_length (const std::string& str)
|
||||
{
|
||||
int byteLength = str.length ();
|
||||
int charLength = byteLength;
|
||||
const char* data = str.data ();
|
||||
|
||||
// Decrement the number of bytes for each byte that matches 0b10??????
|
||||
// this way only the first byte of any utf8 sequence is counted.
|
||||
for (int i = 0; i < byteLength; i++)
|
||||
{
|
||||
// Extract the first two bits and check whether they are 10
|
||||
if ((data[i] & 0xC0) == 0x80)
|
||||
charLength--;
|
||||
}
|
||||
|
||||
return charLength;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Width of a string in character cells.
|
||||
unsigned int utf8_width (const std::string& str)
|
||||
{
|
||||
unsigned int length = 0;
|
||||
std::string::size_type i = 0;
|
||||
unsigned int c;
|
||||
while ((c = utf8_next_char (str, i)))
|
||||
{
|
||||
// Control characters, and more especially newline characters, make
|
||||
// mk_wcwidth() return -1. Ignore that, thereby "adding zero" to length.
|
||||
// Since control characters are not displayed in reports, this is a valid
|
||||
// choice.
|
||||
int l = mk_wcwidth (c);
|
||||
if (l != -1)
|
||||
length += l;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
unsigned int utf8_text_length (const std::string& str)
|
||||
{
|
||||
int byteLength = str.length ();
|
||||
int charLength = byteLength;
|
||||
const char* data = str.data ();
|
||||
bool in_color = false;
|
||||
|
||||
// Decrement the number of bytes for each byte that matches 0b10??????
|
||||
// this way only the first byte of any utf8 sequence is counted.
|
||||
for (int i = 0; i < byteLength; i++)
|
||||
{
|
||||
if (in_color)
|
||||
{
|
||||
if (data[i] == 'm')
|
||||
in_color = false;
|
||||
|
||||
--charLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data[i] == 033)
|
||||
{
|
||||
in_color = true;
|
||||
--charLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Extract the first two bits and check whether they are 10
|
||||
if ((data[i] & 0xC0) == 0x80)
|
||||
--charLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return charLength;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
unsigned int utf8_text_width (const std::string& str)
|
||||
{
|
||||
bool in_color = false;
|
||||
|
||||
unsigned int length = 0;
|
||||
std::string::size_type i = 0;
|
||||
unsigned int c;
|
||||
while ((c = utf8_next_char (str, i)))
|
||||
{
|
||||
if (in_color)
|
||||
{
|
||||
if (c == 'm')
|
||||
in_color = false;
|
||||
}
|
||||
else if (c == 033)
|
||||
{
|
||||
in_color = true;
|
||||
}
|
||||
else
|
||||
length += mk_wcwidth (c);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string utf8_substr (
|
||||
const std::string& input,
|
||||
unsigned int start,
|
||||
unsigned int length /* = 0 */)
|
||||
{
|
||||
// Find the starting index.
|
||||
std::string::size_type index_start = 0;
|
||||
for (unsigned int i = 0; i < start; i++)
|
||||
utf8_next_char (input, index_start);
|
||||
|
||||
std::string result;
|
||||
if (length)
|
||||
{
|
||||
std::string::size_type index_end = index_start;
|
||||
for (unsigned int i = 0; i < length; i++)
|
||||
utf8_next_char (input, index_end);
|
||||
|
||||
result = input.substr (index_start, index_end - index_start);
|
||||
}
|
||||
else
|
||||
result = input.substr (index_start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,45 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2013 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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 NONINFRINGEMENT. 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_UTF8
|
||||
#define INCLUDED_UTF8
|
||||
|
||||
#include <string>
|
||||
|
||||
unsigned int utf8_codepoint (const std::string&);
|
||||
unsigned int utf8_next_char (const std::string&, std::string::size_type&);
|
||||
std::string utf8_character (unsigned int);
|
||||
int utf8_sequence (unsigned int);
|
||||
unsigned int utf8_length (const std::string&);
|
||||
unsigned int utf8_text_length (const std::string&);
|
||||
unsigned int utf8_width (const std::string& str);
|
||||
unsigned int utf8_text_width (const std::string&);
|
||||
const std::string utf8_substr (const std::string&, unsigned int, unsigned int length = 0);
|
||||
|
||||
int mk_wcwidth (wchar_t);
|
||||
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,211 +0,0 @@
|
|||
/*
|
||||
* This is an implementation of wcwidth() and wcswidth() (defined in
|
||||
* IEEE Std 1002.1-2001) for Unicode.
|
||||
*
|
||||
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
|
||||
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
|
||||
*
|
||||
* In fixed-width output devices, Latin characters all occupy a single
|
||||
* "cell" position of equal width, whereas ideographic CJK characters
|
||||
* occupy two such cells. Interoperability between terminal-line
|
||||
* applications and (teletype-style) character terminals using the
|
||||
* UTF-8 encoding requires agreement on which character should advance
|
||||
* the cursor by how many cell positions. No established formal
|
||||
* standards exist at present on which Unicode character shall occupy
|
||||
* how many cell positions on character terminals. These routines are
|
||||
* a first attempt of defining such behavior based on simple rules
|
||||
* applied to data provided by the Unicode Consortium.
|
||||
*
|
||||
* For some graphical characters, the Unicode standard explicitly
|
||||
* defines a character-cell width via the definition of the East Asian
|
||||
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
|
||||
* In all these cases, there is no ambiguity about which width a
|
||||
* terminal shall use. For characters in the East Asian Ambiguous (A)
|
||||
* class, the width choice depends purely on a preference of backward
|
||||
* compatibility with either historic CJK or Western practice.
|
||||
* Choosing single-width for these characters is easy to justify as
|
||||
* the appropriate long-term solution, as the CJK practice of
|
||||
* displaying these characters as double-width comes from historic
|
||||
* implementation simplicity (8-bit encoded characters were displayed
|
||||
* single-width and 16-bit ones double-width, even for Greek,
|
||||
* Cyrillic, etc.) and not any typographic considerations.
|
||||
*
|
||||
* Much less clear is the choice of width for the Not East Asian
|
||||
* (Neutral) class. Existing practice does not dictate a width for any
|
||||
* of these characters. It would nevertheless make sense
|
||||
* typographically to allocate two character cells to characters such
|
||||
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
|
||||
* represented adequately with a single-width glyph. The following
|
||||
* routines at present merely assign a single-cell width to all
|
||||
* neutral characters, in the interest of simplicity. This is not
|
||||
* entirely satisfactory and should be reconsidered before
|
||||
* establishing a formal standard in this area. At the moment, the
|
||||
* decision which Not East Asian (Neutral) characters should be
|
||||
* represented by double-width glyphs cannot yet be answered by
|
||||
* applying a simple rule from the Unicode database content. Setting
|
||||
* up a proper standard for the behavior of UTF-8 character terminals
|
||||
* will require a careful analysis not only of each Unicode character,
|
||||
* but also of each presentation form, something the author of these
|
||||
* routines has avoided to do so far.
|
||||
*
|
||||
* http://www.unicode.org/unicode/reports/tr11/
|
||||
*
|
||||
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* for any purpose and without fee is hereby granted. The author
|
||||
* disclaims all warranties with regard to this software.
|
||||
*
|
||||
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
*/
|
||||
|
||||
#include <cmake.h>
|
||||
#include <wchar.h>
|
||||
|
||||
struct interval {
|
||||
int first;
|
||||
int last;
|
||||
};
|
||||
|
||||
/* auxiliary function for binary search in interval table */
|
||||
static int bisearch(wchar_t ucs, const struct interval *table, int max) {
|
||||
int min = 0;
|
||||
int mid;
|
||||
|
||||
if (ucs < table[0].first || ucs > table[max].last)
|
||||
return 0;
|
||||
while (max >= min) {
|
||||
mid = (min + max) / 2;
|
||||
if (ucs > table[mid].last)
|
||||
min = mid + 1;
|
||||
else if (ucs < table[mid].first)
|
||||
max = mid - 1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The following two functions define the column width of an ISO 10646
|
||||
* character as follows:
|
||||
*
|
||||
* - The null character (U+0000) has a column width of 0.
|
||||
*
|
||||
* - Other C0/C1 control characters and DEL will lead to a return
|
||||
* value of -1.
|
||||
*
|
||||
* - Non-spacing and enclosing combining characters (general
|
||||
* category code Mn or Me in the Unicode database) have a
|
||||
* column width of 0.
|
||||
*
|
||||
* - SOFT HYPHEN (U+00AD) has a column width of 1.
|
||||
*
|
||||
* - Other format characters (general category code Cf in the Unicode
|
||||
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
|
||||
*
|
||||
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
|
||||
* have a column width of 0.
|
||||
*
|
||||
* - Spacing characters in the East Asian Wide (W) or East Asian
|
||||
* Full-width (F) category as defined in Unicode Technical
|
||||
* Report #11 have a column width of 2.
|
||||
*
|
||||
* - All remaining characters (including all printable
|
||||
* ISO 8859-1 and WGL4 characters, Unicode control characters,
|
||||
* etc.) have a column width of 1.
|
||||
*
|
||||
* This implementation assumes that wchar_t characters are encoded
|
||||
* in ISO 10646.
|
||||
*/
|
||||
|
||||
int mk_wcwidth(wchar_t ucs)
|
||||
{
|
||||
/* sorted list of non-overlapping intervals of non-spacing characters */
|
||||
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
|
||||
static const struct interval combining[] = {
|
||||
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
|
||||
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
|
||||
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
|
||||
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
|
||||
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
|
||||
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
|
||||
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
|
||||
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
|
||||
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
|
||||
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
|
||||
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
|
||||
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
|
||||
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
|
||||
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
|
||||
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
|
||||
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
|
||||
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
|
||||
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
|
||||
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
|
||||
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
|
||||
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
|
||||
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
|
||||
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
|
||||
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
|
||||
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
|
||||
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
|
||||
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
|
||||
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
|
||||
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
|
||||
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
|
||||
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
|
||||
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
|
||||
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
|
||||
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
|
||||
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
|
||||
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
|
||||
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
|
||||
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
|
||||
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
|
||||
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
|
||||
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
|
||||
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
|
||||
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
|
||||
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
|
||||
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
|
||||
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
|
||||
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
|
||||
{ 0xE0100, 0xE01EF }
|
||||
};
|
||||
|
||||
/* test for 8-bit control characters */
|
||||
if (ucs == 0)
|
||||
return 0;
|
||||
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
|
||||
return -1;
|
||||
|
||||
/* binary search in table of non-spacing characters */
|
||||
if (bisearch(ucs, combining,
|
||||
sizeof(combining) / sizeof(struct interval) - 1))
|
||||
return 0;
|
||||
|
||||
/* if we arrive here, ucs is not a combining or C0/C1 control character */
|
||||
|
||||
return 1 +
|
||||
(ucs >= 0x1100 &&
|
||||
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
|
||||
ucs == 0x2329 || ucs == 0x232a ||
|
||||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
|
||||
ucs != 0x303f) || /* CJK ... Yi */
|
||||
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
|
||||
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
|
||||
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
|
||||
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
|
||||
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
|
||||
(ucs >= 0xffe0 && ucs <= 0xffe6)
|
||||
#ifndef CYGWIN
|
||||
||
|
||||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
|
||||
(ucs >= 0x30000 && ucs <= 0x3fffd)
|
||||
#endif
|
||||
)
|
||||
);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue