2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
8 * Show last revision where each line modified
10 * Prints the specified files with each line annotated with the revision
11 * number where it was last modified. With no argument, annotates all
12 * all the files in the directory (recursive by default).
17 /* Options from the command line. */
19 static int force_tag_match = 1;
20 static int force_binary = 0;
21 static char *tag = NULL;
22 static int tag_validated;
23 static char *date = NULL;
25 static int is_rannotate;
27 static int annotate_fileproc (void *callerdat, struct file_info *);
28 static int rannotate_proc (int argc, char **argv, char *xwhere,
29 char *mwhere, char *mfile, int shorten,
30 int local, char *mname, char *msg);
32 static const char *const annotate_usage[] =
34 "Usage: %s %s [-lRfF] [-r rev] [-D date] [files...]\n",
35 "\t-l\tLocal directory only, no recursion.\n",
36 "\t-R\tProcess directories recursively.\n",
37 "\t-f\tUse head revision if tag/date not found.\n",
38 "\t-F\tAnnotate binary files.\n",
39 "\t-r rev\tAnnotate file as of specified revision/tag.\n",
40 "\t-D date\tAnnotate file as of specified date.\n",
41 "(Specify the --help global option for a list of other help options)\n",
45 /* Command to show the revision, date, and author where each line of a
49 annotate (int argc, char **argv)
55 is_rannotate = (strcmp(cvs_cmd_name, "rannotate") == 0);
58 usage (annotate_usage);
61 while ((c = getopt (argc, argv, "+lr:D:fFR")) != -1)
75 date = Make_Date (optarg);
85 usage (annotate_usage);
93 if (current_parsed_root->isremote)
97 if (is_rannotate && !supported_request ("rannotate"))
98 error (1, 0, "server does not support rannotate");
104 if (!force_tag_match)
108 option_with_arg ("-r", tag);
110 client_senddate (date);
115 for (i = 0; i < argc; i++)
117 send_to_server ("rannotate\012", 0);
121 send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
122 send_file_names (argc, argv, SEND_EXPAND_WILD);
123 send_to_server ("annotate\012", 0);
125 return get_responses_and_close ();
127 #endif /* CLIENT_SUPPORT */
134 for (i = 0; i < argc; i++)
136 err += do_module (db, argv[i], MISC, "Annotating", rannotate_proc,
137 (char *) NULL, 0, local, 0, 0, (char *) NULL);
143 err = rannotate_proc (argc + 1, argv - 1, (char *) NULL,
144 (char *) NULL, (char *) NULL, 0, local, (char *) NULL,
153 rannotate_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile, int shorten, int local, char *mname, char *msg)
155 /* Begin section which is identical to patch_proc--should this
156 be abstracted out somehow? */
165 repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
166 + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
167 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
168 where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
170 (void) strcpy (where, argv[0]);
172 /* if mfile isn't null, we need to set up to do only part of the module */
178 /* if the portion of the module is a path, put the dir part on repos */
179 if ((cp = strrchr (mfile, '/')) != NULL)
182 (void) strcat (repository, "/");
183 (void) strcat (repository, mfile);
184 (void) strcat (where, "/");
185 (void) strcat (where, mfile);
189 /* take care of the rest */
190 path = xmalloc (strlen (repository) + strlen (mfile) + 5);
191 (void) sprintf (path, "%s/%s", repository, mfile);
194 /* directory means repository gets the dir tacked on */
195 (void) strcpy (repository, path);
196 (void) strcat (where, "/");
197 (void) strcat (where, mfile);
209 /* cd to the starting repository */
210 if ( CVS_CHDIR (repository) < 0)
212 error (0, errno, "cannot chdir to %s", repository);
216 /* End section which is identical to patch_proc. */
218 if (force_tag_match && tag != NULL)
219 which = W_REPOS | W_ATTIC;
230 if (tag != NULL && !tag_validated)
232 tag_check_valid (tag, argc - 1, argv + 1, local, 0, repository);
236 err = start_recursion ( annotate_fileproc, (FILESDONEPROC) NULL,
237 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
238 argc - 1, argv + 1, local, which, 0, CVS_LOCK_READ,
239 where, 1, repository );
240 if ( which & W_REPOS )
249 annotate_fileproc (void *callerdat, struct file_info *finfo)
251 char *expand, *version;
253 if (finfo->rcs == NULL)
256 if (finfo->rcs->flags & PARTIAL)
257 RCS_reparsercsfile (finfo->rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
259 expand = RCS_getexpand (finfo->rcs);
260 version = RCS_getversion (finfo->rcs, tag, date, force_tag_match,
266 /* Distinguish output for various files if we are processing
268 cvs_outerr ("\nAnnotations for ", 0);
269 cvs_outerr (finfo->fullname, 0);
270 cvs_outerr ("\n***************\n", 0);
272 if (!force_binary && expand && expand[0] == 'b')
274 cvs_outerr ("Skipping binary file -- -F not specified.\n", 0);
278 RCS_deltas (finfo->rcs, (FILE *) NULL, (struct rcsbuffer *) NULL,
279 version, RCS_ANNOTATE, NULL, NULL, NULL, NULL);