/* * LIL - Little Interpreted Language * Copyright (C) 2010-2013 Kostas Michalopoulos * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * Kostas Michalopoulos <badsector@runtimelegend.com> */ #define __LIL_C_FILE__#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include <math.h>#include "lil.h" /* Enable pools for reusing values, lists and environments. This will use more memory and * will rely on the runtime/OS to free the pools once the program ends, but will cause * considerably less memory fragmentation and improve the script execution performance. *//*#define LIL_ENABLE_POOLS*/ /* Enable limiting recursive calls to lil_parse - this can be used to avoid call stack * overflows and is also useful when running through an automated fuzzer like AFL *//*#define LIL_ENABLE_RECLIMIT 10000*/ /* Visual C++ does not have atoll (Pelles C does and thinks it is fully MSVC compatible) */#if defined(_MSC_VER) && !defined(__POCC__)#define atoll _atoi64/* disable warning about unsafe standard C calls */#pragma warning(disable:4996)/* disable float/int conversion warnings */#pragma warning(disable:4244)#endif #define ERROR_NOERROR 0#define ERROR_DEFAULT 1#define ERROR_FIXHEAD 2 #define CALLBACKS 8#define MAX_CATCHER_DEPTH 16384#define HASHMAP_CELLS 256#define HASHMAP_CELLMASK 0xFF /* note: static lil_xxx functions might become public later */ struct hashentry_t{ char* k; void* v;}; struct hashcell_t{ struct hashentry_t* e; size_t c;}; typedef struct _hashmap_t{ struct hashcell_t cell[HASHMAP_CELLS];} hashmap_t; struct _lil_value_t{ size_t l;#ifdef LIL_ENABLE_POOLS size_t c;#endif char* d;}; struct _lil_var_t{ char* n; char* w; struct _lil_env_t* env; lil_value_t v;}; struct _lil_env_t{ struct _lil_env_t* parent; lil_func_t func; lil_value_t catcher_for; lil_var_t* var; size_t vars; hashmap_t varmap; lil_value_t retval; int retval_set; int breakrun;}; struct _lil_list_t{ lil_value_t* v; size_t c; size_t cap;}; struct _lil_func_t{ char* name; lil_value_t code; lil_list_t argnames; lil_func_proc_t proc;}; struct _lil_t{ const char* code; /* need save on parse */ const char* rootcode; size_t clen; /* need save on parse */ size_t head; /* need save on parse */ int ignoreeol; lil_func_t* cmd; size_t cmds; size_t syscmds; hashmap_t cmdmap; char* catcher; int in_catcher; char* dollarprefix; lil_env_t env; lil_env_t rootenv; lil_env_t downenv; lil_value_t empty; int error; size_t err_head; char* err_msg; lil_callback_proc_t callback[CALLBACKS]; size_t parse_depth; void* data; char* embed; size_t embedlen;}; typedef struct _expreval_t{ const char* code; size_t len, head; lilint_t ival; double dval; int type; int error;} expreval_t; static lil_value_t next_word(lil_t lil);static void register_stdcmds(lil_t lil); #ifdef LIL_ENABLE_POOLSstatic lil_value_t* pool;static int poolsize, poolcap;static lil_list_t* listpool;static size_t listpoolsize, listpoolcap;static lil_env_t* envpool;static size_t envpoolsize, envpoolcap;#endif static char* strclone(const char* s){ size_t len = strlen(s) + 1; char* ns = malloc(len); if (!ns) return NULL; memcpy(ns, s, len); return ns;} static unsigned long hm_hash(const char* key){ unsigned long hash = 5381; int c; while ((c = *key++)) hash = ((hash << 5) + hash) + c; return hash;} static void hm_init(hashmap_t* hm){ memset(hm, 0, sizeof(hashmap_t));} static void hm_destroy(hashmap_t* hm){ size_t i, j; for (i=0; i<HASHMAP_CELLS; i++) { for (j=0; j<hm->cell[i].c; j++) free(hm->cell[i].e[j].k); free(hm->cell[i].e); }} static void hm_put(hashmap_t* hm, const char* key, void* value){ struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK); size_t i; for (i=0; i<cell->c; i++) if (!strcmp(key, cell->e[i].k)) { cell->e[i].v = value; return; } cell->e = realloc(cell->e, sizeof(struct hashentry_t)*(cell->c + 1)); cell->e[cell->c].k = strclone(key); cell->e[cell->c].v = value; cell->c++;} static void* hm_get(hashmap_t* hm, const char* key){ struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK); size_t i; for (i = 0; i<cell->c; i++) if (!strcmp(key, cell->e[i].k)) return cell->e[i].v; return NULL;} static int hm_has(hashmap_t* hm, const char* key){ struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK); size_t i; for (i = 0; i < cell->c; i++) if (!strcmp(key, cell->e[i].k)) return 1; return 0;} #ifdef LIL_ENABLE_POOLSstatic lil_value_t alloc_from_pool(void){ if (poolsize > 0) { poolsize--; return pool[poolsize]; } else { lil_value_t val = calloc(1, sizeof(struct _lil_value_t)); return val; }} static void release_to_pool(lil_value_t val){ if (poolsize == poolcap) { poolcap = poolcap ? (poolcap + poolcap / 2) : 64; pool = realloc(pool, sizeof(lil_value_t)*poolcap); } pool[poolsize++] = val;} static void ensure_capacity(lil_value_t val, size_t cap){ if (val->c < cap) { val->c = cap + 128; val->d = realloc(val->d, val->c); }}#endif static lil_value_t alloc_value_len(const char* str, size_t len){#ifdef LIL_ENABLE_POOLS lil_value_t val = alloc_from_pool();#else lil_value_t val = calloc(1, sizeof(struct _lil_value_t));#endif if (!val) return NULL; if (str) { val->l = len;#ifdef LIL_ENABLE_POOLS ensure_capacity(val, len + 1);#else val->d = malloc(len + 1); if (!val->d) { free(val); return NULL; }#endif memcpy(val->d, str, len); val->d[len] = 0; } else { val->l = 0;#ifdef LIL_ENABLE_POOLS ensure_capacity(val, 1); val->d[0] = '\0';#else val->d = NULL;#endif } return val;} static lil_value_t alloc_value(const char* str){ return alloc_value_len(str, str ? strlen(str) : 0);} lil_value_t lil_clone_value(lil_value_t src){ lil_value_t val; if (!src) return NULL;#ifdef LIL_ENABLE_POOLS val = alloc_from_pool();#else val = calloc(1, sizeof(struct _lil_value_t));#endif if (!val) return NULL; val->l = src->l; if (src->l) {#ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + 1);#else val->d = malloc(val->l + 1); if (!val->d) { free(val); return NULL; }#endif memcpy(val->d, src->d, val->l + 1); } else {#ifdef LIL_ENABLE_POOLS ensure_capacity(val, 1); val->d[0] = '\0';#else val->d = NULL;#endif } return val;} int lil_append_char(lil_value_t val, char ch){#ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + 2); val->d[val->l++] = ch; val->d[val->l] = '\0';#else char* new = realloc(val->d, val->l + 2); if (!new) return 0; new[val->l++] = ch; new[val->l] = 0; val->d = new;#endif return 1;} int lil_append_string_len(lil_value_t val, const char* s, size_t len){#ifndef LIL_ENABLE_POOLS char* new;#endif if (!s || !s[0]) return 1;#ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + len + 1); memcpy(val->d + val->l, s, len + 1);#else new = realloc(val->d, val->l + len + 1); if (!new) return 0; memcpy(new + val->l, s, len + 1); val->d = new;#endif val->l += len; return 1;} int lil_append_string(lil_value_t val, const char* s){ return lil_append_string_len(val, s, strlen(s));} int lil_append_val(lil_value_t val, lil_value_t v){#ifndef LIL_ENABLE_POOLS char* new;#endif if (!v || !v->l) return 1;#ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + v->l + 1); memcpy(val->d + val->l, v->d, v->l + 1);#else new = realloc(val->d, val->l + v->l + 1); if (!new) return 0; memcpy(new + val->l, v->d, v->l + 1); val->d = new;#endif val->l += v->l; return 1;} void lil_free_value(lil_value_t val){ if (!val) return;#ifdef LIL_ENABLE_POOLS release_to_pool(val);#else free(val->d); free(val);#endif} lil_list_t lil_alloc_list(void){ lil_list_t list;#ifdef LIL_ENABLE_POOLS if (listpoolsize > 0) return listpool[--listpoolsize];#endif list = calloc(1, sizeof(struct _lil_list_t)); list->v = NULL; return list;} void lil_free_list(lil_list_t list){ size_t i; if (!list) return; for (i = 0; i<list->c; i++) lil_free_value(list->v[i]);#ifdef LIL_ENABLE_POOLS list->c = 0; if (listpoolsize == listpoolcap) { listpoolcap = listpoolcap ? (listpoolcap + listpoolcap / 2) : 32; listpool = realloc(listpool, sizeof(lil_list_t)*listpoolcap); } listpool[listpoolsize++] = list;#else free(list->v); free(list);#endif} void lil_list_append(lil_list_t list, lil_value_t val){ if (list->c == list->cap) { size_t cap = list->cap ? (list->cap + list->cap / 2) : 32; lil_value_t* nv = realloc(list->v, sizeof(lil_value_t)*cap); if (!nv) return; list->cap = cap; list->v = nv; } list->v[list->c++] = val;} size_t lil_list_size(lil_list_t list){ return list->c;} lil_value_t lil_list_get(lil_list_t list, size_t index){ return index >= list->c ? NULL : list->v[index];} static int needs_escape(const char* str){ size_t i; if (!str || !str[0]) return 1; for (i=0; str[i]; i++) if (ispunct(str[i]) || isspace(str[i])) return 1; return 0;} lil_value_t lil_list_to_value(lil_list_t list, int do_escape){ lil_value_t val = alloc_value(NULL); size_t i, j; for (i=0; i<list->c; i++) { int escape = do_escape ? needs_escape(lil_to_string(list->v[i])) : 0; if (i) lil_append_char(val, ' '); if (escape) { lil_append_char(val, '{'); for (j=0; j < list->v[i]->l; j++) { if (list->v[i]->d[j] == '{') lil_append_string(val, "}\"\\o\"{"); else if (list->v[i]->d[j] == '}') lil_append_string(val, "}\"\\c\"{"); else lil_append_char(val, list->v[i]->d[j]); } lil_append_char(val, '}'); } else lil_append_val(val, list->v[i]); } return val;} lil_env_t lil_alloc_env(lil_env_t parent){ lil_env_t env;#ifdef LIL_ENABLE_POOLS if (envpoolsize > 0) { size_t i, j; env = envpool[--envpoolsize];Lines 1–500 of 3526. Load more
/* * LIL - Little Interpreted Language * Copyright (C) 2010-2013 Kostas Michalopoulos * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * Kostas Michalopoulos <badsector@runtimelegend.com> */ #define __LIL_C_FILE__ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <math.h> #include "lil.h" /* Enable pools for reusing values, lists and environments. This will use more memory and * will rely on the runtime/OS to free the pools once the program ends, but will cause * considerably less memory fragmentation and improve the script execution performance. */ /*#define LIL_ENABLE_POOLS*/ /* Enable limiting recursive calls to lil_parse - this can be used to avoid call stack * overflows and is also useful when running through an automated fuzzer like AFL */ /*#define LIL_ENABLE_RECLIMIT 10000*/ /* Visual C++ does not have atoll (Pelles C does and thinks it is fully MSVC compatible) */ #if defined(_MSC_VER) && !defined(__POCC__) #define atoll _atoi64 /* disable warning about unsafe standard C calls */ #pragma warning(disable:4996) /* disable float/int conversion warnings */ #pragma warning(disable:4244) #endif #define ERROR_NOERROR 0 #define ERROR_DEFAULT 1 #define ERROR_FIXHEAD 2 #define CALLBACKS 8 #define MAX_CATCHER_DEPTH 16384 #define HASHMAP_CELLS 256 #define HASHMAP_CELLMASK 0xFF /* note: static lil_xxx functions might become public later */ struct hashentry_t { char* k; void* v; }; struct hashcell_t { struct hashentry_t* e; size_t c; }; typedef struct _hashmap_t { struct hashcell_t cell[HASHMAP_CELLS]; } hashmap_t; struct _lil_value_t { size_t l; #ifdef LIL_ENABLE_POOLS size_t c; #endif char* d; }; struct _lil_var_t { char* n; char* w; struct _lil_env_t* env; lil_value_t v; }; struct _lil_env_t { struct _lil_env_t* parent; lil_func_t func; lil_value_t catcher_for; lil_var_t* var; size_t vars; hashmap_t varmap; lil_value_t retval; int retval_set; int breakrun; }; struct _lil_list_t { lil_value_t* v; size_t c; size_t cap; }; struct _lil_func_t { char* name; lil_value_t code; lil_list_t argnames; lil_func_proc_t proc; }; struct _lil_t { const char* code; /* need save on parse */ const char* rootcode; size_t clen; /* need save on parse */ size_t head; /* need save on parse */ int ignoreeol; lil_func_t* cmd; size_t cmds; size_t syscmds; hashmap_t cmdmap; char* catcher; int in_catcher; char* dollarprefix; lil_env_t env; lil_env_t rootenv; lil_env_t downenv; lil_value_t empty; int error; size_t err_head; char* err_msg; lil_callback_proc_t callback[CALLBACKS]; size_t parse_depth; void* data; char* embed; size_t embedlen; }; typedef struct _expreval_t { const char* code; size_t len, head; lilint_t ival; double dval; int type; int error; } expreval_t; static lil_value_t next_word(lil_t lil); static void register_stdcmds(lil_t lil); #ifdef LIL_ENABLE_POOLS static lil_value_t* pool; static int poolsize, poolcap; static lil_list_t* listpool; static size_t listpoolsize, listpoolcap; static lil_env_t* envpool; static size_t envpoolsize, envpoolcap; #endif static char* strclone(const char* s) { size_t len = strlen(s) + 1; char* ns = malloc(len); if (!ns) return NULL; memcpy(ns, s, len); return ns; } static unsigned long hm_hash(const char* key) { unsigned long hash = 5381; int c; while ((c = *key++)) hash = ((hash << 5) + hash) + c; return hash; } static void hm_init(hashmap_t* hm) { memset(hm, 0, sizeof(hashmap_t)); } static void hm_destroy(hashmap_t* hm) { size_t i, j; for (i=0; i<HASHMAP_CELLS; i++) { for (j=0; j<hm->cell[i].c; j++) free(hm->cell[i].e[j].k); free(hm->cell[i].e); } } static void hm_put(hashmap_t* hm, const char* key, void* value) { struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK); size_t i; for (i=0; i<cell->c; i++) if (!strcmp(key, cell->e[i].k)) { cell->e[i].v = value; return; } cell->e = realloc(cell->e, sizeof(struct hashentry_t)*(cell->c + 1)); cell->e[cell->c].k = strclone(key); cell->e[cell->c].v = value; cell->c++; } static void* hm_get(hashmap_t* hm, const char* key) { struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK); size_t i; for (i = 0; i<cell->c; i++) if (!strcmp(key, cell->e[i].k)) return cell->e[i].v; return NULL; } static int hm_has(hashmap_t* hm, const char* key) { struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK); size_t i; for (i = 0; i < cell->c; i++) if (!strcmp(key, cell->e[i].k)) return 1; return 0; } #ifdef LIL_ENABLE_POOLS static lil_value_t alloc_from_pool(void) { if (poolsize > 0) { poolsize--; return pool[poolsize]; } else { lil_value_t val = calloc(1, sizeof(struct _lil_value_t)); return val; } } static void release_to_pool(lil_value_t val) { if (poolsize == poolcap) { poolcap = poolcap ? (poolcap + poolcap / 2) : 64; pool = realloc(pool, sizeof(lil_value_t)*poolcap); } pool[poolsize++] = val; } static void ensure_capacity(lil_value_t val, size_t cap) { if (val->c < cap) { val->c = cap + 128; val->d = realloc(val->d, val->c); } } #endif static lil_value_t alloc_value_len(const char* str, size_t len) { #ifdef LIL_ENABLE_POOLS lil_value_t val = alloc_from_pool(); #else lil_value_t val = calloc(1, sizeof(struct _lil_value_t)); #endif if (!val) return NULL; if (str) { val->l = len; #ifdef LIL_ENABLE_POOLS ensure_capacity(val, len + 1); #else val->d = malloc(len + 1); if (!val->d) { free(val); return NULL; } #endif memcpy(val->d, str, len); val->d[len] = 0; } else { val->l = 0; #ifdef LIL_ENABLE_POOLS ensure_capacity(val, 1); val->d[0] = '\0'; #else val->d = NULL; #endif } return val; } static lil_value_t alloc_value(const char* str) { return alloc_value_len(str, str ? strlen(str) : 0); } lil_value_t lil_clone_value(lil_value_t src) { lil_value_t val; if (!src) return NULL; #ifdef LIL_ENABLE_POOLS val = alloc_from_pool(); #else val = calloc(1, sizeof(struct _lil_value_t)); #endif if (!val) return NULL; val->l = src->l; if (src->l) { #ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + 1); #else val->d = malloc(val->l + 1); if (!val->d) { free(val); return NULL; } #endif memcpy(val->d, src->d, val->l + 1); } else { #ifdef LIL_ENABLE_POOLS ensure_capacity(val, 1); val->d[0] = '\0'; #else val->d = NULL; #endif } return val; } int lil_append_char(lil_value_t val, char ch) { #ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + 2); val->d[val->l++] = ch; val->d[val->l] = '\0'; #else char* new = realloc(val->d, val->l + 2); if (!new) return 0; new[val->l++] = ch; new[val->l] = 0; val->d = new; #endif return 1; } int lil_append_string_len(lil_value_t val, const char* s, size_t len) { #ifndef LIL_ENABLE_POOLS char* new; #endif if (!s || !s[0]) return 1; #ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + len + 1); memcpy(val->d + val->l, s, len + 1); #else new = realloc(val->d, val->l + len + 1); if (!new) return 0; memcpy(new + val->l, s, len + 1); val->d = new; #endif val->l += len; return 1; } int lil_append_string(lil_value_t val, const char* s) { return lil_append_string_len(val, s, strlen(s)); } int lil_append_val(lil_value_t val, lil_value_t v) { #ifndef LIL_ENABLE_POOLS char* new; #endif if (!v || !v->l) return 1; #ifdef LIL_ENABLE_POOLS ensure_capacity(val, val->l + v->l + 1); memcpy(val->d + val->l, v->d, v->l + 1); #else new = realloc(val->d, val->l + v->l + 1); if (!new) return 0; memcpy(new + val->l, v->d, v->l + 1); val->d = new; #endif val->l += v->l; return 1; } void lil_free_value(lil_value_t val) { if (!val) return; #ifdef LIL_ENABLE_POOLS release_to_pool(val); #else free(val->d); free(val); #endif } lil_list_t lil_alloc_list(void) { lil_list_t list; #ifdef LIL_ENABLE_POOLS if (listpoolsize > 0) return listpool[--listpoolsize]; #endif list = calloc(1, sizeof(struct _lil_list_t)); list->v = NULL; return list; } void lil_free_list(lil_list_t list) { size_t i; if (!list) return; for (i = 0; i<list->c; i++) lil_free_value(list->v[i]); #ifdef LIL_ENABLE_POOLS list->c = 0; if (listpoolsize == listpoolcap) { listpoolcap = listpoolcap ? (listpoolcap + listpoolcap / 2) : 32; listpool = realloc(listpool, sizeof(lil_list_t)*listpoolcap); } listpool[listpoolsize++] = list; #else free(list->v); free(list); #endif } void lil_list_append(lil_list_t list, lil_value_t val) { if (list->c == list->cap) { size_t cap = list->cap ? (list->cap + list->cap / 2) : 32; lil_value_t* nv = realloc(list->v, sizeof(lil_value_t)*cap); if (!nv) return; list->cap = cap; list->v = nv; } list->v[list->c++] = val; } size_t lil_list_size(lil_list_t list) { return list->c; } lil_value_t lil_list_get(lil_list_t list, size_t index) { return index >= list->c ? NULL : list->v[index]; } static int needs_escape(const char* str) { size_t i; if (!str || !str[0]) return 1; for (i=0; str[i]; i++) if (ispunct(str[i]) || isspace(str[i])) return 1; return 0; } lil_value_t lil_list_to_value(lil_list_t list, int do_escape) { lil_value_t val = alloc_value(NULL); size_t i, j; for (i=0; i<list->c; i++) { int escape = do_escape ? needs_escape(lil_to_string(list->v[i])) : 0; if (i) lil_append_char(val, ' '); if (escape) { lil_append_char(val, '{'); for (j=0; j < list->v[i]->l; j++) { if (list->v[i]->d[j] == '{') lil_append_string(val, "}\"\\o\"{"); else if (list->v[i]->d[j] == '}') lil_append_string(val, "}\"\\c\"{"); else lil_append_char(val, list->v[i]->d[j]); } lil_append_char(val, '}'); } else lil_append_val(val, list->v[i]); } return val; } lil_env_t lil_alloc_env(lil_env_t parent) { lil_env_t env; #ifdef LIL_ENABLE_POOLS if (envpoolsize > 0) { size_t i, j; env = envpool[--envpoolsize];