Fix mbed-client-cli part

pull/7745/head
Olli-Pekka Puolitaival 2018-08-10 15:16:45 +03:00
parent 9f3704e7b9
commit 75400ed31b
10 changed files with 0 additions and 1276 deletions

View File

@ -1,2 +0,0 @@
test/*
source/ns_list_internal/*

View File

View File

@ -1,5 +0,0 @@
SRCS := $(wildcard source/*.c)
LIB := libCmdline.a
EXPORT_HEADERS := mbed-client-cli
include ../exported_rules.mk

105
README.md
View File

@ -33,108 +33,3 @@ We have a [developer website](https://os.mbed.com) for asking questions, engagin
## Getting started for contributors
We also have a [contributing and publishing guide](https://os.mbed.com/contributing/) that covers licensing, contributor agreements and style guidelines.
=======
# mbed-client-cli
This is the Command Line Library for a CLI application. This library provides methods for:
* Adding commands to the interpreter.
* Deleting commands from the interpreter.
* Executing commands.
* Adding command aliases to the interpreter.
* Searching command arguments.
## API
Command Line Library API is described in the snipplet below:
```c++
// if thread safety for CLI terminal output is needed
// configure output mutex wait cb before initialization so it's available immediately
cmd_set_mutex_wait_func( (func)(void) );
// configure output mutex release cb before initialization so it's available immediately
cmd_set_mutex_wait_func( (func)(void) );
// initialize cmdline with print function
cmd_init( (func)(const char* fmt, va_list ap) );
// configure ready cb
cmd_set_ready_cb( (func)(int retcode) );
// register command for library
cmd_add( <command>, (int func)(int argc, char *argv[]), <help>, <man>);
//execute some existing commands
cmd_exe( <command> );
```
## Tracing
Command Line Library has trace messages, which are disabled by default.
"MBED_CLIENT_CLI_TRACE_ENABLE" flag if defined, enables all the trace prints for debugging.
## Usage example
Adding new commands to the Command Line Library and executing the commands:
```c++
//example print function
void myprint(const char* fmt, va_list ap){ vprintf(fmt, ap); }
// ready cb, calls next command to be executed
void cmd_ready_cb(int retcode) { cmd_next( retcode ); }
// dummy command with some option
int cmd_dummy(int argc, char *argv[]){
if( cmd_has_option(argc, argv, "o") ) {
cmd_printf("This is o option");
} else {
return CMDLINE_RETCODE_INVALID_PARAMETERS;
}
return CMDLINE_RETCODE_SUCCESS;
}
// timer cb (pseudo-timer-code)
void timer_ready_cb(void) {
cmd_ready(CMDLINE_RETCODE_SUCCESS);
}
// long command, that needs for example some events to complete the command execution
int cmd_long(int argc, char *argv[] ) {
timer_start( 5000, timer_ready_cb ); //pseudo timer code
return CMDLINE_RETCODE_EXCUTING_CONTINUE;
}
void main(void) {
cmd_init( &myprint ); // initialize cmdline with print function
cmd_set_ready_cb( cmd_ready_cb ); // configure ready cb
cmd_add("dummy", cmd_dummy, 0, 0); // add one dummy command
cmd_add("long", cmd_long, 0, 0); // add one dummy command
//execute dummy and long commands
cmd_exe( "dummy;long" );
}
```
## Thread safety
The CLI library is not thread safe, but the CLI terminal output can be locked against other
output streams, for example if both traces and CLI output are using serial out.
```c++
static Mutex MyMutex;
// mutex wait cb, acquires the mutex, waiting if necessary
static void mutex_wait(void)
{
MyMutex.lock();
}
// mutex release cb, releases the mutex
static void my_mutex_release(void)
{
MyMutex.unlock();
}
void main(void) {
cmd_mutex_wait_func( my_mutex_wait ); // configure mutex wait function before initializing
cmd_mutex_release_func( my_mutex_release ); // configure mutex release function before initializing
cmd_init( &myprint ); // initialize cmdline with print function
cmd_set_ready_cb( cmd_ready_cb ); // configure ready cb.
//CLI terminal output now locks against MyMutex
}
```

View File

@ -1,33 +0,0 @@
{
"name": "mbed-client-cli",
"version": "0.3.0",
"description": "Command Line Library for mbedOS",
"keywords": [
"cli",
"client",
"cmd"
],
"author": "Jussi Vatjus-Anttila",
"repository": {
"url": "https://github.com/ARMmbed/mbed-client-cli.git",
"type": "git"
},
"homepage": "https://github.com/ARMmbed/mbed-client-cli.git",
"licenses": [
{
"url": "https://spdx.org/licenses/Apache-2.0",
"type": "Apache-2.0"
}
],
"dependencies": {
"mbed-trace": "^1.1.2"
},
"testTargetDependencies": {
"x86-linux-native": {
"cpputest": "ARMmbed/cpputest"
},
"x86-windows-native": {
"cpputest": "ARMmbed/cpputest"
}
}
}

View File

@ -1,14 +0,0 @@
if(DEFINED TARGET_LIKE_X86_LINUX_NATIVE)
add_library( mbed-client-cli
ns_cmdline.c
ns_list_internal/ns_list.c
)
add_definitions("-g -O0 -fprofile-arcs -ftest-coverage")
target_link_libraries(mbed-client-cli gcov)
else()
add_library( mbed-client-cli
ns_cmdline.c
ns_list_internal/ns_list.c
)
target_link_libraries(mbed-client-cli)
endif()

View File

@ -1,23 +0,0 @@
/*
* Copyright (c) 2016 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* All functions can be inlined, and definitions are in ns_list.h.
* Define NS_LIST_FN before including it to generate external definitions.
*/
#define NS_LIST_FN extern
#include "ns_list.h"

