summaryrefslogtreecommitdiff
path: root/src/dged/buffers.c
blob: f591385a5f07966fbcbe3e247c4bf1410699832a (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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include "buffers.h"
#include "buffer.h"

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

struct buffer_entry {
  struct buffer buffer;
  bool empty;
};

void buffers_init(struct buffers *buffers, uint32_t initial_capacity) {
  VEC_INIT(&buffers->buffers, initial_capacity);
  VEC_INIT(&buffers->add_hooks, 32);
  VEC_INIT(&buffers->remove_hooks, 32);
}

struct buffer *buffers_add(struct buffers *buffers, struct buffer buffer) {
  struct buffer_entry *slot = NULL;
  VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) {
    if (e->empty) {
      slot = e;
    }
  }

  if (slot == NULL) {
    VEC_APPEND(&buffers->buffers, struct buffer_entry * new);
    slot = new;
  }

  slot->buffer = buffer;
  slot->empty = false;

  VEC_FOR_EACH(&buffers->add_hooks, struct buffers_hook * hook) {
    hook->callback(&slot->buffer, hook->userdata);
  }

  return &slot->buffer;
}

uint32_t buffers_add_add_hook(struct buffers *buffers, buffers_hook_cb callback,
                              void *userdata) {
  VEC_PUSH(&buffers->add_hooks, ((struct buffers_hook){
                                    .callback = callback,
                                    .userdata = userdata,
                                }));

  return VEC_SIZE(&buffers->add_hooks) - 1;
}

uint32_t buffers_add_remove_hook(struct buffers *buffers,
                                 buffers_hook_cb callback, void *userdata) {
  VEC_PUSH(&buffers->remove_hooks, ((struct buffers_hook){
                                       .callback = callback,
                                       .userdata = userdata,
                                   }));

  return VEC_SIZE(&buffers->remove_hooks) - 1;
}

struct buffer *buffers_find(struct buffers *buffers, const char *name) {
  VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) {
    if (!e->empty && strcmp(name, e->buffer.name) == 0) {
      return &e->buffer;
    }
  }

  return NULL;
}

struct buffer *buffers_find_by_filename(struct buffers *buffers,
                                        const char *path) {
  VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) {
    if (!e->empty && e->buffer.filename != NULL &&
        strcmp(path, e->buffer.filename) == 0) {
      return &e->buffer;
    }
  }

  return NULL;
}

bool buffers_remove(struct buffers *buffers, const char *name) {
  struct buffer_entry *buf_entry = NULL;
  VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) {
    if (!e->empty && strcmp(name, e->buffer.name) == 0) {
      buf_entry = e;
    }
  }

  if (buf_entry == NULL) {
    return false;
  }

  VEC_FOR_EACH(&buffers->remove_hooks, struct buffers_hook * hook) {
    hook->callback(&buf_entry->buffer, hook->userdata);
  }

  buf_entry->empty = true;
  buffer_destroy(&buf_entry->buffer);
  return true;
}

void buffers_for_each(struct buffers *buffers, buffers_hook_cb callback,
                      void *userdata) {
  VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) {
    if (!e->empty) {
      callback(&e->buffer, userdata);
    }
  }
}

uint32_t buffers_num_buffers(struct buffers *buffers) {
  return VEC_SIZE(&buffers->buffers);
}

struct buffer *buffers_first(struct buffers *buffers) {
  return buffers_num_buffers(buffers) > 0
             ? &VEC_ENTRIES(&buffers->buffers)[0].buffer
             : NULL;
}

void buffers_destroy(struct buffers *buffers) {
  VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) {
    if (!e->empty) {
      buffer_destroy(&e->buffer);
      e->empty = true;
    }
  }

  VEC_DESTROY(&buffers->buffers);
  VEC_DESTROY(&buffers->add_hooks);
  VEC_DESTROY(&buffers->remove_hooks);
}