📄 rcsrev.c
字号:
/* * RCS revision number handling *//* Copyright (C) 1982, 1988, 1989 Walter Tichy Copyright 1990, 1991 by Paul Eggert Distributed under license by the Free Software Foundation, Inc.This file is part of RCS.RCS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.RCS is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with RCS; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.Report problems and direct all questions to: rcs-bugs@cs.purdue.edu*//* $Log: rcsrev.c,v $ * Revision 5.3 1991/08/19 03:13:55 eggert * Add `-r$', `-rB.'. Remove botches like `<now>' from messages. Tune. * * Revision 5.2 1991/04/21 11:58:28 eggert * Add tiprev(). * * Revision 5.1 1991/02/25 07:12:43 eggert * Avoid overflow when comparing revision numbers. * * Revision 5.0 1990/08/22 08:13:43 eggert * Remove compile-time limits; use malloc instead. * Ansify and Posixate. Tune. * Remove possibility of an internal error. Remove lint. * * Revision 4.5 89/05/01 15:13:22 narten * changed copyright header to reflect current distribution rules * * Revision 4.4 87/12/18 11:45:22 narten * more lint cleanups. Also, the NOTREACHED comment is no longer necessary, * since there's now a return value there with a value. (Guy Harris) * * Revision 4.3 87/10/18 10:38:42 narten * Updating version numbers. Changes relative to version 1.1 actually * relative to 4.1 * * Revision 1.3 87/09/24 14:00:37 narten * Sources now pass through lint (if you ignore printf/sprintf/fprintf * warnings) * * Revision 1.2 87/03/27 14:22:37 jenkins * Port to suns * * Revision 4.1 83/03/25 21:10:45 wft * Only changed $Header to $Id. * * Revision 3.4 82/12/04 13:24:08 wft * Replaced getdelta() with gettree(). * * Revision 3.3 82/11/28 21:33:15 wft * fixed compartial() and compnum() for nil-parameters; fixed nils * in error messages. Testprogram output shortenend. * * Revision 3.2 82/10/18 21:19:47 wft * renamed compnum->cmpnum, compnumfld->cmpnumfld, * numericrevno->numricrevno. * * Revision 3.1 82/10/11 19:46:09 wft * changed expandsym() to check for source==nil; returns zero length string * in that case. *//*#define REVTEST*//* version REVTEST is for testing the routines that generate a sequence * of delta numbers needed to regenerate a given delta. */#include "rcsbase.h"libId(revId, "$Id: rcsrev.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")static char const *branchtip P((char const*));static struct hshentry *genbranch P((struct hshentry const*,char const*,unsigned,char const*,char const*,char const*,struct hshentries**)); unsignedcountnumflds(s) char const *s;/* Given a pointer s to a dotted number (date or revision number), * countnumflds returns the number of digitfields in s. */{ register char const *sp; register unsigned count; if ((sp=s)==nil) return(0); if (*sp == '\0') return(0); count = 1; do { if (*sp++ == '.') count++; } while (*sp); return(count);} voidgetbranchno(revno,branchno) char const *revno; struct buf *branchno;/* Given a non-nil revision number revno, getbranchno copies the number of the branch * on which revno is into branchno. If revno itself is a branch number, * it is copied unchanged. */{ register unsigned numflds; register char *tp; bufscpy(branchno, revno); numflds=countnumflds(revno); if (!(numflds & 1)) { tp = branchno->string; while (--numflds) while (*tp++ != '.') ; *(tp-1)='\0'; }}int cmpnum(num1, num2) char const *num1, *num2;/* compares the two dotted numbers num1 and num2 lexicographically * by field. Individual fields are compared numerically. * returns <0, 0, >0 if num1<num2, num1==num2, and num1>num2, resp. * omitted fields are assumed to be higher than the existing ones.*/{ register char const *s1, *s2; register size_t d1, d2; register int r; s1=num1==nil?"":num1; s2=num2==nil?"":num2; for (;;) { /* Give precedence to shorter one. */ if (!*s1) return (unsigned char)*s2; if (!*s2) return -1; /* Strip leading zeros, then find number of digits. */ while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ; while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ; /* Do not convert to integer; it might overflow! */ if (d1 != d2) return d1<d2 ? -1 : 1; if ((r = memcmp(s1, s2, d1))) return r; s1 += d1; s2 += d1; /* skip '.' */ if (*s1) s1++; if (*s2) s2++; }}int cmpnumfld(num1, num2, fld) char const *num1, *num2; unsigned fld;/* Compare the two dotted numbers at field fld. * num1 and num2 must have at least fld fields. * fld must be positive.*/{ register char const *s1, *s2; register size_t d1, d2; s1 = num1; s2 = num2; /* skip fld-1 fields */ while (--fld) { while (*s1++ != '.') ; while (*s2++ != '.') ; } /* Now s1 and s2 point to the beginning of the respective fields */ while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ; while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ; return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;} static voidcantfindbranch(revno, date, author, state) char const *revno, date[datesize], *author, *state;{ char datebuf[datesize]; error("No revision on branch %s has%s%s%s%s%s%s.", revno, date ? " a date before " : "", date ? date2str(date,datebuf) : "", author ? " and author "+(date?0:4) : "", author ? author : "", state ? " and state "+(date||author?0:4) : "", state ? state : "" );} static voidabsent(revno, field) char const *revno; unsigned field;{ struct buf t; bufautobegin(&t); error("%s %s absent", field&1?"revision":"branch", partialno(&t,revno,field) ); bufautoend(&t);} intcompartial(num1, num2, length) char const *num1, *num2; unsigned length;/* compare the first "length" fields of two dot numbers; the omitted field is considered to be larger than any number *//* restriction: at least one number has length or more fields */{ register char const *s1, *s2; register size_t d1, d2; register int r; s1 = num1; s2 = num2; if (!s1) return 1; if (!s2) return -1; for (;;) { if (!*s1) return 1; if (!*s2) return -1; while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ; while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ; if (d1 != d2) return d1<d2 ? -1 : 1; if ((r = memcmp(s1, s2, d1))) return r; s1 += d1; s2 += d1; if (*s1 == '.') s1++; if (*s2 == '.') s2++; if ( --length == 0 ) return 0; }}char * partialno(rev1,rev2,length) struct buf *rev1; char const *rev2; register unsigned length;/* Function: Copies length fields of revision number rev2 into rev1. * Return rev1's string. */{ register char *r1; bufscpy(rev1, rev2); r1 = rev1->string; while (length) { while (*r1!='.' && *r1) ++r1; ++r1; length--; } /* eliminate last '.'*/ *(r1-1)='\0'; return rev1->string;} static voidstore1(store, next) struct hshentries ***store; struct hshentry *next;/* * Allocate a new list node that addresses NEXT. * Append it to the list that **STORE is the end pointer of. */{ register struct hshentries *p; p = ftalloc(struct hshentries); p->first = next; **store = p; *store = &p->rest;}struct hshentry * genrevs(revno,date,author,state,store) char const *revno, *date, *author, *state; struct hshentries **store;/* Function: finds the deltas needed for reconstructing the * revision given by revno, date, author, and state, and stores pointers * to these deltas into a list whose starting address is given by store. * The last delta (target delta) is returned. * If the proper delta could not be found, nil is returned. */{ unsigned length; register struct hshentry * next; int result; char const *branchnum; struct buf t; char datebuf[datesize]; bufautobegin(&t); if (!(next = Head)) { error("RCS file empty"); goto norev; } length = countnumflds(revno); if (length >= 1) { /* at least one field; find branch exactly */ while ((result=cmpnumfld(revno,next->num,1)) < 0) { store1(&store, next); next = next->next; if (!next) { error("branch number %s too low", partialno(&t,revno,1)); goto norev; } } if (result>0) { absent(revno, 1); goto norev; } } if (length<=1){ /* pick latest one on given branch */ branchnum = next->num; /* works even for empty revno*/ while ((next!=nil) && (cmpnumfld(branchnum,next->num,1)==0) && !( (date==nil?1:(cmpnum(date,next->date)>=0)) && (author==nil?1:(strcmp(author,next->author)==0)) && (state ==nil?1:(strcmp(state, next->state) ==0)) ) ) { store1(&store, next); next=next->next; } if ((next==nil) || (cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ { cantfindbranch( length ? revno : partialno(&t,branchnum,1), date, author, state ); goto norev; } else { store1(&store, next);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -