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

codegenerator.cpp

/***************************************************************************
                          codegenerator.cpp  -  description
                             -------------------
    begin                : Die Jul 9 2002
    copyright            : (C) 2002-2008 by Andre Simon
    email                : andre.simon1@gmx.de
 ***************************************************************************/


/*
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 <climits>
#include <memory>

#include "codegenerator.h"

#include "htmlgenerator.h"
#include "xhtmlgenerator.h"
#include "rtfgenerator.h"
#include "latexgenerator.h"
#include "texgenerator.h"
#include "xmlgenerator.h"
#include "svggenerator.h"
#include "re/Matcher.h"
#include "astyle/astyle.h"
#include "astyle/ASStreamIterator.h"

#if !defined (QT)
#include "ansigenerator.h"
#include "xterm256generator.h"
#endif

using namespace std;

namespace highlight
{

      const unsigned int CodeGenerator::NUMBER_BUILTIN_STATES = 10;

00056       CodeGenerator * CodeGenerator::getInstance ( OutputType type )
      {
            CodeGenerator* generator=NULL;
            switch ( type )
            {
                  case HTML:
                        generator = new HtmlGenerator();
                        break;
                  case XHTML:
                        generator = new XHtmlGenerator();
                        break;
                  case TEX:
                        generator = new TexGenerator ();
                        break;
                  case LATEX:
                        generator = new LatexGenerator();
                        break;
                  case RTF:
                        generator = new RtfGenerator ();
                        break;
                  case XML:
                        generator = new XmlGenerator();
                        break;
                  case SVG:
                        generator = new SVGGenerator();
                        break;
#if !defined (QT)
                  case ANSI:
                        generator = new AnsiGenerator();
                        break;
                  case XTERM256:
                        generator = new Xterm256Generator();
                        break;
#endif
                  default:
                        break;
            }
            return generator;
      }

00096       CodeGenerator::CodeGenerator ( highlight::OutputType type )
                  :in ( NULL ),
                  out ( NULL ),
                  encoding ( "none" ),
                  docTitle ( "Source file" ),
                  maskWs ( false ),
                  excludeWs ( false ),
                  fragmentOutput ( false ),
                  showLineNumbers ( false ),
                  lineNumberFillZeroes ( false ),
                  lineNumber ( 0 ),
                  lineNumberOffset ( 0 ),
                  includeStyleDef ( false ),
                  lineIndex ( 0 ),
                  lineNumberWidth ( 5 ),
                  maxLineCnt ( UINT_MAX ),
                  terminatingChar ( '\0' ),
                  formatter ( NULL ),
                  formattingEnabled ( false ),
                  formattingPossible ( false ),
                  validateInput ( false ),
                  tagsEnabled ( false ),
                  keywordCase ( StringTools::CASE_UNCHANGED ),
                  outputType ( type )
      {
      }

      CodeGenerator::~CodeGenerator()
      {
            delete formatter;
      }

00128       bool CodeGenerator::initTheme ( const string& themePath )
      {
            this->themePath=themePath;
            return docStyle.load ( themePath );
      }

00134       bool CodeGenerator::hasWhiteBGColour()
      {
            StyleColour bgCol = docStyle.getBgColour();
            return bgCol.getRed ( HTML ) == "ff" && bgCol.getGreen ( HTML ) == "ff" && bgCol.getBlue ( HTML ) == "ff";
      }

00140       const string& CodeGenerator::getStyleName()
      {
            return themePath;
      }

00145       void CodeGenerator::setLineNumberWidth ( int w )
      {
            lineNumberWidth=w;
      }

00150       int CodeGenerator::getLineNumberWidth()
      {
            return lineNumberWidth;
      }

00155       void CodeGenerator::setPrintLineNumbers ( bool flag, unsigned int startCnt )
      {
            showLineNumbers=flag;
            lineNumberOffset = startCnt-1;
      }

00161       bool CodeGenerator::getPrintLineNumbers()
      {
            return showLineNumbers;
      }

00166       void CodeGenerator::setPrintZeroes ( bool flag )
      {
            lineNumberFillZeroes=flag;
      }

00171       bool CodeGenerator::getPrintZeroes()
      {
            return lineNumberFillZeroes;
      }

00176       void CodeGenerator::setIncludeStyle ( bool flag )
      {
            includeStyleDef = flag;
      }

00181       void CodeGenerator::setStyleInputPath ( const string& path )
      {
            styleInputPath = path;
      }
00185       void CodeGenerator::setStyleOutputPath ( const string& path )
      {
            styleOutputPath = path;
      }

00190       const string&  CodeGenerator::getStyleInputPath()
      {
            return styleInputPath;
      }
00194       const string&  CodeGenerator::getStyleOutputPath()
      {
            return styleOutputPath;
      }

00199       void CodeGenerator::setFragmentCode ( bool flag )
      {
            fragmentOutput=flag;
      }
00203       bool CodeGenerator::getFragmentCode()
      {
            return fragmentOutput;
      }

00208       void CodeGenerator::setValidateInput ( bool flag )
      {
            validateInput=flag;
      }
00212       bool CodeGenerator::getValidateInput()
      {
            return validateInput;
      }

00217       void CodeGenerator::setBaseFont ( const string& s )
      {
            baseFont = s;
      }

00222       void CodeGenerator::setBaseFontSize ( const string& s )
      {
            baseFontSize = s ;
      }

00227       const string CodeGenerator::getBaseFont() const
      {
            if ( !baseFont.empty() ) return baseFont;
            switch ( outputType )
            {
                  case LATEX:
                        return "ttfamily";
                        break;
                  case TEX:
                        return "tt";
                        break;
                  default:
                        return "Courier New";
            }
      }

00243       const string& CodeGenerator::getBaseFontSize()
      {
            if ( baseFontSize.empty() && outputType != LATEX && outputType != TEX )
            {
                  return docStyle.getFontSize();
            }
            else
            {
                  return baseFontSize;
            }
      }

00255       void CodeGenerator::setTitle ( const string & title )
      {
            if ( !title.empty() ) docTitle= title;
      }

00260       string CodeGenerator::getTitle()
      {
            return docTitle;
      }

00265       void CodeGenerator::setEncoding ( const string& encodingName )
      {
            encoding = encodingName;
      }

00270       bool CodeGenerator::formattingDisabled()
      {
            return !formattingEnabled;
      }

00275       void CodeGenerator::setMaxInputLineCnt ( unsigned int cnt )
      {
            maxLineCnt = cnt;
      }

00280       bool CodeGenerator::formattingIsPossible()
      {
            return formattingPossible;
      }

00285       void CodeGenerator::setPreformatting ( WrapMode lineWrappingStyle,
                                             unsigned int lineLength,
                                             int numberSpaces )
      {
            bool enableWrap = lineWrappingStyle!=WRAP_DISABLED;
            bool replaceTabs = numberSpaces > 0;

            if ( enableWrap || replaceTabs )
            {
                  preFormatter.setWrap ( enableWrap );
                  preFormatter.setWrapIndentBraces ( lineWrappingStyle==WRAP_DEFAULT );
                  preFormatter.setWrapLineLength ( lineLength );
                  preFormatter.setReplaceTabs ( replaceTabs );
                  preFormatter.setNumberSpaces ( numberSpaces );
            }
      }

00302       void CodeGenerator::setKeyWordCase ( StringTools::KeywordCase keyCase )
      {
            keywordCase = keyCase;
      }

00307       void CodeGenerator::addMarkedLine ( int lineNo, string& helpTxt )
      {
            markLines[lineNo] = helpTxt;
      }

00312       const LanguageDefinition &CodeGenerator::getLanguage()
      {
            return langInfo;
      }

00317       void CodeGenerator::reset()
      {
            lineIndex = 0;
            lineNumber = 0;
            line.clear();
            preFormatter.reset();
            inFile.clear();
            outFile.clear();
      }

      /** sucht vorwaerts ab Position searchPos Ziffer in s und liefert Integerwert
      der gefundenen Zahl zurueck.
      Im SymbolString stehen die den einzelnen Symbolen zugeordneten Konstanten
      immer HINTER diesen Symbolen*/
