logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git

humanize.c (2025B)


  1. // Collection of Unix tools, comparable to coreutils
  2. // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
  4. #define _DEFAULT_SOURCE
  5. // strtonum
  6. #define _OPENBSD_SOURCE
  7. // On non-BSDs use libbsd
  8. #include <err.h> // errx
  9. #include <errno.h> // EINVAL, ERANGE
  10. #include <limits.h> // LLONG_MIN, LLONG_MAX
  11. #include <stdbool.h> // bool
  12. #include <stdio.h> // fprintf
  13. #include <stdlib.h> // strtonum
  14. #include <string.h> // strerror
  15. #include <unistd.h> // opt*, getopt
  16. void
  17. dtosi(double num, char *buf, size_t bufsize, bool iec)
  18. {
  19. char *si_prefixes[9] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y"};
  20. char *iec_prefixes[9] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"};
  21. int div = iec ? 1024 : 1000;
  22. char **prefixes = iec ? iec_prefixes : si_prefixes;
  23. unsigned quotient = 0;
  24. while(num > div && quotient < 9)
  25. {
  26. num /= div;
  27. quotient += 1;
  28. }
  29. snprintf(buf, bufsize, "%g %s", num, prefixes[quotient]);
  30. }
  31. static void
  32. usage()
  33. {
  34. fprintf(stderr, "Usage: humanize [-bd] number\n");
  35. }
  36. int
  37. main(int argc, char *argv[])
  38. {
  39. // default to -d
  40. bool iec = false;
  41. int c = -1;
  42. while((c = getopt(argc, argv, ":bd")) != -1)
  43. {
  44. switch(c)
  45. {
  46. case 'b':
  47. iec = true;
  48. break;
  49. case 'd':
  50. iec = false;
  51. break;
  52. case ':':
  53. fprintf(stderr, "Error: Missing operand for option: '-%c'\n", optopt);
  54. usage();
  55. return 1;
  56. case '?':
  57. fprintf(stderr, "Error: Unrecognised option: '-%c'\n", optopt);
  58. usage();
  59. return 1;
  60. }
  61. }
  62. argc -= optind;
  63. argv += optind;
  64. if(argc < 1)
  65. {
  66. usage();
  67. return 1;
  68. }
  69. for(int argi = 0; argi < argc; argi++)
  70. {
  71. const char *errstr = NULL;
  72. char buf[32] = "";
  73. // 1024^(6+1) goes higher than long long; don't ask for the moon
  74. long long n = strtonum(argv[argi], LLONG_MIN, LLONG_MAX, &errstr);
  75. if(errstr)
  76. {
  77. errx(1, "strtonum: %s is %s", argv[argi], errstr);
  78. }
  79. dtosi(n, buf, 32, iec);
  80. printf("%s\n", buf);
  81. }
  82. return 0;
  83. }