/**************************************************************************
 * FILE : sue_general_netlister.cpp
 * 
 * AUTHOR : Mike Perrott
 * 
 * DESCRIPTION : creates Hspice and CppSim netlists from SUE files.
 ************************************************************************/

/**************************************************************************
Copyright (c) 2004 Michael H Perrott
All rights reserved.


Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the
above copyright notice and the following two paragraphs appear in
all copies of this software.

IN NO EVENT SHALL MICHAEL H PERROTT BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF MICHAEL H
PERROTT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

MICHAEL H PERROTT SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THE SOFTWARE PROVIDED
HEREUNDER IS ON AN "AS IS" BASIS, AND MICHAEL H PERROTT HAS NO
OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
**************************************************************************/

#include "sue2_common_code.h"

void determine_simruns_directory(char *simruns_dir_name);
void extract_sue_library_name(char *sue_file_name, char *sue_library_name);
void extract_cadencelib_dir_name(char *sue_file_name, char *cppsim_library_name);
MODULE *mark_active_modules(MODULE *first_module, char *top_module_name);
void determine_active_modules(MODULE *first_module, char *top_sue_module_name,
                              char *control_string);
void create_archive_directory(char *simruns_base_dir_name,
	    char *suelib_base_dir_name, char *cadencelib_base_dir_name);
void recursively_delete_directory(char *cur_dir_name);
void copy_ascii_file(char *infile_name, char *outfile_name);
void copy_file(char *infile_name, char *outfile_name);
void recursively_copy_directory(char *cur_dir_name, char *cur_archive_dir_name);

main(int argc,char *argv[])
{
char top_sue_module_name[MAX_CHAR_LENGTH];
char netlist_filename[MAX_CHAR_LENGTH];
PARAMETER *param_list;
MODULE *first_module, *top_module, *cur_module;
DIR *dir;
FILE *fp;
int i;

char simruns_dir_name[MAX_CHAR_LENGTH];
char cadencelib_dir_name[MAX_CHAR_LENGTH];
char cur_file_name[MAX_CHAR_LENGTH];
char archive_simruns_base_dir_name[MAX_CHAR_LENGTH];
char archive_suelib_base_dir_name[MAX_CHAR_LENGTH];
char archive_cadencelib_base_dir_name[MAX_CHAR_LENGTH];
char cur_archive_dir_name[MAX_CHAR_LENGTH];
char cur_archive_file_name[MAX_CHAR_LENGTH];
char cur_dir_name[MAX_CHAR_LENGTH];
char cur_base_dir_name[MAX_CHAR_LENGTH];

if (argc < 4)
  {
   printf("error: need three arguments!\n");
   printf("  archive_cppsim_library sue_top_module sue_lib_file all/single\n");
   exit(1);
  }

strcpy(top_sue_module_name,argv[1]);


param_list = init_parameter();

//// extract modules
first_module = extract_sue_modules(argv[2],param_list);
// print_keyinfo_modules(first_module); exit(1);
warn_about_duplicate_modules(first_module);

//// process modules
connect_sue_instances_to_modules(first_module);
trim_node_naming_instances_from_modules(first_module);
first_module = trim_node_naming_modules(first_module);

//print_keyinfo_modules(first_module);

determine_active_modules(first_module, top_sue_module_name, argv[3]);

create_archive_directory(archive_simruns_base_dir_name,
       archive_suelib_base_dir_name, archive_cadencelib_base_dir_name);

determine_simruns_directory(simruns_dir_name);
cur_module = first_module;
while (cur_module != NULL)
   {
    if (cur_module->active_sue_module_flag == 1)
       {
       // copy SueLib files
       sprintf(cur_archive_dir_name,"%s/%s",
		archive_suelib_base_dir_name,cur_module->library_path);
       if ((dir = opendir(cur_archive_dir_name)) == NULL) 
          {
           if (makedir(cur_archive_dir_name) != 0)
              {
               printf("error in 'main':\n");
               printf("     cannot create archive subdirectory:\n");
               printf("     '%s'\n",cur_archive_dir_name);
               exit(1);
              }
	  }
       else
	   closedir(dir);

       sprintf(cur_archive_file_name,"%s/%s.sue",
	       cur_archive_dir_name,cur_module->name);
       copy_file(cur_module->full_filename,cur_archive_file_name);

       // copy CadenceLib files
       extract_cadencelib_dir_name(cur_module->full_filename,cur_base_dir_name);
       
       if ((dir = opendir(cur_base_dir_name)) == NULL) 
          {
	    printf("error in 'main':  can't open CadenceLib directory:\n");
            printf("   '%s'\n",cur_base_dir_name);
            exit(1);
	  }
       else
	   closedir(dir);

       if ((dir = opendir(archive_cadencelib_base_dir_name)) == NULL) 
          {
	    printf("error in 'main':  can't open archive directory for CadenceLib directory:\n");
            printf("   '%s'\n",archive_cadencelib_base_dir_name);
            exit(1);
	  }
       else
	   closedir(dir);

       sprintf(cur_dir_name,"%s/%s",cur_base_dir_name,
                 cur_module->library_path);
       sprintf(cur_archive_dir_name,"%s/%s",archive_cadencelib_base_dir_name,
	         cur_module->library_path);

       if ((dir = opendir(cur_dir_name)) != NULL) 
          {
	   closedir(dir);

           if ((dir = opendir(cur_archive_dir_name)) == NULL) 
              {
              if (makedir(cur_archive_dir_name) != 0)
                 {
                 printf("error in 'main':\n");
                 printf("     can't create archive subdirectory:\n");
                 printf("     '%s'\n",cur_archive_dir_name);
                 exit(1);
                 }
	      }
           else
	      closedir(dir);

           sprintf(cur_dir_name,"%s/%s/%s",cur_base_dir_name,
                  cur_module->library_path,cur_module->name);

           if ((dir = opendir(cur_dir_name)) != NULL) 
              {
	       closedir(dir);
               sprintf(cur_archive_dir_name,"%s/%s/%s",
                     archive_cadencelib_base_dir_name,
	             cur_module->library_path,cur_module->name);
               recursively_copy_directory(cur_dir_name, cur_archive_dir_name);
	      }
	  }

       /*
       printf("code_dir: %s/%s/%s\n",cadencelib_dir_name,
	      cur_module->library_path,cur_module->name);
       printf("sim_runs_dir: %s/%s/%s\n",simruns_dir_name,
              cur_module->library_path,cur_module->name);
       */
       }
    cur_module = cur_module->next;
   }
}

