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 { '<', "&lt;" },
177 { '>', "&gt;" },
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 }