aboutsummaryrefslogtreecommitdiff
path: root/buf.c
blob: a485708d180e53db43917d803fb4b04618a7302f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "buf.h"

#define min(a,b) (a<b) ? a : b

struct buf_node{
    char* text;
    struct buf_node* next;
};

struct buf{
    buf_node* head;
    buf_node* tail;
    size_t cap;
    size_t ins;
    size_t pop;
}; // a "thick" linked list (buffered for mem efficiency)

buf_node* newbufnode(size_t cap){
    buf_node* bufnode = malloc(sizeof(buf_node));
    bufnode->text = malloc(sizeof(char)*cap);
    return bufnode;
}

buf* newbuf(size_t cap){
    buf* buffer = malloc(sizeof(buf));
    buffer->tail = buffer->head = newbufnode(cap);
    buffer->cap = cap;
    buffer->ins = buffer->pop = 0;
    return buffer;
}

size_t buflen(buf* buffer){
    buf_node* cur = buffer->tail;
    size_t size = buffer->ins-buffer->pop+buffer->cap;
    while (cur != buffer->head) {
        cur = cur->next; // skips one iter        ^^^
        size += buffer->cap;
    };
    return size;
}

void extendbuf(buf* buffer){
    buffer->head->next = newbufnode(buffer->cap);
    buffer->head = buffer->head->next;
    // buffer->ins = 0 is taken care of in the function that uses this.
}

void shortenbuf(buf* buffer){
    buf_node* tmp = buffer->tail;
    buffer->tail = buffer->tail->next;
    free(tmp);
    buffer->pop = 0;
}

char popchrbuf(buf* buffer){
    if (buffer->pop == buffer->cap) shortenbuf(buffer);
    buffer->pop++;
    return buffer->tail->text[buffer->pop-1];
}
char* popstrbuf(buf* buffer, size_t ct){
    char* str = malloc((ct+1)*sizeof(char)); str[ct] = 0;
    size_t rem;
    for (size_t loc = 0; ct>loc; loc += rem){
        if (buffer->pop == buffer->cap) shortenbuf(buffer);
        rem = min(buffer->cap, ct-loc);
        memcpy(str+loc, buffer->tail->text+buffer->pop, rem);
        buffer->pop += rem;
    } /* probably some inefficiencies here*/
    return str;
}

void inschrbuf(buf* buffer, char chr){
    if (buffer->ins == buffer->cap) extendbuf(buffer);
    buffer->cap++;
    buffer->head->text[buffer->cap-1] = chr;
}
void insstrbuf(buf* buffer, char* str){
    size_t len = strlen(str);
    size_t tgt = min(len, buffer->cap - buffer->ins);
    memcpy(buffer->head->text+buffer->ins, str, tgt);
    buffer->ins += len;
    buffer->ins %= buffer->cap;
    for (;tgt<len; tgt += buffer->cap){
        extendbuf(buffer);
        memcpy(buffer->head->text, str+tgt, min(len-tgt, buffer->cap));
    }
}

char* peekstrbuf(buf* buffer, size_t loc, size_t len){
    char* str = malloc(sizeof(char)*(len+1)); str[len] = 0;
    buf_node* start;

    loc += buffer->ins;
    for (start = buffer->tail; loc>0;
            loc -= buffer->cap)
        start = start->next; // start,loc is where one starts streaming
    if (len > buffer->cap){
        memcpy(str, start->text+loc, buffer->cap-loc);
        len -= buffer->cap - loc;
    }
    for (; len > buffer->cap; len -= buffer->cap ){
        memcpy(str, start->text, buffer->cap);
    }
    memcpy(str, start->text, len);
    return str;
}