Bool StrUtil_CapacityToBytes(uint64 *out, // OUT: The output value const char *str, // IN: String to parse unsigned int bytes) // IN: Bytes per unit in an // unadorned string { double quantity; char *rest; ASSERT(out); ASSERT(str); errno = 0; quantity = strtod(str, &rest); if (errno == ERANGE) { return FALSE; } /* Skip over any whitespace in the suffix. */ while (*rest == ' ' || *rest == '\t') { rest++; } if (*rest != '\0') { uint64 shift; Bool suffixOK = TRUE; /* * [kK], [mM], [gG], and [tT] represent kilo, mega, giga, and tera * byte quantities respectively. [bB] represents a singular byte * quantity. [sS] represents a sector quantity. * * For kilo, mega, giga, and tera we're OK with an additional byte * suffix. Otherwise, the presence of an additional suffix is an error. */ switch (*rest) { case 'b': case 'B': shift = 0; suffixOK = FALSE; break; case 's': case 'S': shift = 9; suffixOK = FALSE; break; case 'k': case 'K': shift = 10; break; case 'm': case 'M': shift = 20; break; case 'g': case 'G': shift = 30; break; case 't': case 'T': shift = 40; break; default : return FALSE; } switch(*++rest) { case '\0': break; case 'b': case 'B': if (suffixOK && !*++rest) { break; } /* FALLTHRU */ default: return FALSE; } quantity *= CONST64U(1) << shift; } else { /* * No suffix, so multiply by the number of bytes per unit as specified * by the caller. */ quantity *= bytes; } *out = quantity; return TRUE; }
char * StrUtil_FormatSizeInBytesUnlocalized(uint64 size) // IN { /* * XXX TODO, BUG 199661: * This is a direct copy of Msg_FormatSizeInBytes without localization. * These two functions should ideally share the basic functionality, and * just differ in the string localization */ char const *fmt; double sizeInSelectedUnit; unsigned int precision; char *sizeFormat; char *sizeString; char *result; static const double epsilon = 0.01; double delta; if (size >= CONST64U(1) << 40 /* 1 TB */) { fmt = "%s TB"; sizeInSelectedUnit = (double)size / (CONST64U(1) << 40); precision = 1; } else if (size >= CONST64U(1) << 30 /* 1 GB */) { fmt = "%s GB"; sizeInSelectedUnit = (double)size / (CONST64U(1) << 30); precision = 1; } else if (size >= CONST64U(1) << 20 /* 1 MB */) { fmt = "%s MB"; sizeInSelectedUnit = (double)size / (CONST64U(1) << 20); precision = 1; } else if (size >= CONST64U(1) << 10 /* 1 KB */) { fmt = "%s KB"; sizeInSelectedUnit = (double)size / (CONST64U(1) << 10); precision = 1; } else if (size >= CONST64U(2) /* 2 bytes */) { fmt = "%s bytes"; sizeInSelectedUnit = (double)size; precision = 0; // No fractional byte. } else if (size >= CONST64U(1) /* 1 byte */) { fmt = "%s byte"; sizeInSelectedUnit = (double)size; precision = 0; // No fractional byte. } else { ASSERT(size == CONST64U(0) /* 0 bytes */); fmt = "%s bytes"; sizeInSelectedUnit = (double)size; precision = 0; // No fractional byte. } /* * We cast to uint32 instead of uint64 here because of a problem with the * NetWare Tools build. However, it's safe to cast to uint32 since we have * already reduced the range of sizeInSelectedUnit above. */ // If it would display with .0, round it off and display the integer value. delta = (uint32)(sizeInSelectedUnit + 0.5) - sizeInSelectedUnit; if (delta < 0) { delta = -delta; } if (delta <= epsilon) { precision = 0; sizeInSelectedUnit = (double)(uint32)(sizeInSelectedUnit + 0.5); } sizeFormat = Str_Asprintf(NULL, "%%.%uf", precision); sizeString = Str_Asprintf(NULL, sizeFormat, sizeInSelectedUnit); result = Str_Asprintf(NULL, fmt, sizeString); free(sizeFormat); free(sizeString); return result; }
void Str_UnitTests(void) { char buf[1024]; wchar_t bufw[1024]; int count; int32 num1 = 0xDEADBEEF; int32 num2 = 0x927F82CD; int64 num3 = CONST64U(0xCAFEBABE42439021); #ifdef _WIN32 double num4 = 5.1923843; double num5 = 0.000482734; double num6 = 8274102.3872; #endif int numChars; char empty[1] = {'\0'}; wchar_t wempty[1] = {L'\0'}; /* test empty string */ count = Str_Snprintf(buf, 1, empty); if (0 != count) { FAIL("Failed empty string test"); } count = Str_Snwprintf(bufw, 1, wempty); if (0 != count) { FAIL("Failed empty string test (W)"); } /* test borderline overflow */ count = Str_Snprintf(buf, 2, "ba"); if (-1 != count) { FAIL("Failed borderline overflow test - count"); } if (buf[1]) { FAIL("Failed borderline overflow test - NULL term"); } count = Str_Snwprintf(bufw, 2, L"ba"); if (-1 != count) { FAIL("Failed borderline overflow test - count (W)"); } if (bufw[1]) { FAIL("Failed borderline overflow test - NULL term (W)"); } /* test egregious overflow */ count = Str_Snprintf(buf, 2, "baabaa"); if (-1 != count) { FAIL("Failed egregious overflow test - count"); } if (buf[1]) { FAIL("Failed egregious overflow test - NULL term"); } count = Str_Snwprintf(bufw, 2, L"baabaa"); if (-1 != count) { FAIL("Failed egregious overflow test - count (W)"); } if (bufw[1]) { FAIL("Failed egregious overflow test - NULL term (W)"); } /* test 'n' argument */ count = Str_Snprintf(buf, 1024, "foo %n\n", &numChars); if (-1 == count) { FAIL("Failed 'n' arg test - count"); } if (4 != numChars) { FAIL("Failed 'n' arg test - numChars"); } count = Str_Snwprintf(bufw, 1024, L"foo %n\n", &numChars); if (-1 == count) { FAIL("Failed 'n' arg test - count (W)"); } if (4 != numChars) { FAIL("Failed 'n' arg test - numChars (W)"); } bCompare = TRUE; // simple PrintAndCheck("hello\n"); PrintAndCheckW(L"hello\n"); // string arguments PrintAndCheck("whazz %s up %S doc\n", "hello", L"hello"); PrintAndCheckW(L"whazz %s up %S doc\n", L"hello", "hello"); // character arguments PrintAndCheck("whazz %c up %C doc\n", 'a', L'a'); PrintAndCheckW(L"whazz %c up %C doc\n", L'a', 'a'); // 32-bit integer arguments PrintAndCheck("%d %i %o %u %x %X\n", num1, num1, num1, num1, num1, num1); PrintAndCheckW(L"%d %i %o %u %x %X\n", num1, num1, num1, num1, num1, num1); // 'p' argument bCompare = FALSE; PrintAndCheck("%p\n", buf); PrintAndCheckW(L"%p\n", buf); bCompare = TRUE; // 64-bit bCompare = FALSE; PrintAndCheck("%LX %llX %qX\n", num3, num3, num3); PrintAndCheckW(L"%LX %llX %qX\n", num3, num3, num3); bCompare = TRUE; // more 64-bit #ifdef _WIN32 PrintAndCheck("%I64X\n", num3); PrintAndCheckW(L"%I64X\n", num3); #else PrintAndCheck("%LX\n", num3); PrintAndCheckW(L"%LX\n", num3); #endif #ifdef _WIN32 // exponent digits printed differs vs. POSIX // floating-point PrintAndCheck("%e %E %f %g %G\n", num4, num5, num6); PrintAndCheckW(L"%e %E %f %g %G\n", num4, num5, num6); #endif // positional arguments bCompare = FALSE; PrintAndCheck("%3$LX %1$x %2$x\n", num1, num2, num3); PrintAndCheckW(L"%3$LX %1$x %2$x\n", num1, num2, num3); bCompare = TRUE; #ifdef _WIN32 // exponent digits printed differs vs. POSIX // width and precision PrintAndCheck("%15.1g %20.2f %*.*f\n", num6, num6, 15, 3, num6); PrintAndCheckW(L"%15.1g %20.2f %*.*f\n", num6, num6, 15, 3, num6); #endif #ifdef _WIN32 // exponent digits printed differs vs. POSIX // flags PrintAndCheck("%-15e %+f %015g\n", num4, num5, num6); PrintAndCheckW(L"%-15e %+f %015g\n", num4, num5, num6); #endif #ifdef _WIN32 // exponent digits printed differs vs. POSIX // more flags PrintAndCheck("%#X %#E %#G\n", num1, num1, num1); PrintAndCheckW(L"%#X %#E %#G\n", num1, num1, num1); #endif }