Mercurial > hg > nnchat
comparison util.c @ 413:14b685cdbd2c
Rename files.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 24 May 2012 06:41:07 +0300 |
parents | libnnutil.c@3e64acb433e8 |
children | d015ecbd231d |
comparison
equal
deleted
inserted
replaced
412:3e64acb433e8 | 413:14b685cdbd2c |
---|---|
1 /* | |
2 * NNChat - Custom chat client for NewbieNudes.com chatrooms | |
3 * Written by Matti 'ccr' Hämäläinen | |
4 * (C) Copyright 2008-2012 Tecnic Software productions (TNSP) | |
5 */ | |
6 #include "util.h" | |
7 | |
8 | |
9 #define PUSHCHAR(x) th_vputch(&result, &resSize, &resPos, x) | |
10 #define PUSHSTR(x) th_vputs(&result, &resSize, &resPos, x) | |
11 | |
12 char *nn_encode_str1(const char *str) | |
13 { | |
14 const char *s = str; | |
15 char *result; | |
16 size_t resSize, resPos = 0; | |
17 | |
18 if (str == NULL) return NULL; | |
19 | |
20 resSize = strlen(str) + NN_ALLOC_SIZE; | |
21 if ((result = th_malloc(resSize)) == NULL) | |
22 return NULL; | |
23 | |
24 while (*s) | |
25 { | |
26 switch (*s) | |
27 { | |
28 case 32: | |
29 PUSHCHAR('+'); | |
30 break; | |
31 | |
32 default: | |
33 if (th_isalnum(*s)) | |
34 PUSHCHAR(*s); | |
35 else | |
36 { | |
37 char tmpStr[4]; | |
38 snprintf(tmpStr, sizeof(tmpStr), "%2X", (unsigned char) *s); | |
39 PUSHCHAR('%'); | |
40 PUSHSTR(tmpStr); | |
41 } | |
42 break; | |
43 } | |
44 s++; | |
45 } | |
46 PUSHCHAR(0); | |
47 | |
48 return result; | |
49 } | |
50 | |
51 | |
52 static int nn_get_hexdigit(const int c, const int shift) | |
53 { | |
54 int i; | |
55 | |
56 if (c >= 'A' && c <= 'F') | |
57 i = c - 'A' + 10; | |
58 else if (c >= 'a' && c <= 'f') | |
59 i = c - 'a' + 10; | |
60 else if (c >= '0' && c <= '9') | |
61 i = c - '0'; | |
62 else | |
63 return -1; | |
64 | |
65 return i << shift; | |
66 } | |
67 | |
68 | |
69 char *nn_decode_str1(const char *str) | |
70 { | |
71 const char *s = str; | |
72 char *result; | |
73 size_t resSize, resPos = 0; | |
74 int c; | |
75 | |
76 if (str == NULL) return NULL; | |
77 | |
78 resSize = strlen(str) + NN_ALLOC_SIZE; | |
79 if ((result = th_malloc(resSize)) == NULL) | |
80 return NULL; | |
81 | |
82 while (*s) | |
83 { | |
84 switch (*s) | |
85 { | |
86 case '+': | |
87 PUSHCHAR(' '); | |
88 s++; | |
89 break; | |
90 | |
91 case '½': | |
92 /* Escape these .. */ | |
93 PUSHCHAR('½'); | |
94 PUSHCHAR('½'); | |
95 s++; | |
96 break; | |
97 | |
98 case '\r': | |
99 PUSHCHAR(' '); | |
100 s++; | |
101 break; | |
102 | |
103 case '%': | |
104 s++; | |
105 if (*s == '%') | |
106 PUSHCHAR('%'); | |
107 else if ((c = nn_get_hexdigit(*s, 4)) >= 0) | |
108 { | |
109 int i = nn_get_hexdigit(*(++s), 0); | |
110 if (i >= 0) | |
111 { | |
112 PUSHCHAR(c | i); | |
113 } | |
114 else | |
115 { | |
116 PUSHCHAR('§'); | |
117 PUSHCHAR(*s); | |
118 } | |
119 } | |
120 else | |
121 { | |
122 PUSHCHAR('§'); | |
123 PUSHCHAR(*s); | |
124 } | |
125 s++; | |
126 break; | |
127 | |
128 default: | |
129 PUSHCHAR(*s); | |
130 s++; | |
131 } | |
132 } | |
133 PUSHCHAR(0); | |
134 | |
135 return result; | |
136 } | |
137 | |
138 | |
139 char *nn_strip_tags(const char *str) | |
140 { | |
141 const char *s = str; | |
142 char *result; | |
143 size_t resSize, resPos = 0; | |
144 | |
145 if (str == NULL) return NULL; | |
146 | |
147 resSize = strlen(str) + NN_ALLOC_SIZE; | |
148 if ((result = th_malloc(resSize)) == NULL) | |
149 return NULL; | |
150 | |
151 while (*s) | |
152 { | |
153 if (*s == '<') | |
154 { | |
155 while (*s && *s != '>') s++; | |
156 if (*s == '>') s++; | |
157 } | |
158 else | |
159 PUSHCHAR(*s++); | |
160 } | |
161 PUSHCHAR(0); | |
162 | |
163 return result; | |
164 } | |
165 | |
166 | |
167 typedef struct | |
168 { | |
169 char c; | |
170 char *ent; | |
171 } html_entity_t; | |
172 | |
173 | |
174 static const html_entity_t HTMLEntities[] = | |
175 { | |
176 { '<', "<" }, | |
177 { '>', ">" }, | |
178 }; | |
179 | |
180 static const int numHTMLEntities = sizeof(HTMLEntities) / sizeof(HTMLEntities[0]); | |
181 | |
182 | |
183 char *nn_encode_str2(const char *str) | |
184 { | |
185 const char *s = str; | |
186 char *result; | |
187 size_t resSize, resPos = 0; | |
188 | |
189 if (str == NULL) return NULL; | |
190 | |
191 resSize = strlen(str) + NN_ALLOC_SIZE; | |
192 if ((result = th_malloc(resSize)) == NULL) | |
193 return NULL; | |
194 | |
195 while (*s) | |
196 { | |
197 int i; | |
198 BOOL found = FALSE; | |
199 for (i = 0; i < numHTMLEntities; i++) | |
200 if (HTMLEntities[i].c == *s) | |
201 { | |
202 PUSHSTR(HTMLEntities[i].ent); | |
203 found = TRUE; | |
204 break; | |
205 } | |
206 if (!found) PUSHCHAR(*s); | |
207 | |
208 s++; | |
209 } | |
210 PUSHCHAR(0); | |
211 | |
212 return result; | |
213 } | |
214 | |
215 | |
216 char *nn_decode_str2(const char *str) | |
217 { | |
218 const char *s = str; | |
219 char *result; | |
220 size_t resSize, resPos = 0; | |
221 | |
222 if (str == NULL) return NULL; | |
223 | |
224 resSize = strlen(str); | |
225 if ((result = th_malloc(resSize)) == NULL) | |
226 return NULL; | |
227 | |
228 while (*s) | |
229 { | |
230 if (*s == '&') | |
231 { | |
232 int i; | |
233 BOOL found = FALSE; | |
234 for (i = 0; i < numHTMLEntities; i++) | |
235 { | |
236 const html_entity_t *ent = &HTMLEntities[i]; | |
237 int len = strlen(ent->ent); | |
238 if (!strncmp(s, ent->ent, len)) | |
239 { | |
240 PUSHCHAR(ent->c); | |
241 s += len; | |
242 found = TRUE; | |
243 break; | |
244 } | |
245 } | |
246 if (!found) PUSHCHAR(*s++); | |
247 } | |
248 else | |
249 PUSHCHAR(*s++); | |
250 } | |
251 PUSHCHAR(0); | |
252 | |
253 return result; | |
254 } | |
255 | |
256 | |
257 char *nn_dbldecode_str(const char *str) | |
258 { | |
259 char *res, *tmp; | |
260 | |
261 if ((tmp = nn_decode_str1(str)) == NULL) | |
262 return NULL; | |
263 | |
264 res = nn_decode_str2(tmp); | |
265 th_free(tmp); | |
266 | |
267 return res; | |
268 } | |
269 | |
270 | |
271 char *nn_dblencode_str(const char *str) | |
272 { | |
273 char *res, *tmp; | |
274 | |
275 if ((tmp = nn_encode_str2(str)) == NULL) | |
276 return NULL; | |
277 | |
278 res = nn_encode_str1(tmp); | |
279 th_free(tmp); | |
280 | |
281 return res; | |
282 } | |
283 | |
284 | |
285 int nn_editbuf_write(nn_editbuf_t *buf, ssize_t pos, int ch) | |
286 { | |
287 if (buf->len+1 >= buf->size) return -3; | |
288 | |
289 if (pos < 0) | |
290 return -1; | |
291 else if (pos >= buf->len) | |
292 buf->data[buf->len++] = ch; | |
293 else | |
294 buf->data[pos] = ch; | |
295 | |
296 return 0; | |
297 } | |
298 | |
299 | |
300 int nn_editbuf_insert(nn_editbuf_t *buf, ssize_t pos, int ch) | |
301 { | |
302 if (buf->len+1 >= buf->size) return -3; | |
303 | |
304 if (pos < 0) | |
305 return -1; | |
306 else if (pos >= buf->len) | |
307 { | |
308 buf->data[buf->len] = ch; | |
309 } | |
310 else | |
311 { | |
312 memmove(&(buf->data[pos+1]), &(buf->data[pos]), buf->len - pos + 1); | |
313 buf->data[pos] = ch; | |
314 } | |
315 buf->len++; | |
316 return 0; | |
317 } | |
318 | |
319 | |
320 int nn_editbuf_delete(nn_editbuf_t *buf, ssize_t pos) | |
321 { | |
322 if (pos < 0) | |
323 return -1; | |
324 else if (pos < buf->len) | |
325 { | |
326 memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos); | |
327 buf->len--; | |
328 return 0; | |
329 } | |
330 else | |
331 return -2; | |
332 } | |
333 | |
334 | |
335 void nn_editbuf_clear(nn_editbuf_t *buf) | |
336 { | |
337 buf->len = 0; | |
338 buf->pos = 0; | |
339 } | |
340 | |
341 | |
342 nn_editbuf_t * nn_editbuf_new(ssize_t n) | |
343 { | |
344 nn_editbuf_t *res = th_calloc(1, sizeof(nn_editbuf_t)); | |
345 | |
346 res->data = (char *) th_malloc(n); | |
347 res->size = n; | |
348 | |
349 return res; | |
350 } | |
351 | |
352 | |
353 void nn_editbuf_free(nn_editbuf_t *buf) | |
354 { | |
355 if (buf != NULL) | |
356 { | |
357 th_free(buf->data); | |
358 th_free(buf); | |
359 } | |
360 } | |
361 | |
362 | |
363 nn_editbuf_t * nn_editbuf_copy(nn_editbuf_t *src) | |
364 { | |
365 nn_editbuf_t *res; | |
366 | |
367 assert(src != NULL); | |
368 | |
369 if (src == NULL) return NULL; | |
370 | |
371 if ((res = nn_editbuf_new(src->size)) == NULL) | |
372 return NULL; | |
373 | |
374 memcpy(res->data, src->data, src->size); | |
375 res->pos = res->len = src->len; | |
376 | |
377 return res; | |
378 } | |
379 | |
380 | |
381 char * nn_editbuf_get_string(nn_editbuf_t *buf, ssize_t start, ssize_t end) | |
382 { | |
383 char *str; | |
384 ssize_t siz; | |
385 | |
386 if (buf == NULL) | |
387 return NULL; | |
388 | |
389 if (start < 0 || end > buf->len || start >= buf->len) | |
390 return NULL; | |
391 | |
392 if (end < 0) | |
393 { | |
394 siz = buf->len - start + 1; | |
395 } | |
396 else if (start <= end) | |
397 { | |
398 siz = end - start + 1; | |
399 } | |
400 else | |
401 return NULL; | |
402 | |
403 if ((str = th_malloc(siz + 1)) == NULL) | |
404 return NULL; | |
405 | |
406 memcpy(str, buf->data + start, siz); | |
407 str[siz] = 0; | |
408 | |
409 return str; | |
410 } | |
411 | |
412 | |
413 void nn_editbuf_setpos(nn_editbuf_t *buf, ssize_t pos) | |
414 { | |
415 assert(buf != NULL); | |
416 | |
417 if (pos < 0) | |
418 buf->pos = 0; | |
419 else if (pos >= buf->len) | |
420 buf->pos = buf->len; | |
421 else | |
422 buf->pos = pos; | |
423 } | |
424 | |
425 | |
426 static uint8_t nn_hash_user(const char *name) | |
427 { | |
428 /* | |
429 int n = 0; | |
430 const uint8_t *c = (uint8_t *)name; | |
431 uint8_t hash = 0xff; | |
432 | |
433 while (*c && n < 4) | |
434 { | |
435 hash = (hash << 1) ^ tolower(*c); | |
436 c++; n++; | |
437 } | |
438 | |
439 return (hash & 0xff); | |
440 */ | |
441 return tolower(name[0]); | |
442 } | |
443 | |
444 | |
445 static void nn_user_insert(nn_user_t **list, nn_user_t *node) | |
446 { | |
447 node->next = *list; | |
448 *list = node; | |
449 } | |
450 | |
451 | |
452 nn_user_t *nn_userhash_foreach(const nn_userhash_t *list, int (*func)(const nn_user_t *)) | |
453 { | |
454 int i; | |
455 | |
456 if (list == NULL) return NULL; | |
457 | |
458 for (i = 0; i < NN_NUM_BUCKETS; i++) | |
459 if (list->buckets[i] != NULL) | |
460 { | |
461 nn_user_t *curr = list->buckets[i]; | |
462 while (curr != NULL) | |
463 { | |
464 if (func(curr) != 0) | |
465 return curr; | |
466 curr = curr->next; | |
467 } | |
468 } | |
469 | |
470 return NULL; | |
471 } | |
472 | |
473 | |
474 nn_user_t *nn_user_find(const nn_userhash_t *list, const char *name) | |
475 { | |
476 uint8_t hash; | |
477 | |
478 if (list == NULL) return NULL; | |
479 | |
480 hash = nn_hash_user(name); | |
481 if (list->buckets[hash] != NULL) | |
482 { | |
483 nn_user_t *curr = list->buckets[hash]; | |
484 while (curr != NULL) | |
485 { | |
486 if (th_strcasecmp(curr->name, name) == 0) | |
487 return curr; | |
488 curr = curr->next; | |
489 } | |
490 } | |
491 | |
492 return NULL; | |
493 } | |
494 | |
495 | |
496 static nn_user_t *nn_user_match_do(nn_user_t *list, const char *pattern, size_t len) | |
497 { | |
498 nn_user_t *curr = list; | |
499 | |
500 while (curr != NULL) | |
501 { | |
502 if (len <= strlen(curr->name) && th_strncasecmp(curr->name, pattern, len) == 0) | |
503 return curr; | |
504 curr = curr->next; | |
505 } | |
506 return NULL; | |
507 } | |
508 | |
509 | |
510 nn_user_t *nn_user_match(const nn_userhash_t *list, const char *pattern, const char *current, BOOL again) | |
511 { | |
512 uint8_t hash; | |
513 | |
514 if (list == NULL || pattern == NULL) return NULL; | |
515 | |
516 hash = nn_hash_user(pattern); | |
517 if (list->buckets[hash] != NULL) | |
518 { | |
519 nn_user_t *curr = list->buckets[hash]; | |
520 size_t len = strlen(pattern); | |
521 | |
522 if (current != NULL) | |
523 { | |
524 nn_user_t *found = NULL; | |
525 while (curr != NULL) | |
526 { | |
527 if (th_strcasecmp(curr->name, current) == 0) | |
528 { | |
529 if (again) | |
530 return curr; | |
531 found = curr->next; | |
532 break; | |
533 } | |
534 curr = curr->next; | |
535 } | |
536 | |
537 if (found != NULL && (found = nn_user_match_do(found, pattern, len)) != NULL) | |
538 return found; | |
539 } | |
540 | |
541 if ((curr = nn_user_match_do(list->buckets[hash], pattern, len)) != NULL) | |
542 return curr; | |
543 } | |
544 | |
545 return NULL; | |
546 } | |
547 | |
548 | |
549 nn_userhash_t *nn_userhash_new(void) | |
550 { | |
551 return th_calloc(1, sizeof(nn_userhash_t)); | |
552 } | |
553 | |
554 | |
555 int nn_userhash_insert(nn_userhash_t *list, const char *name) | |
556 { | |
557 uint8_t hash; | |
558 nn_user_t *user; | |
559 | |
560 /* Check arguments */ | |
561 if (list == NULL || name == NULL) | |
562 return -1; | |
563 | |
564 /* Check if username is already there */ | |
565 if (nn_user_find(list, name) != NULL) | |
566 return 1; | |
567 | |
568 /* No, we'll add it */ | |
569 if ((user = th_calloc(1, sizeof(nn_user_t))) == NULL) | |
570 return -3; | |
571 | |
572 user->name = th_strdup(name); | |
573 if (user->name == NULL) | |
574 return -4; | |
575 | |
576 hash = nn_hash_user(name); | |
577 nn_user_insert(&(list->buckets[hash]), user); | |
578 | |
579 return 0; | |
580 } | |
581 | |
582 | |
583 int nn_userhash_delete(nn_userhash_t *list, const char *name) | |
584 { | |
585 uint8_t hash; | |
586 | |
587 /* Check arguments */ | |
588 if (list == NULL || name == NULL) | |
589 return -1; | |
590 | |
591 /* Check if username is already there */ | |
592 hash = nn_hash_user(name); | |
593 if (list->buckets[hash] != NULL) | |
594 { | |
595 nn_user_t *curr, *prev; | |
596 curr = list->buckets[hash]; | |
597 prev = NULL; | |
598 while (curr != NULL) | |
599 { | |
600 if (th_strcasecmp(curr->name, name) == 0) | |
601 { | |
602 if (prev) | |
603 prev->next = curr->next; | |
604 else | |
605 list->buckets[hash] = curr->next; | |
606 | |
607 nn_user_free(curr); | |
608 | |
609 return 0; | |
610 } | |
611 else | |
612 { | |
613 prev = curr; | |
614 curr = curr->next; | |
615 } | |
616 } | |
617 } | |
618 | |
619 return 1; | |
620 } | |
621 | |
622 | |
623 nn_user_t *nn_user_copy(const nn_user_t *src) | |
624 { | |
625 nn_user_t *user; | |
626 | |
627 if (src == NULL) return NULL; | |
628 | |
629 if ((user = th_calloc(1, sizeof(nn_user_t))) == NULL) | |
630 return NULL; | |
631 | |
632 /* Copy relevant data */ | |
633 user->name = th_strdup(src->name); | |
634 user->lastspoke = src->lastspoke; | |
635 user->joined = src->joined; | |
636 | |
637 return user; | |
638 } | |
639 | |
640 | |
641 void nn_user_free(nn_user_t *user) | |
642 { | |
643 th_free(user->name); | |
644 th_free(user); | |
645 } | |
646 | |
647 | |
648 void nn_user_free_list(nn_user_t *list) | |
649 { | |
650 nn_user_t *next, *curr = list; | |
651 | |
652 while (curr != NULL) | |
653 { | |
654 next = curr->next; | |
655 nn_user_free(curr); | |
656 curr = next; | |
657 } | |
658 } | |
659 | |
660 void nn_userhash_free(nn_userhash_t *hash) | |
661 { | |
662 int i; | |
663 if (hash == NULL) | |
664 return; | |
665 | |
666 for (i = 0; i < NN_NUM_BUCKETS; i++) | |
667 { | |
668 nn_user_free_list(hash->buckets[i]); | |
669 hash->buckets[i] = NULL; | |
670 } | |
671 | |
672 th_free(hash); | |
673 } | |
674 | |
675 | |
676 char *nn_username_encode(char *str) | |
677 { | |
678 unsigned char *c = (unsigned char *) str; | |
679 if (str == NULL) return NULL; | |
680 for (; *c ; c++) | |
681 if (*c == ' ') *c = 255; | |
682 return str; | |
683 } | |
684 | |
685 | |
686 char *nn_username_decode(char *str) | |
687 { | |
688 unsigned char *c = (unsigned char *) str; | |
689 if (str == NULL) return NULL; | |
690 for (; *c ; c++) | |
691 if (*c == 255) *c = ' '; | |
692 return str; | |
693 } | |
694 | |
695 | |
696 nn_window_t *nn_window_new(const char *id) | |
697 { | |
698 nn_window_t *res = th_calloc(1, sizeof(nn_window_t)); | |
699 | |
700 if (res == NULL) return NULL; | |
701 | |
702 res->data = th_ringbuf_new(NN_BACKBUF_LEN, th_free); | |
703 if (res->data == NULL) | |
704 { | |
705 th_free(res); | |
706 return NULL; | |
707 } | |
708 | |
709 res->id = th_strdup(id); | |
710 | |
711 return res; | |
712 } | |
713 | |
714 | |
715 void nn_window_free(nn_window_t *win) | |
716 { | |
717 if (win != NULL) | |
718 { | |
719 th_ringbuf_free(win->data); | |
720 th_free(win->id); | |
721 th_free(win); | |
722 } | |
723 } | |
724 | |
725 | |
726 nn_strtuple_t *nn_strtuple_new(size_t len, char *str) | |
727 { | |
728 nn_strtuple_t *tuple = th_calloc(1, sizeof(nn_strtuple_t)); | |
729 tuple->len = len; | |
730 tuple->str = str; | |
731 return tuple; | |
732 } | |
733 | |
734 | |
735 void nn_strtuple_free(nn_strtuple_t *tuple) | |
736 { | |
737 th_free(tuple->str); | |
738 th_free(tuple); | |
739 } |