1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <precomp.h>
29 #include <cosv/commandline.hxx>
30 
31 // NOT FULLY DECLARED SERVICES
32 #include <cosv/file.hxx>
33 
34 
35 namespace csv
36 {
37 
38 namespace
39 {
40 
41 const intt C_nNoOption = -1;
42 
43 const char * sIncludeOptionShort = "-A:";
44 const char * sIncludeOptionLong  = "--Arguments:";
45 const uintt nIncludeOptionShort_Length = strlen(sIncludeOptionShort);
46 const uintt nIncludeOptionLong_Length = strlen(sIncludeOptionLong);
47 
48 
49 /** Analyses, if an option is the one to include a file with
50     further command line arguments.
51 */
52 bool                IsIncludeOption(
53                         const String &      i_option );
54 
55 /** Gets the file name from an include-arguments-option.
56 */
57 String              IncludeFile_fromIncludeOption(
58                         const String &      i_option );
59 
60 
61 bool
62 IsIncludeOption(const String & i_option)
63 {
64     return strncmp(i_option, sIncludeOptionShort, nIncludeOptionShort_Length) == 0
65            OR
66            strncmp(i_option, sIncludeOptionLong, nIncludeOptionLong_Length) == 0;
67 }
68 
69 String
70 IncludeFile_fromIncludeOption(const String & i_option)
71 {
72     if ( strncmp(i_option, sIncludeOptionShort, nIncludeOptionShort_Length)
73          == 0 )
74     {
75         return String(i_option, nIncludeOptionShort_Length, str::maxsize);
76     }
77     else
78     if ( strncmp(i_option, sIncludeOptionLong, nIncludeOptionLong_Length)
79          == 0 )
80     {
81         return String(i_option, nIncludeOptionLong_Length, str::maxsize);
82     }
83     return String::Null_();
84 }
85 
86 
87 }   // end anonymous namespace
88 
89 
90 
91 
92 /** Local helper class for searching a possible option name in a vector of
93     ->OptionDescription.
94 */
95 struct CommandLine::
96 FindOptionByText
97 {
98     bool                operator()(
99                             const CommandLine::OptionDescription &
100                                                 i_option )
101                         { return i_option.sText == sOption; }
102 
103     /// @param i_searchText [i_searchText != ""]
104                         FindOptionByText(
105                             const String &      i_option )
106                         :   sOption(i_option)   { }
107   private:
108     const String        sOption;
109 };
110 
111 
112 typedef std::vector<StringVector::const_iterator>   StringCIteratorList;
113 typedef std::vector<intt>                           OptionIdList;
114 
115 bool
116 CommandLine::Interpret( int    argc,
117                         char * argv[] )
118 {
119     Get_Arguments(argc,argv);
120     csv_assert(aOptionPoints.size() == aOptionIds.size());
121 
122     StringVector::const_iterator
123         itNext          = aCommandLine.begin();
124         ++itNext;       // Move 1 forward from program name.
125     StringVector::const_iterator
126         itEnd           = aCommandLine.end();
127     StringCIteratorList::const_iterator
128         itOptPtsEnd     = aOptionPoints.end();
129 
130     OptionIdList::const_iterator
131         itOptIds = aOptionIds.begin();
132     for ( StringCIteratorList::const_iterator itOptPts = aOptionPoints.begin();
133           itOptPts != itOptPtsEnd AND bIsOk;
134           ++itOptPts, ++itOptIds )
135     {
136         // May be, there are arguments which do not belong to the last option:
137         // itNext != *is
138         Handle_FreeArguments(itNext, *itOptPts);
139 
140         itNext = do_HandleOption( *itOptIds,
141                                   *itOptPts + 1,
142                                   itOptPts+1 == itOptPtsEnd ? itEnd : *(itOptPts+1) );
143         csv_assert(itNext <= itEnd);
144     }   // end for (is)
145     Handle_FreeArguments(itNext, itEnd);
146 
147     return bIsOk;
148 }
149 
150 CommandLine::CommandLine()
151     :   aOptions(),
152         aCommandLine(),
153         bIsOk(false)
154 {
155 }
156 
157 void
158 CommandLine::Add_Option( intt                i_id,
159                          String              i_text )
160 {
161     aOptions.push_back(OptionDescription( i_id,
162                                           i_text ));
163 }
164 
165 void
166 CommandLine::Get_Arguments( int    argc,
167                             char * argv[] )
168 {
169     aCommandLine.erase(aCommandLine.begin(),aCommandLine.end());
170     aCommandLine.reserve(argc);
171 
172     char ** pArgEnd = argv + argc;
173     for ( char ** pArg = &argv[0];
174           pArg != pArgEnd;
175           ++pArg )
176     {
177         Store_Argument(*pArg);
178     }   // end for
179     Find_OptionPoints();
180     bIsOk = true;
181 }
182 
183 intt
184 CommandLine::Find_Option( const String & i_text ) const
185 {
186     if (i_text.empty())
187         return C_nNoOption;
188 
189     FindOptionByText aSearch(i_text);
190     OptionList::const_iterator
191         itFound = std::find_if( aOptions.begin(),
192                                 aOptions.end(),
193                                 aSearch );
194     if (itFound != aOptions.end())
195     {
196         return (*itFound).nId;
197     }
198     return C_nNoOption;
199 }
200 
201 bool
202 CommandLine::Store_Argument( const String & i_arg )
203 {
204     if ( NOT IsIncludeOption(i_arg) )
205     {
206         aCommandLine.push_back(i_arg);
207         return true;
208     }
209 
210     return Try2Include_Options(i_arg);
211 }
212 
213 void
214 CommandLine::Find_OptionPoints()
215 {
216     StringVector::const_iterator    itEnd   = aCommandLine.end();
217     for ( StringVector::const_iterator it = aCommandLine.begin() + 1;
218           it != itEnd;
219           ++it )
220     {
221         intt    nOption = Find_Option(*it);
222         if (nOption != C_nNoOption)
223         {
224             aOptionPoints.push_back(it);
225             aOptionIds.push_back(nOption);
226         }
227     }   // end for (i)
228 }
229 
230 void
231 CommandLine::Handle_FreeArguments( StringVector::const_iterator i_begin,
232                                    StringVector::const_iterator i_end )
233 {
234     for ( StringVector::const_iterator it = i_begin;
235           it != i_end AND bIsOk;
236           ++it )
237     {
238         do_HandleFreeArgument(*it);
239     }
240 }
241 
242 bool
243 CommandLine::Try2Include_Options(const String & i_includeOption)
244 {
245     static StringVector
246         aIncludedOptionFiles_;
247 
248     const String
249         aOptionFile(IncludeFile_fromIncludeOption(i_includeOption));
250 
251     // Avoid recursion deadlock 1
252     if ( std::find( aIncludedOptionFiles_.begin(),
253                     aIncludedOptionFiles_.end(),
254                     aOptionFile )
255          != aIncludedOptionFiles_.end() )
256     {
257         Cerr() << "\nError: Self inclusion of option file "
258                << aOptionFile
259                << ".\n"
260                << Endl();
261         return false;
262     }
263 
264     // Avoid recursion deadlock 2
265     aIncludedOptionFiles_.push_back(aOptionFile);
266 
267     bool ok = Include_Options(aOptionFile);
268 
269     // Avoid recursion deadlock 3
270     aIncludedOptionFiles_.pop_back();
271 
272     return ok;
273 }
274 
275 bool
276 CommandLine::Include_Options( const String & i_optionsFile )
277 {
278     StreamStr
279         aIncludedText(500);
280     bool ok = Load_Options(aIncludedText, i_optionsFile);
281     if (NOT ok)
282         return false;
283 
284     StringVector
285         aIncludedOptions;
286     Split(aIncludedOptions, aIncludedText.c_str());
287 
288     StringVector::const_iterator itEnd = aIncludedOptions.end();
289     for ( StringVector::const_iterator it = aIncludedOptions.begin();
290           it != itEnd;
291           ++it )
292     {
293         Store_Argument(*it);
294     }   // end for
295 
296     return true;
297 }
298 
299 bool
300 CommandLine::Load_Options( StreamStr &      o_text,
301                            const String &   i_optionsFile )
302 {
303     if (i_optionsFile.empty())
304         return false;
305 
306     File
307         aOptionsFile(i_optionsFile, CFM_READ);
308     OpenCloseGuard
309         aOFGuard(aOptionsFile);
310     if (NOT aOFGuard)
311     {
312         Cerr() << "\nError: Options file "
313                << i_optionsFile
314                << " not found.\n"
315                << Endl();
316         return false;
317     }
318 
319     StreamStr
320         aLoad(aOptionsFile);
321     o_text.swap(aLoad);
322     return true;
323 }
324 
325 
326 
327 
328 /******************         OptionDescription       ***********************/
329 
330 
331 CommandLine::
332 OptionDescription::OptionDescription( intt          i_id,
333                                       String        i_text )
334     :   nId(i_id),
335         sText(i_text)
336 {
337 }
338 
339 
340 
341 
342 }   // namespace csv
343