Initial revision
[TestXSLT.git] / libsablot / src / engine / datastr.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable 
23  * instead of those above.  If you wish to allow use of your 
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32
33 #include "datastr.h"
34 #include "verts.h"
35 #include "utf8.h"
36 #include "tree.h"
37
38 // GP: clean (only 1 eFlag routine)
39
40 // #include <malloc.h> - not needed and deprecated anyway
41
42 /* const Str* theEmptyString = new Str(""); */
43
44 //     implementations for List are in datastr.h (List is a template)
45
46
47 /*****************************************************************
48 DynBlock
49
50   is a class for "dynamic memory blocks", i.e. blocks that can 
51   grow in size.
52 *****************************************************************/
53
54 DynBlock::DynBlock()
55 {
56     first = last = NULL;
57     byteCount = 0;
58 }
59
60 inline void DynBlock::remove()
61 {
62     DynBlockItem *d, *d_was;
63     if (first)
64     {
65         for (d = first; d; )
66         {
67             d_was = d;
68             d = d_was -> next;
69             delete [] d_was -> data;
70             delete d_was;
71         }
72     };
73     first = last = NULL;
74     byteCount = 0;
75 }
76
77 DynBlock::~DynBlock()
78 {
79     remove();
80 }
81
82 inline Bool DynBlock::isEmpty() const
83 {
84     return !byteCount;
85 }
86
87 void DynBlock::nadd(const char *data, int bytes)
88 {
89     DynBlockItem *newitem = new DynBlockItem;
90     newitem -> data = new char[bytes];
91     memcpy(newitem -> data, data, bytes);
92     newitem -> byteCount = bytes;
93     newitem -> next = NULL;
94     if (last)
95         last -> next = newitem;
96     else
97         first = newitem;
98     last = newitem;
99     byteCount += bytes;
100 }
101
102 char* DynBlock::getPointer() const
103 {
104     if (!first)
105         return NULL;
106     if (first -> next)
107         compact();
108     return (first -> data);
109 }
110
111 // compactToBuffer() joins the parts in a buffer. Returns buf+byteCount.
112 // if kill_ then the parts will be deallocated
113
114 int DynBlock::compactToBuffer_(char* buf, Bool kill_)
115 {
116     int compactedBytes = 0;
117     char *p = buf;
118     if (first)
119     {
120         DynBlockItem *d, *d_was;
121         for (d = first; d; )
122         {
123             memcpy(p, d -> data, d -> byteCount);
124             p += d -> byteCount;
125             compactedBytes += d -> byteCount;
126             d = (d_was = d) -> next;
127             if (kill_)
128             {
129                 delete[] d_was -> data;
130                 delete d_was;
131             }
132         };
133         if (kill_)
134         {
135             first = last = NULL;
136             byteCount = 0;
137         }
138     }
139     return compactedBytes;
140 }
141
142
143 #define thisNoConst (const_cast<DynBlock*>(this))
144
145
146 char* DynBlock::compactToBuffer() const
147 {
148     char *newdata = new char[byteCount+1];
149     newdata[thisNoConst -> compactToBuffer_(newdata, FALSE)] = 0;
150     return newdata;
151 }
152
153 void DynBlock::compact() const
154 {
155     if (!first || !(first -> next)) return;
156     int byteCountWas = byteCount;
157     char *newdata = new char[byteCount];
158     thisNoConst -> compactToBuffer_(newdata, TRUE);
159     thisNoConst -> first = thisNoConst -> last = new DynBlockItem;
160     thisNoConst -> first -> data = newdata;
161     thisNoConst -> byteCount = first -> byteCount = byteCountWas;
162     thisNoConst -> first -> next = NULL;
163 }
164
165
166
167 //
168 //     DynStrBlock
169 //     a flavour of DynBlock for use in dynamic strings
170 //
171 // compactString() allocates a new buffer to hold 'firstPart'
172 // plus the concat of all the DynStrBlock's parts. Kills the parts
173 // of the DynStrBlock.
174 //
175 char* DynStrBlock::compactString_(const char *firstPart, int firstLen)
176 {
177     int newLength = firstLen + byteCount;
178     char *newdata = new char[newLength + 1];
179     if (firstLen)
180         memcpy(newdata, firstPart, firstLen);
181     if (first)
182         compactToBuffer_(newdata + firstLen, TRUE);
183     newdata[newLength] = 0;
184     return newdata;
185 }
186
187
188
189
190 //
191 //                Str
192 //                static string
193 //
194
195
196 Str::Str()
197 {
198     text_ = NULL;
199     byteLength_ = 0;
200 }
201
202 Str::Str(const Str& string)
203 {
204     text_ = NULL;
205     operator= (string);
206 }
207
208 Str::Str(char c)
209 {
210     text_ = NULL;
211     operator= (c);
212 }
213
214 Str::Str(int num)
215 {
216     text_ = NULL;
217     operator= (num);
218 }
219
220 Str::Str(double num)
221 {
222     text_ = NULL;
223     operator= (num);
224 }
225
226 Str::Str(const char *chars)
227 {
228     if (!chars) 
229         chars="";
230     text_ = NULL;
231     operator= (chars);
232 }
233
234 Str::Str(const DStr &dstring)
235 {
236     text_ = NULL;
237     operator= (dstring);
238 }
239
240 Str& Str::operator=(const Str& string)
241 {
242     remove_();
243     int hisByteLen = string.length();
244     byteLength_ = hisByteLen;
245     text_ = claimMemory(hisByteLen + 1);
246     memcpy(operator char*(), string.operator char*(), hisByteLen+1);
247     return *this;
248 }
249
250 Str& Str::operator=(const DStr& dynamic)
251 {
252     remove_();
253     nset((char*) dynamic, dynamic.length());
254     return *this;
255 }
256
257 Str& Str::operator=(const char* chars)
258 {
259     nset(NZ(chars), strlen(chars));
260     return *this;
261 }
262
263 Str& Str::operator= (char c)
264 {
265     remove_();
266     char *p;
267     *(p = claimMemory(2)) = c;
268     p[1] = 0;
269     byteLength_ = 1;
270     text_ = p;
271     return *this;
272 }
273
274 Str& Str::operator= (int num)
275 {
276     remove_();
277     char buf[20];
278     sprintf(buf,"%d",num);
279     operator=(buf);
280     return *this;
281 }
282
283 Str& Str::operator= (double num)
284 {
285     remove_();
286     char buf[20];
287     sprintf(buf,"%.13g",num);
288     operator=(buf);
289     return *this;
290 }
291
292 void Str::nset(const char* chars, int len)
293 {
294     assert(chars);
295     remove_();
296     byteLength_ = len;
297     text_ = claimMemory(len + 1);
298     memcpy(text_, chars, len);
299     text_[len] = 0;
300 }
301
302 char Str::operator[] (int index) const
303 {
304     assert(index >= 0 && index <= length());
305     pack_();
306     return text_[index];
307 }
308
309 Bool Str::isEmpty() const
310 {
311     return !length(); // this is virtual
312 }
313
314 int Str::length() const
315 {
316     return byteLength_;
317 }
318
319 Str::operator char*() const
320 {
321     if (!text_)
322         const_cast<Str*>(this) -> empty();
323     return text_;
324 }
325
326 void Str::empty()
327 {
328     byteLength_ = 0;
329     remove_();
330     *(text_ = claimMemory(1)) = 0;
331 }
332
333 int Str::compare(const char* otherChars) const
334 {
335     int cmp = strcmp(operator char*(), otherChars);
336     if (!cmp)
337         return 0;
338     else return (cmp > 0 ? 1 : -1);
339 }
340
341 int Str::compare(const Str& other) const
342 {
343     return compare((const char*) other);
344 }
345
346 Bool Str::operator== (const Str& other) const
347 {
348     return (Bool) !strcmp(operator char*(), (char*) other);
349 }
350
351 Bool Str::operator== (const char* otherChars) const
352 {
353     return (Bool) !strcmp(operator char*(), otherChars);
354 }
355
356 Bool Str::operator== (char* otherChars) const
357 {
358     return (Bool) !strcmp(operator char*(), otherChars);
359 }
360
361 Bool Str::eqNoCase (const Str& other) const
362 {
363     return (strEqNoCase(operator char*(), (char*) other) ? TRUE : FALSE);
364 }
365
366 Bool Str::eqNoCase (const char* other) const
367 {
368     return (strEqNoCase(operator char*(), other) ? TRUE : FALSE);
369 }
370
371 Bool Str::operator< (const char* other)
372 {
373     return compare(other) < 0;
374 }
375
376 Bool Str::operator< (const Str &other)
377 {
378   return operator<((const char*) other);
379 }
380
381 Bool Str::toDouble(double &d) const
382 {
383     char *stopper;
384     d = strtod(operator char*(),&stopper);
385     return (!!*stopper);
386 }
387
388 Str::~Str()
389 {
390     remove_();
391 }
392
393 DStr& Str::appendSelf(DStr& other)
394 {
395     other.nadd(operator char*(), length());
396     remove_();
397     return other;
398 }
399
400 DStr Str::operator+ (const Str& other) const
401 {
402     pack_();
403     other.pack_();
404     DStr temp(*this);
405     temp += other;
406     return temp;
407 }
408
409 DStr Str::operator+ (const char* otherChars) const
410 {
411     pack_();
412     DStr temp(*this);
413     temp += otherChars;
414     return temp;
415 }
416
417 DStr Str::operator+ (int num) const
418 {
419     pack_();
420     DStr temp(*this);
421     temp += num;
422     return temp;
423 }
424
425
426 // pack_() is overridden in DStr to put the pieces of the dynamic
427 // string together
428 //
429 void Str::pack_() const
430 {
431     if (!text_)
432         const_cast<Str*>(this) -> empty();
433 };
434
435
436 // a ridiculous old function (almost dead)
437 // FIXME: do away with it and namechar() too
438 //
439 void Str::speakTerse(DStr &ret)
440 {
441     int i;
442     char c;
443     pack_();
444     for (i = 0; i < length(); i++)
445     {
446         switch(c = (*this)[i])
447         {
448         case '\n': 
449             ret += "&#10;"; break;
450         case '\t': 
451             ret += "&#9;"; break;
452         default:
453             ret += c;
454         };
455     };
456 }
457
458 char* Str::cloneData()
459 {
460   pack_();
461   char *ret = new char[length() + 1];
462   strcpy(ret, text_);
463   return ret;
464 }
465
466
467 //
468 //
469 //                  DStr
470 //                  dynamic string
471 //
472 //
473
474
475 DStr::DStr()
476 {
477 };
478
479 DStr::DStr(char c)
480 {
481     // was: text = NULL 
482     // which leaks memory since Str::Str() is called
483     returnMemory(text_);
484     operator+=(c);
485 };
486 DStr::DStr(const char *chars)
487 {
488     // was: text = NULL 
489     // which leaks memory since Str::Str() is called
490     returnMemory(text_);
491     operator+=(chars);
492 };
493
494 DStr::DStr(const Str& string)
495 {
496     // was: text = NULL 
497     // which leaks memory since Str::Str() is called
498     returnMemory(text_);
499     operator+=(string);
500 };
501
502 DStr::DStr(const DStr& dstring)
503   : Str()
504 {
505     // was: text = NULL 
506     // which leaks memory since Str::Str() is called
507     returnMemory(text_);
508     operator+=(dstring);
509 };
510
511 DStr& DStr::operator=(const DStr& other)
512 {
513     remove_();
514     operator+=(other);
515     return *this;
516 }
517
518
519 DStr& DStr::nadd(const char *adding, int len)
520 {
521     assert(adding);
522     if (text_)
523         blocks.nadd(adding, len);
524     else
525         nset(adding,len);
526     return *this;
527 }
528
529
530 DStr& DStr::operator+= (const char *adding)
531 {
532     if (!text_ || *adding)
533         nadd(adding, strlen(adding));
534     return *this;
535 }
536
537 DStr& DStr::operator+= (const Str& addingStr)
538 {
539     nadd((char*) addingStr, addingStr.length());
540     return *this;
541 }
542
543 DStr& DStr::operator+=(const DStr& other)
544 {
545     if (!other.text_) return *this;
546     nadd(other.text_, other.byteLength_);
547     DynBlockItem *b;
548     for (b = other.blocks.first; b; b = b -> next)
549         nadd(b -> data, b -> byteCount);
550     return *this;
551 }
552
553 DStr& DStr::operator+= (int addingnum)
554 {
555     Str temp = addingnum;
556     return operator +=(temp);
557 }
558
559 DStr& DStr::operator+= (char addingc)
560 {
561     Str temp = addingc;
562     return operator +=(temp);
563 }
564
565 DStr& DStr::appendSelf(DStr& other)
566 {
567     other.nadd(text_, byteLength_);
568     DynBlockItem *b;
569     for (b = blocks.first; b; b = b -> next)
570         other.nadd(b -> data, b -> byteCount);
571     remove_();
572     byteLength_ = 0;
573     return other;
574 }
575
576 DStr::~DStr()
577 {
578     remove_();
579 }
580
581 void DStr::remove_()
582 {
583     returnMemory(text_);
584     blocks.remove();   
585 }
586
587 void DStr::pack_() const
588 {
589     // if not needed leave asap
590     if (blocks.isEmpty()) return;
591     int blocksLen = blocks.byteCount;
592     // concat text_ with the contents of all blocks
593     char *oldText_ = const_cast<DStr*>(this) -> text_;
594     const_cast<DStr*>(this) -> text_ =
595         const_cast<DynStrBlock*>(&blocks) -> 
596         compactString_(text_, byteLength_);
597     returnMemory(oldText_);
598     const_cast<DStr*>(this) -> byteLength_ += blocksLen;
599     // the length stays the same
600 }
601
602 int DStr::length() const
603 {
604     return byteLength_ + blocks.byteCount; 
605 }
606
607 DStr::operator char* () const
608 {
609     pack_();
610     return Str::operator char*();
611 }
612
613
614
615 //
616 //
617 //  string functions
618 //
619 //
620
621 void escapeChars(DStr& result, const Str& what, 
622                  const char* toEscape, const char** substitutes)
623 {
624     char *pStart = what, *p = pStart;
625     int chunkLength;
626     while (pStart)
627     {
628         p = strpbrk(pStart, toEscape);
629         if (p)
630         {
631             if ((chunkLength = (int)(p - pStart)))
632                 result.nadd(pStart, chunkLength);
633             result += substitutes[(int) (NZ(strchr(toEscape, *p)) - toEscape)];
634             pStart = ++p;
635         }
636         else 
637         {
638             result += pStart;
639             pStart = NULL;
640         }
641     }
642 }
643
644
645 //
646 //
647 //                  QName
648 //                  holds a qname as in the XML spec
649 //
650 //
651
652 QName::QName()
653 {
654     local = UNDEF_PHRASE;
655     uri = UNDEF_PHRASE;
656     prefix = UNDEF_PHRASE;
657 }
658
659 QName::QName(const QName &other)
660 {
661     local = other.local;
662     uri = other.uri;
663     prefix = other.prefix;
664 }
665
666 QName& QName::operator =(const QName& other)
667 {
668     local = other.local;
669     uri = other.uri;
670     prefix = other.prefix;
671     return *this;
672 }
673
674 Bool QName::isEmpty() const
675 {
676     return (uri == UNDEF_PHRASE && local == UNDEF_PHRASE);
677 };
678
679 void QName::empty()
680 {
681     prefix = UNDEF_PHRASE;
682     local = UNDEF_PHRASE;
683     uri = UNDEF_PHRASE;
684 }
685
686 /*
687 void QName::speak(DStr &s, SpeakMode mode) const
688 {
689     if (prefix != UNDEF_PHRASE)
690     {
691         s += dict().getKey(prefix);
692         s += ":";
693     };
694     s += dict().getKey(local);
695 }
696 */
697
698 /*
699 Bool QName::prefixIsNS(const Str &uri2) const
700 {
701     Phrase uri2Id;
702     dict().insert(uri2, uri2Id);
703     return (uri == uri2Id);
704
705 */
706
707 void QName::setPrefix(Phrase prefix_)
708 {
709     prefix = prefix_;
710 //    dict().insert(pref, prefix);
711 }
712
713
714 void QName::setLocal(Phrase local_)
715 {
716     local = local_;
717 //    dict().insert(loc, local);
718 }
719
720 void QName::setUri(Phrase uri_)
721 {
722     uri = uri_;
723 //    dict().insert(u, uri);
724 }
725
726
727 Bool QName::operator== (const QName &other) const
728 {
729     return local == other.local && uri == other.uri;
730 }
731
732 /*
733 Str QName::getname() const
734 {
735     DStr s;
736     speak(s,SM_NAME);
737     return s;
738 }
739 */
740
741 Phrase QName::getLocal() const
742 {
743     return local;
744 //  return dict().getKey(local);
745 }
746
747 Phrase QName::getUri() const
748 {
749     return uri;
750 //  return dict().getKey(uri);
751 }
752
753 Phrase QName::getPrefix() const
754 {
755     return prefix;
756 //  return dict().getKey(prefix);
757 }
758
759 Bool QName::hasPrefix() const
760 {
761    return (prefix != UNDEF_PHRASE);
762 }
763
764
765 //
766 //
767 //  QNameList
768 //
769 //
770
771 int QNameList::findNdx(const QName &what) const
772 {
773     int count = number();
774     for (int i = 0; i < count; i++)
775                 // checking for equality of local and uri
776                 if ((*this)[i] -> operator==(what))
777                     return i;
778     return -1;
779 }
780
781 //
782 //    EQName
783 //
784
785 EQName::EQName()
786 {
787 };
788
789 EQName::EQName(const EQName& other)
790 {
791     prefix = other.getPrefix();
792     uri = other.getUri();
793     local = other.getLocal();
794 };
795
796 Bool EQName::isEmpty() const
797 {
798     return prefix.isEmpty() && uri.isEmpty() && local.isEmpty();
799 }
800
801 void EQName::empty()
802 {
803     prefix.empty();
804     uri.empty();
805     local.empty();          
806 }
807
808 void EQName::set(const QName& q, const HashTable& dict)
809 {
810     prefix = dict.getKey(q.getPrefix());
811     uri = dict.getKey(q.getUri());
812     local = dict.getKey(q.getLocal());
813 }
814
815 void EQName::setPrefix(const Str& prefix_)
816 {
817     prefix = prefix_;
818 }
819
820 void EQName::setLocal(const Str& local_)
821 {
822     local = local_;
823 }
824
825 void EQName::setUri(const Str& uri_)
826 {
827     uri = uri_;
828 }
829
830 void EQName::getname(Str& fullName) const
831 {
832     DStr strg;
833     if (!prefix.isEmpty())
834     {
835         strg += prefix;
836         strg += ":";
837     };
838     strg += local;
839     fullName = strg;
840 }
841
842 const Str& EQName::getLocal() const
843 {
844     return local;
845 }
846
847 const Str& EQName::getUri() const
848 {
849     return uri;
850 }
851
852 const Str& EQName::getPrefix() const
853 {
854     return prefix;
855 }
856
857 Bool EQName::hasPrefix() const
858 {
859     return !prefix.isEmpty();
860 }
861
862 Bool EQName::operator==(const EQName &other) const
863 {
864     return (uri == other.getUri() 
865         && local == other.getLocal() 
866             && uri == other.getUri());
867 }
868
869
870
871 //
872 //
873 //                  StrStrList
874 //
875 //
876
877
878
879 int StrStrList::findNum(const Str &key_) const
880 {
881     int i, count = number();
882     for (i = 0; (i < count) && !(key_ == ((*this)[i] -> key)); i++) {};
883     return (i < count) ? i : -1;
884 }
885
886 Str* StrStrList::find(const Str &_key) const
887 {
888     int ndx = findNum(_key);
889     return (ndx != -1) ? &((*this)[ndx] -> value) : NULL;
890 }
891
892 void StrStrList::appendConstruct(const Str &key, const Str& value)
893 {
894     StrStr* newItem = new StrStr;
895     newItem -> key  = key;
896     newItem -> value = value;
897     append(newItem);
898 }
899
900 //
901 //
902 //                  NamespaceStack
903 //
904 //
905
906 int NamespaceStack::findNum(const Str &prefix_) const
907 {
908     int i, count = number();
909     for (i = count-1; (i >= 0) && !(prefix_ == ((*this)[i] -> prefix)); i--) {};
910     return i;
911 }
912
913 const Str* NamespaceStack::getUri(const Str &_prefix) const
914 {
915     int ndx = findNum(_prefix);
916     return (ndx != -1) ? &((*this)[ndx] -> uri) : NULL;
917 }
918
919
920 Bool NamespaceStack::isHidden(const Str &_prefix) const
921 {
922     int ndx = findNum(_prefix);
923     return (ndx != -1) ? ((*this)[ndx] -> hidden) : TRUE;
924 }
925
926 void NamespaceStack::appendConstruct(const Str &prefix, const Str& uri,
927                                      Bool _hidden)
928 {
929     NamespaceStackObj* newItem = new NamespaceStackObj;
930     newItem -> prefix  = prefix;
931     newItem -> uri = uri;
932     newItem -> hidden = _hidden;
933     append(newItem);
934 }
935
936
937 //
938 //
939 //                  EQNameList
940 //
941 //
942
943
944 const EQName* EQNameList::find(const EQName &what) const
945 {
946     int i, count = number();
947     for (i = 0; (i < count) && !(what == (*operator[](i))); i++) {};
948     return (i < count) ? operator[](i) : NULL;
949 }
950
951
952
953 //
954 //
955 //                  EQNameStrList
956 //
957 //
958
959 // returns -1 if the EQName was not found
960 int EQNameStrList::findNdx(const EQName &what) const
961 {
962     int i, count = number();
963     for (i = 0; i < count && !(what == operator[](i) -> key); i++) {};
964     return (i < count) ? i : -1;
965 }
966
967 const Str* EQNameStrList::find(const EQName &what) const
968 {
969     int i = findNdx(what);
970     return (i != -1 ? &(operator[](i) -> value) : NULL);
971 }
972
973 void EQNameStrList::appendConstruct(const EQName &key, const Str& value)
974 {
975     EQNameStr* newItem = new EQNameStr(key, value);
976     append(newItem);
977 }
978
979
980
981 /************************************/
982 /* PrefixList */
983 int UriList::findNdx(Phrase what) {
984   for (int i = 0; i < number(); i++) {
985     Phrase foo = (*this)[i];
986     if (foo == what) return i;
987   }
988   return -1;
989 }
990
991 void UriList::addUri(Phrase what) {
992   int i = findNdx(what);
993   if (i == -1) append(what);
994 }
995
996
997