void copy_ascii_file(char *infile_name, char *outfile_name)
{
FILE *infile, *outfile;
static int cur_char;

if ((infile = fopen(infile_name,"r")) == NULL)
  {
   printf("error in 'copy_ascii_file':  can't open file:  '%s'\n",infile_name);
   exit(1);
  }
if ((outfile = fopen(outfile_name,"w")) == NULL)
  {
   printf("error in 'copy_ascii_file':  can't open file:  '%s'\n",outfile_name);
   exit(1);
  }
while ((cur_char = fgetc(infile)) != EOF)
   {
    fputc(cur_char,outfile);
   }

fclose(infile);
fclose(outfile);
}

void copy_file(char *infile_name, char *outfile_name)
{
FILE *infile, *outfile;
static int cur_char;

if ((infile = fopen(infile_name,"rb")) == NULL)
  {
   printf("error in 'copy_file':  can't open file:  '%s'\n",infile_name);
   exit(1);
  }
if ((outfile = fopen(outfile_name,"wb")) == NULL)
  {
   printf("error in 'copy_file':  can't open file:  '%s'\n",outfile_name);
   exit(1);
  }
while ((cur_char = fgetc(infile)) != EOF)
   {
    fputc(cur_char,outfile);
   }

fclose(infile);
fclose(outfile);
}

void determine_active_modules(MODULE *first_module, char *top_sue_module_name,
                              char *control_string)
{
MODULE *cur_module;
char cur_sue_dir_name[MAX_CHAR_LENGTH];
DIR *dir;
struct dirent *entry;
char cur_sue_module_name[MAX_CHAR_LENGTH];
int i;

cur_module = mark_active_modules(first_module, top_sue_module_name);

if (strcmp(control_string,"all") == 0)
   {
   extract_sue_library_name(cur_module->full_filename,cur_sue_dir_name);

   if ((dir = opendir(cur_sue_dir_name)) == NULL) 
      {
       printf("error in 'determine_active_modules':\n");
       printf("  cannot open library directory:\n");
       printf("      %s\n",cur_sue_dir_name);
       exit(1);     
      }

   chdir(cur_sue_dir_name);
   while ((entry = readdir(dir)) != NULL) 
       {
       if (is_sue_file(entry->d_name))
	 {
	  sprintf(cur_sue_module_name,"%s",entry->d_name);
          for (i = 0; cur_sue_module_name[i] != '\0'; i++);
          for (     ; i >= 0; i--)
	    if (cur_sue_module_name[i] == '.')
	       break;
	  if (cur_sue_module_name[i] != '.')
	    {
	      printf("error in 'determine_active_modules':\n");
              printf("  sue module name appears to be messed up!\n");
              printf("   -> name: '%s'\n",cur_sue_module_name);
              exit(1);
	    }
          cur_sue_module_name[i] = '\0';
          mark_active_modules(first_module, cur_sue_module_name);
	 }
       }
   closedir(dir);
   }
}