00331       State CodeGenerator::getState ( const string &s, unsigned int searchPos )
      {
            string::size_type pos = s.find_first_of ( "1234567890", searchPos+1 );
            if ( pos==string::npos ) return _UNKNOWN;

            string::size_type pos2 = s.find ( ' ', pos );
            int result=_UNKNOWN;
            StringTools::str2num<int> ( result, s.substr ( pos, pos2-pos ), std::dec );
            return ( State ) result;
      }

00342       unsigned int CodeGenerator::getLineNumber()
      {
            return lineNumber;
      }

00347       bool CodeGenerator::readNewLine ( string &newLine )
      {

            bool eof;
            if ( lineIndex ) terminatingChar=newLine[lineIndex-1];
            if ( formattingPossible && formattingEnabled )
            {
                  eof=!formatter->hasMoreLines();
                  if ( !eof )
                  {
                        newLine = formatter->nextLine();
                  }
            }
            // reformatting not enabled
            else
            {
#ifdef __APPLE__
                  eof = ! getline ( *in, newLine, '\r' ); // MacOS
#else
                  eof = ! getline ( *in, newLine );        // other OS
#endif
            }

            return eof || ( lineNumber == maxLineCnt );
      }



00375       void CodeGenerator::matchRegex ( const string &line )
      {

            regexGroups.clear();
            int matchBegin=0;
            int matchLen=0;
            int groupID=0;
            // cycle through all regex, save the start and ending indices to report them later
            for ( unsigned int i=0; i<langInfo.getRegexElements().size(); i++ )
            {
                  RegexElement *regexElem = langInfo.getRegexElements() [i];
                  auto_ptr<Matcher> matcher ( regexElem->rePattern->createMatcher ( line ) );
                  while ( matcher->findNextMatch() )
                  {
                        groupID = ( regexElem->capturingGroup<0 ) ? matcher->getGroupNum()-1 : regexElem->capturingGroup;
                        matchBegin =  matcher->getStartingIndex ( groupID );
                        if ( matchBegin<0 ) continue;
                        matchLen = matcher->getEndingIndex ( groupID ) - matchBegin;
                        /*
                                    std::cerr << "\nmatchBegin="<<1+ matchBegin
                                              << " matchLen old" << ( matcher->getGroup(matcher->getGroupNum()-1).size())
                                              << " matchLen new" << matchLen<<" group: "<<(matcher->getGroup(matcher->getGroupNum()-1))
                                              << " group id= "<<regexElem->groupID<<"\n";
                        */
                        regexGroups.insert (
                            make_pair ( matchBegin+1, ReGroup ( regexElem->open, matchLen, regexElem->kwClass ) ) );
                  }
            }
      }

