static int indirectAlias ( char *alias, ARRAY8Ptr clientAddress, CARD16 connectionType, ChooserFunc function, char *closure, int depth, int broadcast) { DisplayEntry *d; int haveLocalhost = 0; if (depth == MAX_DEPTH) return 0; for (d = database; d; d = d->next) { if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName)) continue; if (scanHostlist (d->hosts, clientAddress, connectionType, function, closure, depth + 1, broadcast)) { haveLocalhost = 1; } } return haveLocalhost; }
/* Returns non-0 if string is matched by pattern. Does case folding. */ static int patternMatch( const char *string, const char *pattern ) { int p, s; if (!string) string = ""; for (;;) { s = *string++; switch (p = *pattern++) { case '*': if (!*pattern) return 1; for (string--; *string; string++) if (patternMatch( string, pattern )) return 1; return 0; case '?': if (s == '\0') return 0; break; case '\0': return s == '\0'; case '\\': p = *pattern++; /* fall through */ default: if (tolower( p ) != tolower( s )) return 0; } } }
int ForEachMatchingIndirectHost ( ARRAY8Ptr clientAddress, CARD16 connectionType, ChooserFunc function, char *closure) { int haveLocalhost = 0; DisplayEntry *d; char *clientName = NULL; for (d = database; d; d = d->next) { switch (d->type) { case DISPLAY_ALIAS: case DISPLAY_LISTEN: continue; case DISPLAY_PATTERN: if (!clientName) clientName = NetworkAddressToHostname (connectionType, clientAddress); if (!patternMatch (clientName, d->entry.displayPattern)) continue; break; case DISPLAY_ADDRESS: if (d->entry.displayAddress.connectionType != connectionType || !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, clientAddress)) { continue; } break; } if (!d->hosts) continue; if (d->notAllowed) break; if (d->chooser) { ARRAY8Ptr choice; choice = IndirectChoice (clientAddress, connectionType); if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice)) haveLocalhost = 1; else (*function) (connectionType, choice, closure); } else if (scanHostlist (d->hosts, clientAddress, connectionType, function, closure, 0, FALSE)) { haveLocalhost = 1; } break; } free (clientName); return haveLocalhost; }
static int scanEntrylist(int fh, int nh, ARRAY8Ptr clientAddress, CARD16 connectionType, char **clientName) { HostEntry *h; AliasEntry *a; int na; for (h = accData->hostList + fh; nh; nh--, h++) { switch (h->type) { case HOST_ALIAS: for (a = accData->aliasList, na = accData->nAliases; na; na--, a++) if (patternMatch(a->name, h->entry.aliasPattern)) if (scanEntrylist(a->hosts, a->nhosts, clientAddress, connectionType, clientName)) return True; break; case HOST_PATTERN: if (!*clientName) *clientName = networkAddressToHostname(connectionType, clientAddress); if (patternMatch(*clientName, h->entry.hostPattern)) return True; break; case HOST_ADDRESS: if (h->entry.displayAddress.connectionType == connectionType && XdmcpARRAY8Equal(&h->entry.displayAddress.hostAddress, clientAddress)) return True; break; default: break; } } return False; }
void ForEachChooserHost ( ARRAY8Ptr clientAddress, CARD16 connectionType, ChooserFunc function, char *closure) { int haveLocalhost = 0; DisplayEntry *d; char *clientName = NULL; for (d = database; d; d = d->next) { switch (d->type) { case DISPLAY_ALIAS: continue; case DISPLAY_PATTERN: if (!clientName) clientName = NetworkAddressToHostname (connectionType, clientAddress); if (!patternMatch (clientName, d->entry.displayPattern)) continue; break; case DISPLAY_ADDRESS: if (d->entry.displayAddress.connectionType != connectionType || !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, clientAddress)) { continue; } break; } if (!d->hosts) continue; if (d->notAllowed) break; if (!d->chooser) break; if (scanHostlist (d->hosts, clientAddress, connectionType, function, closure, 0, TRUE)) { haveLocalhost = 1; } break; } if (clientName) free (clientName); if (haveLocalhost) (*function) (connectionType, getLocalAddress(), closure); }
void test_patternMatch() { std::cout << "########################################" << std::endl; std::cout << __FUNCTION__ << std::endl; std::cout << "########################################" << std::endl; const char * text = "aababba"; const char * pattern_1 = "abba"; const char * pattern_2 = "abbx"; int pos = patternMatch(pattern_1, text); if (pos > -1) std::cout << "Pattern \"" << pattern_1 << "\" is found at position " << pos << " in text \"" << text << "\"." << std::endl; else std::cout << "Pattern \"" << pattern_1 << "\" is not found in text \"" << text << "\"." << std::endl; pos = patternMatch(pattern_2, text); if (pos > -1) std::cout << "Pattern \"" << pattern_2 << "\" is found at position " << pos << " in text \"" << text << "\"." << std::endl; else std::cout << "Pattern \"" << pattern_2 << "\" is not found in text \"" << text << "\"." << std::endl; std::cout << std::endl; }
int UseChooser ( ARRAY8Ptr clientAddress, CARD16 connectionType) { DisplayEntry *d; char *clientName = NULL; for (d = database; d; d = d->next) { switch (d->type) { case DISPLAY_ALIAS: continue; case DISPLAY_PATTERN: if (!clientName) clientName = NetworkAddressToHostname (connectionType, clientAddress); if (!patternMatch (clientName, d->entry.displayPattern)) continue; break; case DISPLAY_ADDRESS: if (d->entry.displayAddress.connectionType != connectionType || !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, clientAddress)) { continue; } break; } if (!d->hosts) continue; if (d->notAllowed) break; if (d->chooser && !IndirectChoice (clientAddress, connectionType)) { if (clientName) free (clientName); return 1; } break; } if (clientName) free (clientName); return 0; }
int AcceptableDisplayAddress ( ARRAY8Ptr clientAddress, CARD16 connectionType, xdmOpCode type) { DisplayEntry *d; char *clientName = NULL; if (!*accessFile) return 1; if (type == INDIRECT_QUERY) return 1; for (d = database; d; d = d->next) { if (d->hosts) continue; switch (d->type) { case DISPLAY_ALIAS: case DISPLAY_LISTEN: continue; case DISPLAY_PATTERN: if (!clientName) clientName = NetworkAddressToHostname (connectionType, clientAddress); if (!patternMatch (clientName, d->entry.displayPattern)) continue; break; case DISPLAY_ADDRESS: if (d->entry.displayAddress.connectionType != connectionType || !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, clientAddress)) { continue; } break; } break; } free (clientName); return (d != 0) && (d->notAllowed == 0) && (type == BROADCAST_QUERY ? d->notBroadcast == 0 : 1); }
static int checkHostlist( HostEntry **hosts, int nh, AliasEntry *aliases, int na, int depth, int flags ) { HostEntry *h; AliasEntry *a; int hn, an, am; for (h = *hosts, hn = 0; hn < nh; hn++, h = h->next) if (h->type == HOST_ALIAS) { if (depth == MAX_DEPTH) { LogError( "XDMCP ACL: alias recursion involving %%%s\n", h->entry.aliasPattern ); return 1; } for (a = aliases, an = 0, am = 0; an < na; an++, a = a->next) if (patternMatch( a->name, h->entry.aliasPattern )) { am = 1; if ((flags & CHECK_NOT) && a->hasBad) { LogError( "XDMCP ACL: alias %%%s with unresolved hosts " "in denying rule\n", a->name ); return 1; } if (checkHostlist( a->pHosts, a->nhosts, aliases, na, depth + 1, flags )) return 1; } if (!am) { if (flags & CHECK_NOT) { LogError( "XDMCP ACL: unresolved alias pattern %%%s " "in denying rule\n", h->entry.aliasPattern ); return 1; } else LogWarn( "XDMCP ACL: unresolved alias pattern %%%s\n", h->entry.aliasPattern ); } } else if (h->type == HOST_PATTERN && (flags & CHECK_NO_PAT)) LogWarn( "XDMCP ACL: wildcarded pattern %'s in host-only context\n", h->entry.hostPattern ); return 0; }
static void scanHostlist(int fh, int nh, ARRAY8Ptr clientAddress, CARD16 connectionType, ChooserFunc function, char *closure, int broadcast, int *haveLocalhost) { HostEntry *h; AliasEntry *a; int na; for (h = accData->hostList + fh; nh; nh--, h++) { switch (h->type) { case HOST_ALIAS: for (a = accData->aliasList, na = accData->nAliases; na; na--, a++) if (patternMatch(a->name, h->entry.aliasPattern)) /* XXX originally swapped, no wildcards in alias name matching */ scanHostlist(a->hosts, a->nhosts, clientAddress, connectionType, function, closure, broadcast, haveLocalhost); break; case HOST_ADDRESS: if (haveLocalhost && XdmcpARRAY8Equal(getLocalAddress(), &h->entry.displayAddress.hostAddress)) *haveLocalhost = True; else if (function) (*function)(connectionType, &h->entry.displayAddress.hostAddress, closure); break; case HOST_BROADCAST: if (broadcast && function) (*function)(FamilyBroadcast, 0, closure); break; default: break; } } }
/** * This function returns true only if it is certain that * all events for the given node in the given frame will * be filtered. It is used to optimize stepping. (If this * function returns true the stepping algorithm does not * have to step through every instruction in this frame; * instead, it can use more efficient method entry/exit * events. */ jboolean eventFilter_predictFiltering(HandlerNode *node, jframeID frame) { Filter *filter = FILTERS_ARRAY(node); int i; jclass clazz; jmethodID method; jlocation location; jboolean willBeFiltered = JNI_FALSE; jboolean done = JNI_FALSE; JNIEnv *env = getEnv(); jint error; error = jvmdi->GetFrameLocation(frame, &clazz, &method, &location); if (error != JVMDI_ERROR_NONE) { return JNI_FALSE; } for (i = 0; (i < FILTER_COUNT(node)) && (!done); ++i, ++filter) { switch (filter->modifier) { case JDWP_REQUEST_MODIFIER(ClassOnly): if (!(*env)->IsAssignableFrom(env, clazz, filter->u.ClassOnly.clazz)) { willBeFiltered = JNI_TRUE; done = JNI_TRUE; } break; case JDWP_REQUEST_MODIFIER(Count): { /* * If preceeding filters have determined that events will * be filtered out, that is fine and we won't get here. * However, the count must be decremented - even if * subsequent filters will filter these events. We * thus must end now unable to predict */ done = JNI_TRUE; break; } case JDWP_REQUEST_MODIFIER(ClassMatch): { if (!patternMatch(clazz, filter->u.ClassMatch.classPattern)) { willBeFiltered = JNI_TRUE; done = JNI_TRUE; } break; } case JDWP_REQUEST_MODIFIER(ClassExclude): { if (patternMatch(clazz, filter->u.ClassExclude.classPattern)) { willBeFiltered = JNI_TRUE; done = JNI_TRUE; } break; } } } (*env)->DeleteGlobalRef(env, clazz); return willBeFiltered; }
/* * Determine if this event is interesting to this handler. * Do so by checking each of the handler's filters. * Return false if any of the filters fail, * true if the handler wants this event. * Anyone modifying this function should check * eventFilterRestricted_passesUnloadFilter and * eventFilter_predictFiltering as well. * * If shouldDelete is returned true, a count filter has expired * and the corresponding node should be deleted. */ jboolean eventFilterRestricted_passesFilter(JNIEnv *env, JVMDI_Event *event, HandlerNode *node, jboolean *shouldDelete) { jthread thread; jclass clazz; Filter *filter = FILTERS_ARRAY(node); int i; *shouldDelete = JNI_FALSE; eventThreadAndClass(event, &thread, &clazz); /* * Suppress most events if they happen in debug threads */ if ((event->kind != JVMDI_EVENT_CLASS_PREPARE) && (event->kind != JVMDI_EVENT_CLASS_UNLOAD) && (event->kind != JVMDI_EVENT_CLASS_LOAD) && threadControl_isDebugThread(thread)) { return JNI_FALSE; } for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) { switch (filter->modifier) { case JDWP_REQUEST_MODIFIER(ThreadOnly): if (!(*env)->IsSameObject(env, thread, filter->u.ThreadOnly.thread)) { return JNI_FALSE; } break; case JDWP_REQUEST_MODIFIER(ClassOnly): /* Class filters catch events in the specified * class and any subclass/subinterface. */ if (!(*env)->IsAssignableFrom(env, clazz, filter->u.ClassOnly.clazz)) { return JNI_FALSE; } break; /* This is kinda cheating assumming the JVMDI event * fields will be in the same locations, but it is * true now. */ case JDWP_REQUEST_MODIFIER(LocationOnly): if (event->u.breakpoint.method != filter->u.LocationOnly.method || event->u.breakpoint.location != filter->u.LocationOnly.location || !(*env)->IsSameObject(env, clazz, filter->u.LocationOnly.clazz)) { return JNI_FALSE; } break; case JDWP_REQUEST_MODIFIER(FieldOnly): /* Field watchpoints can be triggered from the * declared class or any subclass/subinterface. */ if ((event->u.field_access.field != filter->u.FieldOnly.field) || !(*env)->IsSameObject(env, event->u.field_access.field_clazz, filter->u.FieldOnly.clazz)) { return JNI_FALSE; } break; case JDWP_REQUEST_MODIFIER(ExceptionOnly): /* do we want caught/uncaught exceptions */ if (!((event->u.exception.catch_clazz == NULL)? filter->u.ExceptionOnly.uncaught : filter->u.ExceptionOnly.caught)) { return JNI_FALSE; } /* do we care about exception class */ if (filter->u.ExceptionOnly.exception != NULL) { jclass exception = event->u.exception.exception; /* do we want this exception class */ if (!(*env)->IsInstanceOf(env, exception, filter->u.ExceptionOnly.exception)) { return JNI_FALSE; } } break; case JDWP_REQUEST_MODIFIER(InstanceOnly): { jobject eventInst = eventInstance(event); jobject filterInst = filter->u.InstanceOnly.instance; /* if no error and doesn't match, don't pass * filter */ if (eventInst != NULL && !(*env)->IsSameObject(env, eventInst, filterInst)) { return JNI_FALSE; } break; } case JDWP_REQUEST_MODIFIER(Count): { JDI_ASSERT(filter->u.Count.count > 0); if (--filter->u.Count.count > 0) { return JNI_FALSE; } *shouldDelete = JNI_TRUE; break; } case JDWP_REQUEST_MODIFIER(Conditional): /*** if (... filter->u.Conditional.exprID ...) { return JNI_FALSE; } ***/ break; case JDWP_REQUEST_MODIFIER(ClassMatch): { if (!patternMatch(clazz, filter->u.ClassMatch.classPattern)) { return JNI_FALSE; } break; } case JDWP_REQUEST_MODIFIER(ClassExclude): { if (patternMatch(clazz, filter->u.ClassExclude.classPattern)) { return JNI_FALSE; } break; } case JDWP_REQUEST_MODIFIER(Step): if (!(*env)->IsSameObject(env, thread, filter->u.Step.thread)) { return JNI_FALSE; } if (!stepControl_handleStep(env, event)) { return JNI_FALSE; } break; default: ERROR_MESSAGE_EXIT("Invalid filter modifier"); return JNI_FALSE; } } return JNI_TRUE; }
/* * See if the event's mods match up with the contents of "basket". * * If we find a Count mod before rejecting an event, we decrement it. We * need to do this even if later mods cause us to ignore the event. */ static bool modsMatch(JdwpState* state, JdwpEvent* pEvent, ModBasket* basket) { JdwpEventMod* pMod = pEvent->mods; for (int i = pEvent->modCount; i > 0; i--, pMod++) { switch (pMod->modKind) { case MK_COUNT: assert(pMod->count.count > 0); pMod->count.count--; break; case MK_CONDITIONAL: assert(false); // should not be getting these break; case MK_THREAD_ONLY: if (pMod->threadOnly.threadId != basket->threadId) return false; break; case MK_CLASS_ONLY: if (!dvmDbgMatchType(basket->classId, pMod->classOnly.refTypeId)) return false; break; case MK_CLASS_MATCH: if (!patternMatch(pMod->classMatch.classPattern, basket->className)) return false; break; case MK_CLASS_EXCLUDE: if (patternMatch(pMod->classMatch.classPattern, basket->className)) return false; break; case MK_LOCATION_ONLY: if (!locationMatch(&pMod->locationOnly.loc, basket->pLoc)) return false; break; case MK_EXCEPTION_ONLY: if (pMod->exceptionOnly.refTypeId != 0 && !dvmDbgMatchType(basket->excepClassId, pMod->exceptionOnly.refTypeId)) return false; if ((basket->caught && !pMod->exceptionOnly.caught) || (!basket->caught && !pMod->exceptionOnly.uncaught)) return false; break; case MK_FIELD_ONLY: if (!dvmDbgMatchType(basket->classId, pMod->fieldOnly.refTypeId) || pMod->fieldOnly.fieldId != basket->field) return false; break; case MK_STEP: if (pMod->step.threadId != basket->threadId) return false; break; case MK_INSTANCE_ONLY: if (pMod->instanceOnly.objectId != basket->thisPtr) return false; break; default: ALOGE("unhandled mod kind %d", pMod->modKind); assert(false); break; } } return true; }
int readDir(QFileInfo *fi, FileNameList *fnList, FileNameDict *fnDict, StringDict *exclDict, QStrList *patList, QStrList *exclPatList, StringList *resultList, StringDict *resultDict, bool errorIfNotExist, bool recursive, QDict<void> *killDict, QDict<void> *paths ) { QCString dirName = fi->absFilePath().utf8(); if (paths && paths->find(dirName)==0) { paths->insert(dirName,(void*)0x8); } if (fi->isSymLink()) { } QDir dir(dirName); dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden ); int totalSize=0; //printf("killDict=%p count=%d\n",killDict,killDict->count()); const QFileInfoList *list = dir.entryInfoList(); if (list) { QFileInfoListIterator it( *list ); QFileInfo *cfi; while ((cfi=it.current())) { if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0) { // file should not be excluded //printf("killDict->find(%s)\n",cfi->absFilePath().data()); if (!cfi->exists() || !cfi->isReadable()) { if (errorIfNotExist) { } } else if (cfi->isFile() && (patList==0 || patternMatch(*cfi,patList)) && !patternMatch(*cfi,exclPatList) && (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0) ) { totalSize+=cfi->size()+cfi->absFilePath().length()+4; QCString name=cfi->fileName().utf8(); //printf("New file %s\n",name.data()); if (fnDict) { FileDef *fd=new FileDef(cfi->dirPath().utf8()+"/",name); FileName *fn=0; if (!name.isEmpty() && (fn=(*fnDict)[name])) { fn->append(fd); } else { fn = new FileName(cfi->absFilePath().utf8(),name); fn->append(fd); if (fnList) fnList->inSort(fn); fnDict->insert(name,fn); } } QCString *rs=0; if (resultList || resultDict) { rs=new QCString(cfi->absFilePath().utf8()); } if (resultList) resultList->append(rs); if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs); if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8); } else if (recursive && cfi->isDir() && !patternMatch(*cfi,exclPatList) && cfi->fileName().at(0)!='.') // skip "." ".." and ".dir" { cfi->setFile(cfi->absFilePath()); totalSize+=readDir(cfi,fnList,fnDict,exclDict, patList,exclPatList,resultList,resultDict,errorIfNotExist, recursive,killDict,paths); } } ++it; } } return totalSize; }
ARRAY8Ptr getLocalAddress(void) { static int haveLocalAddress; if (!haveLocalAddress) { #if defined(IPv6) && defined(AF_INET6) struct addrinfo *ai; if (getaddrinfo(localHostname(), 0, 0, &ai)) { XdmcpAllocARRAY8(&localAddress, 4); localAddress.data[0] = 127; localAddress.data[1] = 0; localAddress.data[2] = 0; localAddress.data[3] = 1; } else { if (ai->ai_family == AF_INET) { XdmcpAllocARRAY8(&localAddress, sizeof(struct in_addr)); memcpy(localAddress.data, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, sizeof(struct in_addr)); } else /* if (ai->ai_family == AF_INET6) */ { XdmcpAllocARRAY8(&localAddress, sizeof(struct in6_addr)); memcpy(localAddress.data, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, sizeof(struct in6_addr)); } freeaddrinfo(ai); #else struct hostent *hostent; if ((hostent = gethostbyname(localHostname()))) { XdmcpAllocARRAY8(&localAddress, hostent->h_length); memmove(localAddress.data, hostent->h_addr, hostent->h_length); #endif haveLocalAddress = True; } } return &localAddress; } void scanAccessDatabase(int force) { struct _displayAddress *da; char *cptr; int nChars, i; debug("scanAccessDatabase\n"); if (Setjmp(cnftalk.errjmp)) return; /* may memleak */ if (startConfig(GC_gXaccess, &accData->dep, force) <= 0) return; free(accData->hostList); accData->nHosts = gRecvInt(); accData->nListens = gRecvInt(); accData->nAliases = gRecvInt(); accData->nAcls = gRecvInt(); nChars = gRecvInt(); if (!(accData->hostList = (HostEntry *) Malloc(accData->nHosts * sizeof(HostEntry) + accData->nListens * sizeof(ListenEntry) + accData->nAliases * sizeof(AliasEntry) + accData->nAcls * sizeof(AclEntry) + nChars))) { closeGetter(); return; } accData->listenList = (ListenEntry *)(accData->hostList + accData->nHosts); accData->aliasList = (AliasEntry *)(accData->listenList + accData->nListens); accData->acList = (AclEntry *)(accData->aliasList + accData->nAliases); cptr = (char *)(accData->acList + accData->nAcls); for (i = 0; i < accData->nHosts; i++) { switch ((accData->hostList[i].type = gRecvInt())) { case HOST_ALIAS: accData->hostList[i].entry.aliasPattern = cptr; cptr += gRecvStrBuf(cptr); break; case HOST_PATTERN: accData->hostList[i].entry.hostPattern = cptr; cptr += gRecvStrBuf(cptr); break; case HOST_ADDRESS: da = &accData->hostList[i].entry.displayAddress; da->hostAddress.data = (unsigned char *)cptr; cptr += (da->hostAddress.length = gRecvArrBuf(cptr)); switch (gRecvInt()) { #ifdef AF_INET case AF_INET: da->connectionType = FamilyInternet; break; #endif #if defined(IPv6) && defined(AF_INET6) case AF_INET6: da->connectionType = FamilyInternet6; break; #endif #ifdef AF_DECnet case AF_DECnet: da->connectionType = FamilyDECnet; break; #endif /*#ifdef AF_UNIX case AF_UNIX: #endif*/ default: da->connectionType = FamilyLocal; break; } break; case HOST_BROADCAST: break; default: logError("Received unknown host type %d from config reader\n", accData->hostList[i].type); return; } } for (i = 0; i < accData->nListens; i++) { accData->listenList[i].iface = gRecvInt(); accData->listenList[i].mcasts = gRecvInt(); accData->listenList[i].nmcasts = gRecvInt(); } for (i = 0; i < accData->nAliases; i++) { accData->aliasList[i].name = cptr; cptr += gRecvStrBuf(cptr); accData->aliasList[i].hosts = gRecvInt(); accData->aliasList[i].nhosts = gRecvInt(); } for (i = 0; i < accData->nAcls; i++) { accData->acList[i].entries = gRecvInt(); accData->acList[i].nentries = gRecvInt(); accData->acList[i].hosts = gRecvInt(); accData->acList[i].nhosts = gRecvInt(); accData->acList[i].flags = gRecvInt(); } } /* Returns True if string is matched by pattern. Does case folding. */ static int patternMatch(const char *string, const char *pattern) { int p, s; if (!string) string = ""; for (;;) { s = *string++; switch (p = *pattern++) { case '*': if (!*pattern) return True; for (string--; *string; string++) if (patternMatch(string, pattern)) return True; return False; case '?': if (s == '\0') return False; break; case '\0': return s == '\0'; case '\\': p = *pattern++; /* fall through */ default: if (tolower(p) != tolower(s)) return False; } } }
ExprPtr Parser::primaryExpression(bool se) { ExprPtr ret; /* TODO if(test(TMinus)) { return inScope(new UnaryExpr(PrimaryExpression(se), Token.Minus)); }*/ if(token == TCase) { ret = patternMatch(se); } else if (token == TIdent || token == TTypeIdent) { string const& name = nextIdent(se); auto varDecl = resolveLocal(currentScope, name); if(varDecl) ret = inScope(new VarRef(varDecl)); else ret = inScope(new NamedRef(name)); } else if(token == TConstNum) { if(tokenStr.find('.') != string::npos) ret = inScope(new FConstExpr(tokenNum(se))); else ret = inScope(new ConstExpr(tokenNum(se))); } else if(test(TLParen)) { ret = expression(false); expect(TRParen); } else if (firstControlSeq[token]) { ret = controlSeqExpression(se); } else { throw CompileError(CEParseError, currentLine); } while(true) { switch(token) { case TLParen: { next(false); auto call = inScope(new CallExpr()); call->func = ret; ret = call; if(token != TRParen) { do { ExprPtr const& param = expression(false); call->parameters.push_back(param); } while(test(TComma)); } expect(TRParen, se); break; } /* case Token.Dot: { Next(false); var name = ExpectIdent(se); ret = InScope(new SlotRef(ret, name)); break; }*/ default: return ret; } } }