libdev.a

C Helper library
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/libdev.a

README.md (13216B)


      1 <p align="center">
      2 <img src="../plain/.pic.png" /><br />
      3 <img src="https://img.shields.io/badge/language-C-blue.svg"/> &nbsp;
      4 <img src="https://img.shields.io/badge/license-Apache--2.0-yellow.svg" /> &nbsp;
      5 <img src="https://travis-ci.org/Ne02ptzero/libdev.a.svg?branch=master" />&nbsp;
      6 <a href="https://scan.coverity.com/projects/ne02ptzero-libdev-a">
      7   <img alt="Coverity Scan Build Status"
      8        src="https://scan.coverity.com/projects/10482/badge.svg"/>
      9 </a>
     10 </p>
     11 
     12 -----------------------------------------------------------------
     13 
     14 <p align="center">A small developer library with some helpers in it</p>
     15 <p align="center">                                                              
     16   <a href="#linked-lists">Linked Lists</a> • <a href="#type-definitions">Types Definitions</a> • <a href="#singletons">Singletons</a> • <a href="#print-helpers">Print Helpers</a> • <a href="#assertions">Assertions</a> • <a href="#unit-tests">Unit Tests</a>
     17 </p>
     18 
     19 
     20 
     21 ## Usage & Installation
     22 ### Clone the repository
     23 ```
     24 git clone https://github.com/Ne02ptzero/libdev.a
     25 ```
     26 ### Compile
     27 ```
     28 make
     29 ```
     30 ### Test
     31 ```
     32 make test
     33 ```
     34 ### Use
     35 You'll need to include the header file in your project's code
     36 ```C
     37 #include <libdev.h>
     38 ```
     39 Compilation
     40 ```
     41 gcc myfile.c -L library_directory -ldev
     42 ```
     43 <h2 align="center">HELPERS</h2>
     44 ## Linked Lists
     45 In libdev, all the linked lists are from the same struct
     46 ```C
     47 typedef struct		s_list {
     48 	void				*member;	// Actual member
     49 	size_t				size; 		// Size of the member
     50 	struct s_list		*next;		// Next in list
     51 	struct s_list		*prev;		// Prev in list
     52 	struct s_list		*head;		// Head of the list
     53 }					t_list;
     54 
     55 ```
     56 In all my examples, I will use the following struct as an example. But you're free to use any type of data you want to. ```void *``` Magic !
     57 ```C
     58 typedef struct    s_example {
     59   int         a;
     60   char        b;
     61 }                 t_example;
     62 ```
     63 Here's how to use it:
     64 ### Add a member
     65 #### Define
     66 ```C
     67 list_add(t_list *main_list, void *new_member, size_t size_of_the_new_member); // MACRO
     68 
     69 ```
     70 #### Example
     71 ```C
     72 t_example		member;
     73 t_list			*list = NULL; // Important, on the first creation the list pointer _needs_ to be NULL.
     74 
     75 member.a = 3;
     76 member.b = 'l';
     77 list_add(list, &member, sizeof(t_example));
     78 ```
     79 This code will add the ```t_example member``` to a new linked list.
     80 Note there is no list initialization, you just need to set the pointer to NULL the first time you create it.
     81 If the list already exist, the member will be added at the end.
     82 ### Iteration over a list
     83 #### Define
     84 ```C
     85 list_for_each(t_list *list_head, t_list *tmp, void *member); // MACRO
     86 ```
     87 #### Example
     88 Our new struct as already been added in the list, now we want to iterate over it:
     89 ```C
     90 t_list		*tmp;
     91 t_example	*ptr;
     92 
     93 list_for_each(list, tmp, ptr) {
     94 	printf("%d - %c\n", ptr->a, ptr->b);
     95 }
     96 ```
     97 ```list``` is the head of the list pointer, ```tmp``` is just a ```t_list``` pointer (used to iterate without changing the head pointer), and ```ptr``` is your custom pointer. In this example, it's a ```t_example *```, but you can do it with anything.
     98 ### Reverse Iteration
     99 #### Define
    100 ```C
    101 list_for_each_rev(t_list *list_head, t_list *tmp, void *member); // MACRO
    102 ```
    103 #### Example
    104 Working the same way as ```list_for_each```, but instead of beginning at the list head, and follow the members by ```next```, it's beginning from the tail and follow the members by ```prev```
    105 ### Add After
    106 #### Define
    107 ```C
    108 list_add_after(t_list *list_head, t_list *list_entry, void *member, size_t size_of_the_member); // MACRO
    109 ```
    110 #### Example
    111 Working the same way as ```list_add```, but instead of adding the new member at the end, it's adding the new member after the ```list_entry``` member.
    112 ### Add Before
    113 #### Define
    114 ```C
    115 list_add_before(t_list *list_head, t_list *list_entry, void *member, size_t size_of_the_member); // MACRO
    116 ```
    117 #### Example
    118 Working the same way as ```list_add```, but instead of adding the new member at the end, it's adding the new member before the ```list_entry``` member.
    119 ### Useful functions
    120 ```C
    121 size_t		list_size(t_list *list); // Function
    122 ```
    123 Get the list size.
    124 ```C
    125 list_tail(t_list *head_list); // MACRO
    126 ```
    127 Return the last ```t_list *``` entry in ```head_list```.
    128 ```C
    129 void	*list_get(t_list *list_head, void *ptr, size_t size);
    130 ```
    131 Search into the ```list_head``` linked list, compare each ```member``` to ```ptr``` with ```memcmp```. Return the ```member``` if found, ```NULL``` if not. ```size``` is for memory comparation.
    132 ## Type definitions
    133 Types helpers in order to achieve easy bits / data manipulation
    134 
    135 Real Type | Name | Size (bits) | Size (Bytes) | Range
    136 --------- | ---- | ----------- | ------------ | -----
    137 signed char | s8_t | 8 | 1 | -128 to 127
    138 unsigned char | u8_t | 8 | 1 | 0 to 255
    139 signed short | s16_t | 16 | 2 | -32,768 to 32,767
    140 unsigned short | u16_t | 16 | 2 | 0 to 65,535
    141 signed int | s32_t | 32 | 4 | -2,147,483,648 to 2,147,483,647
    142 unsigned int | u32_t | 32 | 4 | 0 to 4,294,967,295
    143 signed long long | s64_t | 64 | 8 | -9,223,372,036,854,775,807 to 9,223,372,036,854,775,807
    144 unsigned long long | u64_t | 64 | 8 | 0 to 18,446,744,073,709,551,615
    145 
    146 ## Singletons
    147 #### Definition
    148 ```C
    149 void		*singleton_lists(u8_t list_type, void *ptr);
    150 ```
    151 #### Example
    152 Singletons are a way to avoid global variables. The way it works is quite simple: You set a variable to a function, this function stores it, and you can retrieve the same variable later. Let's see an example:
    153 ```C
    154 enum {
    155   T_LISTS
    156 };
    157 
    158 // ...
    159 
    160 t_list		*list;
    161 // We do some things with this list
    162 singleton_lists(T_LISTS, list);
    163 
    164 // Some function, far far away ...
    165 
    166 list = singleton_lists(T_LISTS, NULL);
    167 ```
    168 In order to set / retrieve the list, you need an unique identifier. In this example, an enum is used, but you can actually use what you want. Some notes though: The id used needs to be unique, and in a range of a ```unsigned char```.
    169 
    170 Note: In this example, i use a ```t_list``` pointer, but you can pass any data you want to store. ```void *``` Magic !
    171 ## Print Helpers
    172 ### Info
    173 #### Definition
    174 ```C
    175 void		info(char *str, ...);
    176 ```
    177 Print an information
    178 #### Example
    179 ```C
    180 info("This information is very important: %s\n", "No, not really");
    181 ```
    182 ### Warning
    183 #### Definition
    184 ```C
    185 void		warning(char *str, ...);
    186 ```
    187 Print a warning (stderr output)
    188 #### Example
    189 ```C
    190 warning("Something bad happened ! Code: %d\n", 10);
    191 ```
    192 ### Error
    193 #### Definition
    194 ```C
    195 void		error(char *str, ...);
    196 ```
    197 Print an error (stderr output), print a backtrace then quit with code 1
    198 #### Example
    199 ```C
    200 error("We need to stop for this reason: %s\n", "UNACCEPTABLE CONDITIOOOOONS");
    201 ```
    202 
    203 As you can see in the examples above, all the print functions use the printf format.
    204 
    205 ## Assertions
    206 An assertion is a simple test on a condition. If the condition is false, the program stop.
    207 #### Definition
    208 ```C
    209 L_ASSERT(condition); // MACRO
    210 ```
    211 #### Example
    212 ```C
    213 char	*str;
    214 
    215 str = malloc(10);
    216 // Test the malloc
    217 L_ASSERT(str);
    218 ```
    219 If the malloc failed, this is what the print look like:
    220 ```
    221 > Assertion (str) failed at main.c:29
    222 > Function: function5
    223 > Backtrace:
    224 > ./a.out(print_trace+0x19) [0x400cac]
    225 > ./a.out(function5+0x6b) [0x400c81]
    226 > ./a.out(function4+0xe) [0x400c14]
    227 > ./a.out(function3+0xe) [0x400c04]
    228 > ./a.out(function2+0xe) [0x400bf4]
    229 > ./a.out(function1+0xe) [0x400be4]
    230 > ./a.out(main+0x9) [0x400c8c]
    231 > /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7f2694011b45]
    232 > ./a.out() [0x400b09]
    233 ```
    234 Note that if you want the function names in your backtrace, you _must_ compile your code with the ```-rdynamic``` flag.
    235 
    236 ## Unit Tests
    237 ### Declare a test
    238 #### Definition
    239 ```C
    240 TEST(name); // MACRO
    241 ```
    242 #### Example
    243 ```C
    244 TEST(test_name) {
    245 	...
    246 }
    247 ```
    248 #### Do the test
    249 Inside the test, you must use the ```T_ASSERT``` macro. Here's a simple example
    250 ```C
    251 TEST(test_name) {
    252 	int	i = 1;
    253 	T_ASSERT(i == 1, "Bad initialization");
    254 	return TEST_SUCCESS;
    255 }
    256 ```
    257 In this example, we are testing than ```i``` is equal to 1. In order to do that, we call ```T_ASSERT```. Same as ```L_ASSERT```, this macro return an error if the condition is wrong. But rather than quitting the program, it just return the error to the test handler. Here's an example output if the test failed:
    258 ```
    259 > Testing test_name ...                            [ FAILED ]
    260 > 	Bad initialization: Test: 'i == 1', File main.c:33
    261 ```
    262 As you see, the second parameter of the macro is the error returned if the test failed.
    263 The error message max length is 250.
    264 
    265 You *must* finish all of your tests with the ```TEST_SUCCESS``` macro, in order to inform the test handler that all went well.
    266 
    267 ### Register a Test
    268 Your test is now declared, but you must register it to the test handler. In libdev.a, all the tests are registered in groups.
    269 #### Definition
    270 ```C
    271 reg_test(group, name); // MACRO
    272 ```
    273 #### Example
    274 If you want to register the ```test_name``` test, you must write this.
    275 ```C
    276 reg_test("Test Group", test_name);
    277 ```
    278 Groups are for ... grouped tests.
    279 ### Launch a Group Test
    280 Now that all our tests are registered, time to launch them !
    281 #### Definition
    282 ```C
    283 t_test_results	test_group(char *group); // FUNCTION
    284 ```
    285 #### Example
    286 Here's how to launch:
    287 ```C
    288 test_group("Test Group");
    289 ```
    290 This function will run all the tests registered under the name ```Test Group```, in order of insertion.
    291 As you can see, this function return a structure. Here's the content:
    292 ```C
    293 typedef struct		s_test_results {
    294 	size_t				success;
    295 	size_t				failed;
    296 	size_t				total;
    297 }					t_test_results;
    298 ```
    299 Just a quick result of the tests. You can completly ignore it if you want to.
    300 
    301 Example output:
    302 ```
    303 ================================== linked_list ===================================
    304 > Testing list_add_null ...                                                 [ OK ]
    305 > Testing list_add_member ...                                               [ OK ]
    306 > Testing list_add_member_head_list ...                                     [ OK ]
    307 > Testing list_add_member_test_multiples ...                                [ FAILED ]
    308 > 	Head pointer is not right: Test: '!(ptr->next->head == ptr)', File main.c:48
    309 > Testing list_for_each ...                                                 [ OK ]
    310 > Testing list_tail ...                                                     [ OK ]
    311 > Testing list_add_after ...                                                [ OK ]
    312 > Testing list_add_before ...                                               [ OK ]
    313 > Testing list_for_each_rev ...                                             [ OK ]
    314 > Testing list_size ...                                                     [ OK ]
    315 > Results: Total: 10, Success: 9, Failed: 1. COVERAGE: 90%
    316 ```
    317 
    318 ### Launch all the Tests
    319 #### Defintion
    320 ```C
    321 void			test_all(void); // FUNCTION
    322 ```
    323 #### Example
    324 The usage is pretty straightforward:
    325 ```
    326 test_all();
    327 ```
    328 This will launch all the group test, one by one, then print a result.
    329 
    330 Example output:
    331 ```
    332 ================================== linked_list ===================================
    333 > Testing list_add_null ...                                                 [ OK ]
    334 > Testing list_add_member ...                                               [ OK ]
    335 > Testing list_add_member_head_list ...                                     [ OK ]
    336 > Testing list_add_member_test_multiples ...                                [ FAILED ]
    337 > 	Head pointer is not right: Test: '!(ptr->next->head == ptr)', File main.c:48
    338 > Testing list_for_each ...                                                 [ OK ]
    339 > Testing list_tail ...                                                     [ OK ]
    340 > Testing list_add_after ...                                                [ OK ]
    341 > Testing list_add_before ...                                               [ OK ]
    342 > Testing list_for_each_rev ...                                             [ OK ]
    343 > Testing list_size ...                                                     [ OK ]
    344 > Results: Total: 10, Success: 9, Failed: 1. COVERAGE: 90%
    345 ===================================== types ======================================
    346 > Testing s8_t ...                                                          [ OK ]
    347 > Testing u8_t ...                                                          [ OK ]
    348 > Testing s16_t ...                                                         [ OK ]
    349 > Testing u16_t ...                                                         [ OK ]
    350 > Testing s32_t ...                                                         [ OK ]
    351 > Testing u32_t ...                                                         [ OK ]
    352 > Testing s64_t ...                                                         [ OK ]
    353 > Testing u64_t ...                                                         [ OK ]
    354 > Results: Total: 8, Success: 8, Failed: 0. COVERAGE: 100%
    355 =================================== singletons ===================================
    356 > Testing singleton_set ...                                                 [ OK ]
    357 > Testing singleton_get ...                                                 [ OK ]
    358 > Testing singleton_replace ...                                             [ OK ]
    359 > Results: Total: 3, Success: 3, Failed: 0. COVERAGE: 100%
    360 
    361 ==================================== RESULTS =====================================
    362 > TESTS SUCCESS:	20
    363 > TESTS FAILED:		1
    364 > TOTAL COVERAGE:	95%
    365 ```