From 38839cad1ff36e1a15d4d5873d4e210499f85e45 Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Thu, 12 Nov 2015 08:18:41 +0000
Subject: [PATCH] Avoid creating new objects when it's avoidable (use
 Graphic.copy(), modify existing objects, use object function-local variables,
 etc).

---
 exec/dorkit/ansi_input.js   | 54 ++++++++++++++++++-------------------
 exec/dorkit/attribute.js    |  3 ++-
 exec/dorkit/jsexec_input.js |  1 -
 exec/dorkit/screen.js       | 35 ++++++++++++------------
 exec/load/dorkit.js         | 44 ++++++++++++++++++------------
 5 files changed, 73 insertions(+), 64 deletions(-)

diff --git a/exec/dorkit/ansi_input.js b/exec/dorkit/ansi_input.js
index 7d8d8c5cd3..b49d7640da 100644
--- a/exec/dorkit/ansi_input.js
+++ b/exec/dorkit/ansi_input.js
@@ -1,6 +1,7 @@
 var ai={
 	charbuf:'',
 	ansi_started:0,
+	input_queue:new Queue("dorkit_input"),
 
 	// Called every 100ms *and* every char.
 	add:function(ch) {
@@ -8,13 +9,12 @@ var ai={
 		var q;
 		var byte;
 		var m;
-		q = new Queue("dorkit_input");
 
 		if (ch == '\x1b') {
 			if (this.ansi_started) {
 				for(i=0; i<this.charbuf.length; i++) {
 					byte = this.charbuf.substr(i,1)
-					q.write(byte);
+					this.input_queue.write(byte);
 				}
 			}
 			this.ansi_started = Date.now();
@@ -25,7 +25,7 @@ var ai={
 		// Add the character to charbuf.
 		if (ch !== undefined && ch.length > 0) {
 			if (!this.ansi_started) {
-				q.write(ch);
+				this.input_queue.write(ch);
 				return;
 			}
 
@@ -37,25 +37,25 @@ var ai={
 					case '\x1b[A':
 					case '\x1bOA':
 					case '\x1bA':
-						q.write("KEY_UP\x00"+this.charbuf);
+						this.input_queue.write("KEY_UP\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[B':
 					case '\x1bOB':
 					case '\x1bB':
-						q.write("KEY_DOWN\x00"+this.charbuf);
+						this.input_queue.write("KEY_DOWN\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[C':
 					case '\x1bOC':
 					case '\x1bC':
-						q.write("KEY_RIGHT\x00"+this.charbuf);
+						this.input_queue.write("KEY_RIGHT\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[D':
 					case '\x1bOD':
 					case '\x1bD':
-						q.write("KEY_LEFT\x00"+this.charbuf);
+						this.input_queue.write("KEY_LEFT\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1bH':
@@ -64,108 +64,108 @@ var ai={
 					case '\x1b[L':
 					case '\x1b[w':
 					case '\x1b[OH':
-						q.write("KEY_HOME\x00"+this.charbuf);
+						this.input_queue.write("KEY_HOME\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1bK':
 					case '\x1b[K':
 					case '\x1b[4~':
 					case '\x1bOK':
-						q.write("KEY_END\x00"+this.charbuf);
+						this.input_queue.write("KEY_END\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1bP':
 					case '\x1bOP':
 					case '\x1b[11~':
-						q.write("KEY_F1\x00"+this.charbuf);
+						this.input_queue.write("KEY_F1\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1bQ':
 					case '\x1bOQ':
 					case '\x1b[12~':
-						q.write("KEY_F2\x00"+this.charbuf);
+						this.input_queue.write("KEY_F2\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b?w':
 					case '\x1bOR':
 					case '\x1bOw':
 					case '\x1b[13~':
-						q.write("KEY_F3\x00"+this.charbuf);
+						this.input_queue.write("KEY_F3\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b?x':
 					case '\x1bOS':
 					case '\x1bOx':
 					case '\x1b[14~':
-						q.write("KEY_F4\x00"+this.charbuf);
+						this.input_queue.write("KEY_F4\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b?t':
 					case '\x1bOt':
 					case '\x1b[15~':
-						q.write("KEY_F5\x00"+this.charbuf);
+						this.input_queue.write("KEY_F5\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b?u':
 					case '\x1b[17~':
 					case '\x1bOu':
-						q.write("KEY_F6\x00"+this.charbuf);
+						this.input_queue.write("KEY_F6\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b?q':
 					case '\x1b[18~':
 					case '\x1bOq':
-						q.write("KEY_F7\x00"+this.charbuf);
+						this.input_queue.write("KEY_F7\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b?r':
 					case '\x1b[19~':
 					case '\x1bOr':
-						q.write("KEY_F8\x00"+this.charbuf);
+						this.input_queue.write("KEY_F8\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b?p':
 					case '\x1b[20~':
 					case '\x1bOp':
-						q.write("KEY_F9\x00"+this.charbuf);
+						this.input_queue.write("KEY_F9\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[21~':
-						q.write("KEY_F10\x00"+this.charbuf);
+						this.input_queue.write("KEY_F10\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[23~':
-						q.write("KEY_F11\x00"+this.charbuf);
+						this.input_queue.write("KEY_F11\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[24~':
-						q.write("KEY_F12\x00"+this.charbuf);
+						this.input_queue.write("KEY_F12\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[M':
 					case '\x1b[V':
 					case '\x1b[5~':
-						q.write("KEY_PGUP\x00"+this.charbuf);
+						this.input_queue.write("KEY_PGUP\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[U':
 					case '\x1b[6~':
-						q.write("KEY_PGDOWN\x00"+this.charbuf);
+						this.input_queue.write("KEY_PGDOWN\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[@':
 					case '\x1b[2~':
-						q.write("KEY_INS\x00"+this.charbuf);
+						this.input_queue.write("KEY_INS\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 					case '\x1b[3~':
-						q.write("KEY_DEL\x00"+this.charbuf);
+						this.input_queue.write("KEY_DEL\x00"+this.charbuf);
 						this.ansi_started = 0;
 						break;
 				}
 				m = this.charbuf.match(/^\x1b\[([0-9]+);([0-9]+)R$/);
 				if (m !== null) {
-					q.write(format("POSITION_"+m[1]+"_"+m[2]+"\x00"+this.charbuf));
+					this.input_queue.write(format("POSITION_"+m[1]+"_"+m[2]+"\x00"+this.charbuf));
 					this.ansi_started = 0;
 				}
 				if (!this.ansi_started)
@@ -177,7 +177,7 @@ var ai={
 		if (this.charbuf.length > 10 || (this.ansi_started && this.ansi_started + 100 < Date.now())) {
 			for(i=0; i<this.charbuf.length; i++) {
 				byte = this.charbuf.substr(i,1)
-				q.write(byte);
+				this.input_queue.write(byte);
 			}
 			this.ansi_started = 0;
 		}
diff --git a/exec/dorkit/attribute.js b/exec/dorkit/attribute.js
index b980047bf6..f43699f08a 100644
--- a/exec/dorkit/attribute.js
+++ b/exec/dorkit/attribute.js
@@ -77,6 +77,7 @@ Attribute.prototype = {
 		this.value |= (val & 0x07);
 	},
 
+	_curatr:new Attribute(7),
 	ansi:function(curatr) {
 		var str="";
 		if(curatr !== undefined && curatr.value === this.value)
@@ -88,7 +89,7 @@ Attribute.prototype = {
 				|| (!(this.blink) && curatr.blink) || this.value === 7) {
 			str += "0;";
 			if (curatr === undefined)
-				curatr = new Attribute(7);
+				curatr = this.curatr;
 			curatr.value = 7;
 		}
 		if(this.blink) {                     /* special attributes */
diff --git a/exec/dorkit/jsexec_input.js b/exec/dorkit/jsexec_input.js
index 426a3fb986..833d3db3d9 100644
--- a/exec/dorkit/jsexec_input.js
+++ b/exec/dorkit/jsexec_input.js
@@ -1,7 +1,6 @@
 js.load_path_list.unshift(js.exec_dir+"/dorkit/");
 js.load_path_list.unshift(system.exec_dir+"/dorkit/");
 load('ansi_input.js');
-var q = new Queue("dorkit_input");
 var k;
 
 while(!js.terminated) {
diff --git a/exec/dorkit/screen.js b/exec/dorkit/screen.js
index 5d65da7a9f..5199ae1e46 100644
--- a/exec/dorkit/screen.js
+++ b/exec/dorkit/screen.js
@@ -20,6 +20,9 @@ function Screen(w, h, attr, fill)
 	this.stored_pos = {x:0, y:0};
 	this.attr = new Attribute(7);
 }
+Screen.ANSIRe = /^(.*?)\x1b\[([<-\?]{0,1})([0-;]*)([ -\/]*)([@-~])([\x00-\xff]*)$/;
+Screen.ANSIFragRe = /^(.*?)(\x1b(\[([<-\?]{0,1})([0-;]*)([ -\/]*)([@-~])?)?)$/;
+Screen.StripColonRe = /:[^;:]*/g;
 
 Screen.prototype.print=function(str) {
 	var m;
@@ -33,16 +36,18 @@ Screen.prototype.print=function(str) {
 	var i;
 	var tg;
 	var seq;
+	var x;
+	var y;
 
 	function writech(scr, ch) {
 		var i;
-		var gr;
 
 		function check_scrollup(scr) {
+			var i;
+
 			while (scr.pos.y >= scr.graphic.height) {
 				// Scroll up...
-				gr = scr.graphic.get(0,1,scr.graphic.width-1, scr.graphic.height-2);
-				scr.graphic.put(gr,0,0);
+				scr.graphic.copy(0,1,scr.graphic.width-1, scr.graphic.height-2, 0, 0);
 				for (i=0; i<scr.graphic.width; i++) {
 					scr.graphic.data[i][scr.graphic.height-1].ch = scr.graphic.ch;
 					scr.graphic.data[i][scr.graphic.height-1].attr = scr.attr.value;
@@ -73,7 +78,7 @@ Screen.prototype.print=function(str) {
 				scr.pos.y++;
 				check_scrollup(scr);
 				break;
-			case '\x0c':	// For feed (clear screen and home)
+			case '\x0c':	// Form feed (clear screen and home)
 				scr.graphic.clear();
 				scr.pos.x=0;
 				scr.pos.y=0;
@@ -83,7 +88,7 @@ Screen.prototype.print=function(str) {
 				break;
 			default:
 				scr.graphic.data[scr.pos.x][scr.pos.y].ch = ch;
-				scr.graphic.data[scr.pos.x][scr.pos.y].attr = new Attribute(scr.attr);
+				scr.graphic.data[scr.pos.x][scr.pos.y].attr.value = scr.attr.value;
 				scr.pos.x++;
 				if (scr.pos.x >= scr.graphic.width) {
 					scr.pos.x = 0;
@@ -113,7 +118,7 @@ Screen.prototype.print=function(str) {
 	str = this.escbuf + str;
 	this.escbuf = '';
 
-	while((m=str.match(/^(.*?)\x1b\[([<-\?]{0,1})([0-;]*)([ -\/]*)([@-~])([\x00-\xff]*)$/)) !== null) {
+	while((m=str.match(Screen.ANSIRe)) !== null) {
 		chars = m[1];
 		ext = m[2];
 		pb = m[3];
@@ -121,8 +126,6 @@ Screen.prototype.print=function(str) {
 		fb = m[5];
 		remain = m[6];
 		seq = ext + ib + fb;
-		var x;
-		var y;
 
 		str = remain;
 
@@ -131,7 +134,7 @@ Screen.prototype.print=function(str) {
 			writech(this, chars[i]);
 
 		// We don't support any : paramters... strip and ignore.
-		p = pb.replace(/:[^;:]*/g, '');
+		p = pb.replace(Screen.StripColonRe, '');
 		p = p.split(';');
 
 		switch(fb) {
@@ -139,10 +142,8 @@ Screen.prototype.print=function(str) {
 				param_defaults(p, [1]);
 				if (p[1] > this.graphic.width - this.pos.x)
 					p[1] = this.graphic.width - this.pos.x;
-				if (this.pos.x < this.graphic.width-1) {
-					tg = this.graphic.get(this.pos.x, this.pos.y, this.graphic.width-1 - p[1], this.pos.y);
-					tg = this.graphic.put(this.pos.x + p[1], this.pos.y, this.graphic.width - 1, this.pos.y);
-				}
+				if (this.pos.x < this.graphic.width-1)
+					this.graphic.copy(this.pos.x, this.pos.y, this.graphic.width-1 - p[1], this.pos.y, this.pos.x + p[1], this.pos.y);
 				for (x = 0; x<p[1]; x++) {
 					this.graphic.data[this.pos.x + x][this.pos.y].ch = this.graphic.ch;
 					this.graphic.data[this.pos.x + x][this.pos.y].attr = this.attr.value;
@@ -241,10 +242,8 @@ Screen.prototype.print=function(str) {
 				param_defaults(p, [1]);
 				if (p[1] > this.graphic.width - this.pos.x)
 					p[1] = this.graphic.width - this.pos.x;
-				if (this.pos.x < this.graphic.width-1) {
-					tg = this.graphic.get(this.pos.x + p[1], this.pos.y, this.graphic.width - 1, this.pos.y);
-					tg = this.graphic.put(this.pos.x, this.pos.y, (this.graphic.width - 1) - p[1], this.pos.y);
-				}
+				if (this.pos.x < this.graphic.width-1)
+					this.graphic.copy(this.pos.x + p[1], this.pos.y, this.graphic.width - 1, this.pos.y, this.pos.x, this.pos.y);
 				for (x = 0; x<p[1]; x++) {
 					this.graphic.data[(this.width - 1) - x][this.pos.y].ch = this.graphic.ch;
 					this.graphic.data[(this.width - 1) - x][this.pos.y].attr = this.attr.value;
@@ -358,7 +357,7 @@ Screen.prototype.print=function(str) {
 				log("Sent unsupported ANSI sequence '"+ext+pb+ib+fb+"' please let shurd@sasktel.net net know about this so it can be fixed.");
 		}
 	}
-	if ((m=str.match(/^(.*?)(\x1b(\[([<-\?]{0,1})([0-;]*)([ -\/]*)([@-~])?)?)$/)) !== null) {
+	if ((m=str.match(Screen.ANSIFragRe)) !== null) {
 		str = m[1];
 		this.escbuf = m[2];
 	}
diff --git a/exec/load/dorkit.js b/exec/load/dorkit.js
index 10ecdd4d93..3c4f0fdfb7 100644
--- a/exec/load/dorkit.js
+++ b/exec/load/dorkit.js
@@ -73,13 +73,17 @@ var dk = {
 		x:1,					// Current column (1-based)
 		y:1,					// Current row (1-based)
 		_attr:new Attribute(7),
+		_new_attr:new Attribute(7),
 		get attr() {
 			return this._attr;
 		},
 		set attr(val) {
-			var n = new Attribute(val);
-			this.print(n.ansi(this._attr));
-			this._attr = n;
+			if (typeof(val)=='object')
+				this._new_attr.value = val.value;
+			else
+				this._new_attr.value = val;
+			this.print(this._new_attr.ansi(this._attr));
+			this._attr.value = this._new_attr.value;
 		},
 		ansi:true,				// ANSI support is enabled
 		charset:'cp437',		// Supported character set
@@ -91,28 +95,37 @@ var dk = {
 		keybuf:'',
 		local_screen:new Screen(80, 24, 7, ' '),
 		remote_screen:new Screen(80, 24, 7, ' '),
+		input_queue:new Queue("dorkit_input"),
 
 		/*
 		 * Returns a string with ^A codes converted to ANSI or stripped
 		 * as appropriate.
 		 */
+		_orig_attr:new Attribute(7),
+		_next_attr:new Attribute(7),
 		parse_ctrla:function(txt, orig_attr) {
 			var ret='';
 			var i;
 			var curr_attr;
-			var next_attr;
+			var next_attr = this._next_attr;
 
-			if (orig_attr !== undefined)
-				curr_attr = new Attribute(orig_attr);
-			next_attr = new Attribute(curr_attr);
+			if (orig_attr !== undefined) {
+				curr_attr = this._orig_attr;
+				curr_attr.value = orig_attr.value;
+				next_attr.value = curr_attr.value;
+			}
+			else
+				next_attr.value = 7;
 
 			function attr_str() {
 				var ansi_str;
 
 				if (curr_attr === undefined || curr_attr.value != next_attr.value) {
 					ansi_str = next_attr.ansi(curr_attr);
-					if (curr_attr === undefined)
-						curr_attr = new Attribute(next_attr);
+					if (curr_attr === undefined) {
+						curr_attr = this._orig_attr;
+						curr_attr.value = next_attr.value;
+					}
 					else
 						curr_attr.value = next_attr.value;
 					return ansi_str;
@@ -295,8 +308,7 @@ var dk = {
 		 * true when the entire ANSI sequence is available.
 		 */
 		waitkey:function(timeout) {
-			var q = new Queue("dorkit_input");
-			if (q.poll(timeout) === false)
+			if (this.input_queue.poll(timeout) === false)
 				return false;
 			return true;
 		},
@@ -316,8 +328,7 @@ var dk = {
 			}
 			if (!this.waitkey(0))
 				return undefined;
-			var q = new Queue("dorkit_input");
-			ret = q.read();
+			ret = this.input_queue.read();
 			if (ret.length > 1) {
 				if (ret.substr(0, 9) === 'POSITION_') {
 					m = ret.match(/^POSITION_([0-9]+)_([0-9]+)/);
@@ -343,8 +354,7 @@ var dk = {
 			}
 			if (!this.waitkey(0))
 				return undefined;
-			var q = new Queue("dorkit_input");
-			ret = q.read();
+			ret = this.input_queue.read();
 			if (ret.length > 1) {
 				ret=this.key[ret.replace(/^.*\x00/,'')];
 				this.keybuf = ret.substr(1);
@@ -449,7 +459,7 @@ var dk = {
 		main_dir:undefined,
 		gen_dir:undefined,
 		sysop_name:undefined,
-		default_attr:undefined,
+		default_attr:new Attribute(7),
 		mode:(js.global.bbs !== undefined
 				&& js.global.server !== undefined
 				&& js.global.client !== undefined
@@ -568,7 +578,7 @@ var dk = {
 		else
 			this.user.ansi_supported = (df[38].toUpperCase === 'Y') ? true : false;
 		this.misc.record_locking = (df[39].toUpperCase === 'N') ? false : true;
-		this.system.default_attr = new Attribute(parseInt(df[40], 10));
+		this.system.default_attr.value = parseInt(df[40], 10);
 		this.user.time_credits = parseInt(df[41], 10);
 		// TODO: Parse a date out of this.
 		this.user.last_new_file_scan_date = df[42];
-- 
GitLab