rcs.c (68bebbd7) rcs.c (79822b2a)
1/*
2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 *
4 * You may distribute under the terms of the GNU General Public License as
5 * specified in the README file that comes with the CVS source distribution.
6 *
7 * The routines contained in this file do all the rcs file parsing and
8 * manipulation

--- 78 unchanged lines hidden (view full) ---

87static char *truncate_revnum PROTO ((const char *));
88static char *printable_date PROTO((const char *));
89static char *escape_keyword_value PROTO ((const char *, int *));
90static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
91 const char *, size_t, enum kflag, char *,
92 size_t, char **, size_t *));
93static void cmp_file_buffer PROTO((void *, const char *, size_t));
94
1/*
2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 *
4 * You may distribute under the terms of the GNU General Public License as
5 * specified in the README file that comes with the CVS source distribution.
6 *
7 * The routines contained in this file do all the rcs file parsing and
8 * manipulation

--- 78 unchanged lines hidden (view full) ---

87static char *truncate_revnum PROTO ((const char *));
88static char *printable_date PROTO((const char *));
89static char *escape_keyword_value PROTO ((const char *, int *));
90static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
91 const char *, size_t, enum kflag, char *,
92 size_t, char **, size_t *));
93static void cmp_file_buffer PROTO((void *, const char *, size_t));
94
95enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH};
96static void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *,
97 enum rcs_delta_op, char **, size_t *,
98 char **, size_t *));
99
100/* Routines for reading, parsing and writing RCS files. */
101static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
102 char **));
103static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
104 struct rcsbuffer *));
105static void freedeltatext PROTO ((Deltatext *));
106
107static void RCS_putadmin PROTO ((RCSNode *, FILE *));

--- 2013 unchanged lines hidden (view full) ---

2121 * Get existing revision number corresponding to tag or revision.
2122 * Similar to RCS_gettag but less interpretation imposed.
2123 * For example:
2124 * -- If tag designates a magic branch, RCS_tag2rev
2125 * returns the magic branch number.
2126 * -- If tag is a branch tag, returns the branch number, not
2127 * the revision of the head of the branch.
2128 * If tag or revision is not valid or does not exist in file,
95/* Routines for reading, parsing and writing RCS files. */
96static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
97 char **));
98static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
99 struct rcsbuffer *));
100static void freedeltatext PROTO ((Deltatext *));
101
102static void RCS_putadmin PROTO ((RCSNode *, FILE *));

--- 2013 unchanged lines hidden (view full) ---

2116 * Get existing revision number corresponding to tag or revision.
2117 * Similar to RCS_gettag but less interpretation imposed.
2118 * For example:
2119 * -- If tag designates a magic branch, RCS_tag2rev
2120 * returns the magic branch number.
2121 * -- If tag is a branch tag, returns the branch number, not
2122 * the revision of the head of the branch.
2123 * If tag or revision is not valid or does not exist in file,
2129 * exit with error.
2124 * return NULL.
2130 */
2131char *
2132RCS_tag2rev (rcs, tag)
2133 RCSNode *rcs;
2134 char *tag;
2135{
2136 char *rev, *pa, *pb;
2137 int i;

--- 62 unchanged lines hidden (view full) ---

2200 return (RCS_head (rcs));
2201
2202 /* If valid tag let translate_symtag say yea or nay. */
2203 rev = translate_symtag (rcs, tag);
2204
2205 if (rev)
2206 return rev;
2207
2125 */
2126char *
2127RCS_tag2rev (rcs, tag)
2128 RCSNode *rcs;
2129 char *tag;
2130{
2131 char *rev, *pa, *pb;
2132 int i;

--- 62 unchanged lines hidden (view full) ---

2195 return (RCS_head (rcs));
2196
2197 /* If valid tag let translate_symtag say yea or nay. */
2198 rev = translate_symtag (rcs, tag);
2199
2200 if (rev)
2201 return rev;
2202
2208 error (1, 0, "tag `%s' does not exist", tag);
2209 /* NOT REACHED -- error (1 ... ) does not return here */
2210 return 0;
2203 /* Trust the caller to print warnings. */
2204 return NULL;
2211}
2212
2213/*
2214 * Find the revision for a specific tag.
2215 * If force_tag_match is set, return NULL if an exact match is not
2216 * possible otherwise return RCS_head (). We are careful to look for
2217 * and handle "magic" revisions specially.
2218 *

--- 1933 unchanged lines hidden (view full) ---

4152 else
4153 dest = workfile;
4154
4155 /* Remove `dest', just in case. It's okay to get ENOENT here,
4156 since we just want the file not to be there. (TODO: decide
4157 whether it should be considered an error for `dest' to exist
4158 at this point. If so, the unlink call should be removed and
4159 `symlink' should signal the error. -twp) */
2205}
2206
2207/*
2208 * Find the revision for a specific tag.
2209 * If force_tag_match is set, return NULL if an exact match is not
2210 * possible otherwise return RCS_head (). We are careful to look for
2211 * and handle "magic" revisions specially.
2212 *

--- 1933 unchanged lines hidden (view full) ---

4146 else
4147 dest = workfile;
4148
4149 /* Remove `dest', just in case. It's okay to get ENOENT here,
4150 since we just want the file not to be there. (TODO: decide
4151 whether it should be considered an error for `dest' to exist
4152 at this point. If so, the unlink call should be removed and
4153 `symlink' should signal the error. -twp) */
4160 if (unlink (dest) < 0 && !existence_error (errno))
4154 if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4161 error (1, errno, "cannot remove %s", dest);
4162 if (symlink (info->data, dest) < 0)
4163 error (1, errno, "cannot create symbolic link from %s to %s",
4164 dest, info->data);
4165 if (free_value)
4166 free (value);
4167 if (free_rev)
4168 free (rev);

