min_array/test/test_array.c

77 lines
2.8 KiB
C
Raw Normal View History

2021-03-21 19:45:06 +00:00
/** This is a test for `min_array.h`: takes an arbitrary stream, (Cntl-d stops
2021-03-21 19:52:45 +00:00
in some implementations of interactive terminals,) and greedily extracts
2021-03-21 19:45:06 +00:00
integers in the style of `strtol` until it gets to the end-of-file or a
null-terminator. */
#include <stdlib.h> /* size_t EXIT_ strtol */
#include <stdio.h> /* FILE fopen fclose fread [f]printf ferror perror */
2021-08-29 19:58:17 +00:00
#include <string.h> /* strpbrk */
2021-03-21 18:11:08 +00:00
#include <errno.h> /* errno */
#include <ctype.h> /* isdigit */
#include <limits.h> /* LONG_ INT_ _MIN _MAX */
#include <assert.h> /* assert */
2021-03-21 20:22:06 +00:00
#include "../src/min_array.h"
struct num { size_t line; int num; };
2021-03-21 18:11:08 +00:00
MIN_ARRAY(char, char)
2021-03-21 20:22:06 +00:00
MIN_ARRAY(num, struct num)
2021-03-21 18:11:08 +00:00
2021-08-29 18:49:27 +00:00
/** 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`.
2021-03-21 22:13:25 +00:00
@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) {
2021-03-21 18:11:08 +00:00
const size_t granularity = 1024;
size_t nread;
char *cursor;
assert(fp && string);
2021-08-29 18:49:27 +00:00
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);
2021-03-21 18:11:08 +00:00
if(ferror(fp) || !(cursor = char_array_new(string))) return 0;
*cursor = '\0';
return 1;
}
2021-03-21 19:45:06 +00:00
/** Stores the entire stream and then stores the extracted `int` numbers. */
2021-03-21 18:11:08 +00:00
int main(void) {
int success = EXIT_FAILURE;
struct char_array str = MIN_ARRAY_IDLE;
struct num_array nums = MIN_ARRAY_IDLE;
2021-03-21 20:22:06 +00:00
struct num *num;
2021-03-21 18:11:08 +00:00
long big_num;
char *a, *anum = 0;
2021-03-21 19:45:06 +00:00
size_t i, line = 1 /* Unix: delimited by '\n'. */;
2021-03-21 18:11:08 +00:00
errno = 0; /* In case we are running it as part of another editor. */
2021-03-21 22:13:25 +00:00
if(!fp_to_str(stdin, &str)) goto catch;
2021-03-21 19:45:06 +00:00
/* 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; }
2021-03-21 18:11:08 +00:00
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)
2021-03-21 19:45:06 +00:00
goto catch; /* Long conversion failed, (not all platforms.) */
2021-03-21 18:11:08 +00:00
if(big_num < INT_MIN || big_num > INT_MAX)
{ errno = ERANGE; goto catch; }
2021-03-21 23:17:10 +00:00
if(!(num = num_array_new(&nums))) goto catch;
2021-03-21 20:22:06 +00:00
num->line = line;
num->num = (int)big_num;
2021-03-21 18:11:08 +00:00
}
2021-03-21 19:45:06 +00:00
fprintf(stderr, "Extracted:\n");
2021-03-21 20:22:06 +00:00
for(i = 0; i < nums.size; i++) printf("Line %lu: %d\n",
(unsigned long)nums.data[i].line, nums.data[i].num);
2021-03-21 18:11:08 +00:00
success = EXIT_SUCCESS;
goto finally;
catch:
2021-03-21 20:22:06 +00:00
fprintf(stderr, "Line %lu ", (unsigned long)line), perror("stdin");
2021-03-21 18:11:08 +00:00
finally:
char_array_(&str);
num_array_(&nums);
return success;
}