pro mg_opt::setProperty, short_name=shortName
compile_opt strictarr
if (n_elements(shortName) gt 0L) then begin
self.shortName = shortName
endif
end
pro mg_opt::getProperty, long_name=longName, short_name=shortName, $
boolean=boolean, metavar=metavar, $
key_column_width=keyColumnWidth, $
help_header=helpHeader
compile_opt strictarr
if (arg_present(longName)) then longName = self.longName
if (arg_present(shortName)) then shortName = self.shortName
if (arg_present(boolean)) then boolean = self.boolean
if (arg_present(metavar)) then metavar = self.metavar
if (arg_present(keyColumnWidth) || arg_present(helpHeader)) then begin
helpHeader = '--' + self.longName
helpText = self.metavar eq '' ? strupcase(self.longName) : self.metavar
if (~self.boolean) then begin
helpHeader += '=' + helpText
endif
if (self.shortName ne '') then begin
helpHeader += ', -' + self.shortName
if (~self.boolean) then helpHeader += ' ' + helpText
endif
keyColumnWidth = strlen(helpHeader)
endif
end
function mg_opt::isPresent
compile_opt strictarr
return, self.present
end
function mg_opt::getHelp
compile_opt strictarr
return, self.help
end
function mg_opt::getValue, present=present
compile_opt strictarr
present = self.present
if (self.boolean) then begin
return, self.present ? 1B : 0B
endif else begin
return, self.present ? self.value : self.default
endelse
end
pro mg_opt::setValue, value
compile_opt strictarr
on_error, 2
self.present = 1B
if (n_elements(value) gt 0L) then begin
self.value = value
endif else begin
if (~self.boolean) then begin
message, 'non-boolean options like --' + self.longName + ' must have a value if present'
endif
endelse
end
function mg_opt::init, long_name=longName, boolean=boolean, $
help=help, default=default, metavar=metavar
compile_opt strictarr
self.longName = longName
self.boolean = keyword_set(boolean)
self.help = n_elements(help) gt 0L ? help : ''
self.default = n_elements(default) gt 0L ? default : ''
self.metavar = n_elements(metavar) gt 0L ? metavar : ''
return, 1
end
pro mg_opt__define
compile_opt strictarr
define = { mg_opt, $
longName: '', $
shortName: '', $
value: '', $
present: 0B, $
boolean: 0B, $
metavar: '', $
help: '', $
default: '' }
end
function mg_options::get, optname, params=params, n_params=nparams, $
present=present
compile_opt strictarr
on_error, 2
if (keyword_set(params)) then return, self.params->get(/all, count=nparams)
opt = self.longOptions->get(optname, found=found)
if (~found) then message, string(optname, format='(%"option %s not found")')
return, opt->getValue(present=present)
end
pro mg_options::_displayHelp
compile_opt strictarr
keys = self.longOptions->keys(count=nkeys)
shortNames = self.shortOptions->keys(count=nshortNames)
args = ''
if (self.nparamsAccepted[0] gt 0L) then begin
args += strjoin('arg' + strtrim(indgen(self.nparamsAccepted[0]) + 1, 2), ' ')
endif
case 1 of
self.nParamsAccepted[1] lt 0L: args += '...'
self.nParamsAccepted[1] eq 0L:
self.nParamsAccepted[1] gt 0L: begin
if (self.nparamsAccepted[1] gt self.nparamsAccepted[0]) then begin
optionalArgIndices $
= indgen(self.nparamsAccepted[1] - self.nparamsAccepted[0]) $
+ self.nparamsAccepted[0]
if (args ne '') then args += ' '
args += strjoin('[arg' + strtrim(optionalArgIndices, 2) + ']', ' ')
endif
end
endcase
print, self.appname, args, format='(%"usage: %s [options] %s")'
print
keyColumnWidth = 2L
maxKeyColumnWidth = 24L
for k = 0L, nkeys - 1L do begin
opt = self.longOptions->get(keys[k])
opt->getProperty, key_column_width=keyWidth
keyColumnWidth >= keyWidth
endfor
keyColumnWidth = keyColumnWidth <
combinedFormat = '(%" %-' + strtrim(keyColumnWidth, 2L) + 's %s")'
splitFormat1 = '(%" %-0s")'
splitFormat2 = '(%"' + strjoin((strarr(maxKeyColumnWidth + 4L) + ' ')) + '%s")'
print, 'options:'
keyind = sort(keys)
for k = 0L, nkeys - 1L do begin
opt = self.longOptions->get(keys[keyind[k]])
opt->getProperty, help_header=helpHeader
if (strlen(helpHeader) gt maxKeyColumnWidth) then begin
print, helpHeader, format=splitFormat1
print, opt->getHelp(), format=splitFormat2
endif else begin
print, helpHeader, opt->getHelp(), format=combinedFormat
endelse
endfor
end
pro mg_options::_displayVersion
compile_opt strictarr
print, self.appname, self.version, format='(%"%s %s")'
end
pro mg_options::parseArgs, args, error_message=errorMsg
compile_opt strictarr
errorMsg = ''
_args = n_elements(args) eq 0L ? command_line_args(count=nargs) : args
_nargs = n_elements(nargs) eq 0L ? n_elements(args) : nargs
argumentExpected = 0B
for a = 0L, _nargs - 1L do begin
if (argumentExpected) then begin
opt->setValue, _args[a]
argumentExpected = 0B
continue
endif
if (strpos(_args[a], '--') eq 0L) then begin
equalpos = strpos(_args[a], '=')
if (equalpos eq -1L) then begin
optname = strmid(_args[a], 2L)
endif else begin
optname = strmid(_args[a], 2L, equalpos - 2L)
endelse
opt = self.longOptions->get(optname, found=found)
opt->getProperty, boolean=boolean
if (~found) then begin
errorMsg = string(optname, format='(%"unknown option: --%s")')
return
endif
if (boolean) then begin
opt->setValue
endif else begin
if (equalpos eq -1L) then begin
argumentExpected = 1B
endif else begin
opt->setValue, strmid(_args[a], equalpos + 1L)
endelse
endelse
continue
endif
if (strpos(_args[a], '-') eq 0L) then begin
for sf = 1L, strlen(_args[a]) - 1L do begin
shortName = strmid(_args[a], sf, 1)
opt = self.shortOptions->get(shortName, found=found)
if (~found) then begin
errorMsg = string(shortName, format='(%"unknown option: -%s")')
return
endif
opt->getProperty, boolean=boolean
if (boolean) then begin
opt->setValue
endif else begin
if (sf ne strlen(_args[a]) - 1L) then begin
msg = '(%"non-boolean option -%s must be specified last to accept a value")'
errorMsg = string(shortName, format=msg)
return
endif
argumentExpected = 1B
endelse
endfor
continue
endif
self.params->add, _args[a]
endfor
if (argumentExpected) then begin
errorMsg = string(_args[a - 1L], format='(%"argument expected for %s")')
return
endif
helpOpt = self.longOptions->get('help')
if (helpOpt->isPresent()) then self->_displayHelp
versionOpt = self.longOptions->get('version', found=versionFound)
if (versionFound && versionOpt->isPresent()) then self->_displayVersion
if (helpOpt->isPresent() || (versionFound && versionOpt->isPresent())) then return
nparams = self.params->count()
if (nparams lt self.nParamsAccepted[0]) then begin
errorMsg = string(self.nParamsAccepted[0], nparams, $
format='(%"%d parameters required, %d given")')
return
endif
if (self.nParamsAccepted[1] ge 0L && nparams gt self.nParamsAccepted[1]) then begin
errorMsg = string(self.nParamsAccepted[1], nparams, $
format='(%"%d parameters allowed, %d given")')
return
endif
end
pro mg_options::addOption, longForm, shortForm, help=help, default=default, $
boolean=boolean, metavar=metavar
compile_opt strictarr
opt = obj_new('mg_opt', $
long_name=longForm, $
boolean=boolean, help=help, default=default, metavar=metavar)
self.longOptions->put, longForm, opt
if (n_elements(shortForm) gt 0L) then begin
self.shortOptions->put, shortForm, opt
opt->setProperty, short_name=shortForm
endif
end
pro mg_options::addParams, nparamsRange
compile_opt strictarr
on_error, 2
if (nparamsRange[0] lt 0L) then begin
message, 'minimum number of params must be positive'
endif
if (nparamsRange[1] gt 0L && (nparamsRange[1] lt nparamsRange[0])) then begin
message, 'maximum number of params must be greater than minimum number'
endif
self.nParamsAccepted = nparamsRange
end
pro mg_options::cleanup
compile_opt strictarr
opts = self.longOptions->values(count=count)
if (count gt 0L) then obj_destroy, opts
obj_destroy, [self.longOptions, self.shortOptions, self.params]
end
function mg_options::init, app_name=appname, version=version
compile_opt strictarr
self.appname = n_elements(appname) eq 0L ? 'app' : appname
self.version = n_elements(version) eq 0L ? '' : version
self.longOptions = obj_new('MGcoHashTable', key_type=7, value_type=11)
self.shortOptions = obj_new('MGcoHashTable', key_type=7, value_type=11)
self.params = obj_new('MGcoArrayList', type=7)
self->addOption, 'help', 'h', /boolean, help='display this help'
if (self.version ne '') then begin
self->addOption, 'version', /boolean, help='display version information'
endif
return, 1
end
pro mg_options__define
compile_opt strictarr
define = { mg_options, $
appname: '', $
version: '', $
longOptions: obj_new(), $
shortOptions: obj_new(), $
params: obj_new(), $
nParamsAccepted: lonarr(2) $
}
end
opts = obj_new('mg_options', app_name='mg_options_example', version='1.0')
opts->addOption, 'verbose', 'v', $
/boolean, $
help='set to print a verbose greeting'
opts->addOption, 'name', 'n', help='name of user to greet', default='Mike', $
metavar='user''s name'
opts->parseArgs, error_message=errorMsg
if (errorMsg ne '') then begin
oldQuiet = !quiet
!quiet = 0
message, errorMsg, /informational, /noname
!quiet = oldQuiet
end
if (errorMsg eq '' && ~opts->get('help') && ~opts->get('version')) then begin
print, (opts->get('verbose') ? 'Greetings and salutations' : 'Hello'), $
opts->get('name'), $
format='(%"%s, %s!")'
endif
obj_destroy, opts
end