tools/baseconvert: New tool

This tool allows for easy conversion between relevant bases
for unsigned numbers.

You may be able to coerce it into converting signed numbers into
unsigned numbers if you know how, though that is not an officially
supported use case (aka that’s using UB in the STL).
Soda
BodgeMaster 2022-10-08 08:29:01 +02:00
parent 17792ec5bf
commit 379903d751
3 changed files with 153 additions and 0 deletions

View File

@ -61,6 +61,7 @@ create_directory bin/tools
COMPILE_COMMANDS=( COMPILE_COMMANDS=(
"$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -l:cli.so -o bin/tools/dumpnbt" "$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -l:cli.so -o bin/tools/dumpnbt"
"$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump" "$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump"
"$CXX_WITH_FLAGS src/tools/baseconvert.cpp -I./include -Lbin/lib -l:cli.so -o bin/tools/baseconvert"
#"$CXX_WITH_FLAGS src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet" #"$CXX_WITH_FLAGS src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet"
) )
for command in ${!COMPILE_COMMANDS[@]}; do for command in ${!COMPILE_COMMANDS[@]}; do

22
scripts/test/baseconvert.sh Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
echo "================================================================================"
echo -n "Testing \`baseconvert\`... "
[ $(baseconvert -d "0xFFFFFFFFFFFFFFFF") = "18446744073709551615" ] \
&& [ $(baseconvert -x "0xFFFFFFFFFFFFFFFF") = "0xffffffffffffffff" ] \
&& [ $(baseconvert -o "0xFFFFFFFFFFFFFFFF") = "01777777777777777777777" ] \
&& [ $(baseconvert -b "0xFFFFFFFFFFFFFFFF") = "0b1111111111111111111111111111111111111111111111111111111111111111" ] \
&& [ $(baseconvert -x "0XFFFFFFFFFFFFFFFF") = "0xffffffffffffffff" ] \
&& [ $(baseconvert -d "0") = "0" ] \
&& [ $(baseconvert -x "0") = "0x0" ] \
&& [ $(baseconvert -o "0") = "0" ] \
&& [ $(baseconvert -b "0") = "0b0" ] \
&& [ $(baseconvert -b "4") = "0b100" ] \
&& [ $(baseconvert -x "07777" ) = "0xfff" ] \
&& [ $(baseconvert -x "0o7777" ) = "0xfff" ] \
&& [ $(baseconvert -x "0O7777" ) = "0xfff" ] \
&& [ $(baseconvert -o "0b1000" ) = "010" ] \
&& [ $(baseconvert -o "0B1000" ) = "010" ] \
&& echo "PASS" \
|| echo "FAIL"
echo "================================================================================"

130
src/tools/baseconvert.cpp Normal file
View File

@ -0,0 +1,130 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include <bitset>
#include <cstdint>
#include <iostream>
#include <vector>
#include "../lib/cli.hpp"
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
int main(int argc, char* argv[]) {
std::vector<CLI::Flag> flags;
flags.push_back(CLI::Flag('x', "hexadecimal", "base 16"));
flags.push_back(CLI::Flag('o', "octal", "base 8"));
flags.push_back(CLI::Flag('b', "binary", "base 2"));
flags.push_back(CLI::Flag('d', "decimal", "base 10"));
flags.push_back(CLI::Flag('h', "help", "print help and exit"));
flags.push_back(CLI::Flag('l', "license", "print license information and exit"));
std::vector<CLI::Option> options;
std::vector<CLI::Argument> arguments;
arguments.push_back(CLI::Argument("NUMBER", "the number to convert"));
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Convert numbers between predefined bases", "This only works for unsigned numbers.\n\tBaseConvert understands the prefixes 0x, 0b, 0o, and 0 in input numbers.");
if (cliParser.getFlag("help").value) {
std::cout << cliParser.getUsage() << std::endl;
return EXIT_SUCCESS;
}
if (cliParser.getFlag("license").value){
std::cout
<< "Copyright 2022, FOSS-VG Developers and Contributers\n"
<< "\n"
<< "BaseConvert is part of the FOSS-VG development tool suite.\n"
<< "\n"
<< "This program is free software: you can redistribute it and/or modify it\n"
<< "under the terms of the GNU Affero General Public License as published\n"
<< "by the Free Software Foundation, version 3.\n"
<< "\n"
<< "This program is distributed in the hope that it will be useful,\n"
<< "but WITHOUT ANY WARRANTY; without even the implied\n"
<< "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
<< "See the GNU Affero General Public License for more details.\n"
<< "\n"
<< "You should have received a copy of the GNU Affero General Public License\n"
<< "version 3 along with this program.\n"
<< "If not, see https://www.gnu.org/licenses/agpl-3.0.en.html"
<< std::endl;
return EXIT_SUCCESS;
}
if (cliParser.wrongUsage) {
std::cout << cliParser.getUsage() << std::endl;
return EXIT_USAGE;
}
std::string numberString = cliParser.getArgument(0).value;
uint8_t base = 10;
uint64_t* number = new uint64_t;
if (numberString == "") {
std::cerr << "Empty string is not a valid number." << std::endl;
return EXIT_RUNTIME;
}
if (numberString[0] == '0') {
if (numberString.substr(0, 2)=="0x" || numberString.substr(0, 2)=="0X") {
base = 16;
numberString = numberString.substr(2, numberString.length()-2);
} else if (numberString.substr(0, 2)=="0b" || numberString.substr(0, 2)=="0B") {
base = 2;
numberString = numberString.substr(2, numberString.length()-2);
} else if (numberString.substr(0, 2)=="0o" || numberString.substr(0, 2)=="0O") {
base = 8;
numberString = numberString.substr(2, numberString.length()-2);
} else {
base = 8;
}
}
*number = std::stoull(numberString, nullptr, base);
if (cliParser.getFlag("hexadecimal").value) {
std::cout << "0x" << std::hex << *number << std::endl;
} else if (cliParser.getFlag("octal").value) {
*number==0? std::cout << "0" << std::endl : std::cout << "0" << std::oct << *number << std::endl;
} else if (cliParser.getFlag("binary").value) {
std::bitset<64> bitset = std::bitset<64>(*number);
bool foundFirstBit = false;
std::cout << "0b";
for (uint8_t i=0; i<64; i++) {
if (bitset[63-i]) {
std::cout << "1";
foundFirstBit = true;
} else if (foundFirstBit) {
std::cout << "0";
}
}
if (!foundFirstBit) {
std::cout << "0";
}
std::cout << std::endl;
} else if (cliParser.getFlag("decimal").value) {
std::cout << *number << std::endl;
} else {
std::cout << cliParser.getUsage() << std::endl;
return EXIT_USAGE;
}
delete number;
return EXIT_SUCCESS;
}