diff options
Diffstat (limited to 'src/Fl_Help_View.cxx')
| -rw-r--r-- | src/Fl_Help_View.cxx | 568 |
1 files changed, 382 insertions, 186 deletions
diff --git a/src/Fl_Help_View.cxx b/src/Fl_Help_View.cxx index 0b55393ee..3f0c38bba 100644 --- a/src/Fl_Help_View.cxx +++ b/src/Fl_Help_View.cxx @@ -35,7 +35,7 @@ #include "flstring.h" // -// System and C++ header files +// System header files // #include <stdio.h> @@ -44,9 +44,7 @@ #include <ctype.h> #include <errno.h> #include <math.h> -#include <map> -#include <vector> -#include <string> +#include <string.h> // // Debugging @@ -88,14 +86,22 @@ public: textsize_ = 12; value_ = 0; - blocks_.clear(); + blocks_ = 0; + blocks_count_ = 0; + blocks_alloc_ = 0; link_ = (Fl_Help_Func *)0; - link_list_.clear(); + link_list_ = 0; + link_list_count_ = 0; + link_list_alloc_ = 0; - directory_.clear(); - filename_.clear(); + targets_ = 0; + targets_count_ = 0; + targets_alloc_ = 0; + + directory_ = 0; + filename_ = 0; topline_ = 0; leftline_ = 0; @@ -120,9 +126,11 @@ public: /** Helper class to manage margins in Fl_Help_View. */ class Margin_Stack { - std::vector<int> margins_; + enum { MAX_MARGINS = 64 }; + int margins_[MAX_MARGINS]; + int count_; public: - Margin_Stack() = default; + Margin_Stack() : count_(0) {} void clear(); int current() const; int pop(); @@ -134,11 +142,23 @@ public: allow buffer management to avoid buffer overflows in stack variables used to edit strings for formatting and drawing (STR #3275). */ - class Edit_Buffer : public std::string { + class Edit_Buffer { + char *buf_; + int len_; + int alloc_; + void ensure(int needed); public: + Edit_Buffer(); + ~Edit_Buffer(); void add(int ucs); int cmp(const char *str); int width() const; + void clear(); + void append(const char *s, int n); + Edit_Buffer &operator+=(char c); + char operator[](int i) const { return (buf_ && i >= 0 && i < len_) ? buf_[i] : '\0'; } + const char *c_str() const { return buf_ ? buf_ : ""; } + int size() const { return len_; } }; /** Private struct to describe blocks of text. */ @@ -158,9 +178,11 @@ public: /** Private class to hold a link with target and its position on screen. */ struct Link { - std::string filename_; // Filename part of a link - std::string target; // Target part of a link + char *filename_; // Filename part of a link (malloc'd) + char *target; // Target part of a link (malloc'd) Fl_Rect box; // Clickable rectangle that defines the link area + Link() : filename_(0), target(0) {} + ~Link() { if (filename_) free(filename_); if (target) free(target); } }; /** Private font stack element definition. */ @@ -176,13 +198,15 @@ public: /** Private class to hold font information on a stack. */ struct Font_Stack { + enum { MAX_FONTS = 100 }; void init(Fl_Font f, Fl_Fontsize s, Fl_Color c); void top(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c); void push(Fl_Font f, Fl_Fontsize s, Fl_Color c); void pop(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c); - size_t count() const; + int count() const; private: - std::vector<Font_Style> elts_; ///< font elements + Font_Style elts_[MAX_FONTS]; ///< font elements + int count_; ///< number of elements on stack }; enum { ALIGN_RIGHT = -1, ALIGN_CENTER, ALIGN_LEFT }; ///< Alignments @@ -193,16 +217,24 @@ public: // HTML source and raw data const char *value_; ///< Copy of raw HTML text, as set by `value()` or `load()` - std::string directory_; ///< Directory for current document - std::string filename_; ///< Original file name from `load()` + char *directory_; ///< Directory for current document (malloc'd) + char *filename_; ///< Original file name from `load()` (malloc'd) // HTML document data - std::string title_; ///< Title string from <title> tag + char title_[256]; ///< Title string from <title> tag Font_Stack fstack_; ///< Font and style stack - std::vector<Text_Block> blocks_; ///< List of all text blocks on screen - std::vector<std::shared_ptr<Link> > link_list_; ///< List of all clickable links and their position on screen - std::map<std::string, int> target_line_map_; ///< List of vertical position of all HTML Targets in a document + Text_Block *blocks_; ///< Array of all text blocks on screen + int blocks_count_; ///< Number of blocks + int blocks_alloc_; ///< Allocated size of blocks array + Link **link_list_; ///< Array of pointers to links + int link_list_count_; ///< Number of links + int link_list_alloc_; ///< Allocated size of link_list array + // Target name to line mapping (simple linear search) + struct Target { char *name; int line; }; + Target *targets_; ///< Array of target names and their line positions + int targets_count_; ///< Number of targets + int targets_alloc_; ///< Allocated size of targets array int topline_; ///< Vertical offset of document, measure in pixels int leftline_; ///< Horizontal offset of document, measure in pixels @@ -247,14 +279,15 @@ public: // HTML source and raw data, getter void free_data(); - std::shared_ptr<Link> find_link(int, int); - void follow_link(std::shared_ptr<Link>); + Link *find_link(int, int); + void follow_link(Link *linkp); // HTML interpretation and formatting Text_Block *add_block(const char *s, int xx, int yy, int ww, int hh, uchar border = 0); - void add_link(const std::string &link, int xx, int yy, int ww, int hh); - void add_target(const std::string &n, int yy); + void add_link(const char *link, int xx, int yy, int ww, int hh); + void add_target(const char *n, int yy); + int find_target(const char *name); int do_align(Text_Block *block, int line, int xx, int a, int &l); void format(); void format_table(int *table_width, int *columns, const char *table); @@ -369,8 +402,8 @@ int Fl_Help_View::Impl::current_pos_ = 0; // static int quote_char(const char *); -static std::string to_lower(const std::string &str); -static size_t url_scheme(const std::string &url, bool skip_slashes=false); +static char *to_lower(const char *str); // caller must free() +static size_t url_scheme(const char *url, bool skip_slashes=false); static const char *vanilla(const char *p, const char *end); static uint32_t command(const char *cmd); @@ -434,30 +467,71 @@ static Fl_Menu_Item rmb_menu[] = { // ---- Helper class to manage margins in Fl_Help_View void Fl_Help_View::Impl::Margin_Stack::clear() { - margins_.clear(); - margins_.push_back(4); // default margin + count_ = 1; + margins_[0] = 4; // default margin } int Fl_Help_View::Impl::Margin_Stack::current() const { - return margins_.back(); + return margins_[count_ - 1]; } int Fl_Help_View::Impl::Margin_Stack::pop() { - if (margins_.size() > 1) { - margins_.pop_back(); + if (count_ > 1) { + count_--; } - return margins_.back(); + return margins_[count_ - 1]; } int Fl_Help_View::Impl::Margin_Stack::push(int indent) { int xx = current() + indent; - margins_.push_back(xx); + if (count_ < MAX_MARGINS) { + margins_[count_++] = xx; + } return xx; } // ---- Helper class HV_Edit_Buffer to ease buffer management +Fl_Help_View::Impl::Edit_Buffer::Edit_Buffer() { + buf_ = 0; + len_ = 0; + alloc_ = 0; +} + +Fl_Help_View::Impl::Edit_Buffer::~Edit_Buffer() { + if (buf_) free(buf_); +} + +void Fl_Help_View::Impl::Edit_Buffer::ensure(int needed) { + int total = len_ + needed + 1; + if (total > alloc_) { + int newalloc = alloc_ ? alloc_ * 2 : 64; + while (newalloc < total) newalloc *= 2; + buf_ = (char *)realloc(buf_, newalloc); + alloc_ = newalloc; + } +} + +void Fl_Help_View::Impl::Edit_Buffer::clear() { + len_ = 0; + if (buf_) buf_[0] = '\0'; +} + +void Fl_Help_View::Impl::Edit_Buffer::append(const char *s, int n) { + ensure(n); + memcpy(buf_ + len_, s, n); + len_ += n; + buf_[len_] = '\0'; +} + +Fl_Help_View::Impl::Edit_Buffer &Fl_Help_View::Impl::Edit_Buffer::operator+=(char c) { + ensure(1); + buf_[len_++] = c; + buf_[len_] = '\0'; + return *this; +} + // Append one Unicode character (code point) to the buffer. // The Unicode character \p ucs is converted to UTF-8 and appended to // the buffer. @@ -527,7 +601,7 @@ void Fl_Help_View::Impl::Font_Style::set(Fl_Font afont, Fl_Fontsize asize, Fl_Co \param[in] c color to apply */ void Fl_Help_View::Impl::Font_Stack::init(Fl_Font f, Fl_Fontsize s, Fl_Color c) { - elts_.clear(); + count_ = 0; push(f, s, c); } @@ -540,7 +614,7 @@ void Fl_Help_View::Impl::Font_Stack::init(Fl_Font f, Fl_Fontsize s, Fl_Color c) \note This function does not pop the stack, it just returns the top element. */ void Fl_Help_View::Impl::Font_Stack::top(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c) { - elts_.back().get(f, s, c); + elts_[count_ - 1].get(f, s, c); } @@ -552,7 +626,9 @@ void Fl_Help_View::Impl::Font_Stack::top(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c \param[in] c color to apply */ void Fl_Help_View::Impl::Font_Stack::push(Fl_Font f, Fl_Fontsize s, Fl_Color c) { - elts_.push_back(Font_Style(f, s, c)); + if (count_ < MAX_FONTS) { + elts_[count_++].set(f, s, c); + } fl_font(f, s); fl_color(c); } @@ -569,8 +645,8 @@ void Fl_Help_View::Impl::Font_Stack::push(Fl_Font f, Fl_Fontsize s, Fl_Color c) but the top element will be applied again. */ void Fl_Help_View::Impl::Font_Stack::pop(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c) { - if (elts_.size() > 1) - elts_.pop_back(); + if (count_ > 1) + count_--; top(f, s, c); fl_font(f, s); fl_color(c); @@ -581,8 +657,8 @@ void Fl_Help_View::Impl::Font_Stack::pop(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c \brief Gets the current count of font style elements in the stack. \return stack size in number of elements */ -size_t Fl_Help_View::Impl::Font_Stack::count() const { - return elts_.size(); +int Fl_Help_View::Impl::Font_Stack::count() const { + return count_; } @@ -664,22 +740,55 @@ void Fl_Help_View::Impl::free_data() { value_ = 0; } - blocks_ .clear(); - link_list_.clear(); - target_line_map_.clear(); + // Free blocks array + if (blocks_) { + free(blocks_); + blocks_ = 0; + } + blocks_count_ = 0; + blocks_alloc_ = 0; + + // Free link list + if (link_list_) { + int i; + for (i = 0; i < link_list_count_; i++) { + delete link_list_[i]; + } + free(link_list_); + link_list_ = 0; + } + link_list_count_ = 0; + link_list_alloc_ = 0; + + // Free targets + if (targets_) { + int i; + for (i = 0; i < targets_count_; i++) { + if (targets_[i].name) free(targets_[i].name); + } + free(targets_); + targets_ = 0; + } + targets_count_ = 0; + targets_alloc_ = 0; + + // Free directory and filename + if (directory_) { free(directory_); directory_ = 0; } + if (filename_) { free(filename_); filename_ = 0; } } /** \brief Find out if the mouse is over a hyperlink and return the link data. \parm[in] xx, yy Pixel coordinates inside the widget. - \return Shared pointer to the link if found, 0 otherwise. + \return Pointer to the link if found, 0 otherwise. */ -std::shared_ptr<Fl_Help_View::Impl::Link> Fl_Help_View::Impl::find_link(int xx, int yy) +Fl_Help_View::Impl::Link *Fl_Help_View::Impl::find_link(int xx, int yy) { - for (auto &link : link_list_) { - if (link->box.contains(xx, yy)) { - return link; + int i; + for (i = 0; i < link_list_count_; i++) { + if (link_list_[i]->box.contains(xx, yy)) { + return link_list_[i]; } } return 0; @@ -690,54 +799,65 @@ std::shared_ptr<Fl_Help_View::Impl::Link> Fl_Help_View::Impl::find_link(int xx, \brief Follow a link and load the target document or scroll to the target. This function clears the current selection and loads a new document or scrolls to a target line in the current document. - \param linkp Shared pointer to the link to follow. + \param linkp Pointer to the link to follow. */ -void Fl_Help_View::Impl::follow_link(std::shared_ptr<Link> linkp) +void Fl_Help_View::Impl::follow_link(Link *linkp) { clear_selection(); view.set_changed(); - std::string target = linkp->target;; // Current target - if ( (linkp->filename_ != filename_) && !linkp->filename_.empty() ) { + // Helper to check if filename differs from current + int filename_differs = 0; + if (linkp->filename_ && linkp->filename_[0]) { + if (!filename_ || strcmp(linkp->filename_, filename_) != 0) { + filename_differs = 1; + } + } + + if (filename_differs) { // Load the new document, if the filename is different - std::string url; + char url[FL_PATH_MAX * 2]; + url[0] = '\0'; + size_t directory_scheme_length = url_scheme(directory_); size_t filename_scheme_length = url_scheme(linkp->filename_); + if ( (directory_scheme_length > 0) && (filename_scheme_length == 0) ) { // If directory_ starts with a scheme (e.g.ftp:), but linkp->filename_ does not: if (linkp->filename_[0] == '/') { // If linkp->filename_ is absolute... - url = directory_.substr(0, directory_scheme_length) + linkp->filename_;; + snprintf(url, sizeof(url), "%.*s%s", (int)directory_scheme_length, directory_, linkp->filename_); } else { // If linkp->filename_ is relative, the URL is the directory_ plus the filename - url = directory_ + "/" + linkp->filename_; + snprintf(url, sizeof(url), "%s/%s", directory_ ? directory_ : "", linkp->filename_); } } else if (linkp->filename_[0] != '/' && (filename_scheme_length == 0)) { // If the filename is relative and does not start with a scheme (ftp: , etc.)... - if (!directory_.empty()) { + if (directory_ && directory_[0]) { // If we have a current directory, use that as the base for the URL - url = directory_ + "/" + linkp->filename_; + snprintf(url, sizeof(url), "%s/%s", directory_, linkp->filename_); } else { // If we do not have a current directory, use the application's current working directory - char dir[FL_PATH_MAX]; // Current directory (static size ok until we have fl_getcwd_std() + char dir[FL_PATH_MAX]; fl_getcwd(dir, sizeof(dir)); - url = "file:" + std::string(dir) + "/" + linkp->filename_; + snprintf(url, sizeof(url), "file:%s/%s", dir, linkp->filename_); } } else { // If the filename is absolute or starts with a protocol (e.g.ftp:), use it as is - url = linkp->filename_; + snprintf(url, sizeof(url), "%s", linkp->filename_); } // If a target is specified, append it to the URL - if (!linkp->target.empty()) { - url += "#" + linkp->target; + if (linkp->target && linkp->target[0]) { + size_t len = strlen(url); + snprintf(url + len, sizeof(url) - len, "#%s", linkp->target); } - load(url.c_str()); + load(url); - } else if (!target.empty()) { + } else if (linkp->target && linkp->target[0]) { // Keep the same document, scroll to the target line - topline(target.c_str()); + topline(linkp->target); } else { // No target, no filename, just scroll to the top of the document topline(0); @@ -769,8 +889,14 @@ Fl_Help_View::Impl::Text_Block *Fl_Help_View::Impl::add_block( // printf("add_block(s = %p, xx = %d, yy = %d, ww = %d, hh = %d, border = %d)\n", // s, xx, yy, ww, hh, border); - blocks_.push_back(Text_Block()); // Add a new block to the vector - temp = &blocks_.back(); + // Grow the array if needed + if (blocks_count_ >= blocks_alloc_) { + int newalloc = blocks_alloc_ ? blocks_alloc_ * 2 : 64; + blocks_ = (Text_Block *)realloc(blocks_, newalloc * sizeof(Text_Block)); + blocks_alloc_ = newalloc; + } + + temp = &blocks_[blocks_count_++]; memset(temp, 0, sizeof(Text_Block)); temp->start = s; @@ -791,24 +917,33 @@ Fl_Help_View::Impl::Text_Block *Fl_Help_View::Impl::add_block( \param[in] link a filename, followed by a hash and a target. All parts are optional. \param[in] xx, yy, ww, hh bounding box of the link text on screen */ -void Fl_Help_View::Impl::add_link(const std::string &link, int xx, int yy, int ww, int hh) +void Fl_Help_View::Impl::add_link(const char *link, int xx, int yy, int ww, int hh) { - auto new_link = std::make_shared<Link>(); // Create a new link storage object. + Link *new_link = new Link(); // Create a new link storage object. - new_link->box = { xx, yy, ww, hh }; + new_link->box = Fl_Rect(xx, yy, ww, hh); - size_t hash_pos = link.find('#'); // Find the hash character - if (hash_pos != std::string::npos) { + const char *hash = link ? strchr(link, '#') : 0; + if (hash) { // If a '#' is found, split the link into filename and target - new_link->filename_ = link.substr(0, hash_pos); - new_link->target = link.substr(hash_pos + 1); + int flen = (int)(hash - link); + new_link->filename_ = (char *)malloc(flen + 1); + memcpy(new_link->filename_, link, flen); + new_link->filename_[flen] = '\0'; + new_link->target = fl_strdup(hash + 1); } else { // No '#' found, use the whole link as filename - new_link->filename_ = link; - new_link->target.clear(); + new_link->filename_ = link ? fl_strdup(link) : 0; + new_link->target = 0; } - link_list_.push_back(new_link); // Add the link to the list. + // Grow the array if needed + if (link_list_count_ >= link_list_alloc_) { + int newalloc = link_list_alloc_ ? link_list_alloc_ * 2 : 32; + link_list_ = (Link **)realloc(link_list_, newalloc * sizeof(Link *)); + link_list_alloc_ = newalloc; + } + link_list_[link_list_count_++] = new_link; } @@ -817,10 +952,39 @@ void Fl_Help_View::Impl::add_link(const std::string &link, int xx, int yy, int w \param[in] n Name of target (string) \param[in] yy line number of target position */ -void Fl_Help_View::Impl::add_target(const std::string &n, int yy) +void Fl_Help_View::Impl::add_target(const char *n, int yy) { - std::string target = to_lower(n); // Convert target name to lower case - target_line_map_[target] = yy; // Store the target line in the map + char *target = to_lower(n); // Convert target name to lower case + + // Grow the array if needed + if (targets_count_ >= targets_alloc_) { + int newalloc = targets_alloc_ ? targets_alloc_ * 2 : 32; + targets_ = (Target *)realloc(targets_, newalloc * sizeof(Target)); + targets_alloc_ = newalloc; + } + + targets_[targets_count_].name = target; + targets_[targets_count_].line = yy; + targets_count_++; +} + +/** + \brief Finds a target by name and returns its line position. + \param[in] name Name of target (string) + \return line number, or -1 if not found + */ +int Fl_Help_View::Impl::find_target(const char *name) +{ + char *lower = to_lower(name); + int i; + for (i = 0; i < targets_count_; i++) { + if (targets_[i].name && strcmp(targets_[i].name, lower) == 0) { + free(lower); + return targets_[i].line; + } + } + free(lower); + return -1; } @@ -860,7 +1024,7 @@ int Fl_Help_View::Impl::do_align( if (line < 31) line ++; - while (l < (int)link_list_.size()) { + while (l < link_list_count_) { link_list_[l]->box.x( link_list_[l]->box.x() + offset); l++; } @@ -917,9 +1081,12 @@ void Fl_Help_View::Impl::format() { Fl_Boxtype b = view.box() ? view.box() : FL_DOWN_BOX; // Box to draw... Margin_Stack margins; // Left margin stack... - std::vector<int> OL_num; // if nonnegative, in OL mode and this is the item number + // Simple OL_num stack using fixed-size array + enum { MAX_OL_DEPTH = 64 }; + int OL_num[MAX_OL_DEPTH]; + int OL_num_count = 0; - OL_num.push_back(-1); + OL_num[OL_num_count++] = -1; DEBUG_FUNCTION(__LINE__,__FUNCTION__); @@ -932,9 +1099,20 @@ void Fl_Help_View::Impl::format() { { // Reset state variables... done = 1; - blocks_.clear(); - link_list_.clear(); - target_line_map_.clear(); + // Clear blocks + blocks_count_ = 0; + // Clear links + { + int li; + for (li = 0; li < link_list_count_; li++) delete link_list_[li]; + link_list_count_ = 0; + } + // Clear targets + { + int ti; + for (ti = 0; ti < targets_count_; ti++) if (targets_[ti].name) free(targets_[ti].name); + targets_count_ = 0; + } size_ = 0; bgcolor_ = view.color(); textcolor_ = textcolor(); @@ -942,7 +1120,7 @@ void Fl_Help_View::Impl::format() { tc = rc = bgcolor_; - title_ = "Untitled"; + strcpy(title_, "Untitled"); if (!value_) return; @@ -1097,10 +1275,13 @@ void Fl_Help_View::Impl::format() { else if (buf.cmp("TITLE")) { // Copy the title in the document... - title_.clear(); - for ( ; *ptr != '<' && *ptr; ptr++) { - title_.push_back(*ptr); + int title_len = 0; + for ( ; *ptr != '<' && *ptr && title_len < (int)sizeof(title_) - 1; ptr++) { + title_[title_len++] = *ptr; } + title_[title_len] = '\0'; + // Skip any remaining title content + while (*ptr && *ptr != '<') ptr++; buf.clear(); } else if (buf.cmp("A")) @@ -1163,10 +1344,10 @@ void Fl_Help_View::Impl::format() { if (errno || endptr == attr || ol_num < 0) ol_num = 1; } - OL_num.push_back(ol_num); + if (OL_num_count < MAX_OL_DEPTH) OL_num[OL_num_count++] = ol_num; } else if (buf.cmp("UL")) - OL_num.push_back(-1); + if (OL_num_count < MAX_OL_DEPTH) OL_num[OL_num_count++] = -1; if (buf.cmp("UL") || buf.cmp("OL") || @@ -1261,10 +1442,10 @@ void Fl_Help_View::Impl::format() { if (buf.cmp("LI")) { block->ol = 0; - if (OL_num.size() && (OL_num.back() >= 0)) { + if (OL_num_count > 0 && OL_num[OL_num_count - 1] >= 0) { block->ol = 1; - block->ol_num = OL_num.back(); - OL_num.back()++; + block->ol_num = OL_num[OL_num_count - 1]; + OL_num[OL_num_count - 1]++; } } @@ -1296,7 +1477,7 @@ void Fl_Help_View::Impl::format() { if (buf.cmp("/OL") || buf.cmp("/UL")) { - if (OL_num.size()) OL_num.pop_back(); + if (OL_num_count > 0) OL_num_count--; } if (buf.cmp("/UL") || @@ -1444,9 +1625,9 @@ void Fl_Help_View::Impl::format() { for (i = 0, ww = -6; i < colspan; i ++) ww += columns[column + i] + 6; - if (block->end == block->start && blocks_.size() > 1) + if (block->end == block->start && blocks_count_ > 1) { - blocks_.pop_back(); + blocks_count_--; block --; } @@ -2350,62 +2531,64 @@ Fl_Color Fl_Help_View::Impl::get_color(const char *n, Fl_Color c) */ Fl_Shared_Image *Fl_Help_View::Impl::get_image(const char *name, int W, int H) { - std::string url; + char url[FL_PATH_MAX * 2]; Fl_Shared_Image *ip; // Image pointer... if (!name || !name[0]) { // No image name given, return broken image return (Fl_Shared_Image *)&broken_image; } - std::string imagename = name; + const char *imagename = name; size_t directory_scheme_length = url_scheme(directory_); size_t imagename_scheme_length = url_scheme(imagename); + url[0] = '\0'; + // See if the image can be found... if ( (directory_scheme_length > 0) && (imagename_scheme_length == 0) ) { // If directory_ starts with a scheme (e.g.ftp:), but linkp->filename_ does not: if (imagename[0] == '/') { // If linkp->filename_ is absolute... - url = directory_.substr(0, directory_scheme_length) + imagename;; + snprintf(url, sizeof(url), "%.*s%s", (int)directory_scheme_length, directory_, imagename); } else { // If linkp->filename_ is relative, the URL is the directory_ plus the filename - url = directory_ + "/" + imagename; + snprintf(url, sizeof(url), "%s/%s", directory_ ? directory_ : "", imagename); } } else if (imagename[0] != '/' && (imagename_scheme_length == 0)) { // If the filename is relative and does not start with a scheme (ftp: , etc.)... - if (!directory_.empty()) { + if (directory_ && directory_[0]) { // If we have a current directory, use that as the base for the URL - url = directory_ + "/" + imagename; + snprintf(url, sizeof(url), "%s/%s", directory_, imagename); } else { // If we do not have a current directory, use the application's current working directory - char dir[FL_PATH_MAX]; // Current directory (static size ok until we have fl_getcwd_std() + char dir[FL_PATH_MAX]; fl_getcwd(dir, sizeof(dir)); - url = "file:" + std::string(dir) + "/" + imagename; + snprintf(url, sizeof(url), "file:%s/%s", dir, imagename); } } else { // If the filename is absolute or starts with a protocol (e.g.ftp:), use it as is - url = imagename; + snprintf(url, sizeof(url), "%s", imagename); } if (link_) { - const char *n = (*link_)(&view, url.c_str()); + const char *n = (*link_)(&view, url); if (n == 0) return 0; - url = n; + snprintf(url, sizeof(url), "%s", n); } - if (url.empty()) return 0; + if (!url[0]) return 0; // If the URL starts with "file:", remove it - if (url.find("file:") == 0) { - url = url.substr(5); + if (strncmp(url, "file:", 5) == 0) { + memmove(url, url + 5, strlen(url + 5) + 1); } if (initial_load) { - if ((ip = Fl_Shared_Image::get(url.c_str(), W, H)) == 0) { + if ((ip = Fl_Shared_Image::get(url, W, H)) == 0) { ip = (Fl_Shared_Image *)&broken_image; } } else { // draw or resize - if ((ip = Fl_Shared_Image::find(url.c_str(), W, H)) == 0) { + if ((ip = Fl_Shared_Image::find(url, W, H)) == 0) { ip = (Fl_Shared_Image *)&broken_image; } else { ip->release(); @@ -2697,7 +2880,7 @@ void Fl_Help_View::Impl::draw() fl_color(textcolor_); // Draw all visible blocks... - for (i = 0, block = &blocks_[0]; i < (int)blocks_.size(); i ++, block ++) + for (i = 0, block = &blocks_[0]; i < (int)blocks_count_; i ++, block ++) if ((block->y + block->h) >= topline_ && block->y < (topline_ + view.h())) { line = 0; @@ -3215,6 +3398,7 @@ Fl_Help_View::Fl_Help_View(int xx, int yy, int ww, int hh, const char *l) */ Fl_Help_View::~Fl_Help_View() { + delete impl_; } @@ -3234,7 +3418,7 @@ int Fl_Help_View::handle(int event) */ int Fl_Help_View::Impl::handle(int event) { - static std::shared_ptr<Link> linkp = 0; // currently clicked link + static Link *linkp = 0; // currently clicked link int xx = Fl::event_x() - view.x() + leftline_; int yy = Fl::event_y() - view.y() + topline_; @@ -3454,10 +3638,14 @@ int Fl_Help_View::Impl::load(const char *f) { FILE *fp; // File to read from long len; // Length of file - std::string target; // Target in file - std::string localname; // Local filename - std::string error; // Error buffer - std::string newname; // New filename buffer + char target[FL_PATH_MAX]; // Target in file + char localname[FL_PATH_MAX]; // Local filename + char error[FL_PATH_MAX * 2]; // Error buffer + char newname[FL_PATH_MAX]; // New filename buffer + + target[0] = '\0'; + localname[0] = '\0'; + newname[0] = '\0'; // printf("load(%s)\n",f); fflush(stdout); @@ -3472,41 +3660,43 @@ int Fl_Help_View::Impl::load(const char *f) if ( fl_open_uri(f, urimsg, sizeof(urimsg)) == 0 ) { clear_selection(); - newname = f; - size_t hash_pos = newname.rfind('#'); - if (hash_pos != std::string::npos) { - target = newname.substr(hash_pos + 1); - newname.resize(hash_pos); + strlcpy(newname, f, sizeof(newname)); + char *hash = strrchr(newname, '#'); + if (hash) { + strlcpy(target, hash + 1, sizeof(target)); + *hash = '\0'; } if (link_) { - const char *n = (*link_)(&view, newname.c_str()); + const char *n = (*link_)(&view, newname); if (n == 0) return 0; - localname = n; + strlcpy(localname, n, sizeof(localname)); } else { - localname = newname; + strlcpy(localname, newname, sizeof(localname)); } free_data(); - filename_ = newname; + filename_ = fl_strdup(newname); // Note: We do not support Windows backslashes, since they are illegal // in URLs... - directory_ = newname; - size_t slash_pos = directory_.rfind('/'); - if (slash_pos == std::string::npos) { - directory_.clear(); - } else if ((slash_pos > 0) && (directory_[slash_pos-1] != '/')) { - directory_.resize(slash_pos); + directory_ = fl_strdup(newname); + char *slash = strrchr(directory_, '/'); + if (!slash) { + free(directory_); + directory_ = 0; + } else if ((slash > directory_) && (*(slash-1) != '/')) { + *slash = '\0'; } - error = "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" - "<BODY><H1>Error</H1>" - "<P>Unable to follow the link \"" - + std::string(f) + "\" - " + std::string(urimsg) + ".</P></BODY>"; - value(error.c_str()); + snprintf(error, sizeof(error), + "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" + "<BODY><H1>Error</H1>" + "<P>Unable to follow the link \"%s\" - %s.</P></BODY>", + f, urimsg); + value(error); return -1; } else { return 0; @@ -3515,42 +3705,43 @@ int Fl_Help_View::Impl::load(const char *f) clear_selection(); - newname = f; - size_t hash_pos = newname.rfind('#'); - if (hash_pos != std::string::npos) { - target = newname.substr(hash_pos + 1); - newname.resize(hash_pos); + strlcpy(newname, f, sizeof(newname)); + char *hash = strrchr(newname, '#'); + if (hash) { + strlcpy(target, hash + 1, sizeof(target)); + *hash = '\0'; } if (link_) { - const char *n = (*link_)(&view, newname.c_str()); + const char *n = (*link_)(&view, newname); if (n == 0) return -1; - localname = n; + strlcpy(localname, n, sizeof(localname)); } else { - localname = newname; + strlcpy(localname, newname, sizeof(localname)); } free_data(); - filename_ = newname; - directory_ = newname; + filename_ = fl_strdup(newname); + directory_ = fl_strdup(newname); // Note: We do not support Windows backslashes, since they are illegal // in URLs... - size_t slash_pos = directory_.rfind('/'); - if (slash_pos == std::string::npos) { - directory_.clear(); - } else if ((slash_pos > 0) && (directory_[slash_pos-1] != '/')) { - directory_.resize(slash_pos); + char *slash = strrchr(directory_, '/'); + if (!slash) { + free(directory_); + directory_ = 0; + } else if ((slash > directory_) && (*(slash-1) != '/')) { + *slash = '\0'; } - if (localname.find("file:") == 0) { - localname.erase(0, 5); // Adjust for local filename... + if (strncmp(localname, "file:", 5) == 0) { + memmove(localname, localname + 5, strlen(localname + 5) + 1); } int ret = 0; - if ((fp = fl_fopen(localname.c_str(), "rb")) != 0) + if ((fp = fl_fopen(localname, "rb")) != 0) { fseek(fp, 0, SEEK_END); len = ftell(fp); @@ -3562,11 +3753,12 @@ int Fl_Help_View::Impl::load(const char *f) } else { - error = "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" - "<BODY><H1>Error</H1>" - "<P>Unable to follow the link \"" +localname + "\" - " - + strerror(errno) + ".</P></BODY>"; - value_ = fl_strdup(error.c_str()); + snprintf(error, sizeof(error), + "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" + "<BODY><H1>Error</H1>" + "<P>Unable to follow the link \"%s\" - %s.</P></BODY>", + localname, strerror(errno)); + value_ = fl_strdup(error); ret = -1; } @@ -3574,8 +3766,8 @@ int Fl_Help_View::Impl::load(const char *f) format(); initial_load = 0; - if (!target.empty()) - topline(target.c_str()); + if (target[0]) + topline(target); else topline(0); @@ -3626,7 +3818,7 @@ int Fl_Help_View::Impl::find(const char *s, int p) if (p < 0 || p >= (int)strlen(value_)) p = 0; // Look for the string... - for (i = (int)blocks_.size(), b = &blocks_[0]; i > 0; i--, b++) { + for (i = (int)blocks_count_, b = &blocks_[0]; i > 0; i--, b++) { if (b->end < (value_ + p)) continue; @@ -3761,10 +3953,10 @@ const char *Fl_Help_View::filename() const { \see Fl_Help_View::filename() const */ const char *Fl_Help_View::Impl::filename() const { - if (filename_.empty()) + if (!filename_ || !filename_[0]) return 0; else - return filename_.c_str(); + return filename_; } @@ -3785,10 +3977,10 @@ const char *Fl_Help_View::directory() const { \see Fl_Help_View::directory() const */ const char *Fl_Help_View::Impl::directory() const { - if (directory_.empty()) + if (!directory_ || !directory_[0]) return 0; else - return directory_.c_str(); + return directory_; } @@ -3810,7 +4002,7 @@ const char *Fl_Help_View::title() const { */ const char *Fl_Help_View::Impl::title() const { - return title_.c_str(); + return title_; } @@ -3830,11 +4022,10 @@ void Fl_Help_View::topline(const char *anchor) { */ void Fl_Help_View::Impl::topline(const char *anchor) { - std::string target_name = to_lower(anchor); // Convert to lower case - auto tl = target_line_map_.find(target_name); - if (tl != target_line_map_.end()) { + int line = find_target(anchor); + if (line >= 0) { // Found the target name, scroll to the line - topline(tl->second); + topline(line); } else { // Scroll to the top. topline(0); @@ -4361,12 +4552,15 @@ static int quote_char(const char *p) { // But as with everything in HTML, nobody cares and everybody does what they // want anyway ;-) . -static std::string to_lower(const std::string &str) { - std::string lower_str; - lower_str.reserve(str.size()); - for (char c : str) { - lower_str += fl_tolower(c); +static char *to_lower(const char *str) { + if (!str) return 0; + int len = (int)strlen(str); + char *lower_str = (char *)malloc(len + 1); + int i; + for (i = 0; i < len; i++) { + lower_str[i] = fl_tolower(str[i]); } + lower_str[len] = '\0'; return lower_str; } @@ -4377,21 +4571,23 @@ static std::string to_lower(const std::string &str) { \return 0 if not found, otherwise the length of the scheme string including the following '/' characters. */ -static size_t url_scheme(const std::string &url, bool skip_slashes) +static size_t url_scheme(const char *url, bool skip_slashes) { + if (!url) return 0; + size_t len = strlen(url); // First skip all ascii letters and digits size_t pos = 0; - while ( (pos < url.size()) && ( isalnum(url[pos]) || (url[pos] == '+') || (url[pos] == '-') || (url[pos] == '.') )) { + while ( (pos < len) && ( isalnum(url[pos]) || (url[pos] == '+') || (url[pos] == '-') || (url[pos] == '.') )) { pos++; } // Next, check for the ':' character - if ( (pos < url.size()) && (url[pos] == ':') ) { + if ( (pos < len) && (url[pos] == ':') ) { pos++; // Skip the ':' character if (skip_slashes) { // If found, skip up to two '/' characters as well - if ( (pos < url.size()) && (url[pos] == '/') ) { + if ( (pos < len) && (url[pos] == '/') ) { pos++; // Skip the first '/' character - if ( (pos < url.size()) && (url[pos] == '/') ) { + if ( (pos < len) && (url[pos] == '/') ) { pos++; // Skip the second '/' character } } |
