コード例 #1
0
ファイル: test_prefix_utils.c プロジェクト: dtaht/hnetd
void prefix_increment_t(void)
{
	struct prefix px;

	sput_fail_unless(prefix_increment(&px, &p1, 8) == 0, "Ret is 0");
	sput_fail_if(prefix_cmp(&px, &p2), "px == p2");

	sput_fail_unless(prefix_increment(&px, &p10, 8) == 0, "Ret is 0");
	sput_fail_if(prefix_cmp(&px, &p11), "px == p11");

	sput_fail_unless(prefix_increment(&px, &p10, 16) == 1, "Single possibility");
	sput_fail_if(prefix_cmp(&px, &p10), "px == p10");

	sput_fail_unless(prefix_increment(&px, &p1f, 12) == 1, "Looping");
	sput_fail_if(prefix_cmp(&px, &p10), "px == p10");

	sput_fail_unless(prefix_increment(&px, &p1f, 120) == -1, "Forbidden");

	px.plen = 120;
	sput_fail_unless(prefix_increment(&px, &px, 4) == -1, "Forbidden");
	px.plen = 42;
	sput_fail_unless(prefix_increment(&px, &px, 10) == 0, "32 bits authorized");
	px.plen = 43;
	sput_fail_unless(prefix_increment(&px, &px, 10) == -1, "33 bits forbidden");
}
コード例 #2
0
ファイル: disambiguation.c プロジェクト: dtaht/rabeld
/* fill zone with rt cap rt1, and returns a pointer to zone, or NULL if the
   intersection is empty. */
static const struct zone*
inter(const struct babel_route *rt, const struct babel_route *rt1,
      struct zone *zone)
{
    enum prefix_status dst_st, src_st;
    const struct source *r = rt->src, *r1 = rt1->src;
    dst_st = prefix_cmp(r->prefix, r->plen, r1->prefix, r1->plen);
    if(dst_st == PST_DISJOINT)
        return NULL;
    src_st = prefix_cmp(r->src_prefix, r->src_plen,
                        r1->src_prefix, r1->src_plen);
    if(src_st == PST_DISJOINT)
        return NULL;
    if(dst_st == PST_MORE_SPECIFIC || dst_st == PST_EQUALS) {
        zone->dst_prefix = r->prefix;
        zone->dst_plen = r->plen;
    } else {
        zone->dst_prefix = r1->prefix;
        zone->dst_plen = r1->plen;
    }
    if(src_st == PST_MORE_SPECIFIC || src_st == PST_EQUALS) {
        zone->src_prefix = r->src_prefix;
        zone->src_plen = r->src_plen;
    } else {
        zone->src_prefix = r1->src_prefix;
        zone->src_plen = r1->src_plen;
    }
    return zone;
}
コード例 #3
0
ファイル: disambiguation.c プロジェクト: dtaht/rabeld
static int
conflicts(const struct babel_route *rt, const struct babel_route *rt1)
{
    enum prefix_status dst_st, src_st;
    const struct source *r = rt->src, *r1 = rt1->src;
    dst_st = prefix_cmp(r->prefix, r->plen, r1->prefix, r1->plen);
    if(dst_st == PST_DISJOINT || dst_st == PST_EQUALS)
        return 0;
    src_st = prefix_cmp(r->src_prefix, r->src_plen,
                        r1->src_prefix, r1->src_plen);
    return ((dst_st == PST_LESS_SPECIFIC && src_st == PST_MORE_SPECIFIC) ||
            (dst_st == PST_MORE_SPECIFIC && src_st == PST_LESS_SPECIFIC));
}
コード例 #4
0
ファイル: test_prefix_utils.c プロジェクト: dtaht/hnetd
void prefix_number_t()
{
	struct prefix p;
	prefix_number(&p, &p10, 0, 1);
	sput_fail_if(prefix_cmp(&p, &p10), "Correct prefix");
	prefix_number(&p, &p10, 1, 1);
	sput_fail_if(prefix_cmp(&p, &p11), "Correct prefix");
	prefix_number(&p, &p10, 1, 0);
	sput_fail_if(prefix_cmp(&p, &p10), "Correct prefix");
	prefix_number(&p, &p10, 0xf, 1);
	sput_fail_if(prefix_cmp(&p, &p11), "Correct prefix");
	prefix_number(&p, &p10, 0xf, 4);
	sput_fail_if(prefix_cmp(&p, &p1f), "Correct prefix");
}
コード例 #5
0
ファイル: test_prefix_utils.c プロジェクト: dtaht/hnetd
void prefix_cmp_t(void)
{
	sput_fail_unless(prefix_cmp(&p1, &p11) > 0,
			"Prefix compare diff. plen (1)");
	sput_fail_unless(prefix_cmp(&p11, &p1) < 0,
			"Prefix compare diff. plen (2)");
	sput_fail_unless(prefix_cmp(&p_allones_67, &p_allones_128) > 0,
			"Prefix compare diff. plen (3)");

	sput_fail_unless(prefix_cmp(&p2, &p1) > 0,
			"Prefix compare value (1)");
	sput_fail_unless(prefix_cmp(&p10, &p11) < 0,
			"Prefix compare value (2)");
}
コード例 #6
0
ファイル: test_prefix_utils.c プロジェクト: dtaht/hnetd
void prefix_last_t(void)
{
	struct prefix px;
	sput_fail_unless(prefix_last(&px, &p10, 18) == -1, "Forbidden arg");

	sput_fail_unless(prefix_last(&px, &p10, 16) == 0, "Ret is 0");
	sput_fail_if(prefix_cmp(&px, &p10), "Unmodified");

	sput_fail_unless(prefix_last(&px, &p10, 12) == 0, "Ret is 0");
	sput_fail_if(prefix_cmp(&px, &p1f), "px == p1f");

	sput_fail_unless(prefix_last(&px, &p11, 12) == 0, "Ret is 0");
	sput_fail_if(prefix_cmp(&px, &p1f), "px == p1f");
}
コード例 #7
0
/*
 * Find the correct place to insert the prefix in the prefix list.
 * If the active prefix has changed we need to send an update.
 * The to evaluate prefix must not be in the prefix list.
 */
