/***************************************************************************
main.cpp - description
-------------------
begin : Die Apr 23 22:16:35 CEST 2002
copyright : (C) 2002-2009 by Andre Simon
email : andre.simon1@gmx.de
Highlight is a universal source code to HTML converter. Syntax highlighting
is formatted by Cascading Style Sheets. It's possible to easily enhance
highlight's parsing database.
***************************************************************************/
/*
This file is part of Highlight.
Highlight is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Highlight is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Highlight. If not, see .
*/
#include
#include
#include "main.h"
#include "re/Pattern.h"
#define MAX_LINE__WIDTH 80
using namespace std;
void HLCmdLineApp::printVersionInfo()
{
cout << "\n highlight version "
<< HIGHLIGHT_VERSION
<< "\n Copyright (C) 2002-2010 Andre Simon "
<< "\n\n Artistic Style Classes (1.24)"
<< "\n Copyright (C) 2006-2010 by Jim Pattee "
<< "\n Copyright (C) 1998-2002 by Tal Davidson"
<< "\n\n Regex library (1.09.00)"
<< "\n Copyright (C) 2003-2008 Jeffery Stuart "
<< "\n\n xterm 256 color matching functions"
<< "\n Copyright (C) 2006 Wolfgang Frisch "
<< "\n\n Argparser class"
<< "\n Copyright (C) 2006-2008 Antonio Diaz Diaz "
<< "\n\n This software is released under the terms of the GNU General "
<< "Public License."
<< "\n For more information about these matters, see the file named "
<< "COPYING.\n\n";
}
void HLCmdLineApp::printBadInstallationInfo()
{
cerr << "highlight: Data directory not found ("< filePaths;
string wildcard="*.style";
string directory= dataDir.getThemePath();
string searchDir = directory + wildcard;
bool directoryOK = Platform::getDirectoryEntries ( filePaths, searchDir, true );
if ( !directoryOK )
{
cerr << "highlight: Could not access directory "
<< searchDir
<< ", aborted.\n";
return false;
}
cout << "\nInstalled themes"
<< " (located in " << directory << "):\n\n";
sort ( filePaths.begin(), filePaths.end() );
string temp;
for ( unsigned int i=0;i< filePaths.size(); i++ )
{
temp = ( filePaths[i] ).substr ( directory.length() );
cout < filePaths;
string wildcard="*.lang";
string directory=dataDir.getLangPath();
string searchDir = directory + wildcard;
bool directoryOK = Platform::getDirectoryEntries ( filePaths, searchDir, true );
if ( !directoryOK )
{
cerr << "highlight: Could not access directory "
<< searchDir
<< ", aborted.\n";
return false;
}
sort ( filePaths.begin(), filePaths.end() );
string suffix, desc;
cout << "\nInstalled language definitions"
<< " (located in " << directory << "):\n\n";
for ( unsigned int i=0;i< filePaths.size(); i++ )
{
ConfigurationReader lang ( filePaths[i] );
desc = lang.getParameter ( "description" );
suffix = ( filePaths[i] ).substr ( directory.length() ) ;
suffix = suffix.substr ( 1, suffix.length()- wildcard.length() );
cout << setw ( 20 ) <second==suffix ) {
cout << ((++extCnt==1)?" ( ":" ")<first;
}
}
cout << ((extCnt)?" )":"")<open<<":\t"<rePattern->getPattern() <<"\n";
}
cerr << "\nKEYWORDS:\n";
highlight::KeywordMap::iterator it;
highlight::KeywordMap keys=lang.getKeywords();
for ( it=keys.begin(); it!=keys.end(); it++ )
{
cerr << " "<< it->first << "("<< it->second << ")";
}
cerr <<"\n\n";
}
void HLCmdLineApp::printConfigInfo ( const string& configFile )
{
cout << "\nRoot paths (modify with --" OPT_DATADIR " and --" OPT_ADDDATADIR "):\n";
cout << " Data directory: "<> paramVal )
{
extMap->insert ( make_pair ( paramVal, paramName ) );
}
values.clear();
}
else if ( paramName.find ( "shebang" ) != string::npos )
{
values.str ( config.getParameter ( paramName ) ) ;
paramName = StringTools::getParantheseVal ( paramName );
while ( values >> paramVal )
{
shebangMap->insert ( make_pair ( paramVal, paramName ) );
}
values.clear();
}
}
return true;
}
else
{
cerr << "highlight: Configuration file "<< confPath << " not found.\n";
return false;
}
}
int HLCmdLineApp::getNumDigits ( int i )
{
int res=0;
while ( i )
{
i/=10;
++res;
}
return res;
}
void HLCmdLineApp::printProgressBar ( int total, int count )
{
if ( !total ) return;
int p=100*count / total;
int numProgressItems=p/10;
cout << "\r[";
for ( int i=0;i<10;i++ )
{
cout << ( ( i & fileList,
const string &action )
{
cerr << "highlight: Could not "
<< action
<< " file"
<< ( ( numberErrorFiles>1 ) ?"s":"" ) <<":\n";
copy ( fileList.begin(), fileList.end(), ostream_iterator ( cerr, "\n" ) );
if ( fileList.size() < numberErrorFiles )
{
cerr << "... ["
<< ( numberErrorFiles - fileList.size() )
<< " of "
<< numberErrorFiles
<< " failures not shown, use --"
<< OPT_VERBOSE
<< " switch to print all failures]\n";
}
}
string HLCmdLineApp::analyzeFile ( const string& file )
{
string firstLine;
if ( !file.empty() )
{
ifstream inFile ( file.c_str() );
getline ( inFile, firstLine );
}
else
{
// This copies all the data to a new buffer, uses the data to get the
// first line, then makes cin use the new buffer that underlies the
// stringstream instance
cin_bufcopy << cin.rdbuf();
getline ( cin_bufcopy, firstLine );
cin_bufcopy.seekg ( 0, ios::beg );
cin.rdbuf ( cin_bufcopy.rdbuf() );
}
StringMap::iterator it;
for ( it=scriptShebangs.begin(); it!=scriptShebangs.end();it++ )
{
if ( Pattern::matches ( it->first, firstLine ) ) return it->second;
}
return "";
}
string HLCmdLineApp::guessFileType ( const string& suffix, const string &inputFile )
{
string lcSuffix = StringTools::change_case ( suffix );
string fileType = ( extensions.count ( lcSuffix ) ) ? extensions[lcSuffix] : lcSuffix ;
if ( !fileType.empty() ) return fileType;
return analyzeFile ( inputFile );
}
int HLCmdLineApp::run ( const int argc, const char*argv[] )
{
CmdLineOptions options ( argc, argv );
// set data directory path, where /langDefs and /themes reside
string dataDirPath = ( options.getDataDir().empty() ) ? Platform::getAppPath() :options.getDataDir();
if ( options.printVersion() )
{
printVersionInfo();
return EXIT_SUCCESS;
}
dataDir.setAdditionalDataDir ( options.getAdditionalDataDir() );
dataDir.setAdditionalConfDir ( options.getAdditionalConfDir() );
if ( ! dataDir.searchDataDir ( dataDirPath ) )
{
printBadInstallationInfo();
return EXIT_FAILURE;
}
if ( options.printHelp() )
{
Help::printHelp();
return EXIT_SUCCESS;
}
if ( options.printConfigInfo() )
{
printConfigInfo ( options.getConfigFilePath() );
return EXIT_SUCCESS;
}
if ( options.showThemes() )
{
return printInstalledThemes() ?EXIT_SUCCESS:EXIT_FAILURE;
}
//call before printInstalledLanguages!
loadFileTypeConfig ( "filetypes", &extensions, &scriptShebangs );
if ( options.showLangdefs() )
{
return printInstalledLanguages() ?EXIT_SUCCESS:EXIT_FAILURE;
}
const vector inFileList=options.getInputFileNames();
if ( options.enableBatchMode() && inFileList[0].empty() )
{
return EXIT_FAILURE;
}
string themePath=dataDir.getThemePath ( options.getThemeName() );
auto_ptr generator ( highlight::CodeGenerator::getInstance ( options.getOutputType() ) );
generator->setHTMLAttachAnchors ( options.attachLineAnchors() );
generator->setHTMLOrderedList ( options.orderedList() );
generator->setHTMLInlineCSS ( options.inlineCSS() );
generator->setHTMLEnclosePreTag ( options.enclosePreTag() );
generator->setHTMLAnchorPrefix ( options.getAnchorPrefix() );
generator->setHTMLClassName ( options.getClassName() );
generator->setLATEXReplaceQuotes ( options.replaceQuotes() );
generator->setLATEXNoShorthands ( options.disableBabelShorthands() );
generator->setLATEXPrettySymbols ( options.prettySymbols() );
generator->setRTFPageSize ( options.getPageSize() );
generator->setRTFCharStyles ( options.includeCharStyles() );
generator->setSVGSize ( options.getSVGWidth(), options.getSVGHeight() );
if (options.useCRDelimiter())
generator->setEOLDelimiter('\r');
generator->setValidateInput ( options.validateInput() );
generator->setStyleInputPath ( options.getStyleInFilename() );
generator->setStyleOutputPath ( options.getStyleOutFilename() );
generator->setIncludeStyle ( options.includeStyleDef() );
generator->setPrintLineNumbers ( options.printLineNumbers(), options.getNumberStart() );
generator->setPrintZeroes ( options.fillLineNrZeroes() );
generator->setFragmentCode ( options.fragmentOutput() );
generator->setPreformatting ( options.getWrappingStyle(),
( generator->getPrintLineNumbers() ) ?
options.getLineLength() - options.getNumberWidth() : options.getLineLength(),
options.getNumberSpaces() );
generator->setEncoding ( options.getEncoding() );
generator->setBaseFont ( options.getBaseFont() ) ;
generator->setBaseFontSize ( options.getBaseFontSize() ) ;
generator->setLineNumberWidth ( options.getNumberWidth() );
generator->setStartingNestedLang( options.getStartNestedLang());
generator->disableTrailingNL(options.disableTrailingNL());
bool styleFileWanted = !options.fragmentOutput() || options.styleOutPathDefined();
if ( !generator->initTheme ( themePath ) )
{
cerr << "highlight: Could not find style "
<< themePath
<< ".\n";
return EXIT_FAILURE;
}
if ( options.printOnlyStyle() )
{
if (!options.formatSupportsExtStyle()){
cerr << "highlight: output format supports no external styles.\n";
return EXIT_FAILURE;
}
bool useStdout = options.getStyleOutFilename() =="stdout";
string cssOutFile=options.getOutDirectory() + options.getStyleOutFilename();
bool success=generator->printExternalStyle ( useStdout?"":cssOutFile );
if ( !success )
{
cerr << "highlight: Could not write " << cssOutFile <<".\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
bool formattingEnabled = generator->initIndentationScheme ( options.getIndentScheme() );
if ( !formattingEnabled && !options.getIndentScheme().empty() )
{
cerr << "highlight: Undefined indentation scheme "
<< options.getIndentScheme()
<< ".\n";
return EXIT_FAILURE;
}
if ( !options.getTagsFile().empty() )
{
if ( !generator->initTagInformation ( options.getTagsFile() ) )
{
cerr << "highlight: Could not load ctags file "
<< options.getTagsFile()
<< ".\n";
return EXIT_FAILURE;
}
}
string outDirectory = options.getOutDirectory();
#ifndef WIN32
ifstream dirTest ( outDirectory.c_str() );
if ( !outDirectory.empty() && !options.quietMode() && !dirTest )
{
cerr << "highlight: Output directory \""
<< outDirectory
<< "\" does not exist.\n";
return EXIT_FAILURE;
}
dirTest.close();
#endif
map markedLines = options.getMarkLines();
if ( !markedLines.empty() )
{
map::iterator it;
for ( it=markedLines.begin(); it!=markedLines.end();it++ )
{
generator->addMarkedLine ( it->first, it->second );
}
}
bool initError=false, IOError=false;
unsigned int fileCount=inFileList.size(),
fileCountWidth=getNumDigits ( fileCount ),
i=0,
numBadFormatting=0,
numBadInput=0,
numBadOutput=0;
vector badFormattedFiles, badInputFiles, badOutputFiles;
string inFileName, outFilePath;
string suffix, lastSuffix;
if ( options.syntaxGiven() ) // user defined language definition, valid for all files
{
suffix = guessFileType ( options.getLanguage() );
}
while ( i < fileCount && !initError )
{
if ( !options.syntaxGiven() ) // determine file type for each file
{
suffix = guessFileType ( getFileSuffix ( inFileList[i] ), inFileList[i] );
}
if ( suffix.empty() )
{
if ( !options.enableBatchMode() )
cerr << "highlight: Undefined language definition. Use --"
<< OPT_SYNTAX << " option.\n";
if ( !options.forceOutput() )
{
initError = true;
break;
}
}
if ( suffix != lastSuffix )
{
string langDefPath=dataDir.getLangPath ( suffix+".lang" );
highlight::LoadResult loadRes= generator->loadLanguage ( langDefPath );
if ( loadRes==highlight::LOAD_FAILED_REGEX )
{
cerr << "highlight: Regex error ( "
<< generator->getLanguage().getFailedRegex()
<< " ) in "<getLanguage(), langDefPath );
}
lastSuffix = suffix;
}
string::size_type pos= ( inFileList[i] ).find_last_of ( Platform::pathSeparator );
inFileName = inFileList[i].substr ( pos+1 );
if ( options.enableBatchMode() )
{
outFilePath = outDirectory;
outFilePath += inFileName;
outFilePath += options.getOutFileSuffix();
if ( !options.quietMode() )
{
if ( options.printProgress() )
{
printProgressBar ( fileCount, i+1 );
}
else
{
printCurrentAction ( outFilePath, fileCount, i+1, fileCountWidth );
}
}
}
else
{
outFilePath = options.getSingleOutFilename();
if ( outFilePath.size() && outFilePath==options.getSingleInFilename() )
{
cerr << "highlight: Output path equals input path: \""
<< outFilePath << "\".\n";
initError = true;
break;
}
}
if ( options.useFNamesAsAnchors() )
{
generator->setHTMLAnchorPrefix ( inFileName );
}
generator->setTitle ( options.getDocumentTitle().empty() ?
inFileList[i]:options.getDocumentTitle() );
generator->setKeyWordCase ( options.getKeywordCase() );
highlight::ParseError error = generator->generateFile ( inFileList[i], outFilePath );
if ( error==highlight::BAD_INPUT )
{
if ( numBadInput++ < IO_ERROR_REPORT_LENGTH || options.printDebugInfo() )
{
badInputFiles.push_back ( inFileList[i] );
}
}
else if ( error==highlight::BAD_OUTPUT )
{
if ( numBadOutput++ < IO_ERROR_REPORT_LENGTH || options.printDebugInfo() )
{
badOutputFiles.push_back ( outFilePath );
}
}
if ( formattingEnabled && !generator->formattingIsPossible() )
{
if ( numBadFormatting++ < IO_ERROR_REPORT_LENGTH || options.printDebugInfo() )
{
badFormattedFiles.push_back ( outFilePath );
}
}
++i;
}
if ( i && !options.includeStyleDef()
&& styleFileWanted
&& options.formatSupportsExtStyle() )
{
string cssOutFile=outDirectory + options.getStyleOutFilename();
bool success=generator->printExternalStyle ( cssOutFile );
if ( !success )
{
cerr << "highlight: Could not write " << cssOutFile <<".\n";
IOError = true;
}
}
if ( i && options.printIndexFile() )
{
bool success=generator -> printIndexFile ( inFileList, outDirectory );
if ( !success )
{
cerr << "highlight: Could not write index file.\n";
IOError = true;
}
}
if ( numBadInput )
{
printIOErrorReport ( numBadInput, badInputFiles, "read input" );
IOError = true;
}
if ( numBadOutput )
{
printIOErrorReport ( numBadOutput, badOutputFiles, "write output" );
IOError = true;
}
if ( numBadFormatting )
{
printIOErrorReport ( numBadFormatting, badFormattedFiles, "reformat" );
}
return ( initError || IOError ) ? EXIT_FAILURE : EXIT_SUCCESS;
}
int main ( const int argc, const char *argv[] )
{
HLCmdLineApp app;
return app.run ( argc, argv );
}