#include <iostream>
#include <string>
#include <stdexcept>
#include <cstring>
/*
[19:53:25]{main}z@m:/tmp
$ g++ -std=c++11 src.cpp -o src && ./src pack 2 5 0 2 1 1
18965
[19:53:34]{main}z@m:/tmp
$ g++ -std=c++11 src.cpp -o src && ./src unpack 18965
SignalPower=2 WorkingGroup=5 IsBlocked=0 ChargeLevel=2 HasVideoCall=1 ConnectionType=1
*/
struct __attribute__((packed)) TMobileIdentifier {
using TUnderlyingType = uint16_t;
int ConnectionType : 2;
bool HasVideoCall : 1;
int ChargeLevel : 3;
int Reserved6 : 1;
bool IsBlocked : 1;
int Reserved8 : 1;
int WorkingGroup : 4;
int SignalPower : 3;
};
static_assert(
sizeof(TMobileIdentifier) <= sizeof(TMobileIdentifier::TUnderlyingType),
"TMobileIdentifier doesn't fit into uint16_t"
);
void shift(int& argc, char**& argv) {
if (argc == 0)
throw std::runtime_error("no arugments left to shift");
argc--;
argv++;
}
#define $0 argv[0]
#define $1 argv[1]
#define $2 argv[2]
#define $3 argv[3]
#define $4 argv[4]
#define $5 argv[5]
void usage() {
std::cerr << "Usage: packer [pack|unpack] ...args" << std::endl;
}
int main(int argc, char** argv) {
if (argc == 1) {
usage();
return 1;
}
shift(argc, argv);
std::string mode = $0;
if (mode == "pack") {
shift(argc, argv);
if (argc != 6) {
std::cerr << "Usage: packer pack SIGNAL_POWER WORKING_GROUP IS_BLOCKED CHARGE_LEVEL HAS_VIDEO_CALL CONNECTION_TYPE" << std::endl;
return 1;
}
TMobileIdentifier data = {};
data.SignalPower = std::stoi($0);
data.WorkingGroup = std::stoi($1);
data.IsBlocked = std::stoi($2);
data.ChargeLevel = std::stoi($3);
data.HasVideoCall = std::stoi($4);
data.ConnectionType = std::stoi($5);
TMobileIdentifier::TUnderlyingType encoded = 0;
std::memcpy(&encoded, &data, sizeof(data));
std::cout << encoded << std::endl;
} else if (mode == "unpack") {
shift(argc, argv);
if (argc != 1) {
std::cerr << "Usage: packer unpack NUMBER" << std::endl;
return 1;
}
TMobileIdentifier::TUnderlyingType input = std::stoi($0);
TMobileIdentifier decoded;
std::memcpy(&decoded, &input, sizeof(input));
#define OUTPUT_FIELD(NAME) #NAME "=" << decoded.NAME
std::cout
<< OUTPUT_FIELD(SignalPower) << "\t"
<< OUTPUT_FIELD(WorkingGroup) << "\t"
<< OUTPUT_FIELD(IsBlocked) << "\t"
<< OUTPUT_FIELD(ChargeLevel) << "\t"
<< OUTPUT_FIELD(HasVideoCall) << "\t"
<< OUTPUT_FIELD(ConnectionType)
<< std::endl;
#undef OUTPUT_FIELD
} else {
usage();
}
}