1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: getopt.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_testshl2.hxx"
33 #include "testshl/getopt.hxx"
35 #include "testshl/filehelper.hxx"
38 //----------------------------------------------------------------------------
40 //----------------------------------------------------------------------------
42 void OptDsc::createOptDsc( const rtl::OString
& opt
) {
44 // analyze type of option
45 // in case of flag indicate and set name and hint
46 if ( ( opt
.indexOf("=") == -1 ) && ( opt
.indexOf(":") == -1 ) ) {
49 // extract options dokumentation if any
50 sal_Int32 index
= opt
.indexOf(",");
55 m_name
= opt
.copy( 0, index
);
56 m_hint
= ( opt
.copy( index
+ 1 ) ).trim();
61 vector
< rtl::OString
> optLine
;
63 // ':' indicates that option has optional parameter(s)
64 if ( opt
.indexOf(":") != -1 ) {
65 m_type
|= OT_OPTIONAL
;
66 // create optionline tokenvector
67 split( opt
, ":,", optLine
);
70 // create optionline tokenvector
71 split( opt
, "=,", optLine
);
74 // extract name of option
77 // parameter(s) of string type
78 if ( optLine
[1].indexOf("s") != -1 ) {
82 // parameter(s) of numeric type
83 if ( optLine
[1].indexOf("n") != -1 ) {
87 // multiple parameters allowed
88 if ( optLine
[1].indexOf("@") != -1 ) {
90 m_legend
+= "#1,[arg#n]";
96 // extract options dokumentation if any
97 m_hint
= optLine
[optLine
.size()-1].trim();
102 void OptDsc::split( const rtl::OString
& opt
, const rtl::OString
& cSet
,
103 vector
< rtl::OString
>& optLine
) {
105 const sal_Int32 cSetLen
= cSet
.getLength();
106 const sal_Char
* pcSet
= cSet
.getStr();
108 sal_Int32 oldIndex
= 0;
111 for ( i
= 0; i
< cSetLen
; i
++ ) {
112 index
= opt
.indexOf( pcSet
[i
] );
114 optLine
.push_back( opt
.copy( oldIndex
, index
- oldIndex
) );
115 oldIndex
= index
+ 1;
118 optLine
.push_back( opt
.copy( oldIndex
) );
121 //----------------------------------------------------------------------------
123 //----------------------------------------------------------------------------
126 vector
< OptDsc
* >::iterator iter
= m_optionset
.begin();
127 while ( iter
!= m_optionset
.end() ) {
137 * initialization of GetOpt class means to fill the vector members
138 * representing the commandline and optionset
139 * @param char* cmdLine[] = comandline
140 * @param char* optSet[] = optionset
145 void GetOpt::initialize( char* cmdLine
[], char const * optSet
[] ) {
148 m_cmdline
.push_back( rtl::OString( *cmdLine
) );
151 // insert an empty OString, to mark the end.
152 m_cmdline
.push_back(rtl::OString());
154 while ( *optSet
&& ( rtl::OString( optSet
[0] ).indexOf("-") == 0 ) ) {
155 m_optionset
.push_back( new OptDsc( *optSet
) );
163 * returns a pointer to an object of type optiondescription (OptDsc)
165 * @param rtl::OString& opt = name of option
167 * @return OptDsc* = pointer to requested optiondescription
168 * or NULL if not found
171 OptDsc
* GetOpt::getOptDsc( rtl::OString
& opt
) {
173 vector
< OptDsc
* >::iterator iter
= m_optionset
.begin();
174 while ( iter
!= m_optionset
.end() ) {
175 if ( (*iter
)->getName() == opt
) {
186 * check if option is already present in optionhash
187 * @param const rtl::OString& opt = name of option
191 sal_Bool
GetOpt::hasOpt( const rtl::OString
& opt
) const {
193 if ( m_opthash
.find( opt
) != m_opthash
.end() ) {
202 * handles the initialized comandline vector
203 * and fill the optionhash with evaluated options
207 //> createCmdLineOptions
208 void GetOpt::createCmdLineOptions() {
210 // get iterator of comandline vector
211 vector
< rtl::OString
>::iterator iter
= m_cmdline
.begin();
213 // extract first comandlineparameter as program name
217 // process the whole vector
218 while ( iter
!= m_cmdline
.end() ) {
219 // extract following comandline parameter(s) as program parameter(s)
220 // int nIdxOfMinus = (*iter).indexOf("-");
221 if ( (*iter
).indexOf("-") != 0 ) /* start without '-' */
223 if ((*iter
).getLength() > 0 ) /* is not empty */
225 m_param
.push_back(*iter
);
231 if ( (*iter
).indexOf("-") == 0 )
233 // ignore invalid options
234 if ( ! evaluateOpt( iter
) )
237 // check if wrong option has got a parameter
238 // and skip that, too
239 if( (iter
+ 1) != m_cmdline
.end() )
241 if ( (*(iter
+ 1)).indexOf("-") != 0 )
248 rtl::OString
opt( (*iter
) );
249 vector
< rtl::OString
> optValues
;
252 if ( ! getOptDsc( opt
)->isFlag() ) {
253 // but has optional parameters
254 if ( getOptDsc( opt
)->isOptional() ) {
255 // no parameters present
256 if ( ! hasParam( iter
) ) {
257 m_opthash
[ opt
] = optValues
;
264 // more than one option parameters occured
265 if ( (*iter
).indexOf( "," ) != -1 ) {
266 tokenize( (*iter
), "," , optValues
);
269 optValues
.push_back( (*iter
) );
272 // create key/value pair in optionhash and clear value vector
273 m_opthash
[ opt
] = optValues
;
278 } ///< createCmdLineOptions
282 * check if option has parameter(s)
283 * @param vector< rtl::OString >::iterator iter = iterator of
289 sal_Bool
GetOpt::hasParam( vector
< rtl::OString
>::iterator iter
) {
290 if ( iter
+1 == m_cmdline
.end() ) {
293 if ( (*(iter
+1)).indexOf("-") == 0 ) {
296 if ( (*(iter
+1)) == "" ) {
305 * option evaluation in general means to verify if the option occur is
306 * a member of optionset say an admitted option, if so does it appear with
307 * the right or tolerable usage
309 * @param vector< rtl::OString >::iterator iter = iterator of
315 sal_Bool
GetOpt::evaluateOpt( vector
< rtl::OString
>::iterator iter
) {
317 // option is no member of optionset
318 if ( ! exist( (*iter
) ) ) {
319 cout
<< "Unknown option " << (*iter
).getStr()
320 << " occurred !" << endl
;
325 if ( getOptDsc( (*iter
) )->isFlag() ) {
329 // parameter not optional
330 if ( ! getOptDsc( (*iter
) )->isOptional() ) {
332 // verify that next vectoritem is present and no option
333 if ( ( *( iter
+ 1 ) ).getLength() &&
334 ( ( *( iter
+ 1 ) ).indexOf( "-" ) != 0 ) ) {
336 // if we are waiting for one single parameter
337 if ( getOptDsc( *iter
)->isSingle() ) {
338 // but find multiple parameters
339 if( ( *( iter
+ 1 ) ).indexOf(",") != -1 ) {
340 cout
<< "Wrong use of option " << (*iter
).getStr()
341 << " too many parameters !" << endl
;
349 cout
<< "Wrong use of option " << (*iter
).getStr()
350 << " parameter missing !" << endl
;
353 // parameter optional
354 if ( getOptDsc( *iter
)->isSingle() ) {
356 if ( hasParam( iter
) ) {
357 if( ( *( iter
+ 1 ) ).indexOf(",") != -1 ) {
358 cout
<< "Wrong use of option " << (*iter
).getStr()
359 << " too many parameters !" << endl
;
370 void GetOpt::createOpt( rtl::OString
& optDscStr
) {
371 m_optionset
.push_back( new OptDsc( optDscStr
) );
376 * conditional addition of an option to optionhash
377 * overriding options, already present in optionhash, is not permitted
379 * @param rtl::OString& optStr = optionstring which is to break in a
380 * key/value pair and to add to optionhash
385 void GetOpt::addOpt( rtl::OString
& optStr
, sal_Bool eval
) {
387 vector
< rtl::OString
> optTok
;
388 tokenize( optStr
, "=", optTok
);
390 // prevent override of commandline options
391 // by options from ini file
392 if( hasOpt( optTok
[0] ) ) {
396 // evaluate rigth usage of option
398 if ( ! evaluateOpt( optTok
.begin() ) ) {
402 vector
< rtl::OString
> optValues
;
404 if ( optTok
.size() > 1 ) {
405 rtl::OString
oValStr( optTok
[1] );
407 if ( oValStr
.indexOf(",") == -1 ) {
408 optValues
.push_back( oValStr
);
411 tokenize( oValStr
, ",", optValues
);
414 m_opthash
[ optTok
[0] ] = optValues
;
421 * verify the existance of an option in optionset
422 * @param rtl::OString& opt = option name
426 sal_Bool
GetOpt::exist( rtl::OString
& opt
) {
427 if ( getOptDsc( opt
) ) {
435 * verify the existance of variables inside options
440 sal_Bool
GetOpt::hasVars() {
441 if ( m_varvec
.size() ) {
450 * proceeds a buffer representing the content of an ini file and adds the
451 * options to optionhash. The optionstrings in the file are allowed to contain
452 * variables indicated by delimiters described with varDelim
454 * @param rtl::OString iOpts = raw filecontent
455 * @param const rtl::OString& varDelim = delimiter indicating a variable
460 void GetOpt::str2Opt( rtl::OString iOpts
) {
462 // tokenize filecontent by '\n' to create a vector of lines
463 vector
< rtl::OString
> iniLines
;
464 tokenize( iOpts
, "\n", iniLines
);
466 sal_uInt32 tCnt
= iniLines
.size();
470 for ( i
= 1; i
< tCnt
; i
++ ) {
471 rtl::OString
optLine( iniLines
[i
] );
473 if ( ! ( optLine
.indexOf("#") == 0 ) ) {
474 // filter valid options after trim
475 if ( ( optLine
.indexOf("-") == 0 ) ) {
476 // line contains a variable
477 if ( ( optLine
.indexOf( m_vardelim
) != -1 ) ) {
478 // push to var vector for later process
479 m_varvec
.push_back( optLine
);
488 void GetOpt::replVars() {
490 // process vector of lines containing variables
491 vector
< rtl::OString
>::iterator iter
= m_varvec
.begin();
492 while ( iter
!= m_varvec
.end() ) {
494 while ( ( index
= (*iter
).indexOf( m_vardelim
) ) != -1 ) {
495 vector
< rtl::OString
> varLineTok
;
496 rtl::OString
varKey( "-" );
497 tokenize( *iter
, m_vardelim
, varLineTok
);
498 varKey
+= varLineTok
[1];
499 vector
< rtl::OString
> keyValues
= getOptVec( varKey
);
501 if ( keyValues
.size() > 1 ) {
504 vector
< rtl::OString
>::iterator kvi
= keyValues
.begin();
505 while ( kvi
!= keyValues
.end() ) {
508 if ( kvi
!= keyValues
.end() ) {
512 (*iter
) = (*iter
).replaceAt(
513 index
, varKey
.getLength()+1, rplStr
);
516 if( *(keyValues
[0])) {
517 (*iter
) = (*iter
).replaceAt(
518 index
, varKey
.getLength()+1, keyValues
[0] );
530 * displays a formatted usagescreen
535 void GetOpt::showUsage() {
538 frm
.fCol
= getMaxNameLength() + 2;
539 frm
.sCol
= frm
.fCol
+ getMaxLegendLength() + 2 ;
542 vector
< rtl::OString
> nameVec
;
543 vector
< rtl::OString
> paramVec
;
545 tokenize( getName(), "/\\", nameVec
);
546 if ( m_param
.empty() ) {
547 if ( hasOpt( "-db" ) ) {
548 tokenize( getOpt( "-db" ), "/\\", paramVec
);
551 paramVec
.push_back( rtl::OString( "not available" ) );
555 tokenize( getFirstParam(), "/\\", paramVec
);
558 cout
<< "\n\n\n\n\nUsage: prgname param [options]\n\nPRGNAME = [path]";
560 if ( !nameVec
.empty() ) {
561 cout
<< (*(nameVec
.end()-1)).getStr();
563 cout
<< "\nPARAM = [path]";
564 if ( !paramVec
.empty() ) {
565 cout
<< (*(paramVec
.end()-1)).getStr() << endl
;
568 cout
<< "\nOPTIONS = [" << flush
;
570 vector
< OptDsc
* >::iterator iter
= m_optionset
.begin();
572 while ( iter
!= m_optionset
.end() ) {
573 cout
<< (*iter
)->getName().getStr() << "," << flush
;
576 cout
<< "]\n\nOPTIONS:\n" << flush
;
578 iter
= m_optionset
.begin();
580 while ( iter
!= m_optionset
.end() ) {
581 cout
<< optDsc2Str( *iter
, frm
).getStr() << endl
<< flush
;
590 * displays the actual option/parameter status
595 void GetOpt::printStatus( void ) {
597 sal_uInt32 maxlen
= getMaxNameLength();
598 optHashMap::iterator iter
= m_opthash
.begin();
601 while ( iter
!= m_opthash
.end() ) {
602 rtl::OString
option( (*iter
).first
);
604 cout
.setf(ios::left
);
605 cout
.width( maxlen
+1 );
606 cout
<< option
.getStr() << "= ";
608 if ( ! getOptDsc( option
)->isFlag() ) {
609 if ( ! getOptVec( option
).empty() ) {
611 for ( j
= 0; j
< (*iter
).second
.size(); j
++ ) {
612 cout
<< (( (*iter
).second
)[j
]).getStr() << " ";
629 * converts an object of type optiondescription (OptDsc) to a formatted
630 * displayable string for usagescreen needs
631 * @param OptDsc* optDsc = pointer to option description
632 * @param sFormat frm = format structur
634 * @return const rtl::OString = formatted string for display purposes
636 //> optDsc2Str >>> to be replaced by intelliget algorythm <<<
637 const rtl::OString
GetOpt::optDsc2Str( OptDsc
* optDsc
, sFormat frm
) {
639 sal_Char
* buf
= new sal_Char
[ frm
.len
+ 1 ];
640 sal_Char
* pBuf
= buf
;
643 for ( i
= 0; i
< frm
.len
; i
++ ) {
648 rtl::OStringBuffer
strBuf( buf
);
649 rtl::OString oStr
= strBuf
.makeStringAndClear();
651 oStr
= oStr
.replaceAt( 0, optDsc
->getName().getLength(),
653 if ( optDsc
->isOptional() ) {
654 oStr
= oStr
.replaceAt( frm
.fCol
-1, 1, "[" );
656 oStr
= oStr
.replaceAt( frm
.fCol
, optDsc
->getLegend().getLength(),
657 optDsc
->getLegend() );
658 if ( optDsc
->isOptional() ) {
659 oStr
= oStr
.replaceAt( frm
.fCol
+ optDsc
->getLegend().getLength() ,
662 if ( ( frm
.sCol
+ optDsc
->getHint().getLength() ) >= frm
.len
) {
664 oStr
= oStr
.replaceAt( frm
.sCol
, frm
.len
- frm
.sCol
,
668 oStr
= oStr
.replaceAt( frm
.sCol
,
669 optDsc
->getHint().getLength(), optDsc
->getHint() );
680 * returns the maximum length of all optionnames for format purposes
682 * @return sal_uInt32 length of longest optionname
685 sal_uInt32
GetOpt::getMaxNameLength() {
688 vector
< OptDsc
* >::iterator iter
= m_optionset
.begin();
690 while ( iter
!= m_optionset
.end() ) {
691 if( len
< (*iter
)->getName().getLength() ){
692 len
= (*iter
)->getName().getLength();
697 } ///< getMaxNameLength
701 * returns the maximum length of all option legends for format purposes
703 * @return sal_uInt32 length of longest optionlegend
705 //> getMaxLegendLength
706 sal_uInt32
GetOpt::getMaxLegendLength() {
709 vector
< OptDsc
* >::iterator iter
= m_optionset
.begin();
711 while ( iter
!= m_optionset
.end() ) {
712 if( len
< (*iter
)->getLegend().getLength() ){
713 len
= (*iter
)->getLegend().getLength();
719 } ///< getMaxLegendLength
723 * reads the filecontent and pass it to str2opt to add valid options
725 * @param rtl::OString iniPth = full qualified filename
726 * @return ::osl::FileBase::RC = to indicate errors
729 ::osl::FileBase::RC
GetOpt::getIniOptions( rtl::OString iniPth
) {
731 ::osl::FileStatus
fState( FileStatusMask_All
);
732 ::osl::DirectoryItem dItem
;
733 rtl::OUString
nrmPath( FileHelper::convertPath( iniPth
) );
735 ::osl::DirectoryItem::get( nrmPath
, dItem
);
736 dItem
.getFileStatus( fState
);
737 rtl::OUString
fName( fState
.getFileURL() );
738 ::osl::File
iniFile( fName
);
740 const sal_uInt32 filesize
= (sal_uInt32
)fState
.getFileSize();
742 ::osl::FileBase::RC ret
;
743 sal_uInt64 bytesread
;
745 if ( ( ret
= iniFile
.open( OpenFlag_Read
) ) != ::osl::FileBase::E_None
) {
748 char* buf
= new char[ filesize
+ 1 ];
749 ret
= iniFile
.read( buf
, filesize
, bytesread
);
750 buf
[ filesize
] = '\0';
760 * tokenize a string in dependance of a character set and stores the tokens
762 * @param const rtl::OString& opt = optionstring to tokenize
763 * @param const rtl::OString& cSet = characterset of delimiters
764 * @param vector< rtl::OString >& optLine = vector of tokens
765 * @param sal_Bool strip = indicates if CR,LF and TAB should be stripped off
770 void GetOpt::tokenize( const rtl::OString
& opt
, const rtl::OString
& cSet
,
771 vector
< rtl::OString
>& optLine
, sal_Bool strip
) {
773 const sal_Char
* pText
; // pointer f. text,
774 const sal_Char
* pcSet
; // charset and
775 vector
< const sal_Char
* > delimVec
; // vector of delimiters
777 // parametercheck for opt ...
778 if( ! opt
.getLength() ) {
782 if( ! cSet
.getLength() ) {
785 // pointer to begin of textinstance
786 pText
= opt
.getStr();
790 // charset-pointer to begin of charset
791 pcSet
= cSet
.getStr();
795 if( ( ( *pText
== *pcSet
) ) && ( pText
!= opt
) ) {
796 delimVec
.push_back( pText
);
806 delimVec
.push_back( opt
+ opt
.getLength() );
808 sal_Char
* pToken
; // ptr to token chars
809 const sal_Char
* pBegin
; // ptr to begin of current,
810 const sal_Char
* pEnd
=opt
; // and begin of prev. token
813 while ( pEnd
< delimVec
[delimVec
.size()-1] ) {
816 if( pBegin
> opt
.getStr() ) {
821 sal_uInt32 nSize
= pEnd
- pBegin
;
824 // allocate memory for token
825 sal_Char
* cToken
= new sal_Char
[ nSize
+ 1 ];
827 // get address of allocated memory
830 // copy token from text
832 for ( j
= 0; j
< nSize
; ++j
) {
833 *pToken
++ = *pBegin
++;
838 rtl::OString
oTok(cToken
);
841 // strip off CR,LF and TAB
842 oTok
= oTok
.replace( 0x0a, 0x20 );
843 oTok
= oTok
.replace( 0x0d, 0x20 );
844 oTok
= oTok
.replace( 0x09, 0x20 );
849 optLine
.push_back( oTok
);
852 // free memory where cToken points to
859 // -----------------------------------------------------------------------------
860 rtl::OString
& GetOpt::getOpt( const rtl::OString
& opt
)
862 if (m_opthash
.find( opt
) != m_opthash
.end())
864 if (!m_opthash
[opt
].empty())
866 return *( m_opthash
[opt
].begin() );
871 aStr
+= " ): Value not found.";
872 throw ValueNotFoundException(aStr
.getStr());
875 throw ValueNotFoundException(opt
);
879 // -----------------------------------------------------------------------------
881 Exception::Exception()
885 //---------------------------------------------------------------------
886 Exception::Exception(char const* sAsciiMessage
)
887 : m_sAsciiMessage(sAsciiMessage
)
890 //---------------------------------------------------------------------
891 Exception::Exception(rtl::OString
const& sAsciiMessage
)
892 : m_sAsciiMessage(sAsciiMessage
)
895 //---------------------------------------------------------------------
897 rtl::OUString
Exception::message() const
899 return rtl::OStringToOUString( m_sAsciiMessage
, RTL_TEXTENCODING_ASCII_US
);
901 //---------------------------------------------------------------------
902 char const* Exception::what() const
904 return m_sAsciiMessage
.getLength() ? m_sAsciiMessage
.getStr() : "FAILURE in REGSCAN: No description available";
907 // -----------------------------------------------------------------------------
908 static const char c_sValueNotFoundException
[] = "GetOpt: Value not Found Exception: ";
909 //---------------------------------------------------------------------
910 ValueNotFoundException::ValueNotFoundException()
911 : Exception( rtl::OString(RTL_CONSTASCII_STRINGPARAM(c_sValueNotFoundException
)) )
914 //---------------------------------------------------------------------
916 ValueNotFoundException::ValueNotFoundException(char const* sException
)
917 : Exception( rtl::OString(RTL_CONSTASCII_STRINGPARAM(c_sValueNotFoundException
)) + sException
)