void zlistx_destroy (zlistx_t **self_p) { assert (self_p); if (*self_p) { zlistx_t *self = *self_p; zlistx_purge (self); free (self->head); free (self); *self_p = NULL; } }
void zlistx_test (bool verbose) { printf (" * zlistx: "); // @selftest zlistx_t *list = zlistx_new (); assert (list); assert (zlistx_size (list) == 0); // Test operations on an empty list assert (zlistx_first (list) == NULL); assert (zlistx_last (list) == NULL); assert (zlistx_next (list) == NULL); assert (zlistx_prev (list) == NULL); assert (zlistx_find (list, "hello") == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); zlistx_purge (list); zlistx_sort (list); // Use item handlers zlistx_set_destructor (list, (zlistx_destructor_fn *) zstr_free); zlistx_set_duplicator (list, (zlistx_duplicator_fn *) strdup); zlistx_set_comparator (list, (zlistx_comparator_fn *) strcmp); // Try simple insert/sort/delete/next assert (zlistx_next (list) == NULL); zlistx_add_end (list, "world"); assert (streq ((char *) zlistx_next (list), "world")); zlistx_add_end (list, "hello"); assert (streq ((char *) zlistx_prev (list), "hello")); zlistx_sort (list); assert (zlistx_size (list) == 2); void *handle = zlistx_find (list, "hello"); char *item1 = (char *) zlistx_item (list); char *item2 = (char *) zlistx_handle_item (handle); assert (item1 == item2); assert (streq (item1, "hello")); zlistx_delete (list, handle); assert (zlistx_size (list) == 1); char *string = (char *) zlistx_detach (list, NULL); assert (streq (string, "world")); free (string); assert (zlistx_size (list) == 0); // Check next/back work // Now populate the list with items zlistx_add_start (list, "five"); zlistx_add_end (list, "six"); zlistx_add_start (list, "four"); zlistx_add_end (list, "seven"); zlistx_add_start (list, "three"); zlistx_add_end (list, "eight"); zlistx_add_start (list, "two"); zlistx_add_end (list, "nine"); zlistx_add_start (list, "one"); zlistx_add_end (list, "ten"); // Test our navigation skills assert (zlistx_size (list) == 10); assert (streq ((char *) zlistx_last (list), "ten")); assert (streq ((char *) zlistx_prev (list), "nine")); assert (streq ((char *) zlistx_prev (list), "eight")); assert (streq ((char *) zlistx_prev (list), "seven")); assert (streq ((char *) zlistx_prev (list), "six")); assert (streq ((char *) zlistx_prev (list), "five")); assert (streq ((char *) zlistx_first (list), "one")); assert (streq ((char *) zlistx_next (list), "two")); assert (streq ((char *) zlistx_next (list), "three")); assert (streq ((char *) zlistx_next (list), "four")); // Sort by alphabetical order zlistx_sort (list); assert (streq ((char *) zlistx_first (list), "eight")); assert (streq ((char *) zlistx_last (list), "two")); // Moving items around handle = zlistx_find (list, "six"); zlistx_move_start (list, handle); assert (streq ((char *) zlistx_first (list), "six")); zlistx_move_end (list, handle); assert (streq ((char *) zlistx_last (list), "six")); zlistx_sort (list); assert (streq ((char *) zlistx_last (list), "two")); // Copying a list zlistx_t *copy = zlistx_dup (list); assert (copy); assert (zlistx_size (copy) == 10); assert (streq ((char *) zlistx_first (copy), "eight")); assert (streq ((char *) zlistx_last (copy), "two")); zlistx_destroy (©); // Delete items while iterating string = (char *) zlistx_first (list); assert (streq (string, "eight")); string = (char *) zlistx_next (list); assert (streq (string, "five")); zlistx_delete (list, zlistx_cursor (list)); string = (char *) zlistx_next (list); assert (streq (string, "four")); zlistx_purge (list); zlistx_destroy (&list); // @end printf ("OK\n"); }
void ziflist_reload (ziflist_t *self) { assert (self); zlistx_t *list = (zlistx_t *) self; zlistx_purge (list); #if defined (HAVE_GETIFADDRS) struct ifaddrs *interfaces; if (getifaddrs (&interfaces) == 0) { struct ifaddrs *interface = interfaces; while (interface) { // On Solaris, loopback interfaces have a NULL in ifa_broadaddr if (interface->ifa_broadaddr && interface->ifa_addr && interface->ifa_addr->sa_family == AF_INET && s_valid_flags (interface->ifa_flags)) { inaddr_t address = *(inaddr_t *) interface->ifa_addr; inaddr_t netmask = *(inaddr_t *) interface->ifa_netmask; inaddr_t broadcast = *(inaddr_t *) interface->ifa_broadaddr; // If the returned broadcast address is the same as source // address, build the broadcast address from the source // address and netmask. if (address.sin_addr.s_addr == broadcast.sin_addr.s_addr) broadcast.sin_addr.s_addr |= ~(netmask.sin_addr.s_addr); interface_t *item = s_interface_new (interface->ifa_name, address, netmask, broadcast); if (item) zlistx_add_end (list, item); } interface = interface->ifa_next; } } freeifaddrs (interfaces); # elif defined (__UNIX__) int sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock != -1) { int num_interfaces = 0; struct ifconf ifconfig = { 0 }; // First ioctl call gets us length of buffer; second call gets us contents if (!ioctl (sock, SIOCGIFCONF, (caddr_t) &ifconfig, sizeof (struct ifconf))) { ifconfig.ifc_buf = (char *) zmalloc (ifconfig.ifc_len); if (!ioctl (sock, SIOCGIFCONF, (caddr_t) &ifconfig, sizeof (struct ifconf))) num_interfaces = ifconfig.ifc_len / sizeof (struct ifreq); } int index; for (index = 0; index < num_interfaces; index++) { struct ifreq *ifr = &ifconfig.ifc_req [index]; // Check interface flags bool is_valid = false; if (!ioctl (sock, SIOCGIFFLAGS, (caddr_t) ifr, sizeof (struct ifreq))) is_valid = s_valid_flags (ifr->ifr_flags); // Get interface properties inaddr_t address = { 0 }; if (!ioctl (sock, SIOCGIFADDR, (caddr_t) ifr, sizeof (struct ifreq))) address = *((inaddr_t *) &ifr->ifr_addr); else is_valid = false; inaddr_t broadcast = { 0 }; if (!ioctl (sock, SIOCGIFBRDADDR, (caddr_t) ifr, sizeof (struct ifreq))) broadcast = *((inaddr_t *) &ifr->ifr_addr); else is_valid = false; inaddr_t netmask = { 0 }; if (!ioctl (sock, SIOCGIFNETMASK, (caddr_t) ifr, sizeof (struct ifreq))) netmask = *((inaddr_t *) &ifr->ifr_addr); else is_valid = false; if (is_valid) { interface_t *item = s_interface_new (ifr->ifr_name, address, netmask, broadcast); if (item) zlistx_add_end (list, item); } } free (ifconfig.ifc_buf); close (sock); } # elif defined (__WINDOWS__) ULONG addr_size = 0; DWORD rc = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &addr_size); assert (rc == ERROR_BUFFER_OVERFLOW); PIP_ADAPTER_ADDRESSES pip_addresses = (PIP_ADAPTER_ADDRESSES) zmalloc (addr_size); rc = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pip_addresses, &addr_size); assert (rc == NO_ERROR); PIP_ADAPTER_ADDRESSES cur_address = pip_addresses; while (cur_address) { PIP_ADAPTER_UNICAST_ADDRESS pUnicast = cur_address->FirstUnicastAddress; PIP_ADAPTER_PREFIX pPrefix = cur_address->FirstPrefix; PWCHAR friendlyName = cur_address->FriendlyName; size_t asciiSize = wcstombs (0, friendlyName, 0) + 1; char *asciiFriendlyName = (char *) zmalloc (asciiSize); wcstombs (asciiFriendlyName, friendlyName, asciiSize); bool valid = (cur_address->OperStatus == IfOperStatusUp) && (pUnicast && pPrefix) && (pUnicast->Address.lpSockaddr->sa_family == AF_INET) && (pPrefix->PrefixLength <= 32); if (valid) { inaddr_t address = *(inaddr_t *) pUnicast->Address.lpSockaddr; inaddr_t netmask; netmask.sin_addr.s_addr = htonl ((0xffffffffU) << (32 - pPrefix->PrefixLength)); inaddr_t broadcast = address; broadcast.sin_addr.s_addr |= ~(netmask.sin_addr.s_addr); interface_t *item = s_interface_new (asciiFriendlyName, address, netmask, broadcast); if (item) zlistx_add_end (list, item); } free (asciiFriendlyName); cur_address = cur_address->Next; } free (pip_addresses); # else # error "Interface detection TBD on this operating system" # endif }
/// // Remove all items from the list, and destroy them if the item destructor // is set. void QZlistx::purge () { zlistx_purge (self); }
static ztrie_node_t * s_ztrie_parse_path (ztrie_t *self, const char *path, int mode) { int state = 0; char *needle, *beginToken = NULL, *beginRegex = NULL; ztrie_node_t *parent = self->root; if (zlistx_size (self->params) > 0) zlistx_purge (self->params); int len = strlen (path); needle = (char *) path; char *needle_stop = needle + len; // Ignore trailing delimiter if (needle[len-1] == self->delimiter) needle_stop -= 1; while (needle < needle_stop + 1) { // It is valid not to have an delimiter at the end of the path if (*needle == self->delimiter || needle == needle_stop) { // Token starts with delimiter ignore everything that comes before if (state == 0) { beginToken = needle + 1; state++; if (mode == MODE_INSERT || mode == MODE_LOOKUP) // Increment so regexes are parsed which is only relevant // during INSERT or LOOKUP. Using different states gives a small // performance boost for matching. state++; } // Token ends with delimiter. else if (state < 3) { int matchType = zlistx_size (self->params) > 0? NODE_TYPE_PARAM: beginRegex? NODE_TYPE_REGEX: NODE_TYPE_STRING; char *matchToken = beginRegex? beginRegex: beginToken; int matchTokenLen = needle - matchToken - (beginRegex? 1: 0); // Illegal token if (matchTokenLen == 0) return NULL; ztrie_node_t *match = NULL; // Asterisk nodes are only allowed at the end of a route if (needle == needle_stop && *matchToken == '*') { if (zlistx_size (parent->children) == 0) { matchType = NODE_TYPE_ASTERISK; matchToken = needle - 1; matchTokenLen = 1; } // Asterisk must be a leaf in the tree else return NULL; } else { matchType = zlistx_size (self->params) > 0? NODE_TYPE_PARAM: beginRegex? NODE_TYPE_REGEX: NODE_TYPE_STRING; matchToken = beginRegex? beginRegex: beginToken; matchTokenLen = needle - matchToken - (beginRegex? 1: 0); } // In insert and lookup mode only do a string comparison if (mode == MODE_INSERT || mode == MODE_LOOKUP) match = s_ztrie_compare_token (parent, matchToken, matchTokenLen); else // Otherwise evaluate regexes if (mode == MODE_MATCH) match = s_ztrie_matches_token (parent, matchToken, matchTokenLen); // Mismatch behavior depends on mode if (!match) { // Append to common prefix if (mode == MODE_INSERT) { // It's not allowed to append on asterisk if (parent->token_type == NODE_TYPE_ASTERISK || (zlistx_size (parent->children) == 1 && ((ztrie_node_t *) (zlistx_first (parent->children)))->token_type == NODE_TYPE_ASTERISK)) return NULL; parent = s_ztrie_node_new (parent, matchToken, matchTokenLen, self->params, matchType); } else // No match for path found if (mode == MODE_MATCH || mode == MODE_LOOKUP) return NULL; } // If a match has been found it becomes the parent for next path token else { parent = match; // In case a asterisk match has been made skip the rest of the route if (parent->token_type == NODE_TYPE_ASTERISK) break; } // Cleanup for next token beginRegex = NULL; if (zlistx_size (self->params) > 0) zlistx_purge (self->params); // Token end equals token begin beginToken = needle + 1; } } else // regex starts with '{' if (state == 2 && *needle == '{') { beginRegex = needle + 1; state++; } else // in the middle of the regex. Found a named regex. if (state == 3 && (*needle == ':')) { zlistx_add_end (self->params, s_strndup (beginRegex, needle - beginRegex)); beginRegex = needle + 1; } else // regex ends with { if (state == 3 && *needle == '}') { state--; } needle++; } // In matching mode the discovered node must be an endpoint if (parent && mode == MODE_MATCH && !parent->endpoint) return NULL; return parent; }