178 lines
2.9 KiB
C
178 lines
2.9 KiB
C
/*++
|
|
|
|
This file contains stuff for buffering input and output. We use
|
|
this buffering to allow us to deal with end-of-media conditions
|
|
on input or output streams.
|
|
|
|
Warning: at this time, these buffers don't get flushed automatically
|
|
on exit; bclose() must be called.
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "buf.h"
|
|
|
|
extern char *progname;
|
|
|
|
static PBUF balloc(void);
|
|
static void bfree(PBUF);
|
|
|
|
//
|
|
// Create a new buffer and associate it with a file. If the file
|
|
// can't be opened, return NULL.
|
|
//
|
|
PBUF
|
|
bopen(const char *file, int mode)
|
|
{
|
|
PBUF pb;
|
|
|
|
pb = balloc();
|
|
|
|
if (-1 == (pb->fd = open(file, mode, 0666))) {
|
|
fprintf(stderr, "%s: open: ", progname);
|
|
perror(file);
|
|
exit(1);
|
|
}
|
|
pb->mode = mode;
|
|
pb->count = 0;
|
|
pb->offset = 0;
|
|
|
|
return pb;
|
|
}
|
|
|
|
//
|
|
// Same as bopen, but from a file descriptor.
|
|
//
|
|
PBUF
|
|
bfdopen(int fd, int mode)
|
|
{
|
|
PBUF pb;
|
|
|
|
pb = balloc();
|
|
|
|
pb->fd = fd;
|
|
pb->mode = mode;
|
|
pb->count = 0;
|
|
pb->offset = 0;
|
|
|
|
return pb;
|
|
}
|
|
|
|
void
|
|
bclose(PBUF pb)
|
|
{
|
|
if (pb->mode & O_WRONLY && pb->offset != 0) {
|
|
bflush(pb);
|
|
}
|
|
(void)close(pb->fd);
|
|
bfree(pb);
|
|
}
|
|
|
|
int
|
|
bgetc(PBUF pb)
|
|
{
|
|
if (pb->offset == pb->count) {
|
|
bfill(pb);
|
|
}
|
|
|
|
// We don't worry about reaching EOF here; the caller has to
|
|
// know how many bytes are available and read only that many,
|
|
|
|
return pb->data[pb->offset++];
|
|
}
|
|
|
|
void
|
|
bputc(PBUF pb, int c)
|
|
{
|
|
pb->data[pb->offset++] = (char)c;
|
|
if (sizeof(pb->data) == ++pb->count) {
|
|
bflush(pb);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set a buffer back to the beginning; that is, the next character
|
|
// read will be the first one. Could be used on write buffers as well,
|
|
// but not as likely.
|
|
//
|
|
void
|
|
brewind(PBUF pb)
|
|
{
|
|
pb->offset = 0;
|
|
}
|
|
|
|
//
|
|
// balloc --
|
|
// Allocate and initialize a buffer. A pointer to the new buffer
|
|
// is returned. We set fd to -1 to help find out if people are
|
|
// writing to a buffer before opening it.
|
|
//
|
|
static PBUF
|
|
balloc()
|
|
{
|
|
PBUF pb;
|
|
|
|
if (NULL == (pb = malloc(sizeof(BUF)))) {
|
|
fprintf(stderr, "%s: malloc: virtual memory exhausted\n",
|
|
progname);
|
|
exit(4);
|
|
}
|
|
return pb;
|
|
}
|
|
|
|
static void
|
|
bfree(PBUF pb)
|
|
{
|
|
free(pb);
|
|
}
|
|
|
|
//
|
|
// write the contents of a buffer, dealing with end-of-media, if necessary.
|
|
//
|
|
void
|
|
bflush(PBUF pb)
|
|
{
|
|
int nbyte;
|
|
|
|
nbyte = write(pb->fd, pb->data, sizeof(pb->data));
|
|
if (-1 == nbyte) {
|
|
if (ENOSPC == errno) {
|
|
// end-of-media; do something about it.
|
|
} else {
|
|
fprintf(stderr, "%s: ", progname);
|
|
perror("write");
|
|
exit(1);
|
|
}
|
|
}
|
|
pb->count = 0;
|
|
pb->offset = 0;
|
|
}
|
|
|
|
//
|
|
// fill a buffer with data, dealing with end-of-media, if necessary.
|
|
//
|
|
void
|
|
bfill(PBUF pb)
|
|
{
|
|
int nbyte;
|
|
|
|
nbyte = read(pb->fd, pb->data, sizeof(pb->data));
|
|
if (-1 == nbyte) {
|
|
fprintf(stderr, "%s: ", progname);
|
|
perror("read");
|
|
exit(2);
|
|
}
|
|
if (0 == nbyte) {
|
|
// we have reached the end of file. Give user opportunity
|
|
// to replace the media, and fill the rest of this
|
|
// buffer XXX.mjb
|
|
return;
|
|
}
|
|
pb->count = nbyte;
|
|
pb->offset = 0;
|
|
}
|