]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/Utils/common/Properties.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / Utils / common / Properties.cpp
1 //####COPYRIGHTBEGIN####
2 //                                                                          
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 //
6 // This program is part of the eCos host tools.
7 //
8 // This program is free software; you can redistribute it and/or modify it 
9 // under the terms of the GNU General Public License as published by the Free 
10 // Software Foundation; either version 2 of the License, or (at your option) 
11 // any later version.
12 // 
13 // This program is distributed in the hope that it will be useful, but WITHOUT 
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
16 // more details.
17 // 
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc., 
20 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 //
22 // ----------------------------------------------------------------------------
23 //                                                                          
24 //####COPYRIGHTEND####
25 // Properties.cpp: implementation of the CProperties class.
26 //
27 //////////////////////////////////////////////////////////////////////
28 #include "Properties.h"
29 #include "eCosTrace.h"
30 //////////////////////////////////////////////////////////////////////
31 // Construction/Destruction
32 //////////////////////////////////////////////////////////////////////
33
34 CProperties::CProperties()
35 {
36 }
37
38 CProperties::~CProperties()
39 {
40 }
41
42 #ifdef _WIN32
43 bool CProperties::LoadFromRegistry(HKEY hTopKey,LPCTSTR szRegKey)
44 {
45   HKEY hKey;
46   LONG l=RegOpenKeyEx (hTopKey, szRegKey, 0L, KEY_QUERY_VALUE, &hKey);
47   bool rc=(ERROR_SUCCESS==l);
48   if(rc){
49     TCHAR szName[256];
50     DWORD dwSizeName=sizeof szName;
51     DWORD dwMaxDatalen;
52     DWORD dwType;
53     if(ERROR_SUCCESS==RegQueryInfoKey(hKey,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&dwMaxDatalen,NULL,NULL)){
54       char *Data=new char[dwMaxDatalen];
55       DWORD dwDatalen=dwMaxDatalen;
56       for(DWORD dwIndex=0;ERROR_SUCCESS==RegEnumValue(hKey, dwIndex, szName, &dwSizeName, NULL, &dwType, (LPBYTE)Data, &dwDatalen);dwIndex++){ 
57         
58         CProperties::CProperty *p=Lookup(szName);
59         if(p){
60           switch(p->Type){
61             case CProperty::Integer:
62               if(REG_DWORD==dwType){
63                 p->SetValue(*(int *)Data);
64               } else {
65                 TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
66                 rc=false;
67               }
68               break;
69             case CProperty::Bool:
70               if(REG_DWORD==dwType){
71                 p->SetValue((bool)0!=*(int *)Data);
72               } else {
73                 TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
74                 rc=false;
75               }
76               break;
77             case CProperty::Char:
78               if(REG_DWORD==dwType){
79                 p->SetValue(*(char *)Data);
80               } else {
81                 TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
82                 rc=false;
83               }
84               break;
85             case CProperty::Short:
86               if(REG_DWORD==dwType){
87                 p->SetValue(*(short *)Data);
88               } else {
89                 TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
90                 rc=false;
91               }
92               break;
93             case CProperty::Float:
94             case CProperty::Double:
95             case CProperty::szString: 
96               if(REG_SZ==dwType){
97                 rc&=p->SetValue((LPCTSTR)Data);
98               } else {
99                 TRACE(_T("Type mismatch - %s: expected REG_SZ, got %d\n"),(LPCTSTR)p->strName,dwType);
100                 rc=false;
101               }
102               break;
103             case CProperty::Void:
104               if(REG_BINARY==dwType){
105                 memcpy(p->pData,Data,MIN(dwDatalen,p->nLength));
106               } else {
107                 TRACE(_T("Type mismatch - %s: expected REG_BINARY, got %d\n"),(LPCTSTR)p->strName,dwType);
108                 rc=false;
109               }
110               break;
111           }
112         } else {
113           TRACE(_T("CProperties::LoadFromRegistry - unrecognized value %s in key %s\n"),szName,szRegKey);
114           rc=false;
115         }
116         dwSizeName=sizeof szName;
117         dwDatalen=dwMaxDatalen;
118       }
119       delete [] Data;
120       dwSizeName=sizeof szName;
121     }
122     RegCloseKey(hKey);
123   } else {
124     TRACE(_T("Failed to open %s\n"),szRegKey);
125   }
126   
127   return rc;
128 }
129
130 bool CProperties::SaveToRegistry(HKEY hTopKey,LPCTSTR szRegKey) const
131 {
132   HKEY hKey;
133   CreateKey(szRegKey);
134   bool rc=(ERROR_SUCCESS==RegOpenKeyEx (hTopKey, szRegKey, 0L, KEY_SET_VALUE, &hKey));
135   if(rc){
136     for(int i=ar.size()-1;i>=0;--i){
137       // Initializations are simply to avoid compiler warnings.
138       DWORD dwDatalen=0; 
139       DWORD dwType=REG_DWORD;
140       BYTE *Data=0;
141       // strValue and dw *must* be in scope for RegSetValueEx below.
142       DWORD dw;
143       String strValue;
144       const CProperty &p=ar[i];
145       switch(p.Type){
146         case CProperties::CProperty::Integer:
147         case CProperties::CProperty::Bool:
148         case CProperties::CProperty::Char:
149         case CProperties::CProperty::Short:
150           dwType=REG_DWORD;
151           dwDatalen=sizeof(DWORD);
152           dw=p.GetValue();
153           Data=(BYTE *)&dw;
154           break;
155         case CProperties::CProperty::Float:
156         case CProperties::CProperty::Double:
157         case CProperties::CProperty::szString:
158           strValue=p.GetStringValue();
159           Data=(BYTE *)(LPCTSTR)strValue;
160           dwType=REG_SZ;
161           dwDatalen=(1+strValue.size())*sizeof(_TCHAR);
162           break;
163         case CProperties::CProperty::Void:
164           Data=(BYTE *)p.pData;
165           dwType=REG_BINARY;
166           dwDatalen=p.nLength;
167           break;
168         default:
169           assert(false);
170           break;
171       }
172       rc&=(ERROR_SUCCESS==RegSetValueEx(hKey,p.strName,0,dwType,Data,dwDatalen));
173     }
174   }   
175   RegCloseKey(hKey);
176   return rc;    
177 }
178
179 // Create all keys down to the one specified
180 bool CProperties::CreateKey(LPCTSTR pszKey,HKEY hKey/*=HKEY_CURRENT_USER*/)
181 {
182   bool rc=true;
183   LPCTSTR pcStart=pszKey;
184   LPCTSTR pcEnd;
185   do {
186     HKEY hKey2;
187     pcEnd=_tcschr(pcStart,_TCHAR('\\'));
188     if(NULL==pcEnd){
189       pcEnd=pcStart+_tcslen(pcStart);
190     }
191     String strKey(pcStart,pcEnd-pcStart);
192     if(ERROR_SUCCESS!=RegCreateKeyEx(hKey,                // handle to an open key
193       strKey,         // address of subkey name
194       0,           // reserved
195       0,           // address of class string
196       REG_OPTION_NON_VOLATILE,          // special options flag
197       KEY_ALL_ACCESS,        // desired security access
198       NULL,
199       // address of key security structure
200       &hKey2,          // address of buffer for opened handle
201       NULL// address of disposition value buffer);
202       )){
203       rc=false;
204       break;
205     }
206     RegCloseKey(hKey);
207     hKey=hKey2;
208     pcStart=pcEnd+1;
209   } while (_TCHAR('\0')!=*pcEnd);
210   RegCloseKey(hKey);
211   return rc;
212 }
213
214 #endif
215
216 bool CProperties::LoadFromCommandString(LPCTSTR psz)
217 {
218   bool rc=true;
219   const TCHAR *cNext;
220   for(LPCTSTR c=_tcschr(psz,_TCHAR('-'));c;c=_tcschr(cNext,_TCHAR('-'))){
221     c++;
222     const TCHAR *pEq=_tcschr(c,_TCHAR('='));
223     if(NULL==pEq){
224       TRACE(_T("Failed to find '=' after %s\n"),c);
225       rc=false;
226       break;
227     }
228     String strName(c,pEq-c);
229     CProperties::CProperty *p=Lookup(strName);
230     c=pEq+1;
231     String str;
232     if(_TCHAR('"')==*c){
233       // Value is a quoted string
234       for(cNext=c+1;_TCHAR('"')!=*cNext;cNext++){
235         if(_TCHAR('\\')==*cNext){
236           cNext++;
237         }
238         str+=*cNext;
239       }
240     } else {
241       // Value is simply terminated by whitespace
242       for(cNext=c;_TCHAR('\0')!=*cNext && !_istspace(*cNext);cNext++);
243       str=String(c,cNext-c);
244     }
245     if(p){
246       rc&=p->SetValue(str);
247     } else {
248       TRACE(_T("Properties: unrecognized attribute %s in command string\n"),(LPCTSTR)strName);
249       rc=false;
250     }
251     c=cNext;
252   }
253   return rc;
254 }
255
256 CProperties::CProperty * CProperties::Lookup(LPCTSTR pszName)
257 {
258   for(int i=ar.size()-1;i>=0;--i){
259     CProperties::CProperty &p=ar[i];
260     if(0==_tcsicmp(p.strName,pszName)){
261       return &p;
262     }
263   }
264   return NULL;
265 }
266
267 String CProperties::MakeCommandString() const
268 {
269   String strResult;
270   bool bFirst=true;
271   for(int i=ar.size()-1;i>=0;--i){
272     String str;    
273     const CProperty &p=ar[i];
274     switch(p.Type){
275       case CProperties::CProperty::Integer:
276       case CProperties::CProperty::Bool:
277       case CProperties::CProperty::Char:
278       case CProperties::CProperty::Short:
279         str.Format(_T("-%s=%u"),(LPCTSTR)p.strName,p.GetValue());
280         break;
281       case CProperties::CProperty::szString:
282         {
283           // Quote the string, escaping existing quotes as necessary
284           str.Format(_T("-%s=\""),(LPCTSTR)p.strName);
285           for(LPCTSTR c=p.GetStringValue();*c;c++){
286             if(_TCHAR('"')==*c){
287               str+=_TCHAR('\\');
288             }
289             str+=*c;
290           }
291           str+=_TCHAR('"');
292         }
293         break;
294       case CProperties::CProperty::Float:
295       case CProperties::CProperty::Double:
296       case CProperties::CProperty::Void:
297         str.Format(_T("-%s=%s"),(LPCTSTR)p.GetStringValue());
298         break;
299     }
300     if(!bFirst){
301       strResult+=_TCHAR(' ');
302     }
303     bFirst=false;
304     strResult+=str;
305   }
306   return strResult;
307 }       
308
309 bool CProperties::CreatePathToFile(LPCTSTR pszDir) 
310 {
311   // Create intermediate directories
312 #ifdef _WIN32
313   const TCHAR cSep='\\';
314 #else // UNIX
315   const TCHAR cSep='/';
316 #endif
317   for(LPCTSTR c=_tcschr(pszDir,cSep);c;c=_tcschr(c+1,cSep)){
318 #ifdef _WIN32
319     if(c==pszDir+2 && _istalpha(pszDir[0]) && _TCHAR(':')==pszDir[1]){
320       continue; // don't attempt to create "C:"
321     }
322 #endif
323     String strDir(pszDir,c-pszDir);
324     struct _stat buf;
325     if(!(0==_tstat(strDir,&buf) && (S_IFDIR&buf.st_mode))){
326       // Need to create directory
327       bool b=(0==_tmkdir(strDir));
328       TRACE(_T("Create directory %s rc=%d\n"),(LPCTSTR)strDir,b);
329       if(!b){
330         return false;
331       }
332     }
333   }
334   return true;
335 }
336
337 bool CProperties::SaveToFile(LPCTSTR pszFileName) const
338 {
339   CreatePathToFile(pszFileName);
340   FILE *f=_tfopen(pszFileName,_T("w") MODE_TEXT);
341   if(f){
342     for(int i=ar.size()-1;i>=0;--i){
343       const CProperty &p=ar[i];
344       String str(p.strName);
345       str+=_TCHAR('=');
346       switch(p.Type){
347         case CProperties::CProperty::Integer:
348         case CProperties::CProperty::Bool:
349         case CProperties::CProperty::Char:
350         case CProperties::CProperty::Short:
351           str+=String::SFormat(_T("%u"),p.GetValue());
352           break;
353         case CProperties::CProperty::Float:
354         case CProperties::CProperty::Double:
355         case CProperties::CProperty::szString:
356         case CProperties::CProperty::Void:
357           str+=p.GetStringValue();
358           break;
359       }
360       str+=_TCHAR('\n');
361       _fputts(str,f);
362     }
363     fclose(f);
364   }
365   return (0!=f);
366 }
367
368 bool CProperties::LoadFromFile(LPCTSTR pszFileName)
369 {
370   FILE *f=_tfopen(pszFileName,_T("r") MODE_TEXT);
371   bool rc=(0!=f);
372   if(rc){
373     TCHAR buf[4096];
374     int nLine=0;
375     String str;
376     while(_fgetts(buf,sizeof(buf)-1,f)){
377       
378       nLine++;
379       int nLen=_tcslen(buf);
380       if(nLen>0){
381         // Remove trailing '\n'
382         if(_TCHAR('\n')==buf[nLen-1]){
383           buf[--nLen]=_TCHAR('\0');
384         }
385         // Remove trailing '\r'
386         if(_TCHAR('\r')==buf[nLen-1]){
387           buf[--nLen]=_TCHAR('\0');
388         }
389         
390         // Check for continuation lines
391         if(_TCHAR('\\')==buf[nLen-1]){
392           buf[--nLen]=_TCHAR('\0');
393           str+=buf;
394         } else {
395           str+=buf;
396           LPCTSTR c=(LPCTSTR)str;
397           const TCHAR *pEq=_tcschr(c,_TCHAR('='));
398           if(pEq){
399             const String strName(c,pEq-c);
400             CProperties::CProperty *p=Lookup(strName);
401             if(p){
402               pEq++;
403               rc&=p->SetValue(pEq);
404             } else {
405               ERROR(_T("Unknown attribute %s found in %s line %d\n"),(LPCTSTR)strName,pszFileName,nLine);
406               rc=false;
407             }
408           }
409           str=_T("");
410         }
411       }
412     }
413     fclose(f);
414   }
415   return rc;
416 }
417
418 CProperties::CProperty::CProperty(LPCTSTR pszName,Typetype type,void *_pData):
419   strName(pszName),
420   Type(type),
421   pData(_pData)
422 {
423 }
424
425 CProperties::CProperty::~CProperty()
426 {
427 }
428
429 void CProperties::Add(LPCTSTR pszName,int &n) 
430 {
431   CProperty p(pszName,CProperty::Integer,&n);
432   ar.push_back(p);
433 }
434
435 void CProperties::Add(LPCTSTR pszName,unsigned int &n)
436 {
437   CProperty p(pszName,CProperty::Integer,&n);
438   ar.push_back(p);
439 }
440
441 void CProperties::Add(LPCTSTR pszName,bool &b)
442 {
443   CProperty p(pszName,CProperty::Bool,&b);
444   ar.push_back(p);
445 }
446
447 void CProperties::Add(LPCTSTR pszName,char &c)
448 {
449   CProperty p(pszName,CProperty::Char,&c);
450   ar.push_back(p);
451 }
452
453 void CProperties::Add(LPCTSTR pszName,unsigned char &c)
454 {
455   CProperty p(pszName,CProperty::Char,&c);
456   ar.push_back(p);
457 }
458
459 void CProperties::Add(LPCTSTR pszName,short &s)
460 {
461   CProperty p(pszName,CProperty::Short,&s);
462   ar.push_back(p);
463 }
464
465 void CProperties::Add(LPCTSTR pszName,unsigned short &s)
466 {
467   CProperty p(pszName,CProperty::Short,&s);
468   ar.push_back(p);
469 }
470
471 void CProperties::Add(LPCTSTR pszName,float &f)
472 {
473   CProperty p(pszName,CProperty::Float,&f);
474   ar.push_back(p);
475 }
476
477 void CProperties::Add(LPCTSTR pszName,double &f) 
478 {
479   CProperty p(pszName,CProperty::Double,&f);
480   ar.push_back(p);
481 }
482
483 void CProperties::Add(LPCTSTR pszName,void *pv,unsigned int _nLength)
484 {
485   CProperty p(pszName,CProperty::Void,pv);
486   p.nLength=_nLength;
487   ar.push_back(p);
488 }
489
490 void CProperties::Add(LPCTSTR pszName,String &s)
491 {
492   CProperty p(pszName,CProperty::szString,(void *)&s);
493   ar.push_back(p);
494 }
495
496 unsigned long CProperties::CProperty::GetValue() const
497 {
498   unsigned long dw;
499   switch(Type){
500     case Integer:
501       dw=*(int *)pData;
502       break;
503     case Bool:
504       dw=*(bool *)pData;
505       break;
506     case Char:
507       dw=*(char *)pData;
508       break;
509     case Short:
510       dw=*(short *)pData;
511       break;
512     default:
513       dw=0;
514       assert(false);
515   }
516   return dw;
517 }
518
519 const String CProperties::CProperty::GetStringValue() const 
520 {
521   String str;
522   switch(Type){
523     case szString:
524       str=*(String *)pData; 
525       break;
526     case CProperties::CProperty::Integer:
527     case CProperties::CProperty::Bool:
528     case CProperties::CProperty::Char:
529     case CProperties::CProperty::Short:
530       str.Format(_T("%u"),GetValue());
531       break;
532     case CProperties::CProperty::Float:
533       str.Format(_T("%e"),*(float *)(pData));
534       break;
535     case CProperties::CProperty::Double:
536       str.Format(_T("%e"),*(double *)(pData));
537       break;
538     case CProperties::CProperty::Void:
539       {
540         unsigned char *c=(unsigned char *)pData;
541         for(unsigned int i=0;i<nLength;i++){
542           TCHAR buf[3];
543           _tprintf(buf,_T("%02x"),c[i]);
544           str+=buf;
545         }
546       }
547       break;
548     default:
549       break;
550   }
551   return str;
552 }
553
554 bool CProperties::CProperty::SetValue(int n)
555 {
556   bool rc=true;
557   switch(Type){
558     case Integer:
559       *(int *)(pData)=n;
560       break;
561     case Bool:
562       *(bool *)(pData)=(0!=n);
563       break;
564     case Char:
565       *(char *)(pData)=(char)n; //FIXME: range checks
566       break;
567     case Short:
568       *(short *)(pData)=(short)n;//FIXME: range checks
569       break;
570     default:
571       TRACE(_T("Failed to set '%s' to integer value '%d'\n"),(LPCTSTR)strName,n);
572       break;
573   }
574   return rc;
575 }
576
577 bool CProperties::CProperty::SetValue(double n)
578 {
579   bool rc=true;
580   switch(Type){
581     case Double:
582       *(float *)(pData)=(float)n;//FIXME: range checks?
583       break;
584     case Float:
585       *(double *)(pData)=n;
586       break;
587     default:
588       TRACE(_T("Failed to set '%s' to double value '%f'\n"),(LPCTSTR)strName,n);
589       rc=false;
590       break;
591   }
592   
593   return rc;
594 }
595
596 bool CProperties::CProperty::SetValue(LPCTSTR psz)
597 {
598   bool rc=false;
599   TCHAR *pEnd;
600   double d=0.0;
601   long l=0;
602   switch(Type){
603     case szString:
604       *(String *)pData=psz;
605       rc=true;
606       break;
607     case Float:
608       d=_tcstod(psz,&pEnd);
609       rc=(_TCHAR('\0')==*pEnd);
610       if(rc){
611         SetValue((float)d);
612       }
613       break;
614     case Double:
615       d=_tcstod(psz,&pEnd);
616       rc=(_TCHAR('\0')==*pEnd);
617       if(rc){
618         SetValue(d);
619       }
620       break;
621     case Integer:
622     case Bool:
623     case Char:
624     case Short:
625       l=_tcstol(psz,&pEnd,10);
626       rc=(_TCHAR('\0')==*pEnd);
627       if(rc){
628         SetValue((int)l);
629       }
630       break;
631     default:
632       TRACE(_T("Failed to set '%s' to string value '%s'\n"),(LPCTSTR)strName,psz);
633       break;
634   }
635   return rc;
636 }
637