finally, bump the version
[alioth/cvs.git] / contrib / rcs-5.7-commitid.patch
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@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);