--- 153 unchanged lines hidden (view full) ---

4322 if (sout == RUN_TTY)
4323 error (1, 0, "special file %s cannot be written to stdout",
4324 rcs->path);
4325 dest = sout;
4326 }
4327
4328 /* Unlink `dest', just in case. It's okay if this provokes a
4329 ENOENT error. */
4155 error (1, errno, "cannot remove %s", dest);
4156 if (symlink (info->data, dest) < 0)
4157 error (1, errno, "cannot create symbolic link from %s to %s",
4158 dest, info->data);
4159 if (free_value)
4160 free (value);
4161 if (free_rev)
4162 free (rev);

--- 153 unchanged lines hidden (view full) ---

4316 if (sout == RUN_TTY)
4317 error (1, 0, "special file %s cannot be written to stdout",
4318 rcs->path);
4319 dest = sout;
4320 }
4321
4322 /* Unlink `dest', just in case. It's okay if this provokes a
4323 ENOENT error. */
4330 if (unlink (dest) < 0 && existence_error (errno))
4324 if (CVS_UNLINK (dest) < 0 && existence_error (errno))
4331 error (1, errno, "cannot remove %s", dest);
4332 if (mknod (dest, special_file, devnum) < 0)
4333 error (1, errno, "could not create special file %s",
4334 dest);
4335#else
4336 error (1, 0,
4337"cannot create %s: unable to create special files on this system",
4338workfile);

--- 926 unchanged lines hidden (view full) ---

5265 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5266 &dtext->text, &bufsize, &dtext->len);
5267
5268 /* ... and the change text for the old delta should be a diff. */
5269 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5270 memset (commitpt->text, 0, sizeof (Deltatext));
5271
5272 bufsize = 0;
4325 error (1, errno, "cannot remove %s", dest);
4326 if (mknod (dest, special_file, devnum) < 0)
4327 error (1, errno, "could not create special file %s",
4328 dest);
4329#else
4330 error (1, 0,
4331"cannot create %s: unable to create special files on this system",
4332workfile);

--- 926 unchanged lines hidden (view full) ---

