(.+)<\/ProjectName>/);
if (filename) {
//return only first item of regexp
return filename[1];
} else {
//There is no specified ProjectName, thus use filename without extension as our langpack name
return FSO.GetBaseName(plugin_project_file);
}
}
//Get MUUID of plugin from source file.
function GetMUUID (folder,array) {
//first, find necessary file list, we are looking for UNICODE_AWARE function, usually this function are in *.cpp, sometimes in *.c and *.h
//init fillelist array
muuidfilelist=new Array();
//search for files in "folder" by mask, put result into muuidfilelist
FindFiles (folder,"\\.cpp$|\\.c$|\\.h$",muuidfilelist);
//now we have files, let's put them to Enumerator
filesenum=new Enumerator(muuidfilelist);
//cycle through file list and lookup each file for UNICODE_AWARE
while (!filesenum.atEnd()) {
//curfile is our current file in files enumerator
curfile=filesenum.item();
//this is a regexp to search UNICODE_AWARE
var find=/(?:UNICODE_AWARE(?:\s*?\|\s*?STATIC_PLUGIN)?,[\s\S]*?\{)(.+?)(?=\}\s{0,2}\})/g;
//read file fully into var "allstrings"
allstrings=ReadFile(curfile);
//search regexp in "allstrings" and put results into var "string"
string=find.exec(allstrings);
//if current file have found UNICODE_AWARE, var "string" exists, so parse it.
if (string) {
//remove spaces, "0x" and "{", in second [1] item of array "string". RegExp "find" have subregexp (.+?), which are our MUUID in "string[1]"
vals=string[1].replace(/0x|\{|\x20/g,"");
//now split values of muuid in "vals" by "," into array "values"
values=vals.split(",");
//we get array of values, if length of this array not equal to 12 values (starting from zero, thus length is 11), that's mean we found something else, not MUUID. Log it and quit, if length is 12, so check it and generate MUUID
if (values.length==11) {
//now check, is there some values, which have omitted zero after 0x, like in alarms: " 0x4dd7762b, 0xd612, 0x4f84, { 0xaa, 0x86, 0x(no_zero_here_)6, 0x8f, 0x17, 0x85, 0x9b, 0x6d}"
//first value in values have to be 8 bytes, while length less than 8, add leading "0" to values[0],
while (values[0].length<8) {values[0]="0"+values[0]};
//next two values have to be 4 bytes, adding leading zeros, while length less than 4.
for (i=1;i<=2;i++) {
while (values[i].length<4) {
values[i]="0"+values[i];
}
}
//other values have to be 2 bytes, same as above, adding zeros
for (i=3;i<=10;i++) {
while (values[i].length<2) {
values[i]="0"+values[i];
}
}
//Push to array founded #muuid
var muuid="#muuid {"+values[0]+"-"+values[1]+"-"+values[2]+"-"+values[3]+values[4]+"-"+values[5]+values[6]+values[7]+values[8]+values[9]+values[10]+"}";
};
};
//moving to next file
filesenum.moveNext();
};
//if we didn't find muuid, put alarm into "muuid"
if (!muuid) {muuid=";#muuid for "+plugin+" not found, please specify manually!"}
//output result into array
array.push(muuid)
//log output
if (log) WScript.Echo(muuid);
};
//For status plugins, namely KeepStatus, StartupStatus and AdvancedAutoAway we need add for all of them common source files to parsing array, because they exist one layer upper of pluginfolder
function CheckStatusPlugins (plug) {
if (plug.match(/(KeepStatus|StartupStatus|AdvancedAutoAway)/)) {
resourcefiles.push(trunk+"\\Plugins\\StatusPlugins\\resource.rc");
sourcefiles.push(trunk+"\\Plugins\\StatusPlugins\\commonstatus.cpp");
sourcefiles.push(trunk+"\\Plugins\\StatusPlugins\\confirmdialog.cpp");
}
}
//read text file, removing all commented text for further processing
function ReadFile (file) {
//If file zero size, return;
if (FSO.GetFile(file).Size==0) return;
//reading current file
file_stream=FSO.GetFile(file).OpenAsTextStream(ForReading, TristateUseDefault);
//read file fully into var
allstrings=file_stream.ReadAll();
//remove all comments. The text starting with \\ (but not with ":\\" it's a links like http://miranda-ng.org/ and ")//" -there is one comment right after needed string)
//and remove multi-line comments, started with /* and ended with */
text=allstrings.replace(/(?:[^\):])(\/{2}.+?(?=$))|(\s\/\*[\S\s]+?\*\/)/mg,".")
//close file
file_stream.Close();
return text
}
//Parsing filelist into stringsarray by parsefunction (ParseSourceFile OR ParseRCFile)
function ParseFiles (filelist,stringsarray, parsefunction) {
//create enumerator filesenum from filelist
filesenum=new Enumerator(filelist);
//cycle through file list
while (!filesenum.atEnd()) {
//record into current_strings current length of stringsarray
var current_strings=stringsarray.length;
//record into crap_strings current length of crap array
var crap_strings=crap.length;
//curfile is our current file in files enumerator
curfile=filesenum.item();
//read file (filtering comments) into filetext
var filetext=ReadFile(curfile);
//now apply a parsing function to current filetext, and put result into stringsarray
parsefunction(filetext,stringsarray);
//string variable to cut out a trunkPath from absolute path
curfilepath=new String(curfile);
//if after parsing file our stringsarray length greater then var "current_strings", so parsed file return some strings. Thus, we need add a comment with filename
if (stringsarray.length>current_strings) stringsarray.splice(current_strings,0,";file "+curfilepath.substring(trunkPath.length));
//do the same for crap array, add a ;file +relative path to file with crap
if (crap.length>crap_strings) crap.splice(crap_strings,0,";file "+curfilepath.substring(trunkPath.length));
//move to next file
filesenum.moveNext();
};
}
//*.RC files line-by-line parser for RC_File, return result into "array"
function ParseRCFile(FileTextVar,array) {
var find=/^(?!\/{1,2})\s*(CONTROL|(?:DEF)?PUSHBUTTON|[LRC]TEXT|(?:AUTO)?RADIOBUTTON|GROUPBOX|(?:AUTO)?CHECKBOX|CAPTION|MENUITEM|POPUP)\s*"((?:(?:""[^"]+?"")*[^"]*?)*)"\s*?(,|$|\\)/mgi;
//now make a job, till end of matching regexp
while ((string = find.exec(FileTextVar)) != null) {
// check for some garbage like "List1","Tab1" etc. in *.rc files, we do not need this.
onestring=string[2].replace(/^(((List|Tab|Tree|Spin|Custom|Slider|DateTimePicker|Radio|Check|HotKey|Progress)\d)|(whiterect|IndSndList|&?[Oo][Kk]|ICQ|Jabber|WhatsApp|OSD|Google|Miranda NG|SMS|Miranda|Windows|&\w)|(%.(.*%)?))$/g,"");
// ignore some popup menu craps
if (string[1]=="POPUP" && onestring.match(/^([a-zA-Z ]*(menu|context|popup))|([A-Z][a-z]+([A-Z][a-z]*)+)|(new item)$/g))
continue;
//if there is double "", replace with single one
onestring=onestring.replace(/\"{2}/g,"\"");
//check result. If it does not match [a-z] (no any letter in results, such as "..." or "->") it's a crap, break further actions.
if (!onestring.match(/[a-z]/i)) var onestring="";
//if still something in onestring, push to array
if (onestring) array.push("["+onestring+"]");
}
};
//Source files C++ (*.h,*.c,*.cpp) and *.pas,*.dpr,*.inc (Pascal) multiline parser for translations using LPGEN() LPGENT() TranslateT() Translate() _T() TranslateW()
function ParseSourceFile (FileTextVar,array) {
//not store ?: functions LPGEN or LPGENT? or Translate(T or W) or _T, than any unnecessary space \s, than not stored ?: "(" followed by ' or " (stored and used as \1) than \S\s - magic with multiline capture, ending with not stored ?= \1 (we get " or ' after "("), than none or few spaces \x20 followed by )/m=multiline g=global
//var find= /(?:LPGENT?|Translate[TW]?|_T)(?:\s*?\(\s*?L?\s*)(['"])([\S\s]*?)(?=\1,?\x20*?(?:tmp)?\))/mg;
//comment previous line and uncomment following line to output templates without _T() function in source files. Too many garbage from _T()..
var find= /(?:LPGEN[TW]?|Translate[TW]?)(?:\s*?\(\s*?L?\s*)((?:(?:"[^"\\]*(?:\\[\S\s][^"\\]*)*")\s*)*)(?:\s*?,?\s*?(?:tmp)?\))/gm;
//now make a job, till end of matching regexp
while ((string = find.exec(FileTextVar)) != null) {
//first, init empty var
var string;
//replace newlines and all spaces and tabs between two pairs of " or ' with the void string ("") in first [1] subregexp ([\S\s]*?), and Delphi newlines "'#13#10+" replace
onestring=string[1].replace(/["']?(?:\#13\#10)*?\\?\r*\n(?:(?:\x20|\t)*['"])?/g,"");
//trim single-line whitespaces - multi-line parsing catches whitespaces after last " in single-line case
trimedstring=onestring.replace(/[\s]*$/g,"");
//remove trailing slash from the string. This is a tree item, slash is a crap :)
noslashstring=trimedstring.replace(/\/(?=$)/g,"");
//remove first and last "
nofirstlaststring=noslashstring.slice(1, -1)
//remove escape slashes before ' and "
stringtolangpack=nofirstlaststring.replace(/\\(")/g,"$1");
///if our string still exist, and length at least one symbol
if (stringtolangpack.length>0) {
//brand new _T() crap filtering engine :)
clearstring=filter_T(stringtolangpack);
//finally put string into array including cover brackets []
if (clearstring) {array.push("["+clearstring+"]")}
};
}
};
//filter _T() function results
function filter_T(string) {
//filter for exact matched strings
var filter1=/^(&?[Oo][Kk]|ICQ|Jabber|WhatsApp|OSD|Google|Miranda NG|SMS|Miranda|Windows)$/g;
//filter string starting from following words
var filter2=/^(SOFTWARE\\|SYSTEM\\|http|ftp|UTF-|utf-|TEXT|EXE|exe|txt|css|html|dat[^a]|txt|MS\x20|CLVM|TM_|CLCB|CLSID|CLUI|HKEY_|MButton|BUTTON|WindowClass|MHeader|RichEdit|RICHEDIT|STATIC|EDIT|CList|listbox|LISTBOX|combobox|COMBOBOX|TitleB|std\w|iso-|windows-||\w\\\w|urn\:|<\?xml|<\!|h\d|\.!\.).*$/g;
//filter string ending with following words
var filter3=/^.+(001|\/value|\*!\*|=)$/g;
//filter from Kildor
var filter4=/^((d\s\w)|\[\/?(\w|url|img|size|quote|color)(=\w*)?\]?|(\\\w)|(%\w+%)|(([\w-]+\.)*\.(\w{2,4}|travel|museum|xn--\w+))|\W|\s|\d)+$/gi;
//filter from Kildor for remove filenames and paths.
var filter5=/^[\w_:%.\\\/*-]+\.\w+$/g;
//apply filters to our string
test1=filter1.test(string);
test2=filter2.test(string);
test3=filter3.test(string);
test4=filter4.test(string);
test5=filter5.test(string);
//if match (test1) first filter and NOT match other tests, thus string are good, return this string back.
//if (test1 && !test2 && !test3 && !test4 && !test5) {
if (!test1 && !test2 && !test3 && !test4 && !test5) {
return string;
} else {
//in other case, string is a garbage, put into crap array.
crap.push(string);
return;
}
};
//Parse Version.h file to get one translated string from "Description" and make a plugin template header.
function ParseVersion_h (pluginfolder,array) {
//cleanup var
var VersionFile;
//Let's try default locations of version.h file;
//Check pluginfolder root.
if (FSO.FileExists(FSO.BuildPath(pluginfolder,"version.h"))) VersionFile=FSO.BuildPath(pluginfolder,"version.h");
//Check src\include subfolder of plugin root folder
if (FSO.FileExists(FSO.BuildPath(pluginfolder,"src\\include\\version.h"))) VersionFile=FSO.BuildPath(pluginfolder,"src\\include\\version.h");
//Check .\src subfolder
if (FSO.FileExists(FSO.BuildPath(pluginfolder,"src\\version.h"))) VersionFile=FSO.BuildPath(pluginfolder,"src\\version.h");
//If we still not found version.h, return
if (!VersionFile) return;
//read file fully into var allstrings
allstrings=ReadFile(VersionFile)
//define RegExp for defines.
var filename=/(?:#define\s+_*?FILENAME\s+")(.+)(?=")/m;
var pluginname=/(?:#define\s+_*?PLUG(?:IN)?_?NAME\s+")(.+)(?=")/i;
var author=/(?:#define\s+_*?(?:PLUGIN_?)?AUTHORS?\s+")(.+)(?=")/i;
var MAJOR_VERSION=/(?:#define\s+_*?(?:MAJOR_VERSION|VER_MAJOR)\s+)(\d+)/i;
var MINOR_VERSION=/(?:#define\s+_*?(?:MINOR_VERSION|VER_MINOR)\s+)(\d+)/i;
var RELEASE_NUM=/(?:#define\s+_*?(?:RELEASE_NUM|VER_REVISION|VER_RELEASE)\s+)(\d+)/i;
var BUILD_NUM=/(?:#define\s+_*?(?:BUILD_NUM|VER_BUILD)\s+)(\d+)/i;
var VERSION_STRING=/(?:#define\s+_*?VERSION_STRING\s+")([\d\.]+)\"/i;
var description=/(?:#define\s+_*?(?:PLUGIN_|MTEXT_)?DESC(?:RIPTION|_STRING)?\s+")(.+)(?=")/i;
//exec RegExps
filename=filename.exec(allstrings);
pluginname=pluginname.exec(allstrings);
MAJOR_VERSION=MAJOR_VERSION.exec(allstrings);
MINOR_VERSION=MINOR_VERSION.exec(allstrings);
RELEASE_NUM=RELEASE_NUM.exec(allstrings);
BUILD_NUM=BUILD_NUM.exec(allstrings);
VERSION_STRING=VERSION_STRING.exec(allstrings);
author=author.exec(allstrings);
description=description.exec(allstrings);
//add a header start mark
array.push(";============================================================");
//push results of regexp vars into array
if (filename) array.push("; File: "+filename[1]); else array.push("; File: "+plugin+".dll");
if (pluginname) array.push("; Plugin: "+pluginname[1]); else array.push("; Plugin: "+plugin);
if (VERSION_STRING) array.push("; Version: "+VERSION_STRING[1]);
if (MAJOR_VERSION && !VERSION_STRING) array.push("; Version: "+MAJOR_VERSION[1]+"."+MINOR_VERSION[1]+"."+RELEASE_NUM[1]+"."+BUILD_NUM[1]);
if (!MAJOR_VERSION && !VERSION_STRING) array.push("; Version: x.x.x.x");
if (author) array.push("; Authors: "+fixHexa(author[1])); else array.push("; Authors: ");
//add a header end mark
array.push(";============================================================");
if (description) array.push("["+description[1]+"]");
}
//Replaces \x?? hex codes with their char representation
function fixHexa(string) {
return string.replace(/\\x([a-fA-F0-9]{2})" "/g,function() {
return String.fromCharCode(parseInt(arguments[1],16));
});
}
//Removes duplicates, not mine, found at http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
function eliminateDuplicates(arr) {
var i,
len=arr.length,
out=[],
obj={};
for (i=0;i