From e2fd902f091f24bf016267dc4c185cbe8ecaf15d Mon Sep 17 00:00:00 2001 From: saundersp <pierre.saundersgb@gmail.com> Date: Thu, 7 Nov 2024 22:23:49 +0100 Subject: [PATCH] Added files --- .gitignore | 1 + Makefile | 35 +++++++ format_bytes/Makefile | 39 ++++++++ format_bytes/src/format_bytes.cpp | 66 ++++++++++++ format_bytes/src/format_bytes.hpp | 11 ++ format_bytes/src/toolbox.cpp | 85 ++++++++++++++++ format_bytes/src/toolbox.hpp | 126 +++++++++++++++++++++++ format_bytes/src/unit_test.cpp | 46 +++++++++ format_time/Makefile | 43 ++++++++ format_time/src/format_time.cpp | 67 +++++++++++++ format_time/src/format_time.hpp | 19 ++++ format_time/src/format_time_ns.cpp | 73 ++++++++++++++ format_time/src/toolbox.cpp | 85 ++++++++++++++++ format_time/src/toolbox.hpp | 126 +++++++++++++++++++++++ format_time/src/unit_test.cpp | 155 +++++++++++++++++++++++++++++ gcd/Makefile | 31 ++++++ gcd/src/gcd.cpp | 63 ++++++++++++ 17 files changed, 1071 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 format_bytes/Makefile create mode 100644 format_bytes/src/format_bytes.cpp create mode 100644 format_bytes/src/format_bytes.hpp create mode 100644 format_bytes/src/toolbox.cpp create mode 100644 format_bytes/src/toolbox.hpp create mode 100644 format_bytes/src/unit_test.cpp create mode 100644 format_time/Makefile create mode 100644 format_time/src/format_time.cpp create mode 100644 format_time/src/format_time.hpp create mode 100644 format_time/src/format_time_ns.cpp create mode 100644 format_time/src/toolbox.cpp create mode 100644 format_time/src/toolbox.hpp create mode 100644 format_time/src/unit_test.cpp create mode 100644 gcd/Makefile create mode 100644 gcd/src/gcd.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e56396a --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +.PHONY: all +all: gcd/bin/gcd format_bytes/bin/format_bytes format_time/bin/format_time format_time/bin/format_time_ns + +format_time/bin/format_time: + @cd format_time && exec make -s + +format_time/bin/format_time_ns: + @cd format_time && exec make -s + +format_bytes/bin/format_bytes: + @cd format_bytes && exec make -s + +gcd/bin/gcd: + @cd gcd && exec make -s + +.PHONY: install +install: gcd/bin/gcd format_bytes/bin/format_bytes format_time/bin/format_time format_time/bin/format_time_ns + @cp -v compress convertUTF8 extract $^ /usr/bin + @cd /usr/bin && chmod -v u+x compress convertUTF8 extract gcd format_bytes format_time format_time_ns + +.PHONY: uninstall +uninstall: + @cd /usr/bin && rm -v compress convertUTF8 extract gcd format_bytes format_time format_time_ns + +.PHONY: clean +clean: + @(cd gcd && exec make -s clean) + @(cd format_bytes && exec make -s clean) + @(cd format_time && exec make -s clean) + +.PHONY: mrproper +mrproper: clean + @(cd gcd && exec make -s mrproper) + @(cd format_bytes && exec make -s mrproper) + @(cd format_time && exec make -s mrproper) diff --git a/format_bytes/Makefile b/format_bytes/Makefile new file mode 100644 index 0000000..e231237 --- /dev/null +++ b/format_bytes/Makefile @@ -0,0 +1,39 @@ +CXX := g++ +CFLAGS := -std=c++11 -m64 -Wall -Werror -Wextra -O3 + +.PHONY: all +all: bin/format_bytes + +bin: + @mkdir -v bin + +bin/format_bytes: src/format_bytes.cpp src/toolbox.cpp | check-cxx-works bin + @echo Compiling $< + @${CXX} ${CFLAGS} $^ -o $@ + +bin/format_bytes_test: src/format_bytes.cpp src/toolbox.cpp src/unit_test.cpp | check-cxx-works bin + @echo Compiling $^ + @${CXX} ${CFLAGS} -DTEST $^ -o $@ + +.PHONY: install +install: bin/format_bytes + @cp -v $^ /usr/bin + +.PHONY: uninstall +uninstall: /usr/bin/format_bytes + @rm -v $^ + +.PHONY: test +test: bin/format_bytes_test + @./$^ + +.PHONY: clean +clean: + @rm -rfv bin + +.PHONY: mrproper +mrproper: clean + +.PHONY: check-cxx-works +check-cxx-works: + @${CXX} --version >/dev/null 2>&1 || (echo 'Please install a C++ compiler.' && exit 1) diff --git a/format_bytes/src/format_bytes.cpp b/format_bytes/src/format_bytes.cpp new file mode 100644 index 0000000..d928491 --- /dev/null +++ b/format_bytes/src/format_bytes.cpp @@ -0,0 +1,66 @@ +#include <string> +#include <array> +#include <stdint.h> +#include "toolbox.hpp" + +static constexpr const size_t STRING_BUFFER_SIZE = 64; +static constexpr const std::array<const char[3], 7> format_prefix = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; + +/** + * @brief Convert a given numbers of bytes to a human readable format + * + * @param n Number of bytes + * @return Human readable format of the numbers of bytes + */ +std::string format_bytes(uint64_t n) noexcept { + char s[STRING_BUFFER_SIZE] = { 0 }; + + if(n == 0){ + sprintf(s, "0%s", format_prefix[0]); + return s; + } + + size_t j = 0; + for(int8_t i = static_cast<int8_t>(format_prefix.size() - 1) * 10; i >= 0; i -= 10){ + const uint64_t nsi = n >> i; + if(nsi > 0){ + const int8_t idx = i / 10; + j += ullstr(nsi, j, s); + for(int k = 0; format_prefix[idx][k] > 0; ++k) + s[j++] = format_prefix[idx][k]; + s[j++] = ' '; + n &= u64(-1) >> (64 - i); + } + } + + /* Remove trailing character */ + s[j - 1] = '\0'; + + return std::string(s); +} + +#ifndef TEST +int32_t main(const int32_t argc, const char* const* argv) noexcept { + + uint64_t n = 0; + if (argc > 2) return fprintf(stderr, "Invalid usage : (%s $NUMBER) or (echo $NUMBER | %s)\n", argv[0], argv[0]); + else if (argc == 2){ + if(sstrtoull(argv[1], n) == EXIT_FAILURE) + return EXIT_FAILURE; + } else { + size_t i = 0; + char c, BUFFER[STRING_BUFFER_SIZE]; + for(; i < STRING_BUFFER_SIZE && (c = fgetc(stdin)) != EOF; ++i) + BUFFER[i] = c; + if(i == STRING_BUFFER_SIZE){ + fprintf(stderr, "Error while converting to integer : invalid stdin input (too large)\n"); + return EXIT_FAILURE; + } + if(sstrtoull(BUFFER, n) == EXIT_FAILURE) + return EXIT_FAILURE; + } + + printf("%s\n", format_bytes(n).c_str()); + return EXIT_SUCCESS; +} +#endif diff --git a/format_bytes/src/format_bytes.hpp b/format_bytes/src/format_bytes.hpp new file mode 100644 index 0000000..cd7fa10 --- /dev/null +++ b/format_bytes/src/format_bytes.hpp @@ -0,0 +1,11 @@ +#pragma once +#include <string> +#include <stdint.h> + +/** + * @brief Convert a given numbers of bytes to a human readable format + * + * @param n Number of bytes + * @return Human readable format of the numbers of bytes + */ +std::string format_bytes(uint64_t n) noexcept; diff --git a/format_bytes/src/toolbox.cpp b/format_bytes/src/toolbox.cpp new file mode 100644 index 0000000..4ccbdfc --- /dev/null +++ b/format_bytes/src/toolbox.cpp @@ -0,0 +1,85 @@ +#include <cstdlib> +#include <stdio.h> +#include <errno.h> +#include <cstring> +#include <limits.h> +#include <stdint.h> + +/** + * @brief Convert a given string to an unsigned 64 bit integer + * + * @param str Input string to convert + * @param n Integer output + * @return EXIT_SUCCESS if succesful otherwise EXIT_FAILURE + */ +int32_t sstrtoull(const char* str, uint64_t& n) noexcept { + errno = 0; + char* endptr = nullptr; + const uint64_t a = strtoull(str, &endptr, 10); + + switch(errno){ + case 0: + n = a; + return EXIT_SUCCESS; + case ERANGE: + fprintf(stderr, "Error while converting to integer : numerical result out of range ("); + if(a == 0) + fprintf(stderr, "underflow occurred"); + else if(a == ULLONG_MAX) + fprintf(stderr, "overflow occurred"); + else + fprintf(stderr, "unspecified"); + fprintf(stderr, ")\n"); + return EXIT_FAILURE; + default: + fprintf(stderr, "Unspecified error occurred while converting to integer: %s\n", strerror(errno)); + return EXIT_FAILURE; + } +} + +/** + * @brief Swap two given memory values + * + * @tparam T Type of memory placeholder + * @param a Firat memory pointer + * @param b Second memory pointer + */ +template<typename T> +inline void swap(T* const a, T* const b) noexcept { + const T temp = *a; + *a = *b; + *b = temp; + +} + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param offset of the string location to append + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, const size_t offset, char* const str) noexcept { + size_t i = 0; + + for (; num > 0; num /= 10) + str[offset + i++] = num % 10 + '0'; + + str[offset + i] = '\0'; + + for (size_t j = 0; j < i / 2; ++j) + swap(str + offset + j, str + offset + i - j - 1); + return i; +} + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, char* const str) noexcept { + return ullstr(num, 0, str); +} diff --git a/format_bytes/src/toolbox.hpp b/format_bytes/src/toolbox.hpp new file mode 100644 index 0000000..06fb2f9 --- /dev/null +++ b/format_bytes/src/toolbox.hpp @@ -0,0 +1,126 @@ +#pragma once +#include <stdint.h> +#include <stddef.h> + +/** + * @brief Cast a variable to an unsigned 64 bit integer + * + * @tparam T Type of the variable to cast + * @param vae Variable to cast + * @return Casted variable + */ +template<typename T> +static constexpr uint64_t u64(const T var) noexcept { + return static_cast<uint64_t>(var); +} + +/** + * @brief Convert a given string to an unsigned 64 bit integer + * + * @param str Input string to convert + * @param n Integer output + * @return EXIT_SUCCESS if successful otherwise EXIT_FAILURE + */ +int32_t sstrtoull(const char* const str, uint64_t& n) noexcept; + +/** + * @brief Swap two given memory values + * + * @tparam T Type of memory placeholder + * @param a Firat memory pointer + * @param b Second memory pointer + */ +inline void swap(char* const a, char* const b) noexcept; + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param offset of the string location to append + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, const size_t offset, char* const str) noexcept; + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, char* const str) noexcept; + +namespace AnsiColor { + constexpr const char* const Reset = "\e[0m"; + + // Regular + constexpr const char* const Black = "\e[0;30m"; + constexpr const char* const Red = "\e[0;31m"; + constexpr const char* const Green = "\e[0;32m"; + constexpr const char* const Yellow = "\e[0;33m"; + constexpr const char* const Blue = "\e[0;34m"; + constexpr const char* const Purple = "\e[0;35m"; + constexpr const char* const Cyan = "\e[0;36m"; + constexpr const char* const White = "\e[0;37m"; + + // Bold + constexpr const char* const BoldBlack = "\e[1;30m"; + constexpr const char* const BoldRed = "\e[1;31m"; + constexpr const char* const BoldGreen = "\e[1;32m"; + constexpr const char* const BoldYellow = "\e[1;33m"; + constexpr const char* const BoldBlue = "\e[1;34m"; + constexpr const char* const BoldPurple = "\e[1;35m"; + constexpr const char* const BoldCyan = "\e[1;36m"; + constexpr const char* const BoldWhite = "\e[1;37m"; + + // Underline + constexpr const char* const UnderBlack = "\e[4;30m"; + constexpr const char* const UnderRed = "\e[4;31m"; + constexpr const char* const UnderGreen = "\e[4;32m"; + constexpr const char* const UnderYellow = "\e[4;33m"; + constexpr const char* const UnderBlue = "\e[4;34m"; + constexpr const char* const UnderPurple = "\e[4;35m"; + constexpr const char* const UnderCyan = "\e[4;36m"; + constexpr const char* const UnderWhite = "\e[4;37m"; + + // Background + constexpr const char* const BgBlack = "\e[40m"; + constexpr const char* const BgRed = "\e[41m"; + constexpr const char* const BgGreen = "\e[42m"; + constexpr const char* const BgYellow = "\e[43m"; + constexpr const char* const BgBlue = "\e[44m"; + constexpr const char* const BgPurple = "\e[45m"; + constexpr const char* const BgCyan = "\e[46m"; + constexpr const char* const BgWhite = "\e[47m"; + + // High Intensity + constexpr const char* const HIBlack = "\e[0;90m"; + constexpr const char* const HIRed = "\e[0;91m"; + constexpr const char* const HIGreen = "\e[0;92m"; + constexpr const char* const HIYellow = "\e[0;93m"; + constexpr const char* const HIBlue = "\e[0;94m"; + constexpr const char* const HIPurple = "\e[0;95m"; + constexpr const char* const HICyan = "\e[0;96m"; + constexpr const char* const HIWhite = "\e[0;97m"; + + // Bold High Intensity + constexpr const char* const BoldHIBlack = "\e[1;90m"; + constexpr const char* const BoldHIRed = "\e[1;91m"; + constexpr const char* const BoldHIGreen = "\e[1;92m"; + constexpr const char* const BoldHIYellow = "\e[1;93m"; + constexpr const char* const BoldHIBlue = "\e[1;94m"; + constexpr const char* const BoldHIPurple = "\e[1;95m"; + constexpr const char* const BoldHICyan = "\e[1;96m"; + constexpr const char* const BoldHIWhite = "\e[1;97m"; + + // High Intensity Background + constexpr const char* const HIBgBlack = "\e[0;100m"; + constexpr const char* const HIBgRed = "\e[0;101m"; + constexpr const char* const HIBgGreen = "\e[0;102m"; + constexpr const char* const HIBgYellow = "\e[0;103m"; + constexpr const char* const HIBgBlue = "\e[0;104m"; + constexpr const char* const HIBgPurple = "\e[0;105m"; + constexpr const char* const HIBgCyan = "\e[0;106m"; + constexpr const char* const HIBgWhite = "\e[0;107m"; +}; diff --git a/format_bytes/src/unit_test.cpp b/format_bytes/src/unit_test.cpp new file mode 100644 index 0000000..39914c2 --- /dev/null +++ b/format_bytes/src/unit_test.cpp @@ -0,0 +1,46 @@ +#include <iostream> +#include "toolbox.hpp" +#include "format_bytes.hpp" + +/** + * @brief Test if a given result is equal of the expected one and log result + * + * @tparam T type of returning values + * @param name of the unit test + * @param expected result of the function call + * @param result of the function + */ +template<typename T> +void Assert(const char* const name, const T& expected, const T& result) noexcept { + if (expected != result) + std::cerr << AnsiColor::Red << "[ ] - " << name << AnsiColor::Reset << " - Expected '" << expected << "' but got '" << result << "' instead\n"; + else + std::cout << AnsiColor::Green << "[✓] - " << name << AnsiColor::Reset << "\n"; +} + +/** + * @brief Test suite for the format_byte output + */ +void format_byte_test(void) noexcept { + std::cout << AnsiColor::BoldWhite << "\tTesting format_byte_size str suite" << AnsiColor::Reset << "\n"; + + Assert("format_bytes str null", std::string("0B"), format_bytes(u64(0))); + Assert("format_bytes str byte", std::string("1B"), format_bytes(u64(1))); + Assert("format_bytes str kilobyte", std::string("1KB"), format_bytes(u64(1) << 10)); + Assert("format_bytes str megabyte", std::string("1MB"), format_bytes(u64(1) << 20)); + Assert("format_bytes str gigabyte", std::string("1GB"), format_bytes(u64(1) << 30)); + Assert("format_bytes str terabyte", std::string("1TB"), format_bytes(u64(1) << 40)); + Assert("format_bytes str petabyte", std::string("1PB"), format_bytes(u64(1) << 50)); + Assert("format_bytes str exabyte", std::string("1EB"), format_bytes(u64(1) << 60)); + // Unsupported due to number of byte bigger than currently supported by ISO c++ + // Assert("format_bytes zettabyte", std::string("1ZB"), format_bytes(u64(1)<<70)); + // Assert("format_bytes yottabyte", std::string("1YB"), format_bytes(u64(1)<<80)); + // uint64_t_MAX == 2**64 == 18446744073709551615 == -1 + Assert("format_bytes str max", std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B"), format_bytes(u64(-1))); + Assert("format_bytes str max", std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B"), format_bytes(18446744073709551615ull)); + Assert("format_bytes str longest", std::string("10EB 1000PB 1000TB 1000GB 1000MB 1000KB 1000B"), format_bytes(12656215539330294760ull)); +} + +int32_t main(void) noexcept { + format_byte_test(); +} diff --git a/format_time/Makefile b/format_time/Makefile new file mode 100644 index 0000000..ebad271 --- /dev/null +++ b/format_time/Makefile @@ -0,0 +1,43 @@ +CXX := g++ +CFLAGS := -std=c++11 -m64 -Wall -Werror -Wextra -O3 + +.PHONY: all +all: bin/format_time bin/format_time_ns + +bin: + @mkdir -v bin + +bin/format_time: src/format_time.cpp src/toolbox.cpp | check-cxx-works bin + @echo Compiling $< + @${CXX} ${CFLAGS} $^ -o $@ + +bin/format_time_ns: src/format_time_ns.cpp src/toolbox.cpp | check-cxx-works bin + @echo Compiling $^ + @${CXX} ${CFLAGS} $^ -o $@ + +bin/format_time_test: src/format_time.cpp src/format_time_ns.cpp src/toolbox.cpp src/unit_test.cpp | check-cxx-works bin + @echo Compiling $^ + @${CXX} ${CFLAGS} -DTEST $^ -o $@ + +.PHONY: install +install: bin/format_time bin/format_time_ns + @cp -v $^ /usr/bin + +.PHONY: uninstall +uninstall: /usr/bin/format_time /usr/bin/format_time_ns + @rm -v $^ + +.PHONY: test +test: bin/format_time_test + @./$^ + +.PHONY: clean +clean: + @rm -rfv bin + +.PHONY: mrproper +mrproper: clean + +.PHONY: check-cxx-works +check-cxx-works: + @${CXX} --version >/dev/null 2>&1 || (echo 'Please install a C++ compiler.' && exit 1) diff --git a/format_time/src/format_time.cpp b/format_time/src/format_time.cpp new file mode 100644 index 0000000..5c80e76 --- /dev/null +++ b/format_time/src/format_time.cpp @@ -0,0 +1,67 @@ +#include <string> +#include <array> +#include <stdint.h> +#include "toolbox.hpp" + +static constexpr const size_t STRING_BUFFER_SIZE = 64; +static constexpr const uint8_t N_TIMES = 8; +static constexpr const char time_formats[N_TIMES + 1] = "smhjwMyc"; +static constexpr const std::array<const uint64_t, N_TIMES> time_numbers = { 1, 60, 3600, 86400, 604800, 2629800, 31557600, u64(315576e4) }; + +/** + * @brief Convert a given number of seconds to a human readable format + * + * @param time Number of seconds + * @return Human readable formatted string + */ +std::string format_time(uint64_t time) noexcept { + char s[STRING_BUFFER_SIZE] = { 0 }; + + if(time == 0){ + sprintf(s, "0%c", time_formats[0]); + return s; + } + + uint64_t res; + size_t j = 0; + for(int8_t i = static_cast<int8_t>(time_numbers.size() - 1); i >= 0; --i) { + if(time >= time_numbers[i]){ + res = time / time_numbers[i]; + time %= time_numbers[i]; + j += ullstr(res, j, s); + s[j++] = time_formats[i]; + s[j++] = ' '; + } + } + + /* Remove trailing character */ + s[j - 1] = '\0'; + + return std::string(s); +} + +#ifndef TEST +int32_t main(const int32_t argc, const char* const* argv) noexcept { + + uint64_t n = 0; + if (argc > 2) return fprintf(stderr, "Invalid usage : (%s $NUMBER) or (echo $NUMBER | %s)\n", argv[0], argv[0]); + else if (argc == 2){ + if(sstrtoull(argv[1], n) == EXIT_FAILURE) + return EXIT_FAILURE; + } else { + size_t i = 0; + char c, BUFFER[STRING_BUFFER_SIZE]; + for(; i < STRING_BUFFER_SIZE && (c = fgetc(stdin)) != EOF; ++i) + BUFFER[i] = c; + if(i == STRING_BUFFER_SIZE){ + fprintf(stderr, "Error while converting to integer : invalid stdin input (too large)\n"); + return EXIT_FAILURE; + } + if(sstrtoull(BUFFER, n) == EXIT_FAILURE) + return EXIT_FAILURE; + } + + printf("%s\n", format_time(n).c_str()); + return EXIT_SUCCESS; +} +#endif diff --git a/format_time/src/format_time.hpp b/format_time/src/format_time.hpp new file mode 100644 index 0000000..a0f9a2d --- /dev/null +++ b/format_time/src/format_time.hpp @@ -0,0 +1,19 @@ +#pragma once +#include <string> +#include <stdint.h> + +/** + * @brief Convert a given number of seconds to a human readable format + * + * @param time Number of seconds + * @return Human readable formatted string + */ +std::string format_time(uint64_t time) noexcept; + +/** + * @brief Convert a given number of nanoseconds to a human readable format + * + * @param time Number of nanoseconds + * @return Human readable formatted string + */ +std::string format_time_ns(uint64_t time) noexcept; diff --git a/format_time/src/format_time_ns.cpp b/format_time/src/format_time_ns.cpp new file mode 100644 index 0000000..01f109a --- /dev/null +++ b/format_time/src/format_time_ns.cpp @@ -0,0 +1,73 @@ +#include <string> +#include <array> +#include <stdint.h> +#include "toolbox.hpp" + +static constexpr const size_t STR_BUFFER_SIZE = 64; +static constexpr const int8_t N_TIMES = 11; +static constexpr const std::array<const char* const, N_TIMES> time_formats = { "ns", "us", "ms", "s", "m", "h", "j", "w", "M", "y", "c" }; +static constexpr const std::array<const uint64_t, N_TIMES> time_numbers = { 1, 1000, 1000000, u64(1e9), u64(6e10), u64(36e11), u64(864e11), + u64(6048e11), u64(26298e11), u64(315576e11), u64(315576e13) }; + +#define STRING_BUFFER_SIZE 64 + +/** + * @brief Convert a given number of nanoseconds to a human readable format + * + * @param time Number of nanoseconds + * @return Human readable formatted string + */ +std::string format_time_ns(uint64_t time) noexcept { + char s[STRING_BUFFER_SIZE] = {0}; + size_t j = 0; + + if (time == 0){ + sprintf(s, "0%s", time_formats[0]); + return s; + } + + uint64_t res; + for (int8_t i = time_numbers.size() - 1; i >= 0; --i) { + if (time >= time_numbers[i]) { + res = time / time_numbers[i]; + time %= time_numbers[i]; + j += ullstr(res, j, s); + for(int k = 0; time_formats[i][k] > 0; ++k) + s[j++] = time_formats[i][k]; + s[j++] = ' '; + } + } + + /* Remove trailing character */ + s[j - 1] = '\0'; + + std::string ss(s); + + return ss; +} + +#ifndef TEST +int32_t main(const int32_t argc, const char* const* argv) noexcept { + + uint64_t n = 0; + if (argc > 2) return fprintf(stderr, "Invalid usage : (%s $NUMBER) or (echo $NUMBER | %s)\n", argv[0], argv[0]); + else if (argc == 2){ + if(sstrtoull(argv[1], n) == EXIT_FAILURE) + return EXIT_FAILURE; + } else { + size_t i = 0; + char c, BUFFER[STR_BUFFER_SIZE]; + for(; i < STR_BUFFER_SIZE && (c = fgetc(stdin)) != EOF; ++i) + BUFFER[i] = c; + if(i == STR_BUFFER_SIZE){ + fprintf(stderr, "Error while converting to integer : invalid stdin input (too large)\n"); + return EXIT_FAILURE; + } + if(sstrtoull(BUFFER, n) == EXIT_FAILURE) + return EXIT_FAILURE; + } + + printf("%s\n", format_time_ns(n).c_str()); + return EXIT_SUCCESS; +} +#endif diff --git a/format_time/src/toolbox.cpp b/format_time/src/toolbox.cpp new file mode 100644 index 0000000..471efd1 --- /dev/null +++ b/format_time/src/toolbox.cpp @@ -0,0 +1,85 @@ +#include <cstdlib> +#include <stdio.h> +#include <errno.h> +#include <cstring> +#include <limits.h> +#include <stdint.h> + +/** + * @brief Convert a given string to an unsigned 64 bit integer + * + * @param str Input string to convert + * @param n Integer output + * @return EXIT_SUCCESS if successful otherwise EXIT_FAILURE + */ +int32_t sstrtoull(const char* str, uint64_t& n) noexcept { + errno = 0; + char* endptr = nullptr; + const uint64_t a = strtoull(str, &endptr, 10); + + switch(errno){ + case 0: + n = a; + return EXIT_SUCCESS; + case ERANGE: + fprintf(stderr, "Error while converting to integer : numerical result out of range ("); + if(a == 0) + fprintf(stderr, "underflow occurred"); + else if(a == ULLONG_MAX) + fprintf(stderr, "overflow occurred"); + else + fprintf(stderr, "unspecified"); + fprintf(stderr, ")\n"); + return EXIT_FAILURE; + default: + fprintf(stderr, "Unspecified error occurred while converting to integer: %s\n", strerror(errno)); + return EXIT_FAILURE; + } +} + +/** + * @brief Swap two given memory values + * + * @tparam T Type of memory placeholder + * @param a Firat memory pointer + * @param b Second memory pointer + */ +template<typename T> +inline void swap(T* const a, T* const b) noexcept { + const T temp = *a; + *a = *b; + *b = temp; + +} + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param offset of the string location to append + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, const size_t offset, char* const str) noexcept { + size_t i = 0; + + for (; num > 0; num /= 10) + str[offset + i++] = num % 10 + '0'; + + str[offset + i] = '\0'; + + for (size_t j = 0; j < i / 2; ++j) + swap(str + offset + j, str + offset + i - j - 1); + return i; +} + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, char* const str) noexcept { + return ullstr(num, 0, str); +} diff --git a/format_time/src/toolbox.hpp b/format_time/src/toolbox.hpp new file mode 100644 index 0000000..06fb2f9 --- /dev/null +++ b/format_time/src/toolbox.hpp @@ -0,0 +1,126 @@ +#pragma once +#include <stdint.h> +#include <stddef.h> + +/** + * @brief Cast a variable to an unsigned 64 bit integer + * + * @tparam T Type of the variable to cast + * @param vae Variable to cast + * @return Casted variable + */ +template<typename T> +static constexpr uint64_t u64(const T var) noexcept { + return static_cast<uint64_t>(var); +} + +/** + * @brief Convert a given string to an unsigned 64 bit integer + * + * @param str Input string to convert + * @param n Integer output + * @return EXIT_SUCCESS if successful otherwise EXIT_FAILURE + */ +int32_t sstrtoull(const char* const str, uint64_t& n) noexcept; + +/** + * @brief Swap two given memory values + * + * @tparam T Type of memory placeholder + * @param a Firat memory pointer + * @param b Second memory pointer + */ +inline void swap(char* const a, char* const b) noexcept; + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param offset of the string location to append + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, const size_t offset, char* const str) noexcept; + +/** + * @brief Convert a given number to string + * + * @param num Number to convert + * @param str String to append the number to + * @return number of written bytes + */ +size_t ullstr(uint64_t num, char* const str) noexcept; + +namespace AnsiColor { + constexpr const char* const Reset = "\e[0m"; + + // Regular + constexpr const char* const Black = "\e[0;30m"; + constexpr const char* const Red = "\e[0;31m"; + constexpr const char* const Green = "\e[0;32m"; + constexpr const char* const Yellow = "\e[0;33m"; + constexpr const char* const Blue = "\e[0;34m"; + constexpr const char* const Purple = "\e[0;35m"; + constexpr const char* const Cyan = "\e[0;36m"; + constexpr const char* const White = "\e[0;37m"; + + // Bold + constexpr const char* const BoldBlack = "\e[1;30m"; + constexpr const char* const BoldRed = "\e[1;31m"; + constexpr const char* const BoldGreen = "\e[1;32m"; + constexpr const char* const BoldYellow = "\e[1;33m"; + constexpr const char* const BoldBlue = "\e[1;34m"; + constexpr const char* const BoldPurple = "\e[1;35m"; + constexpr const char* const BoldCyan = "\e[1;36m"; + constexpr const char* const BoldWhite = "\e[1;37m"; + + // Underline + constexpr const char* const UnderBlack = "\e[4;30m"; + constexpr const char* const UnderRed = "\e[4;31m"; + constexpr const char* const UnderGreen = "\e[4;32m"; + constexpr const char* const UnderYellow = "\e[4;33m"; + constexpr const char* const UnderBlue = "\e[4;34m"; + constexpr const char* const UnderPurple = "\e[4;35m"; + constexpr const char* const UnderCyan = "\e[4;36m"; + constexpr const char* const UnderWhite = "\e[4;37m"; + + // Background + constexpr const char* const BgBlack = "\e[40m"; + constexpr const char* const BgRed = "\e[41m"; + constexpr const char* const BgGreen = "\e[42m"; + constexpr const char* const BgYellow = "\e[43m"; + constexpr const char* const BgBlue = "\e[44m"; + constexpr const char* const BgPurple = "\e[45m"; + constexpr const char* const BgCyan = "\e[46m"; + constexpr const char* const BgWhite = "\e[47m"; + + // High Intensity + constexpr const char* const HIBlack = "\e[0;90m"; + constexpr const char* const HIRed = "\e[0;91m"; + constexpr const char* const HIGreen = "\e[0;92m"; + constexpr const char* const HIYellow = "\e[0;93m"; + constexpr const char* const HIBlue = "\e[0;94m"; + constexpr const char* const HIPurple = "\e[0;95m"; + constexpr const char* const HICyan = "\e[0;96m"; + constexpr const char* const HIWhite = "\e[0;97m"; + + // Bold High Intensity + constexpr const char* const BoldHIBlack = "\e[1;90m"; + constexpr const char* const BoldHIRed = "\e[1;91m"; + constexpr const char* const BoldHIGreen = "\e[1;92m"; + constexpr const char* const BoldHIYellow = "\e[1;93m"; + constexpr const char* const BoldHIBlue = "\e[1;94m"; + constexpr const char* const BoldHIPurple = "\e[1;95m"; + constexpr const char* const BoldHICyan = "\e[1;96m"; + constexpr const char* const BoldHIWhite = "\e[1;97m"; + + // High Intensity Background + constexpr const char* const HIBgBlack = "\e[0;100m"; + constexpr const char* const HIBgRed = "\e[0;101m"; + constexpr const char* const HIBgGreen = "\e[0;102m"; + constexpr const char* const HIBgYellow = "\e[0;103m"; + constexpr const char* const HIBgBlue = "\e[0;104m"; + constexpr const char* const HIBgPurple = "\e[0;105m"; + constexpr const char* const HIBgCyan = "\e[0;106m"; + constexpr const char* const HIBgWhite = "\e[0;107m"; +}; diff --git a/format_time/src/unit_test.cpp b/format_time/src/unit_test.cpp new file mode 100644 index 0000000..71b53aa --- /dev/null +++ b/format_time/src/unit_test.cpp @@ -0,0 +1,155 @@ +#include <iostream> +#include "toolbox.hpp" +#include "format_time.hpp" + +/** + * @brief Test if a given result is equal of the expected one and log result + * + * @tparam T type of returning values + * @param name of the unit test + * @param expected result of the function call + * @param result of the function + */ +template<typename T> +void Assert(const char* const name, const T& expected, const T& result) noexcept { + if (expected != result) + std::cerr << AnsiColor::Red << "[ ] - " << name << AnsiColor::Reset << " - Expected '" << expected << "' but got '" << result << "' instead\n"; + else + std::cout << AnsiColor::Green << "[✓] - " << name << AnsiColor::Reset << "\n"; +} + +/** + * @brief Test suite for the format_time output + */ +void format_time_test(void) noexcept { + std::cout << AnsiColor::BoldWhite << "\tTesting format_time str suite" << AnsiColor::Reset << "\n"; + + // https://en.wikipedia.org/wiki/Unit_of_time + Assert("format_time str null", std::string("0s"), format_time(u64(0))); + Assert("format_time str second", std::string("1s"), format_time(u64(1))); + Assert("format_time str decasecond", std::string("10s"), format_time(u64(10))); + Assert("format_time str minute", std::string("1m"), format_time(u64(60))); + Assert("format_time str milliday", std::string("1m 26s"), format_time(u64(86))); // missing 0.4s due to precision + Assert("format_time str hectosecond", std::string("1m 40s"), format_time(u64(100))); + Assert("format_time str kilosecond", std::string("16m 40s"), format_time(u64(1e3))); + Assert("format_time str hour", std::string("1h"), format_time(u64(3600))); + Assert("format_time str day", std::string("1j"), format_time(u64(86400))); + Assert("format_time str week/sennight", std::string("1w"), format_time(u64(604800))); + Assert("format_time str megasecond", std::string("1w 4j 13h 46m 40s"), format_time(u64(1e6))); + Assert("format_time str fortnight", std::string("2w"), format_time(u64(1209600))); + Assert("format_time str lunar month (draconitic)", std::string("3w 6j 5h 5m 35s"), format_time(u64(2351135))); // missing 0.8 due to precision + Assert("format_time str lunar month (tropical)", std::string("3w 6j 7h 43m 4s"), format_time(u64(2360584))); // missing 0.7 due to precision + Assert("format_time str lunar month (sidereal)", std::string("3w 6j 7h 43m 11s"), format_time(u64(2360591))); // missing 0.6 to precision + Assert("format_time str lunar month (anomalistic)", std::string("3w 6j 13h 18m 33s"), format_time(u64(2380713))); // missing 0.2 due to precision + Assert("format_time str lunar month (synodic)", std::string("4w 1j 12h 44m 2s"), format_time(u64(2551442))); // missing 0.9 due to precision + Assert("format_time str month", std::string("1M"), format_time(u64(2629800))); + Assert("format_time str quarantine", std::string("1M 1w 2j 13h 30m"), format_time(u64(3456e3))); + Assert("format_time str semester", std::string("4M 4j 6h"), format_time(u64(10886400))); + Assert("format_time str lunar year", std::string("11M 2w 5j 13h 22m 48s"), format_time(u64(30617568))); + Assert("format_time str common year", std::string("11M 4w 2j 4h 30m"), format_time(u64(31536e3))); + Assert("format_time str year", std::string("1y"), format_time(u64(31557600))); + Assert("format_time str tropical year", std::string("11M 4w 2j 10h 18m 45s"), format_time(u64(31556925))); // missing 0.216 due to precision + Assert("format_time str gregorian year", std::string("11M 4w 2j 10h 19m 12s"), format_time(u64(31556952))); + Assert("format_time str sidereal year", std::string("1y 9m 9s"), format_time(u64(31558149))); // missing 0.7635456 due to precision + Assert("format_time str leap year", std::string("1y 18h"), format_time(u64(31622400))); + Assert("format_time str olympiad", std::string("4y"), format_time(u64(126230400))); + Assert("format_time str lusturm", std::string("5y"), format_time(u64(157788e3))); + Assert("format_time str decade", std::string("10y"), format_time(u64(315576e3))); + Assert("format_time str indiction", std::string("15y"), format_time(u64(473364e3))); + Assert("format_time str score", std::string("20y"), format_time(u64(631152e3))); + Assert("format_time str gigasecond", std::string("31y 8M 1w 19h 46m 40s"), format_time(u64(1e9))); + Assert("format_time str jubilee", std::string("50y"), format_time(u64(157788e4))); + Assert("format_time str century", std::string("1c"), format_time(u64(315576e4))); + + Assert("format_time str millennium", std::string("10c"), format_time(u64(315576e5))); + Assert("format_time str age", std::string("257c 72y"), format_time(u64(813302467200))); + Assert("format_time str terasecond", std::string("3168c 80y 10M 2w 2j 8h 46m 40s"), format_time(u64(1e13))); + Assert("format_time str megaannum", std::string("10000c"), format_time(u64(315576e8))); + Assert("format_time str petasecond", std::string("316880c 87y 9M 3w 2j 9h 16m 40s"), format_time(u64(1e15))); + Assert("format_time str galactic year", std::string("2300000c"), format_time(u64(7258248e9))); + Assert("format_time str kalpa", std::string("43200000c"), format_time(u64(136328832e9))); + Assert("format_time str eon", std::string("10000000c"), format_time(u64(315576e11))); + Assert("format_time str exasecond", std::string("316880878c 14y 1w 3j 13h 46m 40s"), format_time(u64(1e18))); + // Cannot use number bigger than currently supported ISO C++ + //Assert("format_time str zettasecond", std::string(""), format_time(u64(1e21))); + //Assert("format_time str yottasecond", std::string(""), format_time(u64(1e24))); + //Assert("format_time str ronnasecond", std::string(""), format_time(u64(1e27))); + //Assert("format_time str quettasecond", std::string(""), format_time(u64(1e30))); + // uint64_t MAX == 2**64 == 18446744073709551615 == -1 + Assert("format_time str max", std::string("5845420460c 90y 7M 2w 1j 17h 30m 15s"), format_time(u64(-1))); + Assert("format_time str max", std::string("5845420460c 90y 7M 2w 1j 17h 30m 15s"), format_time(18446744073709551615ull)); + Assert("format_time str longest", std::string("1000000000c 10y 10M 3w 6j 10h 10m 10s"), format_time(3155760000344243410ull)); +} + +/** + * @brief Test suite for the format_time_ns output + */ +void format_time_ns_test(void) noexcept { + std::cout << AnsiColor::BoldWhite << "\tTesting format_time_ns str suite" << AnsiColor::Reset << "\n"; + + // https://en.wikipedia.org/wiki/Unit_of_time + Assert("format_time_ns str null", std::string("0ns"), format_time_ns(u64(0))); + Assert("format_time_ns str nanosecond", std::string("1ns"), format_time_ns(u64(1))); + Assert("format_time_ns str shake", std::string("10ns"), format_time_ns(u64(10))); + Assert("format_time_ns str microsecond", std::string("1us"), format_time_ns(u64(1e3))); + Assert("format_time_ns str millisecond", std::string("1ms"), format_time_ns(u64(1e6))); + Assert("format_time_ns str centisecond", std::string("10ms"), format_time_ns(u64(1e7))); + Assert("format_time_ns str decisecond", std::string("100ms"), format_time_ns(u64(1e8))); + Assert("format_time_ns str second", std::string("1s"), format_time_ns(u64(1e9))); + Assert("format_time_ns str decasecond", std::string("10s"), format_time_ns(u64(1e10))); + Assert("format_time_ns str minute", std::string("1m"), format_time_ns(u64(6e10))); + Assert("format_time_ns str milliday", std::string("1m 26s 400ms"), format_time_ns(u64(864e8))); + Assert("format_time_ns str hectosecond", std::string("1m 40s"), format_time_ns(u64(1e11))); + Assert("format_time_ns str kilosecond", std::string("16m 40s"), format_time_ns(u64(1e12))); + Assert("format_time_ns str hour", std::string("1h"), format_time_ns(u64(36e11))); + Assert("format_time_ns str day", std::string("1j"), format_time_ns(u64(864e11))); + Assert("format_time_ns str week/sennight", std::string("1w"), format_time_ns(u64(6048e11))); + Assert("format_time_ns str megasecond", std::string("1w 4j 13h 46m 40s"), format_time_ns(u64(1e15))); + Assert("format_time_ns str fortnight", std::string("2w"), format_time_ns(u64(12096e11))); + Assert("format_time_ns str lunar month (draconitic)", std::string("3w 6j 5h 5m 35s 800ms"), format_time_ns(u64(23511358e8))); + Assert("format_time_ns str lunar month (tropical)", std::string("3w 6j 7h 43m 4s 700ms"), format_time_ns(u64(23605847e8))); + Assert("format_time_ns str lunar month (sidereal)", std::string("3w 6j 7h 43m 11s 600ms"), format_time_ns(u64(23605916e8))); + Assert("format_time_ns str lunar month (anomalistic)", std::string("3w 6j 13h 18m 33s 200ms"), format_time_ns(u64(23807132e8))); + Assert("format_time_ns str lunar month (synodic)", std::string("4w 1j 12h 44m 2s 900ms"), format_time_ns(u64(25514429e8))); + Assert("format_time_ns str month", std::string("1M"), format_time_ns(u64(26298e11))); + Assert("format_time_ns str quarantine", std::string("1M 1w 2j 13h 30m"), format_time_ns(u64(3456e12))); + Assert("format_time_ns str semester", std::string("4M 4j 6h"), format_time_ns(u64(108864e11))); + Assert("format_time_ns str lunar year", std::string("11M 2w 5j 13h 22m 48s"), format_time_ns(u64(30617568e9))); + Assert("format_time_ns str common year", std::string("11M 4w 2j 4h 30m"), format_time_ns(u64(31536e12))); + Assert("format_time_ns str year", std::string("1y"), format_time_ns(u64(315576e11))); + Assert("format_time_ns str tropical year", std::string("11M 4w 2j 10h 18m 45s"), format_time_ns(u64(31556925e9))); + Assert("format_time_ns str gregorian year", std::string("11M 4w 2j 10h 19m 12s"), format_time_ns(u64(31556952e9))); + Assert("format_time_ns str sidereal year", std::string("1y 9m 9s"), format_time_ns(u64(31558149e9))); + Assert("format_time_ns str leap year", std::string("1y 18h"), format_time_ns(u64(316224e11))); + Assert("format_time_ns str olympiad", std::string("4y"), format_time_ns(u64(1262304e11))); + Assert("format_time_ns str lusturm", std::string("5y"), format_time_ns(u64(157788e12))); + Assert("format_time_ns str decade", std::string("10y"), format_time_ns(u64(315576e12))); + Assert("format_time_ns str indiction", std::string("15y"), format_time_ns(u64(473364e12))); + Assert("format_time_ns str score", std::string("20y"), format_time_ns(u64(631152e12))); + Assert("format_time_ns str gigasecond", std::string("31y 8M 1w 19h 46m 40s"), format_time_ns(u64(1e18))); + Assert("format_time_ns str jubilee", std::string("50y"), format_time_ns(u64(157788e13))); + Assert("format_time_ns str century", std::string("1c"), format_time_ns(u64(315576e13))); + // Cannot use number bigger than currently supported ISO C++ + //Assert("format_time_ns str millennium", std::string("10c"), format_time_ns(u64(315576e14))); + //Assert("format_time_ns str age", std::string("257c 72y"), format_time_ns(u64(8133024672e11))); + //Assert("format_time_ns str terasecond", std::string("3168c 80y 10M 2w 2j 8h 46m 40s"), format_time_ns(u64(1e22))); + //Assert("format_time_ns str megaannum", std::string("10000c"), format_time_ns(u64(315576e17))); + //Assert("format_time_ns str petasecond", std::string("316880c 87y 9M 3w 2j 9h 16m 40s"), format_time_ns(u64(1e24))); + //Assert("format_time_ns str galactic year", std::string("2300000c"), format_time_ns(u64(7258248e18))); + //Assert("format_time_ns str eon", std::string("10000000c"), format_time_ns(u64(136328832e18))); + //Assert("format_time_ns str kalpa", std::string("43200000c"), format_time_ns(u64(315576e20))); + //Assert("format_time_ns str exasecond", std::string("316880878c 14y 1w 3j 13h 46m 40s"), format_time_ns(u64(1e27))); + //Assert("format_time_ns str zettasecond", std::string(""), format_time_ns(u64(1e30))); + //Assert("format_time_ns str yottasecond", std::string(""), format_time_ns(u64(1e33))); + //Assert("format_time_ns str ronnasecond", std::string(""), format_time_ns(u64(1e36))); + //Assert("format_time_ns str quettasecond", std::string(""), format_time_ns(u64(1e39))); + // uint64_t_MAX == 2**64 == 18446744073709551615 == -1 + Assert("format_time_ns str max", std::string("5c 84y 6M 2w 1j 8h 34m 33s 709ms 551us 615ns"), format_time_ns(u64(-1))); + Assert("format_time_ns str max", std::string("5c 84y 6M 2w 1j 8h 34m 33s 709ms 551us 615ns"), format_time_ns(18446744073709551615ull)); + Assert("format_time_ns str longest", std::string("1c 10y 10M 3w 6j 10h 10m 10s 100ms 100us 100ns"), format_time_ns(3500003410100100100ull)); +} + +int32_t main(void) noexcept { + format_time_test(); + format_time_ns_test(); +} diff --git a/gcd/Makefile b/gcd/Makefile new file mode 100644 index 0000000..1692eb0 --- /dev/null +++ b/gcd/Makefile @@ -0,0 +1,31 @@ +CXX := g++ +CFLAGS := -std=c++11 -m64 -Wall -Werror -Wextra -O3 + +.PHONY: all +all: bin/gcd + +bin: + @mkdir -v bin + +bin/gcd: src/gcd.cpp | check-cxx-works bin + @echo Compiling $< + @${CXX} ${CFLAGS} $^ -o $@ + +.PHONY: install +install: bin/gcd + @cp -v $^ /usr/bin + +.PHONY: uninstall +uninstall: /usr/bin/gcd + @rm -v $^ + +.PHONY: clean +clean: + @rm -rfv bin + +.PHONY: mrproper +mrproper: clean + +.PHONY: check-cxx-works +check-cxx-works: + @${CXX} --version >/dev/null 2>&1 || (echo 'Please install a C++ compiler.' && exit 1) diff --git a/gcd/src/gcd.cpp b/gcd/src/gcd.cpp new file mode 100644 index 0000000..ab9e715 --- /dev/null +++ b/gcd/src/gcd.cpp @@ -0,0 +1,63 @@ +#include <cstdlib> +#include <stdio.h> +#include <errno.h> +#include <cstring> +#include <limits.h> +#include <stdint.h> + +/** + * @brief Calculate the greatest common divisor (GCD) + * + * @param a First integer + * @param b Second integer + * @return greatest common divisor between a and b + */ +constexpr int64_t gcd(const int64_t& a, const int64_t& b) noexcept { return a == 0 ? b : gcd(b % a, a); } + +/** + * @brief Convert a given string to a 64 bit integer + * + * @param str Input string to convert + * @param n Integer output + * @return EXIT_SUCCESS if successful otherwise EXIT_FAILURE + */ +int32_t sstrtoll(const char* const str, int64_t& n) noexcept { + errno = 0; + char* endptr = nullptr; + const int64_t a = strtoll(str, &endptr, 10); + + switch(errno){ + case 0: + n = a; + return EXIT_SUCCESS; + case ERANGE: + fprintf(stderr, "Error while converting to integer : numerical result out of range ("); + if(a == LLONG_MIN) + fprintf(stderr, "underflow occurred"); + else if(a == LLONG_MAX) + fprintf(stderr, "overflow occurred"); + else + fprintf(stderr, "unspecified"); + fprintf(stderr, ")\n"); + return EXIT_FAILURE; + default: + fprintf(stderr, "Unspecified error occurred while converting to integer: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + n = a; + return EXIT_SUCCESS; +} + +int32_t main(const int32_t argc, const char* const* argv) noexcept { + if (argc != 3){ + fprintf(stderr, "Syntax : gcd number1 number2\n"); + return EXIT_FAILURE; + } + int64_t a, b; + if(sstrtoll(argv[1], a) == EXIT_FAILURE) return EXIT_FAILURE; + if(sstrtoll(argv[2], b) == EXIT_FAILURE) return EXIT_FAILURE; + + const int64_t hcf = gcd(std::abs(a), std::abs(b)); + printf("Common factor = %ld\nResult = %ld/%ld\n", hcf, a / hcf, b / hcf); + return EXIT_SUCCESS; +}