diff --git a/rak/error_number.h b/rak/error_number.h index 224c3b0b..64fbfbb5 100644 --- a/rak/error_number.h +++ b/rak/error_number.h @@ -44,11 +44,12 @@ namespace rak { class error_number { public: + static const int e_access = EACCES; static const int e_again = EAGAIN; - static const int e_intr = EINTR; - static const int e_deadlk = EDEADLK; static const int e_connreset = ECONNRESET; static const int e_connaborted = ECONNABORTED; + static const int e_deadlk = EDEADLK; + static const int e_intr = EINTR; error_number() : m_errno(0) {} error_number(int e) : m_errno(e) {} @@ -66,6 +67,8 @@ public: static error_number current() { return errno; } static void clear_global() { errno = 0; } + bool operator == (const error_number& e) const { return m_errno == e.m_errno; } + private: int m_errno; }; diff --git a/rak/file_stat.h b/rak/file_stat.h index 7fec55f0..b14abcda 100644 --- a/rak/file_stat.h +++ b/rak/file_stat.h @@ -72,77 +72,3 @@ private: } #endif -// rak - Rakshasa's toolbox -// Copyright (C) 2005-2006, Jari Sundell -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - -#ifndef RAK_FILE_STAT_H -#define RAK_FILE_STAT_H - -#include -#include -#include - -namespace rak { - -class file_stat { -public: - // Consider storing rak::error_number. - - bool update(int fd) { return fstat(fd, &m_stat) == 0; } - bool update(const char* filename) { return stat(filename, &m_stat) == 0; } - bool update(const std::string& filename) { return update(filename.c_str()); } - - bool is_regular() const { return S_ISREG(m_stat.st_mode); } - bool is_directory() const { return S_ISDIR(m_stat.st_mode); } - bool is_character() const { return S_ISCHR(m_stat.st_mode); } - bool is_block() const { return S_ISBLK(m_stat.st_mode); } - bool is_fifo() const { return S_ISFIFO(m_stat.st_mode); } - bool is_link() const { return S_ISLNK(m_stat.st_mode); } - bool is_socket() const { return S_ISSOCK(m_stat.st_mode); } - - off_t size() const { return m_stat.st_size; } - - time_t access_time() const { return m_stat.st_atime; } - time_t change_time() const { return m_stat.st_ctime; } - time_t modified_time() const { return m_stat.st_mtime; } - -private: - struct stat m_stat; -}; - -} - -#endif diff --git a/rak/partial_queue.h b/rak/partial_queue.h new file mode 100644 index 00000000..21f3523a --- /dev/null +++ b/rak/partial_queue.h @@ -0,0 +1,198 @@ +// rak - Rakshasa's toolbox +// Copyright (C) 2005-2006, Jari Sundell +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RAK_PARTIAL_QUEUE_H +#define RAK_PARTIAL_QUEUE_H + +#include +#include +#include + +namespace rak { + +// First step, don't allow overflowing to the next layer. Only disable +// the above layers for now. + +// We also include 0 in a single layer as some chunk may be available +// only through seeders. + +class partial_queue { +public: + typedef uint8_t key_type; + typedef uint32_t mapped_type; + typedef uint16_t size_type; + typedef std::pair size_pair_type; + + static const size_type num_layers = 8; + + partial_queue() : m_data(NULL), m_maxLayerSize(0) {} + ~partial_queue() { disable(); } + + bool is_full() const { return m_ceiling == 0; } + bool is_layer_full(size_type l) const { return m_layers[l].second >= m_maxLayerSize; } + + bool is_enabled() const { return m_data != NULL; } + + // Add check to see if we can add more. Also make it possible to + // check how full we are in the lower parts so the caller knows when + // he can stop searching. + // + // Though propably not needed, as we must continue til the first + // layer is full. + + size_type max_size() const { return m_maxLayerSize * num_layers; } + size_type max_layer_size() const { return m_maxLayerSize; } + + // Must be less that or equal to (max size_type) / num_layers. + void enable(size_type ls); + void disable(); + + void clear(); + + // Safe to call while pop'ing and it will not reuse pop'ed indices + // so it is guaranteed to reach max_size at some point. This will + // ensure that the user needs to refill with new data at regular + // intervals. + bool insert(key_type key, mapped_type value); + + // Only call this when pop'ing as it moves the index. + bool prepare_pop(); + + mapped_type pop(); + +private: + partial_queue(const partial_queue&); + void operator = (const partial_queue&); + + static size_type ceiling(size_type layer) { return (2 << layer) - 1; } + + void find_non_empty(); + + mapped_type* m_data; + size_type m_maxLayerSize; + + size_type m_index; + size_type m_ceiling; + + size_pair_type m_layers[num_layers]; +}; + +inline void +partial_queue::enable(size_type ls) { + if (ls == 0) + throw std::logic_error("partial_queue::enable(...) ls == 0."); + + delete [] m_data; + m_data = new mapped_type[ls * num_layers]; + + m_maxLayerSize = ls; +} + +inline void +partial_queue::disable() { + delete [] m_data; + m_data = NULL; + + m_maxLayerSize = 0; +} + +inline void +partial_queue::clear() { + if (m_data == NULL) + return; + + m_index = 0; + m_ceiling = ceiling(num_layers - 1); + + std::memset(m_layers, 0, num_layers * sizeof(size_pair_type)); +} + +inline bool +partial_queue::insert(key_type key, mapped_type value) { + if (key >= m_ceiling) + return false; + + size_type idx = 0; + + // Hmm... since we already check the 'm_ceiling' above, we only need + // to find the target layer. Could this be calculated directly? + while (key >= ceiling(idx)) + ++idx; + + m_index = std::min(m_index, idx); + + // Currently don't allow overflow. + if (is_layer_full(idx)) + throw std::logic_error("partial_queue::insert(...) layer already full."); + //return false; + + m_data[m_maxLayerSize * idx + m_layers[idx].second] = value; + m_layers[idx].second++; + + if (is_layer_full(idx)) + // Set the ceiling to 0 when layer 0 is full so no more values can + // be inserted. + m_ceiling = idx > 0 ? ceiling(idx - 1) : 0; + + return true; +} + +// is_empty() will iterate to the first layer with un-popped elements +// and return true, else return false when it reaches a overflowed or +// the last layer. +inline bool +partial_queue::prepare_pop() { + while (m_layers[m_index].first == m_layers[m_index].second) { + if (is_layer_full(m_index) || m_index + 1 == num_layers) + return false; + + m_index++; + } + + return true; +} + +inline partial_queue::mapped_type +partial_queue::pop() { + if (m_index >= num_layers || m_layers[m_index].first >= m_layers[m_index].second) + throw std::logic_error("partial_queue::pop() bad state."); + + return m_data[m_index * m_maxLayerSize + m_layers[m_index].first++]; +} + +} + +#endif diff --git a/rak/string_manip.h b/rak/string_manip.h index 5ed3942f..f21b0bfc 100644 --- a/rak/string_manip.h +++ b/rak/string_manip.h @@ -78,6 +78,37 @@ Sequence trim(const Sequence& seq) { return trim_begin(trim_end(seq)); } +template +Sequence trim_begin_classic(const Sequence& seq) { + if (seq.empty() || !std::isspace(*seq.begin(), std::locale::classic())) + return seq; + + typename Sequence::size_type pos = 0; + + while (pos != seq.length() && std::isspace(seq[pos], std::locale::classic())) + pos++; + + return seq.substr(pos, seq.length() - pos); +} + +template +Sequence trim_end_classic(const Sequence& seq) { + if (seq.empty() || !std::isspace(*(--seq.end()), std::locale::classic())) + return seq; + + typename Sequence::size_type pos = seq.size(); + + while (pos != 0 && std::isspace(seq[pos - 1], std::locale::classic())) + pos--; + + return seq.substr(0, pos); +} + +template +Sequence trim_classic(const Sequence& seq) { + return trim_begin_classic(trim_end_classic(seq)); +} + // Consider rewritting such that m_seq is replaced by first/last. template class split_iterator_t { @@ -159,8 +190,8 @@ template OutputIterator copy_escape_html(InputIterator first, InputIterator last, OutputIterator dest) { while (first != last) { - if (std::isalpha(*first) || - std::isdigit(*first) || + if (std::isalpha(*first, std::locale::classic()) || + std::isdigit(*first, std::locale::classic()) || *first == '-') { *(dest++) = *first; diff --git a/src/display/canvas.h b/src/display/canvas.h index 9cb8224b..1d5e59f3 100644 --- a/src/display/canvas.h +++ b/src/display/canvas.h @@ -111,6 +111,10 @@ public: void print(int x, int y, char* str, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { mvwprintw(m_window, y, x, str, a1, a2, a3, a4, a5, a6, a7, a8); } + void print_char(const chtype ch) { waddch(m_window, ch); } + + void print_char(int x, int y, const chtype ch) { mvwaddch(m_window, y, x, ch); } + void set_attr(int x, int y, int n, int attr, int color) { mvwchgat(m_window, y, x, n, attr, color, NULL); } // Initialize stdscr. diff --git a/src/display/client_info.cc b/src/display/client_info.cc index b2e787e7..af7f1138 100644 --- a/src/display/client_info.cc +++ b/src/display/client_info.cc @@ -62,7 +62,7 @@ struct client_info_equal { }; ClientInfo::ClientInfo() { - m_containers[TYPE_AZUREUS].reserve(28); + m_containers[TYPE_AZUREUS].reserve(30); insert(TYPE_AZUREUS, "AZ", "Azureus"); insert(TYPE_AZUREUS, "BC", "BitComet"); @@ -85,6 +85,7 @@ ClientInfo::ClientInfo() { insert(TYPE_AZUREUS, "QT", "Qt 4 Torrent example"); insert(TYPE_AZUREUS, "SZ", "Shareaza"); insert(TYPE_AZUREUS, "RT", "Retriever"); + insert(TYPE_AZUREUS, "CD", "Enhanced CTorrent"); m_containers[TYPE_COMPACT].reserve(10); @@ -94,7 +95,7 @@ ClientInfo::ClientInfo() { insert(TYPE_COMPACT, "U", "UPnP NAT Bit Torrent"); insert(TYPE_COMPACT, "O", "Osprey Permaseed"); - m_containers[TYPE_MAINLINE].reserve(4); + m_containers[TYPE_MAINLINE].reserve(5); insert(TYPE_MAINLINE, "M", "Mainline"); } diff --git a/src/display/window_download_chunks_seen.cc b/src/display/window_download_chunks_seen.cc index dbf9b916..8512f5c1 100644 --- a/src/display/window_download_chunks_seen.cc +++ b/src/display/window_download_chunks_seen.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include "core/download.h" @@ -72,30 +73,34 @@ WindowDownloadChunksSeen::redraw() { return; } - char buffer[m_canvas->get_width()]; - char* position; - char* end = buffer + m_canvas->get_width() - 2; - const uint8_t* chunk = seen; const uint8_t* last = seen + m_download->download()->chunks_total(); + const torrent::Bitfield* bitfield = m_download->download()->bitfield(); + for (int y = 1; y < m_canvas->get_height() && chunk < last; ++y) { - position = buffer + std::max(snprintf(buffer, end - buffer, "%5d", (int)(chunk - seen)), 0); + m_canvas->print(0, y, "%5d ", (int)(chunk - seen)); while (chunk < last) { + chtype attr; + + if (bitfield->get(chunk - seen)) + attr = A_NORMAL; +// else if (foo->is_downloading(chunk - seen)) +// attr = A_UNDERLINE; + else + attr = A_BOLD; + + m_canvas->print_char(attr | rak::value_to_hexchar<0>(std::min(*chunk, 0xF))); + chunk++; + if ((chunk - seen) % 10 == 0) { - if (end - position < 11) + if (m_canvas->get_x() + 12 > m_canvas->get_width()) break; - *position++ = ' '; + m_canvas->print_char(' '); } - - *position++ = rak::value_to_hexchar<0>(std::min(*chunk, 0xF)); - chunk++; } - - *position = 0; - m_canvas->print(0, y, "%s", buffer); } } diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc index 61590f83..1d3882c6 100644 --- a/src/display/window_peer_list.cc +++ b/src/display/window_peer_list.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include "core/download.h" #include "rak/algorithm.h" @@ -120,7 +121,7 @@ WindowPeerList::redraw() { x += 6; if (p.incoming_queue_size()) - m_canvas->print(x, y, "%i", p.incoming_index(0)); + m_canvas->print(x, y, "%i", p.incoming_queue(0)->index()); x += 6;