Permalink
Browse files

Replace memstream with bytebuffer.

  • Loading branch information...
nsf committed Aug 3, 2013
1 parent a2e217f commit 66c3f91b14e24510319bce6b5cc2fecf8cf5abff
Showing with 110 additions and 73 deletions.
  1. +67 −0 src/bytebuffer.c
  2. +17 −0 src/bytebuffer.h
  3. +0 −27 src/memstream.c
  4. +0 −19 src/memstream.h
  5. +26 −27 src/termbox.c
@@ -0,0 +1,67 @@
#include "bytebuffer.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void bytebuffer_reserve(struct bytebuffer *b, int cap) {
if (b->cap >= cap) {
return;
}
// prefer doubling capacity
if (b->cap * 2 >= cap) {
cap = b->cap * 2;
}
char *newbuf = malloc(cap);

This comment has been minimized.

@rofl0r

rofl0r Aug 5, 2013

Contributor

you're aware that malloc can fail ?

This comment has been minimized.

@nsf

nsf Aug 5, 2013

Owner

Yes. In practice, however, on desktop systems it almost never fails. Especially if you have a swap partition.

I'll replace malloc with xmalloc which calls abort() on allocation failure later.

This comment has been minimized.

@rofl0r

rofl0r Aug 5, 2013

Contributor

that's false.if you disable overcommit, which is a pretty sane thing to do ( see http://ewontfix.com/3/ ), you can very well run out of ram.
i dont see how calling abort() would improve the situation over segfaulting. in fact you would just create a library that cannot be used in a robust application, and may lead to a termbox entry on http://suckless.org/sucks . aborting on resource exhaustion is a bug.

This comment has been minimized.

@wm4

wm4 Aug 5, 2013

i dont see how calling abort() would improve the situation over segfaulting.

Security issues. abort() is definitely cleaner compared to a completely unchecked malloc().

This comment has been minimized.

@nsf

nsf Aug 5, 2013

Owner

you would just create a library that cannot be used in a robust application, and may lead to a termbox entry on http://suckless.org/sucks

Do you really believe I care about that?

This comment has been minimized.

@lucy

lucy Aug 5, 2013

You don't care about your library being usable in robust applications?

This comment has been minimized.

@nsf

nsf Aug 5, 2013

Owner

You don't care about your library being usable in robust applications?

No. Why should I care?

