Logo Search packages:      
Sourcecode: hitop version File versions

htmlstream.cc

#include "htmlstream.h"
#ifndef __htmlh__
  #include "html.h"
#endif
#ifndef __parammaph__
  #include "parammap.h"
#endif
#ifndef __errorh__
  #include "error.h"
#endif
#ifndef __tables_elementsh__
  #include "tables/elements.h"
#endif

#include <fstream>
#include <stack>
#include <set>

void HTMLStream::Slice(ostream& Out,string& What){
  if(What.empty()) return;
  unsigned int lastSpace=0,lineLength=0;
  bool inMarkup=false,inQuotes=false,inDoubles=false;
  unsigned int len=What.length();
  for(unsigned int i=0;i<len;++i){
    ++lineLength;
    if((lineLength>=80)&&(lastSpace>0)){
      What[lastSpace]='\n';
      lineLength=i-lastSpace;
      lastSpace=0;
    }
    char c=What[i];
    if(c=='\n' || c=='\r'){
      lastSpace=0;
      lineLength=0;
    }else if(c=='>'&&!inQuotes&&!inDoubles){
      inMarkup=false;
    }else if(c=='<'&&!inQuotes&&!inDoubles){
      inMarkup=true;
    }else if(c=='\''&&inMarkup&&!inDoubles){
      inQuotes=!inQuotes;
    }else if(c=='\"'&&inMarkup&&!inQuotes){
      inDoubles=!inDoubles;
    }else if(c==' '&&!inQuotes&&!inDoubles){
      lastSpace=i;
    }
  }  
  Out<<What<<endl;
  What.erase();
}

ostream& operator<<(ostream& out,const HTMLStream& html){
  string buffer;
  map<TokenMap::Token,int>::iterator tokenPos;
  for(HTMLStream::const_iterator cur=html.m_stream.begin();cur!=html.m_stream.end();++cur){
    if(cur->m_isMarkup){
      tokenPos=g_HTMLFlags.find(cur->Token());
      if(tokenPos==g_HTMLFlags.end()){
        buffer+=cur->Print();
      }else{
        if(tokenPos->second&Before) HTMLStream::Slice(out,buffer);
        buffer+=cur->Print();
        if(tokenPos->second&After) HTMLStream::Slice(out,buffer);
      }
    }else{
      buffer+=cur->Print();
      if(cur->m_preformat){
        out<<buffer;
        buffer.erase();
      }
    }
  }
  HTMLStream::Slice(out,buffer);
  return out;
}

istream& operator>>(istream& in,HTMLStream& what){
  bool inElement=false,inSingles=false,inDoubles=false;
  int line=1;
  char c,prev='\0';
  string buff;

  what.m_stream.clear();
  while(!in.eof()){
    in.get(c);
    if(in.eof()) break;
    if(c==10){
      ++line;
      c=' ';
    }else if((c==13)||(c==9)){
      c=' ';
    }

    if((!inElement&&(c=='<'))||(inElement&&(c=='>')&&!inSingles&&!inDoubles)){
      if(!buff.empty()&&(buff!=" ")){
        what.m_stream.push_back(HTML(what.m_FName,line,inElement,buff));
      }
      buff.erase();
      inElement=!inElement;
      prev='\0';
    }else{
      if((c=='\'')&&inElement&&!inDoubles) inSingles=!inSingles;
      if((c=='"')&&inElement&&!inSingles) inDoubles=!inDoubles;
      if((prev!=' ')||(c!=' ')) buff+=c;
      prev=c;
    }
  }
  if(inElement) Warn(e_EndedInElement);
  if(inDoubles) Warn(e_EndedInQuotes);
  if(inSingles) Warn(e_EndedInSingles);
  if(!buff.empty()&&(buff!=" ")){
    what.m_stream.push_back(HTML(what.m_FName,line,inElement,buff));
  }

  return in;
}

HTMLStream::HTMLStream():m_curVars(NULL),Recurse(0),m_debugLevel(1){
}