void create_archive_directory(char *simruns_base_dir_name,
             char *suelib_base_dir_name, char *cadencelib_base_dir_name)
{
int i;
DIR *dir, *dir_temp;
struct dirent *entry;
const char *cppsim_home_dir_const = NULL;
char cppsim_home_dir[MAX_CHAR_LENGTH];
char archive_dir_name[MAX_CHAR_LENGTH];
char next_dir_name[MAX_CHAR_LENGTH];
char cur_file_name[MAX_CHAR_LENGTH];

///////////// CPPSIMHOME environment variable /////////

cppsim_home_dir_const = getenv("CPPSIMHOME");
if (cppsim_home_dir_const != NULL)
  {
  sprintf(cppsim_home_dir,cppsim_home_dir_const);
  for (i = 0; cppsim_home_dir[i] != '\0'; i++)
    if (cppsim_home_dir[i] == '\\')
       cppsim_home_dir[i] = '/';
  }
else
  {
    printf("Error:  you must define environment variable CPPSIMHOME\n");
    printf("  before running CppSim\n");
    printf("  -> include the following statement in your .cshrc[.mine] file:\n");
    printf("     setenv CPPSIMHOME $HOME/CppSim\n");
    exit(1);
  }

if ((dir = opendir(cppsim_home_dir)) == NULL) 
   {
    printf("Error:  cannot open CppSim home directory specified\n");
    printf("        by the UNIX environment variable CPPSIMHOME = '%s'\n",
                    cppsim_home_dir);
    printf("  -> perhaps you need to redefine UNIX environment variable CPPSIMHOME\n");
    printf("     within your .cshrc[.mine] file:\n");
    exit(1);
   } 
else
   closedir(dir);

// make fresh archive directory or clear out the previously made one //

sprintf(archive_dir_name,"%s/Archive",cppsim_home_dir);

if ((dir = opendir(archive_dir_name)) == NULL) 
   {
    if (makedir(archive_dir_name) != 0)
       {
        printf("error in 'create_archive_directory':\n");
        printf("     cannot create archive directory:\n");
        printf("     '%s'\n",archive_dir_name);
        exit(1);
       }
   } 
else
   {
    chdir(archive_dir_name);
    while ((entry = readdir(dir)) != NULL) 
        {
	 if (strcmp(entry->d_name,".") == 0 ||
	     strcmp(entry->d_name,"..") == 0)
             continue;

	 if ((dir_temp = opendir(entry->d_name)) != NULL) // directory
	    {
	    closedir(dir_temp);
	    sprintf(next_dir_name,"%s/%s",archive_dir_name,entry->d_name);
	    recursively_delete_directory(next_dir_name);
	    }
         else // file
    	   {
	     sprintf(cur_file_name,"%s/%s",archive_dir_name,entry->d_name);
             if (remove(cur_file_name) != 0)
	       {
               printf("error in 'create_archive_directory':\n");
               printf("     cannot clean out the archive directory\n");
               printf("     in particular, deletion of the following file failed:\n");
               printf("     '%s'\n",cur_file_name);
               printf("     -> try changing the permissions of the directory/file\n");
               printf("        and make sure that no process is currently accessing that file\n");
               exit(1);
	       }
	   }
	}
    closedir(dir);    
   }

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

sprintf(simruns_base_dir_name,"%s/SimRuns",archive_dir_name);
if (makedir(simruns_base_dir_name) != 0)
    {
     printf("error in 'create_archive_directory':\n");
     printf("     cannot create archive subdirectory:\n");
     printf("     '%s'\n",simruns_base_dir_name);
     printf("     -> try changing the permissions of the directory\n");
     printf("        '%s'\n",archive_dir_name);
     exit(1);
    }

sprintf(suelib_base_dir_name,"%s/SueLib",archive_dir_name);
if (makedir(suelib_base_dir_name) != 0)
    {
     printf("error in 'create_archive_directory':\n");
     printf("     cannot create archive subdirectory:\n");
     printf("     '%s'\n",suelib_base_dir_name);
     printf("     -> try changing the permissions of the directory\n");
     printf("        '%s'\n",archive_dir_name);
     exit(1);
    }

sprintf(cadencelib_base_dir_name,"%s/CadenceLib",archive_dir_name);
if (makedir(cadencelib_base_dir_name) != 0)
    {
     printf("error in 'create_archive_directory':\n");
     printf("     cannot create archive subdirectory:\n");
     printf("     '%s'\n",cadencelib_base_dir_name);
     printf("     -> try changing the permissions of the directory\n");
     printf("        '%s'\n",archive_dir_name);
     exit(1);
    }

}

