diff --git a/expand_number.3 b/expand_number.3 new file mode 100644 index 0000000..7fd9eb2 --- /dev/null +++ b/expand_number.3 @@ -0,0 +1,86 @@ +.\" Copyright (c) 2007 Eric Anderson +.\" Copyright (c) 2007 Pawel Jakub Dawidek +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd July 20, 2019 +.Dt EXPAND_NUMBER 3 +.Os +.Sh NAME +.Nm expand_number +.Nd format a number from human readable form +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In libutil.h +.Ft int +.Fo expand_number +.Fa "const char *buf" "uint64_t *num" +.Fc +.Sh DESCRIPTION +The +.Fn expand_number +function parses the +.Fa buf +string and stores a unsigned 64-bit quantity at +.Fa *num . +.Pp +The +.Fn expand_number +function +is case-insensitive and +follows the SI power of two convention. +.Pp +The suffixes are: +.Bl -column "Suffix" "Description" "1000000000000000000" -offset indent +.It Sy "Suffix" Ta Sy "Description" Ta Sy "Multiplier" +.It Li K Ta No kilo Ta 1024 +.It Li M Ta No mega Ta 1048576 +.It Li G Ta No giga Ta 1073741824 +.It Li T Ta No tera Ta 1099511627776 +.It Li P Ta No peta Ta 1125899906842624 +.It Li E Ta No exa Ta 1152921504606846976 +.El +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The +.Fn expand_number +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The given string contains no digits. +.It Bq Er EINVAL +An unrecognized suffix was given. +.It Bq Er ERANGE +Result doesn't fit into 64 bits. +.El +.Sh SEE ALSO +.Xr humanize_number 3 +.Sh HISTORY +The +.Fn expand_number +function first appeared in +.Fx 6.3 . diff --git a/expand_number.c b/expand_number.c new file mode 100644 index 0000000..77db226 --- /dev/null +++ b/expand_number.c @@ -0,0 +1,95 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2007 Eric Anderson + * Copyright (c) 2007 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +int +expand_number(const char *buf, uint64_t *num) +{ + char *endptr; + uintmax_t umaxval; + uint64_t number; + unsigned shift; + int serrno; + + serrno = errno; + errno = 0; + umaxval = strtoumax(buf, &endptr, 0); + if (umaxval > UINT64_MAX) + errno = ERANGE; + if (errno != 0) + return (-1); + errno = serrno; + number = umaxval; + + switch (tolower((unsigned char)*endptr)) { + case 'e': + shift = 60; + break; + case 'p': + shift = 50; + break; + case 't': + shift = 40; + break; + case 'g': + shift = 30; + break; + case 'm': + shift = 20; + break; + case 'k': + shift = 10; + break; + case 'b': + case '\0': /* No unit. */ + *num = number; + return (0); + default: + /* Unrecognized unit. */ + errno = EINVAL; + return (-1); + } + + if ((number << shift) >> shift != number) { + /* Overflow */ + errno = ERANGE; + return (-1); + } + *num = number << shift; + return (0); +} diff --git a/libutil.exports b/libutil.exports index 7609d9d..686ece7 100644 --- a/libutil.exports +++ b/libutil.exports @@ -1,3 +1,4 @@ +_expand_number _freemntopts _getmnt_silent _getmntoptnum diff --git a/libutil.h b/libutil.h index 11bd56e..616b30d 100644 --- a/libutil.h +++ b/libutil.h @@ -58,6 +58,7 @@ struct in_addr; struct sockaddr; __BEGIN_DECLS +int expand_number(const char *_buf, uint64_t *_num); int humanize_number(char *_buf, size_t _len, int64_t _number, const char *_suffix, int _scale, int _flags); diff --git a/libutil.xcodeproj/project.pbxproj b/libutil.xcodeproj/project.pbxproj index c4fa887..baf180c 100644 --- a/libutil.xcodeproj/project.pbxproj +++ b/libutil.xcodeproj/project.pbxproj @@ -82,6 +82,8 @@ BA79F9E613BB76B0006A292D /* wipefs.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA79F9BC13BB70FF006A292D /* wipefs.3 */; }; BA79F9E913BB77FA006A292D /* libutil.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA79F9AB13BB70FF006A292D /* libutil.plist */; }; BA79F9EA13BB77FF006A292D /* libutil.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA79F9AC13BB70FF006A292D /* libutil.txt */; }; + C198003123F661F9004D70D5 /* expand_number.c in Sources */ = {isa = PBXBuildFile; fileRef = C198003023F661DF004D70D5 /* expand_number.c */; }; + C198003223F66284004D70D5 /* expand_number.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C198002F23F661DF004D70D5 /* expand_number.3 */; }; FDA46DED1D6D110000C63528 /* libutil.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = FDA46DEC1D6D110000C63528 /* libutil.plist */; }; FDA4991B199D6A0400A32E83 /* humanize_number_test.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA4991A199D6A0400A32E83 /* humanize_number_test.c */; }; FDA4991C199D6B9300A32E83 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA79F9C513BB718B006A292D /* libutil.dylib */; }; @@ -164,6 +166,7 @@ dstPath = /usr/local/share/man/man3; dstSubfolderSpec = 0; files = ( + C198003223F66284004D70D5 /* expand_number.3 in CopyFiles */, BA79F9DD13BB76B0006A292D /* getmntopts.3 in CopyFiles */, BA79F9DE13BB76B0006A292D /* humanize_number.3 in CopyFiles */, BA79F9DF13BB76B0006A292D /* pidfile.3 in CopyFiles */, @@ -244,6 +247,8 @@ BA79F9BD13BB70FF006A292D /* wipefs.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wipefs.cpp; sourceTree = ""; }; BA79F9BE13BB70FF006A292D /* wipefs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wipefs.h; sourceTree = ""; }; BA79F9C513BB718B006A292D /* libutil.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libutil.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + C198002F23F661DF004D70D5 /* expand_number.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = expand_number.3; sourceTree = ""; }; + C198003023F661DF004D70D5 /* expand_number.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = expand_number.c; sourceTree = ""; }; FDA46DEC1D6D110000C63528 /* libutil.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = libutil.plist; sourceTree = ""; }; FDA49903199D69B000A32E83 /* humanize_number_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = humanize_number_test; sourceTree = BUILT_PRODUCTS_DIR; }; FDA4991A199D6A0400A32E83 /* humanize_number_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = humanize_number_test.c; sourceTree = ""; }; @@ -294,8 +299,11 @@ BA79F99513BB70D7006A292D = { isa = PBXGroup; children = ( + C198002F23F661DF004D70D5 /* expand_number.3 */, + C198003023F661DF004D70D5 /* expand_number.c */, BA79F9A313BB70FF006A292D /* ExtentManager.cpp */, BA79F9A413BB70FF006A292D /* ExtentManager.h */, + 7259A9711D519321008F83F6 /* Frameworks */, BA79F9A513BB70FF006A292D /* getmntopts.3 */, BA79F9A613BB70FF006A292D /* getmntopts.c */, BA79F9A713BB70FF006A292D /* humanize_number.3 */, @@ -307,6 +315,7 @@ BA79F9AE13BB70FF006A292D /* mntopts.h */, BA79F9AF13BB70FF006A292D /* pidfile.3 */, BA79F9B013BB70FF006A292D /* pidfile.c */, + BA79F9C613BB718B006A292D /* Products */, BA79F9B313BB70FF006A292D /* realhostname_sa.3 */, BA79F9B413BB70FF006A292D /* realhostname.3 */, BA79F9B513BB70FF006A292D /* realhostname.c */, @@ -315,16 +324,14 @@ FDA49919199D6A0400A32E83 /* tests */, BA79F9B813BB70FF006A292D /* trimdomain.3 */, BA79F9B913BB70FF006A292D /* trimdomain.c */, + FDBC27081741B47200CA4B2B /* tzlink_internal.h */, FDBC26F91741B18500CA4B2B /* tzlink.c */, FDBC27091741B47200CA4B2B /* tzlink.h */, - FDBC27081741B47200CA4B2B /* tzlink_internal.h */, FDBC26F11741B13400CA4B2B /* tzlinkd */, BA79F9BC13BB70FF006A292D /* wipefs.3 */, BA79F9BD13BB70FF006A292D /* wipefs.cpp */, BA79F9BE13BB70FF006A292D /* wipefs.h */, FDBC270C1741B66500CA4B2B /* xcconfigs */, - BA79F9C613BB718B006A292D /* Products */, - 7259A9711D519321008F83F6 /* Frameworks */, ); sourceTree = ""; }; @@ -431,6 +438,7 @@ FDBC26EC1741B13400CA4B2B /* Sources */, FDBC26ED1741B13400CA4B2B /* Frameworks */, FDBC26EE1741B13400CA4B2B /* CopyFiles */, + 35459D5A24BF78E800AD3207 /* Install Sandbox Profile */, ); buildRules = ( ); @@ -447,14 +455,15 @@ BA79F99713BB70D7006A292D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0420; + LastUpgradeCheck = 1200; }; buildConfigurationList = BA79F99A13BB70D7006A292D /* Build configuration list for PBXProject "libutil" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = BA79F99513BB70D7006A292D; productRefGroup = BA79F9C613BB718B006A292D /* Products */; @@ -473,6 +482,26 @@ /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ + 35459D5A24BF78E800AD3207 /* Install Sandbox Profile */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/tzlinkd/com.apple.tzlinkd.sb", + ); + name = "Install Sandbox Profile"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(INSTALL_ROOT)/System/Library/Sandbox/Profiles/com.apple.tzlinkd.sb", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ ${PLATFORM_NAME} = \"macosx\" ]; then\n ${CP} ${SCRIPT_INPUT_FILE_0} ${SCRIPT_OUTPUT_FILE_0}\nfi\n"; + }; BA79F9DA13BB750E006A292D /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -512,6 +541,7 @@ BA79F9CC13BB7207006A292D /* getmntopts.c in Sources */, BA79F9CD13BB7207006A292D /* humanize_number.c in Sources */, BA79F9CE13BB7207006A292D /* pidfile.c in Sources */, + C198003123F661F9004D70D5 /* expand_number.c in Sources */, BA79F9D013BB7207006A292D /* realhostname.c in Sources */, BA79F9D113BB7207006A292D /* reexec_to_match_kernel.c in Sources */, BA79F9D213BB7207006A292D /* trimdomain.c in Sources */, @@ -590,6 +620,7 @@ 3EB206CD1F5096F100B150D3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -597,6 +628,7 @@ 3EB206CE1F5096F100B150D3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -606,6 +638,34 @@ baseConfigurationReference = 3F09C378186D1F73007AF93C /* base.xcconfig */; buildSettings = { APPLY_RULES_IN_COPY_FILES = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; "PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary; "PLIST_FILE_OUTPUT_FORMAT[sdk=macosx*]" = XML; USE_HEADERMAP = NO; @@ -617,6 +677,32 @@ baseConfigurationReference = 3F09C378186D1F73007AF93C /* base.xcconfig */; buildSettings = { APPLY_RULES_IN_COPY_FILES = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; "PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary; "PLIST_FILE_OUTPUT_FORMAT[sdk=macosx*]" = XML; USE_HEADERMAP = NO; @@ -627,7 +713,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 3F7A5E8820510D34007087AF /* lib.xcconfig */; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = YES; DYLIB_COMPATIBILITY_VERSION = 1.0; DYLIB_CURRENT_VERSION = 1.0; EXECUTABLE_PREFIX = lib; @@ -654,7 +740,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 3F7A5E8820510D34007087AF /* lib.xcconfig */; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = YES; DYLIB_COMPATIBILITY_VERSION = 1.0; DYLIB_CURRENT_VERSION = 1.0; EXECUTABLE_PREFIX = lib; @@ -676,6 +762,8 @@ isa = XCBuildConfiguration; baseConfigurationReference = FDA4991D199D6CB800A32E83 /* test.xcconfig */; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -684,6 +772,8 @@ isa = XCBuildConfiguration; baseConfigurationReference = FDA4991D199D6CB800A32E83 /* test.xcconfig */; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -691,6 +781,7 @@ FDA49911199D69B800A32E83 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -698,6 +789,7 @@ FDA49912199D69B800A32E83 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -705,6 +797,7 @@ FDBC26E51741B09300CA4B2B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -712,6 +805,7 @@ FDBC26E61741B09300CA4B2B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -719,6 +813,7 @@ FDBC26EA1741B09D00CA4B2B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -726,6 +821,7 @@ FDBC26EB1741B09D00CA4B2B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -734,6 +830,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = FDBC270D1741B66500CA4B2B /* tzlinkd.xcconfig */; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; }; name = Debug; @@ -742,6 +839,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = FDBC270D1741B66500CA4B2B /* tzlinkd.xcconfig */; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; }; name = Release; diff --git a/tests/humanize_number_test.c b/tests/humanize_number_test.c new file mode 100644 index 0000000..3e7ea3a --- /dev/null +++ b/tests/humanize_number_test.c @@ -0,0 +1,621 @@ +/*- + * Copyright 2012 Clifton Royston + * Copyright 2013 John-Mark Gurney + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_STR_FLAGS_RESULT 80 +#define MAX_INT_STR_DIGITS 12 +#ifdef __APPLE__ +#define nitems(x) (sizeof((x)) / sizeof((x)[0])) +#define __INT_MAX INT_MAX +#endif /* __APPLE__ */ + +static const int64_t halfExabyte = (int64_t)500*1000*1000*1000*1000*1000L; + +static struct { + int retval; + const char *res; + int64_t num; + int flags; + int scale; +} test_args[] = { + /* tests 0-13 test 1000 suffixes */ + { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + + /* tests 14-27 test 1024 suffixes */ + { 2, "0 ", (int64_t)0L, 0, HN_AUTOSCALE }, + { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE }, + { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE }, + { 3, "1 G", (int64_t)512*1024*1024L, 0, HN_AUTOSCALE }, + { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 2, "1 ", (int64_t)1L, 0, HN_AUTOSCALE }, + { 3, "2 K", (int64_t)1536L, 0, HN_AUTOSCALE }, + { 3, "2 M", (int64_t)1536*1024L, 0, HN_AUTOSCALE }, + { 3, "2 G", (int64_t)1536*1024*1024L, 0, HN_AUTOSCALE }, + { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + + /* tests 28-37 test rounding */ + { 3, "0 M", (int64_t)500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "1 M", (int64_t)1000*1000L + 500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "2 M", (int64_t)1000*1000L + 500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 3, "0 K", (int64_t)512L-1, 0, HN_AUTOSCALE }, + { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE }, + { 3, "0 M", (int64_t)512*1024L-1, 0, HN_AUTOSCALE }, + { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE }, + { 3, "1 M", (int64_t)1024*1024L + 512*1024L-1, 0, HN_AUTOSCALE }, + { 3, "2 M", (int64_t)1024*1024L + 512*1024L, 0, HN_AUTOSCALE }, + + /* tests 38-61 test specific scale factors with 1000 divisor */ + { 3, "0 k", (int64_t)0L, HN_DIVISOR_1000, 1 }, + { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, 1 }, + { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, 2 }, + { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, 2 }, + { 3, "0 G", (int64_t)500*1000L, HN_DIVISOR_1000, 3 }, + { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 3 }, + { 3, "0 T", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 4 }, + { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 4 }, + { 3, "0 P", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 5 }, + { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 }, + { 3, "0 E", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, + { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, + { 3, "0 k", (int64_t)1L, HN_DIVISOR_1000, 1 }, + { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, 1 }, + { 3, "0 M", (int64_t)1500L, HN_DIVISOR_1000, 2 }, + { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, 2 }, + { 3, "0 G", (int64_t)1500*1000L, HN_DIVISOR_1000, 3 }, + { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 3 }, + { 3, "0 T", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 4 }, + { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 4 }, + { 3, "0 P", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 5 }, + { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 }, + { 3, "0 E", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, + { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, + + /* tests 62-85 test specific scale factors with 1024 divisor */ + { 3, "0 K", (int64_t)0L, 0, 1 }, + { 3, "1 K", (int64_t)512L, 0, 1 }, + { 3, "0 M", (int64_t)512L, 0, 2 }, + { 3, "1 M", (int64_t)512*1024L, 0, 2 }, + { 3, "0 G", (int64_t)512*1024L, 0, 3 }, + { 3, "1 G", (int64_t)512*1024*1024L, 0, 3 }, + { 3, "0 T", (int64_t)512*1024*1024L, 0, 4 }, + { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, 4 }, + { 3, "0 P", (int64_t)512*1024*1024*1024L, 0, 5 }, + { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, 5 }, + { 3, "0 E", (int64_t)512*1024*1024*1024*1024L, 0, 6 }, + { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, 6 }, + { 3, "0 K", (int64_t)1L, 0, 1 }, + { 3, "2 K", (int64_t)1536L, 0, 1 }, + { 3, "0 M", (int64_t)1536L, 0, 2 }, + { 3, "2 M", (int64_t)1536*1024L, 0, 2 }, + { 3, "0 G", (int64_t)1536*1024L, 0, 3 }, + { 3, "2 G", (int64_t)1536*1024*1024L, 0, 3 }, + { 3, "0 T", (int64_t)1536*1024*1024L, 0, 4 }, + { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, 4 }, + { 3, "0 P", (int64_t)1536*1024*1024*1024L, 0, 5 }, + { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, 5 }, + { 3, "0 E", (int64_t)1536*1024*1024*1024*1024L, 0, 6 }, + { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, 6 }, + + /* tests 86-99 test invalid specific scale values of < 0 or >= 7 with + and without HN_DIVISOR_1000 set */ + /* all should return errors with new code; with old, the latter 3 + are instead processed as if having AUTOSCALE and/or GETSCALE set */ + { -1, "", (int64_t)1L, 0, 7 }, + { -1, "", (int64_t)1L, HN_DIVISOR_1000, 7 }, + { -1, "", (int64_t)1L, 0, 1000 }, + { -1, "", (int64_t)1L, HN_DIVISOR_1000, 1000 }, + { -1, "", (int64_t)0L, 0, 1000*1000 }, + { -1, "", (int64_t)0L, HN_DIVISOR_1000, 1000*1000 }, + { -1, "", (int64_t)0L, 0, INT_MAX }, + { -1, "", (int64_t)0L, HN_DIVISOR_1000, INT_MAX }, + + /* Negative scale values are not handled well + by the existing library routine - should report as error */ + /* all should return errors with new code, fail assertion with old */ + + { -1, "", (int64_t)1L, 0, -1 }, + { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1 }, + { -1, "", (int64_t)1L, 0, -1000 }, + { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1000 }, + + /* __INT_MIN doesn't print properly, skipped. */ + + { -1, "", (int64_t)1L, 0, -__INT_MAX }, + { -1, "", (int64_t)1L, HN_DIVISOR_1000, -__INT_MAX }, + + + /* tests for scale == 0, without autoscale */ + /* tests 100-114 test scale 0 with 1000 divisor - print first N digits */ + { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, 0 }, + { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, 0 }, + { 3, "10 ", (int64_t)10L, HN_DIVISOR_1000, 0 }, + { 3, "0 M", (int64_t)150L, HN_DIVISOR_1000, HN_NOSPACE }, + { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, HN_NOSPACE }, + { 3, "0 M", (int64_t)999L, HN_DIVISOR_1000, HN_NOSPACE }, + { 4, "150", (int64_t)150L, HN_DIVISOR_1000, 0 }, + { 4, "500", (int64_t)500L, HN_DIVISOR_1000, 0 }, + { 4, "999", (int64_t)999L, HN_DIVISOR_1000, 0 }, + { 5, "100", (int64_t)1000L, HN_DIVISOR_1000, 0 }, + { 5, "150", (int64_t)1500L, HN_DIVISOR_1000, 0 }, + { 7, "500", (int64_t)500*1000L, HN_DIVISOR_1000, 0 }, + { 8, "150", (int64_t)1500*1000L, HN_DIVISOR_1000, 0 }, + { 10, "500", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 0 }, + { 11, "150", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 0 }, + + /* tests 115-126 test scale 0 with 1024 divisor - print first N digits */ + { 2, "0 ", (int64_t)0L, 0, 0 }, + { 2, "1 ", (int64_t)1L, 0, 0 }, + { 3, "10 ", (int64_t)10L, 0, 0 }, + { 4, "150", (int64_t)150L, 0, 0 }, + { 4, "500", (int64_t)500L, 0, 0 }, + { 4, "999", (int64_t)999L, 0, 0 }, + { 5, "100", (int64_t)1000L, 0, 0 }, + { 5, "150", (int64_t)1500L, 0, 0 }, + { 7, "500", (int64_t)500*1000L, 0, 0 }, + { 8, "150", (int64_t)1500*1000L, 0, 0 }, + { 10, "500", (int64_t)500*1000*1000L, 0, 0 }, + { 11, "150", (int64_t)1500*1000*1000L, 0, 0 }, + + /* Test boundary cases for very large positive/negative number formatting */ + /* Explicit scale, divisor 1024 */ + + /* XXX = requires length 5 (buflen 6) for some cases*/ + /* KLUDGE - test loop below will bump length 5 up to 5 */ + { 3, "8 E", INT64_MAX, 0, 6 }, + { 4, "-8 E", -INT64_MAX, 0, 6 }, + { 3, "0 E", (int64_t)92*1024*1024*1024*1024*1024L, 0, 6 }, + { 3, "0 E", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 6 }, + { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, 0, 6 }, + { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 6 }, + { 3, "0 E", (int64_t)81*1024*1024*1024*1024*1024L, 0, 6 }, + { 3, "0 E", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 6 }, + { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, 5 }, + { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 5 }, + { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, 5 }, + { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 5 }, + { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, 5 }, + { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 5 }, + + /* Explicit scale, divisor 1000 */ + { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, 6 }, + { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, 6 }, + { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, + { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, + { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, + { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, + { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, + { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, + { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, + { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, + + /* Autoscale, divisor 1024 */ + { 3, "8 E", INT64_MAX, 0, HN_AUTOSCALE }, + { 4, "-8 E", -INT64_MAX, 0, HN_AUTOSCALE }, + { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, + /* Autoscale, divisor 1000 */ + { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, + + /* 0 scale, divisor 1024 */ + { 12, "skdj", INT64_MAX, 0, 0 }, + { 21, "-9223", -INT64_MAX, 0, 0 }, + { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, 0, 0 }, + { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 0 }, + { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, 0, 0 }, + { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 0 }, + { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, 0, 0 }, + { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 0 }, + + /* 0 scale, divisor 1000 */ + /* XXX - why does this fail? */ + { -1, "", INT64_MAX, HN_DIVISOR_1000, 0 }, + { 21, "-9223", -INT64_MAX, HN_DIVISOR_1000, 0 }, + { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, + { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, + { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, + { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, + /* Expected to pass */ + { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, + { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, + + + + /* Need to implement tests for GETSCALE */ +/* { ?, "", (int64_t)0L, HN_DIVISOR_1000, HN_GETSCALE }, + ... +*/ + /* Tests for HN_DECIMAL */ + /* Positive, Autoscale */ + { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "994 k", (int64_t)994*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "995 k", (int64_t)995*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "1.0 M", (int64_t)1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "994 M", (int64_t)994*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "995 M", (int64_t)995*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + + { 5, "500 K", (int64_t)500*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "994 K", (int64_t)994*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "995 K", (int64_t)995*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "999 K", (int64_t)999*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "1.0 M", (int64_t)1000*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "1.0 M", (int64_t)1018*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "1.0 M", (int64_t)1019*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "1.5 M", (int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "1.9 M", (int64_t)1996*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "2.0 M", (int64_t)1997*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "2.0 M", (int64_t)2047*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "2.0 M", (int64_t)2048*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "2.0 M", (int64_t)2099*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "2.1 M", (int64_t)2100*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "9.9 M", (int64_t)10188*1024L, HN_DECIMAL, HN_AUTOSCALE }, + /* XXX - shouldn't the following two be "10. M"? */ + { 4, "10 M", (int64_t)10189*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 4, "10 M", (int64_t)10240*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "500 M", (int64_t)500*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "994 M", (int64_t)994*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "995 M", (int64_t)995*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "999 M", (int64_t)999*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "1.0 G", (int64_t)1000*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "1.0 G", (int64_t)1023*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, + + /* Negative, Autoscale - should pass */ + { 6, "-1.5 ", -(int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 6, "-1.9 ", -(int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 6, "-9.9 ", -(int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + + { 6, "-1.5 ", -(int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 6, "-1.9 ", -(int64_t)1949*1024L, HN_DECIMAL, HN_AUTOSCALE }, + { 6, "-9.7 ", -(int64_t)9949*1024L, HN_DECIMAL, HN_AUTOSCALE }, + + /* Positive/negative, at maximum scale */ + { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, + { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + /* Negatives work with latest rev only: */ + { 6, "-9.2 ", -INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + { 6, "-8.9 ", -(int64_t)8949*1000*1000*1000*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, + + { 5, "8.0 E", INT64_MAX, HN_DECIMAL, HN_AUTOSCALE }, + { 5, "7.9 E", INT64_MAX-(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE }, + { 6, "-8.0 ", -INT64_MAX, HN_DECIMAL, HN_AUTOSCALE }, + { 6, "-7.9 ", -INT64_MAX+(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE }, + + /* Positive, Fixed scales */ + { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, + { 5, "0.5 M", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "949 k", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, + { 5, "0.9 M", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "950 k", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, + { 5, "1.0 M", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, + { 5, "1.0 M", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "0.5 G", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 }, + { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, + { 5, "1.0 G", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 }, + /* Positive/negative, at maximum scale */ + { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 }, + { 5, "1.0 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, + { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, + { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, + { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, 6 }, + + /* HN_DECIMAL + binary + fixed scale cases not completed */ + { 5, "512 K", (int64_t)512*1024L, HN_DECIMAL, 1 }, + { 5, "0.5 M", (int64_t)512*1024L, HN_DECIMAL, 2 }, + + /* Negative, Fixed scales */ + /* Not yet added, but should work with latest rev */ + +}; + + +/* Command line options usage */ +static void +usage(char * progname) { + printf("%s: tests libutil humanize_number function\n", progname); + printf("Usage: %s [-nE] [-l num] [-v]\n\n", progname); + printf("Options:\n"); + printf("\t-l num\tSet max length for result; buflen = num + 1\n"); + printf("\t\t (NOTE: does not change expected result strings.)\n"); + printf("\t-n\tInclude negative scale tests, which cause older libutil\n"); + printf("\t\t version of function to coredump with assertion failure\n"); + printf("\t-E\tInclude numbers > 1/2 Exa[byte] which currently fail\n"); + printf("\t-v\tVerbose - always print summary results\n"); + printf("\t-h, -?\tShow options\n"); +} + +/* Parse command line options */ +static void +read_options(int argc, char * const argv[], size_t *bufLength, + int *includeNegativeScale, int *includeExabytes, int *verbose) { + int ch; + size_t temp; + + while ((ch = getopt(argc, argv, "nEh?vl:")) != -1) { + switch (ch) { + default: + usage(argv[0]); + exit(1); + break; /* UNREACHABLE */ + case 'h' : + case '?' : + usage(argv[0]); + exit(0); + break; /* UNREACHABLE */ + case 'l' : + sscanf(optarg, "%zu", &temp); + *bufLength = temp + 1; + break; + case 'n' : + *includeNegativeScale = 1; + break; + case 'E' : + *includeExabytes = 1; + break; + case 'v' : + *verbose = 1; + break; + } + } +} + +static struct { + int value; + const char *name; + } flags[] = { + { HN_AUTOSCALE, "HN_AUTOSCALE" }, + { HN_GETSCALE, "HN_GETSCALE" }, + { HN_DIVISOR_1000, "HN_DIVISOR_1000"}, + { HN_B, "HN_B"}, + { HN_DECIMAL, "HN_DECIMAL"}, +}; + +static const char *separator = "|"; + +/* Format flags parameter for meaningful display */ +static char * +str_flags(int hn_flags, char *noFlags) { + size_t i; + char * result; + + result = malloc(MAX_STR_FLAGS_RESULT); + result[0] = '\0'; + + for (i = 0; i < sizeof flags / sizeof *flags; i++) { + if (hn_flags & flags[i].value) { + if (*result != 0) + strlcat(result, separator, + MAX_STR_FLAGS_RESULT); + strlcat(result, flags[i].name, MAX_STR_FLAGS_RESULT); + } + } + + if (strlen(result) == 0) + strlcat(result, noFlags, MAX_STR_FLAGS_RESULT); + return result; +} + + +/* Format scale parameter for meaningful display */ +static char * +str_scale(int scale) { + char *result; + + if (scale == HN_AUTOSCALE || scale == HN_GETSCALE) + return str_flags(scale, ""); + + result = malloc(MAX_INT_STR_DIGITS); + result[0] = '\0'; + snprintf(result, MAX_INT_STR_DIGITS, "%d", scale); + return result; +} + +static void +testskipped(size_t i) +{ + + printf("ok %zu # skip - not turned on\n", i); +#ifdef __APPLE__ + printf("[PASS] test %zu\n", i); +#endif /* __APPLE__ */ +} + +int +main(int argc, char * const argv[]) +{ + char *buf; + char *flag_str, *scale_str; + size_t buflen, errcnt, i, skipped, tested; + int r; + int includeNegScale; + int includeExabyteTests; + int verbose; + + buflen = 4; + includeNegScale = 0; + includeExabyteTests = 0; + verbose = 0; + + read_options(argc, argv, &buflen, &includeNegScale, + &includeExabyteTests, &verbose); + + buf = malloc(buflen); + errcnt = 0; + tested = 0; + skipped = 0; + + if (buflen != 4) + printf("Warning: buffer size %zu != 4, expect some results to differ.\n", buflen); + + printf("1..%zu\n", nitems(test_args)); +#ifdef __APPLE__ + printf("[TEST] humanize_number_test\n"); +#endif /* __APPLE__ */ + for (i = 0; i < nitems(test_args); i++) { +#ifdef __APPLE__ + printf("[BEGIN] test %zu\n", i + 1); +#endif /* __APPLE__ */ + /* KLUDGE */ + if (test_args[i].num == INT64_MAX && buflen == 4) { + /* Start final tests which require buffer of 6 */ + free(buf); + buflen = 6; + buf = malloc(buflen); + if (verbose) + printf("Buffer length increased to %zu\n", + buflen); + } + + if (test_args[i].scale < 0 && ! includeNegScale) { + skipped++; + testskipped(i + 1); + continue; + } + if (test_args[i].num >= halfExabyte && ! includeExabyteTests) { + skipped++; + testskipped(i + 1); + continue; + } + + r = humanize_number(buf, buflen, test_args[i].num, "", + test_args[i].scale, test_args[i].flags); + flag_str = str_flags(test_args[i].flags, "[no flags]"); + scale_str = str_scale(test_args[i].scale); + + if (r != test_args[i].retval) { + if (verbose) + printf("wrong return value on index %zu, " + "buflen: %zu, got: %d + \"%s\", " + "expected %d + \"%s\"; num = %jd, " + "scale = %s, flags= %s.\n", + i, buflen, r, buf, test_args[i].retval, + test_args[i].res, + (intmax_t)test_args[i].num, + scale_str, flag_str); + else + printf("not ok %zu # return %d != %d\n", + i + 1, r, test_args[i].retval); + errcnt++; +#ifdef __APPLE__ + printf("[FAIL] test %zu\n", i + 1); +#endif /* __APPLE__ */ + } else if (strcmp(buf, test_args[i].res) != 0) { + if (verbose) + printf("result mismatch on index %zu, got: " + "\"%s\", expected \"%s\"; num = %jd, " + "scale = %s, flags= %s.\n", + i, buf, test_args[i].res, + (intmax_t)test_args[i].num, + scale_str, flag_str); + else + printf("not ok %zu # buf \"%s\" != \"%s\"\n", + i + 1, buf, test_args[i].res); + errcnt++; +#ifdef __APPLE__ + printf("[FAIL] test %zu\n", i + 1); +#endif /* __APPLE__ */ + } else { + if (verbose) + printf("successful result on index %zu, " + "returned %d, got: \"%s\"; num = %jd, " + "scale = %s, flags= %s.\n", + i, r, buf, + (intmax_t)test_args[i].num, + scale_str, flag_str); + else + printf("ok %zu\n", i + 1); +#ifdef __APPLE__ + printf("[PASS] test %zu\n", i + 1); +#endif /* __APPLE__ */ + } + tested++; + } + + printf("[SUMMARY]\n"); + if (verbose) + printf("total errors: %zu/%zu tests, %zu skipped\n", errcnt, + tested, skipped); + + if (errcnt) + return 1; + + return 0; +} diff --git a/tests/libutil.plist b/tests/libutil.plist new file mode 100644 index 0000000..13610a6 --- /dev/null +++ b/tests/libutil.plist @@ -0,0 +1,28 @@ + + + + + Project + libutil + Tests + + + Command + + /AppleInternal/Tests/libutil/humanize_number_test + -v + -n + + TestName + humanize_number_test + WhenToRun + + PRESUBMISSION + NIGHTLY + + + + Timeout + 30 + + diff --git a/tzlinkd/com.apple.tzlinkd.sb b/tzlinkd/com.apple.tzlinkd.sb index 313636a..101e990 100644 --- a/tzlinkd/com.apple.tzlinkd.sb +++ b/tzlinkd/com.apple.tzlinkd.sb @@ -7,5 +7,8 @@ (allow file-write-create file-write-unlink (literal "/private/var/db/timezone/localtime")) +(allow file-write-create file-write-unlink + (literal "/private/etc/localtime")) + (allow file-read* (literal "/private/var/db/timezone/zoneinfo")) diff --git a/tzlinkd/tzlinkd.c b/tzlinkd/tzlinkd.c index 3c14c03..10ca904 100644 --- a/tzlinkd/tzlinkd.c +++ b/tzlinkd/tzlinkd.c @@ -34,9 +34,89 @@ static int set_timezone(const char *); static int build_source_path(char *, size_t, const char *); static int validate_source_path(const char *); +#if TARGET_OS_OSX +#include +#include +#include +#include +#include +#include +#include +#include + +static void +enter_sandbox(void) +{ + char buf[PATH_MAX] = ""; + + char *home_env = getenv("HOME"); + if (home_env == NULL) { + os_log_debug(OS_LOG_DEFAULT, "$HOME not set, falling back to using getpwuid"); + struct passwd *pwd = getpwuid(getuid()); + if (pwd == NULL) { + os_log_error(OS_LOG_DEFAULT, "failed to get passwd entry for uid %u", getuid()); + exit(EXIT_FAILURE); + } + home_env = pwd->pw_dir; + } + + char *home = realpath(home_env, NULL); + if (home == NULL) { + os_log_error(OS_LOG_DEFAULT, "failed to resolve user's home directory: %{darwin.errno}d", errno); + exit(EXIT_FAILURE); + } + + if (!_set_user_dir_suffix("tzlinkd") || + confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)) == 0) { + os_log_error(OS_LOG_DEFAULT, "failed to initialize temporary directory: %{darwin.errno}d", errno); + exit(EXIT_FAILURE); + } + + char *tempdir = realpath(buf, NULL); + if (tempdir == NULL) { + os_log_error(OS_LOG_DEFAULT, "failed to resolve temporary directory: %{darwin.errno}d", errno); + exit(EXIT_FAILURE); + } + + if (confstr(_CS_DARWIN_USER_CACHE_DIR, buf, sizeof(buf)) == 0) { + os_log_error(OS_LOG_DEFAULT, "failed to initialize cache directory: %{darwin.errno}d", errno); + exit(EXIT_FAILURE); + } + + char *cachedir = realpath(buf, NULL); + if (cachedir == NULL) { + os_log_error(OS_LOG_DEFAULT, "failed to resolve cache directory: %{darwin.errno}d", errno); + exit(EXIT_FAILURE); + } + + const char *parameters[] = { + "HOME", home, + "TMPDIR", tempdir, + "DARWIN_CACHE_DIR", cachedir, + NULL + }; + + char *sberror = NULL; + // Note: The name of the sandbox profile here does not include the '.sb' extension. + if (sandbox_init_with_parameters("com.apple.tzlinkd", SANDBOX_NAMED, parameters, &sberror) != 0) { + os_log_error(OS_LOG_DEFAULT, "Failed to enter sandbox: %{public}s", sberror); + exit(EXIT_FAILURE); + } + + free(home); + free(tempdir); + free(cachedir); + free(sberror); +} +#endif /* TARGET_OS_OSX */ + int main(void) { +#if TARGET_OS_OSX + enter_sandbox(); +#endif /* TARGET_OS_OSX */ + dispatch_queue_t queue; xpc_connection_t listener;