summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Stoeckmann <tobias@cvs.openbsd.org>2007-09-13 13:10:58 +0000
committerTobias Stoeckmann <tobias@cvs.openbsd.org>2007-09-13 13:10:58 +0000
commite149a4581854b359e674cd5b1a129eb8549b09b1 (patch)
tree3d8ba2761956633f4145b85b3bb978526add5baa
parent67529b284be16edf396f300e8e1f24219d36d2c3 (diff)
Added annotate support for local and remote repositories. Behaves like
GNU cvs but is a little faster. OK joris@, ray@, xsa@
-rw-r--r--usr.bin/cvs/annotate.c70
-rw-r--r--usr.bin/cvs/rcs.c131
-rw-r--r--usr.bin/cvs/rcs.h6
-rw-r--r--usr.bin/cvs/util.h4
4 files changed, 187 insertions, 24 deletions
diff --git a/usr.bin/cvs/annotate.c b/usr.bin/cvs/annotate.c
index df80a3f1da6..b112211c596 100644
--- a/usr.bin/cvs/annotate.c
+++ b/usr.bin/cvs/annotate.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: annotate.c,v 1.37 2007/02/22 06:42:09 otto Exp $ */
+/* $OpenBSD: annotate.c,v 1.38 2007/09/13 13:10:57 tobias Exp $ */
/*
* Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org>
+ * Copyright (c) 2007 Tobias Stoeckmann <tobias@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
@@ -17,6 +18,10 @@
#include <sys/param.h>
#include <sys/dirent.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
#include <unistd.h>
#include "cvs.h"
@@ -108,15 +113,68 @@ cvs_annotate(int argc, char **argv)
void
cvs_annotate_local(struct cvs_file *cf)
{
+ int i;
+ char date[10], rnum[13], *p;
+ RCSNUM *crev;
+ struct cvs_line **alines;
+
cvs_log(LP_TRACE, "cvs_annotate_local(%s)", cf->file_path);
cvs_file_classify(cf, NULL);
- if (cf->file_status == FILE_UNKNOWN ||
- cf->file_status == FILE_UNLINK)
+ if (cf->file_status == FILE_UNKNOWN || cf->file_status == FILE_UNLINK ||
+ cf->file_type != CVS_FILE)
return;
- cvs_printf("Annotations for %s", cf->file_name);
- cvs_printf("\n***************\n");
- cvs_printf("no code yet\n");
+ if (rev == NULL)
+ rcs_rev_getlines(cf->file_rcs, cf->file_rcsrev, &alines);
+ else {
+ crev = rcsnum_parse(rev);
+
+ if (rcsnum_cmp(crev, cf->file_rcsrev, 0) < 0) {
+ if (!force_head) {
+ /* Stick at weird GNU cvs, ignore error. */
+ rcsnum_free(crev);
+ return;
+ }
+ rcsnum_cpy(cf->file_rcsrev, crev, 0);
+ }
+ rcs_rev_getlines(cf->file_rcs, crev, &alines);
+ rcsnum_free(crev);
+ }
+
+ /* Stick at weird GNU cvs, ignore error. */
+ if (alines == NULL)
+ return;
+
+ cvs_log(LP_RCS, "Annotations for %s", cf->file_path);
+ cvs_log(LP_RCS, "***************");
+
+ for (i = 0; alines[i] != NULL; i++) {
+ rcsnum_tostr(alines[i]->l_delta->rd_num, rnum, sizeof(rnum));
+ strftime(date, sizeof(date), "%d-%b-%y",
+ &(alines[i]->l_delta->rd_date));
+ if (alines[i]->l_len &&
+ alines[i]->l_line[alines[i]->l_len - 1] == '\n')
+ alines[i]->l_line[alines[i]->l_len - 1] = '\0';
+ else {
+ p = xmalloc(alines[i]->l_len + 1);
+ memcpy(p, alines[i]->l_line, alines[i]->l_len);
+ p[alines[i]->l_len] = '\0';
+
+ if (alines[i]->l_needsfree)
+ xfree(alines[i]->l_line);
+ alines[i]->l_line = p;
+ alines[i]->l_len++;
+ alines[i]->l_needsfree = 1;
+ }
+ cvs_printf("%-12.12s (%-8.8s %s): %s\n", rnum,
+ alines[i]->l_delta->rd_author, date, alines[i]->l_line);
+
+ if (alines[i]->l_needsfree)
+ xfree(alines[i]->l_line);
+ xfree(alines[i]);
+ }
+
+ xfree(alines);
}
diff --git a/usr.bin/cvs/rcs.c b/usr.bin/cvs/rcs.c
index 37a3bd1e6ce..0744daddcfc 100644
--- a/usr.bin/cvs/rcs.c
+++ b/usr.bin/cvs/rcs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcs.c,v 1.217 2007/09/07 23:05:04 joris Exp $ */
+/* $OpenBSD: rcs.c,v 1.218 2007/09/13 13:10:57 tobias Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -73,6 +73,10 @@
#define RCS_NOSCOL 0x01 /* no terminating semi-colon */
#define RCS_VOPT 0x02 /* value is optional */
+#define ANNOTATE_NEVER 0
+#define ANNOTATE_NOW 1
+#define ANNOTATE_LATER 2
+
/* opaque parse data */
struct rcs_pdata {
u_int rp_lines;
@@ -219,7 +223,8 @@ static const char *rcs_errstrs[] = {
int rcs_errno = RCS_ERR_NOERR;
-int rcs_patch_lines(struct cvs_lines *, struct cvs_lines *);
+int rcs_patch_lines(struct cvs_lines *, struct cvs_lines *,
+ struct cvs_line **, struct rcs_delta *);
static void rcs_parse_init(RCSFILE *);
static int rcs_parse_admin(RCSFILE *);
static int rcs_parse_delta(RCSFILE *);
@@ -1022,7 +1027,8 @@ rcs_tag_resolve(RCSFILE *file, const char *tag)
}
int
-rcs_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines)
+rcs_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines,
+ struct cvs_line **alines, struct rcs_delta *rdp)
{
u_char op;
char *ep;
@@ -1075,7 +1081,12 @@ rcs_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines)
for (i = 0; (i < nbln) && (dlp != NULL); i++) {
ndlp = TAILQ_NEXT(dlp, l_list);
TAILQ_REMOVE(&(dlines->l_lines), dlp, l_list);
- xfree(dlp);
+ if (alines != NULL && dlp->l_line != NULL) {
+ dlp->l_delta = rdp;
+ alines[dlp->l_lineno_orig - 1] =
+ dlp;
+ } else
+ xfree(dlp);
dlp = ndlp;
/* last line is gone - reset dlp */
if (dlp == NULL) {
@@ -1091,6 +1102,12 @@ rcs_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines)
if (lp == NULL)
fatal("truncated RCS patch");
TAILQ_REMOVE(&(plines->l_lines), lp, l_list);
+ if (alines != NULL) {
+ if (lp->l_needsfree == 1)
+ xfree(lp->l_line);
+ lp->l_line = NULL;
+ lp->l_needsfree = 0;
+ }
TAILQ_INSERT_AFTER(&(dlines->l_lines), dlp,
lp, l_list);
dlp = lp;
@@ -2623,14 +2640,15 @@ rcs_translate_tag(const char *revstr, RCSFILE *rfp)
* return it as a pointer to a struct cvs_lines.
*/
struct cvs_lines *
-rcs_rev_getlines(RCSFILE *rfp, RCSNUM *frev)
+rcs_rev_getlines(RCSFILE *rfp, RCSNUM *frev, struct cvs_line ***alines)
{
size_t plen;
- int i, done, nextroot;
+ int annotate, done, i, nextroot;
RCSNUM *tnum, *bnum;
struct rcs_branch *brp;
- struct rcs_delta *hrdp, *trdp, *rdp;
+ struct rcs_delta *hrdp, *prdp, *rdp, *trdp;
u_char *patch;
+ struct cvs_line *line, *nline;
struct cvs_lines *dlines, *plines;
if ((hrdp = rcs_findrev(rfp, rfp->rf_head)) == NULL)
@@ -2648,14 +2666,43 @@ rcs_rev_getlines(RCSFILE *rfp, RCSNUM *frev)
bnum = tnum;
}
+ if (alines != NULL) {
+ /* start with annotate first at requested revision */
+ annotate = ANNOTATE_LATER;
+ *alines = NULL;
+ } else
+ annotate = ANNOTATE_NEVER;
+
dlines = cvs_splitlines(hrdp->rd_text, hrdp->rd_tlen);
done = 0;
rdp = hrdp;
- if (!rcsnum_differ(rdp->rd_num, bnum))
- goto next;
+ if (!rcsnum_differ(rdp->rd_num, bnum)) {
+ if (annotate == ANNOTATE_LATER) {
+ /* found requested revision for annotate */
+ i = 0;
+ TAILQ_FOREACH(line, &(dlines->l_lines), l_list) {
+ line->l_lineno_orig = line->l_lineno;
+ i++;
+ }
+
+ *alines = xcalloc(i + 1, sizeof(struct cvs_line *));
+ (*alines)[i] = NULL;
+ annotate = ANNOTATE_NOW;
+ /* annotate down to 1.1 from where we are */
+ if (bnum == tnum)
+ bnum = rcsnum_alloc();
+ bnum = rcsnum_parse("1.1");
+ if (!rcsnum_differ(rdp->rd_num, bnum)) {
+ goto next;
+ }
+ } else
+ goto next;
+ }
+
+ prdp = hrdp;
if ((rdp = rcs_findrev(rfp, hrdp->rd_next)) == NULL)
goto done;
@@ -2680,12 +2727,37 @@ again:
plen = rdp->rd_tlen;
patch = rdp->rd_text;
plines = cvs_splitlines(patch, plen);
- rcs_patch_lines(dlines, plines);
+ if (annotate == ANNOTATE_NOW)
+ rcs_patch_lines(dlines, plines, *alines, prdp);
+ else
+ rcs_patch_lines(dlines, plines, NULL, NULL);
cvs_freelines(plines);
- if (!rcsnum_differ(rdp->rd_num, bnum))
- break;
+ if (!rcsnum_differ(rdp->rd_num, bnum)) {
+ if (annotate != ANNOTATE_LATER)
+ break;
+
+ /* found requested revision for annotate */
+ i = 0;
+ TAILQ_FOREACH(line, &(dlines->l_lines), l_list) {
+ line->l_lineno_orig = line->l_lineno;
+ i++;
+ }
+ *alines = xcalloc(i + 1, sizeof(struct cvs_line *));
+ (*alines)[i] = NULL;
+ annotate = ANNOTATE_NOW;
+
+ /* annotate down to 1.1 from where we are */
+ if (bnum == tnum)
+ bnum = rcsnum_alloc();
+ bnum = rcsnum_parse("1.1");
+
+ if (!rcsnum_differ(rdp->rd_num, bnum))
+ break;
+ }
+
+ prdp = rdp;
rdp = trdp;
}
@@ -2705,8 +2777,18 @@ next:
break;
}
- if (brp == NULL)
+ if (brp == NULL) {
+ if (annotate != ANNOTATE_NEVER) {
+ if (*alines != NULL)
+ xfree(*alines);
+ *alines = NULL;
+ cvs_freelines(dlines);
+ if (bnum != tnum)
+ rcsnum_free(bnum);
+ return (NULL);
+ }
fatal("expected branch not found on branch list");
+ }
if ((rdp = rcs_findrev(rfp, brp->rb_num)) == NULL)
fatal("rcs_rev_getlines: failed to get delta for target rev");
@@ -2714,6 +2796,25 @@ next:
goto again;
}
done:
+ /* put remaining lines of 1.1 into annotate buffer */
+ if (annotate == ANNOTATE_NOW) {
+ for (line = TAILQ_FIRST(&(dlines->l_lines));
+ line != NULL; line = nline) {
+ nline = TAILQ_NEXT(line, l_list);
+ TAILQ_REMOVE(&(dlines->l_lines), line, l_list);
+ if (line->l_line == NULL) {
+ xfree(line);
+ continue;
+ }
+
+ line->l_delta = rdp;
+ (*alines)[line->l_lineno_orig - 1] = line;
+ }
+
+ cvs_freelines(dlines);
+ dlines = NULL;
+ }
+
if (bnum != tnum)
rcsnum_free(bnum);
@@ -2738,7 +2839,7 @@ rcs_rev_getbuf(RCSFILE *rfp, RCSNUM *rev, int mode)
BUF *bp;
expand = 0;
- lines = rcs_rev_getlines(rfp, rev);
+ lines = rcs_rev_getlines(rfp, rev, NULL);
bp = cvs_buf_alloc(1024, BUF_AUTOEXT);
if (!(mode & RCS_KWEXP_NONE)) {
@@ -2785,7 +2886,7 @@ rcs_rev_write_fd(RCSFILE *rfp, RCSNUM *rev, int fd, int mode)
extern int print_stdout;
expand = 0;
- lines = rcs_rev_getlines(rfp, rev);
+ lines = rcs_rev_getlines(rfp, rev, NULL);
if (!(mode & RCS_KWEXP_NONE)) {
if (rfp->rf_expand != NULL)
diff --git a/usr.bin/cvs/rcs.h b/usr.bin/cvs/rcs.h
index f3c2e763a5a..b4e294207cb 100644
--- a/usr.bin/cvs/rcs.h
+++ b/usr.bin/cvs/rcs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcs.h,v 1.77 2007/06/01 17:47:47 niallo Exp $ */
+/* $OpenBSD: rcs.h,v 1.78 2007/09/13 13:10:57 tobias Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -215,6 +215,7 @@ typedef struct rcs_file {
} RCSFILE;
extern int rcs_errno;
+struct cvs_line;
struct cvs_lines;
RCSFILE *rcs_open(const char *, int, int, ...);
@@ -260,7 +261,8 @@ const char *rcs_errstr(int);
void rcs_write(RCSFILE *);
void rcs_rev_write_stmp(RCSFILE *, RCSNUM *, char *, int);
void rcs_rev_write_fd(RCSFILE *, RCSNUM *, int, int);
-struct cvs_lines *rcs_rev_getlines(RCSFILE *, RCSNUM *);
+struct cvs_lines *rcs_rev_getlines(RCSFILE *, RCSNUM *,
+ struct cvs_line ***);
BUF *rcs_rev_getbuf(RCSFILE *, RCSNUM *, int);
int rcs_kflag_get(const char *);
diff --git a/usr.bin/cvs/util.h b/usr.bin/cvs/util.h
index fb73a9e17d7..1e80fa00bff 100644
--- a/usr.bin/cvs/util.h
+++ b/usr.bin/cvs/util.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.h,v 1.21 2007/09/04 19:07:04 tobias Exp $ */
+/* $OpenBSD: util.h,v 1.22 2007/09/13 13:10:57 tobias Exp $ */
/*
* Copyright (c) 2006 Niall O'Higgins <niallo@openbsd.org>
* All rights reserved.
@@ -45,9 +45,11 @@ void cvs_freeargv(char **, int);
u_int cvs_revision_select(RCSFILE *, char *);
struct cvs_line {
+ struct rcs_delta *l_delta;
u_char *l_line;
size_t l_len;
int l_lineno;
+ int l_lineno_orig;
int l_needsfree;
TAILQ_ENTRY(cvs_line) l_list;
};