/*************************************************************************** * 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 #include #include #include #include #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; }