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