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()
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(); }