summaryrefslogtreecommitdiff
path: root/src/stable/optparser.cpp
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2012-03-25 20:00:08 +0000
committerMike Buland <eichlan@xagasoft.com>2012-03-25 20:00:08 +0000
commit469bbcf0701e1eb8a6670c23145b0da87357e178 (patch)
treeb5b062a16e46a6c5d3410b4e574cd0cc09057211 /src/stable/optparser.cpp
parentee1b79396076edc4e30aefb285fada03bb45e80d (diff)
downloadlibbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.gz
libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.bz2
libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.xz
libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.zip
Code is all reorganized. We're about ready to release. I should write up a
little explenation of the arrangement.
Diffstat (limited to 'src/stable/optparser.cpp')
-rw-r--r--src/stable/optparser.cpp492
1 files changed, 492 insertions, 0 deletions
diff --git a/src/stable/optparser.cpp b/src/stable/optparser.cpp
new file mode 100644
index 0000000..050232c
--- /dev/null
+++ b/src/stable/optparser.cpp
@@ -0,0 +1,492 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/optparser.h"
9#include "bu/sio.h"
10using namespace Bu;
11
12#include <stdlib.h>
13
14Bu::OptParser::OptParser()
15{
16}
17
18Bu::OptParser::~OptParser()
19{
20}
21
22void Bu::OptParser::parse( int argc, char **argv )
23{
24 for( int j = 1; j < argc; j++ )
25 {
26 if( argv[j][0] == '-' )
27 {
28 // Now we're on to something, which kind is it?
29 if( argv[j][1] == '-' )
30 {
31 int iEPos;
32 for( iEPos = 2; argv[j][iEPos] != '\0' &&
33 argv[j][iEPos] != '='; iEPos++ ) { }
34
35 Bu::String sOpt;
36 int iCount = argc-j;
37 Bu::String sExtraParam;
38 if( argv[j][iEPos] == '=' )
39 {
40 sOpt.set( argv[j]+2, iEPos-2 );
41 iCount++;
42 sExtraParam.set( argv[j]+iEPos+1 );
43 }
44 else
45 {
46 sOpt.set( argv[j]+2 );
47 }
48 if( !hlOption.has( sOpt ) )
49 {
50 optionError( "--" + sOpt );
51 }
52 else
53 {
54 // Long param, cool, that's easy, first search for =
55 Option *pOpt = hlOption.get( sOpt );
56 if( pOpt->sUsed )
57 {
58 Bu::StrArray aParams( iCount );
59 aParams.append( sOpt );
60 if( sExtraParam.isSet() )
61 {
62 aParams.append( argv[j]+iEPos+1 );
63 }
64 for( int k = j+1; k < argc; k++ )
65 {
66 aParams.append( argv[k] );
67 }
68 j += pOpt->sUsed( aParams );
69 }
70 else if( pOpt->pProxy )
71 {
72 if( pOpt->sOverride.isSet() )
73 {
74 pOpt->pProxy->setValue( pOpt->sOverride );
75 }
76 else if( sExtraParam.isSet() )
77 {
78 pOpt->pProxy->setValueFromStr( sExtraParam );
79 }
80 else if( argv[j+1] != '\0' )
81 {
82 pOpt->pProxy->setValueFromStr( argv[j+1] );
83 j++;
84 }
85 }
86 }
87 }
88 else
89 {
90 int iCPos;
91 for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ )
92 {
93 if( !hsOption.has( argv[j][iCPos] ) )
94 {
95 Bu::String sOpt("-");
96 sOpt += argv[j][iCPos];
97 optionError( sOpt );
98 }
99 else
100 {
101 Option *pOpt = hsOption.get( argv[j][iCPos] );
102 char buf[2] = {argv[j][iCPos], '\0'};
103 if( pOpt->sUsed )
104 {
105 Bu::StrArray aParams( argc-j+1 );
106 aParams.append( buf );
107 int iMod = 0;
108 if( argv[j][iCPos+1] != '\0' )
109 {
110 aParams.append( argv[j]+iCPos+1 );
111 iMod = -1;
112 }
113 for( int k = j+1; k < argc; k++ )
114 {
115 aParams.append( argv[k] );
116 }
117 int iUsed = pOpt->sUsed( aParams );
118 if( iUsed > 0 )
119 {
120 j += iUsed + iMod;
121 break;
122 }
123 }
124 else if( pOpt->pProxy )
125 {
126 if( pOpt->sOverride.isSet() )
127 {
128 pOpt->pProxy->setValue( pOpt->sOverride );
129 }
130 else if( argv[j][iCPos+1] != '\0' )
131 {
132 pOpt->pProxy->setValueFromStr(
133 argv[j]+iCPos+1
134 );
135 break;
136 }
137 else if( argv[j+1] )
138 {
139 pOpt->pProxy->setValueFromStr(
140 argv[j+1]
141 );
142 j++;
143 break;
144 }
145 }
146 }
147 }
148 }
149 }
150 else
151 {
152 if( !sNonOption )
153 {
154 optionError( argv[j] );
155 }
156 else
157 {
158 int iCount = argc-j;
159 Bu::StrArray aParams( iCount );
160 for( int k = j; k < argc; k++ )
161 {
162 aParams.append( argv[k] );
163 }
164 j += sNonOption( aParams );
165 }
166 }
167 }
168}
169
170void Bu::OptParser::parse( const Bu::String &sLine )
171{
172 Bu::String sCmd = sLine.clone();
173 int iParams = 0;
174 bool bInGap = true;
175 bool bInQuote = false;
176 for( Bu::String::iterator i = sCmd.begin(); i; i++ )
177 {
178 if( bInQuote == false && (*i == ' ' || *i == '\t') )
179 {
180 if( bInGap == false )
181 {
182 bInGap = true;
183 }
184 }
185 else if( *i == '"' )
186 {
187 bInQuote = !bInQuote;
188 }
189 else
190 {
191 if( bInGap )
192 {
193 iParams++;
194 bInGap = false;
195 }
196 }
197 }
198
199 bInQuote = false;
200 bInGap = true;
201 char **asParam = new char*[iParams];
202 iParams = 0;
203 for( char *i = sCmd.getStr(); *i; i++ )
204 {
205 if( bInQuote == false && (*i == ' ' || *i == '\t') )
206 {
207 if( bInGap == false )
208 {
209 bInGap = true;
210 *i = '\0';
211 }
212 }
213 else if( *i == '"' )
214 {
215 bInQuote = !bInQuote;
216 }
217 else
218 {
219 if( bInGap )
220 {
221 asParam[iParams++] = i;
222 bInGap = false;
223 }
224 }
225 }
226
227 parse( iParams, asParam );
228
229 delete[] asParam;
230}
231
232void Bu::OptParser::addOption( const Option &opt )
233{
234 lOption.append( opt );
235 if( opt.cOpt != '\0' )
236 hsOption.insert( opt.cOpt, &lOption.last() );
237 if( opt.sOpt.isSet() )
238 hlOption.insert( opt.sOpt, &lOption.last() );
239}
240
241void Bu::OptParser::setOverride( char cOpt, const Bu::Variant &sOverride )
242{
243 hsOption.get( cOpt )->sOverride = sOverride;
244}
245
246void Bu::OptParser::setOverride( const Bu::String &sOpt, const Bu::Variant &sOverride )
247{
248 hlOption.get( sOpt )->sOverride = sOverride;
249}
250
251void Bu::OptParser::setHelpDefault( const Bu::String &sOpt, const Bu::String &sTxt )
252{
253 hlOption.get( sOpt )->sHelpDefault = sTxt;
254}
255
256void Bu::OptParser::addHelpOption( char c, const Bu::String &s, const Bu::String &sHelp )
257{
258 Option o;
259 o.sUsed = slot( this, &OptParser::optHelp );
260 o.cOpt = c;
261 o.sOpt = s;
262 o.sHelp = sHelp;
263 addOption( o );
264}
265
266void Bu::OptParser::addHelpBanner( const Bu::String &sText, bool bFormatted )
267{
268 Banner b;
269 b.sText = sText;
270 b.bFormatted = bFormatted;
271 if( lOption.getSize() > 0 )
272 {
273 for( b.iAfter = lOption.begin(); b.iAfter+1; b.iAfter++ ) { }
274 }
275 lBanner.append( b );
276}
277
278int Bu::OptParser::optHelp( StrArray /*aParams*/ )
279{
280 bool bHasShort = false;
281 int iMaxWidth = 0;
282 int iScrWidth = 80;
283 char *env = getenv("COLUMNS");
284 if( env )
285 iScrWidth = strtol( env, NULL, 10 );
286 for( OptionList::iterator i = lOption.begin(); i; i++ )
287 {
288 if( (*i).cOpt != '\0' )
289 bHasShort = true;
290 int lOptSize = (*i).sOpt.getSize() + (*i).sHelpDefault.getSize();
291 if( (*i).sOpt.isSet() && iMaxWidth < lOptSize )
292 iMaxWidth = lOptSize;
293 }
294 int iIndent = 4;
295 if( bHasShort )
296 iIndent += 4;
297 if( iMaxWidth > 0 )
298 iIndent += 4 + iMaxWidth;
299
300 BannerList::iterator iBanner;
301 for( iBanner = lBanner.begin(); iBanner; iBanner++ )
302 {
303 if( (*iBanner).iAfter )
304 break;
305
306 if( (*iBanner).bFormatted )
307 sio << format( (*iBanner).sText, iScrWidth-1, 0 );
308 else
309 sio << (*iBanner).sText;
310 sio << sio.nl;
311 }
312 for( OptionList::iterator i = lOption.begin(); i; i++ )
313 {
314 sio << " ";
315 if( bHasShort )
316 {
317 if( (*i).cOpt == '\0' )
318 sio << " ";
319 else
320 sio << "-" << (*i).cOpt;
321 sio << " ";
322 }
323 if( iMaxWidth > 0 )
324 {
325 if( (*i).sOpt.isSet() )
326 {
327 sio << "--" << Fmt(iMaxWidth, Fmt::Left)
328 << (*i).sOpt + (*i).sHelpDefault;
329 }
330 else
331 {
332 sio << " " << Fmt(iMaxWidth) << "";
333 }
334 sio << " ";
335 }
336 sio << format( (*i).sHelp, iScrWidth-iIndent-1, iIndent );
337 sio << sio.nl;
338
339 for( ; iBanner; iBanner++ )
340 {
341 if( (*iBanner).iAfter != i )
342 break;
343
344 if( (*iBanner).bFormatted )
345 sio << format( (*iBanner).sText, iScrWidth-1, 0 );
346 else
347 sio << (*iBanner).sText;
348 sio << sio.nl;
349 }
350 }
351 exit( 0 );
352 return 0;
353}
354
355void Bu::OptParser::optionError( const Bu::String &sOption )
356{
357 sio << "Unregcognized option discovered: " << sOption << sio.nl << sio.nl;
358 exit( 1 );
359}
360
361void Bu::OptParser::setNonOption( OptionSignal sSignal )
362{
363 sNonOption = sSignal;
364}
365
366Bu::String Bu::OptParser::format( const Bu::String &sIn, int iWidth,
367 int iIndent )
368{
369 Bu::String sOut;
370 Bu::String sIndent;
371 for( int j = 0; j < iIndent; j++ )
372 sIndent.append(" ", 1);
373 bool bFirst = true;
374 int iSpaceCount = 0;
375 bool bSpace = false;
376 int iPrevLineLen;
377 int iLineLen = 0;
378 Bu::String::const_iterator iLastSpace, iStart;
379 for( Bu::String::const_iterator i = iLastSpace = iStart = sIn.begin(); i; i++ )
380 {
381 if( *i == ' ' )
382 {
383 if( bSpace == false )
384 {
385 iLastSpace = i;
386 iSpaceCount++;
387 bSpace = true;
388 iPrevLineLen = iLineLen;
389 }
390 }
391 else
392 {
393 bSpace = false;
394 }
395 iLineLen++;
396
397 if( iLineLen >= iWidth )
398 {
399 iSpaceCount--;
400 if( bFirst == true )
401 bFirst = false;
402 else
403 sOut += sIndent;
404 int iExtraSpaces = iWidth-iPrevLineLen;
405 bSpace = false;
406 float fFill = 0.0;
407 int iSubSpaceCount = 0;
408 float fAdd = ((float)iExtraSpaces/(float)iSpaceCount);
409 for( Bu::String::const_iterator k = iStart; k != iLastSpace; k++ )
410 {
411 sOut += *k;
412 if( *k == ' ' )
413 {
414 if( bSpace == false && iExtraSpaces > 0 )
415 {
416 bSpace = true;
417 fFill += fAdd;
418 iSubSpaceCount++;
419 for( int sp = 0; sp < (int)(fFill); sp++ )
420 {
421 sOut += ' ';
422 iExtraSpaces--;
423 }
424 fFill -= (int)fFill;
425 if( iSubSpaceCount == iSpaceCount && iExtraSpaces > 0 )
426 {
427 for(; iExtraSpaces > 0; iExtraSpaces-- )
428 {
429 sOut += ' ';
430 }
431 }
432 }
433 }
434 else
435 bSpace = false;
436 }
437 //sOut.append( iStart, iLastSpace );
438 sOut.append("\n");
439 for(; iLastSpace && *iLastSpace == ' '; iLastSpace++ ) { }
440 iStart = i = iLastSpace;
441 bSpace = false;
442 iLineLen = 1;
443 iSpaceCount = 0;
444 }
445 }
446 if( !bFirst )
447 sOut += sIndent;
448 sOut.append( iStart );
449 return sOut;
450}
451
452
453//
454// Code for Bu::OptParser::_ValueProxy
455//
456
457Bu::OptParser::_ValueProxy::_ValueProxy()
458{
459}
460
461Bu::OptParser::_ValueProxy::~_ValueProxy()
462{
463}
464
465//
466// Code for Bu::OptParser::Option
467//
468
469Bu::OptParser::Option::Option() :
470 cOpt( '\0' ),
471 pProxy( NULL )
472{
473}
474
475Bu::OptParser::Option::Option( const Option &rSrc ) :
476 cOpt( rSrc.cOpt ),
477 sOpt( rSrc.sOpt ),
478 sHelp( rSrc.sHelp ),
479 sUsed( rSrc.sUsed ),
480 pProxy( NULL ),
481 sOverride( rSrc.sOverride )
482{
483 if( rSrc.pProxy )
484 pProxy = rSrc.pProxy->clone();
485}
486
487Bu::OptParser::Option::~Option()
488{
489 delete pProxy;
490 pProxy = NULL;
491}
492