#include <cctype>
#include <cstdlib>
#include "engine.h"
using namespace std;
#define DEBUG_DO_PARSING false
#define PARSE_DBL_QUO_STRING parseString(DBL_QUOTES,inDblQuotes)
#define PARSE_SIN_QUO_STRING parseString(SIN_QUOTES,inSinQuotes)
#define PARSE_BCK_QUO_STRING parseString(BCK_QUOTES,inBckQuotes)
#define PARSE_A_MARKUP_COMNT parseBigComment("<!-", "-->", inComment)
#define PARSE_PAS_MOD2_COMNT parseBigComment("(*", "*)", inComment)
#define PARSE_CLASSICC_COMNT parseBigComment("/*", "*/", inComment)
#define PARSE_HASKL_98_COMNT parseBigComment("{-", "-", inComment)
#define PARSE_HTML_TAGS parseBigComment("<", ">", inHtmTags)
#define PARSE_A_MS_ASP_COMNT parseComment("'")
#define PARSE_A_ADA_95_COMNT parseComment("--")
#define PARSE_C_INLINE_COMNT parseComment("//")
#define PARSE_UNIXHASH_COMNT parseComment("#")
#define PARSE_ASSEMBLY_COMNT parseComment(";")
#define PARSE_DBLCOLON_COMNT parseComment("::")
#define PARSE_REMINDER_COMNT \
parseComment("REM"); \
parseComment("rem")
#define PARSE_ZEROHASH_COMNT parseCharZeroComment('#')
#define PARSE_ZFORTRAN_COMNT \
parseCharZeroComment('C'); \
parseCharZeroComment('c'); \
parseCharZeroComment('*'); \
parseCharZeroComment('!')
#define PARSE_ASSEMBLY_MACRO parseVariable("%")
#define PARSE_SCALAR_VARIABL parseVariable("$")
#define PARSE_ARRAYS_VARIABL parseVariable("@")
#define PARSE_HASHED_VARIABL parseVariable("%")
#define PRE_PARSE_CODE pre_parse()
#define PARSE_PREPROCESSOR parsePreProc()
#define PARSE_LABELS parseLabel()
#define PARSE_KEYWORDS parseKeys()
#define PARSE_NUMBERS parseNum()
void Engine::init_switches() {
opt_bigtab = false;
opt_webcpp = false;
opt_hypinc = false;
opt_follow = false;
opt_number = false;
opt_extcss = false;
opt_anchor = false;
inHtmTags = false;
inDblQuotes = false;
inSinQuotes = false;
inBckQuotes = false;
inComment = false;
endComment = false;
doStrings = Yes;
doNumbers = Yes;
doKeywords = Yes;
doCaseKeys = Yes;
doSymbols = No;
doLabels = No;
doPreProc = No;
doScalars = No;
doArrays = No;
doHashes = No;
doHtmlTags = No;
doHtmComnt = No;
doHskComnt = No;
doPasComnt = No;
doBigComnt = No;
doCinComnt = No;
doUnxComnt = No;
doAsmComnt = No;
doRemComnt = No;
doAdaComnt = No;
doFtnComnt = No;
doTclComnt = No;
doAspComnt = No;
doBatComnt = No;
lncount = 1;
tabwidth = 8;
tw = "8";
IO.init_switches();
}
void Engine::setTabWidth(string width) {
tabwidth = atoi(width.data());
if(tabwidth == 0) {
tabwidth = 8;
tw = "8";
}
tw = width;
}
void Engine::pre_parse() {
int i_esc = 0;
for (int i=0; i < (int)buffer.size(); i++) {
if (buffer[i] == '&') {buffer.replace(i,1,"&");i_esc+=4;}
else
if (buffer[i] == '<') {buffer.replace(i,1, "<");i_esc+=3;}
else
if (buffer[i] == '>') {buffer.replace(i,1, ">");i_esc+=3;}
if (opt_bigtab)
if (buffer[i] == '\t') {
int j;
buffer.erase(i,1);
if((i-i_esc) % tabwidth == 0) {
for(j=0; j < tabwidth; j++) {
buffer.insert(i," ");
}
i+=tabwidth-1;
}else{
int spaces = tabwidth - ((i-i_esc) % tabwidth);
for(j=0; j < spaces; j++) {
buffer.insert(i," ");
}
i+=spaces-1;
}
}
}
}
void Engine::eraseTags(int start, int fin) {
if(fin == 0) {fin = buffer.size();}
if(fin == -1) {fin = buffer.size();}
int erase1, erase2;
int offset1, offset2;
string srchstr;
srchstr = "<font CLASS=";
offset1 = 20;
offset2 = 7;
while(buffer.find(srchstr,start) != -1 &&
buffer.find(srchstr,start) < fin) {
erase1 = buffer.find(srchstr,start);
if(erase1 != -1 && erase1 < fin) {
buffer.erase(erase1,offset1);
}
erase2 = buffer.find("</font>",start);
if(erase2 != -1 && erase2 < fin) {
buffer.erase(erase2,offset2);
}
}
inDblQuotes = false;
inSinQuotes = false;
inBckQuotes = false;
}
void Engine::makeAnchor() {
IO << "<a name=\"line" << lncount << "\"/>";
}
void Engine::makeMargin() {
string space = "";
if(lncount < 100000) {space += " ";}
if(lncount < 10000) {space += " ";}
if(lncount < 1000) {space += " ";}
if(lncount < 100) {space += " ";}
if(lncount < 10) {space += " ";}
IO << space << "<font CLASS=comment>"
<< lncount << ":</font> ";
}
bool Engine::abortParse() {
if(endComment) {return true;}
if(inDblQuotes) {return true;}
if(!doAspComnt) {
if(inSinQuotes) {return true;}
}
if(inBckQuotes) {return true;}
if(inComment) {return true;}
return false;
}
bool Engine::abortColour(int index) {
if(doHtmComnt
&& ( isInsideIt(index,"<",">")
&& isInsideIt(index,">","<") )) {return true;}
if(isInsideIt(index,"/*","*/")) {return true;}
if(isInsideIt(index,"(*","*)")) {return true;}
if(isInsideIt(index,"<!",">")) {return true;}
if(isInsideIt(index,"\"","\"")) {return true;}
if(!doAspComnt) {
if(isInsideIt(index,"'","'")) {return true;}
}
if(isInsideIt(index,"`","`")) {return true;}
return false;
}
bool Engine::isInsideIt(int index, string start, string end) {
if(buffer.find(start,0) == -1) {return false;}
int l = 0;
int r = 0;
int idx;
idx = buffer.find(end,index);
while(idx < buffer.size()) {
if(idx != -1 && buffer[idx-1] != '\\'){r++;}
idx = buffer.find(end,idx+1);
}
idx = buffer.rfind(start,index);
while(idx > 0) {
if(idx != -1 && buffer[idx-1] != '\\'){l++;}
idx = buffer.rfind(start,idx-1);
}
if(r % 2 == 1 && l % 2 == 1) {return true;}
return false;
}
bool Engine::isInsideTag(int index) {
return false;
}
bool Engine::isNotWord(int index) {
if(isalpha(buffer[index+1])) {return false;}
while(index > 0) {
if(isalpha(buffer[index])) {return false;}
if(buffer[index] == '_') {return false;}
if(buffer[index] == '#') {return false;}
if(ispunct(buffer[index]) ||
isspace(buffer[index])) {return true;}
index--;
}
return true;
}
void Engine::parsePreProc() {
if(abortParse()) {return;}
if(buffer[0] != '#') {return;}
if(opt_hypinc) {
hyperIncludeMe();
}
buffer += " ";
buffer.insert(0, "<font CLASS=preproc>");
int end;
for(int i=8;i<buffer.size();i++) {
if(isspace(buffer[i])) {end = i;i=buffer.size();}
}
buffer.insert(end, "</font>");
}
bool Engine::isSymbol(char c) {
switch(c) {
case '!':
case '|':
case '-':
case '=':
case '+': return true;
default : return false;
}
}
void Engine::parseSymbol() {
if(abortParse()) {return;}
int end;
int insert = 0;
for(int i=0; i < buffer.size(); i++) {
if(isSymbol(buffer[i])) {
end = i;
while(isSymbol(buffer[end+1])) {end++;}
if(colourSymbol(i,end)) {
insert += 27;
i = end + insert;
}
}
}
}
bool Engine::colourSymbol(int s, int f) {
if(abortColour(s)) {return false;}
if(!isNotWord(s)) {return false;}
buffer.insert(s,"<font CLASS=symbols>");
buffer.insert(f+21,"</font>");
return true;
}
void Engine::parseLabel() {
if(abortParse()) {return;}
if(buffer.find("/*") != -1) {return;}
if(buffer.find("(*") != -1) {return;}
int end, beg;
end = buffer.size()-1;
beg = buffer.rfind(" ",end);
if(beg == -1) {beg = 0;}
if(buffer[end] == ':') {
colourLabel(beg,end);
}
}
void Engine::colourLabel(int beg, int end) {
if(abortColour(beg)) {return;}
buffer.insert(beg,"<font CLASS=preproc>");
buffer.insert(end+21,"</font>");
}
void Engine::parseNum()
{
if(buffer[0] == '#') {return;}
if(abortParse()) {return;}
vector<int> nums;
vector<int> ends;
int end, insert;
for(int i=0; i < buffer.size(); i++) {
if(isdigit(buffer[i]) && !isalpha(buffer[i-1])) {
end = i;
while(isdigit(buffer[end+1]) ||
(buffer[end+1] == '.' &&
isdigit(buffer[end+2])))
{end++;}
nums.push_back(i);
ends.push_back(end);
i=end;
}
}
for(int j=0; j < (int)ends.size(); j++) {
if(j == 0) {insert = 0;}
else {insert += 27;}
if(!colourNum(nums[j]+insert, ends[j]+insert)) {
insert -= 27;
}
}
}
bool Engine::colourNum(int s, int f) {
if(abortColour(s)) {return false;}
if(!isNotWord(s)) {return false;}
string cssclass;
int fpt;
fpt = buffer.find(".",s);
if(fpt != -1 && fpt < f) {
cssclass = "<font CLASS=floatpt>";
} else
cssclass = "<font CLASS=integer>";
buffer.insert(s, cssclass);
buffer.insert(f+21, "</font>");
return true;
}
void Engine::parseString(char quotetype, bool &inside) {
if(doAdaComnt && !doRemComnt && quotetype == SIN_QUOTES) {return;}
if(doAspComnt && quotetype == SIN_QUOTES) {return;}
string quote, escap1, escap2, cssclass;
int index,offset;
index = 0;
if (quotetype == DBL_QUOTES) {
if(inSinQuotes || inBckQuotes) {return;}
quote = "\"";
if (!doAspComnt) {
escap1 = "'";
} else {
escap1 = "`";
}
escap2 = "`";
cssclass = "dblquot";
} else if(quotetype == SIN_QUOTES) {
if(inDblQuotes || inBckQuotes) {return;}
quote = "'";
escap1 = "\"";
escap2 = "`";
cssclass = "sinquot";
} else if(quotetype == BCK_QUOTES) {
if(inDblQuotes || inSinQuotes) {return;}
quote = "`";
escap1 = "\"";
escap2 = "'";
cssclass = "preproc";
}
index = buffer.find(quote,index);
if(index == -1) {return;}
while (index < string::npos) {
if(buffer[index -1] == '\\') {
if(buffer[index -2] == '\'' && buffer[index +1] == '\'') {
index = buffer.find(quote,index+1);
}
}
if(index == -1) {return;}
while(isInsideIt(index,escap1,escap1)){
index = buffer.find(quote,index +1);
if(index == -1) {return;}
}
while(isInsideIt(index,escap2,escap2)){
index = buffer.find(quote,index +1);
if(index == -1) {return;}
}
while(doHtmComnt && isInsideIt(index,">","<") ) {
index = buffer.find(quote,index +1);
if(index == -1) {return;}
}
while (buffer[index -1] == '\\' &&
(buffer[index -2] != '\\' ||
(buffer[index -3] == '\\' &&
buffer[index -4] != '\\'))) {
index = buffer.find(quote,index +1);
if(index == -1) {return;}
}
if(index != -1 && !inComment) {
colourString(index, inside, cssclass);
}
if(inside) {offset = index + 21;}
else {offset = index + 7;}
index = buffer.find(quote,offset);
if(index == -1) {return;}
if(index > buffer.size()){return;}
}
}
void Engine::colourString(int index, bool &inside, string cssclass) {
if(index > buffer.size()){return;}
string fntag = "<font CLASS=" + cssclass + ">";
if(!inside) {
buffer.insert(index, fntag);
} else {
buffer.insert(index+1, "</font>");
}
inside = !inside;
}
void Engine::parseBigComment(string start, string end, bool &inside) {
string search, escap, css;
int index,offset;
bool erase;
index = 0;
erase = true;
css = "comment";
if(inside) {search = end;}
else {search = start;}
index = buffer.find(search,index);
if(index == -1) {return;}
if(doCinComnt && start == "/*" && buffer.find("//") < index) {return;}
if(doUnxComnt && start == "/*" && buffer.find("#") < index) {return;}
if(start == "<" && end == ">" && doHtmlTags) {
if(buffer.find("<!-") == index || inHtmTags)
if(!inside)
return;
erase = false;
css = "preproc";
}
while (index < string::npos) {
if(inside) {search = end;}
else {search = start;}
index = buffer.find(search,index);
if(index == -1) {return;}
if(buffer[index -1] == '\\') {
if(buffer[index -2] == '\'' && buffer[index +1] == '\'') {
index = buffer.find(search,index+1);
}
}
if(index == -1) {return;}
if(!isInsideIt(index, "\"", "\"") &&
!isInsideIt(index, "'", "'") &&
!isInsideIt(index, "`", "`")) {
if(inside) {
index += end.size()-1;
if(buffer.find(end) == -1) {endComment = true;}
}
else if(erase)eraseTags(index,0);
colourString(index, inside, css);
}
if(inside) {
offset = index + 21;
search = end;
}
else {
offset = index + 7;
search = start;
}
index = buffer.find(search,offset);
if(index == -1) {return;}
if(index > buffer.size()){return;}
}
}
void Engine::parseKeys() {
if(buffer[0] == '#') {return;}
if(abortParse()) {return;}
int i, index, offset = 20;
string cmpkey;
for(i=0; i < (int)keys.size(); i++) {
cmpkey = keys[i];
index = noCaseFind(cmpkey,0);
while(index < buffer.size() && index != -1) {
if(isKey(index-1, (index) + keys[i].size())) {
colourKeys(index, keys[i], "keyword");
}
index = noCaseFind(cmpkey,(index+cmpkey.size()+offset));
}
}
for(i=0; i < (int)types.size(); i++) {
cmpkey = types[i];
index = noCaseFind(cmpkey,0);
while(index < buffer.size() && index != -1) {
if(isKey(index-1, (index) + types[i].size())) {
colourKeys(index, types[i], "keytype");
}
index = noCaseFind(cmpkey,(index+cmpkey.size()+offset));
}
}
}
int Engine::noCaseFind(string search, int index) {
if(doCaseKeys) {
return buffer.find(search,index);
}
if(search == "class") {
return buffer.find(search,index);
}
string tmp;
tmp = buffer;
for(int i=0; i < tmp.size(); i++) {
tmp[i] = toupper(tmp[i]);
}
for(int j=0; j < search.size(); j++) {
search[j] = toupper(search[j]);
}
return tmp.find(search,index);
}
bool Engine::isKey(int before, int after) const {
if(buffer[before] == '#') {return false;}
if(buffer[before] == '_') {return false;}
if(buffer[after] == '_') {return false;}
if(isalnum(buffer[before])) {return false;}
if(isalnum(buffer[after])) {return false;}
if(ispunct(buffer[before]) || isspace(buffer[before])) {
if(ispunct(buffer[after]) || isspace(buffer[after])) {
return true;
}
}
return true;
}
void Engine::colourKeys(int index, string key, string cssclass) {
if(abortColour(index)) {
return;
}
buffer.insert(index, "<font CLASS=" + cssclass + ">");
buffer.insert(index+key.size()+20, "</font>");
}
void Engine::parseVariable(string var) {
int index;
int test;
index = buffer.find(var,0);
test = buffer.find("#",0);
if(test != -1 && test < index) {return;}
while(index < string::npos) {
if(index != -1) {colourVariable(index);}
index = buffer.find(var,index +22);
}
}
void Engine::colourVariable(int index) {
int end = 0;
buffer.insert(index, "<font CLASS=preproc>");
int i = index+21;
while(!end && i < buffer.size()) {
if(!isalnum(buffer[i])) {
if(buffer[i] == '_') {i++;}
if(isspace(buffer[i])) {end = i;}
if(ispunct(buffer[i])) {end = i;}
if(buffer[i] == '=') {end = i;}
if(buffer[i] == ',') {end = i;}
if(buffer[i] == '{') {end = i;}
if(buffer[i] == '[') {end = i;}
if(buffer[i] == '(') {end = i;}
if(buffer[i] == '\'') {end = i;}
if(buffer[i] == '\n') {end = i;}
}
if(i == buffer.size() -1) {end = i+1;}
else i++;
}
if(buffer[end -1] == '\"') {end--;}
if(buffer[end -1] == ')') {end--;}
buffer.insert(end, "</font>");
}
void Engine::parseComment(string cmnt) {
if(inComment) {return;}
int index = buffer.find(cmnt,0);
if(index == -1) {return;}
if(cmnt == "#" && index != -1 && buffer[index -1] != '\\') {
if(index != 0) {
while(buffer[index -1] == '=' && index < string::npos) {
index = buffer.find("#",index+1);
}
}
}
if(buffer[index -1] == '$') {return;}
if(buffer[index -1] == '\\') {return;}
colourComment(index);
}
void Engine::colourComment(int index) {
if(abortColour(index)) {
return;
}
if(doCinComnt) {
if(buffer.rfind("http:",index) == index -5) {
return;
}
}
eraseTags(index,0);
buffer.insert(index, "<font CLASS=comment>");
buffer.insert(buffer.size(), "</font>");
}
void Engine::parseCharZeroComment(char zchar) {
if(buffer[0] == zchar) {colourComment(0);}
}
void Engine::doParsing() {
if(opt_anchor) {
makeAnchor();
}
if(opt_number) {
makeMargin();
}
IO.rline(buffer);
PRE_PARSE_CODE;
if(doSymbols) parseSymbol();
if(DEBUG_DO_PARSING) cerr << endl << 0 << ": buffer is: " << buffer << endl;
if(doLabels) PARSE_LABELS;
if(doStrings)
{
PARSE_DBL_QUO_STRING;
PARSE_SIN_QUO_STRING;
PARSE_BCK_QUO_STRING;
}
if(DEBUG_DO_PARSING) cerr << 1 << ": buffer is: " << buffer << endl;
if(doPreProc) PARSE_PREPROCESSOR;
if(doPasComnt) PARSE_PAS_MOD2_COMNT;
if(doHtmComnt) PARSE_A_MARKUP_COMNT;
if(doBigComnt) PARSE_CLASSICC_COMNT;
if(doHskComnt) PARSE_HASKL_98_COMNT;
if(doHtmlTags) PARSE_HTML_TAGS;
if(doKeywords) PARSE_KEYWORDS;
if(DEBUG_DO_PARSING) cerr << 2 << ": buffer is: " << buffer << endl;
if(doScalars) PARSE_SCALAR_VARIABL;
if(doArrays) PARSE_ARRAYS_VARIABL;
if(doHashes) PARSE_HASHED_VARIABL;
if(DEBUG_DO_PARSING) cerr << 3 << ": buffer is: " << buffer << endl;
if(doNumbers) PARSE_NUMBERS;
if(DEBUG_DO_PARSING) cerr << 4 << ": buffer is: " << buffer << endl;
if(doAdaComnt) {PARSE_A_ADA_95_COMNT;}
if(doAspComnt) {PARSE_A_MS_ASP_COMNT;}
if(doCinComnt) {PARSE_C_INLINE_COMNT;}
if(doUnxComnt) {PARSE_UNIXHASH_COMNT;}
if(doAsmComnt) {PARSE_ASSEMBLY_COMNT;}
if(doBatComnt) {PARSE_DBLCOLON_COMNT;}
if(doRemComnt) {PARSE_REMINDER_COMNT;}
if(doFtnComnt) {PARSE_ZFORTRAN_COMNT;}
if(doTclComnt) {PARSE_ZEROHASH_COMNT;}
if(DEBUG_DO_PARSING) cerr << 5 << ": buffer is: " << buffer << endl;
hyperTagMe();
hyperNameMe();
hyperLinkMe();
if(DEBUG_DO_PARSING) cerr << 6 << ": buffer is: " << buffer << endl;
IO << buffer << "\n";
endComment = inComment;
lncount++;
buffer = "";
}
void Engine::begHtml(string name) {
string gen;
string style;
string openht;
gen = "<!--\n\
This file was generated by Web C Plus Plus software v0.8.0\n\
Webcpp Copyright (C)2001, (C)2002, (C)2003 Jeffrey Bakker under the GNU GPL\n\
Get webcpp at http://webcpp.sf.net\n-->\n\n";
if(opt_extcss) {
Scs2.writeCSS(Scs2.getThemeName() + ".css");
style = "<link rel=\"stylesheet\" type=\"text/css\" href=\""
+ Scs2.getThemeName() + ".css\"/>\n";
} else {
style = "<style type=\"text/css\">\n\n"
+ Scs2.getCSSdata() + "</style>\n";
}
openht = "<html>\n<head>\n<title>" + name + "</title>\n"
+ style + "</head>\n<body>\n<pre>\n\n";
if(IO.isOredir()) {
IO << "Content-Type: text/html\n\n";
}
IO << gen << openht;
}
void Engine::endHtml() {
IO << "\n\n</pre>\n\n";
if(opt_webcpp) {
string made;
made = "<hr size=4>\n\
<table cellpadding=3 cellspacing=3 bgcolor=#000000><tr>\n\
<td bgcolor=#ff0000><tt><font size=+2 color=#000000>w</font></tt></td>\n\
<td bgcolor=#ffbb00><tt><font size=+2 color=#000000>e</font></tt></td>\n\
<td bgcolor=#ffff00><tt><font size=+2 color=#000000>b</font></tt></td>\n\
<td bgcolor=#00ff00><tt><font size=+2 color=#000000>c</font></tt></td>\n\
<td bgcolor=#0000ff><tt><font size=+2 color=#000000>p</font></tt></td>\n\
<td bgcolor=#bb00ff><tt><font size=+2 color=#000000>p</font></tt></td>\n\
</tr><tr><td colspan=6>\n\
<a href=\"http://webcpp.sf.net\"><center><b>\
<font color=#ffffff>web c plus plus</font></b></center>\n\
</a></td></tr>\n\
</table>";
IO << made;
}
IO << "\n\n</body>\n</html>\n";
}
void Engine::hyperTagMe() {
int index;
index = buffer.find("TagMe:",0);
if(index == -1) {return;}
if(abortColour(index)) {
return;
}
buffer.erase(index,6);
for(int i=index; i < buffer.size(); i++) {
if (buffer.substr(i,4) == "<") buffer.replace(i,4, "<");
else if (buffer.substr(i,4) == ">") buffer.replace(i,4, ">");
}
}
void Engine::hyperLinkMe() {
int index;
index = buffer.find("LinkMe:",0);
if(index == -1) {return;}
if(abortColour(index)) {
return;
}
string link;
link = buffer.substr(index+7);
buffer.erase(index, buffer.size() - index);
buffer.insert(0, "<a href=\"" + link + "\">");
buffer += "</a>";
}
void Engine::hyperNameMe() {
int index;
index = buffer.find("NameMe:",0);
if(index == -1) {return;}
if(abortColour(index)) {
return;
}
string name;
name = buffer.substr(index+7);
buffer.erase(index, buffer.size() - index);
buffer.insert(0, "<a name=\"" + name + "\">");
buffer += "</a>";
}
void Engine::hyperIncludeMe() {
int incl, insr;
incl = buffer.find("#include",0);
if(incl == -1) {return;}
insr = buffer.find("\"",incl+1);
if(insr == -1) {return;}
string cmd;
string link;
link = buffer.substr(insr);
link = link.substr(0,link.find("\"</font>"));
if(opt_follow) {
cmd = "webcpp " + link.substr(1) + " -A:k -H";
if(opt_bigtab) {
cmd += " -t";
if(tabwidth != 8) {
cmd += "=";
cmd += tw;
}
}
if(opt_webcpp) cmd += " -m";
if(opt_number) cmd += " -l";
if(opt_anchor) cmd += " -a";
if(opt_extcss) cmd += " -X";
if(Scs2.getThemeName() != "typical") {
cmd += " -c=" + Scs2.getThemeName();
}
if(Scs2.getImageFile() != "") {
cmd += " -i=" + Scs2.getImageFile();
}
cerr << "\nHyperInclude found " + link.substr(1) + "\n";
cerr << cmd << "\n";
system(cmd.data());
}
link = "<a href=" + link + ".html\">";
buffer.insert(insr, link);
buffer.insert(buffer.size(),"</a>");
}