aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile67
-rw-r--r--src/l4arg.c163
-rw-r--r--src/l4arg.h28
-rw-r--r--src/l4array.c178
-rw-r--r--src/l4array.h43
-rw-r--r--src/l4array2.c26
-rw-r--r--src/l4array2.h25
-rw-r--r--src/l4list.c236
-rw-r--r--src/l4list.h66
9 files changed, 832 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..35de0e9
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,67 @@
+# Programs
+HOST=
+CC= $(HOST)c99
+AR= $(HOST)ar
+RANLIB= $(HOST)ranlib
+RM= rm -f
+MKDIR= mkdir
+MKDIR_P= $(MKDIR) -p
+INSTALL= install -c -m 644
+
+# User flags
+CFLAGS= -g -O2 -pipe
+LDFLAGS=
+
+# Internal flags
+L4B_CFLAGS= -Wall -I. $(CFLAGS)
+L4B_LDFLAGS= $(LDFLAGS)
+
+# Installation
+DESTDIR=
+PREFIX= /usr/local
+LIBDIR= $(DESTDIR)$(PREFIX)/lib
+INCLUDEDIR= $(DESTDIR)$(PREFIX)/include
+
+# Tasks definition
+lib_LIBRARIES= libl4basic.a
+libl4basic_a_OBJECTS= l4array.o l4array2.o l4list.o l4arg.o
+libl4basic_a_HEADERS= $(libl4basic_a_OBJECTS:.o=.h)
+
+# Build dependencies
+l4array_o_DEPENDS=
+l4array2_o_DEPENDS=
+l4list_o_DEPENDS=
+l4arg_o_DEPENDS= l4array.o
+
+.POSIX:
+.PHONY: all clean install install-HEADERS install-LIB \
+ uninstall deinstall remove
+.SUFFIXES: .c.o
+.c.o:
+ $(CC) $(L4B_CFLAGS) -c $< -o $@
+
+all: $(lib_LIBRARIES)
+libl4basic.a: $(libl4basic_a_OBJECTS)
+ $(AR) rcs $@ $(libl4basic_a_OBJECTS)
+ $(RANLIB) $@
+l4array.o: l4array.c l4array.h $(l4array_o_DEPENDS)
+l4array2.o: l4array2.c l4array2.h $(l4array2_o_DEPENDS)
+l4list.o: l4list.c l4list.h $(l4list_o_DEPENDS)
+l4arg.o: l4arg.c l4arg.h $(l4arg_o_DEPENDS)
+
+clean:
+ $(RM) $(lib_LIBRARIES) $(libl4basic_a_OBJECTS)
+
+install: all install-HEADERS install-LIB
+install-LIB:
+ -$(MKDIR_P) $(LIBDIR)
+ $(INSTALL) $(lib_LIBRARIES) $(LIBDIR)
+install-HEADERS:
+ -$(MKDIR_P) $(INCLUDEDIR)
+ $(INSTALL) $(libl4basic_a_HEADERS) $(INCLUDEDIR)
+
+deinstall: uninstall
+remove: uninstall
+uninstall:
+ for i in $(lib_LIBRARIES); do $(RM) $(LIBDIR)/$$i; done
+ for i in $(libl4basic_a_HEADERS); do $(RM) $(INCLUDEDIR)/$$i; done
diff --git a/src/l4arg.c b/src/l4arg.c
new file mode 100644
index 0000000..9908665
--- /dev/null
+++ b/src/l4arg.c
@@ -0,0 +1,163 @@
+#include "l4arg.h"
+#include "l4array.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+/* 基本上優先順序是 escape -> quoting -> delimiter */
+
+#define abort_l4arg_toargv \
+ do{ \
+ l4da_free(parr); \
+ l4da_free(tmpstr); \
+ return NULL; \
+ }while(0)
+
+char** l4arg_toargv(const char* str,
+ const char* delim, const char* quoting, const char* esc){
+ int i;
+ char escaped = 0, quoted = 0, delimed = 0;
+ L4DA* parr;
+ L4DA* tmpstr;
+ char* addstr, tmpchar;
+ char** rval;
+ parr = l4da_create(sizeof(char*), 0);
+ if(parr == NULL){
+ return NULL;
+ }
+ tmpstr = l4da_create(sizeof(char), 0);
+ if(tmpstr == NULL){
+ l4da_free(parr);
+ return NULL;
+ }
+ for(i=0; str[i]!='\0'; i++){
+ if(escaped){
+ if(l4da_pushback(tmpstr, &str[i]) < 0){
+ abort_l4arg_toargv;
+ }
+ escaped = 0;
+ delimed = 0;
+ continue;
+ }
+ if(quoted){
+ if(strchr(quoting, str[i]) != NULL){
+ quoted = 0;
+ continue;
+ }
+ if(l4da_pushback(tmpstr, &str[i]) < 0){
+ abort_l4arg_toargv;
+ }
+ delimed = 0;
+ continue;
+ }
+ if(strchr(esc, str[i]) != NULL){
+ escaped = 1;
+ continue;
+ }
+ if(strchr(quoting, str[i]) != NULL){
+ quoted = 1;
+ continue;
+ }
+ if(strchr(delim, str[i]) != NULL){
+ if(l4da_getlen(tmpstr) > 0){
+ tmpchar = '\0';
+ if(l4da_pushback(tmpstr, &tmpchar) < 0){
+ abort_l4arg_toargv;
+ }
+ addstr = (char*)l4da_drop_struct(tmpstr);
+ if(l4da_pushback(parr, &addstr) < 0){
+ l4da_free(parr);
+ return NULL;
+ }
+ tmpstr = l4da_create(sizeof(char), 0);
+ if(tmpstr == NULL){
+ l4da_free(parr);
+ return NULL;
+ }
+ }
+ delimed = 1;
+ continue;
+ }
+ if(l4da_pushback(tmpstr, &str[i]) < 0){
+ abort_l4arg_toargv;
+ }
+ delimed = 0;
+ }
+ if(!delimed){
+ tmpchar = '\0';
+ if(l4da_pushback(tmpstr, &tmpchar) < 0){
+ abort_l4arg_toargv;
+ }
+ addstr = (char*)l4da_drop_struct(tmpstr);
+ if(l4da_pushback(parr, &addstr) < 0){
+ l4da_free(parr);
+ return NULL;
+ }
+ }
+ addstr = NULL;
+ if(l4da_pushback(parr, &addstr) < 0){
+ l4da_free(parr);
+ return NULL;
+ }
+ rval = (char**)l4da_drop_struct(parr);
+ return rval;
+}
+
+void l4arg_toargv_free(char** pargv){
+ int i;
+ for(i=0; pargv[i]!=NULL; i++){
+ free(pargv[i]);
+ }
+ free(pargv);
+}
+
+/* 為什麼叫做 qarg 呢?因為這是用來解析很像 QEMU 命令列參數的參數 */
+
+L4QARG* l4qarg_parse(const char* str){
+ char** pargv = l4arg_toargv(str, ",", "\"\'", "\\");
+ if(pargv == NULL){
+ return NULL;
+ }
+ int i, allc;
+ L4QARG* qargarr;
+ char* pos;
+ for(i=0; pargv[i]!=NULL; i++);
+ allc = i + 1;
+ qargarr = (L4QARG*) malloc(sizeof(L4QARG) * allc);
+ if(qargarr == NULL){
+ l4arg_toargv_free(pargv);
+ return NULL;
+ }
+ for(i=0; pargv[i]!=NULL; i++){
+ pos = strchr(pargv[i], '=');
+ if(pos == NULL){
+ qargarr[i].arg_name = pargv[i];
+ qargarr[i].arg_value = NULL;
+ }else{
+ *pos = '\0';
+ qargarr[i].arg_name = pargv[i];
+ pos++;
+ qargarr[i].arg_value = (char*) malloc(strlen(pos)+1);
+ if(qargarr[i].arg_value == NULL){
+ l4arg_toargv_free(pargv);
+ return NULL;
+ }
+ strcpy(qargarr[i].arg_value, pos);
+ }
+ }
+ free(pargv);
+ qargarr[i].arg_name = NULL;
+ qargarr[i].arg_value = NULL;
+ return qargarr;
+}
+
+void l4qarg_free(L4QARG* qarg){
+ int i;
+ for(i=0; !(qarg[i].arg_name == NULL && qarg[i].arg_value == NULL); i++){
+ free(qarg[i].arg_name);
+ if(qarg[i].arg_value != NULL){
+ free(qarg[i].arg_value);
+ }
+ }
+ free(qarg);
+}
diff --git a/src/l4arg.h b/src/l4arg.h
new file mode 100644
index 0000000..68352c8
--- /dev/null
+++ b/src/l4arg.h
@@ -0,0 +1,28 @@
+#ifndef L4LIB_ARG_PARSER
+#define L4LIB_ARG_PARSER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char** l4arg_toargv(const char*, const char*, const char*, const char*);
+void l4arg_toargv_free(char**);
+
+typedef struct l4lib_qarg {
+ char* arg_name;
+ char* arg_value;
+} L4QARG;
+
+L4QARG* l4qarg_parse(const char*);
+void l4qarg_free(L4QARG*);
+#define l4qarg_n(qargitem) ((qargitem).arg_name)
+#define l4qarg_v(qargitem) ((qargitem).arg_value)
+#define l4qarg_hasvalue(qargitem) (((qargitem).arg_value != NULL))
+#define l4qarg_end(qargitem) \
+ ((((qargitem).arg_name) == NULL) && (((qargitem).arg_value) == NULL))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/l4array.c b/src/l4array.c
new file mode 100644
index 0000000..b57c021
--- /dev/null
+++ b/src/l4array.c
@@ -0,0 +1,178 @@
+#include "l4array.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+L4DA* l4da_create_setmax(int itemsize, int len, int maxlen){
+ if(itemsize <= 0 || len < 0 || maxlen < len){
+ return NULL;
+ }
+ L4DA* arr = (L4DA*)malloc(sizeof(L4DA));
+ if(arr == NULL){
+ return NULL;
+ }
+ arr->arr_itemsize = itemsize;
+ arr->arr_curlen = len;
+ arr->arr_maxlen = maxlen;
+ if(maxlen != 0){
+ arr->arr_data = malloc(itemsize * maxlen);
+ if(arr->arr_data == NULL){
+ free(arr);
+ return NULL;
+ }
+ }else{
+ arr->arr_data = NULL;
+ }
+ return arr;
+}
+
+L4DA* l4da_create(int itemsize, int len){
+ return l4da_create_setmax(itemsize, len, len);
+}
+
+void l4da_free(L4DA* arr){
+ if(arr->arr_data != NULL){
+ free(arr->arr_data);
+ }
+ free(arr);
+}
+
+int l4da_pushback(L4DA* arr, const void* data){
+ if((arr->arr_maxlen) < (arr->arr_curlen + 1)){
+ if(arr->arr_maxlen != 0){
+ if(l4da_setmax(arr, arr->arr_maxlen*2) < 0){
+ return -1;
+ }
+ }else{
+ if(l4da_setmax(arr, 1) < 0){
+ return -1;
+ }
+ }
+ }
+ memcpy(l4da_vp(arr, arr->arr_curlen), data, arr->arr_itemsize);
+ arr->arr_curlen++;
+ return 0;
+}
+
+int l4da_setlen(L4DA* arr, int len){
+ if(len > (arr->arr_maxlen)){
+ if(l4da_setmax(arr, len) < 0){
+ return -1;
+ }else{
+ arr->arr_curlen = len;
+ }
+ }else{
+ arr->arr_curlen = len;
+ return 0;
+ }
+ return 0;
+}
+
+int l4da_setmax(L4DA* arr, int max){
+ void* newptr;
+ if(arr->arr_data == NULL){
+ newptr = malloc((arr->arr_itemsize)*max);
+ if(newptr == NULL){
+ return -1;
+ }else{
+ arr->arr_maxlen = max;
+ arr->arr_data = newptr;
+ return 0;
+ }
+ }
+ newptr = realloc(arr->arr_data, (arr->arr_itemsize)*max);
+ if(newptr == NULL){
+ return -1;
+ }else{
+ arr->arr_maxlen = max;
+ arr->arr_data = newptr;
+ }
+ return 0;
+}
+
+int l4da_strip(L4DA* arr){
+ if(arr->arr_data == NULL){
+ return 0;
+ }
+ L4DA* newptr;
+ /* 其實縮小空間營該一定會成功才對......
+ * 不過還是保險一點,加個判斷式,別說 memory leak 是我害的
+ * 當然也是避免編譯器一直跳 warning
+ */
+ if((arr->arr_maxlen) > (arr->arr_curlen)){
+ arr->arr_maxlen = arr->arr_curlen;
+ newptr = realloc(arr->arr_data, (arr->arr_curlen)*(arr->arr_itemsize));
+ if(newptr == NULL){
+ return -1;
+ }
+ arr->arr_data = newptr;
+ }
+ return 0;
+}
+
+/* 基本上直接玩 struct 的函式還是少用吧 */
+void* l4da_drop_struct(L4DA* arr){
+ void* toreturn = arr->arr_data;
+ free(arr);
+ return toreturn;
+}
+
+L4DA* l4da_make_struct(void* data, int itemsize, int len, int maxlen){
+ if(itemsize <= 0 || len < 0 || maxlen < len){
+ return NULL;
+ }
+ L4DA* arr = (L4DA*)malloc(sizeof(L4DA));
+ if(arr == NULL){
+ return NULL;
+ }
+ arr->arr_itemsize = itemsize;
+ arr->arr_curlen = len;
+ arr->arr_maxlen = maxlen;
+ arr->arr_data = data;
+ return arr;
+}
+
+L4DA* l4da_dup(const L4DA* arr){
+ L4DA* newarr = l4da_create_setmax(
+ l4da_itemsize(arr), l4da_getlen(arr), l4da_getmax(arr));
+ if(newarr == NULL){
+ return NULL;
+ }
+ memcpy(newarr->arr_data, arr->arr_data,
+ l4da_getlen(arr) * l4da_itemsize(arr));
+ return newarr;
+}
+
+int l4da_combine(L4DA* arr, const L4DA* att){
+ if(l4da_itemsize(arr) != l4da_itemsize(att)){
+ return -2;
+ }
+ if(l4da_setlen(arr, l4da_getlen(arr) + l4da_getlen(att)) < 0){
+ return -1;
+ }
+ memcpy(l4da_vp(arr, l4da_getlen(arr)), att->arr_data,
+ l4da_getlen(att) * l4da_itemsize(att));
+ return 0;
+}
+
+L4DA* l4da_filereadline_delim(FILE* infile, int chr){
+ L4DA* newarr = l4da_create(1, 0);
+ if(newarr == NULL){
+ return NULL;
+ }
+ int c;
+ char towrite;
+ while((c = getc(infile)) != chr && !feof(infile)){
+ towrite = c;
+ if(l4da_pushback(newarr, (void*)&towrite) < 0){
+ l4da_free(newarr);
+ return NULL;
+ }
+ }
+ towrite = '\0';
+ if(l4da_pushback(newarr, (void*)&towrite) < 0){
+ l4da_free(newarr);
+ return NULL;
+ }
+ return newarr;
+}
diff --git a/src/l4array.h b/src/l4array.h
new file mode 100644
index 0000000..192f49d
--- /dev/null
+++ b/src/l4array.h
@@ -0,0 +1,43 @@
+#ifndef L4LIB_DYNAMIC_ARRAY
+#define L4LIB_DYNAMIC_ARRAY
+
+#include <stdio.h> /* 取得 FILE */
+
+/*********** 一維陣列 ***********/
+
+typedef struct l4lib_dyn_arr{
+ int arr_itemsize; /* 每個項目的大小 */
+ int arr_curlen; /* 陣列總長度 */
+ int arr_maxlen; /* 陣列最大長度 */
+ void* arr_data; /* 資料區 */
+} L4DA ;
+
+L4DA* l4da_create_setmax(int, int, int);
+L4DA* l4da_create(int, int);
+void l4da_free(L4DA*);
+int l4da_pushback(L4DA*, const void*);
+#define l4da_popback(arr) (((arr)->arr_curlen)--)
+#define l4da_getlen(arr) ((arr)->arr_curlen)
+int l4da_setlen(L4DA*, int);
+#define l4da_getmax(arr) ((arr)->arr_maxlen)
+int l4da_setmax(L4DA*, int);
+int l4da_strip(L4DA*);
+#define l4da_itemsize(arr) ((arr)->arr_itemsize)
+#define l4da_data(arr) ((arr)->arr_data)
+#define l4da_v(arr, type, num) \
+ (*(((type*)((arr)->arr_data))+(num)))
+#define l4da_vp(arr, num) \
+ ((void*)(((char*)((arr)->arr_data))+(((arr)->arr_itemsize)*(num))))
+
+#define l4da_readline() (l4da_filereadline_delim(stdin, '\n'))
+#define l4da_readline_delim(delim) (l4da_filereadline_delim(stdin, (delim)))
+#define l4da_filereadline(infile) (l4da_filereadline_delim((infile), '\n'))
+L4DA* l4da_filereadline_delim(FILE*, int);
+
+L4DA* l4da_dup(const L4DA*);
+int l4da_combine(L4DA*, const L4DA*);
+
+void* l4da_drop_struct(L4DA*);
+L4DA* l4da_make_struct(void*, int, int, int);
+
+#endif
diff --git a/src/l4array2.c b/src/l4array2.c
new file mode 100644
index 0000000..24d6db0
--- /dev/null
+++ b/src/l4array2.c
@@ -0,0 +1,26 @@
+#include "l4array2.h"
+#include <stdlib.h>
+
+L4DA2* l4da2_create(int itemsize, int lenx, int leny){
+ if(lenx <= 0 || leny <= 0 || itemsize <= 0){
+ return NULL;
+ }
+ L4DA2* arr = (L4DA2*)malloc(sizeof(L4DA2));
+ if(arr == NULL){
+ return NULL;
+ }
+ arr->arr_itemsize = itemsize;
+ arr->arr_lenx = lenx;
+ arr->arr_leny = leny;
+ arr->arr_data = malloc(itemsize*lenx*leny);
+ if(arr->arr_data == NULL){
+ free(arr);
+ return NULL;
+ }
+ return arr;
+}
+
+void l4da2_free(L4DA2* arr){
+ free(arr->arr_data);
+ free(arr);
+}
diff --git a/src/l4array2.h b/src/l4array2.h
new file mode 100644
index 0000000..e10fc0b
--- /dev/null
+++ b/src/l4array2.h
@@ -0,0 +1,25 @@
+#ifndef L4LIB_DYNAMIC_ARRAY_D2
+#define L4LIB_DYNAMIC_ARRAY_D2
+
+/*********** 二維陣列 (其實是用一維陣列來模擬,功能有限) ***********/
+
+typedef struct l4lib_dyn_2darr{
+ int arr_itemsize; /* 每個項目的大小 */
+ int arr_lenx; /* 陣列 x 方向長度 */
+ int arr_leny; /* 陣列 y 方向長度 */
+ void* arr_data; /* 資料區 */
+} L4DA2 ;
+
+L4DA2* l4da2_create(int, int, int);
+void l4da2_free(L4DA2*);
+#define l4da2_getlenx(arr) ((arr)->arr_lenx)
+#define l4da2_getleny(arr) ((arr)->arr_leny)
+#define l4da2_itemsize(arr) ((arr)->arr_itemsize)
+#define l4da2_data(arr) ((arr)->arr_data)
+#define l4da2_v(arr, type, numx, numy) \
+ (*(((type*)((arr)->arr_data))+((numx)*(l4da2_getleny(arr)))+(numy)))
+#define l4da2_vp(arr, numx, numy) \
+ ((void*)(((char*)((arr)->arr_data))+ \
+ ((arr)->arr_itemsize)*((numx)*(l4da2_getleny(arr))+(numy))))
+
+#endif
diff --git a/src/l4list.c b/src/l4list.c
new file mode 100644
index 0000000..bcde31b
--- /dev/null
+++ b/src/l4list.c
@@ -0,0 +1,236 @@
+#include "l4list.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+L4LL* l4ll_create(void){
+ L4LL* newlist = (L4LL*)malloc(sizeof(L4LL));
+ if(newlist == NULL){
+ return NULL;
+ }
+ newlist->list_first = NULL;
+ newlist->list_last = NULL;
+ newlist->list_len = 0;
+ return newlist;
+}
+
+void l4ll_free(L4LL* oldlist){
+ if(oldlist->list_len <= 0){
+ free(oldlist);
+ return;
+ }
+ L4LLNODE* i;
+ L4LLNODE* next;
+ for(i=oldlist->list_first; i!=NULL; i=next){
+ next = i->node_next;
+ if(i->node_data_size){ /* 只要資料大小不為零,就還要釋放資料區 */
+ free(i->node_data);
+ }
+ free(i);
+ }
+ free(oldlist);
+}
+
+static L4LLNODE*
+l4ll_initfirst(L4LL* list, const void* data, int size){
+ /* 插入第一個資料,如果 list 不是空的就別用!
+ * 否則會造成資料結構混亂和 memory leak */
+ L4LLNODE* node = (L4LLNODE*)malloc(sizeof(L4LLNODE));
+ if(node == NULL){
+ return NULL;
+ }
+ void* newdata;
+ if(size != 0){
+ newdata = malloc(size);
+ if(newdata == NULL){
+ free(node);
+ return NULL;
+ }
+ memcpy(newdata, data, size);
+ }
+ list->list_first = node;
+ list->list_last = node;
+ list->list_len = 1;
+ node->node_prev = NULL;
+ node->node_next = NULL;
+ node->node_data = (size != 0) ? newdata : NULL;
+ node->node_data_size = size;
+ return node;
+}
+
+L4LLNODE* l4ll_insert_prev(L4LL* list, L4LLNODE* node,
+ const void* data, int size){
+ /* list 送 NULL 來的我不理它,就自己去 segfault 吧
+ * node 送 NULL 來只能在 list 是空的時候用 */
+ if(list->list_len == 0){
+ return l4ll_initfirst(list, data, size);
+ }
+ L4LLNODE* newnode = (L4LLNODE*)malloc(sizeof(L4LLNODE));
+ if(newnode == NULL){
+ return NULL;
+ }
+ void* newdata;
+ if(size != 0){
+ newdata = malloc(size);
+ if(newdata == NULL){
+ free(newnode);
+ return NULL;
+ }
+ memcpy(newdata, data, size);
+ }
+ list->list_len++;
+ if(list->list_first == node){ /* 如果是第一個,那要修改 list_first */
+ list->list_first = newnode;
+ }
+ L4LLNODE* oldprev = node->node_prev;
+ node->node_prev = newnode;
+ newnode->node_next = node;
+ newnode->node_prev = oldprev;
+ if(oldprev != NULL){
+ oldprev->node_next = newnode;
+ }
+ newnode->node_data = (size != 0) ? newdata : NULL;
+ newnode->node_data_size = size;
+ return newnode;
+}
+
+L4LLNODE* l4ll_insert_next(L4LL* list, L4LLNODE* node,
+ const void* data, int size){
+ /* 基本上同 l4ll_insert_prev */
+ if(list->list_len == 0){
+ return l4ll_initfirst(list, data, size);
+ }
+ L4LLNODE* newnode = (L4LLNODE*)malloc(sizeof(L4LLNODE));
+ if(newnode == NULL){
+ return NULL;
+ }
+ void* newdata;
+ if(size != 0){
+ newdata = malloc(size);
+ if(newdata == NULL){
+ free(newnode);
+ return NULL;
+ }
+ memcpy(newdata, data, size);
+ }
+ list->list_len++;
+ if(list->list_last == node){
+ list->list_last = newnode;
+ }
+ L4LLNODE* oldnext = node->node_next;
+ node->node_next = newnode;
+ newnode->node_prev = node;
+ newnode->node_next = oldnext;
+ if(oldnext != NULL){
+ oldnext->node_prev = newnode;
+ }
+ newnode->node_data = (size != 0) ? newdata : NULL;
+ newnode->node_data_size = size;
+ return newnode;
+}
+
+void l4ll_remove(L4LL* list, L4LLNODE* node){
+ /* 不要在 node 傳 NULL,這一點意義也沒有且我不知道會發生什麼事 */
+ if(list->list_first == node){
+ list->list_first = node->node_next;
+ }
+ if(list->list_last == node){
+ list->list_last = node->node_prev;
+ }
+ list->list_len--; /* 不考慮長度為零的情況,空白是想要刪什麼? */
+ L4LLNODE* oldnext = node->node_next;
+ L4LLNODE* oldprev = node->node_prev;
+ if(node->node_data_size != 0){
+ free(node->node_data);
+ }
+ free(node);
+ if(oldnext != NULL){
+ oldnext->node_prev = oldprev;
+ }
+ if(oldprev != NULL){
+ oldprev->node_next = oldnext;
+ }
+}
+
+L4LLNODE* l4ll_goto(L4LLNODE* node, int count){
+ int i;
+ if(count == 0){
+ return node;
+ }else if(count > 0){
+ for(i=1; i<=count; i++){
+ node = node->node_next;
+ if(node == NULL){
+ return NULL;
+ }
+ }
+ }else{
+ count = -count;
+ for(i=1; i<=count; i++){
+ node = node->node_prev;
+ if(node == NULL){
+ return NULL;
+ }
+ }
+ }
+ return node;
+}
+
+#if 0
+int l4ll_pushback(L4LL* list, void* data, int size){
+ L4LLNODE* cur_save = list->list_current; /* 等一下要把現在位置搬回去 */
+ list->list_current = list->list_last;
+ int result = l4ll_insnext(list, data, size);
+ if(result == 0){ /* 成功 */
+ if(cur_save != NULL){ /* 原先的現在位置若為空就無意義了 */
+ list->list_current = cur_save;
+ }
+ }else{ /* 失敗 */
+ list->list_current = cur_save;
+ }
+ return result;
+}
+
+
+int l4ll_pushfront(L4LL*, void*){ /* 取自 l4ll_pushback */
+ L4LLNODE* cur_save = list->list_current;
+ list->list_current = list->list_front;
+ int result = l4ll_insprev(list, data, size);
+ if(result == 0){
+ if(cur_save != NULL){
+ list->list_current = cur_save;
+ }
+ }else{
+ list->list_current = cur_save;
+ }
+ return result;
+}
+
+int l4ll_popback(L4LL*){
+ L4LLNODE* cur_save = list->list_current;
+ L4LLNODE* last_save = list->list_last
+ list->list_current = last_save;
+ int result = l4ll_remove(list, L4LL_PREV);
+ if(result == 0){
+ if(cur_save != NULL && ){
+ list->list_current = cur_save;
+ }
+ }else{
+ list->list_current = cur_save;
+ }
+ return result;
+}
+
+int l4ll_popfront(L4LL*){
+ L4LLNODE* cur_save = list->list_current;
+ list->list_current = list->list_first;
+ int result = l4ll_remove(list, L4LL_NEXT);
+ if(result == 0){
+ if(cur_save != NULL){
+ list->list_current = cur_save;
+ }
+ }else{
+ list->list_current = cur_save;
+ }
+ return result;
+}
+#endif
diff --git a/src/l4list.h b/src/l4list.h
new file mode 100644
index 0000000..2ad7199
--- /dev/null
+++ b/src/l4list.h
@@ -0,0 +1,66 @@
+#ifndef L4LIB_BASIC_DATA_STRUCTURE
+#define L4LIB_BASIC_DATA_STRUCTURE
+
+/*********** list ***********/
+
+typedef struct l4lib_list_node{ /* list 中每一個項目用的資料結構,會有很多個 */
+ struct l4lib_list_node* node_prev;
+ struct l4lib_list_node* node_next;
+ void* node_data;
+ int node_data_size;
+} L4LLNODE;
+
+typedef struct l4lib_list{ /* 管理 list 用的,每個 list 只有一個 */
+ struct l4lib_list_node* list_first;
+ struct l4lib_list_node* list_last;
+ int list_len;
+} L4LL;
+
+L4LL* l4ll_create(void);
+void l4ll_free(L4LL*);
+#define l4ll_prev(node) ((node)->node_prev)
+#define l4ll_next(node) ((node)->node_next)
+#define l4ll_len(list) ((list)->list_len)
+#define l4ll_node_back(list) ((list)->list_last)
+#define l4ll_node_front(list) ((list)->list_first)
+#define l4ll_data(node) ((node)->node_data)
+#define l4ll_datasize(node) ((node)->node_data_size)
+L4LLNODE* l4ll_insert_prev(L4LL*, L4LLNODE*, const void*, int);
+L4LLNODE* l4ll_insert_next(L4LL*, L4LLNODE*, const void*, int);
+void l4ll_remove(L4LL*, L4LLNODE*);
+#define l4ll_pushback(list,data,size) \
+ (l4ll_insert_next((list),(l4ll_node_back(list)),(data),(size)))
+#define l4ll_pushfront(list,data,size) \
+ (l4ll_insert_prev((list),(l4ll_node_front(list)),(data),(size)))
+#define l4ll_popback(list) \
+ (l4ll_remove((list),(l4ll_node_back((list)))))
+#define l4ll_popfront(list) \
+ (l4ll_remove((list),(l4ll_node_front((list)))))
+L4LLNODE* l4ll_goto(L4LLNODE*, int);
+
+/*********** stack ***********/
+
+typedef L4LL L4STACK;
+#define l4stack_create() (l4ll_create())
+#define l4stack_free(list) (l4ll_free(list))
+#define l4stack_push(list,data,size) (l4ll_pushback((list),(data),(size)))
+#define l4stack_pop(list) (l4ll_popback(list))
+#define l4stack_len(list) (l4ll_len(list))
+#define l4stack_data(list) (l4ll_data(l4ll_node_back(list)))
+#define l4stack_datasize(list) (l4ll_datasize(l4ll_node_back(list)))
+
+/*********** queue ***********/
+
+typedef L4LL L4QUEUE;
+#define l4queue_create() (l4ll_create())
+#define l4queue_free(list) (l4ll_free(list))
+#define l4queue_push(list,data,size) (l4ll_pushback((list),(data),(size)))
+#define l4queue_pop(list) (l4ll_popfront(list))
+#define l4queue_len(list) (l4ll_len(list))
+#define l4queue_frontdata(list) (l4ll_data(l4ll_node_front(list)))
+#define l4queue_frontdatasize(list) (l4ll_datasize(l4ll_node_front(list)))
+#define l4queue_backdata(list) (l4ll_data(l4ll_node_back(list)))
+#define l4queue_backdatasize(list) (l4ll_datasize(l4ll_node_back(list)))
+#define l4queue_data(list) (l4queue_frontdata(list))
+#define l4queue_datasize(list) (l4queue_frontdatasize(list))
+#endif