Home | History | Annotate | Line # | Download | only in contrib
      1 ChangeLog entry:
      2 
      3 Thanks to Paul Eggert who suggested using better random numbers as
      4 well as using the base62 format for compactness and provided the
      5 sample divide_by and convert functions used here.
      6 
      7 2005-09-29  Mark D. Baushke  <mdb (a] gnu.org>
      8 
      9 	* man/rcsfile.5in: Document new commitid delta phrase.
     10 	* man/rcsfile.5: Regenerated.
     11 
     12 	* src/ci.c (RANDOM_BYTES, COMMITID_RAW_SIZE): New constants.
     13 	(mainProg): Add commitid to delta records. Use
     14 	random data and represent in base62 or fall back to using the
     15 	same basic format construction as is used by CVS and CVSNT.
     16 	(divide_by): New function used by convert.
     17 	(convert): New fucntion to convert to base62.
     18 	* rcsbase.h (commitidsize): Room for base62 encoded block or
     19 	32bit pid plus a 32bit time rendered as hex plus one
     20 	NUL byte round up to 64.
     21 	(struct hshentry): Add new commitid field.
     22 	* src/rcsgen.c (putdelta): Preserve old commitid entries.
     23 	* src/rcssyn.c (Kcommitid): New global constant keyword.
     24 	(getdelta): Add optional parsing for it.
     25 	* src/rlog.c (putadelta): Print it out.
     26 
     27 Index:man/rcsfile.5
     28 --- man/rcsfile.5~	1995-06-16 06:58:26.000000000 +0000
     29 +++ man/rcsfile.5	2005-09-27 20:53:01.023504000 +0000
     30 @@ -1,4 +1,4 @@
     31 -.lf 1 ./rcsfile.5in
     32 +.lf 1 rcsfile.5in
     33  .\" Set p to 1 if your formatter can handle pic output.
     34  .if t .nr p 1
     35  .de Id
     36 @@ -69,6 +69,7 @@ nonterminal symbols are in
     37  		\f3state\fP	{\f2id\fP}\f3;\fP
     38  		\f3branches\fP	{\f2num\fP}*\f3;\fP
     39  		\f3next\fP	{\f2num\fP}\f3;\fP
     40 +		{ \f3commitid\fP \f2id\fP\f3;\fP }
     41  		{ \f2newphrase\fP }*
     42  .LP
     43  \f2desc\fP	::=	\f3desc\fP	\f2string\fP
     44 @@ -128,6 +129,18 @@ and all the digits of years thereafter.
     45  Dates use the Gregorian calendar; times use UTC.
     46  .PP
     47  The
     48 +.I commitid
     49 +is followed by an
     50 +.I id
     51 +token. This token is intended to be unique across
     52 +multiple files and is used to help group files as
     53 +being a part of the same logical commit.
     54 +This token must uniquely identify the commit
     55 +operation that was applied to a set of RCS files.
     56 +In particular, it must be unique among all the
     57 +commitids in this file.
     58 +.PP
     59 +The
     60  .I newphrase
     61  productions in the grammar are reserved for future extensions
     62  to the format of \*r files.
     63 @@ -230,7 +243,7 @@ The following diagram shows an example o
     64  .fi
     65  .\}
     66  .if \np \{\
     67 -.lf 232
     68 +.lf 245
     69  .PS 4.250i 3.812i
     70  .\" -2.0625 -4.25 1.75 0
     71  .\" 0.000i 4.250i 3.812i 0.000i
     72 @@ -239,7 +252,7 @@ The following diagram shows an example o
     73  .nr 0x 1
     74  \h'3.812i'
     75  .sp -1
     76 -.lf 242
     77 +.lf 255
     78  \h'2.062i-(\w'Head'u/2u)'\v'0.125i-(0v/2u)+0v+0.22m'Head
     79  .sp -1
     80  \h'2.062i'\v'0.250i'\D'l0.000i 0.500i'
     81 @@ -256,7 +269,7 @@ The following diagram shows an example o
     82  .sp -1
     83  \h'1.688i'\v'0.750i'\D'l0.000i 0.500i'
     84  .sp -1
     85 -.lf 244
     86 +.lf 257
     87  \h'2.062i-(\w'2.1'u/2u)'\v'1.000i-(0v/2u)+0v+0.22m'2.1
     88  .sp -1
     89  \h'2.062i'\v'1.250i'\D'l0.000i 0.500i'
     90 @@ -265,7 +278,7 @@ The following diagram shows an example o
     91  .sp -1
     92  \h'2.062i'\v'1.750i'\D'l-0.025i -0.100i'
     93  .sp -1
     94 -.lf 246
     95 +.lf 259
     96  \h'2.062i-(\w'1.3'u/2u)'\v'2.000i-(1v/2u)+0v+0.22m'1.3
     97  .sp -1
     98  \h'2.062i'\v'2.250i'\D'l-0.375i -0.500i'
     99 @@ -280,7 +293,7 @@ The following diagram shows an example o
    100  .sp -1
    101  \h'1.375i'\v'1.500i'\D'l0.025i 0.100i'
    102  .sp -1
    103 -.lf 249
    104 +.lf 262
    105  \h'1.375i-(\w'1.3.1.1'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.3.1.1
    106  .sp -1
    107  \h'1.375i'\v'1.000i'\D'l-0.375i 0.500i'
    108 @@ -295,7 +308,7 @@ The following diagram shows an example o
    109  .sp -1
    110  \h'2.062i'\v'2.750i'\D'l-0.025i -0.100i'
    111  .sp -1
    112 -.lf 252
    113 +.lf 265
    114  \h'2.062i-(\w'1.2'u/2u)'\v'3.000i-(1v/2u)+0v+0.22m'1.2
    115  .sp -1
    116  \h'2.062i'\v'3.250i'\D'l-0.375i -0.500i'
    117 @@ -310,7 +323,7 @@ The following diagram shows an example o
    118  .sp -1
    119  \h'0.375i'\v'2.500i'\D'l0.025i 0.100i'
    120  .sp -1
    121 -.lf 255
    122 +.lf 268
    123  \h'0.375i-(\w'1.2.1.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.1.1
    124  .sp -1
    125  \h'0.375i'\v'2.000i'\D'l-0.375i 0.500i'
    126 @@ -325,7 +338,7 @@ The following diagram shows an example o
    127  .sp -1
    128  \h'0.375i'\v'1.500i'\D'l0.025i 0.100i'
    129  .sp -1
    130 -.lf 257
    131 +.lf 270
    132  \h'0.375i-(\w'1.2.1.3'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.1.3
    133  .sp -1
    134  \h'0.375i'\v'1.000i'\D'l-0.375i 0.500i'
    135 @@ -340,7 +353,7 @@ The following diagram shows an example o
    136  .sp -1
    137  \h'2.750i'\v'2.500i'\D'l0.025i 0.100i'
    138  .sp -1
    139 -.lf 261
    140 +.lf 274
    141  \h'2.750i-(\w'1.2.2.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.2.1
    142  .sp -1
    143  \h'2.750i'\v'2.000i'\D'l-0.375i 0.500i'
    144 @@ -355,7 +368,7 @@ The following diagram shows an example o
    145  .sp -1
    146  \h'3.438i'\v'1.250i'\D'l0.025i 0.100i'
    147  .sp -1
    148 -.lf 264
    149 +.lf 277
    150  \h'3.438i-(\w'\s-21.2.2.1.1.1\s0'u/2u)'\v'1.000i-(1v/2u)+1v+0.22m'\s-21.2.2.1.1.1\s0
    151  .sp -1
    152  \h'3.438i'\v'0.750i'\D'l-0.375i 0.500i'
    153 @@ -370,7 +383,7 @@ The following diagram shows an example o
    154  .sp -1
    155  \h'2.750i'\v'1.500i'\D'l0.025i 0.100i'
    156  .sp -1
    157 -.lf 267
    158 +.lf 280
    159  \h'2.750i-(\w'1.2.2.2'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.2.2
    160  .sp -1
    161  \h'2.750i'\v'1.000i'\D'l-0.375i 0.500i'
    162 @@ -385,7 +398,7 @@ The following diagram shows an example o
    163  .sp -1
    164  \h'2.062i'\v'3.750i'\D'l-0.025i -0.100i'
    165  .sp -1
    166 -.lf 270
    167 +.lf 283
    168  \h'2.062i-(\w'1.1'u/2u)'\v'4.000i-(1v/2u)+0v+0.22m'1.1
    169  .sp -1
    170  \h'2.062i'\v'4.250i'\D'l-0.375i -0.500i'
    171 @@ -398,9 +411,9 @@ The following diagram shows an example o
    172  .if \n(00 .fi
    173  .br
    174  .nr 0x 0
    175 -.lf 271
    176 +.lf 284
    177  .PE
    178 -.lf 272
    179 +.lf 285
    180  .\}
    181  .PP
    182  .SH IDENTIFICATION
    183 Index:man/rcsfile.5in
    184 --- man/rcsfile.5in~	1995-06-05 08:28:35.000000000 +0000
    185 +++ man/rcsfile.5in	2005-09-27 20:52:46.424504000 +0000
    186 @@ -68,6 +68,7 @@ nonterminal symbols are in
    187  		\f3state\fP	{\f2id\fP}\f3;\fP
    188  		\f3branches\fP	{\f2num\fP}*\f3;\fP
    189  		\f3next\fP	{\f2num\fP}\f3;\fP
    190 +		{ \f3commitid\fP \f2id\fP\f3;\fP }
    191  		{ \f2newphrase\fP }*
    192  .LP
    193  \f2desc\fP	::=	\f3desc\fP	\f2string\fP
    194 @@ -127,6 +128,18 @@ and all the digits of years thereafter.
    195  Dates use the Gregorian calendar; times use UTC.
    196  .PP
    197  The
    198 +.I commitid
    199 +is followed by an
    200 +.I id
    201 +token. This token is intended to be unique across
    202 +multiple files and is used to help group files as
    203 +being a part of the same logical commit.
    204 +This token must uniquely identify the commit
    205 +operation that was applied to a set of RCS files.
    206 +In particular, it must be unique among all the
    207 +commitids in this file.
    208 +.PP
    209 +The
    210  .I newphrase
    211  productions in the grammar are reserved for future extensions
    212  to the format of \*r files.
    213 Index:src/rcsbase.h
    214 --- src/rcsbase.h~	1995-06-16 06:19:24.000000000 +0000
    215 +++ src/rcsbase.h	2005-09-28 21:47:51.490505000 +0000
    216 @@ -222,6 +222,11 @@ Report problems and direct all questions
    217                                /* 1 sets the default locking to strict;      */
    218                                /* used in production environments.           */
    219  
    220 +/* base64_encode(128 random bits) needs 24 bytes + 1 for NUL */
    221 +/* time_t may be 64bits on some machines needs 16 bytes + 1 as hex */
    222 +#define commitidsize	   64 /* time+1+base64(128bits)+1 | pid+time+rand+1 */
    223 +#define urandom_dev "/dev/urandom"
    224 +
    225  #define yearlength	   16 /* (good through AD 9,999,999,999,999,999)    */
    226  #define datesize (yearlength+16)	/* size of output of time2date */
    227  #define RCSTMPPREFIX '_' /* prefix for temp files in working dir  */
    228 @@ -358,6 +363,7 @@ struct hshentry {
    229  	char const	  * lockedby; /* who locks the revision		    */
    230  	char const	  * state;    /* state of revision (Exp by default) */
    231  	char const	  * name;     /* name (if any) by which retrieved   */
    232 +	char const        * commitid; /* text string to associate commits   */
    233  	struct cbuf	    log;      /* log message requested at checkin   */
    234          struct branchhead * branches; /* list of first revisions on branches*/
    235  	struct cbuf	    ig;	      /* ignored phrases in admin part	    */
    236 @@ -662,6 +668,7 @@ extern int               TotalDeltas;
    237  extern char const *const expand_names[];
    238  extern char const
    239  	Kaccess[], Kauthor[], Kbranch[], Kcomment[],
    240 +	Kcommitid[],
    241  	Kdate[], Kdesc[], Kexpand[], Khead[], Klocks[], Klog[],
    242  	Knext[], Kstate[], Kstrict[], Ksymbols[], Ktext[];
    243  void unexpected_EOF P((void)) exiting;
    244 Index:src/ci.c
    245 --- src/ci.c~	1995-06-16 06:19:24.000000000 +0000
    246 +++ src/ci.c	2005-09-29 21:57:57.814504000 +0000
    247 @@ -262,6 +262,10 @@ static void cleanup P((void));
    248  static void incnum P((char const*,struct buf*));
    249  static void addassoclst P((int,char const*));
    250  
    251 +enum {RANDOM_BYTES = 8};
    252 +enum {COMMITID_RAW_SIZE = (sizeof(time_t) + RANDOM_BYTES)};
    253 +static void convert P((char const input[COMMITID_RAW_SIZE], char *output));
    254 +
    255  static FILE *exfile;
    256  static RILE *workptr;			/* working file pointer		*/
    257  static struct buf newdelnum;		/* new revision number		*/
    258 @@ -285,6 +289,7 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
    259  	char olddate[datesize];
    260  	char newdatebuf[datesize + zonelenmax];
    261  	char targetdatebuf[datesize + zonelenmax];
    262 +	char commitid[commitidsize];
    263  	char *a, **newargv, *textfile;
    264  	char const *author, *krev, *rev, *state;
    265  	char const *diffname, *expname;
    266 @@ -309,6 +314,45 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
    267  	suffixes = X_DEFAULT;
    268  	nextassoc = &assoclst;
    269  
    270 +	{
    271 +		char buf[COMMITID_RAW_SIZE] = { 0, };
    272 +		ssize_t len = 0;
    273 +		time_t rightnow = time (NULL);
    274 +		char *startrand = buf + sizeof (time_t);
    275 +		unsigned char *p = (unsigned char *) startrand;
    276 +		size_t randbytes = RANDOM_BYTES;
    277 +		int flags = O_RDONLY;
    278 +		int fd;
    279 +#ifdef O_NOCTTY
    280 +		flags |= O_NOCTTY;
    281 +#endif
    282 +		if (rightnow != (time_t)-1)
    283 +			while (rightnow > 0) {
    284 +				*--p = rightnow % (UCHAR_MAX + 1);
    285 +				rightnow /= UCHAR_MAX + 1;
    286 +			}
    287 +		else {
    288 +			/* try to use more random data */
    289 +			randbytes = COMMITID_RAW_SIZE;
    290 +			startrand = buf;
    291 +		}
    292 +		fd = open (urandom_dev, flags);
    293 +		if (fd >= 0) {
    294 +			len = read (fd, startrand, randbytes);
    295 +			close (fd);
    296 +		}
    297 +		if (len <= 0) {
    298 +			/* no random data was available so use pid */
    299 +			long int pid = (long int)getpid ();
    300 +			p = (unsigned char *) (startrand + sizeof (pid));
    301 +			while (pid > 0) {
    302 +			    *--p = pid % (UCHAR_MAX + 1);
    303 +			    pid /= UCHAR_MAX + 1;
    304 +			}
    305 +		}
    306 +		convert(buf, commitid);
    307 +	}
    308 +
    309  	argc = getRCSINIT(argc, argv, &newargv);
    310  	argv = newargv;
    311  	while (a = *++argv,  0<--argc && *a++=='-') {
    312 @@ -532,6 +576,8 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
    313  	newdelta.name = 0;
    314  	clear_buf(&newdelta.ig);
    315  	clear_buf(&newdelta.igtext);
    316 +	/* set commitid */
    317 +	newdelta.commitid=commitid;
    318  	/* set author */
    319  	if (author)
    320  		newdelta.author=author;     /* set author given by -w         */
    321 @@ -1317,3 +1363,38 @@ addassoclst(flag, sp)
    322  	*nextassoc = pt;
    323  	nextassoc = &pt->nextsym;
    324  }
    325 +
    326 +static char const alphabet[62] =
    327 +  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    328 +
    329 +/* Divide BUF by D, returning the remainder.  Replace BUF by the
    330 +   quotient.  BUF[0] is the most significant part of BUF.
    331 +   D must not exceed UINT_MAX >> CHAR_BIT.  */
    332 +static unsigned int
    333 +divide_by (unsigned char buf[COMMITID_RAW_SIZE], unsigned int d)
    334 +{
    335 +  unsigned int carry = 0;
    336 +  int i;
    337 +  for (i = 0; i < COMMITID_RAW_SIZE; i++)
    338 +    {
    339 +      unsigned int byte = buf[i];
    340 +      unsigned int dividend = (carry << CHAR_BIT) + byte;
    341 +      buf[i] = dividend / d;
    342 +      carry = dividend % d;
    343 +    }
    344 +  return carry;
    345 +}
    346 +
    347 +static void
    348 +convert (char const input[COMMITID_RAW_SIZE], char *output)
    349 +{
    350 +  static char const zero[COMMITID_RAW_SIZE] = { 0, };
    351 +  unsigned char buf[COMMITID_RAW_SIZE];
    352 +  size_t o = 0;
    353 +  memcpy (buf, input, COMMITID_RAW_SIZE);
    354 +  while (memcmp (buf, zero, COMMITID_RAW_SIZE) != 0)
    355 +    output[o++] = alphabet[divide_by (buf, sizeof alphabet)];
    356 +  if (! o)
    357 +    output[o++] = '0';
    358 +  output[o] = '\0';
    359 +}
    360 Index:src/rcsgen.c
    361 --- src/rcsgen.c~	1995-06-16 06:19:24.000000000 +0000
    362 +++ src/rcsgen.c	2005-09-27 22:08:47.421504000 +0000
    363 @@ -547,6 +547,9 @@ putdelta(node, fout)
    364  
    365  	aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
    366  	awrite(node->ig.string, node->ig.size, fout);
    367 +
    368 +	if (node->commitid)
    369 +		aprintf(fout, "%s\t%s;\n", Kcommitid, node->commitid);
    370  }
    371  
    372  
    373 Index:src/rcssyn.c
    374 --- src/rcssyn.c~	1995-06-16 06:19:24.000000000 +0000
    375 +++ src/rcssyn.c	2005-09-27 22:08:47.429504000 +0000
    376 @@ -171,6 +171,7 @@ char const
    377  	Kauthor[]   = "author",
    378  	Kbranch[]   = "branch",
    379  	Kcomment[]  = "comment",
    380 +	Kcommitid[] = "commitid",
    381  	Kdate[]     = "date",
    382  	Kdesc[]     = "desc",
    383  	Kexpand[]   = "expand",
    384 @@ -433,6 +434,13 @@ getdelta()
    385  	Delta->lockedby = 0;
    386  	Delta->log.string = 0;
    387  	Delta->selector = true;
    388 +
    389 +	if (getkeyopt(Kcommitid)) {
    390 +		Delta->commitid = NextString;
    391 +		nextlex();
    392 +		getsemi(Kcommitid);
    393 +        }
    394 +
    395  	Delta->ig = getphrases(Kdesc);
    396          TotalDeltas++;
    397          return (true);
    398 Index:src/rlog.c
    399 --- src/rlog.c~	1995-06-16 06:19:24.000000000 +0000
    400 +++ src/rlog.c	2005-09-26 17:23:55.257504000 +0000
    401 @@ -591,6 +591,10 @@ putadelta(node,editscript,trunk)
    402  	      aprintf(out, insDelFormat,
    403                               editscript->insertlns, editscript->deletelns);
    404  
    405 +	if ( node->commitid )
    406 +	   aprintf(out, "%s commitid: %s", (editscript) ? ";" : "",
    407 +		   node->commitid);
    408 +
    409          newbranch = node->branches;
    410          if ( newbranch ) {
    411  	   bufautobegin(&branchnum);
    412