blob: 8d109751db923ff60592609b36e37dfb0f95a076 [file] [log] [blame] [raw]
var fs = require('fs');
var child_process = require('child_process');
function cleanAndGetIndexes(text) {
var addRules = {
name: "add",
openTag: "{+",
replaceOpenTag: "",
closeTag: "+}",
replaceCloseTag: "",
}
var delRules = {
name: "del",
openTag: "[-",
replaceOpenTag: "",
closeTag: "-]",
replaceCloseTag: "",
}
var rules = [addRules, delRules];
TagTypeEnum = {
OPENING : 1,
CLOSING : 2
}
function tagLookup(rules, text, pos) {
var seen = false;
var type = null;
var rule = null;
for (var i = 0; i<rules.length; i++) {
var candidateTag = text.slice(pos, pos+rules[i].openTag.length);
// console.log("Comparing "+candidateTag+" with "+rules[i].openTag);
if (rules[i].openTag == candidateTag) {
seen = true;
type = TagTypeEnum.OPENING;
rule = i;
break;
}
var candidateTag = text.slice(pos, pos+rules[i].closeTag.length);
// console.log("Comparing "+candidateTag+" with "+rules[i].closeTag);
if (rules[i].closeTag == candidateTag) {
seen = true;
type = TagTypeEnum.CLOSING;
rule = i;
break;
}
}
return {seen: seen,
rule: rule,
type: type}
}
var finalText = "";
var posInFinalText = 0; // character that is going to be treated
// The position in the original text:
var posInText = 0; // character that is going to be treated
StateEnum = {
OUTSIDE_TAG : 1,
INSIDE_TAG : 2
}
var state = StateEnum.OUTSIDE_TAG;
var zones = [[],[]];
var currentTextBeginPos = 0;
var currentTextEndPos = null;
var currentTagBeginPos = null;
var currentTagEndPos = null;
var currentTag = null;
function forward() {
posInFinalText = posInFinalText + 1;
posInText = posInText + 1;
}
function seenOpeningTag() {
memorizeText();
currentTagBeginPos = posInFinalText;
finalText = finalText.concat(rules[currentTag].replaceOpenTag);
posInFinalText = posInFinalText + rules[currentTag].replaceOpenTag.length;
posInText = posInText + rules[currentTag].openTag.length;
currentTextBeginPos = posInText;
}
function seenClosingTag() {
memorizeText();
finalText = finalText.concat(rules[currentTag].replaceCloseTag);
posInFinalText = posInFinalText + rules[currentTag].replaceCloseTag.length;
posInText = posInText + rules[currentTag].closeTag.length;
currentTagEndPos = posInFinalText - 1;
zones[currentTag].push({begin: currentTagBeginPos, end: currentTagEndPos});
currentTextBeginPos = posInText;
}
function memorizeText() {
currentTextEndPos = posInText - 1;
if (currentTextEndPos >= currentTextBeginPos) {
finalText = finalText.concat(text.slice(currentTextBeginPos,currentTextEndPos+1));
}
}
function end() {
memorizeText();
}
function log_error(string) {
console.log(string);
}
while (posInText < text.length) {
var tag = tagLookup(rules, text, posInText);
if(tag.seen && tag.type == TagTypeEnum.OPENING) {
if (state != StateEnum.OUTSIDE_TAG) {
log_error("Opening tag while not outside tag (tags cannot be nested)");
return null;
}
currentTag = tag.rule;
seenOpeningTag();
state = StateEnum.INSIDE_TAG;
} else if(tag.seen && tag.type == TagTypeEnum.CLOSING) {
if (state != StateEnum.INSIDE_TAG) {
log_error("Closing tag while not inside tag.");
return null;
}
if (currentTag != tag.rule) {
log_error("Closing tag, but not of the same type as previously opened.");
return null;
}
seenClosingTag();
state = StateEnum.OUTSIDE_TAG;
} else {
forward();
}
}
end();
// console.log(JSON.stringify(finalText)+JSON.stringify(zones));
return {text: finalText, zones: zones};
}
function buildDiffHandler(config) {
return function diffHandler(req, res, next) {
// console.log("req: "+JSON.stringify(JSON.decycle(req)));
// console.log("");
// console.log("res: "+JSON.stringify(JSON.decycle(res)));
// console.log("");
// console.log("next: "+JSON.stringify(JSON.decycle(next)));
var before = req.body.before;
var after = req.body.after;
if (before === undefined) {
console.log("Warning : Bad request : wrong \"before\"");
//return next(new Error("Bad request : wrong \"before\""));
}
if (after === undefined) {
console.log("Warning : Bad request : wrong \"after\"");
//return next(new Error("Bad request : wrong \"after\""));
}
//console.log("Before: ");
//console.log(before);
//console.log("After: ");
//console.log(after);
// TODO : make async the two creation of temp files + call to wdiff ?
var wdiffExe = config.wdiffExe;
var tempBeforePath = config.wdiffTmpDir + "/gcc-explorer-wdiff-before";
fs.writeFileSync(tempBeforePath, before);
var tempAfterPath = config.wdiffTmpDir + "/gcc-explorer-wdiff-after";
fs.writeFileSync(tempAfterPath, after);
// TODO : get rid of this buffer or calculate it...
var maxSize = 100000;
var wdiffResult = child_process.spawnSync(
wdiffExe,
[tempBeforePath, tempAfterPath],
{maxBuffer: 100000});
res.set('Content-Type', 'application/json');
var cleaned = cleanAndGetIndexes(wdiffResult.stdout.toString());
if (cleaned == null) {
res.end(JSON.stringify({
computedDiff: "Failed to clean the diff",
zones: null
}));
} else {
res.end(JSON.stringify({
computedDiff: cleaned.text,
// for debug only:
//computedDiff: cleaned.text+
// "\n//// for reference: ////\n"+
// wdiffResult.stdout.toString(),
zones: cleaned.zones
}));
}
}
}
module.exports = {
buildDiffHandler: buildDiffHandler,
};