~kvik/lu9-p9

ref: c85dc2c7a75a78c497c55ce5ad276f8f9fa04e17 lu9-p9/base/env.c -rw-r--r-- 2.8 KiB
c85dc2c7kvik misc: use usize instead of lua_Unsigned 1 year, 3 months ago
                                                                                
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* Environment variables
 *
 * p9.env object provides a map between the /env device and Lua,
 * with its dynamic fields representing the environment variables.
 * Assigning a value to the field writes to the environment:
 *
 * 	p9.env.var = "value"
 *
 * while reading a value reads from the environment:
 *
 * 	assert(p9.env.var == "value")
 *
 * A value can be a string or a list.
 * A list is encoded (decoded) to (from) the environment as a
 * list of strings according to the encoding used by the rc(1)
 * shell (0-byte separated fields).
 *
 *	lua> p9.env.list = {"a", "b", "c"}
 *	rc> echo $#list  * $list
 *	3  * a b c
 *
 * p9.getenv(name) and p9.setenv(name, val) provide the more
 * usual API.
 */

static int
p9_getenv(lua_State *L)
{
	int fd;
	long len, elems, i;
	char env[Smallbuf];
	const char *buf, *s, *e;
	
	snprint(env, sizeof env, "/env/%s", luaL_checkstring(L, 1));
	if((fd = open(env, OREAD)) == -1){
		lua_pushnil(L);
		return 1;
	}
	slurp(L, fd, -1);
	close(fd);
	len = luaL_len(L, -1);
	buf = lua_tostring(L, -1);
	/* Empty */
	if(len == 0){
		lua_pushnil(L);
		return 1;
	}
	/* String (not a list) */
	if(buf[len-1] != '\0')
		return 1;
	/* List */
	for(elems = i = 0; i < len; i++)
		if(buf[i] == '\0') elems++;
	s = buf;
	e = buf + len;
	lua_createtable(L, elems, 0);
	for(i = 1; s < e; i++){
		lua_pushstring(L, s);
		lua_rawseti(L, -2, i);
		s = memchr(s, '\0', e - s);
		s++;
	}
	return 1;
}

static int
p9_getenv_index(lua_State *L)
{
	lua_remove(L, 1);
	return p9_getenv(L);
}

static int
p9_setenv(lua_State *L)
{
	int fd, ntab, n, t, i;
	char env[Smallbuf];
	luaL_Buffer b;
	
	snprint(env, sizeof env, "/env/%s", luaL_checkstring(L, 1));
	t = lua_type(L, 2);
	if(t != LUA_TNIL && t != LUA_TSTRING && t != LUA_TTABLE)
		return luaL_argerror(L, 2, "nil, string, or table expected");
	if((fd = create(env, OWRITE, 0644)) == -1)
		return error(L, "open: %r");
	/*
	 * Writes below are not fully checked for
	 * error (write(n) != n), because env(3)
	 * may truncate the value at its dumb 16k
	 * limit. Encoding a knowledge of this limit
	 * sucks, as does env(3).
	 */
	if(t == LUA_TNIL){
		close(fd);
		return 0;
	}else if(t == LUA_TSTRING){
		n = luaL_len(L, 2);
		if(write(fd, lua_tostring(L, 2), n) == -1){
			close(fd);
			return error(L, "write: %r");
		}
	}else{
		ntab = luaL_len(L, 2);
		luaL_buffinit(L, &b);
		for(i = 1; i <= ntab; i++){
			t = lua_geti(L, 2, i);
			if(t != LUA_TSTRING){
				if(luaL_callmeta(L, -1, "__tostring")
				&& lua_type(L, -1) == LUA_TSTRING){
					lua_replace(L, -2);
				}else{
					lua_pop(L, 1);
					continue;
				}
			}
			luaL_addvalue(&b);
			luaL_addchar(&b, '\0');
		}
		if(write(fd, luaL_buffaddr(&b), luaL_bufflen(&b)) == -1){
			close(fd);
			return error(L, "write: %r");
		}
	}
	close(fd);
	return 0;
}

static int
p9_setenv_newindex(lua_State *L)
{
	lua_remove(L, 1);
	return p9_setenv(L);
}