parent
9ff2ebbffa
commit
d38cbcc0c6
@ -0,0 +1,239 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 03/2010 by Olaf Rempel *
|
||||
* razzor@kopf-tisch.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; version 2 of the License *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "linebuffer.h"
|
||||
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
struct lbuf {
|
||||
size_t size;
|
||||
size_t pos;
|
||||
|
||||
char *token;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* creates linebuffer with given size
|
||||
*/
|
||||
struct lbuf * lbuf_create(size_t size)
|
||||
{
|
||||
struct lbuf *buf = malloc(sizeof(struct lbuf) + size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
buf->size = size;
|
||||
buf->pos = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* frees the linebuffer and all data in it
|
||||
*/
|
||||
void lbuf_free(struct lbuf *buf)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* clears the linebuffer
|
||||
* - returns the datasize it was holding
|
||||
*/
|
||||
int lbuf_clear(struct lbuf *buf)
|
||||
{
|
||||
int oldpos = buf->pos;
|
||||
buf->pos = 0;
|
||||
return oldpos;
|
||||
}
|
||||
|
||||
/*
|
||||
* get pointer to internal data
|
||||
* - returns pointer to datasize
|
||||
*/
|
||||
char * lbuf_getdata(struct lbuf *buf, size_t *len)
|
||||
{
|
||||
if (len != NULL)
|
||||
*len = buf->pos;
|
||||
|
||||
return buf->data;
|
||||
}
|
||||
|
||||
/*
|
||||
* appends data to the buffer
|
||||
* - returns the number of bytes copied
|
||||
*/
|
||||
int lbuf_append(struct lbuf *buf, const char *src, size_t size)
|
||||
{
|
||||
int len = MIN(buf->size - buf->pos, size);
|
||||
memcpy(buf->data + buf->pos, src, len);
|
||||
buf->pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* reads as much data as it can get from a FD
|
||||
* - returns the number of bytes read, or -1 on error
|
||||
*/
|
||||
int lbuf_readfd(struct lbuf *buf, int fd)
|
||||
{
|
||||
int len = read(fd, buf->data + buf->pos, buf->size - buf->pos);
|
||||
if (len <= 0)
|
||||
return -1;
|
||||
|
||||
buf->pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* parses as much data as it can get from a FD
|
||||
* parses means: backspaces remove one byte from the end of the buffer
|
||||
* - returns 0 on success, or -1 on error
|
||||
*/
|
||||
int lbuf_parsefd(struct lbuf *buf, int fd)
|
||||
{
|
||||
char tmp[32];
|
||||
int len = read(fd, tmp, sizeof(tmp));
|
||||
if (len <= 0)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
/* "understand" backspace */
|
||||
if (tmp[i] == 0x08 && buf->pos > 0) {
|
||||
buf->pos--;
|
||||
|
||||
/* copy */
|
||||
} else if (tmp[i] >= ' ' || tmp[i] == '\n') {
|
||||
*(buf->data + buf->pos++) = tmp[i];
|
||||
}
|
||||
|
||||
if (buf->pos > buf->size)
|
||||
return -1;
|
||||
}
|
||||
/* TODO: return bytes appended to buffer? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* writes as much data as it can to a FD
|
||||
* - returns the number of bytes written, or -1 on error
|
||||
*/
|
||||
int lbuf_writefd(struct lbuf *buf, int fd)
|
||||
{
|
||||
int len = write(fd, buf->data, buf->pos);
|
||||
if (len <= 0)
|
||||
return -1;
|
||||
|
||||
/* handle partial writes */
|
||||
if (len != buf->pos)
|
||||
memmove(buf->data, buf->data + len, buf->pos - len);
|
||||
|
||||
buf->pos -= len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* append va_list to buffer
|
||||
* - returns number ob bytes appended, or -1 on error
|
||||
*/
|
||||
int lbuf_vprintf(struct lbuf *buf, const char *fmt, va_list az)
|
||||
{
|
||||
int len = vsnprintf(buf->data + buf->pos, buf->size - buf->pos, fmt, az);
|
||||
if (len < 0 || len >= (buf->size - buf->pos))
|
||||
return -1;
|
||||
|
||||
buf->pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* printf into buffer
|
||||
* - returns number of bytes appended, or -1 on error
|
||||
*/
|
||||
int lbuf_printf(struct lbuf *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list az;
|
||||
|
||||
va_start(az, fmt);
|
||||
int ret = lbuf_vprintf(buf, fmt, az);
|
||||
va_end(az);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* get next non-empty token
|
||||
* - returns pointer to next token
|
||||
* - returns NULL if no delimter is found in buffer
|
||||
*/
|
||||
char * lbuf_gettok(struct lbuf *buf, const char *delim)
|
||||
{
|
||||
char *start = buf->data;
|
||||
char *end = buf->data + buf->pos;
|
||||
int dlen = strlen(delim);
|
||||
|
||||
while (1) {
|
||||
buf->token = NULL;
|
||||
|
||||
/* find first delimiter in buffer */
|
||||
int i;
|
||||
for (i = 0; i < dlen; i++) {
|
||||
char *tok = memchr(start, delim[i], end - start);
|
||||
if (tok != NULL && (tok < buf->token || buf->token == NULL))
|
||||
buf->token = tok;
|
||||
}
|
||||
|
||||
/* nothing found */
|
||||
if (buf->token == NULL)
|
||||
return NULL;
|
||||
|
||||
/* delimter found on start pos -> skip empty token */
|
||||
if (buf->token == start) {
|
||||
start++;
|
||||
if (start >= end)
|
||||
return NULL;
|
||||
} else {
|
||||
/* non-empty token found, exit */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* overwrite token, return start ptr */
|
||||
*(buf->token) = '\0';
|
||||
return start;
|
||||
}
|
||||
|
||||
/*
|
||||
* release previous fetched line
|
||||
* - returns number of remaining bytes in buffer
|
||||
*/
|
||||
int lbuf_freetok(struct lbuf *buf)
|
||||
{
|
||||
if (buf->token != NULL) {
|
||||
buf->pos -= (buf->token - buf->data) +1;
|
||||
memmove(buf->data, buf->token +1, buf->pos);
|
||||
buf->token = NULL;
|
||||
}
|
||||
return buf->pos;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
#ifndef _LINEBUFFER_H_
|
||||
#define _LINEBUFFER_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* hide details */
|
||||
struct lbuf;
|
||||
|
||||
struct lbuf * lbuf_create(size_t size);
|
||||
void lbuf_free(struct lbuf *buf);
|
||||
|
||||
int lbuf_clear(struct lbuf *buf);
|
||||
|
||||
int lbuf_readfd(struct lbuf *buf, int fd);
|
||||
int lbuf_parsefd(struct lbuf *buf, int fd);
|
||||
int lbuf_writefd(struct lbuf *buf, int fd);
|
||||
|
||||
char * lbuf_getdata(struct lbuf *buf, size_t *len);
|
||||
|
||||
int lbuf_append(struct lbuf *buf, const char *src, size_t size);
|
||||
int lbuf_vprintf(struct lbuf *buf, const char *fmt, va_list ap);
|
||||
int lbuf_printf(struct lbuf *buf, const char *fmt, ...);
|
||||
|
||||
char * lbuf_gettok(struct lbuf *buf, const char *delim);
|
||||
int lbuf_freetok(struct lbuf *buf);
|
||||
|
||||
#endif /* _LINEBUFFER_H_ */
|
Loading…
Reference in new issue