00405       unsigned char CodeGenerator::getInputChar()
      {
            bool eol = lineIndex == line.length();

            if ( eol )
            {
                  bool eof=false;
                  if ( preFormatter.isEnabled() )
                  {
                        if ( !preFormatter.hasMoreLines() )
                        {
                              eof=readNewLine ( line );
                              preFormatter.setLine ( line );
                        }
                        line = preFormatter.getNextLine();
                  }
                  else
                  {
                        eof=readNewLine ( line );
                  }
                  lineIndex=0;
                  ++lineNumber;
                  line=StringTools::trimRight ( line );
                  matchRegex ( line );

                  return ( eof ) ?'\0':'\n';
            }

            return line[lineIndex++];
      }

00436       State CodeGenerator::getCurrentState ()
      {

            unsigned char c='\0';

            if ( token.length() ==0 )
            {
                  c=getInputChar();
            }
            else
            {
                  lineIndex-= ( token.length()-1 );
                  c=token[0];
            }
            if ( c=='\n' )
            {
                  return _EOL;   // End of line
            }

            if ( c=='\0' )
            {
                  return _EOF;   // End of file
            }

//  if (iswspace(c)) {
            if ( c==' ' || c=='\t' )
            {
                  token= c;
                  return _WS;
            }

            /** TODO
                COMMENT ... END 2 eintraege in langdef (ML_COMMENT_START=regex(), ML_COMMENT_END=regex())
                weil comment sonst als identifier erkannt wird
            */

            // Test if a regular expression was found at the current position
            if ( !regexGroups.empty() )
            {
                  if ( regexGroups.count ( lineIndex ) )
                  {
                        token = line.substr ( lineIndex-1, regexGroups[lineIndex].length );
                        unsigned int oldIndex= lineIndex;
                        if ( regexGroups[oldIndex].length>1 ) lineIndex+= regexGroups[lineIndex].length-1;

                        if ( regexGroups[oldIndex].state==IDENTIFIER_BEGIN || regexGroups[oldIndex].state==KEYWORD )
                        {
                              string reservedWord= ( langInfo.isIgnoreCase() ) ? StringTools::change_case ( token ) :token;
                              currentKeywordClass=langInfo.isKeyword ( reservedWord );
                              if ( !currentKeywordClass && regexGroups[oldIndex].state==KEYWORD )
                                    currentKeywordClass = regexGroups[oldIndex].kwClass;
                              return ( currentKeywordClass ) ? KEYWORD : STANDARD;
                        }
                        else
                        {
                              return regexGroups[oldIndex].state;
                        }
                  }
            }

            unsigned int symbolLength;
            size_t symbolPos;
            size_t symbolFind;
            string symbols=langInfo.getSymbolString();

            //TODO this while loop kills performance - adjust search algorithm

            symbolPos = symbols.find ( c );
            // search symbols (comment delimiters, directives etc.)
            // before keywords, because alphabetic chars may be part of symbols, too
            while ( symbolPos!= string::npos )
            {
                  symbolFind = symbols.find ( ' ', symbolPos );
                  if ( symbolFind==string::npos ) break;
                  symbolLength=symbolFind-symbolPos;
                  token = symbols.substr ( symbolPos, symbolLength );
                  // Abfrage nach Leerzeichen in SymbolString verhindert falsches
                  // Erkennen von Symbolteilen:
                  if ( lineIndex && token == line.substr ( lineIndex-1, symbolLength )
                          && symbols[symbolPos-1]==' ' )
                  {
                        lineIndex += ( symbolLength-1 );
                        return getState ( symbols, symbolPos );
                  }
                  else
                  {
                        symbolPos = symbols.find_first_not_of ( ' ',symbols.find ( ' ',symbolPos ) );
                  }
            }

            // Character not referring to any state
            token = c;
            return STANDARD;
      }

//it is faster to pass ostream reference
00532       void CodeGenerator::maskString ( ostream& ss, const string & s )
      {
            for ( unsigned int i=0;i< s.length();i++ )
            {
                  ss << maskCharacter ( s[i] );
            }
      }

00540       void CodeGenerator::printMaskedToken ( bool addMetaInfo, bool flushWhiteSpace,
                                             StringTools::KeywordCase tcase )
      {
            if ( flushWhiteSpace ) flushWs();

            if ( addMetaInfo && tagsEnabled )
            {
                  bool insertMetaInfo=metaInfo.tagExists ( token );
                  if ( insertMetaInfo ) *out<<getMetaInfoOpenTag ( metaInfo.getTagInfo ( token ) );
                  maskString ( *out, StringTools::change_case ( token, tcase ) );
                  if ( insertMetaInfo ) *out<<getMetaInfoCloseTag();
            }
            else
            {
                  maskString ( *out, StringTools::change_case ( token, tcase ) );
            }
            token.clear();
      }

00559       bool CodeGenerator::styleFound()
      {
            return docStyle.found();
      }

00564       bool CodeGenerator::printIndexFile ( const vector<string> &fileList,
                                           const string &outPath )
      {
            return true;
      }

