Logo Search packages:      
Sourcecode: highlight version File versions  Download package

main.cpp

/***************************************************************************
                          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 <http://www.gnu.org/licenses/>.
*/


#include <memory>
#include <algorithm>
#include "main.h"
#include "re/Pattern.h"

#define MAX_LINE__WIDTH       80

using namespace std;

00042 void HLCmdLineApp::printVersionInfo()
{
      cout << "\n highlight version "
      << HIGHLIGHT_VERSION
      << "\n Copyright (C) 2002-2009 Andre Simon <andre.simon1 at gmx.de>"
      << "\n\n Artistic Style Classes (1.23)"
      << "\n Copyright (C) 2006-2008 by Jim Pattee <jimp03 at email.com>"
      << "\n Copyright (C) 1998-2002 by Tal Davidson"
      << "\n\n Regex library (1.09.00)"
      << "\n Copyright (C) 2003-2008 Jeffery Stuart <stuart at cs.unr.edu>"
      << "\n\n xterm 256 color matching functions"
      << "\n Copyright (C) 2006 Wolfgang Frisch <wf at frexx.de>"
      << "\n\n Argparser class"
      << "\n Copyright (C) 2006-2008 Antonio Diaz Diaz <ant_diaz at teleline.es>"
      << "\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";
}

00062 void HLCmdLineApp::printBadInstallationInfo()
{
      cerr << "highlight: Data directory not found ("<<DataDir::LSB_DATA_DIR<<")."
      " Bad installation or wrong "<< OPT_DATADIR << " parameter."
      << "\n\nCopy the highlight files into one of the directories listed "
      << "in INSTALL.\nYou may also set the data directory with "
      << OPT_DATADIR << " and " << OPT_ADDDATADIR << ".\n";
}

00071 bool HLCmdLineApp::printInstalledThemes()
{
      vector <string> 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 <<temp.substr ( 1, temp.length()- wildcard.length() ) << endl;
      }
      cout <<"\nUse name of the desired theme"
      << " with the --" OPT_STYLE " option.\n" << endl;
      return true;
}


00104 bool HLCmdLineApp::printInstalledLanguages()
{
      vector <string> 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() );
            cout << setw ( 20 ) <<setiosflags ( ios::left ) <<desc<<": "<<suffix.substr ( 1, suffix.length()- wildcard.length() ) << endl;
      }
      cout <<"\nUse name of the desired language"
      << " with the --" OPT_SYNTAX " option.\n" << endl;
      return true;
}

