aboutsummaryrefslogtreecommitdiff
path: root/src/compose.c
blob: b8be2481c18ba9e6a4b37aee3e5394acb08628a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
 * LSPIPAT - LUA SPIPAT WRAPPER
 * Copyright (C) 2010, Robin Haberkorn
 * License: LGPL
 *
 * CORE: COMPOSITION OPERATIONS
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>

#include "lspipat.h"

struct composeOperator {
	struct pat *(*str_pat)(VString, struct pat *);
	struct pat *(*pat_str)(struct pat *, VString);
	struct pat *(*chr_pat)(Character, struct pat *);
	struct pat *(*pat_chr)(struct pat *, Character);
	struct pat *(*pat_pat)(struct pat *, struct pat *);
};

 	/* at least one parameter must be a pattern, both are only allowed to be numbers, strings or patterns */

static int
genericComposeOperator(lua_State *L, struct composeOperator spipat)
{
	VString		str = VSTRING_INITIALIZER;
	PATTERN_WRAPPER *new;

	if (!(new = lua_newuserdata(L, sizeof(PATTERN_WRAPPER))))
		L_ERROR(L_ALLOC);
	memset(new, 0, sizeof(PATTERN_WRAPPER));
	lua_insert(L, 1);

	if (lua_isstring(L, 2)) {		/* lvalue number/string, rvalue is pattern */
		PATTERN_WRAPPER *rvalue = lua_touserdata(L, 3);

		if (!rvalue->pattern)
			L_ERROR(L_FREED);
		str.ptr = lua_tolstring(L, 2, (size_t *)&str.len);

		new->type = PATTERN_ONESUBPAT;
		new->u.onesubpat.pattern = luaL_ref(L, LUA_REGISTRYINDEX);

		new->pattern = str.len == 1 ? spipat.chr_pat(*str.ptr, rvalue->pattern)
					    : spipat.str_pat(str, rvalue->pattern);

		lua_pop(L, 1);			/* `new' at stack top */
	} else {				/* lvalue must be pattern */
		PATTERN_WRAPPER *lvalue = luaL_checkudata(L, 2, PATTERN_MT);

		if (!lvalue->pattern)
			L_ERROR(L_FREED);

		if (lua_isstring(L, 3)) {	/* rvalue number/string */
			str.ptr = lua_tolstring(L, 3, (size_t *)&str.len);

			new->pattern = str.len == 1 ? spipat.pat_chr(lvalue->pattern, *str.ptr)
						    : spipat.pat_str(lvalue->pattern, str);

			lua_pop(L, 1);

			new->type = PATTERN_ONESUBPAT;
			new->u.onesubpat.pattern = luaL_ref(L, LUA_REGISTRYINDEX);
		} else {			/* rvalue must be pattern */
			PATTERN_WRAPPER *rvalue = luaL_checkudata(L, 3, PATTERN_MT);

			if (!rvalue->pattern)
				L_ERROR(L_FREED);

			new->type = PATTERN_TWOSUBPAT;
			new->u.twosubpat.pattern2 = luaL_ref(L, LUA_REGISTRYINDEX);
			new->u.twosubpat.pattern1 = luaL_ref(L, LUA_REGISTRYINDEX);

			new->pattern = spipat.pat_pat(lvalue->pattern, rvalue->pattern);
		}
	}

	if (!new->pattern)
		L_ERROR(L_ALLOC);

	luaL_getmetatable(L, PATTERN_MT);
	lua_setmetatable(L, -2);

	return 1;
}

#define STDCOMPOSEOP(LFNC, SPIFNC)						\
	LUA_SIG(LFNC)								\
	{									\
		return genericComposeOperator(L, (struct composeOperator) {	\
			.str_pat = SPIFNC##_str_pat,				\
			.pat_str = SPIFNC##_pat_str,				\
			.chr_pat = SPIFNC##_chr_pat,				\
			.pat_chr = SPIFNC##_pat_chr,				\
			.pat_pat = SPIFNC##_pat_pat				\
		});								\
	}

STDCOMPOSEOP(l_op_and,	spipat_and)
STDCOMPOSEOP(l_op_or,	spipat_or)

#undef STDCOMPOSEOP