2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (c) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
13 * Show last revision where each line modified
15 * Prints the specified files with each line annotated with the revision
16 * number where it was last modified. With no argument, annotates all
17 * all the files in the directory (recursive by default).
22 /* Options from the command line. */
24 static int backwards
= 0;
25 static int force_tag_match
= 1;
26 static int force_binary
= 0;
27 static char *tag
= NULL
;
28 static int tag_validated
;
29 static char *date
= NULL
;
31 static int is_rannotate
;
33 static int annotate_fileproc (void *callerdat
, struct file_info
*);
34 static int rannotate_proc (int argc
, char **argv
, char *xwhere
,
35 char *mwhere
, char *mfile
, int shorten
,
36 int local
, char *mname
, char *msg
);
38 static const char *const annotate_usage
[] =
40 "Usage: %s %s [-blRfF] [-r rev] [-D date] [files...]\n",
41 "\t-b\tBackwards, show when a line was removed.\n",
42 "\t-l\tLocal directory only, no recursion.\n",
43 "\t-R\tProcess directories recursively.\n",
44 "\t-f\tUse head revision if tag/date not found.\n",
45 "\t-F\tAnnotate binary files.\n",
46 "\t-r rev\tAnnotate file as of specified revision/tag.\n",
47 "\t-D date\tAnnotate file as of specified date.\n",
48 "(Specify the --help global option for a list of other help options)\n",
52 /* Command to show the revision, date, and author where each line of a
56 annotate (int argc
, char **argv
)
62 is_rannotate
= (strcmp(cvs_cmd_name
, "rannotate") == 0);
65 usage (annotate_usage
);
68 while ((c
= getopt (argc
, argv
, "+blr:D:fFR")) != -1)
81 parse_tagdate (&tag
, &date
, optarg
);
84 if (date
) free (date
);
85 date
= Make_Date (optarg
);
95 usage (annotate_usage
);
102 #ifdef CLIENT_SUPPORT
103 if (current_parsed_root
->isremote
)
107 if (is_rannotate
&& !supported_request ("rannotate"))
108 error (1, 0, "server does not support rannotate");
116 if (!force_tag_match
)
120 option_with_arg ("-r", tag
);
122 client_senddate (date
);
127 for (i
= 0; i
< argc
; i
++)
129 send_to_server ("rannotate\012", 0);
133 send_files (argc
, argv
, local
, 0, SEND_NO_CONTENTS
);
134 send_file_names (argc
, argv
, SEND_EXPAND_WILD
);
135 send_to_server ("annotate\012", 0);
137 return get_responses_and_close ();
139 #endif /* CLIENT_SUPPORT */
146 for (i
= 0; i
< argc
; i
++)
148 err
+= do_module (db
, argv
[i
], MISC
, "Annotating", rannotate_proc
,
149 NULL
, 0, local
, 0, 0, NULL
);
155 err
= rannotate_proc (argc
+ 1, argv
- 1, NULL
, NULL
, NULL
, 0,
164 rannotate_proc (int argc
, char **argv
, char *xwhere
, char *mwhere
,
165 char *mfile
, int shorten
, int local
, char *mname
, char *msg
)
167 /* Begin section which is identical to patch_proc--should this
168 be abstracted out somehow? */
177 repository
= xmalloc (strlen (current_parsed_root
->directory
) + strlen (argv
[0])
178 + (mfile
== NULL
? 0 : strlen (mfile
) + 1) + 2);
179 (void) sprintf (repository
, "%s/%s", current_parsed_root
->directory
, argv
[0]);
180 where
= xmalloc (strlen (argv
[0]) + (mfile
== NULL
? 0 : strlen (mfile
) + 1)
182 (void) strcpy (where
, argv
[0]);
184 /* if mfile isn't null, we need to set up to do only part of the module */
190 /* if the portion of the module is a path, put the dir part on repos */
191 if ((cp
= strrchr (mfile
, '/')) != NULL
)
194 (void) strcat (repository
, "/");
195 (void) strcat (repository
, mfile
);
196 (void) strcat (where
, "/");
197 (void) strcat (where
, mfile
);
201 /* take care of the rest */
202 path
= Xasprintf ("%s/%s", repository
, mfile
);
205 /* directory means repository gets the dir tacked on */
206 (void) strcpy (repository
, path
);
207 (void) strcat (where
, "/");
208 (void) strcat (where
, mfile
);
220 /* cd to the starting repository */
221 if (CVS_CHDIR (repository
) < 0)
223 error (0, errno
, "cannot chdir to %s", repository
);
228 /* End section which is identical to patch_proc. */
230 if (force_tag_match
&& tag
!= NULL
)
231 which
= W_REPOS
| W_ATTIC
;
242 if (tag
!= NULL
&& !tag_validated
)
244 tag_check_valid (tag
, argc
- 1, argv
+ 1, local
, 0, repository
, false);
248 err
= start_recursion (annotate_fileproc
, NULL
, NULL
, NULL
, NULL
,
249 argc
- 1, argv
+ 1, local
, which
, 0, CVS_LOCK_READ
,
250 where
, 1, repository
);
260 annotate_fileproc (void *callerdat
, struct file_info
*finfo
)
262 char *expand
, *version
;
264 if (finfo
->rcs
== NULL
)
267 if (finfo
->rcs
->flags
& PARTIAL
)
268 RCS_reparsercsfile (finfo
->rcs
, NULL
, NULL
);
270 expand
= RCS_getexpand (finfo
->rcs
);
271 version
= RCS_getversion (finfo
->rcs
, tag
, date
, force_tag_match
, NULL
);
276 /* Distinguish output for various files if we are processing
278 cvs_outerr ("\nAnnotations for ", 0);
279 cvs_outerr (finfo
->fullname
, 0);
280 cvs_outerr ("\n***************\n", 0);
282 if (!force_binary
&& expand
&& expand
[0] == 'b')
284 cvs_outerr ("Skipping binary file -- -F not specified.\n", 0);
288 RCS_deltas (finfo
->rcs
, NULL
, NULL
,
290 backwards
? RCS_ANNOTATE_BACKWARDS
: RCS_ANNOTATE
,
291 NULL
, NULL
, NULL
, NULL
);