Check-in [4f3db7f982]
Overview
SHA1:4f3db7f982775837fa0e627dcee01572741dfb19
Date: 2013-11-23 21:28:45
User: suchenwi
Comment:added several file commands, fixed backslash substitutions
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2013-11-24
08:24
[07c2ea91bc] added [file join], [file split] (user: suchenwi, tags: trunk)
2013-11-23
21:28
[4f3db7f982] added several file commands, fixed backslash substitutions (user: suchenwi, tags: trunk)
2013-11-20
20:58
[3d61c6fe53] added [catch] (user: suchenwi, tags: trunk)
Changes

Modified tcl053.js from [368d355e33] to [623beb5ebc].

     7      7    * Based on Picol by Salvatore Sanfilippo (<http://antirez.com/page/picol>)
     8      8    * (c) Stéphane Arnold 2007
     9      9    * Richard Suchenwirth 2007, 2013: cleanup, additions
    10     10    * vim: syntax=javascript autoindent softtabwidth=4
    11     11    */
    12     12   // 'use strict'; // breaks some tests, like expr 0376, for loop
    13     13   var _step = 0; // set to 1 for debugging
    14         -var fs = require('fs');
    15         -var puts = console.log;
           14  +if(process.env["DEBUG"] == 1) _step = 1;
           15  +var fs    = require('fs');
           16  +var puts  = console.log; // saves a lot of typing... ;^)
    16     17   
    17     18   function TclInterp () {
    18     19       this.patchlevel = "0.5.3";
    19     20       this.callframe  = [{}];
    20     21       this.level      = 0;
    21     22       this.levelcall  = [];
    22     23       this.commands   = {};
    23     24       this.procs      = [];
    24     25       this.script     = "";
           26  +    this.getsing    = 0;
    25     27       this.OK  = 0;
    26     28       this.RET = 1;
    27     29       this.BRK = 2;
    28     30       this.CNT = 3;
    29     31       this.getVar = function(name) {
    30         -        var nm = name.toString();
           32  +        var nm  = name.toString();
           33  +	// no arrays supported yet, but a read-only exception for ::env()
    31     34           if (nm.match("^::env[(]")) nm = nm.substr(2);
    32     35           if (nm.match("^env[(]")) {
    33     36               var key = nm.substr(4,nm.length-5);
    34     37               var val = process.env[key];
    35     38           } else if (nm.match("^::")) {
    36     39               var val = this.callframe[0][nm.substr(2)]; // global
    37     40           } else {
    38     41               var val = this.callframe[this.level][name];
    39     42           }
    40     43           if (val == null) throw 'can\'t read "'+name+'": no such variable';
    41     44           return val;
    42     45       }
    43     46       this.setVar = function(name, val) {
    44         -        var nm = name.toString();
    45         -        if (nm.match("^::")) {
    46         -            this.callframe[0][nm.substr(2)] = val;
    47         -        } else {this.callframe[this.level][name] = val;}
    48         -        return val;
           47  +      var nm  = name.toString();
           48  +      if (val != null && val.toString().match(/\\/))
           49  +	val = eval("'"+val.toString()+"'");
           50  +      if (nm.match("^::")) {
           51  +	this.callframe[0][nm.substr(2)] = val;
           52  +      } else {this.callframe[this.level][name] = val;}
           53  +      return val;
    49     54       }
    50     55       this.setVar("argc",  process.argv.length-2);
    51     56       this.setVar("argv0", process.argv[1]);
    52     57       this.setVar("argv",  process.argv.slice(2));
    53     58       this.setVar("errorInfo", "");
    54     59   
    55     60       this.incrLevel = function() {
    56         -      //puts("going down from ("+this.level+"): "+this.levelcall);
    57     61         this.callframe[++this.level] = {};
    58     62         return this.level;
    59     63       }
    60     64       this.decrLevel = function() {
    61     65         this.callframe[this.level] = null;
    62     66         this.level--;
    63     67         if (this.level < 0) throw "Exit application";
................................................................................
   102    106         } catch (e) {
   103    107   	var msg = code.substr(0,128);
   104    108   	if(msg.length >= 125) msg += "...";
   105    109   	var msg = e+'\n        while executing\n"'+msg+'"';
   106    110   	for(var i = this.level; i > 0; i--)
   107    111   	  msg += '\n        invoked from within\n"'+this.levelcall[i]+'"'
   108    112   	this.setVar("::errorInfo", msg);
          113  +	if(_step) puts("e: "+e);
   109    114   	throw e;
   110    115         }
   111    116       }
   112    117       this.eval2 = function(code) {
   113    118         this.code  = this.OK;
   114    119         var parser = new TclParser(code);
   115    120         var args   = [];
................................................................................
   168    173   	  args[args.length-1] = args[args.length-1].toString() + text.toString();
   169    174   	}
   170    175         }
   171    176         if (args.length > 0) result = this.call(args);
   172    177         return this.objectify(result);
   173    178       }
   174    179       //---------------------------------- Commands in alphabetical order
          180  +    /*this.registerCommand("after", function (interp, args) {
          181  +        this.arity(args, 3);
          182  +	var code = args[2].toString();
          183  +	setTimeout(args[1], function(code) {interp.eval(code)});
          184  +	});*/
   175    185       this.registerCommand("append", function (interp, args) {
   176    186           this.arity(args, 2, Infinity);
   177    187           var vname = args[1].toString();
   178    188   	try {var str = interp.getVar(vname);} catch(e) {var str = "";}
   179    189   	for (var i = 2; i < args.length; i++) str += args[i].toString();
   180    190           interp.setVar(vname, str);
   181    191           return str;
................................................................................
   202    212         });
   203    213       this.registerCommand("continue", function (interp, args) {
   204    214           interp.code = interp.CNT;
   205    215           return;
   206    216         });
   207    217       this.registerSubCommand("clock", "format", function (interp, args) {
   208    218           var now = new Date();
   209         -        now.setTime(args[1]);
   210         -        return now.toString();
          219  +        now.setTime(args[1]*1000);
          220  +        var ts = now.toString().split(" ");
          221  +	var tz = ts[6].toString().replace("(","").replace(")","");
          222  +	return ts[0]+" "+ts[1]+" "+ts[2]+" "+ts[4]+" "+tz+" "+ts[3];
   211    223         });
   212    224       this.registerSubCommand("clock", "milliseconds", function (interp, args) {
   213    225   	var t = new Date();
   214    226   	return t.valueOf();
   215    227         });
   216    228       this.registerSubCommand("clock", "scan", function (interp, args) {
   217    229           return Date.parse(args[1]);
................................................................................
   356    368       var sqrt = Math.sqrt; // "publish" other Math.* functions as needed
   357    369   
   358    370       this.registerCommand("expr", function (interp, args) {
   359    371   	var expression = args.slice(1).join(" ");
   360    372   	return interp.expr(interp, expression);
   361    373         });
   362    374       this.expr = function (interp, expression) { // also used in for, if, while
          375  +      var mx;
   363    376         try {
   364         -	var mx = expression.match(/(\[.*\])/g);
          377  +	mx = expression.match(/(\[.*\])/g);
   365    378   	for (var i in mx)
   366    379   	  puts("have to deal with "+mx[i].toString());
   367    380         } catch(e) {puts(i+". exception: "+e);}
   368    381         mx = expression.match(/(\$[A-Za-z0-9_:]+)/g);
   369         -      for (i in mx) {
          382  +      for (var i in mx) {
   370    383   	var val = interp.getVar(mx[i].slice(1)).toString();
   371    384   	if(isNaN(val) || !isFinite(val)) val = '"'+val+'"';
   372    385   	eval("var "+mx[i]+' = '+val);
   373    386         }
   374    387         var res = eval(expression);
   375    388         if(res == false) res = 0; else if(res == true) res = 1;
   376    389         return res;
   377    390       };
          391  +    this.registerSubCommand("file", "atime", function (interp, args) {
          392  +        this.arity(args, 2);
          393  +	var stat = fs.statSync(args[1].toString());
          394  +	return stat.atime.getTime()/1000;
          395  +      })
   378    396       this.registerSubCommand("file", "dirname", function (interp, args) {
   379    397           this.arity(args, 2);
   380         -	var path = args[1].toString().split("/");
   381         -	path.pop();
   382         -	return path.join("/");
          398  +	return interp.dirname(args[1].toString());
          399  +     });
          400  +    this.dirname = function(p) { // also used in [glob]
          401  +      //require("path"); //not working :(
          402  +      //return path.dirname(p.toString());
          403  +      if(p == ".") p = process.cwd();
          404  +      p = p.split("/"); 
          405  +      p.pop();
          406  +      if(p == "") return("/");
          407  +      return p.join("/");
          408  +    };
          409  +    this.registerSubCommand("file", "exists", function (interp, args) {
          410  +        this.arity(args, 2);
          411  +	var file = args[1].toString();
          412  +	try {var fd = fs.openSync(file,"r");} catch(e) {return 0;}
          413  +	fs.closeSync(fd);
          414  +	return 1;
          415  +     });
          416  +    this.registerSubCommand("file", "extension", function (interp, args) {
          417  +        this.arity(args, 2);
          418  +	var fn  = args[1].toString();
          419  +	var res = fn.split(".").pop();
          420  +	res = (res == fn)? "" : "."+res;
          421  +	return res;
          422  +     });
          423  +    this.registerSubCommand("file", "mtime", function (interp, args) {
          424  +        this.arity(args, 2);
          425  +	var stat = fs.statSync(args[1].toString());
          426  +	return stat.mtime.getTime()/1000;
          427  +      })
          428  +    this.registerSubCommand("file", "size", function (interp, args) {
          429  +        this.arity(args, 2);
          430  +	var stat = fs.statSync(args[1].toString());
          431  +	return stat.size;
          432  +      })
          433  +    this.registerSubCommand("file", "tail", function (interp, args) {
          434  +        this.arity(args, 2);
          435  +	return args[1].toString().split("/").pop();
   383    436         });
   384    437       this.registerCommand("for", function (interp, args) {
   385    438           this.arity(args, 5);
   386    439           interp.eval(args[1].toString());
   387    440           if(interp.code != interp.OK) return;
   388    441           var cond = args[2].toString();
   389    442           var step = args[3].toString();
................................................................................
   430    483   	if(fmt=="%x") {
   431    484   	  var x = new Number(val);
   432    485   	  return x.toString(16);
   433    486   	} else if(fmt=="%X") {
   434    487   	  var x = new Number(val);
   435    488   	  return x.toString(16).toUpperCase();
   436    489   	}
   437         -	else throw "unknown format";
   438         -	
   439         -      });
   440         -    /*
   441         -    this.registerCommand("gets", function (interp, args) {
   442         -        this.arity(args, 2, 3);
   443         -	this.tmp = null;
   444         -	rl.on('line', itp.gets);
   445         -	while(true) {
   446         -	  if(this.tmp != null) break;
   447         -	};
   448         -	rl.on('line', this.getsevalputs);
   449         -        var reply = this.tmp;
   450         -        // = prompt(args[1],"");
   451         -        //process.stdin.resume();
   452         -        //process.stdin.on('data', function(str) {
   453         -        //reply = str;
   454         -        //    });
   455         -        if(args[2] != null) {
   456         -	  interp.setVar(args[2],interp.objectify(reply));
   457         -	  return reply.length;
   458         -        } else return reply;
   459         -      });
   460         -    */
          490  +	else throw "unknown format";	
          491  +      });
          492  +   this.registerCommand("gets0", function (interp, args) {
          493  +	this.arity(args, 2, 3);
          494  +	interp.getsing = 1;
          495  +	//interp.buf = "";
          496  +	//while(interp.buf == "") {
          497  +	//interp.timeout = setTimeout(function(){}, 10000);
          498  +	//  if(interp.getsing==0) break;
          499  +	//}
          500  +	return; // result will be in interp.buf when done
          501  +     });
          502  +   this.gets = function(char) {
          503  +     try {
          504  +       if(char.match(/foo[\r\n]/)) {
          505  +	 this.getsing = 0;
          506  +	 puts("received: "+this.buf);
          507  +       } else {
          508  +	 puts("<"+char+">"+this.getsing);
          509  +	 this.buf += char;
          510  +       }
          511  +     } catch(e) {puts(e)};
          512  +   }
          513  +   this.registerCommand("glob", function (interp, args) {
          514  +	this.arity(args, 2, Infinity);
          515  +	args.shift();
          516  +	var res    = [];
          517  +	var prefix = "";
          518  +	var dir    = ".";
          519  +	for (var arg in args) {
          520  +	  var path    = args[arg].toString();
          521  +	  if(path.match("[/]")) {
          522  +	     var dir    = interp.dirname(path);
          523  +	     var prefix = dir+"/";
          524  +	  }
          525  +	  var pattern = path.split("/").pop().replace(/[*]/g,".*");
          526  +	  var files   = fs.readdirSync(dir);
          527  +	  for (var i in files) {
          528  +	    if(files[i].match("^[.]")) continue;
          529  +	    if(files[i] == pattern) {res.push(files[i]);}
          530  +	    if(files[i].match("^"+pattern+"$")) {
          531  +	      var file = (dir == ".")? files[i] : dir+"/"+files[i];
          532  +	      res.push(file.replace(/\/\//,"/"));
          533  +	    }
          534  +	  }
          535  +	}
          536  +	return res;
          537  +      });
   461    538       this.registerCommand("if", function (interp, args) {
   462    539           this.arity(args, 3, Infinity);
   463    540           var cond = args[1].toString();
   464    541           var test = interp.objectify(interp.expr(interp, cond));
   465    542           if (test.toBoolean()) return interp.eval(args[2].toString());
   466    543           if (args.length == 3) return;
   467    544           for (var i = 3; i < args.length; ) {
................................................................................
   535    612           return interp.mkList(interp.procs);
   536    613       });
   537    614       this.registerSubCommand("info", "script", function (interp, args) {
   538    615           return interp.script;
   539    616       });
   540    617       this.registerSubCommand("info", "vars", function (interp, args) {
   541    618   	var res = [];
   542         -	for(i in interp.callframe[interp.level]) {
          619  +	for(var i in interp.callframe[interp.level]) {
   543    620   	  try {
   544    621   	    if(interp.getVar(i) != null) {res.push(i);}
   545    622   	  } catch(e) {};
   546    623   	}
   547    624   	return res;
   548    625       });
   549    626       this.registerCommand("join", function (interp, args) {
................................................................................
   597    674         });
   598    675       this.registerCommand("llength", function (interp, args) {
   599    676           this.arity(args, 2);
   600    677           return args[1].toList().length;
   601    678         });
   602    679       this.registerCommand("lrange", function (interp, args) {
   603    680           this.arity(args, 4);
   604         -        var list    = interp.objectify(args[1]);
          681  +        var list  = interp.objectify(args[1]);
   605    682           var start = list.listIndex(args[2]);
   606         -        var end     = list.listIndex(args[3])+1;
          683  +        var end   = list.listIndex(args[3])+1;
   607    684           try {
   608    685   	  return list.content.slice(start, end);
   609    686           } catch (e) {return [];}
   610    687         });
   611    688       this.registerCommand("lreverse", function (interp, args) {
   612    689           this.arity(args, 2);
   613    690           return args[1].toList().reverse();
................................................................................
   691    768           if (args.length == 3) interp.setVar(name, val);
   692    769           return interp.getVar(name);
   693    770       });
   694    771       this.registerCommand("source", function (interp, args) {
   695    772           this.arity(args, 2);
   696    773           interp.script = args[1].toString();
   697    774           try {
   698         -	  var data = fs.readFileSync(interp.script).toString();
          775  +	  var data = fs.readFileSync(interp.script,{encoding: 'utf8'}).toString();
   699    776           } catch(e) {
          777  +	  puts("e: "+e);
   700    778   	  throw 'couldn\' read file "'+interp.script
   701    779   	    +'": no such file or directory';}
   702         -	var res    = interp.eval(data);
          780  +	var res       = interp.eval(data);
   703    781   	interp.script = "";
   704    782   	return res;
   705    783         });
   706    784       this.registerCommand("split", function (interp, args) {
   707    785           this.arity(args, 2, 3);
   708    786           var str = args[1].toString();
   709    787           var sep = (args.length == 3)? args[2].toString() : " ";
................................................................................
   884    962   Tcl.isDecimal  = new RegExp("^[+\\-]?[1-9][0-9]*$");
   885    963   Tcl.isHex      = new RegExp("^0x[0-9a-fA-F]+$");
   886    964   Tcl.isOctal    = new RegExp("^[+\\-]?0[0-7]*$");
   887    965   Tcl.isHexSeq   = new RegExp("[0-9a-fA-F]*");
   888    966   Tcl.isOctalSeq = new RegExp("[0-7]*");
   889    967   Tcl.isList     = new RegExp("[\\{\\} ]");
   890    968   Tcl.isNested   = new RegExp("^\\{.*\\}$");
   891         -Tcl.getVar     = new RegExp("^[a-zA-Z0-9_]+", "g");
          969  +Tcl.getVar     = new RegExp("^[:a-zA-Z0-9_]+", "g");
   892    970   
   893    971   Tcl.Proc = function (interp, args) {
   894    972      var priv = this.privdata;
   895    973      interp.incrLevel();
   896    974      var arglist = priv[0].toList();
   897    975      var body    = priv[1];
   898    976      var call    = []; 
................................................................................
   920    998          } else if (name == "args") {
   921    999              interp.setVar("args", new TclObject(args.slice(i, args.length)));
   922   1000              break;
   923   1001          }
   924   1002          interp.setVar(name, interp.objectify(args[i]));
   925   1003      }
   926   1004      if (name == "args" && i+1 < arglist.length)
   927         -       throw "'args' should be the last argument";
         1005  +     throw "'args' should be the last argument";
   928   1006      try {
   929   1007          var res = interp.eval(body);
   930   1008          interp.code = interp.OK;
   931   1009          interp.decrLevel();
   932   1010          return res;
   933   1011      } catch (e) {
   934   1012          interp.decrLevel();
................................................................................
   940   1018     var sub  = args[1].toString();
   941   1019     var main = args.shift().toString()+" "+sub;
   942   1020     args[0]  = main;
   943   1021     var ens  = this.ensemble;
   944   1022     if (ens == null) {
   945   1023       throw "Not an ensemble command: "+main;
   946   1024     } else if (ens[sub] == null) {
   947         -    
   948         -    var matches   = 0, lastmatch = "";
         1025  +    var matches = 0, lastmatch = "";
   949   1026       for (var i in ens) { // maybe unambiguous prefix?
   950   1027         if (i.match("^"+sub) != null) {
   951   1028   	matches  += 1;
   952   1029   	lastmatch = i;
   953   1030         } 
   954   1031       }
   955   1032       if(matches == 1) {
................................................................................
  1105   1182   function TclCommand(func, privdata) {
  1106   1183     if (func == null) throw "No such function";
  1107   1184     this.func     = func;
  1108   1185     this.privdata = privdata;
  1109   1186     this.ensemble = arguments[2];
  1110   1187     
  1111   1188     this.call = function(interp, args) {
  1112         -    var r = (this.func)(interp, args);
  1113         -    r = interp.objectify(r);
  1114         -    return r;
         1189  +    var res = (this.func)(interp, args);
         1190  +    res = interp.objectify(res);
         1191  +    return res;
  1115   1192     }
  1116   1193     this.arity = function (args, min, max) {
  1117   1194       if(max == undefined) max = min;
  1118   1195       if (args.length < min || args.length > max) {
  1119   1196         throw min + ".."+max + " words expected, got "+args.length;
  1120   1197       }
  1121   1198     } 
................................................................................
  1137   1214     this.len         = text.length;
  1138   1215     this.type        = this.EOL;
  1139   1216     this.cur         = this.text.charAt(0);
  1140   1217     this.getText     = function () {
  1141   1218       return this.text.substring(this.start,this.end+1);
  1142   1219     }
  1143   1220     this.parseString = function () {
  1144         -    var newword = (this.type==this.SEP ||
         1221  +    var newword = (this.type == this.SEP ||
  1145   1222   		   this.type == this.EOL || this.type == this.STR);
  1146   1223       if (newword && this.cur == "{") return this.parseBrace();
  1147   1224       else if (newword && this.cur == '"') {
  1148   1225         this.insidequote = true;
  1149   1226         this.feedchar();
  1150   1227       }
  1151   1228       this.start = this.index;
  1152   1229       while (true) {
  1153   1230         if (this.len == 0) {
  1154         -	this.end = this.index-1;
         1231  +	this.end  = this.index-1;
  1155   1232   	this.type = this.ESC;
  1156   1233   	return this.OK;
  1157   1234         }
  1158   1235         /*if (this.cur == "\\") { // works not :(
  1159   1236   	if (this.len >= 2) this.feedSequence();
  1160   1237   	}
  1161   1238   	else*/ if ("$[ \t\n\r;".indexOf(this.cur)>=0) {
  1162   1239   	if ("$[".indexOf(this.cur)>=0 || !this.insidequote) {
  1163         -	  this.end = this.index-1;
         1240  +	  this.end  = this.index-1;
  1164   1241   	  this.type = this.ESC;
  1165   1242   	  return this.OK;
  1166   1243   	}
  1167   1244         }
  1168   1245         else if (this.cur == '"' && this.insidequote) {
  1169   1246   	this.end  = this.index-1;
  1170   1247   	this.type = this.ESC;
................................................................................
  1173   1250   	return this.OK;
  1174   1251         }
  1175   1252         this.feedchar();
  1176   1253       }
  1177   1254       return this.OK;
  1178   1255     }
  1179   1256     this.parseList = function () {
  1180         -    var level = 0;
         1257  +    var level  = 0;
  1181   1258       this.start = this.index;
  1182   1259       while (true) {
  1183   1260         if (this.len == 0) {
  1184   1261   	this.end  = this.index;
  1185   1262   	this.type = this.EOL;
  1186   1263   	return;
  1187   1264         }
................................................................................
  1299   1376         }
  1300   1377         if (this.cur == "#" && this.type == this.EOL) {
  1301   1378   	this.parseComment();
  1302   1379   	continue;
  1303   1380         }
  1304   1381         return this.parseString();
  1305   1382       }
  1306         -    puts("unreachable?");
  1307         -    return this.OK; // unreached
         1383  +    //return this.OK; // unreached
  1308   1384     }
  1309   1385     this.feedSequence = function () {
  1310   1386       //return;
  1311   1387       if (this.cur != "\\") throw "Invalid escape sequence";
  1312   1388       var cur = this.steal(1);
  1313   1389       puts("enter feedSequence, text: "+this.text+" cur: "+cur);
  1314   1390       var specials = {};
................................................................................
  1360   1436       return word;
  1361   1437     }
  1362   1438     this.feedcharstart = function () {
  1363   1439       this.feedchar();
  1364   1440       this.start = this.index;
  1365   1441     }
  1366   1442     this.setPos = function (index) {
  1367         -    var d = index-this.index;
         1443  +    var d      = index-this.index;
  1368   1444       this.index = index;
  1369         -    this.len -= d;
  1370         -    this.cur = this.text.charAt(this.index);
         1445  +    this.len  -= d;
         1446  +    this.cur   = this.text.charAt(this.index);
  1371   1447     }
  1372   1448     this.feedchar = function () {
  1373   1449       this.index++;
  1374   1450       this.len--;
  1375   1451       if (this.len < 0)
  1376   1452         throw "End of file reached";
  1377   1453       this.cur = this.text.charAt(this.index);
................................................................................
  1380   1456   //------------------------------------- main Read-Eval-Print loop
  1381   1457   var itp = new TclInterp();
  1382   1458   var res;
  1383   1459   process.argv.slice(2).forEach(function(cmd,index,array) {
  1384   1460          itp.eval(cmd);
  1385   1461        });
  1386   1462   var readline = require('readline');
  1387         -var rl = readline.createInterface(process.stdin, process.stdout);
         1463  +var rl       = readline.createInterface(process.stdin, process.stdout);
  1388   1464   rl.setPrompt('% ');
  1389   1465   rl.prompt();
  1390         -itp.getsevalputs = function(line) {
         1466  +itp.gets = function(line) {
         1467  +  if (itp.getsing == 0) {
  1391   1468       try {
  1392   1469         res = itp.eval(line.trim());
  1393   1470       } catch(e) {res = e;}
  1394         -    if(res != null && res.toString() != "" && res.toString().length) 
  1395         -      puts(res.toString());
  1396         -    rl.prompt();
         1471  +    if (itp.getsing == 0) {
         1472  +      if(res != null && res.toString().length) 
         1473  +	puts(res.toString());
         1474  +      rl.prompt();
         1475  +    }
         1476  +  } else {itp.buf = line; itp.getsing = 0; rl.prompt();}
  1397   1477   };
  1398         -itp.gets = function(line) {
  1399         -  puts("received "+line); 
  1400         -  this.tmp = line;
  1401         -}
  1402         -rl.on('line', itp.getsevalputs
  1403         -).on('close',function() {
  1404         -    process.exit(0);
  1405         -  });
         1478  +rl.on('line', itp.gets).on('close',function() {process.exit(0);});

Modified test_tcljs.tcl from [da8fb3dc27] to [744eb2cb5e].

     4      4   # [clock format 0] was excluded because the timezone string differed.
     5      5   
     6      6   set vars [info vars] ;# for later cleanup
     7      7   set version 0.5.3
     8      8   set total   0
     9      9   set passed  0
    10     10   set fail    0
    11         -puts "------------------------ [info script] patchlevel: [info patchlevel]"
           11  +puts "----- [info script] of [clock format [file mtime [info script]]], patchlevel: [info patchlevel]"
    12     12   
    13     13   proc e.g. {cmd -> expected} {
           14  +    #puts $cmd
    14     15       incr ::total
    15     16       incr ::fail ;# to also count exceptions
    16     17       set res [uplevel 1 $cmd]
    17     18       if ![string equal $res $expected] {
    18         -    #if {$res != $expected} {} #should work, but wouldn't
           19  +	#if {$res != $expected} {}
    19     20   	puts "**** $cmd -> $res, expected: $expected"
    20     21       } else {incr ::passed; incr ::fail -1}
    21     22   }
    22     23   
    23     24   # e.g. {exec echo hello} -> hello ;# needs blocking exec
    24     25   
    25     26   e.g. {append new hello} -> hello
    26     27   e.g. {set x foo}        -> foo
    27     28   e.g. {append x bar}     -> foobar
    28     29   
    29     30   proc sum args {expr [join $args +]}
    30     31   e.g. {sum 1 2 3} -> 6
    31         -#native sum2 {function (interp, args) {return eval(args.join("+"));}}
    32         -#e.g. {sum2 2 3 4} -> 9
    33     32   
    34         -e.g. {catch foo msg} -> 1
    35         -e.g. {set msg} -> {invalid command name "foo"}
           33  +e.g. {catch foo msg}    -> 1
           34  +e.g. {set msg}          -> {invalid command name "foo"}
    36     35   e.g. {catch {expr 7*6}} -> 0
    37     36   e.g. {catch {expr 7*6} msg; set msg} -> 42
    38     37   
           38  +e.g. {clock format 0}   -> {Thu Jan 01 01:00:00 CET 1970}
           39  +
    39     40   e.g. {concat {a b} {c d}} -> {a b c d}
           41  +e.g. {concat $::version}  -> $version
    40     42   
    41     43   e.g. {set d [dict create a 1 b 2 c 3]} -> {a 1 b 2 c 3}
    42     44   e.g. {dict exists $d c} -> 1
    43     45   e.g. {dict exists $d x} -> 0
    44     46   e.g. {dict get $d b}    -> 2
    45     47   e.g. {dict keys $d}     -> {a b c}
    46     48   e.g. {dict set d b 5}   -> {a 1 b 5 c 3}
................................................................................
    47     49   e.g. {dict set d x 7}   -> {a 1 b 5 c 3 x 7}
    48     50   e.g. {dict unset d b}   -> {a 1 c 3 x 7}
    49     51   e.g. {dict unset d x}   -> {a 1 c 3}
    50     52   e.g. {dict unset d nix} -> {a 1 c 3}
    51     53   e.g. {dict set dx a 1}  -> {a 1} ;# create new dict if not exists
    52     54   
    53     55   e.g. {set home [file dirname [pwd]]; list} -> {}
    54         -e.g. {string equal [set env(HOME)] $home}   -> 1
           56  +e.g. {string equal [set env(HOME)] $home}  -> 1
           57  +# e.g. {string equal $::env(HOME) $home}  -> 1
    55     58   e.g. {string equal [set ::env(HOME)] $home} -> 1
           59  +e.g. {file dirname /foo/bar/grill}          -> /foo/bar
           60  +e.g. {file tail    /foo/bar/grill}          -> grill
    56     61   
    57     62   e.g. {expr 6*7}         -> 42
    58     63   e.g. {expr {6 * 7 + 1}} -> 43
    59     64   e.g. {set x 43}         -> 43
    60     65   e.g. {expr {$x-1}}      -> 42
    61     66   e.g. {expr $x-1}        -> 42
    62     67   if ![info exists auto_path] { ;#these tests are not for a real tclsh
    63         -    e.g. {clock format 0} -> {Thu Jan 01 1970 01:00:00 GMT+0100 (CET)}
    64     68       e.g. {set i [expr 1/0]} -> Infinity
    65     69       e.g. {expr $i==$i+42}   -> 1
    66     70       e.g. {set n [expr sqrt(-1)]} -> NaN
    67     71       e.g. {expr $n == $n} -> 0
    68     72       e.g. {expr $n==$n}   -> 0
    69     73       e.g. {expr $n!=$n}   -> 1
    70     74       e.g. {info patchlevel} -> $version
................................................................................
    90     94   e.g. {expr {$x+1}} -> 4
    91     95   e.g. {set x a; set y b; expr {$x == $y}} -> 0
    92     96   e.g. {expr {$x != $y}} -> 1
    93     97   e.g. {expr 43 % 5}     -> 3 
    94     98   e.g. {set x -44; expr {-$x}} -> 44
    95     99   e.g. {expr 1<<3} -> 8
    96    100   
          101  +e.g. {file dirname foo/bar/grill}  -> foo/bar
          102  +e.g. {file dirname /foo/bar/grill} -> /foo/bar
          103  +e.g. {file extension foo.txt}      -> .txt
          104  +e.g. {file extension Makefile}     -> ""
          105  +e.g. {file tail foo/bar/grill}     -> grill
          106  +
    97    107   set forres ""
    98    108   e.g. {for {set i 0} {$i < 5} {incr i} {append forres $i}; set forres} -> 01234
    99    109   e.g. {foreach i {a b c d e} {append foreachres $i}; set foreachres}   -> abcde
   100    110   
   101    111   e.g. {format %x 255} -> ff
   102    112   e.g. {format %X 254} -> FE
   103    113   
   104    114   e.g. {set x 41}  -> 41
   105    115   e.g. {incr x}    -> 42
   106    116   e.g. {incr x 2}  -> 44
   107    117   e.g. {incr x -3} -> 41
   108    118   
   109         -e.g. {info args e.g.} -> {cmd -> expected}
          119  +e.g. {info args e.g.}        -> {cmd -> expected}
   110    120   e.g. {unset -nocomplain foo} -> {}
   111         -e.g. {info exists foo} -> 0
   112         -e.g. {set foo 42}      -> 42
   113         -e.g. {info exists foo} -> 1
   114         -e.g. {info level}      -> 0 ;# e.g. runs the command one level up
          121  +e.g. {info exists foo}       -> 0
          122  +e.g. {set foo 42}            -> 42
          123  +e.g. {info exists foo}       -> 1
          124  +e.g. {info level}            -> 0 ;# e.g. runs the command one level up
   115    125   e.g. {proc f x {set y 0; info vars}} -> ""
   116         -e.g. {f 41}            -> {x y}
          126  +e.g. {f 41}                          -> {x y}
   117    127   set tmp [f 40]; e.g. {lappend tmp z} -> {x y z}
   118    128   e.g. {info args f}      -> x
   119    129   e.g. {info body f}      -> {set y 0; info vars}
   120    130   e.g. {info bod f}       -> {set y 0; info vars}
   121    131   
   122    132   e.g. {join {a b c}}     -> {a b c}
   123    133   e.g. {join {a b c} +}   -> {a+b+c}
................................................................................
   138    148   e.g. {lsearch $x y}       -> -1
   139    149   e.g. {lsort {z x y}}      -> {x y z}
   140    150   
   141    151   e.g. {proc f args {expr [join $args +]}} -> ""
   142    152   e.g. {f 1}     -> 1
   143    153   e.g. {f 1 2}   -> 3
   144    154   e.g. {f 1 2 3} -> 6
          155  +e.g. {proc f {arg b} {expr $arg*$b}; f 6 7} -> 42 ;# should work with 'args'
   145    156   
   146    157   e.g. {regexp {X[ABC]Y} XAY}    -> 1
   147    158   e.g. {regexp {X[ABC]Y} XDY}    -> 0
   148    159   e.g. {regsub {[A-C]+} uBAAD x} -> uxD 
   149    160   
   150    161   e.g. {split "a b  c d"}     -> {a b {} c d}
   151    162   e.g. {split " a b  c d"}     -> {{} a b {} c d}
   152    163   e.g. {split "a b  c d "}     -> {a b {} c d {}}
   153    164   e.g. {split usr/local/bin /} -> {usr local bin}
   154    165   e.g. {split /usr/local/bin /} -> {{} usr local bin}
   155    166   e.g. {split abc ""}          -> {a b c}
   156    167   
   157         -e.g. {string compare a b}     -> -1
   158         -e.g. {string compare b a}     -> 1
   159         -e.g. {string compare b b}     -> 0
   160         -e.g. {string equal foo foo}   -> 1
   161         -e.g. {string equal foo bar}   -> 0
   162         -e.g. {string index abcde 2}   -> c
   163         -e.g. {string length ""}       -> 0
   164         -e.g. {string length foo}      -> 3
   165         -e.g. {string range hello 1 3} -> ell
   166         -e.g. {string tolower Tcl}     -> tcl
   167         -e.g. {string toupper Tcl}     -> TCL
   168         -e.g. {string trim " foo "}    -> foo
          168  +e.g. {string compare a b}       -> -1
          169  +e.g. {string compare b a}       -> 1
          170  +e.g. {string compare b b}       -> 0
          171  +e.g. {string equal foo foo}     -> 1
          172  +e.g. {string equal foo bar}     -> 0
          173  +e.g. {string index abcde 2}     -> c
          174  +e.g. {string length ""}         -> 0
          175  +e.g. {string length foo}        -> 3
          176  +e.g. {string range hello 1 3}   -> ell
          177  +e.g. {string range hello 1 end} -> ello
          178  +e.g. {string tolower Tcl}       -> tcl
          179  +e.g. {string toupper Tcl}       -> TCL
          180  +e.g. {string trim " foo "}      -> foo
   169    181   
   170         -e.g. {set x a.\x62.c} -> a.b.c ;# severe malfunction, breaks test suite operation :(
          182  +e.g. {set x a.\x62.c} -> a.b.c
          183  +e.g. {set e \u20ac} -> "€" ;# breaks in node v0.6.19, works in v0.10.22
          184  +
   171    185   
   172    186   puts "total $total tests, passed $passed, failed $fail"
   173    187   #----------- clean up variables used in tests
   174    188   foreach var [info vars] {
   175    189       set pos [lsearch $vars $var] ;# expr can't substitute commands yet
   176         -    set neq [string compare $var vars]
   177    190       if {$var != "vars" && $pos < 0} {unset $var}
   178    191   }
   179         -unset vars var pos neq
          192  +unset vars var pos
   180    193   puts "vars now: [info vars]"
   181    194   puts "[llength [info commands]] commands implemented"