p2  0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
string.c
Go to the documentation of this file.
1 
2 
3 
4 
5 //
6 // (c) 2008 why the lucky stiff, the freelance professor
7 //
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include "p2.h"
12 #include "internal.h"
13 #include "khash.h"
14 #include "table.h"
15 
16 #define BYTES_FACTOR 1 / 8 * 9
17 #define BYTES_CHUNK 32
18 #define BYTES_ALIGN(len) PN_ALIGN(len + sizeof(struct PNBytes), BYTES_CHUNK) - sizeof(struct PNBytes)
19 
20 void potion_add_str(Potion *P, PN s) {
21  int ret;
22  kh_put(str, P->strings, s, &ret);
23  PN_QUICK_FWD(struct PNTable *, P->strings);
24 }
25 
26 PN potion_lookup_str(Potion *P, const char *str) {
27  vPN(Table) t = P->strings;
28  unsigned k = kh_get(str, t, str);
29  if (k != kh_end(t)) return kh_key(str, t, k);
30  return PN_NIL;
31 }
32 
33 PN potion_str(Potion *P, const char *str) {
34  PN val = potion_lookup_str(P, str);
35  if (val == PN_NIL) {
36  size_t len = strlen(str);
37  vPN(String) s = PN_ALLOC_N(PN_TSTRING, struct PNString, len + 1);
38  s->len = (PN_SIZE)len;
39  PN_MEMCPY_N(s->chars, str, char, len);
40  s->chars[len] = '\0';
41  potion_add_str(P, (PN)s);
42  val = (PN)s;
43  }
44  return val;
45 }
46 
47 PN potion_str2(Potion *P, char *str, size_t len) {
48  PN exist = PN_NIL;
49 
50  vPN(String) s = PN_ALLOC_N(PN_TSTRING, struct PNString, len + 1);
51  s->len = (PN_SIZE)len;
52  PN_MEMCPY_N(s->chars, str, char, len);
53  s->chars[len] = '\0';
54 
55  exist = potion_lookup_str(P, s->chars);
56  if (exist == PN_NIL) {
57  potion_add_str(P, (PN)s);
58  exist = (PN)s;
59  }
60  return exist;
61 }
62 
63 PN potion_strcat(Potion *P, char *str, char *str2) {
64  PN exist = PN_NIL;
65  int len = strlen(str);
66  int len2 = strlen(str2);
67  vPN(String) s = PN_ALLOC_N(PN_TSTRING, struct PNString, len+len2+1);
68  PN_MEMCPY_N(s->chars, str, char, len);
69  PN_MEMCPY_N(s->chars+len, str2, char, len2);
70  s->chars[len+len2] = '\0';
71  s->len = len+len2;
72  exist = potion_lookup_str(P, s->chars);
73  if (exist == PN_NIL) {
74  potion_add_str(P, (PN)s);
75  exist = (PN)s;
76  }
77  return exist;
78 }
79 
80 PN potion_str_format(Potion *P, const char *format, ...) {
81  vPN(String) s;
82  PN_SIZE len;
83  va_list args;
84 
85  va_start(args, format);
86  len = (PN_SIZE)vsnprintf(NULL, 0, format, args);
87  va_end(args);
88  s = PN_ALLOC_N(PN_TSTRING, struct PNString, len + 1);
89 
90  va_start(args, format);
91  vsnprintf(s->chars, len + 1, format, args);
92  va_end(args);
93  s->len = len;
94  return (PN)s;
95 }
96 
99 static PN potion_str_length(Potion *P, PN cl, PN self) {
100  return PN_NUM(potion_cp_strlen_utf8(PN_STR_PTR(self)));
101 }
102 
105 static PN potion_str_eval(Potion *P, PN cl, PN self) {
106  return potion_eval(P, self, POTION_JIT);
107 }
108 
111 static PN potion_str_number(Potion *P, PN cl, PN self) {
112  char *str = PN_STR_PTR(self);
113  int i = 0, dec = 0, sign = 0, len = PN_STR_LEN(self);
114  if (len < 1) return PN_ZERO;
115 
116  sign = (str[0] == '-' ? -1 : 1);
117  if (str[0] == '-' || str[0] == '+') {
118  dec++; str++; len--;
119  }
120  for (i = 0; i < len; i++)
121  if (str[i] < '0' || str[i] > '9')
122  break;
123  if (i < 10 && i == len) {
124  return PN_NUM(sign * PN_ATOI(str, i, 10));
125  }
126 
127  return potion_decimal(P, PN_STR_PTR(self), PN_STR_LEN(self));
128 }
129 
132 static PN potion_str_string(Potion *P, PN cl, PN self) {
133  return self;
134 }
135 
138 static PN potion_str_print(Potion *P, PN cl, PN self) {
139  fwrite(PN_STR_PTR(self), 1, PN_STR_LEN(self), stdout);
140  return PN_NIL;
141 }
142 
143 static size_t potion_utf8char_offset(const char *s, size_t index) {
144  int i;
145  for (i = 0; s[i]; i++)
146  if ((s[i] & 0xC0) != 0x80)
147  if (index-- == 0)
148  return i;
149  return i;
150 }
151 
152 inline static PN potion_str_slice_index(PN index, size_t len, int nilvalue) {
153  int i = PN_INT(index);
154  int corrected;
155  if (PN_IS_NIL(index)) {
156  corrected = nilvalue;
157  } else if (i < 0) {
158  corrected = i + len;
159  if (corrected < 0) {
160  corrected = 0;
161  }
162  } else if (i > len) {
163  corrected = len;
164  } else {
165  corrected = i;
166  }
167  return PN_NUM(corrected);
168 }
169 
175 static PN potion_str_slice(Potion *P, PN cl, PN self, PN start, PN end) {
176  char *str = PN_STR_PTR(self);
177  size_t len = potion_cp_strlen_utf8(str);
178  size_t startoffset = potion_utf8char_offset(str, PN_INT(potion_str_slice_index(start, len, 0)));
179  size_t endoffset;
180  if (end < start) {
181  endoffset = potion_utf8char_offset(str, PN_INT(potion_str_slice_index(start+end, len, len)));
182  } else {
183  endoffset = potion_utf8char_offset(str, PN_INT(potion_str_slice_index(end, len, len)));
184  }
185  return potion_str2(P, str + startoffset, endoffset - startoffset);
186 }
187 
190 static PN potion_str_bytes(Potion *P, PN cl, PN self) {
191  return potion_byte_str2(P, PN_STR_PTR(self), PN_STR_LEN(self));
192 }
193 
198 static PN potion_str_add(Potion *P, PN cl, PN self, PN x) {
199  char *s = malloc(PN_STR_LEN(self) + PN_STR_LEN(x));
200  PN str;
201  if (s == NULL) potion_allocation_error();
202  PN_MEMCPY_N(s, PN_STR_PTR(self), char, PN_STR_LEN(self));
203  PN_MEMCPY_N(s + PN_STR_LEN(self), PN_STR_PTR(x), char, PN_STR_LEN(x));
204  str = potion_str2(P, s, PN_STR_LEN(self) + PN_STR_LEN(x));
205  free(s);
206  return str;
207 }
208 
213 static PN potion_str_ord(Potion *P, PN cl, PN self) {
214  self = potion_fwd(self);
215  if (PN_STR_LEN(self) != 1)
216  return PN_NIL;
217  return PN_NUM(PN_STR_PTR(self)[0]);
218 }
219 
224 static PN potion_str_at(Potion *P, PN cl, PN self, PN index) {
225  return potion_str_slice(P, cl, self, index, PN_NUM(PN_INT(index) + 1));
226 }
227 
228 PN potion_byte_str(Potion *P, const char *str) {
229  return potion_byte_str2(P, str, strlen(str));
230 }
231 
232 PN potion_byte_str2(Potion *P, const char *str, size_t len) {
233  vPN(Bytes) s = (struct PNBytes *)potion_bytes(P, len);
234  PN_MEMCPY_N(s->chars, str, char, len);
235  s->chars[len] = '\0';
236  return (PN)s;
237 }
238 
239 PN potion_bytes(Potion *P, size_t len) {
240  size_t siz = BYTES_ALIGN(len + 1);
241  vPN(Bytes) s = PN_ALLOC_N(PN_TBYTES, struct PNBytes, siz);
242  s->siz = (PN_SIZE)siz;
243  s->len = (PN_SIZE)len;
244  return (PN)s;
245 }
246 
247 PN_SIZE pn_printf(Potion *P, PN bytes, const char *format, ...) {
248  PN_SIZE len;
249  va_list args;
250  vPN(Bytes) s = (struct PNBytes *)potion_fwd(bytes);
251 
252  va_start(args, format);
253  len = (PN_SIZE)vsnprintf(NULL, 0, format, args);
254  va_end(args);
255 
256  if (s->len + len + 1 > s->siz) {
257  size_t siz = BYTES_ALIGN(((s->len + len) * BYTES_FACTOR) + 1);
258  PN_REALLOC(s, PN_TBYTES, struct PNBytes, siz);
259  s->siz = (PN_SIZE)siz;
260  }
261 
262  va_start(args, format);
263  vsnprintf(s->chars + s->len, len + 1, format, args);
264  va_end(args);
265 
266  s->len += len;
267  return len;
268 }
269 
270 void potion_bytes_obj_string(Potion *P, PN bytes, PN obj) {
271  potion_bytes_append(P, 0, bytes, potion_send(obj, PN_string));
272 }
273 
278 PN potion_bytes_append(Potion *P, PN cl, PN self, PN str) {
279  vPN(Bytes) s = (struct PNBytes *)potion_fwd(self);
280  PN fstr = potion_fwd(str);
281  PN_SIZE len = PN_STR_LEN(fstr);
282 
283  if (s->len + len + 1 > s->siz) {
284  size_t siz = BYTES_ALIGN(((s->len + len) * BYTES_FACTOR) + 1);
285  PN_REALLOC(s, PN_TBYTES, struct PNBytes, siz);
286  s->siz = (PN_SIZE)siz;
287  }
288 
289  PN_MEMCPY_N(s->chars + s->len, PN_STR_PTR(fstr), char, len);
290  s->len += len;
291  s->chars[s->len] = '\0';
292  return self;
293 }
294 
298 static PN potion_bytes_length(Potion *P, PN cl, PN self) {
299  PN str = potion_fwd(self);
300  return PN_NUM(PN_STR_LEN(str));
301 }
302 
305 // TODO: ensure it's UTF-8 data
307  PN exist = potion_lookup_str(P, PN_STR_PTR(self = potion_fwd(self)));
308  if (exist == PN_NIL) {
309  PN_SIZE len = PN_STR_LEN(self);
310  vPN(String) s = PN_ALLOC_N(PN_TSTRING, struct PNString, len + 1);
311  s->len = len;
312  PN_MEMCPY_N(s->chars, PN_STR_PTR(self), char, len + 1);
313  potion_add_str(P, (PN)s);
314  exist = (PN)s;
315  }
316  return exist;
317 }
318 
321 static PN potion_bytes_print(Potion *P, PN cl, PN self) {
322  self = potion_fwd(self);
323  fwrite(PN_STR_PTR(self), 1, PN_STR_LEN(self), stdout);
324  return PN_NIL;
325 }
326 
331 static PN potion_bytes_each(Potion *P, PN cl, PN self, PN block) {
332  self = potion_fwd(self);
333  char *s = PN_STR_PTR(self);
334  int i;
335  for (i = 0; i < PN_STR_LEN(self); i++) {
336  PN_CLOSURE(block)->method(P, block, P->lobby, potion_byte_str2(P, &s[i], 1));
337  }
338  return PN_NIL;
339 }
340 
345 static PN potion_bytes_at(Potion *P, PN cl, PN self, PN index) {
346  char c;
347  self = potion_fwd(self);
348  index = PN_INT(index);
349  if (index >= PN_STR_LEN(self) || (signed long)index < 0)
350  return PN_NIL;
351  c = PN_STR_PTR(self)[index];
352  return potion_byte_str2(P, &c, 1);
353 }
354 
363 static PN potion_str_cmp(Potion *P, PN cl, PN self, PN str) {
364  if (PN_IS_STR(str)) {
365  return strcmp(PN_STR_PTR(self), PN_STR_PTR(str));
366  } else {
367  return strcmp(PN_STR_PTR(self), PN_STR_PTR(potion_send(PN_string, str)));
368  }
369 }
370 
372  P->strings = PN_CALLOC_N(PN_TSTRINGS, struct PNTable, 0);
373 }
374 
376  PN str_vt = PN_VTABLE(PN_TSTRING);
377  PN byt_vt = PN_VTABLE(PN_TBYTES);
379  potion_method(str_vt, "eval", potion_str_eval, 0);
380  potion_method(str_vt, "length", potion_str_length, 0);
381  potion_method(str_vt, "number", potion_str_number, 0);
382  potion_method(str_vt, "print", potion_str_print, 0);
383  potion_method(str_vt, "string", potion_str_string, 0);
384  potion_method(str_vt, "slice", potion_str_slice, "start=N,end=N");
385  potion_method(str_vt, "bytes", potion_str_bytes, 0);
386  potion_method(str_vt, "+", potion_str_add, "str=S");
387  potion_method(str_vt, "ord", potion_str_ord, 0);
388  potion_method(str_vt, "cmp", potion_str_cmp, "str=o");
389 
391  potion_method(byt_vt, "append", potion_bytes_append, "str=S");
392  potion_method(byt_vt, "length", potion_bytes_length, 0);
393  potion_method(byt_vt, "print", potion_bytes_print, 0);
394  potion_method(byt_vt, "string", potion_bytes_string, 0);
395  potion_method(byt_vt, "ord", potion_str_ord, 0);
396  potion_method(byt_vt, "each", potion_bytes_each, "block=&");
397 }