View File

@ -1,721 +0,0 @@
/*
* Copyright (c) 2016 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NS_LIST_H_
#define NS_LIST_H_
#include "ns_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file
* \brief Linked list support library
*
* The ns_list.h file provides a doubly-linked list/queue, providing O(1)
* performance for all insertion/removal operations, and access to either
* end of the list.
*
* Memory footprint is two pointers for the list head, and two pointers in each
* list entry. It is similar in concept to BSD's TAILQ.
*
* Although the API is symmetrical and O(1) in both directions, due to internal
* pointer design, it is *slightly* more efficient to insert at the end when
* used as a queue, and to iterate forwards rather than backwards.
*
* Example of an entry type that can be stored to this list.
* ~~~
* typedef struct example_entry
* {
* uint8_t *data;
* uint32_t data_count;
* ns_list_link_t link;
* }
* example_entry_t;
*
* static NS_LIST_HEAD(example_entry_t, link) my_list;
* ns_list_init(&my_list);
* ~~~
* OR
* ~~~
* NS_LIST_HEAD(example_entry_t, link) my_list = NS_LIST_INIT(my_list);
* ~~~
* OR
* ~~~
* static NS_LIST_DEFINE(my_list, example_entry_t, link);
* ~~~
* OR
* ~~~
* typedef NS_LIST_HEAD(example_entry_t, link) example_list_t;
* example_list_t NS_LIST_NAME_INIT(my_list);
* ~~~
* NOTE: the link field SHALL NOT be accessed by the user.
*
* An entry can exist on multiple lists by having multiple link fields.
*
* All the list operations are implemented as macros, most of which are backed
* by optionally-inline functions. The macros do not evaluate any arguments more
* than once, unless documented.
*
* In macro documentation, `list_t` refers to a list type defined using
* NS_LIST_HEAD(), and `entry_t` to the entry type that was passed to it.
*/
/** \brief Underlying generic linked list head.
*
* Users should not use this type directly, but use the NS_LIST_HEAD() macro.
*/
typedef struct ns_list {
void *first_entry; ///< Pointer to first entry, or NULL if list is empty
void **last_nextptr; ///< Pointer to last entry's `next` pointer, or
///< to head's `first_entry` pointer if list is empty
} ns_list_t;
/** \brief Declare a list head type
*
* This union stores the real list head, and also encodes as compile-time type
* information the offset of the link pointer, and the type of the entry.
*
* Note that type information is compiler-dependent; this means
* ns_list_get_first() could return either `void *`, or a pointer to the actual
* entry type. So `ns_list_get_first()->data` is not a portable construct -
* always assign returned entry pointers to a properly typed pointer variable.
* This assignment will be then type-checked where the compiler supports it, and
* will dereference correctly on compilers that don't support this extension.
* ~~~
* NS_LIST_HEAD(example_entry_t, link) my_list;
*
* example_entry_t *entry = ns_list_get_first(&my_list);
* do_something(entry->data);
* ~~~
* Each use of this macro generates a new anonymous union, so these two lists
* have different types:
* ~~~
* NS_LIST_HEAD(example_entry_t, link) my_list1;
* NS_LIST_HEAD(example_entry_t, link) my_list2;
* ~~~
* If you need to use a list type in multiple places, eg as a function
* parameter, use typedef:
* ~~~
* typedef NS_LIST_HEAD(example_entry_t, link) example_list_t;
*
* void example_function(example_list_t *);
* ~~~
*/
#define NS_LIST_HEAD(entry_type, field) \
union \
{ \
ns_list_t slist; \
NS_STATIC_ASSERT(offsetof(entry_type, field) <= UINT_FAST8_MAX, "link offset too large") \
char (*offset)[offsetof(entry_type, field)]; \
entry_type *type; \
}
/// \privatesection
/** \brief Get offset of link field in entry.
* \return `(ns_list_offset_t)` The offset of the link field for entries on the specified list
*/
#define NS_LIST_OFFSET_(list) ((ns_list_offset_t) sizeof *(list)->offset)
/** \brief Get the entry type.
* \def NS_LIST_TYPE_
*
* \return The type of entry on the specified list.
*
* Only available if the compiler provides a "typeof" operator.
*/
#if defined __cplusplus && __cplusplus >= 201103L
#define NS_LIST_TYPE_(list) decltype(*(list)->type)
#elif defined __GNUC__
#define NS_LIST_TYPE_(list) __typeof__(*(list)->type)
#endif
/** \brief Check for compatible pointer types
*
* Although this can be done portably, the GCC custom version is provided to
* produce a clearer diagnostic, and it produces an error rather than a warning.
*
* The portable version will produce a diagnostic about a pointer mismatch on
* the == inside the sizeof operator. For example ARM/Norcroft C gives the error:
*
* operand types are incompatible ("entry_t *" and "other_t *")
*/
#ifdef CPPCHECK
#define NS_PTR_MATCH_(a, b, str) ((void) 0)
#elif defined __GNUC__
#define NS_PTR_MATCH_(a, b, str) __extension__ \
({ NS_STATIC_ASSERT(__builtin_types_compatible_p(__typeof__ (*(a)), __typeof__ (*(b))), \
str) })
#else
#define NS_PTR_MATCH_(a, b, str) ((void) sizeof ((a) == (b)))
#endif
/** \brief Internal macro to cast returned entry pointers to correct type.
*
* Not portable in C, alas. With GCC or C++11, the "get entry" macros return
* correctly-typed pointers. Otherwise, the macros return `void *`.
*
* The attempt at a portable version would work if the C `?:` operator wasn't
* broken - `x ? (t *) : (void *)` should really have type `(t *)` in C, but
* it has type `(void *)`, which only makes sense for C++. The `?:` is left in,
* in case some day it works. Some compilers may still warn if this is
* assigned to a different type.
*/
#ifdef NS_LIST_TYPE_
#define NS_LIST_TYPECAST_(list, val) ((NS_LIST_TYPE_(list) *) (val))
#else
#define NS_LIST_TYPECAST_(list, val) (0 ? (list)->type : (val))
#endif
/** \brief Internal macro to check types of input entry pointer. */
#define NS_LIST_TYPECHECK_(list, entry) \
(NS_PTR_MATCH_((list)->type, (entry), "incorrect entry type for list"), (entry))
/** \brief Type used to pass link offset to underlying functions
*
* We could use size_t, but it would be unnecessarily large on 8-bit systems,
* where we can be (pretty) confident we won't have next pointers more than
* 256 bytes into a structure.
*/
typedef uint_fast8_t ns_list_offset_t;
/// \publicsection
/** \brief The type for the link member in the user's entry structure.
*
* Users should not access this member directly - just pass its name to the
* list head macros. The funny prev pointer simplifies common operations
* (eg insertion, removal), at the expense of complicating rare reverse iteration.
*
* NB - the list implementation relies on next being the first member.
*/
typedef struct ns_list_link {
void *next; ///< Pointer to next entry, or NULL if none
void **prev; ///< Pointer to previous entry's (or head's) next pointer
} ns_list_link_t;
/** \brief "Poison" value placed in unattached entries' link pointers.
* \internal What are good values for this? Platform dependent, maybe just NULL
*/
#define NS_LIST_POISON ((void *) 0xDEADBEEF)
/** \brief Initialiser for an entry's link member
*
* This initialiser is not required by the library, but a user may want an
* initialiser to include in their own entry initialiser. See
* ns_list_link_init() for more discussion.
*/
#define NS_LIST_LINK_INIT(name) \
NS_FUNNY_INTPTR_OK \
{ NS_LIST_POISON, NS_LIST_POISON } \
NS_FUNNY_INTPTR_RESTORE
/** \hideinitializer \brief Initialise an entry's list link
*
* This "initialises" an unattached entry's link by filling the fields with
* poison. This is optional, as unattached entries field pointers are not
* meaningful, and it is not valid to call ns_list_get_next or similar on
* an unattached entry.
*
* \param entry Pointer to an entry
* \param field The name of the link member to initialise
*/
#define ns_list_link_init(entry, field) ns_list_link_init_(&(entry)->field)
/** \hideinitializer \brief Initialise a list
*
* Initialise a list head before use. A list head must be initialised using this
* function or one of the NS_LIST_INIT()-type macros before use. A zero-initialised
* list head is *not* valid.
*
* If used on a list containing existing entries, those entries will
* become detached. (They are not modified, but their links are now effectively
* undefined).
*
* \param list Pointer to a NS_LIST_HEAD() structure.
*/
#define ns_list_init(list) ns_list_init_(&(list)->slist)
/** \brief Initialiser for an empty list
*
* Usage in an enclosing initialiser:
* ~~~
* static my_type_including_list_t x = {
* "Something",
* 23,
* NS_LIST_INIT(x),
* };
* ~~~
* NS_LIST_DEFINE() or NS_LIST_NAME_INIT() may provide a shorter alternative
* in simpler cases.
*/
#define NS_LIST_INIT(name) { { NULL, &(name).slist.first_entry } }
/** \brief Name and initialiser for an empty list
*
* Usage:
* ~~~
* list_t NS_LIST_NAME_INIT(foo);
* ~~~
* acts as
* ~~~
* list_t foo = { empty list };
* ~~~
* Also useful with designated initialisers:
* ~~~
* .NS_LIST_NAME_INIT(foo),
* ~~~
* acts as
* ~~~
* .foo = { empty list },
* ~~~
*/
#define NS_LIST_NAME_INIT(name) name = NS_LIST_INIT(name)
/** \brief Define a list, and initialise to empty.
*
* Usage:
* ~~~
* static NS_LIST_DEFINE(my_list, entry_t, link);
* ~~~
* acts as
* ~~~
* static list_type my_list = { empty list };
* ~~~
*/
#define NS_LIST_DEFINE(name, type, field) \
NS_LIST_HEAD(type, field) NS_LIST_NAME_INIT(name)
/** \hideinitializer \brief Add an entry to the start of the linked list.
*
* ns_list_add_to_end() is *slightly* more efficient than ns_list_add_to_start().
*
* \param list `(list_t *)` Pointer to list.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_to_start(list, entry) \
ns_list_add_to_start_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Add an entry to the end of the linked list.
*
* \param list `(list_t *)` Pointer to list.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_to_end(list, entry) \
ns_list_add_to_end_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Add an entry before a specified entry.
*
* \param list `(list_t *)` Pointer to list.
* \param before `(entry_t *)` Existing entry before which to place the new entry.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_before(list, before, entry) \
ns_list_add_before_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, before), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Add an entry after a specified entry.
*
* ns_list_add_before() is *slightly* more efficient than ns_list_add_after().
*
* \param list `(list_t *)` Pointer to list.
* \param after `(entry_t *)` Existing entry after which to place the new entry.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_after(list, after, entry) \
ns_list_add_after_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, after), NS_LIST_TYPECHECK_(list, entry))
/** \brief Check if a list is empty.
*
* \param list `(const list_t *)` Pointer to list.
*
* \return `(bool)` true if the list is empty.
*/
#define ns_list_is_empty(list) ((bool) ((list)->slist.first_entry == NULL))
/** \brief Get the first entry.
*
* \param list `(const list_t *)` Pointer to list.
*
* \return `(entry_t *)` Pointer to first entry.
* \return NULL if list is empty.
*/
#define ns_list_get_first(list) NS_LIST_TYPECAST_(list, (list)->slist.first_entry)
/** \hideinitializer \brief Get the previous entry.
*
* \param list `(const list_t *)` Pointer to list.
* \param current `(const entry_t *)` Pointer to current entry.
*
* \return `(entry_t *)` Pointer to previous entry.
* \return NULL if current entry is first.
*/
#define ns_list_get_previous(list, current) \
NS_LIST_TYPECAST_(list, ns_list_get_previous_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current)))
/** \hideinitializer \brief Get the next entry.
*
* \param list `(const list_t *)` Pointer to list.
* \param current `(const entry_t *)` Pointer to current entry.
*
* \return `(entry_t *)` Pointer to next entry.
* \return NULL if current entry is last.
*/
#define ns_list_get_next(list, current) \
NS_LIST_TYPECAST_(list, ns_list_get_next_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current)))
/** \hideinitializer \brief Get the last entry.
*
* \param list `(const list_t *)` Pointer to list.
*
* \return `(entry_t *)` Pointer to last entry.
* \return NULL if list is empty.
*/
#define ns_list_get_last(list) \
NS_LIST_TYPECAST_(list, ns_list_get_last_(&(list)->slist, NS_LIST_OFFSET_(list)))
/** \hideinitializer \brief Remove an entry.
*
* \param list `(list_t *)` Pointer to list.
* \param entry `(entry_t *)` Entry on list to be removed.
*/
#define ns_list_remove(list, entry) \
ns_list_remove_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Replace an entry.
*
* \param list `(list_t *)` Pointer to list.
* \param current `(entry_t *)` Existing entry on list to be replaced.
* \param replacement `(entry_t * restrict)` New entry to be the replacement.
*/
#define ns_list_replace(list, current, replacement) \
ns_list_replace_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current), NS_LIST_TYPECHECK_(list, replacement))
/** \hideinitializer \brief Concatenate two lists.
*
* Attach the entries on the source list to the end of the destination
* list, leaving the source list empty.
*
* \param dst `(list_t *)` Pointer to destination list.
* \param src `(list_t *)` Pointer to source list.
*
*/
#define ns_list_concatenate(dst, src) \
(NS_PTR_MATCH_(dst, src, "concatenating different list types"), \
ns_list_concatenate_(&(dst)->slist, &(src)->slist, NS_LIST_OFFSET_(src)))
/** \brief Iterate forwards over a list.
*
* Example:
* ~~~
* ns_list_foreach(const my_entry_t, cur, &my_list)
* {
* printf("%s\n", cur->name);
* }
* ~~~
* Deletion of the current entry is not permitted as its next is checked after
* running user code.
*
* The iteration pointer is declared inside the loop, using C99/C++, so it
* is not accessible after the loop. This encourages good code style, and
* matches the semantics of C++11's "ranged for", which only provides the
* declaration form:
* ~~~
* for (const my_entry_t cur : my_list)
* ~~~
* If you need to see the value of the iteration pointer after a `break`,
* you will need to assign it to a variable declared outside the loop before
* breaking:
* ~~~
* my_entry_t *match = NULL;
* ns_list_foreach(my_entry_t, cur, &my_list)
* {
* if (cur->id == id)
* {
* match = cur;
* break;
* }
* }
* ~~~
*
* The user has to specify the entry type for the pointer definition, as type
* extraction from the list argument isn't portable. On the other hand, this
* also permits const qualifiers, as in the example above, and serves as
* documentation. The entry type will be checked against the list type where the
* compiler supports it.
*
* \param type Entry type `([const] entry_t)`.
* \param e Name for iteration pointer to be defined
* inside the loop.
* \param list `(const list_t *)` Pointer to list - evaluated multiple times.
*/
#define ns_list_foreach(type, e, list) \
for (type *e = ns_list_get_first(list); e; e = ns_list_get_next(list, e))
/** \brief Iterate forwards over a list, where user may delete.
*
* As ns_list_foreach(), but deletion of current entry is permitted as its
* next pointer is recorded before running user code.
*
* Example:
* ~~~
* ns_list_foreach_safe(my_entry_t, cur, &my_list)
* {
* ns_list_remove(cur);
* }
* ~~~
* \param type Entry type `(entry_t)`.
* \param e Name for iteration pointer to be defined
* inside the loop.
* \param list `(list_t *)` Pointer to list - evaluated multiple times.
*/
#define ns_list_foreach_safe(type, e, list) \
for (type *e = ns_list_get_first(list), *_next; \
e && (_next = ns_list_get_next(list, e), true); e = _next)
/** \brief Iterate backwards over a list.
*
* As ns_list_foreach(), but going backwards - see its documentation.
* Iterating forwards is *slightly* more efficient.
*/
#define ns_list_foreach_reverse(type, e, list) \
for (type *e = ns_list_get_last(list); e; e = ns_list_get_previous(list, e))
/** \brief Iterate backwards over a list, where user may delete.
*
* As ns_list_foreach_safe(), but going backwards - see its documentation.
* Iterating forwards is *slightly* more efficient.
*/
#define ns_list_foreach_reverse_safe(type, e, list) \
for (type *e = ns_list_get_last(list), *_next; \
e && (_next = ns_list_get_previous(list, e), true); e = _next)
/** \hideinitializer \brief Count entries on a list
*
* Unlike other operations, this is O(n). Note: if list might contain over
* 65535 entries, this function **must not** be used to get the entry count.
*
* \param list `(const list_t *)` Pointer to list.
* \return `(uint_fast16_t)` Number of entries that are stored in list.
*/
#define ns_list_count(list) ns_list_count_(&(list)->slist, NS_LIST_OFFSET_(list))
/** \privatesection
* Internal functions - designed to be accessed using corresponding macros above
*/
NS_INLINE void ns_list_init_(ns_list_t *list);
NS_INLINE void ns_list_link_init_(ns_list_link_t *link);
NS_INLINE void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry);
NS_INLINE void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry);
NS_INLINE void ns_list_add_before_(ns_list_offset_t link_offset, void *before, void *restrict entry);
NS_INLINE void ns_list_add_after_(ns_list_t *list, ns_list_offset_t link_offset, void *after, void *restrict entry);
NS_INLINE void *ns_list_get_next_(ns_list_offset_t link_offset, const void *current);
NS_INLINE void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t link_offset, const void *current);
NS_INLINE void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset);
NS_INLINE void ns_list_remove_(ns_list_t *list, ns_list_offset_t link_offset, void *entry);
NS_INLINE void ns_list_replace_(ns_list_t *list, ns_list_offset_t link_offset, void *current, void *restrict replacement);
NS_INLINE void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset);
NS_INLINE uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t link_offset);
/* Provide definitions, either for inlining, or for ns_list.c */
#if defined NS_ALLOW_INLINING || defined NS_LIST_FN
#ifndef NS_LIST_FN
#define NS_LIST_FN NS_INLINE
#endif
/* Pointer to the link member in entry e */
#define NS_LIST_LINK_(e, offset) ((ns_list_link_t *)((char *)(e) + offset))
/* Lvalue of the next link pointer in entry e */
#define NS_LIST_NEXT_(e, offset) (NS_LIST_LINK_(e, offset)->next)
/* Lvalue of the prev link pointer in entry e */
#define NS_LIST_PREV_(e, offset) (NS_LIST_LINK_(e, offset)->prev)
/* Convert a pointer to a link member back to the entry;
* works for linkptr either being a ns_list_link_t pointer, or its next pointer,
* as the next pointer is first in the ns_list_link_t */
#define NS_LIST_ENTRY_(linkptr, offset) ((void *)((char *)(linkptr) - offset))
NS_LIST_FN void ns_list_init_(ns_list_t *list)
{
list->first_entry = NULL;
list->last_nextptr = &list->first_entry;
}
NS_LIST_FN void ns_list_link_init_(ns_list_link_t *link)
{
NS_FUNNY_INTPTR_OK
link->next = NS_LIST_POISON;
link->prev = NS_LIST_POISON;
NS_FUNNY_INTPTR_RESTORE
}
NS_LIST_FN void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry)
{
void *next;
NS_LIST_PREV_(entry, offset) = &list->first_entry;
NS_LIST_NEXT_(entry, offset) = next = list->first_entry;
if (next) {
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset);
} else {
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
}
list->first_entry = entry;
}
NS_LIST_FN void ns_list_add_after_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict entry)
{
void *next;
NS_LIST_PREV_(entry, offset) = &NS_LIST_NEXT_(current, offset);
NS_LIST_NEXT_(entry, offset) = next = NS_LIST_NEXT_(current, offset);
if (next) {
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset);
} else {
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
}
NS_LIST_NEXT_(current, offset) = entry;
}
NS_LIST_FN void ns_list_add_before_(ns_list_offset_t offset, void *current, void *restrict entry)
{
void **prev_nextptr;
NS_LIST_NEXT_(entry, offset) = current;
NS_LIST_PREV_(entry, offset) = prev_nextptr = NS_LIST_PREV_(current, offset);
*prev_nextptr = entry;
NS_LIST_PREV_(current, offset) = &NS_LIST_NEXT_(entry, offset);
}
NS_LIST_FN void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry)
{
void **prev_nextptr;
NS_LIST_NEXT_(entry, offset) = NULL;
NS_LIST_PREV_(entry, offset) = prev_nextptr = list->last_nextptr;
*prev_nextptr = entry;
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
}
NS_LIST_FN void *ns_list_get_next_(ns_list_offset_t offset, const void *current)
{
return NS_LIST_NEXT_(current, offset);
}
NS_LIST_FN void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t offset, const void *current)
{
if (current == list->first_entry) {
return NULL;
}
// Tricky. We don't have a direct previous pointer, but a pointer to the
// pointer that points to us - ie &head->first_entry OR &{prev}->next.
// This makes life easier on insertion and removal, but this is where we
// pay the price.
// We have to check manually for being the first entry above, so we know it's
// a real link's next pointer. Then next is the first field of
// ns_list_link_t, so we can use the normal offset value.
return NS_LIST_ENTRY_(NS_LIST_PREV_(current, offset), offset);
}
NS_LIST_FN void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset)
{
if (!list->first_entry) {
return NULL;
}
// See comments in ns_list_get_previous_()
return NS_LIST_ENTRY_(list->last_nextptr, offset);
}
NS_LIST_FN void ns_list_remove_(ns_list_t *list, ns_list_offset_t offset, void *removed)
{
void *next;
void **prev_nextptr;
next = NS_LIST_NEXT_(removed, offset);
prev_nextptr = NS_LIST_PREV_(removed, offset);
if (next) {
NS_LIST_PREV_(next, offset) = prev_nextptr;
} else {
list->last_nextptr = prev_nextptr;
}
*prev_nextptr = next;
ns_list_link_init_(NS_LIST_LINK_(removed, offset));
}
NS_LIST_FN void ns_list_replace_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict replacement)
{
void *next;
void **prev_nextptr;
NS_LIST_PREV_(replacement, offset) = prev_nextptr = NS_LIST_PREV_(current, offset);
NS_LIST_NEXT_(replacement, offset) = next = NS_LIST_NEXT_(current, offset);
if (next) {
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(replacement, offset);
} else {
list->last_nextptr = &NS_LIST_NEXT_(replacement, offset);
}
*prev_nextptr = replacement;
ns_list_link_init_(NS_LIST_LINK_(current, offset));
}
NS_LIST_FN void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset)
{
ns_list_link_t *src_first;
src_first = src->first_entry;
if (!src_first) {
return;
}
*dst->last_nextptr = src_first;
NS_LIST_PREV_(src_first, offset) = dst->last_nextptr;
dst->last_nextptr = src->last_nextptr;
ns_list_init_(src);
}
NS_LIST_FN uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t offset)
{
uint_fast16_t count = 0;
for (void *p = list->first_entry; p; p = NS_LIST_NEXT_(p, offset)) {
count++;
}
return count;
}
#endif /* defined NS_ALLOW_INLINING || defined NS_LIST_FN */
#ifdef __cplusplus
}
#endif
#endif /* NS_LIST_H_ */

