home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
prgramer
/
rcs
/
sources
/
version_.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-19
|
11KB
|
393 lines
#ifndef lint
static char rcsid[] = "$Id: version_number.c,v 1.16.1.2 91/01/29 07:20:26 berliner Exp $";
#endif
/*
* Copyright (c) 1989, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License
* as specified in the README file that comes with the CVS 1.0 kit.
*
* Version Number
*
* Returns the requested version number of the RCS file, satisfying tags
* and walking branches, if necessary.
*
* "rcs" is the full pathname to the ,v file which is read to determine
* the current head version number for the RCS file. Things are
* complicated by needing to walk branches and symbolic tags. The
* algorithm used here for branches is not quite the same as that
* included with RCS, but should work 99.999% of the time (or more).
*
* The result is placed in "vers"; null-string if error.
*/
#include <ctype.h>
#include "cvs.h"
Version_Number(rcs, tag, date, vers)
char *rcs;
char *tag;
char *date;
char *vers;
{
FILE *fpin;
char rev[50];
vers[0] = rev[0] = '\0'; /* Assume failure */
/*
* Open the RCS file. If it failed, just return, as the version
* is already nulled.
*/
if ((fpin = fopen(rcs, "r")) == NULL)
return 0;
get_version(fpin, tag, date, rev, vers);
if (vers[0] == '\0' && tag[0] != '\0') {
if (!isdigit(tag[0])) {
char *cp, temp[MAXLINELEN];
extern char update_dir[];
if (CVSroot[0] != '\0' &&
strncmp(rcs, CVSroot, strlen(CVSroot)) == 0) {
cp = rcs + strlen(CVSroot) + 1;
} else {
if ((cp = index_sep(rcs)) == NULL && update_dir[0] != '\0') {
(void) sprintf(temp, "%s%c%s", update_dir, DIRSEP, rcs);
cp = temp;
} else {
cp = rcs;
}
}
if (force_tag_match) {
if (!quiet)
warn(0, "tag %s undefined in %s; ignored", tag, cp);
} else {
if (!quiet)
warn(0, "tag %s undefined in %s; using %s", tag, cp, rev);
(void) strcpy(vers, rev);
}
} else {
if (!force_tag_match)
(void) strcpy(vers, rev);
}
}
(void) fclose(fpin);
}
/*
* The main driver for doing the work of getting the required revision
* number. Returns computed revision in "rev" or "vers" depending
* on whether the "tag" could be satisfied or not.
*/
static
get_version(fp, tag, date, rev, vers)
FILE *fp;
char *tag;
char *date;
char *rev;
char *vers;
{
char line[MAXLINELEN];
char *cp;
int symtag_matched = 0;
/*
* Scan to find the current "head" setting,
* which really isn't the head if the RCS file is using a branch
* for the head, sigh.
*
* Assumption here is that the "head" line is always first.
*/
if (fgets(line, sizeof(line), fp) == NULL)
return 0;
if (strncmp(line, RCSHEAD, sizeof(RCSHEAD) - 1) != 0 ||
!isspace(line[sizeof(RCSHEAD) - 1]) ||
(cp = rindex(line, ';')) == NULL)
return 0;
*cp = '\0'; /* strip the ';' */
if ((cp = rindex(line, ' ')) == NULL &&
(cp = rindex(line, '\t')) == NULL)
return 0;
cp++;
(void) strcpy(rev, cp);
/*
* The "rev" string now contains the value of the RCS "head".
* Read the next line to find out if we should walk the branches.
*
* Assumption here is that "branch" is always on the second line
* of the RCS file. If a "branch" line does not exist, we assume
* it is an old format RCS file, and blow it off.
*/
if (fgets(line, sizeof(line), fp) == NULL)
return 0;
if (strncmp(line, RCSBRANCH, sizeof(RCSBRANCH) - 1) == 0 &&
isspace(line[sizeof(RCSBRANCH) - 1]) &&
(cp = rindex(line, ';')) != NULL) {
*cp = '\0'; /* strip the ';' */
if ((cp = rindex(line, ' ')) == NULL &&
(cp = rindex(line, '\t')) == NULL)
return 0;
cp++;
if (*cp != 0)
(void) strcpy(rev, cp);
}
/*
* "rev" now contains either the "head" value, or the "branch"
* value (if it was set). If we're looking for a particular symbolic
* or numeric tag, we must find the symbol, and then do
* branch completion as usual, if necessary.
*/
if (date[0] != '\0') {
get_date(fp, date, rev, vers);
return 0;
}
if (tag[0] != '\0') {
/* return of 0 means we found an exact match, or there was an error */
if ((symtag_matched = get_tag(fp, tag, rev, vers)) == 0)
return 0;
}
/*
* "rev" now contains either the "head" value, or the tag value,
* or the "branch" value. get_branch() will fill in "rev" with
* the highest numbered branch off "rev", if necessary.
*/
get_branch(fp, rev);
if (tag[0] == '\0' || isdigit(tag[0]) || symtag_matched < 0) {
if ((numdots(rev) & 1) != 0)
(void) strcpy(vers, rev);
}
}
/*
* We were requested to find a particular symbolic or numeric revision.
* So, scan for the "symbols" line in the RCS file, or for the first
* match of a line if the tag is numeric.
*
* Would really like to use strtok() here, but callers in update() are
* already using it.
*
* Return value of 0 means to use "vers" as it stands, while a return value
* of 1 means to use "rev", but to check for possible branch completions
* to find the head of a branch.
*/
static
get_tag(fp, tag, rev, vers)
FILE *fp;
char *tag;
char *rev;
char *vers;
{
char line[MAXLINELEN];
char *cp, *cprev;
if (isdigit(tag[0])) {
while (tag[strlen(tag)-1] == '.')
tag[strlen(tag)-1] = '\0'; /* strip trailing dots */
if ((numdots(tag) & 1) == 0) {
(void) strcpy(rev, tag);
return (1); /* let get_branch() figure it out */
}
}
while (fgets(line, sizeof(line), fp) != NULL) {
if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0) {
rewind(fp);
return (1); /* use head */
}
/*
* For numeric tags, the RCS file contains the revision
* number all by itself on a single line, so we check for
* that match here.
*/
if (isdigit(tag[0])) {
if ((cp = rindex(line, '\n')) != NULL)
*cp = '\0';
if (strcmp(tag, line) == 0) {
(void) strcpy(vers, line);
return (0); /* a match for a numeric tag */
}
continue;
}
if (strncmp(line, RCSSYMBOL, sizeof(RCSSYMBOL)-1)!=0 ||
!isspace(line[sizeof(RCSSYMBOL) - 1]))
continue;
/*
* A rather ugly loop to process the "symbols" line. I would
* really rather use strtok(), but other above me already are,
* and strtok() blows up in this case.
*/
for (cp = line + sizeof(RCSSYMBOL); cp; ) {
while (isspace(*cp))
cp++;
if (*cp == ';')
break;
if (!*cp) {
if (fgets(line, sizeof(line), fp) == NULL)
return 0;
cp = line;
continue;
}
/* symbols and revisions are separated by a colon */
if ((cprev = index(cp, ':')) == NULL) {
while (*cp && !isspace(*cp) && *cp!=';')
cp++;
continue;
}
*cprev++ = '\0';
/*
* "cp" points to the NULL-terminated symbolic name;
* "cprev" points to the revision, which must be NULL-terminated;
*/
if (strcmp(tag, cp) == 0) {
if ((cp = index(cprev, ' ')) == NULL
&& (cp = index(cprev, ';')) == NULL
&& (cp = index(cprev, '\n')) == NULL)
continue;
*cp = '\0';
(void) strcpy(rev, cprev);
return (-1); /* look for branches off rev */
} else {
while (!isspace(*cp) && *cp!=';')
cp++;
}
}
return (1);
}
return (0);
}
/*
* Decides if we should determine the highest branch number, and
* returns it in "rev". This is only done if there are
* an even number of dots ('.') in the revision number passed in.
*/
static
get_branch(fp, rev)
FILE *fp;
char *rev;
{
char line[MAXLINELEN];
char branch[50];
char *cp;
int len, dots = numdots(rev);
if ((dots & 1) != 0)
return 0;
(void) sprintf(branch, "%s.", rev);
len = strlen(branch);
while (fgets(line, sizeof(line), fp) != NULL) {
if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0)
return 0;
if (isdigit(line[0])) {
if ((cp = rindex(line, '\n')) != NULL)
*cp = '\0'; /* strip the newline */
if (numdots(line) == dots+1 &&
strncmp(line, branch, len) == 0) {
if ((numdots(rev) & 1) == 0 || strcmp(rev, line) <= 0)
(void) strcpy(rev, line);
}
}
}
}
/*
* Look up a the most recent revision, based on the supplied date.
* But do some funky stuff if necessary to follow any vendor branch.
*/
static
get_date(fp, date, rev, version)
FILE *fp;
char *date;
char *rev;
char *version;
{
char *cp;
if ((numdots(rev) & 1) == 0) {
/*
* A branch is the head, so get the revision from the branch
* specified in "rev". If we didn't get a match, try the trunk.
*/
get_branch_date(fp, date, rev, version);
if (version[0] == '\0') {
if ((cp = index(rev, '.')) != NULL)
*cp = '\0';
rewind(fp);
get_branch_date(fp, date, rev, version);
}
} else {
/*
* The trunk is the head. Get the revision from the trunk and
* see if it evaluates to 1.1. If so, walk the 1.1.1 branch looking
* for a match and return that; if not, just return 1.1.
*/
if ((cp = rindex(rev, '.')) != NULL)
*cp = '\0'; /* turn the revision into a branch */
get_branch_date(fp, date, rev, version);
if (strcmp(version, "1.1") == 0) {
rewind(fp);
get_branch_date(fp, date, "1.1.1", version);
}
}
}
static
get_branch_date(fp, date, rev, version)
FILE *fp;
char *date;
char *rev;
char *version;
{
char line[MAXLINELEN], last_rev[50], curdate[50], date_dot[50];
int date_dots, date_dotlen;
char *cp, *semi;
last_rev[0] = '\0';
curdate[0] = '\0';
(void) sprintf(date_dot, "%s.", rev);
date_dotlen = strlen(date_dot);
date_dots = numdots(rev);
while (fgets(line, sizeof(line), fp) != NULL) {
if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0)
return 0;
if (isdigit(line[0])) {
if ((cp = rindex(line, '\n')) != NULL)
*cp = '\0'; /* strip the newline */
if ((date_dots == 0 || strncmp(date_dot, line, date_dotlen) == 0) &&
numdots(line) == date_dots+1)
(void) strcpy(last_rev, line);
else
last_rev[0] = '\0';
continue;
}
if (strncmp(line, RCSDATE, sizeof(RCSDATE) - 1) == 0 &&
isspace(line[sizeof(RCSDATE) - 1]) &&
last_rev[0] != '\0') {
for (cp = line; *cp && !isspace(*cp); cp++)
;
while (*cp && isspace(*cp))
cp++;
if (*cp && (semi = index(cp, ';')) != NULL) {
*semi = '\0'; /* strip the semicolon */
if (datecmp(cp, date) <= 0 && datecmp(cp, curdate) >= 0) {
(void) strcpy(curdate, cp);
(void) strcpy(version, last_rev);
}
}
}
}
}
/*
* Compare two dates in RCS format.
* Beware the change in format on January 1, 2000,
* when years go from 2-digit to full format.
*/
int
datecmp(date1, date2)
char *date1, *date2;
{
int length_diff = strlen(date1) - strlen(date2);
return length_diff ? length_diff : strcmp(date1, date2);
}