version 1.14, 2010/07/23 08:31:19 |
version 1.15, 2010/07/23 21:46:05 |
|
|
|
|
#define BUF_INCR 128 |
#define BUF_INCR 128 |
|
|
struct rcs_buf { |
struct buf { |
u_int cb_flags; |
u_int cb_flags; |
|
|
/* buffer handle, buffer size, and data length */ |
/* buffer handle, buffer size, and data length */ |
|
|
|
|
#define SIZE_LEFT(b) (b->cb_size - b->cb_len) |
#define SIZE_LEFT(b) (b->cb_size - b->cb_len) |
|
|
static void rcs_buf_grow(BUF *, size_t); |
static void buf_grow(BUF *, size_t); |
|
|
/* |
/* |
* rcs_buf_alloc() |
* buf_alloc() |
* |
* |
* Create a new buffer structure and return a pointer to it. This structure |
* Create a new buffer structure and return a pointer to it. This structure |
* uses dynamically-allocated memory and must be freed with rcs_buf_free(), |
* uses dynamically-allocated memory and must be freed with buf_free(), |
* once the buffer is no longer needed. |
* once the buffer is no longer needed. |
*/ |
*/ |
BUF * |
BUF * |
rcs_buf_alloc(size_t len, u_int flags) |
buf_alloc(size_t len, u_int flags) |
{ |
{ |
BUF *b; |
BUF *b; |
|
|
|
|
} |
} |
|
|
/* |
/* |
* rcs_buf_load() |
* buf_load() |
* |
* |
* Open the file specified by <path> and load all of its contents into a |
* Open the file specified by <path> and load all of its contents into a |
* buffer. |
* buffer. |
|
|
* Sets errno on error. |
* Sets errno on error. |
*/ |
*/ |
BUF * |
BUF * |
rcs_buf_load(const char *path, u_int flags) |
buf_load(const char *path, u_int flags) |
{ |
{ |
int fd; |
int fd; |
ssize_t ret; |
ssize_t ret; |
|
|
errno = EFBIG; |
errno = EFBIG; |
goto out; |
goto out; |
} |
} |
buf = rcs_buf_alloc(st.st_size, flags); |
buf = buf_alloc(st.st_size, flags); |
for (bp = buf->cb_buf; ; bp += (size_t)ret) { |
for (bp = buf->cb_buf; ; bp += (size_t)ret) { |
len = SIZE_LEFT(buf); |
len = SIZE_LEFT(buf); |
ret = read(fd, bp, len); |
ret = read(fd, bp, len); |
|
|
int saved_errno; |
int saved_errno; |
|
|
saved_errno = errno; |
saved_errno = errno; |
rcs_buf_free(buf); |
buf_free(buf); |
buf = NULL; |
buf = NULL; |
errno = saved_errno; |
errno = saved_errno; |
goto out; |
goto out; |
|
|
return (buf); |
return (buf); |
} |
} |
|
|
/* |
|
* rcs_buf_free() |
|
* |
|
* Free the buffer <b> and all associated data. |
|
*/ |
|
void |
void |
rcs_buf_free(BUF *b) |
buf_free(BUF *b) |
{ |
{ |
if (b->cb_buf != NULL) |
if (b->cb_buf != NULL) |
xfree(b->cb_buf); |
xfree(b->cb_buf); |
|
|
} |
} |
|
|
/* |
/* |
* rcs_buf_release() |
* buf_release() |
* |
* |
* Free the buffer <b>'s structural information but do not free the contents |
* Free the buffer <b>'s structural information but do not free the contents |
* of the buffer. Instead, they are returned and should be freed later using |
* of the buffer. Instead, they are returned and should be freed later using |
* free(). |
* free(). |
*/ |
*/ |
void * |
void * |
rcs_buf_release(BUF *b) |
buf_release(BUF *b) |
{ |
{ |
void *tmp; |
void *tmp; |
|
|
|
|
} |
} |
|
|
/* |
/* |
* rcs_buf_get() |
* buf_get() |
*/ |
*/ |
u_char * |
u_char * |
rcs_buf_get(BUF *b) |
buf_get(BUF *b) |
{ |
{ |
return (b->cb_buf); |
return (b->cb_buf); |
} |
} |
|
|
/* |
/* |
* rcs_buf_empty() |
* buf_empty() |
* |
* |
* Empty the contents of the buffer <b> and reset pointers. |
* Empty the contents of the buffer <b> and reset pointers. |
*/ |
*/ |
void |
void |
rcs_buf_empty(BUF *b) |
buf_empty(BUF *b) |
{ |
{ |
memset(b->cb_buf, 0, b->cb_size); |
memset(b->cb_buf, 0, b->cb_size); |
b->cb_len = 0; |
b->cb_len = 0; |
} |
} |
|
|
/* |
/* |
* rcs_buf_putc() |
* buf_putc() |
* |
* |
* Append a single character <c> to the end of the buffer <b>. |
* Append a single character <c> to the end of the buffer <b>. |
*/ |
*/ |
void |
void |
rcs_buf_putc(BUF *b, int c) |
buf_putc(BUF *b, int c) |
{ |
{ |
u_char *bp; |
u_char *bp; |
|
|
|
|
if (bp == (b->cb_buf + b->cb_size)) { |
if (bp == (b->cb_buf + b->cb_size)) { |
/* extend */ |
/* extend */ |
if (b->cb_flags & BUF_AUTOEXT) |
if (b->cb_flags & BUF_AUTOEXT) |
rcs_buf_grow(b, (size_t)BUF_INCR); |
buf_grow(b, (size_t)BUF_INCR); |
else |
else |
errx(1, "rcs_buf_putc failed"); |
errx(1, "buf_putc failed"); |
|
|
/* the buffer might have been moved */ |
/* the buffer might have been moved */ |
bp = b->cb_buf + b->cb_len; |
bp = b->cb_buf + b->cb_len; |
|
|
} |
} |
|
|
/* |
/* |
* rcs_buf_getc() |
* buf_getc() |
* |
* |
* Return u_char at buffer position <pos>. |
* Return u_char at buffer position <pos>. |
* |
* |
*/ |
*/ |
u_char |
u_char |
rcs_buf_getc(BUF *b, size_t pos) |
buf_getc(BUF *b, size_t pos) |
{ |
{ |
return (b->cb_buf[pos]); |
return (b->cb_buf[pos]); |
} |
} |
|
|
/* |
/* |
* rcs_buf_append() |
* buf_append() |
* |
* |
* Append <len> bytes of data pointed to by <data> to the buffer <b>. If the |
* Append <len> bytes of data pointed to by <data> to the buffer <b>. If the |
* buffer is too small to accept all data, it will attempt to append as much |
* buffer is too small to accept all data, it will attempt to append as much |
|
|
* Returns the number of bytes successfully appended to the buffer. |
* Returns the number of bytes successfully appended to the buffer. |
*/ |
*/ |
size_t |
size_t |
rcs_buf_append(BUF *b, const void *data, size_t len) |
buf_append(BUF *b, const void *data, size_t len) |
{ |
{ |
size_t left, rlen; |
size_t left, rlen; |
u_char *bp, *bep; |
u_char *bp, *bep; |
|
|
|
|
if (left < len) { |
if (left < len) { |
if (b->cb_flags & BUF_AUTOEXT) { |
if (b->cb_flags & BUF_AUTOEXT) { |
rcs_buf_grow(b, len - left); |
buf_grow(b, len - left); |
bp = b->cb_buf + b->cb_len; |
bp = b->cb_buf + b->cb_len; |
} else |
} else |
rlen = bep - bp; |
rlen = bep - bp; |
|
|
} |
} |
|
|
/* |
/* |
* rcs_buf_fappend() |
* buf_fappend() |
* |
* |
*/ |
*/ |
size_t |
size_t |
rcs_buf_fappend(BUF *b, const char *fmt, ...) |
buf_fappend(BUF *b, const char *fmt, ...) |
{ |
{ |
size_t ret; |
size_t ret; |
int n; |
int n; |
|
|
va_end(vap); |
va_end(vap); |
|
|
if (n == -1) |
if (n == -1) |
errx(1, "rcs_buf_fappend: failed to format data"); |
errx(1, "buf_fappend: failed to format data"); |
|
|
ret = rcs_buf_append(b, str, n); |
ret = buf_append(b, str, n); |
xfree(str); |
xfree(str); |
return (ret); |
return (ret); |
} |
} |
|
|
/* |
/* |
* rcs_buf_len() |
* buf_len() |
* |
* |
* Returns the size of the buffer that is being used. |
* Returns the size of the buffer that is being used. |
*/ |
*/ |
size_t |
size_t |
rcs_buf_len(BUF *b) |
buf_len(BUF *b) |
{ |
{ |
return (b->cb_len); |
return (b->cb_len); |
} |
} |
|
|
/* |
/* |
* rcs_buf_write_fd() |
* buf_write_fd() |
* |
* |
* Write the contents of the buffer <b> to the specified <fd> |
* Write the contents of the buffer <b> to the specified <fd> |
*/ |
*/ |
int |
int |
rcs_buf_write_fd(BUF *b, int fd) |
buf_write_fd(BUF *b, int fd) |
{ |
{ |
u_char *bp; |
u_char *bp; |
size_t len; |
size_t len; |
|
|
} |
} |
|
|
/* |
/* |
* rcs_buf_write() |
* buf_write() |
* |
* |
* Write the contents of the buffer <b> to the file whose path is given in |
* Write the contents of the buffer <b> to the file whose path is given in |
* <path>. If the file does not exist, it is created with mode <mode>. |
* <path>. If the file does not exist, it is created with mode <mode>. |
*/ |
*/ |
int |
int |
rcs_buf_write(BUF *b, const char *path, mode_t mode) |
buf_write(BUF *b, const char *path, mode_t mode) |
{ |
{ |
int fd; |
int fd; |
open: |
open: |
|
|
err(1, "%s", path); |
err(1, "%s", path); |
} |
} |
|
|
if (rcs_buf_write_fd(b, fd) == -1) { |
if (buf_write_fd(b, fd) == -1) { |
(void)unlink(path); |
(void)unlink(path); |
errx(1, "rcs_buf_write: rcs_buf_write_fd: `%s'", path); |
errx(1, "buf_write: buf_write_fd: `%s'", path); |
} |
} |
|
|
if (fchmod(fd, mode) < 0) |
if (fchmod(fd, mode) < 0) |
|
|
} |
} |
|
|
/* |
/* |
* rcs_buf_write_stmp() |
* buf_write_stmp() |
* |
* |
* Write the contents of the buffer <b> to a temporary file whose path is |
* Write the contents of the buffer <b> to a temporary file whose path is |
* specified using <template> (see mkstemp.3). NB. This function will modify |
* specified using <template> (see mkstemp.3). NB. This function will modify |
* <template>, as per mkstemp |
* <template>, as per mkstemp |
*/ |
*/ |
void |
void |
rcs_buf_write_stmp(BUF *b, char *template) |
buf_write_stmp(BUF *b, char *template) |
{ |
{ |
int fd; |
int fd; |
|
|
|
|
|
|
worklist_add(template, &temp_files); |
worklist_add(template, &temp_files); |
|
|
if (rcs_buf_write_fd(b, fd) == -1) { |
if (buf_write_fd(b, fd) == -1) { |
(void)unlink(template); |
(void)unlink(template); |
errx(1, "rcs_buf_write_stmp: rcs_buf_write_fd: `%s'", template); |
errx(1, "buf_write_stmp: buf_write_fd: `%s'", template); |
} |
} |
|
|
(void)close(fd); |
(void)close(fd); |
} |
} |
|
|
/* |
/* |
* rcs_buf_grow() |
* buf_grow() |
* |
* |
* Grow the buffer <b> by <len> bytes. The contents are unchanged by this |
* Grow the buffer <b> by <len> bytes. The contents are unchanged by this |
* operation regardless of the result. |
* operation regardless of the result. |
*/ |
*/ |
static void |
static void |
rcs_buf_grow(BUF *b, size_t len) |
buf_grow(BUF *b, size_t len) |
{ |
{ |
b->cb_buf = xrealloc(b->cb_buf, 1, b->cb_size + len); |
b->cb_buf = xrealloc(b->cb_buf, 1, b->cb_size + len); |
b->cb_size += len; |
b->cb_size += len; |