Shared files Introduction Here we provide functions that should be used by all parts of the program. report.h : Debugging and reporting To enable the debug() function on all of the software, just type: ./configure --enable-debug and recompile with 'make'. To enable the debug() function only in specific files: 1) Configure without enabling debug (that is without --enable-debug) 2) Edit the source file that you want to debug and put the following line at the top, before the #include "report.h" line: #define DEBUG 3) Then recompile with 'make' This way, the global DEBUG macro is off but is locally enabled in certains parts of the software. The reporting levels have the following meaning. Reporting Levels 0 RPT_CRIT Critical conditions: the program stops right after this. Only use this if the program is actually exited from the current function. 1 RPT_ERR Error conditions: serious problem, program continues. Use this just before you return -1 from a function. 2 RPT_WARNING Warning conditions: Something that the user should fix, but the program can continue without a real problem. Ex: Protocol errors from a client. 3 RPT_NOTICE Major event in the program: (un)loading of driver, client (dis)connect. 4 RPT_INFO Minor event in the program: the activation of a setting, details of a loaded driver, a key reservation, a keypress, a screen switch. 5 RPT_DEBUG Insignificant event: What function has been called, what subpart of a function is being executed, what was received and sent over the socket, etc. Levels 4 (maybe) and 5 (certainly) should be reported using the debug function. The code that this function generates will not be in the executable when compiled without debugging. This way memory and CPU cycles are saved. report.h file defines 3 functions for debugging and reporting: Sets reporting level and message destination int set_reporting char * application_name int new_level int new_dest Returns the content of the byte. Report the message to the selected destination if important enough void report const int level const char *format ... Returns nothing (void). The format parameter is the same as the one used by printf. Send debugging information if important enough Consider the debug function to be exactly the same as the report function. The only difference is that it is only compiled in if DEBUG is defined. LL.h : Linked Lists (Doubly-Linked Lists) Creating a list To create a list, do the following: LinkedList *list; list = LL_new(); if(!list) handle_an_error(); The list can hold any type of data. You will need to typecast your datatype to a "void *", though. So, to add something to the list, the following would be a good way to start: typedef struct my_data { char string[16]; int number; } my_data; my_data *thingie; for(something to something else) { thingie = malloc(sizeof(my_data)); LL_AddNode(list, (void *)thingie); // typecast it to a "void *" } For errors, the general convention is that "0" means success, and a negative number means failure. Check LL.c to be sure, though. Changing data To change the data, try this: thingie = (my_data *)LL_Get(list); // typecast it back to "my_data" thingie->number = another_number; You don't need to "Put" the data back, but it doesn't hurt anything. LL_Put(list, (void *)thingie); However, if you want to point the node's data somewhere else, you'll need to get the current data first, keep track of it, then set the data to a new location: my_data * old_thingie, new_thingie; old_thingie = (my_data *)LL_Get(list); LL_Put(list, (void *)new_thingie); // Now, do something with old_thingie. (maybe, free it?) Or, you could just delete the node entirely and then add a new one: my_data * thingie; thingie = (my_data *)LL_DeleteNode(list); free(thingie); thingie->number = 666; LL_InsertNode(list, (void *)thingie); Iterations throught the list To iterate on each list item, try this: LL_Rewind(list); do { my_data = (my_data *)LL_Get(list); /* ... do something to it ... */ } while(LL_Next(list) == 0); Using the list as a stack or a queue You can also treat the list like a stack, or a queue. Just use the following functions: LL_Push() // Regular stack stuff: add, remove, peek, rotate LL_Pop() LL_Top() LL_Roll() LL_Shift() // Other end of the stack (like in perl) LL_Unshift() LL_Look() LL_UnRoll() LL_Enqueue() // Standard queue operations LL_Dequeue() There are also other goodies, like sorting and searching. Future Array-like operations will come later, to allow numerical indexing: LL_nGet(list, 3); LL_nSwap(list, 6, 13); LL_nPut(list, -4, data); // Puts item at 4th place from the end.. More ideas for later: LL_MoveNode(list, amount); // Slides a node to another spot in the list -- LL_MoveNode(list, -1); // moves a node back one toward the head That's about it, for now... Be sure to free the list when you're done! See LL.c for more detailed descriptions of these functions.