HTMLStream::HTMLStream(HTMLStream* parent):m_curVars(&parent->m_curVars),
  Recurse(parent->Recurse+1),m_debugLevel(parent->m_debugLevel){
  if(Recurse>16){
    Error(e_TooDeep);
  }
}

HTMLStream& HTMLStream::operator=(const HTMLStream& Original){
  //if(&Original!=this)
  m_stream=Original.m_stream;
  return *this;
}

enum StreamMark {DEF,IF,ELSEIF,ELSE,COMMENT};

void HTMLStream::Mark(){
  stack<pair<StreamMark,iterator> > parsestack;
  for(iterator Cur=m_stream.begin();Cur!=m_stream.end();++Cur){
    int token=Cur->Token();
    if(parsestack.empty()||(parsestack.top().first!=COMMENT)||
      (parsestack.top().first==COMMENT && token==TokenMap::SLASHCOMMENT)){
      switch(token){
      case TokenMap::COMMENT:
        parsestack.push(make_pair(COMMENT,Cur));
        break;
      case TokenMap::SLASHCOMMENT:
        if((parsestack.empty())||(parsestack.top().first!=COMMENT)) Error(*Cur,e_CloseNoComment);
        parsestack.top().second->m_myPair=Cur;
        parsestack.pop();
        break;
      case TokenMap::DEF1:
      case TokenMap::DEF2:
        parsestack.push(make_pair(DEF,Cur));
        break;
      case TokenMap::SLASHDEF1:
      case TokenMap::SLASHDEF2:
        if((parsestack.empty())||(parsestack.top().first!=DEF)) Error(*Cur,e_CloseNoDef);
        parsestack.top().second->m_myPair=Cur;
        parsestack.pop();
        break;
      case TokenMap::IF1:
      case TokenMap::IF2:
        parsestack.push(make_pair(IF,Cur));
        break;
      case TokenMap::ELSEIF:
        if((parsestack.empty())||((parsestack.top().first!=IF)&&(parsestack.top().first!=ELSEIF))) Error(*Cur,e_ElseIfNoIf);
        parsestack.push(make_pair(ELSEIF,Cur));
        break;
      case TokenMap::ELSE1:
      case TokenMap::ELSE2:
        if((parsestack.empty())||((parsestack.top().first!=IF)&&(parsestack.top().first!=ELSEIF))) Error(*Cur,e_ElseNoIf);
        parsestack.push(make_pair(ELSE,Cur));
        break;
      case TokenMap::SLASHIF1:
      case TokenMap::SLASHIF2:
        if(parsestack.empty()||((parsestack.top().first!=IF)
          &&(parsestack.top().first!=ELSEIF)&&(parsestack.top().first!=ELSE))){
          Error(*Cur,e_CloseNoIf);
        }else{
          iterator elseLocation=NULL;
          while(parsestack.top().first!=IF){
            parsestack.top().second->m_myPair=Cur;
            parsestack.top().second->m_myElse=elseLocation;
            elseLocation=parsestack.top().second;
            parsestack.pop();
          }
          parsestack.top().second->m_myPair=Cur;
          parsestack.top().second->m_myElse=elseLocation;
          parsestack.pop();
        }
      }
    }
  }
  iterator Cur;
  if(!parsestack.empty()){
    StreamMark mark=parsestack.top().first;
    Cur=parsestack.top().second;
    switch(mark){
      case DEF: Error(*Cur,e_DefNoClose);
      case IF: Error(*Cur,e_IfNoClose);
      case ELSEIF: Error(*Cur,e_ElseIfNoClose);
      case ELSE: Error(*Cur,e_ElseNoClose);
      case COMMENT: Error(*Cur,e_CommentNoClose);
    }
  }
}

void HTMLStream::SetVar(const string& name,const string& value,
  Vars::Scope scope){
  m_curVars.Set(name,value,scope);
}

