Skip to content
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.

Copy link
@rofl0r

rofl0r Aug 5, 2013

Contributor

you're aware that malloc can fail ?

This comment has been minimized.

Copy link
@nsf

nsf Aug 5, 2013

Author 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.

Copy link
@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.

Copy link
@nsf

nsf Aug 5, 2013

Author 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.

Copy link
@lucy

lucy Aug 5, 2013

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

This comment has been minimized.

Copy link
@nsf

nsf Aug 5, 2013

Author 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.

This file was deleted.

@@ -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.

Copy link
Contributor

@rofl0r 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.

Copy link
Owner Author

@nsf 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.

Copy link
Owner Author

@nsf nsf replied Aug 5, 2013

1cd409c

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

Please sign in to comment.