Code:
//[email protected]
//Neo1
#define _WIN32_WINNT 0x0500
//For Win32 I/O function
#include <windows.h>
//For screen output
#include <iostream>
//For the output buffer
#include <sstream>
//For exceptions
#include <exception>
//To check for delimiters in keywords with ispunct(), isspace() and iscntrl()
#include <cctype>
//The functions for going through the code and coloring it
void CPP(std::stringstream &SS, DWORD &i, char ch, char *pBuffer);
void Quote(std::stringstream &SS, DWORD &i, char ch, char *pBuffer);
void Comment(std::stringstream &SS, DWORD &i, char ch, char *pBuffer);
void Character(std::stringstream &SS, DWORD &i, char ch, char *pBuffer);
int main(int argc, char* argv[])
{
//Color Codes
std::string CommentColor = "#00008B";
std::string CPPColor = "#008B00";
std::string QuoteColor = "#FF4500";
std::string CharacterColor = "#BEBEBE";
//Pointer to the raw buffer
char *pBuffer = NULL;
//Array of keywords
std::string Keywords[] = {"auto","const","double","float","int","short","struct","unsigned",
"break","continue","else","for","long","signed","switch","void",
"case","default","enum","goto","register","sizeof","typedef","volatile",
"char","do","extern","if","return","static","union","while",
"asm","dynamic_cast","namespace","reinterpret_cast","try","bool",
"explicit","new","static_cast","typeid","catch","false","operator",
"template","typename","class","friend","private","this","using",
"const_cast","inline","public","throw","virtual","delete","mutable",
"protected","true","wchar_t"};
//Calculate number of keywords
const unsigned int NumOfKeywords = ( sizeof(Keywords)/sizeof(Keywords[0]) );
//Check if the number of arguments are valid
if(argc != 2)
{
std::cout << "Invalid number of arguments, "
<< "Correct usage is: paint FILEPATH"
<< std::endl;
return 1;
}
//Open the handle for the inputfile
HANDLE hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hInputFile == INVALID_HANDLE_VALUE)
{
std::cerr << "Error " << GetLastError() << " occured." << std::endl;
return 1;
}
//Get the filesize
LARGE_INTEGER li;
if(!GetFileSizeEx(hInputFile, &li))
{
std::cerr << "Error " << GetLastError() << " occured." << std::endl;
return 1;
}
DWORD InputSize = li.QuadPart;
//Needed to avoid segfault when using Readfile() and Writefile()
DWORD lpNumberOfBytesWritten, dwBytesRead;
//Declare proper amount of memory for the buffer
try
{
pBuffer = new char[InputSize];
}
catch (std::bad_alloc&)
{
std::cerr << "Error allocating memory." << std::endl;
return 1;
}
//Declare a stringstream for the HTML code and the title
std::stringstream SS;
//Figure out what to call the new .html file
SS << argv[1] << ".html";
std::string OutputFileName = SS.str();
//Reset the stringstream and fill it with the HTML code and CSS style
SS.str("");
SS << "<html>\n<head>\n<title>" << argv[1] << "</title>\n"
<< "<style>\n"
<< "#comment {\ncolor: " << CommentColor << ";\nfont-style: italic;\n}\n"
<< "#cpp {\ncolor: " << CPPColor << ";\n}\n"
<< "#quote {\ncolor: " << QuoteColor << ";\n}\n"
<< "#character {\ncolor: " << CharacterColor << ";\n}\n"
<< "#keyword {\nfont-weight: bold;\n}\n"
<< "</style>\n"
<< "</head>\n<body>\n"
<< "<pre>\n";
//Open the handle for the outputfile
HANDLE hOutputFile = CreateFile(OutputFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if(hOutputFile == INVALID_HANDLE_VALUE)
{
std::cerr << "Error " << GetLastError() << " occured." << std::endl;
return 1;
}
//Read the inputfile into the buffer
if(!ReadFile(hInputFile, pBuffer, InputSize, &dwBytesRead, NULL))
{
std::cerr << "Error " << GetLastError() << " occured." << std::endl;
return 1;
}
//To hold the active character in the code
char ch;
//To keep track of the keywords in the code
bool IsKeyWord;
//Main parser loop, with all the loop counters
for(DWORD i = 0, j = 0, k = 0, l = 0; i < InputSize; i++)
{
//Retrieve a character from the buffer
ch = pBuffer[i];
switch(ch)
{
case '#':
CPP(SS, i, ch, pBuffer);
break;
case '"':
Quote(SS, i, ch, pBuffer);
break;
case '/':
Comment(SS, i, ch, pBuffer);
break;
case '\'':
Character(SS, i, ch, pBuffer);
break;
case '<':
//Remember to replace '<' and '>' with the appropriate HTML codes
SS << "<";
break;
case '>':
//Remember to replace '<' and '>' with the appropriate HTML codes
SS << ">";
break;
default:
//The character does not need to be color tagged if we got this far, so now we check if it is a keyword and needs to be in bold
//Loop through all the strings
for(j = 0; j < NumOfKeywords; j++)
{
//Loop through all the letters in each string
for(k = 0; k < Keywords[j].size(); k++)
{
//We assume that the current character is a keyword by default
IsKeyWord = true;
//Check if it matches the current character in the keyword string array
if(!(pBuffer[i+k] == Keywords[j][k]))
{
//If not, it ain't a keyword
IsKeyWord = false;
//Break out of the inner for-loop, and try to match it to the next word in the string-array
break;
}
}
//If we matched some letters to a keyword, we need to check if there is a delimiter after the keyword, else it ain't a keyword
if(IsKeyWord)
{
//Check the next character in the buffer
if( !( isspace(pBuffer[i+k]) || ispunct(pBuffer[i+k]) || iscntrl(pBuffer[i+k]) ) )
{
//If it's not a space, it's not a keyword
IsKeyWord = false;
}
}
//If we got this far and the bool is still TRUE, the current ch and the following characters in the buffer is a match to one of the keywords
if(IsKeyWord)
{
//Add the starting tag
SS << "<span id=\"keyword\">";
//Loop through the keyword we found, which has the length k
for(l = 0; l < k; l++)
{
//Remember to add the current ch (which was a match to the first letter in one of the keywords) before incrementing to the next char in buffer
SS << ch;
i++;
ch = pBuffer[i];
}
//Add closing tag and the ch from last iteration of the loop
SS << "</span>";
SS << ch;
//Done, break out of outer loop
break;
}
}
//If we got this far and IsKeyWord != TRUE, no keywords was matched to the buffer at this time, so we just add the character and go on
if(!IsKeyWord)
{
SS << ch;
}
break;
}
}
//Close the HTML tags
SS << "</pre>\n</body>\n</html>";
//Dump the stringstream in string, so we can put it back in the dynamical memory buffer and so that we know it's size
std::string data = SS.str();
//Empty the buffer again
delete[] pBuffer;
//Resize it to fit the new tagged code
try
{
pBuffer = new char[data.length()];
}
//Check for bad allocs
catch (std::bad_alloc&)
{
std::cerr << "Error allocating memory." << std::endl;
return 1;
}
//Empty the string into the newly resized buffer
for(DWORD i = 0; i < data.length(); i++)
{
pBuffer[i] = data[i];
}
//Output the new code from the buffer to the HTML file
if(!WriteFile(hOutputFile, pBuffer, data.length(), &lpNumberOfBytesWritten, NULL))
{
std::cerr << "Error " << GetLastError() << " occured." << std::endl;
return 1;
}
//Close handles when done
if(!CloseHandle(hInputFile) || !CloseHandle(hOutputFile))
{
std::cerr << "Error " << GetLastError() << " occured." << std::endl;
return 1;
}
//Clean up memory
delete[] pBuffer;
//Return success
return 0;
}
void CPP(std::stringstream &SS, DWORD &i, char ch, char *pBuffer)
{
//Add the starting tag
SS << "<span id=\"cpp\">" << ch;
//Start scanning buffer until a newline is encountered
while(ch != '\n')
{
i++;
ch = pBuffer[i];
//Remember to replace '<' and '>' with the appropriate HTML codes
(ch == '<')? SS << "<" : (ch == '>')? SS << ">" : SS << ch;
}
//Newline found, add the closing tag
SS << "</span>";
}
void Quote(std::stringstream &SS, DWORD &i, char ch, char *pBuffer)
{
//Add the starting tag
SS << "<span id=\"quote\">" << ch;
//Scan through the buffer until another " is encountered
do
{
i++;
ch = pBuffer[i];
//Remember to replace '<' and '>' with the appropriate HTML codes
(ch == '<')? SS << "<" : (ch == '>')? SS << ">" : SS << ch;
} while(ch != '"' || pBuffer[i-1] == '\\');
//"-found, add the closing tag
SS << "</span>";
}
void Comment(std::stringstream &SS, DWORD &i, char ch, char *pBuffer)
{
//Check the next character in the buffer to check if there is 2 consecutive slashes
if(pBuffer[i+1] == '/')
{
//Comment found, add the starting tag
SS << "<span id=\"comment\">" << ch;
//Scan through the buffer until a newline is encountered
while(ch != '\n')
{
i++;
ch = pBuffer[i];
//Remember to replace '<' and '>' with the appropriate HTML codes
(ch == '<')? SS << "<" : (ch == '>')? SS << ">" : SS << ch;
}
//Newline found, add closing tag, and return
SS << "</span>";
return;
}
//Check for a C-style comment instead
else if(pBuffer[i+1] == '*')
{
//C-style Comment found, add the starting tag
SS << "<span id=\"comment\">" << ch;
//Scan through the buffer until a closing tag is encountered
while(ch != '*')
{
while(pBuffer[i+1] != '/')
{
i++;
ch = pBuffer[i];
//Remember to replace '<' and '>' with the appropriate HTML codes
(ch == '<')? SS << "<" : (ch == '>')? SS << ">" : SS << ch;
}
}
//Closing tag found, add closing HTML-tag, and return
SS << "</span>";
return;
}
//If the next character is not a * or a star, simply add the single slash to the stringstream and continue
else { SS << ch; }
}
void Character(std::stringstream &SS, DWORD &i, char ch, char *pBuffer)
{
//Add the starting tag
SS << "<span id=\"character\">" << ch;
//Start scanning buffer until another character is encountered
do
{
i++;
ch = pBuffer[i];
//If character is an escape character, ignore it and the next character and continue
if(ch == '\\')
{
SS << '\\';
SS << pBuffer[++i];
continue;
}
//Remember to replace '<' and '>' with the appropriate HTML codes
(ch == '<')? SS << "<" : (ch == '>')? SS << ">" : SS << ch;
} while(ch != '\'');
//Character found, add the closing tag
SS << "</span>";
}
It now takes care of C-style comments aswell, and all the coloring code is in functions. Oh and it won't make the first half of a word like 'automatic' or 'intelligent' bold anymore. Also, it SHOULD handle backslashes properly now, had a couple of problems with that one, but it seems to be working now