void
prefix_evaluate(struct prefix *p, struct rib_entry *re)
{
	struct prefix	*xp;

	if (re->flags & F_RIB_NOEVALUATE || rde_noevaluate()) {
		/* decision process is turned off */
		if (p != NULL)
			LIST_INSERT_HEAD(&re->prefix_h, p, rib_l);
		if (re->active != NULL) {
			re->active->aspath->active_cnt--;
			re->active = NULL;
		}
		return;
	}

	if (p != NULL) {
		if (LIST_EMPTY(&re->prefix_h))
			LIST_INSERT_HEAD(&re->prefix_h, p, rib_l);
		else {
			LIST_FOREACH(xp, &re->prefix_h, rib_l)
				if (prefix_cmp(p, xp) > 0) {
					LIST_INSERT_BEFORE(xp, p, rib_l);
					break;
				} else if (LIST_NEXT(xp, rib_l) == NULL) {
					/* if xp last element ... */
					LIST_INSERT_AFTER(xp, p, rib_l);
					break;
				}
		}
	}

	xp = LIST_FIRST(&re->prefix_h);
	if (xp == NULL || xp->aspath->flags & F_ATTR_LOOP ||
	    (xp->aspath->nexthop != NULL &&
	    xp->aspath->nexthop->state != NEXTHOP_REACH))
		/* xp is ineligible */
		xp = NULL;

	if (re->active != xp) {
		/* need to generate an update */
		if (re->active != NULL)
			re->active->aspath->active_cnt--;

		/*
		 * Send update with remove for re->active and add for xp
		 * but remember that xp may be NULL aka ineligible.
		 * Additional decision may be made by the called functions.
		 */
		rde_generate_updates(re->ribid, xp, re->active);
		if ((re->flags & F_RIB_NOFIB) == 0)
			rde_send_kroute(xp, re->active);

		re->active = xp;
		if (xp != NULL)
			xp->aspath->active_cnt++;
	}
}
コード例 #8
0
ファイル: disambiguation.c プロジェクト: dtaht/rabeld
/* This function assumes rt1 and rt2 non disjoint. */
static int
rt_cmp(const struct babel_route *rt1, const struct babel_route *rt2)
{
    enum prefix_status dst_st, src_st;
    const struct source *r1 = rt1->src, *r2 = rt2->src;
    dst_st = prefix_cmp(r1->prefix, r1->plen, r2->prefix, r2->plen);
    if(dst_st == PST_MORE_SPECIFIC)
        return -1;
    else if(dst_st == PST_LESS_SPECIFIC)
        return 1;
    src_st = prefix_cmp(r1->src_prefix, r1->src_plen,
                        r2->src_prefix, r2->src_plen);
    if(src_st == PST_MORE_SPECIFIC)
        return -1;
    else if(src_st == PST_LESS_SPECIFIC)
        return 1;
    return 0;
}
コード例 #9
0
ファイル: if.c プロジェクト: yubo/quagga
/* Lookup interface by prefix */
struct interface *if_lookup_prefix(struct prefix *prefix)
{
	struct listnode *node;
	struct listnode *cnode;
	struct interface *ifp;
	struct connected *c;

