]> jfr.im git - irc/quakenet/newserv.git/blob - lib/irc_string.c
longtoduration formats 0 and 1 back to how they were.
[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
236 * human-friendly output (that is sometimes format 0), and
237 * 2 for a different human-friendly output.
238 */
239
240 const char *longtoduration(unsigned long interval, int format) {
241 int days,hours,minutes,seconds;
242 static char outstring[100];
243 int pos=0;
244
245 seconds=interval%60;
246 minutes=(interval%3600)/60;
247 hours=(interval%(3600*24))/3600;
248 days=interval/(3600*24);
249
250 if(format<2) {
251 if (format==0 || (days>0 && (hours||minutes||seconds))) {
252 sprintf(outstring,"%d day%s, %02d:%02d:%02d",
253 days,(days==1)?"":"s",hours,minutes,seconds);
254 } else if (days>0) {
255 sprintf(outstring, "%d day%s",days,(days==1)?"":"s");
256 } else {
257 if (hours>0) {
258 pos += sprintf(outstring+pos,"%d hour%s ",hours,hours==1?"":"s");
259 }
260 if (minutes>0 || (hours>0 && seconds>0)) {
261 pos += sprintf(outstring+pos,"%d minute%s ",minutes,minutes==1?"":"s");
262 }
263 if (seconds>0 || !interval) {
264 pos += sprintf(outstring+pos,"%d second%s ",seconds,seconds==1?"":"s");
265 }
266 }
267 } else {
268 if (days>0) {
269 pos += sprintf(outstring+pos, "%dd ",days);
270 }
271 if (hours>0 || (days>0 && (minutes>0 || seconds>0))) {
272 pos += sprintf(outstring+pos, "%dh ",hours);
273 }
274 if (minutes>0 || ((days>0 || hours>0) && seconds>0)) {
275 pos += sprintf(outstring+pos, "%dm ",minutes);
276 }
277 if (seconds>0 || !interval) {
278 pos += sprintf(outstring+pos, "%ds ",seconds);
279 }
280 }
281
282 return outstring;
283 }
284
285 /*
286 * durationtolong:
287 * Converts the specified string into a number of seconds, as per O
288 */
289
290 int durationtolong(const char *string) {
291 int total=0;
292 int current=0;
293 char *ch=(char *)string,*och;
294
295 while (*ch) {
296 och=ch;
297 current=strtol(ch,&ch,10);
298 if (och==ch) /* No numbers found */
299 break;
300 if (current) {
301 switch (*ch++) {
302 case '\0':
303 ch--;
304 /* Drop through */
305 case 's':
306 total+=current;
307 break;
308
309 case 'm':
310 total+=(current * 60);
311 break;
312
313 case 'h':
314 total+=(current * 3600);
315 break;
316
317 case 'd':
318 total+=(current * 86400);
319 break;
320
321 case 'w':
322 total+=(current * 604800);
323 break;
324
325 case 'M':
326 total+=(current * 2592000);
327 break;
328
329 case 'y':
330 total+=(current * 31557600);
331 }
332 }
333 }
334 return total;
335 }
336
337 /*
338 * mmatch()
339 *
340 * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
341 *
342 *
343 * From: Carlo Wood <carlo@runaway.xs4all.nl>
344 * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl>
345 * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem)
346 * To: coder-com@mail.undernet.org (coder committee)
347 * Date: Mon, 2 Sep 1996 12:26:01 +0200 (MET DST)
348 *
349 * We need a new function `mmatch(const char *old_mask, const char *new_mask)'
350 * which returns `true' likewise the current `match' (start with copying it),
351 * but which treats '*' and '?' in `new_mask' differently (not "\*" and "\?" !)
352 * as follows: a '*' in `new_mask' does not match a '?' in `old_mask' and
353 * a '?' in `new_mask' does not match a '\?' in `old_mask'.
354 * And ofcourse... a '*' in `new_mask' does not match a '\*' in `old_mask'...
355 * And last but not least, '\?' and '\*' in `new_mask' now become one character.
356 *
357 * Kindly BSD licensed by Run for Newserv.
358 */
359
360 int mmatch(const char *old_mask, const char *new_mask)
361 {
362 const char *m = old_mask;
363 const char *n = new_mask;
364 const char *ma = m;
365 const char *na = n;
366 int wild = 0;
367 int mq = 0, nq = 0;
368
369 while (1)
370 {
371 if (*m == '*')
372 {
373 while (*m == '*')
374 m++;
375 wild = 1;
376 ma = m;
377 na = n;
378 }
379
380 if (!*m)
381 {
382 if (!*n)
383 return 0;
384 for (m--; (m > old_mask) && (*m == '?'); m--)
385 ;
386 if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
387 return 0;
388 if (!wild)
389 return 1;
390 m = ma;
391
392 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
393 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
394 ++na;
395
396 n = ++na;
397 }
398 else if (!*n)
399 {
400 while (*m == '*')
401 m++;
402 return (*m != 0);
403 }
404 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
405 {
406 m++;
407 mq = 1;
408 }
409 else
410 mq = 0;
411
412 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
413 if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
414 {
415 n++;
416 nq = 1;
417 }
418 else
419 nq = 0;
420
421 /*
422 * This `if' has been changed compared to match() to do the following:
423 * Match when:
424 * old (m) new (n) boolean expression
425 * * any (*m == '*' && !mq) ||
426 * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) ||
427 * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) &&
428 * ToLower(*m) == ToLower(*n) &&
429 * !((mq && !nq) || (!mq && nq)))
430 *
431 * Here `any' also includes \* and \? !
432 *
433 * After reworking the boolean expressions, we get:
434 * (Optimized to use boolean shortcircuits, with most frequently occuring
435 * cases upfront (which took 2 hours!)).
436 */
437 if ((*m == '*' && !mq) ||
438 ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
439 (*m == '?' && !mq && (*n != '*' || nq)))
440 {
441 if (*m)
442 m++;
443 if (*n)
444 n++;
445 }
446 else
447 {
448 if (!wild)
449 return 1;
450 m = ma;
451
452 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
453 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
454 ++na;
455
456 n = ++na;
457 }
458 }
459 }
460
461 /*
462 * Compare if a given string (name) matches the given
463 * mask (which can contain wild cards: '*' - match any
464 * number of chars, '?' - match any single character.
465 *
466 * return 0, if match
467 * 1, if no match
468 */
469
470 /*
471 * match
472 *
473 * Rewritten by Andrea Cocito (Nemesi), November 1998.
474 *
475 * Permission kindly granted by Andrea to be used under the BSD license.
476 *
477 */
478
479 /****************** Nemesi's match() ***************/
480
481 int match(const char *mask, const char *string)
482 {
483 const char *m = mask, *s = string;
484 char ch;
485 const char *bm, *bs; /* Will be reg anyway on a decent CPU/compiler */
486
487 /* Process the "head" of the mask, if any */
488 while ((ch = *m++) && (ch != '*'))
489 switch (ch)
490 {
491 case '\\':
492 if (*m == '?' || *m == '*')
493 ch = *m++;
494 default:
495 if (ToLower(*s) != ToLower(ch))
496 return 1;
497 case '?':
498 if (!*s++)
499 return 1;
500 };
501 if (!ch)
502 return *s;
503
504 /* We got a star: quickly find if/where we match the next char */
505 got_star:
506 bm = m; /* Next try rollback here */
507 while ((ch = *m++))
508 switch (ch)
509 {
510 case '?':
511 if (!*s++)
512 return 1;
513 case '*':
514 bm = m;
515 continue; /* while */
516 case '\\':
517 if (*m == '?' || *m == '*')
518 ch = *m++;
519 default:
520 goto break_while; /* C is structured ? */
521 };
522 break_while:
523 if (!ch)
524 return 0; /* mask ends with '*', we got it */
525 ch = ToLower(ch);
526 while (ToLower(*s++) != ch)
527 if (!*s)
528 return 1;
529 bs = s; /* Next try start from here */
530
531 /* Check the rest of the "chunk" */
532 while ((ch = *m++))
533 {
534 switch (ch)
535 {
536 case '*':
537 goto got_star;
538 case '\\':
539 if (*m == '?' || *m == '*')
540 ch = *m++;
541 default:
542 if (ToLower(*s) != ToLower(ch))
543 {
544 /* If we've run out of string, give up */
545 if (!*bs)
546 return 1;
547 m = bm;
548 s = bs;
549 goto got_star;
550 };
551 case '?':
552 if (!*s++)
553 return 1;
554 };
555 };
556 if (*s)
557 {
558 m = bm;
559 s = bs;
560 goto got_star;
561 };
562 return 0;
563 }
564
565 /*
566 * collapse()
567 * Collapse a pattern string into minimal components.
568 * This particular version is "in place", so that it changes the pattern
569 * which is to be reduced to a "minimal" size.
570 *
571 * (C) Carlo Wood - 6 Oct 1998
572 * Speedup rewrite by Andrea Cocito, December 1998.
573 * Note that this new optimized alghoritm can *only* work in place.
574 *
575 * Permission kindly granted by Andrea to be used under the BSD license.
576 *
577 */
578
579 char *collapse(char *mask)
580 {
581 int star = 0;
582 char *m = mask;
583 char *b;
584
585 if (m)
586 {
587 do
588 {
589 if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
590 {
591 b = m;
592 do
593 {
594 if (*m == '*')
595 star = 1;
596 else
597 {
598 if (star && (*m != '?'))
599 {
600 *b++ = '*';
601 star = 0;
602 };
603 *b++ = *m;
604 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
605 *b++ = *++m;
606 };
607 }
608 while (*m++);
609 break;
610 }
611 else
612 {
613 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
614 m++;
615 };
616 }
617 while (*m++);
618 };
619 return mask;
620 }
621
622 /* a protected version of atoi that will return an error if broke/etc */
623 int protectedatoi(char *buf, int *value) {
624 char *ep;
625 long lval;
626
627 errno = 0;
628 lval = strtol(buf, &ep, 10);
629 if (buf[0] == '\0' || *ep != '\0')
630 return 0;
631
632 if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || (lval > INT_MAX || lval < INT_MIN))
633 return 0;
634
635 *value = lval;
636 return 1;
637 }