new, smaller, faster and untested version of KLISP
[syren.git] / src / syren_script.c
blob442fdd77508e2dccc2382c69c4ede44ce351d662
1 /*
2 Syren -- a lightweight downloader for Linux/BSD/MacOSX
3 inspired by Axel Copyright 2001-2002 Wilmer van der Gaast
4 version 0.0.6 (atomic alien)
5 coded by Ketmar // Avalon Group
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License with
18 the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL;
19 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
20 Suite 330, Boston, MA 02111-1307 USA
23 Syren scripting engine
25 #ifndef _SYREN_SCRIPT_C
26 #define _SYREN_SCRIPT_C
29 #include "syren_os.h"
30 #include "syren_common.h"
31 #include "syren_str.h"
32 #include "syren_msg.h"
33 #include "syren_hdrs.h"
34 #include "syren_script.h"
37 char *SyLoadWholeFile (const char *fname) {
38 int fd;
39 char *p;
40 int left, rd;
41 int64_t sz;
42 char *res = NULL;
44 if (!fname || !fname[0]) return NULL;
45 if (!strcmp(fname, "-")) {
46 fd = 1;
47 sz = 1024; res = malloc(sz); if (!res) return NULL;
48 *res = '\0'; p = res; left = sz-1;
49 while (1) {
50 rd = read(fd, p, left);
51 if (rd <= 0) return res;
52 p[rd] = '\0';
53 sz = sz*2;
54 if (sz > 2*1024*1024) p = NULL; else p = realloc(res, sz);
55 if (!p) { free(res); return NULL; }
56 res = p; p = p+strlen(p); left = sz-(p-res)-1;
58 } else {
59 int fd = SyOpenFile(fname, SY_FMODE_READ, SY_FALSE);
60 if (fd < 0) return NULL;
61 sz = SyFileSize(fd);
62 if (sz > 0 || sz <= 4*1024*1024) {
63 res = calloc(1, sz+1);
64 if (res) {
65 if (SyReadFile(fd, res, sz) != SY_OK) { free(res); res = NULL; }
68 SyCloseFile(fd);
71 return res;
75 #ifdef SYREN_USE_SCRIPT
76 TSyBool syScriptOK = SY_FALSE;
79 static const TSyPrintStr *xpfn = NULL;
82 static char *resstr = NULL;
84 void KLispPrintF (const char *fmt, ...) {
85 int n, size = 256;
86 va_list ap;
87 char *p, *np;
89 if ((p = malloc(size)) == NULL) return;
90 while (1) {
91 memset(p, 0, size);
92 va_start(ap, fmt);
93 n = vsnprintf(p, size, fmt?fmt:"", ap);
94 va_end(ap);
95 if (n > -1 && n < size) break;
96 if (n > -1) size = n+1; else size *= 2;
97 if ((np = realloc(p, size)) == NULL) { free(p); return; }
98 p = np;
101 np = SySPrintf("%s%s", resstr?resstr:"", p);
102 free(p);
103 if (!np) return;
104 free(resstr);
105 resstr = np;
107 /*fprintf(stderr, "!!!%s!!!\n", resstr);*/
108 while ((p = strchr(resstr, '\n'))) {
109 *p = '\0';
110 if (xpfn) SyMessage(xpfn, SY_MSG_MSG, "%s", resstr);
111 p++; np = resstr; while ((*np++ = *p++)) ;
113 if (!*resstr) { free(resstr); resstr = NULL; }
117 static void KLispFlush (void) {
118 if (xpfn && resstr && *resstr) SyMessage(xpfn, SY_MSG_MSG, "%s", resstr);
119 if (resstr) { free(resstr); resstr = NULL; }
123 static int KLPrim_Load (KLISP_POOL_DEF int args) {
124 int cell;
125 char *t, *str;
126 const char *sexpr, *s;
128 /*KLispPrintCell(KLISP_POOL_ARG args); KLispPrintF("\n");*/
129 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "$", "load", 1)) return 0;
130 s = KLISP_CELL(KLISP_CELL(args).car).str;
131 if (!*s) return KLispError(KLISP_POOL_ARG "load: invalid file name");
133 t = SySPrintf("%s.lsp", s);
134 if (!t) goto errquit;
135 str = SyLoadWholeFile(t);
136 if (str) goto loaded;
137 free(t);
139 str = getenv("HOME");
140 if (str != NULL) {
141 t = SySPrintf("%s/.syren/%s.lsp", str, s);
142 if (!t) goto errquit;
143 str = SyLoadWholeFile(t);
144 if (str) goto loaded;
145 free(t);
148 t = SySPrintf("/etc/syren/%s.lsp", s);
149 if (!t) goto errquit;
150 str = SyLoadWholeFile(t);
151 if (str) goto loaded;
152 free(t);
154 return KLispError(KLISP_POOL_ARG "file not found: %s.lsp", s);
155 loaded:
156 KLispPrintF("file: %s\n", t);
157 sexpr = str; cell = KLispParseSExpr(KLISP_POOL_ARG &sexpr);
158 free(str);
159 if (KLISP_POOL->error) {
160 KLispPrintF("%s: PARSE ERROR: %s\n", t, KLISP_POOL->error);
161 free(t);
162 return 0;
164 free(t);
165 return cell;
166 errquit:
167 return KLispErrorMem(KLISP_POOL_ARG0);
171 typedef enum {
172 UDATA_URL
173 } TUDataType;
176 static void *KLCheckUType (KLISP_POOL_DEF int args, TUDataType ctype) {
177 void *ptr;
179 if (!args) goto error;
180 args = KLISP_CELL(args).car;
181 if (!args) goto error;
182 if (KLISP_CELL(args).ctype != KLISP_TYPE_UDATA) goto error;
183 ptr = KLISP_CELL(args).udata;
184 if (*((TUDataType *)ptr) != ctype) goto error;
186 return ptr;
187 error:
188 KLispError(KLISP_POOL_ARG "invalid udata type");
189 return NULL;
193 typedef struct {
194 TUDataType utype;
195 TSyURL *url;
196 } TUDataURL;
199 /* URL object */
200 static int KURLFinalizer (KLISP_POOL_DEF void *ptr, int udatacell) {
201 /*fprintf(stderr, "finalizer for <%s>\n", ((TUDataURL *)ptr)->url);*/
202 free(ptr);
203 return 0;
208 typedef struct {
209 TSyProto proto;
210 char *protostr;
211 char *user, *pass;
212 char *host;
213 int port; TSyBool defaultPort;
214 char *dir, *file, *query, *anchor;
215 } TSyURL;
217 #define XURL_MENTRY(name) \
218 {1, KURL_Get##name, "Get" #name}, \
219 {1, KURL_Set##name, "Set" #name},
221 #define XURL_SFIELD(name,fldname) \
222 static int KURL_Get##name (KLISP_POOL_DEF int args) {\
223 TUDataURL *uurl; \
225 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "u", "URL:Get" #name, 1)) return 0; \
226 if (!(uurl = KLCheckUType(KLISP_POOL_ARG args, UDATA_URL))) return 0; \
228 return KLispNewSym(KLISP_POOL_ARG uurl->url->fldname); \
230 static int KURL_Set##name (KLISP_POOL_DEF int args) { \
231 TUDataURL *uurl; \
232 char *s; \
234 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "u$", "URL:Set" #name, 1)) return 0; \
235 if (!(uurl = KLCheckUType(KLISP_POOL_ARG args, UDATA_URL))) return 0; \
236 args = KLISP_CELL(KLISP_CELL(args).cdr).car; \
237 s = SyStrDup(KLISP_CELL(args).str); \
238 if (s) { \
239 SyStrFree(uurl->url->fldname); \
240 uurl->url->fldname = s; \
242 return 1; \
245 return 0; \
247 #define XURL_NFIELD(name,fldname) \
248 static int KURL_Get##name (KLISP_POOL_DEF int args) {\
249 TUDataURL *uurl; \
251 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "u", "URL:Get" #name, 1)) return 0; \
252 if (!(uurl = KLCheckUType(KLISP_POOL_ARG args, UDATA_URL))) return 0; \
254 return KLispNewNum(KLISP_POOL_ARG uurl->url->fldname); \
256 static int KURL_Set##name (KLISP_POOL_DEF int args) { \
257 TUDataURL *uurl; \
259 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "un", "URL:Set" #name, 1)) return 0; \
260 if (!(uurl = KLCheckUType(KLISP_POOL_ARG args, UDATA_URL))) return 0; \
261 args = KLISP_CELL(KLISP_CELL(args).cdr).car; \
262 uurl->url->fldname = (int)KLISP_CELL(args).num; \
264 return 1; \
268 XURL_SFIELD(Proto, protostr)
269 XURL_SFIELD(User, user)
270 XURL_SFIELD(Pass, pass)
271 XURL_SFIELD(Host, host)
272 XURL_SFIELD(Dir, dir)
273 XURL_SFIELD(File, file)
274 XURL_SFIELD(Query, query)
275 XURL_SFIELD(Anchor, anchor)
276 XURL_NFIELD(Port, port)
278 struct _TKLispPrimItem uURLMethods[] = {
279 XURL_MENTRY(Proto)
280 XURL_MENTRY(User)
281 XURL_MENTRY(Pass)
282 XURL_MENTRY(Host)
283 XURL_MENTRY(Dir)
284 XURL_MENTRY(File)
285 XURL_MENTRY(Query)
286 XURL_MENTRY(Anchor)
287 XURL_MENTRY(Port)
288 {0, NULL, NULL}
291 #undef XURL_MENTRY
292 #undef XURL_SFIELD
295 static int KLPrim_URL (KLISP_POOL_DEF int args) {
296 TUDataURL *uurl;
297 int coURL;
299 uurl = calloc(1, sizeof(TUDataURL));
300 uurl->url = state->url;
301 coURL = KLispNewUData(KLISP_POOL_ARG uurl, KURLFinalizer);
302 if (coURL < 0) { free(uurl); return -1; }
303 if (!KLispRegisterMethods(KLISP_POOL_ARG coURL, uURLMethods)) {
304 free(uurl);
305 return -1;
308 return coURL;
313 / * return NULL or new string * /
314 char *SyHdrGetCookie (const TSyHdrs *hdr, const char *name);
315 void SyHdrDeleteCookie (TSyHdrs *hdr, const char *name);
318 extern TSyHdrs *scHdrs;
320 static int KLPrim_HdrGetField (KLISP_POOL_DEF int args) {
321 char *val;
323 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "$", "HdrGetField", 1)) return 0;
324 if (!scHdrs) return 0; /* no headers here */
325 val = SyHdrGetFieldValue(scHdrs, KLISP_CELL(KLISP_CELL(args).car).str);
326 if (!val) return 0; /* no such field */
327 args = KLispNewSym(KLISP_POOL_ARG val);
328 SyStrFree(val);
330 return args;
334 static int KLPrim_HdrSetField (KLISP_POOL_DEF int args) {
335 int arg1, arg2;
337 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "$[$N]", "HdrSetField", 1)) return 0;
338 if (!scHdrs) return 0; /* no headers here */
339 arg1 = KLISP_CELL(args).car;
340 arg2 = KLISP_CAR_EX(KLISP_CDR_EX(args));
341 if (arg2) {
342 if (SyHdrSetFieldValue(scHdrs, KLISP_CELL(arg1).str, KLISP_CELL(arg2).str) != SY_OK) return 0;
343 } else {
344 if (SyHdrDeleteField(scHdrs, KLISP_CELL(arg1).str) != SY_OK) return 0;
347 return 1;
351 static int KLPrim_HdrGetCode (KLISP_POOL_DEF int args) {
352 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "", "HdrGetCode", 1)) return 0;
353 if (!scHdrs) return 0; /* no headers here */
355 return KLispNewNum(KLISP_POOL_ARG scHdrs->code);
359 static int KLPrim_HdrSetCode (KLISP_POOL_DEF int args) {
360 if (!KLispCheckArgs(KLISP_POOL_ARG args, 1, "n", "HdrSetCode", 1)) return 0;
361 if (!scHdrs) return 0; /* no headers here */
362 scHdrs->code = (int)(KLISP_CELL(KLISP_CAR_EX(args)).num);
364 return 1;
368 struct _TKLispPrimItem syKLispPrimList[] = {
369 {1, KLPrim_Load, "load"},
370 {1, KLPrim_URL, "URL"},
371 {1, KLPrim_HdrGetField, "HdrGetField"},
372 {1, KLPrim_HdrSetField, "HdrSetField"},
373 {1, KLPrim_HdrGetCode, "HdrGetCode"},
374 {1, KLPrim_HdrSetCode, "HdrSetCode"},
376 {0, NULL, NULL}
380 static TKLispPool *pool = NULL;
383 TSyResult SyScriptInit (const TSyPrintStr *pfn) {
384 syScriptOK = SY_FALSE;
385 if (!(pool = KLispNewPool())) {
386 SyMessage(pfn, SY_MSG_WARNING, "can't initialize scripting engine");
387 return SY_ERROR;
389 if (!KLispRegisterPrims(KLISP_POOL_ARG klispPrimList)) {
390 SyMessage(pfn, SY_MSG_WARNING, "can't initialize scripting engine primitives");
391 KLispFreePool(KLISP_POOL_ARG0);
392 return SY_ERROR;
394 if (!KLispRegisterPrims(KLISP_POOL_ARG syKLispPrimList)) {
395 SyMessage(pfn, SY_MSG_WARNING, "can't initialize scripting engine primitives (1)");
396 KLispFreePool(KLISP_POOL_ARG0);
397 return SY_ERROR;
399 syScriptOK = SY_TRUE;
401 return SY_OK;
405 void SyScriptDeinit (void) {
406 if (syScriptOK != SY_TRUE) return;
407 KLispFreePool(KLISP_POOL_ARG0);
408 KLispRBTCleanup();
409 syScriptOK = SY_FALSE;
413 static int Eval (KLISP_POOL_DEF const char *str, const TSyPrintStr *pfn) {
414 int optPrintParsed = 0, optPrintResult = 0, optPrintError = 0;
416 xpfn = pfn;
417 KLispEvalStringEx(KLISP_POOL_ARG str, &optPrintParsed, &optPrintResult, &optPrintError);
418 KLispFlush();
419 xpfn = NULL;
420 if (KLISP_POOL->error) {
421 SyMessage(pfn, SY_MSG_WARNING, "script error: %s", KLISP_POOL->error);
422 return 0;
425 return 1;
429 TSyResult SyScriptLoad (const char *fname, TSyBool showNoFile, const TSyPrintStr *pfn) {
430 char *str;
432 if (syScriptOK != SY_TRUE) return SY_ERROR;
433 str = SyLoadWholeFile(fname);
434 if (!str) {
435 if (showNoFile == SY_TRUE) SyMessage(pfn, SY_MSG_WARNING, "can't load script: %s", fname?fname:"()");
436 return SY_ERROR;
438 if (!Eval(KLISP_POOL_ARG str, pfn)) return SY_ERROR;
440 return SY_OK;
444 void SyScriptLoadInit (const char *argv0, const TSyPrintStr *pfn) {
445 char *t, *s, *l;
447 if (syScriptOK != SY_TRUE) return;
448 SyScriptLoad("/etc/syren/syren.lsp", SY_FALSE, pfn);
449 t = getenv("HOME");
450 if (t != NULL) {
451 s = SySPrintf("%s/.syren/syren.lsp", t);
452 SyScriptLoad(s, SY_FALSE, pfn);
453 SyStrFree(s);
454 s = SySPrintf("%s/syren.lsp", t);
455 SyScriptLoad(s, SY_FALSE, pfn);
456 SyStrFree(s);
458 if (argv0) {
459 s = SyStrDup(argv0);
460 if (s) {
461 t = s; l = NULL;
462 while (*t) {
463 if (*t == '/') l = t;
464 t++;
466 if (l) {
467 *l = '\0';
468 t = SySPrintf("%s/syren.lsp", s);
469 if (t) {
470 SyScriptLoad(t, SY_FALSE, pfn);
471 SyStrFree(t);
474 SyStrFree(s);
477 SyScriptLoad("syren.lsp", SY_FALSE, pfn);
481 TSyResult SyScriptCallback (const char *event, const TSyPrintStr *pfn) {
482 int cb;
484 cb = KLispGetSymbol(KLISP_POOL_ARG event);
485 if (cb <= 0) return SY_OK;
487 xpfn = pfn;
488 /*KLispPrintCell(KLISP_POOL_ARG cb);
489 KLispPrintF("\n");*/
490 KLispFreeError(KLISP_POOL_ARG0);
491 cb = KLispNewCons(KLISP_POOL_ARG KLISP_CELL(cb).cdr, 0);
492 /*KLispPrintCell(KLISP_POOL_ARG cb);
493 KLispPrintF("\n");*/
494 if (cb >= 0) KLispEval(KLISP_POOL_ARG cb, NULL, NULL);
495 KLispFlush();
496 xpfn = NULL;
497 if (KLISP_POOL->error) {
498 SyMessage(pfn, SY_MSG_WARNING, "script error: %s", KLISP_POOL->error);
499 return SY_ERROR;
502 return SY_OK;
504 #endif
507 #endif