386BSD 0.1 development
[unix-history] / usr / othersrc / public / cvs-1.3 / src / entries.c
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Entries file to Files file
*
* Creates the file Files containing the names that comprise the project, from
* the Entries file.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)entries.c 1.37 92/03/31";
#endif
#if __STDC__
static Node *AddEntryNode (List * list, char *name, char *version,
char *timestamp, char *options, char *tag,
char *date);
#else
static Node *AddEntryNode ();
#endif /* __STDC__ */
static FILE *entfile;
static char *entfilename; /* for error messages */
/*
* Write out the line associated with a node of an entries file
*/
static int
write_ent_proc (node)
Node *node;
{
Entnode *p;
p = (Entnode *) node->data;
if (fprintf (entfile, "/%s/%s/%s/%s/", node->key, p->version,
p->timestamp, p->options) == EOF)
error (1, errno, "cannot write %s", entfilename);
if (p->tag)
{
if (fprintf (entfile, "T%s\n", p->tag) == EOF)
error (1, errno, "cannot write %s", entfilename);
}
else if (p->date)
{
if (fprintf (entfile, "D%s\n", p->date) == EOF)
error (1, errno, "cannot write %s", entfilename);
}
else if (fprintf (entfile, "\n") == EOF)
error (1, errno, "cannot write %s", entfilename);
return (0);
}
/*
* write out the current entries file given a list, making a backup copy
* first of course
*/
static void
write_entries (list)
List *list;
{
/* open the new one and walk the list writing entries */
entfilename = CVSADM_ENTBAK;
entfile = open_file (entfilename, "w+");
(void) walklist (list, write_ent_proc);
if (fclose (entfile) == EOF)
error (1, errno, "error closing %s", entfilename);
/* now, atomically (on systems that support it) rename it */
rename_file (entfilename, CVSADM_ENT);
}
/*
* Removes the argument file from the Entries file if necessary.
*/
void
Scratch_Entry (list, fname)
List *list;
char *fname;
{
Node *node;
if (trace)
(void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
/* hashlookup to see if it is there */
if ((node = findnode (list, fname)) != NULL)
{
delnode (node); /* delete the node */
if (!noexec)
write_entries (list); /* re-write the file */
}
}
/*
* Enters the given file name/version/time-stamp into the Entries file,
* removing the old entry first, if necessary.
*/
void
Register (list, fname, vn, ts, options, tag, date)
List *list;
char *fname;
char *vn;
char *ts;
char *options;
char *tag;
char *date;
{
Node *node;
if (trace)
(void) fprintf (stderr, "-> Register(%s, %s, %s, %s, %s %s)\n",
fname, vn, ts, options, tag ? tag : "",
date ? date : "");
/* was it already there? */
if ((node = findnode (list, fname)) != NULL)
{
/* take it out */
delnode (node);
/* add the new one and re-write the file */
(void) AddEntryNode (list, fname, vn, ts, options, tag, date);
if (!noexec)
write_entries (list);
}
else
{
/* add the new one */
node = AddEntryNode (list, fname, vn, ts, options, tag, date);
if (!noexec)
{
/* append it to the end */
entfilename = CVSADM_ENT;
entfile = open_file (entfilename, "a");
(void) write_ent_proc (node);
if (fclose (entfile) == EOF)
error (1, errno, "error closing %s", entfilename);
}
}
}
/*
* Node delete procedure for list-private sticky dir tag/date info
*/
static void
freesdt (p)
Node *p;
{
struct stickydirtag *sdtp;
sdtp = (struct stickydirtag *) p->data;
if (sdtp->tag)
free (sdtp->tag);
if (sdtp->date)
free (sdtp->date);
if (sdtp->options)
free (sdtp->options);
free ((char *) sdtp);
}
/*
* Read the entries file into a list, hashing on the file name.
*/
List *
ParseEntries (aflag)
int aflag;
{
List *entries;
char line[MAXLINELEN];
char *cp, *user, *vn, *ts, *options;
char *tag_or_date, *tag, *date;
char *dirtag, *dirdate;
int lineno = 0;
FILE *fpin;
/* get a fresh list... */
entries = getlist ();
/*
* Parse the CVS/Tag file, to get any default tag/date settings. Use
* list-private storage to tuck them away for Version_TS().
*/
ParseTag (&dirtag, &dirdate);
if (aflag || dirtag || dirdate)
{
struct stickydirtag *sdtp;
sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
bzero ((char *) sdtp, sizeof (*sdtp));
sdtp->aflag = aflag;
sdtp->tag = xstrdup (dirtag);
sdtp->date = xstrdup (dirdate);
/* feed it into the list-private area */
entries->list->data = (char *) sdtp;
entries->list->delproc = freesdt;
}
again:
fpin = fopen (CVSADM_ENT, "r");
if (fpin == NULL)
error (0, errno, "cannot open %s for reading", CVSADM_ENT);
else
{
while (fgets (line, sizeof (line), fpin) != NULL)
{
lineno++;
if (line[0] == '/')
{
user = line + 1;
if ((cp = index (user, '/')) == NULL)
continue;
*cp++ = '\0';
vn = cp;
if ((cp = index (vn, '/')) == NULL)
continue;
*cp++ = '\0';
ts = cp;
if ((cp = index (ts, '/')) == NULL)
continue;
*cp++ = '\0';
options = cp;
if ((cp = index (options, '/')) == NULL)
continue;
*cp++ = '\0';
tag_or_date = cp;
if ((cp = index (tag_or_date, '\n')) == NULL)
continue;
*cp = '\0';
tag = (char *) NULL;
date = (char *) NULL;
if (*tag_or_date == 'T')
tag = tag_or_date + 1;
else if (*tag_or_date == 'D')
date = tag_or_date + 1;
(void) AddEntryNode (entries, user, vn, ts, options, tag, date);
}
else
{
/* try conversion only on first line */
if (lineno == 1)
{
(void) fclose (fpin);
check_entries ((char *) NULL);
goto again;
}
}
}
}
/* clean up and return */
if (fpin)
(void) fclose (fpin);
if (dirtag)
free (dirtag);
if (dirdate)
free (dirdate);
return (entries);
}
/*
* Look at the entries file to determine if it is in the old entries format.
* If so, convert it to the new format.
*/
void
check_entries (dir)
char *dir;
{
FILE *fpin, *fpout;
char tmp[MAXLINELEN];
char line[MAXLINELEN];
char entname[MAXLINELEN];
char entbak[MAXLINELEN];
char *cp, *user, *rev, *ts, *opt;
if (dir != NULL)
{
(void) sprintf (entname, "%s/%s", dir, CVSADM_ENT);
(void) sprintf (entbak, "%s/%s", dir, CVSADM_ENTBAK);
}
else
{
(void) strcpy (entname, CVSADM_ENT);
(void) strcpy (entbak, CVSADM_ENTBAK);
}
fpin = open_file (entname, "r");
if (fgets (line, sizeof (line), fpin) == NULL)
{
(void) fclose (fpin);
return;
}
(void) fclose (fpin);
if (line[0] != '/')
{
rename_file (entname, entbak);
fpin = open_file (entbak, "r");
fpout = open_file (entname, "w+");
while (fgets (line, sizeof (line), fpin) != NULL)
{
if (line[0] == '/')
{
if (fputs (line, fpout) == EOF)
error (1, errno, "cannot write %s", CVSADM_ENT);
continue;
}
rev = line;
if ((ts = index (line, '|')) == NULL)
continue;
*ts++ = '\0';
if ((user = rindex (ts, ' ')) == NULL)
continue;
*user++ = '\0';
if ((cp = index (user, '|')) == NULL)
continue;
*cp = '\0';
opt = "";
#ifdef HAVE_RCS5
#ifdef HAD_RCS4
opt = "-V4";
#endif
#endif
if (fprintf (fpout, "/%s/%s/%s/%s/\n", user, rev, ts, opt) == EOF)
error (1, errno, "cannot write %s", CVSADM_ENT);
}
(void) fclose (fpin);
if (fclose (fpout) == EOF)
error (1, errno, "cannot close %s", entname);
/* clean up any old Files or Mod files */
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_FILE);
else
(void) strcpy (tmp, CVSADM_FILE);
if (isfile (tmp))
(void) unlink (tmp);
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_MOD);
else
(void) strcpy (tmp, CVSADM_MOD);
if (isfile (tmp))
(void) unlink (tmp);
}
}
/*
* Free up the memory associated with the data section of an ENTRIES type
* node
*/
static void
Entries_delproc (node)
Node *node;
{
Entnode *p;
p = (Entnode *) node->data;
free (p->version);
free (p->timestamp);
free (p->options);
if (p->tag)
free (p->tag);
if (p->date)
free (p->date);
free ((char *) p);
}
/*
* Get an Entries file list node, initialize it, and add it to the specified
* list
*/
static Node *
AddEntryNode (list, name, version, timestamp, options, tag, date)
List *list;
char *name;
char *version;
char *timestamp;
char *options;
char *tag;
char *date;
{
Node *p;
Entnode *entdata;
/* get a node and fill in the regular stuff */
p = getnode ();
p->type = ENTRIES;
p->delproc = Entries_delproc;
/* this one gets a key of the name for hashing */
p->key = xstrdup (name);
/* malloc the data parts and fill them in */
p->data = xmalloc (sizeof (Entnode));
entdata = (Entnode *) p->data;
entdata->version = xstrdup (version);
entdata->timestamp = xstrdup (timestamp);
entdata->options = xstrdup (options);
if (entdata->options == NULL)
entdata->options = xstrdup ("");/* must be non-NULL */
entdata->tag = xstrdup (tag);
entdata->date = xstrdup (date);
/* put the node into the list */
if (addnode (list, p) != 0)
error (0, 0, "Duplicate filename in entries file (%s) -- ignored",
name);
return (p);
}
/*
* Write out/Clear the CVS/Tag file.
*/
void
WriteTag (dir, tag, date)
char *dir;
char *tag;
char *date;
{
FILE *fout;
char tmp[PATH_MAX];
if (noexec)
return;
if (dir == NULL)
(void) strcpy (tmp, CVSADM_TAG);
else
(void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
if (tag || date)
{
fout = open_file (tmp, "w+");
if (tag)
{
if (fprintf (fout, "T%s\n", tag) == EOF)
error (1, errno, "write to %s failed", tmp);
}
else
{
if (fprintf (fout, "D%s\n", date) == EOF)
error (1, errno, "write to %s failed", tmp);
}
if (fclose (fout) == EOF)
error (1, errno, "cannot close %s", tmp);
}
else
(void) unlink_file (tmp);
}
/*
* Parse the CVS/Tag file for the current directory.
*/
void
ParseTag (tagp, datep)
char **tagp;
char **datep;
{
FILE *fp;
char line[MAXLINELEN];
char *cp;
if (tagp)
*tagp = (char *) NULL;
if (datep)
*datep = (char *) NULL;
fp = fopen (CVSADM_TAG, "r");
if (fp)
{
if (fgets (line, sizeof (line), fp) != NULL)
{
if ((cp = rindex (line, '\n')) != NULL)
*cp = '\0';
if (*line == 'T' && tagp)
*tagp = xstrdup (line + 1);
else if (*line == 'D' && datep)
*datep = xstrdup (line + 1);
}
(void) fclose (fp);
}
}