/*
 *  copyright.C from ObjectProDSP 0.1
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  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 version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */

/* program to add copyright notice to top of program with required 
   commenting of text based on file type */

#include <stream.h>
#include <stdlib.h>
#include <string.h>
#include "ObjProGen/copyright.h"
#include "ObjProDSP/version.h"
#include "ObjProGen/mkstr.h"



const char * AddCopyright::plot_file_prologue =
	"ObjectProDSP binary plot file.\nversion 1000000\n" ;
const int AddCopyright::byte_boundary=3000 ;
const char * AddCopyright::created_by =
	OBJ_PRO_DSP_VERSION_XSTR(created by ObjectProDSP OBJ_PRO_DSP_VERSION_NUM) ;
int AddCopyright::default_user_flag = 0 ;
	// set this if you wat user notices on code generated by MakeTarget

const char * const FileType::termination_line =
	"ObjectProDSP is a trademark of Mountain Math Software." ;

static FileType copy_file_type[] = {
	{".menu",FileType::per_line,"//  "},
	// {".usr",FileType::per_line,"//  ",0,0,0,1},
	{".usr",FileType::bracketed,"/*",0," */"," *  ",1},
	{".C",FileType::bracketed,"/*",0," */"," *  ",1},
	{".c",FileType::bracketed,"/*",0," */"," *  ",1},
	{".h",FileType::bracketed,"/*",0," */"," *  ",1},
	{0,FileType::per_line,"%  ","ALL.tex_"},
	{".tex",FileType::per_line,"%  "},
	{".roff",FileType::per_line,"\\\"  "},
	{"_list",FileType::per_line,"#  "},
	{".sh",FileType::per_line,"#  ",0,0,0,0,"#!/bin/sh"},
	{".hlp",FileType::per_line,"#  "},
	{".pl",FileType::per_line,"#  ",0,0,0,0,"#!/usr/bin/perl"},
	{".rec",FileType::per_line,"#  "},
	{0,FileType::per_line,"#  ","Makefile"},
	{0,FileType::per_line,"#  ","makefile"},
	{0,FileType::per_line,"#  ","set_"},
	{0,FileType::per_line,"#  ","makemake."},
	{0,FileType::per_line,"#  ","domakemake"},
	{".nod",FileType::per_line,"//  ",0,0,0,1},
	{".l",FileType::bracketed,"/*",0," */"," *  ",1},
	{".y",FileType::bracketed,"/*",0," */"," *  ",1},
	{0,FileType::end_of_types}
} ;

FileType * AddCopyright::file_type = copy_file_type;

static FileType copy_no_notice[] = {
	{".xwd",FileType::no_notice},
	{".xml",FileType::no_notice},
	{".dat",FileType::no_notice},
	{".dpp",FileType::no_notice},
	{".cmp",FileType::no_notice},
	{".cmpb",FileType::no_notice},
	{".ps",FileType::no_notice},
	{0,FileType::no_notice,0,"READ_ME"},
	{0,FileType::end_of_types}
} ;

FileType * AddCopyright::no_notice = copy_no_notice ;


int FileType::has_suffix(const char * name)
{
	if (!suffix) return 0 ;
	return (FindSuffix(name,suffix) != 0) ;
}

int FileType::has_prefix(const char * name)
{
	if (!prefix) return 0 ;
	return !strncmp(name,prefix,length) ;
}

void FileType::init()
{
	check_start() ;
	if (suffix) length = strlen(suffix);
	else if (prefix) length = strlen(prefix);
	else {
		cerr << "Bad FileType table.\n" ;
		exit(1);
	}
}

static int may_start_line(const char * test, const char * line)
{
	if (!test) return 0 ;
	return ! strncmp(test,line,strlen(test));
}

int FileType::may_be_comment_terminate(const char * line)
{
	if (comment_middle) {
		int len = strlen(comment_middle) ;
		if (strncmp(line,comment_middle,len)) return 0 ;
		line += len ;
	}
	return ! strcmp(line,termination_line);
}

