--- /dev/null
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef UCG_ERRNO_H_
+#define UCG_ERRNO_H_
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large or too small */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol option not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+
+/* SystemV IPC */
+#define EIDRM 82 /* Identifier removed */
+#define ENOMSG 83 /* No message of desired type */
+#define EOVERFLOW 84 /* Value too large to be stored in data type */
+
+/* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */
+#define EILSEQ 85 /* Illegal byte sequence */
+
+/* From IEEE Std 1003.1-2001 */
+/* Base, Realtime, Threads or Thread Priority Scheduling option errors */
+#define ENOTSUP 86 /* Not supported */
+
+/* Realtime option errors */
+#define ECANCELED 87 /* Operation canceled */
+
+/* Realtime, XSI STREAMS option errors */
+#define EBADMSG 88 /* Bad or Corrupt message */
+
+/* XSI STREAMS option errors */
+#define ENODATA 89 /* No message available */
+#define ENOSR 90 /* No STREAM resources */
+#define ENOSTR 91 /* Not a STREAM */
+#define ETIME 92 /* STREAM ioctl timeout */
+
+/* File system extended attribute errors */
+#define ENOATTR 93 /* Attribute not found */
+
+/* Realtime, XSI STREAMS option errors */
+#define EMULTIHOP 94 /* Multihop attempted */
+#define ENOLINK 95 /* Link has been severed */
+#define EPROTO 96 /* Protocol error */
+
+#define ELAST 96 /* Must equal largest errno */
+
+#include_next <errno.h>
+
+#endif /* !UCG_ERRNO_H_ */
--- /dev/null
+/* empty, just have it for compat */
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_STDIO_H_
+#define UCG_STDIO_H_
+
+#include_next <stdio.h>
+
+static inline void setbuf(FILE *stream, char *buf)
+{
+ /* ignore setbuf, it is not implemented in avr-libc */
+ (void)stream;
+ (void)buf;
+}
+
+#endif /* !UCG_ERRNO_H_ */
--- /dev/null
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The
+ * elements are singly linked for minimum space and pointer manipulation
+ * overhead at the expense of O(n) removal for arbitrary elements. New
+ * elements can be added to the list after an existing element or at the
+ * head of the list. Elements being removed from the head of the list
+ * should use the explicit macro for this purpose for optimum
+ * efficiency. A singly-linked list may only be traversed in the forward
+ * direction. Singly-linked lists are ideal for applications with large
+ * datasets and few or no removals or for implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Include the definition of NULL only on NetBSD because sys/null.h
+ * is not available elsewhere. This conditional makes the header
+ * portable and it can simply be dropped verbatim into any system.
+ * The caveat is that on other systems some other header
+ * must provide NULL before the macros can be used.
+ */
+#ifdef __NetBSD__
+#include <sys/null.h>
+#endif
+
+#if defined(QUEUEDEBUG)
+# if defined(_KERNEL)
+# define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__)
+# else
+# include <err.h>
+# define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__)
+# endif
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = (head)->slh_first; \
+ (var) != SLIST_END(head); \
+ (var) = (var)->field.sle_next)
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var) != SLIST_END(head) && \
+ ((tvar) = SLIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) do { \
+ (head)->slh_first = SLIST_END(head); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_REMOVE_AFTER(slistelm, field) do { \
+ (slistelm)->field.sle_next = \
+ SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = (head)->slh_first; \
+ while(curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ } \
+} while (/*CONSTCOND*/0)
+
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods.
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = ((head)->lh_first); \
+ (var) != LIST_END(head); \
+ (var) = ((var)->field.le_next))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST((head)); \
+ (var) != LIST_END(head) && \
+ ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_MOVE(head1, head2) do { \
+ LIST_INIT((head2)); \
+ if (!LIST_EMPTY((head1))) { \
+ (head2)->lh_first = (head1)->lh_first; \
+ LIST_INIT((head1)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+/*
+ * List functions.
+ */
+#if defined(QUEUEDEBUG)
+#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \
+ if ((head)->lh_first && \
+ (head)->lh_first->field.le_prev != &(head)->lh_first) \
+ QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_LIST_OP(elm, field) \
+ if ((elm)->field.le_next && \
+ (elm)->field.le_next->field.le_prev != \
+ &(elm)->field.le_next) \
+ QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \
+ __FILE__, __LINE__); \
+ if (*(elm)->field.le_prev != (elm)) \
+ QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \
+ (elm)->field.le_next = (void *)1L; \
+ (elm)->field.le_prev = (void *)1L;
+#else
+#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)
+#define QUEUEDEBUG_LIST_OP(elm, field)
+#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field)
+#endif
+
+#define LIST_INIT(head) do { \
+ (head)->lh_first = LIST_END(head); \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ QUEUEDEBUG_LIST_OP((listelm), field) \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != \
+ LIST_END(head)) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ QUEUEDEBUG_LIST_OP((listelm), field) \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \
+ if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_REMOVE(elm, field) do { \
+ QUEUEDEBUG_LIST_OP((elm), field) \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
+} while (/*CONSTCOND*/0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
+} while (/*CONSTCOND*/0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->sqh_first); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = ((var)->field.sqe_next))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
+ for ((var) = ((head)->sqh_first); \
+ (var) != SIMPLEQ_END(head) && \
+ ((next = ((var)->field.sqe_next)), 1); \
+ (var) = (next))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
+ if ((head)->sqh_first == (elm)) { \
+ SIMPLEQ_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->sqh_first; \
+ while (curelm->field.sqe_next != (elm)) \
+ curelm = curelm->field.sqe_next; \
+ if ((curelm->field.sqe_next = \
+ curelm->field.sqe_next->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(curelm)->field.sqe_next; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_CONCAT(head1, head2) do { \
+ if (!SIMPLEQ_EMPTY((head2))) { \
+ *(head1)->sqh_last = (head2)->sqh_first; \
+ (head1)->sqh_last = (head2)->sqh_last; \
+ SIMPLEQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_LAST(head, type, field) \
+ (SIMPLEQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *)(void *) \
+ ((char *)((head)->sqh_last) - offsetof(struct type, field))))
+
+/*
+ * Tail queue definitions.
+ */
+#define _TAILQ_HEAD(name, type, qual) \
+struct name { \
+ qual type *tqh_first; /* first element */ \
+ qual type *qual *tqh_last; /* addr of last next element */ \
+}
+#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { TAILQ_END(head), &(head).tqh_first }
+
+#define _TAILQ_ENTRY(type, qual) \
+struct { \
+ qual type *tqe_next; /* next element */ \
+ qual type *qual *tqe_prev; /* address of previous next element */\
+}
+#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) (NULL)
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head))
+
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->tqh_first); \
+ (var) != TAILQ_END(head); \
+ (var) = ((var)->field.tqe_next))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, next) \
+ for ((var) = ((head)->tqh_first); \
+ (var) != TAILQ_END(head) && \
+ ((next) = TAILQ_NEXT(var, field), 1); (var) = (next))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\
+ (var) != TAILQ_END(head); \
+ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var) != TAILQ_END(head) && \
+ ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev))
+
+/*
+ * Tail queue functions.
+ */
+#if defined(QUEUEDEBUG)
+#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \
+ if ((head)->tqh_first && \
+ (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \
+ QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \
+ if (*(head)->tqh_last != NULL) \
+ QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_OP(elm, field) \
+ if ((elm)->field.tqe_next && \
+ (elm)->field.tqe_next->field.tqe_prev != \
+ &(elm)->field.tqe_next) \
+ QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \
+ __FILE__, __LINE__); \
+ if (*(elm)->field.tqe_prev != (elm)) \
+ QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \
+ if ((elm)->field.tqe_next == NULL && \
+ (head)->tqh_last != &(elm)->field.tqe_next) \
+ QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\
+ (head), (elm), __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \
+ (elm)->field.tqe_next = (void *)1L; \
+ (elm)->field.tqe_prev = (void *)1L;
+#else
+#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)
+#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)
+#define QUEUEDEBUG_TAILQ_OP(elm, field)
+#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)
+#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)
+#endif
+
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = TAILQ_END(head); \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \
+ (elm)->field.tqe_next = TAILQ_END(head); \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ QUEUEDEBUG_TAILQ_OP((listelm), field) \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \
+ TAILQ_END(head)) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ QUEUEDEBUG_TAILQ_OP((listelm), field) \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \
+ QUEUEDEBUG_TAILQ_OP((elm), field) \
+ if (((elm)->field.tqe_next) != TAILQ_END(head)) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \
+ TAILQ_END(head)) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_CONCAT(head1, head2, field) do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first; /* first element */ \
+ struct type **stqh_last; /* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue access methods.
+ */
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+#define STAILQ_END(head) NULL
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head))
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_INIT(head) do { \
+ (head)->stqh_first = NULL; \
+ (head)->stqh_last = &(head)->stqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+ (head)->stqh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.stqe_next = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+ (listelm)->field.stqe_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
+ (head)->stqh_last = &(head)->stqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ if ((head)->stqh_first == (elm)) { \
+ STAILQ_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->stqh_first; \
+ while (curelm->field.stqe_next != (elm)) \
+ curelm = curelm->field.stqe_next; \
+ if ((curelm->field.stqe_next = \
+ curelm->field.stqe_next->field.stqe_next) == NULL) \
+ (head)->stqh_last = &(curelm)->field.stqe_next; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->stqh_first); \
+ (var); \
+ (var) = ((var)->field.stqe_next))
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_CONCAT(head1, head2) do { \
+ if (!STAILQ_EMPTY((head2))) { \
+ *(head1)->stqh_last = (head2)->stqh_first; \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *)(void *) \
+ ((char *)((head)->stqh_last) - offsetof(struct type, field))))
+
+
+#ifndef _KERNEL
+/*
+ * Circular queue definitions. Do not use. We still keep the macros
+ * for compatibility but because of pointer aliasing issues their use
+ * is discouraged!
+ */
+
+/*
+ * __launder_type(): We use this ugly hack to work around the the compiler
+ * noticing that two types may not alias each other and elide tests in code.
+ * We hit this in the CIRCLEQ macros when comparing 'struct name *' and
+ * 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC
+ * 4.8) declare these comparisons as always false, causing the code to
+ * not run as designed.
+ *
+ * This hack is only to be used for comparisons and thus can be fully const.
+ * Do not use for assignment.
+ *
+ * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix
+ * this by changing the head/tail sentinal values, but see the note above
+ * this one.
+ */
+static __inline const void * __launder_type(const void *);
+static __inline const void *
+__launder_type(const void *__x)
+{
+ __asm __volatile("" : "+r" (__x));
+ return __x;
+}
+
+#if defined(QUEUEDEBUG)
+#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \
+ if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \
+ (head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \
+ QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \
+ __FILE__, __LINE__); \
+ if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \
+ (head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \
+ QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \
+ if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \
+ if ((head)->cqh_last != (elm)) \
+ QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \
+ (elm), __FILE__, __LINE__); \
+ } else { \
+ if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \
+ QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \
+ (elm), __FILE__, __LINE__); \
+ } \
+ if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \
+ if ((head)->cqh_first != (elm)) \
+ QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \
+ (elm), __FILE__, __LINE__); \
+ } else { \
+ if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \
+ QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \
+ (elm), __FILE__, __LINE__); \
+ }
+#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \
+ (elm)->field.cqe_next = (void *)1L; \
+ (elm)->field.cqe_prev = (void *)1L;
+#else
+#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field)
+#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field)
+#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field)
+#endif
+
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
+ QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
+ QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
+ QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \
+ if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+ QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->cqh_first); \
+ (var) != CIRCLEQ_ENDC(head); \
+ (var) = ((var)->field.cqe_next))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for ((var) = ((head)->cqh_last); \
+ (var) != CIRCLEQ_ENDC(head); \
+ (var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+/* For comparisons */
+#define CIRCLEQ_ENDC(head) (__launder_type(head))
+/* For assignments */
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head))
+
+#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
+ (((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
+ ? ((head)->cqh_first) \
+ : (elm->field.cqe_next))
+#define CIRCLEQ_LOOP_PREV(head, elm, field) \
+ (((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
+ ? ((head)->cqh_last) \
+ : (elm->field.cqe_prev))
+#endif /* !_KERNEL */
+
+#endif /* !_SYS_QUEUE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_SYS_TYPES_H_
+#define UCG_SYS_TYPES_H_
+
+typedef intptr_t ssize_t;
+
+#endif /* UCG_SYS_TYPES_H_ */
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_DELAY_H_
+#define UCG_DELAY_H_
+
+#include <util/delay.h>
+
+#include <stdint.h>
+
+/**
+ * Loop during *ms* milliseconds
+ */
+static inline void ucg_delay_ms(uint16_t ms)
+{
+ _delay_ms(ms);
+}
+
+#endif /* UCG_DELAY_H_ */
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_IRQ_H_
+#define UCG_IRQ_H_
+
+#include <avr/interrupt.h>
+
+typedef uint8_t ucg_irqflags_t;
+
+static inline void ucg_irq_lock(void)
+{
+ cli();
+}
+
+static inline void ucg_irq_unlock(void)
+{
+ sei();
+}
+
+static inline ucg_irqflags_t ucg_irq_lock_save(void)
+{
+ ucg_irqflags_t flags;
+
+ flags = SREG;
+ cli();
+ return flags;
+}
+
+static inline void ucg_irq_unlock_restore(ucg_irqflags_t flags)
+{
+ SREG = flags;
+}
+
+static inline int ucg_irq_locked(void)
+{
+ return !(bit_is_set(SREG,7));
+}
+
+#endif /* UCG_IRQ_H_ */
--- /dev/null
+/*
+ * Copyright 2016, Fabrice DESCLAUX <serpilliere@droids-corp.org>
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_REENT_INTR_H_
+#define UCG_REENT_INTR_H_
+
+#define UCG_REENT_INTR(f) f()
+
+#endif
--- /dev/null
+/* empty, just have it for compat */
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+ARCH_CFLAGS += -Wall -W
+ARCH_CFLAGS += -I$(UCGINE)/arch/$(UCGINE_ARCH)/include
+ARCH_CFLAGS += -Os
+ARCH_CFLAGS += -ffunction-sections
+
+ARCH_LDFLAGS += -Wl,--gc-sections
+
+ARCH_CROSS := avr-
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UGC_AVR_UART_H_
+#define UGC_AVR_UART_H_
+
+#include <ucg_uart.h>
+
+typedef volatile uint8_t *uart_reg_t;
+
+struct ucg_avr_uart {
+ /* Example: */
+ uart_reg_t reg_udr; /* &UDR0 */
+ uart_reg_t reg_ucsra; /* &UCSR0A */
+ uart_reg_t reg_ucsrb; /* &UCSR0B */
+ uart_reg_t reg_ucsrc; /* &UCSR0C */
+ uart_reg_t reg_ubrrl; /* &UBRR0L */
+ uart_reg_t reg_ubrrh; /* &UBRR0H */
+
+ uint32_t bit_udre:3; /* UDRE0 */
+ uint32_t bit_rxc:3; /* RXC0 */
+ uint32_t bit_udrie:3; /* UDRIE0 */
+ uint32_t bit_txen:3; /* RXEN0 */
+ uint32_t bit_rxen:3; /* TXEN0 */
+ uint32_t bit_rxcie:3; /* RXCIE0 */
+ uint32_t bit_u2x:3; /* U2X0 */
+};
+
+const struct ucg_uart_driver_ops avr_uart_ops;
+
+#endif /* UGC_AVR_UART_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <avr/io.h>
+#include <ucg_uart.h>
+#include <ucg_avr_uart.h>
+
+static void disable_tx_irq(struct ucg_uart *uart)
+{
+ struct ucg_avr_uart *avr_uart = uart->driver_data;
+ *avr_uart->reg_ucsrb &= ~(1 << avr_uart->bit_udrie);
+}
+
+static void enable_tx_irq(struct ucg_uart *uart)
+{
+ struct ucg_avr_uart *avr_uart = uart->driver_data;
+ *avr_uart->reg_ucsrb |= (1 << avr_uart->bit_udrie);
+}
+
+static uint8_t tx_ready(struct ucg_uart *uart)
+{
+ struct ucg_avr_uart *avr_uart = uart->driver_data;
+ return !!(*avr_uart->reg_ucsra & (1 << avr_uart->bit_udre));
+}
+
+static uint8_t rx_ready(struct ucg_uart *uart)
+{
+ struct ucg_avr_uart *avr_uart = uart->driver_data;
+ return !!(*avr_uart->reg_ucsra & (1 << avr_uart->bit_rxc));
+}
+
+static void set_udr(struct ucg_uart *uart, char c)
+{
+ struct ucg_avr_uart *avr_uart = uart->driver_data;
+ *avr_uart->reg_udr = c;
+}
+
+static char get_udr(struct ucg_uart *uart)
+{
+ struct ucg_avr_uart *avr_uart = uart->driver_data;
+ return *avr_uart->reg_udr;
+}
+
+static int set_conf(struct ucg_uart *uart, const struct ucg_uart_config *conf)
+{
+ struct ucg_avr_uart *avr_uart = uart->driver_data;
+ uint16_t baudreg;
+ uint8_t lo, hi;
+ uint8_t use_u2x = 1; /* always use double speed */
+
+ if (conf->enable == 0) {
+ *avr_uart->reg_ucsrb = 0;
+ return 0;
+ }
+
+ if (use_u2x)
+ baudreg = (F_CPU / (conf->baudrate * 8UL)) - 1;
+ else
+ baudreg = (F_CPU / (conf->baudrate * 16UL)) - 1;
+
+ lo = (uint8_t)baudreg;
+ hi = (uint8_t)((baudreg >> 8) & 0xF);
+
+ *avr_uart->reg_ubrrl = lo;
+ *avr_uart->reg_ubrrh = hi;
+
+ *avr_uart->reg_ucsra = (
+ (use_u2x << avr_uart->bit_u2x));
+ *avr_uart->reg_ucsrb = (
+ (1 << avr_uart->bit_txen) |
+ (1 << avr_uart->bit_rxen) |
+ (1 << avr_uart->bit_rxcie));
+
+ return 0;
+}
+
+const struct ucg_uart_driver_ops avr_uart_ops = {
+ .disable_tx_irq = disable_tx_irq,
+ .enable_tx_irq = enable_tx_irq,
+ .tx_ready = tx_ready,
+ .rx_ready = rx_ready,
+ .set_udr = set_udr,
+ .get_udr = get_udr,
+ .set_conf = set_conf,
+};
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_DELAY_H_
+#define UCG_DELAY_H_
+
+#include <stdint.h>
+#include <unistd.h>
+
+/**
+ * Loop during *ms* milliseconds
+ */
+static inline void ucg_delay_ms(uint16_t ms)
+{
+ (void)ms;
+ //usleep(ms * 1000);
+}
+
+#endif /* UCG_DELAY_H_ */
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_IRQ_H_
+#define UCG_IRQ_H_
+
+#include <stdint.h>
+
+typedef uint8_t ucg_irqflags_t;
+
+static inline void ucg_irq_lock(void)
+{
+}
+
+static inline void ucg_irq_unlock(void)
+{
+}
+
+static inline ucg_irqflags_t ucg_irq_lock_save(void)
+{
+ return 0;
+}
+
+static inline void ucg_irq_unlock_restore(ucg_irqflags_t flags)
+{
+ (void)flags;
+}
+
+static inline int ucg_irq_locked(void)
+{
+ return 0;
+}
+
+#endif /* UCG_IRQ_H_ */
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+ARCH_CFLAGS += -Wall -W
+ARCH_CFLAGS += -I$(UCGINE)/arch/$(UCGINE_ARCH)/include
+ARCH_CFLAGS += -O3
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_DELAY_H_
+#define UCG_DELAY_H_
+
+#include <stdint.h>
+
+/**
+ * Loop during *ms* milliseconds
+ */
+static inline void ucg_delay_ms(uint16_t ms)
+{
+ /* XXX use F_CPU */
+ while (ms-- > 0) {
+ volatile int x = 5971;
+ while (x-- > 0)
+ __asm("nop");
+ }
+}
+
+#endif /* UCG_DELAY_H_ */
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_IRQ_H_
+#define UCG_IRQ_H_
+
+#include <stdint.h>
+
+typedef uint32_t ucg_irqflags_t;
+
+static inline uint32_t __ucg_get_primask(void)
+{
+ ucg_irqflags_t primask_reg;
+
+ asm volatile (
+ "mrs %0, primask\n"
+ : "=r" (primask_reg)
+ :
+ : );
+
+ return primask_reg;
+}
+
+static inline void __ucg_set_primask(ucg_irqflags_t primask_reg)
+{
+ asm volatile (
+ "msr primask, %0\n"
+ :
+ : "r" (primask_reg)
+ : );
+}
+
+static inline void ucg_irq_lock(void)
+{
+ __asm volatile ("cpsid i");
+}
+
+static inline void ucg_irq_unlock(void)
+{
+ __asm volatile ("cpsie i");
+}
+
+static inline ucg_irqflags_t ucg_irq_lock_save(void)
+{
+ ucg_irqflags_t flags;
+
+ flags = __ucg_get_primask();
+ ucg_irq_lock();
+ return flags;
+}
+
+static inline void ucg_irq_unlock_restore(ucg_irqflags_t flags)
+{
+ __ucg_set_primask(flags);
+}
+
+static inline int ucg_irq_locked(void)
+{
+ ucg_irqflags_t flags = __ucg_get_primask();
+ return !!flags;
+}
+
+#endif /* UCG_IRQ_H_ */
--- /dev/null
+/*
+ * Copyright 2016, Fabrice DESCLAUX <serpilliere@droids-corp.org>
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_REENT_INTR_H_
+#define UCG_REENT_INTR_H_
+
+/* XXX doc */
+void ucg_reent_intr(uint32_t *context, void *fct);
+//void ucg_reent_intr(uint32_t *context);
+
+/*
+.align 4
+.long my_var
+*/
+#define UCG_REENT_INTR(f) \
+ __asm__ volatile ( \
+ "SUB SP, SP, 0x38 \n" \
+ "STR LR, [SP] \n" \
+ "ADD R0, SP, 0x10 \n" \
+ "LDR R1, =" #f " \n" \
+ "BL ucg_reent_intr \n" \
+ "POP {LR} \n" \
+ "ADD SP, SP, 0xC \n" \
+ "BX LR \n" \
+ : \
+ : \
+ : /* No clobbers */ \
+ )
+
+#define old_UCG_REENT_INTR(f) \
+ __asm__ volatile ( \
+ "SUB SP, SP, 0x38 \n" \
+ "STR LR, [SP] \n" \
+ "ADD R0, SP, 0x10 \n" \
+ "MOV R1, %[value] \n" \
+ "BL ucg_reent_intr \n" \
+ "POP {LR} \n" \
+ "ADD SP, SP, 0xC \n" \
+ "BX LR \n" \
+ : \
+ : [value]"r" ((uint32_t)f) \
+ : /* No clobbers */ \
+ )
+
+#define XXX_UCG_REENT_INTR(f) \
+ __asm__ volatile ( \
+ "SUB SP, SP, 0x38 \n" \
+ "STR LR, [SP] \n" \
+ "ADD R0, SP, 0x10 \n" \
+ "BL ucg_reent_intr \n" \
+ "POP {LR} \n" \
+ "ADD SP, SP, 0xC \n" \
+ "BX LR \n" \
+ )
+
+#endif
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+ARCH_CFLAGS += -I$(UCGINE)/arch/$(UCGINE_ARCH)/include
+ARCH_CFLAGS += -DUSE_STDPERIPH_DRIVER
+ARCH_CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
+ARCH_CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+ARCH_CFLAGS += -ffunction-sections
+
+ARCH_LDFLAGS += -Wl,--gc-sections
+ARCH_LDFLAGS += --specs=rdimon.specs -lc
+ARCH_LDFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
+ARCH_LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+
+ARCH_CROSS := arm-none-eabi-
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UGC_STM32_UART_H_
+#define UGC_STM32_UART_H_
+
+#include <stm32f4xx.h>
+
+#include <ucg_uart.h>
+
+struct ucg_stm32_uart {
+ /* Example: */
+ USART_TypeDef *uart; /* USART2 */
+ uint32_t rcc_uart; /* RCC_APB1Periph_USART2 */
+ uint32_t rcc_gpio; /* RCC_AHB1Periph_GPIOA */
+ GPIO_TypeDef *gpio; /* GPIOA */
+ uint8_t gpio_af; /* GPIO_AF_USART2 */
+ uint16_t gpio_pins; /* GPIO_Pin_2 | GPIO_Pin_3 */
+ uint8_t gpio_speed; /* GPIO_Speed_25MHz */
+ uint8_t irq; /* USART2_IRQn */
+ uint8_t irq_preempt_prio; /* 0 */
+ uint8_t irq_sub_prio; /* 0 */
+};
+
+const struct ucg_uart_driver_ops stm32_uart_ops;
+
+#endif /* UGC_STM32_UART_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include <ucg_uart.h>
+#include <ucg_stm32_uart.h>
+
+static void disable_tx_irq(struct ucg_uart *uart)
+{
+ struct ucg_stm32_uart *stm32_uart = uart->driver_data;
+
+ stm32_uart->uart->SR &= ~(USART_FLAG_TXE);
+ stm32_uart->uart->CR1 &= ~(USART_CR1_TXEIE);
+}
+
+static void enable_tx_irq(struct ucg_uart *uart)
+{
+ struct ucg_stm32_uart *stm32_uart = uart->driver_data;
+
+ stm32_uart->uart->CR1 |= USART_CR1_TXEIE;
+}
+
+static uint8_t tx_ready(struct ucg_uart *uart)
+{
+ struct ucg_stm32_uart *stm32_uart = uart->driver_data;
+
+ return !!(stm32_uart->uart->SR & USART_FLAG_TXE);
+}
+
+static uint8_t rx_ready(struct ucg_uart *uart)
+{
+ struct ucg_stm32_uart *stm32_uart = uart->driver_data;
+
+ return !!(stm32_uart->uart->SR & USART_FLAG_RXNE);
+}
+
+static void set_udr(struct ucg_uart *uart, char c)
+{
+ struct ucg_stm32_uart *stm32_uart = uart->driver_data;
+
+ stm32_uart->uart->DR = c;
+}
+
+static char get_udr(struct ucg_uart *uart)
+{
+ struct ucg_stm32_uart *stm32_uart = uart->driver_data;
+
+ return stm32_uart->uart->DR;
+}
+
+static int set_conf(struct ucg_uart *uart, const struct ucg_uart_config *conf)
+{
+ USART_InitTypeDef u;
+ GPIO_InitTypeDef gpio;
+ NVIC_InitTypeDef nvic;
+ struct ucg_stm32_uart *stm32_uart = uart->driver_data;
+ int i;
+
+ /* even if it is asked to disable, keep the RCC enabled */
+
+ /* Enable the peripheral clock. */
+ RCC_APB1PeriphClockCmd(stm32_uart->rcc_uart, ENABLE);
+ __asm("dsb");
+
+ /* Enable the peripheral clock for GPIO. */
+ RCC_AHB1PeriphClockCmd(stm32_uart->rcc_gpio, ENABLE);
+ __asm("dsb");
+
+ if (conf->enable == 0) {
+ USART_ITConfig(stm32_uart->uart, USART_IT_TXE, DISABLE);
+ USART_ITConfig(stm32_uart->uart, USART_IT_RXNE, DISABLE);
+ USART_Cmd(stm32_uart->uart, ENABLE);
+
+ nvic.NVIC_IRQChannel = stm32_uart->irq;
+ nvic.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&nvic);
+ return 0;
+ }
+
+ if (conf->nbits != 8)
+ return -EINVAL;
+
+ /* connect to alternate function */
+ for (i = 0; i < 16; i++) {
+ if ((1 << i) & stm32_uart->gpio_pins) {
+ GPIO_PinAFConfig(stm32_uart->gpio, i,
+ stm32_uart->gpio_af);
+ }
+ }
+
+ GPIO_StructInit(&gpio);
+ gpio.GPIO_Speed = stm32_uart->gpio_speed;
+
+ /* configure rx and tx */
+ gpio.GPIO_Pin = stm32_uart->gpio_pins;
+ gpio.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_Init(stm32_uart->gpio, &gpio);
+
+ /* USART configuration */
+ u.USART_BaudRate = conf->baudrate;
+ u.USART_WordLength = USART_WordLength_8b;
+ u.USART_StopBits = USART_StopBits_1;
+ u.USART_Parity = USART_Parity_No;
+ u.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+ u.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
+ USART_Init(stm32_uart->uart, &u);
+
+ /* Enable and set EXTI Interrupt to the defined priority */
+ nvic.NVIC_IRQChannel = stm32_uart->irq;
+ /* nvic.NVIC_IRQChannelPreemptionPriority = stm32_uart->irq_preempt_prio; */
+ /* nvic.NVIC_IRQChannelSubPriority = stm32_uart->irq_sub_prio; */
+ nvic.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&nvic);
+
+ /* Enable RX interruption */
+ USART_ITConfig(stm32_uart->uart, USART_IT_RXNE, ENABLE);
+
+ /* Enable USART */
+ USART_Cmd(stm32_uart->uart, ENABLE);
+
+ return 0;
+}
+
+const struct ucg_uart_driver_ops stm32_uart_ops = {
+ .disable_tx_irq = disable_tx_irq,
+ .enable_tx_irq = enable_tx_irq,
+ .tx_ready = tx_ready,
+ .rx_ready = rx_ready,
+ .set_udr = set_udr,
+ .get_udr = get_udr,
+ .set_conf = set_conf,
+};
--- /dev/null
+/*
+ * Copyright 2016, Fabrice DESCLAUX <serpilliere@droids-corp.org>
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "ucg_reent_intr.h"
+
+struct saved_stack {
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r12;
+ uint32_t lr;
+ uint32_t pc;
+ uint32_t psr;
+};
+
+struct wrapper_stack {
+ uint32_t psr;
+ uint32_t lr;
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r12;
+ uint32_t pc;
+};
+
+__attribute__((naked)) uint32_t
+ret_wrapper_stkalign_float(void)
+{
+ __asm__ volatile (
+ /* restore float */
+ "ADD SP, SP, 0x50 \n"
+ /* restore PSR, LR */
+ "POP {R0, LR} \n"
+ /* restore PSR */
+ //"MSR PSR, R0 \n"
+ "msr APSR_nzcvq, R0 \n"
+ /* restore PSR, LR */
+ "POP {R0-R3, R12, PC} \n"
+ );
+}
+
+
+__attribute__((naked)) uint32_t
+ret_wrapper_stknoalign_float(void)
+{
+ __asm__ volatile (
+ /* restore float */
+ "ADD SP, SP, 0x50 \n"
+ /* remove padding */
+ "ADD SP, SP, 0x4 \n"
+ /* restore PSR, LR */
+ "POP {R0, LR} \n"
+ /* restore PSR */
+ //"MSR PSR, R0 \n"
+ "msr APSR_nzcvq, R0 \n"
+ /* restore PSR, LR */
+ "POP {R0-R3, R12, PC} \n"
+ );
+}
+
+
+__attribute__((naked)) uint32_t
+ret_wrapper_stkalign_nofloat(void)
+{
+ __asm__ volatile (
+ /* restore float */
+ "ADD SP, SP, 0x8 \n"
+ /* restore PSR, LR */
+ "POP {R0, LR} \n"
+ /* restore PSR */
+ //"MSR PSR, R0 \n"
+ "msr APSR_nzcvq, R0 \n"
+ /* restore PSR, LR */
+ "POP {R0-R3, R12, PC} \n"
+ );
+}
+
+__attribute__((naked)) uint32_t
+ret_wrapper_stknoalign_nofloat(void)
+{
+ __asm__ volatile (
+ /* restore float */
+ "ADD SP, SP, 0x8 \n"
+ /* remove padding */
+ "ADD SP, SP, 0x4 \n"
+ /* restore PSR, LR */
+ "POP {R0, LR} \n"
+ /* restore PSR */
+ //"MSR PSR, R0 \n"
+ "msr APSR_nzcvq, R0 \n"
+ /* restore PSR, LR */
+ "POP {R0-R3, R12, PC} \n"
+ );
+}
+
+void reent_intr(void);
+
+void ucg_reent_intr(uint32_t *context, void *fct)
+//void ucg_reent_intr(uint32_t *context)
+{
+ struct saved_stack *stk_new = (void *)context;
+ struct saved_stack *stk_old = (void *)(&context[10]);
+ uint32_t exe_return;
+ int stk_padding;
+ struct wrapper_stack wstack;
+
+ stk_padding = (stk_old->psr & 0x200)?1:0;
+
+ /* copy saved ctxt */
+ wstack.r0 = stk_old->r0;
+ wstack.r1 = stk_old->r1;
+ wstack.r2 = stk_old->r2;
+ wstack.r3 = stk_old->r3;
+ wstack.r12 = stk_old->r12;
+ wstack.lr = stk_old->lr;
+ wstack.psr = stk_old->psr & ~0x200;
+ wstack.pc = stk_old->pc | 1;
+
+ exe_return = (uint32_t)context[-4];
+
+
+ stk_new->pc = (uint32_t)fct;
+// stk_new->pc = (uint32_t)reent_intr;
+ /* set arguments */
+ /* stk_new->r0 = 0; */
+ /* stk_new->r1 = 1; */
+ /* stk_new->r2 = 2; */
+ /* stk_new->r3 = 3; */
+ stk_new->r12 = wstack.r12;
+ stk_new->psr = 0x21000000;
+
+ if (exe_return & 0x10) {
+ /* No Float stacked */
+ if (stk_padding) {
+ stk_new->lr = (uint32_t)ret_wrapper_stknoalign_nofloat;
+ memcpy(&context[10+1], &wstack, sizeof(wstack));
+ } else {
+ memcpy(&context[10], &wstack, sizeof(wstack));
+ stk_new->lr = (uint32_t)ret_wrapper_stkalign_nofloat;
+ }
+ } else {
+ /* Float stacked */
+ //STM_EVAL_LEDOn(LED7);
+ memmove(&context[10], &context[18], 18*4);
+ if (stk_padding) {
+ //STM_EVAL_LEDOn(LED10);
+ memcpy(&context[10+18+1], &wstack, sizeof(wstack));
+ stk_new->lr = (uint32_t)ret_wrapper_stknoalign_float;
+ } else {
+ //STM_EVAL_LEDOn(LED9);
+ memcpy(&context[10+18], &wstack, sizeof(wstack));
+ stk_new->lr = (uint32_t)ret_wrapper_stkalign_float;
+ }
+
+ }
+
+ /* force return no fpu */
+ context[-4] |= 0x10;
+ /* create exe_return for real state return */
+ context[8] = 0x1337beef;
+ context[8+1] = exe_return;
+}
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ..)
+
+CROSS = arm-none-eabi-
+
+ifeq ($(CROSS),arm-none-eabi-)
+subdir-y := spi-flash spi-flash-client test-callout test-cmd test-mk test-uart
+endif
+ifeq ($(CROSS),avr-)
+subdir-y := spi-flash spi-flash-client test-callout test-cmd test-mk test-uart
+endif
+ifeq ($(CROSS),)
+subdir-y := test-cmdline test-mk
+endif
+
+subdir-y := $(dir $(wildcard */Makefile))
+
+include $(UCGINE)/mk/ucgine.mk
+
+.PHONY: all
+all: $(all-targets)
+
+.PHONY: clean
+clean: _ucgine_clean
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# XXX
+UCGINE ?= /home/zer0/projects/ucgine
+
+MCU = atmega328p
+F_CPU = 8000000UL
+AVRDUDE_PORT = /dev/ttyUSB0
+AVRDUDE_PROG = arduino
+AVRDUDE_BAUD = 57600
+
+O ?= $(CURDIR)/build
+
+CROSS = avr-
+ifneq ($(CROSS),avr-)
+$(error AVR target only, cannot override CROSS)
+endif
+
+CFLAGS += -g -O2 -Wall
+CFLAGS += -I$(UCGINE)/arch/avr/include
+CFLAGS += -mmcu=$(MCU)
+CFLAGS += -DF_CPU=$(F_CPU)
+LDFLAGS += -mmcu=$(MCU)
+
+# cirbuf
+CFLAGS += -I$(UCGINE)/lib/cirbuf/include
+exe-y-$(O)/spi-client += $(UCGINE)/lib/cirbuf/ucg_cirbuf.c
+# uart
+CFLAGS += -I$(UCGINE)/arch/avr/include
+CFLAGS += -I$(UCGINE)/arch/avr/uart/include
+CFLAGS += -I$(UCGINE)/lib/uart
+CFLAGS += -I$(UCGINE)/lib/uart/include
+exe-y-$(O)/spi-client += $(UCGINE)/lib/uart/ucg_uart.c
+exe-y-$(O)/spi-client += $(UCGINE)/arch/avr/uart/ucg_avr_uart.c
+
+# local files
+exe-y-$(O)/spi-client += main.c uart.c
+
+objcopy-hex-y-$(O)/spi-client.hex := $(O)/spi-client
+objcopy-bin-y-$(O)/spi-client.bin := $(O)/spi-client
+
+include $(UCGINE)/mk/ucgine.mk
+
+.PHONY: all
+all: $(all-targets)
+
+.PHONY: clean
+clean: _ucgine_clean
+
+.PHONY: burn
+burn: all
+ avrdude -e -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROG) \
+ -b $(AVRDUDE_BAUD) -U flash:w:$(O)/spi-client:e
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <ucg_irq.h>
+#include <ucg_delay.h>
+
+#include "uart.h"
+
+static void ss_high(void)
+{
+ printf("ss_high\r\n");
+ PORTB |= (1 << 2);
+}
+
+static void ss_low(void)
+{
+ printf("ss_low\r\n");
+ PORTB &= (~(1 << 2));
+}
+
+static uint8_t spi_sendrecv(uint8_t tx)
+{
+ uint8_t rx;
+
+ SPDR = tx;
+
+ /* Wait for transmission complete */
+ while ((SPSR & (1 << SPIF)) == 0)
+ ;
+
+ ucg_delay_ms(100);
+ rx = SPDR;
+
+ printf("sent 0x%2.2x, recvd 0x%2.2x '%c'\r\n",
+ tx, rx, isprint(rx) ? rx : '.');
+ ucg_delay_ms(1000);
+
+ return rx;
+}
+
+int main(void)
+{
+ uint8_t i;
+
+ /* spi: SS (PB2), MOSI (PB3), SCK (PB5) */
+ DDRB = (1 << 2) | (1 << 3) | (1 << 5);
+
+ ss_high();
+
+ /* blink led before start (unfortunatly it's on SCK, we can't
+ * use it during spi transfer) */
+ for (i = 0; i < 3; i++) {
+ PORTB |= (1 << 5);
+ ucg_delay_ms(500);
+ PORTB &= (~(1 << 5));
+ ucg_delay_ms(500);
+ }
+
+ uart_init();
+
+ ucg_irq_unlock();
+
+ printf("hello\r\n");
+
+#if 0 /* test serial (echo) */
+ {
+ char c;
+ int ret;
+
+ while (1) {
+ ret = fread(&c, 1, 1, stdin);
+ if (ret == 1)
+ fwrite(&c, 1, 1, stdout);
+ }
+ }
+#endif
+
+ /* remove power reduction on spi */
+ PRR &= ~(1 << PRSPI);
+
+ /* Enable SPI, Master, set clock rate fck/16 */
+ SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
+
+ ss_low();
+ ucg_delay_ms(1000);
+
+ /* read 5 bytes at address 0x1000 */
+ spi_sendrecv(0x03);
+ spi_sendrecv(0x00);
+ spi_sendrecv(0x10);
+ spi_sendrecv(0x00);
+ for (i = 0; i < 12; i++)
+ spi_sendrecv(0x00); /* data 0 to 12 */
+ ss_high();
+
+ while (1);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <ucg_irq.h>
+#include <ucg_cirbuf.h>
+#include <ucg_uart.h>
+#include <ucg_avr_uart.h>
+
+#include "uart.h"
+
+/* rx & tx buffers */
+static char rx_buf[128];
+static struct ucg_cirbuf rx_cirbuf;
+static char tx_buf[128];
+static struct ucg_cirbuf tx_cirbuf;
+/* generic uart struct */
+static struct ucg_uart main_uart;
+/* avr-specific uart struct */
+static struct ucg_avr_uart avr_uart_data = {
+ .reg_udr = &UDR0,
+ .reg_ucsra = &UCSR0A,
+ .reg_ucsrb = &UCSR0B,
+ .reg_ucsrc = &UCSR0C,
+ .reg_ubrrl = &UBRR0L,
+ .reg_ubrrh = &UBRR0H,
+ .bit_udre = UDRE0,
+ .bit_rxc = RXC0,
+ .bit_udrie = UDRIE0,
+ .bit_rxen = RXEN0,
+ .bit_txen = TXEN0,
+ .bit_rxcie = RXCIE0,
+ .bit_u2x = U2X0,
+};
+
+/* send on stdout */
+static int std_send(char c, FILE *f)
+{
+ (void)f;
+ ucg_uart_send(&main_uart, c, WAIT);
+ return 0;
+}
+
+/* recv on stdin */
+static int std_recv(FILE *f)
+{
+ int16_t c;
+
+ (void)f;
+ c = ucg_uart_recv(&main_uart, NOWAIT);
+ if (c < 0)
+ return _FDEV_EOF;
+
+ return c;
+}
+
+SIGNAL(USART_RX_vect)
+{
+ ucg_uart_rx_intr(&main_uart);
+}
+
+SIGNAL(USART_UDRE_vect)
+{
+ ucg_uart_tx_intr(&main_uart);
+}
+
+int uart_init(void)
+{
+ int ret;
+ struct ucg_uart_config conf;
+
+ ret = ucg_uart_init(&main_uart, &avr_uart_ops, &avr_uart_data,
+ &rx_cirbuf, rx_buf, sizeof(rx_buf),
+ &tx_cirbuf, tx_buf, sizeof(tx_buf));
+ if (ret < 0)
+ return ret;
+ ucg_uart_getconf(&main_uart, &conf);
+ conf.baudrate = 57600;
+ ret = ucg_uart_setconf(&main_uart, &conf);
+ if (ret < 0)
+ return ret;
+
+ fdevopen(std_send, std_recv);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UART_H_
+#define UART_H_
+
+#include <stdio.h>
+
+int uart_init(void);
+
+#endif
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# XXX
+STLINK ?= /home/zer0/projects/stm32/stlink
+UCGINE ?= /home/zer0/projects/ucgine
+STM_COMMON ?= /home/zer0/projects/stm32/stm32_discovery_arm_gcc/STM32F4-Discovery_FW_V1.1.0
+
+O ?= $(CURDIR)/build
+PROG = $(O)/spi-flash
+
+CROSS = arm-none-eabi-
+
+CFLAGS = -g -O2 -Wall -Tstm32_flash.ld
+CFLAGS += -DUSE_STDPERIPH_DRIVER
+CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
+CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+CFLAGS += -I.
+CFLAGS += -I$(UCGINE)/arch/stm32/include
+
+# Include files from STM libraries
+CFLAGS += -I$(STM_COMMON)/Utilities/STM32F4-Discovery
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/inc
+
+CFLAGS += -I$(UCGINE)/lib/gloss/include
+
+LDFLAGS = -Tstm32_flash.ld --specs=rdimon.specs -lc
+LDFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
+LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+
+# local files
+exe-y-$(PROG) := main.c uart.c system_stm32f4xx.c
+# stm32 standard periph lib
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_spi.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c
+# startup file
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s
+# gloss
+exe-y-$(PROG) += $(UCGINE)/lib/gloss/ucg_gloss_stubs.c
+exe-y-$(PROG) += $(UCGINE)/lib/gloss/ucg_gloss_chardev.c
+
+objcopy-hex-y-$(PROG).hex := $(PROG)
+objcopy-bin-y-$(PROG).bin := $(PROG)
+
+include $(UCGINE)/mk/ucgine.mk
+
+.PHONY: all
+all: $(all-targets)
+
+.PHONY: clean
+clean: _ucgine_clean
+
+# Flash the STM32F4
+.PHONY: burn
+burn: all
+ $(STLINK)/st-flash write $(PROG).bin 0x8000000
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ucg_delay.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <stm32f4xx.h>
+
+#include "uart.h"
+
+//#define debug_printf(args...) printf(args)
+#define debug_printf(args...)
+
+struct spi_state {
+ uint8_t cmd; /* current command */
+#define SPI_F_WREN 0x01 /* write enabled */
+ uint8_t status; /* status flags */
+ uint32_t len; /* number of rx/tx bytes since last reset */
+ uint32_t addr; /* current rd/wr address */
+};
+
+static struct spi_state spi_state;
+
+#define SPI_DATA_LEN 8192 /* must be a power of 2 */
+static uint8_t spi_data[SPI_DATA_LEN];
+
+static void led_on(void)
+{
+ GPIOD->ODR |= (1 << 13);
+}
+
+static void led_off(void)
+{
+ GPIOD->ODR &= (~(1 << 13));
+}
+
+static int spi_init(void)
+{
+ SPI_InitTypeDef spi;
+ GPIO_InitTypeDef gpio;
+
+ /* Enable peripheral clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
+
+ /* Enable the AHB1 peripheral clock for GPIOA. */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+ __asm("dsb");
+
+ /* connect the pins to the desired alternate function,
+ * configure them: */
+ GPIO_StructInit(&gpio);
+ gpio.GPIO_Speed = GPIO_Speed_25MHz; /* common */
+ gpio.GPIO_OType = GPIO_OType_PP;
+
+ /* SPI1_NSS: PA4 */
+ gpio.GPIO_Pin = GPIO_Pin_4;
+ gpio.GPIO_Mode = GPIO_Mode_IN; /* do not use the hw NSS */
+ GPIO_Init(GPIOA, &gpio);
+
+ /* SPI1_SCK: PA5 */
+ gpio.GPIO_Pin = GPIO_Pin_5;
+ gpio.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
+ GPIO_Init(GPIOA, &gpio);
+
+ /* SPI1_MISO: PA6 */
+ gpio.GPIO_Pin = GPIO_Pin_6;
+ gpio.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
+ GPIO_Init(GPIOA, &gpio);
+
+ /* SPI1_MOSI: PA7 */
+ gpio.GPIO_Pin = GPIO_Pin_7;
+ gpio.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
+ GPIO_Init(GPIOA, &gpio);
+
+ /* Program the Polarity, Phase, First Data, Baud Rate Prescaler, Slave
+ * Management, Peripheral Mode and CRC Polynomial values */
+ SPI_StructInit(&spi);
+ spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
+ spi.SPI_Mode = SPI_Mode_Slave;
+ spi.SPI_DataSize = SPI_DataSize_8b;
+ spi.SPI_CPOL = SPI_CPOL_Low; /* CK to 0 when idle */
+ spi.SPI_CPHA = SPI_CPHA_1Edge; /* data on first transition */
+ spi.SPI_NSS = SPI_NSS_Soft; /* manage nss by software */
+ spi.SPI_FirstBit = SPI_FirstBit_MSB;
+ SPI_Init(SPI1, &spi);
+
+ /* Enable the SPI */
+ SPI_Cmd(SPI1, ENABLE);
+
+ return 0;
+}
+
+static uint8_t spi_data_read(uint32_t addr)
+{
+ addr &= (SPI_DATA_LEN - 1);
+ return spi_data[addr];
+}
+
+static void spi_data_write(uint32_t addr, uint8_t val)
+{
+ addr &= (SPI_DATA_LEN - 1);
+ spi_data[addr] = val;
+}
+
+/* executed at startup */
+static void spi_state_init(void)
+{
+ memset(&spi_state, 0, sizeof(spi_state));
+}
+
+/* executed between each command when nss goes low */
+static void spi_state_reset(void)
+{
+ SPI_SendData(SPI1, 0);
+ spi_state.cmd = 0;
+ spi_state.len = 0;
+ spi_state.addr = 0;
+}
+
+static void spi_data_intr(void)
+{
+ uint8_t rd_c;
+ uint8_t wr_c = 0;
+
+ rd_c = SPI_ReceiveData(SPI1);
+
+ /* first byte, set command */
+ if (spi_state.len == 0)
+ spi_state.cmd = rd_c;
+
+ switch(spi_state.cmd) {
+ /* Read Memory, no dummy cycle */
+ case 0x03:
+ if (spi_state.len == 0) {
+ spi_state.addr = 0;
+ } else if (spi_state.len <= 3) {
+ spi_state.addr <<= 8;
+ spi_state.addr |= rd_c;
+ }
+ /* send data */
+ if (spi_state.len >= 3) {
+ wr_c = spi_data_read(spi_state.addr);
+ spi_state.addr++;
+ }
+ break;
+ /* Read Memory with dummy cycle */
+ case 0x0B:
+ if (spi_state.len == 0) {
+ spi_state.addr = 0;
+ } else if (spi_state.len <= 3) {
+ spi_state.addr <<= 8;
+ spi_state.addr |= rd_c;
+ } else {
+ wr_c = spi_data_read(spi_state.addr);
+ spi_state.addr++;
+ }
+ break;
+
+ /* Byte-Program (02H) */
+ case 0x02:
+ if (spi_state.len == 0) {
+ spi_state.addr = 0;
+ } else if (spi_state.len <= 3) {
+ spi_state.addr <<= 8;
+ spi_state.addr |= rd_c;
+ } else if (spi_state.len == 4 &&
+ (spi_state.status & SPI_F_WREN)) {
+ spi_data_write(spi_state.addr, rd_c);
+ } else {
+ /* ignore next bytes */
+ }
+ break;
+
+ /* Write-Enable (06H) */
+ case 0x06:
+ if (spi_state.len == 0)
+ spi_state.status |= SPI_F_WREN;
+ /* ignore next bytes */
+ break;
+
+ /* Write-Disable (04H) */
+ case 0x04:
+ if (spi_state.len == 0)
+ spi_state.status &= (~SPI_F_WREN);
+ /* ignore next bytes */
+ break;
+
+ /* Auto Address Increment Programming (ADH) */
+ case 0xAD:
+ /* Erase 4 KByte of memory array (20H) */
+ case 0x20:
+ /* Erase 32 KByte block of memory (52H) */
+ case 0x52:
+ /* Erase 64 KByte block of memory (D8H) */
+ case 0xD8:
+ /* Chip-Erase (60H) or (C7H) */
+ case 0x60:
+ case 0xC7:
+ /* Read-Status-Register (05H) */
+ case 0x05:
+ /* Enable-Write-Status-Register (50H) */
+ case 0x50:
+ /* Write-Status-Register (01H) */
+ case 0x01:
+ /* Read-ID (90H) or (ABH) */
+ case 0x90:
+ case 0xAB:
+ /* JEDEC-ID (9FH) */
+ case 0x9F:
+ /* EnableSOtooutputRY/BY# status during AAI programming (70H) */
+ case 0x70:
+ /* Disable SO as RY/BY# status during AAI programming (80H) */
+ case 0x80:
+
+ default:
+ /* switch on LED on unknown command */
+ led_on();
+ break;
+ }
+
+ SPI_SendData(SPI1, wr_c);
+ spi_state.len++;
+ debug_printf("rx=0x%2.2x tx=0x%2.2x\n", rd_c, wr_c);
+}
+
+/* called on state transition on the NSS pin */
+static void spi_nss_intr(uint8_t nss)
+{
+ if (nss) {
+ debug_printf("ss high\n");
+ SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);
+ } else {
+ debug_printf("ss low\n");
+ SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Reset);
+ /* it's a new command, reset our spi_state structure */
+ spi_state_reset();
+ }
+}
+
+int main(void)
+{
+ unsigned i;
+ uint8_t prev_nss = 1, nss;
+
+ /* enable the clock to GPIOD, and stall instruction pipeline as per
+ * errata 2.1.13 "Delay after an RCC peripheral clock enabling" */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+ __asm("dsb");
+
+ /* set pin 13 to be general purpose output */
+ GPIOD->MODER = (1 << 26);
+
+ /* toggle the pin */
+ for (i = 0; i < 3; i++) {
+ led_on();
+ ucg_delay_ms(500);
+ led_off();
+ ucg_delay_ms(500);
+ }
+
+ uart_init();
+ uart_register_stdio();
+ printf("salut\n");
+
+ if (spi_init() < 0) {
+ printf("SPI init failed\n");
+ goto end;
+ }
+
+ spi_state_init();
+
+ /* init spi data */
+ memset(spi_data, 0, sizeof(spi_data));
+ strcpy((char *)&spi_data[0x1000], "Dr0idZ C0rp");
+
+ while (1) {
+ /* inspect nss changes */
+ nss = !!(GPIOA->IDR & (1 << 4));
+ if (nss != prev_nss) {
+ spi_nss_intr(nss);
+ prev_nss = nss;
+ }
+
+ /* data received */
+ if (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) != RESET)
+ spi_data_intr();
+ }
+
+ end:
+ printf("end\n");
+ while (1);
+ return 0;
+}
--- /dev/null
+/*
+*****************************************************************************
+**
+** File : stm32_flash.ld
+**
+** Abstract : Linker script for STM32F407VG Device with
+** 1024KByte FLASH, 192KByte RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Environment : Atollic TrueSTUDIO(R)
+**
+** Distribution: The file is distributed \93as is,\94 without any warranty
+** of any kind.
+**
+** (c)Copyright Atollic AB.
+** You may use this file as-is or modify it according to the needs of your
+** project. Distribution of this file (unmodified or modified) is not
+** permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the
+** rights to distribute the assembled, compiled & linked contents of this
+** file as part of an application binary file, provided that it is built
+** using the Atollic TrueSTUDIO(R) toolchain.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20020000; /* end of 128K RAM on AHB bus*/
+
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
+ MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ _exit = .;
+ } >FLASH
+
+
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >FLASH
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >FLASH
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array*))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = .;
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ PROVIDE ( __end__ = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(4);
+ } >RAM
+
+ /* MEMORY_bank1 section, code must be located here explicitly */
+ /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
+ .memory_b1_text :
+ {
+ *(.mb1text) /* .mb1text sections (code) */
+ *(.mb1text*) /* .mb1text* sections (code) */
+ *(.mb1rodata) /* read-only data (constants) */
+ *(.mb1rodata*)
+ } >MEMORY_B1
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
--- /dev/null
+/**
+ ******************************************************************************
+ * @file stm32f4xx_conf.h
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 19-September-2011
+ * @brief Library configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_CONF_H
+#define __STM32F4xx_CONF_H
+
+#if defined (HSE_VALUE)
+/* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */
+ #undef HSE_VALUE
+ #define HSE_VALUE ((uint32_t)8000000)
+#endif /* HSE_VALUE */
+
+/* Includes ------------------------------------------------------------------*/
+/* Uncomment the line below to enable peripheral header file inclusion */
+#include "stm32f4xx_adc.h"
+#include "stm32f4xx_can.h"
+#include "stm32f4xx_crc.h"
+#include "stm32f4xx_cryp.h"
+#include "stm32f4xx_dac.h"
+#include "stm32f4xx_dbgmcu.h"
+#include "stm32f4xx_dcmi.h"
+#include "stm32f4xx_dma.h"
+#include "stm32f4xx_exti.h"
+#include "stm32f4xx_flash.h"
+#include "stm32f4xx_fsmc.h"
+#include "stm32f4xx_hash.h"
+#include "stm32f4xx_gpio.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx_iwdg.h"
+#include "stm32f4xx_pwr.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_rng.h"
+#include "stm32f4xx_rtc.h"
+#include "stm32f4xx_sdio.h"
+#include "stm32f4xx_spi.h"
+#include "stm32f4xx_syscfg.h"
+#include "stm32f4xx_tim.h"
+#include "stm32f4xx_usart.h"
+#include "stm32f4xx_wwdg.h"
+#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* If an external clock source is used, then the value of the following define
+ should be set to the value of the external clock source, else, if no external
+ clock is used, keep this define commented */
+/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
+
+
+/* Uncomment the line below to expanse the "assert_param" macro in the
+ Standard Peripheral Library drivers code */
+/* #define USE_FULL_ASSERT 1 */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#endif /* __STM32F4xx_CONF_H */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+/**
+ ******************************************************************************
+ * @file system_stm32f4xx.c
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 30-September-2011
+ * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+ * This file contains the system clock configuration for STM32F4xx devices,
+ * and is generated by the clock configuration tool
+ * stm32f4xx_Clock_Configuration_V1.0.0.xls
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
+ * and Divider factors, AHB/APBx prescalers and Flash settings),
+ * depending on the configuration made in the clock xls tool.
+ * This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f4xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (16 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. If the system clock source selected by user fails to startup, the SystemInit()
+ * function will do nothing and HSI still used as system clock source. User can
+ * add some code to deal with this issue inside the SetSysClock() function.
+ *
+ * 4. The default value of HSE crystal is set to 25MHz, refer to "HSE_VALUE" define
+ * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or
+ * through PLL, and you are using different crystal you have to adapt the HSE
+ * value to your own configuration.
+ *
+ * 5. This file configures the system clock as follows:
+ *=============================================================================
+ *=============================================================================
+ * Supported STM32F4xx device revision | Rev A
+ *-----------------------------------------------------------------------------
+ * System Clock source | PLL (HSE)
+ *-----------------------------------------------------------------------------
+ * SYSCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * HCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * AHB Prescaler | 1
+ *-----------------------------------------------------------------------------
+ * APB1 Prescaler | 4
+ *-----------------------------------------------------------------------------
+ * APB2 Prescaler | 2
+ *-----------------------------------------------------------------------------
+ * HSE Frequency(Hz) | 25000000
+ *-----------------------------------------------------------------------------
+ * PLL_M | 25
+ *-----------------------------------------------------------------------------
+ * PLL_N | 336
+ *-----------------------------------------------------------------------------
+ * PLL_P | 2
+ *-----------------------------------------------------------------------------
+ * PLL_Q | 7
+ *-----------------------------------------------------------------------------
+ * PLLI2S_N | NA
+ *-----------------------------------------------------------------------------
+ * PLLI2S_R | NA
+ *-----------------------------------------------------------------------------
+ * I2S input clock | NA
+ *-----------------------------------------------------------------------------
+ * VDD(V) | 3.3
+ *-----------------------------------------------------------------------------
+ * Main regulator output voltage | Scale1 mode
+ *-----------------------------------------------------------------------------
+ * Flash Latency(WS) | 5
+ *-----------------------------------------------------------------------------
+ * Prefetch Buffer | OFF
+ *-----------------------------------------------------------------------------
+ * Instruction cache | ON
+ *-----------------------------------------------------------------------------
+ * Data cache | ON
+ *-----------------------------------------------------------------------------
+ * Require 48MHz for USB OTG FS, | Enabled
+ * SDIO and RNG clock |
+ *-----------------------------------------------------------------------------
+ *=============================================================================
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f4xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f4xx.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+ * @{
+ */
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to use external SRAM mounted
+ on STM324xG_EVAL board as data memory */
+/* #define DATA_IN_ExtSRAM */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/************************* PLL Parameters *************************************/
+/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
+#define PLL_M 25
+#define PLL_N 336
+
+/* SYSCLK = PLL_VCO / PLL_P */
+#define PLL_P 2
+
+/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
+#define PLL_Q 7
+
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+ * @{
+ */
+
+ uint32_t SystemCoreClock = 168000000;
+
+ __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+static void SetSysClock(void);
+#ifdef DATA_IN_ExtSRAM
+ static void SystemInit_ExtMemCtl(void);
+#endif /* DATA_IN_ExtSRAM */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the Embedded Flash Interface, the PLL and update the
+ * SystemFrequency variable.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000;
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFF;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x24003010;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000;
+
+#ifdef DATA_IN_ExtSRAM
+ SystemInit_ExtMemCtl();
+#endif /* DATA_IN_ExtSRAM */
+
+ /* Configure the System clock source, PLL Multiplier and Divider factors,
+ AHB/APBx prescalers and Flash settings ----------------------------------*/
+ SetSysClock();
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 16 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 25 MHz), user has to ensure that HSE_VALUE is same as the real
+ * frequency of the crystal used. Otherwise, this function may
+ * have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate(void)
+{
+ uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case 0x00: /* HSI used as system clock source */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04: /* HSE used as system clock source */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08: /* PLL used as system clock source */
+
+ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+ SYSCLK = PLL_VCO / PLL_P
+ */
+ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+ pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+
+ if (pllsource != 0)
+ {
+ /* HSE used as PLL clock source */
+ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+ else
+ {
+ /* HSI used as PLL clock source */
+ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+
+ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+ SystemCoreClock = pllvco/pllp;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK frequency --------------------------------------------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @brief Configures the System clock source, PLL Multiplier and Divider factors,
+ * AHB/APBx prescalers and Flash settings
+ * @Note This function should be called only once the RCC clock configuration
+ * is reset to the default reset state (done in SystemInit() function).
+ * @param None
+ * @retval None
+ */
+static void SetSysClock(void)
+{
+/******************************************************************************/
+/* PLL (clocked by HSE) used as System clock source */
+/******************************************************************************/
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+ /* Enable HSE */
+ RCC->CR |= ((uint32_t)RCC_CR_HSEON);
+
+ /* Wait till HSE is ready and if Time out is reached exit */
+ do
+ {
+ HSEStatus = RCC->CR & RCC_CR_HSERDY;
+ StartUpCounter++;
+ } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+ if ((RCC->CR & RCC_CR_HSERDY) != RESET)
+ {
+ HSEStatus = (uint32_t)0x01;
+ }
+ else
+ {
+ HSEStatus = (uint32_t)0x00;
+ }
+
+ if (HSEStatus == (uint32_t)0x01)
+ {
+ /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
+ RCC->APB1ENR |= RCC_APB1ENR_PWREN;
+ PWR->CR |= PWR_CR_VOS;
+
+ /* HCLK = SYSCLK / 1*/
+ RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
+
+ /* PCLK2 = HCLK / 2*/
+ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
+
+ /* PCLK1 = HCLK / 4*/
+ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
+
+ /* Configure the main PLL */
+ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
+ (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
+
+ /* Enable the main PLL */
+ RCC->CR |= RCC_CR_PLLON;
+
+ /* Wait till the main PLL is ready */
+ while((RCC->CR & RCC_CR_PLLRDY) == 0)
+ {
+ }
+
+ /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
+ FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
+
+ /* Select the main PLL as system clock source */
+ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
+ RCC->CFGR |= RCC_CFGR_SW_PLL;
+
+ /* Wait till the main PLL is used as system clock source */
+ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
+ {
+ }
+ }
+ else
+ { /* If HSE fails to start-up, the application will have wrong clock
+ configuration. User can add here some code to deal with this error */
+ }
+
+}
+
+/**
+ * @brief Setup the external memory controller. Called in startup_stm32f4xx.s
+ * before jump to __main
+ * @param None
+ * @retval None
+ */
+#ifdef DATA_IN_ExtSRAM
+/**
+ * @brief Setup the external memory controller.
+ * Called in startup_stm32f4xx.s before jump to main.
+ * This function configures the external SRAM mounted on STM324xG_EVAL board
+ * This SRAM will be used as program data memory (including heap and stack).
+ * @param None
+ * @retval None
+ */
+void SystemInit_ExtMemCtl(void)
+{
+/*-- GPIOs Configuration -----------------------------------------------------*/
+/*
+ +-------------------+--------------------+------------------+------------------+
+ + SRAM pins assignment +
+ +-------------------+--------------------+------------------+------------------+
+ | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 |
+ | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 |
+ | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 |
+ | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 |
+ | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 |
+ | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 |
+ | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 |
+ | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+
+ | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 |
+ | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 |
+ | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+
+ | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 |
+ | | PE15 <-> FSMC_D12 |
+ +-------------------+--------------------+
+*/
+ /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
+ RCC->AHB1ENR = 0x00000078;
+
+ /* Connect PDx pins to FSMC Alternate function */
+ GPIOD->AFR[0] = 0x00cc00cc;
+ GPIOD->AFR[1] = 0xcc0ccccc;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xaaaa0a0a;
+ /* Configure PDx pins speed to 100 MHz */
+ GPIOD->OSPEEDR = 0xffff0f0f;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FSMC Alternate function */
+ GPIOE->AFR[0] = 0xc00cc0cc;
+ GPIOE->AFR[1] = 0xcccccccc;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xaaaa828a;
+ /* Configure PEx pins speed to 100 MHz */
+ GPIOE->OSPEEDR = 0xffffc3cf;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FSMC Alternate function */
+ GPIOF->AFR[0] = 0x00cccccc;
+ GPIOF->AFR[1] = 0xcccc0000;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xaa000aaa;
+ /* Configure PFx pins speed to 100 MHz */
+ GPIOF->OSPEEDR = 0xff000fff;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FSMC Alternate function */
+ GPIOG->AFR[0] = 0x00cccccc;
+ GPIOG->AFR[1] = 0x000000c0;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0x00080aaa;
+ /* Configure PGx pins speed to 100 MHz */
+ GPIOG->OSPEEDR = 0x000c0fff;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+/*-- FSMC Configuration ------------------------------------------------------*/
+ /* Enable the FSMC interface clock */
+ RCC->AHB3ENR = 0x00000001;
+
+ /* Configure and enable Bank1_SRAM2 */
+ FSMC_Bank1->BTCR[2] = 0x00001015;
+ FSMC_Bank1->BTCR[3] = 0x00010603;
+ FSMC_Bank1E->BWTR[2] = 0x0fffffff;
+/*
+ Bank1_SRAM2 is configured as follow:
+
+ p.FSMC_AddressSetupTime = 3;
+ p.FSMC_AddressHoldTime = 0;
+ p.FSMC_DataSetupTime = 6;
+ p.FSMC_BusTurnAroundDuration = 1;
+ p.FSMC_CLKDivision = 0;
+ p.FSMC_DataLatency = 0;
+ p.FSMC_AccessMode = FSMC_AccessMode_A;
+
+ FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;
+ FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
+ FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
+ FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
+ FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
+ FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
+*/
+
+}
+#endif /* DATA_IN_ExtSRAM */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include "stm32f4xx.h"
+
+#include <ucg_gloss_chardev.h>
+
+static _ssize_t
+uart_write_r(__attribute__((unused)) struct _reent *r,
+ __attribute__((unused)) int fd,
+ const void *ptr, size_t len)
+{
+ size_t i;
+ const char *buf = ptr;
+
+
+ for (i = 0; i < len; i++) {
+ /* wait that uart is ready */
+ while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
+ ;
+ USART_SendData(USART2, buf[i]);
+ }
+ return len;
+}
+
+static _ssize_t
+uart_read_r(__attribute__((unused)) struct _reent *r,
+ __attribute__((unused)) int fd,
+ void *ptr, size_t len)
+{
+ size_t i;
+ char *buf = ptr;
+
+ for (i = 0; i < len; i++) {
+ /* wait that uart is ready */
+ while (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET)
+ ;
+ buf[i] = USART_ReceiveData(USART2);
+ }
+ return len;
+}
+
+struct ucg_chardev uart_stdin_dev = {
+ .name = "stdin",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = uart_read_r,
+ .write_r = NULL,
+};
+
+struct ucg_chardev uart_stdout_dev = {
+ .name = "stdout",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = NULL,
+ .write_r = uart_write_r,
+};
+
+struct ucg_chardev uart_stderr_dev = {
+ .name = "stderr",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = NULL,
+ .write_r = uart_write_r,
+};
+
+void uart_init(void)
+{
+ USART_InitTypeDef uart;
+ GPIO_InitTypeDef gpio;
+
+ /* Enable the USART2 peripheral clock. */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
+ __asm("dsb");
+
+ /* Enable the AHB1 peripheral clock for GPIOA. */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+ __asm("dsb");
+
+ /* connect to alternate function */
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
+
+ GPIO_StructInit(&gpio);
+ gpio.GPIO_Speed = GPIO_Speed_25MHz;
+
+ /* configure tx on PA2 */
+ gpio.GPIO_Pin = GPIO_Pin_2;
+ gpio.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_Init(GPIOA, &gpio);
+
+ /* configure rx on PA3 */
+ gpio.GPIO_Pin = GPIO_Pin_3;
+ gpio.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_Init(GPIOA, &gpio);
+
+ /* USART configuration */
+ uart.USART_BaudRate = 115200;
+ uart.USART_WordLength = USART_WordLength_8b;
+ uart.USART_StopBits = USART_StopBits_1;
+ uart.USART_Parity = USART_Parity_No;
+ uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+ uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
+ USART_Init(USART2, &uart);
+
+ /* Enable USART */
+ USART_Cmd(USART2, ENABLE);
+}
+
+void uart_register_stdio(void)
+{
+ ucg_chardev_register(&uart_stdin_dev);
+ ucg_chardev_register(&uart_stdout_dev);
+ ucg_chardev_register(&uart_stderr_dev);
+
+ /* Disable buffering */
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+}
+
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UART_H_
+#define UART_H_
+
+/* initialize uart periph */
+void uart_init(void);
+
+/* register standard input/output */
+void uart_register_stdio(void);
+
+#endif /* UART_H_ */
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ../..)
+include $(UCGINE)/mk/ucgine-pre.mk
+
+O ?= $(CURDIR)/build
+PROG = $(O)/test-callout
+
+UCGINE_SUBARCH ?= stm32f4
+CFLAGS += -DUCGINE_ARCH_$(UCGINE_ARCH)
+CFLAGS += -DUCGINE_SUBARCH_$(UCGINE_SUBARCH)
+CFLAGS += $(ARCH_CFLAGS)
+CFLAGS += -g -Werror -I.
+
+LDFLAGS += $(ARCH_LDFLAGS)
+
+ifeq ($(UCGINE_ARCH),avr)
+MCU = atmega328p
+F_CPU = 8000000UL
+AVRDUDE_PORT = /dev/ttyUSB0
+AVRDUDE_PROG = arduino
+AVRDUDE_BAUD = 57600
+CFLAGS += -DF_CPU=$(F_CPU)
+CFLAGS += -I$(UCGINE)/arch/avr/uart/include
+CFLAGS += -mmcu=$(MCU)
+LDFLAGS += -mmcu=$(MCU)
+endif
+
+ifeq ($(UCGINE_ARCH),stm32)
+ifeq ($(UCGINE_SUBARCH),stm32f3)
+ver = 3
+STLINK ?= /home/zer0/projects/stm32/stlink
+STM_COMMON ?= /home/zer0/projects/stm32/stm32_discovery_arm_gcc/STM32F3-Discovery_FW_V1.1.0
+CFLAGS += -Tstm32_flash.ld
+CFLAGS += -I$(STM_COMMON)/src
+CFLAGS += -I$(STM_COMMON)/Libraries
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/Device/ST/STM32F30x/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/STM32F30x_StdPeriph_Driver/inc
+CFLAGS += -I$(UCGINE)/lib/gloss/include
+CFLAGS += -I$(UCGINE)/arch/stm32/include
+CFLAGS += -I$(UCGINE)/arch/stm32/uart/include
+LDFLAGS += -Tstm32_flash.ld
+# stm32 standard periph lib
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_exti.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_gpio.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rcc.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_misc.c
+# leds
+exe-y-$(PROG) += $(STM_COMMON)/src/stm32f3_discovery.c
+# system & startup file
+exe-y-$(PROG) += $(STM_COMMON)/src/system_stm32f30x.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/CMSIS/Device/ST/STM32F30x/Source/Templates/TrueSTUDIO/startup_stm32f30x.s
+# reentrant interrupts
+exe-y-$(PROG) += $(UCGINE)/arch/stm32/ucg_reent_intr.c
+else
+ver = 4
+STLINK ?= /home/zer0/projects/stm32/stlink
+STM_COMMON ?= /home/zer0/projects/stm32/stm32_discovery_arm_gcc/STM32F4-Discovery_FW_V1.1.0
+CFLAGS += -Tstm32_flash.ld
+CFLAGS += -I$(STM_COMMON)/Utilities/STM32F4-Discovery
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/inc
+CFLAGS += -I$(UCGINE)/lib/gloss/include
+CFLAGS += -I$(UCGINE)/arch/stm32/include
+CFLAGS += -I$(UCGINE)/arch/stm32/uart/include
+LDFLAGS += -Tstm32_flash.ld
+exe-y-$(PROG) += system_stm32f4xx.c
+# stm32 standard periph lib
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c
+# leds
+exe-y-$(PROG) += $(STM_COMMON)/Utilities/STM32F4-Discovery/stm32f4_discovery.c
+# startup file
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s
+# reentrant interrupts
+exe-y-$(PROG) += $(UCGINE)/arch/stm32/ucg_reent_intr.c
+endif
+endif
+
+ifeq ($(UCGINE_ARCH),posix)
+$(error Not supported on posix)
+endif
+
+# callout
+CFLAGS += -I$(UCGINE)/lib/callout/include
+exe-y-$(PROG) += $(UCGINE)/lib/callout/ucg_callout.c
+
+exe-y-$(PROG) += main.c
+
+objcopy-hex-y-$(PROG).hex := $(PROG)
+objcopy-bin-y-$(PROG).bin := $(PROG)
+
+include $(UCGINE)/mk/ucgine-post.mk
+
+.PHONY: all
+all: $(all-targets)
+
+.PHONY: clean
+clean: _ucgine_clean
+
+# Flash the STM32
+.PHONY: burn
+burn: all
+ifeq ($(CROSS),arm-none-eabi-)
+ $(STLINK)/st-flash write $(PROG).bin 0x8000000
+endif
+ifeq ($(CROSS),avr-)
+ avrdude -e -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROG) \
+ -b $(AVRDUDE_BAUD) -U flash:w:$(PROG):e
+endif
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include <ucg_delay.h>
+#include <ucg_irq.h>
+#include <ucg_callout.h>
+#include <ucg_reent_intr.h>
+
+static volatile uint32_t global_ms;
+static volatile uint8_t brightness; /* 0 to 100 */
+static volatile int8_t brightness_inc = 1;
+static struct ucg_callout_mgr *p_intr_cm = NULL;
+
+#if defined(UCGINE_ARCH_stm32)
+
+#if defined(UCGINE_SUBARCH_stm32f3)
+#include <stm32f30x.h>
+#include <stm32f3_discovery.h>
+#elif defined(UCGINE_SUBARCH_stm32f4)
+#include <stm32f4xx.h>
+#include <stm32f4_discovery.h>
+#endif
+
+static void target_init(void)
+{
+ RCC_ClocksTypeDef RCC_Clocks;
+
+ /* Get SYSCLK, HCLK and PCLKx frequency */
+ RCC_GetClocksFreq(&RCC_Clocks);
+ /* generate an interrupt every ms */
+ SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
+
+ /* Initialize LEDs */
+ STM_EVAL_LEDInit(LED6);
+}
+
+static void led_on(void)
+{
+ STM_EVAL_LEDOn(LED6);
+}
+
+static void led_off(void)
+{
+ STM_EVAL_LEDOff(LED6);
+}
+
+void reent_intr(void)
+{
+ global_ms++;
+ if (p_intr_cm != NULL)
+ ucg_callout_manage(p_intr_cm);
+}
+
+/* called every ms */
+__attribute__ ((naked)) void SysTick_Handler(void)
+{
+ UCG_REENT_INTR(reent_intr);
+}
+#elif defined(UCGINE_ARCH_avr)
+#include <avr/io.h>
+
+static void led_on(void)
+{
+ PORTB |= (1 << 5);
+}
+
+static void led_off(void)
+{
+ PORTB &= (~(1 << 5));
+}
+
+SIGNAL(TIMER0_OVF_vect)
+{
+ static uint16_t i = 0;
+
+ i++;
+ if ((i & 0x3) != 0)
+ return;
+
+ global_ms++;
+ if (p_intr_cm != NULL)
+ ucg_callout_manage(p_intr_cm);
+}
+
+static void target_init(void)
+{
+ DDRB = (1 << 5);
+
+ TCCR0B = (1 << CS01); /* div = 8 */
+ TIMSK0 |= (1 << TOIE0); /* enable timer0 intr */
+}
+#endif
+
+static uint16_t get_time_ms(void)
+{
+ ucg_irqflags_t flags;
+ uint32_t ms;
+
+ flags = ucg_irq_lock_save();
+ ms = global_ms;
+ ucg_irq_unlock_restore(flags);
+ return ms;
+}
+
+/* every ms, enable or disable the led depending on brightness */
+static void led_control_cb(struct ucg_callout_mgr *cm,
+ struct ucg_callout *tim, void *arg)
+{
+ static uint8_t accu;
+
+ (void)arg;
+
+ accu += brightness;
+ if (accu < 100) {
+ led_off();
+ } else {
+ led_on();
+ accu -= 100;
+ }
+
+ ucg_callout_reschedule(cm, tim, 1);
+}
+
+/* every 50 ms, change increase or decrease the brightness from 0 to 100 */
+static void led_update_brightness_cb(struct ucg_callout_mgr *cm,
+ struct ucg_callout *tim, void *arg)
+{
+ (void)arg;
+
+ brightness += brightness_inc;
+ if (brightness == 0)
+ brightness_inc = 1;
+ else if (brightness == 100)
+ brightness_inc = -1;
+
+ ucg_callout_reschedule(cm, tim, 10);
+}
+
+/* every second, sleep during 100ms */
+static void sleep_cb(struct ucg_callout_mgr *cm,
+ struct ucg_callout *tim, void *arg)
+{
+ (void)arg;
+
+ ucg_delay_ms(200);
+ ucg_callout_reschedule(cm, tim, 300);
+}
+
+int main(void)
+{
+ struct ucg_callout_mgr intr_cm;
+ struct ucg_callout_mgr loop_cm;
+ struct ucg_callout br_timer;
+ struct ucg_callout led_timer;
+ struct ucg_callout sleep_timer;
+ int i;
+
+ target_init();
+
+ /* toggle the pin before starting */
+ for (i = 0; i < 3; i++) {
+ ucg_delay_ms(500);
+ ucg_delay_ms(500);
+ }
+
+ /* init loop callout manager */
+ ucg_callout_mgr_init(&loop_cm, get_time_ms);
+
+ /* load a timer in the loop cmgr that will update the brightness */
+ ucg_callout_init(&br_timer, led_update_brightness_cb, NULL, 128);
+ ucg_callout_schedule(&loop_cm, &br_timer, 0);
+
+ /* init intr callout manager */
+ ucg_callout_mgr_init(&intr_cm, get_time_ms);
+ ucg_irq_lock();
+ p_intr_cm = &intr_cm;
+ ucg_irq_unlock();
+
+ /* load a timer in the intr cmgr that control led on/off */
+ ucg_callout_init(&led_timer, led_control_cb, NULL, 128);
+ ucg_callout_schedule(&intr_cm, &led_timer, 0);
+
+ /* load a lower prio timer in the intr cmgr that just sleeps */
+ ucg_callout_init(&sleep_timer, sleep_cb, NULL, 100);
+ ucg_callout_schedule(&intr_cm, &sleep_timer, 0);
+
+ while (1) {
+ ucg_callout_manage(&loop_cm);
+ }
+
+ while (1);
+ return 0;
+}
--- /dev/null
+/*
+*****************************************************************************
+**
+** File : stm32_flash.ld
+**
+** Abstract : Linker script for STM32F407VG Device with
+** 1024KByte FLASH, 192KByte RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Environment : Atollic TrueSTUDIO(R)
+**
+** Distribution: The file is distributed \93as is,\94 without any warranty
+** of any kind.
+**
+** (c)Copyright Atollic AB.
+** You may use this file as-is or modify it according to the needs of your
+** project. Distribution of this file (unmodified or modified) is not
+** permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the
+** rights to distribute the assembled, compiled & linked contents of this
+** file as part of an application binary file, provided that it is built
+** using the Atollic TrueSTUDIO(R) toolchain.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20020000; /* end of 128K RAM on AHB bus*/
+
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
+ MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ _exit = .;
+ } >FLASH
+
+
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >FLASH
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >FLASH
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array*))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = .;
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ PROVIDE ( __end__ = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(4);
+ } >RAM
+
+ /* MEMORY_bank1 section, code must be located here explicitly */
+ /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
+ .memory_b1_text :
+ {
+ *(.mb1text) /* .mb1text sections (code) */
+ *(.mb1text*) /* .mb1text* sections (code) */
+ *(.mb1rodata) /* read-only data (constants) */
+ *(.mb1rodata*)
+ } >MEMORY_B1
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
--- /dev/null
+/**
+ ******************************************************************************
+ * @file stm32f4xx_conf.h
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 19-September-2011
+ * @brief Library configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_CONF_H
+#define __STM32F4xx_CONF_H
+
+#if defined (HSE_VALUE)
+/* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */
+ #undef HSE_VALUE
+ #define HSE_VALUE ((uint32_t)8000000)
+#endif /* HSE_VALUE */
+
+/* Includes ------------------------------------------------------------------*/
+/* Uncomment the line below to enable peripheral header file inclusion */
+#include "stm32f4xx_adc.h"
+#include "stm32f4xx_can.h"
+#include "stm32f4xx_crc.h"
+#include "stm32f4xx_cryp.h"
+#include "stm32f4xx_dac.h"
+#include "stm32f4xx_dbgmcu.h"
+#include "stm32f4xx_dcmi.h"
+#include "stm32f4xx_dma.h"
+#include "stm32f4xx_exti.h"
+#include "stm32f4xx_flash.h"
+#include "stm32f4xx_fsmc.h"
+#include "stm32f4xx_hash.h"
+#include "stm32f4xx_gpio.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx_iwdg.h"
+#include "stm32f4xx_pwr.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_rng.h"
+#include "stm32f4xx_rtc.h"
+#include "stm32f4xx_sdio.h"
+#include "stm32f4xx_spi.h"
+#include "stm32f4xx_syscfg.h"
+#include "stm32f4xx_tim.h"
+#include "stm32f4xx_usart.h"
+#include "stm32f4xx_wwdg.h"
+#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* If an external clock source is used, then the value of the following define
+ should be set to the value of the external clock source, else, if no external
+ clock is used, keep this define commented */
+/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
+
+
+/* Uncomment the line below to expanse the "assert_param" macro in the
+ Standard Peripheral Library drivers code */
+/* #define USE_FULL_ASSERT 1 */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#endif /* __STM32F4xx_CONF_H */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+/**
+ ******************************************************************************
+ * @file system_stm32f4xx.c
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 30-September-2011
+ * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+ * This file contains the system clock configuration for STM32F4xx devices,
+ * and is generated by the clock configuration tool
+ * stm32f4xx_Clock_Configuration_V1.0.0.xls
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
+ * and Divider factors, AHB/APBx prescalers and Flash settings),
+ * depending on the configuration made in the clock xls tool.
+ * This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f4xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (16 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. If the system clock source selected by user fails to startup, the SystemInit()
+ * function will do nothing and HSI still used as system clock source. User can
+ * add some code to deal with this issue inside the SetSysClock() function.
+ *
+ * 4. The default value of HSE crystal is set to 25MHz, refer to "HSE_VALUE" define
+ * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or
+ * through PLL, and you are using different crystal you have to adapt the HSE
+ * value to your own configuration.
+ *
+ * 5. This file configures the system clock as follows:
+ *=============================================================================
+ *=============================================================================
+ * Supported STM32F4xx device revision | Rev A
+ *-----------------------------------------------------------------------------
+ * System Clock source | PLL (HSE)
+ *-----------------------------------------------------------------------------
+ * SYSCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * HCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * AHB Prescaler | 1
+ *-----------------------------------------------------------------------------
+ * APB1 Prescaler | 4
+ *-----------------------------------------------------------------------------
+ * APB2 Prescaler | 2
+ *-----------------------------------------------------------------------------
+ * HSE Frequency(Hz) | 25000000
+ *-----------------------------------------------------------------------------
+ * PLL_M | 25
+ *-----------------------------------------------------------------------------
+ * PLL_N | 336
+ *-----------------------------------------------------------------------------
+ * PLL_P | 2
+ *-----------------------------------------------------------------------------
+ * PLL_Q | 7
+ *-----------------------------------------------------------------------------
+ * PLLI2S_N | NA
+ *-----------------------------------------------------------------------------
+ * PLLI2S_R | NA
+ *-----------------------------------------------------------------------------
+ * I2S input clock | NA
+ *-----------------------------------------------------------------------------
+ * VDD(V) | 3.3
+ *-----------------------------------------------------------------------------
+ * Main regulator output voltage | Scale1 mode
+ *-----------------------------------------------------------------------------
+ * Flash Latency(WS) | 5
+ *-----------------------------------------------------------------------------
+ * Prefetch Buffer | OFF
+ *-----------------------------------------------------------------------------
+ * Instruction cache | ON
+ *-----------------------------------------------------------------------------
+ * Data cache | ON
+ *-----------------------------------------------------------------------------
+ * Require 48MHz for USB OTG FS, | Enabled
+ * SDIO and RNG clock |
+ *-----------------------------------------------------------------------------
+ *=============================================================================
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f4xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f4xx.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+ * @{
+ */
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to use external SRAM mounted
+ on STM324xG_EVAL board as data memory */
+/* #define DATA_IN_ExtSRAM */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/************************* PLL Parameters *************************************/
+/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
+#define PLL_M 25
+#define PLL_N 336
+
+/* SYSCLK = PLL_VCO / PLL_P */
+#define PLL_P 2
+
+/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
+#define PLL_Q 7
+
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+ * @{
+ */
+
+ uint32_t SystemCoreClock = 168000000;
+
+ __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+static void SetSysClock(void);
+#ifdef DATA_IN_ExtSRAM
+ static void SystemInit_ExtMemCtl(void);
+#endif /* DATA_IN_ExtSRAM */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the Embedded Flash Interface, the PLL and update the
+ * SystemFrequency variable.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000;
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFF;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x24003010;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000;
+
+#ifdef DATA_IN_ExtSRAM
+ SystemInit_ExtMemCtl();
+#endif /* DATA_IN_ExtSRAM */
+
+ /* Configure the System clock source, PLL Multiplier and Divider factors,
+ AHB/APBx prescalers and Flash settings ----------------------------------*/
+ SetSysClock();
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 16 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 25 MHz), user has to ensure that HSE_VALUE is same as the real
+ * frequency of the crystal used. Otherwise, this function may
+ * have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate(void)
+{
+ uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case 0x00: /* HSI used as system clock source */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04: /* HSE used as system clock source */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08: /* PLL used as system clock source */
+
+ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+ SYSCLK = PLL_VCO / PLL_P
+ */
+ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+ pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+
+ if (pllsource != 0)
+ {
+ /* HSE used as PLL clock source */
+ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+ else
+ {
+ /* HSI used as PLL clock source */
+ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+
+ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+ SystemCoreClock = pllvco/pllp;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK frequency --------------------------------------------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @brief Configures the System clock source, PLL Multiplier and Divider factors,
+ * AHB/APBx prescalers and Flash settings
+ * @Note This function should be called only once the RCC clock configuration
+ * is reset to the default reset state (done in SystemInit() function).
+ * @param None
+ * @retval None
+ */
+static void SetSysClock(void)
+{
+/******************************************************************************/
+/* PLL (clocked by HSE) used as System clock source */
+/******************************************************************************/
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+ /* Enable HSE */
+ RCC->CR |= ((uint32_t)RCC_CR_HSEON);
+
+ /* Wait till HSE is ready and if Time out is reached exit */
+ do
+ {
+ HSEStatus = RCC->CR & RCC_CR_HSERDY;
+ StartUpCounter++;
+ } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+ if ((RCC->CR & RCC_CR_HSERDY) != RESET)
+ {
+ HSEStatus = (uint32_t)0x01;
+ }
+ else
+ {
+ HSEStatus = (uint32_t)0x00;
+ }
+
+ if (HSEStatus == (uint32_t)0x01)
+ {
+ /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
+ RCC->APB1ENR |= RCC_APB1ENR_PWREN;
+ PWR->CR |= PWR_CR_VOS;
+
+ /* HCLK = SYSCLK / 1*/
+ RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
+
+ /* PCLK2 = HCLK / 2*/
+ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
+
+ /* PCLK1 = HCLK / 4*/
+ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
+
+ /* Configure the main PLL */
+ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
+ (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
+
+ /* Enable the main PLL */
+ RCC->CR |= RCC_CR_PLLON;
+
+ /* Wait till the main PLL is ready */
+ while((RCC->CR & RCC_CR_PLLRDY) == 0)
+ {
+ }
+
+ /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
+ FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
+
+ /* Select the main PLL as system clock source */
+ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
+ RCC->CFGR |= RCC_CFGR_SW_PLL;
+
+ /* Wait till the main PLL is used as system clock source */
+ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
+ {
+ }
+ }
+ else
+ { /* If HSE fails to start-up, the application will have wrong clock
+ configuration. User can add here some code to deal with this error */
+ }
+
+}
+
+/**
+ * @brief Setup the external memory controller. Called in startup_stm32f4xx.s
+ * before jump to __main
+ * @param None
+ * @retval None
+ */
+#ifdef DATA_IN_ExtSRAM
+/**
+ * @brief Setup the external memory controller.
+ * Called in startup_stm32f4xx.s before jump to main.
+ * This function configures the external SRAM mounted on STM324xG_EVAL board
+ * This SRAM will be used as program data memory (including heap and stack).
+ * @param None
+ * @retval None
+ */
+void SystemInit_ExtMemCtl(void)
+{
+/*-- GPIOs Configuration -----------------------------------------------------*/
+/*
+ +-------------------+--------------------+------------------+------------------+
+ + SRAM pins assignment +
+ +-------------------+--------------------+------------------+------------------+
+ | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 |
+ | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 |
+ | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 |
+ | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 |
+ | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 |
+ | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 |
+ | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 |
+ | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+
+ | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 |
+ | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 |
+ | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+
+ | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 |
+ | | PE15 <-> FSMC_D12 |
+ +-------------------+--------------------+
+*/
+ /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
+ RCC->AHB1ENR = 0x00000078;
+
+ /* Connect PDx pins to FSMC Alternate function */
+ GPIOD->AFR[0] = 0x00cc00cc;
+ GPIOD->AFR[1] = 0xcc0ccccc;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xaaaa0a0a;
+ /* Configure PDx pins speed to 100 MHz */
+ GPIOD->OSPEEDR = 0xffff0f0f;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FSMC Alternate function */
+ GPIOE->AFR[0] = 0xc00cc0cc;
+ GPIOE->AFR[1] = 0xcccccccc;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xaaaa828a;
+ /* Configure PEx pins speed to 100 MHz */
+ GPIOE->OSPEEDR = 0xffffc3cf;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FSMC Alternate function */
+ GPIOF->AFR[0] = 0x00cccccc;
+ GPIOF->AFR[1] = 0xcccc0000;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xaa000aaa;
+ /* Configure PFx pins speed to 100 MHz */
+ GPIOF->OSPEEDR = 0xff000fff;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FSMC Alternate function */
+ GPIOG->AFR[0] = 0x00cccccc;
+ GPIOG->AFR[1] = 0x000000c0;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0x00080aaa;
+ /* Configure PGx pins speed to 100 MHz */
+ GPIOG->OSPEEDR = 0x000c0fff;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+/*-- FSMC Configuration ------------------------------------------------------*/
+ /* Enable the FSMC interface clock */
+ RCC->AHB3ENR = 0x00000001;
+
+ /* Configure and enable Bank1_SRAM2 */
+ FSMC_Bank1->BTCR[2] = 0x00001015;
+ FSMC_Bank1->BTCR[3] = 0x00010603;
+ FSMC_Bank1E->BWTR[2] = 0x0fffffff;
+/*
+ Bank1_SRAM2 is configured as follow:
+
+ p.FSMC_AddressSetupTime = 3;
+ p.FSMC_AddressHoldTime = 0;
+ p.FSMC_DataSetupTime = 6;
+ p.FSMC_BusTurnAroundDuration = 1;
+ p.FSMC_CLKDivision = 0;
+ p.FSMC_DataLatency = 0;
+ p.FSMC_AccessMode = FSMC_AccessMode_A;
+
+ FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;
+ FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
+ FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
+ FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
+ FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
+ FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
+*/
+
+}
+#endif /* DATA_IN_ExtSRAM */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ../..)
+include $(UCGINE)/mk/ucgine-pre.mk
+
+O ?= $(CURDIR)/build
+PROG = $(O)/test-cmd
+
+CFLAGS += $(ARCH_CFLAGS)
+CFLAGS += -g -Werror -I.
+
+LDFLAGS += $(ARCH_LDFLAGS)
+
+# local files
+exe-y-$(PROG) := main.c commands.c uart.c
+
+ifeq ($(UCGINE_ARCH),avr)
+MCU = atmega328p
+F_CPU = 8000000UL
+AVRDUDE_PORT = /dev/ttyUSB0
+AVRDUDE_PROG = arduino
+AVRDUDE_BAUD = 57600
+CFLAGS += -DF_CPU=$(F_CPU)
+CFLAGS += -I$(UCGINE)/arch/avr/uart/include
+CFLAGS += -mmcu=$(MCU)
+CFLAGS += -DUCG_CMD_NO_PAGER
+LDFLAGS += -mmcu=$(MCU)
+# uart
+exe-y-$(PROG) += $(UCGINE)/arch/avr/uart/ucg_avr_uart.c
+endif
+ifeq ($(UCGINE_ARCH),stm32)
+STLINK ?= /home/zer0/projects/stm32/stlink
+STM_COMMON ?= /home/zer0/projects/stm32/stm32_discovery_arm_gcc/STM32F4-Discovery_FW_V1.1.0
+CFLAGS += -Tstm32_flash.ld
+CFLAGS += -I$(STM_COMMON)/Utilities/STM32F4-Discovery
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/inc
+CFLAGS += -I$(UCGINE)/lib/gloss/include
+CFLAGS += -I$(UCGINE)/arch/stm32/include
+CFLAGS += -I$(UCGINE)/arch/stm32/uart/include
+LDFLAGS += -Tstm32_flash.ld
+exe-y-$(PROG) += system_stm32f4xx.c
+# stm32 standard periph lib
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c
+# startup file
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s
+# gloss
+exe-y-$(PROG) += $(UCGINE)/lib/gloss/ucg_gloss_stubs.c
+exe-y-$(PROG) += $(UCGINE)/lib/gloss/ucg_gloss_chardev.c
+# uart
+exe-y-$(PROG) += $(UCGINE)/arch/stm32/uart/ucg_stm32_uart.c
+endif
+ifeq ($(UCGINE_ARCH),posix)
+CFLAGS += -DUCG_CMD_HAVE_SOCKET -DUCG_CMD_HAVE_TERMIOS
+endif
+
+# cirbuf
+CFLAGS += -I$(UCGINE)/lib/cirbuf/include
+exe-y-$(PROG) += $(UCGINE)/lib/cirbuf/ucg_cirbuf.c
+# uart
+CFLAGS += -I$(UCGINE)/lib/uart/include
+exe-y-$(PROG) += $(UCGINE)/lib/uart/ucg_uart.c
+# cmd
+CFLAGS += -I$(UCGINE)/lib/cmd/include
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_parse.c
+ifeq ($(CROSS),)
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_parse_etheraddr.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_parse_file.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_parse_ipaddr.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_socket.c
+endif
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_termios.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_parse_num.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_parse_string.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_rdline.c
+exe-y-$(PROG) += $(UCGINE)/lib/cmd/ucg_cmd_vt100.c
+
+objcopy-hex-y-$(PROG).hex := $(PROG)
+objcopy-bin-y-$(PROG).bin := $(PROG)
+
+# XXX where to define the all target?
+include $(UCGINE)/mk/ucgine-post.mk
+
+.PHONY: all
+all: $(all-targets)
+ $(CROSS)size $(PROG)
+
+.PHONY: clean
+clean: _ucgine_clean
+
+.PHONY: burn
+burn: all
+ifeq ($(UCGINE_ARCH),stm32)
+ $(STLINK)/st-flash write $(PROG).bin 0x8000000
+endif
+ifeq ($(UCGINE_ARCH),avr)
+ avrdude -e -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROG) \
+ -b $(AVRDUDE_BAUD) -U flash:w:$(PROG):e
+endif
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <ucg_cmd_parse.h>
+#include <ucg_cmd_parse_num.h>
+#include <ucg_cmd_parse_string.h>
+#include <ucg_cmd.h>
+
+/**********************************************************/
+
+struct cmd_hello_result {
+ ucg_cmd_fixed_string_t hello;
+ ucg_cmd_fixed_string_t name;
+};
+
+static void cmd_hello_parsed(void *parsed_result,
+ struct ucg_cmd *cl, void *data)
+{
+ struct cmd_hello_result *res = parsed_result;
+
+ (void)data;
+ ucg_cmd_printf(cl, "hello %s\n", res->name);
+}
+
+static ucg_cmd_tk_string_t cmd_hello_hello =
+ UCG_CMD_TK_STRING(struct cmd_hello_result, hello, "hello");
+
+static ucg_cmd_tk_string_t cmd_hello_name =
+ UCG_CMD_TK_STRING(struct cmd_hello_result, name, NULL);
+
+static ucg_cmd_inst_t cmd_hello = {
+ .f = cmd_hello_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "Say hello",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_hello_hello,
+ (void *)&cmd_hello_name,
+ NULL,
+ },
+};
+
+/**********************************************************/
+
+struct cmd_hello_tutu_result {
+ ucg_cmd_fixed_string_t hello;
+ ucg_cmd_fixed_string_t name1;
+ ucg_cmd_fixed_string_t name2;
+};
+
+static void cmd_hello_tutu_parsed(void *parsed_result,
+ struct ucg_cmd *cl, void *data)
+{
+ struct cmd_hello_tutu_result *res = parsed_result;
+
+ (void)data;
+ ucg_cmd_printf(cl, "hello %s and %s\n", res->name1, res->name2);
+}
+
+static ucg_cmd_tk_string_t cmd_hello_tutu_hello =
+ UCG_CMD_TK_STRING(struct cmd_hello_tutu_result, hello, "hello");
+
+static ucg_cmd_tk_string_t cmd_hello_tutu_name1 =
+ UCG_CMD_TK_STRING(struct cmd_hello_tutu_result, name1, "tutu");
+
+static ucg_cmd_tk_string_t cmd_hello_tutu_name2 =
+ UCG_CMD_TK_STRING(struct cmd_hello_tutu_result, name2, NULL);
+
+static ucg_cmd_inst_t cmd_hello_tutu = {
+ .f = cmd_hello_tutu_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "Say hello to tutu and someone else",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_hello_tutu_hello,
+ (void *)&cmd_hello_tutu_name1,
+ (void *)&cmd_hello_tutu_name2,
+ NULL,
+ },
+};
+
+/**********************************************************/
+
+struct cmd_hello_toto_result {
+ ucg_cmd_fixed_string_t hello;
+ ucg_cmd_fixed_string_t name;
+ uint16_t count;
+};
+
+static void cmd_hello_toto_parsed(void *parsed_result,
+ struct ucg_cmd *cl, void *data)
+{
+ uint16_t i;
+ struct cmd_hello_toto_result *res = parsed_result;
+
+ (void)data;
+ for (i = 0; i < res->count; i++)
+ ucg_cmd_printf(cl, "hello %s\n", res->name);
+}
+
+static ucg_cmd_tk_string_t cmd_hello_toto_hello =
+ UCG_CMD_TK_STRING(struct cmd_hello_toto_result, hello, "hello");
+
+static ucg_cmd_tk_string_t cmd_hello_toto_name =
+ UCG_CMD_TK_STRING(struct cmd_hello_toto_result, name, "toto#titi");
+
+static ucg_cmd_tk_num_t cmd_hello_toto_count =
+ UCG_CMD_TK_NUM(struct cmd_hello_toto_result, count, UINT16);
+
+static ucg_cmd_inst_t cmd_hello_toto = {
+ .f = cmd_hello_toto_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "Say hello to toto or titi several times",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_hello_toto_hello,
+ (void *)&cmd_hello_toto_name,
+ (void *)&cmd_hello_toto_count,
+ NULL,
+ },
+};
+
+/****** CONTEXT (list of instruction) */
+
+ucg_cmd_ctx_t main_ctx = {
+ .name = "main",
+ .insts = {
+ &cmd_hello,
+ &cmd_hello_tutu,
+ &cmd_hello_toto,
+ NULL,
+ },
+};
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef COMMANDS_H_
+#define COMMANDS_H_
+
+#include <ucg_cmd_parse.h>
+
+extern ucg_cmd_ctx_t main_ctx;
+
+#endif /* COMMANDS_H_ */
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include <ucg_irq.h>
+#include <ucg_delay.h>
+
+#include <ucg_cmd.h>
+#include <ucg_cmd_termios.h>
+
+#include "commands.h"
+
+#include "uart.h"
+
+#if defined(__ARM_EABI__)
+#include <stm32f4xx.h>
+
+static void led_on(void)
+{
+ GPIOD->ODR |= (1 << 13);
+}
+
+static void led_off(void)
+{
+ GPIOD->ODR &= (~(1 << 13));
+}
+
+static void target_init(void)
+{
+ /* enable the clock to GPIOD, and stall instruction pipeline as per
+ * errata 2.1.13 "Delay after an RCC peripheral clock enabling" */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+ __asm("dsb");
+
+ /* set pin 13 to be general purpose output */
+ GPIOD->MODER = (1 << 26);
+}
+#elif defined(__AVR__)
+#include <avr/io.h>
+
+static void led_on(void)
+{
+ PORTB |= (1 << 5);
+}
+
+static void led_off(void)
+{
+ PORTB &= (~(1 << 5));
+}
+
+static void target_init(void)
+{
+ DDRB = (1 << 5);
+}
+#else
+static void led_on(void)
+{
+ printf("led on\n");
+}
+
+static void led_off(void)
+{
+ printf("led off\n");
+}
+
+static void target_init(void)
+{
+}
+#endif
+
+int main(void)
+{
+ unsigned i;
+ struct ucg_cmd cl;
+ const char *prompt = "\033[32mtest> \033[0m";
+ unsigned cl_flags = 0;
+
+ target_init();
+
+ /* toggle the pin */
+ for (i = 0; i < 3; i++) {
+ led_on();
+ ucg_delay_ms(500);
+ led_off();
+ ucg_delay_ms(500);
+ }
+
+ uart_init();
+ ucg_irq_unlock();
+ printf("hello\n");
+ ucg_delay_ms(500);
+
+#if defined( __AVR__) || defined(__ARM_EABI__)
+ cl_flags = UCG_CMD_F_IGNORE_EOF;
+#endif
+ ucg_cmd_init(&cl, &main_ctx, prompt, stdin, stdout);
+ if (ucg_cmd_termios_raw(&cl) < 0) {
+ printf("cannot set termios in raw mode\n");
+ return 1;
+ }
+
+ ucg_cmd_interact(&cl, cl_flags);
+ ucg_cmd_termios_restore(&cl);
+
+ return 0;
+}
--- /dev/null
+/*
+*****************************************************************************
+**
+** File : stm32_flash.ld
+**
+** Abstract : Linker script for STM32F407VG Device with
+** 1024KByte FLASH, 192KByte RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Environment : Atollic TrueSTUDIO(R)
+**
+** Distribution: The file is distributed \93as is,\94 without any warranty
+** of any kind.
+**
+** (c)Copyright Atollic AB.
+** You may use this file as-is or modify it according to the needs of your
+** project. Distribution of this file (unmodified or modified) is not
+** permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the
+** rights to distribute the assembled, compiled & linked contents of this
+** file as part of an application binary file, provided that it is built
+** using the Atollic TrueSTUDIO(R) toolchain.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20020000; /* end of 128K RAM on AHB bus*/
+
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
+ MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ _exit = .;
+ } >FLASH
+
+
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >FLASH
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >FLASH
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array*))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = .;
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ PROVIDE ( __end__ = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(4);
+ } >RAM
+
+ /* MEMORY_bank1 section, code must be located here explicitly */
+ /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
+ .memory_b1_text :
+ {
+ *(.mb1text) /* .mb1text sections (code) */
+ *(.mb1text*) /* .mb1text* sections (code) */
+ *(.mb1rodata) /* read-only data (constants) */
+ *(.mb1rodata*)
+ } >MEMORY_B1
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
--- /dev/null
+/**
+ ******************************************************************************
+ * @file stm32f4xx_conf.h
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 19-September-2011
+ * @brief Library configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_CONF_H
+#define __STM32F4xx_CONF_H
+
+#if defined (HSE_VALUE)
+/* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */
+ #undef HSE_VALUE
+ #define HSE_VALUE ((uint32_t)8000000)
+#endif /* HSE_VALUE */
+
+/* Includes ------------------------------------------------------------------*/
+/* Uncomment the line below to enable peripheral header file inclusion */
+#include "stm32f4xx_adc.h"
+#include "stm32f4xx_can.h"
+#include "stm32f4xx_crc.h"
+#include "stm32f4xx_cryp.h"
+#include "stm32f4xx_dac.h"
+#include "stm32f4xx_dbgmcu.h"
+#include "stm32f4xx_dcmi.h"
+#include "stm32f4xx_dma.h"
+#include "stm32f4xx_exti.h"
+#include "stm32f4xx_flash.h"
+#include "stm32f4xx_fsmc.h"
+#include "stm32f4xx_hash.h"
+#include "stm32f4xx_gpio.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx_iwdg.h"
+#include "stm32f4xx_pwr.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_rng.h"
+#include "stm32f4xx_rtc.h"
+#include "stm32f4xx_sdio.h"
+#include "stm32f4xx_spi.h"
+#include "stm32f4xx_syscfg.h"
+#include "stm32f4xx_tim.h"
+#include "stm32f4xx_usart.h"
+#include "stm32f4xx_wwdg.h"
+#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* If an external clock source is used, then the value of the following define
+ should be set to the value of the external clock source, else, if no external
+ clock is used, keep this define commented */
+/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
+
+
+/* Uncomment the line below to expanse the "assert_param" macro in the
+ Standard Peripheral Library drivers code */
+/* #define USE_FULL_ASSERT 1 */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#endif /* __STM32F4xx_CONF_H */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+/**
+ ******************************************************************************
+ * @file system_stm32f4xx.c
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 30-September-2011
+ * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+ * This file contains the system clock configuration for STM32F4xx devices,
+ * and is generated by the clock configuration tool
+ * stm32f4xx_Clock_Configuration_V1.0.0.xls
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
+ * and Divider factors, AHB/APBx prescalers and Flash settings),
+ * depending on the configuration made in the clock xls tool.
+ * This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f4xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (16 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. If the system clock source selected by user fails to startup, the SystemInit()
+ * function will do nothing and HSI still used as system clock source. User can
+ * add some code to deal with this issue inside the SetSysClock() function.
+ *
+ * 4. The default value of HSE crystal is set to 25MHz, refer to "HSE_VALUE" define
+ * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or
+ * through PLL, and you are using different crystal you have to adapt the HSE
+ * value to your own configuration.
+ *
+ * 5. This file configures the system clock as follows:
+ *=============================================================================
+ *=============================================================================
+ * Supported STM32F4xx device revision | Rev A
+ *-----------------------------------------------------------------------------
+ * System Clock source | PLL (HSE)
+ *-----------------------------------------------------------------------------
+ * SYSCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * HCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * AHB Prescaler | 1
+ *-----------------------------------------------------------------------------
+ * APB1 Prescaler | 4
+ *-----------------------------------------------------------------------------
+ * APB2 Prescaler | 2
+ *-----------------------------------------------------------------------------
+ * HSE Frequency(Hz) | 25000000
+ *-----------------------------------------------------------------------------
+ * PLL_M | 25
+ *-----------------------------------------------------------------------------
+ * PLL_N | 336
+ *-----------------------------------------------------------------------------
+ * PLL_P | 2
+ *-----------------------------------------------------------------------------
+ * PLL_Q | 7
+ *-----------------------------------------------------------------------------
+ * PLLI2S_N | NA
+ *-----------------------------------------------------------------------------
+ * PLLI2S_R | NA
+ *-----------------------------------------------------------------------------
+ * I2S input clock | NA
+ *-----------------------------------------------------------------------------
+ * VDD(V) | 3.3
+ *-----------------------------------------------------------------------------
+ * Main regulator output voltage | Scale1 mode
+ *-----------------------------------------------------------------------------
+ * Flash Latency(WS) | 5
+ *-----------------------------------------------------------------------------
+ * Prefetch Buffer | OFF
+ *-----------------------------------------------------------------------------
+ * Instruction cache | ON
+ *-----------------------------------------------------------------------------
+ * Data cache | ON
+ *-----------------------------------------------------------------------------
+ * Require 48MHz for USB OTG FS, | Enabled
+ * SDIO and RNG clock |
+ *-----------------------------------------------------------------------------
+ *=============================================================================
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f4xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f4xx.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+ * @{
+ */
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to use external SRAM mounted
+ on STM324xG_EVAL board as data memory */
+/* #define DATA_IN_ExtSRAM */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/************************* PLL Parameters *************************************/
+/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
+#define PLL_M 25
+#define PLL_N 336
+
+/* SYSCLK = PLL_VCO / PLL_P */
+#define PLL_P 2
+
+/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
+#define PLL_Q 7
+
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+ * @{
+ */
+
+ uint32_t SystemCoreClock = 168000000;
+
+ __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+static void SetSysClock(void);
+#ifdef DATA_IN_ExtSRAM
+ static void SystemInit_ExtMemCtl(void);
+#endif /* DATA_IN_ExtSRAM */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the Embedded Flash Interface, the PLL and update the
+ * SystemFrequency variable.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000;
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFF;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x24003010;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000;
+
+#ifdef DATA_IN_ExtSRAM
+ SystemInit_ExtMemCtl();
+#endif /* DATA_IN_ExtSRAM */
+
+ /* Configure the System clock source, PLL Multiplier and Divider factors,
+ AHB/APBx prescalers and Flash settings ----------------------------------*/
+ SetSysClock();
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 16 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 25 MHz), user has to ensure that HSE_VALUE is same as the real
+ * frequency of the crystal used. Otherwise, this function may
+ * have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate(void)
+{
+ uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case 0x00: /* HSI used as system clock source */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04: /* HSE used as system clock source */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08: /* PLL used as system clock source */
+
+ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+ SYSCLK = PLL_VCO / PLL_P
+ */
+ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+ pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+
+ if (pllsource != 0)
+ {
+ /* HSE used as PLL clock source */
+ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+ else
+ {
+ /* HSI used as PLL clock source */
+ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+
+ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+ SystemCoreClock = pllvco/pllp;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK frequency --------------------------------------------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @brief Configures the System clock source, PLL Multiplier and Divider factors,
+ * AHB/APBx prescalers and Flash settings
+ * @Note This function should be called only once the RCC clock configuration
+ * is reset to the default reset state (done in SystemInit() function).
+ * @param None
+ * @retval None
+ */
+static void SetSysClock(void)
+{
+/******************************************************************************/
+/* PLL (clocked by HSE) used as System clock source */
+/******************************************************************************/
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+ /* Enable HSE */
+ RCC->CR |= ((uint32_t)RCC_CR_HSEON);
+
+ /* Wait till HSE is ready and if Time out is reached exit */
+ do
+ {
+ HSEStatus = RCC->CR & RCC_CR_HSERDY;
+ StartUpCounter++;
+ } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+ if ((RCC->CR & RCC_CR_HSERDY) != RESET)
+ {
+ HSEStatus = (uint32_t)0x01;
+ }
+ else
+ {
+ HSEStatus = (uint32_t)0x00;
+ }
+
+ if (HSEStatus == (uint32_t)0x01)
+ {
+ /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
+ RCC->APB1ENR |= RCC_APB1ENR_PWREN;
+ PWR->CR |= PWR_CR_VOS;
+
+ /* HCLK = SYSCLK / 1*/
+ RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
+
+ /* PCLK2 = HCLK / 2*/
+ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
+
+ /* PCLK1 = HCLK / 4*/
+ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
+
+ /* Configure the main PLL */
+ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
+ (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
+
+ /* Enable the main PLL */
+ RCC->CR |= RCC_CR_PLLON;
+
+ /* Wait till the main PLL is ready */
+ while((RCC->CR & RCC_CR_PLLRDY) == 0)
+ {
+ }
+
+ /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
+ FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
+
+ /* Select the main PLL as system clock source */
+ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
+ RCC->CFGR |= RCC_CFGR_SW_PLL;
+
+ /* Wait till the main PLL is used as system clock source */
+ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
+ {
+ }
+ }
+ else
+ { /* If HSE fails to start-up, the application will have wrong clock
+ configuration. User can add here some code to deal with this error */
+ }
+
+}
+
+/**
+ * @brief Setup the external memory controller. Called in startup_stm32f4xx.s
+ * before jump to __main
+ * @param None
+ * @retval None
+ */
+#ifdef DATA_IN_ExtSRAM
+/**
+ * @brief Setup the external memory controller.
+ * Called in startup_stm32f4xx.s before jump to main.
+ * This function configures the external SRAM mounted on STM324xG_EVAL board
+ * This SRAM will be used as program data memory (including heap and stack).
+ * @param None
+ * @retval None
+ */
+void SystemInit_ExtMemCtl(void)
+{
+/*-- GPIOs Configuration -----------------------------------------------------*/
+/*
+ +-------------------+--------------------+------------------+------------------+
+ + SRAM pins assignment +
+ +-------------------+--------------------+------------------+------------------+
+ | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 |
+ | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 |
+ | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 |
+ | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 |
+ | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 |
+ | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 |
+ | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 |
+ | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+
+ | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 |
+ | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 |
+ | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+
+ | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 |
+ | | PE15 <-> FSMC_D12 |
+ +-------------------+--------------------+
+*/
+ /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
+ RCC->AHB1ENR = 0x00000078;
+
+ /* Connect PDx pins to FSMC Alternate function */
+ GPIOD->AFR[0] = 0x00cc00cc;
+ GPIOD->AFR[1] = 0xcc0ccccc;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xaaaa0a0a;
+ /* Configure PDx pins speed to 100 MHz */
+ GPIOD->OSPEEDR = 0xffff0f0f;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FSMC Alternate function */
+ GPIOE->AFR[0] = 0xc00cc0cc;
+ GPIOE->AFR[1] = 0xcccccccc;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xaaaa828a;
+ /* Configure PEx pins speed to 100 MHz */
+ GPIOE->OSPEEDR = 0xffffc3cf;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FSMC Alternate function */
+ GPIOF->AFR[0] = 0x00cccccc;
+ GPIOF->AFR[1] = 0xcccc0000;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xaa000aaa;
+ /* Configure PFx pins speed to 100 MHz */
+ GPIOF->OSPEEDR = 0xff000fff;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FSMC Alternate function */
+ GPIOG->AFR[0] = 0x00cccccc;
+ GPIOG->AFR[1] = 0x000000c0;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0x00080aaa;
+ /* Configure PGx pins speed to 100 MHz */
+ GPIOG->OSPEEDR = 0x000c0fff;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+/*-- FSMC Configuration ------------------------------------------------------*/
+ /* Enable the FSMC interface clock */
+ RCC->AHB3ENR = 0x00000001;
+
+ /* Configure and enable Bank1_SRAM2 */
+ FSMC_Bank1->BTCR[2] = 0x00001015;
+ FSMC_Bank1->BTCR[3] = 0x00010603;
+ FSMC_Bank1E->BWTR[2] = 0x0fffffff;
+/*
+ Bank1_SRAM2 is configured as follow:
+
+ p.FSMC_AddressSetupTime = 3;
+ p.FSMC_AddressHoldTime = 0;
+ p.FSMC_DataSetupTime = 6;
+ p.FSMC_BusTurnAroundDuration = 1;
+ p.FSMC_CLKDivision = 0;
+ p.FSMC_DataLatency = 0;
+ p.FSMC_AccessMode = FSMC_AccessMode_A;
+
+ FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;
+ FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
+ FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
+ FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
+ FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
+ FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
+*/
+
+}
+#endif /* DATA_IN_ExtSRAM */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__ARM_EABI__)
+#include "stm32f4xx.h"
+#elif defined(__AVR__)
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <ucg_irq.h>
+#include <ucg_cirbuf.h>
+#include <ucg_uart.h>
+
+#include "uart.h"
+
+#if defined(__ARM_EABI__) || defined(__AVR__)
+/* rx & tx buffers */
+static char rx_buf[64];
+static struct ucg_cirbuf rx_cirbuf;
+static char tx_buf[64];
+static struct ucg_cirbuf tx_cirbuf;
+/* generic uart struct */
+struct ucg_uart main_uart;
+#endif
+
+#if defined(__ARM_EABI__)
+
+#include <ucg_gloss_chardev.h>
+#include <ucg_stm32_uart.h>
+
+static struct ucg_stm32_uart stm32_uart_data = {
+ .uart = USART2,
+ .rcc_uart = RCC_APB1Periph_USART2,
+ .rcc_gpio = RCC_AHB1Periph_GPIOA,
+ .gpio = GPIOA,
+ .gpio_af = GPIO_AF_USART2,
+ .gpio_pins = GPIO_Pin_2 | GPIO_Pin_3,
+ .gpio_speed = GPIO_Speed_25MHz,
+ .irq = USART2_IRQn,
+ .irq_preempt_prio = 2,
+ .irq_sub_prio = 0,
+};
+
+static _ssize_t
+uart_write_r(__attribute__((unused)) struct _reent *r,
+ __attribute__((unused)) int fd,
+ const void *ptr, size_t len)
+{
+ size_t i;
+ const char *buf = ptr;
+
+ for (i = 0; i < len; i++)
+ ucg_uart_send(&main_uart, buf[i], WAIT);
+
+ return len;
+}
+
+static _ssize_t
+uart_read_r(__attribute__((unused)) struct _reent *r,
+ __attribute__((unused)) int fd,
+ void *ptr, size_t len)
+{
+ int c;
+ char *buf = ptr;
+
+ (void)len;
+ c = ucg_uart_recv(&main_uart, NOWAIT);
+ if (c < 0) {
+ r->_errno = EAGAIN;
+ return 0;
+ }
+ buf[0] = c;
+ return 1;
+}
+
+void USART2_IRQHandler(void)
+{
+ if ((USART2->SR & USART_FLAG_TXE))
+ ucg_uart_tx_intr(&main_uart);
+ if ((USART2->SR & USART_FLAG_RXNE))
+ ucg_uart_rx_intr(&main_uart);
+}
+
+struct ucg_chardev uart_stdin_dev = {
+ .name = "stdin",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = uart_read_r,
+ .write_r = NULL,
+};
+
+struct ucg_chardev uart_stdout_dev = {
+ .name = "stdout",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = NULL,
+ .write_r = uart_write_r,
+};
+
+struct ucg_chardev uart_stderr_dev = {
+ .name = "stderr",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = NULL,
+ .write_r = uart_write_r,
+};
+
+static void uart_register_stdio(void)
+{
+ ucg_chardev_register(&uart_stdin_dev);
+ ucg_chardev_register(&uart_stdout_dev);
+ ucg_chardev_register(&uart_stderr_dev);
+
+ /* Disable buffering */
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+}
+
+#elif defined(__AVR__)
+
+#include <ucg_avr_uart.h>
+/* avr-specific uart struct */
+static struct ucg_avr_uart avr_uart_data = {
+ .reg_udr = &UDR0,
+ .reg_ucsra = &UCSR0A,
+ .reg_ucsrb = &UCSR0B,
+ .reg_ucsrc = &UCSR0C,
+ .reg_ubrrl = &UBRR0L,
+ .reg_ubrrh = &UBRR0H,
+ .bit_udre = UDRE0,
+ .bit_rxc = RXC0,
+ .bit_udrie = UDRIE0,
+ .bit_rxen = RXEN0,
+ .bit_txen = TXEN0,
+ .bit_rxcie = RXCIE0,
+ .bit_u2x = U2X0,
+};
+
+/* send on stdout */
+static int std_send(char c, FILE *f)
+{
+ (void)f;
+ ucg_uart_send(&main_uart, c, WAIT);
+ return 0;
+}
+
+/* recv on stdin */
+static int std_recv(FILE *f)
+{
+ int16_t c;
+
+ (void)f;
+ c = ucg_uart_recv(&main_uart, NOWAIT);
+ if (c < 0)
+ return _FDEV_EOF;
+
+ return c;
+}
+
+SIGNAL(USART_RX_vect)
+{
+ ucg_uart_rx_intr(&main_uart);
+}
+
+SIGNAL(USART_UDRE_vect)
+{
+ ucg_uart_tx_intr(&main_uart);
+}
+#endif
+
+int uart_init(void)
+{
+ int ret = 0;
+#if defined(__ARM_EABI__) || defined(__AVR__)
+ struct ucg_uart_config conf;
+ const void *uart_ops;
+ void *uart_data;
+
+#if defined(__ARM_EABI__)
+ uart_ops = &stm32_uart_ops;
+ uart_data = &stm32_uart_data;
+#elif defined(__AVR__)
+ uart_ops = &avr_uart_ops;
+ uart_data = &avr_uart_data;
+#endif
+
+ ret = ucg_uart_init(&main_uart, uart_ops, uart_data,
+ &rx_cirbuf, rx_buf, sizeof(rx_buf),
+ &tx_cirbuf, tx_buf, sizeof(tx_buf));
+ if (ret < 0)
+ return ret;
+
+ ucg_uart_getconf(&main_uart, &conf);
+ conf.baudrate = 57600;
+ ret = ucg_uart_setconf(&main_uart, &conf);
+ if (ret < 0)
+ return ret;
+
+#if defined(__ARM_EABI__)
+ uart_register_stdio();
+#elif defined(__AVR__)
+ fdevopen(std_send, std_recv);
+#endif
+#endif
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UART_H_
+#define UART_H_
+
+#include <stdio.h>
+
+int uart_init(void);
+
+#endif
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ../..)
+
+# output path with trailing slash
+O ?= build/
+
+CFLAGS = -g -O2 -Wall
+CFLAGS += -Idir
+
+cflags-$(O)titi.o := -DTEST
+
+obj-y-$(O)target.o := dir/titi.c dir/toto.c
+
+obj-y-$(O)obj.o := $(O)target.o
+
+ar-y-$(O)toto.a := $(O)obj.o
+exe-y-$(O)prog := main.c $(O)obj.o
+
+copy-y-$(O)install/ := $(O)toto.a $(O)prog
+copy-y-$(O)install/2/toto.a := $(O)toto.a
+slink-y-$(O)install/ := dir/toto.h
+
+subdir-y := test1 test2
+TOTO ?= 1
+mkflags-test1 := TOTO=$(TOTO)
+
+include $(UCGINE)/mk/ucgine.mk
+
+all: _ucgine_all
+
+clean: _ucgine_clean
+
+.PHONY: clean all
--- /dev/null
+int titi(void)
+{
+ return 0;
+}
--- /dev/null
+int toto(void)
+{
+ return 0;
+}
--- /dev/null
+int toto(void);
--- /dev/null
+int main(void)
+{
+ return 0;
+}
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ../../..)
+
+# output path with trailing slash
+O = build/
+
+CFLAGS = -g -O2 -Wall -DTOTO=$(TOTO)
+CFLAGS += -Idir
+
+exe-y-$(O)prog := main.c
+
+include $(UCGINE)/mk/ucgine.mk
+
+all: _ucgine_all
+
+clean: _ucgine_clean
+
+.PHONY: clean all
--- /dev/null
+int main(void)
+{
+ return 0;
+}
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ../../..)
+
+# output path with trailing slash
+O = build/
+
+CFLAGS = -g -O2 -Wall
+CFLAGS += -Idir
+
+exe-y-$(O)prog := main.c
+
+include $(UCGINE)/mk/ucgine.mk
+
+all: _ucgine_all
+
+clean: _ucgine_clean
+
+.PHONY: clean all
--- /dev/null
+int main(void)
+{
+ return 0;
+}
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ../..)
+include $(UCGINE)/mk/ucgine-pre.mk
+
+O ?= $(CURDIR)/build
+PROG = $(O)/test-uart
+
+CROSS = arm-none-eabi-
+
+CFLAGS = -g -O2 -Wall
+CFLAGS += -I.
+
+ifeq ($(CROSS),avr-)
+MCU = atmega328p
+F_CPU = 8000000UL
+AVRDUDE_PORT = /dev/ttyUSB0
+AVRDUDE_PROG = arduino
+AVRDUDE_BAUD = 57600
+CFLAGS += -I$(UCGINE)/arch/avr/include
+CFLAGS += -I$(UCGINE)/arch/avr/uart/include
+CFLAGS += -mmcu=$(MCU)
+CFLAGS += -DF_CPU=$(F_CPU)
+LDFLAGS += -mmcu=$(MCU)
+# uart
+exe-y-$(PROG) += $(UCGINE)/arch/avr/uart/ucg_avr_uart.c
+endif
+
+ifeq ($(CROSS),arm-none-eabi-)
+STLINK ?= /home/zer0/projects/stm32/stlink
+STM_COMMON ?= /home/zer0/projects/stm32/stm32_discovery_arm_gcc/STM32F4-Discovery_FW_V1.1.0
+CFLAGS += -DUSE_STDPERIPH_DRIVER -Tstm32_flash.ld
+CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
+CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+CFLAGS += -I$(STM_COMMON)/Utilities/STM32F4-Discovery
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Include
+CFLAGS += -I$(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/inc
+CFLAGS += -I$(UCGINE)/lib/gloss/include
+CFLAGS += -I$(UCGINE)/arch/stm32/include
+CFLAGS += -I$(UCGINE)/arch/stm32/uart/include
+LDFLAGS = -Tstm32_flash.ld --specs=rdimon.specs -lc
+LDFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
+LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+# stm32 standard periph lib
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c
+# startup file
+exe-y-$(PROG) += $(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s
+# local files
+exe-y-$(PROG) += system_stm32f4xx.c
+# gloss
+exe-y-$(PROG) += $(UCGINE)/lib/gloss/ucg_gloss_stubs.c
+exe-y-$(PROG) += $(UCGINE)/lib/gloss/ucg_gloss_chardev.c
+# uart
+exe-y-$(PROG) += $(UCGINE)/arch/stm32/uart/ucg_stm32_uart.c
+endif
+
+# cirbuf
+CFLAGS += -I$(UCGINE)/lib/cirbuf/include
+exe-y-$(PROG) += $(UCGINE)/lib/cirbuf/ucg_cirbuf.c
+# uart
+CFLAGS += -I$(UCGINE)/lib/uart/include
+exe-y-$(PROG) += $(UCGINE)/lib/uart/ucg_uart.c
+
+exe-y-$(PROG) += uart.c main.c
+
+objcopy-hex-y-$(PROG).hex := $(PROG)
+objcopy-bin-y-$(PROG).bin := $(PROG)
+
+include $(UCGINE)/mk/ucgine-post.mk
+
+.PHONY: all
+all: $(all-targets)
+
+.PHONY: clean
+clean: _ucgine_clean
+
+.PHONY: burn
+burn: all
+ifeq ($(CROSS),arm-none-eabi-)
+ $(STLINK)/st-flash write $(PROG).bin 0x8000000
+endif
+ifeq ($(CROSS),avr-)
+ avrdude -e -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROG) \
+ -b $(AVRDUDE_BAUD) -U flash:w:$(PROG):e
+endif
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ucg_delay.h>
+#include <ucg_irq.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "uart.h"
+
+#if defined(__ARM_EABI__)
+#include <stm32f4xx.h>
+
+static void led_on(void)
+{
+ GPIOD->ODR |= (1 << 13);
+}
+
+static void led_off(void)
+{
+ GPIOD->ODR &= (~(1 << 13));
+}
+
+static void target_init(void)
+{
+ /* enable the clock to GPIOD, and stall instruction pipeline as per
+ * errata 2.1.13 "Delay after an RCC peripheral clock enabling" */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+ __asm("dsb");
+
+ /* set pin 13 to be general purpose output */
+ GPIOD->MODER = (1 << 26);
+}
+#elif defined(__AVR__)
+#include <avr/io.h>
+
+static void led_on(void)
+{
+ PORTB |= (1 << 5);
+}
+
+static void led_off(void)
+{
+ PORTB &= (~(1 << 5));
+}
+
+static void target_init(void)
+{
+ DDRB = (1 << 5);
+}
+#endif
+
+static void big_print(void)
+{
+ printf( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
+}
+
+int main(void)
+{
+ unsigned i;
+ char c;
+ int ret;
+
+ target_init();
+
+ /* toggle the pin */
+ for (i = 0; i < 3; i++) {
+ led_on();
+ ucg_delay_ms(500);
+ led_off();
+ ucg_delay_ms(500);
+ }
+
+ uart_init();
+ ucg_irq_unlock();
+
+ big_print();
+
+ while (1) {
+ ret = fread(&c, 1, 1, stdin);
+ if (ret == 1) {
+ if (c == 'x')
+ big_print();
+ else
+ fwrite(&c, 1, 1, stdout);
+ } else if (ret == 0)
+ clearerr(stdin);
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+*****************************************************************************
+**
+** File : stm32_flash.ld
+**
+** Abstract : Linker script for STM32F407VG Device with
+** 1024KByte FLASH, 192KByte RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Environment : Atollic TrueSTUDIO(R)
+**
+** Distribution: The file is distributed \93as is,\94 without any warranty
+** of any kind.
+**
+** (c)Copyright Atollic AB.
+** You may use this file as-is or modify it according to the needs of your
+** project. Distribution of this file (unmodified or modified) is not
+** permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the
+** rights to distribute the assembled, compiled & linked contents of this
+** file as part of an application binary file, provided that it is built
+** using the Atollic TrueSTUDIO(R) toolchain.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20020000; /* end of 128K RAM on AHB bus*/
+
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
+ MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ _exit = .;
+ } >FLASH
+
+
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >FLASH
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >FLASH
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array*))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = .;
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ PROVIDE ( __end__ = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(4);
+ } >RAM
+
+ /* MEMORY_bank1 section, code must be located here explicitly */
+ /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
+ .memory_b1_text :
+ {
+ *(.mb1text) /* .mb1text sections (code) */
+ *(.mb1text*) /* .mb1text* sections (code) */
+ *(.mb1rodata) /* read-only data (constants) */
+ *(.mb1rodata*)
+ } >MEMORY_B1
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
--- /dev/null
+/**
+ ******************************************************************************
+ * @file stm32f4xx_conf.h
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 19-September-2011
+ * @brief Library configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_CONF_H
+#define __STM32F4xx_CONF_H
+
+#if defined (HSE_VALUE)
+/* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */
+ #undef HSE_VALUE
+ #define HSE_VALUE ((uint32_t)8000000)
+#endif /* HSE_VALUE */
+
+/* Includes ------------------------------------------------------------------*/
+/* Uncomment the line below to enable peripheral header file inclusion */
+#include "stm32f4xx_adc.h"
+#include "stm32f4xx_can.h"
+#include "stm32f4xx_crc.h"
+#include "stm32f4xx_cryp.h"
+#include "stm32f4xx_dac.h"
+#include "stm32f4xx_dbgmcu.h"
+#include "stm32f4xx_dcmi.h"
+#include "stm32f4xx_dma.h"
+#include "stm32f4xx_exti.h"
+#include "stm32f4xx_flash.h"
+#include "stm32f4xx_fsmc.h"
+#include "stm32f4xx_hash.h"
+#include "stm32f4xx_gpio.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx_iwdg.h"
+#include "stm32f4xx_pwr.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_rng.h"
+#include "stm32f4xx_rtc.h"
+#include "stm32f4xx_sdio.h"
+#include "stm32f4xx_spi.h"
+#include "stm32f4xx_syscfg.h"
+#include "stm32f4xx_tim.h"
+#include "stm32f4xx_usart.h"
+#include "stm32f4xx_wwdg.h"
+#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* If an external clock source is used, then the value of the following define
+ should be set to the value of the external clock source, else, if no external
+ clock is used, keep this define commented */
+/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
+
+
+/* Uncomment the line below to expanse the "assert_param" macro in the
+ Standard Peripheral Library drivers code */
+/* #define USE_FULL_ASSERT 1 */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#endif /* __STM32F4xx_CONF_H */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+/**
+ ******************************************************************************
+ * @file system_stm32f4xx.c
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 30-September-2011
+ * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+ * This file contains the system clock configuration for STM32F4xx devices,
+ * and is generated by the clock configuration tool
+ * stm32f4xx_Clock_Configuration_V1.0.0.xls
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
+ * and Divider factors, AHB/APBx prescalers and Flash settings),
+ * depending on the configuration made in the clock xls tool.
+ * This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f4xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (16 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. If the system clock source selected by user fails to startup, the SystemInit()
+ * function will do nothing and HSI still used as system clock source. User can
+ * add some code to deal with this issue inside the SetSysClock() function.
+ *
+ * 4. The default value of HSE crystal is set to 25MHz, refer to "HSE_VALUE" define
+ * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or
+ * through PLL, and you are using different crystal you have to adapt the HSE
+ * value to your own configuration.
+ *
+ * 5. This file configures the system clock as follows:
+ *=============================================================================
+ *=============================================================================
+ * Supported STM32F4xx device revision | Rev A
+ *-----------------------------------------------------------------------------
+ * System Clock source | PLL (HSE)
+ *-----------------------------------------------------------------------------
+ * SYSCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * HCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * AHB Prescaler | 1
+ *-----------------------------------------------------------------------------
+ * APB1 Prescaler | 4
+ *-----------------------------------------------------------------------------
+ * APB2 Prescaler | 2
+ *-----------------------------------------------------------------------------
+ * HSE Frequency(Hz) | 25000000
+ *-----------------------------------------------------------------------------
+ * PLL_M | 25
+ *-----------------------------------------------------------------------------
+ * PLL_N | 336
+ *-----------------------------------------------------------------------------
+ * PLL_P | 2
+ *-----------------------------------------------------------------------------
+ * PLL_Q | 7
+ *-----------------------------------------------------------------------------
+ * PLLI2S_N | NA
+ *-----------------------------------------------------------------------------
+ * PLLI2S_R | NA
+ *-----------------------------------------------------------------------------
+ * I2S input clock | NA
+ *-----------------------------------------------------------------------------
+ * VDD(V) | 3.3
+ *-----------------------------------------------------------------------------
+ * Main regulator output voltage | Scale1 mode
+ *-----------------------------------------------------------------------------
+ * Flash Latency(WS) | 5
+ *-----------------------------------------------------------------------------
+ * Prefetch Buffer | OFF
+ *-----------------------------------------------------------------------------
+ * Instruction cache | ON
+ *-----------------------------------------------------------------------------
+ * Data cache | ON
+ *-----------------------------------------------------------------------------
+ * Require 48MHz for USB OTG FS, | Enabled
+ * SDIO and RNG clock |
+ *-----------------------------------------------------------------------------
+ *=============================================================================
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f4xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f4xx.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+ * @{
+ */
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to use external SRAM mounted
+ on STM324xG_EVAL board as data memory */
+/* #define DATA_IN_ExtSRAM */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/************************* PLL Parameters *************************************/
+/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
+#define PLL_M 25
+#define PLL_N 336
+
+/* SYSCLK = PLL_VCO / PLL_P */
+#define PLL_P 2
+
+/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
+#define PLL_Q 7
+
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+ * @{
+ */
+
+ uint32_t SystemCoreClock = 168000000;
+
+ __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+static void SetSysClock(void);
+#ifdef DATA_IN_ExtSRAM
+ static void SystemInit_ExtMemCtl(void);
+#endif /* DATA_IN_ExtSRAM */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the Embedded Flash Interface, the PLL and update the
+ * SystemFrequency variable.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000;
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFF;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x24003010;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000;
+
+#ifdef DATA_IN_ExtSRAM
+ SystemInit_ExtMemCtl();
+#endif /* DATA_IN_ExtSRAM */
+
+ /* Configure the System clock source, PLL Multiplier and Divider factors,
+ AHB/APBx prescalers and Flash settings ----------------------------------*/
+ SetSysClock();
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 16 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 25 MHz), user has to ensure that HSE_VALUE is same as the real
+ * frequency of the crystal used. Otherwise, this function may
+ * have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate(void)
+{
+ uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case 0x00: /* HSI used as system clock source */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04: /* HSE used as system clock source */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08: /* PLL used as system clock source */
+
+ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+ SYSCLK = PLL_VCO / PLL_P
+ */
+ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+ pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+
+ if (pllsource != 0)
+ {
+ /* HSE used as PLL clock source */
+ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+ else
+ {
+ /* HSI used as PLL clock source */
+ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+
+ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+ SystemCoreClock = pllvco/pllp;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK frequency --------------------------------------------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @brief Configures the System clock source, PLL Multiplier and Divider factors,
+ * AHB/APBx prescalers and Flash settings
+ * @Note This function should be called only once the RCC clock configuration
+ * is reset to the default reset state (done in SystemInit() function).
+ * @param None
+ * @retval None
+ */
+static void SetSysClock(void)
+{
+/******************************************************************************/
+/* PLL (clocked by HSE) used as System clock source */
+/******************************************************************************/
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+ /* Enable HSE */
+ RCC->CR |= ((uint32_t)RCC_CR_HSEON);
+
+ /* Wait till HSE is ready and if Time out is reached exit */
+ do
+ {
+ HSEStatus = RCC->CR & RCC_CR_HSERDY;
+ StartUpCounter++;
+ } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+ if ((RCC->CR & RCC_CR_HSERDY) != RESET)
+ {
+ HSEStatus = (uint32_t)0x01;
+ }
+ else
+ {
+ HSEStatus = (uint32_t)0x00;
+ }
+
+ if (HSEStatus == (uint32_t)0x01)
+ {
+ /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
+ RCC->APB1ENR |= RCC_APB1ENR_PWREN;
+ PWR->CR |= PWR_CR_VOS;
+
+ /* HCLK = SYSCLK / 1*/
+ RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
+
+ /* PCLK2 = HCLK / 2*/
+ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
+
+ /* PCLK1 = HCLK / 4*/
+ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
+
+ /* Configure the main PLL */
+ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
+ (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
+
+ /* Enable the main PLL */
+ RCC->CR |= RCC_CR_PLLON;
+
+ /* Wait till the main PLL is ready */
+ while((RCC->CR & RCC_CR_PLLRDY) == 0)
+ {
+ }
+
+ /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
+ FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
+
+ /* Select the main PLL as system clock source */
+ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
+ RCC->CFGR |= RCC_CFGR_SW_PLL;
+
+ /* Wait till the main PLL is used as system clock source */
+ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
+ {
+ }
+ }
+ else
+ { /* If HSE fails to start-up, the application will have wrong clock
+ configuration. User can add here some code to deal with this error */
+ }
+
+}
+
+/**
+ * @brief Setup the external memory controller. Called in startup_stm32f4xx.s
+ * before jump to __main
+ * @param None
+ * @retval None
+ */
+#ifdef DATA_IN_ExtSRAM
+/**
+ * @brief Setup the external memory controller.
+ * Called in startup_stm32f4xx.s before jump to main.
+ * This function configures the external SRAM mounted on STM324xG_EVAL board
+ * This SRAM will be used as program data memory (including heap and stack).
+ * @param None
+ * @retval None
+ */
+void SystemInit_ExtMemCtl(void)
+{
+/*-- GPIOs Configuration -----------------------------------------------------*/
+/*
+ +-------------------+--------------------+------------------+------------------+
+ + SRAM pins assignment +
+ +-------------------+--------------------+------------------+------------------+
+ | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 |
+ | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 |
+ | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 |
+ | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 |
+ | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 |
+ | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 |
+ | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 |
+ | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+
+ | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 |
+ | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 |
+ | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+
+ | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 |
+ | | PE15 <-> FSMC_D12 |
+ +-------------------+--------------------+
+*/
+ /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
+ RCC->AHB1ENR = 0x00000078;
+
+ /* Connect PDx pins to FSMC Alternate function */
+ GPIOD->AFR[0] = 0x00cc00cc;
+ GPIOD->AFR[1] = 0xcc0ccccc;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xaaaa0a0a;
+ /* Configure PDx pins speed to 100 MHz */
+ GPIOD->OSPEEDR = 0xffff0f0f;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FSMC Alternate function */
+ GPIOE->AFR[0] = 0xc00cc0cc;
+ GPIOE->AFR[1] = 0xcccccccc;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xaaaa828a;
+ /* Configure PEx pins speed to 100 MHz */
+ GPIOE->OSPEEDR = 0xffffc3cf;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FSMC Alternate function */
+ GPIOF->AFR[0] = 0x00cccccc;
+ GPIOF->AFR[1] = 0xcccc0000;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xaa000aaa;
+ /* Configure PFx pins speed to 100 MHz */
+ GPIOF->OSPEEDR = 0xff000fff;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FSMC Alternate function */
+ GPIOG->AFR[0] = 0x00cccccc;
+ GPIOG->AFR[1] = 0x000000c0;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0x00080aaa;
+ /* Configure PGx pins speed to 100 MHz */
+ GPIOG->OSPEEDR = 0x000c0fff;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+/*-- FSMC Configuration ------------------------------------------------------*/
+ /* Enable the FSMC interface clock */
+ RCC->AHB3ENR = 0x00000001;
+
+ /* Configure and enable Bank1_SRAM2 */
+ FSMC_Bank1->BTCR[2] = 0x00001015;
+ FSMC_Bank1->BTCR[3] = 0x00010603;
+ FSMC_Bank1E->BWTR[2] = 0x0fffffff;
+/*
+ Bank1_SRAM2 is configured as follow:
+
+ p.FSMC_AddressSetupTime = 3;
+ p.FSMC_AddressHoldTime = 0;
+ p.FSMC_DataSetupTime = 6;
+ p.FSMC_BusTurnAroundDuration = 1;
+ p.FSMC_CLKDivision = 0;
+ p.FSMC_DataLatency = 0;
+ p.FSMC_AccessMode = FSMC_AccessMode_A;
+
+ FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;
+ FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
+ FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
+ FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
+ FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
+ FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
+*/
+
+}
+#endif /* DATA_IN_ExtSRAM */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__ARM_EABI__)
+#include "stm32f4xx.h"
+#elif defined(__AVR__)
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <ucg_irq.h>
+#include <ucg_cirbuf.h>
+#include <ucg_uart.h>
+
+#include "uart.h"
+
+/* rx & tx buffers */
+static char rx_buf[64];
+static struct ucg_cirbuf rx_cirbuf;
+static char tx_buf[64];
+static struct ucg_cirbuf tx_cirbuf;
+/* generic uart struct */
+struct ucg_uart main_uart;
+
+#if defined(__ARM_EABI__)
+
+#include <ucg_gloss_chardev.h>
+#include <ucg_stm32_uart.h>
+
+static struct ucg_stm32_uart stm32_uart_data = {
+ .uart = USART2,
+ .rcc_uart = RCC_APB1Periph_USART2,
+ .rcc_gpio = RCC_AHB1Periph_GPIOA,
+ .gpio = GPIOA,
+ .gpio_af = GPIO_AF_USART2,
+ .gpio_pins = GPIO_Pin_2 | GPIO_Pin_3,
+ .gpio_speed = GPIO_Speed_25MHz,
+ .irq = USART2_IRQn,
+ .irq_preempt_prio = 2,
+ .irq_sub_prio = 0,
+};
+
+static _ssize_t
+uart_write_r(__attribute__((unused)) struct _reent *r,
+ __attribute__((unused)) int fd,
+ const void *ptr, size_t len)
+{
+ size_t i;
+ const char *buf = ptr;
+
+ for (i = 0; i < len; i++)
+ ucg_uart_send(&main_uart, buf[i], WAIT);
+
+ return len;
+}
+
+static _ssize_t
+uart_read_r(__attribute__((unused)) struct _reent *r,
+ __attribute__((unused)) int fd,
+ void *ptr, size_t len)
+{
+ int c;
+ char *buf = ptr;
+
+ c = ucg_uart_recv(&main_uart, NOWAIT);
+ if (c < 0) {
+ r->_errno = EAGAIN;
+ return 0;
+ }
+ buf[0] = c;
+ return 1;
+}
+
+void USART2_IRQHandler(void)
+{
+ if ((USART2->SR & USART_FLAG_TXE))
+ ucg_uart_tx_intr(&main_uart);
+ if ((USART2->SR & USART_FLAG_RXNE))
+ ucg_uart_rx_intr(&main_uart);
+}
+
+struct ucg_chardev uart_stdin_dev = {
+ .name = "stdin",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = uart_read_r,
+ .write_r = NULL,
+};
+
+struct ucg_chardev uart_stdout_dev = {
+ .name = "stdout",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = NULL,
+ .write_r = uart_write_r,
+};
+
+struct ucg_chardev uart_stderr_dev = {
+ .name = "stderr",
+ .open_r = NULL,
+ .close_r = NULL,
+ .read_r = NULL,
+ .write_r = uart_write_r,
+};
+
+static void uart_register_stdio(void)
+{
+ ucg_chardev_register(&uart_stdin_dev);
+ ucg_chardev_register(&uart_stdout_dev);
+ ucg_chardev_register(&uart_stderr_dev);
+
+ /* Disable buffering */
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+}
+
+#elif defined(__AVR__)
+
+#include <ucg_avr_uart.h>
+/* avr-specific uart struct */
+static struct ucg_avr_uart avr_uart_data = {
+ .reg_udr = &UDR0,
+ .reg_ucsra = &UCSR0A,
+ .reg_ucsrb = &UCSR0B,
+ .reg_ucsrc = &UCSR0C,
+ .reg_ubrrl = &UBRR0L,
+ .reg_ubrrh = &UBRR0H,
+ .bit_udre = UDRE0,
+ .bit_rxc = RXC0,
+ .bit_udrie = UDRIE0,
+ .bit_rxen = RXEN0,
+ .bit_txen = TXEN0,
+ .bit_rxcie = RXCIE0,
+ .bit_u2x = U2X0,
+};
+
+/* send on stdout */
+static int std_send(char c, FILE *f)
+{
+ (void)f;
+ ucg_uart_send(&main_uart, c, WAIT);
+ return 0;
+}
+
+/* recv on stdin */
+static int std_recv(FILE *f)
+{
+ int16_t c;
+
+ (void)f;
+ c = ucg_uart_recv(&main_uart, NOWAIT);
+ if (c < 0)
+ return _FDEV_EOF;
+
+ return c;
+}
+
+SIGNAL(USART_RX_vect)
+{
+ ucg_uart_rx_intr(&main_uart);
+}
+
+SIGNAL(USART_UDRE_vect)
+{
+ ucg_uart_tx_intr(&main_uart);
+}
+#endif
+
+int uart_init(void)
+{
+ int ret;
+ struct ucg_uart_config conf;
+ const void *uart_ops;
+ void *uart_data;
+
+#if defined(__ARM_EABI__)
+ uart_ops = &stm32_uart_ops;
+ uart_data = &stm32_uart_data;
+#else
+ uart_ops = &avr_uart_ops;
+ uart_data = &avr_uart_data;
+#endif
+
+ ret = ucg_uart_init(&main_uart, uart_ops, uart_data,
+ &rx_cirbuf, rx_buf, sizeof(rx_buf),
+ &tx_cirbuf, tx_buf, sizeof(tx_buf));
+ if (ret < 0)
+ return ret;
+
+ ucg_uart_getconf(&main_uart, &conf);
+ conf.baudrate = 57600;
+ ret = ucg_uart_setconf(&main_uart, &conf);
+ if (ret < 0)
+ return ret;
+
+#if defined(__ARM_EABI__)
+ uart_register_stdio();
+#elif defined(__AVR__)
+ fdevopen(std_send, std_recv);
+#endif
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UART_H_
+#define UART_H_
+
+#include <stdio.h>
+
+int uart_init(void);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) <2014-2015>, Olivier Matz <zer0@droids-corp.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Inspired from Intel DPDK rte_timer library */
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CALLOUT_H_
+#define UCG_CALLOUT_H_
+
+#include <sys/queue.h>
+
+#define UCG_CALLOUT_STATS
+/* #define UCG_CALLOUT_DEBUG */
+
+/**
+ * This module provides a timer service. The manager function
+ * ucg_callout_manage() can be called from an interrupt or from a
+ * standard function (usually a main-loop). In the latter case, no
+ * preemption is possible.
+ *
+ * Each timer has a priority: the timers with higher priorities are
+ * scheduled before the others. This feature is mostly useful when the
+ * manager is called from an interrupt. Indeed, the callback function of
+ * a timer with a high priority cannot be preempted by a timer with a
+ * lower priority.
+ *
+ * The module locks interrupts when doing critical operations, ensuring that
+ * critical data are accessed atomically.
+ *
+ * State of timers:
+ * - stopped: initial state after ucg_callout_init()
+ * - scheduled: after a call to ucg_callout_schedule(), the timer is in the
+ * scheduled list of the callout manager
+ * - expired: after a call to ucg_callout_manage(), if the expire time of a
+ * timer is reached, it is moved in a local list and its state is
+ * changed to "expired".
+ * - before starting the callback, the timer goes in state "running".
+ *
+ * Once running, the associated timer is not touched anymore by
+ * ucg_callout_manage(). As a result, the timer MUST be either reloaded
+ * or stopped (and potentially freed).
+ */
+
+/**
+ * Maximum number of nested preemptions.
+ */
+#define UCG_CALLOUT_MAX_RECURSION 5
+
+#ifdef UCG_CALLOUT_STATS
+/**
+ * The structure that stores the timer statistics, mostly useful for debug
+ * purposes.
+ */
+struct ucg_callout_debug_stats {
+ uint32_t schedule; /**< nb of calls to ucg_callout_(re)schedule() */
+ uint32_t stop; /**< nb of calls to ucg_callout_stop() */
+ uint32_t manage; /**< nb of calls to ucg_callout_manage() */
+ uint32_t max_recursion; /** manage() skipped due to max recursion */
+ uint32_t delayed; /** task delayed a bit due to low prio */
+ uint32_t hard_delayed; /** task recheduled later due to low priority */
+
+ uint8_t cur_scheduled; /**< current number of scheduled timers */
+ uint8_t cur_expired; /**< current number of expired timers */
+ uint8_t cur_running; /**< current number of running timers */
+};
+#endif
+
+struct ucg_callout;
+struct ucg_callout_mgr;
+
+/**
+ * The type of a callout callback function.
+ */
+typedef void (ucg_callout_cb_t)(struct ucg_callout_mgr *cm,
+ struct ucg_callout *tim, void *arg);
+
+/**
+ * A callout structure, storing all data associated to a timer.
+ */
+struct ucg_callout {
+ LIST_ENTRY(ucg_callout) next; /**< next/prev in list */
+
+#define UCG_CALLOUT_STATE_STOPPED 0 /**< not scheduled */
+#define UCG_CALLOUT_STATE_SCHEDULED 1 /**< in the scheduled list */
+#define UCG_CALLOUT_STATE_EXPIRED 2 /**< expired, will be executed soon */
+#define UCG_CALLOUT_STATE_RUNNING 3 /**< being executed */
+ uint8_t state; /**< stopped, scheduled, expired */
+ uint8_t priority; /**< the priority of the timer */
+ uint16_t expire; /**< time when timer should expire */
+
+ ucg_callout_cb_t *f; /**< callback function pointer */
+ void *arg; /**< argument given to the cb function. */
+};
+
+/* define the callout list */
+LIST_HEAD(ucg_callout_list, ucg_callout);
+
+/* static initializer for a timer structure */
+#define UCG_CALLOUT_INITIALIZER { }
+
+/**
+ * Type of the function used by a callout manager to get a time reference
+ */
+typedef uint16_t (ucg_callout_get_time_t)(void);
+
+/**
+ * An instance of callout manager. It is possible to have several
+ * managers. A callout is attached to one manager at a time.
+ */
+struct ucg_callout_mgr {
+ ucg_callout_get_time_t *get_time; /**< func to get the time reference */
+ uint16_t prev_time; /**< time of previous call */
+ uint8_t cur_priority; /** priority of running event */
+ uint8_t nb_recursion; /** number of recursion */
+ struct ucg_callout_list sched_list; /**< list of scheduled timers */
+
+#ifdef UCG_CALLOUT_STATS
+ struct ucg_callout_debug_stats stats; /**< stats */
+#endif
+};
+
+/**
+ * Initialize a callout manager
+ *
+ * The callout manager must be initialized before ucg_callout_add() or
+ * ucg_callout_manage() can be called.
+ *
+ * @param cm
+ * Pointer to the uninitialized callout manager structure.
+ * @param get_time
+ * Pointer to a function that returns a time reference (unsigned 16 bits).
+ */
+void ucg_callout_mgr_init(struct ucg_callout_mgr *cm,
+ ucg_callout_get_time_t *get_time);
+
+/**
+ * Initialize a callout structure and set callback function
+ *
+ * Before doing any operation on the callout structure, it has to be
+ * initialized with this function. It is possible to reinitialize a
+ * timer that has been previously scheduled, but it must be stopped.
+ *
+ * @param tim
+ * The timer to initialize.
+ * @param priority
+ * The priority of the callout (high value means higher priority)
+ * @param f
+ * The callback function of the timer.
+ * @param arg
+ * The user argument of the callback function.
+ */
+void ucg_callout_init(struct ucg_callout *tim, ucg_callout_cb_t f, void *arg,
+ uint8_t priority);
+
+/**
+ * Schedule a callout
+ *
+ * The ucg_callout_schedule() function adds the timer in the scheduled
+ * list. After the specified amount of ticks are elapsed, the callback
+ * function of the timer previously given to ucg_callout_init() will be
+ * invoked with its argument.
+ *
+ * The given "tick" value is relative to the current time, and is 16 bits
+ * wide. As it internally uses signed 16 bits comparison, the max value for
+ * ticks is 32767.
+ *
+ * @param cm
+ * The callout manager where the timer should be scheduled
+ * @param tim
+ * The timer handle
+ * @param ticks
+ * The number of ticks before the callback function is called, relative to now
+ * (the reference is given by the get_time() function of the callout manager).
+ * @return
+ * 0 on success, negative on error
+ */
+int ucg_callout_schedule(struct ucg_callout_mgr *cm, struct ucg_callout *tim,
+ uint16_t ticks);
+
+/**
+ * Reschedule a callout
+ *
+ * This function does exactly the same than ucg_callout_schedule()
+ * except that the given time "ticks" is not relative to the current
+ * time but to the "expire" field of the timer.
+ *
+ * Using this function is advised to avoid drift if you want to have periodic
+ * timers.
+ *
+ * This function should preferably be called from the callback function of
+ * the timer. Indeed, if the "expire" field should be a known value or it
+ * can result in an undefined behavior
+ *
+ * The given "tick" value is relative to the "expire" field of the
+ * timer, and is 16 bits wide. As it internally uses signed 16 bits
+ * comparison, the max value for ticks is 32767.
+ *
+ * @param cm
+ * The callout manager where the timer should be scheduled
+ * @param tim
+ * The timer handle
+ * @param ticks
+ * The number of ticks before the callback function is called, relative to
+ * the "expire" value of the timer
+ * @return
+ * 0 on success, negative on error
+ */
+int ucg_callout_reschedule(struct ucg_callout_mgr *cm, struct ucg_callout *tim,
+ uint16_t ticks);
+
+/**
+ * Stop a timer.
+ *
+ * The ucg_callout_stop() function stops a timer associated with the
+ * timer handle tim.
+ *
+ * If the timer is scheduled or expired, it is removed from the list:
+ * the callback function won't be invoked. If the timer is stopped or
+ * running the function does nothing.
+ *
+ * If a timer structure is dynamically allocated, invoking
+ * ucg_callout_stop() is needed before freeing the structure, even if
+ * the freeing occurs in a callback. Indeed, this function can be called
+ * safely from a timer callback. If it succeeds, the timer is not
+ * referenced anymore by the callout manager.
+ *
+ * @param cm
+ * The callout manager where the timer is or was scheduled
+ * @param tim
+ * The timer
+ * @return
+ * 0 on success, negative on error
+ */
+void ucg_callout_stop(struct ucg_callout_mgr *cm, struct ucg_callout *tim);
+
+/**
+ * Return the state of a timer
+ *
+ * @param tim
+ * The timer
+ * @return
+ * - UCG_CALLOUT_STATE_STOPPED: the timer is stopped
+ * - UCG_CALLOUT_STATE_SCHEDULED: the timer is scheduled
+ * - UCG_CALLOUT_STATE_EXPIRED: the timer was moved in a local list before
+ * execution
+ */
+static inline uint8_t ucg_callout_state(struct ucg_callout *tim)
+{
+ return tim->state;
+}
+
+/**
+ * Manage the timer list and execute callback functions.
+ *
+ * This function must be called periodically, either from a loop of from
+ * an interrupt. It browses the list of scheduled timers and runs all
+ * timers that are expired.
+ *
+ * This function must be called at least every 16384 reference ticks of
+ * cm->get_time(), but calling it more often is recommanded to avoid
+ * delaying task abusively.
+ *
+ * The function must be called with IRQ allowed.
+ */
+void ucg_callout_manage(struct ucg_callout_mgr *cm);
+
+/**
+ * Dump statistics about timers.
+ */
+void ucg_callout_dump_stats(struct ucg_callout_mgr *cm);
+
+/**
+ * Set the current priority level
+ *
+ * Prevent callout with a priority lower than "new_prio" to be executed.
+ * If the current priority of the callout manager is already lower higher
+ * than "new_prio", the function won't change the running priority.
+ *
+ * The returned value should be stored by the caller and restored with
+ * ucg_callout_mgr_restore_prio(), preferably in the same function.
+ *
+ * @param cm
+ * The callout manager
+ * @param new_prio
+ * The new running priority
+ *
+ * @return
+ * The value of the running priority before the call og this function
+ */
+uint8_t ucg_callout_mgr_set_prio(struct ucg_callout_mgr *cm, uint8_t new_prio);
+
+/**
+ * Restore the current priority level
+ *
+ * Used after a call to ucg_callout_mgr_set_prio().
+ *
+ * @param cm
+ * The callout manager
+ * @param old_prio
+ * The old running priority
+ */
+void ucg_callout_mgr_restore_prio(struct ucg_callout_mgr *cm, uint8_t old_prio);
+
+#endif /* UCG_CALLOUT_H_ */
--- /dev/null
+/*
+ * Copyright (c) <2014-2015>, Olivier Matz <zer0@droids-corp.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Inspired from Intel DPDK rte_timer library */
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <ucg_irq.h>
+#include <ucg_callout.h>
+
+/* allow to browse a list while modifying the current element */
+#define _LIST_FOREACH_SAFE(cur, next, head, field) \
+ for ((cur) = LIST_FIRST((head)), \
+ (next) = ((cur) ? LIST_NEXT((cur), field) : NULL); \
+ (cur); \
+ (cur) = (next), \
+ (next) = ((cur) ? LIST_NEXT((cur), field) : NULL))
+
+#ifdef UCG_CALLOUT_STATS
+/* called with irq locked */
+#define CALLOUT_STAT_ADD(cm, field, x) do { \
+ cm->stats.field += x; \
+ } while(0)
+#else
+#define CALLOUT_STAT_ADD(cm, field, x) do { } while(0)
+#endif
+
+#ifdef UCG_CALLOUT_DEBUG
+#define callout_dprintf(fmt, ...) \
+ printf("%s(): " fmt, __FUNCTION__, __VA_ARGS__)
+#else
+#define callout_dprintf(...) do { } while (0)
+#endif
+
+/* Initialize a callout manager */
+void
+ucg_callout_mgr_init(struct ucg_callout_mgr *cm,
+ ucg_callout_get_time_t *get_time)
+{
+ memset(cm, 0, sizeof(*cm));
+ cm->get_time = get_time;
+ LIST_INIT(&cm->sched_list);
+}
+
+/* Initialize the timer handle tim for use */
+void
+ucg_callout_init(struct ucg_callout *tim, ucg_callout_cb_t f, void *arg,
+ uint8_t priority)
+{
+ memset(tim, 0, sizeof(*tim));
+ tim->f = f;
+ tim->arg = arg;
+ tim->priority = priority;
+}
+
+/*
+ * Add a timer in the scheduled list (timer must not already be in a list). The
+ * timers are sorted in the list according the expire time (the closer timers
+ * first).
+ *
+ * called with irq locked
+ */
+static void
+callout_add_in_sched_list(struct ucg_callout_mgr *cm, struct ucg_callout *tim)
+{
+ struct ucg_callout *t, *prev_t;
+
+ callout_dprintf("cm=%p tim=%p\r\n", cm, tim);
+ tim->state = UCG_CALLOUT_STATE_SCHEDULED;
+
+ /* list is empty */
+ if (LIST_EMPTY(&cm->sched_list)) {
+ LIST_INSERT_HEAD(&cm->sched_list, tim, next);
+ return;
+ }
+
+ /* 'tim' expires before first entry */
+ t = LIST_FIRST(&cm->sched_list);
+ if ((int16_t)(tim->expire - t->expire) <= 0) {
+ LIST_INSERT_HEAD(&cm->sched_list, tim, next);
+ return;
+ }
+
+ /* find an element that will expire after 'tim' */
+ LIST_FOREACH(t, &cm->sched_list, next) {
+ if ((int16_t)(tim->expire - t->expire) <= 0) {
+ LIST_INSERT_BEFORE(t, tim, next);
+ return;
+ }
+ prev_t = t;
+ }
+
+ /* not found, insert at the end of the list */
+ LIST_INSERT_AFTER(prev_t, tim, next);
+}
+
+/*
+ * Add a timer in the local expired list (timer must not already be in a
+ * list). The timers are sorted in the list according to the priority (high
+ * priority first).
+ *
+ * called with irq locked
+ */
+static void
+callout_add_in_expired_list(struct ucg_callout_mgr *cm,
+ struct ucg_callout_list *expired_list, struct ucg_callout *tim)
+{
+ struct ucg_callout *t, *prev_t;
+
+ (void)cm; /* avoid warning if debug is disabled */
+
+ callout_dprintf("cm=%p tim=%p\r\n", cm, tim);
+ tim->state = UCG_CALLOUT_STATE_EXPIRED;
+
+ /* list is empty */
+ if (LIST_EMPTY(expired_list)) {
+ LIST_INSERT_HEAD(expired_list, tim, next);
+ return;
+ }
+
+ /* 'tim' has a higher prio */
+ t = LIST_FIRST(expired_list);
+ if (tim->priority >= t->priority) {
+ LIST_INSERT_HEAD(expired_list, tim, next);
+ return;
+ }
+
+ /* find an element that will expire after 'tim' */
+ LIST_FOREACH(t, expired_list, next) {
+ if (tim->priority >= t->priority) {
+ LIST_INSERT_BEFORE(t, tim, next);
+ return;
+ }
+ prev_t = t;
+ }
+
+ /* not found, insert at the end of the list */
+ LIST_INSERT_AFTER(prev_t, tim, next);
+}
+
+/*
+ * del from list (timer must be in a list)
+ */
+static void
+callout_del(struct ucg_callout_mgr *cm, struct ucg_callout *tim)
+{
+ (void)cm; /* avoid warning if debug is disabled */
+ callout_dprintf("cm=%p tim=%p\r\n", cm, tim);
+ LIST_REMOVE(tim, next);
+}
+
+/* Reset and start the timer associated with the timer handle tim */
+static int
+__callout_schedule(struct ucg_callout_mgr *cm, struct ucg_callout *tim,
+ uint16_t expire)
+{
+ ucg_irqflags_t flags;
+
+ callout_dprintf("cm=%p tim=%p expire=%d\r\n",
+ cm, tim, expire);
+
+ flags = ucg_irq_lock_save();
+ CALLOUT_STAT_ADD(cm, schedule, 1);
+
+ /* remove it from list */
+ if (tim->state != UCG_CALLOUT_STATE_STOPPED) {
+ /* stats */
+ if (tim->state == UCG_CALLOUT_STATE_SCHEDULED)
+ CALLOUT_STAT_ADD(cm, cur_scheduled, -1);
+ else if (tim->state == UCG_CALLOUT_STATE_EXPIRED)
+ CALLOUT_STAT_ADD(cm, cur_expired, -1);
+ if (tim->state == UCG_CALLOUT_STATE_RUNNING)
+ CALLOUT_STAT_ADD(cm, cur_running, -1);
+
+ callout_del(cm, tim);
+ }
+
+ tim->expire = expire;
+ CALLOUT_STAT_ADD(cm, cur_scheduled, 1);
+ callout_add_in_sched_list(cm, tim);
+ ucg_irq_unlock_restore(flags);
+
+ return 0;
+}
+
+/* Reset and start the timer associated with the timer handle tim */
+int
+ucg_callout_schedule(struct ucg_callout_mgr *cm, struct ucg_callout *tim,
+ uint16_t ticks)
+{
+ return __callout_schedule(cm, tim, cm->get_time() + ticks);
+}
+
+/* Reset and start the timer associated with the timer handle tim */
+int
+ucg_callout_reschedule(struct ucg_callout_mgr *cm, struct ucg_callout *tim,
+ uint16_t ticks)
+{
+ return __callout_schedule(cm, tim, tim->expire + ticks);
+}
+
+/* Stop the timer associated with the timer handle tim */
+void
+ucg_callout_stop(struct ucg_callout_mgr *cm, struct ucg_callout *tim)
+{
+ ucg_irqflags_t flags;
+
+ callout_dprintf("cm=%p tim=%p\r\n", cm, tim);
+
+ flags = ucg_irq_lock_save();
+ if (tim->state != UCG_CALLOUT_STATE_STOPPED) {
+
+ /* stats */
+ if (tim->state == UCG_CALLOUT_STATE_SCHEDULED)
+ CALLOUT_STAT_ADD(cm, cur_scheduled, -1);
+ else if (tim->state == UCG_CALLOUT_STATE_EXPIRED)
+ CALLOUT_STAT_ADD(cm, cur_expired, -1);
+ if (tim->state == UCG_CALLOUT_STATE_RUNNING)
+ CALLOUT_STAT_ADD(cm, cur_running, -1);
+ CALLOUT_STAT_ADD(cm, stop, 1);
+
+ /* remove it from list */
+ callout_del(cm, tim);
+ tim->state = UCG_CALLOUT_STATE_STOPPED;
+ }
+ ucg_irq_unlock_restore(flags);
+}
+
+/* must be called periodically, run all timer that expired */
+void ucg_callout_manage(struct ucg_callout_mgr *cm)
+{
+ struct ucg_callout_list expired_list;
+ struct ucg_callout_list reschedule_list;
+ struct ucg_callout *tim, *tim_next;
+ uint16_t cur_time;
+ uint8_t old_prio;
+ int16_t diff;
+
+ CALLOUT_STAT_ADD(cm, manage, 1);
+ callout_dprintf("cm=%p\r\n", cm);
+
+ /* maximize the number of self-recursions */
+ if (cm->nb_recursion >= UCG_CALLOUT_MAX_RECURSION) {
+ CALLOUT_STAT_ADD(cm, max_recursion, 1);
+ return;
+ }
+
+ ucg_irq_lock();
+ cm->nb_recursion++;
+ LIST_INIT(&expired_list);
+ LIST_INIT(&reschedule_list);
+ cur_time = cm->get_time();
+ old_prio = cm->cur_priority;
+
+ /* move all expired timers in a local list */
+ _LIST_FOREACH_SAFE(tim, tim_next, &cm->sched_list, next) {
+
+ diff = cur_time - tim->expire;
+
+ /* check the expiration time (tasks are sorted) */
+ if (diff < 0)
+ break;
+
+ callout_dprintf("cm=%p diff=%d\r\n", cm, diff);
+
+ /* check the priority, if it's too low, inc stats */
+ if (tim->priority <= cm->cur_priority) {
+ if (diff < 16484)
+ CALLOUT_STAT_ADD(cm, delayed, 1);
+ else {
+ /* reschedule to avoid an overflow */
+ CALLOUT_STAT_ADD(cm, hard_delayed, 1);
+ LIST_REMOVE(tim, next);
+ tim->expire = cur_time;
+ LIST_INSERT_HEAD(&reschedule_list, tim, next);
+ }
+ continue;
+ }
+
+ LIST_REMOVE(tim, next);
+ callout_add_in_expired_list(cm, &expired_list, tim);
+ CALLOUT_STAT_ADD(cm, cur_scheduled, -1);
+ CALLOUT_STAT_ADD(cm, cur_expired, 1);
+ }
+
+ /* reschedule hard_delayed timers, this does not happen usually */
+ while (!LIST_EMPTY(&reschedule_list)) {
+ tim = LIST_FIRST(&reschedule_list);
+ LIST_REMOVE(tim, next);
+ callout_add_in_sched_list(cm, tim);
+ }
+
+ /* for each timer of 'expired' list, execute callback */
+ while (!LIST_EMPTY(&expired_list)) {
+ tim = LIST_FIRST(&expired_list);
+ LIST_REMOVE(tim, next);
+
+ /* execute callback function */
+ CALLOUT_STAT_ADD(cm, cur_expired, -1);
+ CALLOUT_STAT_ADD(cm, cur_running, 1);
+ tim->state = UCG_CALLOUT_STATE_RUNNING;
+ cm->cur_priority = tim->priority;
+ ucg_irq_unlock();
+ tim->f(cm, tim, tim->arg);
+ ucg_irq_lock();
+ }
+
+ cm->cur_priority = old_prio;
+ cm->nb_recursion--;
+ ucg_irq_unlock();
+}
+
+/* set the current priority level */
+uint8_t ucg_callout_mgr_set_prio(struct ucg_callout_mgr *cm, uint8_t new_prio)
+{
+ uint8_t old_prio;
+
+ old_prio = cm->cur_priority;
+ if (new_prio <= old_prio)
+ return old_prio;
+
+ cm->cur_priority = new_prio;
+ return old_prio;
+}
+
+/* restore the current priority level */
+void ucg_callout_mgr_restore_prio(struct ucg_callout_mgr *cm, uint8_t old_prio)
+{
+ cm->cur_priority = old_prio;
+}
+
+/* dump statistics about timers */
+void ucg_callout_dump_stats(struct ucg_callout_mgr *cm)
+{
+#ifdef UCG_CALLOUT_STATS
+ printf("Timer statistics:\r\n");
+ printf(" schedule = %"PRIu32"\r\n", cm->stats.schedule);
+ printf(" stop = %"PRIu32"\r\n", cm->stats.stop);
+ printf(" manage = %"PRIu32"\r\n", cm->stats.manage);
+ printf(" max_recursion = %"PRIu32"\r\n", cm->stats.max_recursion);
+ printf(" delayed = %"PRIu32"\r\n", cm->stats.delayed);
+ printf(" hard_delayed = %"PRIu32"\r\n", cm->stats.hard_delayed);
+
+ printf(" cur_scheduled = %u\r\n", cm->stats.cur_scheduled);
+ printf(" cur_expired = %u\r\n", cm->stats.cur_expired);
+ printf(" cur_running = %u\r\n", cm->stats.cur_running);
+#else
+ printf("No timer statistics, UCG_CALLOUT_STATS is disabled\r\n");
+#endif
+}
--- /dev/null
+/*
+ * Copyright 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CIRBUF_H_
+#define UCG_CIRBUF_H_
+
+#include <stdio.h>
+
+/**
+ * A circular buffer.
+ */
+struct ucg_cirbuf {
+ unsigned maxlen; /**< Total length of the fifo (number of elements). */
+ unsigned start; /**< Index of the first element. */
+ unsigned len; /**< Current len of fifo. */
+ char *buf; /**< Pointer to the data buffer. */
+};
+
+/**
+ * Initialize a circular buffer.
+ *
+ * @param cbuf
+ * A pointer to an uninitialized circular buffer structure.
+ * @param buf
+ * The buffer used to store the data.
+ * @param start
+ * The index of head at initialization.
+ * @param maxlen
+ * The size of the buffer.
+ */
+void ucg_cirbuf_init(struct ucg_cirbuf *cbuf, char *buf, unsigned start,
+ unsigned maxlen);
+
+/**
+ * Check if the circular buffer is full.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * 1 if the circular buffer is full, else 0.
+ */
+static inline int ucg_cirbuf_is_full(const struct ucg_cirbuf *cbuf)
+{
+ return cbuf->len == cbuf->maxlen;
+}
+
+/**
+ * Check if the circular buffer is empty.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * 1 if the circular buffer is empty, else 0.
+ */
+static inline int ucg_cirbuf_is_empty(const struct ucg_cirbuf *cbuf)
+{
+ return cbuf->len == 0;
+}
+
+/**
+ * Get the length of data in the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * The current length of data in the circular buffer.
+ */
+static inline unsigned ucg_cirbuf_get_len(const struct ucg_cirbuf *cbuf)
+{
+ return cbuf->len;
+}
+
+/**
+ * Get the size of the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * Return the maximum size of the circular buffer (used + free elements)
+ */
+static inline unsigned ucg_cirbuf_get_maxlen(const struct ucg_cirbuf *cbuf)
+{
+ return cbuf->maxlen;
+}
+
+/**
+ * Get the lenght of free space in the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * Return the length of free space.
+ */
+static inline unsigned ucg_cirbuf_get_freelen(const struct ucg_cirbuf *cbuf)
+{
+ return cbuf->maxlen - cbuf->len;
+}
+
+/**
+ * Iterator for a circular buffer
+ *
+ * cirbuf: struct cirbuf pointer
+ * i: an integer internally used in the macro
+ * elt: char that takes the value for each iteration
+ */
+#define UCG_CIRBUF_FOREACH(cirbuf, i, elt) \
+ for (i = 0, elt = (cirbuf)->buf[(cirbuf)->start]; \
+ i < ((cirbuf)->len); \
+ i ++, elt = (cirbuf)->buf[((cirbuf)->start + i) % \
+ ((cirbuf)->maxlen)])
+
+/**
+ * Add a character at the head of the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param c
+ * The character to add.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_add_head_safe(struct ucg_cirbuf *cbuf, char c);
+
+/**
+ * Add a character at the head of the circular buffer.
+ *
+ * The function does not check that there is enough free space
+ * in the buffer, so it has to be done by the caller. If it's
+ * not the case, undefined behavior will occur.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param c
+ * The character to add.
+ */
+void ucg_cirbuf_add_head(struct ucg_cirbuf *cbuf, char c);
+
+/**
+ * Add a character at the tail of the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param c
+ * The character to add.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_add_tail_safe(struct ucg_cirbuf *cbuf, char c);
+
+/**
+ * Add a character at the tail of the circular buffer.
+ *
+ * The function does not check that there is enough free space
+ * in the buffer, so it has to be done by the caller. If it's
+ * not the case, undefined behavior will occur.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param c
+ * The character to add.
+ */
+void ucg_cirbuf_add_tail(struct ucg_cirbuf *cbuf, char c);
+
+/**
+ * Remove a char at the head of the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_del_head_safe(struct ucg_cirbuf *cbuf);
+
+/**
+ * Remove a char at the head of the circular buffer.
+ *
+ * The function does not check that there is enough elements
+ * in the buffer, so it has to be done by the caller. If it's
+ * not the case, undefined behavior will occur.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ */
+void ucg_cirbuf_del_head(struct ucg_cirbuf *cbuf);
+
+/**
+ * Remove a char at the tail of the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_del_tail_safe(struct ucg_cirbuf *cbuf);
+
+/**
+ * Remove a char at the tail of the circular buffer.
+ *
+ * The function does not check that there is enough elements
+ * in the buffer, so it has to be done by the caller. If it's
+ * not the case, undefined behavior will occur.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ */
+void ucg_cirbuf_del_tail(struct ucg_cirbuf *cbuf);
+
+/**
+ * Return the element at the tail of the circular buffer.
+ *
+ * The circular buffer must not be empty or an undefined character
+ * will be returned.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * The character at the tail of the circular buffer.
+ */
+char ucg_cirbuf_get_head(const struct ucg_cirbuf *cbuf);
+
+/**
+ * Return the element at the tail of the circular buffer.
+ *
+ * The circular buffer must not be empty or an undefined character
+ * will be returned.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @return
+ * The character at the tail of the circular buffer.
+ */
+char ucg_cirbuf_get_tail(const struct ucg_cirbuf *cbuf);
+
+/**
+ * Add a buffer at the head of the circular buffer.
+ *
+ * Add 'n' bytes of buffer pointed by 'buf' ad the head of th
+ * circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param buf
+ * The pointer to the buffer.
+ * @param n
+ * Number of bytes to add.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_add_buf_head(struct ucg_cirbuf *cbuf, const char *buf,
+ unsigned n);
+
+/**
+ * Add a buffer at the tail of the circular buffer.
+ *
+ * Add 'n' bytes of buffer pointed by 'buf' ad the tail of th
+ * circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param buf
+ * The pointer to the buffer.
+ * @param n
+ * Number of bytes to add.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_add_buf_tail(struct ucg_cirbuf *cbuf, const char *buf,
+ unsigned n);
+
+/**
+ * Remove chars at the head of the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param n
+ * Number of bytes to remove.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_del_buf_head(struct ucg_cirbuf *cbuf, unsigned n);
+
+/**
+ * Remove chars at the tail of the circular buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param n
+ * Number of bytes to remove.
+ * @return
+ * Return 0 on success, or a negative value on error.
+ */
+int ucg_cirbuf_del_buf_tail(struct ucg_cirbuf *cbuf, unsigned n);
+
+/**
+ * Copy multiple bytes from the head of the circular buffer.
+ *
+ * Copy a maximum of 'n' characters from the head of the circular buffer
+ * into a flat buffer pointed by 'buf'. If the circular buffer is
+ * smaller than n, less bytes are copied.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param buf
+ * The pointer to the buffer.
+ * @param n
+ * Maximum number of bytes to copy.
+ * @return
+ * Return the number of copied chars.
+ */
+int ucg_cirbuf_get_buf_head(const struct ucg_cirbuf *cbuf, char *buf,
+ unsigned n);
+
+/**
+ * Copy multiple bytes from the tail of the circular buffer.
+ *
+ * Copy a maximum of 'n' characters from the tail of the circular buffer
+ * into a flat buffer pointed by 'buf'. If the circular buffer is
+ * smaller than n, less bytes are copied.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ * @param buf
+ * The pointer to the buffer.
+ * @param n
+ * Maximum number of bytes to copy.
+ * @return
+ * Return the number of copied chars.
+ */
+int ucg_cirbuf_get_buf_tail(const struct ucg_cirbuf *cbuf, char *buf,
+ unsigned n);
+
+/**
+ * Set the start of the data to the index 0 of the internal buffer.
+ *
+ * After a call to this function, it is possible for the caller to
+ * use cbuf->buf as a linear (read-only) buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ */
+void ucg_cirbuf_align_left(struct ucg_cirbuf *cbuf);
+
+/**
+ * Set the end of the data to the last index of the internal buffer.
+ *
+ * After a call to this function, it is possible for the caller to
+ * use cbuf->buf as a linear (read-only) buffer.
+ *
+ * @param cbuf
+ * The circular buffer pointer.
+ */
+void ucg_cirbuf_align_right(struct ucg_cirbuf *cbuf);
+
+#endif /* CIRBUF_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include <ucg_cirbuf.h>
+
+/* init a circular buffer */
+void
+ucg_cirbuf_init(struct ucg_cirbuf *cbuf, char *buf, unsigned start,
+ unsigned maxlen)
+{
+ cbuf->maxlen = maxlen;
+ cbuf->len = 0;
+ cbuf->start = start;
+ cbuf->buf = buf;
+}
+
+/* return the index of the tail (contains an empty element) */
+static unsigned
+ucg_cirbuf_get_end(const struct ucg_cirbuf *cbuf)
+{
+ unsigned end;
+
+ end = cbuf->start + cbuf->len;
+ if (end >= cbuf->maxlen)
+ end -= cbuf->maxlen;
+
+ return end;
+}
+
+/* multiple add at head */
+int
+ucg_cirbuf_add_buf_head(struct ucg_cirbuf *cbuf, const char *buf, unsigned n)
+{
+ unsigned remain = n;
+ int copy_start;
+ unsigned copy_len;
+
+ if (remain == 0 || remain > ucg_cirbuf_get_freelen(cbuf))
+ return -EINVAL;
+
+ copy_start = cbuf->start - remain;
+ if (copy_start < 0)
+ copy_start += cbuf->maxlen;
+ cbuf->start = copy_start;
+ cbuf->len += remain;
+ copy_len = remain;
+ if ((unsigned)copy_start + copy_len >= cbuf->maxlen)
+ copy_len = cbuf->maxlen - copy_start;
+ if (copy_len > 0) {
+ memcpy(cbuf->buf + copy_start, buf, copy_len);
+ buf += copy_len;
+ remain -= copy_len;
+ }
+ if (remain == 0)
+ return n;
+
+ copy_len = remain;
+ memcpy(cbuf->buf, buf, copy_len);
+
+ return n;
+}
+
+/* multiple add at tail */
+int
+ucg_cirbuf_add_buf_tail(struct ucg_cirbuf *cbuf, const char *buf, unsigned n)
+{
+ unsigned remain = n;
+ unsigned copy_start, copy_len;
+
+ if (remain == 0 || remain > ucg_cirbuf_get_freelen(cbuf))
+ return -EINVAL;
+
+ copy_start = ucg_cirbuf_get_end(cbuf);
+ cbuf->len += remain;
+ copy_len = remain;
+ if (copy_start + copy_len >= cbuf->maxlen)
+ copy_len = cbuf->maxlen - copy_start;
+ if (copy_len > 0) {
+ memcpy(cbuf->buf + copy_start, buf, copy_len);
+ buf += copy_len;
+ remain -= copy_len;
+ }
+ if (remain == 0)
+ return n;
+
+ copy_len = remain;
+ memcpy(cbuf->buf, buf, copy_len);
+
+ return n;
+}
+
+/* single add at head */
+static inline void
+__cirbuf_add_head(struct ucg_cirbuf *cbuf, char c)
+{
+ unsigned start = cbuf->start;
+
+ if (start == 0)
+ start = cbuf->maxlen - 1;
+ else
+ start = start - 1;
+ cbuf->buf[start] = c;
+ cbuf->start = start;
+ cbuf->len++;
+}
+
+/* single add at head, checking if full first */
+int
+ucg_cirbuf_add_head_safe(struct ucg_cirbuf *cbuf, char c)
+{
+ if (!ucg_cirbuf_is_full(cbuf)) {
+ __cirbuf_add_head(cbuf, c);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* single add at head */
+void
+ucg_cirbuf_add_head(struct ucg_cirbuf *cbuf, char c)
+{
+ __cirbuf_add_head(cbuf, c);
+}
+
+/* single add at tail */
+static inline void
+__cirbuf_add_tail(struct ucg_cirbuf *cbuf, char c)
+{
+ unsigned end = ucg_cirbuf_get_end(cbuf);
+
+ cbuf->buf[end] = c;
+ cbuf->len++;
+}
+
+/* single add at tail, checking if full first */
+int
+ucg_cirbuf_add_tail_safe(struct ucg_cirbuf *cbuf, char c)
+{
+ if (!ucg_cirbuf_is_full(cbuf)) {
+ __cirbuf_add_tail(cbuf, c);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* single add at tail */
+void
+ucg_cirbuf_add_tail(struct ucg_cirbuf *cbuf, char c)
+{
+ __cirbuf_add_tail(cbuf, c);
+}
+
+/* multiple delete at head */
+int
+ucg_cirbuf_del_buf_head(struct ucg_cirbuf *cbuf, unsigned size)
+{
+ if (size == 0 || size > ucg_cirbuf_get_len(cbuf))
+ return -EINVAL;
+
+ cbuf->len -= size;
+ if (ucg_cirbuf_is_empty(cbuf)) {
+ cbuf->start += size - 1;
+ cbuf->start %= cbuf->maxlen;
+ }
+ else {
+ cbuf->start += size;
+ cbuf->start %= cbuf->maxlen;
+ }
+ return 0;
+}
+
+/* multiple delete at tail */
+int
+ucg_cirbuf_del_buf_tail(struct ucg_cirbuf *cbuf, unsigned size)
+{
+ if (size == 0 || size > ucg_cirbuf_get_len(cbuf))
+ return -EINVAL;
+
+ cbuf->len -= size;
+ return 0;
+}
+
+/* single del at head */
+static inline void
+__cirbuf_del_head(struct ucg_cirbuf *cbuf)
+{
+ cbuf->len --;
+ if (!ucg_cirbuf_is_empty(cbuf)) {
+ cbuf->start ++;
+ cbuf->start %= cbuf->maxlen;
+ }
+}
+
+/* single del at head, checking if empty first */
+int
+ucg_cirbuf_del_head_safe(struct ucg_cirbuf *cbuf)
+{
+ if (cbuf && !ucg_cirbuf_is_empty(cbuf)) {
+ __cirbuf_del_head(cbuf);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* single del at head */
+void
+ucg_cirbuf_del_head(struct ucg_cirbuf *cbuf)
+{
+ __cirbuf_del_head(cbuf);
+}
+
+/* single del at tail */
+static inline void
+__cirbuf_del_tail(struct ucg_cirbuf *cbuf)
+{
+ cbuf->len--;
+}
+
+/* single del at tail, checking if empty first */
+int
+ucg_cirbuf_del_tail_safe(struct ucg_cirbuf *cbuf)
+{
+ if (cbuf && !ucg_cirbuf_is_empty(cbuf)) {
+ __cirbuf_del_tail(cbuf);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* single del at tail */
+void
+ucg_cirbuf_del_tail(struct ucg_cirbuf *cbuf)
+{
+ __cirbuf_del_tail(cbuf);
+}
+
+/* convert to buffer */
+int
+ucg_cirbuf_get_buf_head(const struct ucg_cirbuf *cbuf, char *buf, unsigned n)
+{
+ unsigned remain = n;
+ unsigned cirbuf_len, copy_start, copy_len;
+
+ cirbuf_len = ucg_cirbuf_get_len(cbuf);
+ if (remain >= cirbuf_len)
+ remain = cirbuf_len;
+
+ if (remain == 0)
+ return 0;
+
+ copy_start = cbuf->start;
+ copy_len = remain;
+ if (copy_start + copy_len >= cbuf->maxlen)
+ copy_len = cbuf->maxlen - copy_start;
+ if (copy_len > 0) {
+ memcpy(buf, cbuf->buf + copy_start, copy_len);
+ buf += copy_len;
+ remain -= copy_len;
+ }
+ if (remain == 0)
+ return n;
+
+ copy_len = remain;
+ memcpy(buf, cbuf->buf, copy_len);
+
+ return n;
+}
+
+/* convert to buffer */
+int
+ucg_cirbuf_get_buf_tail(const struct ucg_cirbuf *cbuf, char *buf, unsigned n)
+{
+ unsigned remain = n;
+ int copy_start;
+ unsigned cirbuf_len, copy_len;
+
+ cirbuf_len = ucg_cirbuf_get_len(cbuf);
+ if (remain >= cirbuf_len)
+ remain = cirbuf_len;
+
+ if (remain == 0)
+ return 0;
+
+ copy_start = ucg_cirbuf_get_end(cbuf) - remain;
+ if (copy_start < 0)
+ copy_start += cbuf->maxlen;
+ copy_len = remain;
+ if ((unsigned)copy_start + copy_len >= cbuf->maxlen)
+ copy_len = cbuf->maxlen - copy_start;
+ if (copy_len > 0) {
+ memcpy(buf, cbuf->buf + copy_start, copy_len);
+ buf += copy_len;
+ remain -= copy_len;
+ }
+ if (remain == 0)
+ return n;
+
+ copy_len = remain;
+ memcpy(buf, cbuf->buf, copy_len);
+
+ return n;
+}
+
+/* get head */
+char
+ucg_cirbuf_get_head(const struct ucg_cirbuf *cbuf)
+{
+ return cbuf->buf[cbuf->start];
+}
+
+/* get tail */
+char
+ucg_cirbuf_get_tail(const struct ucg_cirbuf *cbuf)
+{
+ unsigned end;
+
+ /* should not happen */
+ if (cbuf->len == 0)
+ return 0;
+
+ end = cbuf->start + cbuf->len - 1;
+ if (end >= cbuf->maxlen)
+ end -= cbuf->maxlen;
+ return cbuf->buf[end];
+}
+
+static void
+__ucg_cirbuf_shift(struct ucg_cirbuf *cbuf, unsigned n)
+{
+ char tmp, tmp2;
+ unsigned start, cur, min;
+
+ start = 0;
+ cur = 0;
+ tmp = cbuf->buf[0];
+ min = cbuf->maxlen;
+
+ while (1) {
+ cur = cur + n;
+ if (cur >= cbuf->maxlen)
+ cur -= cbuf->maxlen;
+ tmp2 = cbuf->buf[cur];
+ cbuf->buf[cur] = tmp;
+ tmp = tmp2;
+ if (cur == start) {
+ if ((cur + 1) == min)
+ break;
+ cur++;
+ tmp = cbuf->buf[cur];
+ start = cur;
+ } else if (cur < min) {
+ min = cur;
+ }
+ }
+
+ cbuf->start += n;
+ if (cbuf->start >= cbuf->maxlen)
+ cbuf->start -= cbuf->maxlen;
+}
+
+void ucg_cirbuf_align_left(struct ucg_cirbuf *cbuf)
+{
+ __ucg_cirbuf_shift(cbuf, cbuf->maxlen - cbuf->start);
+}
+
+void ucg_cirbuf_align_right(struct ucg_cirbuf *cbuf)
+{
+ unsigned end = ucg_cirbuf_get_end(cbuf);
+ __ucg_cirbuf_shift(cbuf, cbuf->maxlen - end);
+}
+
+#ifdef TEST_CIRBUF
+#include <stdint.h>
+#include <assert.h>
+
+void dump_it(struct ucg_cirbuf * cbuf)
+{
+ unsigned i;
+ int idx;
+ char e;
+
+ printf("sta=%2.2d len=%2.2d/%2.2d { ",
+ cbuf->start,
+ ucg_cirbuf_get_len(cbuf),
+ ucg_cirbuf_get_maxlen(cbuf));
+
+ for (i = 0; i < ucg_cirbuf_get_maxlen(cbuf); i++) {
+ idx = i - cbuf->start;
+ if (idx < 0)
+ idx += cbuf->maxlen;
+ if (idx < (int)ucg_cirbuf_get_len(cbuf))
+ printf("%2.2x, ", cbuf->buf[i] & 0xFF);
+ else
+ printf("XX, ");
+ }
+ printf("} -> ");
+
+ printf("[ ");
+ UCG_CIRBUF_FOREACH(cbuf, i, e) {
+ printf("%2.2x, ", e & 0xFF);
+ }
+ printf("]\n");
+}
+
+int main(void)
+{
+ unsigned i;
+ struct ucg_cirbuf my_fifo;
+ char fifo_buf[16];
+
+ char buf1[] = { 0x10, 0x11, 0x12 };
+ char buf2[] = { 0x20, 0x21, 0x22, 0x23 };
+
+ char tmp_buf[16];
+ char ref_buf[] = { 0x20, 0x21, 0x22, 0x23, 0x01, 0x10, 0x11, 0x12 };
+
+ /* Test 1 */
+
+ printf("Test 1\n");
+
+ ucg_cirbuf_init(&my_fifo, fifo_buf, 0, 4);
+ assert(ucg_cirbuf_is_empty(&my_fifo));
+ assert(!ucg_cirbuf_is_full(&my_fifo));
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_add_tail(&my_fifo, 1);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 1);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 1);
+ dump_it(&my_fifo);
+
+
+ ucg_cirbuf_add_tail(&my_fifo, 2);
+ assert(!ucg_cirbuf_is_empty(&my_fifo));
+ assert(!ucg_cirbuf_is_full(&my_fifo));
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_add_tail(&my_fifo, 3);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 1);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 3);
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_add_tail(&my_fifo, 4);
+ assert(!ucg_cirbuf_is_empty(&my_fifo));
+ assert(ucg_cirbuf_is_full(&my_fifo));
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_del_tail(&my_fifo);
+ dump_it(&my_fifo);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 3);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 1);
+
+ ucg_cirbuf_del_head(&my_fifo);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 3);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 2);
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_del_head(&my_fifo);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 3);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 3);
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_del_head(&my_fifo);
+ assert(ucg_cirbuf_is_empty(&my_fifo));
+ dump_it(&my_fifo);
+
+
+ /* Test 2 */
+
+ printf("Test 2\n");
+
+ ucg_cirbuf_init(&my_fifo, fifo_buf, 2, 4);
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_add_head(&my_fifo, 4);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 4);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 4);
+ dump_it(&my_fifo);
+
+
+ ucg_cirbuf_add_head(&my_fifo, 3);
+ assert(!ucg_cirbuf_is_empty(&my_fifo));
+ assert(!ucg_cirbuf_is_full(&my_fifo));
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_add_head(&my_fifo, 2);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 2);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 4);
+ dump_it(&my_fifo);
+
+ ucg_cirbuf_add_head(&my_fifo, 1);
+ assert(!ucg_cirbuf_is_empty(&my_fifo));
+ assert(ucg_cirbuf_is_full(&my_fifo));
+ dump_it(&my_fifo);
+
+
+ /* Test 3 */
+
+ printf("Test 3\n");
+
+ for (i = 0; i < 16; i++) {
+ ucg_cirbuf_init(&my_fifo, fifo_buf, i, 16);
+ dump_it(&my_fifo);
+ ucg_cirbuf_add_buf_head(&my_fifo, buf1, sizeof(buf1));
+ dump_it(&my_fifo);
+ ucg_cirbuf_add_head(&my_fifo, 1);
+ dump_it(&my_fifo);
+ ucg_cirbuf_add_buf_head(&my_fifo, buf2, sizeof(buf2));
+ dump_it(&my_fifo);
+ ucg_cirbuf_get_buf_head(&my_fifo, tmp_buf, sizeof(tmp_buf));
+ assert(memcmp(tmp_buf, ref_buf, sizeof(ref_buf)) == 0);
+ }
+
+ /* Test 4 */
+
+ printf("Test 4\n");
+
+ for (i = 0; i < 16; i++) {
+ ucg_cirbuf_init(&my_fifo, fifo_buf, i, 16);
+ dump_it(&my_fifo);
+ ucg_cirbuf_add_buf_tail(&my_fifo, buf2, sizeof(buf2));
+ dump_it(&my_fifo);
+ ucg_cirbuf_add_tail(&my_fifo, 1);
+ dump_it(&my_fifo);
+ ucg_cirbuf_add_buf_tail(&my_fifo, buf1, sizeof(buf1));
+ dump_it(&my_fifo);
+ ucg_cirbuf_get_buf_tail(&my_fifo, tmp_buf, sizeof(tmp_buf));
+ assert(memcmp(tmp_buf, ref_buf, sizeof(ref_buf)) == 0);
+
+ printf("align left\n");
+ ucg_cirbuf_align_left(&my_fifo);
+ dump_it(&my_fifo);
+ ucg_cirbuf_get_buf_tail(&my_fifo, tmp_buf, sizeof(tmp_buf));
+ assert(memcmp(tmp_buf, ref_buf, sizeof(ref_buf)) == 0);
+ assert(my_fifo.start == 0);
+
+ printf("align right\n");
+ ucg_cirbuf_align_right(&my_fifo);
+ dump_it(&my_fifo);
+ ucg_cirbuf_get_buf_tail(&my_fifo, tmp_buf, sizeof(tmp_buf));
+ assert(memcmp(tmp_buf, ref_buf, sizeof(ref_buf)) == 0);
+ assert(my_fifo.start + my_fifo.len == my_fifo.maxlen);
+ }
+
+ /* Test 5 */
+
+ printf("Test 5\n");
+
+ ucg_cirbuf_init(&my_fifo, fifo_buf, 10, 16);
+ dump_it(&my_fifo);
+ i = 0;
+ while (ucg_cirbuf_add_tail_safe(&my_fifo, i) == 0)
+ i++;
+ dump_it(&my_fifo);
+ ucg_cirbuf_del_buf_tail(&my_fifo, 10);
+ dump_it(&my_fifo);
+ assert(ucg_cirbuf_get_len(&my_fifo) == 6);
+ assert(ucg_cirbuf_del_buf_tail(&my_fifo, 10) != 0);
+ assert(ucg_cirbuf_get_tail(&my_fifo) == 5);
+ assert(ucg_cirbuf_get_head(&my_fifo) == 0);
+
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_H_
+#define UCG_CMD_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#ifdef UCG_CMD_HAVE_TERMIOS
+#include <termios.h>
+#endif
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd_rdline.h"
+
+/**
+ * A command line structure.
+ */
+struct ucg_cmd {
+ ucg_cmd_ctx_t *ctx; /**< The list of commands for this context. */
+ struct ucg_rdline rdl; /**< The associated rdline structure. */
+ char prompt[UCG_RDLINE_PROMPT_SIZE]; /**< The command line prompt. */
+#ifdef UCG_CMD_HAVE_TERMIOS
+ struct termios oldterm; /**< The old termios info */
+#endif
+ void *opaque; /**< A user opaque pointer. */
+};
+
+/**
+ * Allocate and initialize a new command line structure
+ *
+ * Allocate and initialize a new command line structure, using the
+ * specified context, prompt and input/output streams.
+ *
+ * Once unused, the command line structure should be freed using
+ * ucg_cmd_free().
+ *
+ * @param ctx
+ * The command line context.
+ * @param prompt
+ * The command line prompt. The string is copied in the ucg_cmd
+ * structure. The prompt must be smaller than UCG_RDLINE_PROMPT_SIZE.
+ * @param f_in
+ * The input stream.
+ * @param f_out
+ * The output stream.
+ * @return
+ * The newly allocated command line structure.
+ */
+struct ucg_cmd *ucg_cmd_new(ucg_cmd_ctx_t *ctx,
+ const char *prompt, FILE *f_in, FILE *f_out);
+
+/**
+ * Initialize a new command line structure
+ *
+ * Initialize a command line structure, using the specified prompt and
+ * specified input/output streams.
+ *
+ * @param cl
+ * The uninitialize command line structure
+ * @param ctx
+ * The command line context
+ * @param prompt
+ * The command line prompt. The string is copied in the ucg_cmd
+ * structure. The prompt must be smaller than UCG_RDLINE_PROMPT_SIZE.
+ * @param f_in
+ * The input stream
+ * @param f_out
+ * The output stream
+ */
+void ucg_cmd_init(struct ucg_cmd *cl, ucg_cmd_ctx_t *ctx,
+ const char *prompt, FILE *f_in, FILE *f_out);
+
+/**
+ * Set the prompt of the given command line.
+ */
+void ucg_cmd_set_prompt(struct ucg_cmd *cl, const char *prompt);
+
+/**
+ * Free a previously allocated command line
+ *
+ * The structure pointed by cl is freed. The streams f_in and f_out are
+ * closed, except if it's stdin, stdout, or stderr. Note: the user
+ * should call ucg_cmd_quit() before calling this function.
+ *
+ * @param cl
+ * The command line pointer.
+ */
+void ucg_cmd_free(struct ucg_cmd *cl);
+
+/**
+ * Parse a file use the given cmd context
+ *
+ * The output file descriptor (used for instance by cmd_printf) is
+ * given as a parameter. It can be -1 if no output is required.
+ */
+struct ucg_cmd *ucg_cmd_file_new(ucg_cmd_ctx_t *ctx,
+ const char *prompt, const char *path, FILE *f_out);
+
+/**
+ * Print data on the output of the command line
+ *
+ * This function is a wrapper to rdline_printf().
+ *
+ * @param cl
+ * The command line pointer.
+ * @param fmt
+ * The format string, followed by variable arguments.
+ * @return
+ * On success, return the number of characters printed (not including
+ * the trailing '\0'). On error, a negative value is returned.
+ */
+int ucg_cmd_printf(struct ucg_cmd *cl, const char *fmt, ...);
+
+/**
+ * Push an input buffer to the command line.
+ *
+ * Typically, this function is called by ucg_cmd_interact() to send the
+ * input characters to the command line process. It can also be called
+ * by a user, for instance when new data is received from an input
+ * socket.
+ *
+ * @param cl
+ * The command line pointer.
+ * @param buf
+ * The address of the input buffer.
+ * @param size
+ * The len of the input buffer.
+ * @return
+ * The function returns the number of processed characters, or a
+ * negative value on error (ex: EOF reached or command line exited).
+ */
+int ucg_cmd_in(struct ucg_cmd *cl, const char *buf, int size);
+
+/* flags for ucg_cmd_interact */
+#define UCG_CMD_F_IGNORE_EOF 0x0001 /**< ignore eof when polling */
+
+/**
+ * Start command line on configured file descriptor. This function
+ * loops until the user explicitelly call ucg_cmd_quit(), or if the
+ * input fd reaches EOF.
+ *
+ * @param cl
+ * The command line pointer
+ * @param flags
+ * Any flags from UCG_CMD_F_*
+ * - UCG_CMD_F_IGNORE_EOF: on eof, clear error and continue polling
+ */
+void ucg_cmd_interact(struct ucg_cmd *cl, unsigned flags);
+
+/**
+ * Stop a running command line.
+ *
+ * Actually it will call ucg_rdline_quit() on the associated rdline.
+ *
+ * @param cl
+ * The command line pointer.
+ */
+void ucg_cmd_quit(struct ucg_cmd *cl);
+
+#endif /* UCG_CMD_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_PARSE_H_
+#define UCG_CMD_PARSE_H_
+
+#include <sys/types.h>
+
+#ifndef offsetof
+#define offsetof(type, field) ((size_t) &( ((type *)0)->field) )
+#endif
+
+// XXX config
+#define UCG_CMD_MAX_TOKEN_SIZE 32 /* including '\0' */
+#define UCG_CMD_MAX_DSTBUF_SIZE 128
+
+/**
+ * A token header.
+ *
+ * Stores a pointer to the ops struct, and the offset: the place to
+ * write the parsed result in the destination structure.
+ */
+struct ucg_cmd_tk_hdr {
+ struct ucg_cmd_tk_ops *ops;
+ unsigned int offset;
+};
+typedef struct ucg_cmd_tk_hdr ucg_cmd_tk_hdr_t;
+
+/**
+ * Operations on token.
+ */
+struct ucg_cmd_tk_ops {
+ /**
+ * parse() converts a buffer containing a token into its parsed
+ * value. Ex: an integer string is converted into its integer
+ * value. The result is stored in "result" whose size is
+ * "res_size". It returns 0 on success and a negative value on
+ * error.
+ */
+ int (*parse)(ucg_cmd_tk_hdr_t *tk, const char *line,
+ void *result, unsigned int res_size);
+
+ /**
+ * complete_start() prepares a completion operation. The
+ * "opaque" arg is an opaque pointer that will be given to
+ * complete_iterate() function. It can be used to store private
+ * data for this completion. For each complete_start() call, the
+ * user must call complete_end() at the end of iterations (if
+ * defined) in case some data have to be freed.
+ *
+ * Return a negative value if completion is not possible, or 0
+ * on success.
+ */
+ int (*complete_start)(ucg_cmd_tk_hdr_t *tk, const char *line,
+ void **opaque);
+
+ /**
+ * complete_iterate() copy in "dst" buffer the next possible
+ * completion for this token. Return 0 on success (final
+ * completion = completion until the end of the token), 1 if
+ * it's an intermediate completion (token not fully completed),
+ * or a negative value on error (or when there is no more
+ * completion). Refer to ucg_cmd_complete_string_iterate() for
+ * an example.
+ */
+ int (*complete_iterate)(ucg_cmd_tk_hdr_t *tk, void **opaque,
+ char *dst, unsigned int dst_size);
+
+ /**
+ * complete_end() is called when the iteration on this token is
+ * finished, this function should free all things allocated
+ * during complete_start().
+ */
+ void (*complete_end)(ucg_cmd_tk_hdr_t *tk, void **opaque);
+
+ /**
+ * help() fills the dstbuf with the help for the token. It returns
+ * -1 on error and 0 on success.
+ */
+ int (*help)(ucg_cmd_tk_hdr_t *tk, char *dst, unsigned int dst_size);
+};
+
+struct ucg_cmd;
+
+/**
+ * Store a command, defined by a list of tokens and a callback function.
+ */
+struct ucg_cmd_inst {
+ /** callback function when the commend is parsed */
+ void (*f)(void *parsed_result, struct ucg_cmd *cl, void *opaque);
+ void *data; /**< opaque pointer given as is to the callback */
+ char *help_str; /**< help for this command */
+ ucg_cmd_tk_hdr_t *tokens[]; /**< list of tokens */
+};
+typedef struct ucg_cmd_inst ucg_cmd_inst_t;
+
+/**
+ * A context is a list of commands.
+ */
+struct ucg_cmd_ctx {
+ const char *name; /**< The name of the context */
+ const ucg_cmd_inst_t *insts[]; /**< List of commands */
+};
+typedef struct ucg_cmd_ctx ucg_cmd_ctx_t;
+
+/* return status for parsing */
+#define UCG_CMD_PARSE_SUCCESS 0
+#define UCG_CMD_PARSE_EMPTY -1
+#define UCG_CMD_PARSE_NOMATCH -2
+#define UCG_CMD_PARSE_AMBIGUOUS -3
+#define UCG_CMD_PARSE_UNTERMINATED_QUOTE -4
+
+/**
+ * Try to parse a buffer according to the specified context. The
+ * argument linebuf must end with "\n\0".
+ *
+ * The function returns:
+ * - UCG_CMD_PARSE_SUCCESS (0) on success
+ * - UCG_CMD_PARSE_EMPTY if there is nothing to parse
+ * - UCG_CMD_PARSE_NOMATCH if line does not match any command
+ * - UCG_CMD_PARSE_AMBIGUOUS if several commands match
+ * - UCG_CMD_PARSE_UNTERMINATED_QUOTE if a quote is used incorrectly
+ */
+int ucg_cmd_parse(struct ucg_cmd *cl, const char *linebuf, void *opaque);
+
+/* return status for completion */
+#define UCG_CMD_COMPLETE_APPEND 0
+#define UCG_CMD_COMPLETE_NONE -1
+#define UCG_CMD_COMPLETE_MANY -2
+
+/**
+ * ucg_cmd_complete() tries to complete the buffer given as a parameter.
+ *
+ * It returns:
+ * - UCG_CMD_COMPLETE_APPEND (0) on success, when a completion is
+ * done (one possible choice). In this case, the chars are
+ * appended in dst buffer.
+ * - UCG_CMD_COMPLETE_NONE: error, no possible completion
+ * - UCG_CMD_COMPLETE_MANY: error, many possble completions, need to call
+ * ucg_cmd_help() function to see all the possibilities.
+ */
+int ucg_cmd_complete(struct ucg_cmd *cl, const char *buf, char *dst,
+ unsigned int size);
+
+/**
+ * Display a contextual help.
+ *
+ * @param cl
+ * The command line pointer
+ * @param line
+ * The current line buffer.
+ */
+void ucg_cmd_help(struct ucg_cmd *cl, const char *line);
+
+/**
+ * Check if the character ends a token
+ *
+ * @param c
+ * The character.
+ * @return
+ * True if (c == '\0' || iscomment(c) || isblank(c) ||
+ * isendofline(c))
+ */
+int ucg_cmd_isendoftoken(char c);
+
+/**
+ * Quote a string and escape original quotes
+ *
+ * @param dst
+ * The destination buffer.
+ * @param dstlen
+ * The length of the destination buffer.
+ * @param src
+ * The source buffer.
+ * @return
+ * Return 0 on success, a negative value on error.
+ */
+int ucg_cmd_quote_token(char *dst, unsigned dstlen, const char *src);
+
+/**
+ * Get one token
+ *
+ * The function removes quotes (if any) and stop copying when the end of
+ * token is reached. The destination buffer is '\0'-terminated.
+ *
+ * @param dst
+ * The destination buffer.
+ * @param dstlen
+ * The length of the destination buffer.
+ * @param src
+ * The source buffer.
+ * @return
+ * Return the number of "consumed" bytes from the source buffer, or
+ * a negative value on error
+ */
+int ucg_cmd_get_token(char *dst, unsigned dstlen, const char *src);
+
+#endif /* UCG_CMD_PARSE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PARSE_ETHERADDR_H_
+#define _PARSE_ETHERADDR_H_
+
+#include "ucg_cmd_parse.h"
+
+struct ucg_cmd_tk_etheraddr_data {
+ uint8_t flags;
+};
+
+struct ucg_cmd_tk_etheraddr {
+ struct ucg_cmd_tk_hdr hdr;
+};
+typedef struct ucg_cmd_tk_etheraddr ucg_cmd_tk_etheraddr_t;
+
+extern struct ucg_cmd_tk_ops ucg_cmd_tk_etheraddr_ops;
+
+#define UCG_CMD_TK_ETHERADDR(structure, field) \
+{ \
+ .hdr = { \
+ .ops = &cmd_token_etheraddr_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+}
+
+
+#endif /* _PARSE_ETHERADDR_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_PARSE_FILE_H_
+#define UCG_CMD_PARSE_FILE_H_
+
+#include "ucg_cmd_parse.h"
+
+/* size of a parsed file */
+#define UCG_FILENAME_SIZE UCG_CMD_MAX_TOKEN_SIZE
+
+typedef char ucg_cmd_filename_t[UCG_FILENAME_SIZE];
+
+#define PARSE_FILE_F_CREATE 0x01 /* file does not necessarilly exist */
+#define PARSE_FILE_F_DIRECTORY 0x02 /* must be a directory */
+struct ucg_cmd_tk_file_data {
+ int flags;
+};
+
+struct ucg_cmd_tk_file {
+ struct ucg_cmd_tk_hdr hdr;
+ struct ucg_cmd_tk_file_data file_data;
+};
+typedef struct ucg_cmd_tk_file ucg_cmd_tk_file_t;
+
+extern struct ucg_cmd_tk_ops ucg_cmd_tk_file_ops;
+
+#define UCG_CMD_TK_FILE(structure, field, node_flags) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_file_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .file_data = { \
+ .flags = node_flags, \
+ }, \
+}
+
+#endif /* UCG_CMD_PARSE_FILE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_PARSE_IPADDR_H_
+#define UCG_CMD_PARSE_IPADDR_H_
+
+#include "ucg_cmd_parse.h"
+
+#define UCG_CMD_IPADDR_V4 0x01
+#define UCG_CMD_IPADDR_V6 0x02
+#define UCG_CMD_IPADDR_NETWORK 0x04
+
+struct ucg_cmd_ipaddr {
+ uint8_t family;
+ union {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } addr;
+ unsigned int prefixlen; /* in case of network only */
+};
+typedef struct ucg_cmd_ipaddr ucg_cmd_ipaddr_t;
+
+struct ucg_cmd_tk_ipaddr_data {
+ uint8_t flags;
+};
+
+struct ucg_cmd_tk_ipaddr {
+ struct ucg_cmd_tk_hdr hdr;
+ struct ucg_cmd_tk_ipaddr_data ipaddr_data;
+};
+typedef struct ucg_cmd_tk_ipaddr ucg_cmd_tk_ipaddr_t;
+
+extern struct ucg_cmd_tk_ops ucg_cmd_tk_ipaddr_ops;
+
+#define UCG_CMD_TK_IPADDR(structure, field) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_ipaddr_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .ipaddr_data = { \
+ .flags = UCG_CMD_IPADDR_V4 | \
+ UCG_CMD_IPADDR_V6, \
+ }, \
+}
+
+#define UCG_CMD_TK_IPV4(structure, field) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_ipaddr_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .ipaddr_data = { \
+ .flags = UCG_CMD_IPADDR_V4, \
+ }, \
+}
+
+#define UCG_CMD_TK_IPV6(structure, field) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_ipaddr_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .ipaddr_data = { \
+ .flags = UCG_CMD_IPADDR_V6, \
+ }, \
+}
+
+#define UCG_CMD_TK_IPNET(structure, field) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_ipaddr_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .ipaddr_data = { \
+ .flags = UCG_CMD_IPADDR_V4 | \
+ UCG_CMD_IPADDR_V6 | \
+ UCG_CMD_IPADDR_NETWORK, \
+ }, \
+}
+
+#define UCG_CMD_TK_IPV4NET(structure, field) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_ipaddr_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .ipaddr_data = { \
+ .flags = UCG_CMD_IPADDR_V4 | \
+ UCG_CMD_IPADDR_NETWORK, \
+ }, \
+}
+
+#define UCG_CMD_TK_IPV6NET(structure, field) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_ipaddr_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .ipaddr_data = { \
+ .flags = UCG_CMD_IPADDR_V4 | \
+ UCG_CMD_IPADDR_NETWORK, \
+ }, \
+}
+
+#endif /* UCG_CMD_PARSE_IPADDR_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_PARSE_NUM_H_
+#define UCG_CMD_PARSE_NUM_H_
+
+#include "ucg_cmd_parse.h"
+
+enum ucg_cmd_numtype {
+ UINT8 = 0,
+ UINT16,
+ UINT32,
+ UINT64,
+ INT8,
+ INT16,
+ INT32,
+ INT64
+#ifndef NO_PARSE_FLOAT
+ ,FLOAT
+#endif
+};
+
+struct ucg_cmd_tk_num_data {
+ enum ucg_cmd_numtype type;
+};
+
+struct ucg_cmd_tk_num {
+ struct ucg_cmd_tk_hdr hdr;
+ struct ucg_cmd_tk_num_data num_data;
+};
+typedef struct ucg_cmd_tk_num ucg_cmd_tk_num_t;
+
+extern struct ucg_cmd_tk_ops ucg_cmd_tk_num_ops;
+
+#define UCG_CMD_TK_NUM(structure, field, numtype) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_num_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .num_data = { \
+ .type = numtype, \
+ }, \
+}
+
+#endif /* UCG_CMD_PARSE_NUM_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_PARSE_STRING_H_
+#define UCG_CMD_PARSE_STRING_H_
+
+#include "ucg_cmd_parse.h"
+
+/* size of a parsed string */
+#define UCG_STR_TOKEN_SIZE UCG_CMD_MAX_TOKEN_SIZE
+
+typedef char ucg_cmd_fixed_string_t[UCG_STR_TOKEN_SIZE];
+
+struct ucg_cmd_tk_string_data {
+ const char *str;
+};
+
+struct ucg_cmd_tk_string {
+ struct ucg_cmd_tk_hdr hdr;
+ struct ucg_cmd_tk_string_data string_data;
+};
+typedef struct ucg_cmd_tk_string ucg_cmd_tk_string_t;
+
+extern struct ucg_cmd_tk_ops ucg_cmd_tk_string_ops;
+
+#define UCG_CMD_TK_STRING(structure, field, string) \
+{ \
+ .hdr = { \
+ .ops = &ucg_cmd_tk_string_ops, \
+ .offset = offsetof(structure, field), \
+ }, \
+ .string_data = { \
+ .str = string, \
+ }, \
+}
+
+#endif /* UCG_CMD_PARSE_STRING_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CMD_RDLINE_H_
+#define CMD_RDLINE_H_
+
+/**
+ * This file is a small equivalent to the GNU readline library, it was
+ * originally designed for very small systems (an 8-bits Atmel AVR
+ * microcontroller), but the library can now run on many emmbedded
+ * systems with or without OS.
+ *
+ * Obviously, it does not support as many things as the GNU readline,
+ * but at least it supports some interresting features like a kill
+ * buffer and a command history.
+ *
+ * It also have a feature that does not have the GNU readline (as far
+ * as I know): it is possible to have several instances of readline
+ * running at the same time, even on a monothread program, since it
+ * works with callbacks.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#include <ucg_cirbuf.h>
+#include <ucg_cmd_vt100.h>
+
+/* configuration */
+#define UCG_RDLINE_BUF_SIZE 32
+#define UCG_RDLINE_PROMPT_SIZE 16
+#define UCG_RDLINE_VT100_BUF_SIZE 8
+#define UCG_RDLINE_HISTORY_BUF_SIZE 64
+#define UCG_RDLINE_MAX_LINES 23 /* pager */
+
+enum ucg_rdline_status {
+ UCG_RDLINE_STOPPED,
+ UCG_RDLINE_RUNNING,
+ UCG_RDLINE_EXITED
+};
+
+struct ucg_rdline;
+
+/**
+ * type of callback given to ucg_rdline_help() to display the content of
+ * the help. The first argument is the rdline pointer. The other args
+ * are buffer and size.
+ */
+typedef int (ucg_rdline_printf_t)(struct ucg_rdline *rdl,
+ const char *fmt, ...);
+
+/**
+ * type of callback invoked when a command is parsed. "rdl" is a pointer
+ * to the ucg_rdline structure, "line" is a pointer to the current line
+ * string ('\0' terminated).
+ */
+typedef void (ucg_rdline_validate_t)(struct ucg_rdline *rdl,
+ const char *line);
+
+/**
+ * type of callback invoked when a completion is requested. "rdl" is a
+ * pointer to the ucg_rdline structure, "line" is a pointer to the
+ * current line string ('\0' terminated). The characters to append
+ * are written to dstbuf.
+ * Return 0 on success: dstbuf contains the characters to append to
+ * the current line ('\0' terminated)
+ * Else return a negative value if no completion is performed.
+ */
+typedef int (ucg_rdline_complete_t)(struct ucg_rdline *rdl, const char *line,
+ char *dstbuf, unsigned int dstsize);
+
+/**
+ * callback invoked when a the help is requested. "rdl" is a pointer to
+ * the ucg_rdline structure, "line" is a pointer to the current line string
+ * ('\0' terminated).
+ */
+typedef void (ucg_rdline_help_t)(struct ucg_rdline *rdl, const char *line);
+
+typedef void (ucg_rdline_pager_cb_t)(struct ucg_rdline *, void *);
+
+struct ucg_rdline {
+ enum ucg_rdline_status status;
+ FILE *f_in;
+ FILE *f_out;
+
+ /* rdline bufs */
+ struct ucg_cirbuf left;
+ struct ucg_cirbuf right;
+ char left_buf[UCG_RDLINE_BUF_SIZE+1]; /* reserve 1 char for the \0 */
+ char right_buf[UCG_RDLINE_BUF_SIZE];
+
+ char prompt[UCG_RDLINE_PROMPT_SIZE];
+
+#ifndef UCG_CMD_NO_RDLINE_KILL_BUF
+ char kill_buf[UCG_RDLINE_BUF_SIZE];
+ unsigned int kill_size;
+#endif
+
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+ /* history */
+ struct ucg_cirbuf history;
+ char history_buf[UCG_RDLINE_HISTORY_BUF_SIZE];
+ int history_cur_line;
+#endif
+
+ /* callbacks and func pointers */
+ ucg_rdline_validate_t *validate;
+ ucg_rdline_complete_t *complete;
+ ucg_rdline_help_t *help;
+
+ /* vt100 parser */
+ struct ucg_cmd_vt100 vt100;
+
+ /* opaque pointer */
+ void *opaque;
+
+#ifndef UCG_CMD_NO_PAGER
+ char *pager_buf; /* buffer used to store paged data */
+ int pager_len; /* total len of buffer */
+ int pager_off; /* offset of next data */
+ int pager_lines; /* number of lines displayed */
+ ucg_rdline_pager_cb_t *pager_cb; /* callback once paging is finished */
+ void *pager_arg; /* argument of callback */
+ int pager_ret; /* saved return value */
+#endif
+};
+
+/**
+ * Init fields for a struct ucg_rdline.
+ *
+ * @param rdl A pointer to an uninitialized struct ucg_rdline
+ * @param fd_in
+ * Input file descriptor
+ * @param fd_out
+ * Output file descriptor
+ * @param validate
+ * A pointer to the function to execute when the user validates the
+ * buffer.
+ * @param complete
+ * A pointer to the function to execute when the user completes the
+ * buffer.
+ * @param help
+ * A pointer to the function to execute when the user ask for
+ * contextual help.
+ */
+void ucg_rdline_init(struct ucg_rdline *rdl,
+ FILE *f_in, FILE *f_out,
+ ucg_rdline_validate_t *validate,
+ ucg_rdline_complete_t *complete,
+ ucg_rdline_help_t *help);
+
+
+/**
+ * Init the current buffer, and display a prompt.
+ *
+ * Also set the rdline status to "running", overriding previous
+ * ucg_rdline_stop() or ucg_rdline_quit().
+ *
+ * @param rdl
+ * A pointer to an initialized struct ucg_rdline
+ * @param prompt
+ * A string containing the prompt, or NULL to keep existing one
+ */
+void ucg_rdline_newline(struct ucg_rdline *rdl, const char *prompt);
+
+/**
+ * Ignore all subsequent received chars.
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ */
+void ucg_rdline_stop(struct ucg_rdline *rdl);
+
+/**
+ * Exit from running rdline loop
+ *
+ * Same than ucg_rdline_stop() except that next calls to ucg_rdline_char_in()
+ * will return UCG_RDLINE_RES_EXITED. Hence, any running rdline() function is
+ * interrupted.
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ */
+void ucg_rdline_quit(struct ucg_rdline *rdl);
+
+/**
+ * Restart after a call to ucg_rdline_stop() or ucg_rdline_quit()
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ */
+void ucg_rdline_restart(struct ucg_rdline *rdl);
+
+/**
+ * Redisplay the current buffer
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ */
+void ucg_rdline_redisplay(struct ucg_rdline *rdl);
+
+/* return status for ucg_rdline_char_in() */
+#define UCG_RDLINE_RES_SUCCESS 0
+#define UCG_RDLINE_RES_VALIDATED 1
+#define UCG_RDLINE_RES_COMPLETED 2
+#define UCG_RDLINE_RES_NOT_RUNNING -1
+#define UCG_RDLINE_RES_EOF -2
+#define UCG_RDLINE_RES_EXITED -3
+#define UCG_RDLINE_RES_CANNOT_COMPLETE -3
+
+/**
+ * Append a char to the readline buffer.
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ * @param c
+ * The character to append
+ * @return
+ * - UCG_RDLINE_RES_VALIDATED when the line has been validated.
+ * - UCG_RDLINE_RES_NOT_RUNNING if it is not running.
+ * - UCG_RDLINE_RES_EOF if EOF (ctrl-d on an empty line).
+ * - UCG_RDLINE_RES_EXITED if user called ucg_rdline_quit()
+ * - Else return UCG_RDLINE_RES_SUCCESS.
+ */
+int ucg_rdline_char_in(struct ucg_rdline *rdl, char c);
+
+#define UCG_RDLINE_F_IGNORE_EOF 0x0001 /**< ignore eof when polling */
+
+/**
+ * Read (and edit) a line
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ * @param prompt
+ * The prompt string
+ * @param flags
+ * Any flags from UCG_RDLINE_F_*
+ * - UCG_RDLINE_F_IGNORE_EOF: on eof, clear error and continue polling
+ * @return
+ * - UCG_RDLINE_RES_VALIDATED when the line has been validated.
+ * - UCG_RDLINE_RES_NOT_RUNNING if it is not running.
+ * - UCG_RDLINE_RES_EOF if EOF (ctrl-d on an empty line).
+ * - UCG_RDLINE_RES_EXITED if user called ucg_rdline_quit()
+ */
+int ucg_rdline(struct ucg_rdline *rdl, const char *prompt, unsigned flags);
+
+/**
+ * write a buffer on rdline file descriptor
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param buf
+ * Pointer to the buffer
+ * @param count
+ * Number of bytes to write
+ * @return
+ * On success, the number of bytes written is returned (zero
+ * indicates nothing was written). On error, -1 is returned, and
+ * errno is set appropriately
+ */
+ssize_t ucg_rdline_write(struct ucg_rdline *rdl, void *buf, size_t count);
+
+/**
+ * write on rdline file descriptor according to a format string
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param fmt
+ * The format strings
+ * @return
+ * On success, return the number of characters printed (not including
+ * the trailing '\0'). On error, a negative value is returned.
+ */
+int ucg_rdline_printf(struct ucg_rdline *rdl, const char *fmt, ...);
+
+/**
+ * write on rdline file descriptor according to a format string
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param fmt
+ * The format strings
+ * @param ap
+ * Variable argument list
+ * @return
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings). On error, a negative value is returned.
+ */
+int ucg_rdline_vprintf(struct ucg_rdline *rdl, const char *fmt, va_list ap);
+
+/**
+ * Return the current buffer, terminated by '\0'.
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ * @return
+ * The rdline buffer
+ */
+const char *ucg_rdline_get_buffer(struct ucg_rdline *rdl);
+
+/**
+ * Add the buffer to history.
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ * @param buf
+ * A buffer that is terminated by '\0'
+ * @return
+ * - 0 on success
+ * - negative on error
+ */
+int ucg_rdline_add_history(struct ucg_rdline *rdl, const char *buf);
+
+/**
+ * Clear current history
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ */
+void ucg_rdline_clear_history(struct ucg_rdline *rdl);
+
+/**
+ * Get the i-th history item
+ *
+ * @param rdl
+ * A pointer to a struct ucg_rdline
+ * @param i
+ * The index of the history item
+ * @return
+ * The i-th string of history, or NULL on error.
+ */
+const char *ucg_rdline_get_history_item(struct ucg_rdline *rdl, unsigned int i);
+
+#ifndef UCG_CMD_NO_PAGER
+/**
+ * Write data asynchronously (using pager if needed)
+ *
+ * If there is enough place to print data on the current page, it is
+ * printed synchronously. Else, a temporary buffer is allocated and
+ * the data is stored in it. When the main rdline is called again, the
+ * pager is flushed before parsing any other commands.
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param buf
+ * Buffer to be sent
+ * @param len
+ * Length of buffer to be sent
+ * @return
+ * On success, the number of bytes written is returned (zero
+ * indicates nothing was written). On error, -1 is returned, and
+ * errno is set appropriately
+ */
+ssize_t ucg_rdline_pager_write(struct ucg_rdline *rdl, void *buf, size_t len);
+
+/**
+ * Print data asynchronously (using pager if needed)
+ *
+ * If there is enough place to print data on the current page, it is
+ * printed synchronously. Else, a temporary buffer is allocated and
+ * the data is stored in it. When the main rdline is called again, the
+ * pager is flushed before parsing any other commands.
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param fmt
+ * The format strings
+ * @return
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings). On error, a negative value is returned.
+ */
+int ucg_rdline_pager_printf(struct ucg_rdline *rdl, const char *fmt, ...);
+
+/**
+ * Set the callback for the pager
+ *
+ * If there is some data in the pager to be printed, set a callback
+ * function that will be called when all the data will be printed. If
+ * the pager is empty, don't do anything and return -1.
+ * @param rdl
+ * The rdline descriptor
+ * @return
+ * - 0 if there is some data in the pager buffer and the callback
+ * is loaded
+ * - -1 if there is no data in pager buffer (in this case the callback
+ * is not called)
+ */
+int ucg_rdline_pager_set_cb(struct ucg_rdline *rdl,
+ ucg_rdline_pager_cb_t *cb, void *arg);
+#endif
+
+#endif /* UCG_CMD_RDLINE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_SOCKET_H_
+#define UCG_CMD_SOCKET_H_
+
+#ifdef UCG_CMD_HAVE_SOCKET
+
+#include <arpa/inet.h>
+
+/**
+ * Helper to create a tcpv4 socket
+ */
+int ucg_cmd_tcpv4_listen(in_addr_t addr, uint16_t port);
+
+/**
+ * Helper to create a tcpv6 socket
+ */
+int ucg_cmd_tcpv6_listen(const struct in6_addr *addr6, uint16_t port);
+
+/**
+ * Helper to create a unix socket
+ */
+int ucg_cmd_unix_listen(const char *filename);
+
+/**
+ * Helper to call accept() and create a new cmd instance
+ */
+struct ucg_cmd *ucg_cmd_accept(ucg_cmd_ctx_t *ctx,
+ const char *prompt, int s);
+#endif
+
+#endif /* UCG_CMD_SOCKET_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_TERMIOS_H_
+#define UCG_CMD_TERMIOS_H_
+
+struct ucg_cmd;
+
+/**
+ * Set the pty in raw mode
+ *
+ * Save the previous configuration in the command line structure.
+ * It is restored with ucg_termios_restore(). The function does
+ * nothing if the platform does not support termios.
+ */
+int ucg_cmd_termios_raw(struct ucg_cmd *cl);
+
+/**
+ * Restore saved termios settings
+ */
+int ucg_cmd_termios_restore(struct ucg_cmd *cl);
+
+#endif /* UCG_CMD_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_VT100_H_
+#define UCG_CMD_VT100_H_
+
+#define ucg_vt100_bell "\007"
+#define ucg_vt100_bs "\010"
+#define ucg_vt100_bs_clear "\010 \010"
+#define ucg_vt100_tab "\011"
+#define ucg_vt100_crnl "\012\015"
+#define ucg_vt100_clear_right "\033[0K"
+#define ucg_vt100_clear_left "\033[1K"
+#define ucg_vt100_clear_down "\033[0J"
+#define ucg_vt100_clear_up "\033[1J"
+#define ucg_vt100_clear_line "\033[2K"
+#define ucg_vt100_clear_screen "\033[2J"
+#define ucg_vt100_up_arr "\033\133\101"
+#define ucg_vt100_down_arr "\033\133\102"
+#define ucg_vt100_right_arr "\033\133\103"
+#define ucg_vt100_left_arr "\033\133\104"
+#define ucg_vt100_multi_right "\033\133%uC"
+#define ucg_vt100_multi_left "\033\133%uD"
+#define ucg_vt100_suppr "\033\133\063\176"
+#define ucg_vt100_home "\033M\033E"
+#define ucg_vt100_word_left "\033\142"
+#define ucg_vt100_word_right "\033\146"
+
+/* Result of parsing : it must be synchronized with
+ * ucg_cmd_vt100_commands[] in vt100.c */
+#define UCG_CMD_KEY_UP_ARR 0
+#define UCG_CMD_KEY_DOWN_ARR 1
+#define UCG_CMD_KEY_RIGHT_ARR 2
+#define UCG_CMD_KEY_LEFT_ARR 3
+#define UCG_CMD_KEY_BKSPACE 4
+#define UCG_CMD_KEY_RETURN 5
+#define UCG_CMD_KEY_CTRL_A 6
+#define UCG_CMD_KEY_CTRL_E 7
+#define UCG_CMD_KEY_CTRL_K 8
+#define UCG_CMD_KEY_CTRL_Y 9
+#define UCG_CMD_KEY_CTRL_C 10
+#define UCG_CMD_KEY_CTRL_F 11
+#define UCG_CMD_KEY_CTRL_B 12
+#define UCG_CMD_KEY_SUPPR 13
+#define UCG_CMD_KEY_TAB 14
+#define UCG_CMD_KEY_CTRL_D 15
+#define UCG_CMD_KEY_CTRL_L 16
+#define UCG_CMD_KEY_RETURN2 17
+#define UCG_CMD_KEY_META_BKSPACE 18
+#define UCG_CMD_KEY_WLEFT 19
+#define UCG_CMD_KEY_WRIGHT 20
+#define UCG_CMD_KEY_HELP 21
+#define UCG_CMD_KEY_CTRL_W 22
+#define UCG_CMD_KEY_CTRL_P 23
+#define UCG_CMD_KEY_CTRL_N 24
+#define UCG_CMD_KEY_META_D 25
+
+extern const char *ucg_cmd_vt100_commands[];
+
+enum ucg_cmd_vt100_parser_state {
+ UCG_CMD_VT100_INIT,
+ UCG_CMD_VT100_ESCAPE,
+ UCG_CMD_VT100_ESCAPE_CSI
+};
+
+#define UCG_CMD_VT100_BUF_SIZE 8
+struct ucg_cmd_vt100 {
+ uint8_t bufpos;
+ char buf[UCG_CMD_VT100_BUF_SIZE];
+ enum ucg_cmd_vt100_parser_state state;
+};
+
+/**
+ * Init
+ */
+void ucg_vt100_init(struct ucg_cmd_vt100 *vt);
+
+#define UCG_VT100_STD_CHAR -1
+#define UCG_VT100_NOT_COMPLETE -2
+/**
+ * Input a new character.
+ * Return UCG_VT100_STD_CHAR if the character is not part of a control sequence
+ * Return UCG_VT100_NOT_COMPLETE if c is not the last char of a control sequence
+ * Else return the index in ucg_vt100_commands[]
+ */
+int ucg_vt100_parser(struct ucg_cmd_vt100 *vt, char c);
+
+#endif /* UCG_CMD_VT100_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd_rdline.h"
+#include "ucg_cmd.h"
+
+static void
+default_valid_buffer(struct ucg_rdline *rdl, const char *line)
+{
+ struct ucg_cmd *cl = rdl->opaque;
+ int ret;
+
+ ret = ucg_cmd_parse(cl, line, cl);
+ if (ret == UCG_CMD_PARSE_AMBIGUOUS)
+ ucg_cmd_printf(cl, "Ambiguous command\n");
+ else if (ret == UCG_CMD_PARSE_NOMATCH)
+ ucg_cmd_printf(cl, "Bad arguments\n");
+ else if (ret == UCG_CMD_PARSE_UNTERMINATED_QUOTE)
+ ucg_cmd_printf(cl, "Unterminated quote\n");
+}
+
+static int
+default_complete_buffer(struct ucg_rdline *rdl, const char *line,
+ char *dstbuf, unsigned int dstsize)
+{
+ int ret;
+ struct ucg_cmd *cl = rdl->opaque;
+ ret = ucg_cmd_complete(cl, line, dstbuf, dstsize);
+ if (ret == UCG_CMD_COMPLETE_APPEND)
+ return 0;
+ return -1;
+}
+
+
+static void
+default_help(struct ucg_rdline *rdl, const char *line)
+{
+ struct ucg_cmd *cl = rdl->opaque;
+
+ ucg_cmd_help(cl, line);
+}
+
+/* ---- Some rdline wrappers ---- */
+
+void
+ucg_cmd_set_prompt(struct ucg_cmd *cl, const char *prompt)
+{
+ snprintf(cl->prompt, sizeof(cl->prompt), "%s", prompt);
+}
+
+void
+ucg_cmd_init(struct ucg_cmd *cl, ucg_cmd_ctx_t *ctx,
+ const char *prompt, FILE *f_in, FILE *f_out)
+{
+ /* init cmd structure */
+ memset(cl, 0, sizeof(struct ucg_cmd));
+ cl->ctx = ctx;
+
+ /* init embedded rdline */
+ ucg_rdline_init(&cl->rdl, f_in, f_out,
+ default_valid_buffer,
+ default_complete_buffer,
+ default_help);
+
+ cl->rdl.opaque = cl;
+ ucg_cmd_set_prompt(cl, prompt);
+ ucg_rdline_newline(&cl->rdl, cl->prompt);
+}
+
+struct ucg_cmd *
+ucg_cmd_new(ucg_cmd_ctx_t *ctx, const char *prompt,
+ FILE *f_in, FILE *f_out)
+{
+ struct ucg_cmd *cl;
+
+ cl = malloc(sizeof(struct ucg_cmd));
+ if (cl == NULL)
+ return NULL;
+
+ ucg_cmd_init(cl, ctx, prompt, f_in, f_out);
+ return cl;
+}
+
+struct ucg_cmd *
+ucg_cmd_file_new(ucg_cmd_ctx_t *ctx, const char *prompt,
+ const char *path, FILE *f_out)
+{
+#if UCG_CMD_HAVE_FILE
+ FILE *f_in;
+
+ f_in = fopen(path, "r");
+ if (f_in == NULL)
+ return NULL;
+ return (ucg_cmd_new(ctx, prompt, f_in, f_out));
+#else
+ (void)ctx;
+ (void)prompt;
+ (void)path;
+ (void)f_out;
+ return NULL;
+#endif
+}
+
+void
+ucg_cmd_free(struct ucg_cmd *cl)
+{
+ struct ucg_rdline *rdl = &cl->rdl;
+
+ if (rdl->f_in != stdin)
+ fclose(rdl->f_in);
+ if (rdl->f_out != rdl->f_in && rdl->f_out != stdout &&
+ rdl->f_out != stderr)
+ fclose(rdl->f_out);
+ free(cl);
+}
+
+int
+ucg_cmd_printf(struct ucg_cmd *cl, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = ucg_rdline_vprintf(&cl->rdl, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/* Push an input buffer in the command line. Typically, this function
+ * is called by ucg_cmd_interact() to send the input characters to the
+ * cmd process. It can also be called by a user callback function,
+ * when a buffer is received from the input socket.
+ *
+ * The function returns the number of processed characters, or a
+ * negative value on error (EOF reached or command line exited. */
+int
+ucg_cmd_in(struct ucg_cmd *cl, const char *buf, int size)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ ret = ucg_rdline_char_in(&cl->rdl, buf[i]);
+
+ if (ret == UCG_RDLINE_RES_VALIDATED &&
+ cl->rdl.status == UCG_RDLINE_STOPPED)
+ break;
+
+ if (ret == UCG_RDLINE_RES_VALIDATED)
+ ucg_rdline_newline(&cl->rdl, cl->prompt);
+ else if (ret == UCG_RDLINE_RES_EOF)
+ return -1;
+ else if (ret == UCG_RDLINE_RES_EXITED)
+ return -1;
+ }
+ return i;
+}
+
+/* Interrupt a running command line (exits from ucg_cmd_interact) */
+void
+ucg_cmd_quit(struct ucg_cmd *cl)
+{
+ ucg_rdline_quit(&cl->rdl);
+}
+
+/* loop until the user explicitelly call ucg_cmd_quit(), or if the input
+ * fd reaches EOF. */
+void
+ucg_cmd_interact(struct ucg_cmd *cl, unsigned flags)
+{
+ int ret;
+ char c;
+
+ c = -1;
+ while (1) {
+ ret = fread(&c, 1, 1, cl->rdl.f_in);
+
+ if (ret == 0) {
+ if (flags & UCG_CMD_F_IGNORE_EOF) {
+ clearerr(cl->rdl.f_in);
+ continue;
+ }
+ break;
+ }
+
+ if (ucg_cmd_in(cl, &c, 1) < 0)
+ break;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd.h"
+
+//#define debug_printf printf
+#define debug_printf(args...) do {} while(0)
+
+/* used internally for ucg_cmd_help() and ucg_cmd_complete() */
+struct cmd_preparse {
+ int nb_valid_tok; /* number of valid tokens in the buffer */
+ void *opaque; /* pointer to opaque data */
+ char comp_tok_buf[UCG_CMD_MAX_TOKEN_SIZE]; /* token to complete */
+ size_t comp_tok_len; /* length of the token to complete */
+ size_t comp_tok_offset; /* offset of token to complete in the line buf */
+};
+
+/* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
+ * own. */
+static int
+isblank2(char c)
+{
+ if (c == ' ' || c == '\t' )
+ return 1;
+ return 0;
+}
+
+static int
+isendofline(char c)
+{
+ if (c == '\n' || c == '\r' )
+ return 1;
+ return 0;
+}
+
+static int
+iscomment(char c)
+{
+ if (c == '#')
+ return 1;
+ return 0;
+}
+
+int
+ucg_cmd_isendoftoken(char c)
+{
+ if (!c || iscomment(c) || isblank2(c) || isendofline(c))
+ return 1;
+ return 0;
+}
+
+static unsigned int
+nb_common_chars(const char * s1, const char * s2)
+{
+ unsigned int i=0;
+
+ while (*s1==*s2 && *s1 && *s2) {
+ s1++;
+ s2++;
+ i++;
+ }
+ return i;
+}
+
+/* quote a string and escape original quotes */
+int ucg_cmd_quote_token(char *dst, unsigned dstlen, const char *src)
+{
+ unsigned s = 0, d = 0;
+
+ /* the 2 quotes + '\0' */
+ if (dstlen < 3)
+ return -EMSGSIZE;
+
+ dst[d++] = '"';
+ while (src[s] != '\0') {
+ if (d >= (dstlen-2))
+ return -EMSGSIZE;
+
+ if (src[s] == '"')
+ dst[d++] = '\\';
+ if (src[s] == '\\' && src[s+1] == '"')
+ dst[d++] = '\\';
+
+ dst[d++] = src[s++];
+ }
+
+ if (d >= (dstlen-2))
+ return -EMSGSIZE;
+ dst[d++] = '"';
+ dst[d++] = '\0';
+ return 0;
+}
+
+/* Remove quotes and stop when we reach the end of token. Return the
+ * number of "eaten" bytes from the source buffer, or a negative value
+ * on error */
+int ucg_cmd_get_token(char *dst, unsigned dstlen, const char *src)
+{
+ unsigned s = 0, d = 0;
+ int quoted = 0;
+
+ /* skip spaces */
+ while (isblank2(src[s]))
+ s++;
+
+ /* empty token */
+ if (ucg_cmd_isendoftoken(src[s]))
+ return -EINVAL;
+
+ /* copy token and remove quotes */
+ while (src[s] != '\0') {
+ if (d >= dstlen)
+ return -EMSGSIZE;
+
+ if (ucg_cmd_isendoftoken(src[s]) && quoted == 0)
+ break;
+
+ if (src[s] == '\\' && src[s+1] == '"') {
+ dst[d++] = '"';
+ s += 2;
+ continue;
+ }
+ if (src[s] == '\\' && src[s+1] == '\\') {
+ dst[d++] = '\\';
+ s += 2;
+ continue;
+ }
+ if (src[s] == '"') {
+ s++;
+ quoted = !quoted;
+ continue;
+ }
+ dst[d++] = src[s++];
+ }
+
+ /* not enough room in dst buffer */
+ if (d >= (dstlen-1))
+ return -EMSGSIZE;
+
+ /* end of string during quote */
+ if (quoted)
+ return -EINVAL;
+
+ dst[d++] = '\0';
+ return s;
+}
+
+/* return the nth token from src and copy it in dst. Return the offset
+ * of the token in src, or a negative value on error. Note: the index
+ * of the first token is 0. */
+static int cmd_get_nth_token(char *dst, unsigned dstlen, int n,
+ const char *src)
+{
+ int ret = 0, offset = 0;
+
+ do {
+ offset += ret;
+
+ /* skip spaces */
+ while (isblank2(src[offset]))
+ offset++;
+
+ /* get the token starting at offset */
+ ret = ucg_cmd_get_token(dst, dstlen, src + offset);
+ if (ret < 0)
+ return ret;
+
+ } while (n--);
+
+ return offset;
+}
+
+/*
+ * try to match the buffer with an instruction (only the first
+ * nb_match_token tokens if != 0).
+ *
+ * Return 0 if we match all the tokens, else the number of matched
+ * tokens, or a negative value on error.
+*/
+static int
+match_inst(const ucg_cmd_inst_t *inst, const char *linebuf,
+ unsigned int nb_match_token, void *resbuf, unsigned resbuf_size)
+{
+ unsigned int token_num = 0;
+ ucg_cmd_tk_hdr_t *token;
+ int n = 0, res;
+ char token_str[UCG_CMD_MAX_TOKEN_SIZE];
+
+ token = inst->tokens[token_num];
+
+ /* check if we match all tokens of inst */
+ while (token) {
+
+ /* we matched enough tokens, return success */
+ if (nb_match_token != 0 && token_num >= nb_match_token)
+ return 0;
+
+ debug_printf("TK\n");
+
+ /* copy token and remove quotes */
+ n = ucg_cmd_get_token(token_str, sizeof(token_str), linebuf);
+ if (n < 0)
+ break;
+
+ /* parse this token */
+ if (resbuf == NULL)
+ res = token->ops->parse(token, token_str, NULL, 0);
+ else {
+ unsigned rb_sz;
+ void *rb = (char *)resbuf + token->offset;
+
+ /* not enough room to store result */
+ if (token->offset > resbuf_size)
+ return -ENOBUFS;
+
+ rb_sz = resbuf_size - token->offset;
+ res = token->ops->parse(token, token_str, rb, rb_sz);
+ }
+
+ /* does not match this token */
+ if (res < 0)
+ break;
+
+ debug_printf("TK parsed (len=%d)\n", n);
+ linebuf += n;
+ token_num ++;
+ token = inst->tokens[token_num];
+ }
+
+ /* does not match */
+ if (token_num == 0)
+ return -ENOENT;
+
+ /* we don't match all the tokens */
+ if (token)
+ return token_num;
+
+ /* are there are some tokens more */
+ while (isblank2(*linebuf))
+ linebuf++;
+
+ /* end of buf, we match all inst */
+ if (*linebuf == '\0' || isendofline(*linebuf) || iscomment(*linebuf))
+ return 0;
+
+ /* garbage after inst */
+ return token_num;
+}
+
+
+/* Check if a line buffer is valid and can be parsed or completed. The
+ * parsing stops when \n or \0 is reached. The also function checks
+ * that tokens are correctly quoted. The number of tokens in the
+ * buffer is returned. */
+static int validate_linebuf(const char *linebuf)
+{
+ int quoted = 0, comment = 0;
+ int i = 0, nbtok = 0, token = 0;
+
+ while (linebuf[i] != '\0') {
+ if (isendofline(linebuf[i]) && quoted == 0)
+ break;
+ if (comment == 1) {
+ i++;
+ continue;
+ }
+ if (iscomment(linebuf[i]) && quoted == 0) {
+ comment = 1;
+ i ++;
+ continue;
+ }
+
+ /* end of token */
+ if (isblank2(linebuf[i]) && quoted == 0)
+ token = 0;
+ /* new token */
+ if (!isblank2(linebuf[i]) && token == 0) {
+ token = 1;
+ nbtok++;
+ }
+
+ if (linebuf[i] == '\\' && linebuf[i+1] == '"') {
+ i += 2;
+ continue;
+ }
+ if (linebuf[i] == '\\' && linebuf[i+1] == '\\') {
+ i += 2;
+ continue;
+ }
+ if (linebuf[i] == '"') {
+ i++;
+ quoted = !quoted;
+ continue;
+ }
+ i++;
+ }
+ if (quoted)
+ return UCG_CMD_PARSE_UNTERMINATED_QUOTE;
+ return nbtok;
+}
+
+/* Try to parse a buffer according to the specified context. The
+ * argument linebuf must end with \n or \0. */
+int
+ucg_cmd_parse(struct ucg_cmd *cl, const char *linebuf,
+ void *opaque)
+{
+ ucg_cmd_ctx_t *ctx = cl->ctx;
+ const ucg_cmd_inst_t **pinst;
+ const ucg_cmd_inst_t *inst;
+ char result_buf[UCG_CMD_MAX_DSTBUF_SIZE];
+ void (*f)(void *, struct ucg_cmd *, void *) = NULL;
+ void *data = NULL;
+ int ret;
+
+ ret = validate_linebuf(linebuf);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return UCG_CMD_PARSE_EMPTY;
+
+
+ /* parse it !! */
+ for (pinst = &ctx->insts[0]; *pinst != NULL; pinst++) {
+ inst = *pinst;
+ debug_printf("INST\n");
+
+ /* fully parsed */
+ ret = match_inst(inst, linebuf, 0, result_buf,
+ sizeof(result_buf));
+
+ if (ret != 0)
+ continue;
+
+ debug_printf("INST fully parsed\n");
+
+ /* if end of buf -> there is no garbage after inst */
+ if (f != NULL) {
+ /* more than 1 inst matches */
+ debug_printf("Ambiguous cmd\n");
+ return UCG_CMD_PARSE_AMBIGUOUS;
+ }
+ f = inst->f;
+ data = inst->data;
+ }
+
+ /* call func */
+ if (f == NULL)
+ return UCG_CMD_PARSE_NOMATCH;
+
+ f(result_buf, opaque, data);
+ return UCG_CMD_PARSE_SUCCESS;
+}
+
+/* called by ucg_cmd_help() and ucg_cmd_complete() to preparse the
+ * line buffer (the operations done are common to these functions) */
+static int cmd_preparse(struct cmd_preparse *preparse, const char *buf)
+{
+ int ret, len, nb_tok;
+
+ /* count the number of tokens in the line buffer */
+ ret = validate_linebuf(buf);
+ if (ret < 0)
+ return ret;
+ nb_tok = ret;
+
+ /* if last token is not complete, decrement nb_valid_tok */
+ len = strlen(buf);
+ if (nb_tok == 0 || isblank2(buf[len - 1])) {
+ preparse->nb_valid_tok = nb_tok;
+ preparse->comp_tok_offset = len;
+ preparse->comp_tok_buf[0] = '\0';
+ preparse->comp_tok_len = 0;
+ }
+ else {
+ preparse->nb_valid_tok = nb_tok - 1;
+
+ /* get the incomplete token (can be empty) and return its
+ * offset in the buffer */
+ preparse->comp_tok_offset =
+ cmd_get_nth_token(preparse->comp_tok_buf,
+ sizeof(preparse->comp_tok_buf),
+ preparse->nb_valid_tok,
+ buf);
+ preparse->comp_tok_len = strlen(preparse->comp_tok_buf);
+ }
+
+ return 0;
+}
+
+/* Display a contextual help in the command line. The contextual help
+ * depends on the buffer given. */
+void ucg_cmd_help(struct ucg_cmd *cl, const char *buf)
+{
+ ucg_cmd_ctx_t *ctx = cl->ctx;
+ ucg_cmd_tk_hdr_t *token;
+ const ucg_cmd_inst_t **pinst;
+ const ucg_cmd_inst_t *inst;
+ struct cmd_preparse preparse;
+ char tmpbuf[UCG_CMD_MAX_DSTBUF_SIZE];
+ char *help_str;
+ size_t n;
+ int iterate;
+
+ cmd_preparse(&preparse, buf);
+
+ debug_printf("display contextual help\n");
+
+ for (pinst = &ctx->insts[0]; *pinst != NULL; pinst++) {
+ inst = *pinst;
+
+ /* get instruction static help string */
+ help_str = inst->help_str;
+ if (help_str == NULL)
+ help_str = "No help";
+
+ /* match the beginning of the command */
+ if (preparse.nb_valid_tok != 0 &&
+ match_inst(inst, buf, preparse.nb_valid_tok,
+ NULL, 0) != 0)
+ continue;
+
+ token = inst->tokens[preparse.nb_valid_tok];
+
+ /* end of inst */
+ if (token == NULL) {
+ ucg_cmd_printf(cl, "%-20s %s\n", "<Return>", help_str);
+ continue;
+ }
+
+ /* token matches, but no completion */
+ if (token->ops->complete_start == NULL ||
+ token->ops->complete_iterate == NULL)
+ iterate = 0;
+ else
+ iterate = 1;
+
+ /* store the incomplete token in tmpbuf */
+ n = preparse.comp_tok_len + 1;
+ if (n > sizeof(tmpbuf))
+ n = sizeof(tmpbuf);
+ snprintf(tmpbuf, sizeof(tmpbuf), "%s", preparse.comp_tok_buf);
+
+ if (iterate == 1 &&
+ token->ops->complete_start(token, tmpbuf,
+ &preparse.opaque) < 0) {
+ /* cancel iteration, complete_start() returned
+ * a negative value, meaning no completion */
+ iterate = 0;
+ if (token->ops->complete_end != NULL)
+ token->ops->complete_end(token,
+ &preparse.opaque);
+ }
+
+ debug_printf(" iterate = %d\n", iterate);
+
+ if (iterate == 0) {
+ /* get token dynamic help string */
+ if ((token->ops->help == NULL) ||
+ (token->ops->help(token, tmpbuf,
+ sizeof(tmpbuf)) < 0))
+ snprintf(tmpbuf, sizeof(tmpbuf), "unknown");
+
+ ucg_cmd_printf(cl, "%-20s %s\n", tmpbuf, help_str);
+ continue;
+ }
+
+ /* iterate over all possible completion for this inst */
+ while (token->ops->complete_iterate(token,
+ &preparse.opaque,
+ tmpbuf,
+ sizeof(tmpbuf)) >= 0) {
+
+
+ debug_printf(" choice <%s>\n", tmpbuf);
+
+ /* get the token and add it in help buffer */
+ ucg_cmd_printf(cl, "%-20s %s\n", tmpbuf,
+ iterate != 0? help_str : "''");
+
+ /* don't display help next time */
+ iterate = 0;
+ }
+
+ /* no more completion, go to next inst */
+ if (token->ops->complete_end != NULL)
+ token->ops->complete_end(token, &preparse.opaque);
+ }
+}
+
+/* try to complete the buffer given as a parameter */
+int
+ucg_cmd_complete(struct ucg_cmd *cl, const char *buf,
+ char *dst, unsigned int dstsize)
+{
+ ucg_cmd_ctx_t *ctx = cl->ctx;
+ ucg_cmd_tk_hdr_t *token;
+ const ucg_cmd_inst_t **pinst;
+ const ucg_cmd_inst_t *inst;
+ struct cmd_preparse preparse;
+ int nb_match = 0;
+ int nb_completion = 0;
+ char completion_buf[UCG_CMD_MAX_TOKEN_SIZE];
+ char tmpbuf[UCG_CMD_MAX_TOKEN_SIZE];
+ int ret;
+ size_t n, completion_len = UCG_CMD_MAX_TOKEN_SIZE;
+
+ debug_printf("%s called\n", __FUNCTION__);
+
+ /* fill the preparse structure that contains infos that will
+ * help us to complete the buffer */
+ ret = cmd_preparse(&preparse, buf);
+ if (ret < 0)
+ return UCG_CMD_COMPLETE_NONE;
+
+ /* try to complete ! */
+ for (pinst = &ctx->insts[0]; *pinst != NULL; pinst++) {
+ inst = *pinst;
+
+ debug_printf("INST\n");
+
+ /* try to match the first tokens */
+ if (preparse.nb_valid_tok != 0 &&
+ match_inst(inst, buf, preparse.nb_valid_tok,
+ NULL, 0) != 0)
+ continue;
+
+ nb_match ++;
+ token = inst->tokens[preparse.nb_valid_tok];
+
+ /* non completable */
+ if (token == NULL ||
+ token->ops->complete_start == NULL ||
+ token->ops->complete_iterate == NULL)
+ continue;
+
+ /* store the incomplete token in tmpbuf */
+ n = preparse.comp_tok_len + 1;
+ if (n > sizeof(tmpbuf))
+ n = sizeof(tmpbuf);
+ snprintf(tmpbuf, n, "%s", preparse.comp_tok_buf);
+
+ /* non completable */
+ if (token->ops->complete_start(token, tmpbuf,
+ &preparse.opaque) < 0) {
+ if (token->ops->complete_end != NULL)
+ token->ops->complete_end(token,
+ &preparse.opaque);
+ continue;
+ }
+
+ /* all possible completion for this token */
+ while (1) {
+
+ ret = token->ops->complete_iterate(token,
+ &preparse.opaque,
+ tmpbuf,
+ sizeof(tmpbuf)-1);
+
+ if (ret < 0)
+ break;
+
+ debug_printf("Completion %s\n", tmpbuf);
+
+ /* we kept at least the room for one char */
+ if (ret == 0)
+ strcat(tmpbuf, " ");
+
+ debug_printf(" choice <%s>\n", tmpbuf);
+
+ /* does the completion match the beginning of
+ * the word ? */
+ if (strncmp(preparse.comp_tok_buf, tmpbuf,
+ preparse.comp_tok_len))
+ continue;
+
+ /* first one, save the buffer */
+ if (nb_completion == 0) {
+ completion_len = snprintf(completion_buf,
+ sizeof(completion_buf),
+ "%s", tmpbuf);
+ }
+ else {
+ n = nb_common_chars(completion_buf, tmpbuf);
+ if (n < completion_len)
+ completion_len = n;
+ }
+ nb_completion ++;
+
+ /* we cannot add any char, just display help */
+ if (completion_len == preparse.comp_tok_len)
+ break;
+ }
+ if (token->ops->complete_end != NULL)
+ token->ops->complete_end(token, &preparse.opaque);
+
+ if (completion_len == preparse.comp_tok_len)
+ break;
+ }
+
+ debug_printf("nb_completion=%d, completion_len=%d\n",
+ (int)nb_completion, (int)completion_len);
+
+ /* one choice, append chars and return */
+ if (nb_completion == 1) {
+ snprintf(dst, dstsize, "%s",
+ completion_buf + preparse.comp_tok_len);
+ return UCG_CMD_COMPLETE_APPEND;
+ }
+
+ /* many choices, but starting with same chars: append chars
+ * and return */
+ if (nb_completion != 0 && completion_len > preparse.comp_tok_len) {
+ if (completion_len >= dstsize)
+ completion_len = dstsize - 1;
+ strncpy(dst, completion_buf + preparse.comp_tok_len,
+ completion_len - preparse.comp_tok_len);
+ dst[completion_len - preparse.comp_tok_len] = '\0';
+ return UCG_CMD_COMPLETE_APPEND;
+ }
+
+ /* no match, nothing to do */
+ if (nb_match == 0 || nb_completion == 0)
+ return UCG_CMD_COMPLETE_NONE;
+
+ return UCG_CMD_COMPLETE_MANY;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <net/ethernet.h>
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd_parse_etheraddr.h"
+
+#define ETHER_ADDRSTRLEN 18
+
+#ifdef __linux__
+#define ea_oct ether_addr_octet
+#else
+#define ea_oct octet
+#endif
+
+static struct ether_addr *
+my_ether_aton(const char *a)
+{
+ int i;
+ static struct ether_addr ether_addr;
+ unsigned int o0, o1, o2, o3, o4, o5;
+
+ i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
+
+ if (i != ETHER_ADDR_LEN)
+ return NULL;
+
+ ether_addr.ea_oct[0] = (uint8_t)o0;
+ ether_addr.ea_oct[1] = (uint8_t)o1;
+ ether_addr.ea_oct[2] = (uint8_t)o2;
+ ether_addr.ea_oct[3] = (uint8_t)o3;
+ ether_addr.ea_oct[4] = (uint8_t)o4;
+ ether_addr.ea_oct[5] = (uint8_t)o5;
+
+ return (struct ether_addr *)ðer_addr;
+}
+
+static int
+cmd_parse_etheraddr(
+ __attribute__((unused)) ucg_cmd_tk_hdr_t *tk,
+ const char *buf, void *res, unsigned ressize)
+{
+ unsigned int token_len = 0;
+ char ether_str[ETHER_ADDRSTRLEN];
+ struct ether_addr *tmp;
+
+ if (res && ressize < sizeof(struct ether_addr))
+ return -1;
+
+ /* if token is too big... */
+ token_len = snprintf(ether_str, sizeof(ether_str), "%s", buf);
+ if (token_len >= sizeof(ether_str))
+ return -1;
+
+ tmp = my_ether_aton(ether_str);
+ if (tmp == NULL)
+ return -1;
+
+ if (res != NULL)
+ memcpy(res, tmp, sizeof(struct ether_addr));
+ return 0;
+}
+
+static int
+cmd_help_etheraddr(
+ __attribute__((unused)) ucg_cmd_tk_hdr_t *tk,
+ char *dstbuf, unsigned int size)
+{
+ snprintf(dstbuf, size, "<ether addr>");
+ return 0;
+}
+
+struct ucg_cmd_tk_ops ucg_cmd_tk_etheraddr_ops = {
+ .parse = cmd_parse_etheraddr,
+ .complete_start = NULL,
+ .complete_iterate = NULL,
+ .complete_end = NULL,
+ .help = cmd_help_etheraddr,
+};
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <dirent.h>
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd_parse_file.h"
+
+struct cmd_complete_file_callback {
+ char *token;
+ DIR *dir;
+};
+
+static int
+cmd_parse_file(ucg_cmd_tk_hdr_t *tk, const char *buf,
+ void *res, unsigned ressize)
+{
+ struct ucg_cmd_tk_file *tk2 = (struct ucg_cmd_tk_file *)tk;
+ struct ucg_cmd_tk_file_data *sd = &tk2->file_data;;
+ unsigned int token_len;
+ struct stat st;
+ int flags, ret;
+ char *tmp, *dname;
+
+ if (res && ressize < UCG_FILENAME_SIZE)
+ return -1;
+
+ token_len = strlen(buf);
+ if (token_len >= (UCG_FILENAME_SIZE - 1) || token_len == 0)
+ return -1;
+
+ flags = sd->flags;
+
+ if (flags & PARSE_FILE_F_CREATE) {
+ /* the directory must exist */
+ tmp = strdup(buf);
+ dname = dirname(tmp);
+ ret = stat(dname, &st);
+ if (ret != 0)
+ ret = lstat(dname, &st);
+ free(tmp);
+ if (ret != 0)
+ return -1;
+ if (!S_ISDIR(st.st_mode))
+ return -1;
+ }
+ else {
+ ret = stat(buf, &st);
+ if (ret != 0)
+ return -1;
+ if (flags & PARSE_FILE_F_DIRECTORY)
+ if (!S_ISDIR(st.st_mode))
+ return -1;
+ }
+
+ /* we already checked that token_len is < FILENAME_SIZE-1 */
+ if (res)
+ strcpy(res, buf);
+
+ return 0;
+}
+
+/*
+ * This function is quite similar to dirname(3) except that:
+ * - it allocates the returned string and don't modify the argument
+ * - the result of dirname2() is not exactly the same than dirname()
+ * path dirname2
+ * "/usr/lib" "/usr"
+ * "/usr/" "/usr"
+ * "/usr" "/"
+ * "usr" "." or "" if allow_empty == 1
+ * "" "." or "" if allow_empty == 1
+ * "/" "/"
+ * "." "." or "" if allow_empty == 1
+ * "./" "."
+ * ".." "." or "" if allow_empty == 1
+ * "../" ".."
+ */
+static char *
+dirname2(const char *path, int allow_empty)
+{
+ char *s;
+ char *last_slash;
+ int len;
+
+ len = strlen(path);
+ if (len == 0 && allow_empty == 0) {
+ s = strdup(".");
+ return s;
+ }
+
+ s = strdup(path);
+ last_slash = strrchr(s, '/');
+ if (last_slash == NULL) {
+ if (allow_empty)
+ s[0] = '\0';
+ else
+ strcpy(s, ".");
+ }
+ else if (last_slash == s)
+ s[1] = '\0';
+ else {
+ *last_slash = '\0';
+ }
+
+ return s;
+}
+
+static int
+cmd_complete_file_start(ucg_cmd_tk_hdr_t *tk,
+ const char *tokstr, void **opaque)
+{
+ char *dname;
+ struct cmd_complete_file_callback *cb;
+
+ (void)tk;
+ *opaque = NULL;
+ cb = malloc(sizeof(*cb));
+ if (cb == NULL)
+ return -1;
+ memset(cb, 0, sizeof(*cb));
+ *opaque = cb;
+
+ cb->token = strdup(tokstr);
+ /* we need to copy again tokstr because dirname() alters the string */
+ dname = dirname2(tokstr, 0);
+ cb->dir = opendir(dname);
+ free(dname);
+
+ if (cb->dir == NULL)
+ return -1;
+
+ return 0;
+}
+
+static int
+cmd_complete_file_iterate(ucg_cmd_tk_hdr_t *tk, void **opaque,
+ char *dstbuf, unsigned int size)
+{
+ struct ucg_cmd_tk_file *tk2 = (struct ucg_cmd_tk_file *)tk;
+ struct ucg_cmd_tk_file_data *sd = &tk2->file_data;
+ struct cmd_complete_file_callback *cb;
+ struct dirent *de;
+ struct stat st;
+ char *dname;
+ int len;
+ int need_join_slash = 1;
+ int flags = sd->flags;
+
+ cb = *opaque;
+ /* read next dir name, skipping "." and ".." */
+ while (1) {
+ de = readdir(cb->dir);
+ if (de == NULL)
+ return -1;
+ if (strcmp(de->d_name, ".") == 0 ||
+ strcmp(de->d_name, "..") == 0)
+ continue;
+
+
+ /* do we need a / to join dirname and basename ? */
+ dname = dirname2(cb->token, 1);
+ len = strlen(dname);
+ if (len == 0 || dname[len - 1] == '/')
+ need_join_slash = 0;
+
+ /* keep one byte for potential '/' */
+ len = snprintf(dstbuf, size-1, "%s%s%s", dname,
+ need_join_slash ? "/" : "", de->d_name);
+ free(dname);
+ if (len < 0 || len >= (int)size - 1)
+ continue;
+
+ /* append '/' if it's a directory */
+ if (stat(dstbuf, &st) != 0) {
+ if (lstat(dstbuf, &st) != 0)
+ return -1;
+ }
+ if (S_ISDIR(st.st_mode)) {
+ strcat(dstbuf, "/");
+ return 1; /* intermediate completion */
+ }
+ /* skip non-directories */
+ else if (flags & PARSE_FILE_F_DIRECTORY)
+ continue;
+ break;
+ }
+
+ return 0;
+}
+
+static void
+cmd_complete_file_end(ucg_cmd_tk_hdr_t *tk, void **opaque)
+{
+ struct cmd_complete_file_callback *cb;
+
+ (void)tk;
+ cb = *opaque;
+
+ if (cb == NULL)
+ return;
+
+ if (cb->dir)
+ closedir(cb->dir);
+ if (cb->token)
+ free(cb->token);
+
+ free(cb);
+}
+
+
+static int
+cmd_help_file(ucg_cmd_tk_hdr_t *tk, char *dstbuf,
+ unsigned int size)
+{
+ struct ucg_cmd_tk_file *tk2 = (struct ucg_cmd_tk_file *)tk;
+ struct ucg_cmd_tk_file_data *sd = &tk2->file_data;;
+ int flags;
+
+ flags = sd->flags;
+ if (flags & PARSE_FILE_F_DIRECTORY)
+ snprintf(dstbuf, size, "<dir>");
+ else
+ snprintf(dstbuf, size, "<file>");
+
+ return 0;
+}
+
+struct ucg_cmd_tk_ops ucg_cmd_tk_file_ops = {
+ .parse = cmd_parse_file,
+ .complete_start = cmd_complete_file_start,
+ .complete_iterate = cmd_complete_file_iterate,
+ .complete_end = cmd_complete_file_end,
+ .help = cmd_help_file,
+};
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For inet_ntop() functions:
+ *
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <netinet/in.h>
+#ifndef __linux__
+#include <net/socket.h>
+#endif
+
+#include <ucg_cmd_parse.h>
+#include <ucg_cmd_parse_ipaddr.h>
+
+#define INADDRSZ 4
+#define IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+my_inet_pton(int af, const char *src, void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ *tp = (unsigned char)new;
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+
+ memcpy(dst, tmp, INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit, count_xdigit;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = count_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ if (count_xdigit >= 4)
+ return (0);
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ count_xdigit++;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + sizeof(int16_t) > endp)
+ return (0);
+ *tp++ = (unsigned char) ((val >> 8) & 0xff);
+ *tp++ = (unsigned char) (val & 0xff);
+ saw_xdigit = 0;
+ count_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ count_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + sizeof(int16_t) > endp)
+ return (0);
+ *tp++ = (unsigned char) ((val >> 8) & 0xff);
+ *tp++ = (unsigned char) (val & 0xff);
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, IN6ADDRSZ);
+ return (1);
+}
+
+static int
+cmd_parse_ipaddr(ucg_cmd_tk_hdr_t *tk, const char *buf,
+ void *res, unsigned ressize)
+{
+ struct ucg_cmd_tk_ipaddr *tk2 =
+ (struct ucg_cmd_tk_ipaddr *)tk;
+ unsigned int token_len = 0;
+ char ip_str[INET6_ADDRSTRLEN+4]; /* '+4' is for prefixlen (if any) */
+ ucg_cmd_ipaddr_t ipaddr;
+ char *prefix, *prefix_end;
+ long prefixlen;
+
+ if (res && ressize < sizeof(ucg_cmd_ipaddr_t))
+ return -1;
+
+ memset(&ipaddr, 0, sizeof(ipaddr));
+
+ /* if token is too big... */
+ token_len = snprintf(ip_str, sizeof(ip_str), "%s", buf);
+ if (token_len >= sizeof(ip_str))
+ return -1;
+
+ /* convert the network prefix */
+ if (tk2->ipaddr_data.flags & UCG_CMD_IPADDR_NETWORK) {
+ prefix = strrchr(ip_str, '/');
+ if (prefix == NULL)
+ return -1;
+ *prefix = '\0';
+ prefix ++;
+ errno = 0;
+ prefixlen = strtol(prefix, &prefix_end, 10);
+ if (errno || (*prefix_end != '\0') )
+ return -1;
+ ipaddr.prefixlen = prefixlen;
+ }
+ else {
+ ipaddr.prefixlen = 0;
+ }
+
+ /* convert the IP addr */
+ if ((tk2->ipaddr_data.flags & UCG_CMD_IPADDR_V4) &&
+ my_inet_pton(AF_INET, ip_str, &ipaddr.addr.ipv4) == 1) {
+ ipaddr.family = AF_INET;
+ if (res != NULL)
+ memcpy(res, &ipaddr, sizeof(ipaddr));
+ return 0;
+ }
+ if ((tk2->ipaddr_data.flags & UCG_CMD_IPADDR_V6) &&
+ my_inet_pton(AF_INET6, ip_str, &ipaddr.addr.ipv6) == 1) {
+ ipaddr.family = AF_INET6;
+ if (res != NULL)
+ memcpy(res, &ipaddr, sizeof(ipaddr));
+ return 0;
+ }
+ return -1;
+
+}
+
+static int
+cmd_help_ipaddr(ucg_cmd_tk_hdr_t *tk, char *dstbuf,
+ unsigned int size)
+{
+ struct ucg_cmd_tk_ipaddr *tk2 =
+ (struct ucg_cmd_tk_ipaddr *)tk;
+
+ switch (tk2->ipaddr_data.flags) {
+ case UCG_CMD_IPADDR_V4:
+ snprintf(dstbuf, size, "<IPv4>");
+ break;
+ case UCG_CMD_IPADDR_V6:
+ snprintf(dstbuf, size, "<IPv6>");
+ break;
+ case UCG_CMD_IPADDR_V4 | UCG_CMD_IPADDR_V6:
+ snprintf(dstbuf, size, "<IPv4/IPv6>");
+ break;
+ case UCG_CMD_IPADDR_NETWORK | UCG_CMD_IPADDR_V4:
+ snprintf(dstbuf, size, "<IPv4 network>");
+ break;
+ case UCG_CMD_IPADDR_NETWORK | UCG_CMD_IPADDR_V6:
+ snprintf(dstbuf, size, "<IPv6 network>");
+ break;
+ case UCG_CMD_IPADDR_NETWORK | UCG_CMD_IPADDR_V4 |
+ UCG_CMD_IPADDR_V6:
+ snprintf(dstbuf, size, "<IPv4/IPv6 network>");
+ break;
+ default:
+ snprintf(dstbuf, size, "<IPaddr (bad flags)>");
+ break;
+ }
+ return 0;
+}
+
+struct ucg_cmd_tk_ops cmd_token_ipaddr_ops = {
+ .parse = cmd_parse_ipaddr,
+ .complete_start = NULL,
+ .complete_iterate = NULL,
+ .complete_end = NULL,
+ .help = cmd_help_ipaddr,
+};
+
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd_parse_num.h"
+
+//#define debug_printf(args...) printf(args)
+#define debug_printf(args...) do {} while(0)
+
+enum num_parse_state_t {
+ START,
+ DEC_NEG,
+ BIN,
+ HEX,
+ FLOAT_POS,
+ FLOAT_NEG,
+
+ ERROR,
+
+ FIRST_OK, /* not used */
+ ZERO_OK,
+ HEX_OK,
+ OCTAL_OK,
+ BIN_OK,
+ DEC_NEG_OK,
+ DEC_POS_OK,
+ FLOAT_POS_OK,
+ FLOAT_NEG_OK
+};
+
+/* Keep it sync with enum in .h */
+static const char * num_help[] = {
+ "<uint8>", "<uint16>", "<uint32>", "<uint64>",
+ "<int8>", "<int16>", "<int32>", "<int64>",
+#ifdef UCG_CMD_HAVE_FLOAT
+ "<float>",
+#endif
+};
+
+static int
+add_to_res(unsigned int c, uint64_t *res, unsigned int base)
+{
+ /* overflow */
+ if ( (UINT64_MAX - c) / base < *res ) {
+ return -1;
+ }
+
+ *res = (uint64_t) (*res * base + c);
+ return 0;
+}
+
+static int
+check_res_size(struct ucg_cmd_tk_num_data *nd, unsigned ressize)
+{
+ switch (nd->type) {
+ case INT8:
+ case UINT8:
+ if (ressize < sizeof(int8_t))
+ return -1;
+ break;
+ case INT16:
+ case UINT16:
+ if (ressize < sizeof(int16_t))
+ return -1;
+ break;
+ case INT32:
+ case UINT32:
+ if (ressize < sizeof(int32_t))
+ return -1;
+ break;
+ case INT64:
+ case UINT64:
+ if (ressize < sizeof(int64_t))
+ return -1;
+ break;
+#ifdef UCG_CMD_HAVE_FLOAT
+ case FLOAT:
+ if (ressize < sizeof(float))
+ return -1;
+ break;
+#endif
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/* parse an int or a float */
+static int
+cmd_parse_num(ucg_cmd_tk_hdr_t *tk, const char *srcbuf,
+ void *res, unsigned ressize)
+{
+ struct ucg_cmd_tk_num_data nd;
+ enum num_parse_state_t st = START;
+ const char * buf = srcbuf;
+ char c = *buf;
+ uint64_t res1 = 0;
+#ifdef UCG_CMD_HAVE_FLOAT
+ uint64_t res2 = 0, res3 = 1;
+#endif
+
+ memcpy(&nd, &((struct ucg_cmd_tk_num *)tk)->num_data, sizeof(nd));
+
+ /* check that we have enough room in res */
+ if (res) {
+ if (check_res_size(&nd, ressize) < 0)
+ return -1;
+ }
+
+ while (st != ERROR && c != '\0') {
+ debug_printf("%c %x -> ", c, c);
+ switch (st) {
+ case START:
+ if (c == '-') {
+ st = DEC_NEG;
+ }
+ else if (c == '0') {
+ st = ZERO_OK;
+ }
+#ifdef UCG_CMD_HAVE_FLOAT
+ else if (c == '.') {
+ st = FLOAT_POS;
+ res1 = 0;
+ }
+#endif
+ else if (c >= '1' && c <= '9') {
+ if (add_to_res(c - '0', &res1, 10) < 0)
+ st = ERROR;
+ else
+ st = DEC_POS_OK;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case ZERO_OK:
+ if (c == 'x') {
+ st = HEX;
+ }
+ else if (c == 'b') {
+ st = BIN;
+ }
+#ifdef UCG_CMD_HAVE_FLOAT
+ else if (c == '.') {
+ st = FLOAT_POS;
+ res1 = 0;
+ }
+#endif
+ else if (c >= '0' && c <= '7') {
+ if (add_to_res(c - '0', &res1, 10) < 0)
+ st = ERROR;
+ else
+ st = OCTAL_OK;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case DEC_NEG:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res1, 10) < 0)
+ st = ERROR;
+ else
+ st = DEC_NEG_OK;
+ }
+#ifdef UCG_CMD_HAVE_FLOAT
+ else if (c == '.') {
+ res1 = 0;
+ st = FLOAT_NEG;
+ }
+#endif
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case DEC_NEG_OK:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res1, 10) < 0)
+ st = ERROR;
+ }
+#ifdef UCG_CMD_HAVE_FLOAT
+ else if (c == '.') {
+ st = FLOAT_NEG;
+ }
+#endif
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case DEC_POS_OK:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res1, 10) < 0)
+ st = ERROR;
+ }
+#ifdef UCG_CMD_HAVE_FLOAT
+ else if (c == '.') {
+ st = FLOAT_POS;
+ }
+#endif
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case HEX:
+ st = HEX_OK;
+ /* no break */
+ case HEX_OK:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res1, 16) < 0)
+ st = ERROR;
+ }
+ else if (c >= 'a' && c <= 'f') {
+ if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
+ st = ERROR;
+ }
+ else if (c >= 'A' && c <= 'F') {
+ if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
+ st = ERROR;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+
+ case OCTAL_OK:
+ if (c >= '0' && c <= '7') {
+ if (add_to_res(c - '0', &res1, 8) < 0)
+ st = ERROR;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case BIN:
+ st = BIN_OK;
+ /* no break */
+ case BIN_OK:
+ if (c >= '0' && c <= '1') {
+ if (add_to_res(c - '0', &res1, 2) < 0)
+ st = ERROR;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+#ifdef UCG_CMD_HAVE_FLOAT
+ case FLOAT_POS:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res2, 10) < 0)
+ st = ERROR;
+ else
+ st = FLOAT_POS_OK;
+ res3 = 10;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case FLOAT_NEG:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res2, 10) < 0)
+ st = ERROR;
+ else
+ st = FLOAT_NEG_OK;
+ res3 = 10;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case FLOAT_POS_OK:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res2, 10) < 0)
+ st = ERROR;
+ if (add_to_res(0, &res3, 10) < 0)
+ st = ERROR;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+
+ case FLOAT_NEG_OK:
+ if (c >= '0' && c <= '9') {
+ if (add_to_res(c - '0', &res2, 10) < 0)
+ st = ERROR;
+ if (add_to_res(0, &res3, 10) < 0)
+ st = ERROR;
+ }
+ else {
+ st = ERROR;
+ }
+ break;
+#endif
+
+ default:
+ debug_printf("not impl ");
+
+ }
+
+#ifdef UCG_CMD_HAVE_FLOAT
+ debug_printf("(%"PRIu32") (%"PRIu32") (%"PRIu32")\n",
+ res1, res2, res3);
+#else
+ debug_printf("(%"PRIu32")\n", res1);
+#endif
+
+ buf ++;
+ c = *buf;
+
+ /* token too long */
+ if (buf-srcbuf > 127)
+ return -1;
+ }
+
+ switch (st) {
+ case ZERO_OK:
+ case DEC_POS_OK:
+ case HEX_OK:
+ case OCTAL_OK:
+ case BIN_OK:
+ if ( nd.type == INT8 && res1 <= INT8_MAX ) {
+ if (res)
+ *(int8_t *)res = (int8_t) res1;
+ return 0;
+ }
+ else if ( nd.type == INT16 && res1 <= INT16_MAX ) {
+ if (res)
+ *(int16_t *)res = (int16_t) res1;
+ return 0;
+ }
+ else if ( nd.type == INT32 && res1 <= INT32_MAX ) {
+ if (res)
+ *(int32_t *)res = (int32_t) res1;
+ return 0;
+ }
+ else if ( nd.type == UINT8 && res1 <= UINT8_MAX ) {
+ if (res)
+ *(uint8_t *)res = (uint8_t) res1;
+ return 0;
+ }
+ else if (nd.type == UINT16 && res1 <= UINT16_MAX ) {
+ if (res)
+ *(uint16_t *)res = (uint16_t) res1;
+ return 0;
+ }
+ else if ( nd.type == UINT32 ) {
+ if (res)
+ *(uint32_t *)res = (uint32_t) res1;
+ return 0;
+ }
+ else if ( nd.type == UINT64 ) {
+ if (res)
+ *(uint64_t *)res = res1;
+ return 0;
+ }
+#ifdef UCG_CMD_HAVE_FLOAT
+ else if ( nd.type == FLOAT ) {
+ if (res)
+ *(float *)res = (float)res1;
+ return 0;
+ }
+#endif
+ else {
+ return -1;
+ }
+ break;
+
+ case DEC_NEG_OK:
+ if ( nd.type == INT8 && res1 <= INT8_MAX + 1 ) {
+ if (res)
+ *(int8_t *)res = (int8_t) (-res1);
+ return 0;
+ }
+ else if ( nd.type == INT16 && res1 <= (uint16_t)INT16_MAX + 1 ) {
+ if (res)
+ *(int16_t *)res = (int16_t) (-res1);
+ return 0;
+ }
+ else if ( nd.type == INT32 && res1 <= (uint32_t)INT32_MAX + 1 ) {
+ if (res)
+ *(int32_t *)res = (int32_t) (-res1);
+ return 0;
+ }
+#ifdef UCG_CMD_HAVE_FLOAT
+ else if ( nd.type == FLOAT ) {
+ if (res)
+ *(float *)res = - (float)res1;
+ return 0;
+ }
+#endif
+ else {
+ return -1;
+ }
+ break;
+
+#ifdef UCG_CMD_HAVE_FLOAT
+ case FLOAT_POS:
+ case FLOAT_POS_OK:
+ if ( nd.type == FLOAT ) {
+ if (res)
+ *(float *)res = (float)res1 +
+ ((float)res2 / (float)res3);
+ return 0;
+
+ }
+ else {
+ return -1;
+ }
+ break;
+
+ case FLOAT_NEG:
+ case FLOAT_NEG_OK:
+ if ( nd.type == FLOAT ) {
+ if (res)
+ *(float *)res = - ((float)res1 +
+((float)res2 / (float)res3));
+ return 0;
+
+ }
+ else {
+ return -1;
+ }
+ break;
+#endif
+ default:
+ debug_printf("error\n");
+ return -1;
+ }
+}
+
+
+/* parse an int or a float */
+static int
+cmd_help_num(ucg_cmd_tk_hdr_t *tk, char *dstbuf,
+ unsigned int size)
+{
+ struct ucg_cmd_tk_num_data nd;
+
+ memcpy(&nd, &((struct ucg_cmd_tk_num *)tk)->num_data, sizeof(nd));
+
+ /* should not happen.... don't so this test */
+ /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
+ /* return -1; */
+
+ strncpy(dstbuf, num_help[nd.type], size);
+ dstbuf[size-1] = '\0';
+ return 0;
+}
+
+
+struct ucg_cmd_tk_ops ucg_cmd_tk_num_ops = {
+ .parse = cmd_parse_num,
+ .complete_start = NULL,
+ .complete_iterate = NULL,
+ .complete_end = NULL,
+ .help = cmd_help_num,
+};
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd_parse_string.h"
+
+#define MULTISTRING_HELP "Mul-choice STRING"
+#define ANYSTRING_HELP "Any STRING"
+#define FIXEDSTRING_HELP "Fixed STRING"
+
+static unsigned int
+get_token_len(const char *s)
+{
+ char c;
+ unsigned int i=0;
+
+ c = s[i];
+ while (c!='#' && c!='\0') {
+ i++;
+ c = s[i];
+ }
+ return i;
+}
+
+static const char *
+get_next_token(const char *s)
+{
+ unsigned int i;
+ i = get_token_len(s);
+ if (s[i] == '#')
+ return s+i+1;
+ return NULL;
+}
+
+static int
+parse_fixed_string(struct ucg_cmd_tk_string_data *sd,
+ const char *buf, unsigned token_len)
+{
+ unsigned int conf_token_len;
+ const char *str;
+
+ str = sd->str;
+ for (str = sd->str; str != NULL ; str = get_next_token(str)) {
+
+ conf_token_len = get_token_len(str);
+
+ /* if token from config is too big... */
+ if (conf_token_len >= UCG_STR_TOKEN_SIZE - 1)
+ continue;
+
+ /* compare conf token and user token */
+ if (token_len == conf_token_len &&
+ strncmp(buf, str, token_len) == 0)
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+cmd_parse_string(ucg_cmd_tk_hdr_t *tk,
+ const char *buf, void *res, unsigned ressize)
+{
+ struct ucg_cmd_tk_string *tk2 =
+ (struct ucg_cmd_tk_string *)tk;
+ struct ucg_cmd_tk_string_data *sd = &tk2->string_data;;
+ unsigned int token_len;
+
+ if (res && ressize < UCG_STR_TOKEN_SIZE)
+ return -1;
+
+ token_len = strlen(buf);
+
+ if (token_len >= (UCG_STR_TOKEN_SIZE - 1) || token_len == 0)
+ return -1;
+
+ /* fixed string */
+ if (sd->str) {
+ if (parse_fixed_string(sd, buf, token_len) < 0)
+ return -1;
+ }
+
+ /* we already checked that token_len is < STR_TOKEN_SIZE-1 */
+ if (res)
+ strcpy(res, buf);
+
+ return 0;
+}
+
+static int
+cmd_complete_string_start(ucg_cmd_tk_hdr_t *tk,
+ __attribute__((unused)) const char *tokstr,
+ void **opaque)
+{
+ struct ucg_cmd_tk_string *tk2 =
+ (struct ucg_cmd_tk_string *)tk;
+ struct ucg_cmd_tk_string_data *sd = &tk2->string_data;;
+ const char *str;
+
+ str = sd->str;
+ *opaque = (void *)str;
+ if (str == NULL)
+ return -1; /* no completion */
+ return 0;
+}
+
+static int
+cmd_complete_string_iterate(ucg_cmd_tk_hdr_t *tk, void **opaque,
+ char *dstbuf, unsigned int size)
+{
+ const char *s;
+ unsigned int len;
+
+ (void)tk;
+ s = *opaque;
+ if (s == NULL)
+ return -1;
+ *opaque = (void *)get_next_token(s);
+
+ len = get_token_len(s);
+ if (len > size - 1)
+ return -1;
+
+ memcpy(dstbuf, s, len);
+ dstbuf[len] = '\0';
+ return 0;
+}
+
+static int
+cmd_help_string(ucg_cmd_tk_hdr_t *tk, char *dstbuf,
+ unsigned int size)
+{
+ (void)tk;
+ snprintf(dstbuf, size, "<string>");
+ return 0;
+}
+
+struct ucg_cmd_tk_ops ucg_cmd_tk_string_ops = {
+ .parse = cmd_parse_string,
+ .complete_start = cmd_complete_string_start,
+ .complete_iterate = cmd_complete_string_iterate,
+ .complete_end = NULL,
+ .help = cmd_help_string,
+};
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_CMD_NO_PAGER
+#define _GNU_SOURCE /* for vasprintf */
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <alloca.h>
+
+#include <ucg_cirbuf.h>
+
+#include "ucg_cmd_rdline.h"
+#include "ucg_cmd_parse.h"
+
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+static void rdline_remove_old_history_item(struct ucg_rdline *rdl);
+static void rdline_remove_first_history_item(struct ucg_rdline *rdl);
+static unsigned int rdline_get_history_size(struct ucg_rdline *rdl);
+#endif /* !UCG_CMD_NO_RDLINE_HISTORY */
+
+#ifndef UCG_CMD_NO_PAGER
+static int rdline_pager_next_page(struct ucg_rdline *rdl);
+static void rdline_pager_reset(struct ucg_rdline *rdl);
+#endif /* !UCG_CMD_NO_PAGER */
+
+
+/* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
+ * own. */
+static int
+isblank2(char c)
+{
+ if (c == ' ' ||
+ c == '\t' )
+ return 1;
+ return 0;
+}
+
+void
+ucg_rdline_init(struct ucg_rdline *rdl,
+ FILE *f_in, FILE *f_out,
+ ucg_rdline_validate_t *validate,
+ ucg_rdline_complete_t *complete,
+ ucg_rdline_help_t *help)
+{
+ memset(rdl, 0, sizeof(*rdl));
+ rdl->f_in = f_in;
+ rdl->f_out = f_out;
+ rdl->validate = validate;
+ rdl->complete = complete;
+ rdl->help = help;
+ rdl->status = UCG_RDLINE_STOPPED;
+
+ /* Disable buffering */
+ setbuf(f_in, NULL);
+ setbuf(f_out, NULL);
+
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+ ucg_cirbuf_init(&rdl->history, rdl->history_buf, 0,
+ UCG_RDLINE_HISTORY_BUF_SIZE);
+#endif /* !UCG_CMD_NO_RDLINE_HISTORY */
+}
+
+void
+ucg_rdline_newline(struct ucg_rdline *rdl, const char *prompt)
+{
+ ucg_vt100_init(&rdl->vt100);
+ ucg_cirbuf_init(&rdl->left, rdl->left_buf, 0, UCG_RDLINE_BUF_SIZE);
+ ucg_cirbuf_init(&rdl->right, rdl->right_buf, 0, UCG_RDLINE_BUF_SIZE);
+
+ /* if pointer is the same or NULL, don't copy it */
+ if (prompt != NULL && prompt != rdl->prompt)
+ snprintf(rdl->prompt, sizeof(rdl->prompt), "%s", prompt);
+
+ ucg_rdline_printf(rdl, "%s", rdl->prompt);
+ rdl->status = UCG_RDLINE_RUNNING;
+
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+ rdl->history_cur_line = -1;
+#endif /* !UCG_CMD_NO_RDLINE_HISTORY */
+}
+
+void
+ucg_rdline_stop(struct ucg_rdline *rdl)
+{
+ rdl->status = UCG_RDLINE_STOPPED;
+}
+
+void
+ucg_rdline_quit(struct ucg_rdline *rdl)
+{
+ rdl->status = UCG_RDLINE_EXITED;
+}
+
+void
+ucg_rdline_restart(struct ucg_rdline *rdl)
+{
+ rdl->status = UCG_RDLINE_RUNNING;
+}
+
+const char *
+ucg_rdline_get_buffer(struct ucg_rdline *rdl)
+{
+ unsigned int len_l, len_r;
+ ucg_cirbuf_align_left(&rdl->left);
+ ucg_cirbuf_align_left(&rdl->right);
+
+ len_l = ucg_cirbuf_get_len(&rdl->left);
+ len_r = ucg_cirbuf_get_len(&rdl->right);
+ memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
+
+ rdl->left_buf[len_l + len_r] = '\0';
+ return rdl->left_buf;
+}
+
+static void
+display_right_buffer(struct ucg_rdline *rdl, int force)
+{
+ unsigned int i;
+ char tmp;
+
+ if (!force && ucg_cirbuf_is_empty(&rdl->right))
+ return;
+
+ ucg_rdline_printf(rdl, ucg_vt100_clear_right);
+ UCG_CIRBUF_FOREACH(&rdl->right, i, tmp) {
+ ucg_rdline_printf(rdl, "%c", tmp);
+ }
+ if (!ucg_cirbuf_is_empty(&rdl->right))
+ ucg_rdline_printf(rdl, ucg_vt100_multi_left,
+ ucg_cirbuf_get_len(&rdl->right));
+}
+
+void
+ucg_rdline_redisplay(struct ucg_rdline *rdl)
+{
+ unsigned int i;
+ char tmp;
+
+ ucg_rdline_printf(rdl, ucg_vt100_home);
+ ucg_rdline_printf(rdl, "%s", rdl->prompt);
+ UCG_CIRBUF_FOREACH(&rdl->left, i, tmp) {
+ ucg_rdline_printf(rdl, "%c", tmp);
+ }
+ display_right_buffer(rdl, 1);
+}
+
+static int
+rdline_parse_char(struct ucg_rdline *rdl, char c)
+{
+ unsigned int i;
+ int cmd;
+ char tmp;
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+ const char *history;
+#endif
+
+ cmd = ucg_vt100_parser(&rdl->vt100, c);
+ if (cmd == UCG_VT100_NOT_COMPLETE)
+ return UCG_RDLINE_RES_SUCCESS;
+
+#ifndef UCG_CMD_NO_PAGER
+ /* display asynchrounous printf if any */
+ if (rdl->pager_buf != NULL) {
+
+ /* user ask to exit pager, or last page is displayed*/
+ if ((cmd == UCG_VT100_STD_CHAR && c == 'q') ||
+ rdline_pager_next_page(rdl) == 0) {
+ int ret;
+
+ ret = rdl->pager_ret;
+ rdline_pager_reset(rdl);
+ if (rdl->pager_cb != NULL) {
+ rdl->pager_cb(rdl, rdl->pager_arg);
+ rdl->pager_cb = NULL;
+ }
+ /* maybe the pager was reloaded in the
+ * callback */
+ if (rdl->pager_buf != NULL)
+ return UCG_RDLINE_RES_SUCCESS;
+
+ /* else, redisplay prompt and return the saved status */
+ ucg_rdline_redisplay(rdl);
+ return ret;
+ }
+
+ /* Some pages remain, lines were displayed in
+ * rdline_pager_next_page() */
+ return UCG_RDLINE_RES_SUCCESS;
+ }
+#endif
+
+ /* process control chars */
+ if (cmd != UCG_VT100_STD_CHAR) {
+ switch (cmd) {
+ case UCG_CMD_KEY_CTRL_B:
+ case UCG_CMD_KEY_LEFT_ARR:
+ if (ucg_cirbuf_is_empty(&rdl->left))
+ break;
+ tmp = ucg_cirbuf_get_tail(&rdl->left);
+ ucg_cirbuf_del_tail(&rdl->left);
+ ucg_cirbuf_add_head(&rdl->right, tmp);
+ ucg_rdline_printf(rdl, ucg_vt100_left_arr);
+ break;
+
+ case UCG_CMD_KEY_CTRL_F:
+ case UCG_CMD_KEY_RIGHT_ARR:
+ if (ucg_cirbuf_is_empty(&rdl->right))
+ break;
+ tmp = ucg_cirbuf_get_head(&rdl->right);
+ ucg_cirbuf_del_head(&rdl->right);
+ ucg_cirbuf_add_tail(&rdl->left, tmp);
+ ucg_rdline_printf(rdl, ucg_vt100_right_arr);
+ break;
+
+ case UCG_CMD_KEY_WLEFT:
+ while (! ucg_cirbuf_is_empty(&rdl->left) &&
+ (tmp = ucg_cirbuf_get_tail(&rdl->left)) &&
+ isblank2(tmp)) {
+ ucg_rdline_printf(rdl, ucg_vt100_left_arr);
+ ucg_cirbuf_del_tail(&rdl->left);
+ ucg_cirbuf_add_head(&rdl->right, tmp);
+ }
+ while (! ucg_cirbuf_is_empty(&rdl->left) &&
+ (tmp = ucg_cirbuf_get_tail(&rdl->left)) &&
+ !isblank2(tmp)) {
+ ucg_rdline_printf(rdl, ucg_vt100_left_arr);
+ ucg_cirbuf_del_tail(&rdl->left);
+ ucg_cirbuf_add_head(&rdl->right, tmp);
+ }
+ break;
+
+ case UCG_CMD_KEY_WRIGHT:
+ while (! ucg_cirbuf_is_empty(&rdl->right) &&
+ (tmp = ucg_cirbuf_get_head(&rdl->right)) &&
+ isblank2(tmp)) {
+ ucg_rdline_printf(rdl, ucg_vt100_right_arr);
+ ucg_cirbuf_del_head(&rdl->right);
+ ucg_cirbuf_add_tail(&rdl->left, tmp);
+ }
+ while (! ucg_cirbuf_is_empty(&rdl->right) &&
+ (tmp = ucg_cirbuf_get_head(&rdl->right)) &&
+ !isblank2(tmp)) {
+ ucg_rdline_printf(rdl, ucg_vt100_right_arr);
+ ucg_cirbuf_del_head(&rdl->right);
+ ucg_cirbuf_add_tail(&rdl->left, tmp);
+ }
+ break;
+
+ case UCG_CMD_KEY_BKSPACE:
+ if(!ucg_cirbuf_del_tail_safe(&rdl->left)) {
+ ucg_rdline_printf(rdl, ucg_vt100_bs);
+ display_right_buffer(rdl, 1);
+ }
+ break;
+
+ case UCG_CMD_KEY_META_BKSPACE:
+ case UCG_CMD_KEY_CTRL_W:
+ while (! ucg_cirbuf_is_empty(&rdl->left) &&
+ isblank2(ucg_cirbuf_get_tail(&rdl->left))) {
+ ucg_rdline_printf(rdl, ucg_vt100_bs);
+ ucg_cirbuf_del_tail(&rdl->left);
+ }
+ while (! ucg_cirbuf_is_empty(&rdl->left) &&
+ !isblank2(ucg_cirbuf_get_tail(&rdl->left))) {
+ ucg_rdline_printf(rdl, ucg_vt100_bs);
+ ucg_cirbuf_del_tail(&rdl->left);
+ }
+ display_right_buffer(rdl, 1);
+ break;
+
+ case UCG_CMD_KEY_META_D:
+ while (! ucg_cirbuf_is_empty(&rdl->right) &&
+ isblank2(ucg_cirbuf_get_head(&rdl->right)))
+ ucg_cirbuf_del_head(&rdl->right);
+ while (! ucg_cirbuf_is_empty(&rdl->right) &&
+ !isblank2(ucg_cirbuf_get_head(&rdl->right)))
+ ucg_cirbuf_del_head(&rdl->right);
+ display_right_buffer(rdl, 1);
+ break;
+
+ case UCG_CMD_KEY_SUPPR:
+ case UCG_CMD_KEY_CTRL_D:
+ if (cmd == UCG_CMD_KEY_CTRL_D &&
+ ucg_cirbuf_is_empty(&rdl->left) &&
+ ucg_cirbuf_is_empty(&rdl->right)) {
+ return UCG_RDLINE_RES_EOF;
+ }
+ if (!ucg_cirbuf_del_head_safe(&rdl->right)) {
+ display_right_buffer(rdl, 1);
+ }
+ break;
+
+ case UCG_CMD_KEY_CTRL_A:
+ if (ucg_cirbuf_is_empty(&rdl->left))
+ break;
+ ucg_rdline_printf(rdl, ucg_vt100_multi_left,
+ ucg_cirbuf_get_len(&rdl->left));
+ while (! ucg_cirbuf_is_empty(&rdl->left)) {
+ tmp = ucg_cirbuf_get_tail(&rdl->left);
+ ucg_cirbuf_del_tail(&rdl->left);
+ ucg_cirbuf_add_head(&rdl->right, tmp);
+ }
+ break;
+
+ case UCG_CMD_KEY_CTRL_E:
+ if (ucg_cirbuf_is_empty(&rdl->right))
+ break;
+ ucg_rdline_printf(rdl, ucg_vt100_multi_right,
+ ucg_cirbuf_get_len(&rdl->right));
+ while (! ucg_cirbuf_is_empty(&rdl->right)) {
+ tmp = ucg_cirbuf_get_head(&rdl->right);
+ ucg_cirbuf_del_head(&rdl->right);
+ ucg_cirbuf_add_tail(&rdl->left, tmp);
+ }
+ break;
+
+#ifndef UCG_CMD_NO_RDLINE_KILL_BUF
+ case UCG_CMD_KEY_CTRL_K:
+ ucg_cirbuf_get_buf_head(&rdl->right, rdl->kill_buf,
+ UCG_RDLINE_BUF_SIZE);
+ rdl->kill_size = ucg_cirbuf_get_len(&rdl->right);
+ ucg_cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
+ ucg_rdline_printf(rdl, ucg_vt100_clear_right);
+ break;
+
+ case UCG_CMD_KEY_CTRL_Y:
+ i=0;
+ while (ucg_cirbuf_get_len(&rdl->right) +
+ ucg_cirbuf_get_len(&rdl->left) <
+ UCG_RDLINE_BUF_SIZE &&
+ i < rdl->kill_size) {
+ ucg_cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
+ ucg_rdline_printf(rdl, "%c", rdl->kill_buf[i]);
+ i++;
+ }
+ display_right_buffer(rdl, 0);
+ break;
+#endif /* !UCG_CMD_NO_RDLINE_KILL_BUF */
+
+ case UCG_CMD_KEY_CTRL_C:
+ ucg_rdline_printf(rdl, "\r\n");
+ ucg_rdline_newline(rdl, rdl->prompt);
+ break;
+
+ case UCG_CMD_KEY_CTRL_L:
+ ucg_rdline_redisplay(rdl);
+ break;
+
+ case UCG_CMD_KEY_HELP: {
+ if (rdl->help == NULL)
+ break;
+
+ ucg_cirbuf_align_left(&rdl->left);
+ rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
+ ucg_rdline_printf(rdl, "\r\n");
+ rdl->help(rdl, rdl->left_buf);
+#ifndef UCG_CMD_NO_PAGER
+ if (rdl->pager_buf != NULL)
+ return UCG_RDLINE_RES_SUCCESS;
+ else
+ rdline_pager_reset(rdl);
+#endif
+ ucg_rdline_redisplay(rdl);
+ break;
+ }
+
+ case UCG_CMD_KEY_TAB: {
+ char tmp_buf[UCG_CMD_MAX_TOKEN_SIZE];
+ int ret;
+ unsigned int tmp_size;
+
+ if (rdl->complete == NULL)
+ break;
+
+ ucg_cirbuf_align_left(&rdl->left);
+ rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
+
+ /* try to complete the complete() */
+ ret = rdl->complete(rdl, rdl->left_buf,
+ tmp_buf, sizeof(tmp_buf));
+
+ /* no completion or error */
+ if (ret < 0) {
+ ucg_cirbuf_align_left(&rdl->left);
+ rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
+ ucg_rdline_printf(rdl, "\r\n");
+ rdl->help(rdl, rdl->left_buf);
+#ifndef UCG_CMD_NO_PAGER
+ if (rdl->pager_buf != NULL)
+ return UCG_RDLINE_RES_SUCCESS;
+ else
+ rdline_pager_reset(rdl);
+#endif
+ ucg_rdline_redisplay(rdl);
+ break;
+ }
+
+ tmp_size = strlen(tmp_buf);
+ /* add chars */
+ i = 0;
+ while(ucg_cirbuf_get_len(&rdl->right) +
+ ucg_cirbuf_get_len(&rdl->left) <
+ UCG_RDLINE_BUF_SIZE &&
+ i < tmp_size) {
+ ucg_cirbuf_add_tail(&rdl->left, tmp_buf[i]);
+ ucg_rdline_printf(rdl, "%c", tmp_buf[i]);
+ i++;
+ }
+ display_right_buffer(rdl, 1);
+ break;
+ }
+
+ case UCG_CMD_KEY_RETURN:
+ case UCG_CMD_KEY_RETURN2: {
+ char tmp;
+ while (!ucg_cirbuf_is_empty(&rdl->right) &&
+ (tmp = ucg_cirbuf_get_head(&rdl->right))) {
+ ucg_cirbuf_del_head(&rdl->right);
+ ucg_cirbuf_add_tail(&rdl->left, tmp);
+ }
+ ucg_cirbuf_align_left(&rdl->left);
+ rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
+ ucg_rdline_printf(rdl, "\r\n");
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+ if (rdl->history_cur_line != -1)
+ rdline_remove_first_history_item(rdl);
+#endif
+
+ if (rdl->validate)
+ rdl->validate(rdl, rdl->left_buf);
+#ifndef UCG_CMD_NO_PAGER
+ /* user may have stopped rdline */
+ if (rdl->status == UCG_RDLINE_EXITED) {
+ rdline_pager_reset(rdl);
+ return UCG_RDLINE_RES_EXITED;
+ }
+ /* there is something in pager buffer, save
+ * return value that will be return once
+ * paging is finished */
+ if (rdl->pager_buf != NULL) {
+ rdl->pager_ret = UCG_RDLINE_RES_VALIDATED;
+ return UCG_RDLINE_RES_SUCCESS;
+ }
+
+ rdline_pager_reset(rdl);
+#else
+ if (rdl->status == UCG_RDLINE_EXITED)
+ return UCG_RDLINE_RES_EXITED;
+#endif
+ return UCG_RDLINE_RES_VALIDATED;
+ }
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+ case UCG_CMD_KEY_UP_ARR:
+ case UCG_CMD_KEY_CTRL_P:
+ if (rdl->history_cur_line == 0) {
+ rdline_remove_first_history_item(rdl);
+ }
+ if (rdl->history_cur_line <= 0) {
+ ucg_rdline_add_history(rdl,
+ ucg_rdline_get_buffer(rdl));
+ rdl->history_cur_line = 0;
+ }
+
+ history = ucg_rdline_get_history_item(rdl,
+ rdl->history_cur_line + 1);
+ if (history == NULL)
+ break;
+
+ rdl->history_cur_line++;
+ ucg_vt100_init(&rdl->vt100);
+ ucg_cirbuf_init(&rdl->left, rdl->left_buf, 0,
+ UCG_RDLINE_BUF_SIZE);
+ ucg_cirbuf_init(&rdl->right, rdl->right_buf, 0,
+ UCG_RDLINE_BUF_SIZE);
+ ucg_cirbuf_add_buf_tail(&rdl->left, history,
+ strlen(history));
+ ucg_rdline_redisplay(rdl);
+ break;
+
+ case UCG_CMD_KEY_DOWN_ARR:
+ case UCG_CMD_KEY_CTRL_N:
+ if (rdl->history_cur_line - 1 < 0)
+ break;
+
+ rdl->history_cur_line--;
+ history = ucg_rdline_get_history_item(rdl,
+ rdl->history_cur_line);
+ if (history == NULL)
+ break;
+
+ ucg_vt100_init(&rdl->vt100);
+ ucg_cirbuf_init(&rdl->left, rdl->left_buf, 0,
+ UCG_RDLINE_BUF_SIZE);
+ ucg_cirbuf_init(&rdl->right, rdl->right_buf, 0,
+ UCG_RDLINE_BUF_SIZE);
+ ucg_cirbuf_add_buf_tail(&rdl->left, history,
+ strlen(history));
+ ucg_rdline_redisplay(rdl);
+
+ break;
+#endif /* !UCG_CMD_NO_RDLINE_HISTORY */
+
+ default:
+ break;
+ }
+
+ return UCG_RDLINE_RES_SUCCESS;
+ }
+
+ if (!isprint((int)c))
+ return UCG_RDLINE_RES_SUCCESS;
+
+ /* standard chars */
+ if (ucg_cirbuf_get_len(&rdl->left) +
+ ucg_cirbuf_get_len(&rdl->right) >= UCG_RDLINE_BUF_SIZE)
+ return UCG_RDLINE_RES_SUCCESS;
+
+ if (ucg_cirbuf_add_tail_safe(&rdl->left, c))
+ return UCG_RDLINE_RES_SUCCESS;
+
+ ucg_rdline_printf(rdl, "%c", c);
+ display_right_buffer(rdl, 0);
+
+ return UCG_RDLINE_RES_SUCCESS;
+}
+
+int
+ucg_rdline_char_in(struct ucg_rdline *rdl, char c)
+{
+ int ret, same = 0;
+ const char *history, *buffer;
+
+ if (rdl->status == UCG_RDLINE_EXITED)
+ return UCG_RDLINE_RES_EXITED;
+ if (rdl->status != UCG_RDLINE_RUNNING)
+ return UCG_RDLINE_RES_NOT_RUNNING;
+
+ ret = rdline_parse_char(rdl, c);
+
+ /* add line to history */
+ if (ret == UCG_RDLINE_RES_VALIDATED) {
+ buffer = ucg_rdline_get_buffer(rdl);
+ history = ucg_rdline_get_history_item(rdl, 0);
+ if (history)
+ same = !strcmp(buffer, history);
+
+ if (strlen(buffer) >= 1 && same == 0)
+ ucg_rdline_add_history(rdl, buffer);
+ }
+
+ return ret;
+}
+
+int
+ucg_rdline(struct ucg_rdline *rdl, const char *prompt, unsigned flags)
+{
+ char c;
+ int ret = UCG_RDLINE_RES_NOT_RUNNING;
+
+ ucg_rdline_newline(rdl, prompt);
+ while (1) {
+ if (fread(&c, 1, 1, rdl->f_in) == 0) {
+ if (flags & UCG_RDLINE_F_IGNORE_EOF) {
+ clearerr(rdl->f_in);
+ continue;
+ }
+ break;
+ }
+ ret = ucg_rdline_char_in(rdl, c);
+ if (ret != UCG_RDLINE_RES_SUCCESS)
+ break;
+ }
+
+ return ret;
+}
+
+/* HISTORY */
+
+#ifndef UCG_CMD_NO_RDLINE_HISTORY
+static void
+rdline_remove_old_history_item(struct ucg_rdline *rdl)
+{
+ char tmp;
+
+ while (! ucg_cirbuf_is_empty(&rdl->history) ) {
+ tmp = ucg_cirbuf_get_head(&rdl->history);
+ ucg_cirbuf_del_head(&rdl->history);
+ if (!tmp)
+ break;
+ }
+}
+
+static void
+rdline_remove_first_history_item(struct ucg_rdline *rdl)
+{
+ char tmp;
+
+ if ( ucg_cirbuf_is_empty(&rdl->history) ) {
+ return;
+ }
+ else {
+ ucg_cirbuf_del_tail(&rdl->history);
+ }
+
+ while (! ucg_cirbuf_is_empty(&rdl->history) ) {
+ tmp = ucg_cirbuf_get_tail(&rdl->history);
+ if (!tmp)
+ break;
+ ucg_cirbuf_del_tail(&rdl->history);
+ }
+}
+
+static unsigned int
+rdline_get_history_size(struct ucg_rdline *rdl)
+{
+ unsigned int i, tmp, ret=0;
+
+ UCG_CIRBUF_FOREACH(&rdl->history, i, tmp) {
+ if (tmp == 0)
+ ret ++;
+ }
+
+ return ret;
+}
+
+const char *
+ucg_rdline_get_history_item(struct ucg_rdline *rdl, unsigned int idx)
+{
+ unsigned int len, i, tmp;
+
+ len = rdline_get_history_size(rdl);
+ if (idx >= len)
+ return NULL;
+
+ ucg_cirbuf_align_left(&rdl->history);
+
+ UCG_CIRBUF_FOREACH(&rdl->history, i, tmp) {
+ if (idx == len - 1) {
+ return rdl->history_buf + i;
+ }
+ if (tmp == 0)
+ len --;
+ }
+
+ return NULL;
+}
+
+int
+ucg_rdline_add_history(struct ucg_rdline *rdl, const char *buf)
+{
+ unsigned int len;
+
+ len = strlen(buf);
+ if (len >= UCG_RDLINE_HISTORY_BUF_SIZE)
+ return -1;
+
+ while (len >= ucg_cirbuf_get_freelen(&rdl->history)) {
+ rdline_remove_old_history_item(rdl);
+ }
+
+ ucg_cirbuf_add_buf_tail(&rdl->history, buf, len);
+ ucg_cirbuf_add_tail(&rdl->history, 0);
+
+ return 0;
+}
+
+void
+ucg_rdline_clear_history(struct ucg_rdline *rdl)
+{
+ ucg_cirbuf_init(&rdl->history, rdl->history_buf, 0,
+ UCG_RDLINE_HISTORY_BUF_SIZE);
+}
+
+#else /* !UCG_CMD_NO_RDLINE_HISTORY */
+
+int ucg_rdline_add_history(struct ucg_rdline *rdl, const char *buf)
+{
+ return -1;
+}
+
+void ucg_rdline_clear_history(struct ucg_rdline *rdl)
+{
+ return;
+}
+
+char *ucg_rdline_get_history_item(struct ucg_rdline *rdl, unsigned int i)
+{
+ return NULL;
+}
+
+
+#endif /* !UCG_CMD_NO_RDLINE_HISTORY */
+
+
+ssize_t
+ucg_rdline_write(struct ucg_rdline *rdl, void *buf, size_t count)
+{
+ return fwrite(buf, 1, count, rdl->f_out);
+}
+
+int
+ucg_rdline_vprintf(struct ucg_rdline *rdl, const char *fmt, va_list ap)
+{
+ if (rdl->f_out == NULL)
+ return -1;
+
+ return vfprintf(rdl->f_out, fmt, ap);
+}
+
+int
+ucg_rdline_printf(struct ucg_rdline *rdl, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = ucg_rdline_vprintf(rdl, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+#ifndef UCG_CMD_NO_PAGER
+/* reset pager state */
+void
+rdline_pager_reset(struct ucg_rdline *rdl)
+{
+ if (rdl->pager_buf) {
+ free(rdl->pager_buf);
+ rdl->pager_buf = NULL;
+ }
+ rdl->pager_lines = 0;
+ rdl->pager_len = 0;
+ rdl->pager_off = 0;
+ rdl->pager_cb = NULL;
+ rdl->pager_arg = NULL;
+ rdl->pager_ret = UCG_RDLINE_RES_SUCCESS;
+}
+
+/* Return the offset of the i-th occurence of char c in string s. If
+ * there is less than i occurences, return -1 and fill i with the
+ * count. */
+static int
+strnchr(const char *s, char c, int *i)
+{
+ int n = 0;
+ const char *orig = s;
+
+ while (*s) {
+ if (*s == c)
+ n++;
+ if (*i == n)
+ return s - orig;
+ s++;
+ }
+ *i = n;
+ return -1;
+}
+
+/* display a page of data from pager, return 0 if all is displayed */
+static int
+rdline_pager_next_page(struct ucg_rdline *rdl)
+{
+ int lines = UCG_RDLINE_MAX_LINES;
+ int displen;
+ char *s;
+
+ s = rdl->pager_buf;
+ if (s == NULL)
+ return 0;
+
+ ucg_rdline_printf(rdl, ucg_vt100_home);
+ ucg_rdline_printf(rdl, ucg_vt100_clear_right);
+
+ s += rdl->pager_off;
+
+ /* we know that s is 0-terminated */
+ displen = strnchr(s, '\n', &lines);
+ rdl->pager_lines = lines;
+
+ /* we can display all the data */
+ if (displen == -1) {
+ fwrite(s, 1, rdl->pager_len, rdl->f_out);
+ free(rdl->pager_buf);
+ rdl->pager_buf = NULL;
+ return 0;
+ }
+
+ displen = displen + 1; /* include \n */
+ fwrite(s, 1, displen, rdl->f_out);
+ rdl->pager_off += displen;
+ rdl->pager_len -= displen;
+
+ ucg_rdline_printf(rdl, "--- press a key to continue ---");
+ return -1;
+}
+
+/* push data in pager */
+ssize_t
+ucg_rdline_pager_write(struct ucg_rdline *rdl, void *buf, size_t len)
+{
+ char *s = buf;
+
+ /* display as many lines as we can */
+ if (rdl->pager_lines < UCG_RDLINE_MAX_LINES) {
+ int lines = UCG_RDLINE_MAX_LINES - rdl->pager_lines;
+ int displen;
+
+ /* we know that s is 0-terminated */
+ displen = strnchr(s, '\n', &lines);
+ rdl->pager_lines += lines;
+
+ /* we can display all the data */
+ if (displen == -1) {
+ fwrite(s, 1, len, rdl->f_out);
+ return 0;
+ }
+ displen = displen + 1; /* include \n */
+ fwrite(s, 1, displen, rdl->f_out);
+ s += displen;
+ len -= displen;
+ }
+
+ if (rdl->pager_buf == NULL) {
+ ucg_rdline_printf(rdl, "--- press a key to continue ---");
+ }
+ rdl->pager_buf = realloc(rdl->pager_buf, rdl->pager_len + len);
+ if (rdl->pager_buf == NULL) {
+ rdline_pager_reset(rdl);
+ return -1;
+ }
+
+ memcpy(rdl->pager_buf + rdl->pager_len, s, len);
+ rdl->pager_len += len;
+ return 0;
+}
+
+/* Print data asynchronously (using pager if needed) */
+int
+ucg_rdline_pager_printf(struct ucg_rdline *rdl, const char *fmt, ...)
+{
+ int n;
+ char *buf = NULL;
+ va_list ap;
+
+ if (rdl->f_out == NULL)
+ return -1;
+
+ va_start(ap, fmt);
+ n = vasprintf(&buf, fmt, ap);
+ va_end(ap);
+
+ if (n > 0)
+ ucg_rdline_pager_write(rdl, buf, n);
+ free(buf);
+ return n;
+}
+
+int ucg_rdline_pager_set_cb(struct ucg_rdline *rdl,
+ ucg_rdline_pager_cb_t *cb, void *arg)
+{
+ if (rdl->pager_buf == NULL)
+ return -1;
+
+ rdl->pager_cb = cb;
+ rdl->pager_arg = arg;
+ return 0;
+}
+#endif /* !UCG_CMD_NO_PAGER */
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#ifdef UCG_CMD_HAVE_TERMIOS
+#include <termios.h>
+#endif
+
+#ifdef UCG_CMD_HAVE_SOCKET
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+#include "ucg_cmd_parse.h"
+#include "ucg_cmd_rdline.h"
+#include "ucg_cmd_socket.h"
+#include "ucg_cmd.h"
+
+#ifdef UCG_CMD_HAVE_SOCKET
+int
+ucg_cmd_tcpv4_listen(in_addr_t addr, uint16_t port)
+{
+ int s;
+ struct sockaddr_in sin_ci;
+ int optval = 1;
+
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return s;
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ &optval, sizeof(optval)) == -1)
+ goto end;
+
+ memset(&sin_ci, 0, sizeof(sin_ci));
+ sin_ci.sin_family = AF_INET;
+ sin_ci.sin_addr.s_addr = addr;
+ sin_ci.sin_port = htons(port);
+#ifndef __linux__
+ sin_ci.sin_len = sizeof(sin_ci);
+#endif
+ if (bind(s, (struct sockaddr *)&sin_ci, sizeof(sin_ci)) < 0)
+ goto end;
+
+ if (listen(s, 1) < 0)
+ goto end;
+
+ return s;
+ end:
+ close(s);
+ return -1;
+}
+
+int
+ucg_cmd_tcpv6_listen(const struct in6_addr *addr6, uint16_t port)
+{
+ int s;
+ struct sockaddr_in6 sin6_ci;
+
+ s = socket(PF_INET6, SOCK_STREAM, 0);
+ if (s < 0)
+ return s;
+
+ bzero(&sin6_ci, sizeof(sin6_ci));
+ sin6_ci.sin6_family = AF_INET6;
+#ifndef __linux__
+ sin6_ci.sin6_len = sizeof(sin6_ci);
+#endif
+ memcpy(&sin6_ci.sin6_addr, addr6, sizeof(sin6_ci.sin6_addr));
+ sin6_ci.sin6_port = htons(port);
+ if (bind(s, (struct sockaddr *) &sin6_ci, sizeof(sin6_ci)) < 0)
+ goto end;
+
+ if (listen(s, 1) < 0)
+ goto end;
+
+ return s;
+ end:
+ close(s);
+ return -1;
+}
+
+int
+ucg_cmd_unix_listen(const char *filename)
+{
+ int s;
+ struct sockaddr_un servAddr;
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0)
+ return s;
+
+ bzero(&servAddr, sizeof(servAddr));
+ servAddr.sun_family = AF_UNIX;
+ memcpy(servAddr.sun_path, filename , strlen(filename));
+
+ unlink(filename);
+ if(bind(s, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
+ goto end;
+
+ if (listen(s, 1) < 0)
+ goto end;
+
+ return s;
+ end:
+ close(s);
+ return -1;
+}
+
+struct ucg_cmd *
+ucg_cmd_accept(ucg_cmd_ctx_t *ctx, const char *prompt, int s)
+{
+ FILE *f;
+ int s2;
+ struct sockaddr sin;
+ socklen_t sinlen;
+
+ sinlen = sizeof(struct sockaddr);
+
+ if ((s2 = accept(s, &sin, &sinlen)) < 0)
+ return NULL;
+
+ f = fdopen(s2, "r+");
+ if (f == NULL) {
+ close(s2);
+ return NULL;
+ }
+ return (ucg_cmd_new(ctx, prompt, f, f));
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#ifdef UCG_CMD_HAVE_TERMIOS
+#include <termios.h>
+#endif
+
+#include "ucg_cmd.h"
+#include "ucg_cmd_termios.h"
+
+int ucg_cmd_termios_raw(struct ucg_cmd *cl)
+{
+ int ret = 0;
+
+#ifdef UCG_CMD_HAVE_TERMIOS
+ struct termios oldterm, term;
+
+ ret = tcgetattr(0, &oldterm);
+ if (ret < 0)
+ return ret;
+
+ memcpy(&term, &oldterm, sizeof(term));
+ term.c_lflag &= ~(ICANON | ECHO | ISIG);
+ ret = tcsetattr(0, TCSANOW, &term);
+ if (ret < 0)
+ return ret;
+
+ memcpy(&cl->oldterm, &oldterm, sizeof(term));
+#endif
+
+ (void)cl; /* silent compiler */
+
+ return ret;
+}
+
+int ucg_cmd_termios_restore(struct ucg_cmd *cl)
+{
+ int ret = 0;
+ (void)cl; /* silent compiler */
+
+#ifdef UCG_CMD_HAVE_TERMIOS
+ ret = tcsetattr(fileno(stdin), TCSANOW, &cl->oldterm);
+#endif
+ return ret;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "ucg_cmd_vt100.h"
+
+const char *ucg_cmd_vt100_commands[] = {
+ ucg_vt100_up_arr,
+ ucg_vt100_down_arr,
+ ucg_vt100_right_arr,
+ ucg_vt100_left_arr,
+ "\177",
+ "\n",
+ "\001",
+ "\005",
+ "\013",
+ "\031",
+ "\003",
+ "\006",
+ "\002",
+ ucg_vt100_suppr,
+ ucg_vt100_tab,
+ "\004",
+ "\014",
+ "\r",
+ "\033\177",
+ ucg_vt100_word_left,
+ ucg_vt100_word_right,
+ "?",
+ "\027",
+ "\020",
+ "\016",
+ "\033\144",
+};
+
+void
+ucg_vt100_init(struct ucg_cmd_vt100 *vt)
+{
+ vt->state = UCG_CMD_VT100_INIT;
+}
+
+
+static int
+match_command(char *buf, unsigned int size)
+{
+ const char *cmd;
+ unsigned int i = 0;
+
+ for (i = 0; i < sizeof(ucg_cmd_vt100_commands) /
+ sizeof(const char *); i++) {
+ cmd = *(ucg_cmd_vt100_commands + i);
+
+ if (size == strlen(cmd) &&
+ !strncmp(buf, cmd, strlen(cmd))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int
+ucg_vt100_parser(struct ucg_cmd_vt100 *vt, char ch)
+{
+ unsigned int size;
+ uint8_t c = (uint8_t) ch;
+
+ if (vt->bufpos > UCG_CMD_VT100_BUF_SIZE) {
+ vt->state = UCG_CMD_VT100_INIT;
+ vt->bufpos = 0;
+ }
+
+ vt->buf[vt->bufpos++] = c;
+ size = vt->bufpos;
+
+ switch (vt->state) {
+ case UCG_CMD_VT100_INIT:
+ if (c == 033) {
+ vt->state = UCG_CMD_VT100_ESCAPE;
+ }
+ else {
+ vt->bufpos = 0;
+ goto match_command;
+ }
+ break;
+
+ case UCG_CMD_VT100_ESCAPE:
+ if (c == 0133) {
+ vt->state = UCG_CMD_VT100_ESCAPE_CSI;
+ }
+ else if (c >= 060 && c <= 0177) {
+ vt->bufpos = 0;
+ vt->state = UCG_CMD_VT100_INIT;
+ goto match_command;
+ }
+ break;
+
+ case UCG_CMD_VT100_ESCAPE_CSI:
+ if (c >= 0100 && c <= 0176) {
+ vt->bufpos = 0;
+ vt->state = UCG_CMD_VT100_INIT;
+ goto match_command;
+ }
+ break;
+
+ default:
+ vt->bufpos = 0;
+ break;
+ }
+
+ return -2;
+
+ match_command:
+ return match_command(vt->buf, size);
+}
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_GLOSS_DEVICE_H_
+#define UCG_GLOSS_DEVICE_H_
+
+#include <sys/queue.h>
+#include <string.h>
+
+/**
+ * Maximum number of devices stored in cache.
+ *
+ * Instead of only storing the devices in a list, the first ones are
+ * stored in a table indexed by the file descriptor. This avoids a
+ * linear browsing on lookup.
+ */
+#define GLOSS_DEVICE_CACHE_MAX 4
+
+/**
+ * Structure describing a device
+ *
+ * It can be registered using ucg_chardev_register(), and allows to
+ * redirect file operations to any channel (uart, spi, ...).
+ */
+struct ucg_chardev {
+ /* filled by ucg_chardev_register() */
+ TAILQ_ENTRY(ucg_chardev) next;
+ int fd;
+
+ /* filled by user before registration */
+ const char *name;
+ int (*open_r)(struct _reent *r, const char *path, int flags, int mode);
+ int (*close_r)(struct _reent *r, int fd);
+ _ssize_t (*read_r)(struct _reent *r, int fd, void *ptr, size_t len);
+ _ssize_t (*write_r)(struct _reent *r, int fd, const void *ptr, size_t len);
+};
+
+/**
+ * The list of devices.
+ */
+TAILQ_HEAD(ucg_chardev_list, ucg_chardev);
+struct ucg_chardev_list ucg_chardev_list;
+
+/**
+ * Table of first ucg_chardev pointers, initialized to NULL.
+ */
+struct ucg_chardev *ucg_chardev_cache[GLOSS_DEVICE_CACHE_MAX];
+
+/**
+ * Register a device
+ *
+ * Register device operations. The structure is appended to the device
+ * list, and its name and fd fields are modified. Therefore, a structure
+ * cannot be registered twice.
+ *
+ * The first three devices to be registered are stdin, stdout and stderr.
+ *
+ * @param dev
+ * The filled device structure
+ * @return
+ * 0 on success, negative on error
+ */
+int ucg_chardev_register(struct ucg_chardev *dev);
+
+/**
+ * Return the device associated to the given file descriptor.
+ *
+ * @param fd
+ * The file descriptor.
+ * @return
+ * The device matching the file descriptor.
+ */
+static inline const struct ucg_chardev *
+ucg_chardev_lookup_from_fd(int fd)
+{
+ const struct ucg_chardev *dev;
+
+ if (fd >= 0 && fd < GLOSS_DEVICE_CACHE_MAX)
+ return ucg_chardev_cache[fd];
+
+ TAILQ_FOREACH(dev, &ucg_chardev_list, next) {
+ if (dev->fd == fd)
+ return dev;
+ }
+ return NULL;
+}
+
+/**
+ * Return the device associated to the given name.
+ *
+ * @param name
+ * The name of the file.
+ * @return
+ * The device matching the file name.
+ */
+static inline const struct ucg_chardev *
+ucg_chardev_lookup_from_name(const char *name)
+{
+ const struct ucg_chardev *dev;
+
+ TAILQ_FOREACH(dev, &ucg_chardev_list, next) {
+ if (strcmp(name, dev->name) == 0)
+ return dev;
+ }
+ return NULL;
+}
+
+#endif /* UCG_GLOSS_DEVICE_H_ */
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <errno.h>
+
+#include <ucg_gloss_chardev.h>
+
+struct ucg_chardev_list ucg_chardev_list =
+ TAILQ_HEAD_INITIALIZER(ucg_chardev_list);
+
+static int max_fd = 0;
+
+/* register a device for file operations */
+int ucg_chardev_register(struct ucg_chardev *dev)
+{
+ if (dev->name == NULL)
+ return -EINVAL;
+
+ if (ucg_chardev_lookup_from_name(dev->name) != NULL)
+ return -EEXIST;
+
+ TAILQ_INSERT_TAIL(&ucg_chardev_list, dev, next);
+
+ dev->fd = max_fd ++;
+ if (dev->fd < GLOSS_DEVICE_CACHE_MAX)
+ ucg_chardev_cache[dev->fd] = dev;
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <reent.h>
+#include <errno.h>
+
+#include <ucg_gloss_chardev.h>
+
+/* provide a dummy environment */
+char *__env[1] = { 0 };
+char **environ = __env;
+
+/* provide a definition of errno if not already provided */
+int errno;
+
+/* defined by the linker, used by _sbrk */
+extern char _ebss;
+
+/* open a device, return its file descriptor */
+int
+_open_r(struct _reent *reent, const char *file, int flags, int mode)
+{
+ const struct ucg_chardev *dev;
+
+ dev = ucg_chardev_lookup_from_name(file);
+ if (dev == NULL) {
+ reent->_errno = ENODEV;
+ return -1;
+ }
+
+ if (dev->open_r)
+ dev->open_r(reent, file, flags, mode);
+
+ return dev->fd;
+}
+
+/* close a device */
+int
+_close_r(struct _reent *reent, int fd)
+{
+ const struct ucg_chardev *dev;
+
+ dev = ucg_chardev_lookup_from_fd(fd);
+ if (dev == NULL) {
+ reent->_errno = EBADF;
+ return -1;
+ }
+
+ /* call the close() handler if defined */
+ if (dev->close_r)
+ return dev->close_r(reent, fd);
+
+ return 0;
+}
+
+/* read a device. */
+_ssize_t
+_read_r(struct _reent *reent, int fd, void *ptr, size_t len)
+{
+ const struct ucg_chardev *dev;
+
+ dev = ucg_chardev_lookup_from_fd(fd);
+ if (dev == NULL) {
+ reent->_errno = EBADF;
+ return -1;
+ }
+
+ if (dev->read_r)
+ return dev->read_r(reent, fd, ptr, len);
+
+ reent->_errno = ENODEV;
+ return -1;
+}
+
+/* write to a device */
+_ssize_t
+_write_r(struct _reent *reent, int fd, const void *ptr, size_t len)
+{
+ const struct ucg_chardev *dev;
+
+ dev = ucg_chardev_lookup_from_fd(fd);
+ if (dev == NULL) {
+ reent->_errno = EBADF;
+ return -1;
+ }
+
+ if (dev->write_r)
+ return dev->write_r(reent, fd, ptr, len);
+
+ reent->_errno = ENODEV;
+ return -1;
+}
+
+/* exit: print error code and loop forever */
+void
+_exit(int rc)
+{
+ printf("exit %d\n", rc);
+ while (1);
+}
+
+/* set owner: not implemented */
+int
+_chown_r(struct _reent *reent,
+ __attribute__((unused)) const char *path,
+ __attribute__((unused)) uid_t owner,
+ __attribute__((unused)) gid_t group)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* execve: not implemented */
+int
+_execve_r(struct _reent *reent,
+ __attribute__((unused)) const char *name,
+ __attribute__((unused)) char *const *argv,
+ __attribute__((unused)) char *const *env)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* fork: not implemented */
+int
+_fork_r(struct _reent *reent)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* fstat: not implemented, all devices are character devices */
+int
+_fstat_r(__attribute__((unused)) struct _reent *reent,
+ __attribute__((unused)) int fildes,
+ struct stat *st)
+{
+ st->st_mode = S_IFCHR;
+ return 0;
+}
+
+/* getpid: not implemented */
+int
+_getpid_r(struct _reent *reent)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+struct timeval;
+
+/* gettimeofday: not implemented */
+int
+_gettimeofday_r(struct _reent *reent,
+ __attribute__((unused)) struct timeval *ptimeval,
+ __attribute__((unused)) void *ptimezone)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* isatty; not implemented */
+int
+_isatty_r(struct _reent *reent, __attribute__((unused)) int file)
+{
+ reent->_errno = ENOTTY;
+ return 0;
+}
+
+/* kill a process: not implemented */
+int
+_kill_r(struct _reent *reent,
+ __attribute__((unused)) int pid,
+ __attribute__((unused)) int sig)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* link: not implemented */
+int
+_link_r(struct _reent *reent,
+ __attribute__((unused)) const char *existing,
+ __attribute__((unused)) const char *new)
+{
+ reent->_errno = EMLINK;
+ return -1;
+}
+
+/* lseek: not implemented */
+_off_t
+_lseek_r(__attribute__((unused)) struct _reent *reent,
+ __attribute__((unused)) int file,
+ __attribute__((unused)) _off_t ptr,
+ __attribute__((unused)) int dir)
+{
+ return 0;
+}
+
+/* readlink: not implemented */
+int
+_readlink_r(struct _reent *reent,
+ __attribute__((unused)) const char *path,
+ __attribute__((unused)) char *buf,
+ __attribute__((unused)) size_t bufsize)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* simple sbrk */
+void *
+_sbrk_r(__attribute__((unused)) struct _reent *reent, ptrdiff_t incr)
+{
+ static char *heap_end = NULL;
+ char *prev_heap_end;
+
+ if (heap_end == NULL)
+ heap_end = &_ebss;
+
+ prev_heap_end = heap_end;
+ heap_end += incr;
+ return (caddr_t)prev_heap_end;
+}
+
+/* stat: not implemented, all devices are character devices */
+int
+_stat_r(__attribute__((unused)) struct _reent *reent,
+ __attribute__((unused)) const char *file,
+ struct stat *st)
+{
+ st->st_mode = S_IFCHR;
+ return 0;
+}
+
+/* symlink: not implemented */
+int
+_symlink_r(struct _reent *reent,
+ __attribute__((unused)) const char *path1,
+ __attribute__((unused)) const char *path2)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* times: not timplemented */
+clock_t
+_times_r(struct _reent *reent,
+ __attribute__((unused)) struct tms *buf)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
+/* unlink: not implemented */
+int
+_unlink_r(struct _reent *reent,
+ __attribute__((unused)) const char *name)
+{
+ reent->_errno = EMLINK;
+ return -1;
+}
+
+/* wait: not implemented */
+int
+_wait_r(struct _reent *reent, __attribute__((unused)) int *status)
+{
+ reent->_errno = ENOSYS;
+ return -1;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2005-2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCG_UART_H_
+#define UCG_UART_H_
+
+#include <ucg_cirbuf.h>
+
+/**
+ * UART interface, using interrupts. Supports 5 to 8 bits characters
+ * (not 9 bits).
+ */
+
+/**
+ * Callback type of tx/rx event.
+ */
+typedef void (ucg_uart_cb_t)(char);
+
+struct ucg_uart;
+
+/**
+ * Configuration of the uart
+ */
+struct ucg_uart_config {
+ uint8_t enable : 1, /**< enable or disable the uart */
+ parity : 2, /**< none, odd or even */
+ stop_bits : 1, /**< 1 or 2 bits at the end of the frame */
+ reserved : 4; /**< nothing for now */
+ uint8_t nbits; /**< number of bits in frame, 5, 6, 7 or 8 */
+ uint32_t baudrate; /**< speed of uart */
+};
+
+/**
+ * Per-arch uart driver operations
+ */
+struct ucg_uart_driver_ops {
+ void (*disable_tx_irq)(struct ucg_uart *uart); /**< Disable tx intrpt */
+ void (*enable_tx_irq)(struct ucg_uart *uart); /**< Enable tx intrpt */
+ uint8_t (*tx_ready)(struct ucg_uart *uart); /**< Test if tx register empty */
+ uint8_t (*rx_ready)(struct ucg_uart *uart); /**< Test if rx register full */
+ void (*set_udr)(struct ucg_uart *uart, char c); /**< Set uart data register */
+ char (*get_udr)(struct ucg_uart *uart); /**< Get uart data register */
+ int (*set_conf)(struct ucg_uart *uart,
+ const struct ucg_uart_config *conf); /**< Set configuration */
+};
+
+/**
+ * Generic Uart structure
+ */
+struct ucg_uart {
+ struct ucg_uart_config conf; /**< Current configuration */
+ ucg_uart_cb_t *rx_cb; /**< RX callback */
+ ucg_uart_cb_t *tx_cb; /**< TX callback */
+ struct ucg_cirbuf *rx_fifo; /**< RX fifo */
+ struct ucg_cirbuf *tx_fifo; /**< TX fifo */
+ const struct ucg_uart_driver_ops *ops; /**< Pointer to arch uart ops */
+ void *driver_data; /**< Opaque arch uart data */
+};
+
+/**
+ * Uart wait directive, used in rx/tx functions.
+ */
+enum ucg_uart_wait {
+ WAIT, /**< Loop until operation can be done */
+ NOWAIT, /**< Return if operation can't be done now */
+};
+
+/**
+ * Handle TX register empty interrupt
+ *
+ * @param uart
+ * The uart structure.
+ */
+void ucg_uart_tx_intr(struct ucg_uart *uart);
+
+/**
+ * Handle RX register empty interrupt
+ *
+ * @param uart
+ * The uart structure.
+ */
+void ucg_uart_rx_intr(struct ucg_uart *uart);
+
+/**
+ * Initialize uart
+ *
+ * Initialize the per-arch and generic uart structure, the rx and tx
+ * fifos, and configure the uart with the default configuration.
+ *
+ * @param uart
+ * The uart structure.
+ * @param ops
+ * A pointer to the per-arch uart operations.
+ * @param driver_data
+ * A pointer to a per-arch uart data structure (ex: struct ucg_stm32_uart *)
+ * @param rx_cbuf
+ * A pointer to an uninitialized cirbuf, used for rx fifo
+ * @param rx_buf
+ * The buffer used by the rx fifo
+ * @param rx_bufsize
+ * The length of rx_buf in bytes
+ * @param tx_cbuf
+ * A pointer to an uninitialized cirbuf, used for tx fifo
+ * @param tx_buf
+ * The buffer used by the tx fifo
+ * @param tx_bufsize
+ * The length of tx_buf in bytes
+ * @return
+ * 0 on success, negative on error.
+ */
+int ucg_uart_init(struct ucg_uart *uart,
+ const struct ucg_uart_driver_ops *ops, void *driver_data,
+ struct ucg_cirbuf *rx_cbuf, char *rx_buf, unsigned rx_bufsize,
+ struct ucg_cirbuf *tx_cbuf, char *tx_buf, unsigned tx_bufsize);
+
+/**
+ * Configure the uart with the given configuration.
+ *
+ * The function ucg_uart_init() must have been called first.
+ *
+ * @param uart
+ * The uart structure.
+ * @param conf
+ * The configuration to be applied.
+ * @return
+ * 0 on success, negative on error.
+ */
+int ucg_uart_setconf(struct ucg_uart *uart, const struct ucg_uart_config *conf);
+
+/**
+ * Get the current configuration of the uart.
+ *
+ * @param uart
+ * The uart structure.
+ * @param conf
+ * The pointer to be filled with the current running configuration.
+ */
+void ucg_uart_getconf(struct ucg_uart *uart, struct ucg_uart_config *conf);
+
+/**
+ * Receive a character.
+ *
+ * Receive the next character, taken from the fifo if any. If NOWAIT is
+ * given, the function returns an error if the fifo is empty. If WAIT is
+ * given, the function loops until a new character can be returned.
+ *
+ * The function can be called from an interrupt, but it should be used
+ * with care if WAIT is given, as it will loop until a character is
+ * received.
+ *
+ * @param uart
+ * The uart structure.
+ * @param wait
+ * The wait directive (WAIT or NOWAIT)
+ * @return
+ * Return the character on success (>= 0), or a negative value on error.
+ */
+int ucg_uart_recv(struct ucg_uart *uart, enum ucg_uart_wait wait);
+
+/**
+ * Send a character.
+ *
+ * Put a new character in the TX fifo. If NOWAIT is given, the function
+ * returns an error if the fifo is full. If WAIT is given, the function
+ * loops until some room is available in the tx fifo.
+ *
+ * The function can be called from an interrupt, but it should be used
+ * with care if WAIT is given, as it will wait that the current
+ * transmission is finished before returning.
+ *
+ * @param uart
+ * The uart structure.
+ * @param wait
+ * The wait directive (WAIT or NOWAIT)
+ * @return
+ * Return the transmitted character on success (>= 0), or a negative
+ * value on error.
+ */
+int ucg_uart_send(struct ucg_uart *uart, char c, enum ucg_uart_wait wait);
+
+/**
+ * Flush the TX fifo
+ *
+ * Loop until the uart TX fifo is empty. The function can be called from
+ * an interrupt, but it should be used with care as it will wait that the
+ * transmission of all bytes of the fifo is finished before returning.
+ *
+ * @param uart
+ * The uart structure.
+ */
+void ucg_uart_flush(struct ucg_uart *uart);
+
+/**
+ * Register a TX callback function
+ *
+ * Register a function that will be called after a character is written
+ * in the UART dta register. This function is called with interrupts
+ * locked, and the user is free to access or modify the tx fifo if
+ * required. Note that the character that has just been transmitted is
+ * not in the tx fifo when the callback is invoked.
+ *
+ * @param uart
+ * The uart structure.
+ * @param f
+ * The function to call on tx event, can be NULL to disable.
+ * @param arg
+ * The opaque argument given to the function.
+ */
+void ucg_uart_register_tx_cb(struct ucg_uart *uart, ucg_uart_cb_t *f);
+
+/**
+ * Register a TX callback function
+ *
+ * Register a function that will be called after a character is read
+ * from the UART dta register. This function is called with interrupts
+ * locked, and the user is free to access or modify the rx fifo if
+ * required. Note that the character that has just been received is
+ * present in the rx fifo when the callback is invoked.
+ *
+ * @param uart
+ * The uart structure.
+ * @param f
+ * The function to call on tx event, can be NULL to disable.
+ * @param arg
+ * The opaque argument given to the function.
+ */
+void ucg_uart_register_rx_cb(struct ucg_uart *uart, ucg_uart_cb_t *f);
+
+#endif /* UCG_UART_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2005-2015, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <ucg_irq.h>
+#include <ucg_cirbuf.h>
+#include <ucg_uart.h>
+
+/* Send the next char, or disable tx interruptions if tx fifo is
+ * empty. Must be called with intrp locked and uart data register
+ * empty. */
+static void ucg_uart_send_next_char(struct ucg_uart *uart)
+{
+ char c;
+
+ if (ucg_cirbuf_is_empty(uart->tx_fifo)) {
+ uart->ops->disable_tx_irq(uart);
+ return;
+ }
+
+ c = ucg_cirbuf_get_tail(uart->tx_fifo);
+ ucg_cirbuf_del_tail(uart->tx_fifo);
+ uart->ops->set_udr(uart, c);
+ if (uart->tx_cb != NULL)
+ uart->tx_cb(c);
+
+ uart->ops->enable_tx_irq(uart);
+
+}
+
+/* Receive char and put it in the fifo. If the rx fifo is full, the char
+ * is dropped. Must be called with intrp locked and uart data register
+ * empty. */
+static void ucg_uart_recv_next_char(struct ucg_uart *uart)
+{
+ char c;
+
+ c = uart->ops->get_udr(uart);
+
+ if (!ucg_cirbuf_is_full(uart->rx_fifo))
+ ucg_cirbuf_add_head(uart->rx_fifo, c);
+
+ if (uart->rx_cb != NULL)
+ uart->rx_cb(c);
+}
+
+/* called by user to handle the "tx register empty" interrupt */
+void ucg_uart_tx_intr(struct ucg_uart *uart)
+{
+ ucg_uart_send_next_char(uart);
+}
+
+/* called by user to handle the "rx register non empty" interrupt */
+void ucg_uart_rx_intr(struct ucg_uart *uart)
+{
+ ucg_uart_recv_next_char(uart);
+}
+
+
+/* get a char from the receive fifo */
+static int ucg_uart_recv_nowait(struct ucg_uart *uart)
+{
+ char c = 0;
+ ucg_irqflags_t flags;
+
+ flags = ucg_irq_lock_save();
+ if (ucg_cirbuf_is_empty(uart->rx_fifo)) {
+ ucg_irq_unlock_restore(flags);
+ return -1;
+ }
+
+ c = ucg_cirbuf_get_tail(uart->rx_fifo);
+ ucg_cirbuf_del_tail(uart->rx_fifo);
+ ucg_irq_unlock_restore(flags);
+
+ return (int)c;
+}
+
+/* get a char from the receive fifo */
+int ucg_uart_recv(struct ucg_uart *uart, enum ucg_uart_wait wait)
+{
+ int c = 0;
+
+ c = ucg_uart_recv_nowait(uart);
+ if (c >= 0)
+ return c;
+
+ if (wait == NOWAIT)
+ return -1;
+
+ if (ucg_irq_locked()) {
+ /* if irq are masked we have to poll uart register */
+ while (!uart->ops->rx_ready(uart))
+ ;
+
+ /* then receive the data, and return it */
+ ucg_uart_recv_next_char(uart);
+ c = ucg_uart_recv_nowait(uart);
+ } else {
+ while ((c = ucg_uart_recv_nowait(uart)) == -1)
+ ;
+ }
+
+ return c;
+}
+
+/* send a char, or put it in the fifo if uart is not ready. Return -1
+ * if fifo is full */
+static int ucg_uart_send_nowait(struct ucg_uart *uart, char c)
+{
+ ucg_irqflags_t flags;
+
+ flags = ucg_irq_lock_save();
+
+ if (ucg_cirbuf_is_full(uart->tx_fifo)) {
+ ucg_irq_unlock_restore(flags);
+ return -1;
+ }
+
+ /* uart is ready to send */
+ if (ucg_cirbuf_is_empty(uart->tx_fifo) && uart->ops->tx_ready(uart)) {
+ uart->ops->set_udr(uart, c);
+ if (uart->tx_cb != NULL)
+ uart->tx_cb(c);
+ uart->ops->enable_tx_irq(uart);
+
+ }
+ else { /* not ready, put char in fifo */
+ ucg_cirbuf_add_head(uart->tx_fifo, c);
+ }
+
+ ucg_irq_unlock_restore(flags);
+ return 0;
+}
+
+/* send a byte */
+int ucg_uart_send(struct ucg_uart *uart, char c, enum ucg_uart_wait wait)
+{
+ /* try to send the char */
+ if (ucg_uart_send_nowait(uart, c) == 0)
+ return 0;
+
+ if (wait == NOWAIT)
+ return -1;
+
+ if (ucg_irq_locked()) {
+ /* if irq are masked we have to poll uart register */
+ while (!uart->ops->tx_ready(uart))
+ ;
+
+ /* then send a data to free a room in the fifo */
+ ucg_uart_send_next_char(uart);
+ ucg_cirbuf_add_head(uart->tx_fifo, c);
+ } else {
+ /* if irq are not locked, we can loop to emit */
+ while (ucg_uart_send_nowait(uart, c) != 0)
+ ;
+ }
+ return 0;
+}
+
+/* flush the tx fifo */
+void ucg_uart_flush(struct ucg_uart *uart)
+{
+ ucg_irqflags_t flags;
+
+ if (ucg_irq_locked()) {
+ /* poll uart register, and send next byte until tx fifo
+ * is empty */
+ while (1) {
+ if (ucg_cirbuf_is_empty(uart->tx_fifo))
+ break;
+ while (!uart->ops->tx_ready(uart))
+ ;
+ ucg_uart_send_next_char(uart);
+ }
+ } else {
+ /* just wait that tx fifo is empty */
+ while (1) {
+ flags = ucg_irq_lock_save();
+ if (ucg_cirbuf_is_empty(uart->tx_fifo)) {
+ ucg_irq_unlock_restore(flags);
+ break;
+ }
+ ucg_irq_unlock_restore(flags);
+ }
+ }
+}
+
+/* read the current running configuration */
+void ucg_uart_getconf(struct ucg_uart *uart, struct ucg_uart_config *conf)
+{
+ memcpy(conf, &uart->conf, sizeof(*conf));
+}
+
+/* set a new uart config */
+int ucg_uart_setconf(struct ucg_uart *uart, const struct ucg_uart_config *conf)
+{
+ int ret;
+
+ ret = uart->ops->set_conf(uart, conf);
+ if (ret < 0)
+ return ret;
+
+ memcpy(&uart->conf, conf, sizeof(*conf));
+ return 0;
+}
+
+/* register the function that will be executed at each byte transmission */
+void ucg_uart_register_tx_cb(struct ucg_uart *uart, void (*f)(char))
+{
+ ucg_irqflags_t flags;
+
+ flags = ucg_irq_lock_save();
+ uart->tx_cb = f;
+ ucg_irq_unlock_restore(flags);
+}
+
+/* register the function that will be executed at each byte reception */
+void ucg_uart_register_rx_cb(struct ucg_uart *uart, void (*f)(char))
+{
+ ucg_irqflags_t flags;
+
+ flags = ucg_irq_lock_save();
+ uart->rx_cb = f;
+ ucg_irq_unlock_restore(flags);
+}
+
+/* init uart and fifos, call the per-arch initialization and set a default
+ * configuration (9600 bauds) */
+int ucg_uart_init(struct ucg_uart *uart,
+ const struct ucg_uart_driver_ops *ops, void *driver_data,
+ struct ucg_cirbuf *rx_cbuf, char *rx_buf, unsigned rx_bufsize,
+ struct ucg_cirbuf *tx_cbuf, char *tx_buf, unsigned tx_bufsize)
+{
+ int ret;
+
+ const struct ucg_uart_config def_conf = {
+ .enable = 1,
+ .parity = 0,
+ .stop_bits = 0,
+ .reserved = 0,
+ .nbits = 8,
+ .baudrate = 9600,
+ };
+
+ memset(uart, 0, sizeof(*uart));
+ ucg_cirbuf_init(rx_cbuf, rx_buf, 0, rx_bufsize);
+ ucg_cirbuf_init(tx_cbuf, tx_buf, 0, tx_bufsize);
+ uart->rx_fifo = rx_cbuf;
+ uart->tx_fifo = tx_cbuf;
+ uart->ops = ops;
+ uart->driver_data = driver_data;
+ ret = ucg_uart_setconf(uart, &def_conf);
+
+ return ret;
+}
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# dump some infos if debug is enabled
+ifeq ($(D),1)
+$(call disp_list,------ all-ar,$(all-ar))
+$(foreach ar,$(all-ar),\
+ $(info,out-$(ar): $(out-$(ar))) \
+ $(call disp_list,pre-$(ar),$(pre-$(ar))) \
+)
+endif
+
+# include dependencies and commands files if they exist
+$(foreach ar,$(all-ar),\
+ $(eval -include $(call depfile,$(ar))) \
+ $(eval -include $(call cmdfile,$(ar))) \
+)
+
+# remove duplicates
+filtered-all-ar := $(sort $(all-ar))
+
+# link several objects files into one shared object
+$(filtered-all-ar): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call ar_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call ar_cmd,$(pre-$(@)),$@),$?),\
+ $(call ar_print_cmd,$(pre-$(@)),$@) && \
+ $(call ar_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call ar_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# ar-y-$(ar) is provided by the user
+# $(ar) is the path of the static library, and the variable contains
+# the list of sources. Several ar-y-$(ar) can be present.
+
+# list all ar builds requested by user
+all-ar := $(patsubst ar-y-%,%,$(filter ar-y-%,$(.VARIABLES)))
+
+# add them to the list of targets
+all-targets += $(all-ar)
+
+# for each ar, create the following variables:
+# out-$(ar) = output path of the arcutable
+# pre-$(ar) = list of prerequisites for this arcutable
+# Some source files need intermediate objects, we define these variables
+# for them too, and add them in a list: $(all-iobj).
+# Last, we add the generated files in $(all-clean-file).
+$(foreach ar,$(all-ar),\
+ $(eval out-$(ar) := $(dir $(ar))) \
+ $(eval pre-$(ar) := ) \
+ $(foreach src,$(ar-y-$(ar)), \
+ $(if $(call is_cc_source,$(src)), \
+ $(eval iobj := $(call src2iobj,$(src),$(out-$(ar)))) \
+ $(eval pre-$(iobj) := $(src)) \
+ $(eval all-iobj += $(iobj)) \
+ $(eval all-clean-file += $(iobj)) \
+ $(eval pre-$(ar) += $(iobj)) \
+ , \
+ $(if $(call is_obj_source,$(src)),\
+ $(eval pre-$(ar) += $(src)) \
+ , \
+ $(error "unsupported source format: $(src)"))) \
+ )\
+ $(eval all-clean-file += $(ar)) \
+)
+
+# link several *.o files into a static libary
+# $1: sources (*.o)
+# $2: dst (xyz.a)
+ar_cmd = ar crsD $(2) $(1)
+
+# print line used to ar object files
+ifeq ($(V),1)
+ar_print_cmd = echo $(call protect_quote,$(call ar_cmd,$1,$2))
+else
+ar_print_cmd = echo " AR $(2)"
+endif
+
+all-clean-file += $(all-ar)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+.PHONY: _ucgine_clean
+_ucgine_clean: $(all-clean-target) FORCE
+ @$(call clean_print_cmd,$(all-clean-file) $(call depfile,$(all-clean-file)) \
+ $(call cmdfile,$(all-clean-file))) && \
+ $(call clean_cmd,$(all-clean-file) $(call depfile,$(all-clean-file)) \
+ $(call cmdfile,$(all-clean-file)))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# remove files
+# $1: files
+clean_cmd = rm -rf $(1)
+
+# print line used to clean files
+ifeq ($(V),1)
+clean_print_cmd = echo $(call protect_quote,$(call clean_cmd,$1))
+else
+clean_print_cmd = echo " CLEAN $(CURDIR)"
+endif
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# dump some infos if debug is enabled
+ifeq ($(D),1)
+$(call disp_list,------ all-copy,$(all-copy))
+$(foreach copy,$(all-copy),\
+ $(info,out-$(copy): $(out-$(copy))) \
+ $(call disp_list,pre-$(copy),$(pre-$(copy))) \
+)
+endif
+
+# include dependencies and commands files if they exist
+$(foreach copy,$(all-copy),\
+ $(eval -include $(call depfile,$(copy))) \
+ $(eval -include $(call cmdfile,$(copy))) \
+)
+
+# remove duplicates
+filtered-all-copy := $(sort $(all-copy))
+
+# convert format of executable
+$(filtered-all-copy): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call copy_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call copy_cmd,$(pre-$(@)),$@),$?),\
+ $(call copy_print_cmd,$(pre-$(@)),$@) && \
+ $(call copy_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call copy_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# copy a file
+# copy-y-$(copy) is provided by the user
+# $(copy) is the path of the directory containing the destination
+# files, and the variable contains the path of the files to copy. Several
+# copy-y-$(copy) can be present.
+
+# list all path requested by user
+_all-copy := $(patsubst copy-y-%,%,$(filter copy-y-%,$(.VARIABLES)))
+all-copy :=
+
+# for each copy, create the following variables:
+# out-$(copy) = output path of the executable
+# pre-$(copy) = list of prerequisites for this executable
+# We also add the files in $(all-copy).
+$(foreach copy,$(_all-copy),\
+ $(if $(notdir $(copy)), \
+ $(if $(call compare,$(words $(copy-y-$(copy))),1), \
+ $(error "only one source file is allowed in copy-y-$(copy)")) \
+ $(eval dst := $(dir $(copy))$(notdir $(copy-y-$(copy)))) \
+ $(eval out-$(copy) := $(dir $(copy))) \
+ $(eval pre-$(copy) := $(copy-y-$(copy))) \
+ $(eval all-copy += $(dst)) \
+ , \
+ $(foreach src,$(copy-y-$(copy)),\
+ $(eval dst := $(copy)$(notdir $(src))) \
+ $(eval out-$(copy) := $(copy)) \
+ $(eval pre-$(dst) := $(src)) \
+ $(eval all-copy += $(dst)) \
+ ) \
+ ) \
+)
+
+# add them to the list of targets and clean
+all-targets += $(all-copy)
+all-clean-file += $(all-copy)
+
+# convert format of executable from elf to ihex
+# $1: source executable (elf)
+# $2: destination file
+copy_cmd = $(CP) $(1) $(2)
+
+# print line used to convert executable format
+ifeq ($(V),1)
+copy_print_cmd = echo $(call protect_quote,$(call copy_cmd,$1,$2))
+else
+copy_print_cmd = echo " COPY $(2)"
+endif
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# dump some infos if debug is enabled
+ifeq ($(D),1)
+$(call disp_list,------ all-exe,$(all-exe))
+$(foreach exe,$(all-exe),\
+ $(info,out-$(exe): $(out-$(exe))) \
+ $(call disp_list,pre-$(exe),$(pre-$(exe))) \
+)
+endif
+
+# include dependencies and commands files if they exist
+$(foreach exe,$(all-exe),\
+ $(eval -include $(call depfile,$(exe))) \
+ $(eval -include $(call cmdfile,$(exe))) \
+)
+
+# remove duplicates
+filtered-all-exe := $(sort $(all-exe))
+
+# link several objects files into one executable
+$(filtered-all-exe): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call link_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call link_cmd,$(pre-$(@)),$@),$?),\
+ $(call link_print_cmd,$(pre-$(@)),$@) && \
+ $(call link_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call link_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# exe-y-$(exe) is provided by the user
+# $(exe) is the path of the binary, and the variable contains
+# the list of sources. Several exe-y-$(exe) can be present.
+
+# list all exe builds requested by user
+all-exe := $(patsubst exe-y-%,%,$(filter exe-y-%,$(.VARIABLES)))
+
+# add them to the list of targets
+all-targets += $(all-exe)
+
+# for each exe, create the following variables:
+# out-$(exe) = output path of the executable
+# pre-$(exe) = list of prerequisites for this executable
+# Some source files need intermediate objects, we define these variables
+# for them too, and add them in a list: $(all-iobj).
+# Last, we add the generated files in $(all-clean-file).
+$(foreach exe,$(all-exe),\
+ $(eval out-$(exe) := $(dir $(exe))) \
+ $(eval pre-$(exe) := ) \
+ $(foreach src,$(exe-y-$(exe)), \
+ $(if $(call is_cc_source,$(src)), \
+ $(eval iobj := $(call src2iobj,$(src),$(out-$(exe)))) \
+ $(eval pre-$(iobj) := $(src)) \
+ $(eval all-iobj += $(iobj)) \
+ $(eval all-clean-file += $(iobj)) \
+ $(eval pre-$(exe) += $(iobj)) \
+ , \
+ $(if $(call is_obj_source,$(src)),\
+ $(eval pre-$(exe) += $(src)) \
+ , \
+ $(if $(call is_alib_source,$(src)),\
+ $(eval pre-$(exe) += $(src)) \
+ , \
+ $(error "unsupported source format: $(src)")))) \
+ )\
+ $(eval all-clean-file += $(exe)) \
+)
+
+# link several *.o files into a exeary
+# $1: sources (*.o) (*.a)
+# $2: dst (xyz.o too)
+link_cmd = $(CC) $(LDFLAGS) $(ldflags-$(2)) -o $(2) $(filter %.o,$(1)) \
+ $(filter %.a,$(1)) $(LDLIBS) $(ldlibs-$(2))
+
+# print line used to link object files
+ifeq ($(V),1)
+link_print_cmd = echo $(call protect_quote,$(call link_cmd,$1,$2))
+else
+link_print_cmd = echo " EXE $(2)"
+endif
+
+all-clean-file += $(all-exe)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# dump some infos if debug is enabled
+ifeq ($(D),1)
+$(call disp_list,------ all-obj,$(all-obj))
+$(foreach obj,$(all-obj),\
+ $(info,out-$(obj): $(out-$(obj))) \
+ $(call disp_list,pre-$(obj),$(pre-$(obj))) \
+)
+$(call disp_list,------ all-iobj,$(all-iobj))
+$(foreach iobj,$(all-iobj),\
+ $(call disp_list,pre-$(iobj),$(pre-$(iobj))) \
+)
+endif
+
+# if a generated file has the same name than a user target,
+# generate an error
+conflicts := $(filter $(all-iobj),$(all-targets))
+$(if $(conflicts), \
+ $(error Intermediate file has the same names than user targets:\
+ $(conflicts)))
+
+# include dependencies and commands files if they exist
+$(foreach obj,$(all-obj),\
+ $(eval -include $(call depfile,$(obj))) \
+ $(eval -include $(call cmdfile,$(obj))) \
+)
+$(foreach iobj,$(all-iobj),\
+ $(eval -include $(call depfile,$(iobj))) \
+ $(eval -include $(call cmdfile,$(iobj))) \
+)
+
+# remove duplicates
+filtered-all-iobj := $(sort $(all-iobj))
+
+# convert source files to intermediate object file
+$(filtered-all-iobj): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,$(call compile_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call compile_cmd,$(pre-$(@)),$@),$?),\
+ $(call compile_print_cmd,$(pre-$(@)),$@) && \
+ $(call compile_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call compile_cmd,$(pre-$(@)),$@),$@) && \
+ $(call obj-fixdep,$@))
+
+# remove duplicates
+filtered-all-obj := $(sort $(all-obj))
+
+# combine several objects files to one
+$(filtered-all-obj): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call combine_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call combine_cmd,$(pre-$(@)),$@),$?),\
+ $(call combine_print_cmd,$(pre-$(@)),$@) && \
+ $(call combine_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call combine_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# obj-y-$(obj) is provided by the user
+# $(obj) is the path of the object, and the variable contains
+# the list of sources. Several obj-y-$(obj) can be present.
+
+# list all object builds requested by user
+all-obj := $(patsubst obj-y-%,%,$(filter obj-y-%,$(.VARIABLES)))
+
+# add them to the list of targets
+all-targets += $(all-obj)
+
+# convert source path to intermediate object path, and filter
+# objects from sources
+# $1: list of source paths
+# $2: output directory (including trailing slash)
+# return: list of intermediate object paths
+src2iobj = $(addprefix $(filter-out ./,$(2)),$(notdir $(strip \
+ $(patsubst %.c,%.o,\
+ $(patsubst %.s,%.o,\
+ $(filter-out %.o,$(1)))))))
+
+# return the file if it matches a extension that is built with cc
+# $1: source file
+is_cc_source = $(filter %.c %.s %S,$(1))
+
+# return the file if it's already an object file: in this case no
+# intermediate object is needed
+# $1: source file
+is_obj_source = $(filter %.o,$(1))
+
+# return the file if it's a static library
+# $1: source file
+is_alib_source = $(filter %.a,$(1))
+
+# for each obj, create the following variables:
+# out-$(obj) = output path of the object
+# pre-$(obj) = list of prerequisites for this object
+# Some source files need intermediate objects, we define these variables
+# for them too, and add them in a list: $(all-iobj).
+# Last, we add the generated files in $(all-clean-file).
+$(foreach obj,$(all-obj),\
+ $(eval out-$(obj) := $(dir $(obj))) \
+ $(eval pre-$(obj) := ) \
+ $(foreach src,$(obj-y-$(obj)), \
+ $(if $(call is_cc_source,$(src)), \
+ $(eval iobj := $(call src2iobj,$(src),$(out-$(obj)))) \
+ $(eval pre-$(iobj) := $(src)) \
+ $(eval all-iobj += $(iobj)) \
+ $(eval all-clean-file += $(iobj)) \
+ $(eval pre-$(obj) += $(iobj)) \
+ , \
+ $(if $(call is_obj_source,$(src)),\
+ $(eval pre-$(obj) += $(src)) \
+ , \
+ $(error "unsupported source format: $(src)"))) \
+ )\
+ $(eval all-clean-file += $(obj)) \
+)
+
+# fix the format of .o.d.tmp (generated by gcc) to a .o.d that defines
+# dependencies as makefile variables
+# $1: object file (.o)
+obj-fixdep = if [ -f $(call file2tmpdep,$(1)) ]; then\
+ echo -n "dep-$(1) = " > $(call depfile,$(1)) && \
+ sed 's,^[^ ][^:]*: ,,' $(call file2tmpdep,$(1)) >> $(call depfile,$(1)) && \
+ rm -f $(call file2tmpdep,$(1)); \
+ else \
+ $(call create_empty_depfile,$(1)); \
+ fi
+
+# compile a file
+# $1: sources
+# $2: dst
+compile_cmd = $(CC) -Wp,-MD,$(call file2tmpdep,$(2)) \
+ $(CPPFLAGS) $(cppflags-$(2)) \
+ $(CFLAGS) $(cflags-$(2)) \
+ -c -o $2 $1
+
+# print line used to compile a file
+ifeq ($(V),1)
+compile_print_cmd = echo $(call protect_quote,$(call compile_cmd,$1,$2))
+else
+compile_print_cmd = echo " CC $(2)"
+endif
+
+# combine several *.o files into one
+# $1: sources (*.o)
+# $2: dst (xyz.o too)
+combine_cmd = $(LD) -r $(1) -o $(2)
+
+# print line used to combine object files
+ifeq ($(V),1)
+combine_print_cmd = echo $(call protect_quote,$(call combine_cmd,$1,$2))
+else
+combine_print_cmd = echo " LD $(2)"
+endif
+
+all-clean-file += $(all-obj)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# dump some infos if debug is enabled
+ifeq ($(D),1)
+$(call disp_list,------ all-objcopy-hex,$(all-objcopy-hex))
+$(foreach objcopy,$(all-objcopy-hex),\
+ $(info,out-$(objcopy): $(out-$(objcopy))) \
+ $(call disp_list,pre-$(objcopy),$(pre-$(objcopy))) \
+)
+$(call disp_list,------ all-objcopy-bin,$(all-objcopy-bin))
+$(foreach objcopy,$(all-objcopy-bin),\
+ $(info,out-$(objcopy): $(out-$(objcopy))) \
+ $(call disp_list,pre-$(objcopy),$(pre-$(objcopy))) \
+)
+endif
+
+# include dependencies and commands files if they exist
+$(foreach objcopy,$(all-objcopy-hex) $(all-objcopy-bin),\
+ $(eval -include $(call depfile,$(objcopy))) \
+ $(eval -include $(call cmdfile,$(objcopy))) \
+)
+
+# remove duplicates
+filtered-all-objcopy-hex := $(sort $(all-objcopy-hex))
+
+# convert format of executable
+$(filtered-all-objcopy-hex): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call objcopy_hex_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call objcopy_hex_cmd,$(pre-$(@)),$@),$?),\
+ $(call objcopy_print_cmd,$(pre-$(@)),$@) && \
+ $(call objcopy_hex_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call objcopy_hex_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
+
+# remove duplicates
+filtered-all-objcopy-bin := $(sort $(all-objcopy-bin))
+
+# convert format of executable
+$(filtered-all-objcopy-bin): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call objcopy_bin_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call objcopy_bin_cmd,$(pre-$(@)),$@),$?),\
+ $(call objcopy_print_cmd,$(pre-$(@)),$@) && \
+ $(call objcopy_bin_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call objcopy_bin_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# objcopy changes the format of a binary
+# objcopy-hex-y-$(objcopy), objcopy-bin-y-$(objcopy) are provided by the user
+# $(objcopy) is the path of the binary, and the variable contains
+# the path to the elf. Several objcopy-y-$(objcopy) can be present.
+
+# list all executable builds requested by user
+all-objcopy-hex := $(patsubst objcopy-hex-y-%,%,$(filter objcopy-hex-y-%,$(.VARIABLES)))
+all-objcopy-bin := $(patsubst objcopy-bin-y-%,%,$(filter objcopy-bin-y-%,$(.VARIABLES)))
+
+# add them to the list of targets
+all-targets += $(all-objcopy-hex) $(all-objcopy-bin)
+
+# for each objcopy, create the following variables:
+# out-$(objcopy) = output path of the executable
+# pre-$(objcopy) = list of prerequisites for this executable
+# We also add the generated files in $(all-clean-file).
+$(foreach objcopy,$(all-objcopy-hex),\
+ $(if $(call compare,$(words $(objcopy-hex-y-$(objcopy))),1),\
+ $(error "only one source file is allowed in objcopy-hex-y-$(objcopy)")) \
+ $(eval out-$(objcopy) := $(dir $(objcopy))) \
+ $(eval pre-$(objcopy) := $(objcopy-hex-y-$(objcopy))) \
+ $(eval all-clean-file += $(objcopy)) \
+)
+
+# for each objcopy, create the following variables:
+# out-$(objcopy) = output path of the executable
+# pre-$(objcopy) = list of prerequisites for this executable
+# We also add the generated files in $(all-clean-file).
+$(foreach objcopy,$(all-objcopy-bin),\
+ $(if $(call compare,$(words $(objcopy-bin-y-$(objcopy))),1),\
+ $(error "only one source file is allowed in objcopy-bin-y-$(objcopy)")) \
+ $(eval out-$(objcopy) := $(dir $(objcopy))) \
+ $(eval pre-$(objcopy) := $(objcopy-bin-y-$(objcopy))) \
+ $(eval all-clean-file += $(objcopy)) \
+)
+
+# convert format of executable from elf to ihex
+# $1: source executable (elf)
+# $2: destination file
+objcopy_hex_cmd = $(OBJCOPY) -O ihex $(1) $(2)
+
+# print line used to convert executable format
+ifeq ($(V),1)
+objcopy_print_cmd = echo $(call protect_quote,$(call objcopy_hex_cmd,$1,$2))
+else
+objcopy_print_cmd = echo " OBJCOPY $(2)"
+endif
+
+# convert format of executable from elf to binary
+# $1: source executable (elf)
+# $2: destination file
+objcopy_bin_cmd = $(OBJCOPY) -O binary $(1) $(2)
+
+# print line used to convert executable format
+ifeq ($(V),1)
+objcopy_print_cmd = echo $(call protect_quote,$(call objcopy_bin_cmd,$1,$2))
+else
+objcopy_print_cmd = echo " OBJCOPY $(2)"
+endif
+
+# XXX dup ?
+all-clean-file += $(all-objcopy-hex) $(all-objcopy-bin)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# ---- variables that must be defined:
+#
+# UCGINE: path to ucgine root
+#
+# ---- variable that can be defined anywhere
+#
+# CROSS: prefix of the toolchain
+# CP, LN, GAWK, GREP: coreutils tools
+# CC, CPP, AR, LD, OBJCOPY, OBJDUMP, STRIP: compilers/binutils
+#
+# ---- variable that can be defined by Makefile:
+#
+# obj-y-$(path)
+# exe-y-$(path)
+# ar-y-$(path)
+# shlib-y-$(path)
+# copy-y-$(path)
+# slink-y-$(path)
+# objcopy-y-$(path)
+# subdir-y
+#
+# CPPFLAGS, CFLAGS, LDFLAGS, LDLIBS: global flags
+# cflags-$(path), cppflags-$(path), ldflags-$(path), ldlibs-$(path): per
+# file flags
+# mkflags-$(path): flags for subdirectories
+#
+# ---- variables that can be defined on the command line:
+#
+# EXTRA_CPPFLAGS, EXTRA_CFLAGS, EXTRA_LDFLAGS, EXTRA_LDLIBS: global
+# extra flags
+# extra-cflags-$(path), extra-cppflags-$(path): per object extra flags
+
+ifeq ($(UCGINE),)
+$(error UCGINE environment variable is not defined)
+endif
+
+# list of targets asked by user
+all-targets :=
+# list of files generated
+all-clean-file :=
+
+# usual internal variables:
+# out-$(file) = output path of a generated file
+# pre-$(file) = list of files needed to generate $(file)
+# all-type = list of targets for this type
+
+include $(UCGINE)/mk/ucgine-obj-vars.mk
+include $(UCGINE)/mk/ucgine-exe-vars.mk
+include $(UCGINE)/mk/ucgine-ar-vars.mk
+include $(UCGINE)/mk/ucgine-shlib-vars.mk
+include $(UCGINE)/mk/ucgine-copy-vars.mk
+include $(UCGINE)/mk/ucgine-slink-vars.mk
+include $(UCGINE)/mk/ucgine-objcopy-vars.mk
+include $(UCGINE)/mk/ucgine-subdir-vars.mk
+# must stay at the end
+include $(UCGINE)/mk/ucgine-clean-vars.mk
+
+# dump the list of targets
+ifeq ($(D),1)
+$(call disp_list,------ all-targets,$(all-targets))
+endif
+
+# first rule (default)
+.PHONY: _ucgine_all
+_ucgine_all: $(all-targets)
+
+# the includes below require second expansion
+.SECONDEXPANSION:
+
+include $(UCGINE)/mk/ucgine-obj-rules.mk
+include $(UCGINE)/mk/ucgine-exe-rules.mk
+include $(UCGINE)/mk/ucgine-ar-rules.mk
+include $(UCGINE)/mk/ucgine-shlib-rules.mk
+include $(UCGINE)/mk/ucgine-copy-rules.mk
+include $(UCGINE)/mk/ucgine-slink-rules.mk
+include $(UCGINE)/mk/ucgine-objcopy-rules.mk
+include $(UCGINE)/mk/ucgine-subdir-rules.mk
+include $(UCGINE)/mk/ucgine-clean-rules.mk
+
+.PHONY: FORCE
+FORCE:
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# ---- variables that must be defined:
+#
+# UCGINE: path to ucgine root
+# UCGINE_ARCH: architecture (ex: avr, stm32, ...)
+#
+
+ifeq ($(UCGINE),)
+$(error UCGINE environment variable is not defined)
+endif
+
+ifeq ($(UCGINE_ARCH),)
+$(error UCGINE_ARCH environment variable is not defined)
+endif
+
+MAKEFLAGS += --no-print-directory
+
+include $(UCGINE)/mk/ucgine-tools.mk
+
+include $(UCGINE)/arch/$(UCGINE_ARCH)/mk/ucgine-arch.mk
+
+include $(UCGINE)/mk/ucgine-vars.mk
+
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# dump some infos if debug is enabled
+ifeq ($(D),1)
+$(call disp_list,------ all-shlib,$(all-shlib))
+$(foreach shlib,$(all-shlib),\
+ $(info,out-$(shlib): $(out-$(shlib))) \
+ $(call disp_list,pre-$(shlib),$(pre-$(shlib))) \
+)
+endif
+
+# include dependencies and commands files if they exist
+$(foreach shlib,$(all-shlib),\
+ $(eval -include $(call depfile,$(shlib))) \
+ $(eval -include $(call cmdfile,$(shlib))) \
+)
+
+# remove duplicates
+filtered-all-shlib := $(sort $(all-shlib))
+
+# link several objects files into one shared object
+$(filtered-all-shlib): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call shlib_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call shlib_cmd,$(pre-$(@)),$@),$?),\
+ $(call shlib_print_cmd,$(pre-$(@)),$@) && \
+ $(call shlib_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call shlib_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# shlib-y-$(shlib) is provided by the user
+# $(shlib) is the path of the shared library, and the variable
+# contains the list of sources. Several shlib-y-$(shlib) can be
+# present.
+
+# list all shlib builds requested by user
+all-shlib := $(patsubst shlib-y-%,%,$(filter shlib-y-%,$(.VARIABLES)))
+
+# add them to the list of targets
+all-targets += $(all-shlib)
+
+# for each shlib, create the following variables:
+# out-$(shlib) = output path of the shlibcutable
+# pre-$(shlib) = list of prerequisites for this shlibcutable
+# Some source files need intermediate objects, we define these variables
+# for them too, and add them in a list: $(all-iobj).
+# Last, we add the generated files in $(all-clean-file).
+$(foreach shlib,$(all-shlib),\
+ $(eval out-$(shlib) := $(dir $(shlib))) \
+ $(eval pre-$(shlib) := ) \
+ $(foreach src,$(shlib-y-$(shlib)), \
+ $(if $(call is_cc_source,$(src)), \
+ $(eval iobj := $(call src2iobj,$(src),$(out-$(shlib)))) \
+ $(eval pre-$(iobj) := $(src)) \
+ $(eval all-iobj += $(iobj)) \
+ $(eval all-clean-file += $(iobj)) \
+ $(eval pre-$(shlib) += $(iobj)) \
+ , \
+ $(if $(call is_obj_source,$(src)),\
+ $(eval pre-$(shlib) += $(src)) \
+ , \
+ $(error "unsupported source format: $(src)"))) \
+ )\
+ $(eval all-clean-file += $(shlib)) \
+)
+
+# link several *.o files into a shared libary
+# $1: sources (*.o)
+# $2: dst (xyz.so)
+shlib_cmd = $(CC) $(LDFLAGS) $(ldflags-$(2)) -shared -o $(2) $(1)
+
+# print line used to shlib object files
+ifeq ($(V),1)
+shlib_print_cmd = echo $(call protect_quote,$(call shlib_cmd,$1,$2))
+else
+shlib_print_cmd = echo " SHLIB $(2)"
+endif
+
+all-clean-file += $(all-shlib)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# dump some infos if debug is enabled
+ifeq ($(D),1)
+$(call disp_list,------ all-slink,$(all-slink))
+$(foreach slink,$(all-slink),\
+ $(info,out-$(slink): $(out-$(slink))) \
+ $(call disp_list,pre-$(slink),$(pre-$(slink))) \
+)
+endif
+
+# include dependencies and commands files if they exist
+$(foreach slink,$(all-slink),\
+ $(eval -include $(call depfile,$(slink))) \
+ $(eval -include $(call cmdfile,$(slink))) \
+)
+
+# remove duplicates
+filtered-all-slink := $(sort $(all-slink))
+
+# convert format of executable
+$(filtered-all-slink): $$(pre-$$@) $$(wildcard $$(dep-$$@)) FORCE
+ @[ -d $(dir $@) ] || mkdir -p $(dir $@)
+ @$(call display_deps,$(pre-$(@)),$@,\
+ $(call slink_cmd,$(pre-$(@)),$@),$?)
+ @$(if $(call check_deps,$@,$(call slink_cmd,$(pre-$(@)),$@),$?),\
+ $(call slink_print_cmd,$(pre-$(@)),$@) && \
+ $(call slink_cmd,$(pre-$(@)),$@) && \
+ $(call save_cmd,$(call slink_cmd,$(pre-$(@)),$@),$@) && \
+ $(call create_empty_depfile,$@))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# create a symbolic link of a file
+# slink-y-$(slink) is provided by the user
+# $(slink) is the path of the directory containing the destination
+# files, and the variable contains the path of the files to linked. Several
+# slink-y-$(slink) can be present.
+
+# list all path requested by user
+_all-slink := $(patsubst slink-y-%,%,$(filter slink-y-%,$(.VARIABLES)))
+all-slink :=
+
+# for each slink, create the following variables:
+# out-$(slink) = output path of the executable
+# pre-$(slink) = list of prerequisites for this executable
+# We also add the files in $(all-slink).
+$(foreach slink,$(_all-slink),\
+ $(if $(notdir $(slink)), \
+ $(if $(call compare,$(words $(slink-y-$(slink))),1), \
+ $(error "only one source file is allowed in slink-y-$(slink)")) \
+ $(eval dst := $(dir $(slink))$(notdir $(slink-y-$(slink)))) \
+ $(eval out-$(slink) := $(dir $(slink))) \
+ $(eval pre-$(slink) := $(slink-y-$(slink))) \
+ $(eval all-slink += $(dst)) \
+ , \
+ $(foreach src,$(slink-y-$(slink)),\
+ $(eval dst := $(slink)$(notdir $(src))) \
+ $(eval out-$(slink) := $(slink)) \
+ $(eval pre-$(dst) := $(src)) \
+ $(eval all-slink += $(dst)) \
+ ) \
+ ) \
+)
+
+# add them to the list of targets and clean
+all-targets += $(all-slink)
+all-clean-file += $(all-slink)
+
+# convert format of executable from elf to ihex
+# $1: source executable (elf)
+# $2: destination file
+slink_cmd = $(LN) -nsf $(abspath $(1)) $(2)
+
+# print line used to convert executable format
+ifeq ($(V),1)
+slink_print_cmd = echo $(call protect_quote,$(call slink_cmd,$1,$2))
+else
+slink_print_cmd = echo " SLINK $(2)"
+endif
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+.PHONY: $(subdir-y)
+$(subdir-y): FORCE
+ $(Q)$(MAKE) -C $(@) $(mkflags-$(@)) $(MAKECMDGOALS)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# subdir-y is provided by the user
+# it contains the list of directory to build
+
+# add them to the list of targets
+all-targets += $(subdir-y)
+all-clean-target += $(subdir-y)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+empty:=
+space:= $(empty) $(empty)
+indent:= $(space)$(space)
+
+# define a newline char, useful for debugging with $(info)
+define newline
+
+
+endef
+
+# $(prefix shell commands with $(Q) to silent them, except if V=1
+Q=@
+ifeq ("$(V)-$(origin V)", "1-command line")
+Q=
+endif
+
+# set variable $1 to $2 if the variable has an implicit value or
+# is not defined
+# $1 variable name
+# $2 new variable content
+set_default = $(if \
+ $(call not,$(or \
+ $(compare $(origin $(1)),default), \
+ $(compare $(origin $(1)),undefined) \
+ )),\
+ $(eval $(1) = $(2)) \
+)
+
+# display a list
+# $1 title
+# $2 list
+disp_list = $(info $(1)$(newline)\
+ $(addsuffix $(newline),$(addprefix $(space),$(2))))
+
+# add a dot in front of the file name
+# $1 list of paths
+# return: full paths with files prefixed by a dot
+dotfile = $(strip $(foreach f,$(1),\
+ $(join $(dir $f),.$(notdir $f))))
+
+# convert source/obj files into dot-dep filename
+# $1 list of paths
+# return: full paths with files prefixed by a dot and suffixed with .d
+depfile = $(strip $(call dotfile,$(addsuffix .d,$(1))))
+
+# convert source/obj files into dot-dep filename
+# $1 list of paths
+# return: full paths with files prefixed by a dot and suffixed with .d.tmp
+file2tmpdep = $(strip $(call dotfile,$(addsuffix .d.tmp,$(1))))
+
+# convert source/obj files into dot-cmd filename
+# $1 list of paths
+# return: full paths with files prefixed by a dot and suffixed with .cmd
+cmdfile = $(strip $(call dotfile,$(addsuffix .cmd,$(1))))
+
+# add a \ before each quote
+protect_quote = $(subst ','\'',$(1))
+#'# editor syntax highlight fix
+
+# return an non-empty string if $1 is empty, and vice versa
+# $1 a string
+not = $(if $1,,true)
+
+# return 1 if parameter is a non-empty string, else 0
+boolean = $(if $1,1,0)
+
+# return an empty string if string are equal
+compare = $(strip $(subst $(1),,$(2)) $(subst $(2),,$(1)))
+
+# return a non-empty string if a file does not exist
+# $1: file
+file_missing = $(call compare,$(wildcard $1),$1)
+
+# return a non-empty string if cmdline changed
+# $1: file to be built
+# $2: the command to build it
+cmdline_changed = $(call compare,$(strip $(cmd-$(1))),$(strip $(2)))
+
+# return an non-empty string if the .d file does not exist
+# $1: the dep file (.d)
+depfile_missing = $(call compare,$(wildcard $(1)),$(1))
+
+# return a non-empty string if, according to dep-xyz variable, a file
+# needed to build $1 does not exist. In this case we need to rebuild
+# the file and the .d file.
+# $1: file to be built
+dep-missing = $(call compare,$(wildcard $(dep-$(1))),$(dep-$(1)))
+
+# return an empty string if no prereq is newer than target
+# $1: list of prerequisites newer than target ($?)
+dep-newer = $(strip $(filter-out FORCE,$(1)))
+
+# display why a file should be re-built
+# $1: source files
+# $2: dst file
+# $3: build command
+# $4: all prerequisites newer than target ($?)
+ifeq ($(D),1)
+display_deps = \
+ echo -n "$1 -> $2 " ; \
+ echo -n "file_missing=$(call boolean,$(call file_missing,$(2))) " ; \
+ echo -n "cmdline_changed=$(call boolean,$(call cmdline_changed,$(2),$(3))) " ; \
+ echo -n "depfile_missing=$(call boolean,$(call depfile_missing,$(call depfile,$(2)))) " ; \
+ echo -n "dep-missing=$(call boolean,$(call dep-missing,$(2))) " ; \
+ echo "dep-newer=$(call boolean,$(call dep-newer,$(4)))"
+else
+display_deps=
+endif
+
+# return an empty string if a file should be rebuilt
+# $1: dst file
+# $2: build command
+# $3: all prerequisites newer than target ($?)
+check_deps = \
+ $(or $(call file_missing,$(1)),\
+ $(call cmdline_changed,$(1),$(2)),\
+ $(call depfile_missing,$(call depfile,$(1))),\
+ $(call dep-missing,$(1)),\
+ $(call dep-newer,$(3)))
+
+# create a depfile (.d) with no additional deps
+# $1: object file (.o)
+create_empty_depfile = echo "dep-$(1) =" > $(call depfile,$(1))
+
+# save a command in a file
+# $1: command to build the file
+# $2: name of the file
+save_cmd = echo "cmd-$(2) = $(call protect_quote,$(1))" > $(call cmdfile,$(2))
+
+# remove the FORCE target from the list of all prerequisites $+
+# no arguments, use $+
+prereq = $(filter-out FORCE,$(+))
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+CROSS ?= $(ARCH_CROSS)
+
+# core tools
+CP ?= cp
+LN ?= ln
+GAWK ?= gawk
+GREP ?= grep
+# compiler and binutils, set_default overrides mk implicit value
+# but not command line or standard variables
+$(call set_default,CC,$(CROSS)gcc)
+$(call set_default,CPP,$(CROSS)cpp)
+$(call set_default,AR,$(CROSS)ar)
+$(call set_default,LD,$(CROSS)ld)
+$(call set_default,OBJCOPY,$(CROSS)objcopy)
+$(call set_default,OBJDUMP,$(CROSS)objdump)
+$(call set_default,STRIP,$(CROSS)strip)
+HOSTCC ?= cc
+
+CFLAGS += $(EXTRA_CFLAGS)
+CPPFLAGS += $(EXTRA_CPPFLAGS)
+LDFLAGS += $(EXTRA_LDFLAGS)
+LDLIBS += $(EXTRA_LDLIBS)
--- /dev/null
+#
+# Copyright 2015, Olivier MATZ <zer0@droids-corp.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UCGINE ?= $(abspath ../..)
+
+# XXX we should not need UCGINE_ARCH
+UCGINE_ARCH = posix
+include $(UCGINE)/mk/ucgine-pre.mk
+
+O ?= $(CURDIR)/build
+
+CFLAGS = -g -O2 -Wall
+CFLAGS += -Ilibconfizery
+
+src := libconfizery/cfzy_expr.c
+src += libconfizery/cfzy_list.c
+src += libconfizery/cfzy_htable.c
+src += libconfizery/cfzy_string.c
+src += libconfizery/cfzy_log.c
+src += libconfizery/cfzy_confnode.c
+src += libconfizery/cfzy_conftree.c
+src += libconfizery/cfzy_dotconfig.c
+src += libconfizery/cfzy_c_hdr.c
+src += libconfizery/cfzy_file.c
+src += libconfizery/cfzy_conftree_parser.c
+src += libconfizery/cfzy_confnode_choice.c
+src += libconfizery/cfzy_confnode_choiceconfig.c
+src += libconfizery/cfzy_confnode_comment.c
+src += libconfizery/cfzy_confnode_config.c
+src += libconfizery/cfzy_confnode_if.c
+src += libconfizery/cfzy_confnode_intconfig.c
+src += libconfizery/cfzy_confnode_menu.c
+src += libconfizery/cfzy_confnode_menuconfig.c
+src += libconfizery/cfzy_confnode_root.c
+src += libconfizery/cfzy_confnode_strconfig.c
+ar-y-$(O)/libconfizery/libconfizery.a := $(src)
+
+src := cfzy-basic/main.c
+src += $(O)/libconfizery/libconfizery.a
+exe-y-$(O)/cfzy-basic/cfzy-basic := $(src)
+
+include $(UCGINE)/mk/ucgine-post.mk
+
+.PHONY: all
+all: $(all-targets)
+
+.PHONY: clean
+clean: _ucgine_clean
--- /dev/null
+include $(TOPDIR)/confizery.vars.mk
+
+PROG = cfzy-basic
+
+CFLAGS += -I$(SRCDIR)/libconfizery
+
+LDLIBS = $(BUILDDIR)/libconfizery/libconfizery.a
+
+SRCS = main.c
+
+include $(TOPDIR)/confizery.prog.mk
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <cfzy_log.h>
+#include <cfzy_list.h>
+#include <cfzy_conftree.h>
+#include <cfzy_dotconfig.h>
+#include <cfzy_c_hdr.h>
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("cfzy-basic", level, fmt, ##args)
+
+/* Parsed arguments */
+struct cfzy_arguments {
+ char *input_conftree;
+ char *input_dotconfig;
+ char *output_dotconfig;
+ char *output_c_hdr;
+ char *output_multi_c_hdr;
+};
+
+static void
+usage(const char *prog, int code)
+{
+ fprintf(stderr,
+ "\nUsage : \n");
+ fprintf(stderr,
+ " %s [options]\n", prog);
+ fprintf(stderr,
+ "-h, --help\n"
+ " show help\n");
+ fprintf(stderr,
+ "-d, --debug-level\n"
+ " set debug level (0: no log, 4 noisy)\n");
+ fprintf(stderr,
+ "-c, --input-conftree\n"
+ " path to input configuration tree file "
+ "(mandatory)\n");
+ fprintf(stderr,
+ "-i, --input-dotconfig\n"
+ " path to input dotconfig file\n");
+ fprintf(stderr,
+ "-o, --output-dotconfig\n"
+ " path to output dotconfig file\n");
+ fprintf(stderr,
+ "-O, --output-c-hdr\n"
+ " path to output C header file\n");
+ fprintf(stderr,
+ "-m, --output-multi-c-hdr\n"
+ " path to output multiple C header directory\n");
+ exit(code);
+}
+
+static void
+free_args(struct cfzy_arguments *cfzy_args)
+{
+ if (cfzy_args->input_conftree != NULL)
+ free(cfzy_args->input_conftree);
+ if (cfzy_args->input_dotconfig != NULL)
+ free(cfzy_args->input_dotconfig);
+ if (cfzy_args->output_dotconfig != NULL)
+ free(cfzy_args->output_dotconfig);
+ if (cfzy_args->output_c_hdr != NULL)
+ free(cfzy_args->output_c_hdr);
+ if (cfzy_args->output_multi_c_hdr != NULL)
+ free(cfzy_args->output_multi_c_hdr);
+}
+
+static void
+parse_args(struct cfzy_arguments *cfzy_args, int argc, char **argv)
+{
+ int ch;
+ const char * prog = argv[0];
+ int option_index;
+ int level;
+ static struct option lgopts[] = {
+ {"help", 0, 0, 'h'},
+ {"debug-level", 0, 0, 'd'},
+ {"input-conftree", 0, 0, 'c'},
+ {"input-dotconfig", 0, 0, 'i'},
+ {"output-dotconfig", 0, 0, 'o'},
+ {"output-c-hdr", 0, 0, 'O'},
+ {"output-multi-c-hdr", 0, 0, 'm'},
+ {NULL, 0, 0, 0}
+ };
+
+ while ((ch = getopt_long(argc, argv,
+ "h" /* help */
+ "d:" /* debug-level */
+ "c:" /* input-conftree */
+ "i:" /* input-dotconfig */
+ "o:" /* output-dotconfig */
+ "O:" /* output-c-hdr */
+ "m:" /* output-multi-c-hdr */
+ ,
+ lgopts, &option_index)) != -1) {
+ switch (ch) {
+ case 'h': /* help */
+ free_args(cfzy_args);
+ usage(prog, 0); /* will exit */
+ break;
+
+ case 'd': /* debug-level */
+ level = atoi(optarg);
+ if (level < 0 || level > CFZY_LOG_DEBUG) {
+ LOG(ERR, "invalid log level\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ exit(1);
+ }
+ cfzy_log_set_default_level(level);
+ break;
+
+ case 'c': /* input-conftree */
+ cfzy_args->input_conftree = strdup(optarg);
+ if (cfzy_args->input_conftree == NULL) {
+ LOG(ERR, "Cannot alloc input conftree str\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ exit(1);
+ }
+ break;
+
+ case 'i': /* input-dotconfig */
+ cfzy_args->input_dotconfig = strdup(optarg);
+ if (cfzy_args->input_dotconfig == NULL) {
+ LOG(ERR, "Cannot alloc input dotconfig str\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ exit(1);
+ }
+ break;
+
+ case 'o': /* output-dotconfig */
+ cfzy_args->output_dotconfig = strdup(optarg);
+ if (cfzy_args->output_dotconfig == NULL) {
+ LOG(ERR, "Cannot alloc output dotconfig str\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ exit(1);
+ }
+ break;
+
+ case 'O': /* output-c-hdr */
+ cfzy_args->output_c_hdr = strdup(optarg);
+ if (cfzy_args->output_c_hdr == NULL) {
+ LOG(ERR, "Cannot alloc output c_hdr str\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ exit(1);
+ }
+ break;
+
+ case 'm': /* output-multi-c-hdr */
+ cfzy_args->output_multi_c_hdr = strdup(optarg);
+ if (cfzy_args->output_multi_c_hdr == NULL) {
+ LOG(ERR, "Cannot alloc output multi_c_hdr str\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ exit(1);
+ }
+ break;
+
+ default:
+ LOG(ERR, "invalid option\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ usage(prog, 1); /* will exit */
+ }
+ }
+
+ /* conftree file is mandatory */
+ if (cfzy_args->input_conftree == NULL) {
+ LOG(ERR, "input conftree is mandatory\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ usage(prog, 1); /* will exit */
+ }
+
+ /* check that at least one output argument is given */
+ if (cfzy_args->output_dotconfig == NULL &&
+ cfzy_args->output_c_hdr == NULL &&
+ cfzy_args->output_multi_c_hdr == NULL) {
+ LOG(ERR, "at least one output argument is needed\n");
+ free_args(cfzy_args);
+ cfzy_log_exit();
+ usage(prog, 1); /* will exit */
+ }
+
+ argc -= optind;
+ argv += optind;
+ /* XXX parse mode */
+}
+
+/*
+ * configuration tree
+ *
+ * -i input .config:
+ * default is none
+ *
+ * -o output .config
+ * defaut is none
+ *
+ * ?? output autoconf.h
+ *
+ * output config/xxx.h
+ *
+ * -v verbose
+ *
+ * oldconfig:
+ * prompt for options that have no user value
+ *
+ * silentoldconfig
+ * set all options that have no user value to default
+ *
+ * config
+ * ?
+ *
+ * defconfig
+ * ?
+ *
+ * randconfig
+ * set all options to a random value (only for booleans, other
+ * values are set to default)
+ *
+ * allyesconfig
+ * set all options to y (booleans only)
+ *
+ * allnoconfig
+ * set all options to n (booleans only)
+ *
+ * - ouvrir le fichier conftree
+ * - si -i, ouvrir .config
+ * - effectue les operations
+ * - si -o et/ou ... output
+ */
+
+static int
+do_configuration(struct cfzy_arguments *cfzy_args)
+{
+ struct cfzy_confnode *n;
+ struct cfzy_conftree *conftree;
+ char buf[BUFSIZ];
+ char *s;
+ int ret;
+
+ /* parse configuration tree */
+ conftree = cfzy_conftree_new(cfzy_args->input_conftree);
+ if (conftree == NULL) {
+ LOG(ERR, "Cannot parse configuration tree\n");
+ return -1;
+ }
+
+ /* parse .config if provided */
+ if (cfzy_args->input_dotconfig != NULL &&
+ cfzy_dotconfig_read(conftree, cfzy_args->input_dotconfig) < 0) {
+ cfzy_conftree_free(conftree);
+ LOG(ERR, "Cannot parse dotconfig <%s>\n",
+ cfzy_args->input_dotconfig);
+ return -1;
+ }
+
+#if 0
+ /* evaluate effective values of conftree */
+ if (cfzy_conftree_evaluate(conftree) < 0) {
+ cfzy_conftree_free(conftree);
+ LOG(ERR, "Cannot evaluate configuration tree\n");
+ return -1;
+ }
+#endif
+
+ memset(buf, 0, sizeof(buf));
+
+ /* browse all nodes following priority list and prompt user */
+ TAILQ_FOREACH(n, &conftree->prio_list, prio_next) {
+
+ if (n->flags & CFZY_F_INVISIBLE)
+ continue;
+ if (n->flags & CFZY_F_NO_NAME)
+ continue;
+
+ /* node has a user value or user value cannot be set,
+ * just display it */
+ if ((n->user_value != NULL) || (n->flags & CFZY_F_NO_SET_VALUE)) {
+ /* XXX we should have a difference between
+ * NO_VALUE (menu for instance) and
+ * NO_SET_VALUE */
+ cfzy_confnode_evaluate(n);
+ printf("%s=%s\n", cfzy_confnode_name(n),
+ n->effective_value);
+ continue;
+ }
+
+ /* node cannot be enabled due to deps */
+ ret = cfzy_confnode_check_deps(n);
+ if (ret == 0) {
+ cfzy_confnode_evaluate(n);
+ printf("%s=%s\n", cfzy_confnode_name(n),
+ n->effective_value);
+ continue;
+ }
+ if (ret < 0) {
+ LOG(ERR, "Cannot check deps\n");
+ return -1;
+ }
+
+ /* ok, now prompt user */
+
+ cfzy_confnode_dump(n, stdout, CFZY_DUMP_MODE_STANDARD);
+
+ while (1) {
+ printf("Enter user value for %s > ",
+ cfzy_confnode_name(n));
+ fflush(stdout);
+
+ fgets(buf, sizeof(buf) - 1, stdin);
+ s = buf;
+ strsep(&s, "\r\n");
+
+ /* empty buf means default value */
+ if (strcmp(buf, "") == 0)
+ break;
+
+ /* invalid value, prompt again */
+ if (cfzy_confnode_set_uservalue(n, buf) < 0) {
+ printf("invalid value\n");
+ continue;
+ }
+
+ break;
+ }
+
+ cfzy_confnode_evaluate(n);
+ printf("%s=%s\n", cfzy_confnode_name(n),
+ n->effective_value);
+ }
+
+ /* output .config if provided */
+ if (cfzy_args->output_dotconfig != NULL &&
+ cfzy_dotconfig_write(conftree, cfzy_args->output_dotconfig) < 0) {
+ cfzy_conftree_free(conftree);
+ LOG(ERR, "Cannot output dotconfig <%s>\n",
+ cfzy_args->output_dotconfig);
+ return -1;
+ }
+
+ /* output C header if provided */
+ if (cfzy_args->output_c_hdr != NULL &&
+ cfzy_c_hdr_write(conftree, cfzy_args->output_c_hdr) < 0) {
+ cfzy_conftree_free(conftree);
+ LOG(ERR, "Cannot output C header <%s>\n",
+ cfzy_args->output_c_hdr);
+ return -1;
+ }
+
+ /* output multiple C headers if provided */
+ if (cfzy_args->output_multi_c_hdr != NULL &&
+ cfzy_multi_c_hdr_write(conftree, cfzy_args->output_multi_c_hdr) < 0) {
+ cfzy_conftree_free(conftree);
+ LOG(ERR, "Cannot output multiple C headers <%s>\n",
+ cfzy_args->output_multi_c_hdr);
+ return -1;
+ }
+
+ cfzy_conftree_free(conftree);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int ret = EXIT_SUCCESS;
+ struct cfzy_arguments cfzy_args;
+
+ /* XXX a cfzy_init() would be better */
+ cfzy_log_init();
+
+ memset(&cfzy_args, 0, sizeof(cfzy_args));
+
+ /* argument parsing is always successful (will exit on error) */
+ parse_args(&cfzy_args, argc, argv);
+
+ /* do the configuration */
+ if (do_configuration(&cfzy_args) < 0) {
+ LOG(ERR, "Configuration failed");
+ ret = EXIT_FAILURE;
+ }
+
+ free_args(&cfzy_args);
+ cfzy_log_exit();
+
+ return ret;
+}
--- /dev/null
+include $(TOPDIR)/confizery.vars.mk
+
+PROG = confizery-test
+
+CFLAGS += -I$(SRCDIR)/libconfizery
+
+LDLIBS = $(BUILDDIR)/libconfizery/libconfizery.a
+
+SRCS = main.c
+SRCS += test_expr.c
+SRCS += test_conftree.c
+SRCS += test_dotconfig.c
+
+include $(TOPDIR)/confizery.prog.mk
--- /dev/null
+# circular dependency between FOO and BAR
+config FOO
+ prompt "hello"
+ default y
+ requires BAR
+
+config BAR
+ default y if FOO
--- /dev/null
+# circular dependency between FOO, BAR and TOTO
+config FOO
+ prompt "hello"
+ default y
+ requires TOTO
+
+menuconfig BAR
+ default y
+ requires FOO
+
+config TOTO
--- /dev/null
+#
+# -- Menu 1
+#
+CONFIG_MENU1_CONFIG1=y
+# Hello
+# CONFIG_MENU1_CONFIG2 is not set
+# CONFIG_MENU1_CONFIG3 is not set
+CONFIG_MENU1_CHOICE="MENU1_CHOICE2"
+# CONFIG_MENU1_CHOICE1 is not set
+CONFIG_MENU1_CHOICE2=y
+# CONFIG_MENU1_CHOICE3 is not set
+CONFIG_INT_EXAMPLE=a
+CONFIG_STR_EXAMPLE="my default value"
+#
+# -- My menuconfig node
+#
+# CONFIG_MENUCONFIG1 is not set
--- /dev/null
+#
+# -- Menu 1
+#
+CONFIG_MENU1_CONFIG1=y
+# Hello
+# CONFIG_MENU1_CONFIG2 is not set
+# CONFIG_MENU1_CONFIG3 is not set
+CONFIG_MENU1_CHOICE="MENU1_CHOICE2"
+# CONFIG_MENU1_CHOICE1 is not set
+CONFIG_MENU1_CHOICE2=y d
+# CONFIG_MENU1_CHOICE3 is not set
+CONFIG_STR_EXAMPLE="my default value"
+#
+# -- My menuconfig node
+#
+# CONFIG_MENUCONFIG1 is not set
--- /dev/null
+#
+# -- Menu 1
+#
+z
+CONFIG_MENU1_CONFIG1=y
+# Hello
+# CONFIG_MENU1_CONFIG2 is not set
+# CONFIG_MENU1_CONFIG3 is not set
+CONFIG_MENU1_CHOICE="MENU1_CHOICE2"
+# CONFIG_MENU1_CHOICE1 is not set
+# CONFIG_MENU1_CHOICE3 is not set
+CONFIG_STR_EXAMPLE="my default value"
+#
+# -- My menuconfig node
+#
+# CONFIG_MENUCONFIG1 is not set
--- /dev/null
+# duplicate config name
+config FOO
+
+intconfig FOO
--- /dev/null
+# invalid attribute
+config FOO
+ prompt "hello"
+ foo bar
--- /dev/null
+# invalid command
+foo bar
+ prompt "hello"
--- /dev/null
+# invalid expression
+config FOO
+ prompt "hello"
+ default y if ( invalid expression xx
--- /dev/null
+# invalid default value
+config FOO
+ prompt "hello"
+ default bar
--- /dev/null
+# menuconfig node not closed
+menuconfig FOO
+
+config BAR
+
+# missing endmenuconfig here
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include <cfzy_log.h>
+
+#include "test_expr.h"
+#include "test_conftree.h"
+#include "test_dotconfig.h"
+
+int main(int argc, char **argv)
+{
+ int ret = 0;
+
+ (void)argc;
+
+ /* XXX a cfzy_init() would be better */
+ cfzy_log_init();
+
+ printf("=== test expression parser ===\n");
+ if (test_expr() < 0) {
+ printf("failed\n");
+ ret = 1;
+ }
+ else
+ printf("success\n");
+
+ printf("=== test conf tree ===\n");
+ if (test_conftree(argv[0]) < 0) {
+ printf("failed\n");
+ ret = 1;
+ }
+ else
+ printf("success\n");
+
+ printf("=== test .config ===\n");
+ if (test_dotconfig(argv[0]) < 0) {
+ printf("failed\n");
+ ret = 1;
+ }
+ else
+ printf("success\n");
+
+ cfzy_log_exit();
+
+ if (ret == 0)
+ printf("\n=== SUCCES ===\n");
+ else
+ printf("\n=== FAILED ===\n");
+
+ return ret;
+}
--- /dev/null
+#
+# comments are prefixed by #
+#
+
+# a menu node is a node that has no value but contains several
+# other nodes
+menu MENU1
+ prompt "Menu 1"
+ # comments can also be added inside a node
+
+# a config node is the most basic node, storing a boolean value
+config MENU1_CONFIG1
+ prompt "A config example"
+ default y
+
+# a comment node is a node that has no value but it will display
+# a prompt in the GUI
+comment "Hello"
+
+# a node can have several default values: each expression is evaluated
+# in the same order until one matches. If no expression matches, the
+# default value of the node is used
+config MENU1_CONFIG2
+ prompt "Another config example"
+ default y if !MENU1_CONFIG1
+ default n
+
+# environment variables can be used anywhere in a conftree file: they
+# are evaluated and replaced by their value before parsing the file.
+config MENU1_CONFIG3
+ prompt "A config example"
+ ---help---
+ The content of the PATH variable is $(PATH)
+
+# a choice node cntains several choiceconfig nodes that are exclusive
+# each other
+choice MENU1_CHOICE
+ prompt "This is menu 1 choice 1"
+ default MENU1_CHOICE2 if MENU1_CONFIG1
+ default MENU1_CHOICE3
+ ---help---
+ help of menu1_choice: this is a choice between
+ several values.
+
+choiceconfig MENU1_CHOICE1
+ prompt "choice 1"
+
+choiceconfig MENU1_CHOICE2
+ prompt "choice 2"
+
+choiceconfig MENU1_CHOICE3
+ prompt "choice 3"
+
+endchoice # this closes the "choice" node
+
+# an intconfig node stores an integer value
+intconfig INT_EXAMPLE
+ prompt "integer example"
+ default 12000000
+ ---help---
+ This is the help of the integer node
+
+# a strconfig stores a string
+strconfig STR_EXAMPLE
+ prompt "A strconfig example"
+ default "my default value"
+
+endmenu
+
+# A menuconfig node is a menu node that can be enabled or disabled.
+# The children nodes are available only if the node is enabled.
+menuconfig MENUCONFIG1
+ prompt "My menuconfig node"
+ # If a line is too long, it can be splitted with a backslash
+ default y if !MENU1_CONFIG1 && \
+ MENU1_CHOICE1
+ ---help---
+ Help for the menuconfig node
+
+# the "requires" attribute sets a list of expressions that must be
+# evaluated to True to enable the node.
+config MENUCONFIG1_CONFIG1
+ prompt "again, a config"
+ requires MENU1_CONFIG1
+ requires !MENU1_CHOICE3
+
+if MENU1_CHOICE1 || MENU1_CHOICE2
+
+config MENUCONFIG1_CONFIG2
+ prompt "still another config"
+
+# source another sub conftree file: the path can be relative to this file
+# or absolute. The "./" is not mandatory here.
+source "./subconftree.cfzy"
+
+endif
+
+endmenuconfig
--- /dev/null
+#
+# -- Menu 1
+#
+CONFIG_MENU1_CONFIG1=y
+
+# unknown node name (should be successful anyway)
+CONFIG_MENU1_CONFIG1XAZXZXZ=y
+
+# Hello
+# CONFIG_MENU1_CONFIG2 is not set
+# CONFIG_MENU1_CONFIG3 is not set
+CONFIG_MENU1_CHOICE="MENU1_CHOICE2"
+# CONFIG_MENU1_CHOICE1 is not set
+CONFIG_MENU1_CHOICE2=y
+# CONFIG_MENU1_CHOICE3 is not set
+CONFIG_STR_EXAMPLE="my default value"
+#
+# -- My menuconfig node
+#
+# CONFIG_MENUCONFIG1 is not set
+
+# same option several times (should be ok too)
+CONFIG_INT_EXAMPLE=1234
+CONFIG_INT_EXAMPLE=1234
+CONFIG_INT_EXAMPLE=1234
--- /dev/null
+config FOO
+ prompt "yet another boolean config"
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <libgen.h>
+
+#include <cfzy_log.h>
+#include <cfzy_list.h>
+#include <cfzy_htable.h>
+#include <cfzy_confnode.h>
+#include <cfzy_conftree.h>
+#include <cfzy_dotconfig.h>
+#include <cfzy_c_hdr.h>
+
+#include "test_conftree.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("test_conftree", level, fmt, ##args)
+
+#define SUCCESS 0
+#define CANNOT_PARSE_CONFTREE -1
+#define CANNOT_DUMP_CONFTREE -2
+#define CANNOT_FIND_SYMBOL -3
+#define CANNOT_EVAL_CONFTREE -4
+#define CANNOT_GET_VALUE -5
+#define CANNOT_SET_VALUE -6
+#define INVALID_VALUE -7
+#define CANNOT_FILTER_CONFTREE -8
+#define CANNOT_SAVE_CONFTREE_VALUES -9
+
+/* check that a node is set to the expected value */
+static int test_one_confnode(const struct cfzy_conftree *conftree,
+ const char *name, int expected_value)
+{
+ int val;
+
+ val = cfzy_confnode_get_boolvalue(name, conftree);
+ if (val < 0) {
+ LOG(DEBUG, "cannot get node value\n");
+ return CANNOT_GET_VALUE;
+ }
+ if (val != expected_value) {
+ LOG(DEBUG, "invalid val for %s: val=%d, expect=%d\n",
+ name, val, expected_value);
+ return INVALID_VALUE;
+ }
+
+ return SUCCESS;
+}
+
+static int test_one_conftree(const char *name)
+{
+ struct cfzy_list_head *node_list = NULL;
+ struct cfzy_list_elt *e;
+ struct cfzy_conftree *conftree;
+ struct cfzy_confnode *n;
+ int ret;
+
+ conftree = cfzy_conftree_new(name);
+ if (conftree == NULL)
+ return CANNOT_PARSE_CONFTREE;
+
+ if (cfzy_conftree_evaluate(conftree) < 0) {
+ LOG(DEBUG, "cannot eval conftree\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_EVAL_CONFTREE;
+ }
+
+ if (cfzy_conftree_dump(conftree, "/tmp/conftree.dump") < 0) {
+ cfzy_conftree_free(conftree);
+ return CANNOT_DUMP_CONFTREE;
+ }
+
+ /* node value should be 1 (default) */
+ ret = test_one_confnode(conftree, "MENU1_CONFIG1", 1);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* node value should be 0 (default) */
+ ret = test_one_confnode(conftree, "MENU1_CONFIG2", 0);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* lookup for this node */
+ n = cfzy_htable_lookup(conftree->nodes_htable, "MENU1_CONFIG1");
+ if (n == NULL) {
+ LOG(DEBUG, "cannot find node\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_FIND_SYMBOL;
+ }
+
+ /* try to assign an invalid value: should fail */
+ if (cfzy_confnode_set_uservalue(n, "dummy") == 0) {
+ LOG(DEBUG, "set_uservalue returned 0 but should not\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_SET_VALUE;
+ }
+
+ /* set thiis node to NO */
+ if (cfzy_confnode_set_uservalue(n, "n") < 0) {
+ LOG(DEBUG, "cannot set node value\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_SET_VALUE;
+ }
+
+ /* node value should be 1 because we did not evaluate the tree */
+ ret = test_one_confnode(conftree, "MENU1_CONFIG1", 1);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ if (cfzy_conftree_evaluate(conftree) < 0) {
+ LOG(DEBUG, "cannot eval conftree\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_EVAL_CONFTREE;
+ }
+
+ if (cfzy_conftree_dump(conftree, "/tmp/conftree2.dump") < 0) {
+ cfzy_conftree_free(conftree);
+ return CANNOT_DUMP_CONFTREE;
+ }
+
+ if (cfzy_conftree_save_values(conftree) < 0) {
+ cfzy_conftree_free(conftree);
+ return CANNOT_SAVE_CONFTREE_VALUES;
+ }
+
+ if (cfzy_conftree_dump(conftree, "/tmp/conftree3.dump") < 0) {
+ cfzy_conftree_free(conftree);
+ return CANNOT_DUMP_CONFTREE;
+ }
+
+ /* node value should now be 0 */
+ ret = test_one_confnode(conftree, "MENU1_CONFIG1", 0);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* node value should now be 1 (depends on !MENU1_CONFIG1) */
+ ret = test_one_confnode(conftree, "MENU1_CONFIG2", 1);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* test "choice" nodes */
+
+ /* node value should be 0 (default) */
+ ret = test_one_confnode(conftree, "MENU1_CHOICE1", 0);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* node value should be 0 (default) */
+ ret = test_one_confnode(conftree, "MENU1_CHOICE2", 0);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* node value should be 1 (default) */
+ ret = test_one_confnode(conftree, "MENU1_CHOICE3", 1);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* lookup for this node */
+ n = cfzy_htable_lookup(conftree->nodes_htable, "MENU1_CHOICE1");
+ if (n == NULL) {
+ LOG(DEBUG, "cannot find node\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_FIND_SYMBOL;
+ }
+
+ /* set this node to Y */
+ if (cfzy_confnode_set_uservalue(n, "y") < 0) {
+ LOG(DEBUG, "cannot set node value\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_SET_VALUE;
+ }
+
+ if (cfzy_conftree_evaluate(conftree) < 0) {
+ LOG(DEBUG, "cannot eval conftree\n");
+ cfzy_conftree_free(conftree);
+ return CANNOT_EVAL_CONFTREE;
+ }
+
+ if (cfzy_conftree_dump(conftree, "/tmp/conftree.dump") < 0) {
+ cfzy_conftree_free(conftree);
+ return CANNOT_DUMP_CONFTREE;
+ }
+
+ /* node value should be 1 */
+ ret = test_one_confnode(conftree, "MENU1_CHOICE1", 1);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* node value should be 0 */
+ ret = test_one_confnode(conftree, "MENU1_CHOICE2", 0);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* node value should be 0 */
+ ret = test_one_confnode(conftree, "MENU1_CHOICE3", 0);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* check the "menuconfig" node value, should be 1 (default) */
+ ret = test_one_confnode(conftree, "MENUCONFIG1", 1);
+ if (ret < 0) {
+ cfzy_conftree_free(conftree);
+ return ret;
+ }
+
+ /* check which node were changed by the user */
+ node_list = cfzy_conftree_filter(conftree, CFZY_FILTER_F_USR_CHANGED);
+ if (node_list == NULL) {
+ cfzy_conftree_free(conftree);
+ return CANNOT_FILTER_CONFTREE;
+ }
+ TAILQ_FOREACH(e, node_list, next) {
+ n = e->ptr;
+ printf("node %s\n", cfzy_confnode_name(n));
+ }
+ cfzy_list_free(node_list, NULL);
+
+ /* check which effective value changed */
+ node_list = cfzy_conftree_filter(conftree, CFZY_FILTER_F_EFF_CHANGED);
+ if (node_list == NULL) {
+ cfzy_conftree_free(conftree);
+ return CANNOT_FILTER_CONFTREE;
+ }
+ TAILQ_FOREACH(e, node_list, next) {
+ n = e->ptr;
+ printf("node2 %s\n", cfzy_confnode_name(n));
+ }
+ cfzy_list_free(node_list, NULL);
+
+ cfzy_conftree_free(conftree);
+ return 0;
+}
+
+static int test_one_invalid_conftree(const char *name)
+{
+ struct cfzy_conftree *conftree;
+
+ conftree = cfzy_conftree_new(name);
+ if (conftree == NULL)
+ return CANNOT_PARSE_CONFTREE;
+
+ cfzy_conftree_free(conftree);
+ return 0;
+}
+
+static void print_error(const char *in, int err)
+{
+ printf("Unexpected return value when parsing: <%s>\n", in);
+ switch (err) {
+ case SUCCESS:
+ printf("Test returned success, but should not\n");
+ break;
+ case CANNOT_PARSE_CONFTREE:
+ printf("Cannot parse configuration tree\n");
+ break;
+ case CANNOT_DUMP_CONFTREE:
+ printf("Cannot dump configuration tree\n");
+ break;
+ case CANNOT_EVAL_CONFTREE:
+ printf("Cannot evalulate configuration tree\n");
+ break;
+ case CANNOT_FIND_SYMBOL:
+ printf("Cannot find symbol\n");
+ break;
+ case CANNOT_GET_VALUE:
+ printf("Cannot get node value\n");
+ break;
+ case CANNOT_SET_VALUE:
+ printf("Cannot set node value\n");
+ break;
+ case INVALID_VALUE:
+ printf("invalid value\n");
+ break;
+ case CANNOT_FILTER_CONFTREE:
+ printf("Cannot filter configuration tree\n");
+ break;
+ case CANNOT_SAVE_CONFTREE_VALUES:
+ printf("Cannot save configuration tree values\n");
+ break;
+ default:
+ printf("Invalid error %d\n", err);
+ break;
+ }
+}
+
+int test_conftree(const char *progname)
+{
+ char filename[PATH_MAX];
+ char *progdir;
+ int err;
+
+ cfzy_log_set_default_level(CFZY_LOG_DEBUG);
+
+ /* progdir is the directory where confizery-test is located */
+ progdir = strdup(progname);
+ dirname(progdir);
+
+ /* unexistant file */
+ snprintf(filename, sizeof(filename), "foobar");
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* invalid command */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "invalid-command.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* invalid attribute */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "invalid-attribute.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* circular dependency */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "circular-dep.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* circular dependency */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "circular-dep2.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* node not closed */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "node-not-closed.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* duplicated config name */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "dup-name.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* invalid default value */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "invalid-value.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* invalid expression */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "invalid-expr.cfzy", progdir);
+ err = test_one_invalid_conftree(filename);
+ if (err != CANNOT_PARSE_CONFTREE) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ /* valid config */
+
+ /* an example config */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/test-configs/"
+ "conftree.cfzy", progdir);
+ err = test_one_conftree(filename);
+ if (err != SUCCESS) {
+ print_error(filename, err);
+ goto fail;
+ }
+
+ free(progdir);
+ return 0;
+
+ fail:
+ free(progdir);
+ return -1;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TEST_CONFTREE_H_
+#define _TEST_CONFTREE_H_
+
+/* test cfzy_conftree module */
+int test_conftree(const char *progname);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <libgen.h>
+
+#include <cfzy_log.h>
+#include <cfzy_list.h>
+#include <cfzy_htable.h>
+#include <cfzy_confnode.h>
+#include <cfzy_conftree.h>
+#include <cfzy_dotconfig.h>
+#include <cfzy_c_hdr.h>
+
+#include "test_dotconfig.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("test_dotconfig", level, fmt, ##args)
+
+#define SUCCESS 0
+#define CANNOT_PARSE_CONFTREE -1
+#define CANNOT_EVAL_CONFTREE -2
+#define CANNOT_GENERATE_DOTCONFIG -3
+#define CANNOT_GENERATE_C_HDR -4
+#define CANNOT_READ_DOTCONFIG -5
+
+static void print_error(const char *in, int err)
+{
+ printf("Unexpected return value when parsing: <%s>\n", in);
+ switch (err) {
+ case SUCCESS:
+ printf("Test returned success, but should not\n");
+ break;
+ case CANNOT_PARSE_CONFTREE:
+ printf("Cannot parse configuration tree\n");
+ break;
+ case CANNOT_EVAL_CONFTREE:
+ printf("Cannot evalulate configuration tree\n");
+ break;
+ case CANNOT_GENERATE_DOTCONFIG:
+ printf("Cannot generate dotconfig file\n");
+ break;
+ case CANNOT_GENERATE_C_HDR:
+ printf("Cannot generate C header file\n");
+ break;
+ case CANNOT_READ_DOTCONFIG:
+ printf("Cannot read dotconfig file\n");
+ break;
+ default:
+ printf("Invalid error %d\n", err);
+ break;
+ }
+}
+
+static int test_one_dotconfig(struct cfzy_conftree *conftree,
+ const char *filename, int expected)
+{
+ int ret, err;
+
+ printf("-- Test dotconfig <%s>\n", filename);
+
+ /* XXX we should reset config */
+
+ ret = cfzy_dotconfig_read(conftree, filename);
+ if (ret < 0)
+ err = CANNOT_READ_DOTCONFIG;
+ else
+ err = SUCCESS;
+
+ /* this is the expected result, return success */
+ if (err == expected)
+ return 0;
+
+ print_error(filename, err);
+ return -1;
+}
+
+int test_dotconfig(const char *progname)
+{
+ struct cfzy_conftree *conftree = NULL;
+ int ret;
+ char filename[PATH_MAX];
+ char *progdir;
+
+ cfzy_log_set_default_level(CFZY_LOG_DEBUG);
+
+ /* progdir is the directory where confizery-test is located */
+ progdir = strdup(progname);
+ dirname(progdir);
+
+ /* an example config */
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/test-configs/"
+ "conftree.cfzy", progdir);
+
+ conftree = cfzy_conftree_new(filename);
+ if (conftree == NULL) {
+ LOG(DEBUG, "cannot parse configuration tree\n");
+ goto fail;
+ }
+
+ if (cfzy_conftree_evaluate(conftree) < 0) {
+ LOG(DEBUG, "cannot eval conftree\n");
+ goto fail;
+ }
+
+ /* write the dotconfig file */
+ ret = cfzy_dotconfig_write(conftree, "/tmp/dotconfig");
+ if (ret < 0) {
+ LOG(DEBUG, "cannot write dotconfig file\n");
+ goto fail;
+ }
+
+ /* write the autoconf.h file */
+ ret = cfzy_c_hdr_write(conftree, "/tmp/autoconf.h");
+ if (ret < 0) {
+ LOG(DEBUG, "cannot write autoconf.h file\n");
+ goto fail;
+ }
+
+ /* write the config/foo/bar.h files */
+ ret = cfzy_multi_c_hdr_write(conftree, "/tmp/config");
+ if (ret < 0) {
+ LOG(DEBUG, "cannot write multiple headers file\n");
+ goto fail;
+ }
+
+ /* test a valid config */
+ if (test_one_dotconfig(conftree, "/tmp/dotconfig", SUCCESS) < 0)
+ goto fail;
+
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/test-configs/"
+ "dotconfig", progdir);
+ if (test_one_dotconfig(conftree, filename, SUCCESS) < 0)
+ goto fail;
+
+ /* invalid configs */
+
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "dotconfig-bad-val", progdir);
+ if (test_one_dotconfig(conftree, filename, CANNOT_READ_DOTCONFIG) < 0)
+ goto fail;
+
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "dotconfig-bad-val2", progdir);
+ if (test_one_dotconfig(conftree, filename, CANNOT_READ_DOTCONFIG) < 0)
+ goto fail;
+
+ snprintf(filename, sizeof(filename),
+ "%s/../../src/confizery-test/invalid-configs/"
+ "dotconfig-bad-val3", progdir);
+ if (test_one_dotconfig(conftree, filename, CANNOT_READ_DOTCONFIG) < 0)
+ goto fail;
+
+ cfzy_conftree_free(conftree);
+ free(progdir);
+ return 0;
+
+ fail:
+ if (conftree != NULL)
+ cfzy_conftree_free(conftree);
+ free(progdir);
+ return -1;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TEST_DOTCONFIG_H_
+#define _TEST_DOTCONFIG_H_
+
+/* test cfzy_dotconfig module */
+int test_dotconfig(const char *progname);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <cfzy_expr.h>
+
+#include "test_expr.h"
+
+#define SUCCESS 0
+#define CANNOT_PARSE -1
+#define CANNOT_CONVERT_TO_STR -2
+#define IN_AND_OUT_DIFFERS -3
+#define CANNOT_EVAL -4
+#define CANNOT_GET_VARS -5
+
+/* all variables starting with "A" are evaluated to 1, the other are
+ * evaluated to 0. The variable names "unknown" returns an error
+ * (variable not found). */
+static int getvalue(const char *varname, void *arg)
+{
+ (void)arg;
+
+ if (!strcmp(varname, "unknown"))
+ return -1;
+
+ if (varname[0] == 'A')
+ return 1;
+ return 0;
+}
+
+static int test_one_expr(const char *in)
+{
+ char out[256];
+ struct cfzy_expr *exp;
+ int ret;
+
+ /* valid expression */
+ exp = cfzy_expr_parse(in);
+ if (exp == NULL)
+ return CANNOT_PARSE;
+
+ cfzy_expr_graph_dump("test.graph", exp);
+ ret = cfzy_expr_to_str(exp, out, sizeof(out));
+ if (ret < 0) {
+ cfzy_expr_free(exp);
+ return CANNOT_CONVERT_TO_STR;
+ }
+
+ if (strncmp(in, out, sizeof(out))) {
+ cfzy_expr_free(exp);
+ return IN_AND_OUT_DIFFERS;
+ }
+
+ ret = cfzy_expr_eval(exp, getvalue, NULL);
+ if (ret < 0) {
+ cfzy_expr_free(exp);
+ return CANNOT_EVAL;
+ }
+
+ cfzy_expr_free(exp);
+ return ret;
+}
+
+static void print_error(const char *in, int err)
+{
+ printf("Unexpected return value when parsing: <%s>\n", in);
+ switch(err) {
+ case 0:
+ case 1:
+ printf("Test returned %d, but should not\n", err);
+ break;
+ case CANNOT_PARSE:
+ printf("Cannot parse expression\n");
+ break;
+ case CANNOT_CONVERT_TO_STR:
+ printf("Cannot convert expression to string\n");
+ break;
+ case IN_AND_OUT_DIFFERS:
+ printf("Input and output expressions differ\n");
+ break;
+ case CANNOT_EVAL:
+ printf("Cannot evaluate expression\n");
+ break;
+ case CANNOT_GET_VARS:
+ printf("Cannot get variable list\n");
+ break;
+ default:
+ printf("Invalid error %d\n", err);
+ break;
+ }
+}
+
+/* must be called with an expression containing only A and B as vars */
+static int test_vars(const char *in)
+{
+ struct cfzy_expr *exp;
+ struct cfzy_list_elt *e;
+ struct cfzy_list_head *list;
+ int ret = 0, count = 0;
+
+ /* valid expression */
+ exp = cfzy_expr_parse(in);
+ if (exp == NULL)
+ return CANNOT_PARSE;
+
+ list = cfzy_expr_get_vars(exp);
+ if (list == NULL) {
+ cfzy_expr_free(exp);
+ return CANNOT_GET_VARS;
+ }
+
+ /* list must contain 2 elements: A and B */
+ TAILQ_FOREACH(e, list, next) {
+ count++;
+ if (!strcmp(e->ptr, "A"))
+ continue;
+ if (!strcmp(e->ptr, "B"))
+ continue;
+ ret = CANNOT_GET_VARS;
+ }
+ if (count != 2)
+ ret = CANNOT_GET_VARS;
+
+ cfzy_list_free(list, free);
+ cfzy_expr_free(exp);
+ return ret;
+}
+
+int test_expr(void)
+{
+ int ret = 0, err;
+ const char *in;
+
+ in = "true && true";
+ err = test_one_expr(in);
+ if (err != 1) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ in = "(true || false) && false";
+ err = test_one_expr(in);
+ if (err != 0) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ in = "true || (false && false)";
+ err = test_one_expr(in);
+ if (err != 1) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* && has priority */
+ in = "true || false && false";
+ err = test_one_expr(in);
+ if (err != 1) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* && has priority */
+ in = "false || true && false && true || true && false";
+ err = test_one_expr(in);
+ if (err != 0) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* '==' has priority */
+ in = "false == true && false";
+ err = test_one_expr(in);
+ if (err != 0) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ in = "A";
+ err = test_one_expr(in);
+ if (err != 1) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ in = "B";
+ err = test_one_expr(in);
+ if (err != 0) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ in = "true && (true)";
+ err = test_one_expr(in);
+ if (err != 1) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ in = "(!(A1 && !(B1 || A2 && B2 || A_aa)) || "
+ "(x && !(D && !A) && !(D || E))) == true";
+ err = test_one_expr(in);
+ if (err != 1) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = " ";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "(";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = ")";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "( )";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "A &&";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+ /* invalid expression */
+ in = "A && && B";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "A B";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "A && B || C D";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "A (B)";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "&& A B";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "! A B";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "A && !|| D";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression */
+ in = "A && !";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression, variable must start with a letter */
+ in = "A && _B";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* invalid expression, variable must start with a letter and
+ * numbers are not allowed (at least today) */
+ in = "A == 4";
+ err = test_one_expr(in);
+ if (err != CANNOT_PARSE) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* valid expression, but unknown variable */
+ in = "unknown";
+ err = test_one_expr(in);
+ if (err != CANNOT_EVAL) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ /* valid expression, but won't display like this because
+ * spaces are stripped */
+ in = " true||(false && \n false)";
+ err = test_one_expr(in);
+ if (err != IN_AND_OUT_DIFFERS) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ err = test_vars("A && B || true && A == !B");
+ if (err != 0) {
+ print_error(in, err);
+ ret = -1;
+ }
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TEST_EXPR_H_
+#define _TEST_EXPR_H_
+
+/* test cfzy_expr module */
+int test_expr(void);
+
+#endif
--- /dev/null
+include $(TOPDIR)/confizery.vars.mk
+
+LIB = libconfizery
+
+#INSTALL_HEADERS = cmdline.h
+
+SRCS = cfzy_expr.c
+SRCS += cfzy_list.c
+SRCS += cfzy_htable.c
+SRCS += cfzy_string.c
+SRCS += cfzy_log.c
+SRCS += cfzy_confnode.c
+SRCS += cfzy_conftree.c
+SRCS += cfzy_dotconfig.c
+SRCS += cfzy_c_hdr.c
+SRCS += cfzy_file.c
+SRCS += cfzy_conftree_parser.c
+SRCS += cfzy_confnode_choice.c
+SRCS += cfzy_confnode_choiceconfig.c
+SRCS += cfzy_confnode_comment.c
+SRCS += cfzy_confnode_config.c
+SRCS += cfzy_confnode_if.c
+SRCS += cfzy_confnode_intconfig.c
+SRCS += cfzy_confnode_menu.c
+SRCS += cfzy_confnode_menuconfig.c
+SRCS += cfzy_confnode_root.c
+SRCS += cfzy_confnode_strconfig.c
+
+include $(TOPDIR)/confizery.lib.mk
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "cfzy_log.h"
+#include "cfzy_file.h"
+#include "cfzy_conftree.h"
+#include "cfzy_confnode.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("c_hdr", level, fmt, ##args)
+
+/* does not clean directories on error, if path exist, assume it's a
+ * directory and ignore error */
+int cfzy_recursive_mkdir(const char *path)
+{
+ char tmp[PATH_MAX];
+ char *p = NULL;
+ int n, ret;
+
+ n = snprintf(tmp, sizeof(tmp),"%s", path);
+ if (n <= 0 || n >= PATH_MAX)
+ return -1;
+
+ /* ignore all trailing '/' */
+ while (n > 0 && tmp[--n] == '/')
+ tmp[n] = '\0';
+
+ /* create all intermediate directories */
+ for (p = tmp + 1; *p; p++) {
+ if (*p != '/')
+ continue;
+
+ *p = '\0';
+ if (mkdir(tmp, S_IRWXU) < 0 && errno != EEXIST)
+ return -1;
+
+ *p = '/';
+ }
+
+ /* and last one */
+ ret = mkdir(tmp, S_IRWXU);
+ if (ret < 0 && errno == EEXIST)
+ return 0;
+
+ return ret;
+}
+
+/*
+ * Get the file name from a config name. Replace first underscore
+ * only:
+ * CONFIG_A_B -> config/a/b.h
+ * CONFIG_A__B___C -> config/a/_b/__c.h
+ */
+static char *configname_to_filename(const char *name)
+{
+ char *filename, *s;
+ int len;
+
+ /* allocate room for dst buffer */
+ len = strlen(name);
+ filename = malloc(len + 3);
+ if (filename == NULL)
+ return NULL;
+ strncpy(filename, name, len + 1);
+
+ for (s = filename; *s != '\0'; s++) {
+ /* '/' is not allowed in variable name */
+ if (*s == '/') {
+ free(filename);
+ return NULL;
+ }
+
+ /* convert the first '_' in '/' */
+ if (*s == '_') {
+ *s = '/';
+ while (s[1] == '/')
+ s++;
+ continue;
+ }
+
+ if (isalpha(*s))
+ *s = tolower(*s);
+ }
+ *s++ = '.';
+ *s++ = 'h';
+ *s = '\0';
+
+ return filename;
+}
+
+static int __cfzy_multi_c_hdr_write(const struct cfzy_confnode *n)
+{
+ const struct cfzy_confnode *c;
+ FILE *f = NULL;
+ char *filename = NULL;
+ char *dname_buf = NULL, *dname_ptr = NULL;
+ char oldval[512];
+ char newval[512];
+ int ret, val;
+
+ /* only dump the node if it has a name and a value */
+ if (n->name != NULL && n->effective_value != NULL) {
+ /* get the name of the file (full path) */
+ filename = configname_to_filename(n->name);
+ if (filename == NULL)
+ goto fail;
+
+ /* get directory name from file name */
+ dname_buf = strdup(filename);
+ if (dname_buf == NULL)
+ goto fail;
+ dname_ptr = dirname(dname_buf);
+
+ /* create dirs */
+ if (cfzy_recursive_mkdir(dname_ptr) < 0)
+ goto fail;
+
+ /* get old value */
+ memset(oldval, 0, sizeof(oldval));
+ f = fopen(filename, "r");
+ if (f != NULL) {
+ ret = fread(oldval, 1, sizeof(oldval) - 1, f);
+ if (ret < 0) {
+ LOG(ERR, "cannot read <%s>\n", filename);
+ goto fail;
+ }
+ fclose(f);
+ f = NULL;
+ }
+
+ /* if config node is a bool, we have NULL and n will
+ * output the same val (is not st) */
+ if (n->flags & CFZY_F_VAL_IS_BOOL) {
+ val = cfzy_confnode_str2bool(n, n->effective_value);
+ if (val < 0)
+ return -1;
+
+ /* bool is false -> not set */
+ if (val == 0) {
+ if (snprintf(newval, sizeof(newval),
+ "/* %s is not set */",
+ cfzy_confnode_name(n)) < 0)
+ goto fail;
+ }
+ else {
+ /* bool is true */
+ if (snprintf(newval, sizeof(newval),
+ "/* %s = %s */", cfzy_confnode_name(n),
+ n->effective_value) < 0)
+ goto fail;
+ }
+ }
+ else {
+ if (snprintf(newval, sizeof(newval),
+ "/* %s = %s */", cfzy_confnode_name(n),
+ n->effective_value) < 0)
+ goto fail;
+ }
+
+ /* if the value is different, write the new value */
+ if (strncmp(newval, oldval, sizeof(newval)) != 0) {
+ f = fopen(filename, "w");
+ if (f == NULL) {
+ LOG(ERR, "cannot open file <%s>\n", filename);
+ goto fail;
+ }
+
+ if (fprintf(f, "%s", newval) < 0) {
+ LOG(ERR, "cannot write in <%s>\n",
+ filename);
+ goto fail;
+ }
+ fclose(f);
+ f = NULL;
+ }
+
+ free(dname_buf);
+ free(filename);
+ }
+
+ /* dump all the children of root node */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (__cfzy_multi_c_hdr_write(c) < 0)
+ break;
+ }
+
+ return 0;
+
+ fail:
+ if (f != NULL)
+ fclose(f);
+ if (dname_buf != NULL)
+ free(dname_buf);
+ if (filename != NULL)
+ free(filename);
+
+ return -1;
+}
+
+/* write config/foo/bar.h */
+int cfzy_multi_c_hdr_write(const struct cfzy_conftree *conftree,
+ const char *basedir)
+{
+ char old_cwd_buf[PATH_MAX];
+ char *old_cwd = NULL;
+ const struct cfzy_confnode *c;
+ int ret = 0;
+
+ LOG(INFO, "multi C headers write <%s>\n", basedir);
+
+ if (cfzy_recursive_mkdir(basedir) < 0)
+ return -1;
+
+ old_cwd = getcwd(old_cwd_buf, sizeof(old_cwd_buf));
+ if (old_cwd == NULL) {
+ LOG(ERR, "getcwd failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (chdir(basedir) < 0) {
+ LOG(ERR, "chdir failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* dump all the children of root node */
+ TAILQ_FOREACH(c, &conftree->root->children, child_next) {
+ ret = __cfzy_multi_c_hdr_write(c);
+ if (ret < 0)
+ break;
+ }
+
+ if (chdir(old_cwd) < 0)
+ LOG(ERR, "chdir back to <%s> failed: %s\n",
+ old_cwd, strerror(errno));
+
+ return ret;
+}
+
+/* write config/autoconf.h */
+int cfzy_c_hdr_write(const struct cfzy_conftree *conftree,
+ const char *filename)
+{
+ FILE *tmp_f, *f;
+ const struct cfzy_confnode *c;
+ int ret = 0;
+
+ LOG(INFO, "open old C header <%s>\n", filename);
+
+ /* open old file in read mode */
+
+ f = fopen(filename, "r");
+ if (f == NULL && errno != ENOENT) {
+ printf("cannot open file <%s>: %s\n",
+ filename, strerror(errno));
+ return -1;
+ }
+
+ /* old file exists */
+ if (f != NULL) {
+
+ /* write C header in temp file */
+ tmp_f = tmpfile();
+ if (tmp_f == NULL) {
+ printf("cannot open temp file\n");
+ return -1;
+ }
+
+ /* dump all the children of root node */
+ TAILQ_FOREACH(c, &conftree->root->children, child_next) {
+ ret = cfzy_confnode_c_hdr_write(c, tmp_f);
+ if (ret < 0)
+ break;
+ }
+
+ /* files are the same, nothing to do */
+ if (cfzy_file_compare(f, tmp_f) == 0) {
+ LOG(INFO, "already up to date: <%s>\n", filename);
+ fclose(tmp_f);
+ fclose(f);
+ return 0;
+ }
+
+ fclose(tmp_f);
+ fclose(f);
+ }
+
+ /* reopen the file in write mode */
+
+ LOG(INFO, "write new C header <%s>\n", filename);
+
+ f = fopen(filename, "w");
+ if (f == NULL) {
+ printf("cannot open file <%s>\n", filename);
+ return -1;
+ }
+
+ /* dump all the children of root node */
+ TAILQ_FOREACH(c, &conftree->root->children, child_next) {
+ ret = cfzy_confnode_c_hdr_write(c, f);
+ if (ret < 0)
+ break;
+ }
+
+ fclose(f);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Confizery C header generation
+ *
+ * This module provides the public API to generate the C header files
+ * from the configuration tree.
+ */
+
+#ifndef _CFZY_C_HDR_H_
+#define _CFZY_C_HDR_H_
+
+/**
+ * Write configuration in a C header file
+ *
+ * Write a C header (autoconf.h like) in a file. This single file will
+ * contain a list of #define (one per option) and is desgined to be
+ * included by a C application using this config.
+ *
+ * If the file already exists and has the same content, nothing is
+ * written in it.
+ *
+ * @param conftree
+ * the configuration tree
+ * @param filename
+ * name of the output file
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_c_hdr_write(const struct cfzy_conftree *conftree,
+ const char *filename);
+
+/**
+ * Write the configuration in multiple header files
+ *
+ * Write a C header (autoconf.h like) in a file. Each option is
+ * written in one single file. If one file already exists and has the
+ * same content, nothing is written in it.
+ *
+ * These files are not desgined to be
+ * included by a C application as each option is just included as a C
+ * comment. The goal of these files is to handle the dependencies
+ * properly in the build system.
+ *
+ * @param conftree
+ * the configuration tree
+ * @param filename
+ * name of the output file
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_multi_c_hdr_write(const struct cfzy_conftree *conftree,
+ const char *basedir);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+#include "cfzy_log.h"
+#include "cfzy_list.h"
+#include "cfzy_htable.h"
+#include "cfzy_string.h"
+#include "cfzy_expr.h"
+#include "cfzy_confnode.h"
+#include "cfzy_conftree.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("confnode", level, fmt, ##args)
+
+/* alloc a new confnode */
+struct cfzy_confnode *cfzy_confnode_alloc(struct cfzy_conftree *conftree)
+{
+ struct cfzy_confnode *n;
+
+ n = malloc(sizeof(struct cfzy_confnode));
+ if (n == NULL)
+ return NULL;
+
+ memset(n, 0, sizeof(*n));
+ TAILQ_INIT(&n->children);
+
+ n->conftree = conftree;
+
+ n->expr_deps = cfzy_list_alloc();
+ if (n->expr_deps == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->default_val_list = cfzy_list_alloc();
+ if (n->default_val_list == NULL) {
+ cfzy_list_free(n->expr_deps, NULL);
+ free(n);
+ return NULL;
+ }
+
+ return n;
+}
+
+/* Free the node given as argument, and all its associated data */
+void cfzy_confnode_free(struct cfzy_confnode *n)
+{
+ struct cfzy_confnode *c;
+ struct cfzy_list_elt *e;
+ struct cfzy_confnode_defvalue *defval;
+
+ /* free the children */
+ while ((c = TAILQ_FIRST(&n->children)) != NULL) {
+ TAILQ_REMOVE(&n->children, c, child_next);
+ cfzy_confnode_free(c);
+ }
+
+ /* do the specific free first */
+ if (n->ops && n->ops->free)
+ n->ops->free(n);
+
+ /* free the deps expression list */
+ cfzy_list_free(n->expr_deps, (void *)cfzy_expr_free);
+
+ /* free the deps expression list (manually free each element
+ * instead of providing a function) */
+ while ((e = TAILQ_FIRST(n->default_val_list)) != NULL) {
+ TAILQ_REMOVE(n->default_val_list, e, next);
+ defval = e->ptr;
+ cfzy_expr_free(defval->expr);
+ free(defval->val);
+ free(defval);
+ free(e);
+ }
+ cfzy_list_free(n->default_val_list, NULL);
+
+ if (n->node_deps != NULL)
+ cfzy_list_free(n->node_deps, NULL);
+
+ /* free the name, help, prompt, ... */
+ if (n->name)
+ free(n->name);
+ if (n->prompt)
+ free(n->prompt);
+ if (n->help)
+ free(n->help);
+ if (n->default_value)
+ free(n->default_value);
+ if (n->user_value)
+ free(n->user_value);
+ if (n->effective_value)
+ free(n->effective_value);
+ if (n->old_user_value)
+ free(n->old_user_value);
+ if (n->old_effective_value)
+ free(n->old_effective_value);
+ if (n->filename)
+ free(n->filename);
+
+ free(n);
+}
+
+/* return the list of nodes required to enable this one */
+struct cfzy_list_head *
+cfzy_confnode_get_deplist(const struct cfzy_confnode *n)
+{
+ struct cfzy_list_head *node_list = NULL, *var_list= NULL;
+ struct cfzy_list_elt *e, *e2;
+ struct cfzy_expr *expr;
+ struct cfzy_confnode *c;
+ const char *varname;
+ const struct cfzy_confnode_defvalue *defval;
+ const struct cfzy_conftree *conftree;
+
+ node_list = cfzy_list_alloc();
+ if (node_list == NULL) {
+ LOG(ERR, "cannot allocate node list\n");
+ return NULL;
+ }
+
+ /* get associated configuration tree */
+ conftree = n->conftree;
+
+ /* list of dependencies (expression list) */
+ TAILQ_FOREACH(e, n->expr_deps, next) {
+
+ expr = e->ptr;
+
+ /* get list of variables for this expression */
+ var_list = cfzy_expr_get_vars(expr);
+ if (var_list == NULL) {
+ LOG(ERR, "cannot allocate get list\n");
+ goto fail;
+ }
+
+ /* list of variables in this expression */
+ TAILQ_FOREACH(e2, var_list, next) {
+
+ varname = e2->ptr;
+
+ c = cfzy_htable_lookup(conftree->nodes_htable, varname);
+ if (c == NULL) {
+ LOG(ERR, "cannot find node <%s>\n", varname);
+ goto fail;
+ }
+
+ if (cfzy_list_elt_is_in_list(node_list, c))
+ continue;
+
+ if (cfzy_list_add_tail(node_list, c) < 0) {
+ LOG(ERR, "cannot add node in list\n");
+ goto fail;
+ }
+ }
+
+ cfzy_list_free(var_list, free);
+ var_list = NULL;
+ }
+
+ /* list of conditional default values depending on an expression */
+ TAILQ_FOREACH(e, n->default_val_list, next) {
+
+ defval = e->ptr;
+ expr = defval->expr;
+
+ /* get list of variables for this expression */
+ var_list = cfzy_expr_get_vars(expr);
+ if (var_list == NULL) {
+ LOG(ERR, "cannot allocate get list\n");
+ goto fail;
+ }
+
+ /* list of variables in this expression */
+ TAILQ_FOREACH(e2, var_list, next) {
+
+ varname = e2->ptr;
+
+ c = cfzy_htable_lookup(conftree->nodes_htable, varname);
+ if (c == NULL) {
+ LOG(ERR, "cannot find node <%s>\n", varname);
+ goto fail;
+ }
+
+ if (cfzy_list_elt_is_in_list(node_list, c))
+ continue;
+
+ if (cfzy_list_add_tail(node_list, c) < 0) {
+ LOG(ERR, "cannot add node in list\n");
+ goto fail;
+ }
+ }
+
+ cfzy_list_free(var_list, free);
+ var_list = NULL;
+ }
+
+ /* parent */
+ if (n->parent != NULL && !cfzy_list_elt_is_in_list(node_list, n->parent)) {
+
+ if (cfzy_list_add_tail(node_list, n->parent) < 0) {
+ LOG(ERR, "cannot add node in list\n");
+ goto fail;
+ }
+ }
+
+ return node_list;
+
+ fail:
+ if (node_list != NULL)
+ cfzy_list_free(node_list, NULL);
+ if (var_list != NULL)
+ cfzy_list_free(var_list, free);
+
+ return NULL;
+}
+
+/* Add a conditional default value to a node */
+int cfzy_confnode_add_defval(struct cfzy_confnode *n, const char *val,
+ const char *expr_buf)
+{
+ struct cfzy_confnode_defvalue *defval;
+
+ defval = malloc(sizeof(*defval));
+ if (defval == NULL)
+ return -1;
+
+ memset(defval, 0, sizeof(*defval));
+ defval->expr = cfzy_expr_parse(expr_buf);
+ if (defval->expr == NULL) {
+ free(defval);
+ return -1;
+ }
+
+ defval->val = strdup(val);
+ if (defval->val == NULL) {
+ cfzy_expr_free(defval->expr);
+ free(defval);
+ return -1;
+ }
+
+ if (cfzy_list_add_tail(n->default_val_list, defval) < 0) {
+ free(defval->val);
+ cfzy_expr_free(defval->expr);
+ free(defval);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Parse a line structure (and its associated line buffer) to match an
+ * attribute of a confnode. Return 0 if the line matches, else return
+ * -1 if we cannot match a valid attribute. */
+enum cfzy_parse_return
+cfzy_confnode_add_attr(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ enum cfzy_parse_return ret;
+ struct cfzy_token *first_tok, *tok;
+ const char *linebuf = tklist->linebuf;
+
+ first_tok = TAILQ_FIRST(&tklist->list);
+
+ /* specific attribute */
+ if (n->ops->add_attr != NULL) {
+ ret = n->ops->add_attr(n, tklist, linebuf);
+ if (ret != NO_MATCH)
+ return ret;
+ }
+
+ /* syntax is: "prompt content" */
+ if (tklist->n_token == 2 &&
+ !strcmp(first_tok->str, "prompt")) {
+
+ if (n->flags & CFZY_F_NO_SET_PROMPT) {
+ LOG(ERR, "node does not support 'prompt' attr\n");
+ return ERROR;
+ }
+
+ tok = TAILQ_NEXT(first_tok, next);
+ if (n->prompt != NULL) {
+ free(n->prompt);
+ n->prompt = NULL;
+ }
+ n->prompt = strdup(tok->str);
+ if (n->prompt == NULL) {
+ LOG(ERR, "cannot allocate prompt\n");
+ return ERROR;
+ }
+ return SUCCESS;
+ }
+
+ /* syntax is: "requires EXPRESSION" */
+ if (tklist->n_token > 1 &&
+ !strcmp(first_tok->str, "requires")) {
+ struct cfzy_expr *exp;
+
+ if (n->flags & CFZY_F_NO_SET_DEPS) {
+ LOG(ERR, "node does not support 'requires' attr\n");
+ return ERROR;
+ }
+
+ tok = TAILQ_NEXT(first_tok, next);
+ exp = cfzy_expr_parse(linebuf + tok->offset);
+ if (exp == NULL) {
+ LOG(ERR, "cannot parse expression\n");
+ return ERROR;
+ }
+
+ cfzy_list_add_tail(n->expr_deps, exp);
+ return SUCCESS;
+ }
+
+ /* syntax is: "default VALUE" */
+ if (tklist->n_token == 2 &&
+ !strcmp(first_tok->str, "default")) {
+
+ if (n->flags & CFZY_F_NO_SET_DEFAULT) {
+ LOG(ERR, "node does not support 'default' attr\n");
+ return ERROR;
+ }
+
+ tok = TAILQ_NEXT(first_tok, next);
+ if (cfzy_confnode_str2bool(n, tok->str) < 0) {
+ LOG(ERR, "invalid value for this node\n");
+ return ERROR;
+ }
+
+ if (n->default_value != NULL)
+ free(n->default_value);
+ n->default_value = strdup(tok->str);
+ if (n->default_value == NULL) {
+ LOG(ERR, "cannot add default value\n");
+ return ERROR;
+ }
+
+ return SUCCESS;
+ }
+
+ /* syntax is: "default VALUE if EXPR" */
+ if (tklist->n_token >= 4 &&
+ !strcmp(first_tok->str, "default")) {
+ struct cfzy_token *tok2;
+
+ tok = TAILQ_NEXT(first_tok, next); /* points to value */
+ tok2 = TAILQ_NEXT(tok, next); /* points to "if" */
+
+ if (strcmp(tok2->str, "if"))
+ return NO_MATCH;
+
+ if (n->flags & CFZY_F_NO_SET_DEFAULT) {
+ LOG(ERR, "node does not support 'default' attr\n");
+ return ERROR;
+ }
+
+ tok2 = TAILQ_NEXT(tok2, next); /* points to expression */
+
+ if (cfzy_confnode_str2bool(n, tok->str) < 0) {
+ LOG(ERR, "invalid value for this node\n");
+ return ERROR;
+ }
+
+ if (cfzy_confnode_add_defval(n, tok->str,
+ linebuf + tok2->offset) < 0) {
+ LOG(ERR, "cannot add default value\n");
+ return ERROR;
+ }
+
+ return SUCCESS;
+ }
+
+ return NO_MATCH;
+}
+
+/* write config value in file f in a dotconfig-like manner. Return 0
+ * on success. */
+int cfzy_confnode_dotconfig_write(const struct cfzy_confnode *n, FILE *f)
+{
+ int val;
+ const struct cfzy_confnode *c;
+
+ if (n->ops->dotconfig_write)
+ return n->ops->dotconfig_write(n, f);
+
+ if (n->flags & CFZY_F_DOTCONF_SHOW_TITLE) {
+ if (fprintf(f,
+ "#\n"
+ "# -- %s\n"
+ "#\n", n->prompt) < 0)
+ return -1;
+ }
+
+ /* only dump the children if effective value is not defined
+ * (some nodes like "comment", "if", "menu", ... can have a
+ * NULL effective value) */
+ if (n->effective_value == NULL)
+ goto dump_children;
+
+ /* when a boolean is unset, use the "is not set" syntax */
+ if (n->flags & CFZY_F_VAL_IS_BOOL) {
+ val = cfzy_confnode_str2bool(n, n->effective_value);
+ if (val < 0)
+ return -1;
+
+ if (val == 0) {
+ if (fprintf(f, "# CONFIG_%s is not set\n",
+ cfzy_confnode_name(n)) < 0)
+ return -1;
+ return 0;
+ }
+ }
+
+ /* common case: dump the value, with or without quotes */
+ if (n->flags & CFZY_F_QUOTE_VAL) {
+ char *quoted_value = cfzy_string_quote(n->effective_value);
+
+ if (quoted_value == NULL)
+ return -1;
+
+ if (fprintf(f, "CONFIG_%s=%s\n", cfzy_confnode_name(n),
+ quoted_value) < 0) {
+ free(quoted_value);
+ return -1;
+ }
+ free(quoted_value);
+ }
+ else {
+ if (fprintf(f, "CONFIG_%s=%s\n", cfzy_confnode_name(n),
+ n->effective_value) < 0)
+ return -1;
+ }
+
+ dump_children:
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (cfzy_confnode_dotconfig_write(c, f) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* write config value in file f in a dotconfig-like manner. Return 0
+ * on success. */
+int cfzy_confnode_c_hdr_write(const struct cfzy_confnode *n, FILE *f)
+{
+ int val;
+ const struct cfzy_confnode *c;
+
+ if (n->ops->c_hdr_write)
+ return n->ops->c_hdr_write(n, f);
+
+ /* if no value, don't dump the value of the node, just the children */
+ if (n->effective_value == NULL)
+ goto dump_children;
+
+ if (n->flags & CFZY_F_VAL_IS_BOOL) {
+ val = cfzy_confnode_str2bool(n, n->effective_value);
+ if (val < 0)
+ return -1;
+
+ /* bool is false -> undef */
+ if (val == 0) {
+ if (fprintf(f, "#undef CONFIG_%s\n",
+ cfzy_confnode_name(n)) < 0)
+ return -1;
+ return 0;
+ }
+
+ /* bool is true -> #define to 1 */
+ if (fprintf(f, "#define CONFIG_%s 1\n",
+ cfzy_confnode_name(n)) < 0)
+ return -1;
+ }
+ /* common case: dump the value, with or without quotes */
+ else if (n->flags & CFZY_F_QUOTE_VAL) {
+ char *quoted_value = cfzy_string_quote(n->effective_value);
+
+ if (quoted_value == NULL)
+ return -1;
+
+ if (fprintf(f, "#define CONFIG_%s %s\n",
+ cfzy_confnode_name(n), quoted_value) < 0) {
+ free(quoted_value);
+ return -1;
+ }
+ free(quoted_value);
+ }
+ else {
+ if (fprintf(f, "#define CONFIG_%s %s\n",
+ cfzy_confnode_name(n), n->effective_value) < 0)
+ return -1;
+ }
+
+ dump_children:
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (cfzy_confnode_c_hdr_write(c, f) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* Close the node beeing parsed */
+int cfzy_confnode_close(struct cfzy_confnode *n)
+{
+ if (n->ops->close)
+ return n->ops->close(n);
+
+ return 0;
+}
+
+/* Return the boolean value of the node given the string value */
+int cfzy_confnode_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ if (n->ops->str2bool)
+ return n->ops->str2bool(n, value);
+
+ /* if there is no specific function, any non-NULL value
+ * returns 1 */
+ if (value == NULL)
+ return 0;
+
+ return 1;
+}
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+const char *cfzy_confnode_get_type_str(const struct cfzy_confnode *n)
+{
+ if (n->ops->get_type_str)
+ return n->ops->get_type_str(n);
+
+ return "unknown";
+}
+
+static int __get_path(const struct cfzy_confnode *n, char *buf,
+ int len, int first)
+{
+ int ret = 0, off;
+
+ if (n->parent == NULL)
+ return snprintf(buf, len, "/");
+
+ ret = __get_path(n->parent, buf, len, 0);
+ if (ret < 0)
+ return ret;
+ off = ret;
+ if (off >= len)
+ return -1;
+
+ if (n->flags & CFZY_F_INVISIBLE)
+ return ret;
+
+ /* a visible node must have a name */
+ if (n->name == NULL)
+ return -1;
+
+ ret = snprintf(buf + off, len - off, "%s%s", n->name,
+ first ? "" : "/");
+ if (ret >= len - off)
+ return -1;
+
+ return ret + off;
+}
+
+/* Dump path in buffer. Invisible nodes like 'if' are ignored. */
+int cfzy_confnode_path(const struct cfzy_confnode *n, char *buf, int len)
+{
+ int ret;
+
+ ret = __get_path(n, buf, len, 1);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+/* dump a config file in a file */
+int cfzy_confnode_dump(const struct cfzy_confnode *n, FILE *f, int mode)
+{
+ const struct cfzy_confnode *c;
+ struct cfzy_confnode_defvalue *defval;
+ struct cfzy_list_elt *e;
+ struct cfzy_expr *expr;
+ char buf[512];
+
+ if (fprintf(f, "%s\n", cfzy_confnode_get_type_str(n)) < 0)
+ return -1;
+ if (fprintf(f, " name: %s\n", cfzy_confnode_name(n)) < 0)
+ return -1;
+ if (fprintf(f, " prompt: %s\n", n->prompt) < 0)
+ return -1;
+ if (cfzy_confnode_path(n, buf, sizeof(buf)) == 0) {
+ if (fprintf(f, " path: %s\n", buf) < 0)
+ return -1;
+ }
+
+ if (mode == CFZY_DUMP_MODE_MINIMAL)
+ return 0;
+
+ /* explicit dependencies */
+ TAILQ_FOREACH(e, n->expr_deps, next) {
+ expr = e->ptr;
+ if (cfzy_expr_to_str(expr, buf, sizeof(buf)) < 0)
+ return -1;
+ if (fprintf(f, " requires: %s\n", buf) < 0)
+ return -1;
+ }
+
+ /* XXX display valid values */
+
+ /* default values */
+ TAILQ_FOREACH(e, n->default_val_list, next) {
+ defval = e->ptr;
+
+ if (cfzy_expr_to_str(defval->expr, buf, sizeof(buf)) < 0)
+ return -1;
+
+ if (fprintf(f, " default: %s if %s\n", defval->val, buf) < 0)
+ return -1;
+ }
+ if (fprintf(f, " node_default %s\n", n->default_value) < 0)
+ return -1;
+ if (fprintf(f, " user_value %s\n", n->user_value) < 0)
+ return -1;
+ if (fprintf(f, " effective_value %s\n", n->effective_value) < 0)
+ return -1;
+
+ if (mode == CFZY_DUMP_MODE_STANDARD)
+ return 0;
+
+ if (fprintf(f, " old_user_value %s\n", n->old_user_value) < 0)
+ return -1;
+ if (fprintf(f, " old_effective_value %s\n", n->old_effective_value) < 0)
+ return -1;
+ if (fprintf(f, " parsed at %s:%d\n", n->filename, n->linenum) < 0)
+ return -1;
+
+ if (fprintf(f, "\n") < 0)
+ return -1;
+
+ if (mode == CFZY_DUMP_MODE_FULL)
+ return 0;
+
+ /* dump children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (cfzy_confnode_dump(c, f, CFZY_DUMP_MODE_FULL_RECURSIVE) < 0)
+ return -1;
+ }
+
+ /* close node if it's a directory */
+ if (n->flags & CFZY_F_IS_DIR) {
+ if (fprintf(f, "end%s\n\n", cfzy_confnode_get_type_str(n)) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* set the uservalue of a node */
+int cfzy_confnode_set_uservalue(struct cfzy_confnode *n, const char *value)
+{
+ char *newvalue = NULL;
+
+ if (n->ops->set_uservalue)
+ return n->ops->set_uservalue(n, value);
+
+ /* check if value is valid */
+ if (cfzy_confnode_str2bool(n, value) < 0)
+ return -1;
+
+ if (value != NULL) {
+ newvalue = strdup(value);
+ if (newvalue == NULL) {
+ LOG(ERR, "cannot allocate new value\n");
+ return -1;
+ }
+ }
+
+ if (n->user_value != NULL)
+ free(n->user_value);
+
+ n->user_value = newvalue;
+ return 0;
+}
+
+/* Get the boolean value of a node, given its name, used as a callback
+ * by cfzy_expr_parse() when parsing an expression for
+ * cfzy_confnode_evaluate() */
+int cfzy_confnode_get_boolvalue(const char *name,
+ const struct cfzy_conftree *conftree)
+{
+ const struct cfzy_confnode *n;
+
+ n = cfzy_htable_lookup(conftree->nodes_htable, name);
+ if (n == NULL)
+ return -1;
+
+ return cfzy_confnode_str2bool(n, n->effective_value);
+}
+
+/* return 0 if a parent node is disabled or if a prerequisite
+ * expression is false, else return 1. On error, return -1. */
+int cfzy_confnode_check_deps(struct cfzy_confnode *n)
+{
+ struct cfzy_list_elt *e;
+ struct cfzy_expr *expr;
+ struct cfzy_confnode *parent;
+ int (*get_boolvalue)(const char *, const struct cfzy_conftree *);
+ int (*get_boolvalue_casted)(const char *, void *);
+ int ret;
+
+ /* we use an intermediate variable to have a compiler warning
+ * if the prototype of cfzy_confnode_get_boolvalue changes. We
+ * know that that these types are compatible here. */
+ get_boolvalue = cfzy_confnode_get_boolvalue;
+ get_boolvalue_casted = (void *)get_boolvalue;
+
+ /* check the dep list first */
+ TAILQ_FOREACH(e, n->expr_deps, next) {
+ expr = e->ptr;
+
+ ret = cfzy_expr_eval(expr, get_boolvalue_casted, n->conftree);
+ if (ret < 0)
+ return -1;
+
+ /* the expression is evaluated to 0, we cannot enable
+ * this node */
+ if (ret == 0) {
+ n->effective_value = NULL;
+ LOG(DEBUG, "disable node <%s> (expr dep)\n",
+ cfzy_confnode_name(n));
+ return 0;
+ }
+ }
+
+ /* check the parent nodes */
+ for (parent = n->parent; parent != NULL; parent = parent->parent) {
+ ret = cfzy_confnode_str2bool(parent, parent->effective_value);
+ if (ret < 0)
+ return -1;
+
+ /* a parent node is evaluated to 0, we cannot enable
+ * this node */
+ if (ret == 0) {
+ n->effective_value = NULL;
+ LOG(DEBUG, "disable node <%s> (parent dep)\n",
+ cfzy_confnode_name(n));
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* Evaluate the effective value of a node, assuming all prerequisites
+ * are already evaluated. */
+int cfzy_confnode_evaluate(struct cfzy_confnode *n)
+{
+ struct cfzy_list_elt *e;
+ struct cfzy_confnode_defvalue *defval;
+ int (*get_boolvalue)(const char *, const struct cfzy_conftree *);
+ int (*get_boolvalue_casted)(const char *, void *);
+ int ret;
+
+ LOG(DEBUG, "evaluating node <%s>\n", cfzy_confnode_name(n));
+
+ /* we use an intermediate variable to have a compiler warning
+ * if the prototype of cfzy_confnode_get_boolvalue changes. We
+ * know that that these types are compatible here. */
+ get_boolvalue = cfzy_confnode_get_boolvalue;
+ get_boolvalue_casted = (void *)get_boolvalue;
+
+ /* remove previous effective value */
+ if (n->effective_value != NULL) {
+ free(n->effective_value);
+ n->effective_value = NULL;
+ }
+
+ /* check prerequisites and parents */
+ ret = cfzy_confnode_check_deps(n);
+ if (ret == 0) {
+ /* we cannot enable this node due to dependencies */
+ n->effective_value = NULL;
+ LOG(DEBUG, "disable node <%s> (expr dep)\n",
+ cfzy_confnode_name(n));
+ return 0;
+ }
+ /* error */
+ if (ret < 0)
+ return ret;
+
+ /* user value has the priority */
+ if (n->user_value != NULL) {
+ n->effective_value = strdup(n->user_value);
+ if (n->effective_value == NULL)
+ return -1;
+
+ LOG(DEBUG, "set node <%s> to user value <%s>\n",
+ cfzy_confnode_name(n), n->effective_value);
+ return 0;
+ }
+
+ /* assign a default value */
+ TAILQ_FOREACH(e, n->default_val_list, next) {
+ defval = e->ptr;
+
+ ret = cfzy_expr_eval(defval->expr, get_boolvalue_casted,
+ n->conftree);
+ if (ret < 0)
+ return -1;
+
+ /* the expression is evaluated to 1, use this default
+ * value for this node */
+ if (ret == 1) {
+ n->effective_value = strdup(defval->val);
+ if (n->effective_value == NULL)
+ return -1;
+ LOG(DEBUG, "set node <%s> to default_list value <%s>\n",
+ cfzy_confnode_name(n), n->effective_value);
+ return 0;
+ }
+ }
+
+ if (n->default_value != NULL)
+ n->effective_value = strdup(n->default_value);
+
+ LOG(DEBUG, "set node <%s> to default value <%s>\n",
+ cfzy_confnode_name(n), n->effective_value);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Confizery configuration node
+ *
+ * This module provides functions related to configuration nodes. A
+ * configuration node is a structure that stores a part of the
+ * information of the configuration tree. For instance, a "config" or
+ * "menuconfig" option is stored in a configuration node structure.
+ *
+ * It contains among other fields the name of the node (CONFIG_XYZ),
+ * the prompt and the help. Each node references its parent and a list
+ * of children as some nodes can contains some other nodes (menu, if,
+ * choice, ...). It also contains the default values, the user value,
+ * and the effective value of the node. Some nodes have no values (if,
+ * comment, ...).
+ */
+
+#ifndef _CFZY_CONFNODE_H_
+#define _CFZY_CONFNODE_H_
+
+#include <stdio.h>
+
+#include "cfzy_confnode_ops.h"
+#include "cfzy_conftree_parser.h"
+
+/* confnode flags */
+#define CFZY_F_IS_DIR 0x0001 /**< node can contain other nodes */
+#define CFZY_F_NO_SET_DEPS 0x0002 /**< does not support the "requires" attribute */
+#define CFZY_F_NO_SET_PROMPT 0x0004 /**< does not support the "prompt" attribute */
+#define CFZY_F_NO_SET_DEFAULT 0x0008 /**< does not support the "default" attribute */
+#define CFZY_F_IS_ROOT 0x0010 /**< the root node */
+#define CFZY_F_VAL_IS_BOOL 0x0020 /**< value is a boolean */
+#define CFZY_F_INVISIBLE 0x0040 /**< never seen from cmdline (like the IF node) */
+#define CFZY_F_NO_NAME 0x0080 /**< node has no name (if, comments, ...) */
+#define CFZY_F_NO_SET_VALUE 0x0100 /**< user cannot set value (if, comments, ...) */
+#define CFZY_F_QUOTE_VAL 0x0200 /**< quote value */
+#define CFZY_F_DOTCONF_SHOW_TITLE 0x0400 /**< show title as a comment in dotconfig file */
+
+struct cfzy_conftree;
+
+/**
+ * Structure storing a conditional default value
+ */
+struct cfzy_confnode_defvalue {
+ struct cfzy_expr *expr; /**< expression (condition) */
+ char *val; /**< value */
+};
+
+/**
+ * List of cfzy_node, used to chain children together
+ */
+TAILQ_HEAD(cfzy_confnode_list, cfzy_confnode);
+
+/**
+ * This structure defines a configuration node in the configration
+ * tree, for instance a "menu" entry, or a "bool" entry.
+ */
+struct cfzy_confnode {
+ /* pointer to other nodes in conf tree */
+ struct cfzy_confnode *parent; /**< pointer to parent */
+ struct cfzy_confnode_list children; /**< list of children */
+ TAILQ_ENTRY(cfzy_confnode) child_next; /**< next in children list */
+ struct cfzy_conftree *conftree; /**< back pointer to conftree */
+
+ /* node attributes */
+ char *name; /**< node name (dynamic alloc) */
+ char *prompt; /**< node prompt (dynamic alloc) */
+ char *help; /**< node help (dynamic alloc) */
+ unsigned flags; /**< node flags */
+ struct cfzy_list_head *expr_deps; /**< list of prereq expressions */
+
+ /* where it was parsed */
+ char *filename; /**< name of conftree file */
+ int linenum; /**< line where node was declared */
+
+ /* specific to a node type */
+ const struct cfzy_confnode_ops *ops; /**< specific ops on node */
+ void *private;
+
+ /* values */
+ char *default_value; /**< default value for this node */
+ struct cfzy_list_head *default_val_list; /* conditional default vals */
+ char *user_value; /**< value wanted by the user */
+ char *effective_value; /**< real value, taking care of deps */
+ char *old_user_value; /**< saved user value */
+ char *old_effective_value; /**< saved effective value */
+
+ /* allow to chain this node in a priority ordered list */
+ TAILQ_ENTRY(cfzy_confnode) prio_next; /**< next in ordered list */
+ int in_prio_list; /**< true if present in prio list */
+
+ struct cfzy_list_head *node_deps; /**< list of nodes that must be
+ * evaluated before this one */
+};
+
+/**
+ * Get the name of a node
+ *
+ * @param n
+ * configuration node
+ * @return
+ * pointer to the node name (hosted in the node structure)
+ */
+static inline const char *cfzy_confnode_name(const struct cfzy_confnode *n)
+{
+ if (n->name == NULL)
+ return "no-name";
+ return n->name;
+}
+
+/**
+ * Allocate a new node
+ *
+ * Allocate a new empty node, with no specific ops.
+ *
+ * @param conftree
+ * configuration tree
+ * @return
+ * the allocated configuration node, or NULL on error
+ */
+struct cfzy_confnode *cfzy_confnode_alloc(struct cfzy_conftree *conftree);
+
+/**
+ * Free the node given as argument, and all its associated data
+ *
+ * This function will free the children of the nodes, then the node
+ * itself, first by calling the specific function n->ops->free() if
+ * defined, then by doing the generic operations.
+ *
+ * @param n
+ * configuration node
+ */
+void cfzy_confnode_free(struct cfzy_confnode *n);
+
+/**
+ * Get the prerequisites for this node
+ *
+ * Return the list of nodes required to evaluate the value of the
+ * given node. Indeed, each node has a 'expr_deps' field storing a
+ * list of expressions and a list of default value associated to
+ * expressions. This function returns the list of all nodes referenced
+ * in these expressions and all the ancestor nodes.
+ *
+ * The returned list must be freed by the user with
+ * cfzy_list_free(list, NULL).
+ *
+ * @param n
+ * configuration node
+ * @return
+ * list of nodes, or NULL on error
+ */
+struct cfzy_list_head *
+cfzy_confnode_get_deplist(const struct cfzy_confnode *n);
+
+/**
+ * Add a conditional default value to a node
+ *
+ * @param n
+ * configuration node
+ * @param val
+ * value to be used as default value
+ * @param expr_buf
+ * condition string to enable the default value
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_add_defval(struct cfzy_confnode *n, const char *val,
+ const char *expr_buf);
+
+/**
+ * Parse a line of configuration tree file, expecting an attribute
+ *
+ * This function first tries to match specific node attributes, using
+ * the specific operation n->ops->add_attr() if registered. Then it
+ * tries to match generic attributes (prompt, requires, default).
+ *
+ * This function is internal to the confizery library (called by the
+ * configuration tree parser).
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_add_attr(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Write .config-like configuration in a file
+ *
+ * Write in a file the configuration values of this node and its
+ * descendants. The format of this file is like .config: it can be
+ * sourced by a shell or a Makefile.
+ *
+ * The function calls the specific node operation
+ * n->ops->dotconfig_write() if defined. Else, it uses the defaut
+ * behavior, which varies depending on node flags.
+ *
+ * This function is internal and is called by the public function
+ * cfzy_dotconfig_write().
+ *
+ * @param n
+ * configuration node
+ * @param f
+ * open file with write permissions where config will be written
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_dotconfig_write(const struct cfzy_confnode *n, FILE *f);
+
+/**
+ * Write the configuration in a C header file
+ *
+ * Write in a file the configuration values of this node and its
+ * descendants. The format of this file is a C header, so it can be
+ * included by a C application.
+ *
+ * The function calls the specific node operation
+ * n->ops->c_hdr_write() if defined. Else, it uses the defaut
+ * behavior, which varies depending on node flags.
+ *
+ * This function is internal and is called by the public function
+ * cfzy_c_hdr_write().
+ *
+ * @param n
+ * configuration node
+ * @param f
+ * open file with write permissions where config will be written
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_c_hdr_write(const struct cfzy_confnode *n, FILE *f);
+
+/**
+ * Return a string identifying the node type
+ *
+ * The function calls the specific node operation
+ * n->ops->get_type_str().
+ *
+ * The returned string points to static memory and contains the type
+ * of the node (ex: "config", "menuconfig", "choice", ...)
+ *
+ * @param n
+ * configuration node
+ * @return
+ * pointer to a node type string
+ */
+const char *cfzy_confnode_get_type_str(const struct cfzy_confnode *n);
+
+/**
+ * Return the boolean value of the node given the string value
+ *
+ * Convert the string value given as parameter to a boolean value. It
+ * calls the specific node operation n->ops->str2bool() if
+ * defined. Else, it uses the defaut behavior: return 0 for value=NULL
+ * or 1 for any other value.
+ *
+ * The specific function (if defined) can also return a negative value
+ * to indicate that the given value is not valid for this node.
+ *
+ * @param n
+ * configuration node
+ * @param value
+ * string containing the value
+ * @return
+ * the boolean value (0 or 1) if the string value is valid,
+ * else -1
+ */
+int cfzy_confnode_str2bool(const struct cfzy_confnode *n, const char *value);
+
+/**
+ * Get the path of the node
+ *
+ * @param n
+ * configuration node
+ * @param buf
+ * buffer where the path should be written
+ * @param len
+ * length of the buffer
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_path(const struct cfzy_confnode *n, char *buf, int len);
+
+/* dump modes */
+#define CFZY_DUMP_MODE_MINIMAL 0x0
+#define CFZY_DUMP_MODE_STANDARD 0x1
+#define CFZY_DUMP_MODE_FULL 0x2
+#define CFZY_DUMP_MODE_FULL_RECURSIVE 0x3
+
+/**
+ * Dump a human-readable configuration in a file
+ *
+ * Write in a file the structure fields of this node and its
+ * descendants.
+ *
+ * @param n
+ * configuration node
+ * @param f
+ * open file with write permissions where configuration will be written
+ * @param mode
+ * behavior of dump (CFZY_DUMP_MODE_MINIMAL, CFZY_DUMP_MODE_STANDARD, ...)
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_dump(const struct cfzy_confnode *n, FILE *f, int mode);
+
+/**
+ * Check prerequisites for a node
+ *
+ * @param n
+ * configuration node to be checked
+ * @return
+ * 0 if a parent node is disabled or if a prerequisite expression is
+ * false, 1 if node can be enable. On error, return -1.
+ */
+int cfzy_confnode_check_deps(struct cfzy_confnode *n);
+
+/**
+ * Evaluate the effective value of a node
+ *
+ * Set the new value of n->effective_value, assuming all prerequisites
+ * are already evaluated. This function is used as a callback by
+ * cfzy_expr_parse() when parsing an expression for
+ * cfzy_confnode_evaluate().
+ *
+ * @return n
+ * configuration node
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_evaluate(struct cfzy_confnode *n);
+
+/**
+ * Get the boolean value of a node, given its name
+ *
+ * Return the effective value of a node (assuming it has been
+ * evaluated previously).
+ *
+ * @param name
+ * configuration node name
+ * @param conftree
+ * configuration tree
+ * @return
+ * the boolean value (0 or 1) if the string value is valid,
+ * else -1
+ */
+int cfzy_confnode_get_boolvalue(const char *name,
+ const struct cfzy_conftree *conftree);
+
+/**
+ * Set user value of a configuration node
+ *
+ * To set the user value of a node, the user must not access to the
+ * field directly but use this function. Indeed, a node may want to do
+ * a specific operation (like a check, or modifying children nodes)
+ * stored in n->ops->set_uservalue().
+ *
+ * @return n
+ * configuration node
+ * @param value
+ * value to be set as user value
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_set_uservalue(struct cfzy_confnode *n, const char *value);
+
+/**
+ * Create a new root node
+ *
+ * @param conftree
+ * configuration tree
+ * @return
+ * a pointer to the configuration node, or NULL on error
+ */
+struct cfzy_confnode *cfzy_confnode_root_new(struct cfzy_conftree *conftree);
+
+/**
+ * Parse a line of configuration tree file, expecting new choice node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_choice_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+/**
+ * Parse a line of configuration tree file, expecting new choiceconfig node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_choiceconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Parse a line of configuration tree file, expecting new comment node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_comment_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Parse a line of configuration tree file, expecting new config node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_config_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Parse a line of configuration tree file, expecting new if node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_if_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Parse a line of configuration tree file, expecting new intconfig node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_intconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Parse a line of configuration tree file, expecting new menu node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_menu_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Parse a line of configuration tree file, expecting new menuconfig node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_menuconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Parse a line of configuration tree file, expecting new strconfig node
+ *
+ * @param n
+ * configuration node
+ * @param tklist
+ * list of tokens for this line
+ * @return
+ * SUCCESS if it matches an attribute of this node, NO_MATCH if the line
+ * is not an attribute for this node, ERROR on error
+ */
+enum cfzy_parse_return
+cfzy_confnode_strconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist);
+
+/**
+ * Close the node beeing parsed
+ *
+ * Some nodes can contains other nodes (menu, menuconfig, ...). When
+ * the parser has finished to parse the descendants of the node, it
+ * calls this function to close the node. This can trigger some
+ * specific operations (like checks) if the node type registers a
+ * n->ops->close(). If no specific function is registered, it does
+ * nothing.
+ *
+ * This function is internal to the confizery library (called by the
+ * configuration tree parser).
+ *
+ * @param n
+ * configuration node
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_confnode_close(struct cfzy_confnode *n);
+
+
+#endif /* _CFZY_CONFNODE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_log.h"
+#include "cfzy_list.h"
+#include "cfzy_expr.h"
+#include "cfzy_confnode.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("confnode_choice", level, fmt, ##args)
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *choice_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "choice";
+}
+
+static int choice_str2bool(const struct cfzy_confnode *n, const char *value)
+{
+ struct cfzy_confnode *c;
+
+ /* NULL means "disabled" */
+ if (value == NULL)
+ return 0;
+
+ /* if we have no children, it's because we are creating the
+ * node, so accept all values, we will check them later in
+ * choice_close() */
+ if (TAILQ_EMPTY(&n->children))
+ return 1;
+
+ /* else, the value must be the name of a children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (!strcmp(value, c->name))
+ return 1;
+ }
+
+ /* invalid value */
+ return -1;
+}
+
+static int choice_close(struct cfzy_confnode *n)
+{
+ struct cfzy_confnode_defvalue *defval;
+ struct cfzy_list_elt *e;
+ struct cfzy_confnode *c;
+ char exprbuf[512];
+ int ret;
+
+ /* browse all default values and call choice_str2bool() on
+ * them to check that they are correct */
+ TAILQ_FOREACH(e, n->default_val_list, next) {
+ defval = e->ptr;
+
+ if (choice_str2bool(n, defval->val) < 0) {
+ LOG(ERR, "invalid default value <%s> for node <%s>\n",
+ defval->val, n->name);
+ return -1;
+ }
+ }
+ if (choice_str2bool(n, n->default_value) < 0) {
+ LOG(ERR, "invalid default value <%s> for node <%s>\n",
+ n->default_value, n->name);
+ return -1;
+ }
+
+ /* for each child node */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+
+ /* set default value */
+ if (!strcmp(n->default_value, c->name))
+ c->default_value = strdup("y");
+ else
+ c->default_value = strdup("n");
+
+ if (c->default_value == NULL) {
+ LOG(ERR, "cannot allocate default value>\n");
+ return -1;
+ }
+
+ /* set conditional default values for child nodes with
+ * the same condition */
+ TAILQ_FOREACH(e, n->default_val_list, next) {
+ defval = e->ptr;
+
+ if (cfzy_expr_to_str(defval->expr, exprbuf,
+ sizeof(exprbuf)) < 0) {
+ LOG(ERR, "cannot convert expression to str\n");
+ return -1;
+ }
+
+ if (!strcmp(defval->val, c->name))
+ ret = cfzy_confnode_add_defval(c, "y", exprbuf);
+ else
+ ret = cfzy_confnode_add_defval(c, "n", exprbuf);
+
+ if (ret < 0) {
+ LOG(ERR, "cannot add conditional default\n");
+ return -1;
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+static int choice_set_uservalue(struct cfzy_confnode *n, const char *value)
+{
+ struct cfzy_confnode *c;
+ char *newvalue;
+
+ /* if value is NULL, unset this node and all its children,
+ * falling back to default value */
+ if (value == NULL) {
+ /* this node */
+ if (n->user_value != NULL)
+ free(n->user_value);
+ n->user_value = NULL;
+
+ /* children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (c->user_value != NULL)
+ free(c->user_value);
+ c->user_value = NULL;
+ }
+ return 0;
+ }
+
+ /* if not NULL, the value must be the name of a children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (!strcmp(value, c->name))
+ break;
+ }
+ if (c == NULL)
+ return -1;
+
+
+ /* this node */
+ if (n->user_value != NULL)
+ free(n->user_value);
+ n->user_value = strdup(c->name);
+ if (n->user_value == NULL) {
+ LOG(ERR, "cannot allocate value\n");
+ return -1;
+ }
+
+ /* children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (!strcmp(value, c->name))
+ newvalue = strdup("y");
+ else
+ newvalue = strdup("n");
+
+ if (newvalue == NULL) {
+ LOG(ERR, "cannot allocate value\n");
+ return -1;
+ }
+
+ if (c->user_value != NULL)
+ free(c->user_value);
+ c->user_value = newvalue;
+ }
+
+ return 0;
+}
+
+static struct cfzy_confnode_ops choice_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = choice_close,
+ .dotconfig_write = NULL,
+ .c_hdr_write = NULL,
+ .str2bool = choice_str2bool,
+ .get_type_str = choice_get_type_str,
+ .set_uservalue = choice_set_uservalue,
+};
+
+/* Create a new node */
+enum cfzy_parse_return cfzy_confnode_choice_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "choice") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ n->ops = &choice_ops;
+ n->flags = CFZY_F_IS_DIR | CFZY_F_QUOTE_VAL;
+
+ n->name = strdup(tok->str);
+ if (n->name == NULL)
+ return ERROR;
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_log.h"
+#include "cfzy_expr.h"
+#include "cfzy_confnode.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("confnode_choiceconfig", level, fmt, ##args)
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *choiceconfig_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "choiceconfig";
+}
+
+static int choiceconfig_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ (void)n;
+
+ /* NULL or "n" means disabled */
+ if (value == NULL || !strcmp("n", value))
+ return 0;
+
+ if (!strcmp("y", value))
+ return 1;
+
+ return -1;
+}
+
+static int choiceconfig_set_uservalue(struct cfzy_confnode *n,
+ const char *value)
+{
+ struct cfzy_confnode *c;
+
+ if (value == NULL)
+ return cfzy_confnode_set_uservalue(n->parent, NULL);
+
+ if (!strcmp(value, "y"))
+ return cfzy_confnode_set_uservalue(n->parent, n->name);
+
+ if (!strcmp(value, "n")) {
+ /* node is already set to "n", do nothing so we won't
+ * change the selected choice */
+ if (!strcmp(n->user_value, "n"))
+ return 0;
+
+ /* else just set to 'y' the first brother that we find */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (c != n)
+ break;
+ }
+
+ /* no brother found */
+ if (c == NULL)
+ return -1;
+
+ return cfzy_confnode_set_uservalue(c, "y");
+ }
+
+ return -1;
+}
+
+static struct cfzy_confnode_ops choiceconfig_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = choiceconfig_str2bool,
+ .dotconfig_write = NULL,
+ .c_hdr_write = NULL,
+ .get_type_str = choiceconfig_get_type_str,
+ .set_uservalue = choiceconfig_set_uservalue,
+};
+
+/* Create a new node */
+enum cfzy_parse_return
+cfzy_confnode_choiceconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "choiceconfig") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ n->ops = &choiceconfig_ops;
+ n->flags = CFZY_F_NO_SET_DEFAULT | CFZY_F_VAL_IS_BOOL;
+
+ n->name = strdup(tok->str);
+ if (n->name == NULL)
+ return ERROR;
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_log.h"
+#include "cfzy_confnode.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("comment", level, fmt, ##args)
+
+/* write config value in file f in a dotconfig-like manner. Return 0
+ * on success. */
+static int comment_dotconfig_write(const struct cfzy_confnode *n, FILE *f)
+{
+ if (fprintf(f, "# %s\n", n->prompt) < 0)
+ return -1;
+
+ /* this node has no children, no need to dump them */
+ return 0;
+}
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *comment_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "comment";
+}
+
+static struct cfzy_confnode_ops comment_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = NULL,
+ .dotconfig_write = comment_dotconfig_write,
+ .c_hdr_write = NULL,
+ .get_type_str = comment_get_type_str,
+ .set_uservalue = NULL,
+};
+
+/* Create a new node */
+enum cfzy_parse_return cfzy_confnode_comment_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "comment") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ /* comment string is stored in prompt field, not in name */
+ if (n->prompt != NULL) {
+ free(n->prompt);
+ n->prompt = NULL;
+ }
+ n->prompt = strdup(tok->str);
+ if (n->prompt == NULL) {
+ LOG(ERR, "cannot allocate prompt");
+ return ERROR;
+ }
+ n->ops = &comment_ops;
+ n->flags = CFZY_F_NO_SET_DEFAULT |
+ CFZY_F_NO_SET_PROMPT |
+ CFZY_F_NO_NAME |
+ CFZY_F_NO_SET_VALUE;
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_confnode.h"
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *config_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "config";
+}
+
+static int config_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ (void)n;
+
+ /* NULL or "n" means disabled */
+ if (value == NULL || !strcmp("n", value))
+ return 0;
+
+ if (!strcmp("y", value))
+ return 1;
+
+ return -1;
+}
+
+static struct cfzy_confnode_ops config_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = config_str2bool,
+ .dotconfig_write = NULL,
+ .c_hdr_write = NULL,
+ .get_type_str = config_get_type_str,
+ .set_uservalue = NULL,
+};
+
+/* Create a new node */
+enum cfzy_parse_return cfzy_confnode_config_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "config") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ n->ops = &config_ops;
+ n->flags = CFZY_F_VAL_IS_BOOL;
+
+ n->name = strdup(tok->str);
+ if (n->name == NULL)
+ return ERROR;
+
+ n->default_value = strdup("n");
+ if (n->default_value == NULL) {
+ free(n->name);
+ n->name = NULL;
+ return ERROR;
+ }
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_list.h"
+#include "cfzy_expr.h"
+#include "cfzy_confnode.h"
+
+/* write config value in file f in a dotconfig-like manner. Return -1
+ * on error. */
+static int if_dotconfig_write(const struct cfzy_confnode *n, FILE *f)
+{
+ const struct cfzy_confnode *c;
+ int val;
+
+ val = cfzy_confnode_str2bool(n, n->effective_value);
+ if (val < 0)
+ return -1;
+
+ /* condition is wrong, nothing to dump */
+ if (val == 0)
+ return 0;
+
+ /* else, just dump children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (cfzy_confnode_dotconfig_write(c, f) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *if_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "if";
+}
+
+/* evaluate the expression stored in the node */
+static int if_str2bool(const struct cfzy_confnode *n, const char *value)
+{
+ struct cfzy_list_elt *e;
+ struct cfzy_expr *expr;
+ int (*get_boolvalue)(const char *, const struct cfzy_conftree *);
+ int (*get_boolvalue_casted)(const char *, void *);
+
+ (void)n;
+
+ /* should not happen */
+ if (value != NULL)
+ return -1;
+
+ e = TAILQ_FIRST(n->expr_deps);
+ if (e == NULL)
+ return -1;
+ expr = e->ptr;
+
+ /* we use an intermediate variable to have a compiler warning
+ * if the prototype of cfzy_confnode_get_boolvalue changes. We
+ * know that that these types are compatible here. */
+ get_boolvalue = cfzy_confnode_get_boolvalue;
+ get_boolvalue_casted = (void *)get_boolvalue;
+
+ return cfzy_expr_eval(expr, get_boolvalue_casted, n->conftree);
+}
+
+static struct cfzy_confnode_ops if_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = if_str2bool,
+ .dotconfig_write = if_dotconfig_write,
+ .c_hdr_write = NULL,
+ .get_type_str = if_get_type_str,
+ .set_uservalue = NULL,
+};
+
+/* Create a new node */
+enum cfzy_parse_return cfzy_confnode_if_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ struct cfzy_expr *exp;
+
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "if") || tklist->n_token < 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next); /* points to expression */
+ exp = cfzy_expr_parse(tklist->linebuf + tok->offset);
+ if (exp == NULL)
+ return ERROR;
+
+ if (cfzy_list_add_tail(n->expr_deps, exp) < 0) {
+ cfzy_expr_free(exp);
+ return ERROR;
+ }
+
+ n->ops = &if_ops;
+ n->flags = CFZY_F_INVISIBLE |
+ CFZY_F_NO_NAME |
+ CFZY_F_NO_SET_DEPS |
+ CFZY_F_NO_SET_PROMPT |
+ CFZY_F_NO_SET_DEFAULT |
+ CFZY_F_NO_SET_VALUE |
+ CFZY_F_IS_DIR;
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_confnode.h"
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *intconfig_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "intconfig";
+}
+
+static int intconfig_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ char *end;
+ int64_t val;
+
+ (void)n;
+
+ /* NULL means disabled */
+ if (value == NULL)
+ return 0;
+
+ val = strtoll(value, &end, 0);
+ if (*end != 0)
+ return -1;
+
+ /* XXX check range attr here */
+
+ return val != 0;
+}
+
+static struct cfzy_confnode_ops intconfig_ops = {
+ .free = NULL,
+ .add_attr = NULL, /* XXX range, displayhex */
+ .close = NULL,
+ .str2bool = intconfig_str2bool,
+ .dotconfig_write = NULL,
+ .c_hdr_write = NULL,
+ .get_type_str = intconfig_get_type_str,
+ .set_uservalue = NULL,
+};
+
+/* Create a new node */
+enum cfzy_parse_return cfzy_confnode_intconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "intconfig") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ n->ops = &intconfig_ops;
+ n->flags = 0;
+
+ n->name = strdup(tok->str);
+ if (n->name == NULL)
+ return ERROR;
+
+ n->default_value = strdup("0");
+ if (n->default_value == NULL) {
+ free(n->name);
+ n->name = NULL;
+ return ERROR;
+ }
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_confnode.h"
+
+/* write config value in file f in a dotconfig-like manner. Return 0
+ * on success. */
+static int menu_dotconfig_write(const struct cfzy_confnode *n, FILE *f)
+{
+ const struct cfzy_confnode *c;
+
+ if (fprintf(f,
+ "#\n"
+ "# -- %s\n"
+ "#\n", n->prompt) < 0)
+ return -1;
+
+ /* dump children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (cfzy_confnode_dotconfig_write(c, f) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* this node is always enabled whatever the value */
+static int menu_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ (void)n;
+
+ /* should not happen */
+ if (value != NULL)
+ return -1;
+
+ return 1;
+}
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *menu_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "menu";
+}
+
+static struct cfzy_confnode_ops menu_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = menu_str2bool,
+ .dotconfig_write = menu_dotconfig_write,
+ .c_hdr_write = NULL,
+ .get_type_str = menu_get_type_str,
+ .set_uservalue = NULL,
+};
+
+/* Create a new node */
+enum cfzy_parse_return cfzy_confnode_menu_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "menu") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ n->ops = &menu_ops;
+ n->flags = CFZY_F_IS_DIR |
+ CFZY_F_NO_SET_DEPS |
+ CFZY_F_NO_SET_DEFAULT |
+ CFZY_F_NO_SET_VALUE |
+ CFZY_F_DOTCONF_SHOW_TITLE;
+
+ n->name = strdup(tok->str);
+ if (n->name == NULL)
+ return ERROR;
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_confnode.h"
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *menuconfig_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "menuconfig";
+}
+
+static int menuconfig_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ (void)n;
+
+ if (!strcmp("y", value))
+ return 1;
+
+ if (!strcmp("n", value))
+ return 0;
+
+ return -1;
+}
+
+static struct cfzy_confnode_ops menuconfig_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = menuconfig_str2bool,
+ .dotconfig_write = NULL,
+ .c_hdr_write = NULL,
+ .get_type_str = menuconfig_get_type_str,
+ .set_uservalue = NULL,
+};
+
+/* Create a new node */
+enum cfzy_parse_return
+cfzy_confnode_menuconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "menuconfig") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ n->ops = &menuconfig_ops;
+ n->flags = CFZY_F_IS_DIR | CFZY_F_DOTCONF_SHOW_TITLE |
+ CFZY_F_VAL_IS_BOOL;
+
+ n->name = strdup(tok->str);
+ if (n->name == NULL)
+ return ERROR;
+
+ n->default_value = strdup("n");
+ if (n->default_value == NULL) {
+ free(n->name);
+ n->name = NULL;
+ return ERROR;
+ }
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Confizery configuration node specific operations
+ *
+ * This file describes specific node operations, called internally by
+ * cfzy_confnode module.
+ */
+
+#ifndef _CFZY_CONFNODE_OPS_H_
+#define _CFZY_CONFNODE_OPS_H_
+
+#include <stdio.h>
+
+#include "cfzy_conftree_parser.h"
+
+struct cfzy_confnode;
+struct cfzy_token_list;
+
+/**
+ * Node operation to free the specific node data. Called by
+ * cfzy_confnode_free().
+ */
+typedef void (confnode_free_t)(struct cfzy_confnode *n);
+
+/**
+ * Specific node operation to parse a conftree line, expecting a new
+ * attribute. Called by cfzy_confnode_add_attr().
+ */
+typedef enum cfzy_parse_return
+(confnode_add_attr_t)(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist,
+ const char *linebuf);
+
+/**
+ * Specific node operation to close a node beeing parsed. Called by
+ * cfzy_confnode_close().
+ */
+typedef int (confnode_close_t)(struct cfzy_confnode *n);
+
+/**
+ * Specific node operation that writes the configuration in a
+ * file. Called by cfzy_confnode_dotconfig_write().
+ */
+typedef int (confnode_dotconfig_write_t)(const struct cfzy_confnode *n, FILE *f);
+
+/**
+ * Specific node operation that writes the configuration in a C header
+ * file. Called by cfzy_confnode_c_hdr_write().
+ */
+typedef int (confnode_c_hdr_write_t)(const struct cfzy_confnode *n, FILE *f);
+
+/**
+ * Specific node operation that returns the boolean value of the node
+ * given the string value. Called by cfzy_confnode_str2bool().
+ */
+typedef int (confnode_str2bool_t)(const struct cfzy_confnode *n,
+ const char *strvalue);
+
+/**
+ * Specific node operation that returns a string identifying the node
+ * type. Called by cfzy_confnode_get_type_str().
+ */
+typedef const char *(confnode_get_type_str_t)(const struct cfzy_confnode *n);
+
+/**
+ * Specific node operation to set user value of a configuration
+ * node. Called by cfzy_confnode_set_uservalue().
+ */
+typedef int (confnode_set_uservalue_t)(struct cfzy_confnode *n,
+ const char *strvalue);
+
+/* all node-specific operations */
+struct cfzy_confnode_ops {
+ confnode_free_t *free; /**< free specific node data */
+ confnode_add_attr_t *add_attr; /**< try to parse specific attr */
+ confnode_close_t *close; /**< close node beeing parsed */
+ confnode_dotconfig_write_t *dotconfig_write; /**< write in dotconfig */
+ confnode_c_hdr_write_t *c_hdr_write; /**< write in C header file */
+ confnode_str2bool_t *str2bool; /**< check strvalue and
+ return boolvalue */
+ confnode_get_type_str_t *get_type_str; /**< return type string */
+ confnode_set_uservalue_t *set_uservalue; /**< check and set user val */
+};
+
+#endif /* _CFZY_CONFNODE_OPS_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_confnode.h"
+
+/* this node is always enabled whatever the value */
+static int root_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ (void)n;
+
+ /* should not happen */
+ if (value != NULL)
+ return -1;
+
+ return 1;
+}
+
+static struct cfzy_confnode_ops root_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = root_str2bool,
+ .c_hdr_write = NULL,
+ .dotconfig_write = NULL,
+ .get_type_str = NULL,
+ .set_uservalue = NULL,
+};
+
+/* Create a new root node */
+struct cfzy_confnode *cfzy_confnode_root_new(struct cfzy_conftree *conftree)
+{
+ struct cfzy_confnode *n;
+
+ n = cfzy_confnode_alloc(conftree);
+ if (n == NULL)
+ return NULL;
+
+ n->ops = &root_ops;
+ n->flags = CFZY_F_IS_ROOT |
+ CFZY_F_INVISIBLE |
+ CFZY_F_NO_SET_VALUE |
+ CFZY_F_NO_NAME |
+ CFZY_F_NO_SET_DEFAULT |
+ CFZY_F_NO_SET_DEPS;
+
+ n->name = strdup("root");
+ if (n->name == NULL)
+ return NULL;
+
+ return n;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "cfzy_confnode.h"
+
+/* Return a string identifying the node type ("config", "menuconfig",
+ * "choice", ...) */
+static const char *strconfig_get_type_str(const struct cfzy_confnode *n)
+{
+ (void)n;
+ return "strconfig";
+}
+
+static int strconfig_str2bool(const struct cfzy_confnode *n,
+ const char *value)
+{
+ (void)n;
+
+ if (value == NULL || !strcmp("", value))
+ return 0;
+
+ return 1;
+}
+
+static struct cfzy_confnode_ops strconfig_ops = {
+ .free = NULL,
+ .add_attr = NULL,
+ .close = NULL,
+ .str2bool = strconfig_str2bool,
+ .dotconfig_write = NULL,
+ .c_hdr_write = NULL,
+ .get_type_str = strconfig_get_type_str,
+ .set_uservalue = NULL,
+};
+
+/* Create a new node */
+enum cfzy_parse_return
+cfzy_confnode_strconfig_new(struct cfzy_confnode *n,
+ const struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ if (strcmp(tok->str, "strconfig") || tklist->n_token != 2)
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ n->ops = &strconfig_ops;
+ n->flags = CFZY_F_QUOTE_VAL;
+
+ n->name = strdup(tok->str);
+ if (n->name == NULL)
+ return ERROR;
+
+ n->default_value = strdup("");
+ if (n->default_value == NULL) {
+ free(n->name);
+ n->name = NULL;
+ return ERROR;
+ }
+
+ return SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "cfzy_log.h"
+#include "cfzy_list.h"
+#include "cfzy_htable.h"
+#include "cfzy_confnode.h"
+#include "cfzy_conftree.h"
+#include "cfzy_conftree_parser.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("conftree", level, fmt, ##args)
+
+/* Parse a configuration tree and add all the nodes in the
+ * hashtable. Return the number of nodes or -1 on error. */
+static int conftree_fill_htable(struct cfzy_conftree *conftree,
+ struct cfzy_confnode *n)
+{
+ struct cfzy_confnode *c;
+ int ret, count;
+
+ if (n->name != NULL) {
+ if (cfzy_htable_lookup(conftree->nodes_htable, n->name) != NULL) {
+ LOG(ERR, "duplicate symbol <%s>\n", n->name);
+ return -1;
+ }
+
+ if (cfzy_htable_add(conftree->nodes_htable, n->name, n) < 0)
+ return -1;
+ }
+ count = 1; /* count the nodes recursively */
+
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ ret = conftree_fill_htable(conftree, c);
+ if (ret < 0)
+ return -1;
+ count += ret;
+ }
+
+ return count;
+}
+
+/* Parse a configuration tree and add all the nodes in the hashtable */
+static int conftree_generate_deplist(struct cfzy_confnode *n)
+{
+ struct cfzy_confnode *c;
+
+ n->node_deps = cfzy_confnode_get_deplist(n);
+ if (n->node_deps == NULL)
+ return -1;
+
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (conftree_generate_deplist(c) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Parse a configuration tree and add all the nodes in the
+ * hashtable. Return the number of nodes in the prio_list. */
+static int conftree_fill_prio_list(struct cfzy_conftree *conftree,
+ struct cfzy_confnode *n)
+{
+ struct cfzy_list_elt *e;
+ struct cfzy_confnode *c;
+ int ok = 1;
+ int count = 0, ret;
+
+ if (n->in_prio_list == 1) {
+ count = 1;
+ }
+ else {
+ /* if the node is not in prio_list, check if all
+ * prerequisites are in prio list, and add in the
+ * list */
+ TAILQ_FOREACH(e, n->node_deps, next) {
+ c = e->ptr;
+ if (c->in_prio_list == 0) {
+ ok = 0;
+ break;
+ }
+ }
+ if (ok == 1) {
+ TAILQ_INSERT_TAIL(&conftree->prio_list, n, prio_next);
+ count = 1;
+ n->in_prio_list = 1;
+ }
+ }
+
+ /* process children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ ret = conftree_fill_prio_list(conftree, c);
+ if (ret < 0)
+ return -1;
+ count += ret;
+ }
+
+ return count;
+}
+
+/* create a new configuration tree from filename */
+struct cfzy_conftree *cfzy_conftree_new(const char *filename)
+{
+ struct cfzy_conftree *conftree;
+ int node_count, prio_count, prev;
+
+ LOG(INFO, "Open conftree <%s>\n", filename);
+
+ conftree = malloc(sizeof(*conftree));
+ if (conftree == NULL)
+ return NULL;
+ memset(conftree, 0, sizeof(*conftree));
+
+ conftree->path = strdup(filename);
+ if (conftree->path == NULL) {
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+
+ conftree->root = cfzy_confnode_root_new(conftree);
+ if (conftree->root == NULL) {
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+
+ /* parse the configuration tree file */
+ if (cfzy_conftree_parse(filename, conftree) < 0) {
+ LOG(ERR, "cannot parse configuration tree\n");
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+
+ conftree->nodes_htable = cfzy_htable_alloc();
+ if (conftree->nodes_htable == NULL) {
+ LOG(ERR, "cannot allocate conftree htable\n");
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+
+ /* fill a htable indexed by node name */
+ node_count = conftree_fill_htable(conftree, conftree->root);
+ if (node_count < 0) {
+ LOG(ERR, "cannot fill conftree htable\n");
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+ conftree->count = node_count;
+
+ /* for each node, generate the list of prerequisite nodes */
+ if (conftree_generate_deplist(conftree->root) < 0) {
+ LOG(ERR, "cannot generate dep list\n");
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+
+ /* generate a list ordered by node priority: if Node1 depends
+ * on Node2, then Node1 is located after Node2 in the list. */
+ TAILQ_INIT(&conftree->prio_list);
+ prev = 0;
+ while (1) {
+ prio_count = conftree_fill_prio_list(conftree, conftree->root);
+ if (prio_count < 0) {
+ LOG(ERR, "cannot generate prio list\n");
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+ if (prio_count == node_count)
+ break;
+ if (prio_count == prev) {
+ LOG(ERR, "circular dependency in conf tree\n");
+ cfzy_conftree_free(conftree);
+ return NULL;
+ }
+ prev = prio_count;
+ }
+
+ return conftree;
+}
+
+/* free a configuration tree */
+void cfzy_conftree_free(struct cfzy_conftree *conftree)
+{
+ if (conftree->path != NULL)
+ free(conftree->path);
+ if (conftree->nodes_htable != NULL)
+ cfzy_htable_free(conftree->nodes_htable, NULL);
+ if (conftree->root != NULL)
+ cfzy_confnode_free(conftree->root);
+ free(conftree);
+}
+
+int cfzy_conftree_dump(const struct cfzy_conftree *conftree,
+ const char *filename)
+{
+ FILE *f;
+
+ f = fopen(filename, "w");
+ if (f == NULL) {
+ LOG(ERR, "Cannot open <%s>: %s\n", filename, strerror(errno));
+ return -1;
+ }
+
+ if (cfzy_confnode_dump(conftree->root, f,
+ CFZY_DUMP_MODE_FULL_RECURSIVE) < 0) {
+ LOG(ERR, "Cannot dump confnode tree\n");
+ fclose(f);
+ return -1;
+ }
+
+ fclose(f);
+ return 0;
+}
+
+int cfzy_conftree_evaluate(struct cfzy_conftree *conftree)
+{
+ struct cfzy_confnode *n;
+
+ TAILQ_FOREACH(n, &conftree->prio_list, prio_next) {
+ if (cfzy_confnode_evaluate(n) < 0) {
+ LOG(ERR, "Cannot evaluate conftree\n");
+ return -1;
+ }
+ LOG(DEBUG, "eval %s -> %s\n", n->name, n->effective_value);
+ }
+
+ return 0;
+}
+
+/* same than strcmp() but allow string to be NULL */
+static int strcmp2(const char *s1, const char *s2)
+{
+ if (s1 == NULL && s2 == NULL)
+ return 0;
+ if (s1 == NULL)
+ return -1;
+ if (s2 == NULL)
+ return 1;
+ return strcmp(s1, s2);
+}
+
+static int __filter(struct cfzy_confnode *n, struct cfzy_list_head *node_list,
+ int flags)
+{
+ int add_it = 0;
+ struct cfzy_confnode *c;
+
+ if ((flags & CFZY_FILTER_F_USR_UNSET) && n->user_value == NULL)
+ add_it = 1;
+ else if ((flags & CFZY_FILTER_F_EFF_UNSET) && n->effective_value == NULL)
+ add_it = 1;
+ else if ((flags & CFZY_FILTER_F_USR_CHANGED) &&
+ strcmp2(n->user_value, n->old_user_value))
+ add_it = 1;
+ else if ((flags & CFZY_FILTER_F_EFF_CHANGED) &&
+ strcmp2(n->effective_value, n->old_effective_value))
+ add_it = 1;
+
+ if (add_it == 1) {
+ if (cfzy_list_add_tail(node_list, n) < 0) {
+ LOG(ERR, "cannot add node in list\n");
+ return -1;
+ }
+ }
+
+ /* children nodes */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (__filter(c, node_list, flags) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Get a list of nodes matching conditions (for instance the nodes
+ * that have no user value) */
+struct cfzy_list_head *
+cfzy_conftree_filter(struct cfzy_conftree *conftree, int flags)
+{
+ struct cfzy_list_head *node_list = NULL;
+
+ node_list = cfzy_list_alloc();
+ if (node_list == NULL) {
+ LOG(ERR, "cannot allocate node list\n");
+ return NULL;
+ }
+
+ if (__filter(conftree->root, node_list, flags) < 0) {
+ LOG(ERR, "cannot filter nodes\n");
+ cfzy_list_free(node_list, NULL);
+ return NULL;
+ }
+
+ return node_list;
+}
+
+static int __save_values(struct cfzy_confnode *n)
+{
+ struct cfzy_confnode *c;
+
+ /* duplicate user value */
+ if (n->old_user_value != NULL) {
+ free(n->old_user_value);
+ n->old_user_value = NULL;
+ }
+ if (n->user_value != NULL) {
+ n->old_user_value = strdup(n->user_value);
+ if (n->old_user_value == NULL) {
+ LOG(ERR, "cannot duplicate value\n");
+ return -1;
+ }
+ }
+
+ /* duplicate effective value */
+ if (n->old_effective_value != NULL) {
+ free(n->old_effective_value);
+ n->old_effective_value = NULL;
+ }
+ if (n->effective_value != NULL) {
+ n->old_effective_value = strdup(n->effective_value);
+ if (n->old_effective_value == NULL) {
+ LOG(ERR, "cannot duplicate value\n");
+ return -1;
+ }
+ }
+
+ /* do the same on children */
+ TAILQ_FOREACH(c, &n->children, child_next) {
+ if (__save_values(c) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int cfzy_conftree_save_values(struct cfzy_conftree *conftree)
+{
+ return __save_values(conftree->root);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Confizery configuration tree
+ *
+ * This module defines a structure cfzy_conftree that stores the full
+ * configuration tree (composed of cfzy_confnode structures), and some
+ * meta data like the number of nodes in the tree, a hash table used
+ * to do a node lookup by its name, the path of the configuration tree
+ * file, ...
+ */
+
+#ifndef _CFZY_CONFTREE_H_
+#define _CFZY_CONFTREE_H_
+
+#include "cfzy_confnode.h"
+
+struct cfzy_htable;
+
+/**
+ * Structure storing the config tree
+ */
+struct cfzy_conftree {
+ char *path; /**< path of conftree file */
+ struct cfzy_confnode *root; /**< pointer to root node */
+ int count; /**< number of nodes */
+ struct cfzy_htable *nodes_htable; /**< htable of nodes, indexed by name */
+ struct cfzy_confnode_list prio_list; /**< ordered list of nodes */
+};
+
+/**
+ * Create a new configuration tree
+ *
+ * Parse a configuration tree and allocate a new conftree
+ * structure. The structure must be freed with cfzy_conftree_free().
+ *
+ * @param filename
+ * name of the configuration tree file
+ * @return
+ * the allocated conftree structure, or NULL on error
+ */
+struct cfzy_conftree *cfzy_conftree_new(const char *filename);
+
+/**
+ * Free a configuration tree structure
+ *
+ * Free a configuration tree structure previously allocated with
+ * cfzy_conftree_new().
+ *
+ * @param conftree
+ * the configuration tree structure to be freed
+ */
+void cfzy_conftree_free(struct cfzy_conftree *conftree);
+
+/**
+ * Dump a configuration tree structure in a file
+ *
+ * @param conftree
+ * the configuration tree structure to be freed
+ * @param filename
+ * file where conf should be dumped
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_conftree_dump(const struct cfzy_conftree *conftree,
+ const char *filename);
+
+/**
+ * Evaluate a configuration tree structure
+ *
+ * Parse all nodes following priority list and set the effective_value
+ * field by calling cfzy_confnode_evaluate() which takes care of
+ * default values, user values, and dependencies.
+ *
+ * @param conftree
+ * the configuration tree structure
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_conftree_evaluate(struct cfzy_conftree *conftree);
+
+/**
+ * Save values of configuration tree
+ *
+ * For each node, copy the effective_value field in
+ * old_effective_value and the user_value field in old_user_value.
+ * These values can be used later with cfzy_conftree_filter() to
+ * compare the old values with the new ones.
+ *
+ * @param conftree
+ * the configuration tree structure
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_conftree_save_values(struct cfzy_conftree *conftree);
+
+/* flags to be used with cfzy_conftree_filter() */
+#define CFZY_FILTER_F_USR_UNSET 0x01
+#define CFZY_FILTER_F_EFF_UNSET 0x02
+#define CFZY_FILTER_F_USR_CHANGED 0x04
+#define CFZY_FILTER_F_EFF_CHANGED 0x08
+
+/**
+ * Get a list of nodes matching conditions
+ *
+ * Return the list of nodes in configuration tree that match
+ * conditions. Example: cfzy_conftree_filter(contree,
+ * CFZY_FILTER_F_USR_UNSET) will return all nodes that have no user
+ * value (set to NULL).
+ *
+ * @param conftree
+ * the configuration tree structure
+ * @param flags
+ * list of conditions (CFZY_FILTER_F_*)
+ * @return
+ * 0 on success, negative on error
+ */
+struct cfzy_list_head *
+cfzy_conftree_filter(struct cfzy_conftree *conftree, int flags);
+
+#endif /* _CFZY_CONFTREE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <libgen.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include "cfzy_log.h"
+#include "cfzy_string.h"
+#include "cfzy_expr.h"
+#include "cfzy_htable.h"
+#include "cfzy_conftree.h"
+#include "cfzy_confnode.h"
+#include "cfzy_conftree_parser.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("conftree_parser", level, fmt, ##args)
+
+/*
+ * Structure that stores the state of the configuration tree parser.
+ */
+struct conftree_parse_status {
+ const char *filename; /* name of file beeing parsed */
+ FILE *f; /* pointer to file beeing parsed */
+ int linenum; /* current line number in file */
+ char *curline; /* pointer to current line, or
+ NULL if no current line */
+ struct cfzy_token_list *tklist; /* pointer to current token
+ list of NULL if no current line */
+ struct cfzy_confnode *parent; /* current parent node */
+};
+
+static int __cfzy_conftree_parse(const char *filename,
+ struct cfzy_confnode **pparent);
+
+/* return true if line is empty or contains only spaces/comments */
+static int line_is_empty(const char *buf)
+{
+ while (*buf != '\0' && *buf != '#') {
+ if (!isspace(*buf))
+ return 0;
+ buf++;
+ }
+ return 1;
+}
+
+/*
+ * Add a token in the tklist structure given as argument.
+ *
+ * 'buf': pointer to the beginning of line buffer.
+ * 'offset': offset in the line where start parsing
+ *
+ * Return the number of consumed bytes if a token is found
+ * Return 0 if there is no more token
+ * Return -1 on error
+ */
+static int
+append_token(struct cfzy_token_list *tklist, const char *buf, int offset)
+{
+ struct cfzy_token *tok;
+ const char *s;
+ unsigned len, space_len = 0;
+ char *retbuf;
+
+ /* skip spaces */
+ s = buf + offset;
+ while (*s != '\0' && isspace(*s))
+ s++;
+ if (*s == '\0' || *s == '#')
+ return 0;
+
+ tok = malloc(sizeof(struct cfzy_token));
+ if (tok == NULL) {
+ LOG(ERR, "not enough memory\n");
+ return -1;
+ }
+
+ space_len = s - buf - offset;
+ tok->offset = s - buf;
+
+ /* if it's a quote, unquote the string */
+ if (*s == '"' || *s == '\'') {
+ retbuf = cfzy_string_unquote(s, &len);
+ if (retbuf == NULL)
+ goto free;
+ }
+ /* else wait a space */
+ else {
+ retbuf = strdup(s);
+ if (retbuf == NULL) {
+ LOG(ERR, "not enough memory\n");
+ goto free;
+ }
+
+ for (len = 0;
+ s[len] != '\0' && !isspace(s[len]) && s[len] != '#';
+ len ++)
+ ;
+
+ retbuf[len] = '\0';
+ }
+
+ /* fill token structure and append it in tklist */
+ tok->str = retbuf;
+ TAILQ_INSERT_TAIL(&tklist->list, tok, next);
+ tklist->n_token ++;
+
+ return len + space_len;
+
+ free:
+ free(tok);
+ return -1;
+}
+
+/* free a token list previously allocated with tokenize() */
+static void free_token_list(struct cfzy_token_list *tklist)
+{
+ struct cfzy_token *tok;
+
+ while ((tok = TAILQ_FIRST(&tklist->list)) != NULL) {
+ TAILQ_REMOVE(&tklist->list, tok, next);
+ free(tok->str);
+ free(tok);
+ }
+ free(tklist);
+}
+
+/*
+ * Parse the line contained in buffer 'linebuf'. This function fills a
+ * tklist structure, composed of several tokens.
+ * Return the tklist pointer on success or NULL on error.
+ */
+static struct cfzy_token_list *tokenize(const char *linebuf)
+{
+ struct cfzy_token_list *tklist;
+ int ret, offset = 0;
+
+ tklist = malloc(sizeof(struct cfzy_token_list));
+ if (tklist == NULL) {
+ LOG(ERR, "not enough memory\n");
+ return NULL;
+ }
+
+ memset(tklist, 0, sizeof(struct cfzy_token_list));
+ TAILQ_INIT(&tklist->list);
+
+ /* read tokens from buf and append it to tklist structure */
+ do {
+ ret = append_token(tklist, linebuf, offset);
+ if (ret < 0) {
+ free_token_list(tklist);
+ return NULL;
+ }
+ offset += ret;
+ } while (ret != 0);
+
+ tklist->linebuf = linebuf;
+ return tklist;
+}
+
+/* duplicate buf, replacing variables like $(VAR) by their values */
+char *replace_variables(const char *buf)
+{
+ char *s, *buf_dup, *var;
+ const char *start;
+ char *out = NULL;
+ char c;
+
+ buf_dup = strdup(buf);
+ if (buf_dup == NULL) {
+ LOG(ERR, "not enough memory\n");
+ return NULL;
+ }
+
+ s = buf_dup;
+
+ for ( ; s[0] != '\0' ; s++) {
+
+ start = s;
+
+ /* wait a "$(" */
+ for ( ; s[0] != '\0' && (s[0] != '$' || s[1] != '('); s++);
+ c = s[0];
+ s[0] = '\0';
+ if (cfzy_string_asprintf(&out, "%s", start) < 0)
+ goto fail;
+
+ if (c == '\0')
+ break;
+
+ s += 2;
+ start = s;
+
+ for ( ; s[0] != '\0' && s[0] != ')'; s++);
+ c = s[0];
+ if (c == '\0')
+ goto fail;
+
+ s[0] = '\0';
+ var = getenv(start);
+
+ if (var != NULL) {
+ if (cfzy_string_asprintf(&out, var) < 0)
+ goto fail;
+ }
+
+ }
+
+ free(buf_dup);
+ return out;
+
+ fail:
+ free(buf_dup);
+ if (out != NULL)
+ free(out);
+ return NULL;
+}
+
+/*
+ * Fill state structure with current line. If state->curline is
+ * already set, the function does nothing, else it will read a new
+ * line in the file and tokenize it. Return 0 on success, and -1 on
+ * error. If state->curline is still NULL after a call to this
+ * function, we reached the end of the file.
+ */
+static int get_curline(struct conftree_parse_status *state)
+{
+ char buf[BUFSIZ];
+ int line_len;
+ char *line;
+
+ /* nothing to do */
+ if (state->curline != NULL)
+ return 0;
+
+ state->curline = fgets(buf, sizeof(buf), state->f);
+
+ /* end of file */
+ if (state->curline == NULL) {
+ LOG(DEBUG, "EOF\n");
+ return 0;
+ }
+
+ state->linenum ++;
+ line_len = strlen(state->curline);
+
+ /* if line ends with '\', get another line */
+ while (line_len >= 2 &&
+ state->curline[line_len - 1] == '\n' &&
+ state->curline[line_len - 2] == '\\') {
+ if (line_len >= (int)sizeof(buf) - 1)
+ break;
+
+ line = fgets(buf + line_len - 2,
+ sizeof(buf) - line_len - 2, state->f);
+ if (line == NULL) /* EOF */
+ break;
+
+ line_len = strlen(state->curline);
+ state->linenum ++;
+ }
+
+ state->curline = replace_variables(buf);
+ if (state->curline == NULL) {
+ LOG(ERR, "Cannot eval variables\n");
+ return -1;
+ }
+
+ state->tklist = tokenize(state->curline);
+ if (state->tklist == NULL) {
+ LOG(ERR, "Cannot parse line\n");
+ free(state->curline);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function is called when we processed the current line. It will
+ * free allocated memory (token list) and set state->curline to NULL.
+ */
+static void eat_curline(struct conftree_parse_status *state)
+{
+ if (state->curline != NULL) {
+ free(state->curline);
+ state->curline = NULL;
+ }
+ if (state->tklist != NULL) {
+ free_token_list(state->tklist);
+ state->tklist = NULL;
+ }
+}
+
+/* Try to parse node help. Return NO_MATCH if the current line does
+ * not match the 'help' token, SUCCESS if help is successfully parsed,
+ * or ERROR on error. */
+static enum cfzy_parse_return
+parse_help(struct cfzy_confnode *n, struct conftree_parse_status *state)
+{
+ struct cfzy_token_list *tklist;
+ struct cfzy_token *tok;
+ char *buf;
+
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ buf = state->curline;
+
+ /* EOF */
+ if (buf == NULL)
+ return NO_MATCH;
+
+ /* we want 1 token */
+ tklist = state->tklist;
+ if (tklist->n_token != 1)
+ return NO_MATCH;
+
+ /* we want a "help" token */
+ tok = TAILQ_FIRST(&tklist->list);
+ if (strcmp(tok->str, "help") && strcmp(tok->str, "---help---"))
+ return NO_MATCH;
+
+ LOG(INFO, "parse help\n");
+ eat_curline(state);
+
+ /* parse help content */
+ while (1) {
+
+ /* read next line */
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ buf = state->curline;
+
+ /* EOF */
+ if (buf == NULL)
+ return SUCCESS;
+
+ /* skip empty lines */
+ if (line_is_empty(buf)) {
+ eat_curline(state);
+ continue;
+ }
+
+ /* if line does not start with space, this is this end
+ of help parsing */
+ if (!isspace(*buf))
+ return SUCCESS;
+
+ /* append string in buffer, stripping starting spaces */
+ tok = TAILQ_FIRST(&state->tklist->list);
+ if (cfzy_string_asprintf(&n->help, "%s",
+ buf + tok->offset) < 0)
+ return ERROR;
+
+ eat_curline(state);
+ }
+}
+
+/* Try to parse the "source" command. Return NO_MATCH if the current
+ * line does not match the "source" token, SUCCESS if the file is
+ * successfully sourced, or ERROR on error. */
+static enum cfzy_parse_return source_file(struct conftree_parse_status *state)
+{
+ struct cfzy_token_list *tklist;
+ struct cfzy_token *tok;
+
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ /* EOF */
+ if (state->curline == NULL)
+ return NO_MATCH;
+
+ tklist = state->tklist;
+ tok = TAILQ_FIRST(&tklist->list);
+
+ /* syntax is: source FILE_NAME */
+ if (tklist->n_token != 2 || strcmp(tok->str, "source"))
+ return NO_MATCH;
+
+ tok = TAILQ_NEXT(tok, next);
+ LOG(INFO, "source <%s>\n", tok->str);
+
+ /* parse new file */
+ if (__cfzy_conftree_parse(tok->str, &state->parent) < 0) {
+ LOG(ERR, "error in sourced file\n");
+ return ERROR;
+ }
+
+ eat_curline(state);
+ return SUCCESS;
+}
+
+/* Try to create a new node command ("config", "menuconfig", "choice",
+ * "if", ...). Return NO_MATCH if the current line is not a new node
+ * command, SUCCESS if a new node is created, or ERROR on error. This
+ * function does not parse the attributes of the node but only the
+ * first line. */
+static enum cfzy_parse_return
+new_node(struct conftree_parse_status *state, struct cfzy_confnode **nodep)
+{
+ struct cfzy_token_list *tklist;
+ enum cfzy_parse_return ret;
+
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ /* EOF */
+ if (state->curline == NULL)
+ return NO_MATCH;
+
+ tklist = state->tklist;
+
+ *nodep = cfzy_confnode_alloc(state->parent->conftree);
+ if (*nodep == NULL) {
+ LOG(ERR, "cannot allocate node\n");
+ return ERROR;
+ }
+ (*nodep)->parent = state->parent;
+
+ ret = cfzy_confnode_choice_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_choiceconfig_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_comment_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_config_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_if_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_intconfig_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_menu_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_menuconfig_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+ ret = cfzy_confnode_strconfig_new(*nodep, tklist);
+ if (ret != NO_MATCH)
+ return ret;
+
+ cfzy_confnode_free(*nodep);
+ return NO_MATCH;
+}
+
+/* Try to create a new node with all its attributes and help. Return
+ * NO_MATCH if the current line is not a new node command, SUCCESS if
+ * a new node is created, or ERROR on error. */
+static enum cfzy_parse_return
+parse_confnode(struct conftree_parse_status *state)
+{
+ char *buf;
+ struct cfzy_confnode *n;
+ enum cfzy_parse_return ret;
+ struct cfzy_token_list *tklist;
+
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ buf = state->curline;
+
+ /* EOF */
+ if (buf == NULL)
+ return NO_MATCH;
+
+ /* line must not start with a space */
+ if (isspace(*buf))
+ return NO_MATCH;
+
+ /* if it's a new node command */
+ ret = new_node(state, &n);
+ if (ret == ERROR || ret == NO_MATCH)
+ return ret;
+
+ /* save parsing infos */
+ n->filename = strdup(state->filename);
+ if (n->filename == NULL) {
+ cfzy_confnode_free(n);
+ return ERROR;
+ }
+ n->linenum = state->linenum;
+
+ TAILQ_INSERT_TAIL(&state->parent->children, n, child_next);
+ eat_curline(state);
+
+ /* parse node attributes */
+ while (1) {
+
+ /* fill state structure with current or next line */
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ buf = state->curline;
+ tklist = state->tklist;
+
+ /* EOF */
+ if (buf == NULL)
+ return SUCCESS;
+
+ /* skip empty lines */
+ if (line_is_empty(buf)) {
+ eat_curline(state);
+ continue;
+ }
+
+ /* if line does not start with space, this node is
+ * parsed, break */
+ if (!isspace(*buf))
+ break;
+
+ /* check if it's a node attribute */
+ ret = cfzy_confnode_add_attr(n, tklist);
+ if (ret == ERROR)
+ return ERROR;
+ if (ret == SUCCESS) {
+ eat_curline(state);
+ continue;
+ }
+
+ /* check if it's a help indication */
+ ret = parse_help(n, state);
+ if (ret == ERROR)
+ return ERROR;
+ if (ret == SUCCESS)
+ break;
+
+ /* the attribute is invalid */
+ LOG(ERR, "invalid node attribute\n");
+ return ERROR;
+ }
+
+ /* enter in a new node */
+ if (n->flags & CFZY_F_IS_DIR)
+ state->parent = n;
+
+ return SUCCESS;
+}
+
+/* Try to match the command that closes the current parent node, if
+ * it's a directory. Return NO_MATCH if the line does not match this
+ * command, SUCCESS if the parent node is closed (in this case,
+ * state->parent is updated), or ERROR on error. */
+static enum cfzy_parse_return
+close_dir(struct conftree_parse_status *state)
+{
+ struct cfzy_token_list *tklist;
+ struct cfzy_token *tok;
+ struct cfzy_confnode *n;
+
+ n = state->parent;
+ if ((n->flags & CFZY_F_IS_DIR) == 0)
+ return NO_MATCH;
+
+ /* fill state structure with current or next line */
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ /* EOF */
+ if (state->curline == NULL)
+ return NO_MATCH;
+
+ tklist = state->tklist;
+ if (tklist->n_token != 1)
+ return NO_MATCH;
+
+ /* token must be "endchoice", "endmenu", "endif", ... */
+ tok = TAILQ_FIRST(&tklist->list);
+ if (strncmp(tok->str, "end", 3))
+ return NO_MATCH;
+ if (strcmp(tok->str + 3, cfzy_confnode_get_type_str(n)))
+ return NO_MATCH;
+ if (cfzy_confnode_close(n) < 0) {
+ LOG(ERR, "cannot close node\n");
+ return ERROR;
+ }
+
+ state->parent = n->parent;
+ return SUCCESS;
+}
+
+/*
+ * Parse the configuration tree by reading the file stored in the
+ * 'state' structure. Return SUCCESS or ERROR.
+ */
+static enum cfzy_parse_return parse_conftree(struct conftree_parse_status *state)
+{
+ enum cfzy_parse_return ret;
+ char *buf;
+
+ /* browse all lines of the file */
+ while (1) {
+
+ /* fill state structure with current or next line */
+ if (get_curline(state) < 0)
+ return ERROR;
+
+ buf = state->curline;
+
+ /* EOF */
+ if (buf == NULL)
+ break;
+
+ LOG(DEBUG, "parent=%s: %s",
+ cfzy_confnode_name(state->parent), buf);
+
+ /* skip empty / comments lines */
+ if (line_is_empty(buf)) {
+ eat_curline(state);
+ continue;
+ }
+
+ /* if the line does not start with a space, syntax error */
+ if (isspace(*buf)) {
+ LOG(ERR, "line starts with space\n");
+ return ERROR;
+ }
+
+ /* if it's a source command, parse the new file */
+ ret = source_file(state);
+ if (ret == ERROR)
+ return ERROR;
+ if (ret == SUCCESS)
+ continue;
+
+ /* if the command closes a menu, choice, ... */
+ ret = close_dir(state);
+ if (ret == ERROR)
+ return ERROR;
+ if (ret == SUCCESS) {
+ eat_curline(state);
+ continue;
+ }
+
+ /* parse new node */
+ ret = parse_confnode(state);
+ if (ret == ERROR)
+ return ERROR;
+ if (ret == SUCCESS)
+ continue;
+
+ /* invalid command */
+ LOG(ERR, "invalid command\n");
+ return ERROR;
+ }
+
+ return SUCCESS;
+}
+
+/*
+ * Parse the configuration tree by reading "filename", knowing that
+ * the current parent node is pointed by pparent (which can be
+ * modified at the end of the function). This function will fill open
+ * the file, and fill a state structure for the parser, then call
+ * parse_conftree(). Return 0 on success and -1 on error.
+ */
+static int
+__cfzy_conftree_parse(const char *filename, struct cfzy_confnode **pparent)
+{
+ struct conftree_parse_status state;
+ FILE *f = NULL;
+ char old_cwd_buf[PATH_MAX];
+ char *cwd_buf = NULL, *cwd_ptr = NULL, *old_cwd = NULL;
+ int ret;
+
+ memset(&state, 0, sizeof(state));
+
+ old_cwd = getcwd(old_cwd_buf, sizeof(old_cwd_buf));
+ if (old_cwd == NULL) {
+ LOG(ERR, "getcwd failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ LOG(ERR, "cannot find file <%s>\n", filename);
+ goto fail;
+ }
+
+ cwd_buf = strdup(filename);
+ if (cwd_buf == NULL) {
+ LOG(ERR, "not enough memory\n");
+ goto fail;
+ }
+ cwd_ptr = dirname(cwd_buf);
+ ret = chdir(cwd_ptr);
+ if (ret < 0) {
+ LOG(ERR, "chdir failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ state.filename = filename;
+ state.f = f;
+ state.linenum = 0;
+ state.parent = *pparent;
+ state.curline = NULL;
+
+ /* browse all lines of the file */
+ ret = parse_conftree(&state);
+ if (ret != SUCCESS) {
+ /* node will be freed by caller (cfzy_conftree_new) */
+ LOG(ERR, "parse error at %s:%d\n", filename, state.linenum);
+ LOG(ERR, ">>> %s", state.curline);
+ goto fail;
+ }
+
+ eat_curline(&state); /* will free token_list */
+ fclose(f);
+ free(cwd_buf);
+ if (chdir(old_cwd) < 0) {
+ LOG(ERR, "chdir back to <%s> failed: %s\n",
+ old_cwd, strerror(errno));
+ return -1;
+ }
+
+ *pparent = state.parent;
+ return 0;
+
+ fail:
+ if (state.f != NULL)
+ eat_curline(&state); /* will free token_list */
+ if (f != NULL)
+ fclose(f);
+ if (cwd_buf != NULL)
+ free(cwd_buf);
+ if (old_cwd != NULL)
+ if (chdir(old_cwd) < 0)
+ LOG(ERR, "chdir back to <%s> failed: %s\n",
+ old_cwd, strerror(errno));
+
+ return -1;
+}
+
+/* External api for parsing a new configuration tree file. Return 0 on
+ * success and -1 on error. */
+int cfzy_conftree_parse(const char *filename, struct cfzy_conftree *conftree)
+{
+ int ret;
+ struct cfzy_confnode *parent = conftree->root;
+
+ ret = __cfzy_conftree_parse(filename, &parent);
+ if (ret < 0)
+ return ret;
+
+ if (parent != conftree->root) {
+ LOG(ERR, "Node <%s> not closed properly\n",
+ cfzy_confnode_name(parent));
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Confizery configuration tree parser
+ *
+ * This modules provides an API to parse the configuration tree file
+ * (equivalent to Kconfig file in linux terminology) which describes
+ * the structure of the tree, the option list, the dependencies, the
+ * default values...
+ */
+
+
+#ifndef _CFZY_CONFTREE_PARSER_H_
+#define _CFZY_CONFTREE_PARSER_H_
+
+#include <sys/queue.h>
+
+struct cfzy_conftree;
+
+/**
+ * Return value for some parsing functions.
+ */
+enum cfzy_parse_return {
+ SUCCESS,
+ NO_MATCH,
+ ERROR,
+};
+
+/**
+ * This is the structure defining a token. It is used by the
+ * configuration tree parser. A token is either a word or a string
+ * surrounded by double quotes.
+ */
+struct cfzy_token {
+ TAILQ_ENTRY(cfzy_token) next; /**< pointer to next token */
+ char *str; /**< string */
+ unsigned offset; /**< offset in line */
+};
+
+/**
+ * A list of token, and a pointer to the initial line buffer
+ */
+struct cfzy_token_list {
+ TAILQ_HEAD(, cfzy_token) list; /**< list of tokens */
+ unsigned n_token; /**< number of tokens */
+ const char *linebuf; /**< the line buffer */
+};
+
+/**
+ * Parse configuration tree file and fill the conftree
+ *
+ * This function is called by cfzy_conftree_new() to fill the newly
+ * allocated tree.
+ *
+ * @param filename
+ * path to configuration tree file
+ * @param conftree
+ * an empty configuration tree
+ * @return
+ * 0 on success, or negative on error
+ */
+int cfzy_conftree_parse(const char *filename, struct cfzy_conftree *conftree);
+
+#endif /* _CFZY_CONFTREE_PARSER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "cfzy_log.h"
+#include "cfzy_htable.h"
+#include "cfzy_string.h"
+#include "cfzy_file.h"
+#include "cfzy_conftree.h"
+#include "cfzy_confnode.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("dotconfig", level, fmt, ##args)
+
+/* Allocate and return string containing the value of the
+ * option. Buffer must point to the option (after the '=' in the
+ * .config), and it can be quoted. The string must be freed by the
+ * user. */
+static char *dotconfig_get_optval(const char *buf)
+{
+ const char *s;
+ unsigned i, len;
+ char *retbuf;
+
+ /* skip spaces */
+ s = buf;
+ while (*s != '\0' && isspace(*s))
+ s++;
+ if (*s == '\0' || *s == '#')
+ return 0;
+
+ /* if it's a quote, unquote the string */
+ if (*s == '"' || *s == '\'') {
+ retbuf = cfzy_string_unquote(s, &len);
+ }
+ else {
+ retbuf = strdup(s);
+ if (retbuf == NULL)
+ return NULL;
+
+ for (i = 0; s[i] != '\0' && s[i] != '\n' && s[i] != '#'; i ++)
+ ;
+
+ retbuf[i] = '\0';
+ }
+ return retbuf;
+}
+
+/* parse a line of .config: fill the uservalue of nodes in the
+ * conftree structure */
+static int dotconfig_parse_line(struct cfzy_conftree *conftree, const char *line)
+{
+ struct cfzy_confnode *n;
+ char buf[BUFSIZ];
+ char *nodename, *s;
+ char *optval;
+
+ /* copy line in a writable buffer */
+ buf[sizeof(buf) - 1] = '\0';
+ strncpy(buf, line, sizeof(buf) - 1);
+ s = buf;
+
+ /* skip spaces */
+ while (*s != '\0' && isspace(*s))
+ s++;
+
+ /* nothing to do, empty line */
+ if (*s == '\0')
+ return 0;
+
+ /* skip the first "#", expecting "is not set" */
+ if (*s == '#') {
+ s++;
+ while (*s != '\0' && isspace(*s))
+ s++;
+
+ /* nothing to do, it's a comment */
+ if (*s == '\0')
+ return 0;
+
+ /* get node name, ignore invalid names */
+ if (strncmp("CONFIG_", s, strlen("CONFIG_")))
+ return 0;
+ nodename = s + strlen("CONFIG_");
+ s = nodename;
+
+ /* skip spaces */
+ while (*s != '\0' && !isspace(*s))
+ s++;
+
+ /* nothing to do, it's a comment */
+ if (*s == '\0')
+ return 0;
+
+ *s = '\0';
+ s ++;
+
+ /* should end with "is not set", else it's a comment */
+ if (strcmp(s, "is not set\n"))
+ return 0;
+
+ optval = strdup("n");
+ if (optval == NULL)
+ return -1;
+ }
+ else {
+ /* get node name, ignore invalid names */
+ if (strncmp("CONFIG_", s, strlen("CONFIG_")))
+ return -1;
+ nodename = s + strlen("CONFIG_");
+
+ while (*s != '\0' && *s != '=')
+ s++;
+ /* invalid line */
+ if (*s != '=')
+ return -1;
+
+ *s = '\0';
+ optval = dotconfig_get_optval(s + 1);
+ if (optval == NULL)
+ return -1;
+ }
+
+ /* find the node in the conf htable */
+ n = cfzy_htable_lookup(conftree->nodes_htable, nodename);
+ if (n == NULL) {
+ LOG(NOTICE, "ignore unknown symbol <%s>\n", nodename);
+ free(optval);
+ return 0;
+ }
+
+ /* check that value is valid */
+ if (cfzy_confnode_str2bool(n, optval) < 0) {
+ LOG(ERR, "invalid option value %s=<%s>\n", nodename, optval);
+ free(optval);
+ return -1;
+ }
+
+ /* set value in node */
+ LOG(DEBUG, "%s=<%s>\n", nodename, optval);
+ if (cfzy_confnode_set_uservalue(n, optval) < 0) {
+ LOG(ERR, "cannot set value %s=<%s>\n", nodename, optval);
+ free(optval);
+ return -1;
+ }
+
+ free(optval);
+ return 0;
+}
+
+/* parse .config */
+int cfzy_dotconfig_read(struct cfzy_conftree *conftree, const char *filename)
+{
+ FILE *f;
+ char buf[BUFSIZ];
+ int err = 0;
+
+ LOG(INFO, "dotconfig read <%s>\n", filename);
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ LOG(ERR, "cannot find file <%s>\n", filename);
+ return -1;
+ }
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+
+ if (dotconfig_parse_line(conftree, buf) < 0) {
+ err = -1;
+ break;
+ }
+ }
+ fclose(f);
+
+ return err;
+}
+
+/* write .config */
+int cfzy_dotconfig_write(const struct cfzy_conftree *conftree,
+ const char *filename)
+{
+ FILE *f, *tmp_f;
+ const struct cfzy_confnode *c;
+ int ret = 0;
+
+ LOG(INFO, "open old dotconfig <%s>\n", filename);
+
+ /* open old file in read mode */
+
+ f = fopen(filename, "r");
+ if (f == NULL && errno != ENOENT) {
+ printf("cannot open file <%s>: %s\n",
+ filename, strerror(errno));
+ return -1;
+ }
+
+ /* old file exists */
+ if (f != NULL) {
+
+ /* write C header in temp file */
+ tmp_f = tmpfile();
+ if (tmp_f == NULL) {
+ printf("cannot open temp file\n");
+ return -1;
+ }
+
+ /* dump all the children of root node */
+ TAILQ_FOREACH(c, &conftree->root->children, child_next) {
+ ret = cfzy_confnode_dotconfig_write(c, tmp_f);
+ if (ret < 0)
+ break;
+ }
+
+ /* files are the same, nothing to do */
+ if (cfzy_file_compare(f, tmp_f) == 0) {
+ LOG(INFO, "already up to date: <%s>\n", filename);
+ fclose(tmp_f);
+ fclose(f);
+ return 0;
+ }
+
+ fclose(tmp_f);
+ fclose(f);
+ }
+
+ /* reopen the file in write mode */
+
+ LOG(INFO, "write new C header <%s>\n", filename);
+
+ f = fopen(filename, "w");
+ if (f == NULL) {
+ LOG(ERR, "cannot open file <%s>\n", filename);
+ return -1;
+ }
+
+ /* dump all the children of root node */
+ TAILQ_FOREACH(c, &conftree->root->children, child_next) {
+ ret = cfzy_confnode_dotconfig_write(c, f);
+ if (ret < 0)
+ break;
+ }
+
+ fclose(f);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Confizery dotconfig parsing/generation
+ *
+ * This modules provides an API to parse or generate a .config file
+ * from a configuration tree.
+ */
+
+#ifndef _CFZY_DOTCONFIG_H_
+#define _CFZY_DOTCONFIG_H_
+
+/**
+ * Write configuration in a .config file
+ *
+ * Write the configuration values (.config like) in a file. This file
+ * is designed to be sourced in a shell script or in a makefile.
+ *
+ * If the file already exists and has the same content, nothing is
+ * written in it.
+ *
+ * @param conftree
+ * the configuration tree
+ * @param filename
+ * name of the output file
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_dotconfig_write(const struct cfzy_conftree *conftree,
+ const char *filename);
+
+/**
+ * Read and parse a dotconfig configuration file
+ *
+ * Read the configuration values (.config like) from a file, and set
+ * the values in the configuration tree.
+ *
+ * @param conftree
+ * the configuration tree
+ * @param filename
+ * name of the output file
+ * @return
+ * 0 on success, negative on error
+ */
+int cfzy_dotconfig_read(struct cfzy_conftree *conftree, const char *filename);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/queue.h>
+
+#include "cfzy_list.h"
+#include "cfzy_expr.h"
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define debug_printf(args...) fprintf(stderr, args)
+#else
+#define debug_printf(args...) do { } while(0)
+#endif
+
+/*
+ * Return the operator (or the variable name) of the root node of the
+ * given expression.
+ */
+static const char *op_print(const struct cfzy_expr *exp)
+{
+ switch (exp->optype) {
+ case OP_OR:
+ return "||";
+ case OP_AND:
+ return "&&";
+ case OP_EQUAL:
+ return "==";
+ case OP_OBRACKET:
+ return "(";
+ case OP_NOT:
+ return "!";
+ case OP_CBRACKET:
+ return ")";
+ case OP_VAR:
+ return exp->varname;
+ default:
+ return NULL;
+ }
+}
+
+/* recursive function called by cfzy_expr_graph_dump() */
+static void expr_dump_node(FILE *f, const struct cfzy_expr *exp, int level)
+{
+ if (exp == NULL)
+ return;
+
+ fprintf(f, "vertice %d %s:%p\n", level, op_print(exp), exp);
+
+ if (exp->left) {
+ fprintf(f, "edge %p %p\n", exp, exp->left);
+ expr_dump_node(f, exp->left, level + 1);
+ }
+
+ if (exp->right) {
+ fprintf(f, "edge %p %p\n", exp, exp->right);
+ expr_dump_node(f, exp->right, level + 1);
+ }
+}
+
+/* dump an expression graph in a file */
+int cfzy_expr_graph_dump(const char *filename, const struct cfzy_expr *exp)
+{
+ FILE *f;
+
+ f = fopen(filename, "w");
+ if (f == NULL)
+ return -1;
+ expr_dump_node(f, exp, 0);
+ fclose(f);
+ return 0;
+}
+
+/* return true if it's a binary operator */
+static int expr_is_bin_op(const struct cfzy_expr *exp)
+{
+ if (exp->optype == OP_AND ||
+ exp->optype == OP_OR ||
+ exp->optype == OP_EQUAL)
+ return 1;
+ return 0;
+}
+
+/*
+ * Dump the expression 'exp' as a string into the buffer 'buf' of
+ * length 'len'. The string is nul-terminated. Return the number of
+ * written bytes on success (not including \0), else return -1.
+ */
+int cfzy_expr_to_str(const struct cfzy_expr *exp, char *buf, int len)
+{
+ int n, orig_len;
+
+ orig_len = len;
+
+ /* dump left expression if it's a binary operator (in case of
+ * unary operator, we only use the right child) */
+ if (expr_is_bin_op(exp)) {
+ n = cfzy_expr_to_str(exp->left, buf, len);
+ if (n == -1 || n >= len || len <= 0)
+ return -1;
+ buf += n;
+ len -= n;
+ }
+
+ /* dump the operator */
+ if (expr_is_bin_op(exp))
+ n = snprintf(buf, len, " %s ", op_print(exp));
+ else
+ n = snprintf(buf, len, "%s", op_print(exp));
+ if (n == -1 || n >= len || len <= 0)
+ return -1;
+ buf += n;
+ len -= n;
+
+ /* dump the right expression except if it's a variable */
+ if (exp->optype != OP_VAR) {
+ n = cfzy_expr_to_str(exp->right, buf, len);
+ if (n == -1 || n >= len || len <= 0)
+ return -1;
+ buf += n;
+ len -= n;
+ }
+
+ /* close the bracket if needed */
+ if (exp->optype == OP_OBRACKET) {
+ n = snprintf(buf, len, ")");
+ if (n == -1 || n >= len || len <= 0)
+ return -1;
+ buf += n;
+ len -= n;
+ }
+
+ return orig_len - len;
+}
+
+/*
+ * Evaluate an expression. Return -1 on error, else the value of the
+ * expression (greater or equal to 0).
+ */
+int cfzy_expr_eval(const struct cfzy_expr *exp,
+ int (*getvalue)(const char *, void *), void *opaque_arg)
+{
+ switch (exp->optype) {
+ case OP_OR:
+ return cfzy_expr_eval(exp->left, getvalue, opaque_arg) ||
+ cfzy_expr_eval(exp->right, getvalue, opaque_arg);
+ case OP_AND:
+ return cfzy_expr_eval(exp->left, getvalue, opaque_arg) &&
+ cfzy_expr_eval(exp->right, getvalue, opaque_arg);
+ case OP_EQUAL:
+ return cfzy_expr_eval(exp->left, getvalue, opaque_arg) ==
+ cfzy_expr_eval(exp->right, getvalue, opaque_arg);
+ case OP_OBRACKET:
+ return cfzy_expr_eval(exp->right, getvalue, opaque_arg);
+ case OP_NOT:
+ return !cfzy_expr_eval(exp->right, getvalue, opaque_arg);
+ case OP_VAR:
+ /* constants names (used for testing purposes) */
+ if (!strcmp("true", exp->varname))
+ return 1;
+ if (!strcmp("false", exp->varname))
+ return 0;
+ if (getvalue == NULL)
+ return -1;
+ return getvalue(exp->varname, opaque_arg);
+ default:
+ debug_printf("%s(): bad operator\n", __FUNCTION__);
+ return -1;
+ }
+}
+
+/* The argument 'buf' is expression string that must start with an
+ * opening bracket '('. This function returns the len of the
+ * expression contained until we get the closing bracket corresponding
+ * to buf[0]. Return -1 on error. */
+static int get_brac_len(const char *buf)
+{
+ const char *s = buf;
+ int i = 1;
+
+ if (*s != '(')
+ return -1;
+ s++;
+
+ while(*s != '\0' && i != 0) {
+ if (*s == ')')
+ i--;
+ if (*s == '(')
+ i++;
+ s++;
+ }
+ if (i != 0)
+ return -1;
+
+ return s-buf;
+}
+
+/*
+ * Allocate a new expression exp corresponding to the next characters
+ * in "buf". On success, a new expression exp is returned and the
+ * number of eaten characters is set in "eatlen". If the end of the
+ * string is reached, the expression exp contains the OP_EOF
+ * operator. On error, NULL is returned.
+ */
+ static struct cfzy_expr *get_next_op(const char *buf, unsigned *eatlen)
+{
+ struct cfzy_expr *exp;
+ const char *s;
+ unsigned len;
+
+ s = buf;
+ exp = malloc(sizeof(struct cfzy_expr));
+ if (exp == NULL)
+ return NULL;
+ memset(exp, 0, sizeof(*exp));
+
+ switch (s[0]) {
+ case '#':
+ exp->optype = OP_EOF;
+ *eatlen = s - buf + 1;
+ return exp;
+ case '\0':
+ exp->optype = OP_EOF;
+ *eatlen = s - buf + 1;
+ return exp;
+ case '(':
+ exp->optype = OP_OBRACKET;
+ *eatlen = s - buf + 1;
+ return exp;
+ case ')':
+ exp->optype = OP_CBRACKET;
+ *eatlen = s - buf + 1;
+ return exp;
+ case '!':
+ exp->optype = OP_NOT;
+ *eatlen = s - buf + 1;
+ return exp;
+ case '&':
+ exp->optype = OP_AND;
+ if (s[1] != '&')
+ goto fail;
+ *eatlen = s - buf + 2;
+ return exp;
+ case '|':
+ exp->optype = OP_OR;
+ if (s[1] != '|')
+ goto fail;
+ *eatlen = s - buf + 2;
+ return exp;
+ case '=':
+ if (s[1] != '=')
+ goto fail;
+ exp->optype = OP_EQUAL;
+ *eatlen = s - buf + 2;
+ return exp;
+ default:
+ /* a variable name must start with a letter */
+ if (isalpha(s[0]))
+ break;
+ goto fail;
+ }
+
+ /* It's a variable, get name */
+ while (isalnum(s[0]) || s[0] == '_')
+ s++;
+
+ exp->optype = OP_VAR;
+ *eatlen = s - buf;
+
+ /* alloc string for variable name */
+ len = s - buf;
+ exp->varname = malloc(len+1);
+ memcpy(exp->varname, buf, len);
+ exp->varname[len] = '\0';
+ return exp;
+
+ fail:
+ free(exp);
+ return NULL;
+}
+
+/*
+ * Parse the expression contained in s (which is a modifiable
+ * string). Return 0 on success, in this case the expression tree is
+ * returned in exp_ptr. On error, return -1.
+ */
+static int expr_parse(char *s, struct cfzy_expr **exp_ptr)
+{
+ struct cfzy_expr *top = NULL, *exp, *tmp;
+ int len;
+ unsigned eatlen;
+
+ debug_printf("parse <%s>\n", s);
+
+ if (*s == '\0')
+ return -1;
+
+ while (1) {
+
+ /* skip spaces */
+ while (isspace(*s))
+ s++;
+
+ /* get next operator/operand */
+ exp = get_next_op(s, &eatlen);
+ if (exp == NULL) {
+ debug_printf("Parse error\n");
+ goto fail;
+ }
+
+ if (exp->optype == OP_EOF) {
+ free(exp);
+ exp = NULL;
+ break;
+ }
+
+ debug_printf("New node: %s\n", op_print(exp));
+ switch (exp->optype) {
+
+ case OP_OR:
+ case OP_AND:
+ case OP_EQUAL:
+ /* if it is the first node, error */
+ if (top == NULL)
+ goto fail;
+
+ /* the rightest leaf must be a variable */
+ tmp = top;
+ while (tmp->right)
+ tmp = tmp->right;
+ if (tmp->optype != OP_VAR)
+ goto fail;
+
+ /* if new node priority is lower than root
+ * node, it becomes the new root */
+ if (exp->optype < top->optype) {
+ exp->left = top;
+ top = exp;
+ break;
+ }
+
+ /* exp is placed at the "rightest" leaf. Check
+ * that our parent is not a variable */
+ tmp = top;
+ while (tmp->right && exp->optype > tmp->right->optype)
+ tmp = tmp->right;
+
+ if (tmp->right == NULL)
+ goto fail;
+
+ exp->left = tmp->right;
+ tmp->right = exp;
+ break;
+
+ case OP_OBRACKET:
+ /* if operator is an opening bracket,
+ * recursively call ourself with the
+ * sub-expression */
+ len = get_brac_len(s);
+ if (len < 0) {
+ debug_printf("Cannot find closing bracket\n");
+ goto fail;
+ }
+ s[len-1] = '\0';
+ if (expr_parse(s+1, &exp->right) < 0)
+ goto fail;
+ if (exp->right == NULL)
+ goto fail;
+ s[len-1] = ')';
+ s += len - 1;
+
+ /* if it is the first node */
+ if (top == NULL) {
+ top = exp;
+ break;
+ }
+
+ /* exp is placed at the "rightest" leaf. Check
+ * that our parent is not a variable */
+ tmp = top;
+ while (tmp->right)
+ tmp = tmp->right;
+ if (tmp->optype == OP_VAR)
+ goto fail;
+ tmp->right = exp;
+ break;
+
+ case OP_NOT:
+ case OP_VAR:
+ /* if it is the first node */
+ if (top == NULL) {
+ top = exp;
+ break;
+ }
+
+ /* exp is placed at the "rightest" leaf. Check
+ * that our parent is not a variable */
+ tmp = top;
+ while (tmp->right)
+ tmp = tmp->right;
+ if (tmp->optype == OP_VAR)
+ goto fail;
+ tmp->right = exp;
+ break;
+
+ default:
+ /* should not happen */
+ debug_printf("Parse error\n");
+ goto fail;
+ }
+
+ s += eatlen;
+ }
+
+ if (top == NULL)
+ goto fail;
+
+ /* the rightest leaf must be a variable */
+ tmp = top;
+ while (tmp->right)
+ tmp = tmp->right;
+ if (tmp->optype != OP_VAR) {
+ debug_printf("Missing operand\n");
+ goto fail;
+ }
+
+ *exp_ptr = top;
+ return 0;
+
+ fail:
+ if (top != NULL)
+ cfzy_expr_free(top);
+ if (exp != NULL)
+ cfzy_expr_free(exp);
+
+ return -1;
+}
+
+/*
+ * Parse the expression contained in buf. Return an expression tree or
+ * NULL on error.
+ */
+struct cfzy_expr *cfzy_expr_parse(const char *buf)
+{
+ struct cfzy_expr *top;
+ char *s;
+ int ret;
+
+ s = strdup(buf);
+ if (s == NULL)
+ return NULL;
+
+ ret = expr_parse(s, &top);
+ free(s);
+ if (ret < 0)
+ return NULL;
+ return top;
+}
+
+/* Free an expression tree */
+void cfzy_expr_free(struct cfzy_expr *exp)
+{
+ if (exp == NULL)
+ return;
+
+ if (exp->left) {
+ cfzy_expr_free(exp->left);
+ exp->left = NULL;
+ }
+
+ if (exp->right) {
+ cfzy_expr_free(exp->right);
+ exp->right = NULL;
+ }
+
+ if (exp->varname != NULL)
+ free(exp->varname);
+
+ free(exp);
+}
+
+/* recursive function called by cfzy_expr_get_vars() that browse the
+ * expr tree to fill the list */
+static int
+expr_get_vars(const struct cfzy_expr *exp, struct cfzy_list_head *list)
+{
+ struct cfzy_list_elt *e;
+ char *name;
+
+ if (exp->left) {
+ if (expr_get_vars(exp->left, list) < 0)
+ return -1;
+ }
+
+ if (exp->right) {
+ if (expr_get_vars(exp->right, list) < 0)
+ return -1;
+ }
+
+ if (exp->optype != OP_VAR)
+ return 0;
+
+ /* ignore true and false constants */
+ if (!strcmp(exp->varname, "true"))
+ return 0;
+ if (!strcmp(exp->varname, "false"))
+ return 0;
+
+ /* nothing to do if var is already in list */
+ TAILQ_FOREACH(e, list, next) {
+ if (!strcmp(e->ptr, exp->varname))
+ return 0;
+ }
+
+ name = strdup(exp->varname);
+ if (name == NULL)
+ return -1;
+
+ if (cfzy_list_add_tail(list, name) < 0) {
+ free(name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Return a list containing all variables on which expression depend */
+struct cfzy_list_head *cfzy_expr_get_vars(const struct cfzy_expr *exp)
+{
+ struct cfzy_list_head *list;
+
+ list = cfzy_list_alloc();
+ if (list == NULL)
+ return NULL;
+
+ if (expr_get_vars(exp, list) < 0) {
+ cfzy_list_free(list, free);
+ return NULL;
+ }
+
+ return list;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CFZY_EXPR_H_
+#define _CFZY_EXPR_H_
+
+/**
+ * @file
+ * Confizery Expression
+ *
+ * This module provides functions to parse an expression string and
+ * convert it in a logical expression tree, that can be evaluated,
+ * according to the variables defined in the configuration tree.
+ *
+ * It is used in configuration tree file, for instance in the "if"
+ * node or the "default" attribute.
+ */
+
+#include <sys/queue.h>
+
+#include "cfzy_list.h"
+
+/**
+ * Type of operand in expression tree (from low to high priority)
+ */
+enum cfzy_expr_op {
+ OP_OR,
+ OP_AND,
+ OP_EQUAL,
+ OP_OBRACKET,
+ OP_CBRACKET,
+ OP_NOT,
+ OP_VAR,
+ OP_EOF,
+};
+
+/**
+ * Structure describing an expression tree
+ *
+ * An expression tree is a binary tree. Each node contains an
+ * operator, or a variable name. If it's a unary operator, only the
+ * right child is used, else both left and right children are set.
+ */
+struct cfzy_expr {
+ TAILQ_ENTRY(expr) next; /**< next entry in list */
+ enum cfzy_expr_op optype; /**< operator type */
+ char *varname; /**< var name, only valid if type is OP_VAR */
+ struct cfzy_expr *left; /**< left child */
+ struct cfzy_expr *right; /**< right child */
+};
+
+/**
+ * Parse a string and convert it in an expression tree
+ *
+ * @param buf
+ * String containing an expression
+ * @return
+ * Expression tree, or NULL on error
+ */
+struct cfzy_expr *cfzy_expr_parse(const char *buf);
+
+/**
+ * Free an expression tree previously allocated with cfzy_expr_parse()
+ *
+ * @param exp
+ * Expression to free
+ */
+void cfzy_expr_free(struct cfzy_expr *exp);
+
+/**
+ * Write an expression tree in a string buffer
+ *
+ * Dump the expression 'exp' as a string into the buffer 'buf' of
+ * length 'len'. The output string is always nul-terminated.
+ *
+ * @param exp
+ * Expression tree to dump
+ * @param buf
+ * Destination buffer
+ * @param len
+ * Len of the destination buffer
+ * @return
+ * Number of written bytes on success (not including '\0'), else
+ * return -1.
+ */
+int cfzy_expr_to_str(const struct cfzy_expr *exp, char *buf, int len);
+
+/**
+ * Evaluate an expression tree
+ *
+ * Evaluate the given expression tree according to variables defined
+ * in conftree.
+ *
+ * @param exp
+ * Expression tree to evaluate
+ * @param getvalue
+ * Function used to evaluate a variable. This function should
+ * return the value of the variable (positive), or a negative value
+ * on error (variable invalid or not found).
+ * This argument can be NULL, in this case only "true" and "false" are
+ * evaluated.
+ * @param opaque_arg
+ * Second argument given as-is to getvalue() function.
+ * @return
+ * The value of the expression (greater or equal to 0), or -1 on
+ * error
+ */
+int cfzy_expr_eval(const struct cfzy_expr *exp,
+ int (*getvalue)(const char *, void *), void *opaque_arg);
+
+/**
+ * Dump the expression graph in a file
+ *
+ * Useful for debug purpose only. The output can be parsed with
+ * cfzy_expr_graph.py.
+ *
+ * @param filename
+ * Name of file
+ * @param exp
+ * Expression tree to dump
+ * @return
+ * 0 on succes, -1 on error
+ */
+int cfzy_expr_graph_dump(const char *filename, const struct cfzy_expr *exp);
+
+/**
+ * Return a list containing all variables on which expression depend
+ *
+ * Allocate a list head, and for each variable of the expression,
+ * allocate an element and add it in the list. Each element points to
+ * a string which is allocated and should be freed by the user. Each
+ * variable is present only once in the list.
+ *
+ * @param exp
+ * Expression tree
+ * @return
+ * List containing the variables (it can be empty), or NULL on error.
+ */
+struct cfzy_list_head *cfzy_expr_get_vars(const struct cfzy_expr *exp);
+
+#endif /* _CFZY_EXPR_H_ */
--- /dev/null
+#!/usr/bin/env python
+
+import matplotlib.pyplot as plt
+import networkx as nx
+import sys, re, random
+
+G = nx.Graph()
+labels = {}
+levels = {}
+init_pos = {}
+maxlevel = 0
+
+# always keep the same seed
+random.seed(1234)
+
+# parse lines, new vertice is:
+# vertice LEVEL OPERATOR:VERTICE_NAME
+# new edge is:
+# edge OPERATOR:VERTICE_NAME OPERATOR:VERTICE_NAME
+while True:
+ l = sys.stdin.readline()
+ if l == "":
+ break
+ m = re.match("^vertice ([0-9]+) ([^\s]+)$", l)
+ if m:
+ level = m.groups()[0]
+ level = int(level)
+ operator, name = m.groups()[1].split(":")
+ print "vert: operator = %s, level = %d, name = %s"%(operator, level, name)
+ labels[name] = operator
+ init_pos[name] = (random.random(), -level)
+ levels[name] = level
+ if level > maxlevel:
+ maxlevel = level
+ continue
+ m = re.match("^edge ([^\s]+) ([^\s]+)$", l)
+ if m:
+ vertice1, vertice2 = m.groups()
+ G.add_edge(vertice1, vertice2)
+ continue
+
+pos = nx.spring_layout(G, pos=init_pos)
+
+# root node is blue and bigger
+rootnode = filter(lambda x:levels[x] == 0, levels.keys())
+nx.draw_networkx_nodes(G, pos, node_color='b', node_size=2000, nodelist=rootnode)
+
+# graph other nodes
+for level in range(1, maxlevel + 1):
+ othernodes = filter(lambda x:levels[x] == level, levels.keys())
+ color = (1., float(level)/maxlevel, float(level)/maxlevel)
+ color = [color] * len(othernodes)
+ nx.draw_networkx_nodes(G, pos, node_color=color, node_size=1000, nodelist=othernodes)
+
+nx.draw_networkx_edges(G, pos)
+nx.draw_networkx_labels(G, pos, labels, font_size=20, font_family='sans-serif')
+
+plt.axis('off')
+plt.savefig("weighted_graph.png") # save as png
+plt.show() # display
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "cfzy_log.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("file", level, fmt, ##args)
+
+/* 0 = same file, 1 = different files, -1 = error
+ * the function does not close the files */
+int cfzy_file_compare(FILE *f1, FILE *f2)
+{
+ char buf1[BUFSIZ], buf2[BUFSIZ];
+ size_t ret1, ret2;
+
+ rewind(f1);
+ rewind(f2);
+
+ while (1) {
+ ret1 = fread(buf1, 1, sizeof(buf1), f1);
+ if (ret1 == 0 && ferror(f1))
+ return -1;
+
+ ret2 = fread(buf2, 1, sizeof(buf2), f2);
+ if (ret2 == 0 && ferror(f2))
+ return -1;
+
+ if (ret1 != ret2)
+ return 1;
+
+ if (ret1 == 0) /* implies ret2 == 0 too */
+ return 0;
+
+ if (memcmp(buf1, buf2, ret1))
+ return 1;
+ }
+
+ /* never reached */
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * File-related tools
+ */
+
+#ifndef CFZY_FILE_H
+#define CFZY_FILE_H
+
+#include <stdio.h>
+
+/**
+ * Compare 2 files
+ *
+ * The function rewind to the beginning of the files, then compares
+ * them. The file position indicator is undefined after the execution
+ * of the function, and the files are not closed.
+ *
+ * @param f1
+ * pointer to first stream
+ * @param f2
+ * pointer to second stream
+ * @return
+ * 0 if files are the same, 1 if files are different, -1 on error
+ */
+int cfzy_file_compare(FILE *f1, FILE *f2);
+
+#endif /* CFZY_FILE */
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include "cfzy_htable.h"
+
+/* return the hash from name */
+static uint32_t hash_name(const char *name)
+{
+ uint32_t h = 0;
+ const unsigned char *c;
+
+ /* XXX add murmurhash ? */
+ for (c = (const unsigned char *)name; *c; c++)
+ h += ((((uint32_t)*c) << 4) + (((uint32_t)*c) >> 4)) * 11;
+
+ return h & CFZY_HTABLE_MASK;
+}
+
+/* return the hlist_elt associated to the given name. If not found,
+ * return NULL. */
+static struct cfzy_hlist_elt *
+__cfzy_htable_lookup(const struct cfzy_htable *htable, const char *name)
+{
+ struct cfzy_hlist_elt *e;
+ uint32_t h = hash_name(name);
+
+ LIST_FOREACH(e, &htable->buckets[h], next) {
+ if (!strcmp(name, e->name))
+ break;
+ }
+ return e;
+}
+
+/* return the object associated to the given name. If not found,
+ * return NULL. */
+void *cfzy_htable_lookup(const struct cfzy_htable *htable, const char *name)
+{
+ struct cfzy_hlist_elt *e = __cfzy_htable_lookup(htable, name);
+ if (e == NULL)
+ return NULL;
+ return e->ptr;
+}
+
+/* add an entry in the htable, allocating a new hlist_elt */
+int cfzy_htable_add(struct cfzy_htable *htable, const char *name,
+ void *ptr)
+{
+ struct cfzy_hlist_elt *e;
+ uint32_t h;
+
+ /* The ptr should not be NULL, else we won't differentiate a
+ * lookup matching a NULL element and a non-matching one */
+ if (ptr == NULL)
+ return -1;
+
+ e = malloc(sizeof(struct cfzy_hlist_elt));
+ if (e == NULL)
+ return -1;
+
+ e->name = strdup(name);
+ if (e->name == NULL) {
+ free(e);
+ return -1;
+ }
+
+ e->ptr = ptr;
+ h = hash_name(name);
+ LIST_INSERT_HEAD(&htable->buckets[h], e, next);
+
+ return 0;
+}
+
+/* delete and free an hlist_elt from the htable */
+static int __cfzy_htable_del(struct cfzy_hlist_elt *e)
+{
+ LIST_REMOVE(e, next);
+ free(e->name);
+ free(e);
+ return 0;
+}
+
+/* delete an entry from the htable, freeing the hlist_elt */
+int cfzy_htable_del(struct cfzy_htable *htable, const char *name)
+{
+ struct cfzy_hlist_elt *e = __cfzy_htable_lookup(htable, name);
+
+ if (e == NULL)
+ return -1;
+
+ return __cfzy_htable_del(e);
+}
+
+/* allocate and initialize a new htable */
+struct cfzy_htable *cfzy_htable_alloc(void)
+{
+ struct cfzy_htable *htable;
+ unsigned i;
+
+ htable = malloc(sizeof(struct cfzy_htable));
+ if (htable == NULL)
+ return NULL;
+
+ for (i = 0; i < CFZY_HTABLE_SIZE; i++) {
+ LIST_INIT(&htable->buckets[i]);
+ }
+ return htable;
+}
+
+/* empty the htable, freeing hlist_elt structures, and free the htable */
+void cfzy_htable_free(struct cfzy_htable *htable, void (*free_fct)(void *))
+{
+ struct cfzy_hlist_elt *e;
+ unsigned i;
+
+ for (i = 0; i < CFZY_HTABLE_SIZE; i++) {
+ while ((e = LIST_FIRST(&htable->buckets[i])) != NULL) {
+ if (free_fct != NULL)
+ free_fct(e->ptr);
+
+ __cfzy_htable_del(e);
+ }
+ }
+ free(htable);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CFZY_HTABLE_H_
+#define _CFZY_HTABLE_H_
+
+/**
+ * @file
+ * Confizery Hash Table
+ *
+ * This module is a simple hash table implementation, based on LIST
+ * from sys/queue.h --see queue(3)-- and with a constant number of
+ * buckets. It handles the allocation of chaining structure so any
+ * kind of element can be added/deleted. Each element is referenced by
+ * a string (key).
+ */
+
+#include <sys/queue.h>
+
+/* we use a constant size of htable, it simplifies the code and it is
+ * enough for our purpose */
+
+#define CFZY_HTABLE_ORDER 10
+#define CFZY_HTABLE_SIZE (1 << CFZY_HTABLE_ORDER)
+#define CFZY_HTABLE_MASK (CFZY_HTABLE_SIZE - 1)
+
+/**
+ * A hash table bucket
+ */
+LIST_HEAD(cfzy_hlist_head, cfzy_hlist_elt);
+
+/**
+ * A hash table element, used to chain objects together and store the
+ * name (key). This structure is allocated by cfzy_htable_add().
+ */
+struct cfzy_hlist_elt {
+ LIST_ENTRY(cfzy_hlist_elt) next;
+ char *name;
+ void *ptr;
+};
+
+/**
+ * A hash table structure
+ */
+struct cfzy_htable {
+ struct cfzy_hlist_head buckets[CFZY_HTABLE_SIZE];
+};
+
+/**
+ * Lookup for an element matching the given key
+ *
+ * @param htable
+ * Hash table pointer
+ * @param name
+ * String identifying the element (key)
+ * @return
+ * Pointer to the element, or NULL on error
+ */
+void *cfzy_htable_lookup(const struct cfzy_htable *htable, const char *name);
+
+
+/**
+ * Add an element in the hash table
+ *
+ * Allocate a new cfzy_hlist_elt structure, initialize it to point to
+ * the given pointer "ptr", then queue the structure in the
+ * appropriate hash table bucket.
+ *
+ * @param htable
+ * Hash table pointer
+ * @param name
+ * String identifying the element (key)
+ * @param ptr
+ * Pointer to the element (must not be NULL)
+ * @return
+ * 0 on success, -1 on error
+ */
+int cfzy_htable_add(struct cfzy_htable *htable, const char *name,
+ void *ptr);
+
+/**
+ * Remove an element from the hash table
+ *
+ * Unchain the structure from the hash table bucket, and free the
+ * cfzy_hlist_elt structure.
+ *
+ * @param htable
+ * Hash table pointer
+ * @param name
+ * String identifying the element (key)
+ * @return
+ * 0 on success, -1 on error (element not found)
+ */
+int cfzy_htable_del(struct cfzy_htable *htable, const char *name);
+
+/**
+ * Allocate and initialize a new empty htable
+ *
+ * @return
+ * Hash table pointer or NULL on error
+ */
+struct cfzy_htable *cfzy_htable_alloc(void);
+
+/**
+ * Free a htable
+ *
+ * Empty the htable, freeing all elements (cfzy_hlist_elt structures,
+ * and its pointer, using the provided free_fct), then free the
+ * cfzy_htable.
+ *
+ * @param htable
+ * Hash table pointer
+ * @param free_fct
+ * Function to free an element
+ */
+void cfzy_htable_free(struct cfzy_htable *htable, void (*free_fct)(void *));
+
+#endif /* _CFZY_HTABLE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+#include "cfzy_list.h"
+
+/* allocate a list_elt and insert at the tail of the list */
+int cfzy_list_add_tail(struct cfzy_list_head *list, void *ptr)
+{
+ struct cfzy_list_elt *e;
+
+ e = malloc(sizeof(struct cfzy_list_elt));
+ if (e == NULL)
+ return -1;
+
+ e->ptr = ptr;
+ TAILQ_INSERT_TAIL(list, e, next);
+ return 0;
+}
+
+/* allocate a list_elt and insert at the tail of the list */
+int cfzy_list_add_head(struct cfzy_list_head *list, void *ptr)
+{
+ struct cfzy_list_elt *e;
+
+ e = malloc(sizeof(struct cfzy_list_elt));
+ if (e == NULL)
+ return -1;
+
+ e->ptr = ptr;
+ TAILQ_INSERT_HEAD(list, e, next);
+ return 0;
+}
+
+/* remove from the list and free the list_elt */
+void cfzy_list_del(struct cfzy_list_head *list, struct cfzy_list_elt *e)
+{
+ TAILQ_REMOVE(list, e, next);
+ free(e);
+}
+
+/* check if an elt is in list */
+int cfzy_list_elt_is_in_list(const struct cfzy_list_head *list, const void *ptr)
+{
+ struct cfzy_list_elt *e;
+
+ TAILQ_FOREACH(e, list, next) {
+ if (e->ptr == ptr)
+ return 1;
+ }
+ return 0;
+}
+
+/* allocate a new list_head */
+struct cfzy_list_head *cfzy_list_alloc(void)
+{
+ struct cfzy_list_head *list;
+
+ list = malloc(sizeof(struct cfzy_list_head));
+ if (list == NULL)
+ return NULL;
+
+ TAILQ_INIT(list);
+ return list;
+}
+
+/* empty the list, freeing the list_elt, and free the list_head */
+void cfzy_list_free(struct cfzy_list_head *list, void (*free_fct)(void *))
+{
+ struct cfzy_list_elt *e;
+
+ while ((e = TAILQ_FIRST(list)) != NULL) {
+ TAILQ_REMOVE(list, e, next);
+ if (free_fct != NULL)
+ free_fct(e->ptr);
+ free(e);
+ }
+ free(list);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CFZY_LIST_H_
+#define _CFZY_LIST_H_
+
+/**
+ * @file
+ * Confizery List
+ *
+ * This module is a list implementation, based on TAILQ from
+ * sys/queue.h -see queue(3)-. It handles the allocation of chaining
+ * structure so any kind of element can be chained.
+ *
+ * To be really useful, this API must be used in conjonction with the
+ * TAILQ_* macros. For instance, to browse the list:
+ *
+ * struct cfzy_list_elt *e;
+ * TAILQ_FOREACH(e, list_head, next) {
+ * obj = e->ptr;
+ * ...
+ * }
+ */
+
+#include <sys/queue.h>
+
+/**
+ * A list head
+ */
+TAILQ_HEAD(cfzy_list_head, cfzy_list_elt);
+
+/**
+ * A list element, used to chain objects together. This structure is
+ * allocated by cfzy_list_add().
+ */
+struct cfzy_list_elt {
+ TAILQ_ENTRY(cfzy_list_elt) next;
+ void *ptr;
+};
+
+/**
+ * Insert an element at the tail of the list
+ *
+ * Allocate a cfzy_list_elt structure, set its ptr field and insert it
+ * at the tail of the list.
+ *
+ * @param list
+ * List head to insert the element
+ * @param ptr
+ * Pointer to the object that will be referenced by list_elt->ptr
+ * @return
+ * 0 on succes, and negative on error
+ */
+int cfzy_list_add_tail(struct cfzy_list_head *list, void *ptr);
+
+/**
+ * Insert an element at the head of the list
+ *
+ * Allocate a cfzy_list_elt structure, set its ptr field and insert it
+ * at the head of the list.
+ *
+ * @param list
+ * List head to insert the element
+ * @param ptr
+ * Pointer to the object that will be referenced by list_elt->ptr
+ * @return
+ * 0 on succes, and negative on error
+ */
+int cfzy_list_add_head(struct cfzy_list_head *list, void *ptr);
+
+/**
+ * Remove an element from the list
+ *
+ * Unchain the cfzy_list_elt structure and free it.
+ *
+ * @param list
+ * List head to insert the element
+ * @param elt
+ * List element
+ */
+void cfzy_list_del(struct cfzy_list_head *list, struct cfzy_list_elt *elt);
+
+/**
+ * Check if an element is in the list
+ *
+ * Browse the list and check if there is already an cfzy_list_elt
+ * structure referencing ptr.
+ *
+ * @param list
+ * List head
+ * @param ptr
+ * Pointer to the element
+ * @return
+ * 1 if the element is in list, else 0
+ */
+int cfzy_list_elt_is_in_list(const struct cfzy_list_head *list, const void *ptr);
+
+/**
+ * Allocate a new list
+ *
+ * @return
+ * Pointer to the new list head, or NULL on error
+ */
+struct cfzy_list_head *cfzy_list_alloc(void);
+
+/**
+ * Free a list
+ *
+ * Free all cfzy_list_elt of the list using the free_fct if provided,
+ * then free the cfzy_list_head structure.
+ *
+ * @param list
+ * List head pointer
+ * @param free_fct
+ * Function to free an element
+ */
+void cfzy_list_free(struct cfzy_list_head *list, void (*free_fct)(void *));
+
+#endif /* _CFZY_LIST_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this log of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this log of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "cfzy_log.h"
+#include "cfzy_htable.h"
+
+static struct cfzy_htable *level_htable = NULL;
+static int default_level = CFZY_LOG_NOTICE;
+
+/* initialize log susbsystem */
+int cfzy_log_init(void)
+{
+ level_htable = cfzy_htable_alloc();
+ if (level_htable == NULL)
+ return -1;
+ return 0;
+}
+
+/* free all structures associated to log subsystem */
+void cfzy_log_exit(void)
+{
+ cfzy_htable_free(level_htable, free);
+}
+
+/* set default log level (for log types that are not registered) */
+int cfzy_log_set_default_level(int level)
+{
+ if (level != -1 && (level < CFZY_LOG_ERR || level > CFZY_LOG_DEBUG))
+ return -1;
+ default_level = level;
+ return 0;
+}
+
+/* set log level for a specific log type: the string is added in the
+ * hash table */
+int cfzy_log_set_level(const char *logtype, int level)
+{
+ int *l;
+
+ if (level != -1 && (level < CFZY_LOG_ERR || level > CFZY_LOG_DEBUG))
+ return -1;
+ l = cfzy_htable_lookup(level_htable, logtype);
+
+ /* if log is already registered, it's easy */
+ if (l != NULL) {
+ *l = level;
+ return 0;
+ }
+
+ /* else allocate a new (int *) and store it in the htable */
+ l = malloc(sizeof(*l));
+ if (l == NULL)
+ return -1;
+
+ *l = level;
+ cfzy_htable_add(level_htable, logtype, l);
+ return 0;
+}
+
+/* print a log if given level is <= to configured log level */
+int cfzy_log_printf(const char *logtype, int level, const char *fmt, ...)
+{
+ int *l;
+ va_list ap;
+ int ret;
+
+ l = cfzy_htable_lookup(level_htable, logtype);
+
+ if (l == NULL && level > default_level)
+ return 0;
+ else if (l != NULL && level > *l)
+ return 0;
+
+ va_start(ap, fmt);
+ ret = vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this log of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this log of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CFZY_LOG_H_
+#define _CFZY_LOG_H_
+
+/**
+ * @file
+ * Confizery Log
+ *
+ * This module provides logging helpers. XXX explain
+ */
+
+/* log levels */
+#define CFZY_LOG_ERR 0
+#define CFZY_LOG_WARNING 1
+#define CFZY_LOG_NOTICE 2
+#define CFZY_LOG_INFO 3
+#define CFZY_LOG_DEBUG 4
+
+/**
+ * Initialize log subsystem
+ *
+ * @return
+ * 0 on succes, -1 on error
+ */
+int cfzy_log_init(void);
+
+/**
+ * Uninitialize log subsystem
+ */
+void cfzy_log_exit(void);
+
+/**
+ * Set default log level
+ *
+ * @param level
+ * Level of log, -1 means no log at all
+ * @return
+ * 0 on succes, -1 on error
+ */
+int cfzy_log_set_default_level(int level);
+
+/**
+ * Set log level for a specific log type
+ *
+ * @param logtype
+ * String describing the log type
+ * @param level
+ * Level of log, -1 means no log at all
+ * @return
+ * 0 on succes, -1 on error
+ */
+int cfzy_log_set_level(const char *logtype, int level);
+
+/**
+ * Print a log if given level is <= to configured log level
+ *
+ * The log is displayed on standard error.
+ *
+ * @param logtype
+ * String describing the log type
+ * @param level
+ * Level at which the text must be displayed
+ * @param fmt
+ * Format string, followed by optional arguments, like in printf.
+ * @return
+ * The number of written characters (0 if nothing is diplayed),
+ * or -1 on error.
+ */
+int cfzy_log_printf(const char *logtype, int level, const char *fmt, ...);
+
+#if 0
+/**
+ * Print a log if given level is <= to configured log level
+ */
+#define CFZY_LOG(logtype, level, fmt, args...) \
+ cfzy_log_printf(logtype, CFZY_LOG_##level, fmt, \
+ ## args)
+#else
+#define CFZY_LOG(logtype, level, fmt, args...) \
+ cfzy_log_printf(logtype, CFZY_LOG_##level, "%s():%d " fmt, \
+ __func__, __LINE__, ## args)
+#endif
+
+#endif /* _CFZY_LOG_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cfzy_log.h"
+
+#define LOG(level, fmt, args...) \
+ CFZY_LOG("string", level, fmt, ##args)
+
+/* Acts as a asprintf, except that it appends data after buf (if not
+ * NULL), reallocating memory if necessary. */
+int cfzy_string_asprintf(char **buf, const char *fmt, ...)
+{
+ va_list ap;
+ char dummy;
+ int offset = 0, buflen, ret;
+
+ if (*buf != NULL)
+ offset = strlen(*buf);
+
+ va_start(ap, fmt);
+ ret = vsnprintf(&dummy, 1, fmt, ap);
+ va_end(ap);
+ if (ret < 0) {
+ LOG(ERR, "first vsnprintf failed\n");
+ return ret;
+ }
+
+ buflen = offset + ret + 1;
+ *buf = realloc(*buf, buflen);
+ if (*buf == NULL) {
+ LOG(ERR, "asprintf: not enough memory\n");
+ return -1;
+ }
+
+ va_start(ap, fmt);
+ ret = vsnprintf(*buf + offset, buflen - offset, fmt, ap);
+ va_end(ap);
+
+ if (ret >= buflen || ret < 0) {
+ free(*buf);
+ *buf = NULL;
+ LOG(ERR, "second vsnprintf failed\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+/*
+ * If the buffer is surrounded by quotes (simple or double), this
+ * function will allocate a new string and remove the quotes properly,
+ * also deleting the backslash in occurences of \\, \" or \'. If the
+ * buffer does not start by a quote, the function just return a
+ * duplicate of the input string. On sucess, the eatlen is updated to
+ * the number of consumed bytes (including quotes if any, but not
+ * including \0). On error, return NULL, in this case *eatlen is
+ * undefined.
+ */
+char *cfzy_string_unquote(const char *buf, unsigned *eatlen)
+{
+ char delim;
+ char *out, *s2;
+ const char *s;
+
+ s = buf;
+ out = strdup(s);
+ if (out == NULL) {
+ LOG(ERR, "not enough memory\n");
+ return NULL;
+ }
+
+ if (s[0] == '"')
+ delim = '"';
+ else if (s[0] == '\'')
+ delim = '\'';
+ else {
+ *eatlen = strlen(s);
+ return out;
+ }
+ s++;
+
+ s2 = out;
+ while (*s != delim) {
+ if (*s == '\0') {
+ free(out);
+ return NULL;
+ }
+ if (*s == '\\' && *(s+1) == delim) {
+ *s2 = delim;
+ s += 2;
+ s2 ++;
+ continue;
+ }
+ if (*s == '\\' && *(s+1) == '\\') {
+ *s2 = '\\';
+ s += 2;
+ s2 ++;
+ continue;
+ }
+ *s2 = *s;
+ s ++;
+ s2 ++;
+ }
+ *s2 = '\0';
+
+ *eatlen = s - buf + 1;
+ return out;
+}
+
+/* quote a string and escape original quotes */
+char *cfzy_string_quote(const char *src)
+{
+ int s, d;
+ char *dst;
+
+ /* get dst buf len */
+ for (s = 0, d = 0; src[s] != '\0'; s++, d++) {
+ if (src[s] == '"')
+ d++;
+ if (src[s] == '\\' && src[s+1] == '"')
+ d++;
+ }
+
+ dst = malloc(d + 3); /* 3 for the 2 quotes and the \0 */
+ if (dst == NULL)
+ return NULL;
+
+ dst[0] = '"';
+ for (s = 0, d = 1; src[s] != '\0'; s++, d++) {
+ if (src[s] == '"')
+ dst[d++] = '\\';
+ if (src[s] == '\\' && src[s+1] == '"')
+ dst[d++] = '\\';
+
+ dst[d] = src[s];
+ }
+
+ dst[d++] = '"';
+ dst[d++] = '\0';
+
+ return dst;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * String-related tools
+ */
+
+#ifndef CFZY_STRING_H
+#define CFZY_STRING_H
+
+/**
+ * Append a formatted string in an allocated buffer
+ *
+ * This function acts as a asprintf, with some differences:
+ * - *but can already contain a string, in this case, the new string
+ * is appended.
+ * - *strp is set to NULL on error, like in BSD's asprintf
+ *
+ * @param strp
+ * Pointer to a (char *), must not be NULL. If *strp is NULL a new
+ * buffer is allocated to store the string. Else, if *strp is not
+ * NULL, it must point to a valid string in a buffer that was
+ * previously allocated using malloc.
+ * @param fmt
+ * Format string, followed by other arguments, like in printf
+ * @return
+ * The number of bytes printed. If memory allocation wasn't
+ * possible, or some other error occurs, these functions will return
+ * -1, and the contents of strp is set to NULL.
+ **/
+int cfzy_string_asprintf(char **buf, const char *fmt, ...);
+
+/**
+ * Remove quotes on a string
+ *
+ * If the buffer is surrounded by quotes (simple or double), this
+ * function will allocate a new string and remove the quotes properly,
+ * also deleting the backslash in occurences of \\, \" or \'. If the
+ * buffer does not start by a quote, the function just return a
+ * duplicate of the input string.
+ *
+ * On sucess, the value pointer by eatlen is updated to the len of
+ * consumed bytes in the input buffer, including quotes if any, but
+ * not including \0. On error *eatlen is undefined.
+ *
+ * @param buf
+ * string buffer
+ * @param eatlen
+ * pointer to an int where the number of consumed bytes is written
+ * @return
+ * the unquoted string (allocated), or NULL on error
+ */
+char *cfzy_string_unquote(const char *buf, unsigned *eatlen);
+
+/**
+ * Quote a string with double quotes
+ *
+ * Allocate a new string which is a copy of the first one, surrounded
+ * by quotes and quotes of initial string are escaped with a
+ * backslash.
+ *
+ * @param src
+ * input string
+ * @return
+ * the quoted string (allocated), or NULL on error
+ */
+char *cfzy_string_quote(const char *src);
+
+#endif /* CFZY_STRING */