Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / ircd_string.c
1 /*
2  * IRC - Internet Relay Chat, ircd/ircd_string.c
3  * Copyright (C) 1999 Thomas Helvey
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 1, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id$
20  */
21 #include "ircd_string.h"
22 #include "ircd_defs.h"
23 #include "ircd_chattr.h"
24 #include <assert.h>
25 #include <string.h>
26 /*
27  * include the character attribute tables here
28  */
29 #include "chattr.tab.c"
30
31 /*
32  * strtoken.c
33  *
34  * Walk through a string of tokens, using a set of separators.
35  * -argv 9/90
36  */
37 char* ircd_strtok(char **save, char *str, char *fs)
38 {
39   char *pos = *save;            /* keep last position across calls */
40   char *tmp;
41
42   if (str)
43     pos = str;                  /* new string scan */
44
45   while (pos && *pos && strchr(fs, *pos) != NULL)
46     pos++;                      /* skip leading separators */
47
48   if (!pos || !*pos)
49     return (pos = *save = NULL);        /* string contains only sep's */
50
51   tmp = pos;                    /* now, keep position of the token */
52
53   while (*pos && strchr(fs, *pos) == NULL)
54     pos++;                      /* skip content of the token */
55
56   if (*pos)
57     *pos++ = '\0';              /* remove first sep after the token */
58   else
59     pos = NULL;                 /* end of string */
60
61   *save = pos;
62   return (tmp);
63 }
64
65 /*
66  * canonize
67  *
68  * reduce a string of duplicate list entries to contain only the unique
69  * items.  Unavoidably O(n^2).
70  */
71 char* canonize(char* buffer)
72 {
73   static char cbuf[BUFSIZE];
74   char*       s;
75   char*       t;
76   char*       cp = cbuf;
77   int         l = 0;
78   char*       p = NULL;
79   char*       p2;
80
81   *cp = '\0';
82
83   for (s = ircd_strtok(&p, buffer, ","); s; s = ircd_strtok(&p, NULL, ","))
84   {
85     if (l)
86     {
87       p2 = NULL;
88       for (t = ircd_strtok(&p2, cbuf, ","); t; t = ircd_strtok(&p2, NULL, ","))
89         if (0 == ircd_strcmp(s, t))
90           break;
91         else if (p2)
92           p2[-1] = ',';
93     }
94     else
95       t = NULL;
96     if (!t)
97     {
98       if (l)
99         *(cp - 1) = ',';
100       else
101         l = 1;
102       strcpy(cp, s);
103       if (p)
104         cp += (p - s);
105     }
106     else if (p2)
107       p2[-1] = ',';
108   }
109   return cbuf;
110 }
111
112 /*
113  * ircd_strncpy - optimized strncpy
114  * This may not look like it would be the fastest possible way to do it,
115  * but it generally outperforms everything else on many platforms,
116  * including asm library versions and memcpy, if compiled with the
117  * optimizer on. (-O2 for gcc) --Bleep
118  */
119 char* ircd_strncpy(char* s1, const char* s2, size_t n)
120 {
121   char* endp = s1 + n;
122   char* s = s1;
123
124   assert(0 != s1);
125   assert(0 != s2);
126
127   while (s < endp && (*s++ = *s2++))
128     ;
129   return s1;
130 }
131
132
133 #ifndef FORCEINLINE
134 NTL_HDR_strChattr { NTL_SRC_strChattr }
135 NTL_HDR_strCasediff { NTL_SRC_strCasediff }
136 #endif /* !FORCEINLINE */
137
138 /*=============================================================================
139  * Other functions visible externally
140  */
141
142 int strnChattr(const char *s, size_t n)
143 {
144   const char *rs = s;
145   unsigned int x = ~0;
146   int r = n;
147   while (*rs && r--)
148     x &= IRCD_CharAttrTab[*rs++ - CHAR_MIN];
149   return x;
150 }
151
152 /*
153  * ircd_strcmp - case insensitive comparison of 2 strings
154  * NOTE: see ircd_chattr.h for notes on case mapping.
155  */
156 int ircd_strcmp(const char *a, const char *b)
157 {
158   const char* ra = a;
159   const char* rb = b;
160   while (ToLower(*ra) == ToLower(*rb)) {
161     if (!*ra++)
162       return 0;
163     else
164       ++rb;
165   }
166   return (*ra - *rb);
167 }
168
169 /*
170  * ircd_strncmp - counted case insensitive comparison of 2 strings
171  * NOTE: see ircd_chattr.h for notes on case mapping.
172  */
173 int ircd_strncmp(const char *a, const char *b, size_t n)
174 {
175   const char* ra = a;
176   const char* rb = b;
177   int left = n;
178   if (!left--)
179     return 0;
180   while (ToLower(*ra) == ToLower(*rb)) {
181     if (!*ra++ || !left--)
182       return 0;
183     else
184       ++rb;
185   }
186   return (*ra - *rb);
187 }
188
189 /*
190  * unique_name_vector - create a unique vector of names from
191  * a token separated list
192  * list   - [in]  a token delimited null terminated character array
193  * token  - [in]  the token to replace 
194  * vector - [out] vector of strings to be returned
195  * size   - [in]  maximum number of elements to place in vector
196  * Returns count of elements placed into the vector, if the list
197  * is an empty string { '\0' } 0 is returned.
198  * list, and vector must be non-null and size must be > 0 
199  * Empty strings <token><token> are not placed in the vector or counted.
200  * This function ignores all subsequent tokens when count == size
201  *
202  * NOTE: this function destroys it's input, do not use list after it
203  * is passed to this function
204  */
205 int unique_name_vector(char* list, char token, char** vector, int size)
206 {
207   int   i;
208   int   count = 0;
209   char* start = list;
210   char* end;
211
212   assert(0 != list);
213   assert(0 != vector);
214   assert(0 < size);
215  
216   /*
217    * ignore spurious tokens
218    */
219   while (token == *start)
220     ++start;
221
222   for (end = strchr(start, token); end; end = strchr(start, token)) {
223     *end++ = '\0';
224     /*
225      * ignore spurious tokens
226      */
227     while (token == *end)
228       ++end;
229     for (i = 0; i < count; ++i) {
230       if (0 == ircd_strcmp(vector[i], start))
231         break;
232     }
233     if (i == count) {
234       vector[count++] = start;
235       if (count == size)
236         return count;
237     }
238     start = end;
239   }
240   if (*start)
241     vector[count++] = start;
242
243   return count;
244 }
245
246 /*
247  * token_vector - create a vector of tokens from
248  * a token separated list
249  * list   - [in]  a token delimited null terminated character array
250  * token  - [in]  the token to replace 
251  * vector - [out] vector of strings to be returned
252  * size   - [in]  maximum number of elements to place in vector
253  * returns count of elements placed into the vector, if the list
254  * is an empty string { '\0' } 0 is returned.
255  * list, and vector must be non-null and size must be > 1 
256  * Empty tokens are counted and placed in the list
257  *
258  * NOTE: this function destroys it's input, do not use list after it
259  * is passed to this function
260  */
261 int token_vector(char* list, char token, char** vector, int size)
262 {
263   int   count = 0;
264   char* start = list;
265   char* end;
266
267   assert(0 != list);
268   assert(0 != vector);
269   assert(1 < size);
270  
271   vector[count++] = start;
272   for (end = strchr(start, token); end; end = strchr(start, token)) {
273     *end++ = '\0';
274     start = end;
275     if (*start) {
276       vector[count++] = start;
277       if (count < size)
278         continue;
279     }
280     break;
281   }
282   return count;
283
284
285 /*
286  * host_from_uh - get the host.domain part of a user@host.domain string
287  * ripped from get_sockhost
288  */
289 char* host_from_uh(char* host, const char* userhost, size_t n)
290 {
291   const char* s;
292
293   assert(0 != host);
294   assert(0 != userhost);
295
296   if ((s = strchr(userhost, '@')))
297     ++s;
298   else
299     s = userhost;
300   ircd_strncpy(host, s, n);
301   host[n] = '\0';
302   return host;
303 }
304
305 /* 
306  * this new faster inet_ntoa was ripped from:
307  * From: Thomas Helvey <tomh@inxpress.net>
308  */
309 static const char* IpQuadTab[] =
310 {
311     "0",   "1",   "2",   "3",   "4",   "5",   "6",   "7",   "8",   "9",
312    "10",  "11",  "12",  "13",  "14",  "15",  "16",  "17",  "18",  "19",
313    "20",  "21",  "22",  "23",  "24",  "25",  "26",  "27",  "28",  "29",
314    "30",  "31",  "32",  "33",  "34",  "35",  "36",  "37",  "38",  "39",
315    "40",  "41",  "42",  "43",  "44",  "45",  "46",  "47",  "48",  "49",
316    "50",  "51",  "52",  "53",  "54",  "55",  "56",  "57",  "58",  "59",
317    "60",  "61",  "62",  "63",  "64",  "65",  "66",  "67",  "68",  "69",
318    "70",  "71",  "72",  "73",  "74",  "75",  "76",  "77",  "78",  "79",
319    "80",  "81",  "82",  "83",  "84",  "85",  "86",  "87",  "88",  "89",
320    "90",  "91",  "92",  "93",  "94",  "95",  "96",  "97",  "98",  "99",
321   "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
322   "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
323   "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
324   "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
325   "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
326   "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
327   "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
328   "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
329   "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
330   "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
331   "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
332   "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
333   "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
334   "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
335   "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
336   "250", "251", "252", "253", "254", "255"
337 };
338
339 /*
340  * ircd_ntoa - rewrote and renamed yet again :) --Bleep
341  * inetntoa - in_addr to string
342  *      changed name to remove collision possibility and
343  *      so behaviour is guaranteed to take a pointer arg.
344  *      -avalon 23/11/92
345  *  inet_ntoa --  returned the dotted notation of a given
346  *      internet number
347  *      argv 11/90).
348  *  inet_ntoa --  its broken on some Ultrix/Dynix too. -avalon
349  */
350 const char* ircd_ntoa(const char* in)
351 {
352   static char buf[20];
353   return ircd_ntoa_r(buf, in);
354 }
355
356 /*
357  * reentrant version of above
358  */
359 const char* ircd_ntoa_r(char* buf, const char* in)
360 {
361   char*                p = buf;
362   const unsigned char* a = (const unsigned char*)in;
363   const char*          n;
364
365   assert(0 != buf);
366   assert(0 != in);
367
368   n = IpQuadTab[*a++];
369   while ((*p = *n++))
370     ++p;
371   *p++ = '.';
372   n = IpQuadTab[*a++];
373   while ((*p = *n++))
374     ++p;
375   *p++ = '.';
376   n = IpQuadTab[*a++];
377   while ((*p = *n++))
378     ++p;
379   *p++ = '.';
380   n = IpQuadTab[*a];
381   while ((*p = *n++))
382     ++p;
383   return buf;
384 }
385
386