ref: refs/heads/master
commit c8a01e4463c302bf9a8fa076b763afffba3d6084
Author: Ján Kupec
Date: Tue Mar 24 12:07:08 2009 +0100
Text processing functions added.
- string_to_columns() taken out of Table to text.h
- get_screen_width() taken out of Table to misc.h
- wrap_text() added to text.h
---
src/CMakeLists.txt | 2 +
src/Table.cc | 72 ++------------------------
src/utils/misc.cc | 23 ++++++++
src/utils/misc.h | 16 ++++--
src/utils/text.cc | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/utils/text.h | 25 +++++++++
6 files changed, 210 insertions(+), 71 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 18229f8..dae4a9f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -68,6 +68,7 @@ SET( zypper_utils_HEADERS
utils/pager.h
utils/prompt.h
utils/richtext.h
+ utils/text.h
)
SET( zypper_utils_SRCS
@@ -79,6 +80,7 @@ SET( zypper_utils_SRCS
utils/pager.cc
utils/prompt.cc
utils/richtext.cc
+ utils/text.cc
${zypper_utils_HEADERS}
)
diff --git a/src/Table.cc b/src/Table.cc
index cdaa4be..921a0c6 100644
--- a/src/Table.cc
+++ b/src/Table.cc
@@ -2,10 +2,12 @@
#include <cstring>
#include <cstdlib>
#include
-#include
#include "zypp/base/Logger.h"
+#include "utils/misc.h"
+#include "utils/text.h"
+
#include "Table.h"
// libzypp logger settings
@@ -31,50 +33,6 @@ const char * lines[][3] = {
{ "\xE2\x95\x91", "\xE2\x94\x80", "\xE2\x95\xAB"}, ///< v double, h light
};
-// A non-ASCII string has 3 different lengths:
-// - bytes
-// - characters (non-ASCII ones have multiple bytes in UTF-8)
-// - columns (Chinese characters are 2 columns wide)
-// In #328918 see how confusing these leads to misalignment.
-
-// return the number of columns in str, or -1 if there's an error
-static
-int string_to_columns_e (const string& str) {
- // from smpppd.src.rpm/format.cc, thanks arvin
-
- const char* ptr = str.c_str ();
- size_t s_bytes = str.length ();
- int s_cols = 0;
-
- mbstate_t shift_state;
- memset (&shift_state, 0, sizeof (shift_state));
-
- wchar_t wc;
- size_t c_bytes;
-
- // mbrtowc produces one wide character from a multibyte string
- while ((c_bytes = mbrtowc (&wc, ptr, s_bytes, &shift_state)) > 0) {
- if (c_bytes >= (size_t) -2) // incomplete (-2) or invalid (-1) sequence
- return -1;
-
- s_cols += wcwidth (wc);
-
- s_bytes -= c_bytes;
- ptr += c_bytes;
- }
-
- return s_cols;
-}
-
-static
-unsigned string_to_columns (const string& str) {
- int c = string_to_columns_e (str);
- if (c < 0)
- return str.length(); // fallback if there was an error
- else
- return (unsigned) c;
-}
-
void TableRow::add (const string& s) {
_columns.push_back (s);
}
@@ -136,27 +94,9 @@ Table::Table() :
_has_header (false),
_max_col (0),
_width(0),
- _style (defaultStyle)
-{
- //! \todo move this to utils
-
- const char *cols_env = getenv("COLUMNS");
- if (cols_env)
- _screen_width = ::atoi (cols_env);
- else
- {
- ::rl_initialize();
- //::rl_reset_screen_size();
- ::rl_get_screen_size (NULL, &_screen_width);
- DBG << "readline says we have " << _screen_width << " char wide console screen" << endl;
- }
-
- // safe default
- if (!_screen_width)
- _screen_width = 80;
-
- DBG << "got screen width of " << _screen_width << endl;
-}
+ _style (defaultStyle),
+ _screen_width(get_screen_width())
+{}
void Table::add (const TableRow& tr) {
_rows.push_back (tr);
diff --git a/src/utils/misc.cc b/src/utils/misc.cc
index 04ab29f..83d0d04 100644
--- a/src/utils/misc.cc
+++ b/src/utils/misc.cc
@@ -59,6 +59,29 @@ string readline_getline()
// ----------------------------------------------------------------------------
+unsigned get_screen_width()
+{
+ int width = 80;
+
+ const char *cols_env = getenv("COLUMNS");
+ if (cols_env)
+ width = ::atoi (cols_env);
+ else
+ {
+ ::rl_initialize();
+ //::rl_reset_screen_size();
+ ::rl_get_screen_size (NULL, &width);
+ }
+
+ // safe default
+ if (!width)
+ width = 80;
+
+ return width;
+}
+
+// ----------------------------------------------------------------------------
+
bool is_changeable_media(const zypp::Url & url)
{
MIL << "Checking if this is a changeable medium" << endl;
diff --git a/src/utils/misc.h b/src/utils/misc.h
index ffc3088..67f9b7f 100644
--- a/src/utils/misc.h
+++ b/src/utils/misc.h
@@ -34,6 +34,12 @@ typedef std::setzypp::ResKind ResKindSet;
std::string readline_getline();
+/**
+ * Reads COLUMNS environment variable or gets the screen width from readline,
+ * in that order. Falls back to 80 if all that fails.
+ */
+unsigned get_screen_width();
+
bool is_changeable_media(const zypp::Url & url);
std::string kind_to_string_localized(
@@ -47,29 +53,29 @@ bool equalNVRA(const zypp::Resolvable & lhs, const zypp::Resolvable & rhs);
* Creates a Url out of \a urls_s. If the url_s looks looks_like_url()
* Url(url_s) is returned. Otherwise if \a url_s represends a valid path to
* a file or directory, a dir:// Url is returned. Otherwise an empty Url is
- * returned.
+ * returned.
*/
zypp::Url make_url (const std::string & url_s);
/**
* Returns <code>true</code> if the string \a s contains a substring starting
* at the beginning and ending before the first colon matches any of registered
- * schemes (Url::isRegisteredScheme()).
+ * schemes (Url::isRegisteredScheme()).
*/
bool looks_like_url (const std::string& s);
/**
* Returns <code>true</code> if \a s ends with ".rpm" or starts with "/", "./",
- * or "../".
+ * or "../".
*/
bool looks_like_rpm_file(const std::string & s);
/**
* Download the RPM file specified by \a rpm_uri_str and copy it into
* \a cache_dir.
- *
+ *
* \return The local Pathname of the file in the cache on success, empty
- * Pathname if a problem occurs.
+ * Pathname if a problem occurs.
*/
zypp::Pathname cache_rpm(const std::string & rpm_uri_str,
const std::string & cache_dir);
diff --git a/src/utils/text.cc b/src/utils/text.cc
new file mode 100644
index 0000000..e58a32e
--- /dev/null
+++ b/src/utils/text.cc
@@ -0,0 +1,143 @@
+/*---------------------------------------------------------------------------*\
+ ____ _ _ __ _ __ ___ _ _
+ |_ / || | '_ \ '_ \/ -_) '_|
+ /__|\_, | .__/ .__/\___|_|
+ |__/|_| |_|
+\*---------------------------------------------------------------------------*/
+
+#include
+#include <cstring>
+#include <sstream>
+
+#include "utils/text.h"
+
+using namespace std;
+
+// A non-ASCII string has 3 different lengths:
+// - bytes
+// - characters (non-ASCII ones have multiple bytes in UTF-8)
+// - columns (Chinese characters are 2 columns wide)
+// In #328918 see how confusing these leads to misalignment.
+
+// return the number of columns in str, or -1 if there's an error
+static
+int string_to_columns_e (const string & str)
+{
+ // from smpppd.src.rpm/format.cc, thanks arvin
+
+ const char* ptr = str.c_str ();
+ size_t s_bytes = str.length ();
+ int s_cols = 0;
+
+ mbstate_t shift_state;
+ memset (&shift_state, 0, sizeof (shift_state));
+
+ wchar_t wc;
+ size_t c_bytes;
+
+ // mbrtowc produces one wide character from a multibyte string
+ while ((c_bytes = mbrtowc (&wc, ptr, s_bytes, &shift_state)) > 0)
+ {
+ if (c_bytes >= (size_t) -2) // incomplete (-2) or invalid (-1) sequence
+ return -1;
+
+ s_cols += wcwidth (wc);
+
+ s_bytes -= c_bytes;
+ ptr += c_bytes;
+ }
+
+ return s_cols;
+}
+
+unsigned string_to_columns (const string& str)
+{
+ int c = string_to_columns_e (str);
+ if (c < 0)
+ return str.length(); // fallback if there was an error
+ else
+ return (unsigned) c;
+}
+
+
+void wrap_text(ostream & out, const string & text,
+ unsigned indent, unsigned wrap_width, int initial)
+{
+ const char * s = text.c_str();
+ size_t s_bytes = text.length ();
+ const char * prevwp = s;
+ const char * linep = s;
+ wchar_t wc;
+ size_t bytes_read;
+ bool in_word = false;
+
+ mbstate_t shift_state;
+ memset (&shift_state, 0, sizeof (shift_state));
+
+ unsigned col = 0;
+ unsigned toindent = initial < 0 ? indent : initial;
+ //wchar_t ws[2] = L" ";
+ do
+ {
+ // indentation
+ if (!col)
+ {
+ out << string(toindent, ' ');
+ col = toindent;
+ }
+
+ bytes_read = mbrtowc (&wc, s, s_bytes, &shift_state);
+ if (bytes_read > 0)
+ {
+ col += ::wcwidth(wc);
+
+ if (::iswspace(wc))
+ in_word = false;
+ //else if (::wcscmp(wc, L"\n"))
+ //{
+ // if (!in_word)
+ // prevwp = s;
+ // in_word = true;
+ //}
+ else
+ {
+ if (!in_word)
+ prevwp = s;
+ in_word = true;
+ }
+
+ // current wc exceeded the wrap width
+ if (col > wrap_width)
+ {
+ // update the size of the string to read
+ s_bytes -= (prevwp - linep);
+ // print the line, leave linep point to the start of the last word.
+ for (; linep < prevwp; ++linep)
+ out << *linep;
+ out << endl;
+ // reset column counter
+ col = 0;
+ toindent = indent;
+ // reset original text pointer (points to current wc, not the start of the word)
+ s = linep;
+ // reset shift state
+ ::memset (&shift_state, 0, sizeof (shift_state));
+ }
+ else
+ s += bytes_read;
+ }
+ // we're at the end of the string
+ else if (bytes_read == 0)
+ {
+ // print the rest of the text
+ for(; *linep; ++linep)
+ out << *linep;
+ }
+ else
+ {
+ out << endl << "WCHAR ERROR" << endl;
+ return;
+ }
+ }
+ while(bytes_read > 0);
+}
diff --git a/src/utils/text.h b/src/utils/text.h
new file mode 100644
index 0000000..010a15d
--- /dev/null
+++ b/src/utils/text.h
@@ -0,0 +1,25 @@
+/*---------------------------------------------------------------------------*\
+ ____ _ _ __ _ __ ___ _ _
+ |_ / || | '_ \ '_ \/ -_) '_|
+ /__|\_, | .__/ .__/\___|_|
+ |__/|_| |_|
+\*---------------------------------------------------------------------------*/
+
+#ifndef ZYPPER_UTILS_TEXT_H_
+#define ZYPPER_UTILS_TEXT_H_
+
+#include <string>
+#include <iosfwd>
+
+/** Returns the length of the string in columns */
+/*
+ * TODO
+ * - delete whitespace at the end of lines
+ * - keep one-letter words with the next
+ */
+unsigned string_to_columns (const std::string & str);
+
+void wrap_text(std::ostream & out, const std::string & text,
+ unsigned indent, unsigned wrap_width, int initial = -1);
+
+#endif /* ZYPPER_UTILS_TEXT_H_ */
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org