/*************************************************************************** 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 ); }