diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2f8d3ac --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +build: + gcc -Wall -pedantic hexcalc.c diff --git a/hexcalc.c b/hexcalc.c new file mode 100644 index 0000000..480ccb8 --- /dev/null +++ b/hexcalc.c @@ -0,0 +1,260 @@ +#include +#include +#include +#include + +/* THIS IS A WORK IN PROGRESS. + * + * This is my first program in C and I look forward to learning more and making + * those changes as I go along. Feedback is appreciated, for example -Wall and + * -pedantic (see Makefile) were very appreciated. + * + * I'm not looking for perfection. + * + * The goal is to later maybe putting this into an ATTiny or Atmega328 and put + * it into some hardware. Just for fun with a display and inputs and stuff. + * + * What I learned writing this: + * - Internet searches return pretty unhelpful stuff + * - ... but I found out that there is something called ispunct, isupp, isalnum + * and a lot of other helpful functions that are part of the C standard + * library. If the validation thing even is something I want. + * - but trying to find out what I wanted about these were harder, + * then I remember I have manpages installed - but how do I find them? man + * stdlib.h, stdio.h and string.h didn't have anything, but man ispunct lead + * me to man ctype.h where I found everything I needed. + * + * TODO/Need to look into: + * - Freeing memory after use + * - Use valgrind + * - Look for null pointers and stuff + * - Read about pointers + * - Padding for binary number output + * - Padding for decimal output + * - Decimal to hex converter + * - Other things mentioned in the code +*/ + +#define LINE 20 + +// declare functions - guess these should go into a header file? +// the error messages I got before putting this here were not helpful. +char* validate_input(char*); +char* to_hex(char*); +int hex_to_decimal(char*, char*, int); +char* to_binary(unsigned int, char*); +char* binary_string(char*, char*); +int binary_to_decimal(char*, char*); + +char hex[4]; // 4 characters (ff ff) +int bin[8]; // 8 digits (1111 1111) +int dec[5]; // 5 digits (65 535) + +int main() { + char* buffer = malloc(LINE+1); + char buf2[17]; + char buf3[LINE+1]; + int i; + int ch; + + printf("Enter a number and this program will convert the number to decimal, hexadecimal \n"); + printf("and binary.\n"); + + while (1) { + printf("\n> "); + + for (i = 0; (i < LINE) && (( ch = getchar()) != EOF) && (ch !='\n'); i++) + buffer[i] = ch; + + buffer[i] = '\0'; + int size = i; + + if (buffer[0] == '\0') + break; + + //printf("Given string was: '%c'\n", *test); + + char *test = validate_input(buffer); + int in_decimal; + char *in_binary; + + in_decimal = hex_to_decimal(buffer, buf2, size); + in_binary = to_binary(in_decimal, buf2); + printf("%s as hex:\n", buffer); + printf("decimal> %i\n", in_decimal); + printf("binary> %s\n", binary_string(in_binary, buf3)); + printf("\n"); + + if (*test == 'd') { + printf("%s as decimal:\n", buffer); + in_binary = to_binary(atoi(buffer), buf2); + printf("hex> \n"); + printf("binary> %s\n", binary_string(in_binary, buf3)); + } + + if (*test == 'b') { + printf("%s as binary:\n", buffer); + int binary_in_decimal = binary_to_decimal(buffer, buf2); + printf("hex> \n"); // TODO: Convert binary to hex + printf("decimal> %i\n", binary_in_decimal); + } + + free(test); + } + + printf("Exiting program.\n"); + + return 0; +} + +char* binary_string(char* in_binary, char* buffer) { + int j = 0; // for padding + for (int i = 0; i < 16; i++) { + buffer[i] = (int) in_binary[i]; + } + buffer[17] = '\0'; + + return buffer; +} + +// TODO: +//char* to_hex(char* input) { +//} + +int hex_to_decimal(char* input, char *buff, int size) { + char *pbuff = buff; + int newbuff[8]; + int newbuff_used; + + char *ch = input; + ch += size; + + *pbuff = 1; + + // TODO: Shouldn't have to do this. Look into atoi()? + // 0=48 + // a=97 + for (int i = 0; i < LINE; i++) { + *ch--; + if (*ch == '\0') { + break; + } + if (*ch >= 97) { + int tmp = *ch - 87; + newbuff[i] = tmp; + } else { + newbuff[i] = *ch - 48; + } + newbuff_used = i+1; + } + + int result = 0; + int exp; + for (int i = 0; i < newbuff_used; i++) { + exp = i; + + while (exp > 0) { + newbuff[i] *= 16; + --exp; + } + + result += newbuff[i]; + } + + return result; +} + +char* to_binary(unsigned int input, char *buff) { + char *pbuff = buff; + + int size = 16; + + pbuff += size; + *pbuff-- = '\0'; + + for (int i = 0; i < size; i++) { + *pbuff-- = ((input & 1) == 1) ? '1' : '0'; + + input >>= 1; + + } + return pbuff+1; +} + +int binary_to_decimal(char* input, char *buff) { + char *pbuff = input; + + int size = strlen(input); + printf("size: %i\n", size); + int result = 0; + + pbuff += size; + int exp = 1; + + for (int i = 0; i < size; i++) { + *pbuff--; + + int val = (int) *pbuff; + val -= 48; // TODO: Shouldn't have to do this. Look into atoi()? + + result += val * exp; + + exp *= 2; + } + + return result; +} + +// returns b for binary, h for hex, d for decimal or e for error +char* validate_input(char* input) { + int b_count = 0; // binary + int h_count = 0; // hex (hexadecimal) + int d_count = 0; // decimal (alphanumerical) + int a_count = 0; // letters (alpha) + int length = 0; + + int i; + char *ret = malloc(1); + + for (i = 0; i < 8; i++) { + if (input[i] == '\0') { + printf("\n"); + break; + } + + if (input[i] == '0' || input[i] == '1') + b_count++; + + if (isdigit(input[i])) + d_count++; + + if (isalpha(input[i])) + a_count++; + + if (isxdigit(input[i])) { + h_count++; + } else { + printf("%c error\n", input[i]); + ret[0] = 'e'; + return ret; + } + + length++; + } + + // if it contains letters it's not binary and not a decimal + if (a_count == 0) + ret[0] = 'd'; + + // Hex is written in groups of 2, like ff or 0afe, not fad. + if (a_count != 0 && length == h_count && (h_count == 2 || h_count == 4)) + ret[0] = 'h'; + + // Binary is written in groups of 2 (or 4), like 10, 11, 1011 and 0100, not 1 or 101. + if (a_count == 0 && length == b_count && (b_count % 2 == 0)) + ret[0] = 'b'; + + //printf("%-1c: %d d, %d h, %d b, %d length\n\n", ret[0], d_count, h_count, b_count, length); + + return ret; +}