void HTMLStream::CheckHTML()const{
  stack<pair<string,const_iterator> > parsestack;
  map<TokenMap::Token,int>::iterator pos;
  for(const_iterator Cur=m_stream.begin();Cur!=m_stream.end();++Cur){
    if(Cur->m_isMarkup){
      string TN=Cur->TagName();
      bool slash=(TN[0]=='/');
      TokenMap::Token token=Cur->Token();
      if(slash){
        TN=TN.substr(1,string::npos);
        token=TokenMap::NameToTokenNum(TN);
      }
      pos=g_HTMLFlags.find(token);
      if((pos!=g_HTMLFlags.end())&&(pos->second&Container)){
        if(slash){
          if(parsestack.empty()){
            Warn(*Cur,"WARNING: </"+TN+"> without <"+TN+">"); 
          }else{
            if(parsestack.top().first==TN){
              parsestack.pop();
            }else{
              pair<string,const_iterator> temp=parsestack.top();
              parsestack.pop();
              if((!parsestack.empty())&&(parsestack.top().first==TN)){
                Warn(*(temp.second),"WARNING: <"+temp.first+"> without </"+temp.first+">");
                parsestack.pop();
              }else{
                Warn(*Cur,"WARNING: </"+TN+"> without <"+TN+">");
                parsestack.push(temp);
              }
            }
          }
        }else{
          parsestack.push(pair<string,const_iterator>(TN,Cur));
        }
      }
    }
  }
  const_iterator Cur;
  while(!parsestack.empty()){
    string TN=parsestack.top().first;
    Cur=parsestack.top().second;
    Warn(*Cur,"WARNING: <"+TN+"> without </"+TN+">");
    parsestack.pop();
  }
}

void HTMLStream::Process(){
  Mark();
  for(iterator Cur=m_stream.begin();Cur!=m_stream.end();){
    if(Cur->m_isMarkup){
      Cur->ExpandVariables(m_curVars);
      int token=Cur->Token();
      if(m_debugLevel>=5) Debug(*Cur,Cur->Print());
      map<int,ProcFunc>::iterator entry=m_funcMap.find(token);
      if(entry!=m_funcMap.end()){
        ParamMap paramMap;
        Cur->BuildParamMap(paramMap);
        Cur=(*(entry->second))(*this,Cur,paramMap,Cur->TagName());
      }else{
        switch(Cur->FirstChar()){
        case '#':
          Cur->DropFirstChar();
          break;
        case '@':
          Warn(*Cur,"Possible mistyped command or missing library");
          break;
        }
        ++Cur;
      }
    }else{
      ++Cur;
    }
  }
  //iterator Cur=m_stream.begin();
  //while((Cur!=m_stream.end())&&((Cur->m_content=="  ")||(Cur->m_content==" "))){
  //  m_stream.erase(Cur);
  //  Cur=m_stream.begin();
  //}
}

void HTMLStream::SetContent(iterator first,iterator last){
  m_stream.clear();
  m_stream.insert(m_stream.begin(),first,last);
}

void HTMLStream::SomeVars(const HTML& cur,const ParamMap& paramMap){
  for(ParamMap::const_iterator i=paramMap.begin();i!=paramMap.end();++i){
    if(!m_curVars.Set(i->first,i->second,Vars::Local)){
      Error(cur,e_BadVarName,i->first);
    }
  }
}

void HTMLStream::RegisterCommand(const string& name, ProcFunc func) {
  string temp(name);
  m_funcMap[TokenMap::NameToTokenNum(temp)]=func;
}

void HTMLStream::UnregisterCommand(const string& name, ProcFunc func) {
  string temp(name);
  map<int,ProcFunc>::iterator entry=m_funcMap.find(TokenMap::NameToTokenNum(temp));
  if ((entry!=m_funcMap.end())&&(entry->second==func)) m_funcMap.erase(entry);
}

bool HTMLStream::m_funcMapInitialized=false;
map<int,ProcFunc> HTMLStream::m_funcMap;

Generated by  Doxygen 1.6.0   Back to index