00570       bool CodeGenerator::initIndentationScheme ( const string &indentScheme )
      {

            if ( formatter!=NULL )
            {
                  return true;
            }

            if ( !indentScheme.size() ) return false;

            formatter=new astyle::ASFormatter();

            if ( indentScheme=="allman" || indentScheme=="bsd" || indentScheme=="ansi" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_ALLMAN );
            }
            else if ( indentScheme=="kr"||indentScheme=="k&r"||indentScheme=="k/r" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_KandR );
            }
            else if ( indentScheme=="java" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_JAVA );
            }
            else if ( indentScheme=="stroustrup" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_STROUSTRUP );
            }
            else if ( indentScheme=="whitesmith" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_WHITESMITH );
            }
            else if ( indentScheme=="banner" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_BANNER );
            }
            else if ( indentScheme=="gnu" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_GNU );
            }
            else if ( indentScheme=="linux" )
            {
                  formatter->setFormattingStyle ( astyle::STYLE_LINUX );
            }
            else
            {
                  return false;
            }

            return formattingEnabled=true;
      }

00622       LoadResult CodeGenerator::loadLanguage ( const string& langDefPath )
      {
            bool reloadNecessary= langInfo.needsReload ( langDefPath );
            if ( reloadNecessary )
            {

                  if ( !langInfo.load ( langDefPath ) )
                  {
                        return langInfo.getFailedRegex().size() ? LOAD_FAILED_REGEX : LOAD_FAILED;
                  }

                  formattingPossible=langInfo.enableReformatting();

                  if ( styleTagOpen.size() >NUMBER_BUILTIN_STATES )
                  {
                        // remove dynamic keyword tag delimiters of the old language definition
                        vector<string>::iterator keyStyleOpenBegin =
                            styleTagOpen.begin() + NUMBER_BUILTIN_STATES;
                        vector<string>::iterator keyStyleCloseBegin =
                            styleTagClose.begin() + NUMBER_BUILTIN_STATES;
                        styleTagOpen.erase ( keyStyleOpenBegin, styleTagOpen.end() );
                        styleTagClose.erase ( keyStyleCloseBegin, styleTagClose.end() );
                  }
                  // add new keyword tag delimiters
                  for ( unsigned int i=0;i< langInfo.getKeywordClasses().size(); i++ )
                  {
                        styleTagOpen.push_back ( getMatchingOpenTag ( i ) );
                        styleTagClose.push_back ( getMatchingCloseTag ( i ) );
                  }
            }
            return ( reloadNecessary ) ? LOAD_NEW : LOAD_NONE;
      }


00656       bool CodeGenerator::initTagInformation ( const string& ctagsPath )
      {
            if ( tagsEnabled ) return true; // load tag info once
            tagsEnabled = metaInfo.load ( ctagsPath );
            return tagsEnabled;
      }

00663       bool CodeGenerator::validateInputStream()
      {
            if ( !in ) return false;

            // it is not possible to move stream pointer back with stdin
            if ( ( int ) in->tellg() == -1 ) // -1 : stdin
                  return true;

            // Sources: http://en.wikipedia.org/wiki/Magic_number_(programming)
            // Magic configuration of "file"
            // This is intended for web plugins - only check filetypes often found in the net
            char magic_gif[]    = {'G','I','F','8', 0};
            char magic_png[]    = {0x89,'P','N','G', 0};
            char magic_java[]   = {0xCA,0xFE,0xBA,0xBE, 0};
            char magic_jpeg[]   = {0xFF,0xD8,0xFF, 0};
            char magic_bmp[]    = {'B','M', 0};
            char magic_pdf[]    = {'%','P','D','F', 0};
            char magic_utf8[]   = {0xEF,0xBB,0xBF,0};
            char magic_rar[]    = {'R','a','r','!', 0};
            char magic_zip[]    = {'P','K',0x03,0x04, 0};
            char magic_ace[]    = {'*','*','A','C','E','*','*', 0};
            char magic_tgz[]    = {0x8b,0x1f, 0x00, 0x08, 0};
            char magic_bzip[]   = {'B','Z', 0};

            char* magic_table[] = {magic_utf8,
                                   magic_gif, magic_png, magic_jpeg, magic_bmp, magic_pdf,
                                   magic_java,
                                   magic_rar, magic_zip, magic_ace, magic_tgz, magic_bzip,
                                   0
                                  };

            char buffer [10]={0};
            in->read ( buffer,8 );  //only read the first 8 bytes of input stream

            int magic_index=0;
            while ( magic_table[magic_index] )
            {
                  if ( !strncmp ( buffer, magic_table[magic_index], strlen ( magic_table[magic_index] ) ) )
                  {
                        break;
                  }
                  magic_index++;
            }
            int streamReadPos=0;
            if ( magic_table[magic_index] == magic_utf8 )
            {
                  //setEncoding("utf-8");
                  streamReadPos=3; // remove UTF-8 magic number from output
            }

            in -> seekg ( streamReadPos, ios::beg );
            in-> clear();  // clear fail bit to continue reading

            return !magic_table[magic_index] // points to 0 if no pattern was found
                   || magic_table[magic_index] == magic_utf8;
      }



