summaryrefslogtreecommitdiff
path: root/src/Fl_Help_View.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fl_Help_View.cxx')
-rw-r--r--src/Fl_Help_View.cxx568
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
}
}