From 218d5b0040f5438b383b3541ba208d9b51d4b9dd Mon Sep 17 00:00:00 2001
From: LAN-TW <lantw44@gmail.com>
Date: Fri, 29 Nov 2013 14:06:55 +0800
Subject: Refactor build system and combine some files

---
 .gitignore        |  14 ++++
 Makefile          |  21 ++---
 l4arg/Makefile    |  24 ------
 l4arg/l4arg.h     |  28 -------
 l4arg/qarg.c      |  54 -------------
 l4arg/toargv.c    | 111 -------------------------
 l4bds/Makefile    |  24 ------
 l4bds/l4bds.h     |  66 ---------------
 l4bds/list.c      | 235 -----------------------------------------------------
 l4darr/Makefile   |  24 ------
 l4darr/d1array.c  | 132 ------------------------------
 l4darr/d1arrstr.c |  47 -----------
 l4darr/d2array.c  |  26 ------
 l4darr/l4darr.h   |  64 ---------------
 src/Makefile      |  67 ++++++++++++++++
 src/l4arg.c       | 163 +++++++++++++++++++++++++++++++++++++
 src/l4arg.h       |  28 +++++++
 src/l4array.c     | 178 ++++++++++++++++++++++++++++++++++++++++
 src/l4array.h     |  43 ++++++++++
 src/l4array2.c    |  26 ++++++
 src/l4array2.h    |  25 ++++++
 src/l4list.c      | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/l4list.h      |  66 +++++++++++++++
 23 files changed, 854 insertions(+), 848 deletions(-)
 create mode 100644 .gitignore
 delete mode 100644 l4arg/Makefile
 delete mode 100644 l4arg/l4arg.h
 delete mode 100644 l4arg/qarg.c
 delete mode 100644 l4arg/toargv.c
 delete mode 100644 l4bds/Makefile
 delete mode 100644 l4bds/l4bds.h
 delete mode 100644 l4bds/list.c
 delete mode 100644 l4darr/Makefile
 delete mode 100644 l4darr/d1array.c
 delete mode 100644 l4darr/d1arrstr.c
 delete mode 100644 l4darr/d2array.c
 delete mode 100644 l4darr/l4darr.h
 create mode 100644 src/Makefile
 create mode 100644 src/l4arg.c
 create mode 100644 src/l4arg.h
 create mode 100644 src/l4array.c
 create mode 100644 src/l4array.h
 create mode 100644 src/l4array2.c
 create mode 100644 src/l4array2.h
 create mode 100644 src/l4list.c
 create mode 100644 src/l4list.h

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..305b898
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+.deps
+.libs
+*~
+*.o
+*.lo
+*.a
+*.la
+*.so
+*.tar
+*.tar.*
+*.swp
+tags
+cscope.out
+\#*\#
diff --git a/Makefile b/Makefile
index b0dd0c8..2667da9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,13 @@
 
-.PHONY: all clean install uninstall
+.PHONY: all clean install uninstall deinstall remove
 all: 
-	$(MAKE) -C l4darr all
-	$(MAKE) -C l4bds all
-	$(MAKE) -C l4arg all
+	$(MAKE) -C src all
 clean:
-	$(MAKE) -C l4darr clean
-	$(MAKE) -C l4bds clean
-	$(MAKE) -C l4arg clean
+	$(MAKE) -C src clean
 install:
-	$(MAKE) -C l4darr install
-	$(MAKE) -C l4bds install
-	$(MAKE) -C l4arg install
+	$(MAKE) -C src install
 uninstall:
