diff options
Diffstat (limited to 'dwarflint/wrap.cc')
-rw-r--r-- | dwarflint/wrap.cc | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/dwarflint/wrap.cc b/dwarflint/wrap.cc new file mode 100644 index 00000000..6d40ee02 --- /dev/null +++ b/dwarflint/wrap.cc @@ -0,0 +1,168 @@ +/* Pedantic checking of DWARF files + + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wrap.hh" +#include <cassert> +#include <cstring> + +namespace +{ + size_t + skip_blank (char const *str, size_t pos) + { + while (isblank (str[pos])) + pos++; + return pos; + } +} + +wrapline_t::wrapline_t (size_t start, size_t end, size_t indent) + : _m_start (start) + , _m_end (end) + , _m_indent (indent) +{ + assert (end >= start); +} + +std::string +wrapline_t::build (char const *image) const +{ + assert (_m_end <= std::strlen (image)); + std::string main (image, _m_start, _m_end - _m_start); + char const *padding = spaces (_m_indent); + return std::string (padding) + main; +} + +wrap_str::wrap_str (char const *str, unsigned width) + : _m_image (str) +{ + size_t pos = 0; + bool newline = true; + size_t indent = 0; + size_t str_size = std::strlen (str); + while (pos < str_size) + { + size_t last = pos; + + // This is how long a line we can allocate. + size_t length = width; + + // For newlines, i.e. right after hard EOL (\n) in input string, + // we look for indentation and bullets. + if (newline) + { + pos = skip_blank (str, pos); + if (pos < str_size && str[pos] == '-') + pos = skip_blank (str, pos + 1); + indent = pos - last; + } + length -= indent; + + // Take the remainder of the line, but don't cross hard EOLs. + for (; length > 0 && pos < str_size; --length) + if (str[pos] == '\n') + break; + else + pos++; + + // We may have ended mid-word. Look back to first white space. + // Look as far back as the end of previous line. + size_t space = pos; + for (; space > last; --space) + if (space == str_size || isspace (str[space])) + break; + + // While skipping back, we might end at the very beginning. If + // that's the case, we have a word that doesn't fit user limit. + // Include it whole anyway. For newline, account for + // freshly-introduced indent. + if (space <= last + (newline ? indent : 0)) + { + space = pos; + while (space < str_size && !isspace (str[space])) + space++; + } + + // We have a line! + push_back (wrapline_t (last, space, newline ? 0 : indent)); + + // Skip useless white space at the end of the line, up to EOL. + while (space < str_size && isspace (str[space]) && str[space] != '\n') + space++; + + if (str[space] == '\n') + { + space++; + indent = 0; + newline = true; + } + else + newline = false; + + pos = space; + } +} + +std::string +wrap_str::join () const +{ + std::string ret; + for (const_iterator it = begin (); it != end (); ++it) + ret += build (it) + "\n"; + return ret; +} + +std::string +wrap_str::build (wrap_str::const_iterator it) const +{ + return it->build (_m_image); +} + +namespace +{ + template <unsigned Max> + class spc + { + char *_m_buf; + char *_m_endp; + public: + spc () + : _m_buf (new char[Max]) + , _m_endp (_m_buf + Max - 1) + { + std::memset (_m_buf, ' ', Max - 1); + _m_buf[Max - 1] = 0; + } + ~spc () + { + delete [] _m_buf; + } + char const *get (size_t n) + { + assert (n < Max); + return _m_endp - n; + } + }; +} + +char const * +spaces (size_t n) +{ + static spc<128> spaces; + return spaces.get (n); +} |