]> jfr.im git - irc/quakenet/newserv.git/blame - lib/irc_string.c
A4STATS: remove E style escapes and switch to createtable for indices
[irc/quakenet/newserv.git] / lib / irc_string.c
CommitLineData
c86edd1d
Q
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
abfd7194
CP
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).
4afb8fd8
CP
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
abfd7194
CP
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
c86edd1d
Q
56static 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
c86edd1d
Q
111int match2strings(const char *patrn, const char *string) {
112 return !match(patrn,string);
113}
114
115int match2patterns(const char *patrn, const char *string) {
116 return !mmatch(patrn,string);
117}
c86edd1d
Q
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 */
729c4971 125unsigned long irc_crc32(const char *s) {
c86edd1d
Q
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 */
729c4971 137unsigned long irc_crc32i(const char *s) {
c86edd1d
Q
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
abfd7194
CP
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.
c86edd1d 156 */
abfd7194
CP
157
158int 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)) {
4afb8fd8 163 if(!*u1++)
c86edd1d 164 return 0;
abfd7194
CP
165
166 u2++;
c86edd1d 167 }
abfd7194 168 return ToLower(*u1) - ToLower(*u2);
c86edd1d
Q
169}
170
abfd7194
CP
171
172int 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)
c86edd1d 178 return 0;
abfd7194
CP
179
180 while(ToLower(*u1) == ToLower(*u2)) {
4afb8fd8 181 if(!*u1++ || !remaining--)
c86edd1d 182 return 0;
abfd7194
CP
183
184 u2++;
c86edd1d 185 }
abfd7194
CP
186
187 return ToLower(*u1) - ToLower(*u2);
c86edd1d
Q
188}
189
190/*
191 * delchars: deletes characters occuring in badchars from string
192 */
193
194char *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
7b1dadec 224const char *IPlongtostr(unsigned long IP) {
c86edd1d
Q
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.
632227f5
CP
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.
c86edd1d
Q
238 */
239
240const char *longtoduration(unsigned long interval, int format) {
241 int days,hours,minutes,seconds;
2fb74c5e 242 static char outstring[100];
c86edd1d
Q
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
632227f5
CP
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) {
2fb74c5e
CP
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) {
ecae4ccc 264 sprintf(outstring+pos,"%d second%s ",seconds,seconds==1?"":"s");
2fb74c5e
CP
265 }
266 }
c86edd1d 267 } else {
2fb74c5e
CP
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);
c86edd1d 273 }
2fb74c5e
CP
274 if (minutes>0 || ((days>0 || hours>0) && seconds>0)) {
275 pos += sprintf(outstring+pos, "%dm ",minutes);
c86edd1d 276 }
2fb74c5e 277 if (seconds>0 || !interval) {
ecae4ccc 278 sprintf(outstring+pos, "%ds ",seconds);
c86edd1d
Q
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
290int durationtolong(const char *string) {
291 int total=0;
292 int current=0;
4afb8fd8 293 char *ch=(char *)string,*och;
c86edd1d
Q
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}
e4366dd3 336
4afb8fd8 337/*
c86edd1d
Q
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.
4afb8fd8
CP
356 *
357 * Kindly BSD licensed by Run for Newserv.
c86edd1d
Q
358 */
359
360int 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
e4366dd3 470/*
c86edd1d
Q
471 * match
472 *
473 * Rewritten by Andrea Cocito (Nemesi), November 1998.
474 *
e4366dd3
CP
475 * Permission kindly granted by Andrea to be used under the BSD license.
476 *
c86edd1d
Q
477 */
478
479/****************** Nemesi's match() ***************/
480
481int 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 */
505got_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 };
522break_while:
523 if (!ch)
524 return 0; /* mask ends with '*', we got it */
525 ch = ToLower(ch);
5902608b 526 do {
c86edd1d
Q
527 if (!*s)
528 return 1;
5902608b 529 } while (ToLower(*s++) != ch);
c86edd1d
Q
530 bs = s; /* Next try start from here */
531
532 /* Check the rest of the "chunk" */
533 while ((ch = *m++))
534 {
535 switch (ch)
536 {
537 case '*':
538 goto got_star;
539 case '\\':
540 if (*m == '?' || *m == '*')
541 ch = *m++;
542 default:
543 if (ToLower(*s) != ToLower(ch))
544 {
545 /* If we've run out of string, give up */
546 if (!*bs)
547 return 1;
548 m = bm;
549 s = bs;
550 goto got_star;
551 };
552 case '?':
553 if (!*s++)
554 return 1;
555 };
556 };
557 if (*s)
558 {
559 m = bm;
560 s = bs;
561 goto got_star;
562 };
563 return 0;
564}
565
e4366dd3 566/*
c86edd1d
Q
567 * collapse()
568 * Collapse a pattern string into minimal components.
569 * This particular version is "in place", so that it changes the pattern
570 * which is to be reduced to a "minimal" size.
571 *
572 * (C) Carlo Wood - 6 Oct 1998
573 * Speedup rewrite by Andrea Cocito, December 1998.
574 * Note that this new optimized alghoritm can *only* work in place.
e4366dd3
CP
575 *
576 * Permission kindly granted by Andrea to be used under the BSD license.
577 *
c86edd1d
Q
578 */
579
580char *collapse(char *mask)
581{
582 int star = 0;
583 char *m = mask;
584 char *b;
585
586 if (m)
587 {
588 do
589 {
590 if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
591 {
592 b = m;
593 do
594 {
595 if (*m == '*')
596 star = 1;
597 else
598 {
599 if (star && (*m != '?'))
600 {
601 *b++ = '*';
602 star = 0;
603 };
604 *b++ = *m;
605 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
606 *b++ = *++m;
607 };
608 }
609 while (*m++);
610 break;
611 }
612 else
613 {
614 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
615 m++;
616 };
617 }
618 while (*m++);
619 };
620 return mask;
621}
622
623/* a protected version of atoi that will return an error if broke/etc */
624int protectedatoi(char *buf, int *value) {
625 char *ep;
626 long lval;
627
628 errno = 0;
629 lval = strtol(buf, &ep, 10);
630 if (buf[0] == '\0' || *ep != '\0')
631 return 0;
632
633 if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || (lval > INT_MAX || lval < INT_MIN))
634 return 0;
635
636 *value = lval;
637 return 1;
638}