/* -*-Mode: C++;-*-
 * PRCS - The Project Revision Control System
 * Copyright (C) 1997  Josh MacDonald
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: quick.cc 1.7.1.2.2.8.1.1 Sun, 03 Feb 2002 13:39:38 -0800 jmacd $
 */

#include "prcs.h"

#include "projdesc.h"
#include "fileent.h"
#include "sexp.h"
#include "quick.h"
#include "system.h"
#include "misc.h"

#define prj_lex_val prjtext
#define prj_lex_len prjleng

EXTERN int         prjleng;
EXTERN const char* prjtext;
EXTERN int         prj_lex_this_index;
EXTERN int         prj_lex_cur_index;
EXTERN int         prj_lineno;

QuickElim::QuickElim() :quick_table(new QuickElimTable) { }
QuickElim::~QuickElim() { delete quick_table; }

NprQuickElimPtrError read_quick_elim(const char* filename)
{
    QuickElim* quick_elim = new QuickElim;

    Return_if_fail(quick_elim->init_from_file(filename));

    return quick_elim;
}

static long string_to_posint(const char* string)
{
    char c;
    int val = 0;

    while((c = *string++) != 0) {
	if(c < '0' || c > '9')
	    return -1;
	val *= 10;
	val += (c - '0');
    }

    return val;
}

bool QuickElim::unchanged(const FileEntry* fe) const
{
    QuickElimEntry **lookup, *qe;

    if((lookup = quick_table->lookup(fe->working_path() +
				     cmd_root_project_path_len)) != NULL) {
	qe = *lookup;

	if(qe->length != fe->stat_length())
	    return false;

	if(qe->mtime != fe->stat_mtime())
	    return false;

	if(strcmp(qe->desc_name, fe->descriptor_name()) != 0)
	    return false;

	if(strcmp(qe->version_num, fe->descriptor_version_number()) != 0)
	    return false;

	return true;
    }

    return false;
}

void QuickElim::update(const FileEntry* fe)
{
    QuickElimEntry **lookup, *qe;

    if(option_report_actions)
	return;

    if((lookup = quick_table->lookup(fe->working_path() +
				     cmd_root_project_path_len)) != NULL) {
	qe = *lookup;
    } else {
	qe = new QuickElimEntry;
	qe->name.assign (fe->working_path());
	quick_table->insert (qe->name + cmd_root_project_path_len, qe);
    }

    qe->length = fe->stat_length();
    qe->mtime = fe->stat_mtime();
    qe->desc_name.assign(fe->descriptor_name());
    qe->version_num.assign(fe->descriptor_version_number());
}

PrVoidError QuickElim::update_file(const char* filename) const
{
    ofstream os;

    if(option_report_actions)
	return NoError;

    os.open(filename);

    os << ";; This file is automatically generated, editing may cause PRCS to do\n";
    os << ";; REALLY bad things.\n";

    os << "(Created-By-Prcs-Version " << prcs_version_number[0] << " "
       << prcs_version_number[1] << " " << prcs_version_number[2] << ")\n";

    foreach (qe_ptr, quick_table, QuickElimTable::HashIterator) {
	QuickElimEntry *qe = (*qe_ptr).y();

	os << "(";
	print_protected (qe->name, os);
	os << " " << qe->length << " " << qe->mtime << " ";
	print_protected (qe->desc_name, os);
	os << " ";
	print_protected (qe->version_num, os);
	os << ")\n";
    }

    os.close();

    if(os.fail())
	pthrow prcserror << "Failed writing auxiliary file "
			<< squote(filename) << ", ignoring" << dotendl;

    return NoError;
}

static NprVoidError read_qe_lists(QuickElimTable *table)
{
    PrjTokenType tok = (PrjTokenType)prjlex();

    while (true) {
	if ( tok != PrjOpen)
	    return NonFatalError;

	if ( (PrjTokenType)prjlex() != PrjName)
	    return NonFatalError;

	QuickElimEntry* qe = new QuickElimEntry;

	correct_path(prj_lex_val, &qe->name);

	if (table->isdefined(qe->name)) {
	    delete qe;
	    return NonFatalError;
	}

	if ( (PrjTokenType)prjlex() != PrjName)
	    return NonFatalError;

	qe->length = string_to_posint(prj_lex_val);

	if ( (PrjTokenType)prjlex() != PrjName)
	    return NonFatalError;

	qe->mtime = string_to_posint(prj_lex_val);

	if ( (PrjTokenType)prjlex() != PrjName)
	    return NonFatalError;

	correct_path(prj_lex_val, &qe->desc_name);

	if ( (PrjTokenType)prjlex() != PrjName)
	    return NonFatalError;

	correct_path(prj_lex_val, &qe->version_num);

	if ( (PrjTokenType)prjlex() != PrjClose)
	    return NonFatalError;

	tok = (PrjTokenType)prjlex();

	table->insert(qe->name, qe);

	if (tok == PrjEof)
	    return NoError;
    }
}

NprVoidError QuickElim::init_from_file(const char* file)
{
    If_fail(prj_input << Err_fopen(file, "r")) {
	if(errno != ENOENT)
	    prcswarning << "Error opening auxiliary file " << squote(file) << dotendl;

	return NonFatalError;
    }

    if ( (PrjTokenType)prjlex() != PrjOpen ||
	 (PrjTokenType)prjlex() != PrjName ||
	 strcmp ("Created-By-Prcs-Version", prj_lex_val) != 0 ||
	 (PrjTokenType)prjlex() != PrjName ||
	 (PrjTokenType)prjlex() != PrjName ||
	 (PrjTokenType)prjlex() != PrjName ||
	 (PrjTokenType)prjlex() != PrjClose)
	goto error;

    If_fail (read_qe_lists(quick_table))
	goto error;

    prj_input = NULL;

    return NoError;

error:

    prj_input = NULL;

    prcswarning << "Error parsing auxiliary file " << squote(file) << ", removing" << dotendl;

    If_fail(Err_unlink(file))
	prcswarning << "Unlink failed on auxiliary file " << squote(file) << perror;

    return NoError;
}