00137 void HLCmdLineApp::printDebugInfo ( const highlight::LanguageDefinition &lang,
                                    const string & langDefPath )
{
      cerr << "\nLoading language definition:\n" << langDefPath;
      cerr << "\n\nDescription: " << lang.getDescription();
      cerr << "\n\nSYMBOLS (followed by states):\n" << lang.getSymbolString();
      cerr << "\n\nREGEX:\n";
      highlight::RegexElement *re=NULL;
      for ( unsigned int i=0; i<lang.getRegexElements().size(); i++ )
      {
            re = lang.getRegexElements() [i];
            cerr << "State "<<re->open<<":\t"<<re->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";
}

00160 void HLCmdLineApp::printConfigInfo ( const string& configFile )
{
      cout << "\nRoot paths (modify with --" OPT_DATADIR  " and --" OPT_ADDDATADIR "):\n";
      cout << "  Data directory:         "<<dataDir.getDir() <<"\n";
      if ( !dataDir.getAdditionalDataDir().empty() )
            cout << "  User defined directory: "<<dataDir.getAdditionalDataDir() <<"\n";
      cout << "\nDefault search paths:\n";
      cout << "  Language definitions:   "<<dataDir.getLangPath ( "", true ) <<"\n";
      cout << "  Colour themes:          "<<dataDir.getThemePath ( "", true ) <<"\n";

      if ( !dataDir.getAdditionalDataDir().empty() )
      {
            cout << "\nAdditional search paths:\n";
            cout << "  Language definitions:   "<<dataDir.getAdditionalLangDefDir() <<"\n";
            cout << "  Colour themes:          "<<dataDir.getAdditionalThemeDir() <<"\n";
// cout << "  Indentation schemes:    "<<dataDir.getAdditionalIndentSchemesDir()<<"\n";
      }

      cout << "\nConfiguration paths:\n";
      cout << "  Configuration files:    "<<dataDir.getConfDir ( true ) <<"\n";
      cout << "  User configuration:     "<<configFile<<"\n";
      if ( !dataDir.getAdditionalConfDir().empty() )
      {
            cout << "\nAdditional search paths:\n";
            cout << "  Configuration files:    "<<dataDir.getAdditionalConfDir() <<"\n";
      }
      cout << endl;
#ifdef HL_DATA_DIR
      cout << "Compiler directive HL_DATA_DIR = " <<HL_DATA_DIR<< "\n";
#endif
#ifdef HL_CONFIG_DIR
      cout << "Compiler directive HL_CONFIG_DIR = " <<HL_CONFIG_DIR<< "\n";
#endif

      cout << endl;
}

string HLCmdLineApp::getFileSuffix ( const string &fileName )
{
      size_t ptPos=fileName.rfind ( "." );
      return ( ptPos == string::npos ) ? "" : fileName.substr ( ptPos+1, fileName.length() );
}

bool HLCmdLineApp::loadFileTypeConfig ( const string& name, StringMap* extMap, StringMap* shebangMap )
{
      if ( !extMap || !shebangMap ) return false;
      string confPath=dataDir.getConfDir() + name + ".conf";
      ConfigurationReader config ( confPath );
      if ( config.found() )
      {
            stringstream values;
            string paramName, paramVal;
            for ( unsigned int i=0;i<config.getParameterNames().size();i++ )
            {
                  paramName = config.getParameterNames() [i];

                  if ( paramName.find ( "ext" ) != string::npos )
                  {
                        values.str ( StringTools::change_case ( config.getParameter ( paramName ) ) );
                        paramName = StringTools::getParantheseVal ( paramName );
                        while ( values >> 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<numProgressItems ) ?"#":" " );
      }
      cout<< "] " <<setw ( 3 ) <<p<<"%, "<<count << " / " << total << "  " <<flush;
      if ( p==100 )
      {
            cout << endl;
      }
}

void HLCmdLineApp::printCurrentAction ( const string&outfilePath,
                                        int total, int count, int countWidth )
{
      cout << "Writing file "
      << setw ( countWidth ) << count
      << " of "
      << total
      << ": "
      << outfilePath
      << "\n";
}

00287 void HLCmdLineApp::printIOErrorReport ( unsigned int numberErrorFiles,
                                        vector<string> & fileList,
                                        const string &action )
{
      cerr << "highlight: Could not "
      << action
      << " file"
      << ( ( numberErrorFiles>1 ) ?"s":"" ) <<":\n";
      copy ( fileList.begin(), fileList.end(), ostream_iterator<string> ( 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 );
}


00344 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;
      }
      if ( options.showLangdefs() )
      {
            return printInstalledLanguages() ?EXIT_SUCCESS:EXIT_FAILURE;
      }

      loadFileTypeConfig ( "filetypes", &extensions, &scriptShebangs );

      const  vector <string> inFileList=options.getInputFileNames();

      if ( options.enableBatchMode() && inFileList[0].empty() )
      {
            return EXIT_FAILURE;
      }

      string themePath=dataDir.getThemePath ( options.getThemeName() );

      auto_ptr<highlight::CodeGenerator> 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() );

      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() );

      map <int,string> markedLines = options.getMarkLines();
      if ( !markedLines.empty() )
      {
            map<int, string>::iterator it;
            for ( it=markedLines.begin(); it!=markedLines.end();it++ )
            {
                  generator->addMarkedLine ( it->first, it->second );
            }
      }

      bool styleFileWanted = !options.fragmentOutput() || options.styleOutPathDefined();


      if ( !generator->initTheme ( themePath ) )
      {
            cerr << "highlight: Could not find style "
            << themePath
            << ".\n";
            return EXIT_FAILURE;
      }
      /*
        if (!options.getIndentScheme().empty()){
          string indentSchemePath =
                    dataDir.getIndentSchemesPath(options.getIndentScheme()+".indent");
          if (!generator->initIndentationScheme(indentSchemePath)){
              cerr << "highlight: Could not find indentation scheme "
                   << indentSchemePath
                   << ".\n";
             return EXIT_FAILURE;
          }
        }*/
      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

      bool initError=false, IOError=false;
      unsigned int fileCount=inFileList.size(),
                             fileCountWidth=getNumDigits ( fileCount ),
                                            i=0,
                                              numBadFormatting=0,
                                                               numBadInput=0,
                                                                           numBadOutput=0;

      vector<string> 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 "<<suffix<<".lang\n";
                        initError = true;
                        break;
                  }
                  else if ( loadRes==highlight::LOAD_FAILED )
                  {
                        // do also ignore error msg if --syntax parameter should be skipped
                        if ( !options.isSkippedExt ( suffix ) )
                        {
                              cerr << "highlight: Unknown source file extension \""
                              << suffix
                              << "\".\n";
                        }
                        if ( !options.forceOutput() )
                        {
                              initError = true;
                              break;
                        }
                  }
                  if ( options.printDebugInfo() && loadRes==highlight::LOAD_NEW )
                  {
                        printDebugInfo ( generator->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() )
      {
            bool useStdout =  options.getStyleOutFilename() =="stdout";
            string cssOutFile=outDirectory  + options.getStyleOutFilename();
            bool success=generator->printExternalStyle ( useStdout?"":cssOutFile );
            if ( !success )
            {
                  cerr << "highlight: Could not write " << cssOutFile <<".\n";
                  IOError = true;
            }
            if ( useStdout )
            {
                  return EXIT_SUCCESS;
            }
      }

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

Generated by  Doxygen 1.6.0   Back to index