00722       ParseError CodeGenerator::generateFile ( const string &inFileName,
              const string &outFileName )
      {
            if ( !docStyle.found() )
            {
                  return BAD_STYLE;
            }

            reset();

            ParseError error=PARSE_OK;

            inFile=inFileName;
            outFile=outFileName;
            in = ( inFileName.empty() ? &cin :new ifstream ( inFileName.c_str() ) );

            if ( validateInput )
                  if ( !validateInputStream() ) error= BAD_INPUT;

            if ( !in->fail() && error==PARSE_OK )
            {
                  out = ( outFileName.empty() ? &cout :new ofstream ( outFileName.c_str() ) );
                  if ( out->fail() )
                  {
                        error=BAD_OUTPUT;
                  }
            }

            if ( in->fail() )
            {
                  error=BAD_INPUT;
            }

            if ( error==PARSE_OK )
            {
                  if ( formatter != NULL )
                  {
                        formatter->init ( new astyle::ASStreamIterator ( in ) );
                  }
                  if ( ! fragmentOutput )
                  {
                        *out << getHeader();
                  }

                  printBody();

                  if ( ! fragmentOutput )
                  {
                        *out << getFooter();
                  }
            }

            if ( !outFileName.empty() )
            {
                  delete out; out=NULL;
            }
            if ( !inFileName.empty() )
            {
                  delete in; in=NULL;
            }
            return error;
      }

00785       string CodeGenerator::generateString ( const string &input )
      {

            if ( !docStyle.found() )
            {
                  return "";
            }

            reset();

            in = new istringstream ( input );
            out = new ostringstream ();

            if ( in->fail() || out->fail() )
            {
                  return "";
            }

            if ( formatter != NULL )
            {
                  formatter->init ( new astyle::ASStreamIterator ( in ) );
            }
            if ( ! fragmentOutput )
            {
                  *out << getHeader();
            }

            printBody();

            if ( ! fragmentOutput )
            {
                  *out << getFooter();
            }

            string result = static_cast<ostringstream*> ( out )->str();

            delete out; out=NULL;
            delete in; in=NULL;

            return result;
      }


00828       string CodeGenerator::generateStringFromFile ( const string &inFileName )
      {

            if ( !docStyle.found() )
            {
                  return "";
            }

            reset();

            inFile = inFileName;
            in = new ifstream ( inFileName.c_str() );
            out = new ostringstream ();

            if ( in->fail() || out->fail() )
            {
                  return "";
            }

            if ( validateInput && !validateInputStream() )
            {
                  return "ERROR: detected binary input";
            }

            if ( formatter != NULL )
            {
                  formatter->init ( new astyle::ASStreamIterator ( in ) );
            }
            if ( ! fragmentOutput )
            {
                  *out << getHeader();
            }

            printBody();

            if ( ! fragmentOutput )
            {
                  *out << getFooter();
            }

            string result = static_cast<ostringstream*> ( out )->str();

            delete out; out=NULL;
            delete in; in=NULL;

            return result;
      }

00876       unsigned int CodeGenerator::getStyleID ( State s, unsigned int kwClassID )
      {
            if ( s==KEYWORD && kwClassID )
            {
                  return NUMBER_BUILTIN_STATES + kwClassID-1;
            }
            return ( unsigned int ) s ;
      }

00885       void CodeGenerator::openTag ( State s )
      {
            *out << styleTagOpen[ ( unsigned int ) s];
            currentState=s;
      }

00891       void CodeGenerator::closeTag ( State s )
      {
            *out << styleTagClose[ ( unsigned int ) s];
            flushWs();
            currentState=_UNKNOWN;
      }

00898       void CodeGenerator::openKWTag ( unsigned int kwClassID )
      {
            *out << styleTagOpen[getStyleID ( KEYWORD, kwClassID ) ];
            currentState=KEYWORD;
      }

00904       void CodeGenerator::closeKWTag ( unsigned int kwClassID )
      {
            *out << styleTagClose[getStyleID ( KEYWORD, kwClassID ) ];
            flushWs();
            currentState=_UNKNOWN;
      }


///////////////////////////////////////////////////////////////////////////////

00914       void CodeGenerator::processRootState()
      {

            bool eof=false,
                     firstLine=true; // avoid newline before printing the first output line

            if ( langInfo.highlightingDisabled() )
            {
                  string line;
                  while ( getline ( *in, line ) )
                  {
                        ++lineNumber;
                        insertLineNumber ( !firstLine );
                        flushWs();
                        firstLine=false;
                        maskString ( *out, line );
                  }
                  *out << flush;
                  return;
            }

            State state=STANDARD;

            openTag ( STANDARD );
            do
            {
                  // determine next state
                  state= getCurrentState();

                  // handle current state
                  switch ( state )
                  {
                        case KEYWORD:
                              closeTag ( STANDARD );
                              eof=processKeywordState ( state );
                              openTag ( STANDARD );
                              break;
                        case NUMBER:
                              closeTag ( STANDARD );
                              eof=processNumberState();
                              openTag ( STANDARD );
                              break;
                        case ML_COMMENT:
                              closeTag ( STANDARD );
                              eof=processMultiLineCommentState();
                              openTag ( STANDARD );
                              break;
                        case SL_COMMENT:
                              closeTag ( STANDARD );
                              eof=processSingleLineCommentState();
                              openTag ( STANDARD );
                              break;
                        case STRING:
                              closeTag ( STANDARD );
                              eof=processStringState ( STANDARD );
                              openTag ( STANDARD );
                              break;
                        case DIRECTIVE:
                              closeTag ( STANDARD );
                              eof=processDirectiveState();
                              openTag ( STANDARD );
                              break;
                        case ESC_CHAR:
                              if ( langInfo.allowExtEscSeq() )
                              {
                                    closeTag ( STANDARD );
                                    eof=processEscapeCharState();
                                    openTag ( STANDARD );
                              }
                              else
                              {
                                    printMaskedToken();
                              }
                              break;
                        case SYMBOL:
                              closeTag ( STANDARD );
                              eof=processSymbolState();
                              openTag ( STANDARD );
                              break;
                        case _EOL:
                              insertLineNumber ( !firstLine );
                              firstLine=false;
                              break;
                        case _EOF:
                              eof=true;
                              break;
                        case _WS:
                              processWsState();
                              break;
                        default:
                              printMaskedToken ( true );
                              break;
                  }
            }
            while ( !eof );
            closeTag ( STANDARD );
            *out << getNewLine();
            *out << flush;
      }

