summaryrefslogtreecommitdiffstats
path: root/hw4/l4basic
diff options
context:
space:
mode:
Diffstat (limited to 'hw4/l4basic')
-rw-r--r--hw4/l4basic/l4common.h42
-rw-r--r--hw4/l4basic/l4list.c201
-rw-r--r--hw4/l4basic/l4list.h116
-rw-r--r--hw4/l4basic/l4posix.c333
-rw-r--r--hw4/l4basic/l4posix.h41
-rw-r--r--hw4/l4basic/l4str.c44
-rw-r--r--hw4/l4basic/l4str.h15
7 files changed, 792 insertions, 0 deletions
diff --git a/hw4/l4basic/l4common.h b/hw4/l4basic/l4common.h
new file mode 100644
index 0000000..c41539c
--- /dev/null
+++ b/hw4/l4basic/l4common.h
@@ -0,0 +1,42 @@
+#include "memwrap.h"
+/* This file is modified by autogen.sh */
+/* vim: set sw=4 ts=4 sts=4 et: */
+#ifndef LBS_COMMON_H
+#define LBS_COMMON_H
+
+#include <stddef.h>
+
+#ifdef __STDC_VERSION__
+# include <stdbool.h>
+# if __STDC_VERSION__ >= 201112L
+# define LBS_COMMON_ISO_C11
+# define LBS_COMMON_CHECK_TYPE(x,type) (_Generic ((x), type: (x)))
+# else
+# define LBS_COMMON_ISO_C99
+# define LBS_COMMON_CHECK_TYPE(x,type) (x)
+# endif
+#else
+# ifdef __cplusplus
+# define LBS_COMMON_CXX
+# define LBS_COMMON_CHECK_TYPE(x,type) (x)
+# else
+# define bool char
+# define true 1
+# define false 0
+# define inline
+# define LBS_COMMON_ISO_C89
+# define LBS_COMMON_CHECK_TYPE(x,type) (x)
+# endif /* __cplusplus */
+#endif /* __STDC_VERSION__ */
+
+#define LBS_COMMON_NULL_PTR ((void*)NULL)
+#define LBS_COMMON_DEFINE_GETTER(ns,xt,m,mt) \
+ static inline mt ns ## _get_ ## m (xt x) { \
+ return x->m; \
+ }
+#define LBS_COMMON_DEFINE_SETTER(ns,xt,m,mt) \
+ static inline void ns ## _set_ ## m (xt x, mt v) { \
+ x->m = v; \
+ }
+
+#endif /* LBS_COMMON_H */
diff --git a/hw4/l4basic/l4list.c b/hw4/l4basic/l4list.c
new file mode 100644
index 0000000..3569b19
--- /dev/null
+++ b/hw4/l4basic/l4list.c
@@ -0,0 +1,201 @@
+#include "memwrap.h"
+/* This file is modified by autogen.sh */
+/* vim: set sw=4 ts=4 sts=4 et: */
+#include "l4list.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+LbsListMeta* lbs_list_meta_new (void (*free_func) (void*)) {
+ LbsListMeta* list = xmalloc (sizeof (LbsListMeta));
+ if (list == NULL) {
+ return NULL;
+ }
+
+ list->first = NULL;
+ list->last = NULL;
+ list->len = 0;
+ list->free_func = free_func;
+
+ return list;
+}
+
+void lbs_list_meta_free (LbsListMeta* list) {
+ if (list == NULL) {
+ return;
+ }
+ if (list->len <= 0) {
+ free (list);
+ return;
+ }
+
+ LbsList *iter, *next;
+ for (iter = list->first; iter != NULL; iter = next) {
+ next = iter->next;
+ if (iter->free_func != NULL) {
+ (*(iter->free_func)) (iter->data);
+ } else if (list->free_func != NULL) {
+ (*(list->free_func)) (iter->data);
+ }
+ free (iter);
+ }
+ free (list);
+}
+
+static LbsList* init_first_node (LbsListMeta* list,
+ void* data, void (*free_func) (void*)) {
+
+ /* Warning: This function assumes the list is empty! */
+ LbsList* node = xmalloc (sizeof (LbsList));
+ if (node == NULL) {
+ return NULL;
+ }
+
+ if (list != NULL) {
+ list->first = node;
+ list->last = node;
+ list->len = 1;
+ }
+
+ node->prev = NULL;
+ node->next = NULL;
+ node->data = data;
+ node->free_func = free_func;
+
+ return node;
+}
+
+LbsList* lbs_list_insert_prev (LbsListMeta* list, LbsList* node,
+ void* data, void (*free_func) (void*)) {
+
+ if (list != NULL && list->len <= 0) {
+ return init_first_node (list, data, free_func);
+ }
+
+ LbsList* new_node = xmalloc (sizeof (LbsList));
+ if (new_node == NULL) {
+ return NULL;
+ }
+
+ if (node == NULL) {
+ new_node->prev = NULL;
+ new_node->next = NULL;
+ new_node->data = data;
+ new_node->free_func = free_func;
+ return new_node;
+ }
+
+ if (list != NULL) {
+ list->len++;
+ if (list->first == node) {
+ list->first = new_node;
+ }
+ }
+
+ LbsList* old_prev = node->prev;
+ node->prev = new_node;
+ new_node->next = node;
+ new_node->prev = old_prev;
+ if (old_prev != NULL) {
+ old_prev->next = new_node;
+ }
+
+ new_node->data = data;
+ new_node->free_func = free_func;
+ return new_node;
+}
+
+LbsList* lbs_list_insert_next (LbsListMeta* list, LbsList* node,
+ void* data, void (*free_func) (void*)) {
+
+ if (list != NULL && list->len <= 0) {
+ return init_first_node (list, data, free_func);
+ }
+
+ LbsList* new_node = xmalloc (sizeof (LbsList));
+ if (new_node == NULL) {
+ return NULL;
+ }
+
+ if (node == NULL) {
+ new_node->prev = NULL;
+ new_node->next = NULL;
+ new_node->data = data;
+ new_node->free_func = free_func;
+ return new_node;
+ }
+
+ if (list != NULL) {
+ list->len++;
+ if(list->last == node){
+ list->last = new_node;
+ }
+ }
+
+ LbsList* old_next = node->next;
+ node->next = new_node;
+ new_node->prev = node;
+ new_node->next = old_next;
+ if (old_next != NULL) {
+ old_next->prev = new_node;
+ }
+
+ new_node->data = data;
+ new_node->free_func = free_func;
+ return new_node;
+}
+
+void lbs_list_remove (LbsListMeta* list, LbsList* node) {
+ /* node must not be NULL! */
+ if (list != NULL) {
+ if (list->first == node) {
+ list->first = node->next;
+ }
+ if (list->last == node) {
+ list->last = node->prev;
+ }
+ if (list->len > 0) {
+ list->len--;
+ }
+ }
+
+ LbsList* old_next = node->next;
+ LbsList* old_prev = node->prev;
+
+ if (node->free_func != NULL) {
+ (*(node->free_func)) (node->data);
+ } else if (list != NULL && list->free_func != NULL) {
+ (*(list->free_func)) (node->data);
+ }
+ free (node);
+
+ if (old_next != NULL) {
+ old_next->prev = old_prev;
+ }
+ if (old_prev != NULL) {
+ old_prev->next = old_next;
+ }
+}
+
+LbsList* lbs_list_goto (LbsList* node, int count) {
+ int i;
+
+ if (count > 0) { /* positive */
+ for (i = 0; i < count; i++) {
+ node = node->next;
+ if (node == NULL) {
+ return NULL;
+ }
+ }
+ } else if (count < 0) { /* negative */
+ count = -count;
+ for (i = 0; i < count; i++) {
+ node = node->prev;
+ if (node == NULL) {
+ return NULL;
+ }
+ }
+ }
+
+ return node;
+}
diff --git a/hw4/l4basic/l4list.h b/hw4/l4basic/l4list.h
new file mode 100644
index 0000000..00dba10
--- /dev/null
+++ b/hw4/l4basic/l4list.h
@@ -0,0 +1,116 @@
+#include "memwrap.h"
+/* This file is modified by autogen.sh */
+/* vim: set sw=4 ts=4 sts=4 et: */
+#ifndef LBS_LIST_H
+#define LBS_LIST_H
+
+#include <l4common.h>
+
+typedef struct LbsListStruct { /* list node */
+ /*< private >*/
+ struct LbsListStruct* prev; /* pointer to the previous node */
+ struct LbsListStruct* next; /* pointer to the next node */
+
+ /*< public >*/
+ void (*free_func) (void* data); /* function to free the data pointer */
+ void* data; /* data pointer */
+} LbsList;
+
+typedef struct LbsListMetaStruct { /* list wrapper */
+ /*< private >*/
+ struct LbsListStruct* first; /* pointer to the first node in the list */
+ struct LbsListStruct* last; /* pointer to the last node in the list */
+ size_t len; /* current length of the list */
+
+ /*< public >*/
+ void (*free_func) (void* data);
+ /* Function to free the data pointer. This function is used only if
+ * the free_func field in the node is set to NULL */
+} LbsListMeta;
+
+#define LBS_LIST(x) ((LbsList*)(x))
+#define LBS_LIST_META(x) ((LbsListMeta*)(x))
+
+LbsListMeta* lbs_list_meta_new (void (*free_func) (void*));
+void lbs_list_meta_free (LbsListMeta* list);
+
+#define lbs_list_meta_get_first(list) \
+ (LBS_COMMON_CHECK_TYPE ((list), LbsListMeta*)->first)
+#define lbs_list_meta_get_last(list) \
+ (LBS_COMMON_CHECK_TYPE ((list), LbsListMeta*)->last)
+#define lbs_list_meta_get_len(list) \
+ (LBS_COMMON_CHECK_TYPE ((list), LbsListMeta*)->len)
+#define lbs_list_meta_get_free_func(list) \
+ (LBS_COMMON_CHECK_TYPE ((list), LbsListMeta*)->free_func)
+
+#define lbs_list_meta_set_free_func(list,value) \
+ ((LBS_COMMON_CHECK_TYPE ((list), LbsListMeta*)->free_func) = (value))
+
+#define lbs_list_get_prev(node) \
+ (LBS_COMMON_CHECK_TYPE ((node), LbsList*)->prev)
+#define lbs_list_get_next(node) \
+ (LBS_COMMON_CHECK_TYPE ((node), LbsList*)->next)
+#define lbs_list_get_data(node) \
+ (LBS_COMMON_CHECK_TYPE ((node), LbsList*)->data)
+#define lbs_list_get_free_func(node) \
+ (LBS_COMMON_CHECK_TYPE ((node), LbsList*)->free_func)
+
+#define lbs_list_set_data(node,value) \
+ ((LBS_COMMON_CHECK_TYPE ((node), LbsList*)->data) = (value))
+#define lbs_list_set_free_func(node,value) \
+ ((LBS_COMMON_CHECK_TYPE ((node), LbsList*)->free_func) = (value))
+
+LbsList* lbs_list_insert_prev (LbsListMeta* list, LbsList* node,
+ void* data, void (*free_func) (void*));
+LbsList* lbs_list_insert_next (LbsListMeta* list, LbsList* node,
+ void* data, void (*free_func) (void*));
+void lbs_list_remove (LbsListMeta* list, LbsList* node);
+
+#define lbs_list_push_back(list,data,f) \
+ (lbs_list_insert_next ((list), (lbs_list_meta_get_last (list)), (data), (f)))
+#define lbs_list_push_front(list,data,f) \
+ (lbs_list_insert_prev ((list), (lbs_list_meta_get_first (list)), (data), (f)))
+#define lbs_list_pop_back(list) \
+ (lbs_list_remove ((list), (lbs_list_meta_get_last ((list)))))
+#define lbs_list_pop_front(list) \
+ (lbs_list_remove ((list), (lbs_list_meta_get_first ((list)))))
+
+LbsList* lbs_list_goto (LbsList* node, int count);
+#define lbs_list_meta_goto(list,count) \
+ (lbs_list_goto ((lbs_list_meta_get_first (list)), (count)))
+
+
+#ifndef LBS_LIST_DISABLE_STACK
+
+typedef LbsListMeta LbsStack;
+#define lbs_stack_new(f) (lbs_list_meta_new (f))
+#define lbs_stack_free(stack) (lbs_list_meta_free (stack))
+#define lbs_stack_push(stack,data,f) \
+ (lbs_list_push_back ((stack), (data), (f)))
+#define lbs_stack_pop(stack) (lbs_list_pop_back (stack))
+#define lbs_stack_get_len(stack) (lbs_list_meta_get_len (stack))
+#define lbs_stack_get_data(stack) \
+ (lbs_list_get_data (lbs_list_meta_get_last (stack)))
+
+#endif /* LBS_LIST_DISABLE_STACK */
+
+
+#ifndef LBS_LIST_DISABLE_QUEUE
+
+typedef LbsListMeta LbsQueue;
+#define lbs_queue_new(f) (lbs_list_meta_new (f))
+#define lbs_queue_free(queue) (lbs_list_meta_free (queue))
+#define lbs_queue_enqueue(queue,data,f) \
+ (lbs_list_push_back ((queue), (data), (f)))
+#define lbs_queue_dequeue(queue) (lbs_list_pop_front (queue))
+#define lbs_queue_get_len(queue) (lbs_list_meta_get_len (queue))
+#define lbs_queue_get_front(queue) \
+ (lbs_list_get_data (lbs_list_meta_get_first (queue)))
+#define lbs_queue_get_back(queue) \
+ (lbs_list_get_data (lbs_list_meta_get_last (queue)))
+#define lbs_queue_get_data(queue) (lbs_queue_get_front (queue))
+
+#endif /* LBS_LIST_DISABLE_QUEUE */
+
+
+#endif /* LBS_LIST_H */
diff --git a/hw4/l4basic/l4posix.c b/hw4/l4basic/l4posix.c
new file mode 100644
index 0000000..82b42a0
--- /dev/null
+++ b/hw4/l4basic/l4posix.c
@@ -0,0 +1,333 @@
+#include "memwrap.h"
+/* This file is modified by autogen.sh */
+/* vim: set sw=4 ts=4 sts=4 et: */
+#define _POSIX_C_SOURCE 200809L
+#define _XOPEN_SOURCE 700
+#include "l4posix.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+char* lbs_posix_strcat (const char* str, ...) {
+ va_list ap;
+ char* strp;
+ char* strnow;
+ char* newstr;
+ int len = strlen (str);
+
+ va_start (ap, str);
+ while ((strp = va_arg (ap, char*)) != NULL) {
+ len += strlen (strp);
+ }
+ va_end (ap);
+
+ newstr = xmalloc (len + 1);
+
+ va_start (ap, str);
+ strnow = stpcpy (newstr, str);
+ while ((strp = va_arg (ap, char*)) != NULL) {
+ strnow = stpcpy (strnow, strp);
+ }
+ newstr[len] = '\0';
+ va_end (ap);
+
+ return newstr;
+}
+
+int lbs_posix_add_fd (int fd, int fdflags) {
+ int orgfd = fcntl (fd, F_GETFD);
+ if (orgfd < 0) {
+ return -1;
+ }
+ return fcntl (fd, F_SETFD, orgfd | fdflags);
+}
+
+int lbs_posix_del_fd (int fd, int fdflags) {
+ int orgfd = fcntl (fd, F_GETFD);
+ if (orgfd < 0) {
+ return -1;
+ }
+ return fcntl (fd, F_SETFD, orgfd & ~(fdflags));
+}
+
+int lbs_posix_add_fl (int fd, int flflags) {
+ int orgfl = fcntl (fd, F_GETFL);
+ if (orgfl < 0) {
+ return -1;
+ }
+ return fcntl (fd, F_SETFL, orgfl | flflags);
+}
+
+int lbs_posix_del_fl (int fd, int flflags) {
+ int orgfl = fcntl (fd, F_GETFL);
+ if (orgfl < 0) {
+ return -1;
+ }
+ return fcntl (fd, F_SETFL, orgfl & ~(flflags));
+}
+
+char* lbs_posix_readlink (const char* filename) {
+ struct stat st;
+ if (lstat (filename, &st) < 0) {
+ return NULL;
+ }
+ size_t bufsize = st.st_size ? st.st_size : 8192;
+ char* buf = xmalloc (bufsize + 1);
+ if (buf == NULL) {
+ return NULL;
+ }
+ ssize_t written = readlink (filename, buf, bufsize);
+ if (written < 0) {
+ free (buf);
+ return NULL;
+ }
+ buf[written] = '\0';
+ return buf;
+}
+
+char* lbs_posix_getcwd (void) {
+ char *cwd, *result;
+ size_t size = pathconf (".", _PC_PATH_MAX);
+
+ size = size > 0 ? size : 256;
+ size = size > 8192 ? 8192 : size;
+ cwd = xmalloc (sizeof (char) * size);
+
+ while ((result = getcwd (cwd, size)) == NULL && errno == ERANGE) {
+ size *= 2;
+ cwd = xrealloc (cwd, size);
+ }
+
+ return cwd;
+}
+
+size_t lbs_posix_write_all (int fd, const char* str, size_t size) {
+ ssize_t wtn = 0;
+ if (size <= 0) {
+ size = strlen (str);
+ }
+ size_t rem = size;
+ while (rem > 0) {
+ wtn = write (fd, str, rem);
+ if (wtn < 0) {
+ if (errno != EINTR && errno != EAGAIN) {
+ break;
+ }
+ continue;
+ }
+ str += wtn;
+ rem -= wtn;
+ }
+
+ rem = rem > 0 ? rem : 0;
+ return size - rem;
+}
+
+void lbs_posix_buffer_init (LbsPosixBuffer* buf) {
+ buf->buf_start = 0;
+ buf->buf_len = 0;
+ buf->buf_line = NULL;
+ buf->buf_line_len = 0;
+ buf->buf_error = false;
+ buf->buf_eof = false;
+}
+
+void lbs_posix_buffer_clear (LbsPosixBuffer* buf, bool initial) {
+ buf->buf_start = 0;
+ buf->buf_len = 0;
+
+ if (!initial) {
+ free (buf->buf_line);
+ }
+ buf->buf_line = NULL;
+ buf->buf_line_len = 0;
+ buf->buf_error = false;
+ buf->buf_eof = false;
+}
+
+char* lbs_posix_buffer_getline (int fd, LbsPosixBuffer* buf, int delim) {
+ if (buf->buf_error || buf->buf_eof) {
+ return NULL;
+ }
+
+ if (buf->buf_len == 0) {
+ int rval = read (fd, buf->buf, LBS_POSIX_BUFFER_SIZE);
+ if (rval < 0) {
+ if (errno != EAGAIN && errno != EINTR) {
+ buf->buf_error = true;
+ }
+ return NULL;
+ }
+ if (rval == 0) {
+ buf->buf_eof = true;
+ return NULL;
+ }
+ buf->buf_start = 0;
+ buf->buf_len = rval;
+ }
+
+ int i;
+ for (i = 0; i < buf->buf_len; i++) {
+ if (buf->buf[buf->buf_start + i] == delim) {
+ break;
+ }
+ }
+
+ int buf_line_start = buf->buf_line_len;
+ buf->buf_line_len += i;
+ buf->buf_line = xrealloc (buf->buf_line, buf->buf_line_len + 1);
+ memcpy (buf->buf_line + buf_line_start, buf->buf + buf->buf_start, i);
+ buf->buf_line[buf->buf_line_len] = '\0';
+
+ /* remove CR if delim is LF and delim is found */
+ if (i < buf->buf_len && delim == '\n' && buf->buf_line_len - 1 >= 0 &&
+ buf->buf_line[buf->buf_line_len - 1] == '\r') {
+ buf->buf_line[buf->buf_line_len - 1] = '\0';
+ buf->buf_line_len--;
+ }
+
+ int buf_len_saved = buf->buf_len;
+ buf->buf_start += i + 1;
+ buf->buf_len -= i + 1;
+ if (buf->buf_len <= 0) {
+ buf->buf_start = 0;
+ buf->buf_len = 0;
+ }
+
+ if (i < buf_len_saved) {
+ /* delim is found */
+ char* newstr = buf->buf_line;
+ buf->buf_line = NULL;
+ buf->buf_line_len = 0;
+ memmove (buf->buf, buf->buf + buf->buf_start, buf->buf_len);
+ buf->buf_start = 0;
+ return newstr;
+ }
+
+ return NULL;
+}
+
+#define SOCKADDR(x) ((struct sockaddr*)(x))
+#define SOCKADDR_UN(x) ((struct sockaddr_un*)(x))
+#define SOCKADDR_IN(x) ((struct sockaddr_in*)(x))
+#define SOCKADDR_IN6(x) ((struct sockaddr_in6*)(x))
+
+static char* lbs_posix_socket_name (
+ int sockfd, int (*getter) (int, struct sockaddr*, socklen_t*)) {
+
+ struct sockaddr_storage sock;
+ socklen_t socklen = sizeof (sock);
+
+ memset (&sock, 0, socklen);
+ if ((*getter)(sockfd, SOCKADDR (&sock), &socklen) < 0) {
+ return xstrdup ("invalid socket");
+ }
+
+ int domain = sock.ss_family;
+ if (domain == AF_UNIX) {
+ return xstrdup ("local process");
+ }
+
+ socklen_t ipstrlen;
+ void* ipnet;
+ char* ipstr;
+ if (domain == AF_INET) {
+ ipstrlen = INET_ADDRSTRLEN;
+ ipnet = &(SOCKADDR_IN (&sock)->sin_addr);
+ } else {
+ ipstrlen = INET6_ADDRSTRLEN;
+ ipnet = &(SOCKADDR_IN6 (&sock)->sin6_addr);
+ }
+
+ ipstr = xmalloc (ipstrlen);
+ if (inet_ntop (domain, ipnet, ipstr, ipstrlen) == NULL) {
+ free (ipstr);
+ return xstrdup ("unknown address");
+ }
+
+ return ipstr;
+}
+
+char* lbs_posix_socket_sockname (int sockfd) {
+ return lbs_posix_socket_name (sockfd, getsockname);
+}
+
+char* lbs_posix_socket_peername (int sockfd) {
+ return lbs_posix_socket_name (sockfd, getpeername);
+}
+
+void lbs_posix_exchange_data (int fd[2], LbsPosixProgress prog_cb) {
+ int nfds, active;
+ fd_set rset, wset;
+ fd_set rres, wres;
+ LbsPosixBuffer buf[2];
+
+ FD_ZERO (&rset);
+ FD_SET (fd[0], &rset);
+ FD_SET (fd[1], &rset);
+ FD_ZERO (&wset);
+
+ active = 2;
+ nfds = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1;
+ lbs_posix_buffer_clear (&buf[0], true);
+ lbs_posix_buffer_clear (&buf[1], true);
+
+ while (active && (*prog_cb) (fd, buf)) {
+ rres = rset;
+ wres = wset;
+ if (select (nfds, &rres, &wres, NULL, NULL) >= 0) {
+ for (int i = 0; i < 2; i++) {
+ if (buf[i].buf_len) {
+ /* read buffer full */
+ if (FD_ISSET (fd[!i], &wres)) {
+ int wb = write (fd[!i],
+ buf[i].buf + buf[i].buf_start, buf[i].buf_len);
+ if (wb > 0) {
+ buf[i].buf_start += wb;
+ buf[i].buf_len -= wb;
+ if (!buf[i].buf_len) {
+ FD_CLR (fd[!i], &wset);
+ FD_SET (fd[i], &rset);
+ }
+ } else {
+ if (wb < 0 && (errno == EAGAIN || errno == EINTR)) {
+ continue;
+ } else {
+ FD_CLR (fd[!i], &wset);
+ active = 0;
+ }
+ }
+ }
+ } else {
+ /* read buffer empty */
+ if (FD_ISSET (fd[i], &rres)) {
+ int rb = read (fd[i], buf[i].buf, LBS_POSIX_BUFFER_SIZE);
+ if (rb > 0) {
+ buf[i].buf_start = 0;
+ buf[i].buf_len = rb;
+ FD_CLR (fd[i], &rset);
+ FD_SET (fd[!i], &wset);
+ } else {
+ if (rb < 0 && (errno == EAGAIN || errno == EINTR)) {
+ continue;
+ } else{
+ FD_CLR (fd[i], &rset);
+ active = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/hw4/l4basic/l4posix.h b/hw4/l4basic/l4posix.h
new file mode 100644
index 0000000..a368609
--- /dev/null
+++ b/hw4/l4basic/l4posix.h
@@ -0,0 +1,41 @@
+#include "memwrap.h"
+/* This file is modified by autogen.sh */
+/* vim: set sw=4 ts=4 sts=4 et: */
+#ifndef LBS_POSIX_H
+#define LBS_POSIX_H
+
+#include <l4common.h>
+#include <sys/types.h>
+
+char* lbs_posix_strcat (const char* str, ...);
+int lbs_posix_add_fd (int fd, int fdflags);
+int lbs_posix_del_fd (int fd, int fdflags);
+int lbs_posix_add_fl (int fd, int flflags);
+int lbs_posix_del_fl (int fd, int flflags);
+char* lbs_posix_readlink (const char* filename);
+char* lbs_posix_getcwd (void);
+size_t lbs_posix_write_all (int fd, const char* str, size_t size);
+char* lbs_posix_socket_sockname (int sockfd);
+char* lbs_posix_socket_peername (int sockfd);
+
+
+#define LBS_POSIX_BUFFER_SIZE 4096
+
+typedef struct {
+ char buf[LBS_POSIX_BUFFER_SIZE];
+ off_t buf_start;
+ off_t buf_len;
+ char* buf_line;
+ ssize_t buf_line_len;
+ int buf_error : 1;
+ int buf_eof : 1;
+} LbsPosixBuffer;
+
+void lbs_posix_buffer_init (LbsPosixBuffer* buf);
+void lbs_posix_buffer_clear (LbsPosixBuffer* buf, bool initial);
+char* lbs_posix_buffer_getline (int fd, LbsPosixBuffer* buf, int delim);
+
+typedef int (*LbsPosixProgress) (int fd[2], LbsPosixBuffer buf[2]);
+void lbs_posix_exchange_data (int fd[2], LbsPosixProgress prog_cb);
+
+#endif /* LBS_POSIX_H */
diff --git a/hw4/l4basic/l4str.c b/hw4/l4basic/l4str.c
new file mode 100644
index 0000000..fa1d31b
--- /dev/null
+++ b/hw4/l4basic/l4str.c
@@ -0,0 +1,44 @@
+#include "memwrap.h"
+/* This file is modified by autogen.sh */
+/* vim: set sw=4 ts=4 sts=4 et: */
+
+#include "l4str.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool lbs_str_has_suffix (const char* str, const char* suffix) {
+ size_t len = strlen (str);
+ size_t suflen = strlen (suffix);
+ int i, j;
+ for (i = len - 1, j = suflen - 1; i >= 0 && j >= 0; i--, j--) {
+ if (str[i] != suffix[j]) {
+ return false;
+ }
+ }
+ if (i < 0 && j >= 0) {
+ return false;
+ }
+ return true;
+}
+
+char* lbs_str_printf (const char* format, ...) {
+ va_list ap;
+ char* newstr;
+ int len;
+
+ va_start (ap, format);
+ len = vsnprintf (NULL, 0, format, ap) + 1;
+ va_end (ap);
+
+ newstr = xmalloc (len);
+
+ va_start (ap, format);
+ vsnprintf (newstr, len, format, ap);
+ va_end (ap);
+
+ return newstr;
+}
+
diff --git a/hw4/l4basic/l4str.h b/hw4/l4basic/l4str.h
new file mode 100644
index 0000000..40bb7fe
--- /dev/null
+++ b/hw4/l4basic/l4str.h
@@ -0,0 +1,15 @@
+#include "memwrap.h"
+/* This file is modified by autogen.sh */
+/* vim: set sw=4 ts=4 sts=4 et: */
+#ifndef LBS_STR_H
+#define LBS_STR_H
+
+#include <l4common.h>
+
+#define LBS_STR_STATIC_STRLEN(x) (sizeof(x)/sizeof(char) - 1)
+#define LBS_STR_ARRAY_LEN(x,t) (sizeof(x)/sizeof(t))
+
+bool lbs_str_has_suffix (const char* str, const char* suffix);
+char* lbs_str_printf (const char* format, ...);
+
+#endif /* LBS_STR_H */