1*37cbc181Stobias /* $OpenBSD: annotate.c,v 1.43 2007/10/09 12:59:53 tobias Exp $ */ 2e0d97c9bSxsa /* 35e4c4390Stobias * Copyright (c) 2007 Tobias Stoeckmann <tobias@openbsd.org> 4efaa2accStobias * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org> 5e0d97c9bSxsa * 6e0d97c9bSxsa * Permission to use, copy, modify, and distribute this software for any 7e0d97c9bSxsa * purpose with or without fee is hereby granted, provided that the above 8e0d97c9bSxsa * copyright notice and this permission notice appear in all copies. 9e0d97c9bSxsa * 10e0d97c9bSxsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11e0d97c9bSxsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12e0d97c9bSxsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13e0d97c9bSxsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14e0d97c9bSxsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15e0d97c9bSxsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16e0d97c9bSxsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17e0d97c9bSxsa */ 18e0d97c9bSxsa 191f8531bdSotto #include <sys/param.h> 201f8531bdSotto #include <sys/dirent.h> 215e4c4390Stobias 225e4c4390Stobias #include <stdlib.h> 235e4c4390Stobias #include <string.h> 245e4c4390Stobias #include <time.h> 251f8531bdSotto #include <unistd.h> 26e0d97c9bSxsa 27e0d97c9bSxsa #include "cvs.h" 28e0d97c9bSxsa #include "remote.h" 29e0d97c9bSxsa 30e0d97c9bSxsa void cvs_annotate_local(struct cvs_file *); 31e0d97c9bSxsa 32*37cbc181Stobias extern char *cvs_specified_tag; 33*37cbc181Stobias 34e0d97c9bSxsa static int force_head = 0; 35e0d97c9bSxsa 36e0d97c9bSxsa struct cvs_cmd cvs_cmd_annotate = { 37e0d97c9bSxsa CVS_OP_ANNOTATE, 0, "annotate", 38e0d97c9bSxsa { "ann", "blame" }, 39e0d97c9bSxsa "Show last revision where each line was modified", 40e0d97c9bSxsa "[-flR] [-D date | -r rev] [file ...]", 41e0d97c9bSxsa "D:flRr:", 42e0d97c9bSxsa NULL, 43e0d97c9bSxsa cvs_annotate 44e0d97c9bSxsa }; 45e0d97c9bSxsa 46e0d97c9bSxsa int 47e0d97c9bSxsa cvs_annotate(int argc, char **argv) 48e0d97c9bSxsa { 49e0d97c9bSxsa int ch, flags; 50e0d97c9bSxsa char *arg = "."; 51e0d97c9bSxsa struct cvs_recursion cr; 52e0d97c9bSxsa 53e0d97c9bSxsa flags = CR_RECURSE_DIRS; 54e0d97c9bSxsa 55e0d97c9bSxsa while ((ch = getopt(argc, argv, cvs_cmd_annotate.cmd_opts)) != -1) { 56e0d97c9bSxsa switch (ch) { 57e0d97c9bSxsa case 'D': 58e0d97c9bSxsa break; 59e0d97c9bSxsa case 'f': 60e0d97c9bSxsa force_head = 1; 61e0d97c9bSxsa break; 62e0d97c9bSxsa case 'l': 63e0d97c9bSxsa flags &= ~CR_RECURSE_DIRS; 64e0d97c9bSxsa break; 65e0d97c9bSxsa case 'R': 66e0d97c9bSxsa break; 67e0d97c9bSxsa case 'r': 68efaa2accStobias cvs_specified_tag = optarg; 69e0d97c9bSxsa break; 70e0d97c9bSxsa default: 71e0d97c9bSxsa fatal("%s", cvs_cmd_annotate.cmd_synopsis); 72e0d97c9bSxsa } 73e0d97c9bSxsa } 74e0d97c9bSxsa 75e0d97c9bSxsa argc -= optind; 76e0d97c9bSxsa argv += optind; 77e0d97c9bSxsa 78e0d97c9bSxsa cr.enterdir = NULL; 79e0d97c9bSxsa cr.leavedir = NULL; 80e0d97c9bSxsa 81e0d97c9bSxsa if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 8280f6ca9bSjoris cvs_client_connect_to_server(); 83e0d97c9bSxsa cr.fileproc = cvs_client_sendfile; 84e0d97c9bSxsa 85e0d97c9bSxsa if (force_head == 1) 86e0d97c9bSxsa cvs_client_send_request("Argument -f"); 87e0d97c9bSxsa 88e0d97c9bSxsa if (!(flags & CR_RECURSE_DIRS)) 89e0d97c9bSxsa cvs_client_send_request("Argument -l"); 90e0d97c9bSxsa 91efaa2accStobias if (cvs_specified_tag != NULL) 92efaa2accStobias cvs_client_send_request("Argument -r%s", 93efaa2accStobias cvs_specified_tag); 94e0d97c9bSxsa } else { 95e0d97c9bSxsa cr.fileproc = cvs_annotate_local; 96e0d97c9bSxsa } 97e0d97c9bSxsa 98e0d97c9bSxsa cr.flags = flags; 99e0d97c9bSxsa 100e0d97c9bSxsa if (argc > 0) 101e0d97c9bSxsa cvs_file_run(argc, argv, &cr); 102e0d97c9bSxsa else 103e0d97c9bSxsa cvs_file_run(1, &arg, &cr); 104e0d97c9bSxsa 105e0d97c9bSxsa if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 106e0d97c9bSxsa cvs_client_send_files(argv, argc); 107e0d97c9bSxsa cvs_client_senddir("."); 108e0d97c9bSxsa cvs_client_send_request("annotate"); 109e0d97c9bSxsa cvs_client_get_responses(); 110e0d97c9bSxsa } 111e0d97c9bSxsa 112e0d97c9bSxsa return (0); 113e0d97c9bSxsa } 114e0d97c9bSxsa 115e0d97c9bSxsa void 116e0d97c9bSxsa cvs_annotate_local(struct cvs_file *cf) 117e0d97c9bSxsa { 1185e4c4390Stobias int i; 1195e4c4390Stobias char date[10], rnum[13], *p; 120*37cbc181Stobias RCSNUM *bnum, *rev; 121efaa2accStobias struct cvs_line *line; 1225e4c4390Stobias struct cvs_line **alines; 1235e4c4390Stobias 124e0d97c9bSxsa cvs_log(LP_TRACE, "cvs_annotate_local(%s)", cf->file_path); 125e0d97c9bSxsa 12651ef6581Sjoris cvs_file_classify(cf, cvs_directory_tag); 127e0d97c9bSxsa 1285e4c4390Stobias if (cf->file_status == FILE_UNKNOWN || cf->file_status == FILE_UNLINK || 1295e4c4390Stobias cf->file_type != CVS_FILE) 130e0d97c9bSxsa return; 131e0d97c9bSxsa 132*37cbc181Stobias if (cvs_specified_tag != NULL) { 133f1f4c0cfStobias if ((rev = rcs_translate_tag(cvs_specified_tag, 134f1f4c0cfStobias cf->file_rcs)) == NULL) { 135f1f4c0cfStobias if (!force_head) 136f1f4c0cfStobias /* Stick at weird GNU cvs, ignore error. */ 137f1f4c0cfStobias return; 138*37cbc181Stobias 139f1f4c0cfStobias rev = rcsnum_alloc(); 140f1f4c0cfStobias rcsnum_cpy(cf->file_rcs->rf_head, rev, 0); 141f1f4c0cfStobias } 1425e4c4390Stobias 143*37cbc181Stobias /* 144*37cbc181Stobias * If this is a revision in a branch, we have to go first 145*37cbc181Stobias * from HEAD to branch, then down to 1.1. After that, take 146*37cbc181Stobias * annotated branch and go up to branch revision. This must 147*37cbc181Stobias * be done this way due to different handling of "a" and 148*37cbc181Stobias * "d" in rcs file for annotation. 149*37cbc181Stobias */ 150*37cbc181Stobias if (!RCSNUM_ISBRANCHREV(rev)) { 151*37cbc181Stobias bnum = rev; 152*37cbc181Stobias } else { 153*37cbc181Stobias bnum = rcsnum_alloc(); 154*37cbc181Stobias rcsnum_cpy(rev, bnum, 2); 1555e4c4390Stobias } 156*37cbc181Stobias 157*37cbc181Stobias rcs_rev_getlines(cf->file_rcs, bnum, &alines); 158*37cbc181Stobias 159*37cbc181Stobias /* 160*37cbc181Stobias * Go into branch and receive annotations for branch revision, 161*37cbc181Stobias * with inverted "a" and "d" meaning. 162*37cbc181Stobias */ 163*37cbc181Stobias if (bnum != rev) { 164*37cbc181Stobias rcs_annotate_getlines(cf->file_rcs, rev, &alines); 165*37cbc181Stobias rcsnum_free(bnum); 1665e4c4390Stobias } 167efaa2accStobias rcsnum_free(rev); 168*37cbc181Stobias } else { 169*37cbc181Stobias rcs_rev_getlines(cf->file_rcs, cf->file_rcs->rf_head, &alines); 1705e4c4390Stobias } 1715e4c4390Stobias 1725e4c4390Stobias /* Stick at weird GNU cvs, ignore error. */ 1735e4c4390Stobias if (alines == NULL) 1745e4c4390Stobias return; 1755e4c4390Stobias 1765e4c4390Stobias cvs_log(LP_RCS, "Annotations for %s", cf->file_path); 1775e4c4390Stobias cvs_log(LP_RCS, "***************"); 1785e4c4390Stobias 1795e4c4390Stobias for (i = 0; alines[i] != NULL; i++) { 180efaa2accStobias line = alines[i]; 1815e4c4390Stobias 182efaa2accStobias rcsnum_tostr(line->l_delta->rd_num, rnum, sizeof(rnum)); 183efaa2accStobias strftime(date, sizeof(date), "%d-%b-%y", 184efaa2accStobias &(line->l_delta->rd_date)); 185efaa2accStobias if (line->l_len && line->l_line[line->l_len - 1] == '\n') 186efaa2accStobias line->l_line[line->l_len - 1] = '\0'; 187efaa2accStobias else { 188efaa2accStobias p = xmalloc(line->l_len + 1); 189efaa2accStobias memcpy(p, line->l_line, line->l_len); 190efaa2accStobias p[line->l_len] = '\0'; 191efaa2accStobias 192efaa2accStobias if (line->l_needsfree) 193efaa2accStobias xfree(line->l_line); 194efaa2accStobias line->l_line = p; 195efaa2accStobias line->l_len++; 196efaa2accStobias line->l_needsfree = 1; 1975e4c4390Stobias } 1985e4c4390Stobias cvs_printf("%-12.12s (%-8.8s %s): %s\n", rnum, 199efaa2accStobias line->l_delta->rd_author, date, line->l_line); 2005e4c4390Stobias 201efaa2accStobias if (line->l_needsfree) 202efaa2accStobias xfree(line->l_line); 203efaa2accStobias xfree(line); 2045e4c4390Stobias } 2055e4c4390Stobias 2065e4c4390Stobias xfree(alines); 207e0d97c9bSxsa } 208