01014       bool CodeGenerator::processKeywordState ( State myState )
      {
            State newState=STANDARD;
            unsigned int myClassID=currentKeywordClass;
            bool eof=false,
                     exitState=false;

            openKWTag ( myClassID );
            do
            {
                  printMaskedToken ( true, newState!=_WS,
                                     ( langInfo.isIgnoreCase() ) ? keywordCase : StringTools::CASE_UNCHANGED );
                  newState= getCurrentState();
                  switch ( newState )
                  {
                        case _WS:
                              processWsState();
                              break;
                        case _EOL:
                              insertLineNumber();
                              exitState=true;
                              break;
                        case _EOF:
                              eof = true;
                              break;
                        case KEYWORD_END:
                              exitState=true;
                              break;
                        default:
                              exitState= ( myClassID!=currentKeywordClass ) || ( myState!=newState );
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeKWTag ( myClassID );

            currentKeywordClass=0;
            return eof;
      }

01055       bool CodeGenerator::processNumberState()
      {
            State newState=STANDARD;
            bool eof=false,
                     exitState=false;
            openTag ( NUMBER );
            do
            {
                  printMaskedToken ( false, newState!=_WS );
                  newState= getCurrentState();
                  switch ( newState )
                  {
                        case _WS:
                              processWsState();
                              break;
                        case _EOL:
                              insertLineNumber();
                              exitState=true;
                              break;
                        case _EOF:
                              eof = true;
                              break;
                        default:
                              exitState=newState!=NUMBER;
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeTag ( NUMBER );
            return eof;
      }

01088       bool CodeGenerator::processMultiLineCommentState()
      {
            int commentCount=1;
            int delimPairID = langInfo.getDelimiterPairID ( token );
            State newState=STANDARD;
            bool eof=false, exitState=false;
            openTag ( ML_COMMENT );
            do
            {
                  printMaskedToken ( false, newState!=_WS );
                  newState= getCurrentState();

                  switch ( newState )
                  {
                        case _WS:
                              processWsState();
                              break;
                        case _EOL:
                              wsBuffer += styleTagClose[ML_COMMENT];
                              insertLineNumber();
                              wsBuffer += styleTagOpen[ML_COMMENT];
                              break;
                        case _EOF:
                              eof = true;
                              break;
                        case ML_COMMENT:
                              if ( langInfo.allowNestedMLComments() )
                              {
                                    ++commentCount;
                                    // SmallTalk-Fix: if multiline comment delims are equal,
                                    // end comment when the same delimiter is read again and
                                    // nested comments are not allowed
                                    //break;
                              }
                              // if delimiters are equal, close the comment by continueing to
                              // ML_COMMENT_END section
                              if ( langInfo.delimiterIsDistinct ( ML_COMMENT ) )  break;

                        case ML_COMMENT_END:
                              if ( delimPairID!=langInfo.getDelimiterPairID ( token ) ) break;
                              commentCount--;
                              if ( !commentCount )
                              {
                                    printMaskedToken();
                                    exitState=true;
                              }
                              break;
                        default:
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeTag ( ML_COMMENT );
            return eof;
      }

01145       bool CodeGenerator::processSingleLineCommentState()
      {

            if ( checkSpecialCmd() )
            {
                  return in->bad(); // if input stream is bad, report eof to calling method
            }

            State newState=STANDARD;
            bool eof=false, exitState=false;

            openTag ( SL_COMMENT );
            do
            {
                  printMaskedToken ( false, newState!=_WS );
                  newState= getCurrentState();

                  switch ( newState )
                  {
                        case _WS:
                              processWsState();
                              break;
                        case _EOL:
                              printMaskedToken();
                              if ( preFormatter.isEnabled() && preFormatter.isWrappedLine ( lineNumber-1 ) )
                              {
                                    exitState=false;
                              }
                              else
                              {
                                    exitState=true;
                              }
                              if ( !exitState ) wsBuffer += styleTagClose[SL_COMMENT];
                              insertLineNumber();
                              if ( !exitState ) wsBuffer += styleTagOpen[SL_COMMENT];

                              break;
                        case _EOF:
                              eof = true;
                              break;
                        default:
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeTag ( SL_COMMENT );
            return eof;
      }

01195       bool CodeGenerator::processDirectiveState()
      {
            State  newState=STANDARD;
            bool eof=false, exitState=false;

            openTag ( DIRECTIVE );
            do
            {
                  printMaskedToken ( false, newState!=_WS );
                  newState= getCurrentState();
                  switch ( newState )
                  {
                        case _WS:
                              processWsState();
                              break;
                        case DIRECTIVE_END:
                              printMaskedToken();
                              exitState=true;
                              break;
                        case _EOL:
                              printMaskedToken();
                              if ( preFormatter.isEnabled() && preFormatter.isWrappedLine ( lineNumber-1 ) )
                              {
                                    exitState=false;
                              }
                              else
                              {
                                    exitState= ( terminatingChar!=langInfo.getContinuationChar() );
                              }
                              if ( !exitState ) wsBuffer += styleTagClose[DIRECTIVE];
                              insertLineNumber();
                              if ( !exitState ) wsBuffer += styleTagOpen[DIRECTIVE];
                              break;
                        case ML_COMMENT:
                              closeTag ( DIRECTIVE );
                              eof= processMultiLineCommentState();
                              openTag ( DIRECTIVE );
                              break;
                        case SL_COMMENT:
                              closeTag ( DIRECTIVE );
                              eof= processSingleLineCommentState();
                              openTag ( DIRECTIVE );
                              exitState=true;
                              break;
                        case STRING:
                              closeTag ( DIRECTIVE );
                              eof=processStringState ( DIRECTIVE );
                              openTag ( DIRECTIVE );
                              break;
                        case _EOF:
                              eof = true;
                              break;
                        default:
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeTag ( DIRECTIVE );
            return eof;
      }

01257       bool CodeGenerator::processStringState ( State oldState )
      {
            State newState=STANDARD;
            bool eof=false, exitState=false;
            bool returnedFromOtherState=false;
            // Test if character before string open delimiter token equals to the
            // raw string prefix (Example: r" ", r""" """ in Python)
            bool isRawString=false;
            if ( lineIndex>token.length() )
            {
                  isRawString = line[lineIndex-token.length()-1]==langInfo.getRawStringPrefix();
            }
            int delimPairID = langInfo.getDelimiterPairID ( token );
            State myState= ( oldState==DIRECTIVE ) ? DIRECTIVE_STRING : STRING;
            openTag ( myState );
            do
            {
                  // true if last token was an escape char
                  if ( !returnedFromOtherState )
                  {
                        printMaskedToken ( false, newState!=_WS );
                  }
                  returnedFromOtherState=false;
                  newState= getCurrentState();

                  switch ( newState )
                  {
                        case _WS:
                              processWsState();
                              break;
                        case _EOL:
                              wsBuffer += styleTagClose[myState];
                              insertLineNumber();
                              wsBuffer += styleTagOpen[myState];
                              break;
                        case STRING_END:
                              exitState= true;
                              printMaskedToken();
                              break;
                        case STRING:
                              // if there exist multiple string delimiters, close string if
                              // current delimiters is equal to the opening delimiter
                              exitState = ( delimPairID==langInfo.getDelimiterPairID ( token ) );
                              printMaskedToken();
                              break;
                        case ESC_CHAR:
                              if ( !isRawString )
                              {
                                    closeTag ( myState );
                                    eof=processEscapeCharState();
                                    openTag ( myState );
                                    returnedFromOtherState=true;
                              }
                              break;
                        case _EOF:
                              eof = true;
                              break;
                        default:
                              printMaskedToken();
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeTag ( myState );
            return eof;
      }

01325       bool CodeGenerator::processSymbolState()
      {

            State newState=STANDARD;
            bool eof=false,
                     exitState=false;

            openTag ( SYMBOL );
            do
            {
                  printMaskedToken ( false, newState!=_WS );
                  newState= getCurrentState();
                  switch ( newState )
                  {
                        case _WS:
                              processWsState();
                              break;
                        case _EOL:
                              insertLineNumber();
                              exitState=true;
                              break;
                        case _EOF:
                              eof = true;
                              break;
                        default:
                              exitState=newState!=SYMBOL;
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeTag ( SYMBOL );
            return eof;
      }

01360       bool CodeGenerator::processEscapeCharState()
      {
            State newState=STANDARD;
            bool eof=false, exitState=false;
            openTag ( ESC_CHAR );
            do
            {
                  printMaskedToken ( false, newState!=_WS );
                  newState= getCurrentState();
                  switch ( newState )
                  {
                        case _EOL:
                              insertLineNumber();
                              exitState=true;
                              break;
                        case _WS:
                              processWsState();
                              break;
                        case _EOF:
                              eof = true;
                              break;
                        default:
                              exitState=newState!=ESC_CHAR;
                              break;
                  }
            }
            while ( ( !exitState ) && ( !eof ) );

            closeTag ( ESC_CHAR );
            return eof;
      }

01392       void CodeGenerator::processWsState()
      {
            if ( !maskWs )
            {
                  wsBuffer += token;
                  token.clear();
                  return;
            }
            flushWs();
            int cntWs=0;
            lineIndex--;

            // while (iswspace(line[lineIndex])  ) {
            while ( line[lineIndex]==' ' || line[lineIndex]=='\t' )
            {
                  ++cntWs;
                  ++lineIndex;
            }

            if ( cntWs>1 )
            {
                  unsigned int styleID=getStyleID ( currentState, currentKeywordClass );
                  if ( excludeWs && styleID!=_UNKNOWN )
                  {
                        *out << styleTagClose[styleID];
                  }
                  *out << maskWsBegin;
                  for ( int i=0; i<cntWs; i++ )
                  {
                        *out << spacer;
                  }
                  *out << maskWsEnd;
                  if ( excludeWs && styleID!=_UNKNOWN )
                  {
                        *out << styleTagOpen[styleID];
                  }
            }
            else
            {
                  *out << spacer; //Bugfix fehlender Space nach Strings
            }
            token.clear();
      }

01436       void CodeGenerator::flushWs()
      {
            *out<<wsBuffer;
            wsBuffer.clear();
      }

01442       string CodeGenerator::getNewLine()
      {
            return newLineTag;
      }

01447       void CodeGenerator::insertLineNumber ( bool insertNewLine )
      {

            if ( insertNewLine )
            {
                  wsBuffer += getNewLine();
            }

            if ( showLineNumbers )
            {
                  ostringstream os;
                  ostringstream numberPrefix;
                  if ( lineNumberFillZeroes )
                  {
                        os.fill ( '0' );
                  }
                  os <<setw ( getLineNumberWidth() ) << right << lineNumber+lineNumberOffset;

                  numberPrefix << styleTagOpen[LINENUMBER];
                  maskString ( numberPrefix, os.str() );
                  numberPrefix << spacer
                  << styleTagClose[LINENUMBER];

                  wsBuffer += numberPrefix.str();
            }
      }

01474       unsigned int CodeGenerator::getLineIndex()
      {
            return lineIndex;
      }

01479       bool CodeGenerator::printExternalStyle ( const string &outFile )
      {
            if ( !includeStyleDef && langInfo.getSyntaxHighlight() )
            {
                  ostream *cssOutFile = ( outFile.empty() ? &cout :new ofstream ( outFile.c_str() ) );
                  if ( !cssOutFile->fail() )
                  {
                        *cssOutFile << styleCommentOpen
                        <<" Style definition file generated by highlight "
                        << HIGHLIGHT_VERSION << ", " << HIGHLIGHT_URL
                        << " " << styleCommentClose << "\n";
                        *cssOutFile << "\n" << styleCommentOpen
                        << " Highlighting theme definition: "
                        << styleCommentClose << "\n\n"
                        << getStyleDefinition()
                        << "\n";
                        *cssOutFile << readUserStyleDef();
                        if ( !outFile.empty() ) delete cssOutFile;
                  }
                  else
                  {
                        return false;
                  }
            }
            return true;
      }

01506       string CodeGenerator::readUserStyleDef()
      {
            ostringstream ostr;
            if ( !styleInputPath.empty() )
            {
                  ifstream userStyleDef ( styleInputPath.c_str() );
                  if ( userStyleDef )
                  {
                        ostr << "\n" << styleCommentOpen
                        << " Content of " << styleInputPath
                        << ": " <<styleCommentClose << "\n";
                        string line;
                        while ( getline ( userStyleDef, line ) )
                        {
                              ostr << line << "\n";
                        }
                        userStyleDef.close();
                  }
                  else
                  {
                        ostr << styleCommentOpen
                        << " ERROR: Could not include " << styleInputPath
                        << "." << styleCommentClose << "\n";
                  }
            }
            return ostr.str();
      }


01535       bool CodeGenerator::checkSpecialCmd()
      {

            //cerr << "token: "<<token<< " index"<< lineIndex << " "<<line [ lineIndex ]<<  "sizes: "<<token.size()<<"=="<<line.size()<<endl;
            string noParseCmd="@highlight";
            // if single line comment is described with regex, token is equal to line
            // otherwise start searching after the token, which then consists of comment identifier
            size_t searchStart= ( token.size() ==line.size() ) ? 0 : lineIndex;
            size_t cmdPos = line.find ( noParseCmd, searchStart );
            size_t pos=1;
            if ( cmdPos!=string::npos )
            {
                  string res;
                  string replaceVar;

                  auto_ptr<Pattern> reDefPattern ( Pattern::compile ( "\\$[-\\w]+" ) );
                  auto_ptr<Matcher> m ( reDefPattern->createMatcher ( line.substr ( noParseCmd.size() +cmdPos ) ) );
                  while ( m.get() &&  m->findNextMatch() )
                  {
                        res+=line.substr ( noParseCmd.size() +cmdPos + pos ,
                                           m->getStartingIndex ( 0 )-pos );
                        replaceVar = m->getGroup ( 0 );
                        if ( replaceVar=="$nl" )
                        {
                              res+="\n";
                        }
                        else if ( replaceVar=="$infile" )
                        {
                              res+= ( inFile.size() ) ? inFile: "stdin";
                        }
                        else if ( replaceVar=="$outfile" )
                        {
                              res+= ( outFile.size() ) ? outFile: "stdout";
                        }
                        else if ( replaceVar=="$title" )
                        {
                              res+= docTitle;
                        }
                        else if ( replaceVar=="$theme"||replaceVar=="$style" )
                        {
                              res+= getStyleName();
                        }/*
          else if (replaceVar=="$style-infile") {
             res+= getStyleInputPath();
          }
          else if (replaceVar=="$style-outfile") {
             res+= getStyleOutputPath();
          }*/
                        else if ( replaceVar=="$font-face" )
                        {
                              res+= getBaseFont();
                        }
                        else if ( replaceVar=="$font-size" )
                        {
                              res+= getBaseFontSize();
                        }
                        else if ( replaceVar=="$encoding" )
                        {
                              res+= encoding;
                        }
                        else if ( replaceVar=="$linenum" )
                        {
                              char numBuf[10];
                              snprintf ( numBuf, sizeof ( numBuf ), "%d", lineNumber );
                              res+= string ( numBuf );
                        }
                        pos=m->getEndingIndex ( 0 );
                  }
                  res+=line.substr ( noParseCmd.size() +cmdPos + pos );

                  *out<<res;

                  // hide comment line from output
                  token.clear();
                  lineIndex=line.length();
                  getInputChar();
                  lineNumber--;
                  // end hide

                  return true; // do not parse line as comment
            }

            return false; //parse comment as usual
      }

}

Generated by  Doxygen 1.6.0   Back to index