logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/

strtodur.c (2047B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include "strtodur.h"
  6. #include <assert.h>
  7. #include <errno.h> // errno
  8. #include <stdio.h> // fprintf, perror, sscanf
  9. #include <string.h> // strerror
  10. const char *errstr_nan = "Not a number";
  11. int
  12. strtodur(char *s, struct timespec *dur)
  13. {
  14. if(s == 0 || s[0] == '\0') return 0;
  15. assert(dur);
  16. float in = 0.0;
  17. if(s[0] != '.' && s[0] != ',')
  18. {
  19. int parsed = 0;
  20. errno = 0;
  21. if(sscanf(s, "%10f%n", &in, &parsed) < 1)
  22. {
  23. const char *errstr = errstr_nan;
  24. if((errno = !0))
  25. {
  26. errstr = strerror(errno);
  27. errno = 0;
  28. }
  29. fprintf(
  30. stderr, "%s: error: strtodur failed scanning '%s' as a number: %s\n", argv0, s, errstr);
  31. return -1;
  32. }
  33. s += parsed;
  34. }
  35. if((s[0] == '.' || s[0] == ',') && s[1] != '\0')
  36. {
  37. float fraction = 0.0;
  38. if(s[0] == ',') s[0] = '.';
  39. int parsed = 0;
  40. errno = 0;
  41. if(sscanf(s, "%10f%n", &fraction, &parsed) < 1)
  42. {
  43. const char *errstr = errstr_nan;
  44. if((errno = !0))
  45. {
  46. errstr = strerror(errno);
  47. errno = 0;
  48. }
  49. fprintf(stderr,
  50. "%s: error: strtodur failed scanning decimal part '%s' as a number: %s\n",
  51. argv0,
  52. s,
  53. errstr);
  54. return -1;
  55. }
  56. in += fraction;
  57. s += parsed;
  58. }
  59. if(s[0] != '\0' && s[0] != ',' && s[0] != '.')
  60. {
  61. if(s[1] != '\0')
  62. {
  63. fprintf(stderr,
  64. "%s: error: duration suffix '%s' is too long, should be only one character\n",
  65. argv0,
  66. s);
  67. return -1;
  68. }
  69. switch(s[0])
  70. {
  71. case 's': // seconds
  72. break;
  73. case 'm': // minutes
  74. in *= 60;
  75. break;
  76. case 'h': // hours
  77. in *= 60 * 60;
  78. break;
  79. case 'd': // days
  80. in *= 24 * 60 * 60;
  81. break;
  82. default:
  83. fprintf(stderr, "%s: error: Unknown duration suffix '%c'\n", argv0, s[0]);
  84. return -1;
  85. }
  86. }
  87. dur->tv_sec = in;
  88. dur->tv_nsec = (in - dur->tv_sec) * 1000000000;
  89. return 0;
  90. }