Line data Source code
1 : // Copyright 2014 Bobby Powers. All rights reserved.
2 : // Use of this source code is governed by a BSD-style
3 : // license that can be found in the LICENSE file.
4 :
5 : #include <stdio.h>
6 : #include <stdlib.h>
7 : #include <string.h>
8 : #include <stdbool.h>
9 : #include <sys/types.h>
10 : #include <sys/stat.h>
11 : #include <fcntl.h>
12 : #include <ctype.h>
13 :
14 : #include "utf.h"
15 : #include "sd.h"
16 : #include "sd_internal.h"
17 :
18 :
19 2951 : int slice_make(Slice *s, size_t len, size_t cap)
20 : {
21 2951 : if (!s)
22 1 : return SD_ERR_UNSPECIFIED;
23 :
24 2950 : if (cap) {
25 18 : s->elems = calloc(cap, sizeof(*s->elems));
26 18 : if (!s->elems)
27 0 : return SD_ERR_NOMEM;
28 : } else {
29 2932 : s->elems = NULL;
30 : }
31 2950 : s->len = len;
32 2950 : s->cap = cap;
33 2950 : return SD_ERR_NO_ERROR;
34 : }
35 :
36 4734 : int slice_append(Slice *s, void *e)
37 : {
38 : size_t new_cap;
39 :
40 4734 : if (!s)
41 1 : return SD_ERR_UNSPECIFIED;
42 :
43 4733 : if (s->cap == 0) {
44 1514 : new_cap = 2;
45 1514 : s->elems = calloc(new_cap, sizeof(*s->elems));
46 1514 : if (!s->elems)
47 0 : return SD_ERR_NOMEM;
48 1514 : s->cap = new_cap;
49 : }
50 3219 : else if (s->len == s->cap) {
51 972 : new_cap = s->cap*2;
52 972 : s->elems = realloc(s->elems, new_cap*sizeof(*s->elems));
53 972 : if (!s->elems) {
54 0 : s->len = 0;
55 0 : s->cap = 0;
56 0 : return SD_ERR_NOMEM;
57 : }
58 4004 : for (size_t i = s->len; i < new_cap; ++i)
59 3032 : s->elems[i] = NULL;
60 972 : s->cap = new_cap;
61 : }
62 4733 : s->elems[s->len++] = e;
63 4733 : return SD_ERR_NO_ERROR;
64 : }
65 :
66 3 : int slice_extend(Slice *s, Slice *other)
67 : {
68 3 : if (!s || !other)
69 1 : return SD_ERR_UNSPECIFIED;
70 :
71 : // XXX: could be more efficient
72 6 : for (size_t i = 0; i < other->len; i++)
73 4 : slice_append(s, other->elems[i]);
74 :
75 2 : return SD_ERR_NO_ERROR;
76 : }
77 :
78 : int
79 1594 : strrepl(char *s, const char *orig, const char *new)
80 : {
81 : char *found;
82 1594 : int replacements = 0;
83 1594 : size_t olen = strlen(orig);
84 1594 : size_t nlen = strlen(new);
85 1594 : int diff = strlen(orig) - strlen(new);
86 :
87 : // we will not allocate - exit early if we're being asked to
88 : // do so.
89 1594 : if (diff < 0)
90 1 : return 0;
91 :
92 3230 : while ((found = strstr(s, orig))) {
93 44 : replacements++;
94 44 : memcpy(found, new, strlen(new));
95 : // +1 is to copy trailing null
96 44 : if (diff)
97 29 : memmove(found + nlen, found + olen, strlen(found + olen)+1);
98 44 : s = found + nlen;
99 : }
100 1593 : return replacements;
101 : }
102 :
103 : int
104 4952 : strtrim(const char **s, int len)
105 : {
106 : int n;
107 : Rune r;
108 36831 : for (; (n = charntorune(&r, *s, len)); *s += n, len -= n) {
109 32760 : if (!r || !isspace(r))
110 : break;
111 : }
112 5005 : for (int i = 1; len > 0 && (n = charntorune(&r, &(*s)[len-i], i)); i++) {
113 928 : if (r == Runeerror)
114 0 : continue;
115 928 : if (!isspace(r))
116 875 : break;
117 53 : len -= i;
118 53 : i = 0;
119 : }
120 4952 : return len;
121 : }
122 :
123 : int
124 413 : utf8_tolower(char **s)
125 : {
126 : int n;
127 : Rune u;
128 413 : const size_t slen = strlen(*s);
129 413 : size_t dlen = 0;
130 : char *src, **ss;
131 413 : bool needs_realloc = false;
132 :
133 413 : src = *s;
134 413 : ss = &src;
135 :
136 5052 : for (size_t len = slen; (n = charntorune(&u, *ss, len)); *ss += n, len -= n) {
137 4639 : const Rune l = tolowerrune(u);
138 4639 : needs_realloc |= runelen(l) > n;
139 4639 : dlen += runelen(l);
140 : }
141 413 : char *d = needs_realloc ? realloc(*s, dlen) : *s;
142 413 : if (!d)
143 0 : return SD_ERR_NOMEM;
144 :
145 :
146 413 : src = *s;
147 413 : size_t doff = 0;
148 5052 : for (size_t len = slen; (n = charntorune(&u, *ss, len)); *ss += n, len -= n) {
149 4639 : Rune l = tolowerrune(u);
150 4639 : const int ln = runetochar(&d[doff], &l);
151 4639 : doff += ln;
152 : }
153 :
154 413 : *s = d;
155 :
156 413 : return SD_ERR_NO_ERROR;
157 : }
158 :
159 : size_t
160 36 : round_up(size_t i, size_t n)
161 : {
162 36 : return n*((i - 1)/n + 1);
163 : }
164 :
165 : double
166 1737 : lookup(Table *t, double index)
167 : {
168 1737 : size_t len = t->len;
169 1737 : if (unlikely(t->len == 0))
170 1 : return 0;
171 :
172 1736 : double *x = t->x;
173 1736 : double *y = t->y;
174 :
175 : // if the request is outside the min or max, then we return
176 : // the nearest element of the array
177 1736 : if (unlikely(index < x[0]))
178 2 : return y[0];
179 1734 : else if (unlikely(index > x[len-1]))
180 15 : return y[len-1];
181 :
182 : // binary search makes more sense here
183 1719 : size_t low = 0;
184 1719 : size_t high = len;
185 : size_t mid;
186 9724 : while (low < high) {
187 6286 : mid = low + ((high-low)/2);
188 6286 : if (x[mid] < index)
189 2321 : low = mid + 1;
190 : else
191 3965 : high = mid;
192 : }
193 :
194 : // at this point low == high, so using 'i' seems more readable.
195 1719 : size_t i = low;
196 1719 : if (unlikely(x[i] == index)) {
197 1467 : return y[i];
198 : } else {
199 : // slope = deltaY/deltaX
200 252 : double slope = (y[i] - y[i-1]) / (x[i] - x[i-1]);
201 252 : return (index-x[i-1])*slope + y[i-1];
202 : }
203 :
204 : return 0;
205 : }
206 :
207 : char *
208 265 : normalize_name(const char *n)
209 : {
210 : char *result;
211 265 : size_t len = strlen(n);
212 265 : bool quoted = len > 0 && n[0] == '"' && n[len-1] == '"';
213 265 : int off = quoted ? 1 : 0;
214 :
215 265 : result = strndup(n+off, len - 2*off);
216 265 : if (!result)
217 0 : return NULL;
218 265 : utf8_tolower(&result);
219 : // FIXME: be more efficient
220 265 : strrepl(result, "\\\\", "\\");
221 265 : strrepl(result, "\\n", "_");
222 265 : strrepl(result, "\\r", "_");
223 265 : strrepl(result, "\n", "_");
224 265 : strrepl(result, "\r", "_");
225 265 : strrepl(result, " ", "_");
226 : // FIXME: nbsp - 00A0 / C2A0
227 265 : return result;
228 : }
|