実際にコンパイル、実行可能ですが、動作はとっても遅いです……。
あくまでも 4/1 用のネタとしてご利用ください。
サクラエディタ用の diff.exe を JScript で自作してみる
サクラエディタでは、diff.exeを呼び出すことで、2つのファイルの差分を表示する機能があります。
しかし、Windows用の出回っている diff.exe は古いし、新しめの diff.exe は依存ファイルをいろいろ要求されて動きません。
そこで、以前作った JavaScript のソースを流用して、自前の diff.exe を作成してみました。
内部のアルゴリズムについては、過去の記事で解説しています。
コンパイル手順
まず、.NET Framework に含まれる JScript のコンパイラを探します。
エクスプローラで jsc.exe を検索してみてください。Windows7、Windows10 であれば、C:\Windows\ 以下のどこかにあると思います。
jsc.exe が見つかれば、この記事の末尾にあるソースをコマンドラインからコンパイルして、diff.exeを作成します。
cd /d C:\test
C:\Windows\Microsoft.NET\Framework\v4.0.30319\jsc.exe C:\test\diff.js
パスはそれぞれの環境にあわせて適宜書き換えてください。
出来上がった diff.exe をサクラエディタと同じフォルダに配置します。
既に diff.exe を利用している場合は、いつでも元に戻せるよう、どこか別フォルダに退避しておいて下さい。間違っても上書きしないように!!!
コンパイルした diff.exe は、コマンドラインから起動して使用可能です。
サポートしている出力形式は、ノーマル出力と --context、--unified、--brief です。
引数の仕様は本家 diffutils に合わせていますが、サクラエディタで diff を表示するのに必要な最低限の機能しか実装していません。
diff -u "c:\test\old.txt" "c:\test\new.txt"
ソース
diff.js の名前でローカルに保存して下さい。
import System;
/****************************************************************************
lesser diff.exe for Windows (NOT compatible with GNU Diff)
version 0.01
Copyleft 2020-2021 stonee
license: GPL3 https://www.gnu.org/licenses/gpl-3.0.html
compile:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\jsc.exe diff.js
****************************************************************************/
var fso = new ActiveXObject("Scripting.FileSystemObject");
function isBlank(s) {
for (var i = s.length - 1; i >= 0; i--) {
var n = s.charCodeAt(i);
if (!((n === 0x9) || (n === 0x20) || (n === 0xD) || (n === 0xA))) {
return false;
}
}
return true;
}
//==============================================================================
var Hunks = function() {
this.vList = [];
}
Hunks.prototype.hunk_size = function(i) { return (this.vList[i].end - this.vList[i].start - 1); }
Hunks.prototype.gap = function(i) { return ((i == 0) ? (this.vList[i].start + 1) : (this.vList[i].start - this.vList[i - 1].end + 1)); }
Hunks.prototype.addEntry = function(start, end, isBlankLines) {
this.vList.push({start:start, end:end, isBlankLines:isBlankLines});
}
Hunks.prototype.length = function() { return this.vList.length; }
Hunks.prototype.getHunk = function(i) { return this.vList[i]; }
Hunks.prototype.merge = function(lines, o_Hunk_other) {
var i, n = this.vList.length, nEnd = 0;
for (i = 1; i < n; i++) {
if (nEnd + 1 < i) {
this.vList[nEnd + 1] = this.vList[i];
o_Hunk_other.vList[nEnd + 1] = o_Hunk_other.vList[i];
}
if ((this.vList[i].start - this.vList[nEnd].end + 1) <= lines) {
this.vList[nEnd].end = this.vList[i].end;
this.vList[nEnd].isBlankLines = (this.vList[nEnd].isBlankLines && this.vList[i].isBlankLines);
o_Hunk_other.vList[nEnd].end = o_Hunk_other.vList[i].end;
o_Hunk_other.vList[nEnd].isBlankLines = (o_Hunk_other.vList[nEnd].isBlankLines && o_Hunk_other.vList[i].isBlankLines);
} else {
nEnd++;
}
}
for (i = nEnd + 2; i < n; i++) {
this.vList.pop();
o_Hunk_other.vList.pop();
}
}
//==============================================================================
var DiffEngine = {
bIgnoreCase: false,
flgIgnoreBlank: 0, //0:compare 1:ignore change 2:ignore all
bIgnoreBlankLines: false,
bDetectSimilarLine: true,
strFile_L: "",
strFile_R: "",
vInfo_L: [],
vInfo_R: [],
oHunks_L: null,
oHunks_R: null,
threshold: 0.5,
BLANK_PATTERN: /[\s\t]+/g,
lines: 3,
Compare: function(s1, s2, flgIgnoreBlank) {
var i = 0, j = 0, n1, n2, len1 = s1.length, len2 = s2.length;
var _isWhite = function(n) { return ((n == 0x9) || (n == 0x20) || (n == 0xD) || (n == 0xA)); };
if (flgIgnoreBlank != 0) {
while ((i < len1) && _isWhite(s1.charCodeAt(i))) { i++; }
while ((j < len2) && _isWhite(s2.charCodeAt(j))) { j++; }
} else if (len1 != len2) {
return false;
}
while ((i < len1) && (j < len2)) {
n1 = s1.charCodeAt(i);
n2 = s2.charCodeAt(j);
if ((flgIgnoreBlank != 0) && _isWhite(n1)) {
if (flgIgnoreBlank == 1) {
if (!_isWhite(n2)) { return false; }
j++;
}
i++;
while ((i < len1) && _isWhite(s1.charCodeAt(i))) { i++; }
while ((j < len2) && _isWhite(s2.charCodeAt(j))) { j++; }
} else if ((flgIgnoreBlank != 0) && _isWhite(n2)) {
if (flgIgnoreBlank == 1) { return false; }
j++;
while ((j < len2) && _isWhite(s2.charCodeAt(j))) { j++; }
} else if (n1 != n2) {
return false;
} else {
i++;
j++;
}
}
if (flgIgnoreBlank != 0) {
while ((i < len1) && _isWhite(s1.charCodeAt(i))) { i++; }
while ((j < len2) && _isWhite(s2.charCodeAt(j))) { j++; }
}
return ((i >= len1) && (j >= len2));
},
CompareLine: function(x, y, bStrict) {
if (this.vInfo_L[x].isBlank != this.vInfo_R[y].isBlank) { return 0; }
var s1 = this.vLeft[x], s2 = this.vRight[y];
if (this.vInfo_L[x].isBlank) {
if ((this.flgIgnoreBlank != 0) || (s1 == s2)) { return 2; }
return bStrict ? 0 : 1;
}
if (this.bIgnoreCase) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
}
if (this.Compare(s1, s2, this.flgIgnoreBlank)) { return 2; }
if (bStrict || (this.vInfo_L[x].UniquePair >= 0) || (this.vInfo_R[y].UniquePair >= 0)) {
return 0;
}
s1 = s1.replace(this.BLANK_PATTERN, "");
s2 = s2.replace(this.BLANK_PATTERN, "");
var len1 = s1.length, len2 = s2.length;
return ((len1 > len2) ? this.CalcScore(s2, s1, len2, len1) : this.CalcScore(s1, s2, len1, len2));
},
CalcScore: function(s1, s2, len1, len2) {
var p_max = len1 + 1 - this.threshold * len2;
if (p_max < 1) { return 0; } //optimize
var y, p = 0, k = (len1 + len2 + 2), fp = new Array(k + 1);
do {
fp[k] = -1;
} while (k--);
for (; (p <= p_max) && (fp[len2 + 1] != len2); p++) {
for (k = len1 - p; k < len2; k++) {
for (y = Math.max(fp[k] + 1, fp[k + 2]);
(y < k) && (s1.charCodeAt(y - k + len1) == s2.charCodeAt(y));
y++) {}
fp[k + 1] = y;
}
for (k = len2 + p; k >= len2; k--) {
for (y = Math.max(fp[k] + 1, fp[k + 2]);
(y < len2) && (s1.charCodeAt(y - k + len1) == s2.charCodeAt(y));
y++) {}
fp[k + 1] = y;
}
}
return (1 - (len2 - len1 + p - 1) / len2); //distance score
},
IsDuplicated: function(v, vInfo, i, j, bIgnoreCase, flgIgnoreBlank) {
if ((vInfo[i].isBlank != vInfo[j].isBlank) || (vInfo[i].hash != vInfo[j].hash)) { return false; }
return (bIgnoreCase ? this.Compare(v[i].toLowerCase(), v[j].toLowerCase(), flgIgnoreBlank) : this.Compare(v[i], v[j], flgIgnoreBlank));
},
hash_: function(s, bIgnoreCase) {
s = s.replace(this.BLANK_PATTERN, "");
var i, len = s.length, result = len;
if (len == 0) { return 0; }
if (bIgnoreCase) { s = s.toLowerCase(); }
for (i = 0; i < len; i++) {
result = s.charCodeAt(i) ^ (result << 2);
}
return result;
},
InitInfo: function(len1, len2) {
var i, j, isUnique_L = new Array(len1), isUnique_R = new Array(len2);
const bIgnoreCase = this.bIgnoreCase;
this.vInfo_L = new Array(len1);
this.vInfo_R = new Array(len2);
for (i = 0; i < len1; i++) {
this.vInfo_L[i] = {status:"+", pair:-1, isBlank:isBlank(this.vLeft[i]), hash:this.hash_(this.vLeft[i], bIgnoreCase), UniquePair:-1};
isUnique_L[i] = !(this.vInfo_L[i].isBlank);
}
for (i = 0; i < len2; i++) {
this.vInfo_R[i] = {status:"+", pair:-1, isBlank:isBlank(this.vRight[i]), hash:this.hash_(this.vRight[i], bIgnoreCase), UniquePair:-1};
isUnique_R[i] = !(this.vInfo_R[i].isBlank);
}
if (!this.bDetectSimilarLine) { return; }
for (i = 0; i < len1; i++) {
if (!(isUnique_L[i])) { continue; }
for (j = len1 - 1; j > i; j--) {
if (!(this.vInfo_L[j].isBlank) && this.IsDuplicated(this.vLeft, this.vInfo_L, i, j, bIgnoreCase, 2)) {
isUnique_L[i] = isUnique_L[j] = false;
break;
}
}
}
for (i = 0; i < len2; i++) {
if (!(isUnique_R[i])) { continue; }
for (j = len2 - 1; j > i; j--) {
if (!(this.vInfo_R[j].isBlank) && this.IsDuplicated(this.vRight, this.vInfo_R, i, j, bIgnoreCase, 2)) {
isUnique_R[i] = isUnique_R[j] = false;
break;
}
}
if (!(isUnique_R[i])) { continue; }
for (j = 0; j < len1; j++) {
if (isUnique_L[j] && (this.vInfo_L[j].UniquePair < 0) && (this.CompareLine(j, i, true) > 1)) {
this.vInfo_R[i].UniquePair = j;
this.vInfo_L[j].UniquePair = i;
break;
}
}
}
},
Brief: function(strFile1, strFile2) {
this.strFile_L = strFile1;
this.strFile_R = strFile2;
var s1 = LoadFile(strFile1);
var s2 = LoadFile(strFile2);
this.vLeft = s1.replace(/^\n+|\n+$/g, "").split("\n");
this.vRight = s2.replace(/^\n+|\n+$/g, "").split("\n");
var len1 = this.vLeft.length, len2 = this.vRight.length;
//work around - "No newline at end of file"
if (isBlank(this.vLeft[len1 - 1])) {
this.vLeft.pop();
len1--;
}
if (isBlank(this.vRight[len2 - 1])) {
this.vRight.pop();
len2--;
}
this.InitInfo(len1, len2);
var x, y;
for (x = 0, y = 0; (x < len1) && (y < len2); x++, y++) {
if (this.bIgnoreBlankLines) {
while (this.vInfo_L[x].isBlank && (x < len1 - 1)) { x++; }
while (this.vInfo_R[y].isBlank && (y < len2 - 1)) { y++; }
}
if (this.CompareLine(x, y, true) < 1) { return true; }
}
return false;
},
Diff: function(strFile1, strFile2) {
this.strFile_L = strFile1;
this.strFile_R = strFile2;
var s1 = LoadFile(strFile1);
var s2 = LoadFile(strFile2);
var eol1 = s1.match(/\r\n|\n|\r/);
var eol2 = s2.match(/\r\n|\n|\r/);
this.vLeft = ((eol1 != null) ? s1.split(eol1) : [s1]);
this.vRight = ((eol2 != null) ? s2.split(eol2) : [s2]);
var len1 = this.vLeft.length, len2 = this.vRight.length;
//work around - "No newline at end of file"
if (isBlank(this.vLeft[len1 - 1])) {
this.vLeft.pop();
len1--;
}
if (isBlank(this.vRight[len2 - 1])) {
this.vRight.pop();
len2--;
}
this.InitInfo(len1, len2);
var o = (len1 > len2) ? this.Diff_(len2, len1, true) : this.Diff_(len1, len2, false);
var vResult = [], vWork = [];
for (; o; o = o.prev) {
vResult.unshift(o);
if ((o.op == "-") || (o.op == "+")) { continue; }
this.vInfo_L[o.x].status = this.vInfo_R[o.y].status = o.op;
this.vInfo_L[o.x].pair = o.y;
this.vInfo_R[o.y].pair = o.x;
}
this.CreateHunksList(len1, len2, vResult);
return vResult;
},
//len1 <= len2
Diff_: function(len1, len2, bReverse) {
var p, k = len1 + len2 + 2, fp = new Array(k + 1), ed = new Array(k + 1);
var x, y, x1, y1, y0, score, bIsBlank, org;
var bStrict = !this.bDetectSimilarLine, threshold = this.threshold;
do {
fp[k] = -1;
ed[k] = null;
} while (k--);
for (p = 0; fp[len2 + 1] != len2; p++) {
for (k = len1 - p; k < len2; k++) {
y = Math.max(fp[k] + 1, fp[k + 2]);
x = y - k + len1;
if (bReverse) {
x1 = y; y1 = x;
if (y == fp[k + 2]) {
ed[k + 1] = {op:"+", x:-1, y:y1 - 1, prev:ed[k + 2]};
} else if (y > 0) {
ed[k + 1] = {op:"-", x:x1 - 1, y:-1, prev:ed[k]};
}
} else {
x1 = x; y1 = y;
if ((y != (fp[k] + 1)) || (fp[k + 2] == 0)) {
ed[k + 1] = {op:"-", x:x1 - 1, y:-1, prev:ed[k + 2]};
} else if (y > 0) {
ed[k + 1] = {op:"+", x:-1, y:y1 - 1, prev:ed[k]};
}
}
for (bIsBlank = true, y0 = y, org = ed[k + 1]; x < len1; x++, y++, x1++, y1++) {
if ((score = this.CompareLine(x1, y1, bStrict)) <= threshold) { break; }
if (!this.vInfo_L[x1].isBlank) { bIsBlank = false; }
ed[k + 1] = {op:((score > 1) ? "=" : "!"), x:x1, y:y1, prev:ed[k + 1]};
}
if (bIsBlank && !((x >= (len1 - 1)) && (y >= (len2 - 1)))) { y = y0; ed[k + 1] = org; }
fp[k + 1] = y;
}
for (k = len2 + p; k >= len2; k--) {
y = Math.max(fp[k] + 1, fp[k + 2]);
x = y - k + len1;
if (bReverse) {
x1 = y; y1 = x;
if (y == fp[k + 2]) {
ed[k + 1] = {op:"+", x:-1, y:x - 1, prev:ed[k + 2]};
} else if (y > 0) {
ed[k + 1] = {op:"-", x:y - 1, y:-1, prev:ed[k]};
}
} else {
x1 = x; y1 = y;
if ((y != (fp[k] + 1)) || (fp[k + 2] == 0)) {
ed[k + 1] = {op:"-", x:x - 1, y:-1, prev:ed[k + 2]};
} else if (y > 0) {
ed[k + 1] = {op:"+", x:-1, y:y - 1, prev:ed[k]};
}
}
for (bIsBlank = true, y0 = y, org = ed[k + 1]; y < len2; x++, y++, x1++, y1++) {
if ((score = this.CompareLine(x1, y1, bStrict)) <= threshold) { break; }
if (!this.vInfo_L[x1].isBlank) { bIsBlank = false; }
ed[k + 1] = {op:((score > 1) ? "=" : "!"), x:x1, y:y1, prev:ed[k + 1]};
}
if (bIsBlank && !((x >= (len1 - 1)) && (y >= (len2 - 1)))) { y = y0; ed[k + 1] = org; }
fp[k + 1] = y;
}
}
return ed[len2 + 1];
},
CreateHunksList: function(len1, len2, vResult) {
this.oHunks_L = new Hunks();
this.oHunks_R = new Hunks();
var o_L = this.oHunks_L, o_R = this.oHunks_R;
var o, x = 0, y = 0, x0 = -1, y0 = -1, bIsBlank_L, bIsBlank_R, op_bak = "", i;
for (i = 0; o = vResult[i]; ) {
if (o.op == "-") { //left block
for (x0 = o.x - 1, bIsBlank_L = true; (o = vResult[i]) && (x < len1) && (o.op == "-"); i++, x++) {
if (!this.vInfo_L[x].isBlank) { bIsBlank_L = false; }
}
o_L.addEntry(x0, x, bIsBlank_L);
op_bak = "-";
} else if (o.op == "+") { //right block
if (op_bak != "-") { o_L.addEntry(x - 1, x, true); }
for (y0 = o.y - 1, bIsBlank_R = true; (o = vResult[i]) && (y < len2) && (o.op == "+"); i++, y++) {
if (!this.vInfo_R[o.y].isBlank) { bIsBlank_R = false; }
}
o_R.addEntry(y0, y, bIsBlank_R);
op_bak = "+";
} else if (o.op == "!") { //change
if (op_bak == "-") { o_R.addEntry(o.y - 1, o.y, true); }
x0 = o.x - 1, bIsBlank_L = true;
y0 = o.y - 1, bIsBlank_R = true;
for (op_bak = o.op; (o = vResult[i]) && (o.op == op_bak); i++, x++, y++) {
if (!this.vInfo_L[x].isBlank) { bIsBlank_L = false; }
if (!this.vInfo_R[o.y].isBlank) { bIsBlank_R = false; }
}
o_L.addEntry(x0, x, bIsBlank_L);
o_R.addEntry(y0, y, bIsBlank_R);
} else { //common
if (op_bak == "-") { o_R.addEntry(o.y - 1, o.y, true); }
for (op_bak = o.op; (o = vResult[i]) && (o.op == op_bak); i++, x++, y++) {}
}
}
if (op_bak == "-") { o_R.addEntry(len2 - 1, len2, true); }
}
};//DiffEngine
//==============================================================================
function Int2Str(v) { return ((v == 0) ? "" : (v + "")); }
function do_diff_c(strFile1, strFile2) {
var objDiff = DiffEngine;
objDiff.bDetectSimilarLine = true;
var vResult = objDiff.Diff(strFile1, strFile2);
var vTable = [];
var i, x, y, x_min, y_min, x_max, y_max, oHunk_L, oHunk_R, nHunkLen = 0;
var lines = objDiff.lines;
var dt1 = new Date(fso.GetFile(strFile1).DateLastModified);
var dt2 = new Date(fso.GetFile(strFile2).DateLastModified);
vTable.push("*** " + strFile1 + " " + formatdate(dt1));
vTable.push("--- " + strFile2 + " " + formatdate(dt2));
nHunkLen = objDiff.oHunks_L.length();
for (i = 0; i < nHunkLen; i++) {
oHunk_L = objDiff.oHunks_L.getHunk(i);
oHunk_R = objDiff.oHunks_R.getHunk(i);
vTable.push("***************");
x_min = Math.max(oHunk_L.start - lines + 1, 0);
x_max = Math.min(objDiff.vLeft.length - 1, oHunk_L.end + lines - 1);
vTable.push("*** " + (x_min + 1) + ", " + (x_max + 1) + " ****");
for (x = x_min; x <= x_max; x++) {
switch (objDiff.vInfo_L[x].status) {
case "+":
vTable.push("- " + objDiff.vLeft[x]);
break;
case "!":
vTable.push("! " + objDiff.vLeft[x]);
break;
default:
vTable.push(" " + objDiff.vLeft[x]);
break;
}
}
y_min = Math.max(oHunk_R.start - lines + 1, 0);
y_max = Math.min(objDiff.vRight.length - 1, oHunk_R.end + lines - 1);
vTable.push("--- " + (y_min + 1) + ", " + (y_max + 1) + " ----");
for (y = y_min; y <= y_max; y++) {
switch (objDiff.vInfo_R[y].status) {
case "+":
vTable.push("+ " + objDiff.vRight[y]);
break;
case "!":
vTable.push("! " + objDiff.vRight[y]);
break;
default:
vTable.push(" " + objDiff.vRight[y]);
break;
}
}
}
for (i = 0; i < vTable.length; i++) {
print(vTable[i]);
}
}
function do_diff_u(strFile1, strFile2) {
var objDiff = DiffEngine;
objDiff.bDetectSimilarLine = false;
var vResult = objDiff.Diff(strFile1, strFile2);
var vTable = [], vWork = [], nCount_L = 0, nCount_R = 0, nCount_M = -1;
var i, j, o, n1 = 1, n2 = 1, current;
var lines = objDiff.lines;
var dt1 = new Date(fso.GetFile(strFile1).DateLastModified);
var dt2 = new Date(fso.GetFile(strFile2).DateLastModified);
vTable.push("--- " + strFile1 + " " + formatdate(dt1));
vTable.push("+++ " + strFile2 + " " + formatdate(dt2));
for (i = 0; current = vResult[i]; i++) {
if (current.op == "+") {
if ((i <= 0 || vResult[i - 1].op == "=") && (nCount_M < 0 || nCount_M >= lines)) {
CountLine(i, lines);
vTable.push("@@ -" + + Int2Str(n1 - vWork.length) + "," + nCount_L
+ " +" + Int2Str(n2 - vWork.length) + "," + nCount_R + " @@");
vTable = vTable.concat(vWork);
vWork = [];
}
vTable.push("+" + objDiff.vRight[current.y]);
nCount_M = 0;
n2++;
} else if (current.op == "-") {
if ((i <= 0 || vResult[i - 1].op == "=") && (nCount_M < 0 || nCount_M >= lines)) {
CountLine(i, lines);
vTable.push("@@ -" + Int2Str(n1 - vWork.length) + "," + nCount_L
+ " +" + Int2Str(n2 - vWork.length) + "," + nCount_R + " @@");
vTable = vTable.concat(vWork);
vWork = [];
}
vTable.push("-" + objDiff.vLeft[current.x]);
nCount_M = 0;
n1++;
} else {
if (nCount_M >= 0 && nCount_M < lines) {
vTable.push(" " + objDiff.vLeft[current.x]);
nCount_M++;
} else {
nCount_L = 0;
nCount_R = 0;
nCount_M = -1;
for (j = i + 1; o = vResult[j]; j++) {
if (j > (i + lines)) { break; }
if (o.op != "=") {
vTable.push(" " + objDiff.vLeft[current.x]);
break;
}
}
}
n1++;
n2++;
}
}
function CountLine(i_start, lines) {
nCount_L = vWork.length;
nCount_R = vWork.length;
var nCount_M2 = -1, j, o;
for (j = i_start; o = vResult[j]; j++) {
switch (o.op) {
case "-":
nCount_L++;
nCount_M2 = 0;
break;
case "+":
nCount_R++;
nCount_M2 = 0;
break;
default:
nCount_L++;
nCount_R++;
if (nCount_M2 >= 0 && nCount_M2 < lines) {
nCount_M2++;
if (nCount_M2 >= lines) { return; }
}
break;
}
}
}
for (i = 0; i < vTable.length; i++) {
print(vTable[i]);
}
}
function do_diff_normal(strFile1, strFile2) {
var objDiff = DiffEngine;
objDiff.bDetectSimilarLine = true;
var vResult = objDiff.Diff(strFile1, strFile2);
var vTable = [], vWork = [], vWork2 = [], i, current, strHeader = "", epos;
var arrlen = vResult.length - 1, x = -1;
vTable.push("$diff " + strFile1 + " " + strFile2);
for (i = 0; current = vResult[i]; i++) {
if (objDiff.bIgnoreBlankLines &&
(((current.x >= 0) && objDiff.vInfo_L[current.x].isBlank)
|| ((current.y >= 0) && objDiff.vInfo_R[current.y].isBlank))) {
if (current.x >= 0) { x = current.x; }
continue;
}
if (current.op == "+") {
if (i == 0) {
strHeader = "0a" + (current.y + 1);
} else {
strHeader = (x + 1) + "a" + (current.y + 1);
}
vWork = [];
vWork.push("> " + objDiff.vRight[current.y]);
while ((i < (arrlen - 1)) && vResult[i + 1].op == "+") {
i++;
vWork.push("> " + objDiff.vRight[vResult[i].y]);
}
if (current.y != vResult[i].y) {
epos = vResult[i].y;
if (objDiff.bIgnoreBlankLines) {
while (objDiff.vInfo_R[epos].isBlank) {
vWork.pop();
epos--;
}
}
if (current.y != epos) {
strHeader += "," + (epos + 1);
}
}
vTable.push(strHeader);
vTable = vTable.concat(vWork);
} else if (current.op == "-") {
strHeader = (current.x + 1);
vWork = [];
vWork.push("< " + objDiff.vLeft[current.x]);
while ((i < (arrlen - 1)) && vResult[i + 1].op == "-") {
i++;
vWork.push("< " + objDiff.vLeft[vResult[i].x]);
}
if (current.x != vResult[i].x) {
epos = vResult[i].x;
if (objDiff.bIgnoreBlankLines) {
while (objDiff.vInfo_L[epos].isBlank) {
vWork.pop();
epos--;
}
}
if (current.x != epos) {
strHeader += "," + (epos + 1);
}
}
if (i >= (arrlen - 1)) {
strHeader += "d " + objDiff.vRight.length;
} else {
strHeader += "d " + (vResult[i + 1].y);
}
vTable.push(strHeader);
vTable = vTable.concat(vWork);
x = vResult[i].x;
} else if (current.op == "!") {
vWork = [];
vWork2 = [];
var x0 = (current.x + 1), y0 = (current.y + 1);
vWork.push("< " + objDiff.vLeft[current.x]);
vWork2.push("> " + objDiff.vRight[current.y]);
while ((i < (arrlen - 1)) && vResult[i + 1].op == "!") {
i++;
vWork.push("< " + objDiff.vLeft[vResult[i].x]);
vWork2.push("> " + objDiff.vRight[vResult[i].y]);
}
if (current.x != vResult[i].x) {
strHeader = x0 + "," + (vResult[i].x + 1) + "c" + y0 + "," + (vResult[i].y + 1);
} else {
strHeader = x0 + "c" + y0;
}
vTable.push(strHeader);
vTable = vTable.concat(vWork)
vTable.push("---");
vTable = vTable.concat(vWork2)
x = vResult[i].x;
} else {
x = vResult[i].x;
}
}//for
for (i = 0; i < vTable.length; i++) {
print(vTable[i]);
}
}
function do_diff_q(strFile1, strFile2, strOutputFormat) {
var objDiff = DiffEngine;
objDiff.bDeectSimilarLine = false;
if (objDiff.Brief(strFile1, strFile2)) {
print("Files " + strFile1 + " and " + strFile2 + " differ");
} else if (strOutputFormat == "s") {
print("Files " + strFile1 + " and " + strFile2 + " are identical");
}
}
function pad_zero(n) { return ((n < 10) ? ("0" + n) : n); }
function formatdate(dt) {
var month = dt.getMonth() + 1;
return (dt.getFullYear() + "-" + pad_zero(month) + "-" + pad_zero(dt.getDate()) + " "
+ pad_zero(dt.getHours()) + ":" + pad_zero(dt.getMinutes()) + ":" + pad_zero(dt.getSeconds())
+ ".000000000 +0900");
}
function LoadFile(strFile) {
var o = new ActiveXObject("ADODB.Stream");
var text = "";
o.type = 2;
o.charset = "_autodetect_all";
o.open();
o.loadFromFile(strFile);
text = o.readText(-1);
o.close();
return text;
}
//==============================================================================
function Version() {
print("lesser diff.exe for Windows (NOT compatible with GNU Diff)");
}
function do_diff_main() {
try {
var arg = Environment.GetCommandLineArgs();
var strFile1 = "", strFile2 = "", strOption;
var strOutputFormat = "", nLines = 3;
if (arg.length < 2) {
Version();
return 0;
}
for (var i = 1; i < arg.length; i++) {
strOption = arg[i];
var index = strOption.indexOf("=");
var strOption2 = "";
if (index !== -1) {
strOption2 = strOption.substring(index + 1);
strOption = strOption.substring(0, index);
}
switch (strOption) {
case "--text":
case "--minimal":
case "--label":
break;
case "--context":
strOutputFormat = "c";
if (strOption2 != "") {
nLines = parseInt(strOption2, 10);
if (isNaN(nLines)) { nLines = 3; }
}
break;
case "--inhibit-hunk-merge":
//not implemented
break;
case "--ignore-space-change":
if (DiffEngine.flgIgnoreBlank != 2) {
DiffEngine.flgIgnoreBlank = 1;
}
break;
case "--ignore-all-space":
DiffEngine.flgIgnoreBlank = 2;
break;
case "--ignore-blank-lines":
DiffEngine.bIgnoreBlankLines = true;
break;
case "--ignore-tab-expansion":
case "--expand-tabs":
case "--initial-tab":
//not implemented
break;
case "--ignore-case":
DiffEngine.bIgnoreCase = true;
break;
case "--brief":
if (strOutputFormat != "s") { strOutputFormat = "q"; }
break;
case "--unified":
strOutputFormat = "u";
if (strOption2 != "") {
nLines = parseInt(strOption2, 10);
if (isNaN(nLines)) { nLines = 3; }
}
break;
case "--report-identical-files":
strOutputFormat = "s";
break;
case "--recursive":
break;
case "-v":
case "--version":
Version();
return 0;
break;
case "--help":
Version();
return 0;
break;
default:
var strPrefix = strOption.substring(0, 1);
if ((strPrefix == "-") || (strPrefix == "/")) {
if (strOption.substring(0, 2) == "--") {
//do nothing
} else {
for (var j = 1; j < strOption.length; j++) {
switch (strOption.substring(j, j + 1)) {
case "a": //--text
case "d": //--minimal
case "e": //--ed
case "E": //--ignore-tab-expansion
case "I": //--ignore-matching-lines
case "L": //--label
case "n": //--rcs
case "t": //--expand-tabs
case "T": //--initial-tab
case "r": //--recursive
case "y": //--side-by-side
//not implemented
break;
case "c": //--context
case "C": //--context
strOutputFormat = "c";
if ((i + 1) < arg.length) {
nLines = parseInt(arg[i + 1], 10);
if (isNaN(nLines)) {
nLines = 3;
} else {
i++
}
}
break;
case "q": //--brief
if (strOutputFormat != "s") { strOutputFormat = "q"; }
break;
case "s": //--report-identical-files
strOutputFormat = "s";
break;
case "i": //--ignore-case
break;
case "b": //--ignore-space-change
if (DiffEngine.flgIgnoreBlank != 2) {
DiffEngine.flgIgnoreBlank = 1;
}
break;
case "w": //--inore-all-space
DiffEngine.flgIgnoreBlank = 2;
break;
case "B": //--ignore-blank-lines
DiffEngine.bIgnoreBlankLines = true;
break;
case "u": //--unified
case "U": //--unified
strOutputFormat = "u";
if ((i + 1) < arg.length) {
nLines = parseInt(arg[i + 1], 10);
if (isNaN(nLines)) {
nLines = 3;
} else {
i++
}
}
break;
default:
break;
}
}
}
} else if (strFile1 == "") {
strFile1 = strOption;
} else if (strFile2 == "") {
strFile2 = strOption;
}
break;
}
}
if ((strFile1 == "") || (strFile2 == "")) {
throw "file name is empty";
}
if (!fso.FileExists(strFile1) || !fso.FileExists(strFile2)) {
throw "file not found";
}
DiffEngine.lines = nLines;
if (strOutputFormat == "u") { //unified
do_diff_u(strFile1, strFile2);
} else if ((strOutputFormat == "q") || (strOutputFormat == "s")) {
do_diff_q(strFile1, strFile2, strOutputFormat);
} else if (strOutputFormat == "c") { //context
do_diff_c(strFile1, strFile2);
} else {
do_diff_normal(strFile1, strFile2);
}
return 0;
} catch (e) {
print (e.message || e.toString())
return -1;
} finally {
}
}
do_diff_main();