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
110
111
112
113
114
115
116
117
118
119
120
|
#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)
static 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;
while (cur != buffer->head) {
cur = cur->next;
size += buffer->cap;
};
return size;
}
static 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.
}
static void shortenbuf(buf* buffer){
buf_node* tmp = buffer->tail;
buffer->tail = buffer->tail->next;
free(tmp->text);
free(tmp);
}
char popchrbuf(buf* buffer){
if (buffer->pop == buffer->cap){
shortenbuf(buffer);
buffer->pop = 0;
}
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;
memcpy(str, buffer->tail->text+buffer->pop,
min(ct, buffer->cap-buffer->pop));
size_t loc;
for (loc = buffer->cap - buffer->pop; loc < ct; loc += buffer->cap){
shortenbuf(buffer);
memcpy(str+loc, buffer->tail->text, min(ct-loc, buffer->cap));
}
buffer->pop = ct - loc + buffer->cap;
return str;
}
void inschrbuf(buf* buffer, char chr){
if (buffer->ins == buffer->cap){
extendbuf(buffer);
buffer->ins = 0;
}
buffer->ins++;
buffer->head->text[buffer->ins-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);
for (;tgt<len; tgt += buffer->cap){
extendbuf(buffer);
memcpy(buffer->head->text, str+tgt, min(len-tgt, buffer->cap));
}
buffer->ins = 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->pop;
for (start = buffer->tail; loc>buffer->cap; loc -= buffer->cap)
start = start->next; // start,loc is where one starts streaming
size_t bytect;
for (size_t tgt = 0; len > 0; len -= bytect, tgt += bytect){
bytect = min(buffer->cap - loc, len);
memcpy(str+tgt, start->text+loc, bytect);
start = start->next;
loc = 0;
}
return str;
}
char peekchrbuf(buf* buffer, size_t loc){
buf_node* start;
loc += buffer->pop;
for (start = buffer->tail; loc>buffer->cap; loc -= buffer->cap)
start = start->next;
return start->text[loc];
}
|