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