コード例 #1
0
ファイル: p_regex.c プロジェクト: CyberLeo/zetamuck
void
prim_array_regsub(PRIM_PROTOTYPE)
{
    struct inst *in;
    stk_array *arr;
    stk_array *nw;
    int         matches[MATCH_ARR_SIZE];
    int         flags       = 0;
    char*       write_ptr   = buf;
    int         write_left  = BUFFER_LEN - 1;
    muf_re*     re;
    char*       text;
    char*       textstart;
    const char* errstr;
    int         matchcnt, len;

    CHECKOP(4);

    oper4 = POP(); /* int:Flags */
    oper3 = POP(); /* str:Replace */
    oper2 = POP(); /* str:Pattern */
    oper1 = POP(); /* str:Text */

    if (oper1->type != PROG_ARRAY)
        abort_interp("Argument not an array of strings. (1)");
    if (!array_is_homogenous(oper1->data.array, PROG_STRING))
        abort_interp("Argument not an array of strings. (1)");
    if (oper2->type != PROG_STRING)
        abort_interp("Non-string argument (2)");
    if (oper3->type != PROG_STRING)
        abort_interp("Non-string argument (3)");
    if (oper4->type != PROG_INTEGER)
        abort_interp("Non-integer argument (4)");
    if (!oper2->data.string)
        abort_interp("Empty string argument (2)");

    if (oper4->data.number & MUF_RE_ICASE)
        flags |= PCRE_CASELESS;
    if (oper4->data.number & MUF_RE_EXTENDED)
        flags |= PCRE_EXTENDED;

    if ((re = muf_re_get(oper2->data.string, flags, &errstr)) == NULL)
        abort_interp(errstr);



    nw = new_array_dictionary();
    arr = oper1->data.array;

    if (!re->extra
        && ((oper4->data.number & MUF_RE_ALL ) || array_count(arr) > 2)) {
        /* Study the pattern if the user requested recursive substitution, or
         * if the input array contains at least three items. */
        re->extra = pcre_study(re->re, 0, &errstr);
        if (errstr)
            abort_interp(errstr);
    }

    if (array_first(arr, &temp1)) {
        do {
            write_ptr = buf;
            write_left = BUFFER_LEN - 1;

            in = array_getitem(arr, &temp1);
            textstart = text = (char *)DoNullInd(in->data.string);
            len = strlen(textstart);

            while((*text != '\0') && (write_left > 0))
            {
                if ((matchcnt = pcre_exec(re->re, re->extra, textstart, len,
                                          text-textstart, 0, matches,
                                          MATCH_ARR_SIZE)) < 0)
                {
                    if (matchcnt != PCRE_ERROR_NOMATCH)
                    {
                        abort_interp(muf_re_error(matchcnt));
                    }

                    while((write_left > 0) && (*text != '\0'))
                    {
                        *write_ptr++ = *text++;
                        write_left--;
                    }

                    break;
                }
                else
                {
                    int         allstart    = matches[0];
                    int         allend      = matches[1];
                    int         substart    = -1;
                    int         subend      = -1;
                    char*       read_ptr    = (char *)DoNullInd(oper3->data.string);
                    int         count;

                    for(count = allstart-(text-textstart);
                                (write_left > 0) && (*text != '\0') && (count > 0);
                                count--)
                    {
                        *write_ptr++ = *text++;
                        write_left--;
                    }

                    while((write_left > 0) && (*read_ptr != '\0'))
                    {
                        if (*read_ptr == '\\')
                        {
                            if (!isdigit(*(++read_ptr)))
                            {
                                *write_ptr++ = *read_ptr++;
                                write_left--;
                            }
                            else
                            {
                                int idx = (*read_ptr++) - '0';

                                if ((idx < 0) || (idx >= matchcnt))
                                {
                                    abort_interp("Invalid \\subexp in substitution string. (3)");
                                }

                                substart = matches[idx*2];
                                subend = matches[idx*2+1];

                                if ((substart >= 0) && (subend >= 0) && (substart < len))
                                {
                                    char* ptr = &textstart[substart];

                                    count = subend - substart;

                                    if (count > write_left)
                                    {
                                        abort_interp("Operation would result in overflow");
                                    }

                                    for(; (write_left > 0) && (count > 0) && (*ptr != '\0'); count--)
                                    {
                                        *write_ptr++ = *ptr++;
                                        write_left--;
                                    }
                                }
                            }
                        }
                        else
                        {
                            *write_ptr++ = *read_ptr++;
                            write_left--;
                        }
                    }

                    for(count = allend - allstart; (*text != '\0') && (count > 0); count--)
                        text++;

                    if (allstart == allend && *text) {
                        *write_ptr++ = *text++;
                        write_left--;
                    }
                }

                if ((oper4->data.number & MUF_RE_ALL) == 0)
                {
                    while((write_left > 0) && (*text != '\0'))
                    {
                        *write_ptr++ = *text++;
                        write_left--;
                    }

                    break;
                }
            }

            if (*text != '\0')
                abort_interp("Operation would result in overflow");

            *write_ptr = '\0';

            temp2.type = PROG_STRING;
            temp2.data.string = alloc_prog_string(buf);

            array_setitem(&nw, &temp1, &temp2);
            CLEAR(&temp2);
        } while (array_next(arr, &temp1));
    }

    CLEAR(oper4);
    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);

    PushArrayRaw(nw);
}
コード例 #2
0
ファイル: p_regex.c プロジェクト: CyberLeo/zetamuck
void
prim_regsub(PRIM_PROTOTYPE)
{
    int         matches[MATCH_ARR_SIZE];
    int         flags       = 0;
    char*       write_ptr   = buf;
    int         write_left  = BUFFER_LEN - 1;
    muf_re*     re;
    char*       text;
    char*       textstart;
    const char* errstr;
    int         matchcnt, len;

    CHECKOP(4);

    oper4 = POP(); /* int:Flags */
    oper3 = POP(); /* str:Replace */
    oper2 = POP(); /* str:Pattern */
    oper1 = POP(); /* str:Text */

    if (oper1->type != PROG_STRING)
        abort_interp("Non-string argument (1)");
    if (oper2->type != PROG_STRING)
        abort_interp("Non-string argument (2)");
    if (oper3->type != PROG_STRING)
        abort_interp("Non-string argument (3)");
    if (oper4->type != PROG_INTEGER)
        abort_interp("Non-integer argument (4)");
    if (!oper2->data.string)
        abort_interp("Empty string argument (2)");

    if (oper4->data.number & MUF_RE_ICASE)
        flags |= PCRE_CASELESS;
    if (oper4->data.number & MUF_RE_EXTENDED)
        flags |= PCRE_EXTENDED;

    if ((re = muf_re_get(oper2->data.string, flags, &errstr)) == NULL)
        abort_interp(errstr);

    if (!re->extra && (oper4->data.number & MUF_RE_ALL)) {
        /* User requested a recursive pattern search. This generally means
         * pcre_exec will be called at least twice unless the pattern doesn't
         * exist in the string at all. Presence of this option suggests that
         * the user anticipates the pattern occurring at least once, so it's
         * safest to go ahead and study the pattern. -brevantes */
        re->extra = pcre_study(re->re, 0, &errstr);
        if (errstr)
            abort_interp(errstr);
    }


    textstart = text = (char *)DoNullInd(oper1->data.string);

    len = strlen(textstart);
    while((*text != '\0') && (write_left > 0))
    {
        if ((matchcnt = pcre_exec(re->re, re->extra, textstart, len, text-textstart, 0, matches, MATCH_ARR_SIZE)) < 0)
        {
            if (matchcnt != PCRE_ERROR_NOMATCH)
            {
                abort_interp(muf_re_error(matchcnt));
            }

            while((write_left > 0) && (*text != '\0'))
            {
                *write_ptr++ = *text++;
                write_left--;
            }

            break;
        }
        else
        {
            int         allstart    = matches[0];
            int         allend      = matches[1];
            int         substart    = -1;
            int         subend      = -1;
            char*       read_ptr    = (char *)DoNullInd(oper3->data.string);
            int         count;

            for(count = allstart-(text-textstart); (write_left > 0) && (*text != '\0') && (count > 0); count--)
            {
                *write_ptr++ = *text++;
                write_left--;
            }

            while((write_left > 0) && (*read_ptr != '\0'))
            {
                if (*read_ptr == '\\')
                {
                    if (!isdigit(*(++read_ptr)))
                    {
                        *write_ptr++ = *read_ptr++;
                        write_left--;
                    }
                    else
                    {
                        int idx = (*read_ptr++) - '0';

                        if ((idx < 0) || (idx >= matchcnt))
                        {
                            abort_interp("Invalid \\subexp in substitution string. (3)");
                        }

                        substart = matches[idx*2];
                        subend = matches[idx*2+1];

                        if ((substart >= 0) && (subend >= 0) && (substart < len))
                        {
                            char* ptr = &textstart[substart];

                            count = subend - substart;

                            if (count > write_left)
                            {
                                abort_interp("Operation would result in overflow");
                            }

                            for(; (write_left > 0) && (count > 0) && (*ptr != '\0'); count--)
                            {
                                *write_ptr++ = *ptr++;
                                write_left--;
                            }
                        }
                    }
                }
                else
                {
                    *write_ptr++ = *read_ptr++;
                    write_left--;
                }
            }

            for(count = allend - allstart; (*text != '\0') && (count > 0); count--)
                text++;

            if (allstart == allend && *text) {
                *write_ptr++ = *text++;
                write_left--;
            }
        }

        if ((oper4->data.number & MUF_RE_ALL) == 0)
        {
            while((write_left > 0) && (*text != '\0'))
            {
                *write_ptr++ = *text++;
                write_left--;
            }

            break;
        }
    }

    if (*text != '\0')
        abort_interp("Operation would result in overflow");

    *write_ptr = '\0';

    CLEAR(oper4);
    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);

    PushString(buf);
}
コード例 #3
0
ファイル: p_regex.c プロジェクト: CyberLeo/zetamuck
void
prim_regexp(PRIM_PROTOTYPE)
{
    stk_array*  nu_val  = 0;
    stk_array*  nu_idx  = 0;
    int         matches[MATCH_ARR_SIZE];
    muf_re*     re;
    char*       text;
    int         flags   = 0;
    int         len, i;
    int         matchcnt = 0;
    const char* errstr;

    CHECKOP(3);

    oper3 = POP(); /* int:Flags */
    oper2 = POP(); /* str:Pattern */
    oper1 = POP(); /* str:Text */

    if (oper1->type != PROG_STRING)
        abort_interp("Non-string argument (1)");
    if (oper2->type != PROG_STRING)
        abort_interp("Non-string argument (2)");
    if (oper3->type != PROG_INTEGER)
        abort_interp("Non-integer argument (3)");
    if (!oper2->data.string)
        abort_interp("Empty string argument (2)");

    if (oper3->data.number & MUF_RE_ICASE)
        flags |= PCRE_CASELESS;
    if (oper3->data.number & MUF_RE_EXTENDED)
        flags |= PCRE_EXTENDED;

    if ((re = muf_re_get(oper2->data.string, flags, &errstr)) == NULL)
        abort_interp(errstr);

    text    = (char *)DoNullInd(oper1->data.string);
    len     = strlen(text);

    if ((matchcnt = pcre_exec(re->re, re->extra, text, len, 0, 0, matches, MATCH_ARR_SIZE)) < 0)
    {
        if (matchcnt != PCRE_ERROR_NOMATCH)
        {
            abort_interp(muf_re_error(matchcnt));
        }

        if (((nu_val = new_array_packed(0)) == NULL) ||
            ((nu_idx = new_array_packed(0)) == NULL))
        {
            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }
    }
    else
    {
        if (((nu_val = new_array_packed(matchcnt)) == NULL) ||
            ((nu_idx = new_array_packed(matchcnt)) == NULL))
        {
            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }

        for(i = 0; i < matchcnt; i++)
        {
            int substart = matches[i*2];
            int subend = matches[i*2+1];
            struct inst idx, val;
            stk_array*  nu;

            if ((substart >= 0) && (subend >= 0) && (substart < len))
                snprintf(buf, BUFFER_LEN, "%.*s", (int)(subend - substart), &text[substart]);
            else
                buf[0] = '\0';

            idx.type        = PROG_INTEGER;
            idx.data.number = i;
            val.type        = PROG_STRING;
            val.data.string = alloc_prog_string(buf);

            array_setitem(&nu_val, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            if ((nu = new_array_packed(2)) == NULL)
            {
                array_free(nu_val);
                array_free(nu_idx);

                abort_interp("Out of memory");
            }

            idx.type        = PROG_INTEGER;
            idx.data.number = 0;
            val.type        = PROG_INTEGER;
            val.data.number = substart + 1;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type        = PROG_INTEGER;
            idx.data.number = 1;
            val.type        = PROG_INTEGER;
            val.data.number = subend - substart;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type        = PROG_INTEGER;
            idx.data.number = i;
            val.type        = PROG_ARRAY;
            val.data.array  = nu;

            array_setitem(&nu_idx, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);
        }
    }

    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);

    PushArrayRaw(nu_val);
    PushArrayRaw(nu_idx);
}
コード例 #4
0
ファイル: p_regex.c プロジェクト: hyena/fuzzball
void
prim_regsub(PRIM_PROTOTYPE)
{
	int			matches[MATCH_ARR_SIZE];
	int			flags		= 0;
	char*		write_ptr	= buf;
	int			write_left	= BUFFER_LEN - 1;
	muf_re*		re;
	char*		text;
	char*		textstart;
	const char*	errstr;
	int			matchcnt, len;

	CHECKOP(4);

	oper4 = POP(); /* int:Flags */
	oper3 = POP(); /* str:Replace */
	oper2 = POP(); /* str:Pattern */
	oper1 = POP(); /* str:Text */

	if (oper1->type != PROG_STRING)
		abort_interp("Non-string argument (1)");
	if (oper2->type != PROG_STRING)
		abort_interp("Non-string argument (2)");
	if (oper3->type != PROG_STRING)
		abort_interp("Non-string argument (3)");
	if (oper4->type != PROG_INTEGER)
		abort_interp("Non-integer argument (4)");
	if (!oper2->data.string)
		abort_interp("Empty string argument (2)");

	if (oper4->data.number & MUF_RE_ICASE)
		flags |= PCRE_CASELESS;
	if (oper4->data.number & MUF_RE_EXTENDED)
		flags |= PCRE_EXTENDED;

	if ((re = muf_re_get(oper2->data.string, flags, &errstr)) == NULL)
		abort_interp(errstr);

	textstart = text = DoNullInd(oper1->data.string);

	len = strlen(textstart);
	while((*text != '\0') && (write_left > 0))
	{
		if ((matchcnt = pcre_exec(re->re, NULL, textstart, len, text-textstart, 0, matches, MATCH_ARR_SIZE)) < 0)
		{
			if (matchcnt != PCRE_ERROR_NOMATCH)
			{
				abort_interp(muf_re_error(matchcnt));
			}

			while((write_left > 0) && (*text != '\0'))
			{
				*write_ptr++ = *text++;
				write_left--;
			}

			break;
		}
		else
		{
			int			allstart	= matches[0];
			int			allend		= matches[1];
			int			substart	= -1;
			int			subend		= -1;
			char*		read_ptr	= DoNullInd(oper3->data.string);
			int			count;

			for(count = allstart-(text-textstart); (write_left > 0) && (*text != '\0') && (count > 0); count--)
			{
				*write_ptr++ = *text++;
				write_left--;
			}

			while((write_left > 0) && (*read_ptr != '\0'))
			{
				if (*read_ptr == '\\')
				{
					if (!isdigit(*(++read_ptr)))
					{
						*write_ptr++ = *read_ptr++;
						write_left--;
					}
					else
					{
						int idx = (*read_ptr++) - '0';

						if ((idx < 0) || (idx >= matchcnt))
						{
							abort_interp("Invalid \\subexp in substitution string. (3)");
						}

						substart = matches[idx*2];
						subend = matches[idx*2+1];

						if ((substart >= 0) && (subend >= 0) && (substart < len))
						{
							char* ptr = &textstart[substart];

							count = subend - substart;

							if (count > write_left)
							{
								abort_interp("Operation would result in overflow");
							}

							for(; (write_left > 0) && (count > 0) && (*ptr != '\0'); count--)
							{
								*write_ptr++ = *ptr++;
								write_left--;
							}
						}
					}
				}
				else
				{
					*write_ptr++ = *read_ptr++;
					write_left--;
				}
			}

			for(count = allend - allstart; (*text != '\0') && (count > 0); count--)
				text++;

			if (allstart == allend && *text) {
				*write_ptr++ = *text++;
				write_left--;
			}
		}

		if ((oper4->data.number & MUF_RE_ALL) == 0)
		{
			while((write_left > 0) && (*text != '\0'))
			{
				*write_ptr++ = *text++;
				write_left--;
			}

			break;
		}
	}

	if (*text != '\0')
		abort_interp("Operation would result in overflow");

	*write_ptr = '\0';

	CLEAR(oper4);
	CLEAR(oper3);
	CLEAR(oper2);
	CLEAR(oper1);

	PushString(buf);
}
コード例 #5
0
ファイル: p_regex.c プロジェクト: CyberLeo/protomuck
void
prim_regsub(PRIM_PROTOTYPE)
{
    regmatch_t *matches = 0;
    int flags = 0;
    char *write_ptr = buf;
    int write_left = BUFFER_LEN - 1;
    muf_re *re;
    char *text;
    int nosubs, err, len, i;

    CHECKOP(4);

    oper4 = POP();              /* int:Flags */
    oper3 = POP();              /* str:Replace */
    oper2 = POP();              /* str:Pattern */
    oper1 = POP();              /* str:Text */

    if (oper1->type != PROG_STRING)
        abort_interp("Non-string argument (1)");
    if (oper2->type != PROG_STRING)
        abort_interp("Non-string argument (2)");
    if (oper3->type != PROG_STRING)
        abort_interp("Non-string argument (3)");
    if (oper4->type != PROG_INTEGER)
        abort_interp("Non-integer argument (4)");
    if (!oper2->data.string)
        abort_interp("Empty string argument (2)");

    if (oper4->data.number & MUF_RE_ICASE)
        flags |= REG_ICASE;

    if ((re = muf_re_get(oper2->data.string, flags, &err)) == NULL)
        abort_interp(muf_re_error(err));

    text = DoNullInd(oper1->data.string);
    nosubs = re->re.re_nsub + 1;

    if ((matches = (regmatch_t *) malloc(sizeof(regmatch_t) * nosubs)) == NULL)
        abort_interp("Out of memory");

    while ((*text != '\0') && (write_left > 0)) {
        len = strlen(text);

        if ((err = regexec(&re->re, text, nosubs, matches, 0)) != 0) {
            if (err != REG_NOMATCH) {
                free(matches);
                abort_interp(muf_re_error(err));
            }

            while ((write_left > 0) && (*text != '\0')) {
                *write_ptr++ = *text++;
                write_left--;
            }

            break;
        } else {
            regmatch_t *cm = &matches[0];
            char *read_ptr = DoNullInd(oper3->data.string);
            int soff = cm->rm_so;
            int count;

            for (count = cm->rm_so;
                 (write_left > 0) && (*text != '\0') && (count > 0); count--) {
                *write_ptr++ = *text++;
                write_left--;
            }

            while ((write_left > 0) && (*read_ptr != '\0')) {
                if (*read_ptr == '\\') {
                    if (!isdigit(*(++read_ptr))) {
                        *write_ptr++ = *read_ptr++;
                        write_left--;
                    } else {
                        int idx = (*read_ptr++) - '0';

                        if ((idx < 0) || (idx >= nosubs)) {
                            free(matches);
                            abort_interp("Invalid \\subexp (3)");
                        }

                        cm = &matches[idx];

                        if ((cm->rm_so >= 0) && (cm->rm_eo >= 0)
                            && (cm->rm_so < len)) {
                            char *ptr = &text[cm->rm_so - soff];

                            count = cm->rm_eo - cm->rm_so;

                            if (count > write_left) {
                                free(matches);
                                abort_interp
                                    ("Operation would result in overflow");
                            }

                            for (; (write_left > 0) && (count > 0)
                                 && (*ptr != '\0'); count--) {
                                *write_ptr++ = *ptr++;
                                write_left--;
                            }
                        }
                    }
                } else {
                    *write_ptr++ = *read_ptr++;
                    write_left--;
                }
            }

            cm = &matches[0];

            for (count = cm->rm_eo - cm->rm_so; (*text != '\0') && (count > 0);
                 count--)
                text++;
        }

        if ((oper4->data.number & MUF_RE_ALL) == 0) {
            while ((write_left > 0) && (*text != '\0')) {
                *write_ptr++ = *text++;
                write_left--;
            }

            break;
        }
    }

    free(matches);

    if (*text != '\0')
        abort_interp("Operation would result in overflow");

    *write_ptr = '\0';

    CLEAR(oper4);
    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);

    PushString(buf);
}
コード例 #6
0
ファイル: p_regex.c プロジェクト: CyberLeo/protomuck
void
prim_regexp(PRIM_PROTOTYPE)
{
    stk_array *nu_val = 0;
    stk_array *nu_idx = 0;
    regmatch_t *matches = 0;
    muf_re *re;
    char *text;
    int flags = 0;
    int nosubs, err, len, i;

    CHECKOP(3);

    oper3 = POP();              /* int:Flags */
    oper2 = POP();              /* str:Pattern */
    oper1 = POP();              /* str:Text */

    if (oper1->type != PROG_STRING)
        abort_interp("Non-string argument (1)");
    if (oper2->type != PROG_STRING)
        abort_interp("Non-string argument (2)");
    if (oper3->type != PROG_INTEGER)
        abort_interp("Non-integer argument (3)");
    if (!oper2->data.string)
        abort_interp("Empty string argument (2)");

    if (oper3->data.number & MUF_RE_ICASE)
        flags |= REG_ICASE;

    if ((re = muf_re_get(oper2->data.string, flags, &err)) == NULL)
        abort_interp(muf_re_error(err));

    text = DoNullInd(oper1->data.string);
    len = strlen(text);
    nosubs = re->re.re_nsub + 1;

    if ((matches = (regmatch_t *) malloc(sizeof(regmatch_t) * nosubs)) == NULL)
        abort_interp("Out of memory");

    if ((err = regexec(&re->re, text, nosubs, matches, 0)) != 0) {
        if (err != REG_NOMATCH) {
            free(matches);
            abort_interp(muf_re_error(err));
        }

        if (((nu_val = new_array_packed(0)) == NULL) ||
            ((nu_idx = new_array_packed(0)) == NULL)) {
            free(matches);

            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }
    } else {
        if (((nu_val = new_array_packed(nosubs)) == NULL) ||
            ((nu_idx = new_array_packed(nosubs)) == NULL)) {
            free(matches);

            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }

        for (i = 0; i < nosubs; i++) {
            regmatch_t *cm = &matches[i];
            struct inst idx, val;
            stk_array *nu;

            if ((cm->rm_so >= 0) && (cm->rm_eo >= 0) && (cm->rm_so < len))
                snprintf(buf, BUFFER_LEN, "%.*s", cm->rm_eo - cm->rm_so,
                         &text[cm->rm_so]);
            else
                buf[0] = '\0';

            idx.type = PROG_INTEGER;
            idx.data.number = i;
            val.type = PROG_STRING;
            val.data.string = alloc_prog_string(buf);

            array_setitem(&nu_val, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            if ((nu = new_array_packed(2)) == NULL) {
                free(matches);

                array_free(nu_val);
                array_free(nu_idx);

                abort_interp("Out of memory");
            }

            idx.type = PROG_INTEGER;
            idx.data.number = 0;
            val.type = PROG_INTEGER;
            val.data.number = cm->rm_so + 1;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type = PROG_INTEGER;
            idx.data.number = 1;
            val.type = PROG_INTEGER;
            val.data.number = cm->rm_eo - cm->rm_so;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type = PROG_INTEGER;
            idx.data.number = i;
            val.type = PROG_ARRAY;
            val.data.array = nu;

            array_setitem(&nu_idx, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);
        }
    }

    free(matches);

    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);

    PushArrayRaw(nu_val);
    PushArrayRaw(nu_idx);
}