aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Geerken <devnull@localhost>2013-03-05 14:28:34 +0100
committerSebastian Geerken <devnull@localhost>2013-03-05 14:28:34 +0100
commit09cbe1a36c6ca2762d2e49f173db7ee4fb683448 (patch)
treeaaf322ad1388f2c8a507d1c6a51779c8dd025f24
parent98465834b8b0e7c4a563e651a51befd2a2ab06ac (diff)
parente844f4119a6a5b144b18af4bcc841c816f575159 (diff)
Merge with main repo.
-rw-r--r--dw/iterator.cc10
-rw-r--r--dw/iterator.hh14
-rw-r--r--dw/table.cc2
-rw-r--r--dw/table.hh2
-rw-r--r--dw/textblock.cc14
-rw-r--r--dw/textblock.hh5
-rw-r--r--dw/textblock_iterator.cc2
-rwxr-xr-xinstall-hyphenation221
-rw-r--r--lout/container.cc64
-rw-r--r--lout/container.hh29
-rw-r--r--lout/misc.cc26
-rw-r--r--lout/misc.hh29
-rw-r--r--lout/object.cc24
-rw-r--r--lout/object.hh30
-rw-r--r--src/uicmd.cc15
-rw-r--r--test/containers.cc64
16 files changed, 350 insertions, 201 deletions
diff --git a/dw/iterator.cc b/dw/iterator.cc
index ccfc068b..c31c2706 100644
--- a/dw/iterator.cc
+++ b/dw/iterator.cc
@@ -37,7 +37,7 @@ Iterator::Iterator(Widget *widget, Content::Type mask, bool atEnd)
this->mask = mask;
}
-Iterator::Iterator(Iterator &it): object::Object (), misc::Comparable ()
+Iterator::Iterator(Iterator &it): object::Comparable ()
{
widget = it.widget;
content = it.content;
@@ -214,7 +214,7 @@ object::Object *EmptyIterator::clone ()
return new EmptyIterator (*this);
}
-int EmptyIterator::compareTo (misc::Comparable *other)
+int EmptyIterator::compareTo (object::Comparable *other)
{
EmptyIterator *otherIt = (EmptyIterator*)other;
@@ -266,7 +266,7 @@ TextIterator::TextIterator (TextIterator &it): Iterator (it)
text = it.text;
}
-int TextIterator::compareTo (misc::Comparable *other)
+int TextIterator::compareTo (object::Comparable *other)
{
TextIterator *otherIt = (TextIterator*)other;
@@ -579,7 +579,7 @@ object::Object *DeepIterator::clone ()
return it;
}
-int DeepIterator::compareTo (misc::Comparable *other)
+int DeepIterator::compareTo (object::Comparable *other)
{
DeepIterator *otherDeepIterator = (DeepIterator*)other;
@@ -717,7 +717,7 @@ object::Object *CharIterator::clone()
return cloned;
}
-int CharIterator::compareTo(misc::Comparable *other)
+int CharIterator::compareTo(object::Comparable *other)
{
CharIterator *otherIt = (CharIterator*)other;
int c = it->compareTo(otherIt->it);
diff --git a/dw/iterator.hh b/dw/iterator.hh
index a48356ef..d8a59eec 100644
--- a/dw/iterator.hh
+++ b/dw/iterator.hh
@@ -16,7 +16,7 @@ namespace core {
*
* \sa dw::core::Widget::iterator
*/
-class Iterator: public lout::object::Object, public lout::misc::Comparable
+class Iterator: public lout::object::Comparable
{
protected:
Iterator(Widget *widget, Content::Type mask, bool atEnd);
@@ -103,7 +103,7 @@ public:
EmptyIterator (Widget *widget, Content::Type mask, bool atEnd);
lout::object::Object *clone();
- int compareTo(lout::misc::Comparable *other);
+ int compareTo(lout::object::Comparable *other);
bool next ();
bool prev ();
void highlight (int start, int end, HighlightLayer layer);
@@ -128,7 +128,7 @@ public:
TextIterator (Widget *widget, Content::Type mask, bool atEnd,
const char *text);
- int compareTo(lout::misc::Comparable *other);
+ int compareTo(lout::object::Comparable *other);
bool next ();
bool prev ();
@@ -144,7 +144,7 @@ public:
* iterators do not have the limitation, that iteration is only done within
* a widget, instead, child widgets are iterated through recursively.
*/
-class DeepIterator: public lout::object::Object, public lout::misc::Comparable
+class DeepIterator: public lout::object::Comparable
{
private:
class Stack: public lout::container::typed::Vector<Iterator>
@@ -189,7 +189,7 @@ public:
bool next ();
bool prev ();
inline DeepIterator *cloneDeepIterator() { return (DeepIterator*)clone(); }
- int compareTo(lout::misc::Comparable *other);
+ int compareTo(lout::object::Comparable *other);
/**
* \brief Highlight a part of the current content.
@@ -222,7 +222,7 @@ public:
start, end, hpos, vpos); }
};
-class CharIterator: public lout::object::Object, public lout::misc::Comparable
+class CharIterator: public lout::object::Comparable
{
public:
// START and END must not clash with any char value
@@ -240,7 +240,7 @@ public:
~CharIterator ();
lout::object::Object *clone();
- int compareTo(lout::misc::Comparable *other);
+ int compareTo(lout::object::Comparable *other);
bool next ();
bool prev ();
diff --git a/dw/table.cc b/dw/table.cc
index ee9762fe..5587f469 100644
--- a/dw/table.cc
+++ b/dw/table.cc
@@ -1114,7 +1114,7 @@ object::Object *Table::TableIterator::clone()
return new TableIterator ((Table*)getWidget(), getMask(), index);
}
-int Table::TableIterator::compareTo(misc::Comparable *other)
+int Table::TableIterator::compareTo(object::Comparable *other)
{
return index - ((TableIterator*)other)->index;
}
diff --git a/dw/table.hh b/dw/table.hh
index 7bcc6c1b..b8feb835 100644
--- a/dw/table.hh
+++ b/dw/table.hh
@@ -344,7 +344,7 @@ private:
TableIterator (Table *table, core::Content::Type mask, int index);
lout::object::Object *clone();
- int compareTo(lout::misc::Comparable *other);
+ int compareTo(lout::object::Comparable *other);
bool next ();
bool prev ();
diff --git a/dw/textblock.cc b/dw/textblock.cc
index 9d61e06e..03f15f63 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -1786,9 +1786,8 @@ void Textblock::addText (const char *text, size_t len,
if(i < numParts - 1) {
Word *word = words->getLastRef();
- word->badnessAndPenalty
- .setPenalties (penalties[partPenaltyIndex[i]][0],
- penalties[partPenaltyIndex[i]][1]);
+ setBreakOption (word, style, penalties[partPenaltyIndex[i]][0],
+ penalties[partPenaltyIndex[i]][1]);
if (charRemoved[i])
// Currently, only unconditional hyphens (UTF-8:
@@ -1982,7 +1981,7 @@ void Textblock::addBreakOption (core::style::Style *style)
{
int wordIndex = words->size () - 1;
if (wordIndex >= 0) {
- setBreakOption (words->getRef(wordIndex), style);
+ setBreakOption (words->getRef(wordIndex), style, 0, 0);
// Call of accumulateWordData() is not needed here.
correctLastWordExtremes ();
}
@@ -2008,7 +2007,7 @@ void Textblock::fillSpace (Word *word, core::style::Style *style)
// Do not override a previously set break penalty.
if (!word->content.space) {
- setBreakOption (word, style);
+ setBreakOption (word, style, 0, 0);
word->content.space = true;
word->effSpace = word->origSpace = style->font->spaceWidth +
@@ -2032,7 +2031,8 @@ void Textblock::fillSpace (Word *word, core::style::Style *style)
* (and so addSpace), but may be called, via addBreakOption(), as an
* alternative, e. g. for ideographic characters.
*/
-void Textblock::setBreakOption (Word *word, core::style::Style *style)
+void Textblock::setBreakOption (Word *word, core::style::Style *style,
+ int breakPenalty1, int breakPenalty2)
{
// TODO: lineMustBeBroken should be independent of the penalty
// index? Otherwise, examine the last line.
@@ -2041,7 +2041,7 @@ void Textblock::setBreakOption (Word *word, core::style::Style *style)
case core::style::WHITE_SPACE_NORMAL:
case core::style::WHITE_SPACE_PRE_LINE:
case core::style::WHITE_SPACE_PRE_WRAP:
- word->badnessAndPenalty.setPenalty (0);
+ word->badnessAndPenalty.setPenalties (breakPenalty1, breakPenalty2);
break;
case core::style::WHITE_SPACE_PRE:
diff --git a/dw/textblock.hh b/dw/textblock.hh
index f0f8347f..04a7fa68 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -384,7 +384,7 @@ protected:
bool oofm, int index);
lout::object::Object *clone();
- int compareTo(lout::misc::Comparable *other);
+ int compareTo(lout::object::Comparable *other);
bool next ();
bool prev ();
@@ -494,7 +494,8 @@ protected:
void fillWord (Word *word, int width, int ascent, int descent,
short flags, core::style::Style *style);
void fillSpace (Word *word, core::style::Style *style);
- void setBreakOption (Word *word, core::style::Style *style);
+ void setBreakOption (Word *word, core::style::Style *style,
+ int breakPenalty1, int breakPenalty2);
int textWidth (const char *text, int start, int len,
core::style::Style *style, bool isStart, bool isEnd);
void calcTextSize (const char *text, size_t len, core::style::Style *style,
diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc
index 0956ef29..daf82c50 100644
--- a/dw/textblock_iterator.cc
+++ b/dw/textblock_iterator.cc
@@ -72,7 +72,7 @@ object::Object *Textblock::TextblockIterator::clone()
new TextblockIterator ((Textblock*)getWidget(), getMask(), oofm, index);
}
-int Textblock::TextblockIterator::compareTo(misc::Comparable *other)
+int Textblock::TextblockIterator::compareTo(object::Comparable *other)
{
TextblockIterator *otherTI = (TextblockIterator*)other;
diff --git a/install-hyphenation b/install-hyphenation
index 7ee90602..16fd0423 100755
--- a/install-hyphenation
+++ b/install-hyphenation
@@ -1,116 +1,153 @@
#!/usr/bin/env perl
-
use POSIX;
use File::Basename;
+use Net::FTP;
+
+$commondir = "language/hyph-utf8/tex/generic/hyph-utf8/patterns/txt";
+
+# You may want do adjust these values.
+
+$host = "mirrors.dotsrc.org";
+$dir = "/ctan/$commondir";
+
+#$host = "ctan.org";
+#$dir = "/tex-archive/$commondir";
-sub getpattendir () {
+#$host = "ftp.dante.de";
+#$dir = "/pub/tex/$commondir";
+
+$help = 0;
+if (@ARGV == 0) {
+ $help = 1;
+} else {
+ foreach $arg (@ARGV) {
+ if ($arg eq '-?' || $arg eq '--?' || $arg eq '-h' ||
+ $arg eq '--h' || $arg eq '-help' || $arg eq '--help') {
+ $arg = 1;
+ }
+ }
+}
+
+if ($help) {
+ print "Usage: $0 <lang1> [<lang2> ...]\n\n";
+ print <<EOT;
+Download and install hyphenation patterns from CTAN for different languages.
+Languages are specified as defined by ISO 639-1 ("en" for English etc.).
+
+If there are multiple pattern files for a language (and so the filename is not
+"hyph-<lang>.pat.txt"), you must specify the respective part of the filename,
+e. g. "en-gb" or "en-us". In this case, the extra part ("-gb" or "-us") is
+automatically removed.
+
+If you are not sure, simply specify the language code ("en" in this example);
+you will then given a list of existing pattern files.
+EOT
+} else {
# Extract pattern directory from Makefile, in the same directory as
# this script. A complete interpretation of the Makefiles would be
# too complicated, so only ${prefix} is read, which is (hopefully)
# defined as constant.
-
- my $mf = (dirname $0) . "/Makefile", $prefix = "";
- open MF, $mf or die "Cannot open $mf for reading: $!";
+ $prefix = "";
+ $makefile = (dirname $0) . "/Makefile";
+ open MF, $makefile or die "Cannot open $makefile: $!";
while (<MF>) {
if (/^\s*prefix\s*=\s*(.*)\s*$/) {
$prefix = $1;
- }
+ }
}
-
close MF;
-
+
if ($prefix eq "") {
- die "prefix not defined in $mf";
+ die "Prefix not defined in $makefile.";
}
-
- return "$prefix/lib/dillo/hyphenation";
-}
+ $patterdir = "$prefix/lib/dillo/hyphenation";
-sub printhelp {
- print " Syntax: install-hyphenation <lang1> [<lang2> ...]\n";
- print "\n";
- print " If there are multiple pattern files for a language, and so the file name\n";
- print " is not \"hyph-<lang>.tex\", you can specify the origin by using a colon:\n";
- print " \"<src-lang>:<dest-lang>\", eg. \"de-1996:de\". If both are identical, the\n";
- print " colon can be committed; \"ru\" is equivalent to \"ru:ru\".\n";
-
-}
+ if (!-e $patterdir) {
+ mkdir $patterdir or die "Cannot create directory $patterdir: $!";
+ print "Created $patterdir.\n";
+ }
-sub trpatfile {
- # Extract the data needed by dillo from the TeX file, based on two
- # rules:
- #
- # 1. Extract the argument of the "\pattern" sequence, i. e.
- # anything between "\pattern{" and the next "}".
- # 2. As an exception, comments are always preserved.
+ # Connect to CTAN FTP server, change to the directory where the
+ # patterns lie, and read files list (which may be useful later).
+ $ftp = Net::FTP->new($host,Timeout=>240)
+ or die "Cannot connect to $host: $!";
+ $ftp->login() or die "Cannot login: $!";
+ $ftp->cwd($dir) or die "Cannot change to directory $dir: $!";
+ @files = $ftp->ls or die "Cannot read directory: $!";
- my $url = $_[0], $in = $_[1], $out = $_[2];
-
- open IN, $in or die die "Cannot open $in for reading: $!";
- open OUT, "> $out" or die "Cannot open $out for writing: $!";
-
- printf OUT "%% The original file was downloaded from\n";
- printf OUT "%%\n";
- printf OUT "%% $url\n";
- printf OUT "%%\n";
- printf OUT "%% and automatically translated into this format. The original comments,\n";
- printf OUT "%% including the original copyright notice, are preserved.\n";
- printf OUT "%%\n";
- printf OUT "%% -----------------------------------------------------------------------------\n";
- printf OUT "%%\n";
-
- $inpatterns = 0;
- while (<IN>) {
- if (/^%/) {
- # Adopt all comments
- print OUT;
- } elsif (!$inpatterns) {
- if (/\\patterns\s*{/) {
- $inpatterns = 1;
- }
- } else {
- if (/}/) {
- $inpatterns = 0;
- } else {
- print OUT;
- }
+ # Finally, read pattern files.
+ foreach $arg (@ARGV) {
+ if ($arg =~ /^([a-z]+)-.*$/) {
+ # More files per language, e. g. "en-gb".
+ $lang = $1;
+ } else {
+ # One file per language, e. g. "ru".
+ $lang = $arg;
}
- }
-
- close IN;
- close OUT;
+
+ # First, donwload the pattern file to a temporary file.
+ $tmppat = tmpnam();
+ if ($ftp->get ("hyph-$arg.pat.txt", $tmppat)) {
+ printf ("Successfully downloaded pattern file for \"$arg\".\n");
+
+ # Search for a licence file. (Only a warning, when it does
+ # not exist.)
+ $tmplic = tmpnam();
+ $licfound = 0;
+ if ($ftp->get ("hyph-$arg.lic.txt", $tmplic)) {
+ $licfound = 1;
+ } else {
+ print "Warning: Cannot download license file for \"$arg\": $!\n";
+ }
+
+ # Combine both, licence and pattern, to the final pattern
+ # file.
+ $outfile = "$patterdir/$lang.pat";
+ open OUT, "> $outfile" or die "Cannot open $outfile: $!";
+
+ if ($licfound) {
+ print OUT
+ "% Licence from ftp://$host$dir/hyph-$arg.lic.txt\n";
+ print OUT "%\n";
+ open IN, $tmplic or die "Cannot open $tmplic: $!";
+ while (<IN>) {
+ # Each line from the licence file must be a comment.
+ if (!/^%/) {
+ print OUT "% ";
+ }
+ print OUT;
+ }
+ close IN;
+ unlink $tmplic;
- printf "Wrote pattern file: $out\n";
-}
-
-sub dlpatfile {
- my $lang = $_[0], $destdir = $_[1], $lang1, $lang2;
- if ($lang =~ /(.*):(.*)/) {
- $lang1 = $1;
- $lang2 = $2;
- } else {
- $lang1 = $lang2 = $lang;
+ print OUT "%\n";
+ }
+
+ print OUT "% Patterns from ftp://$host$dir/hyph-$arg.pat.txt\n";
+ print OUT "%\n";
+ open IN, $tmppat or die "Cannot open $tmppat: $!";
+ while (<IN>) {
+ print OUT;
+ }
+ close IN;
+ unlink $tmppat;
+
+ close OUT;
+ } else {
+ # Not found. If a single language was specified (e. g. "en"),
+ # search for possibilities.
+ print "Error: Cannot download pattern file for \"$arg\": $!\n";
+ if ($lang eq $arg) {
+ print "Try one of these:\n";
+ foreach(@files) {
+ if (/^hyph-($lang-.*)\.pat\.txt$/) {
+ print " $1\n";
+ }
+ }
+ }
+ }
}
- my $url = "ftp://ftp.mpi-sb.mpg.de/pub/tex/mirror/ftp.dante.de/pub/tex/language/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-$lang1.tex";
- my $tmp = tmpnam();
- if (system("wget -O $tmp $url") == 0) {
- my $out = "$destdir/$lang2.pat";
- trpatfile $url, $tmp, $out;
- unlink $tmp;
- } else {
- print "Error downloading patterns for language $lang1. See messages above for details.\n"
- }
-}
-
-$destdir = getpattendir;
-
-foreach $lang (@ARGV) {
- if ($lang eq '-?' || $lang eq '--?' || $lang eq '-h' ||
- $lang eq '--h' || $lang eq '-help' || $lang eq '--help') {
- printhelp;
- } else {
- dlpatfile $lang, $destdir;
- }
+ $ftp->quit;
}
diff --git a/lout/container.cc b/lout/container.cc
index deeede57..5e5eda73 100644
--- a/lout/container.cc
+++ b/lout/container.cc
@@ -190,16 +190,72 @@ void Vector::remove(int pos)
*/
void Vector::sort()
{
- qsort(array, numElements, sizeof(Object*), misc::Comparable::compareFun);
+ qsort (array, numElements, sizeof(Object*), Comparable::compareFun);
}
-
/**
- * \bug Not implemented.
+ * \brief Use binary search to find an element in a sorted vector.
+ *
+ * If "mustExist" is true, only exact matches are found; otherwise, -1
+ * is returned. If it is false, the position of the next greater
+ * element is returned, or, if the key is the greatest element, the
+ * size of the array. (This is the value which can be used for
+ * insertion; see insertSortet()).
*/
+int Vector::bsearch(Object *key, bool mustExist)
+{
+ // The case !mustExist is not handled by bsearch(3), so here is a
+ // new implementation.
+
+ int high = numElements - 1, low = 0;
+
+ while (true) {
+ int index = (low + high) / 2;
+ int c = ((Comparable*) key)->compareTo ((Comparable*)array[index]);
+ if (c == 0)
+ return index;
+ else {
+ if (low >= high) {
+ if (mustExist)
+ return -1;
+ else
+ return c > 0 ? index + 1 : index;
+ }
+
+ if (c < 0)
+ high = index - 1;
+ else
+ low = index + 1;
+ }
+ }
+
+
+ /*
+ void *result = ::bsearch (&key, array, numElements, sizeof (Object*),
+ Comparable::compareFun);
+ if (result)
+ return (Object**)result - array;
+ else
+ return -1;
+ */
+}
+
+Object *Vector::VectorIterator::getNext()
+{
+ if (index < vector->numElements - 1)
+ index++;
+
+ return index < vector->numElements ? vector->array[index] : NULL;
+}
+
+bool Vector::VectorIterator::hasNext()
+{
+ return index < vector->numElements - 1;
+}
+
Collection0::AbstractIterator* Vector::createIterator()
{
- return NULL;
+ return new VectorIterator(this);
}
// ------------
diff --git a/lout/container.hh b/lout/container.hh
index f1008e82..c87eb10c 100644
--- a/lout/container.hh
+++ b/lout/container.hh
@@ -102,11 +102,25 @@ public:
*/
class Vector: public Collection
{
+ friend class VectorIterator;
+
private:
object::Object **array;
int numAlloc, numElements;
bool ownerOfObjects;
+ class VectorIterator: public AbstractIterator
+ {
+ private:
+ Vector *vector;
+ int index;
+
+ public:
+ VectorIterator(Vector *vector) { this->vector = vector; index = -1; }
+ bool hasNext();
+ Object *getNext();
+ };
+
protected:
AbstractIterator* createIterator();
@@ -116,12 +130,23 @@ public:
void put(object::Object *newElement, int newPos = -1);
void insert(object::Object *newElement, int pos);
+
+ /**
+ * \brief Insert into an already sorted vector.
+ *
+ * Notice that insertion is not very efficient, unless the position
+ * is rather at the end.
+ */
+ inline void insertSorted(object::Object *newElement)
+ { insert (newElement, bsearch (newElement, false)); }
+
void remove(int pos);
inline object::Object *get(int pos)
{ return (pos >= 0 && pos < numElements) ? array[pos] : NULL; }
inline int size() { return numElements; }
void clear();
void sort();
+ int bsearch(Object *key, bool mustExist);
};
@@ -381,12 +406,16 @@ public:
{ ((untyped::Vector*)this->base)->put(newElement, newPos); }
inline void insert(T *newElement, int pos)
{ ((untyped::Vector*)this->base)->insert(newElement, pos); }
+ inline void insertSorted(T *newElement)
+ { ((untyped::Vector*)this->base)->insertSorted(newElement); }
inline void remove(int pos) { ((untyped::Vector*)this->base)->remove(pos); }
inline T *get(int pos)
{ return (T*)((untyped::Vector*)this->base)->get(pos); }
inline int size() { return ((untyped::Vector*)this->base)->size(); }
inline void clear() { ((untyped::Vector*)this->base)->clear(); }
inline void sort() { ((untyped::Vector*)this->base)->sort(); }
+ inline int bsearch(T *key, bool mustExist)
+ { return ((untyped::Vector*)this->base)->bsearch(key, mustExist); }
};
diff --git a/lout/misc.cc b/lout/misc.cc
index f45a3450..d4db609e 100644
--- a/lout/misc.cc
+++ b/lout/misc.cc
@@ -37,32 +37,6 @@ void init (int argc, char *argv[])
prgName = strdup (argv[0]);
}
-// ----------------
-// Comparable
-// ----------------
-
-Comparable::~Comparable()
-{
-}
-
-/**
- * \brief This static method may be used as compare function for qsort(3), for
- * an array of Object* (Object*[] or Object**).
- */
-int Comparable::compareFun(const void *p1, const void *p2)
-{
- Comparable **c1 = (Comparable**)p1;
- Comparable **c2 = (Comparable**)p2;
- if (c1 && c2)
- return ((*c1)->compareTo(*c2));
- else if (c1)
- return 1;
- else if (c2)
- return -1;
- else
- return 0;
-}
-
// ------------------
// StringBuffer
diff --git a/lout/misc.hh b/lout/misc.hh
index b0c0b2f8..cff8e05b 100644
--- a/lout/misc.hh
+++ b/lout/misc.hh
@@ -65,35 +65,6 @@ inline int AsciiStrcasecmp(const char *s1, const char *s2)
}
/**
- * \brief Instances of a sub class of this interface may be compared (less,
- * greater).
- *
- * Used for sorting etc.
- */
-class Comparable
-{
-public:
- virtual ~Comparable();
-
- /**
- * \brief Compare two objects c1 and c2.
- *
- * return a value < 0, when c1 is less than c2, a value > 0, when c1
- * is greater than c2, or 0, when c1 and c2 are equal.
- *
- * If also object::Object is implemented, and if c1.equals(c2),
- * c1.compareTo(c2) must be 0, but, unlike you may expect,
- * the reversed is not necessarily true. This method returns 0, if,
- * according to the rules for sorting, there is no difference, but there
- * may still be differences (not relevant for sorting), which "equals" will
- * care about.
- */
- virtual int compareTo(Comparable *other) = 0;
-
- static int compareFun(const void *p1, const void *p2);
-};
-
-/**
* \brief Simple (simpler than container::untyped::Vector and
* container::typed::Vector) template based vector.
*/
diff --git a/lout/object.cc b/lout/object.cc
index 85a908b9..99b5902d 100644
--- a/lout/object.cc
+++ b/lout/object.cc
@@ -106,6 +106,30 @@ size_t Object::sizeOf()
return sizeof(Object*);
}
+// ----------------
+// Comparable
+// ----------------
+
+/**
+ * \brief This static method may be used as compare function for
+ * qsort(3) and bsearch(3), for an array of Object* (Object*[] or
+ * Object**).
+ */
+int Comparable::compareFun(const void *p1, const void *p2)
+{
+ Comparable *c1 = *(Comparable**)p1;
+ Comparable *c2 = *(Comparable**)p2;
+
+ if (c1 && c2)
+ return ((c1)->compareTo(c2));
+ else if (c1)
+ return 1;
+ else if (c2)
+ return -1;
+ else
+ return 0;
+}
+
// -------------
// Pointer
// -------------
diff --git a/lout/object.hh b/lout/object.hh
index 9df69987..fd612863 100644
--- a/lout/object.hh
+++ b/lout/object.hh
@@ -34,6 +34,32 @@ public:
};
/**
+ * \brief Instances of a sub class of may be compared (less, greater).
+ *
+ * Used for sorting etc.
+ */
+class Comparable: public Object
+{
+public:
+ /**
+ * \brief Compare two objects c1 and c2.
+ *
+ * Return a value < 0, when c1 is less than c2, a value > 0, when c1
+ * is greater than c2, or 0, when c1 and c2 are equal.
+ *
+ * If c1.equals(c2) (as defined in Object), c1.compareTo(c2) must
+ * be 0, but, unlike you may expect, the reversed is not
+ * necessarily true. This method returns 0, if, according to the
+ * rules for sorting, there is no difference, but there may still
+ * be differences (not relevant for sorting), which "equals" will
+ * care about.
+ */
+ virtual int compareTo(Comparable *other) = 0;
+
+ static int compareFun(const void *p1, const void *p2);
+};
+
+/**
* \brief An object::Object wrapper for void pointers.
*/
class Pointer: public Object
@@ -63,7 +89,7 @@ public:
/**
* \brief An object::Object wrapper for int's.
*/
-class Integer: public Object, misc::Comparable
+class Integer: public Comparable
{
int value;
@@ -82,7 +108,7 @@ public:
*
* As opposed to object::String, the char array is not copied.
*/
-class ConstString: public Object, misc::Comparable
+class ConstString: public Comparable
{
protected:
const char *str;
diff --git a/src/uicmd.cc b/src/uicmd.cc
index 153d5fb4..f08c7e70 100644
--- a/src/uicmd.cc
+++ b/src/uicmd.cc
@@ -901,17 +901,10 @@ static int UIcmd_save_file_check(const char *name)
static void UIcmd_save(BrowserWindow *bw, const DilloUrl *url,
const char *title)
{
- const char *name;
- bool_t first_prompt = 1;
+ char *SuggestedName = UIcmd_make_save_filename(url);
+
while (1) {
- char *SuggestedName;
-
- SuggestedName =
- first_prompt
- ? UIcmd_make_save_filename(url)
- : dStrdup(name);
- first_prompt = 0;
- name = a_Dialog_save_file(title, NULL, SuggestedName);
+ const char *name = a_Dialog_save_file(title, NULL, SuggestedName);
dFree(SuggestedName);
if (name) {
@@ -932,6 +925,8 @@ static void UIcmd_save(BrowserWindow *bw, const DilloUrl *url,
} else {
return; /* no name, so Abort */
}
+
+ SuggestedName = dStrdup(name);
}
}
diff --git a/test/containers.cc b/test/containers.cc
index 646624aa..d8107bdf 100644
--- a/test/containers.cc
+++ b/test/containers.cc
@@ -6,41 +6,76 @@ using namespace lout::container::typed;
void testHashSet ()
{
+ puts ("--- testHashSet ---");
+
HashSet<String> h(true);
h.put (new String ("one"));
h.put (new String ("two"));
h.put (new String ("three"));
- Iterator<String> it = h.iterator ();
- while (it.hasNext ()) {
- String *o = it.getNext ();
- printf ("%s\n", o->chars());
- }
+ puts (h.toString());
}
void testHashTable ()
{
+ puts ("--- testHashTable ---");
+
HashTable<String, Integer> h(true, true);
h.put (new String ("one"), new Integer (1));
h.put (new String ("two"), new Integer (2));
h.put (new String ("three"), new Integer (3));
- for (Iterator<String> it = h.iterator (); it.hasNext (); ) {
- String *k = it.getNext ();
- Integer *v = h.get (k);
- printf ("%s -> %d\n", k->chars(), v->getValue());
- }
+ puts (h.toString());
h.put (new String ("one"), new Integer (4));
h.put (new String ("two"), new Integer (5));
h.put (new String ("three"), new Integer (6));
+
+ puts (h.toString());
+}
+
+void testVector ()
+{
+ puts ("--- testVector ---");
+
+ Vector<String> v (true, 1);
+
+ v.put (new String ("one"));
+ v.put (new String ("two"));
+ v.put (new String ("three"));
+ puts (v.toString());
+
+ v.sort ();
+ puts (v.toString());
+
+ v.insertSorted (new String ("five"));
+ puts (v.toString());
+
+ v.insertSorted (new String ("six"));
+ puts (v.toString());
+
+ v.insertSorted (new String ("four"));
+ puts (v.toString());
+
+ for (int b = 0; b < 2; b++) {
+ bool mustExist = b;
+ printf ("mustExist = %s\n", mustExist ? "true" : "false");
- for (Iterator<String> it = h.iterator (); it.hasNext (); ) {
- String *k = it.getNext ();
- Integer *v = h.get (k);
- printf ("%s -> %d\n", k->chars(), v->getValue());
+ String k ("alpha");
+ printf (" '%s' -> %d\n", k.chars(), v.bsearch (&k, mustExist));
+
+ for (Iterator<String> it = v.iterator(); it.hasNext(); ) {
+ String *k1 = it.getNext();
+ printf (" '%s' -> %d\n", k1->chars(), v.bsearch (k1, mustExist));
+
+ char buf[64];
+ strcpy (buf, k1->chars());
+ strcat (buf, "-var");
+ String k2 (buf);
+ printf (" '%s' -> %d\n", k2.chars(), v.bsearch (&k2, mustExist));
+ }
}
}
@@ -48,6 +83,7 @@ int main (int argc, char *argv[])
{
testHashSet ();
testHashTable ();
+ testVector ();
return 0;
}