linked list V1 / phone-number typos / student setup script V1
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@ core
|
|||||||
*.out
|
*.out
|
||||||
*_test.sh
|
*_test.sh
|
||||||
test/
|
test/
|
||||||
|
test-framework/
|
||||||
users/
|
users/
|
||||||
.exercism
|
.exercism
|
||||||
.projectile
|
.projectile
|
||||||
|
56
c/linked-list/GNUmakefile
Normal file
56
c/linked-list/GNUmakefile
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# The original 'makefile' has a flaw:
|
||||||
|
# 1) it overrides CFLAGS
|
||||||
|
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||||
|
#
|
||||||
|
# It means :
|
||||||
|
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||||
|
# not practical at all.
|
||||||
|
# - Also, it does not allow to run all tests without editing the test source
|
||||||
|
# code.
|
||||||
|
#
|
||||||
|
# To use this makefile (GNU make only):
|
||||||
|
# 1) copy it into exercise directory
|
||||||
|
# 2) add ex.h to exercise include file
|
||||||
|
# 3) add ex.c to exercise source code, and create a suitable main function
|
||||||
|
# 4) use make with one of the following targets :
|
||||||
|
# all: compile and run all predefined tests.
|
||||||
|
# nowarn: compile with no -Werror, and run all predefined tests
|
||||||
|
# debug: compile with -DDEBUG and run all predefined tests
|
||||||
|
# mem: perform memcheck with all tests enabled
|
||||||
|
# unit: build standalone (unit) bimary
|
||||||
|
# unitnowarn: build standalone (unit) binary with -Werror disabled
|
||||||
|
# unitdebug: build standalone binary with -DDEBUG
|
||||||
|
#
|
||||||
|
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||||
|
|
||||||
|
.PHONY: default all nowarn debug mem unit unitnowarn unitdebug standalone
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
ALLSOURCES:=$(wildcard ./*.c)
|
||||||
|
TESTSOURCES:=$(wildcard ./test_*.c)
|
||||||
|
SRC:=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
|
||||||
|
|
||||||
|
include makefile
|
||||||
|
|
||||||
|
all: CFLAGS+=-DTESTALL
|
||||||
|
all: clean test
|
||||||
|
|
||||||
|
nowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||||
|
nowarn: clean all
|
||||||
|
|
||||||
|
debug: CFLAGS+=-DDEBUG
|
||||||
|
debug: all
|
||||||
|
|
||||||
|
mem: CFLAGS+=-DTESTALL
|
||||||
|
mem: clean memcheck
|
||||||
|
|
||||||
|
unitnowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||||
|
unitnowarn: clean unit
|
||||||
|
|
||||||
|
unitdebug: CFLAGS+=-DDEBUG
|
||||||
|
unitdebug: clean unit
|
||||||
|
|
||||||
|
unit: CFLAGS+=-DUNIT_TEST
|
||||||
|
unit: *.c *.h
|
||||||
|
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)
|
63
c/linked-list/HELP.md
Normal file
63
c/linked-list/HELP.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Get the first test compiling, linking and passing by following the [three rules of test-driven development][3-tdd-rules].
|
||||||
|
|
||||||
|
The included makefile can be used to create and run the tests using the `test` task.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ make test
|
||||||
|
```
|
||||||
|
|
||||||
|
Create just the functions you need to satisfy any compiler errors and get the test to fail.
|
||||||
|
Then write just enough code to get the test to pass.
|
||||||
|
Once you've done that, move onto the next test.
|
||||||
|
|
||||||
|
As you progress through the tests, take the time to refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||||
|
|
||||||
|
Try to use standard C99 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||||
|
|
||||||
|
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit linked_list.c linked_list.h` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [C track's documentation](https://exercism.org/docs/tracks/c)
|
||||||
|
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
Make sure you have read the "Guides" section of the [C track][c-track] on the Exercism site.
|
||||||
|
This covers the basic information on setting up the development environment expected by the exercises.
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
|
||||||
|
If you are struggling with a particular exercise, it is possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
To get help if having trouble, you can use the following resources:
|
||||||
|
|
||||||
|
- [StackOverflow][] can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||||
|
- [CPPReference][] can be used to look up information on C concepts, operators, types, standard library functions and more.
|
||||||
|
- [TutorialsPoint][] has similar content as CPPReference in its C programming section.
|
||||||
|
- [The C Programming][K&R] book by K&R is the original source of the language and is still useful today.
|
||||||
|
|
||||||
|
[c-track]: https://exercism.io/my/tracks/c
|
||||||
|
[stackoverflow]: http://stackoverflow.com/questions/tagged/c
|
||||||
|
[cppreference]: https://en.cppreference.com/w/c
|
||||||
|
[tutorialspoint]: https://www.tutorialspoint.com/cprogramming/
|
||||||
|
[K&R]: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/
|
50
c/linked-list/README.md
Normal file
50
c/linked-list/README.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Linked List
|
||||||
|
|
||||||
|
Welcome to Linked List on Exercism's C Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
Implement a doubly linked list.
|
||||||
|
|
||||||
|
Like an array, a linked list is a simple linear data structure. Several
|
||||||
|
common data types can be implemented using linked lists, like queues,
|
||||||
|
stacks, and associative arrays.
|
||||||
|
|
||||||
|
A linked list is a collection of data elements called *nodes*. In a
|
||||||
|
*singly linked list* each node holds a value and a link to the next node.
|
||||||
|
In a *doubly linked list* each node also holds a link to the previous
|
||||||
|
node.
|
||||||
|
|
||||||
|
You will write an implementation of a doubly linked list. Implement a
|
||||||
|
Node to hold a value and pointers to the next and previous nodes. Then
|
||||||
|
implement a List which holds references to the first and last node and
|
||||||
|
offers an array-like interface for adding and removing items:
|
||||||
|
|
||||||
|
* `push` (*insert value at back*);
|
||||||
|
* `pop` (*remove value at back*);
|
||||||
|
* `shift` (*remove value at front*).
|
||||||
|
* `unshift` (*insert value at front*);
|
||||||
|
|
||||||
|
To keep your implementation simple, the tests will not cover error
|
||||||
|
conditions. Specifically: `pop` or `shift` will never be called on an
|
||||||
|
empty list.
|
||||||
|
|
||||||
|
If you want to know more about linked lists, check [Wikipedia](https://en.wikipedia.org/wiki/Linked_list).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @wolf99
|
||||||
|
|
||||||
|
### Contributed to by
|
||||||
|
|
||||||
|
- @patricksjackson
|
||||||
|
- @QLaille
|
||||||
|
- @ryanplusplus
|
||||||
|
- @siebenschlaefer
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
|
||||||
|
Classic computer science topic
|
45
c/linked-list/br-common.h
Normal file
45
c/linked-list/br-common.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef __BR_COMMON_H
|
||||||
|
#define __BR_COMMON_H
|
||||||
|
|
||||||
|
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 30
|
||||||
|
*
|
||||||
|
* __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
|
||||||
|
* For other compilers, simple implementation (for __falltrough__ only)
|
||||||
|
*/
|
||||||
|
#ifndef __has_attribute
|
||||||
|
# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||||
|
# define __GCC4_has_attribute___assume_aligned__ (__GNUC_MINOR__ >= 9)
|
||||||
|
# define __GCC4_has_attribute___copy__ 0
|
||||||
|
# define __GCC4_has_attribute___designated_init__ 0
|
||||||
|
# define __GCC4_has_attribute___externally_visible__ 1
|
||||||
|
# define __GCC4_has_attribute___no_caller_saved_registers__ 0
|
||||||
|
# define __GCC4_has_attribute___noclone__ 1
|
||||||
|
# define __GCC4_has_attribute___nonstring__ 0
|
||||||
|
# define __GCC4_has_attribute___no_sanitize_address__ (__GNUC_MINOR__ >= 8)
|
||||||
|
# define __GCC4_has_attribute___no_sanitize_undefined__ (__GNUC_MINOR__ >= 9)
|
||||||
|
# define __GCC4_has_attribute___fallthrough__ 0
|
||||||
|
# define __GCC4_has_attribute___fallthrough__ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 200
|
||||||
|
*/
|
||||||
|
#if __has_attribute(__fallthrough__)
|
||||||
|
# define fallthrough __attribute__((__fallthrough__))
|
||||||
|
#else
|
||||||
|
# define fallthrough do {} while (0); /* fallthrough */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* See GNUmakefile below for explanation
|
||||||
|
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||||
|
*/
|
||||||
|
#if defined UNIT_TEST || defined DEBUG
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TESTALL
|
||||||
|
# undef TEST_IGNORE
|
||||||
|
# define TEST_IGNORE() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BR_COMMON_H */
|
229
c/linked-list/br-list.h
Normal file
229
c/linked-list/br-list.h
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
/* stripped down version of my adaptation of Linux kernel lists management :
|
||||||
|
* https://github.com/braoult/Tools/blob/master/C/list.h
|
||||||
|
*/
|
||||||
|
#ifndef __LIST_H
|
||||||
|
#define __LIST_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/************ originally in <include/linux/types.h> */
|
||||||
|
struct list_head {
|
||||||
|
struct list_head *next, *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/************ originally in <include/linux/poison.h> */
|
||||||
|
#define LIST_POISON1 ((void *) 0x100)
|
||||||
|
#define LIST_POISON2 ((void *) 0x122)
|
||||||
|
|
||||||
|
/************ originally in <include/linux/kernel.h> */
|
||||||
|
#define container_of(ptr, type, member) \
|
||||||
|
((type *)((char *)(ptr) - offsetof(type, member)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular doubly linked list implementation.
|
||||||
|
*
|
||||||
|
* Some of the internal functions ("__xxx") are useful when
|
||||||
|
* manipulating whole lists rather than single entries, as
|
||||||
|
* sometimes we already know the next/prev entries and we can
|
||||||
|
* generate better code by using them directly rather than
|
||||||
|
* using the generic single-entry routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INIT_LIST_HEAD - Initialize a list_head structure
|
||||||
|
* @list: list_head structure to be initialized.
|
||||||
|
*
|
||||||
|
* Initializes the list_head to point to itself. If it is a list header,
|
||||||
|
* the result is an empty list.
|
||||||
|
*/
|
||||||
|
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||||
|
{
|
||||||
|
list->next = list;
|
||||||
|
list->prev = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a new entry between two known consecutive entries.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
static inline void __list_add(struct list_head *new,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
next->prev = new;
|
||||||
|
new->next = next;
|
||||||
|
new->prev = prev;
|
||||||
|
prev->next = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it after
|
||||||
|
*
|
||||||
|
* Insert a new entry after the specified head.
|
||||||
|
* This is good for implementing stacks.
|
||||||
|
*/
|
||||||
|
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add_tail - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it before
|
||||||
|
*
|
||||||
|
* Insert a new entry before the specified head.
|
||||||
|
* This is useful for implementing queues.
|
||||||
|
*/
|
||||||
|
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a list entry by making the prev/next entries
|
||||||
|
* point to each other.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||||
|
{
|
||||||
|
next->prev = prev;
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __list_del_entry(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_del - deletes entry from list.
|
||||||
|
* @entry: the element to delete from the list.
|
||||||
|
* Note: list_empty() on entry does not return true after this, the entry is
|
||||||
|
* in an undefined state.
|
||||||
|
*/
|
||||||
|
static inline void list_del(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del_entry(entry);
|
||||||
|
entry->next = LIST_POISON1;
|
||||||
|
entry->prev = LIST_POISON2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_empty - tests whether a list is empty
|
||||||
|
* @head: the list to test.
|
||||||
|
*/
|
||||||
|
static inline int list_empty(const struct list_head *head)
|
||||||
|
{
|
||||||
|
return head->next == head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_entry - get the struct for this entry
|
||||||
|
* @ptr: the &struct list_head pointer.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_entry(ptr, type, member) \
|
||||||
|
container_of(ptr, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_first_entry - get the first element from a list
|
||||||
|
* @ptr: the list head to take the element from.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Note, that list is expected to be not empty.
|
||||||
|
*/
|
||||||
|
#define list_first_entry(ptr, type, member) \
|
||||||
|
list_entry((ptr)->next, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_last_entry - get the last element from a list
|
||||||
|
* @ptr: the list head to take the element from.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Note, that list is expected to be not empty.
|
||||||
|
*/
|
||||||
|
#define list_last_entry(ptr, type, member) \
|
||||||
|
list_entry((ptr)->prev, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_next_entry - get the next element in list
|
||||||
|
* @pos: the type * to cursor
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_next_entry(pos, member) \
|
||||||
|
list_entry((pos)->member.next, __typeof__(*(pos)), member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_prev_entry - get the prev element in list
|
||||||
|
* @pos: the type * to cursor
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_prev_entry(pos, member) \
|
||||||
|
list_entry((pos)->member.prev, __typeof__(*(pos)), member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each - iterate over a list
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each(pos, head) \
|
||||||
|
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @n: another &struct list_head to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_safe(pos, n, head) \
|
||||||
|
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||||
|
pos = n, n = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_entry_is_head - test if the entry points to the head of the list
|
||||||
|
* @pos: the type * to cursor
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_entry_is_head(pos, head, member) \
|
||||||
|
(&pos->member == (head))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry - iterate over list of given type
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry(pos, head, member) \
|
||||||
|
for (pos = list_first_entry(head, __typeof__(*pos), member); \
|
||||||
|
!list_entry_is_head(pos, head, member); \
|
||||||
|
pos = list_next_entry(pos, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||||
|
for (pos = list_first_entry(head, __typeof__(*pos), member), \
|
||||||
|
n = list_next_entry(pos, member); \
|
||||||
|
!list_entry_is_head(pos, head, member); \
|
||||||
|
pos = n, n = list_next_entry(n, member))
|
||||||
|
|
||||||
|
#endif /* __LIST_H */
|
126
c/linked-list/linked_list.c
Normal file
126
c/linked-list/linked_list.c
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "br-list.h"
|
||||||
|
#include "linked_list.h"
|
||||||
|
|
||||||
|
struct list_node {
|
||||||
|
ll_data_t data;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* duplicate of list_head struct
|
||||||
|
*/
|
||||||
|
struct list {
|
||||||
|
struct list_head *next, *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* constructs a new (empty) list
|
||||||
|
*/
|
||||||
|
struct list *list_create()
|
||||||
|
{
|
||||||
|
struct list_head *list;
|
||||||
|
|
||||||
|
if (!(list=malloc(sizeof (*list))))
|
||||||
|
return NULL;
|
||||||
|
INIT_LIST_HEAD(list);
|
||||||
|
return (struct list *) list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* counts the items on a list
|
||||||
|
*/
|
||||||
|
size_t list_count(const struct list *list_head)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
struct list_head *p;
|
||||||
|
|
||||||
|
list_for_each(p, (struct list_head *)list_head)
|
||||||
|
len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inserts item at back of a list
|
||||||
|
*/
|
||||||
|
void list_push(struct list *list, ll_data_t item_data)
|
||||||
|
{
|
||||||
|
struct list_node *p;
|
||||||
|
|
||||||
|
if ((p=malloc(sizeof(*p)))) {
|
||||||
|
p->data = item_data;
|
||||||
|
list_add_tail(&p->list, (struct list_head*)list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deletes an element
|
||||||
|
*/
|
||||||
|
static ll_data_t _list_del(struct list_head *list)
|
||||||
|
{
|
||||||
|
struct list_node *node;
|
||||||
|
ll_data_t data;
|
||||||
|
|
||||||
|
node = list_entry(list, struct list_node, list);
|
||||||
|
data = node->data;
|
||||||
|
list_del(&node->list);
|
||||||
|
free(node);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* removes item from back of a list
|
||||||
|
*/
|
||||||
|
ll_data_t list_pop(struct list *list)
|
||||||
|
{
|
||||||
|
return list_empty((struct list_head*)list) ? -1 : _list_del(list->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inserts item at front of a list
|
||||||
|
*/
|
||||||
|
void list_unshift(struct list *list, ll_data_t item_data)
|
||||||
|
{
|
||||||
|
struct list_node *p;
|
||||||
|
|
||||||
|
if ((p=malloc(sizeof(*p)))) {
|
||||||
|
p->data = item_data;
|
||||||
|
list_add(&p->list, (struct list_head*)list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* removes item from front of a list
|
||||||
|
*/
|
||||||
|
ll_data_t list_shift(struct list *list)
|
||||||
|
{
|
||||||
|
return list_empty((struct list_head*)list) ? -1 : _list_del(list->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finds a element that matches data
|
||||||
|
*/
|
||||||
|
static struct list_node *_node_find(struct list *list, ll_data_t data)
|
||||||
|
{
|
||||||
|
struct list_node *p;
|
||||||
|
|
||||||
|
list_for_each_entry(p, (struct list_head *)list, list) {
|
||||||
|
if (p->data == data)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deletes a node that holds the matching data
|
||||||
|
*/
|
||||||
|
void list_delete(struct list *list, ll_data_t data)
|
||||||
|
{
|
||||||
|
struct list_node *p;
|
||||||
|
|
||||||
|
if ((p = _node_find(list, data)))
|
||||||
|
_list_del(&p->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* destroys an entire list
|
||||||
|
* list will be a dangling pointer after calling this method on it
|
||||||
|
*/
|
||||||
|
void list_destroy(struct list *list)
|
||||||
|
{
|
||||||
|
struct list_head *cur, *tmp;
|
||||||
|
|
||||||
|
list_for_each_safe(cur, tmp, (struct list_head *)list)
|
||||||
|
_list_del(cur);
|
||||||
|
free(list);
|
||||||
|
}
|
36
c/linked-list/linked_list.h
Normal file
36
c/linked-list/linked_list.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef LINKED_LIST_H
|
||||||
|
#define LINKED_LIST_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef int ll_data_t;
|
||||||
|
struct list;
|
||||||
|
|
||||||
|
// constructs a new (empty) list
|
||||||
|
struct list *list_create(void);
|
||||||
|
|
||||||
|
// counts the items on a list
|
||||||
|
size_t list_count(const struct list *list);
|
||||||
|
|
||||||
|
// inserts item at back of a list
|
||||||
|
void list_push(struct list *list, ll_data_t item_data);
|
||||||
|
|
||||||
|
// removes item from back of a list
|
||||||
|
ll_data_t list_pop(struct list *list);
|
||||||
|
|
||||||
|
// inserts item at front of a list
|
||||||
|
void list_unshift(struct list *list, ll_data_t item_data);
|
||||||
|
|
||||||
|
// removes item from front of a list
|
||||||
|
ll_data_t list_shift(struct list *list);
|
||||||
|
|
||||||
|
// deletes a node that holds the matching data
|
||||||
|
void list_delete(struct list *list, ll_data_t data);
|
||||||
|
|
||||||
|
// destroys an entire list
|
||||||
|
// list will be a dangling pointer after calling this method on it
|
||||||
|
void list_destroy(struct list *list);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "br-common.h"
|
37
c/linked-list/makefile
Normal file
37
c/linked-list/makefile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
### If you wish to use extra libraries (math.h for instance),
|
||||||
|
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||||
|
|
||||||
|
LIBS = -lm
|
||||||
|
|
||||||
|
###
|
||||||
|
CFLAGS = -std=c99
|
||||||
|
CFLAGS += -g
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Wextra
|
||||||
|
CFLAGS += -pedantic
|
||||||
|
CFLAGS += -Werror
|
||||||
|
CFLAGS += -Wmissing-declarations
|
||||||
|
CFLAGS += -DUNITY_SUPPORT_64
|
||||||
|
|
||||||
|
ASANFLAGS = -fsanitize=address
|
||||||
|
ASANFLAGS += -fno-common
|
||||||
|
ASANFLAGS += -fno-omit-frame-pointer
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: tests.out
|
||||||
|
@./tests.out
|
||||||
|
|
||||||
|
.PHONY: memcheck
|
||||||
|
memcheck: ./*.c ./*.h
|
||||||
|
@echo Compiling $@
|
||||||
|
@$(CC) $(ASANFLAGS) $(CFLAGS) test-framework/unity.c ./*.c -o memcheck.out $(LIBS)
|
||||||
|
@./memcheck.out
|
||||||
|
@echo "Memory check passed"
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.out *.out.dSYM
|
||||||
|
|
||||||
|
tests.out: ./*.c ./*.h
|
||||||
|
@echo Compiling $@
|
||||||
|
@$(CC) $(CFLAGS) test-framework/unity.c ./*.c -o tests.out $(LIBS)
|
243
c/linked-list/test_linked_list.c
Normal file
243
c/linked-list/test_linked_list.c
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include "test-framework/unity.h"
|
||||||
|
#include "linked_list.h"
|
||||||
|
|
||||||
|
struct list *list = NULL;
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
list = list_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
if (list) {
|
||||||
|
list_destroy(list);
|
||||||
|
list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_pop_gets_element_from_the_list(void)
|
||||||
|
{
|
||||||
|
list_push(list, 7);
|
||||||
|
TEST_ASSERT_EQUAL(7, list_pop(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_push_pop_respectively_add_remove_at_the_end_of_the_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE(); // delete this line to run test
|
||||||
|
list_push(list, 11);
|
||||||
|
list_push(list, 13);
|
||||||
|
TEST_ASSERT_EQUAL(13, list_pop(list));
|
||||||
|
TEST_ASSERT_EQUAL(11, list_pop(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_shift_gets_an_element_from_the_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 17);
|
||||||
|
TEST_ASSERT_EQUAL(17, list_shift(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_shift_gets_first_element_from_the_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 23);
|
||||||
|
list_push(list, 5);
|
||||||
|
TEST_ASSERT_EQUAL(23, list_shift(list));
|
||||||
|
TEST_ASSERT_EQUAL(5, list_shift(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_unshift_adds_element_at_start_of_the_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_unshift(list, 23);
|
||||||
|
list_unshift(list, 5);
|
||||||
|
TEST_ASSERT_EQUAL(5, list_shift(list));
|
||||||
|
TEST_ASSERT_EQUAL(23, list_shift(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_pop_push_shift_and_unshift_can_be_used_in_any_order(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 1);
|
||||||
|
list_push(list, 2);
|
||||||
|
TEST_ASSERT_EQUAL(2, list_pop(list));
|
||||||
|
list_push(list, 3);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_shift(list));
|
||||||
|
list_unshift(list, 4);
|
||||||
|
list_push(list, 5);
|
||||||
|
TEST_ASSERT_EQUAL(4, list_shift(list));
|
||||||
|
TEST_ASSERT_EQUAL(5, list_pop(list));
|
||||||
|
TEST_ASSERT_EQUAL(3, list_shift(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_count_an_empty_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
TEST_ASSERT_EQUAL(0, list_count(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_count_a_list_with_items(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 37);
|
||||||
|
list_push(list, 1);
|
||||||
|
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_count_is_correct_after_mutation(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 31);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||||
|
list_unshift(list, 43);
|
||||||
|
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||||
|
list_shift(list);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||||
|
list_pop(list);
|
||||||
|
TEST_ASSERT_EQUAL(0, list_count(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_popping_to_empty_does_not_break_the_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 41);
|
||||||
|
list_push(list, 59);
|
||||||
|
list_pop(list);
|
||||||
|
list_pop(list);
|
||||||
|
list_push(list, 47);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(47, list_pop(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_shifting_to_empty_does_not_break_the_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 41);
|
||||||
|
list_push(list, 59);
|
||||||
|
list_shift(list);
|
||||||
|
list_shift(list);
|
||||||
|
list_push(list, 47);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(47, list_shift(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_deletes_the_only_element(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 61);
|
||||||
|
list_delete(list, 61);
|
||||||
|
TEST_ASSERT_EQUAL(0, list_count(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_deletes_the_element_with_the_specified_value_from_the_list(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 71);
|
||||||
|
list_push(list, 83);
|
||||||
|
list_push(list, 79);
|
||||||
|
list_delete(list, 83);
|
||||||
|
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(79, list_pop(list));
|
||||||
|
TEST_ASSERT_EQUAL(71, list_shift(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_tail
|
||||||
|
(void) {
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 71);
|
||||||
|
list_push(list, 83);
|
||||||
|
list_push(list, 79);
|
||||||
|
list_delete(list, 83);
|
||||||
|
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(79, list_pop(list));
|
||||||
|
TEST_ASSERT_EQUAL(71, list_pop(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_head
|
||||||
|
(void) {
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 71);
|
||||||
|
list_push(list, 83);
|
||||||
|
list_push(list, 79);
|
||||||
|
list_delete(list, 83);
|
||||||
|
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(71, list_shift(list));
|
||||||
|
TEST_ASSERT_EQUAL(79, list_shift(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_deletes_the_first_of_two_elements(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 97);
|
||||||
|
list_push(list, 101);
|
||||||
|
list_delete(list, 97);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(101, list_pop(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_deletes_the_second_of_two_elements(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 97);
|
||||||
|
list_push(list, 101);
|
||||||
|
list_delete(list, 101);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(97, list_pop(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_delete_does_not_modify_the_list_if_the_element_is_not_found(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 89);
|
||||||
|
list_delete(list, 103);
|
||||||
|
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_deletes_only_the_first_occurrence(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE();
|
||||||
|
list_push(list, 73);
|
||||||
|
list_push(list, 9);
|
||||||
|
list_push(list, 9);
|
||||||
|
list_push(list, 107);
|
||||||
|
list_delete(list, 9);
|
||||||
|
TEST_ASSERT_EQUAL(3, list_count(list));
|
||||||
|
TEST_ASSERT_EQUAL(107, list_pop(list));
|
||||||
|
TEST_ASSERT_EQUAL(9, list_pop(list));
|
||||||
|
TEST_ASSERT_EQUAL(73, list_pop(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
UnityBegin("test_linked_list.c");
|
||||||
|
|
||||||
|
RUN_TEST(test_pop_gets_element_from_the_list);
|
||||||
|
RUN_TEST(test_push_pop_respectively_add_remove_at_the_end_of_the_list);
|
||||||
|
RUN_TEST(test_shift_gets_an_element_from_the_list);
|
||||||
|
RUN_TEST(test_shift_gets_first_element_from_the_list);
|
||||||
|
RUN_TEST(test_unshift_adds_element_at_start_of_the_list);
|
||||||
|
RUN_TEST(test_pop_push_shift_and_unshift_can_be_used_in_any_order);
|
||||||
|
RUN_TEST(test_count_an_empty_list);
|
||||||
|
RUN_TEST(test_count_a_list_with_items);
|
||||||
|
RUN_TEST(test_count_is_correct_after_mutation);
|
||||||
|
RUN_TEST(test_popping_to_empty_does_not_break_the_list);
|
||||||
|
RUN_TEST(test_shifting_to_empty_does_not_break_the_list);
|
||||||
|
RUN_TEST(test_deletes_the_only_element);
|
||||||
|
RUN_TEST(test_deletes_the_element_with_the_specified_value_from_the_list);
|
||||||
|
RUN_TEST
|
||||||
|
(test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_tail);
|
||||||
|
RUN_TEST
|
||||||
|
(test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_head);
|
||||||
|
RUN_TEST(test_deletes_the_first_of_two_elements);
|
||||||
|
RUN_TEST(test_deletes_the_second_of_two_elements);
|
||||||
|
RUN_TEST(test_delete_does_not_modify_the_list_if_the_element_is_not_found);
|
||||||
|
RUN_TEST(test_deletes_only_the_first_occurrence);
|
||||||
|
|
||||||
|
return UnityEnd();
|
||||||
|
}
|
@@ -27,9 +27,9 @@
|
|||||||
|
|
||||||
default: all
|
default: all
|
||||||
|
|
||||||
ALLSOURCES=$(wildcard ./*.c)
|
ALLSOURCES:=$(wildcard ./*.c)
|
||||||
TESTSOURCES=$(wildcard ./test_*.c)
|
TESTSOURCES:=$(wildcard ./test_*.c)
|
||||||
SRC=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
|
SRC:=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
|
||||||
|
|
||||||
include makefile
|
include makefile
|
||||||
|
|
||||||
@@ -52,6 +52,5 @@ unitdebug: CFLAGS+=-DDEBUG
|
|||||||
unitdebug: clean unit
|
unitdebug: clean unit
|
||||||
|
|
||||||
unit: CFLAGS+=-DUNIT_TEST
|
unit: CFLAGS+=-DUNIT_TEST
|
||||||
unit: SOURCES=$(wildcard ./*.c)
|
|
||||||
unit: *.c *.h
|
unit: *.c *.h
|
||||||
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)
|
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
#ifndef PHONE_NUMBER_H
|
#ifndef PHONE_NUMBER_H
|
||||||
#define PHONE_NUMBER_H
|
#define PHONE_NUMBER_H
|
||||||
|
|
||||||
#include "br-common.h"
|
|
||||||
|
|
||||||
#define NUMBER_LENGTH 10
|
#define NUMBER_LENGTH 10
|
||||||
|
|
||||||
char *phone_number_clean(const char *input);
|
char *phone_number_clean(const char *input);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "br-common.h"
|
||||||
|
44
c/setup-exercise.sh
Executable file
44
c/setup-exercise.sh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CMD=${0##*/}
|
||||||
|
ROOT=${0%/*}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
printf "usage: %s destination_dir\n" "$CMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($# == 0)); then
|
||||||
|
"$0" "$PWD"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (($# != 1)) || [[ ! -d $1 ]]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
TEMPLATES="$ROOT/templates"
|
||||||
|
|
||||||
|
# copy GNUmakefile and br-common.h
|
||||||
|
echo -n "copying GNUmakefile and br-common.h files... "
|
||||||
|
cp -p "$TEMPLATES/"{GNUmakefile,br-common.h} "$1"
|
||||||
|
echo done.
|
||||||
|
# add include br-common.h in exercise include file
|
||||||
|
INC=${1%/}
|
||||||
|
INC=${INC##*/}
|
||||||
|
INC="$1/${INC//-/_}.h"
|
||||||
|
|
||||||
|
if [[ ! -f "$INC" ]]; then
|
||||||
|
printf "cannot find <%s> include file\n" "$INC"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
STR='#include "br-common.h"'
|
||||||
|
# likely very weak
|
||||||
|
# TODO: check if not already inserted
|
||||||
|
#echo -n "editing $INC include file... "
|
||||||
|
#sed -i "/#define /a $STR" "$INC"
|
||||||
|
#echo done.
|
||||||
|
echo -n "editing $INC include file... "
|
||||||
|
echo "" >> "$INC"
|
||||||
|
echo "$STR" >> "$INC"
|
||||||
|
echo done.
|
56
c/templates/GNUmakefile
Normal file
56
c/templates/GNUmakefile
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# The original 'makefile' has a flaw:
|
||||||
|
# 1) it overrides CFLAGS
|
||||||
|
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||||
|
#
|
||||||
|
# It means :
|
||||||
|
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||||
|
# not practical at all.
|
||||||
|
# - Also, it does not allow to run all tests without editing the test source
|
||||||
|
# code.
|
||||||
|
#
|
||||||
|
# To use this makefile (GNU make only):
|
||||||
|
# 1) copy it into exercise directory
|
||||||
|
# 2) add ex.h to exercise include file
|
||||||
|
# 3) add ex.c to exercise source code, and create a suitable main function
|
||||||
|
# 4) use make with one of the following targets :
|
||||||
|
# all: compile and run all predefined tests.
|
||||||
|
# nowarn: compile with no -Werror, and run all predefined tests
|
||||||
|
# debug: compile with -DDEBUG and run all predefined tests
|
||||||
|
# mem: perform memcheck with all tests enabled
|
||||||
|
# unit: build standalone (unit) bimary
|
||||||
|
# unitnowarn: build standalone (unit) binary with -Werror disabled
|
||||||
|
# unitdebug: build standalone binary with -DDEBUG
|
||||||
|
#
|
||||||
|
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||||
|
|
||||||
|
.PHONY: default all nowarn debug mem unit unitnowarn unitdebug standalone
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
ALLSOURCES:=$(wildcard ./*.c)
|
||||||
|
TESTSOURCES:=$(wildcard ./test_*.c)
|
||||||
|
SRC:=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
|
||||||
|
|
||||||
|
include makefile
|
||||||
|
|
||||||
|
all: CFLAGS+=-DTESTALL
|
||||||
|
all: clean test
|
||||||
|
|
||||||
|
nowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||||
|
nowarn: clean all
|
||||||
|
|
||||||
|
debug: CFLAGS+=-DDEBUG
|
||||||
|
debug: all
|
||||||
|
|
||||||
|
mem: CFLAGS+=-DTESTALL
|
||||||
|
mem: clean memcheck
|
||||||
|
|
||||||
|
unitnowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||||
|
unitnowarn: clean unit
|
||||||
|
|
||||||
|
unitdebug: CFLAGS+=-DDEBUG
|
||||||
|
unitdebug: clean unit
|
||||||
|
|
||||||
|
unit: CFLAGS+=-DUNIT_TEST
|
||||||
|
unit: *.c *.h
|
||||||
|
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)
|
Reference in New Issue
Block a user