1*528e2d0cStobias /* $OpenBSD: getlog.c,v 1.80 2008/01/12 22:39:32 tobias Exp $ */ 26c121f58Sjfb /* 37573783fSxsa * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org> 4e8c16debSjoris * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 56c121f58Sjfb * 6e8c16debSjoris * Permission to use, copy, modify, and distribute this software for any 7e8c16debSjoris * purpose with or without fee is hereby granted, provided that the above 8e8c16debSjoris * copyright notice and this permission notice appear in all copies. 96c121f58Sjfb * 10e8c16debSjoris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11e8c16debSjoris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12e8c16debSjoris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13e8c16debSjoris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14e8c16debSjoris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15e8c16debSjoris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16e8c16debSjoris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 176c121f58Sjfb */ 186c121f58Sjfb 191f8531bdSotto #include <unistd.h> 201f8531bdSotto #include <string.h> 21449bca81Sniallo #include <errno.h> 226c121f58Sjfb 236c121f58Sjfb #include "cvs.h" 249fac60a5Sjoris #include "remote.h" 256c121f58Sjfb 267573783fSxsa #define L_HEAD 0x01 277573783fSxsa #define L_HEAD_DESCR 0x02 287573783fSxsa #define L_NAME 0x04 297573783fSxsa #define L_NOTAGS 0x08 308371e6b6Sxsa #define L_LOGINS 0x10 318371e6b6Sxsa #define L_STATES 0x20 327573783fSxsa 33e8c16debSjoris void cvs_log_local(struct cvs_file *); 3469d26cb1Sxsa 358371e6b6Sxsa static void log_rev_print(struct rcs_delta *); 368371e6b6Sxsa 377573783fSxsa int runflags = 0; 38e8c16debSjoris char *logrev = NULL; 398371e6b6Sxsa char *slist = NULL; 408371e6b6Sxsa char *wlist = NULL; 416c121f58Sjfb 42e4276007Sjfb struct cvs_cmd cvs_cmd_log = { 4362dc927bSjoris CVS_OP_LOG, 0, "log", 44e4276007Sjfb { "lo" }, 45e4276007Sjfb "Print out history information for files", 46e4276007Sjfb "[-bhlNRt] [-d dates] [-r revisions] [-s states] [-w logins]", 47a347ceb8Sxsa "bd:hlNRr:s:tw:", 48e4276007Sjfb NULL, 49e8c16debSjoris cvs_getlog 50e4276007Sjfb }; 51e4276007Sjfb 52449bca81Sniallo struct cvs_cmd cvs_cmd_rlog = { 53449bca81Sniallo CVS_OP_RLOG, 0, "rlog", 54449bca81Sniallo { "rlo" }, 55449bca81Sniallo "Print out history information for files", 56449bca81Sniallo "[-bhlNRt] [-d dates] [-r revisions] [-s states] [-w logins]", 57449bca81Sniallo "bd:hlNRr:s:tw:", 58449bca81Sniallo NULL, 59449bca81Sniallo cvs_getlog 60449bca81Sniallo }; 61449bca81Sniallo 62e8c16debSjoris int 63e8c16debSjoris cvs_getlog(int argc, char **argv) 646c121f58Sjfb { 65f2271752Stobias int ch, flags, i; 66e8c16debSjoris char *arg = "."; 67e8c16debSjoris struct cvs_recursion cr; 686c121f58Sjfb 69e8c16debSjoris rcsnum_flags |= RCSNUM_NO_MAGIC; 70e8c16debSjoris flags = CR_RECURSE_DIRS; 71e8c16debSjoris 72e8c16debSjoris while ((ch = getopt(argc, argv, cvs_cmd_log.cmd_opts)) != -1) { 7316cfc147Sjoris switch (ch) { 747573783fSxsa case 'h': 757573783fSxsa runflags |= L_HEAD; 767573783fSxsa break; 776c121f58Sjfb case 'l': 78e8c16debSjoris flags &= ~CR_RECURSE_DIRS; 796c121f58Sjfb break; 807573783fSxsa case 'N': 817573783fSxsa runflags |= L_NOTAGS; 827573783fSxsa break; 837573783fSxsa case 'R': 847573783fSxsa runflags |= L_NAME; 85*528e2d0cStobias break; 866c121f58Sjfb case 'r': 87e8c16debSjoris logrev = optarg; 8884c3cb67Sxsa break; 898371e6b6Sxsa case 's': 908371e6b6Sxsa runflags |= L_STATES; 918371e6b6Sxsa slist = optarg; 928371e6b6Sxsa break; 937573783fSxsa case 't': 947573783fSxsa runflags |= L_HEAD_DESCR; 957573783fSxsa break; 968371e6b6Sxsa case 'w': 978371e6b6Sxsa runflags |= L_LOGINS; 988371e6b6Sxsa wlist = optarg; 998371e6b6Sxsa break; 1006c121f58Sjfb default: 101e8c16debSjoris fatal("%s", cvs_cmd_log.cmd_synopsis); 1026c121f58Sjfb } 1036c121f58Sjfb } 1046c121f58Sjfb 105e8c16debSjoris argc -= optind; 106e8c16debSjoris argv += optind; 1076c121f58Sjfb 108f2271752Stobias if (cvs_cmdop == CVS_OP_RLOG) { 109f2271752Stobias if (argc == 0) 110f2271752Stobias return 0; 111f2271752Stobias 112f2271752Stobias for (i = 0; i < argc; i++) 113f2271752Stobias if (argv[i][0] == '/') 114f2271752Stobias fatal("Absolute path name is invalid: %s", 115f2271752Stobias argv[i]); 116f2271752Stobias } 117f2271752Stobias 118e8c16debSjoris cr.enterdir = NULL; 119e8c16debSjoris cr.leavedir = NULL; 1209fac60a5Sjoris 1219fac60a5Sjoris if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 12280f6ca9bSjoris cvs_client_connect_to_server(); 1239fac60a5Sjoris cr.fileproc = cvs_client_sendfile; 1249fac60a5Sjoris 1257573783fSxsa if (runflags & L_HEAD) 1267573783fSxsa cvs_client_send_request("Argument -h"); 1277573783fSxsa 1289fac60a5Sjoris if (!(flags & CR_RECURSE_DIRS)) 1299fac60a5Sjoris cvs_client_send_request("Argument -l"); 1309fac60a5Sjoris 1317573783fSxsa if (runflags & L_NOTAGS) 1327573783fSxsa cvs_client_send_request("Argument -N"); 1337573783fSxsa 1347573783fSxsa if (runflags & L_NAME) 1357573783fSxsa cvs_client_send_request("Argument -R"); 1367573783fSxsa 1379fac60a5Sjoris if (logrev != NULL) 1389fac60a5Sjoris cvs_client_send_request("Argument -r%s", logrev); 1397573783fSxsa 1408371e6b6Sxsa if (runflags & L_STATES) 1418371e6b6Sxsa cvs_client_send_request("Argument -s%s", slist); 1428371e6b6Sxsa 1437573783fSxsa if (runflags & L_HEAD_DESCR) 1447573783fSxsa cvs_client_send_request("Argument -t"); 1458371e6b6Sxsa 1468371e6b6Sxsa if (runflags & L_LOGINS) 1478371e6b6Sxsa cvs_client_send_request("Argument -w%s", wlist); 1489fac60a5Sjoris } else { 149e0b2359bSxsa if (cvs_cmdop == CVS_OP_RLOG && 150449bca81Sniallo chdir(current_cvsroot->cr_dir) == -1) 15186fbe768Sxsa fatal("cvs_getlog: %s", strerror(errno)); 152449bca81Sniallo 153bc5d89feSjoris cr.fileproc = cvs_log_local; 1549fac60a5Sjoris } 1559fac60a5Sjoris 156e8c16debSjoris cr.flags = flags; 15769d26cb1Sxsa 158f2271752Stobias if (cvs_cmdop == CVS_OP_LOG || 159f2271752Stobias current_cvsroot->cr_method == CVS_METHOD_LOCAL) { 160e8c16debSjoris if (argc > 0) 161e8c16debSjoris cvs_file_run(argc, argv, &cr); 16225c4314aSjfb else 163e8c16debSjoris cvs_file_run(1, &arg, &cr); 164f2271752Stobias } 16525c4314aSjfb 1669fac60a5Sjoris if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 1679fac60a5Sjoris cvs_client_send_files(argv, argc); 1689fac60a5Sjoris cvs_client_senddir("."); 169e0b2359bSxsa 170e0b2359bSxsa cvs_client_send_request((cvs_cmdop == CVS_OP_RLOG) ? 171e0b2359bSxsa "rlog" : "log"); 172e0b2359bSxsa 1739fac60a5Sjoris cvs_client_get_responses(); 1749fac60a5Sjoris } 1759fac60a5Sjoris 1767e393898Sjoris return (0); 177a96bf98bSjfb } 178df745765Sjfb 179e8c16debSjoris void 180e8c16debSjoris cvs_log_local(struct cvs_file *cf) 1819931af54Sjfb { 182e8c16debSjoris u_int nrev; 1839931af54Sjfb struct rcs_sym *sym; 184e8c16debSjoris struct rcs_lock *lkp; 1859931af54Sjfb struct rcs_delta *rdp; 186874e0b9fSjfb struct rcs_access *acp; 1870a7da307Sxsa char numb[CVS_REV_BUFSZ]; 1889931af54Sjfb 189c76dba03Sjoris cvs_log(LP_TRACE, "cvs_log_local(%s)", cf->file_path); 190c76dba03Sjoris 1915a1806edSjoris cvs_file_classify(cf, cvs_directory_tag); 1925bf4e3f1Sxsa 193e8c16debSjoris if (cf->file_status == FILE_UNKNOWN) { 194f2271752Stobias if (verbosity > 0 && cvs_cmdop != CVS_OP_RLOG) 195e8c16debSjoris cvs_log(LP_ERR, "nothing known about %s", 196e8c16debSjoris cf->file_path); 197e8c16debSjoris return; 198e8c16debSjoris } else if (cf->file_status == FILE_ADDED) { 199ef407d49Sxsa if (verbosity > 0) 2009a192d08Sdavid cvs_log(LP_ERR, "%s has been added, but not committed", 201e8c16debSjoris cf->file_path); 202e8c16debSjoris return; 2039931af54Sjfb } 2049931af54Sjfb 2053daa20b3Sjoris if (cf->file_type == CVS_DIR) { 2063daa20b3Sjoris if (verbosity > 1) 2073daa20b3Sjoris cvs_log(LP_NOTICE, "Logging %s", cf->file_path); 2083daa20b3Sjoris return; 2093daa20b3Sjoris } 2103daa20b3Sjoris 2117573783fSxsa if (runflags & L_NAME) { 2127573783fSxsa cvs_printf("%s\n", cf->file_rpath); 2137573783fSxsa return; 2147573783fSxsa } 2157573783fSxsa 2169fac60a5Sjoris cvs_printf("\nRCS file: %s", cf->file_rpath); 2175f291a7eSxsa 2185f291a7eSxsa if (cvs_cmdop != CVS_OP_RLOG) 2199fac60a5Sjoris cvs_printf("\nWorking file: %s", cf->file_path); 2205f291a7eSxsa 2219fac60a5Sjoris cvs_printf("\nhead:"); 222e8c16debSjoris if (cf->file_rcs->rf_head != NULL) 2239fac60a5Sjoris cvs_printf(" %s", rcsnum_tostr(cf->file_rcs->rf_head, 224e8c16debSjoris numb, sizeof(numb))); 225e8c16debSjoris 2269fac60a5Sjoris cvs_printf("\nbranch:"); 227e8c16debSjoris if (rcs_branch_get(cf->file_rcs) != NULL) { 2289fac60a5Sjoris cvs_printf(" %s", rcsnum_tostr(rcs_branch_get(cf->file_rcs), 229e8c16debSjoris numb, sizeof(numb))); 230874e0b9fSjfb } 2319931af54Sjfb 2329fac60a5Sjoris cvs_printf("\nlocks: %s", (cf->file_rcs->rf_flags & RCS_SLOCK) 233e8c16debSjoris ? "strict" : ""); 234e8c16debSjoris TAILQ_FOREACH(lkp, &(cf->file_rcs->rf_locks), rl_list) 2359fac60a5Sjoris cvs_printf("\n\t%s: %s", lkp->rl_name, 236e8c16debSjoris rcsnum_tostr(lkp->rl_num, numb, sizeof(numb))); 2379931af54Sjfb 2389fac60a5Sjoris cvs_printf("\naccess list:\n"); 239e8c16debSjoris TAILQ_FOREACH(acp, &(cf->file_rcs->rf_access), ra_list) 2409fac60a5Sjoris cvs_printf("\t%s\n", acp->ra_name); 241e8c16debSjoris 2427573783fSxsa if (!(runflags & L_NOTAGS)) { 2439fac60a5Sjoris cvs_printf("symbolic names:\n"); 244e8c16debSjoris TAILQ_FOREACH(sym, &(cf->file_rcs->rf_symbols), rs_list) { 2459fac60a5Sjoris cvs_printf("\t%s: %s\n", sym->rs_name, 246e8c16debSjoris rcsnum_tostr(sym->rs_num, numb, sizeof(numb))); 247874e0b9fSjfb } 2487573783fSxsa } 249874e0b9fSjfb 2509fac60a5Sjoris cvs_printf("keyword substitution: %s\n", 251e8c16debSjoris cf->file_rcs->rf_expand == NULL ? "kv" : cf->file_rcs->rf_expand); 2529931af54Sjfb 2539fac60a5Sjoris cvs_printf("total revisions: %u", cf->file_rcs->rf_ndelta); 2549931af54Sjfb 255e8c16debSjoris if (logrev != NULL) 25640440ce1Sjoris nrev = cvs_revision_select(cf->file_rcs, logrev); 257e8c16debSjoris else 258e8c16debSjoris nrev = cf->file_rcs->rf_ndelta; 259874e0b9fSjfb 2607573783fSxsa if (cf->file_rcs->rf_head != NULL && 2617573783fSxsa !(runflags & L_HEAD) && !(runflags & L_HEAD_DESCR)) 2629fac60a5Sjoris cvs_printf(";\tselected revisions: %u", nrev); 2637573783fSxsa 2649fac60a5Sjoris cvs_printf("\n"); 2657573783fSxsa 2667573783fSxsa if (!(runflags & L_HEAD) || (runflags & L_HEAD_DESCR)) 2679fac60a5Sjoris cvs_printf("description:\n%s", cf->file_rcs->rf_desc); 268874e0b9fSjfb 2697573783fSxsa if (!(runflags & L_HEAD) && !(runflags & L_HEAD_DESCR)) { 270e8c16debSjoris TAILQ_FOREACH(rdp, &(cf->file_rcs->rf_delta), rd_list) { 2718371e6b6Sxsa /* 2728371e6b6Sxsa * if selections are enabled verify that entry is 2738371e6b6Sxsa * selected. 2748371e6b6Sxsa */ 2758371e6b6Sxsa if (logrev == NULL || (rdp->rd_flags & RCS_RD_SELECT)) 2768371e6b6Sxsa log_rev_print(rdp); 2778371e6b6Sxsa } 2788371e6b6Sxsa } 2798371e6b6Sxsa 2808371e6b6Sxsa cvs_printf("%s\n", LOG_REVEND); 2818371e6b6Sxsa } 2828371e6b6Sxsa 2838371e6b6Sxsa static void 2848371e6b6Sxsa log_rev_print(struct rcs_delta *rdp) 2858371e6b6Sxsa { 2868371e6b6Sxsa int i, found; 2870a7da307Sxsa char numb[CVS_REV_BUFSZ], timeb[CVS_TIME_BUFSZ]; 2888371e6b6Sxsa struct cvs_argvector *sargv, *wargv; 2898371e6b6Sxsa 2908371e6b6Sxsa i = found = 0; 2918371e6b6Sxsa 2928371e6b6Sxsa /* -s states */ 2938371e6b6Sxsa if (runflags & L_STATES) { 2948371e6b6Sxsa sargv = cvs_strsplit(slist, ","); 2958371e6b6Sxsa for (i = 0; sargv->argv[i] != NULL; i++) { 2968371e6b6Sxsa if (strcmp(rdp->rd_state, sargv->argv[i]) == 0) { 2978371e6b6Sxsa found++; 2988371e6b6Sxsa break; 2998371e6b6Sxsa } 3008371e6b6Sxsa found = 0; 3018371e6b6Sxsa } 3028371e6b6Sxsa cvs_argv_destroy(sargv); 3038371e6b6Sxsa } 3048371e6b6Sxsa 3058371e6b6Sxsa /* -w[logins] */ 3068371e6b6Sxsa if (runflags & L_LOGINS) { 3078371e6b6Sxsa wargv = cvs_strsplit(wlist, ","); 3088371e6b6Sxsa for (i = 0; wargv->argv[i] != NULL; i++) { 3098371e6b6Sxsa if (strcmp(rdp->rd_author, wargv->argv[i]) == 0) { 3108371e6b6Sxsa found++; 3118371e6b6Sxsa break; 3128371e6b6Sxsa } 3138371e6b6Sxsa found = 0; 3148371e6b6Sxsa } 3158371e6b6Sxsa cvs_argv_destroy(wargv); 3168371e6b6Sxsa } 3178371e6b6Sxsa 318a347ceb8Sxsa if ((runflags & (L_STATES|L_LOGINS)) && found == 0) 3198371e6b6Sxsa return; 3203fe70097Sxsa 3219fac60a5Sjoris cvs_printf("%s\n", LOG_REVSEP); 322daf00afbSxsa 32340440ce1Sjoris rcsnum_tostr(rdp->rd_num, numb, sizeof(numb)); 3249fac60a5Sjoris cvs_printf("revision %s", numb); 325daf00afbSxsa 3268371e6b6Sxsa strftime(timeb, sizeof(timeb), "%Y/%m/%d %H:%M:%S", &rdp->rd_date); 3277573783fSxsa cvs_printf("\ndate: %s; author: %s; state: %s;\n", 3287573783fSxsa timeb, rdp->rd_author, rdp->rd_state); 3299fac60a5Sjoris cvs_printf("%s", rdp->rd_log); 330874e0b9fSjfb } 331