//  Clint - Source code checker for C++
//  Copyright (C) 2001  David Pashley
//
//  This program 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 2 of the License, or
//  (at your option) any later version.
//
//  This program 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 this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "input.h"
#include "config.h"

#include <algorithm>

#ifdef HAVE_SSTREAM
#include <sstream>
#else
#include <strstream>
#endif // HAVE_SSTREAM

namespace clint {
   Input * Input::m_instance = 0;

   Input * Input::instance() {
      if ( m_instance == 0 ) {
         m_instance = new Input;
      }
      return m_instance;
   }

   Input::Input() {
      m_cur_file.input = &std::cin;
      m_cur_file.file = "<stdin>";
      m_cur_file.line = 0;
      m_input_set = false;
   }

   void Input::set_input(std::string filename) {
      if (not m_input_set) {
         m_cur_file.file = filename;
         m_cur_file.input = new std::ifstream( filename.c_str() );
         m_input_set = true;
      }
   }

   const Pair Input::getline() {
      Pair temp;
      // prevent changing the input if we have started to read lines
      if (not m_input_set) {
         m_input_set = true;
      }
      std::string line;
      std::getline(*m_cur_file.input, line);
      temp.first = line;
      //line = parse_cpp(line);
      m_cur_file.line++;
      temp.second = line;
      return temp;
   }

   // Use a recursive decent parser for cpp
   std::string Input::parse_cpp(std::string line) {
      if (line[0] == '#') {
#ifdef HAVE_SSTREAM
         std::istringstream in(line);
#else
         istrstream in(line.c_str());
#endif // HAVE_SSTREAM
         in.get(); // remove '#'
         std::string command;
         while (isalnum(in.peek()) && not in.eof()){
            command+=in.get();
         }
         std::cerr << "line = \"" << line << "\" command = \"" << command << "\" ";
         if (command == std::string("include") ) {
         } else if ( command == "define" ) {
         } else if ( command == "undef" ) {
         } else if ( command == "if" ) {
         } else if ( command == "ifdef" ) {
         } else if ( command == "ifndef" ) {
         } else if ( command == "else" ) {
         } else if ( command == "elif" ) {
         } else if ( command == "endif" ) {
         } else if ( command == "line" ) {
         } else if ( command == "error" ) {
            // Should we have a message?
         } else if ( command == "warning" ) { 
            // This isn't in the C++ grammar
            // Should we have a message?
         } else if ( command == "pragma" ) {
            // Ignore this
         } else if ( command == "" ) {
            // Apparently this is valid
            // Ignore this
         } else {
            std::cerr << "Unknown preprocessor macro" << std::endl;
         }
      }
      return line;
   }

   const int Input::line() const {
      return m_cur_file.line;
   }

   const std::string Input::file() const {
      return m_cur_file.file;
   }

   bool Input::eof() const {
      return ( ( 0 == m_file_status.size() ) and m_cur_file.input->eof() );
   }

   void Input::add_include(std::string include) {
      m_includes.push_back(include);
   }

   void Input::add_define(std::string define, std::string value) {
      m_defines[define] = value;
   }

   bool Input::is_system_header() const {
      std::string directory(m_cur_file.file, 0, m_cur_file.file.rfind('/'));
      std::cerr << directory << std::endl;
      return is_header() and ( find( m_includes.begin(), m_includes.end(), directory ) != m_includes.end() );
   }

   bool Input::is_header() const {
      std::string extension(m_cur_file.file, m_cur_file.file.rfind('.') + 1, std::string::npos);
      return ( extension == "h" or extension == "hxx" or extension == "hpp" );
   }
}


syntax highlighted by Code2HTML, v. 0.9.1