	for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) {
		for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
			if (prefix_cmp(c->address, prefix) == 0) {
				return ifp;
			}
		}
	}
	return NULL;
}
コード例 #10
0
ファイル: test_prefix_utils.c プロジェクト: dtaht/hnetd
void prefix_pton_t(void)
{
	struct prefix p;
	struct prefix p4_1 = {
			.prefix = { .s6_addr = {
					0x00,0x00, 0x00,0x00,  0x00,0x00, 0x00,0x00,
					0x00,0x00, 0xff,0xff,  0x0a }},
					.plen = 104 };

	struct prefix p4_2 = {
			.prefix = { .s6_addr = {
					0x00,0x00, 0x00,0x00,  0x00,0x00, 0x00,0x00,
					0x00,0x00, 0xff,0xff,  0xc0,0xa8, 0x00,0x01 }},
					.plen = 128 };

	sput_fail_unless(prefix_pton(p_allones_67_s, &p) == 1, "Parse 1");
	sput_fail_unless(!prefix_cmp(&p, &p_allones_67), "Parse value 1");

	sput_fail_unless(prefix_pton(p1_s, &p) == 1, "Parse 2");
	sput_fail_unless(!prefix_cmp(&p, &p1), "Parse value 2");

	sput_fail_unless(prefix_pton(px_s, &p) == 1, "Parse 3");
	sput_fail_unless(!prefix_cmp(&p, &px), "Parse value 3");

	sput_fail_unless(prefix_pton("10::/rrx", &p) == 0, "Parse error 1");
	sput_fail_unless(prefix_pton("10::/129", &p) == 0, "Parse error 2");
	sput_fail_unless(prefix_pton("10::/-1", &p) == 0, "Parse error 3");
	sput_fail_unless(prefix_pton("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255./10", &px) == 0, "Parse error 4");
	sput_fail_unless(prefix_pton("10.0.0.0/64", &px) == 0, "Parse error 5");
	sput_fail_unless(prefix_pton("blah-chombier/64", &px) == 0, "Parse error 6");

	/* Parsing IPv4 */
	sput_fail_unless(prefix_pton("10.0.0.0/8", &p) == 1, "Parse v4 1");
	sput_fail_unless(!prefix_cmp(&p, &p4_1), "Parse v4 value 1");

	sput_fail_unless(prefix_pton("192.168.0.1/32", &p) == 1, "Parse v4 2");
	sput_fail_unless(!prefix_cmp(&p, &p4_2), "Parse v4 value 2");

	/* Parsing without slash */
	sput_fail_unless(prefix_pton("192.168.0.1", &p) == 1, "Parse v4 without /");
	sput_fail_unless(!prefix_cmp(&p, &p4_2), "Parse v4 without /");

	sput_fail_unless(prefix_pton("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &p) == 1, "Parse v6 without /");
	sput_fail_unless(!prefix_cmp(&p, &p_allones_128), "Parse v6 without /");
}
コード例 #11
0
ファイル: test_prefix_utils.c プロジェクト: dtaht/hnetd
void prefix_equal_t(void)
{
	sput_fail_if(prefix_cmp(&p_allones_67, &p_allones_67),
			"Same prefixes should be equal (1)");
	sput_fail_if(prefix_cmp(&p_allones_67_can, &p_allones_67_can),
			"Same prefixes should be equal (2)");
	sput_fail_if(prefix_cmp(&p1, &p1),
			"Same prefixes should be equal (3)");
	sput_fail_if(prefix_cmp(&p_allones_67, &p_allones_67_can),
			"Canonical prefix should equal non-canonical one");
	sput_fail_unless(prefix_cmp(&p1, &p10),
			"Different prefix length should imply not equal");
	sput_fail_unless(prefix_cmp(&p1, &p_allones_67),
			"Different prefixes should not be equal");
}
コード例 #12
0
ファイル: test_prefix_utils.c プロジェクト: dtaht/hnetd
void prefix_random_t(void)
{
	int i;
	struct prefix p;

	sput_fail_unless(prefix_random(&p_allones_67, &p, 60),
			"Too short plen for random prefix");

	prefix_random(&p_allones_67_can, &p, 67);
	sput_fail_if(prefix_cmp(&p_allones_67_can, &p),
			"Only one possible random prefix");

	bool success = true;
	for(i = 0; i < 20; i++) {
		prefix_random(&p_allones_67, &p, 70);
		if(!prefix_contains(&p_allones_67, &p)) {
			success = false;
			break;
		}
	}
	sput_fail_unless(success, "Random prefix is in src prefix");
}
コード例 #13
0
ファイル: argparse.c プロジェクト: 873314461/ServerStatus
static int
argparse_long_opt(struct argparse *this_, const struct argparse_option *options)
{
    for (; options->type != ARGPARSE_OPT_END; options++) {
        const char *rest;
        int opt_flags = 0;
        if (!options->long_name)
            continue;

        rest = prefix_skip(this_->argv[0] + 2, options->long_name);
        if (!rest) {
            // Negation allowed?
            if (options->flags & OPT_NONEG) {
                continue;
            }
            // Only boolean/bit allow negation.
            if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT) {
                continue;
            }

            if (!prefix_cmp(this_->argv[0] + 2, "no-")) {
                rest = prefix_skip(this_->argv[0] + 2 + 3, options->long_name);
                if (!rest)
                    continue;
                opt_flags |= OPT_UNSET;
            } else {
                continue;
            }
        }
        if (*rest) {
            if (*rest != '=')
                continue;
            this_->optvalue = rest + 1;
        }
        return argparse_getvalue(this_, options, opt_flags);
    }
    return -2;
}
コード例 #14
0
ファイル: argparse.c プロジェクト: kevinjhanna/steganography
static int
argparse_long_opt(struct argparse *self, const struct argparse_option *options)
{
    for (; options->type != ARGPARSE_OPT_END; options++) {
        const char *rest;
        int opt_flags = 0;
        if (!options->long_name)
            continue;

        rest = prefix_skip(self->argv[0] + 2, options->long_name);
        if (!rest) {
            // negation disabled?
            if (options->flags & OPT_NONEG) {
                continue;
            }
            // only OPT_BOOLEAN/OPT_BIT supports negation
            if (options->type != ARGPARSE_OPT_BOOLEAN && options->type !=
                ARGPARSE_OPT_BIT) {
                continue;
            }

            if (prefix_cmp(self->argv[0] + 2, "no-")) {
                continue;
            }
            rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name);
            if (!rest)
                continue;
            opt_flags |= OPT_UNSET;
        }
        if (*rest) {
            if (*rest != '=')
                continue;
            self->optvalue = rest + 1;
        }
        return argparse_getvalue(self, options, opt_flags | OPT_LONG);
    }
    return -2;
}
コード例 #15
0
ファイル: test_iface.c プロジェクト: sbyx/hnetd
void iface_test_new_managed(void)
{
	struct in_addr v4source = {INADDR_LOOPBACK};
	iface_register_user(&user_mock);
	struct prefix p = {IN6ADDR_LOOPBACK_INIT, 0};
	char test[] = "test";

	struct iface *iface00 = iface_create("test00", "test00", 0);
	iface_update_ipv4_uplink(iface00);
	iface_set_ipv4_uplink(iface00, &v4source, 24);
	iface_commit_ipv4_uplink(iface00);
	/* smock_pull_bool_is("test00", false); */
        /* this was removed in the commit
           a5293745c235a057b6a477ffbd817937eaa9bc12 at 5/2015(!);
        */

	struct iface *iface = iface_create("test0", "test0", 0);
	iface->carrier = true;
	iface_discover_border(iface);

	sput_fail_unless(!!iface, "alloc managed");

	struct iface *iface2 = iface_get("test0");
	sput_fail_unless(iface == iface2, "get after create");

	struct iface *iface3 = iface_create("test0", "test0", 0);
	sput_fail_unless(iface == iface3, "create after create");

	/* smock_pull_bool_is("test0", false); */
        /* this was removed in the commit
           a5293745c235a057b6a477ffbd817937eaa9bc12 at 5/2015(!);
        */

	uloop_cancelled = false;
	uloop_run();
	smock_pull_bool_is("test0", true);

	iface_update_ipv4_uplink(iface);
	iface_set_ipv4_uplink(iface, &v4source, 24);
	iface_commit_ipv4_uplink(iface);
	smock_pull_bool_is("test0", false);

	iface_update_ipv4_uplink(iface);
	iface_commit_ipv4_uplink(iface);
	uloop_cancelled = false;
	uloop_run();
	smock_pull_bool_is("test0", true);

	iface_update_ipv6_uplink(iface);
	iface_add_delegated(iface, &p, NULL, HNETD_TIME_MAX, 0, test, sizeof(test));
	iface_commit_ipv6_uplink(iface);

	smock_pull_bool_is("test0", false);
	sput_fail_unless(!prefix_cmp(&p, (struct prefix *)smock_pull("prefix_prefix")), "prefix address");
	smock_pull_int64_is("prefix_valid", HNETD_TIME_MAX);
	smock_pull_int64_is("prefix_preferred", 0);
	sput_fail_unless(!strcmp(smock_pull("dhcpv6_data"), "test"), "dhcpv6_data");
	smock_pull_int_is("dhcpv6_len", sizeof(test));

	iface_update_ipv4_uplink(iface);
	iface_set_ipv4_uplink(iface, &v4source, 24);
	iface_commit_ipv4_uplink(iface);

	iface_update_ipv6_uplink(iface);
	iface_commit_ipv6_uplink(iface);
	smock_pull_bool_is("prefix_remove", true);

	iface_update_ipv4_uplink(iface);
	iface_commit_ipv4_uplink(iface);

	uloop_cancelled = false;
	uloop_run();
	smock_pull_bool_is("test0", true);

	iface_remove(iface);
	sput_fail_unless(!iface_get("test0"), "delete");
	smock_pull_bool_is("test0", false);
	smock_is_empty();
	iface_unregister_user(&user_mock);
}
コード例 #16
0
ファイル: jimregexp.c プロジェクト: BitThunder/bitthunder
/* 0 failure, 1 success */
static int regmatch(regex_t *preg, int prog)
{
	int scan;	/* Current node. */
	int next;		/* Next node. */
	const char *save;

	scan = prog;

#ifdef DEBUG
	if (scan != 0 && regnarrate)
		fprintf(stderr, "%s(\n", regprop(scan));
#endif
	while (scan != 0) {
		int n;
		int c;
#ifdef DEBUG
		if (regnarrate) {
			fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));	/* Where, what. */
		}
