OSDN Git Service

Initial Commit. Toppers/JSP for Blackfin 3.3.1
[trx-305dsp/dsp.git] / trx305 / kernel / cfg / base / directorymap.cpp
1 /*
2  *  TOPPERS/JSP Kernel
3  *      Toyohashi Open Platform for Embedded Real-Time Systems/
4  *      Just Standard Profile Kernel
5  * 
6  *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
7  *                              Toyohashi Univ. of Technology, JAPAN
8  * 
9  *  上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 
10  *  によって公表されている GNU General Public License の Version 2 に記
11  *  述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
12  *  を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
13  *  利用と呼ぶ)することを無償で許諾する.
14  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16  *      スコード中に含まれていること.
17  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20  *      の無保証規定を掲載すること.
21  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23  *      と.
24  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
26  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27  *        報告すること.
28  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30  * 
31  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
32  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
33  *  含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
34  *  接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
35  * 
36  *  @(#) $Id: directorymap.cpp,v 1.1 2009/01/31 05:27:37 suikan Exp $
37  */
38
39
40 // $Header: /cvsroot/toppersjsp4bf/jsp/cfg/base/directorymap.cpp,v 1.1 2009/01/31 05:27:37 suikan Exp $
41
42 /* MEMO:メモ書き
43      Q: こういうクラスはテンプレートにしたほうがいいと思うが?
44      A: ファイルに吐き出した後、読み出したときにどうやってクラス生成すべきかがわからない
45          (クラスファクトリを作るのはやめたい)
46         今と違う型を代入されたときの対処法がわからない
47 */
48
49
50 #include "base/directorymap.h"
51 #include "base/message.h"
52 #include <stdarg.h>
53 #include <typeinfo>
54 #include <cassert>
55 #include <cstdio>
56
57 #ifdef _MSC_VER
58   #pragma warning(disable:4786)
59 #endif
60
61 using namespace std;
62
63 int Directory::defaultflag = Directory::NOTHING;
64
65 Directory::Directory(const Directory & src)
66 {
67     parent = 0;
68     flag = defaultflag;
69     defaultflag &= ~DESTRUCT;
70
71     type = src.type;
72     switch(type)
73     {
74     case LITERAL:
75         content.literal = new string(*src.content.literal);
76         break;
77     default:
78         content = src.content;
79         break;
80     }
81 }
82
83 Directory::~Directory(void)
84 {
85     disconnect();                       //親との連結を解除
86     map<string,Directory*>::clear();    //子ノードの削除
87     clearContent();                         //自分の中身を削除する
88 }
89
90 void Directory::clearContent(void)
91 {
92     switch(this->getType())
93     {
94     case LITERAL:
95         delete content.literal;
96         break;
97     case OBJECT:
98         delete content.instance;
99         break;
100     default:
101         break;
102     }
103
104     type = UNKNOWN;
105     content.pointer = 0;
106 }
107
108 Directory * Directory::findNode(bool automatic_creation, const string & path)
109 {
110     string::size_type top, tail, length;
111     string work;
112     Directory::iterator scope;
113     Directory * node = this;
114
115     if(this == NULL)
116         return NULL;
117
118     if(path.empty())
119         return this;
120
121     length = path.length();
122     top = 0;
123     if(path[0] == '/')
124     {
125         while(node->getParent() != 0)
126             node = node->getParent();
127         if(path.size() == 1)
128             return node;
129         top = 1;
130     }
131
132     do {
133         tail = path.find_first_of('/', top);
134         if(tail == string::npos)
135             work = path.substr(top);
136         else
137             work = path.substr(top, tail-top);
138
139         if(work.compare(".") == 0 || work.compare("..") == 0)
140         {
141             if(work.size() > 1 && node->getParent() != 0)
142                 node = node->getParent();
143         }else
144         {
145             scope = node->begin();
146             while(scope != node->end())
147             {
148                 if(work.compare((*scope).first) == 0)
149                     break;
150                 ++ scope;
151             }
152
153             if(scope == node->end())
154             {
155                 if(!automatic_creation)
156                     return 0;
157                 node = node->addChild(work, new Directory);
158             }else
159                 node = (*scope).second;
160         }
161         top = tail + 1;
162     } while( tail != string::npos && top < length );
163
164     return node;
165 }
166
167 Directory * Directory::findNode(bool automatic_creation, const char * key, va_list vl)
168 {
169     Directory::iterator scope;
170     Directory * node = this;
171
172     if(this == NULL)
173         return NULL;
174
175     if(key == NULL)
176         return this;
177
178     if(*key == '/' && *(key+1) == '\x0')
179     {
180         while(node->getParent() != 0)
181             node = node->getParent();
182         if(vl == 0)
183             return node;
184         key = va_arg(vl, const char *);
185     }
186
187     do {
188         if(strcmp(key,".") != 0)
189         {
190             if(strcmp(key,"..") == 0)
191             {
192                 node = node->parent;
193             }else
194             {
195                 scope = node->begin();
196                 while(scope != node->end())
197                 {
198                     if((*scope).first.compare(key) == 0)
199                         break;
200                     ++ scope;
201                 }
202
203                 if(scope == node->end())
204                 {
205                     if(!automatic_creation)
206                         return 0;
207                     node = node->addChild(key, new Directory);
208                 }else
209                     node = (*scope).second;
210             }
211         }
212         if(vl != 0)
213             key = va_arg(vl, const char *);
214         else
215             break;
216     } while( key != 0 && node != 0);
217
218     return node;
219 }
220
221 Directory & Directory::operator =(void * pointer)
222 {
223     if(this->getType() != UNKNOWN && this->getType() != POINTER)
224         clearContent();
225
226     type = POINTER;
227     content.pointer = pointer;
228     return *this;
229 }
230
231 Directory & Directory::operator =(long value)
232 {
233     if(this->getType() != UNKNOWN && this->getType() != INTEGER)
234         clearContent();
235
236     type = INTEGER;
237     content.value = value;
238     return *this;
239 }
240
241 Directory & Directory::operator =(const string & literal)
242 {
243     if(this->getType() != UNKNOWN && this->getType() != LITERAL)
244         clearContent();
245
246     type = LITERAL;
247     content.literal = new string(literal);
248
249     return *this;
250 }
251
252 Directory & Directory::operator =(const char * constliteral)
253 {
254     if(this->getType() != UNKNOWN && this->getType() != CONSTLITERAL)
255         clearContent();
256
257     type = CONSTLITERAL;
258     content.const_literal = constliteral;
259     return *this;
260 }
261
262 Directory & Directory::operator =(Garbage * instance)
263 {
264     if(this->getType() != UNKNOWN)
265         clearContent();
266
267     type = OBJECT;
268     content.instance = instance;
269     return *this;
270 }
271
272 void * Directory::operator new(size_t sz)
273 {
274     defaultflag |= DESTRUCT;
275     return ::operator new(sz);
276 }
277
278 void * Directory::operator new(size_t sz, nothrow_t)
279 {
280     defaultflag |= DESTRUCT;
281     return ::operator new(sz, nothrow);
282 }
283
284 Directory::operator const long(void) const
285 {
286     if( type == UNKNOWN )
287         ExceptionMessage("Bad cast exception","不正キャスト例外") << throwException;
288     return content.value;
289 }
290
291 void * Directory::operator * (void) const
292 {
293     if( type == UNKNOWN )
294         ExceptionMessage("Bad cast exception","不正キャスト例外") << throwException;
295     return content.pointer;
296 }
297
298 Directory * Directory::addChild(const std::string & key, Directory * node)
299 {
300     iterator scope;
301     std::pair<iterator, bool> work;
302
303     if(node == 0)
304         node = new Directory;
305     else
306         if(node->parent != 0)
307             node->disconnect();
308
309     node->parent = this;
310     if((scope = find(key)) != end())
311     {
312         Directory * old = (*scope).second;
313         old->disconnect();
314         old->erase();
315     }
316
317     work = insert(value_type(key, node));
318     node->myself = work.first;
319
320     return node;
321 }
322
323 Directory::iterator Directory::erase(iterator it)
324 {
325     iterator result;
326     Directory * scope = (*it).second;
327
328         //戻り値の作成
329     if((result = it) == begin())
330       ++ result;
331     else
332       -- result;
333
334         //外したノードの後始末
335     if((scope->flag & DESTRUCT) != 0)
336         delete scope;
337     else
338         scope->erase();
339
340     return result;
341 }
342
343 void Directory::erase(void)
344 {
345     iterator scope;
346
347     if(this != NULL)
348     {
349         if(parent != 0)
350         {
351             parent->erase(myself);
352         }else
353         {
354             while(!empty())
355             {
356                 scope = begin();
357                 if((scope->second->flag & DESTRUCT) != 0)
358                     delete scope->second;
359                 else
360                     scope->second->erase();
361             }
362         }
363     }
364 }
365
366 void Directory::disconnect(void)
367 {
368     if(parent != 0)
369     {
370         parent->map<string,Directory*>::erase(myself);
371         parent = 0;
372     }
373 }
374
375 Directory * Directory::getNext(void) const
376 {
377     if(parent == 0)
378         return 0;
379
380     iterator scope;
381     scope = myself;
382     ++ scope;
383     if(scope == parent->end())
384         return 0;
385
386     return (*scope).second;
387 }
388
389 Directory * Directory::getPrev(void) const
390 {
391     if(parent == 0 && myself == parent->begin())
392         return 0;
393
394     reverse_iterator scope;
395     
396     scope = parent->rbegin();
397     while(scope != parent->rend() && (*scope).second != (*myself).second)
398         ++ scope;
399
400     ++ scope;
401     return scope != parent->rend() ? (*scope).second : 0;
402 }
403
404 bool Directory::changeKey(const string & key)
405 {
406     Directory * scope;
407
408     if( key.size() == 0)
409         return false;
410
411     scope = parent;
412
413     disconnect();
414     scope->addChild(key, this);
415     return true;
416 }
417
418
419 void Directory::drawTree(ostream * out, int level, string * link)
420 {
421     iterator scope;
422     iterator scope2;
423
424     if(level == 0)
425         link = new string;
426     else
427         *out << (*link).substr(0, (level-1)*3) << " +-";
428
429     *out << '[' << getKey() << ']';
430     switch(type)
431     {
432     case POINTER:
433         out->setf(ios::hex);
434         *out << " : PTR [" << content.pointer << "]";
435         break;
436     case INTEGER:
437         out->setf(ios::dec);
438         *out << " : INT [" << content.value << "]";
439         break;
440     case LITERAL:
441         *out << " : STR [" << *content.literal << "]";
442         break;
443     case CONSTLITERAL:
444         *out << " : CSTR[" << content.const_literal << "]";
445         break;
446     case OBJECT:
447         {
448             *out << " : OBJ";
449             break;
450         }
451     case UNKNOWN:
452         break;
453     default:
454         *out << "UNKNOWN";
455     }
456     *out << '\n';
457     (*link) += " | ";
458     scope = begin();
459     while(scope != end())
460     {
461         scope2 = scope;
462         ++ scope;
463
464         if(scope == end())
465             (*link)[level*3+1] = ' ';
466         (*scope2).second->drawTree(out, level+1, link);
467     }
468
469
470     link->erase(level*3);
471     if(level == 0)
472         delete link;
473 }
474
475 static string escapeXMLLiterals(const string & src)
476 {
477     int index;
478     string::size_type pos;
479     string result;
480     const char   literal[4] ="&<>";
481     const char * escape[3]  = {"&amp;","&lt;","&gt;"};
482
483     result = src;
484     for(index = 0; index < 3; index++)
485     {
486         pos = 0;
487         while((pos = result.find_first_of(literal[index],pos)) != string::npos)
488         {
489             result.erase(pos,1);
490             result.insert(pos, escape[index]);
491             ++ pos;
492         }
493     }
494
495     return result;
496 }
497
498 static string encloseAttributes(const string & src)
499 {
500     if(src.find_first_of('"') != string::npos)
501         return string("'") + src + "'";
502     return string("\"") + src + "\"";
503 }
504
505 void Directory::drawTree_byXML(ostream * out, int level)
506 {
507     iterator scope;
508
509     if(level == 0)
510         *out << "<?xml version='1.0' encoding='Shift_JIS' ?>\n<?xml-stylesheet type='text/xsl' href='basic.xsl' ?>\n";
511
512     *out << "<node key=" << encloseAttributes(escapeXMLLiterals(getKey())) << " type='";
513
514     switch(type)
515     {
516     case POINTER:
517         out->setf(ios::hex);
518         *out << "PTR'><value>" << content.pointer << "</value>";
519         break;
520     case INTEGER:
521         out->setf(ios::dec);
522         *out << "INT'><value>" << content.value << "</value>";
523         break;
524     case LITERAL:
525         *out << "STR'><value>" << escapeXMLLiterals(*content.literal) << "</value>";
526         break;
527     case CONSTLITERAL:
528         *out << "CSTR'><value>" << escapeXMLLiterals(content.const_literal) << "</value>";
529         break;
530     case OBJECT:
531         *out << "OBJ'>";
532         break;
533     case UNKNOWN:
534         *out << "'>";
535         break;
536     default:
537         *out << "UNKNOWN'>";
538     }
539     *out << '\n';
540
541     scope = begin();
542     if(scope != end())
543     {
544         *out << "<child>\n";
545         do{
546             scope->second->drawTree_byXML(out, level+1);
547             ++ scope;
548         }while(scope != end());
549         *out << "</child>\n";
550     }
551     *out << "</node>\n";
552 }
553  
554 Directory * Directory::findChild(const char * key)
555 {
556     string work(key);
557     if(work.find_first_of('/') != string::npos)
558         return findChild(work);
559     return findNode(false, key, 0);
560 }
561
562 Directory * Directory::findChild(const char * key, const char * second, ... )
563 {
564     va_list vl;
565     va_start(vl, second);
566     return findNode(false, key, 0)->findNode(false,second, vl);
567 }
568
569 Directory * Directory::openChild(const char * key)
570 {
571     string work(key);
572     if(work.find_first_of('/') != string::npos)
573         return openChild(work);
574     return findNode(true, key, 0);
575 }
576
577
578 Directory * Directory::openChild(const char * key, const char * second, ... )
579 {
580     va_list vl;
581     va_start(vl, second);
582     return findNode(true, key, 0)->findNode(true, second, vl);
583 }
584
585     //指定したキーを持つ子孫を探す。サーチ順は中順
586 Directory * Directory::findDescandant(const string & key, unsigned int level) const
587 {
588     Directory::const_iterator scope;
589     const Directory * node = this;
590
591     if(empty())
592         return 0;
593
594         //子で探す
595     scope = begin();
596     while( scope != end() )
597     {
598         if((*scope).first.compare(key) == 0)
599             return const_cast<Directory *>((*scope).second);
600         ++ scope;
601     }
602
603     if(level > 0)
604     {
605         scope = begin();
606         while( scope != end() )
607         {
608             if((node = (*scope).second->findDescandant(key, level-1)) != 0)
609                 return const_cast<Directory *>(node);
610             ++ scope;
611         }
612     }
613     return 0;
614 }
615
616 void Directory::copyTo(Directory * dest, int nest)
617 {
618     Directory::iterator scope;
619     Directory * node;
620
621     if(this == NULL)
622         return;
623
624     assert(dest != NULL);
625
626     node = dest;
627     while(node != 0)
628     {
629         if(node == this)
630              ExceptionMessage("CopyTo: dest must not be a descendant node.","CopyTo: 子孫ノードへのコピーはできません") << throwException;
631         node = node->getParent();
632     }
633
634     scope = begin();
635     while(scope != end())
636     {
637         node = dest->findChild((*scope).first);
638         if(node != 0)
639             node->erase();
640
641         node = dest->addChild((*scope).first, new Directory(*(*scope).second));
642         if(nest > 0)
643             (*scope).second->copyTo(node, nest-1);
644
645         ++ scope;
646     }
647 }
648
649 void Directory::Store(ostream * out)
650 {
651     int i;
652     Directory * node;
653
654     out->write((const char *)&type, sizeof(type));
655     switch(type)
656     {
657     case INTEGER:
658         out->write((const char *)&content.value, sizeof(content.value));
659         break;
660     case LITERAL:
661         i = content.literal->size();
662         out->write((const char *)&i, sizeof(int));
663         out->write(content.literal->c_str(), i);
664         break;
665     case CONSTLITERAL:
666         i = strlen(content.const_literal);
667         out->write((const char *)&i, sizeof(int));
668         out->write(content.const_literal, i);
669         break;
670     default:
671         out->write((const char *)&content.pointer, sizeof(content.pointer));
672     }
673     i = size();
674     out->write((const char *)&i, sizeof(int));
675     for(node = getFirstChild(); node != 0; node = node->getNext())
676     {
677         const string & work = node->getKey();
678         i = work.size();
679         out->write((const char *)&i, sizeof(int));
680         out->write(work.c_str(), i);
681         node->Store(out);
682     }
683 }
684
685 void Directory::Load(istream * in)
686 {
687     int i;
688     int count;
689     char buffer[1024];
690
691     in->read((char *)&type, sizeof(type));
692     switch(type)
693     {
694     case INTEGER:
695         in->read((char *)&content.value, sizeof(content.value));
696         break;
697     case CONSTLITERAL:
698     case LITERAL:
699         in->read((char *)&i, sizeof(int));
700         in->read(buffer, i);
701         buffer[i] = '\x0';
702         *this = string(buffer);
703         break;
704     default:
705         in->read((char *)&content.pointer, sizeof(content.pointer));
706     }
707     in->read((char *)&count, sizeof(int));
708     while(count-- > 0)
709     {
710         in->read((char *)&i, sizeof(int));
711         in->read(buffer, i);
712         buffer[i] = '\x0';
713
714         addChild(buffer)->Load(in);
715     }
716 }
717
718 string Directory::toString(const string & default_value) const
719 {
720     if(this == 0)
721         return default_value;
722
723     switch(type)
724     {
725     case POINTER:
726     case OBJECT:
727         {
728             char buffer[256];
729             sprintf(buffer,"%08lx", (long)content.pointer);
730             return string(buffer);
731         }
732     case INTEGER:
733         {
734             char buffer[256];
735             sprintf(buffer,"%ld", content.value);
736             return string(buffer);
737         }
738     case CONSTLITERAL:
739         return string(content.const_literal);
740     case LITERAL:
741         return string(*content.literal);
742         default:
743             return default_value;
744     }
745
746     return default_value;
747 }
748
749 void * Directory::toPointer(const void * default_value) const
750 {
751     if(this == 0)
752         return (void *)default_value;
753
754     switch(type)
755     {
756     case INTEGER:
757         return (void *)&content.value;
758     case CONSTLITERAL:
759         return (void *)content.const_literal;
760     case LITERAL:
761         return (void *)content.literal->c_str();
762     case POINTER:
763         return (void *)content.pointer;
764     case OBJECT:
765         return (void *)content.instance;
766     default:
767         return (void *)default_value;
768     }
769
770     return (void *)default_value;
771 }
772
773 long Directory::toInteger(const long default_value) const
774 {
775     bool minus = false;
776     long work;
777     const char * str;
778
779     if(this == 0)
780         return default_value;
781
782     switch(type)
783     {
784     case INTEGER:
785         return content.value;
786
787     case POINTER:
788         return (long)content.pointer;
789
790     case LITERAL:
791     case CONSTLITERAL:
792         if(type == CONSTLITERAL)
793             str = content.const_literal;
794         else
795             str = content.literal->c_str();
796
797         if(*str == '-')
798         {
799             minus = true;
800             str ++;
801         }
802
803         if(*str == '0')
804         {
805             str ++;
806             if(*str == 'x' || *str == 'X')
807             {
808                 if(sscanf(str+1, "%ux", (int *)&work) == 0)
809                     return default_value;
810             }else
811                 if(*str != '\x0')
812                 {
813                     if(sscanf(str, "%o", (int *)&work) == 0)
814                         return default_value;
815                 }else
816                     return 0;
817         }else
818             if(sscanf(str, "%d", (int *)&work) == 0)
819                 return default_value;
820
821         if(minus)
822             work = -work;
823         return work;
824     default:
825         return default_value;
826     }
827
828     return default_value;
829 }
830
831 static string::size_type find_corresponding_parenthesis(const string & target, string::size_type pos = 0, char left = '(', char right = ')')
832 {
833     int nest;
834
835     nest = 1;
836     do {
837         if(target[pos] == left)
838         {
839             ++ nest;
840         }else
841         {
842             if(target[pos] == right)
843             {
844                 -- nest;
845                 if(nest == 0)
846                     return static_cast<int>(pos);
847             }
848         }
849         ++ pos;
850     }while(pos < target.size());
851
852     return string::npos;
853 }
854
855
856 string Directory::format(const string & fmt, int mode)
857 {
858     Directory * node;
859     string work;
860     string key;
861     string default_value;
862     string::size_type top,tail;
863     string::size_type pos;
864     int i;
865
866     default_value.assign("(null)");
867     tail = 0;
868     while((top = fmt.find_first_of('$', tail)) != string::npos)
869     {
870         if(top != tail)
871             work += fmt.substr(tail, top - tail);
872
873         switch(fmt[top+1])
874         {
875         case '$':
876             tail = top+2;
877             work += '$';
878             break;
879
880         case '@':
881             work += (*myself).first;
882             tail = top + 2;
883             break;
884
885         case '(':
886             top += 2;
887             i = find_corresponding_parenthesis(fmt, top);
888             key = fmt.substr(top, i - top);
889
890             if(key.find_first_of('$') != string::npos)
891                 key = format(key,mode);
892
893             pos = key.find_first_of(',');
894             if(pos != string::npos)
895             {
896                 default_value = key.substr(pos+1);
897                 key.erase(pos);
898             }
899
900             node = findNode(false,key);
901             if((mode & PTRPREFIX) != 0 && (node != NULL && node->type == POINTER))
902                 work += "0x";
903             work += node->toString(default_value);
904
905             tail = i+1;
906             break;
907         }
908     }
909
910     work += fmt.substr(tail);
911
912     return work;
913 }
914
915 map<std::string, Directory *>::size_type Directory::size(map<string, Directory *>::size_type defval) const
916 {
917     size_type      i;
918     const_iterator scope;
919
920     if(this == NULL)
921         return defval;
922
923     i = 0;
924     scope = begin();
925     while(scope != end())
926         ++ i, ++ scope;
927
928     return i;
929 }
930