]> jfr.im git - irc/quakenet/newserv.git/blob - lib/irc_string.c
dd4b748e5204688f7828fbfacaf71a97c619d992
[irc/quakenet/newserv.git] / lib / irc_string.c
1 /* irc_string.c */
2
3 #include "irc_string.h"
4 #include "chattr.tab.c"
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <errno.h>
8
9 /*-
10 * For some sections, the BSD license applies, specifically:
11 * ircd_strcmp ircd_strncmp:
12 *
13 * Copyright (c) 1987
14 * The Regents of the University of California. All rights reserved.
15 *
16 * match/collapse
17 *
18 * Copyright (c) 1998
19 * Andrea Cocito (Nemesi).
20 * Copyright (c)
21 * Run (carlo@runaway.xs4all.nl) 1996
22 *
23 * mmatch/match/collapse
24 *
25 * Copyright (c)
26 * Run (carlo@runaway.xs4all.nl) 1996
27 *
28 * License follows:
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 4. Neither the name of the University/owner? nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 */
54
55
56 static unsigned long crc32_tab[] = {
57 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
58 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
59 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
60 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
61 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
62 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
63 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
64 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
65 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
66 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
67 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
68 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
69 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
70 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
71 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
72 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
73 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
74 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
75 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
76 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
77 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
78 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
79 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
80 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
81 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
82 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
83 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
84 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
85 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
86 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
87 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
88 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
89 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
90 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
91 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
92 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
93 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
94 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
95 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
96 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
97 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
98 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
99 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
100 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
101 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
102 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
103 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
104 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
105 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
106 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
107 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
108 0x2d02ef8dL
109 };
110
111 int match2strings(const char *patrn, const char *string) {
112 return !match(patrn,string);
113 }
114
115 int match2patterns(const char *patrn, const char *string) {
116 return !mmatch(patrn,string);
117 }
118
119 /* This computes a 32 bit CRC of the data in the buffer, and returns the */
120 /* CRC. The polynomial used is 0xedb88320. */
121 /* ============================================================= */
122 /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
123 /* code or tables extracted from it, as desired without restriction. */
124 /* Modified by Fox: no more length parameter, always does the whole string */
125 unsigned long crc32(const char *s) {
126 const char *cp;
127 unsigned long crc32val;
128
129 crc32val = 0;
130 for (cp=s;*cp;cp++) {
131 crc32val=crc32_tab[(crc32val^(*cp)) & 0xff] ^ (crc32val >> 8);
132 }
133 return crc32val;
134 }
135
136 /* Case insensitive version of the above */
137 unsigned long crc32i(const char *s) {
138 const char *cp;
139 unsigned long crc32val;
140
141 crc32val = 0;
142 for (cp=s;*cp;cp++) {
143 crc32val=crc32_tab[(crc32val^(ToLower(*cp))) & 0xff] ^ (crc32val >> 8);
144 }
145 return crc32val;
146 }
147
148 /* ircd_strcmp/ircd_strncmp
149 *
150 * Copyright (c) 1987
151 * The Regents of the University of California. All rights reserved.
152 *
153 * BSD license.
154 *
155 * Modified from this version for ircd usage.
156 */
157
158 int ircd_strcmp(const char *s1, const char *s2) {
159 register const char* u1 = s1;
160 register const char* u2 = s2;
161
162 while(ToLower(*u1) == ToLower(*u2)) {
163 if(!*u1++)
164 return 0;
165
166 u2++;
167 }
168 return ToLower(*u1) - ToLower(*u2);
169 }
170
171
172 int ircd_strncmp(const char *s1, const char *s2, size_t len) {
173 register const char* u1 = s1;
174 register const char* u2 = s2;
175 size_t remaining = len - 1;
176
177 if(!remaining)
178 return 0;
179
180 while(ToLower(*u1) == ToLower(*u2)) {
181 if(!*u1++ || !remaining--)
182 return 0;
183
184 u2++;
185 }
186
187 return ToLower(*u1) - ToLower(*u2);
188 }
189
190 /*
191 * delchars: deletes characters occuring in badchars from string
192 */
193
194 char *delchars(char *string, const char *badchars) {
195 char *s,*d;
196 const char *b;
197 int isbad;
198
199 s=d=string;
200 while (*s) {
201 isbad=0;
202 for(b=badchars;*b;b++) {
203 if (*b==*s) {
204 isbad=1;
205 break;
206 }
207 }
208 if (isbad) {
209 s++;
210 } else {
211 *d++=*s++;
212 }
213 }
214 *d='\0';
215
216 return string;
217 }
218
219 /*
220 * IPtostr:
221 * Converts a long into a "p.q.r.s" IP address
222 */
223
224 const char *IPlongtostr(unsigned long IP) {
225 static char buf[16];
226
227 sprintf(buf,"%lu.%lu.%lu.%lu",(IP>>24),(IP>>16)&255,(IP>>8)&255,IP&255);
228
229 return buf;
230 }
231
232 /*
233 * longtoduration:
234 * Converts a specified number of seconds into a duration string.
235 * format: 0 for the "/stats u" compatible output, 1 for more human-friendly output, 2 for a different human-friendly output.
236 */
237
238 const char *longtoduration(unsigned long interval, int format) {
239 int days,hours,minutes,seconds;
240 static char outstring[100];
241 int pos=0;
242
243 seconds=interval%60;
244 minutes=(interval%3600)/60;
245 hours=(interval%(3600*24))/3600;
246 days=interval/(3600*24);
247
248 if (format==0) {
249 sprintf(outstring,"%d day%s, %02d:%02d:%02d",
250 days,(days==1)?"":"s",hours,minutes,seconds);
251 } else if (format == 1) {
252 if (days>0) {
253 sprintf(outstring, "%d day%s",days,(days==1)?"":"s");
254 } else {
255 if (hours>0) {
256 pos += sprintf(outstring+pos,"%d hour%s ",hours,hours==1?"":"s");
257 }
258 if (minutes>0 || (hours>0 && seconds>0)) {
259 pos += sprintf(outstring+pos,"%d minute%s ",minutes,minutes==1?"":"s");
260 }
261 if (seconds>0 || !interval) {
262 pos += sprintf(outstring+pos,"%d second%s ",seconds,seconds==1?"":"s");
263 }
264 }
265 } else {
266 if (days>0) {
267 pos += sprintf(outstring+pos, "%dd ",days);
268 }
269 if (hours>0 || (days>0 && (minutes>0 || seconds>0))) {
270 pos += sprintf(outstring+pos, "%dh ",hours);
271 }
272 if (minutes>0 || ((days>0 || hours>0) && seconds>0)) {
273 pos += sprintf(outstring+pos, "%dm ",minutes);
274 }
275 if (seconds>0 || !interval) {
276 pos += sprintf(outstring+pos, "%ds ",seconds);
277 }
278 }
279
280 return outstring;
281 }
282
283 /*
284 * durationtolong:
285 * Converts the specified string into a number of seconds, as per O
286 */
287
288 int durationtolong(const char *string) {
289 int total=0;
290 int current=0;
291 char *ch=(char *)string,*och;
292
293 while (*ch) {
294 och=ch;
295 current=strtol(ch,&ch,10);
296 if (och==ch) /* No numbers found */
297 break;
298 if (current) {
299 switch (*ch++) {
300 case '\0':
301 ch--;
302 /* Drop through */
303 case 's':
304 total+=current;
305 break;
306
307 case 'm':
308 total+=(current * 60);
309 break;
310
311 case 'h':
312 total+=(current * 3600);
313 break;
314
315 case 'd':
316 total+=(current * 86400);
317 break;
318
319 case 'w':
320 total+=(current * 604800);
321 break;
322
323 case 'M':
324 total+=(current * 2592000);
325 break;
326
327 case 'y':
328 total+=(current * 31557600);
329 }
330 }
331 }
332 return total;
333 }
334
335 /*
336 * mmatch()
337 *
338 * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
339 *
340 *
341 * From: Carlo Wood <carlo@runaway.xs4all.nl>
342 * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl>
343 * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem)
344 * To: coder-com@mail.undernet.org (coder committee)
345 * Date: Mon, 2 Sep 1996 12:26:01 +0200 (MET DST)
346 *
347 * We need a new function `mmatch(const char *old_mask, const char *new_mask)'
348 * which returns `true' likewise the current `match' (start with copying it),
349 * but which treats '*' and '?' in `new_mask' differently (not "\*" and "\?" !)
350 * as follows: a '*' in `new_mask' does not match a '?' in `old_mask' and
351 * a '?' in `new_mask' does not match a '\?' in `old_mask'.
352 * And ofcourse... a '*' in `new_mask' does not match a '\*' in `old_mask'...
353 * And last but not least, '\?' and '\*' in `new_mask' now become one character.
354 *
355 * Kindly BSD licensed by Run for Newserv.
356 */
357
358 int mmatch(const char *old_mask, const char *new_mask)
359 {
360 const char *m = old_mask;
361 const char *n = new_mask;
362 const char *ma = m;
363 const char *na = n;
364 int wild = 0;
365 int mq = 0, nq = 0;
366
367 while (1)
368 {
369 if (*m == '*')
370 {
371 while (*m == '*')
372 m++;
373 wild = 1;
374 ma = m;
375 na = n;
376 }
377
378 if (!*m)
379 {
380 if (!*n)
381 return 0;
382 for (m--; (m > old_mask) && (*m == '?'); m--)
383 ;
384 if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
385 return 0;
386 if (!wild)
387 return 1;
388 m = ma;
389
390 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
391 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
392 ++na;
393
394 n = ++na;
395 }
396 else if (!*n)
397 {
398 while (*m == '*')
399 m++;
400 return (*m != 0);
401 }
402 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
403 {
404 m++;
405 mq = 1;
406 }
407 else
408 mq = 0;
409
410 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
411 if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
412 {
413 n++;
414 nq = 1;
415 }
416 else
417 nq = 0;
418
419 /*
420 * This `if' has been changed compared to match() to do the following:
421 * Match when:
422 * old (m) new (n) boolean expression
423 * * any (*m == '*' && !mq) ||
424 * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) ||
425 * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) &&
426 * ToLower(*m) == ToLower(*n) &&
427 * !((mq && !nq) || (!mq && nq)))
428 *
429 * Here `any' also includes \* and \? !
430 *
431 * After reworking the boolean expressions, we get:
432 * (Optimized to use boolean shortcircuits, with most frequently occuring
433 * cases upfront (which took 2 hours!)).
434 */
435 if ((*m == '*' && !mq) ||
436 ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
437 (*m == '?' && !mq && (*n != '*' || nq)))
438 {
439 if (*m)
440 m++;
441 if (*n)
442 n++;
443 }
444 else
445 {
446 if (!wild)
447 return 1;
448 m = ma;
449
450 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
451 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
452 ++na;
453
454 n = ++na;
455 }
456 }
457 }
458
459 /*
460 * Compare if a given string (name) matches the given
461 * mask (which can contain wild cards: '*' - match any
462 * number of chars, '?' - match any single character.
463 *
464 * return 0, if match
465 * 1, if no match
466 */
467
468 /*
469 * match
470 *
471 * Rewritten by Andrea Cocito (Nemesi), November 1998.
472 *
473 * Permission kindly granted by Andrea to be used under the BSD license.
474 *
475 */
476
477 /****************** Nemesi's match() ***************/
478
479 int match(const char *mask, const char *string)
480 {
481 const char *m = mask, *s = string;
482 char ch;
483 const char *bm, *bs; /* Will be reg anyway on a decent CPU/compiler */
484
485 /* Process the "head" of the mask, if any */
486 while ((ch = *m++) && (ch != '*'))
487 switch (ch)
488 {
489 case '\\':
490 if (*m == '?' || *m == '*')
491 ch = *m++;
492 default:
493 if (ToLower(*s) != ToLower(ch))
494 return 1;
495 case '?':
496 if (!*s++)
497 return 1;
498 };
499 if (!ch)
500 return *s;
501
502 /* We got a star: quickly find if/where we match the next char */
503 got_star:
504 bm = m; /* Next try rollback here */
505 while ((ch = *m++))
506 switch (ch)
507 {
508 case '?':
509 if (!*s++)
510 return 1;
511 case '*':
512 bm = m;
513 continue; /* while */
514 case '\\':
515 if (*m == '?' || *m == '*')
516 ch = *m++;
517 default:
518 goto break_while; /* C is structured ? */
519 };
520 break_while:
521 if (!ch)
522 return 0; /* mask ends with '*', we got it */
523 ch = ToLower(ch);
524 while (ToLower(*s++) != ch)
525 if (!*s)
526 return 1;
527 bs = s; /* Next try start from here */
528
529 /* Check the rest of the "chunk" */
530 while ((ch = *m++))
531 {
532 switch (ch)
533 {
534 case '*':
535 goto got_star;
536 case '\\':
537 if (*m == '?' || *m == '*')
538 ch = *m++;
539 default:
540 if (ToLower(*s) != ToLower(ch))
541 {
542 /* If we've run out of string, give up */
543 if (!*bs)
544 return 1;
545 m = bm;
546 s = bs;
547 goto got_star;
548 };
549 case '?':
550 if (!*s++)
551 return 1;
552 };
553 };
554 if (*s)
555 {
556 m = bm;
557 s = bs;
558 goto got_star;
559 };
560 return 0;
561 }
562
563 /*
564 * collapse()
565 * Collapse a pattern string into minimal components.
566 * This particular version is "in place", so that it changes the pattern
567 * which is to be reduced to a "minimal" size.
568 *
569 * (C) Carlo Wood - 6 Oct 1998
570 * Speedup rewrite by Andrea Cocito, December 1998.
571 * Note that this new optimized alghoritm can *only* work in place.
572 *
573 * Permission kindly granted by Andrea to be used under the BSD license.
574 *
575 */
576
577 char *collapse(char *mask)
578 {
579 int star = 0;
580 char *m = mask;
581 char *b;
582
583 if (m)
584 {
585 do
586 {
587 if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
588 {
589 b = m;
590 do
591 {
592 if (*m == '*')
593 star = 1;
594 else
595 {
596 if (star && (*m != '?'))
597 {
598 *b++ = '*';
599 star = 0;
600 };
601 *b++ = *m;
602 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
603 *b++ = *++m;
604 };
605 }
606 while (*m++);
607 break;
608 }
609 else
610 {
611 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
612 m++;
613 };
614 }
615 while (*m++);
616 };
617 return mask;
618 }
619
620 /* a protected version of atoi that will return an error if broke/etc */
621 int protectedatoi(char *buf, int *value) {
622 char *ep;
623 long lval;
624
625 errno = 0;
626 lval = strtol(buf, &ep, 10);
627 if (buf[0] == '\0' || *ep != '\0')
628 return 0;
629
630 if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || (lval > INT_MAX || lval < INT_MIN))
631 return 0;
632
633 *value = lval;
634 return 1;
635 }