#endif
		next = regnext(preg, scan);
		n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));

		switch (OP(preg, scan)) {
		case BOL:
			if (preg->reginput != preg->regbol)
				return(0);
			break;
		case EOL:
			if (!reg_iseol(preg, c)) {
				return(0);
			}
			break;
		case WORDA:
			/* Must be looking at a letter, digit, or _ */
			if ((!isalnum(UCHAR(c))) && c != '_')
				return(0);
			/* Prev must be BOL or nonword */
			if (preg->reginput > preg->regbol &&
				(isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
				return(0);
			break;
		case WORDZ:
			/* Can't match at BOL */
			if (preg->reginput > preg->regbol) {
				/* Current must be EOL or nonword */
				if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
					c = preg->reginput[-1];
					/* Previous must be word */
					if (isalnum(UCHAR(c)) || c == '_') {
						break;
					}
				}
			}
			/* No */
			return(0);

		case ANY:
			if (reg_iseol(preg, c))
				return 0;
			preg->reginput += n;
			break;
		case EXACTLY: {
				int opnd;
				int len;
				int slen;

				opnd = OPERAND(scan);
				len = str_int_len(preg->program + opnd);

				slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
				if (slen < 0) {
					return(0);
				}
				preg->reginput += slen;
			}
			break;
		case ANYOF:
			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
				return(0);
			}
			preg->reginput += n;
			break;
		case ANYBUT:
			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
				return(0);
			}
			preg->reginput += n;
			break;
		case NOTHING:
			break;
		case BACK:
			break;
		case BRANCH:
			if (OP(preg, next) != BRANCH)		/* No choice. */
				next = OPERAND(scan);	/* Avoid recursion. */
			else {
				do {
					save = preg->reginput;
					if (regmatch(preg, OPERAND(scan))) {
						return(1);
					}
					preg->reginput = save;
					scan = regnext(preg, scan);
				} while (scan != 0 && OP(preg, scan) == BRANCH);
				return(0);
				/* NOTREACHED */
			}
			break;
		case REP:
		case REPMIN:
			return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);

		case REPX:
		case REPXMIN:
			return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);

		case END:
			return 1;	/* Success! */

		case OPENNC:
		case CLOSENC:
			return regmatch(preg, next);

		default:
			if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
				save = preg->reginput;
				if (regmatch(preg, next)) {
					if (OP(preg, scan) < CLOSE) {
						int no = OP(preg, scan) - OPEN;
						if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
							preg->pmatch[no].rm_so = save - preg->start;
						}
					}
					else {
						int no = OP(preg, scan) - CLOSE;
						if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
							preg->pmatch[no].rm_eo = save - preg->start;
						}
					}
					return(1);
				}
				return(0);
			}
			return REG_ERR_INTERNAL;
		}

		scan = next;
	}

	/*
	 * We get here only if there's trouble -- normally "case END" is
	 * the terminating point.
	 */
	return REG_ERR_INTERNAL;
}
コード例 #17
0
ファイル: jimregexp.c プロジェクト: BitThunder/bitthunder
/*
 - regexec - match a regexp against a string
 */
