mirror of
https://github.com/lxsang/ant-http
synced 2025-07-23 17:19:46 +02:00
the mainline http server
This commit is contained in:
BIN
plugins/.DS_Store
vendored
Normal file
BIN
plugins/.DS_Store
vendored
Normal file
Binary file not shown.
229
plugins/dbhelper.c
Normal file
229
plugins/dbhelper.c
Normal file
@ -0,0 +1,229 @@
|
||||
#include "dbhelper.h"
|
||||
|
||||
sqlite3 * database(const char* file)
|
||||
{
|
||||
sqlite3* db;
|
||||
int rc = sqlite3_open(file,&db);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOG( "Cannot open database: %s %s\n",file, sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return NULL;
|
||||
}
|
||||
return db;
|
||||
}
|
||||
void dbclose(sqlite3* db)
|
||||
{
|
||||
sqlite3_close(db);
|
||||
}
|
||||
int dbquery(sqlite3* db,const char* sql, int (*call_back)())
|
||||
{
|
||||
char *err_msg = 0;
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
int rc = sqlite3_exec(db,sql,call_back,0,&err_msg);
|
||||
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
||||
if(rc != SQLITE_OK)
|
||||
{
|
||||
LOG("Cannot query : '%s' [%s]\n", sql,err_msg);
|
||||
sqlite3_free(err_msg);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
dbfield __field()
|
||||
{
|
||||
dbfield ret = malloc(sizeof *ret);
|
||||
ret->name = NULL;
|
||||
ret->value = NULL;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
dbrecord __record()
|
||||
{
|
||||
dbrecord ret = malloc(sizeof *ret);
|
||||
ret->fields = NULL;
|
||||
ret->idx = 0;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* __name_list(const dbfield f)
|
||||
{
|
||||
char* sql = f->name;
|
||||
for(dbfield p=f->next;p!=NULL;p=p->next)
|
||||
{
|
||||
sql = __s("%s,%s",sql,p->name);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
char* __value_list(const dbfield f)
|
||||
{
|
||||
char* sql = __s("'%s'",f->value);
|
||||
for(dbfield p=f->next;p!=NULL;p=p->next)
|
||||
{
|
||||
sql = __s("%s,'%s'",sql,p->value);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
char* __name_value_list(const dbfield f)
|
||||
{
|
||||
char* sql = __s("%s='%s'", f->name,f->value);
|
||||
for(dbfield p=f->next;p!=NULL;p=p->next)
|
||||
{
|
||||
sql = __s("%s,%s='%s'",sql, p->name,f->value);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
void add_record(dbrecord* r,dbfield f)
|
||||
{
|
||||
dbrecord new_r = malloc(sizeof *new_r);
|
||||
new_r->fields = f;
|
||||
new_r->idx = 1;
|
||||
new_r->next = NULL;
|
||||
if((*r)->idx == 0)
|
||||
*r = new_r;
|
||||
else
|
||||
{
|
||||
dbrecord* temp;
|
||||
for(temp = r;(*temp)->next!=NULL;temp=&((*temp)->next))
|
||||
{
|
||||
(*temp)->idx++;
|
||||
}
|
||||
(*temp)->next = new_r;
|
||||
}
|
||||
//new_r->next = *r;
|
||||
//*r = new_r;
|
||||
}
|
||||
|
||||
void add_field(dbfield* field,const char* name, const char* value)
|
||||
{
|
||||
dbfield new_field = malloc(sizeof *new_field);
|
||||
new_field->name = strdup(name);
|
||||
new_field->value = strdup(value);
|
||||
new_field->next = *field;
|
||||
*field = new_field;
|
||||
}
|
||||
char* value_of(const dbfield f,const char* key)
|
||||
{
|
||||
for(dbfield t = f; t != NULL; t=t->next)
|
||||
if(strcmp(t->name,key)==0)
|
||||
return t->value;
|
||||
return NULL;
|
||||
}
|
||||
int dbinsert(sqlite3* db,const char* table, const dbfield fields)
|
||||
{
|
||||
char* sqlprefix = "INSERT INTO %s (%s) VALUES (%s)";
|
||||
char* name_list = __name_list(fields);
|
||||
char* value_list = __value_list(fields);
|
||||
char* sql = __s(sqlprefix,table,name_list,value_list);
|
||||
int ret = dbquery(db,sql,NULL);
|
||||
free(name_list);
|
||||
free(value_list);
|
||||
free(sql);
|
||||
|
||||
if(ret == 0)
|
||||
return -1;
|
||||
return sqlite3_last_insert_rowid(db);
|
||||
}
|
||||
dbrecord dball(sqlite3* db,const char* table)
|
||||
{
|
||||
return dbselect(db,table,"1=%d",1);
|
||||
}
|
||||
dbrecord dbselect(sqlite3* db, const char* table,const char* fstring,...)
|
||||
{
|
||||
char* sql;
|
||||
char* prefix = "SELECT * FROM %s WHERE (%s)";
|
||||
char* cond;
|
||||
va_list arguments;
|
||||
int dlen;
|
||||
sqlite3_stmt *statement;
|
||||
dbrecord records = __record();
|
||||
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
va_end(arguments);
|
||||
cond = (char*) malloc(dlen*sizeof(char));
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(cond, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
sql = __s(prefix,table,cond);
|
||||
|
||||
if(sqlite3_prepare_v2(db, sql, -1, &statement, 0) == SQLITE_OK)
|
||||
{
|
||||
int cols = sqlite3_column_count(statement);
|
||||
int result = 0;
|
||||
while((result = sqlite3_step(statement)) == SQLITE_ROW)
|
||||
{
|
||||
dbfield fields = __field();
|
||||
for(int col = 0; col < cols; col++)
|
||||
{
|
||||
char *value = (char*)sqlite3_column_text(statement, col);
|
||||
char *name = (char*)sqlite3_column_name(statement, col);
|
||||
add_field(&fields,name,(value!=0)?value:"");
|
||||
}
|
||||
add_record(&records,fields);
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Can not select:%s [%s]\n",sql,sqlite3_errmsg(db));
|
||||
}
|
||||
|
||||
free(cond);
|
||||
free(sql);
|
||||
return records;
|
||||
}
|
||||
int hastable(sqlite3* db,const char* table)
|
||||
{
|
||||
char * prefix = "select * from sqlite_master where type='table' and name='%s'";
|
||||
char* sql = __s(prefix,table);
|
||||
int ret = dbquery(db,sql,NULL);
|
||||
free(sql);
|
||||
return ~ret;
|
||||
}
|
||||
int dbupdate(sqlite3* db,const char* table,const dbfield field,const char* fstring,...)
|
||||
{
|
||||
char* sql;
|
||||
char* prefix = "UPDATE %s SET %s WHERE (%s)";
|
||||
char* cond;
|
||||
char* list;
|
||||
va_list arguments;
|
||||
int dlen;
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
va_end(arguments);
|
||||
cond = (char*) malloc(dlen*sizeof(char));
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(cond, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
list = __name_value_list(field);
|
||||
sql = __s(prefix,table,list,cond);
|
||||
int ret = dbquery(db,sql,NULL);
|
||||
free(cond);
|
||||
free(list);
|
||||
free(sql);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dbdelete(sqlite3* db,const char* table,const char* fstring,...)
|
||||
{
|
||||
char* sql;
|
||||
char* prefix = "DELETE FROM %s WHERE (%s)";
|
||||
char* cond;
|
||||
va_list arguments;
|
||||
int dlen;
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
va_end(arguments);
|
||||
cond = (char*) malloc(dlen*sizeof(char));
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(cond, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
sql = __s(prefix,table,cond);
|
||||
int ret = dbquery(db,sql,NULL);
|
||||
free(cond);
|
||||
free(sql);
|
||||
return ret;
|
||||
}
|
34
plugins/dbhelper.h
Normal file
34
plugins/dbhelper.h
Normal file
@ -0,0 +1,34 @@
|
||||
#include <sqlite3.h>
|
||||
#include "utils.h"
|
||||
|
||||
sqlite3 * database(const char*);
|
||||
typedef struct _dbfield
|
||||
{
|
||||
char* name;
|
||||
char* value;
|
||||
struct _dbfield* next;
|
||||
} *dbfield ;
|
||||
|
||||
typedef struct _dbrecord
|
||||
{
|
||||
dbfield fields;
|
||||
int idx;
|
||||
struct _dbrecord* next;
|
||||
} * dbrecord;
|
||||
|
||||
int dbquery(sqlite3*,const char*, int (*)());
|
||||
int dbinsert(sqlite3*,const char*,const dbfield);
|
||||
int hastable(sqlite3*,const char*);
|
||||
int dbupdate(sqlite3*,const char*,const dbfield,const char*,...);
|
||||
dbrecord dbselect(sqlite3*, const char*,const char*,...);
|
||||
dbrecord dball(sqlite3*,const char*);
|
||||
int dbdelete(sqlite3*,const char*,const char*,...);
|
||||
dbfield __field();
|
||||
dbrecord __record();
|
||||
char* __name_list(const dbfield);
|
||||
char* __value_list(const dbfield);
|
||||
char* __name_value_list(const dbfield);
|
||||
char* value_of(const dbfield,const char*);
|
||||
void add_field(dbfield*,const char*, const char*);
|
||||
void add_record(dbrecord*,dbfield);
|
||||
void dbclose(sqlite3*);
|
138
plugins/dictionary.c
Normal file
138
plugins/dictionary.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include "dictionary.h"
|
||||
|
||||
dictionary dict()
|
||||
{
|
||||
dictionary d = (dictionary)malloc(HASHSIZE*sizeof(association));
|
||||
for(int i=0; i< HASHSIZE;i++)
|
||||
d[i] = NULL;
|
||||
return d;
|
||||
}
|
||||
unsigned hash(const char* key)
|
||||
{
|
||||
unsigned hashval;
|
||||
for (hashval = 0; *key != '\0'; key++)
|
||||
hashval = *key + 31 * hashval;
|
||||
return hashval % HASHSIZE;
|
||||
}
|
||||
association dlookup(dictionary dic,const char* key)
|
||||
{
|
||||
association np;
|
||||
if(dic == NULL) return NULL;
|
||||
for (np = dic[hash(key)]; np != NULL; np = np->next)
|
||||
{
|
||||
if(!np || !np->key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(key, np->key) == 0)
|
||||
return np; /* found */
|
||||
}
|
||||
return NULL; /* not found */
|
||||
}
|
||||
association __put_el_with_key(dictionary dic, const char* key)
|
||||
{
|
||||
association np;
|
||||
unsigned hashval;
|
||||
if(dic == NULL) return NULL;
|
||||
if ((np = dlookup(dic,key)) == NULL) { /* not found */
|
||||
np = (association) malloc(sizeof(*np));
|
||||
if (np == NULL || (np->key = strdup(key)) == NULL)
|
||||
return NULL;
|
||||
hashval = hash(key);
|
||||
np->next = dic[hashval];
|
||||
dic[hashval] = np;
|
||||
}
|
||||
return np;
|
||||
}
|
||||
association dput(dictionary dic,const char* key, const char* value)
|
||||
{
|
||||
if(IS_INT(value))
|
||||
return dput_i(dic,key,atoi(value));
|
||||
else if(IS_FLOAT(value))
|
||||
return dput_f(dic,key,atof(value));
|
||||
else
|
||||
return dput_s(dic,key,value);
|
||||
}
|
||||
association dput_s(dictionary dic,const char* key, const char* value)
|
||||
{
|
||||
association np = __put_el_with_key(dic,key);
|
||||
if(np == NULL) return NULL;
|
||||
if(value == NULL) np->value.s="";
|
||||
else if ((np->value.s = strdup(value)) == NULL)
|
||||
return NULL;
|
||||
return np;
|
||||
}
|
||||
association dput_i(dictionary dic,const char* key, int value)
|
||||
{
|
||||
association np = __put_el_with_key(dic,key);
|
||||
if(np == NULL) return NULL;
|
||||
np->value.i = value;
|
||||
return np;
|
||||
}
|
||||
association dput_f(dictionary dic,const char* key, float value)
|
||||
{
|
||||
association np = __put_el_with_key(dic,key);
|
||||
if(np == NULL) return NULL;
|
||||
np->value.f = value;
|
||||
return np;
|
||||
}
|
||||
association dput_p(dictionary dic,const char* key, void* value)
|
||||
{
|
||||
association np = __put_el_with_key(dic,key);
|
||||
if(np == NULL) return NULL;
|
||||
np->value.p = value;
|
||||
return np;
|
||||
}
|
||||
int dremove(dictionary dic, const char* key)
|
||||
{
|
||||
if(dic == NULL) return 0;
|
||||
int hashval = hash(key);
|
||||
association np = dic[hashval];
|
||||
if(np!=NULL && strcmp(key,np->key)==0)
|
||||
{
|
||||
dic[hashval] = np->next;
|
||||
return 1;
|
||||
}
|
||||
for (np= dic[hashval]; np != NULL; np = np->next)
|
||||
if (np->next!=NULL&&strcmp(key, np->next->key) == 0)
|
||||
{
|
||||
np->next = np->next->next; /* found */
|
||||
return 1;
|
||||
}
|
||||
return 0; /* not found */
|
||||
|
||||
}
|
||||
/**
|
||||
* Get the string data by key
|
||||
* @param dic the dictionary
|
||||
* @param key @
|
||||
* @return the string value
|
||||
*/
|
||||
char* dvalue(dictionary dic,const char* key)
|
||||
{
|
||||
association as = dlookup(dic,key);
|
||||
if(as == NULL) return NULL;
|
||||
return as->value.s;
|
||||
}
|
||||
|
||||
int dvalue_i(dictionary dic, const char* key)
|
||||
{
|
||||
association as = dlookup(dic,key);
|
||||
if(as == NULL) return 0;
|
||||
return as->value.i;
|
||||
}
|
||||
float dvalue_f(dictionary dic, const char* key)
|
||||
{
|
||||
association as = dlookup(dic,key);
|
||||
if(as == NULL) return 0;
|
||||
return as->value.f;
|
||||
}
|
||||
void* dvalue_p(dictionary dic, const char* key)
|
||||
{
|
||||
association as = dlookup(dic,key);
|
||||
if(as == NULL) return NULL;
|
||||
return as->value.p;
|
||||
}
|
||||
|
||||
void freedict(dictionary dic){free(dic);}
|
||||
|
38
plugins/dictionary.h
Normal file
38
plugins/dictionary.h
Normal file
@ -0,0 +1,38 @@
|
||||
#include "utils.h"
|
||||
#define HASHSIZE 255
|
||||
#define for_each_assoc(assoc, dic) \
|
||||
for(int i = 0; i < HASHSIZE; i++) \
|
||||
for(assoc = dic[i];assoc!= NULL; assoc = assoc->next)
|
||||
|
||||
/**
|
||||
* Dictionary for header
|
||||
*/
|
||||
typedef struct __assoc{
|
||||
struct __assoc *next;
|
||||
char *key;
|
||||
union
|
||||
{
|
||||
int i;
|
||||
char* s;
|
||||
float f;
|
||||
void* p;
|
||||
} value;
|
||||
//char *value;
|
||||
} * association;
|
||||
|
||||
typedef association* dictionary;
|
||||
dictionary dict();
|
||||
unsigned hash(const char*);
|
||||
association dlookup(dictionary,const char*);
|
||||
char* dvalue(dictionary, const char*);
|
||||
int dvalue_i(dictionary, const char*);
|
||||
float dvalue_f(dictionary, const char*);
|
||||
void* dvalue_p(dictionary, const char*);
|
||||
association dput(dictionary,const char*, const char*);
|
||||
association dput_s(dictionary,const char*, const char*);
|
||||
association dput_i(dictionary,const char*, int);
|
||||
association dput_f(dictionary,const char*, float);
|
||||
association dput_p(dictionary,const char*, void*);
|
||||
int dremove(dictionary, const char*);
|
||||
void freedict(dictionary);
|
||||
void stest(const char* );
|
BIN
plugins/dummy/.DS_Store
vendored
Normal file
BIN
plugins/dummy/.DS_Store
vendored
Normal file
Binary file not shown.
128
plugins/dummy/dummy.c
Normal file
128
plugins/dummy/dummy.c
Normal file
@ -0,0 +1,128 @@
|
||||
#include "../plugin.h"
|
||||
|
||||
void init();
|
||||
call __init__ = init;
|
||||
sqldb db;
|
||||
|
||||
void init()
|
||||
{
|
||||
db = getdb();
|
||||
if(db == NULL)
|
||||
printf("Unable to get database %s \n", __plugin__.name);
|
||||
// create table
|
||||
char* sql = "CREATE TABLE dummy(id INTEGER PRIMARY KEY, color TEXT);";
|
||||
if(hastable(db,"dummy") == 0)
|
||||
dbquery(db,sql,NULL);
|
||||
printf("Finish init\n");
|
||||
}
|
||||
|
||||
void execute(int client,const char* method,dictionary rq)
|
||||
{
|
||||
|
||||
char * question;
|
||||
|
||||
question = dvalue(rq,"color");
|
||||
dbfield field = __field();
|
||||
|
||||
if(question != NULL)
|
||||
{
|
||||
add_field(&field,"color",question);
|
||||
dbinsert(db,"dummy",field);
|
||||
}
|
||||
free(field);
|
||||
json(client);
|
||||
|
||||
dbrecord records = dball(db,"dummy");
|
||||
|
||||
__t(client,"{ \"records\":[");
|
||||
int cnt = 0;
|
||||
for(dbrecord r = records;r != NULL; r=r->next)
|
||||
{
|
||||
|
||||
if(cnt!=0) __t(client,",");
|
||||
dbfield row = r-> fields;
|
||||
__t(client,"{\"id\":%s,\"color\":\"%s\"}",
|
||||
value_of(row,"id"),
|
||||
value_of(row,"color"));
|
||||
free(row);
|
||||
cnt++;
|
||||
}
|
||||
__t(client, "],\"total\":%d}",records->idx);
|
||||
free(records);
|
||||
//__t(client, query);
|
||||
|
||||
}
|
||||
|
||||
// delete record
|
||||
void delete(int client,const char* method,dictionary rq)
|
||||
{
|
||||
char* id = dvalue(rq,"id");
|
||||
html(client);
|
||||
if(id==NULL)
|
||||
{
|
||||
__t(client,"<p>Invalid delere request <a href='%s'>Back</a></p>", route(NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dbdelete(db,"dummy","id=%s",id))
|
||||
{
|
||||
redirect(client,route(NULL));
|
||||
} else
|
||||
{
|
||||
__t(client,"<p>Invalid delere request <a href='%s'>Back</a></p>", route(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void update(int client,const char* method,dictionary rq)
|
||||
{
|
||||
char * id;
|
||||
html(client);
|
||||
if(IS_GET(method))
|
||||
{
|
||||
id = dvalue(rq,"id");
|
||||
if(id!=NULL)
|
||||
{
|
||||
dbrecord rc = dbselect(db,"dummy","id=%s",id);
|
||||
if(rc->idx > 0)
|
||||
{
|
||||
__t(client,"<html><body><FORM ACTION=\"%s\" METHOD=\"POST\">\
|
||||
Enter a color: \
|
||||
<textarea rows=\"4\" cols=\"50\" NAME=\"color\">%s</textarea>\
|
||||
<INPUT TYPE=\"hidden\" NAME=\"id\" Value=\"%s\">\
|
||||
<INPUT id=\"button\" TYPE=\"submit\">\
|
||||
</FORM> </body></html>",route("update"),value_of(rc->fields,"color"),id);
|
||||
free(rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
__t(client,"<p>No data found. <a href='%s'>Back</a></p>",route(NULL));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
char* color;
|
||||
id = dvalue(rq,"id");
|
||||
color = dvalue(rq,"color");
|
||||
dbfield fields = __field();
|
||||
add_field(&fields,"color",color);
|
||||
if(dbupdate(db,"dummy",fields,"id=%s",id))
|
||||
{
|
||||
redirect(client,route(NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
__t(client,"<p>Invalid Update request <a href='%s'>Back</a></p>", route(NULL));
|
||||
}
|
||||
free(fields);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void jsonex(int client,const char* method,dictionary rq)
|
||||
{
|
||||
//json(client);
|
||||
//__t(client,"{name:\"%s\", age:%d}","Sang",30);
|
||||
jpeg(client);
|
||||
__f(client,htdocs("images/ex.jpg"));
|
||||
}
|
164
plugins/list.c
Normal file
164
plugins/list.c
Normal file
@ -0,0 +1,164 @@
|
||||
#include "list.h"
|
||||
|
||||
Atom __atom()
|
||||
{
|
||||
Atom ret = (Atom){.type = T_UNDEF};
|
||||
return ret;
|
||||
}
|
||||
Atom atom(int type)
|
||||
{
|
||||
Atom ret = (Atom){.type = type};
|
||||
return ret;
|
||||
}
|
||||
list __list()
|
||||
{
|
||||
list ret = malloc(sizeof *ret);
|
||||
ret->e.type = T_UNDEF;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
list last(list l)
|
||||
{
|
||||
list p = l;
|
||||
while( p && p->next != NULL)
|
||||
p = p->next;
|
||||
return p;
|
||||
}
|
||||
|
||||
int size(list l)
|
||||
{
|
||||
int i = 0;
|
||||
list np = l;
|
||||
while(np)
|
||||
{
|
||||
np = np->next;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
Atom lvalueAt(list l,int idx)
|
||||
{
|
||||
list np = lat(l,idx);
|
||||
if(np == NULL) return __atom();
|
||||
return np->e;
|
||||
}
|
||||
|
||||
list lat(list l,int idx)
|
||||
{
|
||||
int i = 0;
|
||||
list np = l;
|
||||
while(np && np->next != NULL)
|
||||
{
|
||||
if(i== idx)
|
||||
return np;
|
||||
np = np->next;
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
list lput(list* l, Atom a)
|
||||
{
|
||||
list new_item = malloc(sizeof *new_item);
|
||||
new_item->e = a;
|
||||
new_item->next = NULL;
|
||||
if((*l) == NULL || (*l)->e.type == T_UNDEF)
|
||||
{
|
||||
(*l) = new_item;
|
||||
return (*l);
|
||||
}
|
||||
list np = last(*l);
|
||||
np->next = new_item;
|
||||
return np->next;
|
||||
}
|
||||
int lremove(list l,int idx)
|
||||
{
|
||||
if(l == NULL) return 0;
|
||||
|
||||
if(idx == 0)
|
||||
{
|
||||
l = l->next;
|
||||
return 1;
|
||||
}
|
||||
list np = lat(l,idx-1);
|
||||
if(np == NULL) return 0;
|
||||
if(np->next == NULL) return 1;
|
||||
np->next = np->next->next;
|
||||
return 1;
|
||||
}
|
||||
char* to_string(Atom a)
|
||||
{
|
||||
switch(a.type)
|
||||
{
|
||||
case T_STR:
|
||||
return a.value.s;
|
||||
break;
|
||||
case T_INT:
|
||||
return __s("%d",a.value.i);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
return __s("%f",a.value.f);
|
||||
break;
|
||||
case T_FIELD:
|
||||
return f2s(a.value.fi);
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
char* fv2s(field f)
|
||||
{
|
||||
switch(f.type)
|
||||
{
|
||||
case T_STR:
|
||||
return __s("%s",f.value.s);
|
||||
break;
|
||||
case T_INT:
|
||||
return __s("%d",f.value.i);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
return __s("%f",f.value.f);
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
char* f2s(field f)
|
||||
{
|
||||
switch(f.type)
|
||||
{
|
||||
case T_STR:
|
||||
return __s("%s='%s'",f.name,f.value.s);
|
||||
break;
|
||||
case T_INT:
|
||||
return __s("%s=%d",f.name,f.value.i);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
return __s("%s=%f",f.name,f.value.f);
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
list split(const char* str, const char* delim)
|
||||
{
|
||||
if(str == NULL || delim == NULL) return NULL;
|
||||
char* str_cpy = strdup(str);
|
||||
char* token;
|
||||
Atom v = atom(T_STR);
|
||||
list l = __list();
|
||||
while((token = strsep(&str_cpy,delim)))
|
||||
{
|
||||
if(strlen(token) > 0)
|
||||
{
|
||||
v = (Atom){.value.s = strdup(token)};
|
||||
lput(&l,v);
|
||||
}
|
||||
}
|
||||
free(str_cpy);
|
||||
if(l->e.type== T_UNDEF)
|
||||
return NULL;
|
||||
|
||||
return l;
|
||||
}
|
57
plugins/list.h
Normal file
57
plugins/list.h
Normal file
@ -0,0 +1,57 @@
|
||||
#include "utils.h"
|
||||
|
||||
#define T_STR 0
|
||||
#define T_INT 1
|
||||
#define T_FLOAT 2
|
||||
#define T_FIELD 3
|
||||
#define T_UNDEF 4
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
int type;
|
||||
union
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
char* s;
|
||||
} value;
|
||||
} field;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
union
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
char* s;
|
||||
field fi;
|
||||
} value;
|
||||
} Atom;
|
||||
|
||||
typedef struct _item
|
||||
{
|
||||
Atom e;
|
||||
struct _item* next;
|
||||
} *list ;
|
||||
|
||||
|
||||
list __list();
|
||||
list lput(list*,Atom);
|
||||
list last(list);
|
||||
int lremove(list,int);
|
||||
int size(list);
|
||||
list lat(list,int);
|
||||
Atom lvalueAt(list, int);
|
||||
Atom atom(int type);
|
||||
char* a2s(Atom);
|
||||
char* f2s(field);
|
||||
char* fv2s(field);
|
||||
list split(const char*, const char*);
|
||||
|
||||
|
||||
|
||||
|
||||
|
214
plugins/plugin.c
Normal file
214
plugins/plugin.c
Normal file
@ -0,0 +1,214 @@
|
||||
#include "plugin.h"
|
||||
|
||||
plugin_header __plugin__;
|
||||
call __init__;
|
||||
// private function
|
||||
|
||||
void __init_plugin__(const char* pl,const char*ph,const char* htdocs, const char* pdir){
|
||||
__plugin__.name = strdup(pl);
|
||||
__plugin__.dbpath= strdup(ph);
|
||||
__plugin__.htdocs = strdup(htdocs);
|
||||
__plugin__.pdir = strdup(pdir);
|
||||
if(__init__ != NULL) __init__();
|
||||
};
|
||||
sqldb getdb()
|
||||
{
|
||||
int plen = strlen(__plugin__.name)+strlen(__plugin__.dbpath)+4;
|
||||
char* path = (char*) malloc(plen*sizeof(char));
|
||||
strcpy(path,__plugin__.dbpath);
|
||||
strcat(path,__plugin__.name);
|
||||
strcat(path,".db");
|
||||
sqldb ret = (sqldb)database(path);
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
void header_base(int client)
|
||||
{
|
||||
|
||||
response(client, "HTTP/1.0 200 OK");
|
||||
response(client, "RPI CAR SERVER ");
|
||||
|
||||
}
|
||||
void redirect(int client,const char*path)
|
||||
{
|
||||
__t(client,"<html><head><meta http-equiv=\"refresh\" content=\"0; url=%s\"></head><body></body></html>",path);
|
||||
}
|
||||
|
||||
void html(int client)
|
||||
{
|
||||
header(client,"text/html; charset=utf-8");
|
||||
}
|
||||
void text(int client)
|
||||
{
|
||||
header(client,"text/plain; charset=utf-8");
|
||||
}
|
||||
void json(int client)
|
||||
{
|
||||
header(client,"application/json");
|
||||
}
|
||||
void jpeg(int client)
|
||||
{
|
||||
header(client,"image/jpeg");
|
||||
}
|
||||
void header(int client, const char* type)
|
||||
{
|
||||
header_base(client);
|
||||
__t(client,"Content-Type: %s",type);
|
||||
response(client,"");
|
||||
}
|
||||
|
||||
void response(int client, const char* data)
|
||||
{
|
||||
char buf[BUFFLEN+3];
|
||||
strcpy(buf, data);
|
||||
int size = strlen(data);
|
||||
buf[size] = '\r';
|
||||
buf[size+1] = '\n';
|
||||
buf[size+2] = '\0';
|
||||
send(client, buf, strlen(buf), 0);
|
||||
}
|
||||
void __ti(int client,int data)
|
||||
{
|
||||
char str[15];
|
||||
sprintf(str, "%d", data);
|
||||
response(client,str);
|
||||
}
|
||||
|
||||
void __t(int client, const char* fstring,...)
|
||||
{
|
||||
|
||||
int dlen;
|
||||
int sent = 0;
|
||||
int buflen = 0;
|
||||
va_list arguments;
|
||||
char * data;
|
||||
char* chunk;
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
va_end(arguments);
|
||||
if ((data = (char*)malloc(dlen*sizeof(char))) != 0)
|
||||
{
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(data, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
if(dlen < BUFFLEN)
|
||||
response(client,data);
|
||||
else
|
||||
{
|
||||
while(sent < dlen - 1)
|
||||
{
|
||||
if(dlen - sent > BUFFLEN)
|
||||
buflen = BUFFLEN;
|
||||
else
|
||||
buflen = dlen - sent - 1;
|
||||
//LOG("BUFFLEN %d\n",buflen);
|
||||
chunk = (char*) malloc((buflen)*sizeof(char));
|
||||
memcpy(chunk,data+sent,buflen);
|
||||
//chunk[buflen-1] = '\0';
|
||||
//response(client,chunk);
|
||||
sent += buflen;
|
||||
send(client, chunk, buflen, 0);
|
||||
free(chunk);
|
||||
}
|
||||
chunk = "\r\n";
|
||||
send(client, chunk, strlen(chunk), 0);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
//
|
||||
}
|
||||
void __b(int client, const unsigned char* data, int size)
|
||||
{
|
||||
char buf[BUFFLEN];
|
||||
int sent = 0;
|
||||
int buflen = 0;
|
||||
if(size <= BUFFLEN)
|
||||
send(client,data,size,0);
|
||||
else
|
||||
{
|
||||
while(sent < size)
|
||||
{
|
||||
if(size - sent > BUFFLEN)
|
||||
buflen = BUFFLEN;
|
||||
else
|
||||
buflen = size - sent;
|
||||
memcpy(buf,data+sent,buflen);
|
||||
send(client,buf,buflen,0);
|
||||
sent += buflen;
|
||||
}
|
||||
}
|
||||
}
|
||||
void __fb(int client, const char* file)
|
||||
{
|
||||
printf("Open file %s\n",file );
|
||||
unsigned char buffer[BUFFLEN];
|
||||
FILE *ptr;
|
||||
ptr = fopen(file,"rb");
|
||||
if(!ptr)
|
||||
{
|
||||
LOG("Cannot read : %s\n", file);
|
||||
return;
|
||||
}
|
||||
while(!feof(ptr))
|
||||
{
|
||||
fread(buffer,BUFFLEN,1,ptr);
|
||||
__b(client,buffer,BUFFLEN);
|
||||
}
|
||||
fclose(ptr);
|
||||
}
|
||||
void __f(int client, const char* file)
|
||||
{
|
||||
unsigned char buf[BUFFLEN];
|
||||
FILE *ptr;
|
||||
ptr = fopen(file,"r");
|
||||
if(!ptr)
|
||||
{
|
||||
LOG("Cannot read : %s\n", file);
|
||||
return;
|
||||
}
|
||||
fgets(buf, sizeof(buf), ptr);
|
||||
while(!feof(ptr))
|
||||
{
|
||||
send(client, buf, strlen(buf), 0);
|
||||
fgets(buf, sizeof(buf), ptr);
|
||||
}
|
||||
fclose(ptr);
|
||||
}
|
||||
|
||||
char* route(const char* repath)
|
||||
{
|
||||
int len = strlen(__plugin__.name) + 2;
|
||||
if(repath != NULL)
|
||||
len += strlen(repath)+1;
|
||||
char * path = (char*) malloc(len*sizeof(char));
|
||||
strcpy(path,"/");
|
||||
strcat(path,__plugin__.name);
|
||||
if(repath != NULL)
|
||||
{
|
||||
strcat(path,"/");
|
||||
strcat(path,repath);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
char* htdocs(const char* repath)
|
||||
{
|
||||
if(repath != NULL)
|
||||
return __s("%s/%s",__plugin__.htdocs,repath);
|
||||
else
|
||||
return __s("%s",__plugin__.htdocs);
|
||||
}
|
||||
int upload(const char* tmp, const char* path)
|
||||
{
|
||||
return !rename(tmp, path);
|
||||
}
|
||||
void set_cookie(int client,dictionary dic)
|
||||
{
|
||||
header_base(client);
|
||||
__t(client,"Content-Type: text/html; charset=utf-8");
|
||||
association assoc;
|
||||
for_each_assoc(assoc,dic){
|
||||
__t(client,"Set-Cookie: %s=%s",assoc->key, assoc->value.s);
|
||||
}
|
||||
response(client,"");
|
||||
}
|
54
plugins/plugin.h
Normal file
54
plugins/plugin.h
Normal file
@ -0,0 +1,54 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "dbhelper.h"
|
||||
#include "dictionary.h"
|
||||
#include "list.h"
|
||||
|
||||
|
||||
#define IS_POST(method) (strcmp(method,"POST")== 0)
|
||||
#define IS_GET(method) (strcmp(method,"GET")== 0)
|
||||
#define R_STR(d,k) (dvalue(d,k))
|
||||
#define R_INT(d,k) (dvalue_i(d,k))
|
||||
#define R_FLOAT(d,k) (dvalue_f(d,k))
|
||||
#define R_PTR(d,k) (dvalue_p(d,k))
|
||||
#define __RESULT__ "{\"result\":%d,\"msg\":\"%s\"}"
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *dbpath;
|
||||
char * htdocs;
|
||||
char*pdir;
|
||||
} plugin_header;
|
||||
|
||||
|
||||
|
||||
typedef void(*call)();
|
||||
|
||||
typedef sqlite3* sqldb;
|
||||
|
||||
extern plugin_header __plugin__;
|
||||
extern call __init__;
|
||||
|
||||
void response(int, const char*);
|
||||
void header_base(int);
|
||||
void header(int,const char*);
|
||||
void redirect(int,const char*);
|
||||
void html(int);
|
||||
void text(int);
|
||||
void json(int);
|
||||
void jpeg(int);
|
||||
void __ti(int,int);
|
||||
void __t(int, const char*,...);
|
||||
void __b(int, const unsigned char*, int);
|
||||
void __f(int, const char*);
|
||||
void __fb(int, const char*);
|
||||
int upload(const char*, const char*);
|
||||
char* route(const char*);
|
||||
char* htdocs(const char*);
|
||||
sqldb getdb();
|
||||
void dbclose(sqldb);
|
||||
void set_cookie(int,dictionary);
|
||||
|
||||
/*Default function for plugin*/
|
||||
void execute(int, const char*,dictionary);
|
10
plugins/urldecode_test.c
Normal file
10
plugins/urldecode_test.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
char* v = url_decode("code=3%2B4");
|
||||
if(match_float(argv[1]))
|
||||
printf("It is a float\n");
|
||||
printf("Result is %s\n",v);
|
||||
return 0;
|
||||
}
|
298
plugins/utils.c
Normal file
298
plugins/utils.c
Normal file
@ -0,0 +1,298 @@
|
||||
#include "utils.h"
|
||||
char* __s(const char* fstring,...)
|
||||
{
|
||||
char* data;
|
||||
va_list arguments;
|
||||
int dlen;
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
va_end(arguments);
|
||||
va_end(arguments);
|
||||
if ((data = (char*)malloc(dlen*sizeof(char))) != 0)
|
||||
{
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(data, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
return data;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Trim a string by a character on both ends
|
||||
* @param str The target string
|
||||
* @param delim the delim
|
||||
*/
|
||||
void trim(char* str, const char delim)
|
||||
{
|
||||
char * p = str;
|
||||
int l = strlen(p);
|
||||
|
||||
while(p[l - 1] == delim) p[--l] = 0;
|
||||
while(* p && (* p) == delim ) ++p, --l;
|
||||
memmove(str, p, l + 1);
|
||||
}
|
||||
|
||||
void removeAll(const char* path,int mode)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
char* file;
|
||||
struct stat st;
|
||||
if( stat(path, &st) == 0)
|
||||
{
|
||||
if(S_ISDIR(st.st_mode))
|
||||
{
|
||||
d = opendir(path);
|
||||
if(d)
|
||||
{
|
||||
while ((dir = readdir(d)) != NULL)
|
||||
{
|
||||
if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..")==0) continue;
|
||||
file = __s("%s/%s",path,dir->d_name);
|
||||
|
||||
removeAll(file,1);
|
||||
free(file);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
}
|
||||
if(mode)
|
||||
remove(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char* __time(time_t time)
|
||||
{
|
||||
struct tm *t = localtime(&time);
|
||||
char * buf = asctime(t);
|
||||
char* pos = strchr(buf,'\n');
|
||||
if(pos) *pos = '\0';
|
||||
return buf;
|
||||
}
|
||||
char* server_time()
|
||||
{
|
||||
return __time(time(NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extension of a file name
|
||||
* @param file The file name
|
||||
* @return the extension
|
||||
*/
|
||||
char* ext(const char* file)
|
||||
{
|
||||
char* token,*ltoken = "";
|
||||
if(file == NULL) return NULL;
|
||||
char* str_cpy = strdup(file);
|
||||
if(strstr(str_cpy,".")<= 0) return "";
|
||||
if(*file == '.')
|
||||
trim(str_cpy,'.');
|
||||
|
||||
while((token = strsep(&str_cpy,".")) && strlen(token)>0) {ltoken = token;}
|
||||
free(str_cpy);
|
||||
return ltoken;
|
||||
|
||||
}
|
||||
/**
|
||||
* Get correct HTTP mime type of a file
|
||||
* This is a minimalistic mime type list supported
|
||||
* by the server
|
||||
* @param file File name
|
||||
* @return The HTTP Mime Type
|
||||
*/
|
||||
char* mime(const char* file)
|
||||
{
|
||||
char * ex = ext(file);
|
||||
if(IEQU(ex,"bmp"))
|
||||
return "image/bmp";
|
||||
else if(IEQU(ex,"jpg") || IEQU(ex,"jpeg"))
|
||||
return "image/jpeg";
|
||||
else if(IEQU(ex,"css"))
|
||||
return "text/css";
|
||||
else if(IEQU(ex,"csv"))
|
||||
return "text/csv";
|
||||
else if(IEQU(ex,"pdf"))
|
||||
return "application/pdf";
|
||||
else if(IEQU(ex,"gif"))
|
||||
return "image/gif";
|
||||
else if(IEQU(ex,"html")||(IEQU(ex,"htm")))
|
||||
return "text/html";
|
||||
else if(IEQU(ex,"json"))
|
||||
return "application/json";
|
||||
else if(IEQU(ex,"js"))
|
||||
return "application/javascript";
|
||||
else if(IEQU(ex,"png"))
|
||||
return "image/png";
|
||||
else if(IEQU(ex,"ppm"))
|
||||
return "image/x-portable-pixmap";
|
||||
else if(IEQU(ex,"rar"))
|
||||
return "application/x-rar-compressed";
|
||||
else if(IEQU(ex,"tiff"))
|
||||
return "image/tiff";
|
||||
else if(IEQU(ex,"tar"))
|
||||
return "application/x-tar";
|
||||
else if(IEQU(ex,"txt"))
|
||||
return "text/plain";
|
||||
else if(IEQU(ex,"ttf"))
|
||||
return "application/x-font-ttf";
|
||||
else if(IEQU(ex,"xhtml"))
|
||||
return "application/xhtml+xml";
|
||||
else if(IEQU(ex,"xml"))
|
||||
return "application/xml";
|
||||
else if(IEQU(ex,"zip"))
|
||||
return "application/zip";
|
||||
else if(IEQU(ex,"svg"))
|
||||
return "image/svg+xml";
|
||||
else if(IEQU(ex,"eot"))
|
||||
return "application/vnd.ms-fontobject";
|
||||
else if(IEQU(ex,"woff") || IEQU(ex,"woff2"))
|
||||
return "application/x-font-woff";
|
||||
else if(IEQU(ex,"otf"))
|
||||
return "application/x-font-otf";
|
||||
else
|
||||
// The other type will be undestant as binary
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
int is_bin(const char* file)
|
||||
{
|
||||
char * ex = ext(file);
|
||||
if(IEQU(ex,"bmp"))
|
||||
return true;
|
||||
else if(IEQU(ex,"jpg") || IEQU(ex,"jpeg"))
|
||||
return true;
|
||||
else if(IEQU(ex,"css"))
|
||||
return false;
|
||||
else if(IEQU(ex,"csv"))
|
||||
return false;
|
||||
else if(IEQU(ex,"pdf"))
|
||||
return true;
|
||||
else if(IEQU(ex,"gif"))
|
||||
return true;
|
||||
else if(IEQU(ex,"html")||(IEQU(ex,"htm")))
|
||||
return false;
|
||||
else if(IEQU(ex,"json"))
|
||||
return false;
|
||||
else if(IEQU(ex,"js"))
|
||||
return false;
|
||||
else if(IEQU(ex,"png"))
|
||||
return true;
|
||||
else if(IEQU(ex,"ppm"))
|
||||
return true;
|
||||
else if(IEQU(ex,"rar"))
|
||||
return true;
|
||||
else if(IEQU(ex,"tiff"))
|
||||
return true;
|
||||
else if(IEQU(ex,"tar"))
|
||||
return true;
|
||||
else if(IEQU(ex,"txt"))
|
||||
return false;
|
||||
else if(IEQU(ex,"ttf"))
|
||||
return true;
|
||||
else if(IEQU(ex,"xhtml"))
|
||||
return false;
|
||||
else if(IEQU(ex,"xml"))
|
||||
return false;
|
||||
else if(IEQU(ex,"zip"))
|
||||
return true;
|
||||
else if(IEQU(ex,"svg"))
|
||||
return false;
|
||||
else if(IEQU(ex,"eot"))
|
||||
return true;
|
||||
else if(IEQU(ex,"woff") || IEQU(ex,"woff2"))
|
||||
return true;
|
||||
else if(IEQU(ex,"otf"))
|
||||
return true;
|
||||
else
|
||||
// The other type will be undestant as binary
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
int match_int(const char* search)
|
||||
{
|
||||
return regex_match("^[-+]?[0-9]+$",search);
|
||||
}
|
||||
int match_float(const char* search)
|
||||
{
|
||||
return regex_match("^[+-]?[0-9]*\\.[0-9]+$",search);
|
||||
}
|
||||
int regex_match(const char* expr,const char* search)
|
||||
{
|
||||
regex_t regex;
|
||||
int reti;
|
||||
char msgbuf[100];
|
||||
int ret;
|
||||
/* Compile regular expression */
|
||||
reti = regcomp(®ex, expr, REG_ICASE | REG_EXTENDED);
|
||||
if( reti ){
|
||||
LOG("Could not compile regex: %s\n",expr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Execute regular expression */
|
||||
reti = regexec(®ex, search, 0, NULL, 0);
|
||||
if( !reti ){
|
||||
//LOG("Match");
|
||||
ret = 1;
|
||||
}
|
||||
else if( reti == REG_NOMATCH ){
|
||||
//LOG("No match");
|
||||
ret = 0;
|
||||
}
|
||||
else{
|
||||
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
||||
LOG("Regex match failed: %s\n", msgbuf);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
|
||||
regfree(®ex);
|
||||
return ret;
|
||||
}
|
||||
char *url_decode(const char *str) {
|
||||
char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
|
||||
|
||||
while (*pstr) {
|
||||
if (*pstr == '%') {
|
||||
if (pstr[1] && pstr[2]) {
|
||||
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
|
||||
pstr += 2;
|
||||
}
|
||||
} else if (*pstr == '+') {
|
||||
*pbuf++ = ' ';
|
||||
} else {
|
||||
*pbuf++ = *pstr;
|
||||
}
|
||||
pstr++;
|
||||
}
|
||||
*pbuf = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *url_encode(const char *str) {
|
||||
char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
|
||||
while (*pstr) {
|
||||
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
|
||||
*pbuf++ = *pstr;
|
||||
else if (*pstr == ' ')
|
||||
*pbuf++ = '+';
|
||||
else
|
||||
*pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
|
||||
pstr++;
|
||||
}
|
||||
*pbuf = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
char from_hex(char ch) {
|
||||
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
|
||||
}
|
||||
|
||||
char to_hex(char code) {
|
||||
static char hex[] = "0123456789abcdef";
|
||||
return hex[code & 15];
|
||||
}
|
43
plugins/utils.h
Normal file
43
plugins/utils.h
Normal file
@ -0,0 +1,43 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <regex.h>
|
||||
#include <time.h>
|
||||
|
||||
#define EQU(a,b) (strcmp(a,b) == 0)
|
||||
#define IEQU(a,b) (strcasecmp(a,b) == 0)
|
||||
#define IS_INT(a) (match_int(a))
|
||||
#define IS_FLOAT(a) (match_float(a))
|
||||
#define DIR_SEP "/"
|
||||
#define true 1
|
||||
#define false 0
|
||||
#ifdef DEBUG
|
||||
#define LOG(a,...) printf("%s:%d: " a, __FILE__, \
|
||||
__LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG(a,...) do{}while(0)
|
||||
#endif
|
||||
#define BUFFLEN 1024
|
||||
|
||||
char* __s(const char*,...);
|
||||
void trim(char*,const char);
|
||||
void removeAll(const char* path,int mode);
|
||||
char* __time(time_t time);
|
||||
char* server_time();
|
||||
char* ext(const char*);
|
||||
char* mime(const char*);
|
||||
int is_bin(const char*);
|
||||
int match_int(const char*);
|
||||
int match_float(const char*);
|
||||
int regex_match(const char*,const char*);
|
||||
char *url_decode(const char *str);
|
||||
char *url_encode(const char *str);
|
||||
char from_hex(char ch);
|
||||
char to_hex(char code);
|
Reference in New Issue
Block a user