void recursively_delete_directory(char *cur_dir_name)
{
DIR *dir, *dir_temp;
struct dirent *entry;
char next_dir_name[MAX_CHAR_LENGTH];
char cur_file_name[MAX_CHAR_LENGTH];

if ((dir = opendir(cur_dir_name)) == NULL) 
   {
     printf("error in 'recursively_delete_directory':\n");
     printf("  can't open directory:\n");
     printf("  '%s'\n",cur_dir_name);
     exit(1);
   } 
else
   {
    chdir(cur_dir_name);
    while ((entry = readdir(dir)) != NULL) 
        {
	 if (strcmp(entry->d_name,".") == 0 ||
	     strcmp(entry->d_name,"..") == 0)
             continue;

	 if ((dir_temp = opendir(entry->d_name)) != NULL) // directory
	    {
	    closedir(dir_temp);
	    sprintf(next_dir_name,"%s/%s",cur_dir_name,entry->d_name);
	    recursively_delete_directory(next_dir_name);
	    }
         else // file
    	   {
	     sprintf(cur_file_name,"%s/%s",cur_dir_name,entry->d_name);
             if (remove(cur_file_name) != 0)
	       {
               printf("error in 'recursively_delete_directory':\n");
               printf("     cannot clean out the archive directory\n");
               printf("     in particular, deletion of the following file failed:\n");
               printf("     '%s'\n",cur_file_name);
               printf("     -> try changing the permissions of the directory/file\n");
               printf("        and make sure that no process is currently accessing that file\n");
               exit(1);
	       }
	   }
	}
    closedir(dir);    
    chdir("..");
    if (rmdir(cur_dir_name) != 0)
      {
       printf("error in 'recursively_delete_directory':\n");
       printf("     cannot clean out the archive directory\n");
       printf("     in particular, deletion of the following directory failed:\n");
       printf("     '%s'\n",cur_dir_name);
       printf("     -> try changing the permissions of the directory\n");
       printf("        and make sure that no process is currently accessing\n");
       printf("        the contents of that directory\n");
       exit(1);
      }
   }
}


void recursively_copy_directory(char *cur_dir_name, char *cur_archive_dir_name)
{
DIR *dir,*dir_temp;
struct dirent *entry;
char next_dir_name[MAX_CHAR_LENGTH];
char next_archive_dir_name[MAX_CHAR_LENGTH];
char cur_file_name[MAX_CHAR_LENGTH];
char cur_archive_file_name[MAX_CHAR_LENGTH]; 

if ((dir = opendir(cur_dir_name)) == NULL) 
   {
     printf("error in 'recursively_copy_directory':\n");
     printf("  can't open directory:\n");
     printf("  '%s'\n",cur_dir_name);
     exit(1);
   } 
else
   {
    if ((dir_temp = opendir(cur_archive_dir_name)) == NULL) 
        {
        if (makedir(cur_archive_dir_name) != 0)
            {
             printf("error in 'recursively_copy_directory':\n");
             printf("     cannot create archive subdirectory:\n");
             printf("     '%s'\n",cur_archive_dir_name);
             exit(1);
            }
        } 
    else
	closedir(dir_temp);

    chdir(cur_dir_name);
    while ((entry = readdir(dir)) != NULL) 
        {
	 if (strcmp(entry->d_name,".") == 0 ||
	     strcmp(entry->d_name,"..") == 0)
             continue;

	 if ((dir_temp = opendir(entry->d_name)) != NULL) 
	    {
	    closedir(dir_temp);
	    sprintf(next_dir_name,"%s/%s",cur_dir_name,entry->d_name);
 	    sprintf(next_archive_dir_name,"%s/%s",cur_archive_dir_name,
                                             entry->d_name);
	    recursively_copy_directory(next_dir_name, next_archive_dir_name);
	    }
         else
    	   {
	     sprintf(cur_file_name,"%s/%s",cur_dir_name,entry->d_name);
             sprintf(cur_archive_file_name,"%s/%s",cur_archive_dir_name,
		     entry->d_name);
             copy_file(cur_file_name,cur_archive_file_name);
	   }
	}
    closedir(dir);    
    chdir("..");
   }
}

