summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2023-02-23 15:42:05 +0100
committerGitHub <noreply@github.com>2023-02-23 15:42:05 +0100
commit9f87af8ad9a3d8112518b6bbb5b6075881a5b9a2 (patch)
treefe96512734abb7b29bc6b8fac9816d7cc0c4ae3f /src
parent92818939267fc7fbb6a33d86fb78576f55ce6aca (diff)
Fl_String refactoring and extension (#683)
- add true unittest and Fl_String testing - interface and printout are similar to gtest without requiring external linkage. just run `unittest --core`. - new Fl_String API - extended API to fl_input_str and fl_password_str - co-authored-by: Albrecht Schlosser <albrechts.fltk@online.de>
Diffstat (limited to 'src')
-rw-r--r--src/Fl_String.cxx600
-rw-r--r--src/fl_ask.cxx72
2 files changed, 564 insertions, 108 deletions
diff --git a/src/Fl_String.cxx b/src/Fl_String.cxx
index e07f23a94..222e34583 100644
--- a/src/Fl_String.cxx
+++ b/src/Fl_String.cxx
@@ -17,137 +17,520 @@
#include <FL/Fl_String.H>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <limits.h>
+
/** \file src/Fl_String.cxx
- Basic Fl_String class for FLTK.
-*/
+ Basic Fl_String class for FLTK.
+ */
+
+
+/*
+ If buffer_ is NULL, c_str() and buffer() will point here.
+ */
+const char Fl_String::NUL = 0;
+
+/**
+ Indicate a maximum value or error.
+ This value is generally used as end of string indicator or as the error
+ indicator by the functions that return a string index.
+ */
+const int Fl_String::npos = INT_MAX;
+
+/**
+ Initialise the class instance.
+ */
+void Fl_String::init_() {
+ buffer_ = NULL;
+ size_ = 0;
+ capacity_ = 0;
+}
+
+/**
+ Grow the buffer to a capacity of at least n bytes.
+
+ This method will always grow the buffer size, or keep it as is, but never
+ shrink it. Use shrink_to_fit() to shrink the buffer as much as possible.
+
+ \param[in] n number of bytes needed, not counting the trailing NUL
+ */
+void Fl_String::grow_(int n) {
+ if (n <= capacity_)
+ return;
+ int alloc_size_ = n + 1; // trailing NUL
+ // round n up so we can grow in chunks
+ if (alloc_size_ <= 24) { // allocate at least 24 bytes
+ alloc_size_ = 24;
+ } else if (alloc_size_ < 1024) {
+ alloc_size_ = (alloc_size_+128) & ~127; // allocate in 128 byte chunks
+ } else {
+ alloc_size_ = (alloc_size_+2048) & ~2047; // allocate in 2k chunks
+ }
+ // allocate now
+ char *new_buffer = (char*)::malloc(alloc_size_);
+ if (buffer_ && (size_ > 0)) {
+ memcpy(new_buffer, buffer_, size_);
+ ::free(buffer_);
+ }
+ if (size_ >= 0)
+ new_buffer[size_] = 0; // trailing NUL
+ buffer_ = new_buffer;
+ capacity_ = alloc_size_-1; // trailing NUL
+}
-/** Constructs an empty string */
+/**
+ Shrink the buffer to n bytes, or size, if size > n.
+
+ Shrink the buffer as much as possible. If \p n is 0 and the string is empty,
+ the buffer will be released.
+
+ \param[in] n shrink buffer to n bytes, not counting the trailing NUL
+ */
+void Fl_String::shrink_(int n) {
+ if (n < size_)
+ n = size_;
+ if (n == capacity_)
+ return;
+ if (n == 0) {
+ if (buffer_)
+ ::free(buffer_);
+ buffer_ = NULL;
+ } else {
+ buffer_ = (char*)::realloc(buffer_, n+1); // NUL
+ buffer_[size_] = 0; // trailing NUL
+ }
+ capacity_ = n;
+}
+
+/**
+ Remove \p n_del bytes at \p at and insert \p n_ins bytes from \p src.
+
+ String will remain NUL terminated. Data in \p ins may contain NULs.
+
+ \param[in] at remove and insert bytes at this index
+ \param[in] n_del number of bytes to remove
+ \param[in] ins insert bytes from here, can be NULL if \p n_ins is also 0
+ \param[in] n_ins number of bytes to insert
+ \return self
+ */
+Fl_String &Fl_String::replace_(int at, int n_del, const char *ins, int n_ins) {
+ if (at > size_) at = size_;
+ if (n_del > size_ - at) n_del = size_ - at;
+ int diff = n_ins - n_del, new_size = size_ + diff;
+ if (diff) {
+ int src = at + n_del, dst = at + n_ins, n = size_ - src;
+ grow_(new_size);
+ if (n > 0) ::memmove(buffer_+dst, buffer_+src, n);
+ }
+ if (n_ins > 0) {
+ ::memmove(buffer_+at, ins, n_ins);
+ }
+ size_ = new_size;
+ buffer_[size_] = 0;
+ return *this;
+}
+
+
+// ---- Assignment ----------------------------------------------------- MARK: -
+
+/**
+ Allocate an empty string.
+ */
Fl_String::Fl_String() {
- init();
+ init_();
+}
+
+/**
+ Copy constructor.
+ \param[in] str copy from another Fl_String
+ */
+Fl_String::Fl_String(const Fl_String &str) {
+ init_();
+ assign(str);
}
-/** Constructor from a C-style string */
-Fl_String::Fl_String(const char *str) {
- init();
- value(str);
+/**
+ Constructor from a C-style string.
+ \param[in] cstr a NUL terminated C-style string
+ */
+Fl_String::Fl_String(const char *cstr) {
+ init_();
+ assign(cstr);
}
-/** Constructor from a buffer of \c size bytes */
+/**
+ Constructor from data of \p size bytes.
+ \param[in] str a block of data that may contain NUL characters
+ \paran[in] size number of bytes to copy
+ */
Fl_String::Fl_String(const char *str, int size) {
- init();
- value(str, size);
+ init_();
+ assign(str, size);
}
-void Fl_String::init() {
- size_ = 0;
- value_ = 0;
- capacity_ = 0;
+/**
+ Destructor.
+ */
+Fl_String::~Fl_String() {
+ if (buffer_)
+ ::free(buffer_);
}
-/** copy constructor */
-Fl_String::Fl_String(const Fl_String &in) {
- init();
- value(in.value(), in.size());
+/**
+ Copy assignment operator
+ \param[in] str copy from another Fl_String
+ \return self
+ */
+Fl_String &Fl_String::operator=(const Fl_String &str) {
+ return assign(str);
}
-/** copy assignment operator */
-Fl_String& Fl_String::operator=(const Fl_String &in) {
- if (this == &in)
- return *this;
- value(in.value(), in.size());
- // debug("copy assigned");
+/**
+ Assign a C-style string.
+ \param[in] cstr a NUL terminated C-style string
+ \return self
+ */
+Fl_String &Fl_String::operator=(const char *cstr) {
+ return assign(cstr);
+}
+
+/**
+ Copy another string.
+ \param[in] str copy from another Fl_String
+ \return self
+ */
+Fl_String &Fl_String::assign(const Fl_String &str) {
+ if (&str == this) return *this;
+ return assign(str.data(), str.size());
+}
+
+/**
+ Assign a C-style string.
+ \param[in] cstr a NUL terminated C-style string
+ \return self
+ */
+Fl_String &Fl_String::assign(const char *cstr) {
+ if (cstr && *cstr) {
+ int len = (int)::strlen(cstr);
+ return assign(cstr, len);
+ } else {
+ resize(0);
+ }
return *this;
}
-/** assignment operator for 'const char *' */
-Fl_String& Fl_String::operator=(const char *in) {
- value(in);
- // debug("*STRING* assigned");
+/**
+ Assign a data block of \p size bytes.
+ \param[in] str a block of data that may contain NUL characters
+ \paran[in] size number of bytes to copy
+ \return self
+ */
+Fl_String &Fl_String::assign(const char *str, int size) {
+ if (size > 0) {
+ grow_(size);
+ memcpy(buffer_, str, size);
+ buffer_[size] = 0;
+ size_ = size;
+ } else {
+ resize(0);
+ }
return *this;
}
-/** Destructor */
-Fl_String::~Fl_String() {
- delete[] value_;
+// ---- Element Access ------------------------------------------------- MARK: -
+
+/**
+ Returns the character at specified bounds checked location.
+ \param[in] n index of character
+ \return character at that index, or NUL if out of bounds
+ */
+char Fl_String::at(int n) const {
+ if ((n < 0) || (n >= size_))
+ return 0;
+ return operator[](n);
}
-/** Grow the buffer size to at least size+1 bytes.
- By default, this call destroys the contents of the current buffer.
- \param size in bytes
- \param preserve_text copy existing text into the new buffer
+/**
+ Returns the character at specified location.
+ \param[in] n index of character
+ \return character at that index
*/
-void Fl_String::alloc_buf(int size, bool preserve_text) {
- if (size < 0)
- return;
- if (size > 0 && size <= capacity_)
- return;
+char Fl_String::operator[](int n) const {
+ if (buffer_)
+ return buffer_[n];
+ else
+ return 0;
+}
- int new_size = (size + 1 + 15) & (~15); // round upwards
- char *new_value = new char[new_size];
- capacity_ = new_size - 1;
+/**
+ Returns a reference to the character at specified location.
+ \param[in] n index of character
+ \return reference to that character, so it can be used as lvalue
+ */
+char &Fl_String::operator[](int n) {
+ if (!buffer_)
+ reserve(1);
+ return buffer_[n];
+}
- if (preserve_text) {
- size_ = (int)strlen(value_);
- // the new buffer always has a higher capacity than the old one
- // make sure we copy the trailing NUL.
- memcpy(new_value, value_, size_+1);
- } else {
- size_ = 0;
- }
- delete[] value_;
- value_ = new_value;
+/**
+ Return a pointer to the NUL terminated string.
+ \return reference to non-mutable string
+ */
+const char *Fl_String::data() const {
+ if (buffer_)
+ return buffer_;
+ else
+ return &NUL;
}
-/** Assigns the string value to a C-style string */
-void Fl_String::value(const char *str) {
- value(str, str ? (int)strlen(str) : 0);
+/**
+ Return a pointer to the writable NUL terminated string.
+ \return reference to mutable string
+ */
+char *Fl_String::data() {
+ if (!buffer_)
+ reserve(1);
+ return buffer_;
}
-/** Returns the number of non-null bytes in the object */
-int Fl_String::slen() const {
- if (!value_) return 0;
- return (int)strlen(value_);
+/**
+ Return a pointer to the NUL terminated string.
+ \return reference to non-mutable string
+ \note same as `const char *Fl_String::data() const`
+ */
+const char *Fl_String::c_str() const {
+ return data();
}
-/** Assigns the string value to a buffer of \c len bytes */
-void Fl_String::value(const char *str, int len) {
- if (str) {
- alloc_buf(len);
- size_ = len;
- memcpy(value_, str, size_);
- value_[size_] = '\0';
- } else { // str == NULL
- size_ = 0; // ignore len !
- delete[] value_; // free buffer
- value_ = NULL; // set null pointer (!)
- capacity_ = 0; // reset capacity
- }
+// ---- Capacity ------------------------------------------------------- MARK: -
+
+/**
+ Checks if the string is empty.
+ \return true if string contains no data
+ */
+bool Fl_String::empty() const {
+ return (size_ == 0);
}
-/** Returns the minimum capacity of the object */
+/**
+ Returns the number of bytes in the string.
+ \return number of bytes in string, not counting trailing NUL
+ */
+int Fl_String::size() const {
+ return size_;
+}
+
+/**
+ Reserve n bytes for storage.
+ If n is less or equal than size, the capacity is set to size.
+ \param[in] n requested minimum size, not counting trailing NUL
+ */
+void Fl_String::reserve(int n) {
+ grow_(n);
+}
+
+/**
+ Return the number of chars that are allocated for storage.
+ \return string capacity, not counting trailing NUL
+ */
int Fl_String::capacity() const {
- return capacity_; // > 0 ? capacity_ - 1 : capacity_;
+ return capacity_;
}
-/** Set the minimum capacity to \c num_bytes plus one for a terminating NUL.
- The contents of the string buffer will be copied if needed.
- \param num_bytes minimum size of buffer
+/**
+ Shrink the capacity to fit the current size.
*/
-void Fl_String::capacity(int num_bytes) {
- alloc_buf(num_bytes, true);
+void Fl_String::shrink_to_fit() {
+ shrink_(size_);
}
+// ---- Operations ----------------------------------------------------- MARK: -
-void Fl_String::release() {
- delete[] value_;
- value_ = 0;
- size_ = 0;
- capacity_ = 0;
+/**
+ Set an empty string.
+ */
+void Fl_String::clear() {
+ resize(0);
+}
+
+/**
+ Insert a C-style string or data.
+ \param[in] at insert at this index
+ \param[in] src copy bytes from here
+ \param[in] n_ins optional number of bytes to copy - if not set, copy C-style string
+ \return self
+ */
+Fl_String &Fl_String::insert(int at, const char *src, int n_ins) {
+ if (n_ins == npos) n_ins = src ? (int)::strlen(src) : 0;
+ return replace_(at, 0, src, n_ins);
+}
+
+/**
+ Insert another string.
+ \param[in] at insert at this index
+ \param[in] src copy string from here
+ \return self
+ */
+Fl_String &Fl_String::insert(int at, const Fl_String &src) {
+ return replace_(at, 0, src.buffer_, src.size_);
+}
+
+/**
+ Erase some bytes within a string.
+ \param[in] at erase at this index
+ \param[in] n_del number of bytes to erase
+ \return self
+ */
+Fl_String &Fl_String::erase(int at, int n_del) {
+ return replace_(at, n_del, NULL, 0);
+}
+
+/**
+ Append a single character.
+ \param[in] c append this byte
+ */
+void Fl_String::push_back(char c) {
+ replace_(size_, 0, &c, 1);
+}
+
+/**
+ Remove the last character.
+ */
+void Fl_String::pop_back() {
+ replace_(size_-1, 1, NULL, 0);
+}
+
+/**
+ Append a C-style string or data.
+ \param[in] src copy bytes from here
+ \param[in] n_ins optional number of bytes to copy - if not set, copy C-style string
+ \return self
+ */
+Fl_String &Fl_String::append(const char *src, int n_ins) {
+ if (n_ins == npos) n_ins = src ? (int)::strlen(src) : 0;
+ return replace_(size_, 0, src, n_ins);
+}
+
+/**
+ Append another string.
+ \param[in] src copy string from here
+ \return self
+ */
+Fl_String &Fl_String::append(const Fl_String &src) {
+ return replace_(size_, 0, src.buffer_, src.size_);
+}
+
+/**
+ Append a single byte.
+ \param[in] c single byte character
+ \return self
+ */
+Fl_String &Fl_String::append(char c) {
+ push_back(c);
+ return *this;
+}
+
+/**
+ Append a C-style string or data.
+ \param[in] src copy C-style string from here
+ \return self
+ */
+Fl_String &Fl_String::operator+=(const char *src) {
+ return append(src);
+}
+
+/**
+ Append another string.
+ \param[in] src copy string from here
+ \return self
+ */
+Fl_String &Fl_String::operator+=(const Fl_String &src) {
+ return append(src);
+}
+
+/**
+ Append a single byte.
+ \param[in] c single byte character
+ \return self
+ */
+Fl_String &Fl_String::operator+=(char c) {
+ return append(c);
+}
+
+/**
+ Replace part of the string with a C-style string or data.
+ \param[in] at erase and insert at this index
+ \param[in] n_del number of bytes to erase
+ \param[in] src copy bytes from here
+ \param[in] n_ins optional number of bytes to copy - if not set, copy C-style string
+ \return self
+ */
+Fl_String &Fl_String::replace(int at, int n_del, const char *src, int n_ins) {
+ if (n_ins == npos) n_ins = src ? (int)::strlen(src) : 0;
+ return replace_(at, n_del, src, n_ins);
+}
+
+/**
+ Replace part of the string with another string.
+ \param[in] at erase and insert at this index
+ \param[in] n_del number of bytes to erase
+ \param[in] src copy string from here
+ \return self
+ */
+Fl_String &Fl_String::replace(int at, int n_del, const Fl_String &src) {
+ return replace_(at, n_del, src.buffer_, src.size_);
+}
+
+/**
+ Return a substring from a string.
+ \param[in] pos copy string from here - if omitted, copy from start
+ \param[in] n number of bytes - if omitted, copy all bytes
+ \return a new string
+ */
+Fl_String Fl_String::substr(int pos, int n) const {
+ if (n > size_) n = size_;
+ int first = pos, last = pos + n;
+ if ((first < 0) || (first > size_) || (last <= first))
+ return Fl_String();
+ if (last > size_) last = size_;
+ return Fl_String(buffer_+first, last-first);
+}
+
+/**
+ Resizes the string to n characters.
+
+ If \p n is less than the current size, the string will be cropped. If \p n
+ is more than the current size, the new space will be filled with
+ NUL characters.
+
+ \param[in] n new size of string
+ */
+void Fl_String::resize(int n) {
+ if (n == size_)
+ return;
+ if (n < size_) {
+ size_ = n;
+ if (buffer_) buffer_[size_] = 0;
+ } else {
+ grow_(n);
+ if (buffer_) ::memset(buffer_+size_, 0, n-size_+1);
+ }
+ size_ = n;
}
-// ============================= DEBUG =============================
+// --- Non Standard ---------------------------------------------------- MARK: -
+
+/**
+ Returns the number of bytes until the first NUL byte.
+ \return number of bytes in C-style string
+ */
+int Fl_String::strlen() const {
+ if (!buffer_) return 0;
+ return (int)::strlen(buffer_);
+}
/**
Write some details about the string to stdout.
@@ -163,7 +546,7 @@ void Fl_String::release() {
void Fl_String::debug(const char *info) const {
if (info) {
printf("Fl_String '%-20s': %p, value = %p (%d/%d):\n%s\n",
- info, this, value_, size_, capacity_, value_ ? value_ : "<NULL>");
+ info, this, buffer_, size_, capacity_, buffer_ ? buffer_ : "<NULL>");
}
}
@@ -191,7 +574,46 @@ void Fl_String::hexdump(const char *info) const {
} else if ((i & 3) == 0) { // separator after 4 bytes
printf(" ");
}
- printf(" %02x", (unsigned char)value_[i]);
+ printf(" %02x", (unsigned char)buffer_[i]);
}
printf("\n");
}
+
+// ---- Non-member functions ------------------------------------------- MARK: -
+
+/**
+ Concatenate two strings.
+ \param[in] lhs first string
+ \param[in] rhs second string
+ \return self
+ */
+Fl_String operator+(const Fl_String &lhs, const Fl_String &rhs) {
+ Fl_String ret = lhs;
+ return ret += rhs;
+}
+
+/**
+ Concatenate two strings.
+ \param[in] lhs first string
+ \param[in] rhs second C-style string
+ \return self
+ */
+Fl_String operator+(const Fl_String &lhs, const char *rhs) {
+ Fl_String ret = lhs;
+ return ret += rhs;
+}
+
+/**
+ Compare two strings.
+ \param[in] lhs first string
+ \param[in] rhs second string
+ \return true if strings are the same size and have the same content
+ */
+bool operator==(const Fl_String &lhs, const Fl_String &rhs) {
+ if (lhs.size() == rhs.size()) {
+ int sz = lhs.size();
+ if (sz == 0) return true;
+ if (memcmp(lhs.data(), rhs.data(), sz) == 0) return true;
+ }
+ return false;
+}
diff --git a/src/fl_ask.cxx b/src/fl_ask.cxx
index 5657cd3b0..6ed6b2667 100644
--- a/src/fl_ask.cxx
+++ b/src/fl_ask.cxx
@@ -320,7 +320,7 @@ const char *fl_input(const char *fmt, const char *defstr, ...) {
/** Shows an input dialog displaying the \p fmt message with variable arguments.
- Like fl_input(), but this method has an additional (first) argument \p maxchar
+ Like fl_input(), but this method has the additional argument \p maxchar
that limits the number of \b characters that can be input. Since the
string is encoded in UTF-8 it is possible that the number of bytes
in the string is larger than \p maxchar.
@@ -329,36 +329,56 @@ const char *fl_input(const char *fmt, const char *defstr, ...) {
returns the string in an Fl_String object that must be released after use. This
can be a local/automatic variable.
+ The \p ret variable is set to 0 if the user clicked OK, and to a negative
+ value if the user canceled the dialog. If the dialog was canceled, the returned
+ string will be empty.
+
\code #include <FL/fl_ask.H> \endcode
Example:
\code
- { Fl_String str = fl_input_str(0, "Enter text:", "");
- printf("Text is: '%s'\n", str.value() ? str.value() : "<cancelled>");
+ { int ret;
+ Fl_String str = fl_input_str(ret, 0, "Enter text:", "");
+ if (ret < 0)
+ printf("Text input was canceled.\n");
+ else
+ printf("Text is: '%s'\n", str.c_str());
} // (str goes out of scope)
\endcode
- If the user hits \c Escape or closes the window \c str.value() returns NULL.
-
+ \param[out] ret 0 if user clicked OK, negative if dialog was canceled
\param[in] maxchar input size limit in characters (not bytes), use 0 for no limit
\param[in] fmt can be used as an sprintf-like format and variables for the message text
\param[in] defstr defines the default returned string if no text is entered
- \return the user string input if OK was pushed or NULL in Fl_String::value()
- \retval Fl_String::value() == NULL if Cancel was pushed or the window was closed by the user
+ \return the user string input if OK was clicked which can be empty
+ \return an empty string and set \p ret to a negative value if the user canceled the dialog
\since 1.4.0
*/
-Fl_String fl_input_str(int maxchar, const char *fmt, const char *defstr, ...) {
+Fl_String fl_input_str(int &ret, int maxchar, const char *fmt, const char *defstr, ...) {
+ Fl_Message msg("?");
+ if (maxchar < 0) maxchar = 0;
+ va_list ap;
+ va_start(ap, defstr);
+ const char *r = msg.input_innards(fmt, ap, defstr, FL_NORMAL_INPUT, maxchar);
+ va_end(ap);
+ ret = (r == NULL) ? -1 : 0;
+ return Fl_String(r);
+}
+/** Shows an input dialog displaying the \p fmt message with variable arguments.
+ \note No information is given if the user canceled the dialog or clicked OK.
+ \see fl_input_str(int &ret, int maxchar, const char *label, const char *deflt = 0, ...)
+ */
+Fl_String fl_input_str(int maxchar, const char *fmt, const char *defstr, ...) {
Fl_Message msg("?");
- if (maxchar < 0)
- maxchar = 0;
+ if (maxchar < 0) maxchar = 0;
va_list ap;
va_start(ap, defstr);
const char *r = msg.input_innards(fmt, ap, defstr, FL_NORMAL_INPUT, maxchar);
va_end(ap);
- return r; // Fl_String(r)
+ return Fl_String(r);
}
/** Shows an input dialog displaying the \p fmt message with variable arguments.
@@ -378,7 +398,6 @@ Fl_String fl_input_str(int maxchar, const char *fmt, const char *defstr, ...) {
\retval NULL if Cancel was pushed or the window was closed by the user
*/
const char *fl_password(const char *fmt, const char *defstr, ...) {
-
Fl_Message msg("?");
va_list ap;
va_start(ap, defstr);
@@ -400,27 +419,42 @@ const char *fl_password(const char *fmt, const char *defstr, ...) {
\code #include <FL/fl_ask.H> \endcode
- \param[in] maxchar input size limit in characters (not bytes); use 0 for no limit
+ \param[out] ret 0 if user clicked OK, negative if dialog was canceled
+ \param[in] maxchar input size limit in characters (not bytes), use 0 for no limit
\param[in] fmt can be used as an sprintf-like format and variables for the message text
\param[in] defstr defines the default returned string if no text is entered
- \return the user string input if OK was pushed or NULL in Fl_String::value()
- \retval Fl_String::value() == NULL if Cancel was pushed or the window was closed by the user
+ \return the user string input if OK was clicked which can be empty
+ \return an empty string and set \p ret to a negative value if the user canceled the dialog
\since 1.4.0
*/
-Fl_String fl_password_str(int maxchar, const char *fmt, const char *defstr, ...) {
+Fl_String fl_password_str(int &ret, int maxchar, const char *fmt, const char *defstr, ...) {
+ Fl_Message msg("?");
+ if (maxchar < 0) maxchar = 0;
+ va_list ap;
+ va_start(ap, defstr);
+ const char *r = msg.input_innards(fmt, ap, defstr, FL_SECRET_INPUT, maxchar);
+ va_end(ap);
+ ret = (r == NULL) ? -1 : 0;
+ return Fl_String(r);
+}
+/** Shows an input dialog displaying the \p fmt message with variable arguments.
+ \note No information is given if the user canceled the dialog or clicked OK.
+ \see fl_password_str(int &ret, int maxchar, const char *label, const char *deflt = 0, ...)
+ */
+Fl_String fl_password_str(int maxchar, const char *fmt, const char *defstr, ...) {
Fl_Message msg("?");
- if (maxchar < 0)
- maxchar = 0;
+ if (maxchar < 0) maxchar = 0;
va_list ap;
va_start(ap, defstr);
const char *r = msg.input_innards(fmt, ap, defstr, FL_SECRET_INPUT, maxchar);
va_end(ap);
- return r; // Fl_String(r)
+ return Fl_String(r);
}
+
/** Sets the preferred position for the message box used in
many common dialogs like fl_message(), fl_alert(),
fl_ask(), fl_choice(), fl_input(), fl_password().