logo

utils-extra

Collection of extra tools for Unixes git clone https://anongit.hacktivis.me/git/utils-extra.git/

humanize.c (2635B)


  1. // utils-extra: Collection of extra tools for Unixes
  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 <errno.h> // EINVAL, ERANGE
  6. #include <limits.h> // LLONG_MIN, LLONG_MAX
  7. #include <stdbool.h> // bool
  8. #include <stdio.h> // fprintf, perror, sscanf
  9. #include <unistd.h> // opt*, getopt
  10. static void
  11. human_num(long double num, bool iec)
  12. {
  13. #define PFX 11
  14. char *si_prefixes[PFX] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q"};
  15. char *iec_prefixes[PFX] = {
  16. "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB"};
  17. unsigned div = iec ? 1024 : 1000;
  18. char **prefixes = iec ? iec_prefixes : si_prefixes;
  19. unsigned quotient = 0;
  20. while(num > div && quotient < PFX)
  21. {
  22. num /= div;
  23. quotient += 1;
  24. }
  25. printf("%Lg %s\n", num, prefixes[quotient]);
  26. }
  27. static void
  28. human_time(long int epoch)
  29. {
  30. int year = 0, month = 0, mday = 0, hour = 0, min = 0, sec = 0;
  31. year = epoch / 31556926; // round(year)
  32. epoch %= 31556926;
  33. month = epoch / 2629743; // year/12
  34. epoch %= 2629743;
  35. mday = epoch / 86400;
  36. epoch %= 86400;
  37. hour = epoch / 3600;
  38. epoch %= 3600;
  39. min = epoch / 60;
  40. epoch %= 60;
  41. sec = epoch;
  42. if(year > 0) printf("%dY ", year);
  43. if(month > 0) printf("%dM ", month);
  44. if(mday > 0) printf("%dD ", mday);
  45. if(hour > 0) printf("%dh ", hour);
  46. if(min > 0) printf("%dm ", min);
  47. if(sec > 0) printf("%ds", sec);
  48. printf("\n");
  49. }
  50. static void
  51. usage()
  52. {
  53. fprintf(stderr, "Usage: humanize [-bdt] number\n");
  54. }
  55. int
  56. main(int argc, char *argv[])
  57. {
  58. // default to -d
  59. bool iec = false, time = false;
  60. int c = -1;
  61. while((c = getopt(argc, argv, ":bdt")) != -1)
  62. {
  63. switch(c)
  64. {
  65. case 'b':
  66. iec = true;
  67. break;
  68. case 'd':
  69. iec = false;
  70. break;
  71. case 't':
  72. time = true;
  73. break;
  74. case ':':
  75. fprintf(stderr, "humanize: Error: Missing operand for option: '-%c'\n", optopt);
  76. usage();
  77. return 1;
  78. case '?':
  79. fprintf(stderr, "humanize: Error: Unrecognised option: '-%c'\n", optopt);
  80. usage();
  81. return 1;
  82. }
  83. }
  84. argc -= optind;
  85. argv += optind;
  86. if(argc < 1)
  87. {
  88. usage();
  89. return 1;
  90. }
  91. for(int argi = 0; argi < argc; argi++)
  92. {
  93. // Keep sscanf here for easier error handling, rest being pure math
  94. if(time)
  95. {
  96. long int epoch = 0;
  97. if(sscanf(argv[argi], "%ld", &epoch) < 1)
  98. {
  99. perror("humanize: sscanf");
  100. return 1;
  101. }
  102. human_time(epoch);
  103. }
  104. else
  105. {
  106. long double num = 0;
  107. if(sscanf(argv[argi], "%Lg", &num) < 1)
  108. {
  109. perror("humanize: sscanf");
  110. return 1;
  111. }
  112. human_num(num, iec);
  113. }
  114. }
  115. return 0;
  116. }