File: [local] / src / usr.bin / cvs / entries.c (download)
Revision 1.58, Tue Jun 6 05:13:39 2006 UTC (18 years ago) by joris
Branch: MAIN
Changes since 1.57: +2 -2 lines
add support for the -D option of update,
-D allows you to update a file to matching a specified date:
opencvs up -D "1 hour ago" foobar will take the first matching
revision that was commited 1 hour ago.
|
/* $OpenBSD: entries.c,v 1.58 2006/06/06 05:13:39 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include "cvs.h"
#include "log.h"
#define CVS_ENTRIES_NFIELDS 6
#define CVS_ENTRIES_DELIM '/'
static struct cvs_ent_line *ent_get_line(CVSENTRIES *, const char *);
CVSENTRIES *
cvs_ent_open(const char *dir)
{
FILE *fp;
size_t len;
CVSENTRIES *ep;
char *p, buf[MAXPATHLEN];
struct cvs_ent *ent;
struct cvs_ent_line *line;
ep = (CVSENTRIES *)xmalloc(sizeof(*ep));
memset(ep, 0, sizeof(*ep));
cvs_path_cat(dir, CVS_PATH_ENTRIES, buf, sizeof(buf));
ep->cef_path = xstrdup(buf);
cvs_path_cat(dir, CVS_PATH_BACKUPENTRIES, buf, sizeof(buf));
ep->cef_bpath = xstrdup(buf);
cvs_path_cat(dir, CVS_PATH_LOGENTRIES, buf, sizeof(buf));
ep->cef_lpath = xstrdup(buf);
TAILQ_INIT(&(ep->cef_ent));
if ((fp = fopen(ep->cef_path, "r")) != NULL) {
while (fgets(buf, sizeof(buf), fp)) {
len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = '\0';
if (buf[0] == 'D' && buf[1] == '\0')
break;
line = (struct cvs_ent_line *)xmalloc(sizeof(*line));
line->buf = xstrdup(buf);
TAILQ_INSERT_TAIL(&(ep->cef_ent), line, entries_list);
}
(void)fclose(fp);
}
if ((fp = fopen(ep->cef_lpath, "r")) != NULL) {
while (fgets(buf, sizeof(buf), fp)) {
len = strlen(buf);
if (len > 0 && buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
p = &buf[1];
if (buf[0] == 'A') {
line = xmalloc(sizeof(*line));
line->buf = xstrdup(p);
TAILQ_INSERT_TAIL(&(ep->cef_ent), line,
entries_list);
} else if (buf[0] == 'R') {
ent = cvs_ent_parse(p);
line = ent_get_line(ep, ent->ce_name);
if (line != NULL)
TAILQ_REMOVE(&(ep->cef_ent), line,
entries_list);
cvs_ent_free(ent);
}
}
(void)fclose(fp);
}
return (ep);
}
struct cvs_ent *
cvs_ent_parse(const char *entry)
{
int i;
struct cvs_ent *ent;
char *fields[CVS_ENTRIES_NFIELDS], *buf, *sp, *dp;
buf = xstrdup(entry);
sp = buf;
i = 0;
do {
dp = strchr(sp, CVS_ENTRIES_DELIM);
if (dp != NULL)
*(dp++) = '\0';
fields[i++] = sp;
sp = dp;
} while (dp != NULL && i < CVS_ENTRIES_NFIELDS);
if (i < CVS_ENTRIES_NFIELDS)
fatal("missing fields in entry line '%s'", entry);
ent = (struct cvs_ent *)xmalloc(sizeof(*ent));
ent->ce_buf = buf;
if (*fields[0] == '\0')
ent->ce_type = CVS_ENT_FILE;
else if (*fields[0] == 'D')
ent->ce_type = CVS_ENT_DIR;
else
ent->ce_type = CVS_ENT_NONE;
ent->ce_status = CVS_ENT_REG;
ent->ce_name = fields[1];
ent->ce_rev = NULL;
if (ent->ce_type == CVS_ENT_FILE) {
if (*fields[2] == '-') {
ent->ce_status = CVS_ENT_REMOVED;
sp = fields[2] + 1;
} else {
sp = fields[2];
if (fields[2][0] == '0' && fields[2][1] == '\0')
ent->ce_status = CVS_ENT_ADDED;
}
if ((ent->ce_rev = rcsnum_parse(sp)) == NULL)
fatal("failed to parse entry revision '%s'", entry);
if (strcmp(fields[3], CVS_DATE_DUMMY) == 0 ||
strncmp(fields[3], "Initial ", 8) == 0 ||
strncmp(fields[3], "Result of merge", 15) == 0)
ent->ce_mtime = CVS_DATE_DMSEC;
else
ent->ce_mtime = cvs_date_parse(fields[3]);
}
ent->ce_conflict = fields[3];
if ((dp = strchr(ent->ce_conflict, '+')) != NULL)
*dp = '\0';
else
ent->ce_conflict = NULL;
if (strcmp(fields[4], ""))
ent->ce_opts = fields[4];
else
ent->ce_opts = NULL;
if (strcmp(fields[5], ""))
ent->ce_tag = fields[5] + 1;
else
ent->ce_tag = NULL;
return (ent);
}
struct cvs_ent *
cvs_ent_get(CVSENTRIES *ep, const char *name)
{
struct cvs_ent *ent;
struct cvs_ent_line *l;
l = ent_get_line(ep, name);
if (l == NULL)
return (NULL);
ent = cvs_ent_parse(l->buf);
return (ent);
}
int
cvs_ent_exists(CVSENTRIES *ep, const char *name)
{
struct cvs_ent_line *l;
l = ent_get_line(ep, name);
if (l == NULL)
return (0);
return (1);
}
void
cvs_ent_close(CVSENTRIES *ep, int writefile)
{
FILE *fp;
struct cvs_ent_line *l;
if (writefile) {
if ((fp = fopen(ep->cef_bpath, "w")) == NULL)
fatal("cvs_ent_close: failed to write %s",
ep->cef_path);
}
while ((l = TAILQ_FIRST(&(ep->cef_ent))) != NULL) {
if (writefile) {
fputs(l->buf, fp);
fputc('\n', fp);
}
TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
xfree(l->buf);
xfree(l);
}
if (writefile) {
fputc('D', fp);
(void)fclose(fp);
if (rename(ep->cef_bpath, ep->cef_path) == -1)
fatal("cvs_ent_close: %s: %s", ep->cef_path,
strerror(errno));
(void)unlink(ep->cef_lpath);
}
xfree(ep->cef_path);
xfree(ep->cef_bpath);
xfree(ep->cef_lpath);
xfree(ep);
}
void
cvs_ent_add(CVSENTRIES *ep, const char *line)
{
FILE *fp;
struct cvs_ent_line *l;
struct cvs_ent *ent;
if ((ent = cvs_ent_parse(line)) == NULL)
fatal("cvs_ent_add: parsing failed '%s'", line);
l = ent_get_line(ep, ent->ce_name);
if (l != NULL)
cvs_ent_remove(ep, ent->ce_name);
cvs_ent_free(ent);
cvs_log(LP_TRACE, "cvs_ent_add(%s, %s)", ep->cef_path, line);
if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
fatal("cvs_ent_add: failed to open '%s'", ep->cef_lpath);
fputc('A', fp);
fputs(line, fp);
fputc('\n', fp);
(void)fclose(fp);
l = (struct cvs_ent_line *)xmalloc(sizeof(*l));
l->buf = xstrdup(line);
TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list);
}
void
cvs_ent_remove(CVSENTRIES *ep, const char *name)
{
FILE *fp;
struct cvs_ent_line *l;
cvs_log(LP_TRACE, "cvs_ent_remove(%s, %s)", ep->cef_path, name);
l = ent_get_line(ep, name);
if (l == NULL)
return;
if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
fatal("cvs_ent_remove: failed to open '%s'",
ep->cef_lpath);
fputc('R', fp);
fputs(l->buf, fp);
fputc('\n', fp);
(void)fclose(fp);
TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
xfree(l->buf);
xfree(l);
}
void
cvs_ent_free(struct cvs_ent *ent)
{
if (ent->ce_rev != NULL)
rcsnum_free(ent->ce_rev);
xfree(ent->ce_buf);
xfree(ent);
}
static struct cvs_ent_line *
ent_get_line(CVSENTRIES *ep, const char *name)
{
char *p, *s;
struct cvs_ent_line *l;
TAILQ_FOREACH(l, &(ep->cef_ent), entries_list) {
if (l->buf[0] == 'D')
p = &(l->buf[2]);
else
p = &(l->buf[1]);
if ((s = strchr(p, '/')) == NULL)
fatal("ent_get_line: bad entry line '%s'", l->buf);
*s = '\0';
if (!strcmp(p, name)) {
*s = '/';
return (l);
}
*s = '/';
}
return (NULL);
}