diff options
Diffstat (limited to 'hw4/l4basic')
-rw-r--r-- | hw4/l4basic/l4common.h | 42 | ||||
-rw-r--r-- | hw4/l4basic/l4list.c | 201 | ||||
-rw-r--r-- | hw4/l4basic/l4list.h | 116 | ||||
-rw-r--r-- | hw4/l4basic/l4posix.c | 333 | ||||
-rw-r--r-- | hw4/l4basic/l4posix.h | 41 | ||||
-rw-r--r-- | hw4/l4basic/l4str.c | 44 | ||||
-rw-r--r-- | hw4/l4basic/l4str.h | 15 |
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 */ |