void determine_simruns_directory(char *simruns_dir_name)
{
int i;
DIR *dir;
const char *cppsim_home_dir_const = NULL;
char cppsim_home_dir[MAX_CHAR_LENGTH];

///////////// CPPSIMHOME environment variable /////////

cppsim_home_dir_const = getenv("CPPSIMHOME");
if (cppsim_home_dir_const != NULL)
  {
  sprintf(cppsim_home_dir,cppsim_home_dir_const);
  for (i = 0; cppsim_home_dir[i] != '\0'; i++)
    if (cppsim_home_dir[i] == '\\')
       cppsim_home_dir[i] = '/';
  }
else
  {
    printf("Error:  you must define environment variable CPPSIMHOME\n");
    printf("  before running CppSim\n");
    printf("  -> include the following statement in your .cshrc[.mine] file:\n");
    printf("     setenv CPPSIMHOME $HOME/CppSim\n");
    exit(1);
  }

if ((dir = opendir(cppsim_home_dir)) == NULL) 
   {
    printf("Error:  cannot open CppSim home directory specified\n");
    printf("        by the UNIX environment variable CPPSIMHOME = '%s'\n",
                    cppsim_home_dir);
    printf("  -> perhaps you need to redefine UNIX environment variable CPPSIMHOME\n");
    printf("     within your .cshrc[.mine] file:\n");
    exit(1);
   } 
else
   closedir(dir);

sprintf(simruns_dir_name,"%s/SimRuns",cppsim_home_dir);

if ((dir = opendir(simruns_dir_name)) == NULL) 
   {
    printf("error in 'determine_simruns_directory':\n");
    printf("     cannot open SimRuns directory:\n");
    printf("     '%s'\n",simruns_dir_name);
    exit(1);
   } 
else
   closedir(dir);

}

void extract_sue_library_name(char *sue_file_name, char *sue_library_name)
{
int i;

strcpy(sue_library_name,sue_file_name);
for (i = 0; sue_library_name[i] != '\0'; i++);
for (    ; i >= 0; i--)
  {
   if (sue_library_name[i] == '/')
      break;
  }

if (sue_library_name[i] != '/')
   {
    printf("error in 'extract_sue_library_name':\n");
       printf("  sue file name seems to be wrong ...\n");
       printf("  file name: '%s'\n",sue_file_name);
       printf("  -> there should be at least one '/' character\n");
       exit(1);
   }
sue_library_name[i] = '\0';
}

void extract_cadencelib_dir_name(char *sue_file_name, char *cppsim_library_name)
{
int i,count;
char temp[MAX_CHAR_LENGTH];
DIR *dir;

strcpy(cppsim_library_name,sue_file_name);
for (i = 0; cppsim_library_name[i] != '\0'; i++);
count = 0;
for (    ; i >= 0; i--)
 {
   if (cppsim_library_name[i] == '/')
      count++;
   if (count == 3)
      break;
 }
if (i < 0)
   {
    printf("error in 'extract_cadencelib_dir_name':\n");
    printf("  sue file name seems to be wrong ...\n");
    printf("  file name: '%s'\n",sue_file_name);
    printf("  -> there should be at least three '/' characters\n");
    exit(1);
   }
if (strncmp(&cppsim_library_name[i],"/SueLib/",8) != 0)
   {
    printf("error in 'extract_cadencelib_dir_name':\n");
    printf("  sue file name seems to be wrong ...\n");
    printf("  file name: '%s'\n",sue_file_name);
    printf("  -> there should be a '/SueLib/' string within the file name\n");
    exit(1);
   }

cppsim_library_name[i] = '\0';
strcat(cppsim_library_name,"/CadenceLib");

if ((dir = opendir(cppsim_library_name)) == NULL) 
   {
    printf("error in 'extract_cadencelib_dir_name':\n");
    printf("     cannot open CadenceLib directory:\n");
    printf("     '%s'\n",cppsim_library_name);
    exit(1);
   } 
else
   closedir(dir);

}




MODULE *mark_active_modules(MODULE *first_module, char *top_module_name)
{
MODULE *cur_module;


cur_module = first_module;
while (cur_module != NULL)
   {
    if (strcmp(cur_module->name,top_module_name) == 0)
      {
       cur_module->active_sue_module_flag = 1;
       break;       
      }
    cur_module = cur_module->next;
   }

if (cur_module == NULL)
   {
    printf("error in 'mark_active_modules':  can't find top_module '%s'\n",
	    top_module_name);
    exit(1);
   }

determine_sue_module_dependencies(cur_module);
return(cur_module);
}
