Files
yallie 9fa3874800 Added the contents of the archive.
Moved the original file to the archive subfolder.
2017-11-20 16:11:42 +03:00

570 lines
16 KiB
JavaScript

//------------------------------------------------------------------------------
// <copyright file="codetohtml.js" company="Microsoft">
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
// </copyright>
//------------------------------------------------------------------------------
/* *******************************************************************************
Derived from Peter Torr's formatCodeToHtml JScript sample.
This JScript file can (theoretically) be used to format source code for any
C-like language. It was written for JScript (and can format itself very nicely!)
but should work with C# and C++.
The default behavior is that extensions .cs and .js are recognized and the
correct .ini files loaded for that language. To support another language,
copy the js_* files and rename them to <lang_extention>_*. Then modify
the files to match the correct values for the desired language.
<lang>_codetohtml.ini Contains the name of the language, the other INI files,
and the CSS file to use.
<lang>_keywords.ini Should contain language keywords.
<lang>_userdefined.ini Should contain user-defined types to special case.
<lang>_futurereserved.ini Should contain future reserved words in the language.
You can also change the files header.txt and footer.txt files to contain whatever you
want for initial and final HTML blocks.
There are two .CSS stylesheets: codeblue and codewhite. Each simply has a different
background color. Change the .CSS file name in the <lang_extention>_codetohtml.ini
file to use whichever .CSS you prefer or use the /stylesheet: command-line option.
********************************************************************************* */
import System;
import System.IO;
// Our own special characters to be replaced by <, >, and &
var sLt = "\u1000";
var sGt = "\u1001";
var sAmp = "\u1002";
var sSpanStart = sLt + "span";
var sSpanEnd = sLt + "/span" + sGt;
// List of punctuation recognised by the language.
var INI_PUNCTUATION = "punctuation";
// To-end-of-line comment character[s]
var INI_LINE_COMMENT = "line_comment";
// Multi-line comments
var INI_MULTILINE_COMMENT_START = "multiline_comment_start";
var INI_MULTILINE_COMMENT_END = "multiline_comment_end";
// The default INI file -- only useful on the command line
var INI_INI_FILE = "ini";
// file containing keywords
var INI_KEYWORD_FILE = "keywords";
// file containing user-defined keywords
var INI_USERDEFINED_FILE = "userdefined";
// file containing future reserved words
var INI_FUTURERESERVED_FILE = "futurereserved";
// file containing user-specified replacements in the output file
var INI_USERREPLACEMENTS_FILE = "replace";
// file to insert at the start of the output
var INI_HEADER_FILE = "header";
// file to append to the end of the output
var INI_FOOTER_FILE = "footer";
// Language used for the transformation
var INI_LANGUAGE = "language";
// Default extension for the output
var INI_EXTENSION = "extension";
// Is the language case-sensitive?
var INI_CASE_SENSITIVE = "case_sensitive";
// People can access the command line in their custom replacements
var INI_COMMANDLINE_ARGS = "commandline";
var g_objOptions = null;
var g_objKeywords = null;
var g_objUserDefined = null;
var g_objFutureReserved = null;
var g_objUserReplacements = null;
var g_reCodeMatcher = null;
var g_sInputFile = "";
var g_sOutputFile = "";
g_objOptions = createDefaultOptions();
if (processCommandLine())
{
processIniFile(g_objOptions[INI_INI_FILE], g_objOptions);
loadSupportFiles();
g_reCodeMatcher = createRegExp();
print("\nRunning with the following options:\n");
dumpObj(g_objOptions, " ");
print("\n");
formatCode();
}//if
function dumpObj(obj, indent)
{
for (var p in obj)
{
if (typeof obj[p] == "object")
{
print(indent + p + ": Object:")
dumpObj(obj[p], indent + " ");
} //if
else
{
print(indent + p + ": " + obj[p]);
} //else
} //for
} //dumpObj()
function processCommandLine()
{
var filesFound = 0;
var args = getCommandLineArguments();
// Start at 1 since we don't want the EXE name
for (var i = 1; i < args.length; i++)
{
var sArg = args[i];
// check for a switch
// slash ('/') character is a valid filename character on UNIX, so we can't use it as a switch
if ((sArg.charAt(0) == "-") || ((sArg.charAt(0) == "/") && Path.DirectorySeparatorChar != "/"))
{
// Option is of the form <name>:<value>
// Add it to the global options.
var iIndex = sArg.indexOf(":");
g_objOptions[sArg.substring(1, iIndex)] = sArg.substring(iIndex + 1);
} //if
// Probably a file name
else
{
switch(filesFound)
{
case 0:
// input file name
g_sInputFile = sArg;
if (System.IO.File.Exists(g_sInputFile))
{
var ext = "js"; //default
ext = System.IO.Path.GetExtension(g_sInputFile);
ext = ext.substring(1, ext.Length); //Trim the "." off the extension
g_objOptions[INI_INI_FILE] = ext + "_codetohtml.ini";
} //if
else
{
print("\n Error: invalid file name or missing file: ", g_sInputFile);
return false;
} //else
break;
case 1:
// output file name
g_sOutputFile = sArg;
break;
default:
// nothing
break;
} //switch
filesFound++;
} //else
} //for
if (filesFound == 0)
{
showUsage();
return false;
} //if
// Save the command line, if people want it
g_objOptions[INI_COMMANDLINE_ARGS] = args;
return true;
} //processCommandLine()
function formatCode()
{
var sHeader = guardedReadFile(g_objOptions[INI_HEADER_FILE]);
var sFooter = guardedReadFile(g_objOptions[INI_FOOTER_FILE]);
var sSource = guardedReadFile(g_sInputFile);
// Replace all the code with the HTML
sSource = sSource.replace(g_reCodeMatcher, ReplaceSource);
// Replace all the tabs with &nbsp;
sSource = sSource.replace(/ {4}|\t/g, sAmp + "nbsp;" + sAmp + "nbsp;"
+ sAmp + "nbsp;" + sAmp + "nbsp;")
// Replace all the newlines with <br>
sSource = sSource.replace(/\n/g, sLt + "br" + sGt + "\n");
// Patch up <, >, and &
sSource = sSource.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
sSource = sSource.replace(/\u1000/g, "<").replace(/\u1001/g, ">").replace(/\u1002/g, "&");
// Add the header and footer text
var sOutputText = sHeader + sSource + sFooter;
// Do user-specified replacements
for (var sCustom in g_objUserReplacements)
{
debugPrint("Replacing %" + sCustom + "% with eval(" + g_objUserReplacements[sCustom] + ")");
var reCustom = new RegExp("%" + sCustom + "%", "gm");
try
{
sOutputText = sOutputText.replace(reCustom, eval(g_objUserReplacements[sCustom]));
} //try
catch(e)
{
logError("Couldn't replace %" + sCustom + "% due to a run-time error");
} //catch
} //for
if (g_sOutputFile == "")
g_sOutputFile = g_sInputFile + "." + g_objOptions[INI_EXTENSION];
writeFile(g_sOutputFile, sOutputText);
} //formatCode()
// Default options for the INI file (if they aren't over-ridden in the codetohtml.ini file)
function createDefaultOptions()
{
var o = new Object();
o[INI_INI_FILE] = "codetohtml.ini";
o[INI_KEYWORD_FILE] = "keywords.ini";
o[INI_USERDEFINED_FILE] = "userdefined.ini";
o[INI_FUTURERESERVED_FILE] = "futurereserved.ini";
o[INI_USERREPLACEMENTS_FILE] = "replace.ini";
o[INI_HEADER_FILE] = "header.txt";
o[INI_FOOTER_FILE] = "footer.txt";
o[INI_PUNCTUATION] = "~!%^&*()-=+{}[\\]|<>,/?;:";
o[INI_LINE_COMMENT] = "\\/\\/";
o[INI_MULTILINE_COMMENT_START] = "\\/\\*";
o[INI_MULTILINE_COMMENT_END] = "\\*\\/";
o[INI_LANGUAGE] = "JScript";
o[INI_EXTENSION] = "html";
o[INI_CASE_SENSITIVE] = "true";
return o;
} //createDefaultOptions()
// Processes the INI file, overriding the defaults with any
// options found in the INI file
function processIniFile(sFileName, obj)
{
try
{
var sData = readFile(sFileName);
var iniEntries = sData.split(Environment.NewLine);
for (var i = 0; i < iniEntries.length; i++)
{
var sEntry = iniEntries[i];
// debugPrint("Got entry '" + sEntry + "'");
// Look for comment lines and empty lines
if ((sEntry.charAt(0) == ";") || (sEntry == ""))
{
// print("It was blank or a comment");
continue;
} //if
// add the <name>=<value> pair to the object
var iIndex = sEntry.indexOf("=");
obj[sEntry.substring(0, iIndex)] = sEntry.substring(iIndex + 1);
} //for
} //try
catch(e)
{
logError("Couldn't process the file " + sFileName);
// logError(getErrorInfo(e));
} //catch
} //processIniFile()
function loadListOfWords(sFileName)
{
try
{
var arrTmp = readFile(sFileName).split(Environment.NewLine);
var objTmp = new Object();
var bCaseSensitive = g_objOptions[INI_CASE_SENSITIVE];
// Populate the object with properties named after
// the elements of the array
for (var i in arrTmp)
{
var s = arrTmp[i];
// case-insensitive?
if (bCaseSensitive != "true")
s = s.toLowerCase();
if (s != "")
objTmp[s] = true;
} //for
return objTmp;
} //try
// Probably the file was not found
catch(e)
{
logError("Couldn't load words from the file " + sFileName);
// logError(getErrorInfo(e));
return new Object();
} //catch
} //loadListOfWords
// Load and process the support files
function loadSupportFiles()
{
g_objKeywords = loadListOfWords(g_objOptions[INI_KEYWORD_FILE]);
g_objUserDefined = loadListOfWords(g_objOptions[INI_USERDEFINED_FILE]);
g_objFutureReserved = loadListOfWords(g_objOptions[INI_FUTURERESERVED_FILE]);
g_objUserReplacements = new Object();
processIniFile(g_objOptions[INI_USERREPLACEMENTS_FILE], g_objUserReplacements);
} //loadSupportFiles()
function createRegExp()
{
// This one works, but colours the entire conditional block,
// which isn't very useful if it is large. Put it back in if you want.
// var sConditionalPattern = "\\/\\*@(?:.|\\n)*?@\\*\\/";
var sConditionalPattern = "(?:\\/\\*@\\w+|@\\w+|@\\*\\/)";
// Single-line and multi-line comments
var sCommentPattern = "(?:" + g_objOptions[INI_LINE_COMMENT] + ".*?$|" +
g_objOptions[INI_MULTILINE_COMMENT_START] + "(?:.|\\n)*?" +
g_objOptions[INI_MULTILINE_COMMENT_END] + ")";
// Regular expressions
var sRegExpPattern = "\\/.*?(?!\\\\).\\/\\w+";
// Various types of numbers
var sExponentialPattern = "(?:(?:\\d+)?\\.)?\\d+e[+-]?\\d+";
var sFloatPattern = "(?:\\d+)?\\.\\d+";
var sOctalPattern = "0\\d+";
var sHexPattern = "0x(?:\\d|[a-f])+";
var sIntPattern = "\\d+";
// Identifiers
var sIdentifierPattern = "\\b[a-z_$]\\w+?\\b";
// Strings, including those with embedded newlines and embedded quotes
var sStringPattern = "(?:\"\"|\'\'|\"(?:\\n|.)*?(?!\\\\).\"|'.*?(?!\\\\).')";
// pre-processor stuff (for our C++ friends)
var sPreProcessor = "^\\s*#.*$";
// Punctuation
var sPunctuationPattern = "[" + g_objOptions[INI_PUNCTUATION] + "]";
// All sorts of code!
var sCodePattern =
"(" + sConditionalPattern + ")|" +
"(" + sCommentPattern + ")|" +
"(" + sRegExpPattern + ")|" +
"(" + sExponentialPattern + ")|" +
"(" + sFloatPattern + ")|" +
"(" + sOctalPattern + ")|" +
"(" + sHexPattern + ")|" +
"(" + sIntPattern + ")|" +
"(" + sIdentifierPattern + ")|" +
"(" + sStringPattern + ")|" +
"(" + sPreProcessor + ")|" +
"(" + sPunctuationPattern + ")";
return new RegExp(sCodePattern, "gim");
} //createRegExp()
function ReplaceSource(match, conditional, comment, re, exp, dec, oct, hex, num, id, str, pre, punct)
{
// debugPrint("Found text '" + match + "'");
if (conditional != undefined)
{
// debugPrint("...it's a conditional comment!");
return (sSpanStart + " class=\"conditional\"" + sGt + conditional + sSpanEnd);
}
if (comment != undefined)
{
// debugPrint("...it's a comment!");
return (sSpanStart + " class=\"comment\"" + sGt + comment + sSpanEnd);
}
if (re != undefined)
{
// debugPrint("...it's a regular expression!");
return (sSpanStart + " class=\"regexp\"" + sGt + re + sSpanEnd);
}
if (id != undefined)
{
// do we need to lower-case the string for matching?
var tmpId = id;
if (g_objOptions[INI_CASE_SENSITIVE] != "true")
tmpId = tmpId.toLowerCase();
// debugPrint("...it's an identifier!");
if (tmpId in g_objKeywords)
{
// debugPrint("...it's a keyword!");
return (sSpanStart + " class=\"keyword\"" + sGt + id + sSpanEnd);
}
else if (tmpId in g_objUserDefined)
{
// debugPrint("...it's a user-defined keyword!");
return (sSpanStart + " class=\"userdefined\"" + sGt + id + sSpanEnd);
}
else if (tmpId in g_objFutureReserved)
{
// debugPrint("...it's a future reserved keyword!");
return (sSpanStart + " class=\"futurereserved\"" + sGt + id + sSpanEnd);
}
else
{
return (sSpanStart + " class=\"identifier\"" + sGt + id + sSpanEnd);
}
} //if
if (exp != undefined)
{
// debugPrint("...it's an exponential number!");
return (sSpanStart + " class=\"exponential\"" + sGt + exp + sSpanEnd);
}
if (dec != undefined)
{
// debugPrint("...it's a decimal number!");
return (sSpanStart + " class=\"decimal\"" + sGt + dec + sSpanEnd);
}
if (oct != undefined)
{
// debugPrint("...it's an octal number (bad)!");
return (sSpanStart + " class=\"octal\"" + sGt + oct + sSpanEnd);
}
if (hex != undefined)
{
// debugPrint("...it's a hex number!");
return (sSpanStart + " class=\"hexadecimal\"" + sGt + hex + sSpanEnd);
}
if (num != undefined)
{
// debugPrint("...it's a normal number!");
return (sSpanStart + " class=\"number\"" + sGt + num + sSpanEnd);
}
if (str != undefined)
{
// debugPrint("...it's a string!");
return (sSpanStart + " class=\"string\"" + sGt + str + sSpanEnd);
}
if (pre != undefined)
{
// debugPrint("...it's a pre-processor directive!");
return (sSpanStart + " class=\"preprocessor\"" + sGt + pre + sSpanEnd);
}
if (punct != undefined)
{
// debugPrint("...it's a punctuator!");
return (sSpanStart + " class=\"punctuation\"" + sGt + punct + sSpanEnd);
}
logError("Found something but don't know what is is! " + match);
return sSpanStart + " class=\"error\"" + sGt + match + sSpanEnd;
} //ReplaceSource()
function guardedReadFile(sFileName)
{
try
{
return readFile(sFileName);
} //try
catch(e)
{
logError("Couldn't open file " + sFileName);
return "";
} //catch
} //guardedReadFile()
function showUsage()
{
logError("\nUsage: codetohtml <infile> [<outfile>]\n\n\
Default for outfile is <infile>.html\n\
Requires the files 'codetohtml.ini', 'keywords.ini', 'userdefined.ini',\n\
and 'futurereserved.ini' to be present in the directory.\n");
} //showUsage()
function debugPrint(s)
{
print(s);
} //debugPrint()
function readFile(sFileName : String) : String
{
var stream : StreamReader = File.OpenText(sFileName);
var sData : String = stream.ReadToEnd();
stream.Close();
return sData;
} //readFile()
function writeFile(sFileName : String, sContents : String)
{
var stream : StreamWriter = File.CreateText(sFileName);
stream.Write(sContents);
stream.Close();
} //writeFile()
function getCommandLineArguments() : Array
{
// BUG - compiler doesn't treat COM+ arrays as JScript arrays yet.
var arrArgs : Array = new Array();
var tmp : String[] = Environment.GetCommandLineArgs();
for (var i : int = 0; i < tmp.Length; i++)
arrArgs.push(tmp[i]);
return arrArgs;
} //getCommandLineArguments()
function logError(s : String)
{
Console.Error.WriteLine(s);
} //logError
function getErrorInfo(e) : String
{
if (e instanceof Error)
return e.number + ": " + e.description;
else if (e instanceof Exception)
return e.ToString() + "\n\n" + e.Message + "\n" + e.StackTrace;
else
return String(e);
} //getErrorInfo()