diff --git a/.gitignore b/.gitignore index e058d00..ebc3ca4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.exe **/.DS_Store bin/ +melody-allocator diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8054e0c --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +EXEC = "melody-allocator" + +$(EXEC): + gcc -o ./$(EXEC) -O2 ./main.c + +install: $(EXEC) + cp $(EXEC) /usr/local/bin/ + chmod +x /usr/local/bin/$(EXEC) + +clean: + rm ./$(EXEC) diff --git a/README.md b/README.md index c58f4e5..69e6af0 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,25 @@ # memory allocator -it allocates memory *(in gibibytes (GiB))* +it allocates memory ## how to use -- run the executable -- enter how many gibibytes you want (max is how many gibibytes of memory you have) -- confirm (y) -- wait for the program to allocate the memory -- your memory is allocated -- press any key or CTRL+C to free the memory and exit the program -- ??? -- profit +``` +usage: allocatememory -b [-o ] [-s] + +OPTIONS + -h displays help + -b number of bytes to allocate (e.g. 1024, 1g, 64K) + -o file to output to + -s run silently (requires -b and -o) + -w disable warnings ("i know what i'm doing!") +``` ## how to compile -- get a c compiler (i use gcc) -- `gcc -o ./allocatememory.exe ./main.c` -- ??? -- profit +- `make` +- (optional) `sudo make install` +- yeag ## why diff --git a/main.c b/main.c index 3353cae..317d945 100644 --- a/main.c +++ b/main.c @@ -1,48 +1,211 @@ #include #include +#include +#include +#include +#include +#include -int main() { +#define BYTES_GIVEN 1 +#define OUTPUT_FILE 2 +#define SILENT 4 +#define BYPASS_WARN 8 - unsigned long long int size = 0; - unsigned int gib = 0; - - printf("please enter the number of gibibytes (GiB) you would like to allocate (1 GiB = 1073741824 bytes):\n> "); - unsigned int digit = 0; - while (1) { - unsigned char input = getchar(); - if (input == '\n') break; - if (input < '0' || input > '9') continue; +#define KiB (unsigned long long int) 0x400 +#define MiB (unsigned long long int) 0x100000 +#define GiB (unsigned long long int) 0x40000000 +#define TiB (unsigned long long int) 0x10000000000 - if (digit > 0) gib = gib * 10; +#define LOADS TiB * 9999 - gib = gib + (unsigned int) input - 48; - digit++; - } +void print_help(); +unsigned char* get_shorthand(unsigned long long int size); +void adjust_by_denomination(unsigned long long int* size, char denomination); +unsigned long long int* allocate_heap(unsigned long long int size, char silent); +void save_heap(unsigned long long int* heap, unsigned long long int size, char* filename, char silent); - size = (unsigned long long int) gib * 1024 * 1024 * 1024; +int main(int argc, char* argv[]) { - printf("you are about to allocate %d GiB (%llu bytes) of heap memory. are you sure? (y/n)\n> ", gib, size); + unsigned char flags = 0; + unsigned long long int size = 0; + unsigned char* filename = NULL; + unsigned char denominator = 0; - unsigned char input = getchar(); - if (input != 'y') return 0; - while (getchar() != '\n'); + int arg; + while ((arg = getopt(argc, argv, "hb:o:sw")) != -1) { + switch (arg) { + case 'h': + print_help(); + exit(0); + case 'b': + size = strtoull(optarg, NULL, 10); + if (errno == EINVAL) { + fprintf(stderr, "argument -b used with invalid value '%s'!\n", optarg); + exit(0); + } + if (errno == ERANGE) { + fprintf(stderr, "byte argument ''%s' out of range!\n", optarg); + exit(0); + } + denominator = optarg[strlen(optarg) - 1]; + flags |= BYTES_GIVEN; + break; + case 'o': + filename = optarg; + flags |= OUTPUT_FILE; + break; + case 's': + if (size == 0 || filename == NULL) { + fprintf(stderr, "cannot run silently without -b and -o set!\n"); + print_help(); + } + flags |= SILENT; + break; + case 'w': + flags |= BYPASS_WARN; + break; + case '?': + if (optopt == 'b' || optopt == 'o') + fprintf(stderr, "argument -%c requires an argument!\n", optopt); + else if (isprint(optopt)) + fprintf(stderr, "unknown argument '-%c'.\n", optopt); + else + fprintf(stderr, "unknown argument character '\\x%x'.\n", optopt); + exit(1); + default: + exit(1); + } + } - printf("please wait"); - unsigned long long int* wtf = (unsigned long long int*) malloc(size); + if (!(flags & BYTES_GIVEN)) { + fprintf(stderr, "argument -b is required!\n", optopt); + print_help(); + exit(1); + } - for (unsigned long long int i = 0; i < size / sizeof(long long int); i++) { - wtf[i] = 0x80085; - if (i > 0 && i % (1024 * 1024 * 1024 / sizeof(long long int)) == 0) printf("."); - } - printf("\n"); + adjust_by_denomination(&size, denominator); - printf("%d GiB (%llu bytes) of heap memory has been allocated. you are insane.\n", gib, size); - printf("press ENTER to release this memory, or CTRL+C to exit the program.\n"); + // even if the user doesn't specify a denomination, it still would be nice to display a truncated amount if available. + unsigned char* shorthand = get_shorthand(size); + if (!(flags & SILENT) && !(flags & BYPASS_WARN)) { + if (shorthand) { + printf("you are about to allocate %s (%llu bytes) of heap memory. are you sure? (y/N)\n> ", shorthand, size); + } else { + printf("you are about to allocate %llu byte%c of heap memory. are you sure? (y/N)\n> ", size, size == 1 ? 0 : 's'); + } - getchar(); + unsigned char input = getchar(); + if (input != 'y') exit(0); + while (getchar() != '\n'); + } - free(wtf); + unsigned long long int* heap = allocate_heap(size, flags & SILENT); + if (filename != NULL) save_heap(heap, size, filename, flags & SILENT); - return 0; + if (!(flags & SILENT)) { + if (shorthand) { + printf("%s (%llu bytes) of heap memory has been allocated. you are insane.\n", shorthand, size); + } else { + printf("%llu byte%c of heap memory ha%s been allocated. you are insane.\n", size, size == 1 ? 0 : 's', size == 1 ? "s" : "ve"); + } + free(shorthand); + + printf("press ENTER to release this memory, or CTRL+C to exit the program.\n"); + getchar(); + free(heap); + exit(0); + } + + free(heap); + return 0; } + +void print_help() { + printf("usage: allocatememory -b [-o ] [-s]\n\n"); + printf("OPTIONS\n"); + printf(" -h\tdisplays help\n"); + printf(" -b\tnumber of bytes to allocate (e.g. 1024, 1g, 64K)\n"); + printf(" -o\tfile to output to\n"); + printf(" -s\trun silently (requires -b and -o)\n"); + printf(" -w\tdisable warnings (\"i know what i'm doing!\")\n"); + exit(0); +} + +unsigned char* get_shorthand(unsigned long long int size) { + if (size < KiB) return 0; + + if (size > LOADS) { + return ">9999 TiB"; + } + + unsigned char* buffer = malloc(sizeof(char) * 12); + + if (size >= TiB) { + snprintf(buffer, 12, "%.2f TiB", (float) size / TiB); + return buffer; + } + if (size >= GiB) { + snprintf(buffer, 12, "%.2f GiB", (float) size / GiB); + return buffer; + } + if (size >= MiB) { + snprintf(buffer, 12, "%.2f MiB", (float) size / MiB); + return buffer; + } + if (size >= KiB) { + snprintf(buffer, 12, "%.2f KiB", (float) size / KiB); + return buffer; + } + + return 0; +} + +void adjust_by_denomination(unsigned long long int* size, char denomination) { + if (denomination >= 'a' && denomination <= 'z') denomination -= 32; + switch (denomination) { + case 'K': + *size *= KiB; + return; + case 'M': + *size *= MiB; + return; + case 'G': + *size *= GiB; + return; + case 'T': + *size *= TiB; + return; + } +} + +unsigned long long int* allocate_heap(unsigned long long int size, char silent) { + if (!silent) { + printf("please wait."); + fflush(stdout); + } + + unsigned long long int* heap = (unsigned long long int*) malloc(size); + + for (unsigned long long int i = 0; i < size / sizeof(long long int); i++) { + heap[i] = i; + if (!silent && i > 0 && i % (1024 * 1024 * 1024 / sizeof(long long int)) == 0) { + printf("."); + fflush(stdout); + } + } + if (!silent) printf("\n"); + + return heap; +} + +void save_heap(unsigned long long int* heap, unsigned long long int size, char* filename, char silent) { + FILE* file = fopen(filename, "wb"); + if (file == NULL) { + printf("failed to open %s!", filename); + exit(1); + } + fwrite(heap, sizeof(char), size, file); + fputs("\n", file); + fclose(file); +}