int rrnx_fr_buffer(rrnx_filereader *reader) {
	if (reader->fp == NULL) {
		// No open file
		return errmsg_none(reader, RRNX_E_NOFILE);
	}

	// Attempt reading from the file
	reader->len = fread(
	    reader->buffer, 1, reader->buffer_size, reader->fp);

	// Reset the current head location
	reader->at = 0;

	// fread() returns zero when eof or error.
	if (reader->len == 0) {
		// Is it error or eof?

		if (ferror(reader->fp)) {
			// Error
			errmsg_syscall(reader, errno,
			    "fread() failed: ");
			    //"%s:%d: fread() failed: ",
			    //reader->filename, reader->row);
		} else {
			// Eof; nothing to buffer.
			errmsg_none(reader, RRNX_E_EOF);
		} // if-else
	} else {
		noerr(reader);
	} // if-else: error or eof

	return reader->err;
}
int rrnx_fr_set_filename(
    rrnx_filereader *reader,
    const char *filename
) {
	noerr(reader);

	if (reader->filename != NULL) {
		// Free previous
		free(reader->filename);
		reader->filename = NULL;
	}

	if (filename != NULL) {
		// Attempt allocation
		int len = strlen(filename);
		reader->filename = malloc(len);
		if (reader->filename != NULL) {
			// Memory allocation succeeded. Copy
			strncpy(reader->filename, filename, len);
		} else {
			// Memory allocation failed.
			errmsg_none(reader, RRNX_E_NOMEM);
		} // if-else
	}

	return reader->err;
}
int rrnx_fr_fclose(rrnx_filereader *reader) {
	noerr(reader);

	if (reader->fp != NULL) {
		int errnum = fclose_silently(reader);

		if (errnum != 0) {
			errmsg_syscall(reader, errnum,
			    "%s: fclose() failed: ", reader->filename);
		} // if: error

		// Free file name, if any.
		rrnx_fr_set_filename(reader, NULL);
	} // if

	return reader->err;
} // rrnx_fr_fclose()
int rrnx_fr_fopen(rrnx_filereader *reader, const char *filename) {
	// Reset error
	noerr(reader);

	if (reader->fp != NULL) {
		// Already file open
		return errmsg(reader, RRNX_E_HASFILE,
		    "%s: cannot open, because previous file (%s) is still open",
		    filename, reader->filename);
	} // if: file already open

	// Attempt opening a stream for the file
	reader->fp = fopen(filename, "r");

	// Inspect result
	if (reader->fp == NULL) {
		// fopen failed
		return errmsg_syscall(reader, errno,
		    "%s: fopen() failed: ", filename);
	} // if: fopen failed

	// File opened succesfully.

	// Reset locational info.
	reader->row = 0;
	reader->col = 0;
	// Reset valid buffer length and head position
	reader->len = 0;
	reader->at = 0;

	// Remember the file name
	rrnx_fr_set_filename(reader, filename);
	if (reader->err) {
		// Memory allocation failed. Abort.
		// Silently close the file
		fclose_silently(reader);
		// Error is propagated upwards.
	}

	return reader->err;
}
int rrnx_fr_unbind(rrnx_filereader *reader) {
	if (reader->fp != NULL) {
                // Remove handle
                reader->fp = NULL;

                // Free file name, if any
		rrnx_fr_set_filename(reader, NULL);

                // Reset location
                reader->row = 0;
                reader->col = 0;

		// Reset head location and valid buffer length
                reader->at = 0;
                reader->len = 0;
	} else {
		// Already unbound, do nothing
	} // if-else

	return noerr(reader);
}
int rrnx_fr_set_buffer_size(rrnx_filereader *reader, int size) {
	void *newptr = realloc(reader->buffer, size);

	if (newptr != NULL) {
		// Allocation succeeded.

		// Update buffer info
		reader->buffer = newptr;
		reader->buffer_size = size;
		// Reset head and valid length
		reader->len = 0;
		reader->at = 0;

		noerr(reader);
	} else {
		// Allocation failed
		errmsg_none(reader, RRNX_E_NOMEM);
	}

	return reader->err;
}
int rrnx_fr_bind(rrnx_filereader *reader, FILE *fp) {
	if (reader->fp != NULL) {
		// Already file open
		return errmsg(reader, RRNX_E_HASFILE,
		    "bind error: previous file (%s) is still open",
		    reader->filename);
	} // if: file already open

	// Binding
	reader->fp = fp;

	// Leave filename unset

	// Reset locational info
	reader->row = 0;
	reader->col = 0;

	// Reset head location and valid buffer length
	reader->at = 0;
	reader->len = 0;

	return noerr(reader);
}
/**
 * Returns:
 * reader->err
 */
