about summary refs log blame commit diff stats
path: root/termbox/bytebuffer.inl
blob: aae8f073720f9c6ea4f09f6edba1691feb8be39c (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                   


            


                                                               


                      
 



                             
 










                                                             


                                                            


             
 



                                                            


                                                   

                 


                                                    
             


                                                                                


                                      


                                                                    
                                         


                                                              

                             


                                                            
                                      
             
                      


                                                              






                                   
 
struct bytebuffer {
  char *buf;
  int len;
  int cap;
};

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

static void bytebuffer_init(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
  }
}

static void bytebuffer_free(struct bytebuffer *b) {
  if (b->buf)
    free(b->buf);
}

static void bytebuffer_clear(struct bytebuffer *b) {
  b->len = 0;
}

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

static void bytebuffer_puts(struct bytebuffer *b, const char *str) {
  bytebuffer_append(b, str, strlen(str));
}

static void bytebuffer_resize(struct bytebuffer *b, int len) {
  bytebuffer_reserve(b, len);
  b->len = len;
}

static void bytebuffer_flush(struct bytebuffer *b, int fd) {
  int yyy = write(fd, b->buf, b->len);
  (void) yyy;
  bytebuffer_clear(b);
}

static void bytebuffer_truncate(struct bytebuffer *b, int n) {
  if (n <= 0)
    return;
  if (n > b->len)
    n = b->len;
  const int nmove = b->len - n;
  memmove(b->buf, b->buf+n, nmove);
  b->len -= n;
}
> end > end > return table.concat(charbytes) >end - __teliva_timestamp: original grid_char_to_glyph_index: >-- convert a chunk of grid into a number >function grid_char_to_glyph_index(g) > return g[1][1] + g[2][1]*2 + g[3][1]*4 + g[4][1]*8 + > g[1][2]*16 + g[2][2]*32 + g[3][2]*64 + g[4][2]*128 + > 1 -- 1-indexing >end - __teliva_timestamp: original render: >function render(window) > window:clear() > curses.attron(curses.color_pair(1)) > for line=1,lines do > for col=1,cols do > window:addstr(utf8(glyph[grid_char_to_glyph_index(grid_char(line, col))])) > end > end > curses.attroff(curses.color_pair(1)) > curses.refresh() >end - __teliva_timestamp: original state: >function state(line, col) > if line < 1 or line > table.getn(grid) or col < 1 or col > table.getn(grid[1]) then > return 0 > end > return grid[line][col] >end - __teliva_timestamp: original num_live_neighbors: >function num_live_neighbors(line, col) > return state(line-1, col-1) + state(line-1, col) + state(line-1, col+1) + > state(line, col-1) + state(line, col+1) + > state(line+1, col-1) + state(line+1, col) + state(line+1, col+1) >end - __teliva_timestamp: original step: >function step() > local new_grid = {} > for line=1,table.getn(grid) do > new_grid[line] = {} > for col=1,table.getn(grid[1]) do > local n = num_live_neighbors(line, col) > if n == 3 then > new_grid[line][col] = 1 > elseif n == 2 then > new_grid[line][col] = grid[line][col] > else > new_grid[line][col] = 0 > end > end > end > grid = new_grid >end - __teliva_timestamp: original sleep: >function sleep(a) > local sec = tonumber(os.clock() + a); > while (os.clock() < sec) do > end >end - __teliva_timestamp: original load_file: >function load_file(window, filename) > local infile = io.open(filename, 'r') > if infile == nil then return end > local line_index = lines > for line in infile:lines() do > if line:sub(1,1) ~= '!' then -- comment; plaintext files can't have whitespace before comments > local col_index = cols > for c in line:gmatch(".") do > if c == '\r' then break end -- DOS line ending > if c == '.' then > grid[line_index][col_index] = 0 > else > grid[line_index][col_index] = 1 > end > col_index = col_index+1 > end > line_index = line_index+1 > end > end >end - __teliva_timestamp: original update: >menu = {{"arrow", "pan"}} > >function update(window, c) > if c == curses.KEY_LEFT then > for i=1,lines*4 do > for j=2,cols*2 do > grid[i][j-1] = grid[i][j] > end > grid[i][cols*2] = 0 > end > elseif c == curses.KEY_DOWN then > for i=lines*4-1,1,-1 do > for j=1,cols*2 do > grid[i+1][j] = grid[i][j] > end > end > for j=1,cols*2 do > grid[1][j] = 0 > end > elseif c == curses.KEY_UP then > for i=2,lines*4 do > for j=1,cols*2 do > grid[i-1][j] = grid[i][j] > end > end > for j=1,cols*2 do > grid[lines*4][j] = 0 > end > elseif c == curses.KEY_RIGHT then > for i=1,lines*4 do > for j=cols*2-1,1,-1 do > grid[i][j+1] = grid[i][j] > end > grid[i][1] = 0 > end > end >end - __teliva_timestamp: original main: >function main() > curses.init_pair(1, 22, 189) > > -- initialize grid based on commandline args > if (#arg == 0) then > -- by default, start from a deterministically random state > for i=1,lines*4 do > for j=1,cols*2 do > grid[i][j] = math.random(0, 1) > end > end > elseif arg[1] == "random" then > -- start from a non-deterministically random start state > math.randomseed(os.time()) > for i=1,lines*4 do > for j=1,cols*2 do > grid[i][j] = math.random(0, 1) > end > end > -- shortcuts for some common patterns > elseif arg[1] == "pentomino" then > -- https://www.conwaylife.com/wiki/Pentomino > grid[83][172] = 1 > grid[83][173] = 1 > grid[84][173] = 1 > grid[84][174] = 1 > grid[85][173] = 1 > elseif arg[1] == "glider" then > -- https://www.conwaylife.com/wiki/Glider > grid[5][4] = 1 > grid[6][5] = 1 > grid[7][3] = 1 > grid[7][4] = 1 > grid[7][5] = 1 > elseif arg[1] == "blinker" then > -- https://www.conwaylife.com/wiki/Blinker > grid[7][3] = 1 > grid[7][4] = 1 > grid[7][5] = 1 > elseif arg[1] == "block" then > -- https://www.conwaylife.com/wiki/Block > grid[5][4] = 1 > grid[5][5] = 1 > grid[6][4] = 1 > grid[6][5] = 1 > elseif arg[1] == "loaf" then > -- https://www.conwaylife.com/wiki/Loaf > grid[5][4] = 1 > grid[5][5] = 1 > grid[6][6] = 1 > grid[7][6] = 1 > grid[8][5] = 1 > grid[7][4] = 1 > grid[6][3] = 1 > else > -- Load a file in the standard "plaintext" format: https://www.conwaylife.com/wiki/Plaintext > -- > -- Each pattern page at https://www.conwaylife.com/wiki provides its > -- plaintext representation in a block called "Pattern Files" on the right. > -- > -- For example, check out the list of Important Patterns at > -- https://www.conwaylife.com/wiki/Category:Patterns_with_Catagolue_frequency_class_0 > load_file(window, arg[1]) > end > > -- main loop > while true do > render(window) > c = curses.getch() > update(window, c) > step() > end >end