diff options
author | Wayne Davison <wayne@opencoder.net> | 2020-07-11 10:32:59 -0700 |
---|---|---|
committer | Wayne Davison <wayne@opencoder.net> | 2020-07-11 11:39:36 -0700 |
commit | da7a3506678329e3ba916201f4f7406c7028ac58 (patch) | |
tree | 68c3a0aff27e7d5b68906373f2f10622c4e0e99e | |
parent | 66ca4fc97bcedb7376dda67b8d07df280eaf462a (diff) | |
download | rsync-da7a3506678329e3ba916201f4f7406c7028ac58.tar.gz |
Some number & string improvements
- Use strdup(do_big_num(...)) to replace num_to_byte_string(...).
- Allow a ',' for a decimal point in a SIZE option in some locales.
- Get rid of old (now unused) strdup() compatibility function.
- Try harder to include the newline in a single error message write.
-rw-r--r-- | cleanup.c | 4 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | lib/compat.c | 85 | ||||
-rw-r--r-- | log.c | 10 | ||||
-rw-r--r-- | options.c | 10 | ||||
-rw-r--r-- | rsync.1.md | 21 | ||||
-rw-r--r-- | util2.c | 18 |
7 files changed, 65 insertions, 85 deletions
@@ -222,10 +222,6 @@ NORETURN void _exit_cleanup(int code, const char *file, int line) * we don't want to output a duplicate error. */ if ((exit_code && line > 0) || am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1)))) { -#ifdef HAVE_USLEEP /* A tiny delay just in case both sender & receiver are sending a msg at the same time. */ - if (am_server && exit_code) - usleep(50); -#endif log_exit(exit_code, exit_file, exit_line); } diff --git a/configure.ac b/configure.ac index a49e6add..69c8f933 100644 --- a/configure.ac +++ b/configure.ac @@ -820,7 +820,7 @@ dnl AC_FUNC_MEMCMP AC_FUNC_UTIME_NULL AC_FUNC_ALLOCA -AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ +AC_CHECK_FUNCS(waitpid wait4 getcwd chown chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ chflags getattrlist \ memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ diff --git a/lib/compat.c b/lib/compat.c index 26a2aa60..513d79b2 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -24,16 +24,24 @@ static char number_separator; -#ifndef HAVE_STRDUP - char *strdup(char *s) +char get_number_separator(void) { - int len = strlen(s) + 1; - char *ret = (char *)malloc(len); - if (ret) - memcpy(ret, s, len); - return ret; + if (!number_separator) { + char buf[32]; + snprintf(buf, sizeof buf, "%f", 3.14); + if (strchr(buf, '.') != NULL) + number_separator = ','; + else + number_separator = '.'; + } + + return number_separator; +} + +char get_decimal_point(void) +{ + return get_number_separator() == ',' ? '.' : ','; } -#endif #ifndef HAVE_GETCWD char *getcwd(char *buf, int size) @@ -155,30 +163,6 @@ int sys_gettimeofday(struct timeval *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 @@ -190,22 +174,35 @@ char *do_big_num(int64 num, int human_flag, const char *fract) char *s; int len, negated; - if (human_flag && !number_separator) { - char buf[32]; - snprintf(buf, sizeof buf, "%f", 3.14); - if (strchr(buf, '.') != NULL) - number_separator = ','; - else - number_separator = '.'; - } + if (human_flag && !number_separator) + (void)get_number_separator(); n = (n + 1) % (sizeof bufs / sizeof bufs[0]); if (human_flag > 1) { - if (human_flag == 2) - HUMANIFY(1000); - else - HUMANIFY(1024); + int mult = human_flag == 2 ? 1000 : 1024; + 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 if ((dnum /= mult) < mult) + units = 'T'; + else { + dnum /= mult; + units = 'P'; + } + if (num < 0) + dnum = -dnum; + snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); + return bufs[n]; + } } s = bufs[n] + sizeof bufs[0] - 1; @@ -350,8 +350,7 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8) output_needs_newline = 0; } - trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r') - ? buf[--len] : 0; + trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r') ? buf[--len] : '\0'; if (len && buf[0] == '\r') { fputc('\r', f); @@ -372,7 +371,12 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8) iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT); ierrno = errno; if (outbuf.len) { - filtered_fwrite(f, convbuf, outbuf.len, 0, 0); + char trailing = inbuf.len ? '\0' : trailing_CR_or_NL; + filtered_fwrite(f, convbuf, outbuf.len, 0, trailing); + if (trailing) { + trailing_CR_or_NL = '\0'; + fflush(f); + } outbuf.len = 0; } /* Log one byte of illegal/incomplete sequence and continue with @@ -1261,7 +1261,7 @@ static ssize_t parse_size_arg(const char *size_arg, char def_suf, const char *op ssize_t limit = -1, size = 1; for (arg = size_arg; isDigit(arg); arg++) {} - if (*arg == '.') + if (*arg == '.' || *arg == get_decimal_point()) /* backward compatibility: always allow '.' */ for (arg++; isDigit(arg); arg++) {} switch (*arg && *arg != '+' && *arg != '-' ? *arg++ : def_suf) { case 'b': case 'B': @@ -1714,20 +1714,20 @@ int parse_arguments(int *argc_p, const char ***argv_p) case OPT_MAX_SIZE: if ((max_size = parse_size_arg(max_size_arg, 'b', "max-size", 0, -1, False)) < 0) return 0; - max_size_arg = num_to_byte_string(max_size); + max_size_arg = strdup(do_big_num(max_size, 0, NULL)); break; case OPT_MIN_SIZE: if ((min_size = parse_size_arg(min_size_arg, 'b', "min-size", 0, -1, False)) < 0) return 0; - min_size_arg = num_to_byte_string(min_size); + min_size_arg = strdup(do_big_num(min_size, 0, NULL)); break; case OPT_BWLIMIT: { ssize_t size = parse_size_arg(bwlimit_arg, 'K', "bwlimit", 512, -1, True); if (size < 0) return 0; - bwlimit_arg = num_to_byte_string(size); + bwlimit_arg = strdup(do_big_num(size, 0, NULL)); bwlimit = (size + 512) / 1024; break; } @@ -2691,7 +2691,7 @@ void server_options(char **args, int *argc_p) } if (block_size) { - if (asprintf(&arg, "-B%u", block_size) < 0) + if (asprintf(&arg, "-B%u", (int)block_size) < 0) goto oom; args[ac++] = arg; } @@ -1726,19 +1726,18 @@ your home directory (remove the '=' for that). This tells rsync to avoid transferring any file that is larger than the specified SIZE. A numeric value can be suffixed with a string to indicate - a size multiplier or left unqualified to specify bytes. Feel free to use a - fractional value along with a suffix, such as `--max-size=1.5m`. + the numeric units or left unqualified to specify bytes. Feel free to use a + fractional value along with the units, such as `--max-size=1.5m`. This option is a transfer rule, not an exclude, so it doesn't affect the data that goes into the file-lists, and thus it doesn't affect deletions. It just limits the files that the receiver requests to be transferred. - The accepted suffix letters are: `B`, `K`, `M`, `G`, `T`, and `P` for - bytes, kilobytes/kibibytes, megabytes/mebibytes, gigabytes/gibibytes, - terabytes/tebibytes, and petabytes/pebibytes. If you use a single-char - suffix or add-on "ib" to it (e.g. "G" or "GiB") then you get units that are + The first letter of a units string can be `B` (bytes), `K` (kilo), `M` + (mega), `G` (giga), `T` (tera), or `P` (peta). If the string is a single + char or has "ib" added to it (e.g. "G" or "GiB") then the units are multiples of 1024. If you use a two-letter suffix that ends with a "B" - (e.g. "kb") then you get units that are multiples of 1000. The suffix + (e.g. "kb") then you get units that are multiples of 1000. The string's letters can be any mix of upper and lower-case that you want to use. Finally, if the string ends with either "+1" or "-1", it is offset by one @@ -2814,10 +2813,10 @@ your home directory (remove the '=' for that). level by one. You can take the level down to 0 (to output numbers as pure digits) by specifying the `--no-human-readable` (`--no-h`) option. - The unit letters that are appended in levels 2 and 3 are: K (kilo), M - (mega), G (giga), or T (tera). For example, a 1234567-byte file would - output as 1.23M in level-2 (assuming that a period is your local decimal - point). + The unit letters that are appended in levels 2 and 3 are: `K` (kilo), `M` + (mega), `G` (giga), `T` (tera), or `P` (peta). For example, a 1234567-byte + file would output as 1.23M in level-2 (assuming that a period is your local + decimal point). Backward compatibility note: versions of rsync prior to 3.1.0 do not support human-readable level 1, and they default to level 0. Thus, @@ -21,7 +21,6 @@ */ #include "rsync.h" -#include "ifuncs.h" #include "itypes.h" #include "inums.h" @@ -71,28 +70,13 @@ int msleep(int t) return True; } -/* Convert a num manually because the needed %lld precision is not a portable sprintf() escape. */ -char *num_to_byte_string(ssize_t num) -{ - char buf[128], *s = buf + sizeof buf - 1; - - *s = '\0'; - if (!num) - *--s = '0'; - while (num) { - *--s = (char)(num % 10) + '0'; - num /= 10; - } - return strdup(s); -} - void *my_alloc(void *ptr, size_t num, size_t size, const char *file, int line) { if (max_alloc && num >= max_alloc/size) { if (!file) return NULL; rprintf(FERROR, "[%s] exceeded --max-alloc=%s setting (file=%s, line=%d)\n", - who_am_i(), num_to_byte_string(max_alloc), file, line); + who_am_i(), do_big_num(max_alloc, 0, NULL), file, line); exit_cleanup(RERR_MALLOC); } if (!ptr) |