/* * IRC - Internet Relay Chat, ircd/ircd_string.c * Copyright (C) 1999 Thomas Helvey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: ircd_string.c 571 2003-10-28 00:12:17Z r33d $ */ #include "config.h" #include "ircd_string.h" #include "ircd_defs.h" #include "ircd_chattr.h" #include "ircd_log.h" #include #include #include /* * include the character attribute tables here */ #include "chattr.tab.c" /* * Disallow a hostname label to contain anything but a [-a-zA-Z0-9]. * It may not start or end on a '.'. * A label may not end on a '-', the maximum length of a label is * 63 characters. * On top of that (which seems to be the RFC) we demand that the * top domain does not contain any digits. */ static const char* hostExpr = "^([-0-9A-Za-z]*[0-9A-Za-z]\\.)+[A-Za-z]+$"; static regex_t hostRegex; static const char* addrExpr = "^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){1,3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$"; static regex_t addrRegex; int init_string(void) { /* * initialize matching expressions * XXX - expressions MUST be correct, don't change expressions * without testing them. Might be a good idea to exit if these fail, * important code depends on them. * TODO: use regerror for an error message */ if (regcomp(&hostRegex, hostExpr, REG_EXTENDED | REG_NOSUB)) return 0; if (regcomp(&addrRegex, addrExpr, REG_EXTENDED | REG_NOSUB)) return 0; return 1; } int string_is_hostname(const char* str) { assert(0 != str); return (strlen(str) <= HOSTLEN && 0 == regexec(&hostRegex, str, 0, 0, 0)); } int string_is_address(const char* str) { assert(0 != str); return (0 == regexec(&addrRegex, str, 0, 0, 0)); } int string_has_wildcards(const char* str) { assert(0 != str); for ( ; *str; ++str) { if ('\\' == *str) { if ('\0' == *++str) break; } else if ('*' == *str || '?' == *str) return 1; } return 0; } /* * strtoken.c * * Walk through a string of tokens, using a set of separators. * -argv 9/90 */ char* ircd_strtok(char **save, char *str, char *fs) { char *pos = *save; /* keep last position across calls */ char *tmp; if (str) pos = str; /* new string scan */ while (pos && *pos && strchr(fs, *pos) != NULL) pos++; /* skip leading separators */ if (!pos || !*pos) return (pos = *save = NULL); /* string contains only sep's */ tmp = pos; /* now, keep position of the token */ while (*pos && strchr(fs, *pos) == NULL) pos++; /* skip content of the token */ if (*pos) *pos++ = '\0'; /* remove first sep after the token */ else pos = NULL; /* end of string */ *save = pos; return (tmp); } /* * canonize * * reduce a string of duplicate list entries to contain only the unique * items. Unavoidably O(n^2). */ char* canonize(char* buffer) { static char cbuf[BUFSIZE]; char* s; char* t; char* cp = cbuf; int l = 0; char* p = NULL; char* p2; *cp = '\0'; for (s = ircd_strtok(&p, buffer, ","); s; s = ircd_strtok(&p, NULL, ",")) { if (l) { p2 = NULL; for (t = ircd_strtok(&p2, cbuf, ","); t; t = ircd_strtok(&p2, NULL, ",")) if (0 == ircd_strcmp(s, t)) break; else if (p2) p2[-1] = ','; } else t = NULL; if (!t) { if (l) *(cp - 1) = ','; else l = 1; strcpy(cp, s); if (p) cp += (p - s); } else if (p2) p2[-1] = ','; } return cbuf; } /* * ircd_strncpy - optimized strncpy * This may not look like it would be the fastest possible way to do it, * but it generally outperforms everything else on many platforms, * including asm library versions and memcpy, if compiled with the * optimizer on. (-O2 for gcc) --Bleep */ char* ircd_strncpy(char* s1, const char* s2, size_t n) { char* endp = s1 + n; char* s = s1; assert(0 != s1); assert(0 != s2); while (s < endp && (*s++ = *s2++)) ; return s1; } #ifndef FORCEINLINE NTL_HDR_strChattr { NTL_SRC_strChattr } NTL_HDR_strCasediff { NTL_SRC_strCasediff } #endif /* !FORCEINLINE */ /* * Other functions visible externally */ int strnChattr(const char *s, size_t n) { const char *rs = s; unsigned int x = ~0; int r = n; while (*rs && r--) x &= IRCD_CharAttrTab[*rs++ - CHAR_MIN]; return x; } /* * ircd_strcmp - case insensitive comparison of 2 strings * NOTE: see ircd_chattr.h for notes on case mapping. */ int ircd_strcmp(const char *a, const char *b) { const char* ra = a; const char* rb = b; while (ToLower(*ra) == ToLower(*rb)) { if (!*ra++) return 0; else ++rb; } return (*ra - *rb); } /* * ircd_strrcmp - case insensitive reverse comparison of 2 strings * NOTE: see ircd_chattr.h for notes on case mapping. */ int ircd_strrcmp(const char *a, const char *b) { const char* ra = a + strlen(a) - strlen(b); const char* rb = b; while (ToLower(*ra) == ToLower(*rb)) { if (!*ra++) return 0; else ++rb; } return (*ra - *rb); } /* * ircd_strncmp - counted case insensitive comparison of 2 strings * NOTE: see ircd_chattr.h for notes on case mapping. */ int ircd_strncmp(const char *a, const char *b, size_t n) { const char* ra = a; const char* rb = b; int left = n; if (!left--) return 0; while (ToLower(*ra) == ToLower(*rb)) { if (!*ra++ || !left--) return 0; else ++rb; } return (*ra - *rb); } /* * unique_name_vector - create a unique vector of names from * a token separated list * list - [in] a token delimited null terminated character array * token - [in] the token to replace * vector - [out] vector of strings to be returned * size - [in] maximum number of elements to place in vector * Returns count of elements placed into the vector, if the list * is an empty string { '\0' } 0 is returned. * list, and vector must be non-null and size must be > 0 * Empty strings are not placed in the vector or counted. * This function ignores all subsequent tokens when count == size * * NOTE: this function destroys it's input, do not use list after it * is passed to this function */ int unique_name_vector(char* list, char token, char** vector, int size) { int i; int count = 0; char* start = list; char* end; assert(0 != list); assert(0 != vector); assert(0 < size); /* * ignore spurious tokens */ while (token == *start) ++start; for (end = strchr(start, token); end; end = strchr(start, token)) { *end++ = '\0'; /* * ignore spurious tokens */ while (token == *end) ++end; for (i = 0; i < count; ++i) { if (0 == ircd_strcmp(vector[i], start)) break; } if (i == count) { vector[count++] = start; if (count == size) return count; } start = end; } if (*start) { for (i = 0; i < count; ++i) if (0 == ircd_strcmp(vector[i], start)) return count; vector[count++] = start; } return count; } /* * token_vector - create a vector of tokens from * a token separated list * list - [in] a token delimited null terminated character array * token - [in] the token to replace * vector - [out] vector of strings to be returned * size - [in] maximum number of elements to place in vector * returns count of elements placed into the vector, if the list * is an empty string { '\0' } 0 is returned. * list, and vector must be non-null and size must be > 1 * Empty tokens are counted and placed in the list * * NOTE: this function destroys it's input, do not use list after it * is passed to this function */ int token_vector(char* list, char token, char** vector, int size) { int count = 0; char* start = list; char* end; assert(0 != list); assert(0 != vector); assert(1 < size); vector[count++] = start; for (end = strchr(start, token); end; end = strchr(start, token)) { *end++ = '\0'; start = end; if (*start) { vector[count++] = start; if (count < size) continue; } break; } return count; } /* * host_from_uh - get the host.domain part of a user@host.domain string * ripped from get_sockhost */ char* host_from_uh(char* host, const char* userhost, size_t n) { const char* s; assert(0 != host); assert(0 != userhost); if ((s = strchr(userhost, '@'))) ++s; else s = userhost; ircd_strncpy(host, s, n); host[n] = '\0'; return host; } /* * this new faster inet_ntoa was ripped from: * From: Thomas Helvey */ static const char* IpQuadTab[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255" }; /* * ircd_ntoa - rewrote and renamed yet again :) --Bleep * inetntoa - in_addr to string * changed name to remove collision possibility and * so behaviour is guaranteed to take a pointer arg. * -avalon 23/11/92 * inet_ntoa -- returned the dotted notation of a given * internet number * argv 11/90). * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon */ const char* ircd_ntoa(const char* in) { static char buf[20]; return ircd_ntoa_r(buf, in); } /* * reentrant version of above */ const char* ircd_ntoa_r(char* buf, const char* in) { char* p = buf; const unsigned char* a = (const unsigned char*)in; const char* n; assert(0 != buf); assert(0 != in); n = IpQuadTab[*a++]; while ((*p = *n++)) ++p; *p++ = '.'; n = IpQuadTab[*a++]; while ((*p = *n++)) ++p; *p++ = '.'; n = IpQuadTab[*a++]; while ((*p = *n++)) ++p; *p++ = '.'; n = IpQuadTab[*a]; while ((*p = *n++)) ++p; return buf; }