int rrnx_fr_readchar(rrnx_filereader *reader, char *dest) {
	// Buffer consumed?
	if (reader->at == reader->len) {
		// Fill buffer with new data. This updated reader->len.
		rrnx_fr_buffer(reader);

		if (reader->err) {
			// Buffering failed; error or eof.
			// Propagate error upwards.
			return reader->err;
		}
	}

	// Otherwise consume a char from the buffer.
	char c = reader->buffer[reader->at];
	reader->at++;

	// Store result
	*dest = c;

	// Update textual location?

	return noerr(reader);
}
/**
 * Possible errors:
 *     RRNX_E_OK        - No error; line was succesfully read
 *     RRNX_E_EOF       - End-of-file
 *     RRNX_E_OVERFLOW  - Current line was too long for the buffer
 *     RRNX_E_SYSCALL   - fread() failed during buffering
 */
int rrnx_fr_readline(
    rrnx_filereader *reader,
    char *dest,
    size_t maxlen
) {
	char c; // current char
	unsigned int i; // writing position
	unsigned int overflow = 0;

	maxlen--; // account for the '\0' terminator which is always added
	i = 0;

	// Advance textual location
	reader->row++;
	reader->col = 0;

	do {
		rrnx_fr_readchar(reader, &c);

		if ((reader->err == RRNX_E_EOF) && (i > 0)) {
			// Eof reached with data.
			// Reinterpret as end-of-line, and reset error.
			noerr(reader);
			break;
		} else if (reader->err) {
			// Error. Propagate upwards.
			break;
		}

		if (c == '\n') {
			// Newline. Stop here
			break;
		}
		else if (c == '\r') {
			// Carriage return; ignore.
		}
		else {
			// Advance textual location within the row
			reader->col++;

			// Append char if there's space left
			if (i < maxlen) {
				dest[i] = c;
				i++;
			} else {
				// Mark overflow, but continue reading.
				overflow = 1;
			}
		}
	} while (1);

	// Finish destination string, always.
	dest[i] = '\0';

	// Examine the state
	// error, eof, overflow or ok?
	if (reader->err) {
		// Has error
	}
	else if (overflow) {
		// No error, but overflow
		errmsg(reader, RRNX_E_OVERFLOW,
		    "Line too long (%d chars, while %d expected at most)",
		    reader->col, maxlen);
		    //"%s:%d: line too long (%d chars, while %d expected at most)",
		    //reader->filename, reader->row, reader->col, maxlen);
	}
	else {
		// No error, no overflow; success!
                noerr(reader);
	}

	return reader->err;
} // rrnx_fr_readline()
Exemple #10
0
int main(void)
{
	plan_tests(37);

	ok1(rszshm_mk(NULL, 0, NULL) == NULL && errno == EINVAL);

	struct rszshm s, t;
	ok1(rszshm_mk(&s, 0, NULL) == NULL && errno == EINVAL);

	ok1(rszshm_mk(&s, 4096, longstr) == NULL && errno == EINVAL);

	fail_mmap_anon = 1;
	ok1(rszshm_mk(&s, 4096, NULL) == NULL && errno == 9010);
	rszshm_rm(&s);
	fail_mmap_anon = 0;

	fail_open = 1;
	ok1(rszshm_mk(&s, 4096, NULL) == NULL && errno == 9005);
	rszshm_rm(&s);
	fail_open = 0;

	fail_ftruncate = 1;
	ok1(rszshm_mk(&s, 4096, NULL) == NULL && errno == 9002);
	rszshm_rm(&s);
	fail_ftruncate = 0;

	fail_mmap_fixed = 1;
	ok1(rszshm_mk(&s, 4096, NULL) == NULL && errno == 9011);
	rszshm_rm(&s);
	fail_mmap_fixed = 0;

	fail_msync = 1;
	ok1(rszshm_mk(&s, 4096, NULL) == NULL && errno == 9003);
	rszshm_rm(&s);
	fail_msync = 0;

	ok1(rszshm_mk(&s, 4096, NULL) != NULL);

	struct rszshm_scan scan = RSZSHM_DFLT_SCAN;
	scan.iter = 1;
	ok1(rszshm_mk(&t, 4096, NULL, scan) == NULL && errno == ENOSPC);

	ok1(rszshm_dt(&s) == 0);
	ok1(rszshm_rm(&s) == 0);

	long pgsz = sysconf(_SC_PAGE_SIZE);
	scan.len = UINT64_MAX - pgsz;
	ok1(rszshm_mk(&t, 4096, NULL, scan) == NULL && errno == ENOMEM);

	ok1(rszshm_mk(&t, 4096, "foo/bar_XXXXXX/0") == NULL && errno == ENOENT);

	struct rszshm *r;
	ok1(rszshm_mkm(r, 4096, NULL) != NULL);

	pid_t p, *pp;
	noerr(p = fork());
	char *fname = strdupa(r->fname);
	if (p)
		waitpid(p, NULL, 0);
	else {
		ok1(rszshm_free(r) == 0);

		struct rszshm *q;
		ok1(rszshm_atm(q, fname) != NULL);

		*((pid_t *) q->dat) = getpid();

		ok1(rszshm_up(q) == 0);
		ok1(rszshm_grow(q) == 1);
		ok1(rszshm_free(q) == 0);
		exit(0);
	}
	pp = (pid_t *) r->dat;
	ok1(p == *pp);

	fail_mmap_fixed = 1;
	ok1(rszshm_up(r) == -1 && errno == 9011);
	fail_mmap_fixed = 0;

	ok1(rszshm_grow(r) == 1);

	ok1(rszshm_dt(r) == 0);

	sa.sa_handler = segvjmp;
	sa.sa_flags = SA_RESETHAND;
	sigemptyset(&sa.sa_mask);
	sigaction(SIGSEGV, &sa, NULL);
	if (setjmp(j) == 0)
		fail("still mapped after detach: %d", *pp);
	else
		pass("access after detach gives segv, OK!");

	ok1(rszshm_at(r, longstr) == NULL && errno == EINVAL);

	fail_open = 1;
	ok1(rszshm_at(r, fname) == NULL && errno == 9005);
	fail_open = 0;

	fail_read = 1;
	ok1(rszshm_at(r, fname) == NULL && errno == 9006);
	fail_read = 0;

	short_read = 1;
	ok1(rszshm_at(r, fname) == NULL && errno == ENODATA);
	short_read = 0;

	fail_mmap_anon = 1;
	ok1(rszshm_at(r, fname) == NULL && errno == 9010);
	fail_mmap_anon = 0;

	bad_mmap_addr = 1;
	ok1(rszshm_at(r, fname) == NULL && errno == ENOSPC);
	bad_mmap_addr = 0;

	fail_mmap_fixed = 1;
	ok1(rszshm_at(r, fname) == NULL && errno == 9011);
	fail_mmap_fixed = 0;

	ok1(rszshm_at(r, fname) != NULL);
	ok1(p == *pp);

	struct rszshm_hdr save = *r->hdr;
	r->hdr->flen = r->flen;
	r->hdr->max  = r->flen;
	ok1(rszshm_grow(r) == -1 && errno == ENOMEM);
	*r->hdr = save;

	fail_flock = 1;
	ok1(rszshm_grow(r) == -1 && errno == 9001);
	fail_flock = 0;

	fail_ftruncate = 1;
	ok1(rszshm_grow(r) == -1 && errno == 9002);
	fail_ftruncate = 0;

	ok1(rszshm_grow(r) == 1);
	ok1(rszshm_dt(r) == 0);
	ok1(rszshm_rm(r) == 0);

	r->fname[0] = '\0';
	ok1(rszshm_rmdir(r) == -1 && errno == ENOTDIR);

	ok1(rszshm_free(r) == 0);

	return exit_status();
}