blob: 84532057b6c2af00e28890db13a1d50fd0cd9527 [file] [log] [blame]
/* --COPYRIGHT--,EPL
* Copyright (c) 2008 Texas Instruments and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
var Cmdr;
/*
* ======== module$meta$init ========
*/
function module$meta$init()
{
Cmdr = this;
}
/*
* ======== instance$meta$init ========
*/
function instance$meta$init(cmdmod, params)
{
var inst = this.$private;
inst.self = this;
inst.cmdmod = cmdmod;
inst.cmdname = cmdmod.$spec.name == 'Main'
? cmdmod.$spec.pkgName : cmdmod.$spec.qualName;
inst.timer = 0;
inst.verbose = false;
}
/*
* ======== error ========
*/
function error(msg)
{
var inst = this.$private;
switch (inst.self.context) {
case Cmdr.SCRIPT:
throw new Error(inst.cmdname
+ ": " + (msg ? msg : 'fatal error'));
break;
case Cmdr.SHELL:
throw new Error(this.$private.cmdname
+ ": " + (msg ? msg : 'fatal error'));
break;
}
}
/*
* ======== getopts ========
*/
function getopts(cmdinst, args)
{
var inst = this.$private;
/* for scalar configs, overwrite the previous option value */
function setScalar(type) {
return (function(obj, prop, value) {
obj[prop] = type(value);
});
};
/* for array configs, add the option value onto the end */
function extendArray(type) {
return (function(obj, prop, value) {
obj[prop].$add(type(value));
});
};
var consmap = {
b: setScalar(Boolean), Ab: extendArray(Boolean),
n: setScalar(Number), An: extendArray(Number),
s: setScalar(String), As: extendArray(String)
};
var cfgarr = [];
var optmap = {};
for each (var cfg in inst.cmdmod.$spec.configs.toArray()) {
var co;
if ((co = cfg.attrString('@CommandOption')) != null) {
var opts = _decodeCommandOption(co);
/* save the config */
cfgarr.push(cfg);
/* add each alias */
for (var i = 0; i < opts.length; i++) {
optmap[opts[i]] = cfg;
}
}
}
while (args.length && args[0][0] == '-') {
var a = args.shift();
if (a == '--help') {
return _help(inst, cfgarr);
}
if (a == '--time') {
inst.timer = java.lang.System.currentTimeMillis();
continue;
}
/* search for the longest matching option */
var opt = undefined;
cfg = undefined;
for (var _opt in optmap) {
if (a.substr(0, _opt.length) != _opt) {
/* doesn't match at all */
continue;
}
if (opt && _opt.length < opt.length) {
/* shorter than the current match */
continue;
}
/* remember it */
opt = _opt;
cfg = optmap[opt];
}
if (!cfg) {
return inst.self.usage('unknown option: ' + a);
}
/* see whether and how the user passed a value as a suffix */
var m = a.substr(opt.length).match(/^([:=]?)(.*)/);
var valFlag = m[1];
var valText = m[2];
var val = undefined;
if (cfg.typeCode == 'b') {
/* if the user passed a value, get it */
if (valFlag) {
val = valText;
if (val == "0" || val == "false") {
val = false;
}
}
else {
/* the config is a boolean, no value is needed */
val = true;
/* process concatenated single-character flags */
if (opt.match(/^-.$/) && valText) {
args.unshift('-' + valText);
}
}
}
else if (valFlag || valText) {
/* user passed the value as a suffix -- get it */
val = valText;
}
else {
/* the value is in the next argument */
val = args.shift();
}
if (val === undefined) {
return inst.self.usage('value required: ' + a);
}
/*
* if the config parameter is a vector, push the new value
* onto the end.
*/
var typeCode = cfg.typeCode;
if (typeCode in consmap) {
consmap[typeCode](cmdinst, cfg.name, val);
}
else {
throw new Error('unsupported typeCode ('
+ typeCode
+ ') for a command line parameter in config '
+ cfg.getQualName());
}
}
for (var cn in optmap) {
cfg = optmap[cn];
if (cmdinst[cfg.name] === undefined) {
return inst.self.usage('undefined parameter: ' + cn);
}
}
return (undefined);
}
/*
* ======== info ========
*/
function info(msg)
{
var inst = this.$private;
if (inst.verbose) {
java.lang.System.out.println(inst.cmdname + ": " + msg);
}
}
/*
* ======== read ========
*/
function read()
{
var inst = this.$private;
if (inst.self.tid) {
return (new java.lang.String(inst.self.socket.takeFromClient()));
}
else if (java.lang.System['in'].readLine) {
/* System.in has already been redirected to a BufferedReader */
return java.lang.System['in'].readLine();
}
else if (inst.br) {
/* already have a local BufferedReader wrapper */
return inst.br.readLine();
}
else {
/* create a BufferedReader wrapping System.in */
inst.br = new java.io.BufferedReader(
new java.io.InputStreamReader(java.lang.System['in']));
return inst.br.readLine();
}
}
/*
* ======== usage ========
*/
function usage(msg)
{
var inst = this.$private;
if (inst.self.context == Cmdr.SCRIPT) {
inst.self.error(msg);
}
if (msg) {
java.lang.System.err.println(inst.cmdname + ": " + msg);
}
return _usage(inst);
}
/*
* ======== time ========
*/
function time(msg)
{
var inst = this.$private;
if (!inst.timer) {
return;
}
java.lang.System.err.print(inst.cmdname + '['
+ (java.lang.System.currentTimeMillis() - inst.timer) + 'ms]');
java.lang.System.err.println(msg ? (': ' + msg) : '');
}
/*
* ======== verbose ========
*/
function verbose(flag)
{
var inst = this.$private;
inst.verbose = Boolean(flag);
}
/*
* ======== warning ========
*/
function warning(msg)
{
if (msg) {
java.lang.System.err.println(this.$private.cmdname + ": " + msg);
}
}
/*
* ======== write ========
*/
function write(s)
{
var inst = this.$private;
if (inst.self.tid) {
inst.self.socket.giveToClient(s);
}
else {
java.lang.System.out.println(s);
}
return;
}
/*
* ======== _decodeCommandOption ========
*/
function _decodeCommandOption(co)
{
co = (co+'').replace(/^\s+|\s+$/g,'').replace(/[\s,]+/, ',').split(',');
var opts = [];
for (var i = 0; i < co.length; i++) {
var opt = co[i];
if (opt == '') {
/* ignore empty options */
continue;
}
else if (opt[0] == '-') {
/* option already includes a dash prefix */
opts.push(opt);
}
else if (opt.length == 1) {
/* short option names start with '-' */
opts.push('-' + opt);
}
else {
/* long option names start with '--' */
opts.push('--' + opt);
}
}
return opts;
}
/*
* ======== _deleteDirectory ========
*/
function _deleteDirectory(dir)
{
var dirFile = java.io.File(dir);
if (dirFile.exists() && dirFile.isDirectory()) {
for each (var f in dirFile.listFiles()) {
if (f.isDirectory() && f.listFiles().length) {
_deleteDirectory(f);
}
try {
f['delete']();
}
catch (e) {
java.lang.System.err.println("Cannot delete file: " +
f.getCanonicalPath());
}
}
dirFile['delete']();
}
}
/*
* ======== _help ========
*/
function _help(inst, cfgarr)
{
var xdoc = inst.cmdmod.$spec.makeXDoc();
java.lang.System.err.println('\nSummary: ' + xdoc.summary + '\n');
_usage(inst);
java.lang.System.err.println('Options:');
for each (var cfg in cfgarr) {
xdoc = cfg.makeXDoc();
var names = _decodeCommandOption(cfg.attrString('@CommandOption'));
java.lang.System.err.println('\t' + names.join(',') + '\t'
+ xdoc.summary);
}
var xmlDir = inst.cmdmod.$package.packageBase + 'package';
if (!java.io.File(xmlDir + '/package.doc.xml').exists()) {
try {
var tmpdir = String(Packages.xdc.services.global.Host.tmpdir())
+ '/';
var Xml = xdc.loadCapsule('xdc/tools/cdoc/Xml.xs');
xmlDir = Xml.gen(inst.cmdmod.$package.packageBase, tmpdir, []);
}
catch (e) {
print('warning: error generating package.doc.xml from ' +
inst.cmdmod.$package.packageBase + '. ' + e);
return 0;
}
}
var xml = xdc.loadXML(java.io.File(xmlDir + '/package.doc.xml').getAbsolutePath());
var details = xml.unit.(@name == 'Main').docSect.(@name == 'details').docPara;
if (details.length()) {
java.lang.System.err.println('Details:');
for each (var node in details) {
java.lang.System.err.println();
var s = String(java.net.URLDecoder.decode(node.@content, 'UTF-8'));
s = s.replace(/^(\s*)/gm, '\t');
java.lang.System.err.println(s);
}
}
if (tmpdir) {
_deleteDirectory(tmpdir);
}
/* exit shell with a zero error status */
return 0;
}
/*
* ======== _usage ========
*/
function _usage(inst)
{
java.lang.System.err.println('Usage: xs ' + inst.cmdname + " [--help]");
for each (var line in inst.cmdmod.usage) {
java.lang.System.err.println('\t' + line);
}
/* exit with an error code of 1 */
return 1;
}