1 /* $OpenBSD: rcsnum.c,v 1.56 2015/01/16 06:40:07 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <ctype.h> 28 #include <string.h> 29 30 #include "cvs.h" 31 32 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 33 34 static void rcsnum_setsize(RCSNUM *, u_int); 35 static char *rcsnum_itoa(u_int16_t, char *, size_t); 36 37 /* 38 * rcsnum_alloc() 39 * 40 * Allocate an RCS number structure and return a pointer to it. 41 */ 42 RCSNUM * 43 rcsnum_alloc(void) 44 { 45 RCSNUM *rnp; 46 47 rnp = xcalloc(1, sizeof(*rnp)); 48 rnp->rn_len = 0; 49 50 return (rnp); 51 } 52 53 /* 54 * rcsnum_addmagic() 55 * 56 * Adds a magic branch number to an RCS number. 57 * Returns 0 on success, or -1 on failure. 58 */ 59 int 60 rcsnum_addmagic(RCSNUM *rn) 61 { 62 if (!rn->rn_len || rn->rn_len > RCSNUM_MAXLEN - 1) 63 return -1; 64 rcsnum_setsize(rn, rn->rn_len + 1); 65 rn->rn_id[rn->rn_len - 1] = rn->rn_id[rn->rn_len - 2]; 66 rn->rn_id[rn->rn_len - 2] = 0; 67 68 return 0; 69 } 70 71 /* 72 * rcsnum_parse() 73 * 74 * Parse a string specifying an RCS number and return the corresponding RCSNUM. 75 */ 76 RCSNUM * 77 rcsnum_parse(const char *str) 78 { 79 char *ep; 80 RCSNUM *num; 81 82 num = rcsnum_alloc(); 83 if (rcsnum_aton(str, &ep, num) < 0 || *ep != '\0') { 84 rcsnum_free(num); 85 num = NULL; 86 } 87 88 return (num); 89 } 90 91 /* 92 * rcsnum_free() 93 * 94 * Free an RCSNUM structure previously allocated with rcsnum_alloc(). 95 */ 96 void 97 rcsnum_free(RCSNUM *rn) 98 { 99 xfree(rn); 100 } 101 102 /* 103 * rcsnum_tostr() 104 * 105 * Format the RCS number <nump> into a human-readable dot-separated 106 * representation and store the resulting string in <buf>, which is of size 107 * <blen>. 108 * Returns a pointer to the start of <buf>. On failure <buf> is set to 109 * an empty string. 110 */ 111 char * 112 rcsnum_tostr(const RCSNUM *nump, char *buf, size_t blen) 113 { 114 u_int i; 115 char tmp[8]; 116 117 if (nump == NULL || nump->rn_len == 0) { 118 buf[0] = '\0'; 119 return (buf); 120 } 121 122 if (strlcpy(buf, rcsnum_itoa(nump->rn_id[0], buf, blen), blen) >= blen) 123 fatal("rcsnum_tostr: truncation"); 124 for (i = 1; i < nump->rn_len; i++) { 125 const char *str; 126 127 str = rcsnum_itoa(nump->rn_id[i], tmp, sizeof(tmp)); 128 if (strlcat(buf, ".", blen) >= blen || 129 strlcat(buf, str, blen) >= blen) 130 fatal("rcsnum_tostr: truncation"); 131 } 132 return (buf); 133 } 134 135 static char * 136 rcsnum_itoa(u_int16_t num, char *buf, size_t len) 137 { 138 u_int16_t i; 139 char *p; 140 141 if (num == 0) 142 return "0"; 143 144 p = buf + len - 1; 145 i = num; 146 bzero(buf, len); 147 while (i) { 148 *--p = '0' + (i % 10); 149 i /= 10; 150 } 151 return (p); 152 } 153 154 /* 155 * rcsnum_cpy() 156 * 157 * Copy the number stored in <nsrc> in the destination <ndst> up to <depth> 158 * numbers deep. If <depth> is 0, there is no depth limit. 159 */ 160 void 161 rcsnum_cpy(const RCSNUM *nsrc, RCSNUM *ndst, u_int depth) 162 { 163 u_int len; 164 165 len = nsrc->rn_len; 166 if (depth != 0 && len > depth) 167 len = depth; 168 169 rcsnum_setsize(ndst, len); 170 memcpy(ndst->rn_id, nsrc->rn_id, len * sizeof(*(nsrc->rn_id))); 171 } 172 173 /* 174 * rcsnum_cmp() 175 * 176 * Compare the two numbers <n1> and <n2>. Returns -1 if <n1> is larger than 177 * <n2>, 0 if they are both the same, and 1 if <n2> is larger than <n1>. 178 * The <depth> argument specifies how many numbers deep should be checked for 179 * the result. A value of 0 means that the depth will be the maximum of the 180 * two numbers, so that a longer number is considered greater than a shorter 181 * number if they are equal up to the minimum length. 182 */ 183 int 184 rcsnum_cmp(RCSNUM *n1, RCSNUM *n2, u_int depth) 185 { 186 int res; 187 u_int i; 188 size_t slen; 189 190 if (!rcsnum_differ(n1, n2)) 191 return (0); 192 193 slen = MINIMUM(n1->rn_len, n2->rn_len); 194 if (depth != 0 && slen > depth) 195 slen = depth; 196 197 for (i = 0; i < slen; i++) { 198 res = n1->rn_id[i] - n2->rn_id[i]; 199 if (res < 0) 200 return (1); 201 else if (res > 0) 202 return (-1); 203 } 204 205 /* If an explicit depth was specified, and we've 206 * already checked up to depth, consider the 207 * revision numbers equal. */ 208 if (depth != 0 && slen == depth) 209 return (0); 210 else if (n1->rn_len > n2->rn_len) 211 return (-1); 212 else if (n2->rn_len > n1->rn_len) 213 return (1); 214 215 return (0); 216 } 217 218 /* 219 * rcsnum_aton() 220 * 221 * Translate the string <str> containing a sequence of digits and periods into 222 * its binary representation, which is stored in <nump>. The address of the 223 * first byte not part of the number is stored in <ep> on return, if it is not 224 * NULL. 225 * Returns 0 on success, or -1 on failure. 226 */ 227 int 228 rcsnum_aton(const char *str, char **ep, RCSNUM *nump) 229 { 230 u_int32_t val; 231 const char *sp; 232 char *s; 233 234 nump->rn_len = 0; 235 nump->rn_id[0] = 0; 236 237 for (sp = str;; sp++) { 238 if (!isdigit((unsigned char)*sp) && (*sp != '.')) 239 break; 240 241 if (*sp == '.') { 242 if (nump->rn_len >= RCSNUM_MAXLEN - 1) 243 goto rcsnum_aton_failed; 244 245 nump->rn_len++; 246 nump->rn_id[nump->rn_len] = 0; 247 continue; 248 } 249 250 val = (nump->rn_id[nump->rn_len] * 10) + (*sp - '0'); 251 if (val > RCSNUM_MAXNUM) 252 fatal("RCSNUM overflow!"); 253 254 nump->rn_id[nump->rn_len] = val; 255 } 256 257 if (ep != NULL) 258 *(const char **)ep = sp; 259 260 /* 261 * Handle "magic" RCS branch numbers. 262 * 263 * What are they? 264 * 265 * Magic branch numbers have an extra .0. at the second farmost 266 * rightside of the branch number, so instead of having an odd 267 * number of dot-separated decimals, it will have an even number. 268 * 269 * Now, according to all the documentation I've found on the net 270 * about this, cvs does this for "efficiency reasons", I'd like 271 * to hear one. 272 * 273 * We just make sure we remove the .0. from in the branch number. 274 * 275 * XXX - for compatibility reasons with GNU cvs we _need_ 276 * to skip this part for the 'log' command, apparently it does 277 * show the magic branches for an unknown and probably 278 * completely insane and not understandable reason in that output. 279 * 280 */ 281 if (nump->rn_len > 2 && nump->rn_id[nump->rn_len - 1] == 0) { 282 /* 283 * Look for ".0.x" at the end of the branch number. 284 */ 285 if ((s = strrchr(str, '.')) != NULL) { 286 s--; 287 while (*s != '.') 288 s--; 289 290 /* 291 * If we have a "magic" branch, adjust it 292 * so the .0. is removed. 293 */ 294 if (!strncmp(s, RCS_MAGIC_BRANCH, 295 sizeof(RCS_MAGIC_BRANCH) - 1)) { 296 nump->rn_id[nump->rn_len - 1] = 297 nump->rn_id[nump->rn_len]; 298 nump->rn_len--; 299 } 300 } 301 } 302 303 /* We can't have a single-digit rcs number. */ 304 if (nump->rn_len == 0) { 305 nump->rn_len++; 306 nump->rn_id[nump->rn_len] = 0; 307 } 308 309 nump->rn_len++; 310 return (nump->rn_len); 311 312 rcsnum_aton_failed: 313 nump->rn_len = 0; 314 return (-1); 315 } 316 317 /* 318 * rcsnum_inc() 319 * 320 * Increment the revision number specified in <num>. 321 * Returns a pointer to the <num> on success, or NULL on failure. 322 */ 323 RCSNUM * 324 rcsnum_inc(RCSNUM *num) 325 { 326 if (num->rn_id[num->rn_len - 1] == RCSNUM_MAXNUM) 327 return (NULL); 328 num->rn_id[num->rn_len - 1]++; 329 return (num); 330 } 331 332 /* 333 * rcsnum_dec() 334 * 335 * Decreases the revision number specified in <num>, if doing so will not 336 * result in an ending value below 1. E.g. 4.2 will go to 4.1 but 4.1 will 337 * be returned as 4.1. 338 */ 339 RCSNUM * 340 rcsnum_dec(RCSNUM *num) 341 { 342 /* XXX - Is it an error for the number to be 0? */ 343 if (num->rn_id[num->rn_len - 1] <= 1) 344 return (num); 345 num->rn_id[num->rn_len - 1]--; 346 return (num); 347 } 348 349 /* 350 * rcsnum_revtobr() 351 * 352 * Retrieve the branch number associated with the revision number <num>. 353 * If <num> is a branch revision, the returned value will be the same 354 * number as the argument. 355 */ 356 RCSNUM * 357 rcsnum_revtobr(const RCSNUM *num) 358 { 359 RCSNUM *brnum; 360 361 if (num->rn_len < 2) 362 return (NULL); 363 364 brnum = rcsnum_alloc(); 365 rcsnum_cpy(num, brnum, 0); 366 367 if (!RCSNUM_ISBRANCH(brnum)) 368 brnum->rn_len--; 369 370 return (brnum); 371 } 372 373 /* 374 * rcsnum_brtorev() 375 * 376 * Retrieve the initial revision number associated with the branch number <num>. 377 * If <num> is a revision number, an error will be returned. 378 */ 379 RCSNUM * 380 rcsnum_brtorev(const RCSNUM *brnum) 381 { 382 RCSNUM *num; 383 384 if (!RCSNUM_ISBRANCH(brnum)) { 385 return (NULL); 386 } 387 388 num = rcsnum_alloc(); 389 rcsnum_setsize(num, brnum->rn_len + 1); 390 rcsnum_cpy(brnum, num, brnum->rn_len); 391 num->rn_id[num->rn_len++] = 1; 392 393 return (num); 394 } 395 396 RCSNUM * 397 rcsnum_new_branch(RCSNUM *rev) 398 { 399 RCSNUM *branch; 400 401 if (rev->rn_len > RCSNUM_MAXLEN - 1) 402 return NULL; 403 404 branch = rcsnum_alloc(); 405 rcsnum_cpy(rev, branch, 0); 406 rcsnum_setsize(branch, rev->rn_len + 1); 407 branch->rn_id[branch->rn_len - 1] = 2; 408 409 return branch; 410 } 411 412 RCSNUM * 413 rcsnum_branch_root(RCSNUM *brev) 414 { 415 RCSNUM *root; 416 417 if (!RCSNUM_ISBRANCHREV(brev)) 418 fatal("rcsnum_branch_root: no revision on branch specified"); 419 420 root = rcsnum_alloc(); 421 rcsnum_cpy(brev, root, 0); 422 root->rn_len -= 2; 423 return (root); 424 } 425 426 static void 427 rcsnum_setsize(RCSNUM *num, u_int len) 428 { 429 num->rn_len = len; 430 } 431 432 int 433 rcsnum_differ(RCSNUM *r1, RCSNUM *r2) 434 { 435 int i, len; 436 437 if (r1->rn_len != r2->rn_len) 438 return (1); 439 440 len = MINIMUM(r1->rn_len, r2->rn_len); 441 for (i = 0; i < len; i++) { 442 if (r1->rn_id[i] != r2->rn_id[i]) 443 return (1); 444 } 445 446 return (0); 447 } 448