summaryrefslogtreecommitdiff
path: root/src/lang/db.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lang/db.cc')
-rw-r--r--src/lang/db.cc237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/lang/db.cc b/src/lang/db.cc
new file mode 100644
index 0000000..9192d09
--- /dev/null
+++ b/src/lang/db.cc
@@ -0,0 +1,237 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <lang/env.h>
21
22static dbmap* GetDB(Env& env) throw(merror_t) {
23 if(!env.db) THROW("htc: no open database");
24 return env.db;
25}
26
27static int eval(Env& env,expr_t* x,int mod=OP_ALL) {
28 mswrite out;
29 if(x->status&OP_PARSE) env.parse(out,x->expr); else x->eval(out,env,mod);
30 return atob(out.str());
31}
32
33////////////////////////////////////////////////////////////////////////////
34
35TOK_IMPL(create) {
36 dbref_t* ref=DBRef(*env.toks,env[0],ms_empty,tok_t::PUBLIC,1);
37 ref->db.Open("/dev/zero",1);
38 sref first,rest=env[1]; int n=0;
39 while(Split(first,rest)) ref->db.InsertTable(n++,first);
40 ref->db.Order(env[2],env[3]);
41}
42
43TOK_IMPL(sort) {
44 dbref_t* ref=(dbref_t*)env.toks->get_this(env[0]);
45 if(env.is_clear(ref)&&ref->is_dbref()) {
46 ref->db.remap();
47 ref->db.Sort(env[1],env[2]);
48 }
49 else THROW("htc: "<<env[0]<<" is not a sortable on the current level");
50}
51
52TOK_IMPL(db) {
53 dbref_t* ref=(dbref_t*)env.toks->get(env[0]);
54 if(env.is_clear(ref)&&ref->is_dbref()) {
55 ref->db.remap();
56 Env(env,ref->db).parse(out,env.arg(1));
57 }
58 else THROW("htc: "<<env[0]<<" is not a db reference");
59}
60
61////////////////////////////////////////////////////////////////////////////
62
63TOK_IMPL(query) {
64 dbmap* db=GetDB(env);
65 expr_t* x[2]={env.arg(0),env.arg(1)};
66 Env nenv(env,*db);
67 nenv.dbat=0;
68 while(nenv.dbat>=0&&env.req->is_running()&&nenv.dbat<db->size()) {
69 int size=db->size();
70 if(eval(nenv,x[0],OP_LOCAL)) nenv.parse(out,x[1]);
71 if(db->size()==size) nenv.dbat++;
72 }
73}
74
75TOK_IMPL(find_rec) {
76 dbmap* db=GetDB(env);
77 Env nenv(env,*db);
78 nenv.dbat=db->Find(env[0]);
79 if(nenv.dbat>=0&&nenv.dbat<db->size()) nenv.parse(out,env.arg(1));
80 else env.parg(out,2);
81}
82
83////////////////////////////////////////////////////////////////////
84
85TOK_IMPL(first_rec) { env.dbat=0; }
86TOK_IMPL(prev_rec) { if(env.dbat>0) env.dbat--; }
87TOK_IMPL(next_rec) { if(env.dbat<GetDB(env)->size()) env.dbat++; }
88TOK_IMPL(exist_rec) { out<<bool(env.dbat>=0&&env.dbat<GetDB(env)->size()); }
89
90TOK_IMPL(rem_rec) {
91 dbmap* db=GetDB(env);
92 if(env.dbat>=0&&env.dbat<env.db->size()) db->Rem(env.dbat);
93}
94
95////////////////////////////////////////////////////////////////////
96
97TOK_IMPL(lastkey) {
98 dbmap* db=GetDB(env);
99 if(!db->empty()) out<<db->at(db->size()-1,db->Index());
100}
101
102TOK_IMPL(prevkey) {
103 dbmap* db=GetDB(env);
104 if(env.dbat>0&&env.dbat<=db->size()) out<<db->at(env.dbat-1,db->Index());
105}
106
107TOK_IMPL(nextkey) {
108 dbmap* db=GetDB(env);
109 if(env.dbat>=0&&env.dbat+1<db->size()) out<<db->at(env.dbat+1,db->Index());
110}
111
112TOK_IMPL(qprevkey) {
113 dbmap* db=GetDB(env);
114 expr_t* x=env.arg(0);
115 Env nenv(env,*db);
116 nenv.dbat=env.dbat-1;
117 while(nenv.dbat>=0&&env.req->is_running()&&nenv.dbat<db->size()) {
118 if(eval(nenv,x,OP_LOCAL)) { out<<db->at(nenv.dbat,db->Index()); break; }
119 else nenv.dbat--;
120 }
121}
122
123TOK_IMPL(qnextkey) {
124 dbmap* db=GetDB(env);
125 expr_t* x=env.arg(0);
126 Env nenv(env,*db);
127 nenv.dbat=env.dbat+1;
128 while(nenv.dbat>=0&&env.req->is_running()&&nenv.dbat<db->size()) {
129 if(eval(nenv,x,OP_LOCAL)) { out<<db->at(nenv.dbat,db->Index()); break; }
130 else nenv.dbat++;
131 }
132}
133
134////////////////////////////////////////////////////////////////////
135
136void envAddDB(tokmap& T)
137{
138 TOK_ADD(create,"xxxx",tok_t::SYSONLY,
139 "%Create a new database\n"
140 "%Syntax: \\create{varname}{tables}{index}{comp}\n"
141 "%\n"
142 "%Index is the unique, ordered table.\n"
143 "%Comp is the compare function.\n"
144 "%A maxmimum of 32 tables are allowed in HDB/1.2\n"
145 );
146 TOK_ADD(sort,"xxx",tok_t::PRIVATE,
147 "%Sort a database\n"
148 "%Syntax: \\sort{varname}{index}{comp}\n"
149 "%\n"
150 "%Note that only globals on the current level are sortable.\n"
151 );
152
153 ////////////////////////////////////////////////////////
154
155 TOK_ADD(db,"xr",tok_t::PRIVATE,
156 "%Set current database\n"
157 "%Syntax: \\db{varname}{body}\n"
158 "%\n"
159 "%Within body, all database functions apply.\n"
160 );
161 TOK_ADD(query,"xr",tok_t::PRIVATE,
162 "%Query current database\n"
163 "%Syntax: \\query{test}{body}\n"
164 "%\n"
165 "%Evaluates body for all record where test is true.\n"
166 "%\n"
167 "%optimizes globals; it is ok to use full function\n"
168 "%expressions in the query. Turned out to be better after all.\n"
169 );
170 TOK_ADD(find_rec,"xr?",tok_t::PRIVATE,
171 "%Find record by key, in current database\n"
172 "%Syntax: \\find.rec{key}{body}<else>\n"
173 "%\n"
174 "%Evaluates body if key is found in the current ordering.\n"
175 "%Otherwise, evaluates <else>, if exist.\n"
176 );
177
178 ////////////////////////////////////////////////////////
179
180 TOK_ADD(first_rec,"",tok_t::PRIVATE,
181 "%Go to first record\n"
182 "%Syntax: \\first.rec\n"
183 );
184 TOK_ADD(exist_rec,"",tok_t::PRIVATE,
185 "%True if current record exist\n"
186 "%Syntax: \\exist.rec\n"
187 );
188 TOK_ADD(next_rec,"",tok_t::PRIVATE,
189 "%Go to next record\n"
190 "%Syntax: \\next.rec\n"
191 );
192 TOK_ADD(prev_rec,"",tok_t::PRIVATE,
193 "%Go to previous record\n"
194 "%Syntax: \\prev.rec\n"
195 );
196 TOK_ADD(rem_rec,"",tok_t::SYSONLY,
197 "%Remove current record\n"
198 "%Syntax: \\rem.rec\n"
199 );
200
201 ////////////////////////////////////////////////////////
202
203 TOK_ADD(lastkey,"",tok_t::PRIVATE,
204 "%Last key of current order\n"
205 "%Syntax: \\lastkey\n"
206 "%\n"
207 "%Silently ignored if not found.\n"
208 );
209 TOK_ADD(prevkey,"",tok_t::PRIVATE,
210 "%Previous key of current order\n"
211 "%Syntax: \\prevkey\n"
212 "%\n"
213 "%Silently ignored if not found.\n"
214 );
215 TOK_ADD(nextkey,"",tok_t::PRIVATE,
216 "%Next key of current order\n"
217 "%Syntax: \\nextkey\n"
218 "%\n"
219 "%Silently ignored if not found.\n"
220 );
221
222 ////////////////////////////////////////////////////////
223
224 TOK_ADD(qprevkey,"r",tok_t::PRIVATE,
225 "%Previous key of current order, satisfying query\n"
226 "%Syntax: \\qprevkey\n"
227 "%\n"
228 "%Silently ignored if not found.\n"
229 );
230 TOK_ADD(qnextkey,"r",tok_t::PRIVATE,
231 "%Next key of current order, satisfying query\n"
232 "%Syntax: \\qnextkey\n"
233 "%\n"
234 "%Silently ignored if not found.\n"
235 );
236
237}