90 lines
2.0 KiB
C
90 lines
2.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include "02-bitwise.h"
|
|
|
|
#define BASES X("0b", 2) X("0", 8) X("", 10) X("0x", 16)
|
|
|
|
#define X(p, b) int int_of_base_##b(unsigned *x, char *s);
|
|
BASES
|
|
#undef X
|
|
|
|
/* printd_base: prints x in base b */
|
|
void printd_base(int b, unsigned x)
|
|
{
|
|
if (!x) {
|
|
putchar('0');
|
|
return;
|
|
}
|
|
|
|
switch (b) {
|
|
#define X(p, b) case b : printf("%s", p); break;
|
|
BASES
|
|
#undef X
|
|
}
|
|
|
|
unsigned m;
|
|
for (m = 1; m * b <= x && m * b > 0; m *= b)
|
|
;
|
|
char d;
|
|
while (m > 0) {
|
|
if ((d = x / m) > 9)
|
|
putchar(d - 10 + 'a');
|
|
else
|
|
putchar(d + '0');
|
|
x %= m;
|
|
m /= b;
|
|
}
|
|
}
|
|
|
|
/* int_of_string: converts string s to int, writes result to *x and returns base
|
|
* of the ints string representation or 0 if s is invalid */
|
|
int int_of_string(unsigned *x, char *s)
|
|
{
|
|
switch (*s) {
|
|
case '0' :
|
|
switch (*(s+1)) {
|
|
case 'b' :
|
|
return int_of_base_2(x, s+2);
|
|
case 'x' :
|
|
return int_of_base_16(x, s+2);
|
|
default :
|
|
return int_of_base_8(x, s+1);
|
|
}
|
|
default :
|
|
return int_of_base_10(x, s);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* int_of_base_b: for base b, convert number string in base b to int and
|
|
* write it to *x. return b or 0 if invalid */
|
|
#define MAKE_INT_OF_BASE(b) \
|
|
int int_of_base_##b(unsigned *x, char *s) \
|
|
{ \
|
|
char d; \
|
|
unsigned px = 0; \
|
|
*x = 0; \
|
|
for (; *s; s++) { \
|
|
d = *s - '0'; \
|
|
if (b > 10 && d > 9) \
|
|
d = tolower(*s) - 'a' + 10; \
|
|
if (d < 0 || d >= b) { \
|
|
printf("error: invalid character in number literal in base " #b "\n"); \
|
|
return 0; \
|
|
} \
|
|
px = *x; \
|
|
*x *= b; \
|
|
*x += d; \
|
|
if (*x < px) { \
|
|
printf("error : number to large\n"); \
|
|
return 0; \
|
|
} \
|
|
} \
|
|
return b; \
|
|
}
|
|
|
|
#define X(p, b) MAKE_INT_OF_BASE(b)
|
|
BASES
|
|
#undef X
|