-	$(MAKE) -C l4darr uninstall
-	$(MAKE) -C l4bds uninstall
-	$(MAKE) -C l4arg uninstall
+	$(MAKE) -C src uninstall
+
+deinstall: uninstall
+remove: uninstall
diff --git a/l4arg/Makefile b/l4arg/Makefile
deleted file mode 100644
index 0f2ffe3..0000000
--- a/l4arg/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-CC=cc
-AR=ar
-RM=rm -f
-INSTALL=install -m 644
-LOCAL_CFLAGS=-g
-CFLAGS=-Wall -I. -I../l4darr $(LOCAL_CFLAGS)
-OBJ=toargv.o qarg.o
-LIBFILE=libl4arg.a
-DESTDIR=/
-PREFIX=/usr/local
-LIBDIR=$(DESTDIR)/$(PREFIX)/lib
-
-.PHONY: all clean
-
-all: $(LIBFILE)
-$(LIBFILE): $(OBJ)
-	$(AR) rcs $(LIBFILE) $(OBJ)
-clean:
-	$(RM) $(LIBFILE) $(OBJ)
-install:
-	mkdir -p $(LIBDIR)
-	$(INSTALL) $(LIBFILE) $(LIBDIR)
-uninstall:
-	$(RM) $(LIBDIR)/$(LIBFILE)
diff --git a/l4arg/l4arg.h b/l4arg/l4arg.h
deleted file mode 100644
index 68352c8..0000000
--- a/l4arg/l4arg.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#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/l4arg/qarg.c b/l4arg/qarg.c
deleted file mode 100644
index 412967c..0000000
--- a/l4arg/qarg.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <l4arg.h>
-
-/* 為什麼叫做 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/l4arg/toargv.c b/l4arg/toargv.c
deleted file mode 100644
index 433ad1a..0000000
--- a/l4arg/toargv.c
+++ /dev/null
@@ -1,111 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <l4arg.h>
-#include <l4darr.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);
-}
diff --git a/l4bds/Makefile b/l4bds/Makefile
deleted file mode 100644
index c4c2caa..0000000
--- a/l4bds/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-CC=cc
-AR=ar
-RM=rm -f
-INSTALL=install -m 644
-LOCAL_CFLAGS=-g
-CFLAGS=-Wall -I. $(LOCAL_CFLAGS)
-OBJ=list.o
-LIBFILE=libl4bds.a
-DESTDIR=/
-PREFIX=/usr/local
-LIBDIR=$(DESTDIR)/$(PREFIX)/lib
-
-.PHONY: all clean
-
-all: $(LIBFILE)
-$(LIBFILE): $(OBJ)
-	$(AR) rcs $(LIBFILE) $(OBJ)
-clean:
-	$(RM) $(LIBFILE) $(OBJ)
-install:
-	mkdir -p $(LIBDIR)
-	$(INSTALL) -c $(LIBFILE) $(LIBDIR)
-uninstall:
-	$(RM) $(LIBDIR)/$(LIBFILE)
diff --git a/l4bds/l4bds.h b/l4bds/l4bds.h
deleted file mode 100644
index 2ad7199..0000000
--- a/l4bds/l4bds.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#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
diff --git a/l4bds/list.c b/l4bds/list.c
deleted file mode 100644
index 09ec746..0000000
--- a/l4bds/list.c
+++ /dev/null
@@ -1,235 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <l4bds.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/l4darr/Makefile b/l4darr/Makefile
deleted file mode 100644
index 4593ccf..0000000
--- a/l4darr/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-CC=cc
-AR=ar
-RM=rm -f
-INSTALL=install -m 644
-LOCAL_CFLAGS=-g
-CFLAGS=-Wall -I. $(LOCAL_CFLAGS)
-OBJ=d1array.o d1arrstr.o d2array.o
-LIBFILE=libl4darr.a
-DESTDIR=/
-PREFIX=/usr/local
-LIBDIR=$(DESTDIR)/$(PREFIX)/lib
-
-.PHONY: all clean
-
-all: $(LIBFILE)
-$(LIBFILE): $(OBJ)
-	$(AR) rcs $(LIBFILE) $(OBJ)
-clean:
-	$(RM) $(LIBFILE) $(OBJ)
-install:
-	mkdir -p $(LIBDIR)
-	$(INSTALL) -c $(LIBFILE) $(LIBDIR)
-uninstall:
-	$(RM) $(LIBDIR)/$(LIBFILE)
diff --git a/l4darr/d1array.c b/l4darr/d1array.c
deleted file mode 100644
index b14bbea..0000000
--- a/l4darr/d1array.c
+++ /dev/null
@@ -1,132 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <l4darr.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;
-}
diff --git a/l4darr/d1arrstr.c b/l4darr/d1arrstr.c
deleted file mode 100644
index 2c6e631..0000000
--- a/l4darr/d1arrstr.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <string.h>
-#include <l4darr.h>
-
-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/l4darr/d2array.c b/l4darr/d2array.c
deleted file mode 100644
index c2d6e69..0000000
--- a/l4darr/d2array.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <stdlib.h>
-#include <l4darr.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/l4darr/l4darr.h b/l4darr/l4darr.h
deleted file mode 100644
index 860f9b9..0000000
--- a/l4darr/l4darr.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#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);
-
-/*********** 二維陣列 (其實是用一維陣列來模擬,功能有限) ***********/
-
-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/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
-- 
cgit