int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
{
	const char *s;
	int scan;

	/* Be paranoid... */
	if (preg == NULL || preg->program == NULL || string == NULL) {
		return REG_ERR_NULL_ARGUMENT;
	}

	/* Check validity of program. */
	if (*preg->program != REG_MAGIC) {
		return REG_ERR_CORRUPTED;
	}

#ifdef DEBUG
	fprintf(stderr, "regexec: %s\n", string);
	regdump(preg);
#endif

	preg->eflags = eflags;
	preg->pmatch = pmatch;
	preg->nmatch = nmatch;
	preg->start = string;	/* All offsets are computed from here */

	/* Must clear out the embedded repeat counts of REPX and REPXMIN opcodes */
	for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
		int op = OP(preg, scan);
		if (op == END)
			break;
		if (op == REPX || op == REPXMIN)
			preg->program[scan + 4] = 0;
	}

	/* If there is a "must appear" string, look for it. */
	if (preg->regmust != 0) {
		s = string;
		while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
			if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
				break;
			}
			s++;
		}
		if (s == NULL)	/* Not present. */
			return REG_NOMATCH;
	}

	/* Mark beginning of line for ^ . */
	preg->regbol = string;

	/* Simplest case:  anchored match need be tried only once (maybe per line). */
	if (preg->reganch) {
		if (eflags & REG_NOTBOL) {
			/* This is an anchored search, but not an BOL, so possibly skip to the next line */
			goto nextline;
		}
		while (1) {
			if (regtry(preg, string)) {
				return REG_NOERROR;
			}
			if (*string) {
nextline:
				if (preg->cflags & REG_NEWLINE) {
					/* Try the next anchor? */
					string = strchr(string, '\n');
					if (string) {
						preg->regbol = ++string;
						continue;
					}
				}
			}
			return REG_NOMATCH;
		}
	}

	/* Messy cases:  unanchored match. */
	s = string;
	if (preg->regstart != '\0') {
		/* We know what char it must start with. */
		while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
			if (regtry(preg, s))
				return REG_NOERROR;
			s++;
		}
	}
	else
		/* We don't -- general case. */
		while (1) {
			if (regtry(preg, s))
				return REG_NOERROR;
			if (*s == '\0') {
				break;
			}
			else {
				int c;
				s += utf8_tounicode(s, &c);
			}
		}

	/* Failure. */
	return REG_NOMATCH;
}