/** This is a test for `min_array.h`: takes an arbitrary stream, (Cntl-d stops in some implementations of interactive terminals,) and greedily extracts integers in the style of `strtol` until it gets to the end-of-file or a null-terminator. */ #include /* size_t EXIT_ strtol */ #include /* FILE fopen fclose fread [f]printf ferror perror */ #include /* strpbrk */ #include /* errno */ #include /* isdigit */ #include /* LONG_ INT_ _MIN _MAX */ #include /* assert */ #include "../src/min_array.h" struct num { size_t line; int num; }; MIN_ARRAY(char, char) MIN_ARRAY(num, struct num) /** Reads the contents of `fp` after the file pointer and appends them to `string`; adds a null-terminator. Does not check for nulls in `fp` or `string`. @return Success, otherwise `string` may have read a partial read and may not be terminated. @throws[fread, malloc] */ static int fp_to_str(FILE *const fp, struct char_array *const string) { const size_t granularity = 1024; size_t nread; char *cursor; assert(fp && string); do if(!(cursor = char_array_buffer(string, granularity)) || !char_array_append(string, nread = fread(cursor, 1, granularity, fp))) return 0; while(nread == granularity); assert(nread < granularity); if(ferror(fp) || !(cursor = char_array_new(string))) return 0; *cursor = '\0'; return 1; } /** Stores the entire stream and then stores the extracted `int` numbers. */ int main(void) { int success = EXIT_FAILURE; struct char_array str = MIN_ARRAY_IDLE; struct num_array nums = MIN_ARRAY_IDLE; struct num *num; long big_num; char *a, *anum = 0; size_t i, line = 1 /* Unix: delimited by '\n'. */; errno = 0; /* In case we are running it as part of another editor. */ if(!fp_to_str(stdin, &str)) goto catch; /* It would be conceivable use the length to continue past the first sentinel '\0', but not that complex. */ fprintf(stderr, "Read:\n<<<%s>>>\n", str.data); for(a = str.data; a = strpbrk(a, "-0123456789\n"); ) { if(*a == '\n') { line++; a++; continue; } if(*a == '-') { anum = a++; continue; } if(!anum || anum != a - 1) anum = a; /* Wasn't negative. */ big_num = strtol(anum, &a, 0); if((!big_num || big_num == LONG_MIN || big_num == LONG_MAX) && errno) goto catch; /* Long conversion failed, (not all platforms.) */ if(big_num < INT_MIN || big_num > INT_MAX) { errno = ERANGE; goto catch; } if(!(num = num_array_new(&nums))) goto catch; num->line = line; num->num = (int)big_num; } fprintf(stderr, "Extracted:\n"); for(i = 0; i < nums.size; i++) printf("Line %lu: %d\n", (unsigned long)nums.data[i].line, nums.data[i].num); success = EXIT_SUCCESS; goto finally; catch: fprintf(stderr, "Line %lu ", (unsigned long)line), perror("stdin"); finally: char_array_(&str); num_array_(&nums); return success; }