logo

utils

Old programs, got split in utils-std and utils-extra git clone https://hacktivis.me/git/utils.git

humanize.c (2855B)


  1. // Collection of Unix tools, comparable to coreutils
  2. // SPDX-FileCopyrightText: 2017-2023 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include <err.h> // errx
  6. #include <errno.h> // EINVAL, ERANGE
  7. #include <limits.h> // LLONG_MIN, LLONG_MAX
  8. #include <stdbool.h> // bool
  9. #include <stdio.h> // fprintf, perror, sscanf
  10. #include <stdlib.h> // strtonum
  11. #include <unistd.h> // opt*, getopt
  12. void
  13. dtosi(double num, char *buf, size_t bufsize, bool iec)
  14. {
  15. #define PFX 11
  16. char *si_prefixes[PFX] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q"};
  17. char *iec_prefixes[PFX] = {
  18. "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB"};
  19. int div = iec ? 1024 : 1000;
  20. char **prefixes = iec ? iec_prefixes : si_prefixes;
  21. unsigned quotient = 0;
  22. while(num > div && quotient < PFX)
  23. {
  24. num /= div;
  25. quotient += 1;
  26. }
  27. snprintf(buf, bufsize, "%g %s", num, prefixes[quotient]);
  28. }
  29. static void
  30. usage()
  31. {
  32. fprintf(stderr, "Usage: humanize [-bdt] number\n");
  33. }
  34. int
  35. main(int argc, char *argv[])
  36. {
  37. // default to -d
  38. bool iec = false, time = false;
  39. int c = -1;
  40. while((c = getopt(argc, argv, ":bdt")) != -1)
  41. {
  42. switch(c)
  43. {
  44. case 'b':
  45. iec = true;
  46. break;
  47. case 'd':
  48. iec = false;
  49. break;
  50. case 't':
  51. time = true;
  52. break;
  53. case ':':
  54. fprintf(stderr, "humanize: Error: Missing operand for option: '-%c'\n", optopt);
  55. usage();
  56. return 1;
  57. case '?':
  58. fprintf(stderr, "humanize: Error: Unrecognised option: '-%c'\n", optopt);
  59. usage();
  60. return 1;
  61. }
  62. }
  63. argc -= optind;
  64. argv += optind;
  65. if(argc < 1)
  66. {
  67. usage();
  68. return 1;
  69. }
  70. for(int argi = 0; argi < argc; argi++)
  71. {
  72. const char *errstr = NULL;
  73. char buf[32] = "";
  74. if(time)
  75. {
  76. int year = 0, month = 0, mday = 0, hour = 0, min = 0, sec = 0;
  77. long int epoch = 0;
  78. if(sscanf(argv[argi], "%ld", &epoch) < 1)
  79. {
  80. perror("humanize: sscanf");
  81. return 1;
  82. }
  83. year = epoch / 31556926; // round(year)
  84. epoch %= 31556926;
  85. month = epoch / 2629743; // year/12
  86. epoch %= 2629743;
  87. mday = epoch / 86400;
  88. epoch %= 86400;
  89. hour = epoch / 3600;
  90. epoch %= 3600;
  91. min = epoch / 60;
  92. epoch %= 60;
  93. sec = epoch;
  94. if(year > 0) printf("%d年 ", year);
  95. if(month > 0) printf("%d月 ", month);
  96. if(mday > 0) printf("%d日 ", mday);
  97. if(hour > 0) printf("%dh ", hour);
  98. if(min > 0) printf("%dm ", min);
  99. if(sec > 0) printf("%ds", sec);
  100. printf("\n");
  101. continue;
  102. }
  103. errno = 0;
  104. long long n = strtoll(argv[argi], NULL, 10);
  105. if(n == LLONG_MIN)
  106. {
  107. errx(1, "%s is too small", argv[argi]);
  108. }
  109. if(n == LLONG_MAX)
  110. {
  111. errx(1, "%s is too large", argv[argi]);
  112. }
  113. if(errno != 0)
  114. {
  115. perror("humanize: strtoll");
  116. }
  117. dtosi(n, buf, 32, iec);
  118. printf("%s\n", buf);
  119. }
  120. return 0;
  121. }