8 * This program is useful for converting between hex strings and signed
9 * integers. It can handle numbers of arbitrary bit sizes (provided they're
10 * between 2 and 63 inclusive.)
15 #define EXIT_WITH_NUMBER 2
17 static int run_unit_tests(void);
19 static void usage(const char *argv0)
21 fprintf(stderr, "%s: convert a hex number to its decimal "
22 "representation.\n", argv0);
23 fprintf(stderr, "\n");
24 fprintf(stderr, "-b [bitsize]: bit size to assume (defaults to 32).\n");
25 fprintf(stderr, "-h: this help message.\n");
26 fprintf(stderr, "-n [number]: number to convert. Must not be 0.\n");
27 fprintf(stderr, "-s: assume signed (default is unsigned).\n");
28 fprintf(stderr, "-u: run unit tests.\n");
31 static int process(char **argv, long long *result)
33 int c, i, argc = 0, bitsize = 32, is_signed = 0;
37 for (i = 0; argv[i]; i++) {
41 while ((c = getopt(argc, argv, "b:hn:su")) != -1) {
44 bitsize = atoi(optarg);
50 if (strncmp(optarg, "0x", 2) != 0) {
51 fprintf(stderr, "The number you pass must start with 0x.\n");
56 number = strtoull(optarg + 2, &endptr, 16);
59 fprintf(stderr, "strtoull failed: error %d (%s)\n",
63 if (*endptr != '\0') {
64 fprintf(stderr, "Garbage at end of string, beginning "
73 return run_unit_tests();
75 fprintf (stderr, "getopt error.\n");
79 if ((bitsize <= 1) || (bitsize >= 64)) {
80 fprintf(stderr, "Invalid bitsize of %d. Bitsize must be "
81 "between 2 and 63, inclusive.\n", bitsize);
85 fprintf(stderr, "You must specify a non-zero number to convert. -h "
89 if (number > (1LL << bitsize)) {
90 fprintf(stderr, "Number %lld does not fit in %d bits.\n",
94 // Mask off unused bits.
96 unsigned long long highest_neg = (1LLU << (bitsize - 1));
97 if ((unsigned long long)number >= highest_neg) {
98 unsigned long long full = (1LLU << bitsize);
102 number &= ((1LLU << bitsize) - 1LLU);
105 return EXIT_WITH_NUMBER;
108 static int run_unit_tests(void)
111 char *help_args[] = { "hexconv", "-h", NULL };
112 char *simple_args[] = { "hexconv", "-n", "0xff", NULL };
113 char *invalid_1[] = { "hexconv", "-n", "123", NULL };
114 char *invalid_2[] = { "hexconv", "-n", "0x123", "-b", "65", NULL };
115 char *invalid_3[] = { "hexconv", "-n", "0xffff", "-b", "8", NULL };
116 char *neg_1[] = { "hexconv", "-n", "0x80", "-b", "8", "-s", NULL };
117 char *neg_2[] = { "hexconv", "-n", "0xff", "-b", "8", "-s", NULL };
118 char *neg_3[] = { "hexconv", "-n", "0xffff", "-b", "16", "-s", NULL };
119 char *neg_4[] = { "hexconv", "-n", "0xfffffe", "-b", "24", "-s", NULL };
121 fprintf(stderr, "*** testing -h ***\n");
122 if (EXIT_SUCCESS != process(help_args, NULL)) abort();
123 fprintf(stderr, "*** testing converting 0xff ***\n");
124 if (EXIT_WITH_NUMBER != process(simple_args, &result)) abort();
125 if (result != 255) abort();
126 fprintf(stderr, "*** testing invalid input 123 ***\n");
127 if (EXIT_FAILURE != process(invalid_1, &result)) abort();
128 fprintf(stderr, "*** testing invalid bitsize input ***\n");
129 if (EXIT_FAILURE != process(invalid_2, &result)) abort();
130 fprintf(stderr, "*** testing too-big input ***\n");
131 if (EXIT_FAILURE != process(invalid_3, &result)) abort();
132 fprintf(stderr, "*** testing converting 0x80 with in signed mode ***\n");
133 if (EXIT_WITH_NUMBER != process(neg_1, &result)) abort();
134 if (result != -128) abort();
135 fprintf(stderr, "*** testing converting 0xff with in signed mode ***\n");
136 if (EXIT_WITH_NUMBER != process(neg_2, &result)) abort();
137 if (result != -1) abort();
138 fprintf(stderr, "*** testing converting 0xffff with in signed mode ***\n");
139 if (EXIT_WITH_NUMBER != process(neg_3, &result)) abort();
140 if (result != -1) abort();
141 fprintf(stderr, "*** testing converting 0xfffffe with in signed mode ***\n");
142 if (EXIT_WITH_NUMBER != process(neg_4, &result)) abort();
143 if (result != -2) abort();
147 int main(int argc, char **argv)
149 long long result = argc; // avoid annoying "unused variable" warning
150 int ret = process(argv, &result);
154 case EXIT_WITH_NUMBER:
155 printf("%lld\n", result);