diff options
author | LAN-TW <lantw44@gmail.com> | 2014-01-14 22:27:34 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2014-01-14 22:27:34 +0800 |
commit | 562b3936c0140c215bc01ecd7ebc40e004f5b3ba (patch) | |
tree | 45eadcc6507d5b4e6a4d8ad2fbb25867c8ba37b9 /hw4 | |
parent | 08b63dcd438ee4ec68fe9eb61b6cd42ee6684963 (diff) | |
download | sp2013-562b3936c0140c215bc01ecd7ebc40e004f5b3ba.tar sp2013-562b3936c0140c215bc01ecd7ebc40e004f5b3ba.tar.gz sp2013-562b3936c0140c215bc01ecd7ebc40e004f5b3ba.tar.bz2 sp2013-562b3936c0140c215bc01ecd7ebc40e004f5b3ba.tar.lz sp2013-562b3936c0140c215bc01ecd7ebc40e004f5b3ba.tar.xz sp2013-562b3936c0140c215bc01ecd7ebc40e004f5b3ba.tar.zst sp2013-562b3936c0140c215bc01ecd7ebc40e004f5b3ba.zip |
HW4: 基本的 HTTP header 解析
Diffstat (limited to 'hw4')
-rw-r--r-- | hw4/Makefile.am | 2 | ||||
-rwxr-xr-x | hw4/autogen.sh | 2 | ||||
-rw-r--r-- | hw4/chttpd/chttpd-conn.c | 87 | ||||
-rw-r--r-- | hw4/chttpd/chttpd-conn.h | 5 | ||||
-rw-r--r-- | hw4/chttpd/chttpd-server.c | 60 | ||||
-rw-r--r-- | hw4/chttpd/chttpd-server.h | 18 | ||||
-rw-r--r-- | hw4/chttpd/chttpd-socket.h | 1 | ||||
-rw-r--r-- | hw4/l4basic/l4array.c | 258 | ||||
-rw-r--r-- | hw4/l4basic/l4array.h | 88 |
9 files changed, 501 insertions, 20 deletions
diff --git a/hw4/Makefile.am b/hw4/Makefile.am index 62f22d8..b04879a 100644 --- a/hw4/Makefile.am +++ b/hw4/Makefile.am @@ -8,6 +8,8 @@ libl4basic_a_SOURCES = \ l4basic/memwrap.h \ l4basic/memwrap.c \ l4basic/l4common.h \ + l4basic/l4array.h \ + l4basic/l4array.c \ l4basic/l4list.h \ l4basic/l4list.c \ l4basic/l4str.h \ diff --git a/hw4/autogen.sh b/hw4/autogen.sh index 3e7805e..70d6dde 100755 --- a/hw4/autogen.sh +++ b/hw4/autogen.sh @@ -17,7 +17,7 @@ echo "==> Downloading l4basic files" git clone "$1" "tmp" cd "tmp" -for i in l4common.h l4list.[ch] l4posix.[ch] l4str.[ch] +for i in l4common.h l4list.[ch] l4posix.[ch] l4str.[ch] l4array.[ch] do generate_file "$i" "../l4basic/l4basic.sed" done diff --git a/hw4/chttpd/chttpd-conn.c b/hw4/chttpd/chttpd-conn.c index 494742d..893661d 100644 --- a/hw4/chttpd/chttpd-conn.c +++ b/hw4/chttpd/chttpd-conn.c @@ -3,18 +3,28 @@ # include "config.h" #endif +#define CHTTPD_SERVER_ENABLE_ERRMSG + #include "chttpd-conn.h" #include "chttpd-log.h" #include "chttpd-server.h" +#include <l4array.h> #include <l4list.h> +#include <l4str.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> #include <stdlib.h> +#include <stdio.h> #include <unistd.h> #define CHTTPD_CONN_THREAD_INIT \ ChttpdConn* conn = ptr_to_ChttpdConn; \ ChttpdServer* server = conn->server; \ - ChttpdLog* hlog = conn->hlog + ChttpdLog* hlog = conn->hlog; \ + unsigned long long id = conn->id; \ + pthread_sigmask (SIG_SETMASK, &server->conn_mask, NULL); #define CHTTPD_CONN_THREAD_DESTROY \ chttpd_log_write (hlog, "[%4llu] terminated", conn->id); \ @@ -23,18 +33,93 @@ pthread_rwlock_unlock (&server->lock); \ return NULL +static inline char* internal_memstr (const void* haystack, + size_t haystacklen, const char* needle) { + + const char* haychar = haystack; + bool matched; + + for (size_t i = 0; i < haystacklen; i++, haychar++) { + matched = true; + for (size_t j = 0; needle[j] != '\0'; j++) { + if (i + j >= haystacklen || haychar[j] != needle[j]) { + matched = false; + break; + } + } + if (matched) { + return (char*)haychar; + } + } + return NULL; +} + +#define ERRLEN 256 void* chttpd_conn_admin (void* ptr_to_ChttpdConn) { CHTTPD_CONN_THREAD_INIT; + chttpd_log_write (hlog, "[%4llu] sorry, function not implemented", id); + CHTTPD_CONN_THREAD_DESTROY; } void* chttpd_conn_http (void* ptr_to_ChttpdConn) { CHTTPD_CONN_THREAD_INIT; + const char hdr_delim[] = "\015\012\015\012"; + _Static_assert (LBS_STR_STATIC_STRLEN (hdr_delim) == 4, + "HTTP header delimiter length must be 4 bytes!"); + + const char line_delim[] = "\015\012"; + _Static_assert (LBS_STR_STATIC_STRLEN (line_delim) == 2, + "HTTP line delimiter length must be 2bytes!"); + + char errmsg[ERRLEN]; + LbsArray* hdr_buf = lbs_array_new (sizeof (char)); + LbsArray* out_buf = lbs_array_new (sizeof (char)); + size_t data_offset; + + while (true) { + ssize_t r = read (conn->connfd, conn->buf, CHTTPD_CONN_BUF_SIZE); + if (r < 0) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } + chttpd_log_write (hlog, "[%4llu] incomplete header: read: %s", + id, get_errmsg (errno, errmsg, ERRLEN)); + goto http_exit; + } else if (r == 0) { + chttpd_log_write (hlog, "[%4llu] incomplete header: premature EOF", + id); + goto http_exit; + } + + const char* hdr_end = internal_memstr (conn->buf, r, hdr_delim); + if (hdr_end != NULL) { + data_offset = hdr_end - conn->buf; + lbs_array_append_mass (hdr_buf, conn->buf, data_offset); + lbs_array_append_data (hdr_buf, &(char){ '\0' }); + data_offset += 4; + break; + } else { + lbs_array_append_mass (hdr_buf, conn->buf, r); + } + } + + char* method_start = hdr_buf->data; + char* hdr_start = internal_memstr (hdr_buf->data, hdr_buf->len, line_delim); + if (hdr_start != NULL) { + *hdr_start = '\0'; + hdr_start += 2; + } + +http_exit: + lbs_array_unref (hdr_buf); + lbs_array_unref (out_buf); CHTTPD_CONN_THREAD_DESTROY; } +#undef ERRLEN void chttpd_conn_ctor (void* conn_generic, unsigned long long id, int connfd, ChttpdLog* hlog, ChttpdServer* server, LbsListMeta* slist) { diff --git a/hw4/chttpd/chttpd-conn.h b/hw4/chttpd/chttpd-conn.h index d3e1f54..58701fc 100644 --- a/hw4/chttpd/chttpd-conn.h +++ b/hw4/chttpd/chttpd-conn.h @@ -6,6 +6,8 @@ #include <l4list.h> #include <sys/types.h> +#define CHTTPD_CONN_BUF_SIZE 4096 + typedef struct { /* read-only */ unsigned long long id; @@ -18,6 +20,9 @@ typedef struct { /* read-write and lock */ pthread_rwlock_t lock; pid_t pid; + + /* private */ + char buf[CHTTPD_CONN_BUF_SIZE]; } ChttpdConn; void* chttpd_conn_admin (void* ptr_to_ChttpdConn); /* TODO: implement this */ diff --git a/hw4/chttpd/chttpd-server.c b/hw4/chttpd/chttpd-server.c index 0fe1576..7d540d0 100644 --- a/hw4/chttpd/chttpd-server.c +++ b/hw4/chttpd/chttpd-server.c @@ -3,6 +3,8 @@ # include "config.h" #endif +#define CHTTPD_SERVER_ENABLE_ERRMSG + #include "memwrap.h" #include "chttpd-log.h" #include "chttpd-server.h" @@ -241,13 +243,6 @@ static void server_notify_setter (int signo) { static void dummy_handler (int signo) { } -static char* get_errmsg (int errnum, char* buf, size_t buflen) { - if (strerror_r (errnum, buf, buflen) != 0) { - snprintf (buf, buflen, "Unknown error %d", errnum); - } - return buf; -} - #define ERRLEN 256 static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { chttpd_server_notify = 1; @@ -278,6 +273,7 @@ static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { /* Check whether we are going to shutdown the server */ if (server_shutdown) { + server_shutdown = 0; pthread_mutex_lock (&chttpd_server_notify_mutex); chttpd_server_notify = 1; pthread_mutex_unlock (&chttpd_server_notify_mutex); @@ -321,16 +317,19 @@ static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { /* Rebuild poll fd list */ if (slist->len > 0) { pfds = xrealloc (pfds, sizeof (struct pollfd) * slist->len); - nfds = slist->len; unsigned c = 0; - for (iter = slist->first; iter != NULL; iter = iter->next, c++) { + for (iter = slist->first; iter != NULL; iter = iter->next) { ChttpdServer* server = iter->data; - pfds[c] = (struct pollfd) { + if (server->attr_close) { + continue; + } + pfds[c++] = (struct pollfd) { .fd = server->sockfd, .events = POLLIN | POLLPRI, .revents = 0 }; } + nfds = c; } else { free (pfds); pfds = NULL; @@ -353,19 +352,24 @@ static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { ChttpdServer* server = iter->data; struct sockaddr_storage addr; char* type; + size_t conn_count; pthread_rwlock_rdlock (&server->lock); addr = server->addr; type = server->attr_admin ? "ADMIN" : "HTTP"; + conn_count = server->conn->len; pthread_rwlock_unlock (&server->lock); char ipstr[INET6_ADDRSTRLEN]; + _Static_assert (INET6_ADDRSTRLEN >= INET_ADDRSTRLEN, + "Why IPv6 address is shorter than IPv4 address?"); switch (addr.ss_family) { case AF_UNIX: CHTTPD_SOCKET_SOCKADDR_UN_SET_NULL (SOCKADDR_UN (&addr)); chttpd_log_write (hlog, - "Server %u: type %s, UNIX socket, path %s", - c, type, SOCKADDR_UN (&addr)->sun_path); + "Server %u: type %s, UNIX socket, path %s" + " (%zu active connections)", + c, type, SOCKADDR_UN (&addr)->sun_path, conn_count); break; case AF_INET: if (!inet_ntop (AF_INET, &(SOCKADDR_IN (&addr)->sin_addr), @@ -373,8 +377,9 @@ static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { strcpy (ipstr, "unknown"); } chttpd_log_write (hlog, "Server %u: type %s, " - "IPv4 socket, address %s, port %" PRIu16, c, type, - ipstr, ntohs (SOCKADDR_IN (&addr)->sin_port)); + "IPv4 socket, address %s, port %" PRIu16 + " (%zu active connections)", c, type, ipstr, + ntohs (SOCKADDR_IN (&addr)->sin_port), conn_count); break; case AF_INET6: if (!inet_ntop (AF_INET6, &(SOCKADDR_IN6 (&addr)->sin6_addr), @@ -382,8 +387,9 @@ static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { strcpy (ipstr, "unknown"); } chttpd_log_write (hlog, "Server %u: type %s, " - "IPv6 socket, address %s, port %" PRIu16, c, type, - ipstr, ntohs (SOCKADDR_IN6 (&addr)->sin6_port)); + "IPv6 socket, address %s, port %" PRIu16 + " (%zu active connections)", c, type, ipstr, + ntohs (SOCKADDR_IN6 (&addr)->sin6_port), conn_count); break; default: chttpd_log_write (hlog, @@ -399,7 +405,12 @@ static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { pthread_sigmask (SIG_UNBLOCK, &crit_mask, NULL); /* Poll for new request */ - if (pfds == NULL) { + if (pfds == NULL || nfds <= 0) { + if (slist->len > 0) { + nanosleep (&(struct timespec){ 0, 500000000 }, NULL); + chttpd_log_write_str (hlog, + "[main] waiting for remaining connections"); + } continue; } @@ -412,10 +423,16 @@ static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { LbsList* iter = slist->first; for (int i = 0; i < nfds; i++, iter = iter->next) { + ChttpdServer* server = iter->data; + for (; server->attr_close; iter = iter->next, server = iter->data); + if (pfds[i].revents & POLLIN || pfds[i].revents & POLLPRI) { pfds[i].revents = 0; /* Reset revents */ - ChttpdServer* server = iter->data; + if (server->attr_close) { + continue; + } + int connfd = accept (server->sockfd, NULL, NULL); if (connfd < 0) { chttpd_log_write (hlog, "[main] accept: %s", @@ -476,6 +493,13 @@ void chttpd_server_ctor (void* server_generic, ChttpdLog* hlog, bool is_admin) { server->hlog = chttpd_log_ref (hlog); server->conn = lbs_list_meta_new (chttpd_conn_dtor); pthread_rwlock_init (&server->lock, NULL); + + sigemptyset (&server->conn_mask); + sigaddset (&server->conn_mask, SIGINT); + sigaddset (&server->conn_mask, SIGTERM); + sigaddset (&server->conn_mask, SIGHUP); + sigaddset (&server->conn_mask, SIGUSR1); + sigaddset (&server->conn_mask, SIGUSR2); } void chttpd_server_dtor (void* server_generic) { diff --git a/hw4/chttpd/chttpd-server.h b/hw4/chttpd/chttpd-server.h index e85716b..e532adf 100644 --- a/hw4/chttpd/chttpd-server.h +++ b/hw4/chttpd/chttpd-server.h @@ -3,9 +3,26 @@ #include <l4list.h> #include <pthread.h> +#include <signal.h> #include <stdbool.h> #include <sys/socket.h> +#if __STDC_VERSION__ < 201112L +# undef _Static_assert +# define _Static_assert(a,b) +#endif + +#ifdef CHTTPD_SERVER_ENABLE_ERRMSG +# include <stdio.h> +# include <string.h> +static inline char* get_errmsg (int errnum, char* buf, size_t buflen) { + if (strerror_r (errnum, buf, buflen) != 0) { + snprintf (buf, buflen, "Unknown error %d", errnum); + } + return buf; +} +#endif + typedef struct { /* read-only */ int sockfd; @@ -13,6 +30,7 @@ typedef struct { socklen_t addrlen; int attr_admin : 1; ChttpdLog* hlog; + sigset_t conn_mask; /* read-write and lock */ pthread_rwlock_t lock; diff --git a/hw4/chttpd/chttpd-socket.h b/hw4/chttpd/chttpd-socket.h index 7bafcad..edb1d7e 100644 --- a/hw4/chttpd/chttpd-socket.h +++ b/hw4/chttpd/chttpd-socket.h @@ -4,6 +4,7 @@ #include <l4common.h> #include <netinet/in.h> +#include <sys/socket.h> #include <sys/un.h> #define CHTTPD_SOCKET_NEW_ERROR_GETADDRINFO -1 diff --git a/hw4/l4basic/l4array.c b/hw4/l4basic/l4array.c new file mode 100644 index 0000000..b59991d --- /dev/null +++ b/hw4/l4basic/l4array.c @@ -0,0 +1,258 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#include "l4array.h" + +#include <stdlib.h> +#include <string.h> + +LbsArray* lbs_array_new_with_max (size_t size, size_t max) { + if (size <= 0) { + return NULL; + } + + LbsArray* array = xmalloc (sizeof (LbsArray)); + if (array == NULL) { + return NULL; + } + + if (max > 0) { + void* data = xmalloc (size * max); + if (data == NULL) { + free (array); + return NULL; + } + array->data = data; + } else { + array->data = NULL; + } + + array->free_func = NULL; + array->size = size; + array->len = max; + array->max = max; + array->ref_count = 1; + array->is_alloc = true; + + return array; +} + +int lbs_array_init_with_max (LbsArray* array, size_t size, size_t max) { + if (size <= 0) { + return -1; + } + + if (max > 0) { + void* data = xmalloc (size * max); + if (data == NULL) { + return -1; + } + array->data = data; + } else { + array->data = NULL; + } + + array->free_func = NULL; + array->size = size; + array->len = max; + array->max = max; + array->ref_count = 1; + array->is_alloc = false; + + return 0; +} + +LbsArray* lbs_array_copy (LbsArray* dest, const LbsArray* src) { + if (dest == NULL) { + dest = lbs_array_new_with_max (src->size, src->max); + if (dest == NULL) { + return NULL; + } + } else { + if (lbs_array_init_with_max (dest, src->size, src->max) < 0) { + return NULL; + } + } + + dest->len = src->len; + dest->free_func = src->free_func; + if (src->data != NULL && dest->data != NULL) { + memcpy (dest->data, src->data, src->size * src->len); + } + return dest; +} + +LbsArray* lbs_array_cat (LbsArray* dest, const LbsArray* more) { + if (dest == NULL) { + return lbs_array_copy (dest, more); + } + + if (dest->size != more->size) { + return NULL; + } + + int oldlen = dest->len; + if (lbs_array_set_len (dest, dest->len + more->len) < 0) { + return NULL; + } + + memcpy (lbs_array_vp (dest, oldlen), more->data, more->size * more->len); + return dest; +} + +void* lbs_array_ref_generic (void* array_generic) { + LbsArray* array = LBS_ARRAY (array_generic); + array->ref_count++; + return array; +} + +void lbs_array_unref_generic (void* array_generic) { + if (array_generic == NULL) { + return; + } + LbsArray* array = LBS_ARRAY (array_generic); + array->ref_count--; + if (array->ref_count <= 0) { + lbs_array_free (array); + } +} + +void lbs_array_free_generic (void* array_generic) { + if (array_generic == NULL) { + return; + } + LbsArray* array = LBS_ARRAY (array_generic); + if (array->free_func != NULL) { + size_t i = 0; + char* d = array->data; + for (; i < array->len; i++, d += array->size) { + (*(array->free_func)) (*((void**)d)); + } + } + free (array->data); + if (array->is_alloc) { + free (array); + } +} + +void* lbs_array_drop_struct (LbsArray* array) { + if (!array->is_alloc) { + return array->data; + } + + void* data = array->data; + free (array); + return data; +} + +LbsArray* lbs_array_make_struct (LbsArray* array, + size_t size, size_t len, size_t max, void* data) { + + if (array == NULL) { + array = lbs_array_new (size); + if (array == NULL) { + return NULL; + } + } else { + if (lbs_array_init (array, size) < 0) { + return NULL; + } + } + + array->len = len; + array->max = max; + array->data = data; + return array; +} + +int lbs_array_set_len (LbsArray* array, size_t len) { + if (len > (array->max)){ + if (lbs_array_set_max (array, len) < 0) { + return -1; + } else { + array->len = len; + } + } else { + array->len = len; + return 0; + } + return 0; +} + +int lbs_array_set_max (LbsArray* array, size_t max) { + void* ptr = xrealloc (array->data, array->size * max); + if (ptr == NULL) { + return -1; + } + + array->max = max; + array->data = ptr; + return 0; +} + +int lbs_array_append_ptr (LbsArray* array, const void* ptr) { + return lbs_array_append_data (array, &ptr); +} + +int lbs_array_append_data (LbsArray* array, const void* data) { + if (array->max < array->len + 1) { + if (array->max > 0) { + if (lbs_array_set_max (array, array->max * 2) < 0) { + return -1; + } + } else { + if (lbs_array_set_max (array, 1) < 0){ + return -1; + } + } + } + + memcpy (lbs_array_vp (array, array->len), data, array->size); + array->len++; + return 0; +} + +int lbs_array_append_mass (LbsArray* array, const void* data, size_t count) { + bool need_expand = false; + + while (array->max < array->len + count) { + need_expand = true; + if (array->max > 0) { + array->max *= 2; + } else { + array->max = 1; + } + } + + if (need_expand) { + if (lbs_array_set_max (array, array->max) < 0) { + return -1; + } + } + + memcpy (lbs_array_vp (array, array->len), data, array->size * count); + array->len += count; + return 0; +} + +int lbs_array_remove (LbsArray* array) { + if (array->len <= 0) { + return -1; + } + + array->len--; + if (array->len < array->max * 2) { + lbs_array_minimize (array); + } + return 0; +} + +int lbs_array_minimize (LbsArray* array) { + if (array->max > array->len) { + void* ptr = xrealloc (array->data, array->size * array->len); + if (ptr == NULL) { + return -1; + } + array->max = array->len; + array->data = ptr; + } + return 0; +} diff --git a/hw4/l4basic/l4array.h b/hw4/l4basic/l4array.h new file mode 100644 index 0000000..1b45995 --- /dev/null +++ b/hw4/l4basic/l4array.h @@ -0,0 +1,88 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#ifndef LBS_ARRAY_H +#define LBS_ARRAY_H + +#include <l4common.h> + +typedef struct LbsArrayStruct { + /*< public >*/ + void* data; /* data */ + void (*free_func) (void* data); + /* function to free the element */ + + /*< private >*/ + size_t size; /* element size */ + size_t len; /* current length */ + size_t max; /* maximal length */ + unsigned ref_count; /* reference count */ + bool is_alloc; /* is allocated using xmalloc */ +} LbsArray; + +#define LBS_ARRAY(x) ((LbsArray*)(x)) + +#define lbs_array_new(size) \ + (lbs_array_new_with_max (size, 0)) +LbsArray* lbs_array_new_with_max (size_t size, size_t max); + +#define lbs_array_init(array, size) \ + (lbs_array_init_with_max (array, size, 0)) +int lbs_array_init_with_max (LbsArray* array, size_t size, size_t max); + +LbsArray* lbs_array_copy (LbsArray* dest, const LbsArray* src); +LbsArray* lbs_array_cat (LbsArray* dest, const LbsArray* more); + +#define lbs_array_ref(array) \ + (lbs_array_ref_generic (LBS_COMMON_CHECK_TYPE ((array), LbsArray*))) +#define lbs_array_unref(array) \ + (lbs_array_unref_generic (LBS_COMMON_CHECK_TYPE ((array), LbsArray*))) +void* lbs_array_ref_generic (void* array); +void lbs_array_unref_generic (void* array); + +#define lbs_array_free(array) \ + (lbs_array_free_generic (LBS_COMMON_CHECK_TYPE ((array), LbsArray*))) +void lbs_array_free_generic (void* array); +void* lbs_array_drop_struct (LbsArray* array); +LbsArray* lbs_array_make_struct (LbsArray* array, size_t size, size_t len, + size_t max, void* data); + +#define lbs_array_get_data(array) \ + (LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->data) +#define lbs_array_get_size(array) \ + (LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->size) +#define lbs_array_get_len(array) \ + (LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->len) +#define lbs_array_get_max(array) \ + (LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->max) +#define lbs_array_get_ref_count(array) \ + (LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->ref_count) +#define lbs_array_get_is_alloc(array) \ + (LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->is_alloc) +#define lbs_array_get_free_func(array) \ + (LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->free_func) + +int lbs_array_set_len (LbsArray* array, size_t len); +int lbs_array_set_max (LbsArray* array, size_t max); +#define lbs_array_set_free_func(array,value) \ + ((LBS_COMMON_CHECK_TYPE ((array), LbsArray*)->free_func) = (value)) + +#define lbs_array_append_var(array,var) \ + (lbs_array_append_data ((array), (&(var)))) +int lbs_array_append_ptr (LbsArray* array, const void* ptr); +int lbs_array_append_data (LbsArray* array, const void* data); +int lbs_array_append_mass (LbsArray* array, const void* data, + size_t count); +int lbs_array_remove (LbsArray* array); +int lbs_array_minimize (LbsArray* array); +#define lbs_array_push_back lbs_array_append_data +#define lbs_array_push lbs_array_append_data +#define lbs_array_pop_back lbs_array_remove +#define lbs_array_pop lbs_array_remove + +#define lbs_array_vp(array, index) \ + ((void*)(((char*)((array)->data))+(((array)->size)*(index)))) +#define lbs_array_v(array, type, index) \ + (*(((type*)((array)->data))+(index))) +#define lbs_array_index lbs_array_v +#define lbs_array_index_ptr lbs_array_vp + +#endif /* LBS_ARRAY_H */ |