aboutsummaryrefslogtreecommitdiff
path: root/sb.c
blob: a36f82ab3e919a0c2b5db6f40a49fb1db58759ed (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
#include <stdlib.h>
#include <string.h>

#include "sb.h"

struct sb {
    sbnode* head;
    sbnode* tail;
    size_t loc;
    size_t sz;
};

struct sbnode {
    char* str;
    sbnode* next;
};

static sbnode* newsbnode(sbnode* prev, size_t sz){
    sbnode* node = malloc(sizeof(sbnode)); // Allocate
    node->str = malloc(sizeof(char)*(sz+1)); node->str[sz] = 0;
    node->next = NULL; // Init
    if (prev) prev->next = node; // Link
    return node;
}

sb* newsb(size_t sz){
    sb* out = malloc(sizeof(sb));
    out->head = out->tail = newsbnode(NULL, sz);
    out->sz = sz;
    out->loc = 0;
    return out;
}

static void extendsb(sb* buf){
    buf->sz *= 2;
    buf->loc = 0;
    buf->tail = newsbnode(buf->tail, buf->sz);
}

void insstr(sb* buf, char* str){
    size_t rem = strlen(str); // remaining chars to push
    while (rem > (buf->sz - buf->loc)){ // while buffer has less room
        // than needed, fill the buffer with str
        memcpy(buf->tail->str+buf->loc, str, buf->sz - buf->loc);
        // move the string pointer by that amount
        str += buf->sz - buf->loc;
        // reduce the number of remaining characters by that amount
        rem -= buf->sz - buf->loc;
        // and add a new node, resetting buf->loc
        extendsb(buf);
    }
    // copy the rest into the buffer
    memcpy(buf->tail->str+buf->loc, str, rem);
    // and advance buf->loc
    buf->loc += rem;
}

static sbnode* freenext(sbnode* node){
    sbnode* out = node->next;
    free(node->str);
    free(node);
    if (node != out) return out;
    else return node;
}

char* decompose(sb* buf){
    // Make the last node a proper string
    buf->tail->str[buf->loc] = 0;
    // Start with the length of the last node
    size_t len = 0;
    // For every non-tail node (cur->next == NULL for it),
    for (sbnode* cur = buf->head; cur != NULL; cur = cur->next){
        // add the length of its string
        len += strlen(cur->str);
    }
    // make a string to fit it all
    char* str = malloc(sizeof(char)*(len+1)); str[len] = 0;
    // and its iterator
    char* pos = str;
    // for every node,
    for (sbnode* cur = buf->head; cur != NULL; cur = freenext(cur)){
        size_t slen = strlen(cur->str);
        memcpy(pos, cur->str, slen); // copy
        pos += slen;
    }
    free(buf);
    return str;
}