/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
/*
	Author: Alain Gibaud
	alain.gibaud@free.fr
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <time.h>
#include <ctype.h>
using namespace std ;

bool extract_registers( ifstream& in , ofstream& out, bool xml = false) ;
bool extract_bits( ifstream& in , ofstream& out) ;
bool extract_processor( ifstream& in , ofstream& out) ;
int execute_command(const string& comm, vector<string>&  r) ;
bool locate_inc() ;
string get_path(const string & path_and_file) ;
string get_filename(const string & path_and_file) ;
string get_nakedfilename(const string &  file) ;
string extract(const string &source) ;
string extract_all(const string &dir) ;

bool decode_arg(int argc, char *argv[]) ;

// --------------------------------
int mode ; // 0 = unknown, 1 = process one file, 2 = locate, 3 = process a directory
string arg ; // file or directory name
// --------------------------------

bool decode_arg(int argc, char *argv[])
{
	int i ;
	mode = 0 ;
	arg.clear() ;
	
	for( i = 1 ; i < argc ; ++i)
	{
		if(argv[i] == string("-locate")) 
		{
			if( mode != 0) return false ;
			mode = 2 ;
		}
		else if( argv[i] == string("-all"))
		{
			if( mode != 0 || i+1 >= argc) return false ;
			arg = argv[++i] ;
			mode = 3 ;
		}
		else
		{
			if( mode != 0) return false ;
			arg = argv[i] ;
			mode = 1 ;
		}			
	}
	return true ;
}

void usage()
{
        cout << "usage: inc2h <inc_file>" << endl ;
        cout << "or     inc2h -locate" << endl ;
        cout << "or     inc2h -all <directory>" << endl ;
        exit(1) ;
}

int main(int argc, char *argv[])
{
    string status ;
    
    if( !decode_arg(argc, argv) ) usage() ;

    switch(mode)
    {
    case 0 : 
    	usage() ; 
	break ;
    
    case 1: status = extract(arg) ;
    	if( status != "")
	{
		cerr << status  << endl ;
		exit(2) ;
	}
	break ;

    case 2: status = locate_inc() ;
    	if( status != "")
	{
		cerr << status  << endl ;
		exit(2) ;
	}
	break ;
     case 3: status = extract_all(arg) ;
    	if( status != "")
	{
		cerr << status  << endl ;
		exit(2) ;
	}
	break ;
   }
        
    return 0 ;
}

bool extract_registers( ifstream& input, ofstream& out, bool xml )
{ 
    string line ;
    bool found ;
    char w1[80], w2[80],w3[80];
    int min = 0xFFFF ;

    for( found = false ; !found &&  getline(input,line,'\n')  ; )
    {
        if( line.find(";----- Register Files",0) != string::npos) found = true   ;
    }
    if( ! found ) return false ;

    out << "//\n// Register Files\n//" << endl ;

    for( found = false ;getline(input,line,'\n')  ;)
    {
        if( line.find("Bits ----",0) != string::npos) break ;
        if( sscanf(line.c_str(), "%s%s%s",  w1,w2,w3) == 3 )
        {
            if( w1[0] == ';' ) continue ;
            if( w2 == string("EQU") )
            {
                int val ;
                if( sscanf(w3,"H'%x'", &val) == 1)
		{
                    if( xml) out << "<item>" << w1 << "</item>" << endl ;
		    
		    else out << "unsigned int " << w1 << "@0x" << hex 
		                        << val << " ;" << endl ;
                    found = true ;
		    if( val < min) min = val ;
		}
            }
        }
    }
    if( found)
    {
    	out << "\n//\n// start of SFRs block\n//" << endl ;
    	out << "#pragma firstsfr 0x" << hex << min << endl ; 
    }
    return found ;
}

bool extract_bits( ifstream& input , ofstream& out )
{
    string line ;
    bool found ;
    char w1[80], w2[80],w3[80] , reg[80], c;
    

    out << "\n//\n// Bits definitions\n//" << endl ;

    for(found= false ;  getline(input,line,'\n') ; )
    {
        if( sscanf(line.c_str(), ";----- %s Bits %c", reg , &c) == 2 )
        {
            out << "\n//----- " << reg << " Bits" << endl ;
            while( getline(input,line,'\n') )
            {
                if( sscanf(line.c_str(), "%s%s%s",  w1,w2,w3) == 3 )
                {
                    if( w1[0] == ';' ) continue ;
                    if( w2 == string("EQU") )
                    {
                        int val ;
                        if( sscanf(w3,"H'%x'", &val) == 1)
                            out << "#define " << w1 << dec << " " << val<< endl ;
                        found = true ;
                    }
                }
                else
                    break ;
            }
        }
    }
    return found ;
}

bool extract_processor( ifstream& input, ofstream& out  )
{
    string line ;
    bool found ;
    char w1[80], w2[80], letter  ;
    

    for( found= false ; !found && getline(input,line,'\n') ; )
    {
        if( sscanf(line.c_str(), "%s __18%c%s",w1,&letter, w2) == 3 )
        {
		if( w1 != string("IFNDEF")) continue ;
		letter = tolower(letter) ;
		out << "#ifndef PROCESSOR" << endl ;
		out << "#define PROCESSOR" << endl ;
		out << "#define p18"<< letter << w2 << endl ;
		out << "//\n// SFR and bits definitions for p18"<< letter << w2 
			<< " device " << endl   ;
			
		time_t t ;  
		time(&t) ;
		struct tm now = *gmtime(&t) ;
		
		out << "// generated from p18" << letter << w2 << ".inc by inc2h utility " << endl ;
		out << "// Alain GIBAUD 2005, (alain.gibaud@free.fr)" << endl ;
//		out << "// (" << now.tm_year << "/" << now.tm_mon+1 <<
//		"/" << now.tm_mday << ")" << endl ; 
		found = true ;
        }
    }
    return found ;
}

int execute_command(const string& comm, vector<string>&  r)
{
    int status ;
    char t[512] ;
    FILE *f ;
    
    r.clear() ;
    f = popen((comm   + " 2>&1"  ).c_str(),"r") ;
    if( f == 0) return -1;
    
    while(fgets(t,511,f) == t)
    {
      unsigned int i = strlen(t) - 1 ;
      if(i >= 0 && t[i] == '\n') t[i] = 0 ;
    	r.push_back( string(t) );	
    }
    status = pclose(f) ;
    return status ;
}

bool locate_inc()
{
    vector<string> r ;
    string dir ;
    
    int s = execute_command("locate p18f1220.inc", r) ;
    
    if( s != 0 || r.size() == 0) return false ;
    
    
    
    for( unsigned int i = 0 ; i < r.size() ; ++i)
    {
    	if( r[i].size() != 0 && r[i][0] == '/')
	{
    		dir = get_path(r[i]) ;
        	cout << dir << endl ;
	}
    }
    
    return true ;
}


string get_path(const string & path_and_file)
{
	
	int i = path_and_file.rfind("/") ;
	return path_and_file.substr(0,i+1) ; ;
}

string get_filename(const string & path_and_file)
{
	int i = path_and_file.rfind("/") ;
	return path_and_file.substr(i+1) ; ;
}

string get_nakedfilename(const string &  file)
{
	int i =  file.rfind(".") ;
	return file.substr(0,i) ; ;
}

string extract(const string &source)
{

    string error ;
    ifstream input(source.c_str()) ;
    
    

    if( ! input.is_open())
    {
        return  "Can't open " + source ;
    }

    istream::pos_type begin = input.tellg() ;
    
    string dest = get_nakedfilename( get_filename(source))+".h" ;
    ofstream output(dest.c_str()) ;
    
    if( ! output.is_open())
    {
        return  "Can't open " + dest;
    }
    
    if( !extract_processor( input, output ))
    {
        return "Can't find processor name"   ;
    }
   
    
    input.clear() ;
    input.seekg(begin) ;
    if( !extract_registers( input, output , false))
    {
        return "Can't find register definitions"   ;
    }

    input.clear() ;
    input.seekg(begin) ;
    if( !extract_bits( input , output))
    {
        return "Can't find bit definitions"  ;
    }

    output << endl << "#endif" << endl ;
    return error ;
}

string extract_all(const string &dir)
{
    string status ;
    vector<string> r ;
     
    int s = execute_command("ls -1 "+dir+"p18f*.inc", r) ;
    
    if( s == 0 && r.size() != 0)
    {
    	for( unsigned int i = 0 ; status == "" && i < r.size() ; ++i)
	{
		cout << "Extracting : " << r[i] << endl << flush;
		status = extract(r[i]) ;
	}
    }
	
    return status ;
}