int FileType::may_be_comment_middle(const char * line)
{
	if (!comment_middle) return 1 ;
	return may_start_line(comment_middle,line);
}

int FileType::may_be_comment_end(const char * line)
{
	if (!comment_end)
		if (comment_middle && type == per_line)
			return ! strcmp(line,comment_middle) ;
		else return *line == '\0' ;
	// if there is no comment end there should be a blank line
	return may_start_line(comment_end,line) ;
}

int FileType::is_first_line(const char * line)
{
	return may_start_line(first_line,line) ;
}

int FileType::may_be_comment_start(const char * line)
{
	if (!comment_start)
		if (may_start_line(comment_middle,line)) return 1 ;
		else return 0 ;
	return may_start_line(comment_start,line)  ;
}

int FileType::may_be_comment(const char * line)
{
	if (may_start_line(comment_start,line)) return 1 ;
	if (may_start_line(comment_end,line)) return 1 ;
	return may_start_line(comment_middle,line) ;
}

void FileType::check_start()
{
	if (comment_start && ! comment_end && ! comment_middle) {
		comment_middle = comment_start ;
		comment_start = 0 ;
	}
}

int FileType::write(ostream& out, const char ** lines)
{
	if (first_line) out << first_line << "\n" ;
	if (!lines) return 0 ;
	if (!*lines) return 0 ;
	int total_out = 0 ;
	if (comment_start) {
		out << comment_start << "\n" ;
		total_out++ ;
	}
	for (const char ** l = lines; *l; l++) {
		if (comment_middle) out << comment_middle ;
		out << *l << "\n" ;
		if (!out.good()) return -1 ;
		total_out++ ;
	}
	if (comment_middle) out << comment_middle;
	out << "\n" ;
	total_out++ ;

	if (comment_middle) out << comment_middle ;
	out << termination_line << "\n" ;
	total_out++ ;

	// write end of comment or add commented line or blank line
	if (comment_end) out << comment_end  ;
	else if (comment_middle && type == per_line) out << comment_middle ;
	out << "\n" ;
	total_out++ ;

	if (!out.good()) return -1 ;
	return total_out ;
}

const the_max_file_lines = 200;
const max_length = 8192 ;
const int AddCopyright::max_file_lines = the_max_file_lines ;
const int AddCopyright::max_line_length = max_length ;
char ** AddCopyright::file_lines = 0 ;
char * AddCopyright::the_line_buffer = 0 ;

AddCopyright::AddCopyright(const char ** mm, const char ** mm_s, const char **u):
	mountain_math(mm),
	mountain_math_short(mm_s),
	user(u),
	the_length(0),
    the_short_length(0),
    the_user_length(0),
	next_file_line(0)
{
	if (!file_lines) file_lines = new char * [max_file_lines];
	if (!the_line_buffer) the_line_buffer = new char[max_line_length] ;
	for (int i = 0 ; i < max_file_lines;i++) file_lines[i] = 0 ;
	for (i = 0; i < max_line_length;i++) the_line_buffer[i] = '\0' ;
	for (FileType * pt = file_type; pt->type != FileType::end_of_types; pt++) 
		pt->init();
	for (pt = no_notice; pt->type != FileType::end_of_types; pt++) pt->init();
	if (mountain_math) for (; mountain_math[the_length]; the_length++);
	if (mountain_math_short)
		for (; mountain_math_short[the_short_length]; the_short_length++);
	if (user) for ( ; user[the_user_length] ; the_user_length++);

	// prevent accidental update with empty or bad arrays
	if (the_length < 10 || the_short_length < 2 ||
			the_length < the_short_length + 10 || the_length > 50
				|| the_short_length > 10 || the_user_length > 50) {
		cerr << "Error in building `copyright.o'.\n" ;
		exit(1);
	}

	int max_length = the_length + the_user_length + 3 ;
	// room for both notices 
	//	+ program name at start (1)
	//	+ separator between notices (2)
	//	+ null pointer at end (3)
	temp_lines = new char * [max_length] ;
	
}