if (b->len > 0) {
// copy what was there, b->len > 0 assumes b->buf != null
memcpy(newbuf, b->buf, b->len);
}
if (b->buf) {
// in case there was an allocated buffer, free it
free(b->buf);
}
b->buf = newbuf;
b->cap = cap;
}
void init_bytebuffer(struct bytebuffer *b, int cap) {
b->cap = 0;
b->len = 0;
b->buf = 0;
if (cap > 0) {
b->cap = cap;
b->buf = malloc(cap); // just assume malloc works always
}
}
void free_bytebuffer(struct bytebuffer *b) {
if (b->buf)
free(b->buf);
}
void clear_bytebuffer(struct bytebuffer *b) {
b->len = 0;
}
void bytebuffer_puts(struct bytebuffer *b, const char *str) {
bytebuffer_append(b, str, strlen(str));
}
void bytebuffer_append(struct bytebuffer *b, const char *data, int len) {
bytebuffer_reserve(b, b->len + len);
memcpy(b->buf + b->len, data, len);
b->len += len;
}
void resize_bytebuffer(struct bytebuffer *b, int len) {
bytebuffer_reserve(b, len);
b->len = len;
}
void flush_bytebuffer(struct bytebuffer *b, int fd) {
write(fd, b->buf, b->len);
clear_bytebuffer(b);
}
@@ -0,0 +1,17 @@
#pragma once
struct bytebuffer {
char *buf;
int len;
int cap;
};
void init_bytebuffer(struct bytebuffer *b, int cap);
void free_bytebuffer(struct bytebuffer *b);
void clear_bytebuffer(struct bytebuffer *b);
void resize_bytebuffer(struct bytebuffer *b, int len);
void bytebuffer_puts(struct bytebuffer *b, const char *str);
void bytebuffer_append(struct bytebuffer *b, const char *data, int len);
// writes the contents of the buffer to the given fd and then clears the buffer
void flush_bytebuffer(struct bytebuffer *b, int fd);

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.
@@ -12,7 +12,7 @@
#include "term.h"
#include "termbox.h"
#include "memstream.h"
#include "bytebuffer.h"
struct cellbuf {
unsigned int width;
@@ -29,8 +29,7 @@ static struct termios orig_tios;
static struct cellbuf back_buffer;
static struct cellbuf front_buffer;
static unsigned char write_buffer_data[32 * 1024];
static struct memstream write_buffer;
static struct bytebuffer output_buffer;
static unsigned int termw;
static unsigned int termh;
@@ -128,11 +127,11 @@ int tb_init(void)
tios.c_cc[VTIME] = 0;
tcsetattr(out_fileno, TCSAFLUSH, &tios);
memstream_init(&write_buffer, out_fileno, write_buffer_data, sizeof(write_buffer_data));
init_bytebuffer(&output_buffer, 32 * 1024);
memstream_puts(&write_buffer, funcs[T_ENTER_CA]);
memstream_puts(&write_buffer, funcs[T_ENTER_KEYPAD]);
memstream_puts(&write_buffer, funcs[T_HIDE_CURSOR]);
bytebuffer_puts(&output_buffer, funcs[T_ENTER_CA]);
bytebuffer_puts(&output_buffer, funcs[T_ENTER_KEYPAD]);
bytebuffer_puts(&output_buffer, funcs[T_HIDE_CURSOR]);
send_clear();
update_term_size();
@@ -147,12 +146,12 @@ int tb_init(void)
void tb_shutdown(void)
{
memstream_puts(&write_buffer, funcs[T_SHOW_CURSOR]);
memstream_puts(&write_buffer, funcs[T_SGR0]);
memstream_puts(&write_buffer, funcs[T_CLEAR_SCREEN]);
memstream_puts(&write_buffer, funcs[T_EXIT_CA]);
memstream_puts(&write_buffer, funcs[T_EXIT_KEYPAD]);
memstream_flush(&write_buffer);
bytebuffer_puts(&output_buffer, funcs[T_SHOW_CURSOR]);
bytebuffer_puts(&output_buffer, funcs[T_SGR0]);
bytebuffer_puts(&output_buffer, funcs[T_CLEAR_SCREEN]);
bytebuffer_puts(&output_buffer, funcs[T_EXIT_CA]);
bytebuffer_puts(&output_buffer, funcs[T_EXIT_KEYPAD]);
flush_bytebuffer(&output_buffer, out_fileno);
tcsetattr(out_fileno, TCSAFLUSH, &orig_tios);
shutdown_term();
@@ -193,16 +192,16 @@ void tb_present(void)
}
if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
write_cursor(cursor_x, cursor_y);
memstream_flush(&write_buffer);
flush_bytebuffer(&output_buffer, out_fileno);
}
void tb_set_cursor(int cx, int cy)
{
if (IS_CURSOR_HIDDEN(cursor_x, cursor_y) && !IS_CURSOR_HIDDEN(cx, cy))
memstream_puts(&write_buffer, funcs[T_SHOW_CURSOR]);
bytebuffer_puts(&output_buffer, funcs[T_SHOW_CURSOR]);
if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y) && IS_CURSOR_HIDDEN(cx, cy))
memstream_puts(&write_buffer, funcs[T_HIDE_CURSOR]);
bytebuffer_puts(&output_buffer, funcs[T_HIDE_CURSOR]);
cursor_x = cx;
cursor_y = cy;
@@ -286,8 +285,8 @@ void tb_set_clear_attributes(uint16_t fg, uint16_t bg)
/* -------------------------------------------------------- */
static unsigned convertnum(uint32_t num, char* buf) {
unsigned i, l = 0;
static int convertnum(uint32_t num, char* buf) {
int i, l = 0;
int ch;
do {
buf[l++] = '0' + (num % 10);
@@ -301,8 +300,8 @@ static unsigned convertnum(uint32_t num, char* buf) {
return l;
}
#define WRITE_LITERAL(X) memstream_write(&write_buffer, (X), sizeof(X) -1)
#define WRITE_INT(X) memstream_write(&write_buffer, buf, convertnum((X), buf))
#define WRITE_LITERAL(X) bytebuffer_append(&output_buffer, (X), sizeof(X)-1)
#define WRITE_INT(X) bytebuffer_append(&output_buffer, buf, convertnum((X), buf))
static void write_cursor(unsigned x, unsigned y) {
char buf[32];
@@ -414,14 +413,14 @@ static void send_attr(uint16_t fg, uint16_t bg)
#define LAST_ATTR_INIT 0xFFFF
static uint16_t lastfg = LAST_ATTR_INIT, lastbg = LAST_ATTR_INIT;
if (fg != lastfg || bg != lastbg) {
memstream_puts(&write_buffer, funcs[T_SGR0]);
bytebuffer_puts(&output_buffer, funcs[T_SGR0]);
write_sgr(fg & 0x0F, bg & 0x0F);
if (fg & TB_BOLD)
memstream_puts(&write_buffer, funcs[T_BOLD]);
bytebuffer_puts(&output_buffer, funcs[T_BOLD]);
if (bg & TB_BOLD)
memstream_puts(&write_buffer, funcs[T_BLINK]);
bytebuffer_puts(&output_buffer, funcs[T_BLINK]);
if (fg & TB_UNDERLINE)
memstream_puts(&write_buffer, funcs[T_UNDERLINE]);
bytebuffer_puts(&output_buffer, funcs[T_UNDERLINE]);
lastfg = fg;
lastbg = bg;
@@ -437,16 +436,16 @@ static void send_char(unsigned int x, unsigned int y, uint32_t c)
write_cursor(x, y);
lastx = x; lasty = y;
if(!c) buf[0] = ' '; // replace 0 with whitespace
memstream_puts(&write_buffer, buf);
bytebuffer_puts(&output_buffer, buf);
}
static void send_clear(void)
{
send_attr(foreground, background);
memstream_puts(&write_buffer, funcs[T_CLEAR_SCREEN]);
bytebuffer_puts(&output_buffer, funcs[T_CLEAR_SCREEN]);
if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
write_cursor(cursor_x, cursor_y);
memstream_flush(&write_buffer);
flush_bytebuffer(&output_buffer, out_fileno);
/* we need to invalidate cursor position too and these two vars are
* used only for simple cursor positioning optimization, cursor

3 comments on commit 66c3f91

@rofl0r

This comment has been minimized.

Contributor

rofl0r replied Aug 5, 2013

this change doesnt really seem to make sense, you're swapping a robust 30 line implementation (the passed buffer is static) out for a non-robust permanently malloc'ing and free'ing 70 line implementation of which the header even relies on unportable compiler specific pragmas.

@nsf

This comment has been minimized.

Owner

nsf replied Aug 5, 2013

this change doesnt really seem to make sense, you're swapping a robust 30 line implementation (the passed buffer is static) out for a non-robust permanently malloc'ing and free'ing 70 line implementation of which the header even relies on unportable compiler specific pragmas.

See later commits, I replace both memstream and ringbuffer with bytebuffer. That was the reason for rewriting memstream in the first place. If I can use a simple universal concept for both of the needs, why not. You're free to disagree, but it's a simplification of the code.

@nsf

This comment has been minimized.

Owner

nsf replied Aug 5, 2013

1cd409c

7 changed files with 66 additions and 213 deletions. See?

Please sign in to comment.