/* -*-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: changes.cc 1.2 Sun, 28 Oct 2001 17:24:49 -0800 jmacd $
*/
#include "prcs.h"
#include "projdesc.h"
#include "fileent.h"
#include "repository.h"
#include "vc.h"
#include "misc.h"
#include "checkin.h"
#include "checkout.h"
#define COL 21
PrVoidError get_projects (RepEntry *rep_entry,
ProjectVersionData *project_data,
ProjectVersionData *parent_data,
ProjectDescriptor **project_desc,
ProjectDescriptor **parent_desc)
{
/* This routine tries to keep two project descriptors in memory at
* all times, thus allowing both forward and reverse traversals to
* be fast in the common case. When a project has more than one
* parent it will be a bit slower... */
static ProjectDescriptor *p1 = NULL;
static ProjectDescriptor *p2 = NULL;
static ProjectVersionData *v1 = NULL;
static ProjectVersionData *v2 = NULL;
bool p1_used = false;
bool p2_used = false;
bool parent_set = false;
bool project_set = false;
if (project_data == v1) {
(*project_desc) = p1;
p1_used = true;
project_set = true;
} else if (project_data == v2) {
(*project_desc) = p2;
p2_used = true;
project_set = true;
}
if (parent_data) {
if (parent_data == v1) {
(*parent_desc) = p1;
p1_used = true;
parent_set = true;
} else if (parent_data == v2) {
(*parent_desc) = p2;
p2_used = true;
parent_set = true;
}
}
if (! project_set) {
Return_if_fail ((*project_desc) << rep_entry-> checkout_prj_file (cmd_root_project_full_name,
project_data->rcs_version(),
KeepNothing));
eliminate_unnamed_files (*project_desc);
if (! p1_used) {
if (p1) delete p1;
p1 = (*project_desc);
v1 = project_data;
p1_used = true;
} else if (! p2_used) {
if (p2) delete p2;
p2 = (*project_desc);
v2 = project_data;
p2_used = true;
}
}
if (parent_data && ! parent_set) {
Return_if_fail ((*parent_desc) << rep_entry-> checkout_prj_file (cmd_root_project_full_name,
parent_data->rcs_version(),
KeepNothing));
eliminate_unnamed_files (*parent_desc);
if (! p1_used) {
if (p1) delete p1;
p1 = (*parent_desc);
v1 = parent_data;
p1_used = true;
} else if (! p2_used) {
if (p2) delete p2;
p2 = (*parent_desc);
v2 = parent_data;
p2_used = true;
}
}
return NoError;
}
static ProjectVersionData *print_project = NULL;
static ProjectVersionData *print_parent = NULL;
static void print_header (ProjectDescriptor *pdesc,
ProjectVersionData *project,
ProjectVersionData *parent)
{
if (print_project != project) {
prcsoutput << cmd_root_project_name << ' '
<< project << ' '
<< time_t_to_rfc822(project->date()) << " by "
<< project->author() << prcsendl;
print_project = project;
if (option_long_format) {
if(strchr(*pdesc->version_log(), '\n') != NULL || strlen(*pdesc->version_log()) > 60) {
prcsoutput << "Version-Log:" << prcsendl
<< pdesc->version_log() << prcsendl;
} else {
prcsoutput << "Version-Log:" << setcol(COL+1)
<< (pdesc->version_log()->index(0) == '\0' ? "empty" : pdesc->version_log()->cast())
<< prcsendl;
}
}
if (! parent) {
prcsoutput << " initial version:" << prcsendl;
}
}
if (print_parent != parent) {
prcsoutput << " changes from parent " << parent << ":" << prcsendl;
print_parent = parent;
}
}
static PrVoidError print_changes (RepEntry *rep_entry,
ProjectVersionData *project_data,
ProjectVersionData *parent_data,
ProjectDescriptor *project,
ProjectDescriptor *parent)
{
/* this code was copied from checkin.cc compute_modified, then changed */
foreach_fileent(fe_ptr, project) {
FileEntry *fe = *fe_ptr;
if (! fe->on_command_line ())
continue;
const char *new_name = fe->working_path();
const char *old_name = NULL;
const char *new_lname = fe->link_name ();
const char *old_lname = NULL;
const char *new_desc = fe->descriptor_version_number();
const char *old_desc = NULL;
FileType new_type = fe->file_type ();
FileType old_type = (FileType) 0;
FileEntry *pred_fe = NULL;
if (parent) {
Return_if_fail (pred_fe << parent->match_fileent (fe));
}
if (! pred_fe) {
print_header (project, project_data, parent_data);
prcsoutput << " " << new_name << setcol(COL) << " added "
<< format_type (new_type, false) << prcsendl;
} else {
bool rename = false;
bool lchange = false;
bool vchange = false;
bool tchange = false;
old_type = pred_fe->file_type ();
old_name = pred_fe->working_path ();
old_lname = pred_fe->link_name ();
old_desc = pred_fe->descriptor_version_number ();
if (! pathname_equal (old_name, new_name)) {
rename = true;
}
if (new_type != old_type) {
tchange = true;
}
if (new_lname && old_lname && strcmp (new_lname, old_lname) != 0) {
lchange = true;
}
if (new_desc && old_desc && strcmp (new_desc, old_desc) != 0) {
vchange = true;
}
if (rename || lchange || tchange || vchange) {
print_header (project, project_data, parent_data);
prcsoutput << " " << new_name << setcol(COL) << " ";
if (rename) {
prcsoutput << "renamed from " << old_name;
}
if (tchange) {
if (rename) { prcsoutput << ", "; }
prcsoutput << "type changed from " << format_type (old_type, false) << " to " << format_type (new_type, false);
}
if (lchange) {
if (rename || tchange) { prcsoutput << ", "; }
prcsoutput << "link changed from " << old_lname << " to " << new_lname;
}
if (vchange) {
if (rename || tchange || lchange) { prcsoutput << ", "; }
RcsVersionData *data;
Return_if_fail (data << rep_entry->lookup_rcs_file_data (fe->descriptor_name (),
fe->descriptor_version_number ()));
prcsoutput << "modified +" << data->plus_lines () << " -" << data->minus_lines ();
}
prcsoutput << prcsendl;
}
}
}
if (parent) {
foreach_fileent (fe_ptr, parent) {
FileEntry *fe = *fe_ptr;
FileEntry *proj_fe = NULL;
if (! fe->on_command_line ())
continue;
Return_if_fail (proj_fe << project->match_fileent (fe));
if (! proj_fe) {
print_header (project, project_data, parent_data);
prcsoutput << " " << fe->working_path () << setcol(COL) << " deleted "
<< format_type (fe->file_type (), false) << prcsendl;
}
}
}
return NoError;
}
PrVoidError output_changes (RepEntry *rep_entry, ProjectVersionData *project_data, ProjectVersionData *parent_data)
{
ProjectDescriptor *project_desc = NULL, *parent_desc = NULL;
Return_if_fail (get_projects (rep_entry, project_data, parent_data, & project_desc, & parent_desc));
Return_if_fail (print_changes (rep_entry, project_data, parent_data, project_desc, parent_desc));
return NoError;
}
PrPrcsExitStatusError changes_command()
{
RepEntry *rep_entry;
ProjectVersionData *first_data;
ProjectVersionData *second_data;
ProjectVersionDataPtrArray *ancestors;
kill_prefix(prcsoutput);
Return_if_fail(rep_entry << Rep_init_repository_entry(cmd_root_project_name,
false, false, true));
if (strcmp (cmd_version_specifier_minor, "0") == 0) {
pthrow prcserror << "You may not specify the 0-minor version for this command" << dotendl;
}
Return_if_fail(first_data << resolve_version(cmd_version_specifier_major,
cmd_version_specifier_minor,
cmd_root_project_full_name,
cmd_root_project_file_path,
NULL,
rep_entry));
if (! cmd_alt_version_specifier_major) {
second_data = first_data;
} else {
if (strcmp (cmd_alt_version_specifier_minor, "0") == 0) {
pthrow prcserror << "You may not specify the 0-minor version for this command" << dotendl;
}
Return_if_fail(second_data << resolve_version(cmd_alt_version_specifier_major,
cmd_alt_version_specifier_minor,
cmd_root_project_full_name,
cmd_root_project_file_path,
NULL,
rep_entry));
}
ancestors = rep_entry->common_lineage (first_data, second_data);
if (ancestors == NULL) {
pthrow prcserror << "Versions " << first_data << " and "
<< second_data << " are not ancestors of each other" << dotendl;
}
ProjectVersionDataPtrArray* summary = rep_entry->project_summary();
foreach (pvd_ptr, ancestors, ProjectVersionDataPtrArray::ArrayIterator) {
ProjectVersionData *pvd = *pvd_ptr;
print_project = NULL;
print_parent = NULL;
if (pvd->parent_count () == 0) {
Return_if_fail (output_changes (rep_entry, pvd, NULL));
} else {
for (int i = 0; i < pvd->parent_count (); i += 1) {
print_parent = NULL;
Return_if_fail (output_changes (rep_entry, pvd, summary->index (pvd->parent_index (i))));
}
}
}
return ExitSuccess;
}
syntax highlighted by Code2HTML, v. 0.9.1