const char *  AddCopyright::next_line(int index, istream& in)
{
	while (index >= next_file_line) if (read_line(in) < 0) return 0 ;
	return file_lines[index] ;
}

int AddCopyright::read_line(istream& in)
{
	if (next_file_line > max_file_lines - 2) return -1 ;
	the_line_buffer[0] = '\0' ;
	if (!in.good()) return -1 ;
	char * buf = &(the_line_buffer[0]) ;
	in.getline(buf,max_line_length);
	int read = in.gcount();
	file_lines[next_file_line] = new char[read+1] ;
	memcpy(file_lines[next_file_line++],buf,read+1);
	return read ;
}

int AddCopyright::is_not_notice_type(const char * path_name)
{
	int ret = 0 ;
	char * name = OpdRemoveDirectory(path_name);
	FileType * found = type(name,no_notice);
	if (found) {
		ret = 1 ;
		found->remove_old++ ;
	}
	delete name ;
	return ret ;
}


FileType * AddCopyright::type(const char * file_name)
{
	return type(file_name,file_type);
}

FileType * AddCopyright::type(const char * file_name,FileType ty[])
{
	for (FileType * pt = ty; pt->type != FileType::end_of_types; pt++) 
		if (pt->has_suffix(file_name)) return pt ;
	for (pt = ty; pt->type != FileType::end_of_types; pt++) 
		if (pt->has_prefix(file_name)) return pt ;
	return 0 ;
}


int AddCopyright::read_error()
{
	cerr << "Error in reading.\n" ;
	return -1 ;
}

int AddCopyright::write_error()
{
	cerr << "Error in writing.\n" ;
	return -1 ;
}


int AddCopyright::write_base(ostream& out, const char * path_name,
	const char * fr)
{
	int ret = 0 ;
	char * name = OpdRemoveDirectory(path_name);
	FileType * typ = type(name);
	if (typ) {
		char * to_delete = 0 ;
		if (fr) if (strstr(fr,"created")) to_delete = Concatenate(name," ",fr);
		else to_delete = Concatenate(name, " for ", fr, " from ObjectProDSP ",
			OBJ_PRO_DSP_VERSION);
		else to_delete = Concatenate(name," from ObjectProDSP ",
			OBJ_PRO_DSP_VERSION);
		temp_lines[0] = to_delete ;
		ret = typ->write(out, (const char **) temp_lines);
		temp_lines[0] = 0 ;
		delete to_delete ;
	}
	delete name ;
	return ret ;
}

int AddCopyright::write(ostream& out, const char * path_name,
	int user_flag, const char * fr)
{
	build_temp_lines(mountain_math,user_flag);
	return write_base(out,path_name,fr);
}

int AddCopyright::write_short(ostream& out, const char * path_name,
	int user_flag, const char * fr)
{
	build_temp_lines(mountain_math_short,user_flag);
	int ret = write_base(out,path_name,fr);
	return ret ;
}

void AddCopyright::build_temp_lines(const char ** mm,int user_flag)
{
	const char ** src = mm ;
	char ** dest = temp_lines + 1 ;
	while (*dest++ = (char *) *src++);
	if (user_flag) if (the_user_length) {
		dest-- ;
		*dest++ = "" ;
		src = user ;
		while (*dest++ = (char *) *src++);
	}
	dest-- ;
	*dest++ = 0 ;
}

int AddCopyright::may_be_comment(const char * line, const char * path_name)
{
	int ret = 0 ;
    char * name = OpdRemoveDirectory(path_name);
    FileType * typ = type(name);
	delete name ;
	if (typ) return typ->may_be_comment(line);
	return ret ;
}

AddCopyright& AddCopyright::add_copyright()
{
	static AddCopyright * the_add_copy_right = 0 ;
	if (the_add_copy_right) return *the_add_copy_right;
	{
#include "cpy_strings.h"
#include "user_cpy_strings.h"
 	 	the_add_copy_right = new  AddCopyright(copyright_text,
			short_copyright_text, user_copyright_text);
	}
	return *the_add_copy_right ;
}
