X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/146d2228ccbbe64a7e5d457294c6b5493f1ff4ae..5dd14f0c3388f69932d521915e039e32b9e6d970:/lib/compat.c diff --git a/lib/compat.c b/lib/compat.c index 5b7a2696..f756f76d 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -1,42 +1,37 @@ -/* - Copyright (C) Andrew Tridgell 1998 - Copyright (C) 2002 by Martin Pool - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/** - * @file compat.c +/* + * Reimplementations of standard functions for platforms that don't have them. * - * Reimplementations of standard functions for platforms that don't - * have them. - **/ - - + * Copyright (C) 1998 Andrew Tridgell + * Copyright (C) 2002 Martin Pool + * Copyright (C) 2004, 2005, 2006 Wayne Davison + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, visit the http://fsf.org website. + */ #include "rsync.h" +#include "itypes.h" +extern char number_separator; #ifndef HAVE_STRDUP char *strdup(char *s) { - int l = strlen(s) + 1; - char *ret = (char *)malloc(l); - if (ret) - strcpy(ret,s); - return ret; + int len = strlen(s) + 1; + char *ret = (char *)malloc(len); + if (ret) + memcpy(ret, s, len); + return ret; } #endif @@ -86,7 +81,7 @@ /** * Find the first ocurrence in @p s of any character in @p accept. * - * Derived from glibc + * Derived from glibc **/ char *strpbrk(const char *s, const char *accept) { @@ -105,7 +100,7 @@ #ifndef HAVE_STRLCPY /** - * Like strncpy but does not 0 fill the buffer and always null + * Like strncpy but does not 0 fill the buffer and always null * terminates. * * @param bufsize is the size of the destination buffer. @@ -128,7 +123,7 @@ #ifndef HAVE_STRLCAT /** - * Like strncat() but does not 0 fill the buffer and always null + * Like strncat() but does not 0 fill the buffer and always null * terminates. * * @param bufsize length of the buffer, which should be one more than @@ -159,3 +154,113 @@ int sys_gettimeofday(struct timeval *tv) return gettimeofday(tv); #endif } + +#define HUMANIFY(mult) \ + do { \ + if (num >= mult || num <= -mult) { \ + double dnum = (double)num / mult; \ + char units; \ + if (num < 0) \ + dnum = -dnum; \ + if (dnum < mult) \ + units = 'K'; \ + else if ((dnum /= mult) < mult) \ + units = 'M'; \ + else if ((dnum /= mult) < mult) \ + units = 'G'; \ + else { \ + dnum /= mult; \ + units = 'T'; \ + } \ + if (num < 0) \ + dnum = -dnum; \ + snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \ + return bufs[n]; \ + } \ + } while (0) + +/* Return the int64 number as a string. If the human_flag arg is non-zero, + * we may output the number in K, M, G, or T units. If we don't add a unit + * suffix, we will append the fract string, if it is non-NULL. We can + * return up to 4 buffers at a time. */ +char *do_big_num(int64 num, int human_flag, const char *fract) +{ + static char bufs[4][128]; /* more than enough room */ + static unsigned int n; + char *s; + int len, negated; + + n = (n + 1) % (sizeof bufs / sizeof bufs[0]); + + if (human_flag > 1) { + if (human_flag == 2) + HUMANIFY(1000); + else + HUMANIFY(1024); + } + + s = bufs[n] + sizeof bufs[0] - 1; + if (fract) { + len = strlen(fract); + s -= len; + strlcpy(s, fract, len + 1); + } else + *s = '\0'; + + len = 0; + + if (!num) + *--s = '0'; + if (num < 0) { + /* A maximum-size negated number can't fit as a positive, + * so do one digit in negated form to start us off. */ + *--s = (char)(-(num % 10)) + '0'; + num = -(num / 10); + len++; + negated = 1; + } else + negated = 0; + + while (num) { + if (human_flag) { + if (len == 3) { + *--s = number_separator; + len = 1; + } else + len++; + } + *--s = (char)(num % 10) + '0'; + num /= 10; + } + + if (negated) + *--s = '-'; + + return s; +} + +/* Return the double number as a string. If the human_flag option is > 1, + * we may output the number in K, M, G, or T units. The buffer we use for + * our result is either a single static buffer defined here, or a buffer + * we get from do_big_num(). */ +char *do_big_dnum(double dnum, int human_flag, int decimal_digits) +{ + static char tmp_buf[128]; +#if SIZEOF_INT64 >= 8 + char *fract; + + snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum); + + if (!human_flag || (dnum < 1000.0 && dnum > -1000.0)) + return tmp_buf; + + for (fract = tmp_buf+1; isDigit(fract); fract++) {} + + return do_big_num((int64)dnum, human_flag, fract); +#else + /* A big number might lose digits converting to a too-short int64, + * so let's just return the raw double conversion. */ + snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum); + return tmp_buf; +#endif +}