5259 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5260 &dtext->text, &bufsize, &dtext->len);
5261
5262 /* ... and the change text for the old delta should be a diff. */
5263 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5264 memset (commitpt->text, 0, sizeof (Deltatext));
5265
5266 bufsize = 0;
5273 switch (diff_exec (workfile, tmpfile, diffopts, changefile))
5267 switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile))
5274 {
5275 case 0:
5276 case 1:
5277 break;
5278 case -1:
5279 /* FIXME-update-dir: message does not include update_dir. */
5280 error (1, errno, "error diffing %s", workfile);
5281 break;

--- 31 unchanged lines hidden (view full) ---

5313 commitpt->text->len = 0;
5314 }
5315 }
5316 else
5317 {
5318 /* This file is not being inserted at the head, but on a side
5319 branch somewhere. Make a diff from the previous revision
5320 to the working file. */
5268 {
5269 case 0:
5270 case 1:
5271 break;
5272 case -1:
5273 /* FIXME-update-dir: message does not include update_dir. */
5274 error (1, errno, "error diffing %s", workfile);
5275 break;

--- 31 unchanged lines hidden (view full) ---

5307 commitpt->text->len = 0;
5308 }
5309 }
5310 else
5311 {
5312 /* This file is not being inserted at the head, but on a side
5313 branch somewhere. Make a diff from the previous revision
5314 to the working file. */
5321 switch (diff_exec (tmpfile, workfile, diffopts, changefile))
5315 switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile))
5322 {
5323 case 0:
5324 case 1:
5325 break;
5326 case -1:
5327 /* FIXME-update-dir: message does not include update_dir. */
5328 error (1, errno, "error diffing %s", workfile);
5329 break;

--- 363 unchanged lines hidden (view full) ---

5693/* FIXME-twp: if a lock owned by someone else is broken, should this
5694 send mail to the lock owner? Prompt user? It seems like such an
5695 obscure situation for CVS as almost not worth worrying much
5696 about. */
5697
5698int
5699RCS_lock (rcs, rev, lock_quiet)
5700 RCSNode *rcs;
5316 {
5317 case 0:
5318 case 1:
5319 break;
5320 case -1:
5321 /* FIXME-update-dir: message does not include update_dir. */
5322 error (1, errno, "error diffing %s", workfile);
5323 break;

--- 363 unchanged lines hidden (view full) ---

5687/* FIXME-twp: if a lock owned by someone else is broken, should this
5688 send mail to the lock owner? Prompt user? It seems like such an
5689 obscure situation for CVS as almost not worth worrying much
5690 about. */
5691
5692int
5693RCS_lock (rcs, rev, lock_quiet)
5694 RCSNode *rcs;
5701 const char *rev;
5695 char *rev;
5702 int lock_quiet;
5703{
5704 List *locks;
5705 Node *p;
5706 char *user;
5707 char *xrev = NULL;
5708
5709 if (rcs->flags & PARTIAL)
5710 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5711
5712 locks = RCS_getlocks (rcs);
5713 if (locks == NULL)
5714 locks = rcs->locks = getlist();
5715 user = getcaller();
5716
5717 /* A revision number of NULL means lock the head or default branch. */
5718 if (rev == NULL)
5719 xrev = RCS_head (rcs);
5696 int lock_quiet;
5697{
5698 List *locks;
5699 Node *p;
5700 char *user;
5701 char *xrev = NULL;
5702
5703 if (rcs->flags & PARTIAL)
5704 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5705
5706 locks = RCS_getlocks (rcs);
5707 if (locks == NULL)
5708 locks = rcs->locks = getlist();
5709 user = getcaller();
5710
5711 /* A revision number of NULL means lock the head or default branch. */
5712 if (rev == NULL)
5713 xrev = RCS_head (rcs);
5714 else
5715 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
5720
5716
5721 /* If rev is a branch number, lock the latest revision on that
5722 branch. I think that if the branch doesn't exist, it's
5723 okay to return 0 -- that just means that the branch is new,
5724 so we don't need to lock it anyway. -twp */
5725 else if (RCS_nodeisbranch (rcs, rev))
5726 {
5727 xrev = RCS_getbranch (rcs, (char *) rev, 1);
5728 if (xrev == NULL)
5729 {
5730 if (!lock_quiet)
5731 error (0, 0, "%s: branch %s absent", rcs->path, rev);
5732 return 1;
5733 }
5734 }
5735
5736 if (xrev == NULL)
5737 xrev = xstrdup (rev);
5738
5739 /* Make sure that the desired revision exists. Technically,
5740 we can update the locks list without even checking this,
5741 but RCS 5.7 did this. And it can't hurt. */
5717 /* Make sure that the desired revision exists. Technically,
5718 we can update the locks list without even checking this,
5719 but RCS 5.7 did this. And it can't hurt. */
5742 if (findnode (rcs->versions, xrev) == NULL)
5720 if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
5743 {
5744 if (!lock_quiet)
5721 {
5722 if (!lock_quiet)
5745 error (0, 0, "%s: revision %s absent", rcs->path, xrev);
5723 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5746 free (xrev);
5747 return 1;
5748 }
5749
5750 /* Is this rev already locked? */
5751 p = findnode (locks, xrev);
5752 if (p != NULL)
5753 {

--- 49 unchanged lines hidden (view full) ---

5803
5804 If REV is not null and is locked by someone else, break their
5805 lock and notify them. It is an open issue whether RCS_unlock
5806 queries the user about whether or not to break the lock. */
5807
5808int
5809RCS_unlock (rcs, rev, unlock_quiet)
5810 RCSNode *rcs;
5724 free (xrev);
5725 return 1;
5726 }
5727
5728 /* Is this rev already locked? */
5729 p = findnode (locks, xrev);
5730 if (p != NULL)
5731 {

--- 49 unchanged lines hidden (view full) ---

5781
5782 If REV is not null and is locked by someone else, break their
5783 lock and notify them. It is an open issue whether RCS_unlock
5784 queries the user about whether or not to break the lock. */
5785
5786int
5787RCS_unlock (rcs, rev, unlock_quiet)
5788 RCSNode *rcs;
5811 const char *rev;
5789 char *rev;
5812 int unlock_quiet;
5813{
5814 Node *lock;
5815 List *locks;
5816 char *user;
5817 char *xrev = NULL;
5818
5819 user = getcaller();

--- 33 unchanged lines hidden (view full) ---

5853 return 1;
5854 }
5855 lock = p;
5856 }
5857 if (lock == NULL)
5858 return 0; /* no lock found, ergo nothing to do */
5859 xrev = xstrdup (lock->key);
5860 }
5790 int unlock_quiet;
5791{
5792 Node *lock;
5793 List *locks;
5794 char *user;
5795 char *xrev = NULL;
5796
5797 user = getcaller();

--- 33 unchanged lines hidden (view full) ---

5831 return 1;
5832 }
5833 lock = p;
5834 }
5835 if (lock == NULL)
5836 return 0; /* no lock found, ergo nothing to do */
5837 xrev = xstrdup (lock->key);
5838 }
5861 else if (RCS_nodeisbranch (rcs, rev))
5839 else
5862 {
5840 {
5863 /* If rev is a branch number, unlock the latest revision on that
5864 branch. */
5865 xrev = RCS_getbranch (rcs, (char *) rev, 1);
5841 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
5866 if (xrev == NULL)
5867 {
5842 if (xrev == NULL)
5843 {
5868 error (0, 0, "%s: branch %s absent", rcs->path, rev);
5844 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5869 return 1;
5870 }
5871 }
5845 return 1;
5846 }
5847 }
5872 else
5873 /* REV is an exact revision number. */
5874 xrev = xstrdup (rev);
5875
5876 lock = findnode (RCS_getlocks (rcs), xrev);
5877 if (lock == NULL)
5878 {
5879 /* This revision isn't locked. */
5880 free (xrev);
5881 return 0;
5882 }

--- 505 unchanged lines hidden (view full) ---

6388 {
6389 beforefile = cvs_temp_name();
6390 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6391 (RCSCHECKOUTPROC)0, NULL);
6392 if (status > 0)
6393 goto delrev_done;
6394
6395 outfile = cvs_temp_name();
5848
5849 lock = findnode (RCS_getlocks (rcs), xrev);
5850 if (lock == NULL)
5851 {
5852 /* This revision isn't locked. */
5853 free (xrev);
5854 return 0;
5855 }

--- 505 unchanged lines hidden (view full) ---

6361 {
6362 beforefile = cvs_temp_name();
6363 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6364 (RCSCHECKOUTPROC)0, NULL);
6365 if (status > 0)
6366 goto delrev_done;
6367
6368 outfile = cvs_temp_name();
6396 status = diff_exec (beforefile, afterfile, "-an", outfile);
6369 status = diff_exec (beforefile, afterfile, NULL, NULL, "-an", outfile);
6397
6398 if (status == 2)
6399 {
6400 /* Not sure we need this message; will diff_exec already
6401 have printed an error? */
6402 error (0, 0, "%s: could not diff", rcs->path);
6403 status = 1;
6404 goto delrev_done;

--- 622 unchanged lines hidden (view full) ---

7027 RCS with file position pointing to the deltas. We close the file
7028 when we are done.
7029
7030 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7031 and *LOGLEN is set to the length of the log message.
7032
7033 On error, give a fatal error. */
7034
6370
6371 if (status == 2)
6372 {
6373 /* Not sure we need this message; will diff_exec already
6374 have printed an error? */
6375 error (0, 0, "%s: could not diff", rcs->path);
6376 status = 1;
6377 goto delrev_done;

--- 622 unchanged lines hidden (view full) ---

7000 RCS with file position pointing to the deltas. We close the file
7001 when we are done.
7002
7003 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7004 and *LOGLEN is set to the length of the log message.
7005
7006 On error, give a fatal error. */
7007
7035static void
7008void
7036RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
7037 RCSNode *rcs;
7038 FILE *fp;
7039 struct rcsbuffer *rcsbuf;
7040 char *version;
7041 enum rcs_delta_op op;
7042 char **text;
7043 size_t *len;

--- 1342 unchanged lines hidden (view full) ---

8386 rcs->expand = NULL;
8387 rcs->access = NULL;
8388 rcs->locks_data = NULL;
8389 rcs->comment = NULL;
8390 rcs->desc = NULL;
8391 rcs->flags |= PARTIAL;
8392}
8393
7009RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
7010 RCSNode *rcs;
7011 FILE *fp;
7012 struct rcsbuffer *rcsbuf;
7013 char *version;
7014 enum rcs_delta_op op;
7015 char **text;
7016 size_t *len;

--- 1342 unchanged lines hidden (view full) ---

8359 rcs->expand = NULL;
8360 rcs->access = NULL;
8361 rcs->locks_data = NULL;
8362 rcs->comment = NULL;
8363 rcs->desc = NULL;
8364 rcs->flags |= PARTIAL;
8365}
8366
8394
8395/* Annotate command. In rcs.c for historical reasons (from back when
8396 what is now RCS_deltas was part of annotate_fileproc). */
8397
8398/* Options from the command line. */
8399
8400static int force_tag_match = 1;
8401static char *tag = NULL;
8402static char *date = NULL;
8403
8404static int annotate_fileproc PROTO ((void *callerdat, struct file_info *));
8405
8406static int
8407annotate_fileproc (callerdat, finfo)
8408 void *callerdat;
8409 struct file_info *finfo;
8410{
8411 FILE *fp = NULL;
8412 struct rcsbuffer *rcsbufp = NULL;
8413 struct rcsbuffer rcsbuf;
8414 char *version;
8415
8416 if (finfo->rcs == NULL)
8417 return (1);
8418
8419 if (finfo->rcs->flags & PARTIAL)
8420 {
8421 RCS_reparsercsfile (finfo->rcs, &fp, &rcsbuf);
8422 rcsbufp = &rcsbuf;
8423 }
8424
8425 version = RCS_getversion (finfo->rcs, tag, date, force_tag_match,
8426 (int *) NULL);
8427 if (version == NULL)
8428 return 0;
8429
8430 /* Distinguish output for various files if we are processing
8431 several files. */
8432 cvs_outerr ("Annotations for ", 0);
8433 cvs_outerr (finfo->fullname, 0);
8434 cvs_outerr ("\n***************\n", 0);
8435
8436 RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, NULL,
8437 NULL, NULL, NULL);
8438 free (version);
8439 return 0;
8440}
8441
8442static const char *const annotate_usage[] =
8443{
8444 "Usage: %s %s [-lRf] [-r rev|-D date] [files...]\n",
8445 "\t-l\tLocal directory only, no recursion.\n",
8446 "\t-R\tProcess directories recursively.\n",
8447 "\t-f\tUse head revision if tag/date not found.\n",
8448 "\t-r rev\tAnnotate file as of specified revision/tag.\n",
8449 "\t-D date\tAnnotate file as of specified date.\n",
8450 "(Specify the --help global option for a list of other help options)\n",
8451 NULL
8452};
8453
8454/* Command to show the revision, date, and author where each line of a
8455 file was modified. */
8456
8457int
8458annotate (argc, argv)
8459 int argc;
8460 char **argv;
8461{
8462 int local = 0;
8463 int c;
8464
8465 if (argc == -1)
8466 usage (annotate_usage);
8467
8468 optind = 0;
8469 while ((c = getopt (argc, argv, "+lr:D:fR")) != -1)
8470 {
8471 switch (c)
8472 {
8473 case 'l':
8474 local = 1;
8475 break;
8476 case 'R':
8477 local = 0;
8478 break;
8479 case 'r':
8480 tag = optarg;
8481 break;
8482 case 'D':
8483 date = Make_Date (optarg);
8484 break;
8485 case 'f':
8486 force_tag_match = 0;
8487 break;
8488 case '?':
8489 default:
8490 usage (annotate_usage);
8491 break;
8492 }
8493 }
8494 argc -= optind;
8495 argv += optind;
8496
8497#ifdef CLIENT_SUPPORT
8498 if (client_active)
8499 {
8500 start_server ();
8501 ign_setup ();
8502
8503 if (local)
8504 send_arg ("-l");
8505 if (!force_tag_match)
8506 send_arg ("-f");
8507 option_with_arg ("-r", tag);
8508 if (date)
8509 client_senddate (date);
8510 send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
8511 send_file_names (argc, argv, SEND_EXPAND_WILD);
8512 send_to_server ("annotate\012", 0);
8513 return get_responses_and_close ();
8514 }
8515#endif /* CLIENT_SUPPORT */
8516
8517 if (tag != NULL)
8518 tag_check_valid (tag, argc, argv, local, 0, "");
8519
8520 return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL,
8521 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
8522 argc, argv, local, W_LOCAL, 0, 1, (char *)NULL,
8523 1);
8524}
8525
8526/*
8527 * For a given file with full pathname PATH and revision number REV,
8528 * produce a file label suitable for passing to diff. The default
8529 * file label as used by RCS 5.7 looks like this:
8530 *
8531 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8532 *
8533 * The date and time used are the revision's last checkin date and time.
8534 * If REV is NULL, use the working copy's mtime instead.
8367/*
8368 * For a given file with full pathname PATH and revision number REV,
8369 * produce a file label suitable for passing to diff. The default
8370 * file label as used by RCS 5.7 looks like this:
8371 *
8372 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8373 *
8374 * The date and time used are the revision's last checkin date and time.
8375 * If REV is NULL, use the working copy's mtime instead.
8376 *
8377 * /dev/null is not statted but assumed to have been created on the Epoch.
8378 * At least using the POSIX.2 definition of patch, this should cause creation
8379 * of files on platforms such as Windoze where the null IO device isn't named
8380 * /dev/null to be parsed by patch properly.
8535 */
8536char *
8537make_file_label (path, rev, rcs)
8538 char *path;
8539 char *rev;
8540 RCSNode *rcs;
8541{
8381 */
8382char *
8383make_file_label (path, rev, rcs)
8384 char *path;
8385 char *rev;
8386 RCSNode *rcs;
8387{
8542 char datebuf[MAXDATELEN];
8388 char datebuf[MAXDATELEN + 1];
8543 char *label;
8389 char *label;
8544 char *file;
8545
8390
8546 file = last_component (path);
8547 label = (char *) xmalloc (strlen (path)
8391 label = (char *) xmalloc (strlen (path)
8548 + (rev == NULL ? 0 : strlen (rev))
8549 + 50);
8392 + (rev == NULL ? 0 : strlen (rev) + 1)
8393 + MAXDATELEN
8394 + 2);
8550
8551 if (rev)
8552 {
8395
8396 if (rev)
8397 {
8553 char *date;
8398 char date[MAXDATELEN + 1];
8399 /* revs cannot be attached to /dev/null ... duh. */
8400 assert (strcmp(DEVNULL, path));
8554 RCS_getrevtime (rcs, rev, datebuf, 0);
8401 RCS_getrevtime (rcs, rev, datebuf, 0);
8555 date = printable_date (datebuf);
8402 (void) date_to_internet (date, datebuf);
8556 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
8403 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
8557 free (date);
8558 }
8559 else
8560 {
8561 struct stat sb;
8404 }
8405 else
8406 {
8407 struct stat sb;
8562 struct tm *wm;
8408 struct tm *wm = NULL;
8563
8409
8564 if (CVS_STAT (file, &sb) < 0)
8565 error (0, 1, "could not get info for `%s'", path);
8410 if (strcmp(DEVNULL, path))
8411 {
8412 char *file = last_component (path);
8413 if (CVS_STAT (file, &sb) < 0)
8414 error (0, 1, "could not get info for `%s'", path);
8415 else
8416 wm = gmtime (&sb.st_mtime);
8417 }
8566 else
8567 {
8418 else
8419 {
8568 wm = gmtime (&sb.st_mtime);
8569 (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d",
8570 wm->tm_year + 1900, wm->tm_mon + 1,
8571 wm->tm_mday, wm->tm_hour,
8572 wm->tm_min, wm->tm_sec);
8420 time_t t = 0;
8421 wm = gmtime(&t);
8422 }
8423
8424 if (wm)
8425 {
8426 (void) tm_to_internet (datebuf, wm);
8573 (void) sprintf (label, "-L%s\t%s", path, datebuf);
8574 }
8575 }
8576 return label;
8577}
8427 (void) sprintf (label, "-L%s\t%s", path, datebuf);
8428 }
8429 }
8430 return label;
8431}