rcsnum.c revision 1.1
1/* $OpenBSD: rcsnum.c,v 1.1 2004/07/13 22:02:40 jfb 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 <sys/param.h> 28 29 30#include <ctype.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34 35#include "rcs.h" 36#include "log.h" 37 38 39 40/* 41 * rcsnum_alloc() 42 * 43 * Allocate an RCS number structure. 44 */ 45 46RCSNUM* 47rcsnum_alloc(void) 48{ 49 RCSNUM *rnp; 50 51 rnp = (RCSNUM *)malloc(sizeof(*rnp)); 52 if (rnp == NULL) { 53 cvs_log(LP_ERR, "failed to allocate RCS number"); 54 return (NULL); 55 } 56 rnp->rn_len = 0; 57 rnp->rn_id = NULL; 58 59 return (rnp); 60} 61 62 63/* 64 * rcsnum_free() 65 * 66 * Free an RCSNUM structure previously allocated with rcsnum_alloc(). 67 */ 68 69void 70rcsnum_free(RCSNUM *rn) 71{ 72 if (rn->rn_id != NULL) 73 free(rn->rn_id); 74 free(rn); 75} 76 77 78/* 79 * rcsnum_tostr() 80 * Returns a pointer to the start of <buf> on success, or NULL on failure. 81 */ 82 83char* 84rcsnum_tostr(const RCSNUM *nump, char *buf, size_t blen) 85{ 86 u_int i; 87 char tmp[8]; 88 89 if (nump->rn_len == 0) { 90 buf[0] = '\0'; 91 return (buf); 92 } 93 94 snprintf(buf, blen, "%u", nump->rn_id[0]); 95 for (i = 1; i < nump->rn_len; i++) { 96 snprintf(tmp, sizeof(tmp), ".%u", nump->rn_id[i]); 97 strlcat(buf, tmp, blen); 98 } 99 100 return (buf); 101} 102 103 104/* 105 * rcsnum_cpy() 106 * 107 * Copy the number stored in <nsrc> in the destination <ndst> up to <depth> 108 * numbers deep. 109 * Returns 0 on success, or -1 on failure. 110 */ 111 112int 113rcsnum_cpy(const RCSNUM *nsrc, RCSNUM *ndst, u_int depth) 114{ 115 u_int len; 116 size_t sz; 117 void *tmp; 118 119 len = nsrc->rn_len; 120 if ((depth != 0) && (len > depth)) 121 len = depth; 122 sz = len * sizeof(u_int16_t); 123 124 tmp = realloc(ndst->rn_id, sz); 125 if (tmp == NULL) { 126 cvs_log(LP_ERR, "failed to reallocate RCSNUM"); 127 return (-1); 128 } 129 130 ndst->rn_id = (u_int16_t *)tmp; 131 ndst->rn_len = len; 132 memcpy(ndst->rn_id, nsrc->rn_id, sz); 133 return (0); 134} 135 136 137/* 138 * rcsnum_cmp() 139 * 140 * Compare the two numbers <n1> and <n2>. Returns -1 if <n1> is larger than 141 * <n2>, 0 if they are both the same, and 1 if <n2> is larger than <n1>. 142 * The <depth> argument specifies how many numbers deep should be checked for 143 * the result. A value of 0 means that the depth will be the minimum of the 144 * two numbers. 145 */ 146 147int 148rcsnum_cmp(const RCSNUM *n1, const RCSNUM *n2, u_int depth) 149{ 150 int res; 151 u_int i; 152 size_t slen; 153 154 slen = MIN(n1->rn_len, n2->rn_len); 155 if ((depth != 0) && (slen > depth)) 156 slen = depth; 157 158 for (i = 0; i < slen; i++) { 159 res = n1->rn_id[i] - n2->rn_id[i]; 160 if (res < 0) 161 return (1); 162 else if (res > 0) 163 return (-1); 164 } 165 166 if (n1->rn_len > n2->rn_len) 167 return (-1); 168 else if (n2->rn_len > n1->rn_len) 169 return (1); 170 171 return (0); 172} 173 174 175/* 176 * rcsnum_aton() 177 * 178 * Translate the string <str> containing a sequence of digits and periods into 179 * its binary representation, which is stored in <nump>. The address of the 180 * first byte not part of the number is stored in <ep> on return, if it is not 181 * NULL. 182 * Returns 0 on success, or -1 on failure. 183 */ 184 185int 186rcsnum_aton(const char *str, char **ep, RCSNUM *nump) 187{ 188 const char *sp; 189 void *tmp; 190 191 if (!isdigit(*str)) 192 return (-1); 193 194 nump->rn_id = (u_int16_t *)malloc(sizeof(u_int16_t)); 195 if (nump->rn_id == NULL) 196 return (-1); 197 198 nump->rn_len = 0; 199 200 for (sp = str; ; sp++) { 201 if (!isdigit(*sp) && (*sp != '.')) { 202 if (nump->rn_id[nump->rn_len] == 0) { 203 return (-1); 204 } 205 break; 206 } 207 208 if (*sp == '.') { 209 nump->rn_len++; 210 tmp = realloc(nump->rn_id, 211 (nump->rn_len + 1) * sizeof(u_int16_t)); 212 if (tmp == NULL) { 213 free(nump->rn_id); 214 nump->rn_len = 0; 215 nump->rn_id = NULL; 216 return (-1); 217 } 218 nump->rn_id = (u_int16_t *)tmp; 219 continue; 220 } 221 222 nump->rn_id[nump->rn_len] *= 10; 223 nump->rn_id[nump->rn_len] += *sp - 0x30; 224 } 225 226 if (ep != NULL) 227 *ep = (char *)sp; 228 229 nump->rn_len++; 230 return (nump->rn_len); 231} 232