|
|
@ -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; |
|
|
|
} |