#include #include #include #include #include #include "intmath.h" int tests_run = 0; int tests_failed = 0; struct Config { int precision; bool human_readable; }; typedef struct Config Config; struct Result { bool success; void* result; }; typedef struct Result Result; Result parse_config(int argc, char* argv[]) { Result res; res.success = false; Config tmp; tmp.precision = 0; tmp.human_readable = false; size_t i = 1; char* argument; char* precision = NULL; while (i < argc) { argument = argv[i]; int comp1 = strcmp(argument, "--precision") == 0; if ( comp1 || strncmp(argument, "-p", 2) == 0 ) { if (precision != NULL) { char* error_msg = malloc(44); snprintf( error_msg, 44, "precision can't be specified multiple times" ); res.result = error_msg; return res; } i++; if (strlen(argument) != 2 && !comp1) { precision = argument + 2; continue; } if (i == argc) { char* error_msg = malloc(57); snprintf( error_msg, 57, "`%s` should be followed by an integer argument", argument ); res.result = error_msg; return res; } precision = argv[i]; } else if ( strcmp(argument, "--human-readable") == 0 || strcmp(argument, "-h") == 0 ) { if (tmp.human_readable != false) { char* error_msg = malloc(52); snprintf( error_msg, 52, "human readability can't be specified multiple times" ); res.result = error_msg; return res; } tmp.human_readable = true; } else { size_t msg_size = 21 + strlen(argument); char* error_msg = malloc(msg_size); snprintf( error_msg, msg_size, "unknown argument: `%s`", argument ); res.result = error_msg; return res; } i++; } if (precision != NULL) { char* endptr; errno = 0; tmp.precision = (int) strtol(precision, &endptr, 10); if (errno != 0) { char* error_msg = malloc(64); char* errno_str = strerror(errno); snprintf( error_msg, 64, "invalid precision: %s", errno_str ); free(errno_str); res.result = error_msg; return res; } if (*endptr != '\0') { char* error_msg = malloc(53); snprintf( error_msg, 53, "the precision may not contain non-numeric characters", precision ); res.result = error_msg; return res; } if (tmp.precision <= 0) { char* error_msg = malloc(50); snprintf( error_msg, 50, "the precision can't be less than or equal to zero" ); res.result = error_msg; return res; } } Config* conf = malloc(sizeof(int) + sizeof(bool)); conf->precision = tmp.precision; conf->human_readable = tmp.human_readable; res.success = true; res.result = conf; return res; } int main (int argc, char* argv[]) { Result res = parse_config(argc, argv); if (res.success == false) { char* err_msg = (char*) res.result; fprintf( stderr, "Error parsing command line: %s\n", err_msg ); return 1; } Config* conf = (Config*) res.result; int precision = conf->precision; bool human_readable = conf->human_readable; printf("precision: %d\n", precision); if (human_readable) printf("human readable\n"); unsigned int base = 10; if (human_readable && precision == 0) { precision = 1; base = 1024; } int blocksize = 1; size_t bufsize = 1; unsigned int bytes_read = 0; size_t new_read_bytes = 0; if (precision != 0) { blocksize = exp_notated_to_int(int_ceiled_exponent_notation_base( bytes_read + 1, precision, base)) - bytes_read; bufsize = 1024; } size_t max_bufsize = 1048576; char* buf = malloc(bufsize); char* tmpbuf; while (1) { /* output */ printf("\r%u", bytes_read); if (fflush(stdin) == EOF) { printf("\n"); perror("error during fflush"); return 1; } /* reading */ new_read_bytes = fread( buf, 1, int_min(blocksize, bufsize)/* + (blocksize == 0)*/, stdin ); if (new_read_bytes == 0) { int err = ferror(stdin); if (err != 0) { printf("\n"); fprintf(stderr, "error reading stdin"); return err; } break; } bytes_read += new_read_bytes; /* resizing buffer and blocksize to read as much as possible * at once */ if (precision == 0) continue; blocksize = exp_notated_to_int(int_ceiled_exponent_notation_base( bytes_read + 1, precision, base)) - bytes_read; if (blocksize > bufsize) { tmpbuf = malloc(bufsize * 2); if (tmpbuf == NULL) { free(tmpbuf); } else { free(buf); buf = tmpbuf; bufsize *= 2; } } } printf("\n"); return 0; }