Release notes for 1.9.1
[blerg.git] / common / stringbucket.c
1 /* Blerg is (C) 2011 The Dominion of Awesome, and is distributed under a
2  * BSD-style license.  Please see the COPYING file for details.
3  */
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/mman.h>
7 #include <sys/file.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <stringbucket.h>
14
15 #define STRINGBUCKET_STRINGSIZE 64
16
17 const char * strnchr(const char *s, int c, int n) {
18         const char *ptr = s;
19         while (n > 0) {
20                 if (*ptr == c)
21                         return ptr;
22                 ptr++;
23                 n--;
24         }
25         return NULL;
26 }
27
28 struct stringbucket * stringbucket_open(const char *filename) {
29         struct stat st;
30         struct stringbucket *obj = malloc(sizeof(struct stringbucket));
31
32         if (obj == NULL) {
33                 perror("stringbucket allocate");
34                 return NULL;
35         }
36
37         obj->fd = open(filename, O_RDWR | O_APPEND | O_CREAT, 0600);
38         flock(obj->fd, LOCK_SH);
39         fstat(obj->fd, &st);
40         flock(obj->fd, LOCK_UN);
41         obj->size = st.st_size;
42         obj->list = mmap(NULL, obj->size, PROT_READ | PROT_WRITE, MAP_SHARED, obj->fd, 0);
43         if (obj->list == NULL) {
44                 perror("stringbucket mmap");
45                 close(obj->fd);
46                 free(obj);
47                 return 0;
48         }
49
50         return obj;
51 }
52
53 void stringbucket_close(struct stringbucket *sb) {
54         munmap(sb->list, sb->size);
55         close(sb->fd);
56         free(sb);
57 }
58
59 int stringbucket_find(struct stringbucket *sb, const char *string) {
60         char * end = sb->list + sb->size;
61         int string_len = strlen(string);
62
63         char * ptr = sb->list;
64         while (ptr < end) {
65                 char * next = (char *) strnchr(ptr, '\n', end - ptr);
66                 if (next == NULL)
67                         next = end;
68                 int len = next - ptr;
69                 if (len > STRINGBUCKET_STRINGSIZE)
70                         len = STRINGBUCKET_STRINGSIZE;
71                 if (memcmp(ptr, string, (len < string_len ? string_len : len)) == 0) {
72                         return (ptr - sb->list);
73                 }
74                 ptr = next + 1;
75         }
76
77         return -1;
78 }
79
80 int stringbucket_add(struct stringbucket *sb, const char *string) {
81         if (stringbucket_find(sb, string) != -1) return 0;
82         flock(sb->fd, LOCK_EX);
83         write(sb->fd, string, strlen(string));
84         write(sb->fd, "\n", 1);
85         flock(sb->fd, LOCK_UN);
86         return 1;
87 }
88
89 int stringbucket_delete(struct stringbucket *sb, const char *string) {
90         int pos = stringbucket_find(sb, string);
91         if (pos == -1) return 0;
92
93         /* We doin' it DOS style! */
94         sb->list[pos] = 0;
95         return 1;
96 }
97
98 void stringbucket_iterate(struct stringbucket *sb, void (*iter)(char *, void *), void *stuff) {
99         char string[STRINGBUCKET_STRINGSIZE + 1];
100         char * ptr = sb->list;
101         char * end = sb->list + sb->size;
102
103         while (ptr < end) {
104                 char * next = (char *) strnchr(ptr, '\n', end - ptr);
105                 if (next == NULL)
106                         next = end;
107                 if (ptr[0] == 0) {
108                         ptr = next + 1;
109                         continue;
110                 }
111                 int len = next - ptr;
112                 memcpy(string, ptr, len);
113                 string[len] = 0;
114                 iter(string, stuff);
115                 ptr = next + 1;
116         }
117 }