/* * comm_setselect * * This is a needed exported function which will be called to register * and deregister interest in a pending IO state for a given FD. */ void comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler, void *client_data, time_t timeout) { fde_t *F = &fd_table[fd]; s_assert(fd >= 0); s_assert(F->flags.open); if(type & COMM_SELECT_READ) { F->read_handler = handler; F->read_data = client_data; poll_update_pollfds(fd, POLLRDNORM, handler); } if(type & COMM_SELECT_WRITE) { F->write_handler = handler; F->write_data = client_data; poll_update_pollfds(fd, POLLWRNORM, handler); } if(timeout) F->timeout = CurrentTime + (timeout / 1000); }
/* * comm_setselect * * This is a needed exported function which will be called to register * and deregister interest in a pending IO state for a given FD. */ void comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler, void *client_data) { fde_t *F = &fd_table[fd]; s_assert(fd >= 0); s_assert(F->flags.open); /* Update the list, even though we're not using it .. */ F->list = list; if(type & COMM_SELECT_READ) { kq_update_events(F, EVFILT_READ, handler); F->read_handler = handler; F->read_data = client_data; } if(type & COMM_SELECT_WRITE) { kq_update_events(F, EVFILT_WRITE, handler); F->write_handler = handler; F->write_data = client_data; } }
/* mod_add_cmd * * inputs - command name * - pointer to struct Message * output - none * side effects - load this one command name * msg->count msg->bytes is modified in place, in * modules address space. Might not want to do that... */ void mod_add_cmd(struct Message *msg) { s_assert(msg != NULL); if(msg == NULL) return; if(hash_find(HASH_COMMAND, msg->cmd) != NULL) return; hash_add(HASH_COMMAND, msg->cmd, msg); msg->count = 0; msg->rcount = 0; msg->bytes = 0; }
static int mr_starttls(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { #ifdef HAVE_LIBCRYPTO ssl_ctl_t *ctl; rb_fde_t *F[2]; if (!MyConnect(client_p)) return 0; if (!ssl_ok || !get_ssld_count()) { sendto_one_numeric(client_p, ERR_STARTTLS, form_str(ERR_STARTTLS), "TLS is not configured"); return 1; } if (rb_socketpair(AF_UNIX, SOCK_STREAM, 0, &F[0], &F[1], "STARTTLS ssld session") == -1) { ilog_error("error creating SSL/TLS socketpair for ssld slave"); sendto_one_numeric(client_p, ERR_STARTTLS, form_str(ERR_STARTTLS), "Unable to create SSL/TLS socketpair for ssld offload slave"); return 1; } s_assert(client_p->localClient != NULL); /* clear out any remaining plaintext lines */ rb_linebuf_donebuf(&client_p->localClient->buf_recvq); sendto_one_numeric(client_p, RPL_STARTTLS, form_str(RPL_STARTTLS)); send_queued(client_p); ctl = start_ssld_accept(client_p->localClient->F, F[1], rb_get_fd(F[0])); if (ctl != NULL) { del_from_cli_fd_hash(client_p); client_p->localClient->F = F[0]; add_to_cli_fd_hash(client_p); client_p->localClient->ssl_ctl = ctl; SetSSL(client_p); } else return 1; #else sendto_one_numeric(client_p, ERR_STARTTLS, form_str(ERR_STARTTLS), "TLS is not configured"); #endif return 0; }
/* * find a spare slot in the fd list. We can optimise this out later! * -- adrian */ static inline int poll_findslot(void) { int i; for (i = 0; i < MAXCONNECTIONS; i++) { if(pollfd_list.pollfds[i].fd == -1) { /* MATCH!!#$*&$ */ return i; } } s_assert(1 == 0); /* NOTREACHED */ return -1; }
/* clean_user_name() * * input - username * output - none * side effects - walks through the username, returning 0 if erroneous */ static int clean_user_name(char *user) { s_assert(user); if(user == NULL) return 0; for (; *user; user++) { if(!IsUserChar(*user)) return 0; } return 1; }
/* mod_add_cmd * * inputs - command name * - pointer to struct Message * output - none * side effects - load this one command name * msg->count msg->bytes is modified in place, in * modules address space. Might not want to do that... */ void mod_add_cmd(struct Message *msg) { s_assert(msg != NULL); if(msg == NULL) return; if (rb_dictionary_find(cmd_dict, msg->cmd) != NULL) return; msg->count = 0; msg->rcount = 0; msg->bytes = 0; rb_dictionary_add(cmd_dict, msg->cmd, msg); }
void add_history(struct Client *client_p, int online) { struct Whowas *who = &WHOWAS[whowas_next]; s_assert(NULL != client_p); if(client_p == NULL) return; if(who->hashv != -1) { if(who->online) del_whowas_from_clist(&(who->online->whowas), who); del_whowas_from_list(&WHOWASHASH[who->hashv], who); } who->hashv = hash_whowas_name(client_p->name); who->logoff = rb_current_time(); /* * NOTE: strcpy ok here, the sizes in the client struct MUST * match the sizes in the whowas struct */ rb_strlcpy(who->name, client_p->name, sizeof(who->name)); strcpy(who->username, client_p->username); strcpy(who->hostname, client_p->host); strcpy(who->realname, client_p->info); strcpy(who->suser, client_p->user->suser); if(!EmptyString(client_p->sockhost) && strcmp(client_p->sockhost, "0") && show_ip(NULL, client_p)) strcpy(who->sockhost, client_p->sockhost); else who->sockhost[0] = '\0'; who->servername = scache_get_name(client_p->servptr->serv->nameinfo); if(online) { who->online = client_p; add_whowas_to_clist(&(client_p->whowas), who); } else who->online = NULL; add_whowas_to_list(&WHOWASHASH[who->hashv], who); whowas_next++; if(whowas_next == NICKNAMEHISTORYLENGTH) whowas_next = 0; }
/* * close_listener - close a single listener */ void close_listener(struct Listener *listener) { s_assert(listener != NULL); if(listener == NULL) return; if(listener->F != NULL) { rb_close(listener->F); listener->F = NULL; } listener->active = 0; if(listener->ref_count) return; free_listener(listener); }
int fbgetc(FBFILE * fb) { s_assert(fb); if(fb == NULL) { errno = EINVAL; return -1; } if(fb->pbptr) { if((fb->pbptr == (fb->pbuf + BUFSIZ)) || (!*fb->pbptr)) fb->pbptr = NULL; } if(fb->ptr < fb->endp || fbfill(fb) > 0) return *fb->ptr++; return EOF; }
void Graphics::Initialize(const GraphicsConfig &config) { s_assert(!Available()); mConfig = config; switch (mConfig.Type) { case GraphicsType::OPENGL3: mCanvas = new OpenGLCanvas; mRenderer = new OpenGLRenderer; mResourceManager = new OpenGLGraphicsResourceManager; break; default: GetLog().Error("[Graphics::Initialize] unsupport GraphicsType!\n"); break; } mRenderer->Initialize(mConfig); mCanvas->Initialize(); mResourceManager->Initialize(mConfig); }
/* clean_nick_name() * * input - nickname * output - none * side effects - walks through the nickname, returning 0 if erroneous */ static int clean_nick_name(char *nick) { s_assert(nick); if(nick == NULL) return 0; /* nicks cant start with a digit or -, and must have a length */ if(*nick == '-' || IsDigit(*nick) || !*nick) return 0; for (; *nick; nick++) { if(!IsNickChar(*nick)) return 0; } return 1; }
/* * close_listener - close a single listener */ void close_listener(struct Listener *listener) { s_assert(listener != NULL); if(listener == NULL) return; if(listener->fd >= 0) { comm_close(listener->fd); listener->fd = -1; } listener->active = 0; if(listener->ref_count) return; free_listener(listener); }
void fbungetc(char c, FBFILE * fb) { s_assert(fb); if(fb == NULL) { errno = EINVAL; return; } if(!fb->pbptr) { fb->pbptr = fb->pbuf + BUFSIZ; } if(fb->pbptr != fb->pbuf) { fb->pbptr--; *fb->pbptr = c; } }
/* * get_listener_name - return displayable listener name and port * returns "host.foo.org:6667" for a given listener */ const char * get_listener_name(const struct Listener *listener) { static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4]; int port = 0; s_assert(NULL != listener); if(listener == NULL) return NULL; #ifdef RB_IPV6 if(listener->addr.ss_family == AF_INET6) port = ntohs(((const struct sockaddr_in6 *)&listener->addr)->sin6_port); else #endif port = ntohs(((const struct sockaddr_in *)&listener->addr)->sin_port); rb_snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name, listener->name, port); return buf; }
/* * add_connection - creates a client which has just connected to us on * the given fd. The sockhost field is initialized with the ip# of the host. * The client is sent to the auth module for verification, and not put in * any client list yet. */ static void add_connection(struct Listener *listener, int fd, struct sockaddr *sai) { struct Client *new_client; s_assert(NULL != listener); /* * get the client socket name from the socket * the client has already been checked out in accept_connection */ new_client = make_client(NULL); memcpy(&new_client->localClient->ip, sai, sizeof(struct irc_sockaddr_storage)); /* * copy address to 'sockhost' as a string, copy it to host too * so we have something valid to put into error messages... */ inetntop_sock((struct sockaddr *) &new_client->localClient->ip, new_client->sockhost, sizeof(new_client->sockhost)); strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host)); #ifdef IPV6 if(new_client->localClient->ip.ss_family == AF_INET6 && ConfigFileEntry.dot_in_ip6_addr == 1) { strlcat(new_client->host, ".", sizeof(new_client->host)); } #endif new_client->localClient->fd = fd; new_client->localClient->listener = listener; ++listener->ref_count; if(check_reject(new_client)) return; start_auth(new_client); }
void add_history(struct Client *client_p, int online) { struct Whowas *who = &WHOWAS[whowas_next]; s_assert(NULL != client_p); if(client_p == NULL) return; if(who->hashv != -1) { if(who->online) del_whowas_from_clist(&(who->online->whowas), who); del_whowas_from_list(&WHOWASHASH[who->hashv], who); } who->hashv = hash_whowas_name(client_p->name); who->logoff = CurrentTime; /* * NOTE: strcpy ok here, the sizes in the client struct MUST * match the sizes in the whowas struct */ strlcpy(who->name, client_p->name, sizeof(who->name)); strcpy(who->username, client_p->username); strcpy(who->hostname, client_p->host); strcpy(who->realname, client_p->info); who->servername = client_p->user->server; if(online) { who->online = client_p; add_whowas_to_clist(&(client_p->whowas), who); } else who->online = NULL; add_whowas_to_list(&WHOWASHASH[who->hashv], who); whowas_next++; if(whowas_next == NICKNAMEHISTORYLENGTH) whowas_next = 0; }
void add_history(struct Client *client_p, int online) { struct Whowas *who = &WHOWAS[whowas_next]; s_assert(NULL != client_p); if (client_p == NULL) return; if (who->hashv != -1) { if (who->online) del_whowas_from_clist(&(who->online->whowas), who); del_whowas_from_list(&WHOWASHASH[who->hashv], who); } who->hashv = hash_whowas_name(client_p->name); who->logoff = rb_current_time(); strcpy(who->name, client_p->name); strcpy(who->username, client_p->username); strcpy(who->hostname, client_p->host); strcpy(who->virthost, client_p->virthost); strcpy(who->realname, client_p->info); who->cloak = IsCloaked(client_p); who->servername = client_p->servptr->name; if (online) { who->online = client_p; add_whowas_to_clist(&(client_p->whowas), who); } else who->online = NULL; add_whowas_to_list(&WHOWASHASH[who->hashv], who); whowas_next++; if (whowas_next == NICKNAMEHISTORYLENGTH) whowas_next = 0; }
const char * find_or_add(const char *name) { int hash_index; SCACHE *ptr; ptr = scache_hash[hash_index = hash(name)]; for (; ptr; ptr = ptr->next) { if(!irccmp(ptr->name, name)) return (ptr->name); } ptr = (SCACHE *) MyMalloc(sizeof(SCACHE)); s_assert(0 != ptr); strlcpy(ptr->name, name, sizeof(ptr->name)); ptr->next = scache_hash[hash_index]; scache_hash[hash_index] = ptr; return ptr->name; }
/* * skip to end of line or the crlfs, return the number of bytes .. */ static inline int linebuf_skip_crlf(char *ch, int len) { int orig_len = len; /* First, skip until the first non-CRLF */ for (; len; len--, ch++) { if(*ch == '\r') break; else if(*ch == '\n') break; } /* Then, skip until the last CRLF */ for (; len; len--, ch++) { if((*ch != '\r') && (*ch != '\n')) break; } s_assert(orig_len > len); return (orig_len - len); }
ResourceStatus OpenGLShaderFactory::Create(OpenGLShader &resource, DataPtr data) { auto type = GLEnumFromShaderType(resource.Config.Type); auto source = resource.Config.Source.c_str(); int32 length = resource.Config.Source.length(); auto shader = glCreateShader(type); s_assert(shader != 0); glShaderSource(shader, 1, &source, &length); glCompileShader(shader); auto status = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); #if SAM_DEBUG auto log_length = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); if (status == GL_FALSE && log_length > 0) { GetLog().Debug("[shader source]:\n%s\n\n", source); auto log = static_cast<GLchar *>(malloc(log_length)); glGetShaderInfoLog(shader, log_length, &log_length, log); GetLog().Debug("[compile log]:\n%s\n\n", log); free(log); } #endif if (status == GL_FALSE) { glDeleteShader(shader); shader = 0; } resource.ShaderID = shader; return ResourceStatus::COMPLETED; }
void Graphics::SetRendererType(GraphicsType type) { s_assert(Available()); mRenderer->Finalize(); mCanvas->Finalize(); mResourceManager->Finalize(); delete mRenderer; delete mResourceManager; mConfig.Type = type; switch (mConfig.Type) { case GraphicsType::OPENGL3: mRenderer = new OpenGLRenderer; mCanvas = new OpenGLCanvas; mResourceManager = new OpenGLGraphicsResourceManager; break; default: GetLog().Error("[Graphics::Initialize] unsupport GraphicsType!\n"); break; } mRenderer->Initialize(mConfig); mCanvas->Initialize(); mResourceManager->Initialize(mConfig); }
void free_listener(struct Listener *listener) { s_assert(NULL != listener); if(listener == NULL) return; /* * remove from listener list */ if(listener == ListenerPollList) ListenerPollList = listener->next; else { struct Listener *prev = ListenerPollList; for (; prev; prev = prev->next) { if(listener == prev->next) { prev->next = listener->next; break; } } } /* free */ rb_free(listener); }
/* * add_connection - creates a client which has just connected to us on * the given fd. The sockhost field is initialized with the ip# of the host. * The client is sent to the auth module for verification, and not put in * any client list yet. */ static void add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, struct sockaddr *lai, void *ssl_ctl) { struct Client *new_client; s_assert(NULL != listener); /* * get the client socket name from the socket * the client has already been checked out in accept_connection */ new_client = make_client(NULL); memcpy(&new_client->localClient->ip, sai, sizeof(struct rb_sockaddr_storage)); memcpy(&new_client->preClient->lip, lai, sizeof(struct rb_sockaddr_storage)); /* * copy address to 'sockhost' as a string, copy it to host too * so we have something valid to put into error messages... */ rb_inet_ntop_sock((struct sockaddr *)&new_client->localClient->ip, new_client->sockhost, sizeof(new_client->sockhost)); rb_strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host)); new_client->localClient->F = F; add_to_cli_fd_hash(new_client); new_client->localClient->listener = listener; new_client->localClient->ssl_ctl = ssl_ctl; if(ssl_ctl != NULL || rb_fd_ssl(F)) SetSSL(new_client); ++listener->ref_count; start_auth(new_client); }
/* * valid_username - check username for validity * * Inputs - pointer to user * Output - YES if valid, NO if not * Side effects - NONE * * Absolutely always reject any '*' '!' '?' '@' in an user name * reject any odd control characters names. * Allow '.' in username to allow for "first.last" * style of username */ bool valid_username(const char *username) { int dots = 0; const char *p = username; s_assert(NULL != p); if(username == NULL) return false; if('~' == *p) ++p; /* reject usernames that don't start with an alphanum * i.e. reject jokers who have '-@somehost' or '.@somehost' * or "-hi-@somehost", "h-----@somehost" would still be accepted. */ if(!IsAlNum(*p)) return false; while(*++p) { if((*p == '.') && ConfigFileEntry.dots_in_ident) { dots++; if(dots > ConfigFileEntry.dots_in_ident) return false; if(!IsUserChar(p[1])) return false; } else if(!IsUserChar(*p)) return false; } return true; }
/* mod_add_cmd * * inputs - command name * - pointer to struct Message * output - none * side effects - load this one command name * msg->count msg->bytes is modified in place, in * modules address space. Might not want to do that... */ void mod_add_cmd(struct Message *msg) { struct MessageHash *ptr; struct MessageHash *last_ptr = NULL; struct MessageHash *new_ptr; int msgindex; s_assert(msg != NULL); if(msg == NULL) return; msgindex = hash(msg->cmd); for (ptr = msg_hash_table[msgindex]; ptr; ptr = ptr->next) { if(strcasecmp(msg->cmd, ptr->cmd) == 0) return; /* Its already added */ last_ptr = ptr; } new_ptr = (struct MessageHash *) MyMalloc(sizeof(struct MessageHash)); new_ptr->next = NULL; DupString(new_ptr->cmd, msg->cmd); new_ptr->msg = msg; msg->count = 0; msg->rcount = 0; msg->bytes = 0; if(last_ptr == NULL) msg_hash_table[msgindex] = new_ptr; else last_ptr->next = new_ptr; }
static int fbfill(FBFILE * fb) { int n; s_assert(fb); if(fb == NULL) { errno = EINVAL; return -1; } if(fb->flags) return -1; n = read(fb->fd, fb->buf, BUFSIZ); if(0 < n) { fb->ptr = fb->buf; fb->endp = fb->buf + n; } else if(n < 0) fb->flags |= FB_FAIL; else fb->flags |= FB_EOF; return n; }
ResourceStatus OpenGLTextureFactory::Create(OpenGLTexture &resource, DataPtr data) { s_assert(data != nullptr); auto &config = resource.Config; resource.Target = GLEnumFromTextureType(config.Type); OpenGLRenderer::Get().ResetTexture(); glGenTextures(1, &resource.TextureID); glActiveTexture(GL_TEXTURE0); glBindTexture(resource.Target, resource.TextureID); s_assert(resource.TextureID != 0); s_assert(config.MipMapCount == 1 || !(IsTextureFilterModeUseMipmap(config.FilterModeMin) || IsTextureFilterModeUseMipmap(config.FilterModeMag))); glTexParameteri(resource.Target, GL_TEXTURE_MIN_FILTER, GLEnumFromTextureFilterMode(config.FilterModeMin)); glTexParameteri(resource.Target, GL_TEXTURE_MAG_FILTER, GLEnumFromTextureFilterMode(config.FilterModeMag)); s_assert(config.Type != TextureType::TEXTURE_CUBE || (config.WrapModeS == TextureWrapMode::CLAMP_TO_EDGE && config.WrapModeT == TextureWrapMode::CLAMP_TO_EDGE && config.WrapModeR == TextureWrapMode::CLAMP_TO_EDGE)); glTexParameteri(resource.Target, GL_TEXTURE_WRAP_S, GLEnumFromTextureWrapMode(config.WrapModeS)); glTexParameteri(resource.Target, GL_TEXTURE_WRAP_T, GLEnumFromTextureWrapMode(config.WrapModeT)); glTexParameteri(resource.Target, GL_TEXTURE_WRAP_R, GLEnumFromTextureWrapMode(config.WrapModeR)); auto faceCount = config.Type == TextureType::TEXTURE_CUBE ? GraphicsConfig::CubeTextureFaceCount : 1; auto isCompressed = IsCompressedPixelFormat(config.ColorFormat); auto internalFormat = GLEnumFromPixelFormatAsInternal(config.ColorFormat); auto layout = isCompressed ? 0 : GLEnumFromPixelFormatAsLayout(config.ColorFormat); auto format = GLEnumFromPixelFormatAsFormat(config.ColorFormat); for (auto faceIndex = 0; faceIndex < faceCount; ++faceIndex) { auto realTarget = resource.Target; if (config.Type == TextureType::TEXTURE_CUBE) { switch (faceIndex) { case 0: realTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X; break; case 1: realTarget = GL_TEXTURE_CUBE_MAP_NEGATIVE_X; break; case 2: realTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_Y; break; case 3: realTarget = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; break; case 4: realTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_Z; break; default: realTarget = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; break; } } for (auto mipMapIndex = 0; mipMapIndex < config.MipMapCount; ++mipMapIndex) { s_assert(config.DataSize[faceIndex][mipMapIndex] > 0); auto width = config.Width >> mipMapIndex; auto height = config.Height >> mipMapIndex; if (width == 0) width = 1; if (height == 0) height = 1; if (isCompressed) { s_assert(config.DataOffset[faceIndex][mipMapIndex] + config.DataSize[faceIndex][mipMapIndex] <= data->GetSize()); glCompressedTexImage2D(realTarget, mipMapIndex, internalFormat, width, height, 0, config.DataSize[faceIndex][mipMapIndex], data->GetBuffer(config.DataOffset[faceIndex][mipMapIndex])); } else { s_assert(config.DataOffset[faceIndex][mipMapIndex] + SizeOfPixelFormat(config.ColorFormat) * width * height <= data->GetSize()); glTexImage2D(realTarget, mipMapIndex, internalFormat, width, height, 0, format, layout, data->GetBuffer(config.DataOffset[faceIndex][mipMapIndex])); } } } return ResourceStatus::COMPLETED; }
/* match() * * Compare if a given string (name) matches the given * mask (which can contain wild cards: '*' - match any * number of chars, '?' - match any single character. * * return 1, if match * 0, if no match * * Originally by Douglas A Lewis ([email protected]) */ #define MATCH_MAX_CALLS 512 /* ACK! This dies when it's less that this and we have long lines to parse */ int match(const char *mask, const char *name) { const unsigned char *m = (const unsigned char *)mask; const unsigned char *n = (const unsigned char *)name; const unsigned char *ma = (const unsigned char *)mask; const unsigned char *na = (const unsigned char *)name; int wild = 0; int calls = 0; s_assert(mask != NULL); s_assert(name != NULL); if(!mask || !name) return 0; /* if the mask is "*", it matches everything */ if((*m == '*') && (*(m + 1) == '\0')) return 1; while(calls++ < MATCH_MAX_CALLS) { if(*m == '*') { /* * XXX - shouldn't need to spin here, the mask should have been * collapsed before match is called */ while(*m == '*') m++; wild = 1; ma = m; na = n; } if(!*m) { if(!*n) return 1; for(m--; (m > (const unsigned char *)mask) && (*m == '?'); m--) ; if(*m == '*' && (m > (const unsigned char *)mask)) return 1; if(!wild) return 0; m = ma; n = ++na; } else if(!*n) { /* * XXX - shouldn't need to spin here, the mask should have been * collapsed before match is called */ while(*m == '*') m++; return (*m == 0); } if(ToLower(*m) != ToLower(*n) && *m != '?') { if(!wild) return 0; m = ma; n = ++na; } else { if(*m) m++; if(*n) n++; } } return 0; }
/* match_esc() * * The match() function with support for escaping characters such * as '*', '?', '#' and '@' */ int match_esc(const char *mask, const char *name) { const unsigned char *m = (const unsigned char *)mask; const unsigned char *n = (const unsigned char *)name; const unsigned char *ma = (const unsigned char *)mask; const unsigned char *na = (const unsigned char *)name; int wild = 0; int calls = 0; int quote = 0; int match1 = 0; s_assert(mask != NULL); s_assert(name != NULL); if(!mask || !name) return 0; /* if the mask is "*", it matches everything */ if((*m == '*') && (*(m + 1) == '\0')) return 1; while(calls++ < MATCH_MAX_CALLS) { if(quote) quote++; if(quote == 3) quote = 0; if(*m == '\\' && !quote) { m++; quote = 1; continue; } if(!quote && *m == '*') { /* * XXX - shouldn't need to spin here, the mask should have been * collapsed before match is called */ while(*m == '*') m++; wild = 1; ma = m; na = n; if(*m == '\\') { m++; /* This means it is an invalid mask -A1kmm. */ if(!*m) return 0; quote++; continue; } } if(!*m) { if(!*n) return 1; if(quote) return 0; for(m--; (m > (const unsigned char *)mask) && (*m == '?'); m--) ;; if(*m == '*' && (m > (const unsigned char *)mask)) return 1; if(!wild) return 0; m = ma; n = ++na; } else if(!*n) { /* * XXX - shouldn't need to spin here, the mask should have been * collapsed before match is called */ if(quote) return 0; while(*m == '*') m++; return (*m == 0); } if(quote) match1 = *m == 's' ? *n == ' ' : ToLower(*m) == ToLower(*n); else if(*m == '?') match1 = 1; else if(*m == '@') match1 = IsLetter(*n); else if(*m == '#') match1 = IsDigit(*n); else match1 = ToLower(*m) == ToLower(*n); if(match1) { if(*m) m++; if(*n) n++; } else { if(!wild) return 0; m = ma; n = ++na; } } return 0; }