View File

@ -1,373 +0,0 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* ns_types.h - Basic compiler and type setup for Nanostack libraries.
*/
#ifndef NS_TYPES_H_
#define NS_TYPES_H_
/** \file
* \brief Basic compiler and type setup
*
* We currently assume C99 or later.
*
* C99 features being relied on:
*
* - <inttypes.h> and <stdbool.h>
* - inline (with C99 semantics, not C++ as per default GCC);
* - designated initialisers;
* - compound literals;
* - restrict;
* - [static N] in array parameters;
* - declarations in for statements;
* - mixing declarations and statements
*
* Compilers should be set to C99 or later mode when building Nanomesh source.
* For GCC this means "-std=gnu99" (C99 with usual GNU extensions).
*
* Also, a little extra care is required for public header files that could be
* included from C++, especially as C++ lacks some C99 features.
*
* (TODO: as this is exposed to API users, do we need a predefine to distinguish
* internal and external use, for finer control? Not yet, but maybe...)
*/
/* Make sure <stdint.h> defines its macros if C++ */
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <stddef.h>
#include <inttypes.h> // includes <stdint.h>; debugf() users need PRIu32 etc
#include <stdbool.h>
/*
* Create the optional <stdint.h> 24-bit types if they don't exist (worth trying
* to use them, as they could exist and be more efficient than 32-bit on 8-bit
* systems...)
*/
#ifndef UINT24_LEAST_MAX
typedef uint_least32_t uint_least24_t;
#define UINT_LEAST24_MAX UINT_LEAST32_MAX
#define UINT24_C(x) UINT32_C(x)
#define PRIoLEAST24 PRIoLEAST32
#define PRIuLEAST24 PRIuLEAST32
#define PRIxLEAST24 PRIxLEAST32
#define PRIXLEAST24 PRIXLEAST32
#endif
#ifndef INT24_LEAST_MAX
typedef int_least32_t int_least24_t;
#define INT24_LEAST_MIN INT_LEAST32_MIN
#define INT24_LEAST_MAX INT_LEAST32_MAX
#define INT24_C(x) INT32_C(x)
#define PRIdLEAST24 PRIdLEAST32
#define PRIiLEAST24 PRIiLEAST32
#endif
#ifndef UINT24_FAST_MAX
typedef uint_fast32_t uint_fast24_t;
#define UINT_FAST24_MAX UINT_FAST32_MAX
#define PRIoFAST24 PRIoFAST32
#define PRIuFAST24 PRIuFAST32
#define PRIxFAST24 PRIxFAST32
#define PRIXFAST24 PRIXFAST32
#endif
#ifndef INT24_FAST_MAX
typedef int_fast32_t int_fast24_t;
#define INT_FAST24_MIN INT_FAST32_MIN
#define INT_FAST24_MAX INT_FAST32_MAX
#define PRIdFAST24 PRIdFAST32
#define PRIiFAST24 PRIiFAST32
#endif
/* Function attribute - C11 "noreturn" or C++11 "[[noreturn]]" */
#ifndef NS_NORETURN
#if defined __cplusplus && __cplusplus >= 201103L
#define NS_NORETURN [[noreturn]]
#elif !defined __cplusplus && __STDC_VERSION__ >= 201112L
#define NS_NORETURN _Noreturn
#elif defined __GNUC__
#define NS_NORETURN __attribute__((__noreturn__))
#elif defined __CC_ARM
#define NS_NORETURN __declspec(noreturn)
#elif defined __IAR_SYSTEMS_ICC__
#define NS_NORETURN __noreturn
#else
#define NS_NORETURN
#endif
#endif
/* C11's "alignas" macro, emulated for integer expressions if necessary */
#ifndef __alignas_is_defined
#if defined __CC_ARM || defined __TASKING__
#define alignas(n) __align(n)
#define __alignas_is_defined 1
#elif (__STDC_VERSION__ >= 201112L) || (defined __cplusplus && __cplusplus >= 201103L)
#include <stdalign.h>
#elif defined __GNUC__
#define alignas(n) __attribute__((__aligned__(n)))
#define __alignas_is_defined 1
#elif defined __IAR_SYSTEMS_ICC__
/* Does this really just apply to the next variable? */
#define alignas(n) __Alignas(data_alignment=n)
#define __Alignas(x) _Pragma(#x)
#define __alignas_is_defined 1
#endif
#endif
/**
* Marker for functions or objects that may be unused, suppressing warnings.
* Place after the identifier:
* ~~~
* static int X MAYBE_UNUSED = 3;
* static int foo(void) MAYBE_UNUSED;
* ~~~
*/
#if defined __CC_ARM || defined __GNUC__
#define MAYBE_UNUSED __attribute__((unused))
#else
#define MAYBE_UNUSED
#endif
/*
* C++ (even C++11) doesn't provide restrict: define away or provide
* alternative.
*/
#ifdef __cplusplus
#ifdef __GNUC__
#define restrict __restrict
#else
#define restrict
#endif
#endif /* __cplusplus */
/**
* C++ doesn't allow "static" in function parameter types: ie
* ~~~
* entry_t *find_entry(const uint8_t address[static 16])
* ~~~
* If a header file may be included from C++, use this __static define instead.
*
* (Syntax introduced in C99 - `uint8_t address[16]` in a prototype was always
* equivalent to `uint8_t *address`, but the C99 addition of static tells the
* compiler that address is never NULL, and always points to at least 16
* elements. This adds no new type-checking, but the information could aid
* compiler optimisation, and it can serve as documentation).
*/
#ifdef __cplusplus
#define __static
#else
#define __static static
#endif
#ifdef __GNUC__
#define NS_GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#endif
/** \brief Compile-time assertion
*
* C11 provides _Static_assert, as does GCC even in C99 mode (and
* as a freestanding implementation, we can't rely on <assert.h> to get
* the static_assert macro).
* C++11 provides static_assert as a keyword, as does G++ in C++0x mode.
*
* The assertion acts as a declaration that can be placed at file scope, in a
* code block (except after a label), or as a member of a struct/union. It
* produces a compiler error if "test" evaluates to 0.
*
* Note that this *includes* the required semicolon when defined, else it
* is totally empty, permitting use in structs. (If the user provided the `;`,
* it would leave an illegal stray `;` if unavailable).
*/
#ifdef __cplusplus
# if __cplusplus >= 201103L || __cpp_static_assert >= 200410
# define NS_STATIC_ASSERT(test, str) static_assert(test, str);
# elif defined __GXX_EXPERIMENTAL_CXX0X__ && NS_GCC_VERSION >= 40300
# define NS_STATIC_ASSERT(test, str) __extension__ static_assert(test, str);
# else
# define NS_STATIC_ASSERT(test, str)
# endif
#else /* C */
# if __STDC_VERSION__ >= 201112L
# define NS_STATIC_ASSERT(test, str) _Static_assert(test, str);
# elif defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM
# ifdef _Static_assert
/*
* Some versions of glibc cdefs.h (which comes in via <stdint.h> above)
* attempt to define their own _Static_assert (if GCC < 4.6 or
* __STRICT_ANSI__) using an extern declaration, which doesn't work in a
* struct/union.
*
* For GCC >= 4.6 and __STRICT_ANSI__, we can do better - just use
* the built-in _Static_assert with __extension__. We have to do this, as
* ns_list.h needs to use it in a union. No way to get at it though, without
* overriding their define.
*/
# undef _Static_assert
# define _Static_assert(x, y) __extension__ _Static_assert(x, y)
# endif
# define NS_STATIC_ASSERT(test, str) __extension__ _Static_assert(test, str);
# else
# define NS_STATIC_ASSERT(test, str)
#endif
#endif
/** \brief Pragma to suppress warnings about unusual pointer values.
*
* Useful if using "poison" values.
*/
#ifdef __IAR_SYSTEMS_ICC__
#define NS_FUNNY_INTPTR_OK _Pragma("diag_suppress=Pe1053")
#define NS_FUNNY_INTPTR_RESTORE _Pragma("diag_default=Pe1053")
#else
#define NS_FUNNY_INTPTR_OK
#define NS_FUNNY_INTPTR_RESTORE
#endif
/** \brief Convert pointer to member to pointer to containing structure */
#define NS_CONTAINER_OF(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member)))
/*
* Inlining could cause problems when mixing with C++; provide a mechanism to
* disable it. This could also be turned off for other reasons (although
* this can usually be done through a compiler flag, eg -O0 on gcc).
*/
#ifndef __cplusplus
#define NS_ALLOW_INLINING
#endif
/* There is inlining problem in GCC version 4.1.x and we know it works in 4.6.3 */
#if defined __GNUC__ && NS_GCC_VERSION < 40600
#undef NS_ALLOW_INLINING
#endif
/** \brief Mark a potentially-inlineable function.
*
* We follow C99 semantics, which requires precisely one external definition.
* To also allow inlining to be totally bypassed under control of
* NS_ALLOW_INLINING, code can be structured as per the example of ns_list:
*
* foo.h
* -----
* ~~~
* NS_INLINE int my_func(int);
*
* #if defined NS_ALLOW_INLINING || defined FOO_FN
* #ifndef FOO_FN
* #define FOO_FN NS_INLINE
* #endif
* FOO_FN int my_func(int a)
* {
* definition;
* }
* #endif
* ~~~
* foo.c
* -----
* ~~~
* #define FOO_FN extern
* #include "foo.h"
* ~~~
* Which generates:
* ~~~
* NS_ALLOW_INLINING set NS_ALLOW_INLINING unset
* ===================== =======================
* Include foo.h Include foo.h
* ------------- -------------
* inline int my_func(int); int my_func(int);
*
* // inline definition
* inline int my_func(int a)
* {
* definition;
* }
*
* Compile foo.c Compile foo.c
* ------------- -------------
* (from .h) inline int my_func(int); int my_func(int);
*
* // external definition
* // because of no "inline" // normal external definition
* extern int my_func(int a) extern int my_func(int a)
* { {
* definition; definition;
* } }
* ~~~
*
* Note that even with inline keywords, whether the compiler inlines or not is
* up to it. For example, gcc at "-O0" will not inline at all, and will always
* call the real functions in foo.o, just as if NS_ALLOW_INLINING was unset.
* At "-O2", gcc could potentially inline everything, meaning that foo.o is not
* referenced at all.
*
* Alternatively, you could use "static inline", which gives every caller its
* own internal definition. This is compatible with C++ inlining (which expects
* the linker to eliminate duplicates), but in C it's less efficient if the code
* ends up non-inlined, and it's harder to breakpoint. I don't recommend it
* except for the most trivial functions (which could then probably be macros).
*/
#ifdef NS_ALLOW_INLINING
#define NS_INLINE inline
#else
#define NS_INLINE
#endif
#if defined __SDCC_mcs51 || defined __ICC8051__ || defined __C51__
/* The 8051 environments: SDCC (historic), IAR (current), Keil (future?) */
#define NS_LARGE __xdata
#define NS_LARGE_PTR __xdata
#ifdef __ICC8051__
#define NS_REENTRANT
#define NS_REENTRANT_PREFIX __idata_reentrant
#else
#define NS_REENTRANT __reentrant
#define NS_REENTRANT_PREFIX
#endif
#define NS_NEAR_FUNC __near_func
#else
/* "Normal" systems. Define it all away. */
#define NS_LARGE
#define NS_LARGE_PTR
#define NS_REENTRANT
#define NS_REENTRANT_PREFIX
#define NS_NEAR_FUNC
#endif
/** \brief Scatter-gather descriptor
*
* Slightly optimised for small platforms - we assume we won't need any
* element bigger than 64K.
*/
typedef struct ns_iovec {
void *iov_base;
uint_fast16_t iov_len;
} ns_iovec_t;
#endif /* NS_TYPES_H */

View File