mirror of https://github.com/GOSTSec/sgminer
Rusty Russell
14 years ago
49 changed files with 4942 additions and 2 deletions
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
noinst_LIBRARIES = libccan.a |
||||
|
||||
libccan_a_SOURCES = compiler/compiler.h opt/helpers.c opt/opt.c opt/opt.h opt/parse.c opt/private.h opt/usage.c typesafe_cb/typesafe_cb.h |
@ -0,0 +1,165 @@
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE |
||||
Version 3, 29 June 2007 |
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
||||
Everyone is permitted to copy and distribute verbatim copies |
||||
of this license document, but changing it is not allowed. |
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates |
||||
the terms and conditions of version 3 of the GNU General Public |
||||
License, supplemented by the additional permissions listed below. |
||||
|
||||
0. Additional Definitions. |
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser |
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU |
||||
General Public License. |
||||
|
||||
"The Library" refers to a covered work governed by this License, |
||||
other than an Application or a Combined Work as defined below. |
||||
|
||||
An "Application" is any work that makes use of an interface provided |
||||
by the Library, but which is not otherwise based on the Library. |
||||
Defining a subclass of a class defined by the Library is deemed a mode |
||||
of using an interface provided by the Library. |
||||
|
||||
A "Combined Work" is a work produced by combining or linking an |
||||
Application with the Library. The particular version of the Library |
||||
with which the Combined Work was made is also called the "Linked |
||||
Version". |
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the |
||||
Corresponding Source for the Combined Work, excluding any source code |
||||
for portions of the Combined Work that, considered in isolation, are |
||||
based on the Application, and not on the Linked Version. |
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the |
||||
object code and/or source code for the Application, including any data |
||||
and utility programs needed for reproducing the Combined Work from the |
||||
Application, but excluding the System Libraries of the Combined Work. |
||||
|
||||
1. Exception to Section 3 of the GNU GPL. |
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License |
||||
without being bound by section 3 of the GNU GPL. |
||||
|
||||
2. Conveying Modified Versions. |
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a |
||||
facility refers to a function or data to be supplied by an Application |
||||
that uses the facility (other than as an argument passed when the |
||||
facility is invoked), then you may convey a copy of the modified |
||||
version: |
||||
|
||||
a) under this License, provided that you make a good faith effort to |
||||
ensure that, in the event an Application does not supply the |
||||
function or data, the facility still operates, and performs |
||||
whatever part of its purpose remains meaningful, or |
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of |
||||
this License applicable to that copy. |
||||
|
||||
3. Object Code Incorporating Material from Library Header Files. |
||||
|
||||
The object code form of an Application may incorporate material from |
||||
a header file that is part of the Library. You may convey such object |
||||
code under terms of your choice, provided that, if the incorporated |
||||
material is not limited to numerical parameters, data structure |
||||
layouts and accessors, or small macros, inline functions and templates |
||||
(ten or fewer lines in length), you do both of the following: |
||||
|
||||
a) Give prominent notice with each copy of the object code that the |
||||
Library is used in it and that the Library and its use are |
||||
covered by this License. |
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license |
||||
document. |
||||
|
||||
4. Combined Works. |
||||
|
||||
You may convey a Combined Work under terms of your choice that, |
||||
taken together, effectively do not restrict modification of the |
||||
portions of the Library contained in the Combined Work and reverse |
||||
engineering for debugging such modifications, if you also do each of |
||||
the following: |
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that |
||||
the Library is used in it and that the Library and its use are |
||||
covered by this License. |
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license |
||||
document. |
||||
|
||||
c) For a Combined Work that displays copyright notices during |
||||
execution, include the copyright notice for the Library among |
||||
these notices, as well as a reference directing the user to the |
||||
copies of the GNU GPL and this license document. |
||||
|
||||
d) Do one of the following: |
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this |
||||
License, and the Corresponding Application Code in a form |
||||
suitable for, and under terms that permit, the user to |
||||
recombine or relink the Application with a modified version of |
||||
the Linked Version to produce a modified Combined Work, in the |
||||
manner specified by section 6 of the GNU GPL for conveying |
||||
Corresponding Source. |
||||
|
||||
1) Use a suitable shared library mechanism for linking with the |
||||
Library. A suitable mechanism is one that (a) uses at run time |
||||
a copy of the Library already present on the user's computer |
||||
system, and (b) will operate properly with a modified version |
||||
of the Library that is interface-compatible with the Linked |
||||
Version. |
||||
|
||||
e) Provide Installation Information, but only if you would otherwise |
||||
be required to provide such information under section 6 of the |
||||
GNU GPL, and only to the extent that such information is |
||||
necessary to install and execute a modified version of the |
||||
Combined Work produced by recombining or relinking the |
||||
Application with a modified version of the Linked Version. (If |
||||
you use option 4d0, the Installation Information must accompany |
||||
the Minimal Corresponding Source and Corresponding Application |
||||
Code. If you use option 4d1, you must provide the Installation |
||||
Information in the manner specified by section 6 of the GNU GPL |
||||
for conveying Corresponding Source.) |
||||
|
||||
5. Combined Libraries. |
||||
|
||||
You may place library facilities that are a work based on the |
||||
Library side by side in a single library together with other library |
||||
facilities that are not Applications and are not covered by this |
||||
License, and convey such a combined library under terms of your |
||||
choice, if you do both of the following: |
||||
|
||||
a) Accompany the combined library with a copy of the same work based |
||||
on the Library, uncombined with any other library facilities, |
||||
conveyed under the terms of this License. |
||||
|
||||
b) Give prominent notice with the combined library that part of it |
||||
is a work based on the Library, and explaining where to find the |
||||
accompanying uncombined form of the same work. |
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License. |
||||
|
||||
The Free Software Foundation may publish revised and/or new versions |
||||
of the GNU Lesser General Public License from time to time. Such new |
||||
versions will be similar in spirit to the present version, but may |
||||
differ in detail to address new problems or concerns. |
||||
|
||||
Each version is given a distinguishing version number. If the |
||||
Library as you received it specifies that a certain numbered version |
||||
of the GNU Lesser General Public License "or any later version" |
||||
applies to it, you have the option of following the terms and |
||||
conditions either of that published version or of any later version |
||||
published by the Free Software Foundation. If the Library as you |
||||
received it does not specify a version number of the GNU Lesser |
||||
General Public License, you may choose any version of the GNU Lesser |
||||
General Public License ever published by the Free Software Foundation. |
||||
|
||||
If the Library as you received it specifies that a proxy can decide |
||||
whether future versions of the GNU Lesser General Public License shall |
||||
apply, that proxy's public statement of acceptance of any version is |
||||
permanent authorization for you to choose that version for the |
||||
Library. |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include "config.h" |
||||
|
||||
/** |
||||
* compiler - macros for common compiler extensions |
||||
* |
||||
* Abstracts away some compiler hints. Currently these include: |
||||
* - COLD |
||||
* For functions not called in fast paths (aka. cold functions) |
||||
* - PRINTF_FMT |
||||
* For functions which take printf-style parameters. |
||||
* - IDEMPOTENT |
||||
* For functions which return the same value for same parameters. |
||||
* - NEEDED |
||||
* For functions and variables which must be emitted even if unused. |
||||
* - UNNEEDED |
||||
* For functions and variables which need not be emitted if unused. |
||||
* - UNUSED |
||||
* For parameters which are not used. |
||||
* - IS_COMPILE_CONSTANT |
||||
* For using different tradeoffs for compiletime vs runtime evaluation. |
||||
* |
||||
* License: LGPL (3 or any later version) |
||||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
||||
* |
||||
* Example: |
||||
* #include <ccan/compiler/compiler.h> |
||||
* #include <stdio.h> |
||||
* #include <stdarg.h> |
||||
* |
||||
* // Example of a (slow-path) logging function. |
||||
* static int log_threshold = 2; |
||||
* static void COLD PRINTF_FMT(2,3) |
||||
* logger(int level, const char *fmt, ...) |
||||
* { |
||||
* va_list ap; |
||||
* va_start(ap, fmt); |
||||
* if (level >= log_threshold) |
||||
* vfprintf(stderr, fmt, ap); |
||||
* va_end(ap); |
||||
* } |
||||
* |
||||
* int main(int argc, char *argv[]) |
||||
* { |
||||
* if (argc != 1) { |
||||
* logger(3, "Don't want %i arguments!\n", argc-1); |
||||
* return 1; |
||||
* } |
||||
* return 0; |
||||
* } |
||||
*/ |
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
/* Expect exactly one argument */ |
||||
if (argc != 2) |
||||
return 1; |
||||
|
||||
if (strcmp(argv[1], "depends") == 0) { |
||||
return 0; |
||||
} |
||||
|
||||
return 1; |
||||
} |
@ -0,0 +1,216 @@
@@ -0,0 +1,216 @@
|
||||
#ifndef CCAN_COMPILER_H |
||||
#define CCAN_COMPILER_H |
||||
#include "config.h" |
||||
|
||||
#ifndef COLD |
||||
#if HAVE_ATTRIBUTE_COLD |
||||
/**
|
||||
* COLD - a function is unlikely to be called. |
||||
* |
||||
* Used to mark an unlikely code path and optimize appropriately. |
||||
* It is usually used on logging or error routines. |
||||
* |
||||
* Example: |
||||
* static void COLD moan(const char *reason) |
||||
* { |
||||
* fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); |
||||
* } |
||||
*/ |
||||
#define COLD __attribute__((cold)) |
||||
#else |
||||
#define COLD |
||||
#endif |
||||
#endif |
||||
|
||||
#ifndef NORETURN |
||||
#if HAVE_ATTRIBUTE_NORETURN |
||||
/**
|
||||
* NORETURN - a function does not return |
||||
* |
||||
* Used to mark a function which exits; useful for suppressing warnings. |
||||
* |
||||
* Example: |
||||
* static void NORETURN fail(const char *reason) |
||||
* { |
||||
* fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); |
||||
* exit(1); |
||||
* } |
||||
*/ |
||||
#define NORETURN __attribute__((noreturn)) |
||||
#else |
||||
#define NORETURN |
||||
#endif |
||||
#endif |
||||
|
||||
#ifndef PRINTF_FMT |
||||
#if HAVE_ATTRIBUTE_PRINTF |
||||
/**
|
||||
* PRINTF_FMT - a function takes printf-style arguments |
||||
* @nfmt: the 1-based number of the function's format argument. |
||||
* @narg: the 1-based number of the function's first variable argument. |
||||
* |
||||
* This allows the compiler to check your parameters as it does for printf(). |
||||
* |
||||
* Example: |
||||
* void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...); |
||||
*/ |
||||
#define PRINTF_FMT(nfmt, narg) \ |
||||
__attribute__((format(__printf__, nfmt, narg))) |
||||
#else |
||||
#define PRINTF_FMT(nfmt, narg) |
||||
#endif |
||||
#endif |
||||
|
||||
#ifndef IDEMPOTENT |
||||
#if HAVE_ATTRIBUTE_CONST |
||||
/**
|
||||
* IDEMPOTENT - a function's return depends only on its argument |
||||
* |
||||
* This allows the compiler to assume that the function will return the exact |
||||
* same value for the exact same arguments. This implies that the function |
||||
* must not use global variables, or dereference pointer arguments. |
||||
*/ |
||||
#define IDEMPOTENT __attribute__((const)) |
||||
#else |
||||
#define IDEMPOTENT |
||||
#endif |
||||
#endif |
||||
|
||||
#if HAVE_ATTRIBUTE_UNUSED |
||||
#ifndef UNNEEDED |
||||
/**
|
||||
* UNNEEDED - a variable/function may not be needed |
||||
* |
||||
* This suppresses warnings about unused variables or functions, but tells |
||||
* the compiler that if it is unused it need not emit it into the source code. |
||||
* |
||||
* Example: |
||||
* // With some preprocessor options, this is unnecessary.
|
||||
* static UNNEEDED int counter; |
||||
* |
||||
* // With some preprocessor options, this is unnecessary.
|
||||
* static UNNEEDED void add_to_counter(int add) |
||||
* { |
||||
* counter += add; |
||||
* } |
||||
*/ |
||||
#define UNNEEDED __attribute__((unused)) |
||||
#endif |
||||
|
||||
#ifndef NEEDED |
||||
#if HAVE_ATTRIBUTE_USED |
||||
/**
|
||||
* NEEDED - a variable/function is needed |
||||
* |
||||
* This suppresses warnings about unused variables or functions, but tells |
||||
* the compiler that it must exist even if it (seems) unused. |
||||
* |
||||
* Example: |
||||
* // Even if this is unused, these are vital for debugging.
|
||||
* static NEEDED int counter; |
||||
* static NEEDED void dump_counter(void) |
||||
* { |
||||
* printf("Counter is %i\n", counter); |
||||
* } |
||||
*/ |
||||
#define NEEDED __attribute__((used)) |
||||
#else |
||||
/* Before used, unused functions and vars were always emitted. */ |
||||
#define NEEDED __attribute__((unused)) |
||||
#endif |
||||
#endif |
||||
|
||||
#ifndef UNUSED |
||||
/**
|
||||
* UNUSED - a parameter is unused |
||||
* |
||||
* Some compilers (eg. gcc with -W or -Wunused) warn about unused |
||||
* function parameters. This suppresses such warnings and indicates |
||||
* to the reader that it's deliberate. |
||||
* |
||||
* Example: |
||||
* // This is used as a callback, so needs to have this prototype.
|
||||
* static int some_callback(void *unused UNUSED) |
||||
* { |
||||
* return 0; |
||||
* } |
||||
*/ |
||||
#define UNUSED __attribute__((unused)) |
||||
#endif |
||||
#else |
||||
#ifndef UNNEEDED |
||||
#define UNNEEDED |
||||
#endif |
||||
#ifndef NEEDED |
||||
#define NEEDED |
||||
#endif |
||||
#ifndef UNUSED |
||||
#define UNUSED |
||||
#endif |
||||
#endif |
||||
|
||||
#ifndef IS_COMPILE_CONSTANT |
||||
#if HAVE_BUILTIN_CONSTANT_P |
||||
/**
|
||||
* IS_COMPILE_CONSTANT - does the compiler know the value of this expression? |
||||
* @expr: the expression to evaluate |
||||
* |
||||
* When an expression manipulation is complicated, it is usually better to |
||||
* implement it in a function. However, if the expression being manipulated is |
||||
* known at compile time, it is better to have the compiler see the entire |
||||
* expression so it can simply substitute the result. |
||||
* |
||||
* This can be done using the IS_COMPILE_CONSTANT() macro. |
||||
* |
||||
* Example: |
||||
* enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON }; |
||||
* |
||||
* // Out-of-line version.
|
||||
* const char *greek_name(enum greek greek); |
||||
* |
||||
* // Inline version.
|
||||
* static inline const char *_greek_name(enum greek greek) |
||||
* { |
||||
* switch (greek) { |
||||
* case ALPHA: return "alpha"; |
||||
* case BETA: return "beta"; |
||||
* case GAMMA: return "gamma"; |
||||
* case DELTA: return "delta"; |
||||
* case EPSILON: return "epsilon"; |
||||
* default: return "**INVALID**"; |
||||
* } |
||||
* } |
||||
* |
||||
* // Use inline if compiler knows answer. Otherwise call function
|
||||
* // to avoid copies of the same code everywhere.
|
||||
* #define greek_name(g) \ |
||||
* (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g)) |
||||
*/ |
||||
#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr) |
||||
#else |
||||
/* If we don't know, assume it's not. */ |
||||
#define IS_COMPILE_CONSTANT(expr) 0 |
||||
#endif |
||||
#endif |
||||
|
||||
#ifndef WARN_UNUSED_RESULT |
||||
#if HAVE_WARN_UNUSED_RESULT |
||||
/**
|
||||
* WARN_UNUSED_RESULT - warn if a function return value is unused. |
||||
* |
||||
* Used to mark a function where it is extremely unlikely that the caller |
||||
* can ignore the result, eg realloc(). |
||||
* |
||||
* Example: |
||||
* // buf param may be freed by this; need return value!
|
||||
* static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size) |
||||
* { |
||||
* return realloc(buf, (*size) *= 2); |
||||
* } |
||||
*/ |
||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) |
||||
#else |
||||
#define WARN_UNUSED_RESULT |
||||
#endif |
||||
#endif |
||||
#endif /* CCAN_COMPILER_H */ |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
#include <ccan/compiler/compiler.h> |
||||
|
||||
static void PRINTF_FMT(2,3) my_printf(int x, const char *fmt, ...) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
unsigned int i = 0; |
||||
|
||||
my_printf(1, "Not a pointer " |
||||
#ifdef FAIL |
||||
"%p", |
||||
#if !HAVE_ATTRIBUTE_PRINTF |
||||
#error "Unfortunately we don't fail if !HAVE_ATTRIBUTE_PRINTF." |
||||
#endif |
||||
#else |
||||
"%i", |
||||
#endif |
||||
i); |
||||
return 0; |
||||
} |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
#include <ccan/compiler/compiler.h> |
||||
#include <ccan/tap/tap.h> |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
plan_tests(2); |
||||
|
||||
ok1(!IS_COMPILE_CONSTANT(argc)); |
||||
#if HAVE_BUILTIN_CONSTANT_P |
||||
ok1(IS_COMPILE_CONSTANT(7)); |
||||
#else |
||||
pass("If !HAVE_BUILTIN_CONSTANT_P, IS_COMPILE_CONSTANT always false"); |
||||
#endif |
||||
return exit_status(); |
||||
} |
@ -0,0 +1,676 @@
@@ -0,0 +1,676 @@
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE |
||||
Version 3, 29 June 2007 |
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
||||
Everyone is permitted to copy and distribute verbatim copies |
||||
of this license document, but changing it is not allowed. |
||||
|
||||
Preamble |
||||
|
||||
The GNU General Public License is a free, copyleft license for |
||||
software and other kinds of works. |
||||
|
||||
The licenses for most software and other practical works are designed |
||||
to take away your freedom to share and change the works. By contrast, |
||||
the GNU General Public License is intended to guarantee your freedom to |
||||
share and change all versions of a program--to make sure it remains free |
||||
software for all its users. We, the Free Software Foundation, use the |
||||
GNU General Public License for most of our software; it applies also to |
||||
any other work released this way by its authors. You can apply it to |
||||
your programs, too. |
||||
|
||||
When we speak of free software, we are referring to freedom, not |
||||
price. Our General Public Licenses are designed to make sure that you |
||||
have the freedom to distribute copies of free software (and charge for |
||||
them if you wish), that you receive source code or can get it if you |
||||
want it, that you can change the software or use pieces of it in new |
||||
free programs, and that you know you can do these things. |
||||
|
||||
To protect your rights, we need to prevent others from denying you |
||||
these rights or asking you to surrender the rights. Therefore, you have |
||||
certain responsibilities if you distribute copies of the software, or if |
||||
you modify it: responsibilities to respect the freedom of others. |
||||
|
||||
For example, if you distribute copies of such a program, whether |
||||
gratis or for a fee, you must pass on to the recipients the same |
||||
freedoms that you received. You must make sure that they, too, receive |
||||
or can get the source code. And you must show them these terms so they |
||||
know their rights. |
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps: |
||||
(1) assert copyright on the software, and (2) offer you this License |
||||
giving you legal permission to copy, distribute and/or modify it. |
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains |
||||
that there is no warranty for this free software. For both users' and |
||||
authors' sake, the GPL requires that modified versions be marked as |
||||
changed, so that their problems will not be attributed erroneously to |
||||
authors of previous versions. |
||||
|
||||
Some devices are designed to deny users access to install or run |
||||
modified versions of the software inside them, although the manufacturer |
||||
can do so. This is fundamentally incompatible with the aim of |
||||
protecting users' freedom to change the software. The systematic |
||||
pattern of such abuse occurs in the area of products for individuals to |
||||
use, which is precisely where it is most unacceptable. Therefore, we |
||||
have designed this version of the GPL to prohibit the practice for those |
||||
products. If such problems arise substantially in other domains, we |
||||
stand ready to extend this provision to those domains in future versions |
||||
of the GPL, as needed to protect the freedom of users. |
||||
|
||||
Finally, every program is threatened constantly by software patents. |
||||
States should not allow patents to restrict development and use of |
||||
software on general-purpose computers, but in those that do, we wish to |
||||
avoid the special danger that patents applied to a free program could |
||||
make it effectively proprietary. To prevent this, the GPL assures that |
||||
patents cannot be used to render the program non-free. |
||||
|
||||
The precise terms and conditions for copying, distribution and |
||||
modification follow. |
||||
|
||||
TERMS AND CONDITIONS |
||||
|
||||
0. Definitions. |
||||
|
||||
"This License" refers to version 3 of the GNU General Public License. |
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of |
||||
works, such as semiconductor masks. |
||||
|
||||
"The Program" refers to any copyrightable work licensed under this |
||||
License. Each licensee is addressed as "you". "Licensees" and |
||||
"recipients" may be individuals or organizations. |
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work |
||||
in a fashion requiring copyright permission, other than the making of an |
||||
exact copy. The resulting work is called a "modified version" of the |
||||
earlier work or a work "based on" the earlier work. |
||||
|
||||
A "covered work" means either the unmodified Program or a work based |
||||
on the Program. |
||||
|
||||
To "propagate" a work means to do anything with it that, without |
||||
permission, would make you directly or secondarily liable for |
||||
infringement under applicable copyright law, except executing it on a |
||||
computer or modifying a private copy. Propagation includes copying, |
||||
distribution (with or without modification), making available to the |
||||
public, and in some countries other activities as well. |
||||
|
||||
To "convey" a work means any kind of propagation that enables other |
||||
parties to make or receive copies. Mere interaction with a user through |
||||
a computer network, with no transfer of a copy, is not conveying. |
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices" |
||||
to the extent that it includes a convenient and prominently visible |
||||
feature that (1) displays an appropriate copyright notice, and (2) |
||||
tells the user that there is no warranty for the work (except to the |
||||
extent that warranties are provided), that licensees may convey the |
||||
work under this License, and how to view a copy of this License. If |
||||
the interface presents a list of user commands or options, such as a |
||||
menu, a prominent item in the list meets this criterion. |
||||
|
||||
1. Source Code. |
||||
|
||||
The "source code" for a work means the preferred form of the work |
||||
for making modifications to it. "Object code" means any non-source |
||||
form of a work. |
||||
|
||||
A "Standard Interface" means an interface that either is an official |
||||
standard defined by a recognized standards body, or, in the case of |
||||
interfaces specified for a particular programming language, one that |
||||
is widely used among developers working in that language. |
||||
|
||||
The "System Libraries" of an executable work include anything, other |
||||
than the work as a whole, that (a) is included in the normal form of |
||||
packaging a Major Component, but which is not part of that Major |
||||
Component, and (b) serves only to enable use of the work with that |
||||
Major Component, or to implement a Standard Interface for which an |
||||
implementation is available to the public in source code form. A |
||||
"Major Component", in this context, means a major essential component |
||||
(kernel, window system, and so on) of the specific operating system |
||||
(if any) on which the executable work runs, or a compiler used to |
||||
produce the work, or an object code interpreter used to run it. |
||||
|
||||
The "Corresponding Source" for a work in object code form means all |
||||
the source code needed to generate, install, and (for an executable |
||||
work) run the object code and to modify the work, including scripts to |
||||
control those activities. However, it does not include the work's |
||||
System Libraries, or general-purpose tools or generally available free |
||||
programs which are used unmodified in performing those activities but |
||||
which are not part of the work. For example, Corresponding Source |
||||
includes interface definition files associated with source files for |
||||
the work, and the source code for shared libraries and dynamically |
||||
linked subprograms that the work is specifically designed to require, |
||||
such as by intimate data communication or control flow between those |
||||
subprograms and other parts of the work. |
||||
|
||||
The Corresponding Source need not include anything that users |
||||
can regenerate automatically from other parts of the Corresponding |
||||
Source. |
||||
|
||||
The Corresponding Source for a work in source code form is that |
||||
same work. |
||||
|
||||
2. Basic Permissions. |
||||
|
||||
All rights granted under this License are granted for the term of |
||||
copyright on the Program, and are irrevocable provided the stated |
||||
conditions are met. This License explicitly affirms your unlimited |
||||
permission to run the unmodified Program. The output from running a |
||||
covered work is covered by this License only if the output, given its |
||||
content, constitutes a covered work. This License acknowledges your |
||||
rights of fair use or other equivalent, as provided by copyright law. |
||||
|
||||
You may make, run and propagate covered works that you do not |
||||
convey, without conditions so long as your license otherwise remains |
||||
in force. You may convey covered works to others for the sole purpose |
||||
of having them make modifications exclusively for you, or provide you |
||||
with facilities for running those works, provided that you comply with |
||||
the terms of this License in conveying all material for which you do |
||||
not control copyright. Those thus making or running the covered works |
||||
for you must do so exclusively on your behalf, under your direction |
||||
and control, on terms that prohibit them from making any copies of |
||||
your copyrighted material outside their relationship with you. |
||||
|
||||
Conveying under any other circumstances is permitted solely under |
||||
the conditions stated below. Sublicensing is not allowed; section 10 |
||||
makes it unnecessary. |
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
||||
|
||||
No covered work shall be deemed part of an effective technological |
||||
measure under any applicable law fulfilling obligations under article |
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
||||
similar laws prohibiting or restricting circumvention of such |
||||
measures. |
||||
|
||||
When you convey a covered work, you waive any legal power to forbid |
||||
circumvention of technological measures to the extent such circumvention |
||||
is effected by exercising rights under this License with respect to |
||||
the covered work, and you disclaim any intention to limit operation or |
||||
modification of the work as a means of enforcing, against the work's |
||||
users, your or third parties' legal rights to forbid circumvention of |
||||
technological measures. |
||||
|
||||
4. Conveying Verbatim Copies. |
||||
|
||||
You may convey verbatim copies of the Program's source code as you |
||||
receive it, in any medium, provided that you conspicuously and |
||||
appropriately publish on each copy an appropriate copyright notice; |
||||
keep intact all notices stating that this License and any |
||||
non-permissive terms added in accord with section 7 apply to the code; |
||||
keep intact all notices of the absence of any warranty; and give all |
||||
recipients a copy of this License along with the Program. |
||||
|
||||
You may charge any price or no price for each copy that you convey, |
||||
and you may offer support or warranty protection for a fee. |
||||
|
||||
5. Conveying Modified Source Versions. |
||||
|
||||
You may convey a work based on the Program, or the modifications to |
||||
produce it from the Program, in the form of source code under the |
||||
terms of section 4, provided that you also meet all of these conditions: |
||||
|
||||
a) The work must carry prominent notices stating that you modified |
||||
it, and giving a relevant date. |
||||
|
||||
b) The work must carry prominent notices stating that it is |
||||
released under this License and any conditions added under section |
||||
7. This requirement modifies the requirement in section 4 to |
||||
"keep intact all notices". |
||||
|
||||
c) You must license the entire work, as a whole, under this |
||||
License to anyone who comes into possession of a copy. This |
||||
License will therefore apply, along with any applicable section 7 |
||||
additional terms, to the whole of the work, and all its parts, |
||||
regardless of how they are packaged. This License gives no |
||||
permission to license the work in any other way, but it does not |
||||
invalidate such permission if you have separately received it. |
||||
|
||||
d) If the work has interactive user interfaces, each must display |
||||
Appropriate Legal Notices; however, if the Program has interactive |
||||
interfaces that do not display Appropriate Legal Notices, your |
||||
work need not make them do so. |
||||
|
||||
A compilation of a covered work with other separate and independent |
||||
works, which are not by their nature extensions of the covered work, |
||||
and which are not combined with it such as to form a larger program, |
||||
in or on a volume of a storage or distribution medium, is called an |
||||
"aggregate" if the compilation and its resulting copyright are not |
||||
used to limit the access or legal rights of the compilation's users |
||||
beyond what the individual works permit. Inclusion of a covered work |
||||
in an aggregate does not cause this License to apply to the other |
||||
parts of the aggregate. |
||||
|
||||
6. Conveying Non-Source Forms. |
||||
|
||||
You may convey a covered work in object code form under the terms |
||||
of sections 4 and 5, provided that you also convey the |
||||
machine-readable Corresponding Source under the terms of this License, |
||||
in one of these ways: |
||||
|
||||
a) Convey the object code in, or embodied in, a physical product |
||||
(including a physical distribution medium), accompanied by the |
||||
Corresponding Source fixed on a durable physical medium |
||||
customarily used for software interchange. |
||||
|
||||
b) Convey the object code in, or embodied in, a physical product |
||||
(including a physical distribution medium), accompanied by a |
||||
written offer, valid for at least three years and valid for as |
||||
long as you offer spare parts or customer support for that product |
||||
model, to give anyone who possesses the object code either (1) a |
||||
copy of the Corresponding Source for all the software in the |
||||
product that is covered by this License, on a durable physical |
||||
medium customarily used for software interchange, for a price no |
||||
more than your reasonable cost of physically performing this |
||||
conveying of source, or (2) access to copy the |
||||
Corresponding Source from a network server at no charge. |
||||
|
||||
c) Convey individual copies of the object code with a copy of the |
||||
written offer to provide the Corresponding Source. This |
||||
alternative is allowed only occasionally and noncommercially, and |
||||
only if you received the object code with such an offer, in accord |
||||
with subsection 6b. |
||||
|
||||
d) Convey the object code by offering access from a designated |
||||
place (gratis or for a charge), and offer equivalent access to the |
||||
Corresponding Source in the same way through the same place at no |
||||
further charge. You need not require recipients to copy the |
||||
Corresponding Source along with the object code. If the place to |
||||
copy the object code is a network server, the Corresponding Source |
||||
may be on a different server (operated by you or a third party) |
||||
that supports equivalent copying facilities, provided you maintain |
||||
clear directions next to the object code saying where to find the |
||||
Corresponding Source. Regardless of what server hosts the |
||||
Corresponding Source, you remain obligated to ensure that it is |
||||
available for as long as needed to satisfy these requirements. |
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided |
||||
you inform other peers where the object code and Corresponding |
||||
Source of the work are being offered to the general public at no |
||||
charge under subsection 6d. |
||||
|
||||
A separable portion of the object code, whose source code is excluded |
||||
from the Corresponding Source as a System Library, need not be |
||||
included in conveying the object code work. |
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any |
||||
tangible personal property which is normally used for personal, family, |
||||
or household purposes, or (2) anything designed or sold for incorporation |
||||
into a dwelling. In determining whether a product is a consumer product, |
||||
doubtful cases shall be resolved in favor of coverage. For a particular |
||||
product received by a particular user, "normally used" refers to a |
||||
typical or common use of that class of product, regardless of the status |
||||
of the particular user or of the way in which the particular user |
||||
actually uses, or expects or is expected to use, the product. A product |
||||
is a consumer product regardless of whether the product has substantial |
||||
commercial, industrial or non-consumer uses, unless such uses represent |
||||
the only significant mode of use of the product. |
||||
|
||||
"Installation Information" for a User Product means any methods, |
||||
procedures, authorization keys, or other information required to install |
||||
and execute modified versions of a covered work in that User Product from |
||||
a modified version of its Corresponding Source. The information must |
||||
suffice to ensure that the continued functioning of the modified object |
||||
code is in no case prevented or interfered with solely because |
||||
modification has been made. |
||||
|
||||
If you convey an object code work under this section in, or with, or |
||||
specifically for use in, a User Product, and the conveying occurs as |
||||
part of a transaction in which the right of possession and use of the |
||||
User Product is transferred to the recipient in perpetuity or for a |
||||
fixed term (regardless of how the transaction is characterized), the |
||||
Corresponding Source conveyed under this section must be accompanied |
||||
by the Installation Information. But this requirement does not apply |
||||
if neither you nor any third party retains the ability to install |
||||
modified object code on the User Product (for example, the work has |
||||
been installed in ROM). |
||||
|
||||
The requirement to provide Installation Information does not include a |
||||
requirement to continue to provide support service, warranty, or updates |
||||
for a work that has been modified or installed by the recipient, or for |
||||
the User Product in which it has been modified or installed. Access to a |
||||
network may be denied when the modification itself materially and |
||||
adversely affects the operation of the network or violates the rules and |
||||
protocols for communication across the network. |
||||
|
||||
Corresponding Source conveyed, and Installation Information provided, |
||||
in accord with this section must be in a format that is publicly |
||||
documented (and with an implementation available to the public in |
||||
source code form), and must require no special password or key for |
||||
unpacking, reading or copying. |
||||
|
||||
7. Additional Terms. |
||||
|
||||
"Additional permissions" are terms that supplement the terms of this |
||||
License by making exceptions from one or more of its conditions. |
||||
Additional permissions that are applicable to the entire Program shall |
||||
be treated as though they were included in this License, to the extent |
||||
that they are valid under applicable law. If additional permissions |
||||
apply only to part of the Program, that part may be used separately |
||||
under those permissions, but the entire Program remains governed by |
||||
this License without regard to the additional permissions. |
||||
|
||||
When you convey a copy of a covered work, you may at your option |
||||
remove any additional permissions from that copy, or from any part of |
||||
it. (Additional permissions may be written to require their own |
||||
removal in certain cases when you modify the work.) You may place |
||||
additional permissions on material, added by you to a covered work, |
||||
for which you have or can give appropriate copyright permission. |
||||
|
||||
Notwithstanding any other provision of this License, for material you |
||||
add to a covered work, you may (if authorized by the copyright holders of |
||||
that material) supplement the terms of this License with terms: |
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the |
||||
terms of sections 15 and 16 of this License; or |
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or |
||||
author attributions in that material or in the Appropriate Legal |
||||
Notices displayed by works containing it; or |
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or |
||||
requiring that modified versions of such material be marked in |
||||
reasonable ways as different from the original version; or |
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or |
||||
authors of the material; or |
||||
|
||||
e) Declining to grant rights under trademark law for use of some |
||||
trade names, trademarks, or service marks; or |
||||
|
||||
f) Requiring indemnification of licensors and authors of that |
||||
material by anyone who conveys the material (or modified versions of |
||||
it) with contractual assumptions of liability to the recipient, for |
||||
any liability that these contractual assumptions directly impose on |
||||
those licensors and authors. |
||||
|
||||
All other non-permissive additional terms are considered "further |
||||
restrictions" within the meaning of section 10. If the Program as you |
||||
received it, or any part of it, contains a notice stating that it is |
||||
governed by this License along with a term that is a further |
||||
restriction, you may remove that term. If a license document contains |
||||
a further restriction but permits relicensing or conveying under this |
||||
License, you may add to a covered work material governed by the terms |
||||
of that license document, provided that the further restriction does |
||||
not survive such relicensing or conveying. |
||||
|
||||
If you add terms to a covered work in accord with this section, you |
||||
must place, in the relevant source files, a statement of the |
||||
additional terms that apply to those files, or a notice indicating |
||||
where to find the applicable terms. |
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the |
||||
form of a separately written license, or stated as exceptions; |
||||
the above requirements apply either way. |
||||
|
||||
8. Termination. |
||||
|
||||
You may not propagate or modify a covered work except as expressly |
||||
provided under this License. Any attempt otherwise to propagate or |
||||
modify it is void, and will automatically terminate your rights under |
||||
this License (including any patent licenses granted under the third |
||||
paragraph of section 11). |
||||
|
||||
However, if you cease all violation of this License, then your |
||||
license from a particular copyright holder is reinstated (a) |
||||
provisionally, unless and until the copyright holder explicitly and |
||||
finally terminates your license, and (b) permanently, if the copyright |
||||
holder fails to notify you of the violation by some reasonable means |
||||
prior to 60 days after the cessation. |
||||
|
||||
Moreover, your license from a particular copyright holder is |
||||
reinstated permanently if the copyright holder notifies you of the |
||||
violation by some reasonable means, this is the first time you have |
||||
received notice of violation of this License (for any work) from that |
||||
copyright holder, and you cure the violation prior to 30 days after |
||||
your receipt of the notice. |
||||
|
||||
Termination of your rights under this section does not terminate the |
||||
licenses of parties who have received copies or rights from you under |
||||
this License. If your rights have been terminated and not permanently |
||||
reinstated, you do not qualify to receive new licenses for the same |
||||
material under section 10. |
||||
|
||||
9. Acceptance Not Required for Having Copies. |
||||
|
||||
You are not required to accept this License in order to receive or |
||||
run a copy of the Program. Ancillary propagation of a covered work |
||||
occurring solely as a consequence of using peer-to-peer transmission |
||||
to receive a copy likewise does not require acceptance. However, |
||||
nothing other than this License grants you permission to propagate or |
||||
modify any covered work. These actions infringe copyright if you do |
||||
not accept this License. Therefore, by modifying or propagating a |
||||
covered work, you indicate your acceptance of this License to do so. |
||||
|
||||
10. Automatic Licensing of Downstream Recipients. |
||||
|
||||
Each time you convey a covered work, the recipient automatically |
||||
receives a license from the original licensors, to run, modify and |
||||
propagate that work, subject to this License. You are not responsible |
||||
for enforcing compliance by third parties with this License. |
||||
|
||||
An "entity transaction" is a transaction transferring control of an |
||||
organization, or substantially all assets of one, or subdividing an |
||||
organization, or merging organizations. If propagation of a covered |
||||
work results from an entity transaction, each party to that |
||||
transaction who receives a copy of the work also receives whatever |
||||
licenses to the work the party's predecessor in interest had or could |
||||
give under the previous paragraph, plus a right to possession of the |
||||
Corresponding Source of the work from the predecessor in interest, if |
||||
the predecessor has it or can get it with reasonable efforts. |
||||
|
||||
You may not impose any further restrictions on the exercise of the |
||||
rights granted or affirmed under this License. For example, you may |
||||
not impose a license fee, royalty, or other charge for exercise of |
||||
rights granted under this License, and you may not initiate litigation |
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that |
||||
any patent claim is infringed by making, using, selling, offering for |
||||
sale, or importing the Program or any portion of it. |
||||
|
||||
11. Patents. |
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this |
||||
License of the Program or a work on which the Program is based. The |
||||
work thus licensed is called the contributor's "contributor version". |
||||
|
||||
A contributor's "essential patent claims" are all patent claims |
||||
owned or controlled by the contributor, whether already acquired or |
||||
hereafter acquired, that would be infringed by some manner, permitted |
||||
by this License, of making, using, or selling its contributor version, |
||||
but do not include claims that would be infringed only as a |
||||
consequence of further modification of the contributor version. For |
||||
purposes of this definition, "control" includes the right to grant |
||||
patent sublicenses in a manner consistent with the requirements of |
||||
this License. |
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free |
||||
patent license under the contributor's essential patent claims, to |
||||
make, use, sell, offer for sale, import and otherwise run, modify and |
||||
propagate the contents of its contributor version. |
||||
|
||||
In the following three paragraphs, a "patent license" is any express |
||||
agreement or commitment, however denominated, not to enforce a patent |
||||
(such as an express permission to practice a patent or covenant not to |
||||
sue for patent infringement). To "grant" such a patent license to a |
||||
party means to make such an agreement or commitment not to enforce a |
||||
patent against the party. |
||||
|
||||
If you convey a covered work, knowingly relying on a patent license, |
||||
and the Corresponding Source of the work is not available for anyone |
||||
to copy, free of charge and under the terms of this License, through a |
||||
publicly available network server or other readily accessible means, |
||||
then you must either (1) cause the Corresponding Source to be so |
||||
available, or (2) arrange to deprive yourself of the benefit of the |
||||
patent license for this particular work, or (3) arrange, in a manner |
||||
consistent with the requirements of this License, to extend the patent |
||||
license to downstream recipients. "Knowingly relying" means you have |
||||
actual knowledge that, but for the patent license, your conveying the |
||||
covered work in a country, or your recipient's use of the covered work |
||||
in a country, would infringe one or more identifiable patents in that |
||||
country that you have reason to believe are valid. |
||||
|
||||
If, pursuant to or in connection with a single transaction or |
||||
arrangement, you convey, or propagate by procuring conveyance of, a |
||||
covered work, and grant a patent license to some of the parties |
||||
receiving the covered work authorizing them to use, propagate, modify |
||||
or convey a specific copy of the covered work, then the patent license |
||||
you grant is automatically extended to all recipients of the covered |
||||
work and works based on it. |
||||
|
||||
A patent license is "discriminatory" if it does not include within |
||||
the scope of its coverage, prohibits the exercise of, or is |
||||
conditioned on the non-exercise of one or more of the rights that are |
||||
specifically granted under this License. You may not convey a covered |
||||
work if you are a party to an arrangement with a third party that is |
||||
in the business of distributing software, under which you make payment |
||||
to the third party based on the extent of your activity of conveying |
||||
the work, and under which the third party grants, to any of the |
||||
parties who would receive the covered work from you, a discriminatory |
||||
patent license (a) in connection with copies of the covered work |
||||
conveyed by you (or copies made from those copies), or (b) primarily |
||||
for and in connection with specific products or compilations that |
||||
contain the covered work, unless you entered into that arrangement, |
||||
or that patent license was granted, prior to 28 March 2007. |
||||
|
||||
Nothing in this License shall be construed as excluding or limiting |
||||
any implied license or other defenses to infringement that may |
||||
otherwise be available to you under applicable patent law. |
||||
|
||||
12. No Surrender of Others' Freedom. |
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or |
||||
otherwise) that contradict the conditions of this License, they do not |
||||
excuse you from the conditions of this License. If you cannot convey a |
||||
covered work so as to satisfy simultaneously your obligations under this |
||||
License and any other pertinent obligations, then as a consequence you may |
||||
not convey it at all. For example, if you agree to terms that obligate you |
||||
to collect a royalty for further conveying from those to whom you convey |
||||
the Program, the only way you could satisfy both those terms and this |
||||
License would be to refrain entirely from conveying the Program. |
||||
|
||||
13. Use with the GNU Affero General Public License. |
||||
|
||||
Notwithstanding any other provision of this License, you have |
||||
permission to link or combine any covered work with a work licensed |
||||
under version 3 of the GNU Affero General Public License into a single |
||||
combined work, and to convey the resulting work. The terms of this |
||||
License will continue to apply to the part which is the covered work, |
||||
but the special requirements of the GNU Affero General Public License, |
||||
section 13, concerning interaction through a network will apply to the |
||||
combination as such. |
||||
|
||||
14. Revised Versions of this License. |
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of |
||||
the GNU General Public License from time to time. Such new versions will |
||||
be similar in spirit to the present version, but may differ in detail to |
||||
address new problems or concerns. |
||||
|
||||
Each version is given a distinguishing version number. If the |
||||
Program specifies that a certain numbered version of the GNU General |
||||
Public License "or any later version" applies to it, you have the |
||||
option of following the terms and conditions either of that numbered |
||||
version or of any later version published by the Free Software |
||||
Foundation. If the Program does not specify a version number of the |
||||
GNU General Public License, you may choose any version ever published |
||||
by the Free Software Foundation. |
||||
|
||||
If the Program specifies that a proxy can decide which future |
||||
versions of the GNU General Public License can be used, that proxy's |
||||
public statement of acceptance of a version permanently authorizes you |
||||
to choose that version for the Program. |
||||
|
||||
Later license versions may give you additional or different |
||||
permissions. However, no additional obligations are imposed on any |
||||
author or copyright holder as a result of your choosing to follow a |
||||
later version. |
||||
|
||||
15. Disclaimer of Warranty. |
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
||||
|
||||
16. Limitation of Liability. |
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
||||
SUCH DAMAGES. |
||||
|
||||
17. Interpretation of Sections 15 and 16. |
||||
|
||||
If the disclaimer of warranty and limitation of liability provided |
||||
above cannot be given local legal effect according to their terms, |
||||
reviewing courts shall apply local law that most closely approximates |
||||
an absolute waiver of all civil liability in connection with the |
||||
Program, unless a warranty or assumption of liability accompanies a |
||||
copy of the Program in return for a fee. |
||||
|
||||
END OF TERMS AND CONDITIONS |
||||
|
||||
How to Apply These Terms to Your New Programs |
||||
|
||||
If you develop a new program, and you want it to be of the greatest |
||||
possible use to the public, the best way to achieve this is to make it |
||||
free software which everyone can redistribute and change under these terms. |
||||
|
||||
To do so, attach the following notices to the program. It is safest |
||||
to attach them to the start of each source file to most effectively |
||||
state the exclusion of warranty; and each file should have at least |
||||
the "copyright" line and a pointer to where the full notice is found. |
||||
|
||||
<one line to give the program's name and a brief idea of what it does.> |
||||
Copyright (C) <year> <name of author> |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
Also add information on how to contact you by electronic and paper mail. |
||||
|
||||
If the program does terminal interaction, make it output a short |
||||
notice like this when it starts in an interactive mode: |
||||
|
||||
<program> Copyright (C) <year> <name of author> |
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
||||
This is free software, and you are welcome to redistribute it |
||||
under certain conditions; type `show c' for details. |
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate |
||||
parts of the General Public License. Of course, your program's commands |
||||
might be different; for a GUI interface, you would use an "about box". |
||||
|
||||
You should also get your employer (if you work as a programmer) or school, |
||||
if any, to sign a "copyright disclaimer" for the program, if necessary. |
||||
For more information on this, and how to apply and follow the GNU GPL, see |
||||
<http://www.gnu.org/licenses/>. |
||||
|
||||
The GNU General Public License does not permit incorporating your program |
||||
into proprietary programs. If your program is a subroutine library, you |
||||
may consider it more useful to permit linking proprietary applications with |
||||
the library. If this is what you want to do, use the GNU Lesser General |
||||
Public License instead of this License. But first, please read |
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>. |
||||
|
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include "config.h" |
||||
|
||||
/** |
||||
* opt - simple command line parsing |
||||
* |
||||
* Simple but powerful command line parsing. |
||||
* |
||||
* Example: |
||||
* #include <ccan/opt/opt.h> |
||||
* #include <stdio.h> |
||||
* #include <stdlib.h> |
||||
* |
||||
* static bool someflag; |
||||
* static int verbose; |
||||
* static char *somestring; |
||||
* |
||||
* static struct opt_table opts[] = { |
||||
* OPT_WITHOUT_ARG("--verbose|-v", opt_inc_intval, &verbose, |
||||
* "Verbose mode (can be specified more than once)"), |
||||
* OPT_WITHOUT_ARG("--someflag", opt_set_bool, &someflag, |
||||
* "Set someflag"), |
||||
* OPT_WITH_ARG("--somefile=<filename>", opt_set_charp, opt_show_charp, |
||||
* &somestring, "Set somefile to <filename>"), |
||||
* OPT_WITHOUT_ARG("--usage|--help|-h", opt_usage_and_exit, |
||||
* "args...\nA silly test program.", |
||||
* "Print this message."), |
||||
* OPT_ENDTABLE |
||||
* }; |
||||
* |
||||
* int main(int argc, char *argv[]) |
||||
* { |
||||
* int i; |
||||
* |
||||
* opt_register_table(opts, NULL); |
||||
* // For fun, register an extra one. |
||||
* opt_register_noarg("--no-someflag", opt_set_invbool, &someflag, |
||||
* "Unset someflag"); |
||||
* if (!opt_parse(&argc, argv, opt_log_stderr)) |
||||
* exit(1); |
||||
* |
||||
* printf("someflag = %i, verbose = %i, somestring = %s\n", |
||||
* someflag, verbose, somestring); |
||||
* printf("%u args left over:", argc - 1); |
||||
* for (i = 1; i < argc; i++) |
||||
* printf(" %s", argv[i]); |
||||
* printf("\n"); |
||||
* return 0; |
||||
* } |
||||
* |
||||
* License: GPL (3 or any later version) |
||||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
||||
*/ |
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
if (argc != 2) |
||||
return 1; |
||||
|
||||
if (strcmp(argv[1], "depends") == 0) { |
||||
printf("ccan/typesafe_cb\n"); |
||||
printf("ccan/compiler\n"); |
||||
return 0; |
||||
} |
||||
|
||||
return 1; |
||||
} |
@ -0,0 +1,173 @@
@@ -0,0 +1,173 @@
|
||||
#include <ccan/opt/opt.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
#include "private.h" |
||||
|
||||
/* Upper bound to sprintf this simple type? Each 3 bits < 1 digit. */ |
||||
#define CHAR_SIZE(type) (((sizeof(type)*CHAR_BIT + 2) / 3) + 1) |
||||
|
||||
/* FIXME: asprintf module? */ |
||||
static char *arg_bad(const char *fmt, const char *arg) |
||||
{ |
||||
char *str = malloc(strlen(fmt) + strlen(arg)); |
||||
sprintf(str, fmt, arg); |
||||
return str; |
||||
} |
||||
|
||||
char *opt_set_bool(bool *b) |
||||
{ |
||||
*b = true; |
||||
return NULL; |
||||
} |
||||
|
||||
char *opt_set_invbool(bool *b) |
||||
{ |
||||
*b = false; |
||||
return NULL; |
||||
} |
||||
|
||||
char *opt_set_bool_arg(const char *arg, bool *b) |
||||
{ |
||||
if (!strcasecmp(arg, "yes") || !strcasecmp(arg, "true")) |
||||
return opt_set_bool(b); |
||||
if (!strcasecmp(arg, "no") || !strcasecmp(arg, "false")) |
||||
return opt_set_invbool(b); |
||||
|
||||
return opt_invalid_argument(arg); |
||||
} |
||||
|
||||
char *opt_set_invbool_arg(const char *arg, bool *b) |
||||
{ |
||||
char *err = opt_set_bool_arg(arg, b); |
||||
|
||||
if (!err) |
||||
*b = !*b; |
||||
return err; |
||||
} |
||||
|
||||
/* Set a char *. */ |
||||
char *opt_set_charp(const char *arg, char **p) |
||||
{ |
||||
*p = (char *)arg; |
||||
return NULL; |
||||
} |
||||
|
||||
/* Set an integer value, various forms. Sets to 1 on arg == NULL. */ |
||||
char *opt_set_intval(const char *arg, int *i) |
||||
{ |
||||
long l; |
||||
char *err = opt_set_longval(arg, &l); |
||||
|
||||
if (err) |
||||
return err; |
||||
*i = l; |
||||
/* Beware truncation... */ |
||||
if (*i != l) |
||||
return arg_bad("value '%s' does not fit into an integer", arg); |
||||
return err; |
||||
} |
||||
|
||||
char *opt_set_uintval(const char *arg, unsigned int *ui) |
||||
{ |
||||
int i; |
||||
char *err = opt_set_intval(arg, &i); |
||||
|
||||
if (err) |
||||
return err; |
||||
if (i < 0) |
||||
return arg_bad("'%s' is negative", arg); |
||||
*ui = i; |
||||
return NULL; |
||||
} |
||||
|
||||
char *opt_set_longval(const char *arg, long *l) |
||||
{ |
||||
char *endp; |
||||
|
||||
/* This is how the manpage says to do it. Yech. */ |
||||
errno = 0; |
||||
*l = strtol(arg, &endp, 0); |
||||
if (*endp || !arg[0]) |
||||
return arg_bad("'%s' is not a number", arg); |
||||
if (errno) |
||||
return arg_bad("'%s' is out of range", arg); |
||||
return NULL; |
||||
} |
||||
|
||||
char *opt_set_ulongval(const char *arg, unsigned long *ul) |
||||
{ |
||||
long int l; |
||||
char *err; |
||||
|
||||
err = opt_set_longval(arg, &l); |
||||
if (err) |
||||
return err; |
||||
*ul = l; |
||||
if (l < 0) |
||||
return arg_bad("'%s' is negative", arg); |
||||
return NULL; |
||||
} |
||||
|
||||
char *opt_inc_intval(int *i) |
||||
{ |
||||
(*i)++; |
||||
return NULL; |
||||
} |
||||
|
||||
/* Display version string. */ |
||||
char *opt_version_and_exit(const char *version) |
||||
{ |
||||
printf("%s\n", version); |
||||
exit(0); |
||||
} |
||||
|
||||
char *opt_usage_and_exit(const char *extra) |
||||
{ |
||||
printf("%s", opt_usage(opt_argv0, extra)); |
||||
exit(0); |
||||
} |
||||
|
||||
void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b) |
||||
{ |
||||
strncpy(buf, *b ? "true" : "false", OPT_SHOW_LEN); |
||||
} |
||||
|
||||
void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b) |
||||
{ |
||||
strncpy(buf, *b ? "false" : "true", OPT_SHOW_LEN); |
||||
} |
||||
|
||||
void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p) |
||||
{ |
||||
size_t len = strlen(*p); |
||||
buf[0] = '"'; |
||||
if (len > OPT_SHOW_LEN - 2) |
||||
len = OPT_SHOW_LEN - 2; |
||||
strncpy(buf+1, *p, len); |
||||
buf[1+len] = '"'; |
||||
if (len < OPT_SHOW_LEN - 2) |
||||
buf[2+len] = '\0'; |
||||
} |
||||
|
||||
/* Set an integer value, various forms. Sets to 1 on arg == NULL. */ |
||||
void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i) |
||||
{ |
||||
snprintf(buf, OPT_SHOW_LEN, "%i", *i); |
||||
} |
||||
|
||||
void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui) |
||||
{ |
||||
snprintf(buf, OPT_SHOW_LEN, "%u", *ui); |
||||
} |
||||
|
||||
void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l) |
||||
{ |
||||
snprintf(buf, OPT_SHOW_LEN, "%li", *l); |
||||
} |
||||
|
||||
void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul) |
||||
{ |
||||
snprintf(buf, OPT_SHOW_LEN, "%lu", *ul); |
||||
} |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
ccan/opt/helpers.o: ccan/opt/helpers.c ccan/opt/opt.h \ |
||||
ccan/compiler/compiler.h config.h ccan/typesafe_cb/typesafe_cb.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ |
||||
/usr/include/stdlib.h /usr/include/features.h \ |
||||
/usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ |
||||
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ |
||||
/usr/include/gnu/stubs-32.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ |
||||
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ |
||||
/usr/include/endian.h /usr/include/bits/endian.h \ |
||||
/usr/include/bits/byteswap.h /usr/include/xlocale.h \ |
||||
/usr/include/sys/types.h /usr/include/bits/types.h \ |
||||
/usr/include/bits/typesizes.h /usr/include/time.h \ |
||||
/usr/include/sys/select.h /usr/include/bits/select.h \ |
||||
/usr/include/bits/sigset.h /usr/include/bits/time.h \ |
||||
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ |
||||
/usr/include/alloca.h /usr/include/string.h /usr/include/errno.h \ |
||||
/usr/include/bits/errno.h /usr/include/linux/errno.h \ |
||||
/usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ |
||||
/usr/include/asm-generic/errno-base.h /usr/include/stdio.h \ |
||||
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdarg.h \ |
||||
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ |
||||
ccan/opt/private.h |
Binary file not shown.
@ -0,0 +1,236 @@
@@ -0,0 +1,236 @@
|
||||
#include <ccan/opt/opt.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <err.h> |
||||
#include <assert.h> |
||||
#include <stdarg.h> |
||||
#include <stdint.h> |
||||
#include "private.h" |
||||
|
||||
struct opt_table *opt_table; |
||||
unsigned int opt_count, opt_num_short, opt_num_short_arg, opt_num_long; |
||||
const char *opt_argv0; |
||||
|
||||
/* Returns string after first '-'. */ |
||||
static const char *first_name(const char *names, unsigned *len) |
||||
{ |
||||
*len = strcspn(names + 1, "|= "); |
||||
return names + 1; |
||||
} |
||||
|
||||
static const char *next_name(const char *names, unsigned *len) |
||||
{ |
||||
names += *len; |
||||
if (names[0] == ' ' || names[0] == '=' || names[0] == '\0') |
||||
return NULL; |
||||
return first_name(names + 1, len); |
||||
} |
||||
|
||||
static const char *first_opt(unsigned *i, unsigned *len) |
||||
{ |
||||
for (*i = 0; *i < opt_count; (*i)++) { |
||||
if (opt_table[*i].type == OPT_SUBTABLE) |
||||
continue; |
||||
return first_name(opt_table[*i].names, len); |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
static const char *next_opt(const char *p, unsigned *i, unsigned *len) |
||||
{ |
||||
for (; *i < opt_count; (*i)++) { |
||||
if (opt_table[*i].type == OPT_SUBTABLE) |
||||
continue; |
||||
if (!p) |
||||
return first_name(opt_table[*i].names, len); |
||||
p = next_name(p, len); |
||||
if (p) |
||||
return p; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
const char *first_lopt(unsigned *i, unsigned *len) |
||||
{ |
||||
const char *p; |
||||
for (p = first_opt(i, len); p; p = next_opt(p, i, len)) { |
||||
if (p[0] == '-') { |
||||
/* Skip leading "-" */ |
||||
(*len)--; |
||||
p++; |
||||
break; |
||||
} |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
const char *next_lopt(const char *p, unsigned *i, unsigned *len) |
||||
{ |
||||
for (p = next_opt(p, i, len); p; p = next_opt(p, i, len)) { |
||||
if (p[0] == '-') { |
||||
/* Skip leading "-" */ |
||||
(*len)--; |
||||
p++; |
||||
break; |
||||
} |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
const char *first_sopt(unsigned *i) |
||||
{ |
||||
const char *p; |
||||
unsigned int len = 0 /* GCC bogus warning */; |
||||
|
||||
for (p = first_opt(i, &len); p; p = next_opt(p, i, &len)) { |
||||
if (p[0] != '-') |
||||
break; |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
const char *next_sopt(const char *p, unsigned *i) |
||||
{ |
||||
unsigned int len = 1; |
||||
for (p = next_opt(p, i, &len); p; p = next_opt(p, i, &len)) { |
||||
if (p[0] != '-') |
||||
break; |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
static void check_opt(const struct opt_table *entry) |
||||
{ |
||||
const char *p; |
||||
unsigned len; |
||||
|
||||
if (entry->type != OPT_HASARG && entry->type != OPT_NOARG) |
||||
errx(1, "Option %s: unknown entry type %u", |
||||
entry->names, entry->type); |
||||
|
||||
if (!entry->desc) |
||||
errx(1, "Option %s: description cannot be NULL", entry->names); |
||||
|
||||
|
||||
if (entry->names[0] != '-') |
||||
errx(1, "Option %s: does not begin with '-'", entry->names); |
||||
|
||||
for (p = first_name(entry->names, &len); p; p = next_name(p, &len)) { |
||||
if (*p == '-') { |
||||
if (len == 1) |
||||
errx(1, "Option %s: invalid long option '--'", |
||||
entry->names); |
||||
opt_num_long++; |
||||
} else { |
||||
if (len != 1) |
||||
errx(1, "Option %s: invalid short option" |
||||
" '%.*s'", entry->names, len+1, p-1); |
||||
opt_num_short++; |
||||
if (entry->type == OPT_HASARG) |
||||
opt_num_short_arg++; |
||||
} |
||||
/* Don't document args unless there are some. */ |
||||
if (entry->type == OPT_NOARG) { |
||||
if (p[len] == ' ' || p[len] == '=') |
||||
errx(1, "Option %s: does not take arguments" |
||||
" '%s'", entry->names, p+len+1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void add_opt(const struct opt_table *entry) |
||||
{ |
||||
opt_table = realloc(opt_table, sizeof(opt_table[0]) * (opt_count+1)); |
||||
opt_table[opt_count++] = *entry; |
||||
} |
||||
|
||||
void _opt_register(const char *names, enum opt_type type, |
||||
char *(*cb)(void *arg), |
||||
char *(*cb_arg)(const char *optarg, void *arg), |
||||
void (*show)(char buf[OPT_SHOW_LEN], const void *arg), |
||||
const void *arg, const char *desc) |
||||
{ |
||||
struct opt_table opt; |
||||
opt.names = names; |
||||
opt.type = type; |
||||
opt.cb = cb; |
||||
opt.cb_arg = cb_arg; |
||||
opt.show = show; |
||||
opt.u.carg = arg; |
||||
opt.desc = desc; |
||||
check_opt(&opt); |
||||
add_opt(&opt); |
||||
} |
||||
|
||||
void opt_register_table(const struct opt_table entry[], const char *desc) |
||||
{ |
||||
unsigned int i, start = opt_count; |
||||
|
||||
if (desc) { |
||||
struct opt_table heading = OPT_SUBTABLE(NULL, desc); |
||||
add_opt(&heading); |
||||
} |
||||
for (i = 0; entry[i].type != OPT_END; i++) { |
||||
if (entry[i].type == OPT_SUBTABLE) |
||||
opt_register_table(subtable_of(&entry[i]), |
||||
entry[i].desc); |
||||
else { |
||||
check_opt(&entry[i]); |
||||
add_opt(&entry[i]); |
||||
} |
||||
} |
||||
/* We store the table length in arg ptr. */ |
||||
if (desc) |
||||
opt_table[start].u.tlen = (opt_count - start); |
||||
} |
||||
|
||||
/* Parse your arguments. */ |
||||
bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...)) |
||||
{ |
||||
int ret; |
||||
unsigned offset = 0; |
||||
|
||||
/* This helps opt_usage. */ |
||||
opt_argv0 = argv[0]; |
||||
|
||||
while ((ret = parse_one(argc, argv, &offset, errlog)) == 1); |
||||
|
||||
/* parse_one returns 0 on finish, -1 on error */ |
||||
return (ret == 0); |
||||
} |
||||
|
||||
void opt_free_table(void) |
||||
{ |
||||
free(opt_table); |
||||
opt_table=0; |
||||
} |
||||
|
||||
void opt_log_stderr(const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
|
||||
va_start(ap, fmt); |
||||
vfprintf(stderr, fmt, ap); |
||||
fprintf(stderr, "\n"); |
||||
va_end(ap); |
||||
} |
||||
|
||||
void opt_log_stderr_exit(const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
|
||||
va_start(ap, fmt); |
||||
vfprintf(stderr, fmt, ap); |
||||
fprintf(stderr, "\n"); |
||||
va_end(ap); |
||||
exit(1); |
||||
} |
||||
|
||||
char *opt_invalid_argument(const char *arg) |
||||
{ |
||||
char *str = malloc(sizeof("Invalid argument '%s'") + strlen(arg)); |
||||
sprintf(str, "Invalid argument '%s'", arg); |
||||
return str; |
||||
} |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
ccan/opt/opt.o: ccan/opt/opt.c ccan/opt/opt.h ccan/compiler/compiler.h \ |
||||
config.h ccan/typesafe_cb/typesafe_cb.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ |
||||
/usr/include/stdlib.h /usr/include/features.h \ |
||||
/usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ |
||||
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ |
||||
/usr/include/gnu/stubs-32.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ |
||||
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ |
||||
/usr/include/endian.h /usr/include/bits/endian.h \ |
||||
/usr/include/bits/byteswap.h /usr/include/xlocale.h \ |
||||
/usr/include/sys/types.h /usr/include/bits/types.h \ |
||||
/usr/include/bits/typesizes.h /usr/include/time.h \ |
||||
/usr/include/sys/select.h /usr/include/bits/select.h \ |
||||
/usr/include/bits/sigset.h /usr/include/bits/time.h \ |
||||
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ |
||||
/usr/include/alloca.h /usr/include/string.h /usr/include/errno.h \ |
||||
/usr/include/bits/errno.h /usr/include/linux/errno.h \ |
||||
/usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ |
||||
/usr/include/asm-generic/errno-base.h /usr/include/stdio.h \ |
||||
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdarg.h \ |
||||
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ |
||||
/usr/include/err.h /usr/include/assert.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdint.h \ |
||||
/usr/include/stdint.h /usr/include/bits/wchar.h ccan/opt/private.h |
@ -0,0 +1,345 @@
@@ -0,0 +1,345 @@
|
||||
#ifndef CCAN_OPT_H |
||||
#define CCAN_OPT_H |
||||
#include <ccan/compiler/compiler.h> |
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdbool.h> |
||||
#include <stdlib.h> |
||||
|
||||
struct opt_table; |
||||
|
||||
/**
|
||||
* OPT_WITHOUT_ARG() - macro for initializing an opt_table entry (without arg) |
||||
* @names: the names of the option eg. "--foo", "-f" or "--foo|-f|--foobar". |
||||
* @cb: the callback when the option is found. |
||||
* @arg: the argument to hand to @cb. |
||||
* @desc: the description for opt_usage(), or opt_hidden. |
||||
* |
||||
* This is a typesafe wrapper for initializing a struct opt_table. The callback |
||||
* of type "char *cb(type *)", "char *cb(const type *)" or "char *cb(void *)", |
||||
* where "type" is the type of the @arg argument. |
||||
* |
||||
* If the @cb returns non-NULL, opt_parse() will stop parsing, use the |
||||
* returned string to form an error message for errlog(), free() the |
||||
* string and return false. |
||||
* |
||||
* Any number of equivalent short or long options can be listed in @names, |
||||
* separated by '|'. Short options are a single hyphen followed by a single |
||||
* character, long options are two hyphens followed by one or more characters. |
||||
* |
||||
* See Also: |
||||
* OPT_WITH_ARG() |
||||
*/ |
||||
#define OPT_WITHOUT_ARG(names, cb, arg, desc) \ |
||||
{ (names), OPT_CB_NOARG((cb), (arg)), { (arg) }, (desc) } |
||||
|
||||
/**
|
||||
* OPT_WITH_ARG() - macro for initializing long and short option (with arg) |
||||
* @names: the option names eg. "--foo=<arg>", "-f" or "-f|--foo <arg>". |
||||
* @cb: the callback when the option is found (along with <arg>). |
||||
* @show: the callback to print the value in get_usage (or NULL) |
||||
* @arg: the argument to hand to @cb and @show |
||||
* @desc: the description for opt_usage(), or opt_hidden. |
||||
* |
||||
* This is a typesafe wrapper for initializing a struct opt_table. The callback |
||||
* is of type "char *cb(const char *, type *)", |
||||
* "char *cb(const char *, const type *)" or "char *cb(const char *, void *)", |
||||
* where "type" is the type of the @arg argument. The first argument to the |
||||
* @cb is the argument found on the commandline. |
||||
* |
||||
* Similarly, if @show is not NULL, it should be of type "void *show(char *, |
||||
* const type *)". It should write up to OPT_SHOW_LEN bytes into the first |
||||
* argument; unless it uses the entire OPT_SHOW_LEN bytes it should |
||||
* nul-terminate that buffer. |
||||
* |
||||
* Any number of equivalent short or long options can be listed in @names, |
||||
* separated by '|'. Short options are a single hyphen followed by a single |
||||
* character, long options are two hyphens followed by one or more characters. |
||||
* A space or equals in @names is ignored for parsing, and only used |
||||
* for printing the usage. |
||||
* |
||||
* If the @cb returns non-NULL, opt_parse() will stop parsing, use the |
||||
* returned string to form an error message for errlog(), free() the |
||||
* string and return false. |
||||
* |
||||
* See Also: |
||||
* OPT_WITHOUT_ARG() |
||||
*/ |
||||
#define OPT_WITH_ARG(name, cb, show, arg, desc) \ |
||||
{ (name), OPT_CB_ARG((cb), (show), (arg)), { (arg) }, (desc) } |
||||
|
||||
/**
|
||||
* OPT_SUBTABLE() - macro for including another table inside a table. |
||||
* @table: the table to include in this table. |
||||
* @desc: description of this subtable (for opt_usage()) or NULL. |
||||
*/ |
||||
#define OPT_SUBTABLE(table, desc) \ |
||||
{ (const char *)(table), OPT_SUBTABLE, \ |
||||
sizeof(_check_is_entry(table)) ? NULL : NULL, NULL, NULL, \ |
||||
{ NULL }, (desc) } |
||||
|
||||
/**
|
||||
* OPT_ENDTABLE - macro to create final entry in table. |
||||
* |
||||
* This must be the final element in the opt_table array. |
||||
*/ |
||||
#define OPT_ENDTABLE { NULL, OPT_END, NULL, NULL, NULL, { NULL }, NULL } |
||||
|
||||
/**
|
||||
* opt_register_table - register a table of options |
||||
* @table: the table of options |
||||
* @desc: description of this subtable (for opt_usage()) or NULL. |
||||
* |
||||
* The table must be terminated by OPT_ENDTABLE. |
||||
* |
||||
* Example: |
||||
* static int verbose = 0; |
||||
* static struct opt_table opts[] = { |
||||
* OPT_WITHOUT_ARG("--verbose", opt_inc_intval, &verbose, |
||||
* "Verbose mode (can be specified more than once)"), |
||||
* OPT_WITHOUT_ARG("-v", opt_inc_intval, &verbose, |
||||
* "Verbose mode (can be specified more than once)"), |
||||
* OPT_WITHOUT_ARG("--usage", opt_usage_and_exit, |
||||
* "args...\nA silly test program.", |
||||
* "Print this message."), |
||||
* OPT_ENDTABLE |
||||
* }; |
||||
* |
||||
* ... |
||||
* opt_register_table(opts, NULL); |
||||
*/ |
||||
void opt_register_table(const struct opt_table *table, const char *desc); |
||||
|
||||
/**
|
||||
* opt_register_noarg - register an option with no arguments |
||||
* @names: the names of the option eg. "--foo", "-f" or "--foo|-f|--foobar". |
||||
* @cb: the callback when the option is found. |
||||
* @arg: the argument to hand to @cb. |
||||
* @desc: the verbose description of the option (for opt_usage()), or NULL. |
||||
* |
||||
* This is used for registering a single commandline option which takes |
||||
* no argument. |
||||
* |
||||
* The callback is of type "char *cb(type *)", "char *cb(const type *)" |
||||
* or "char *cb(void *)", where "type" is the type of the @arg |
||||
* argument. |
||||
* |
||||
* If the @cb returns non-NULL, opt_parse() will stop parsing, use the |
||||
* returned string to form an error message for errlog(), free() the |
||||
* string and return false. |
||||
*/ |
||||
#define opt_register_noarg(names, cb, arg, desc) \ |
||||
_opt_register((names), OPT_CB_NOARG((cb), (arg)), (arg), (desc)) |
||||
|
||||
/**
|
||||
* opt_register_arg - register an option with an arguments |
||||
* @names: the names of the option eg. "--foo", "-f" or "--foo|-f|--foobar". |
||||
* @cb: the callback when the option is found. |
||||
* @show: the callback to print the value in get_usage (or NULL) |
||||
* @arg: the argument to hand to @cb. |
||||
* @desc: the verbose description of the option (for opt_usage()), or NULL. |
||||
* |
||||
* This is used for registering a single commandline option which takes |
||||
* an argument. |
||||
* |
||||
* The callback is of type "char *cb(const char *, type *)", |
||||
* "char *cb(const char *, const type *)" or "char *cb(const char *, void *)", |
||||
* where "type" is the type of the @arg argument. The first argument to the |
||||
* @cb is the argument found on the commandline. |
||||
* |
||||
* At least one of @longopt and @shortopt must be non-zero. If the |
||||
* @cb returns false, opt_parse() will stop parsing and return false. |
||||
* |
||||
* Example: |
||||
* static char *explode(const char *optarg, void *unused) |
||||
* { |
||||
* errx(1, "BOOM! %s", optarg); |
||||
* } |
||||
* ... |
||||
* opt_register_arg("--explode|--boom", explode, NULL, NULL, opt_hidden); |
||||
*/ |
||||
#define opt_register_arg(names, cb, show, arg, desc) \ |
||||
_opt_register((names), OPT_CB_ARG((cb), (show), (arg)), (arg), (desc)) |
||||
|
||||
/**
|
||||
* opt_parse - parse arguments. |
||||
* @argc: pointer to argc |
||||
* @argv: argv array. |
||||
* @errlog: the function to print errors |
||||
* |
||||
* This iterates through the command line and calls callbacks registered with |
||||
* opt_register_table()/opt_register_arg()/opt_register_noarg(). If there |
||||
* are unknown options, missing arguments or a callback returns false, then |
||||
* an error message is printed and false is returned. |
||||
* |
||||
* On success, argc and argv are adjusted so only the non-option elements |
||||
* remain, and true is returned. |
||||
* |
||||
* Example: |
||||
* if (!opt_parse(&argc, argv, opt_log_stderr)) { |
||||
* printf("You screwed up, aborting!\n"); |
||||
* exit(1); |
||||
* } |
||||
* |
||||
* See Also: |
||||
* opt_log_stderr, opt_log_stderr_exit |
||||
*/ |
||||
bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...)); |
||||
|
||||
/**
|
||||
* opt_free_table - free the table. |
||||
* |
||||
* This frees the internal memory. Call this as the last |
||||
* opt function. |
||||
*/ |
||||
void opt_free_table(void); |
||||
|
||||
/**
|
||||
* opt_log_stderr - print message to stderr. |
||||
* @fmt: printf-style format. |
||||
* |
||||
* This is a helper for opt_parse, to print errors to stderr. |
||||
* |
||||
* See Also: |
||||
* opt_log_stderr_exit |
||||
*/ |
||||
void opt_log_stderr(const char *fmt, ...); |
||||
|
||||
/**
|
||||
* opt_log_stderr_exit - print message to stderr, then exit(1) |
||||
* @fmt: printf-style format. |
||||
* |
||||
* Just like opt_log_stderr, only then does exit(1). This means that |
||||
* when handed to opt_parse, opt_parse will never return false. |
||||
* |
||||
* Example: |
||||
* // This never returns false; just exits if there's an erorr.
|
||||
* opt_parse(&argc, argv, opt_log_stderr_exit); |
||||
*/ |
||||
void opt_log_stderr_exit(const char *fmt, ...); |
||||
|
||||
/**
|
||||
* opt_invalid_argument - helper to allocate an "Invalid argument '%s'" string |
||||
* @arg: the argument which was invalid. |
||||
* |
||||
* This is a helper for callbacks to return a simple error string. |
||||
*/ |
||||
char *opt_invalid_argument(const char *arg); |
||||
|
||||
/**
|
||||
* opt_usage - create usage message |
||||
* @argv0: the program name |
||||
* @extra: extra details to print after the initial command, or NULL. |
||||
* |
||||
* Creates a usage message, with the program name, arguments, some extra details |
||||
* and a table of all the options with their descriptions. If an option has |
||||
* description opt_hidden, it is not shown here. |
||||
* |
||||
* If "extra" is NULL, then the extra information is taken from any |
||||
* registered option which calls opt_usage_and_exit(). This avoids duplicating |
||||
* that string in the common case. |
||||
* |
||||
* The result should be passed to free(). |
||||
*/ |
||||
char *opt_usage(const char *argv0, const char *extra); |
||||
|
||||
/**
|
||||
* opt_hidden - string for undocumented options. |
||||
* |
||||
* This can be used as the desc parameter if you want an option not to be |
||||
* shown by opt_usage(). |
||||
*/ |
||||
extern const char opt_hidden[]; |
||||
|
||||
/* Maximum length of arg to show in opt_usage */ |
||||
#define OPT_SHOW_LEN 80 |
||||
|
||||
/* Standard helpers. You can write your own: */ |
||||
/* Sets the @b to true. */ |
||||
char *opt_set_bool(bool *b); |
||||
/* Sets @b based on arg: (yes/no/true/false). */ |
||||
char *opt_set_bool_arg(const char *arg, bool *b); |
||||
void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b); |
||||
/* The inverse */ |
||||
char *opt_set_invbool(bool *b); |
||||
void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b); |
||||
/* Sets @b based on !arg: (yes/no/true/false). */ |
||||
char *opt_set_invbool_arg(const char *arg, bool *b); |
||||
|
||||
/* Set a char *. */ |
||||
char *opt_set_charp(const char *arg, char **p); |
||||
void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p); |
||||
|
||||
/* Set an integer value, various forms. Sets to 1 on arg == NULL. */ |
||||
char *opt_set_intval(const char *arg, int *i); |
||||
void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i); |
||||
char *opt_set_uintval(const char *arg, unsigned int *ui); |
||||
void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui); |
||||
char *opt_set_longval(const char *arg, long *l); |
||||
void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l); |
||||
char *opt_set_ulongval(const char *arg, unsigned long *ul); |
||||
void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul); |
||||
|
||||
/* Increment. */ |
||||
char *opt_inc_intval(int *i); |
||||
|
||||
/* Display version string to stdout, exit(0). */ |
||||
char *opt_version_and_exit(const char *version); |
||||
|
||||
/* Display usage string to stdout, exit(0). */ |
||||
char *opt_usage_and_exit(const char *extra); |
||||
|
||||
/* Below here are private declarations. */ |
||||
/* You can use this directly to build tables, but the macros will ensure
|
||||
* consistency and type safety. */ |
||||
enum opt_type { |
||||
OPT_NOARG = 1, /* -f|--foo */ |
||||
OPT_HASARG = 2, /* -f arg|--foo=arg|--foo arg */ |
||||
OPT_SUBTABLE = 4, /* Actually, longopt points to a subtable... */ |
||||
OPT_END = 8, /* End of the table. */ |
||||
}; |
||||
|
||||
struct opt_table { |
||||
const char *names; /* pipe-separated names, --longopt or -s */ |
||||
enum opt_type type; |
||||
char *(*cb)(void *arg); /* OPT_NOARG */ |
||||
char *(*cb_arg)(const char *optarg, void *arg); /* OPT_HASARG */ |
||||
void (*show)(char buf[OPT_SHOW_LEN], const void *arg); |
||||
union { |
||||
const void *carg; |
||||
void *arg; |
||||
size_t tlen; |
||||
} u; |
||||
const char *desc; |
||||
}; |
||||
|
||||
/* Resolves to the four parameters for non-arg callbacks. */ |
||||
#define OPT_CB_NOARG(cb, arg) \ |
||||
OPT_NOARG, \ |
||||
typesafe_cb_cast3(char *(*)(void *), \ |
||||
char *(*)(typeof(*(arg))*), \ |
||||
char *(*)(const typeof(*(arg))*), \ |
||||
char *(*)(const void *), (cb)), \ |
||||
NULL, NULL |
||||
|
||||
/* Resolves to the four parameters for arg callbacks. */ |
||||
#define OPT_CB_ARG(cb, show, arg) \ |
||||
OPT_HASARG, NULL, \ |
||||
typesafe_cb_cast3(char *(*)(const char *,void *), \ |
||||
char *(*)(const char *, typeof(*(arg))*), \ |
||||
char *(*)(const char *, const typeof(*(arg))*), \ |
||||
char *(*)(const char *, const void *), \ |
||||
(cb)), \ |
||||
typesafe_cb_cast(void (*)(char buf[], const void *), \ |
||||
void (*)(char buf[], const typeof(*(arg))*), (show)) |
||||
|
||||
/* Non-typesafe register function. */ |
||||
void _opt_register(const char *names, enum opt_type type, |
||||
char *(*cb)(void *arg), |
||||
char *(*cb_arg)(const char *optarg, void *arg), |
||||
void (*show)(char buf[OPT_SHOW_LEN], const void *arg), |
||||
const void *arg, const char *desc); |
||||
|
||||
/* We use this to get typechecking for OPT_SUBTABLE */ |
||||
static inline int _check_is_entry(struct opt_table *e UNUSED) { return 0; } |
||||
|
||||
#endif /* CCAN_OPT_H */ |
Binary file not shown.
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
/* Actual code to parse commandline. */ |
||||
#include <ccan/opt/opt.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <assert.h> |
||||
#include "private.h" |
||||
|
||||
/* glibc does this as:
|
||||
/tmp/opt-example: invalid option -- 'x' |
||||
/tmp/opt-example: unrecognized option '--long' |
||||
/tmp/opt-example: option '--someflag' doesn't allow an argument |
||||
/tmp/opt-example: option '--s' is ambiguous |
||||
/tmp/opt-example: option requires an argument -- 's' |
||||
*/ |
||||
static int parse_err(void (*errlog)(const char *fmt, ...), |
||||
const char *argv0, const char *arg, unsigned len, |
||||
const char *problem) |
||||
{ |
||||
errlog("%s: %.*s: %s", argv0, len, arg, problem); |
||||
return -1; |
||||
} |
||||
|
||||
static void consume_option(int *argc, char *argv[], unsigned optnum) |
||||
{ |
||||
memmove(&argv[optnum], &argv[optnum+1], |
||||
sizeof(argv[optnum]) * (*argc-optnum)); |
||||
(*argc)--; |
||||
} |
||||
|
||||
/* Returns 1 if argument consumed, 0 if all done, -1 on error. */ |
||||
int parse_one(int *argc, char *argv[], unsigned *offset, |
||||
void (*errlog)(const char *fmt, ...)) |
||||
{ |
||||
unsigned i, arg, len; |
||||
const char *o, *optarg = NULL; |
||||
char *problem; |
||||
|
||||
if (getenv("POSIXLY_CORRECT")) { |
||||
/* Don't find options after non-options. */ |
||||
arg = 1; |
||||
} else { |
||||
for (arg = 1; argv[arg]; arg++) { |
||||
if (argv[arg][0] == '-') |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!argv[arg] || argv[arg][0] != '-') |
||||
return 0; |
||||
|
||||
/* Special arg terminator option. */ |
||||
if (strcmp(argv[arg], "--") == 0) { |
||||
consume_option(argc, argv, arg); |
||||
return 0; |
||||
} |
||||
|
||||
/* Long options start with -- */ |
||||
if (argv[arg][1] == '-') { |
||||
assert(*offset == 0); |
||||
for (o = first_lopt(&i, &len); o; o = next_lopt(o, &i, &len)) { |
||||
if (strncmp(argv[arg] + 2, o, len) != 0) |
||||
continue; |
||||
if (argv[arg][2 + len] == '=') |
||||
optarg = argv[arg] + 2 + len + 1; |
||||
else if (argv[arg][2 + len] != '\0') |
||||
continue; |
||||
break; |
||||
} |
||||
if (!o) |
||||
return parse_err(errlog, argv[0], |
||||
argv[arg], strlen(argv[arg]), |
||||
"unrecognized option"); |
||||
/* For error messages, we include the leading '--' */ |
||||
o -= 2; |
||||
len += 2; |
||||
} else { |
||||
/* offset allows us to handle -abc */ |
||||
for (o = first_sopt(&i); o; o = next_sopt(o, &i)) { |
||||
if (argv[arg][*offset + 1] != *o) |
||||
continue; |
||||
(*offset)++; |
||||
break; |
||||
} |
||||
if (!o) |
||||
return parse_err(errlog, argv[0], |
||||
argv[arg], strlen(argv[arg]), |
||||
"unrecognized option"); |
||||
/* For error messages, we include the leading '-' */ |
||||
o--; |
||||
len = 2; |
||||
} |
||||
|
||||
if (opt_table[i].type == OPT_NOARG) { |
||||
if (optarg) |
||||
return parse_err(errlog, argv[0], o, len, |
||||
"doesn't allow an argument"); |
||||
problem = opt_table[i].cb(opt_table[i].u.arg); |
||||
} else { |
||||
if (!optarg) { |
||||
/* Swallow any short options as optarg, eg -afile */ |
||||
if (*offset && argv[arg][*offset + 1]) { |
||||
optarg = argv[arg] + *offset + 1; |
||||
*offset = 0; |
||||
} else |
||||
optarg = argv[arg+1]; |
||||
} |
||||
if (!optarg) |
||||
return parse_err(errlog, argv[0], o, len, |
||||
"requires an argument"); |
||||
problem = opt_table[i].cb_arg(optarg, opt_table[i].u.arg); |
||||
} |
||||
|
||||
if (problem) { |
||||
parse_err(errlog, argv[0], o, len, problem); |
||||
free(problem); |
||||
return -1; |
||||
} |
||||
|
||||
/* If no more letters in that short opt, reset offset. */ |
||||
if (*offset && !argv[arg][*offset + 1]) |
||||
*offset = 0; |
||||
|
||||
/* All finished with that option? */ |
||||
if (*offset == 0) { |
||||
consume_option(argc, argv, arg); |
||||
if (optarg && optarg == argv[arg]) |
||||
consume_option(argc, argv, arg); |
||||
} |
||||
return 1; |
||||
} |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
ccan/opt/parse.o: ccan/opt/parse.c ccan/opt/opt.h \ |
||||
ccan/compiler/compiler.h config.h ccan/typesafe_cb/typesafe_cb.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ |
||||
/usr/include/stdlib.h /usr/include/features.h \ |
||||
/usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ |
||||
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ |
||||
/usr/include/gnu/stubs-32.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ |
||||
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ |
||||
/usr/include/endian.h /usr/include/bits/endian.h \ |
||||
/usr/include/bits/byteswap.h /usr/include/xlocale.h \ |
||||
/usr/include/sys/types.h /usr/include/bits/types.h \ |
||||
/usr/include/bits/typesizes.h /usr/include/time.h \ |
||||
/usr/include/sys/select.h /usr/include/bits/select.h \ |
||||
/usr/include/bits/sigset.h /usr/include/bits/time.h \ |
||||
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ |
||||
/usr/include/alloca.h /usr/include/string.h /usr/include/assert.h \ |
||||
ccan/opt/private.h |
Binary file not shown.
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
#ifndef CCAN_OPT_PRIVATE_H |
||||
#define CCAN_OPT_PRIVATE_H |
||||
|
||||
extern struct opt_table *opt_table; |
||||
extern unsigned int opt_count, opt_num_short, opt_num_short_arg, opt_num_long; |
||||
|
||||
extern const char *opt_argv0; |
||||
|
||||
#define subtable_of(entry) ((struct opt_table *)((entry)->names)) |
||||
|
||||
const char *first_sopt(unsigned *i); |
||||
const char *next_sopt(const char *names, unsigned *i); |
||||
const char *first_lopt(unsigned *i, unsigned *len); |
||||
const char *next_lopt(const char *p, unsigned *i, unsigned *len); |
||||
|
||||
int parse_one(int *argc, char *argv[], unsigned *offset, |
||||
void (*errlog)(const char *fmt, ...)); |
||||
|
||||
#endif /* CCAN_OPT_PRIVATE_H */ |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
#include <ccan/opt/opt.h> |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/parse.c> |
||||
#include <ccan/opt/usage.c> |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
opt_register_noarg("-v", opt_version_and_exit, |
||||
(const char *)"1.2.3", |
||||
(const char *)"Print version"); |
||||
return 0; |
||||
} |
@ -0,0 +1,144 @@
@@ -0,0 +1,144 @@
|
||||
#include "config.h" |
||||
#include <stdio.h> |
||||
#include <ccan/tap/tap.h> |
||||
#include <setjmp.h> |
||||
#include <stdlib.h> |
||||
#include <limits.h> |
||||
#include <err.h> |
||||
#include "utils.h" |
||||
|
||||
/* We don't actually want it to exit... */ |
||||
static jmp_buf exited; |
||||
#define errx save_and_jump |
||||
|
||||
static void save_and_jump(int ecode, const char *fmt, ...); |
||||
|
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/usage.c> |
||||
#include <ccan/opt/parse.c> |
||||
|
||||
static char *output = NULL; |
||||
|
||||
static int saved_vprintf(const char *fmt, va_list ap) |
||||
{ |
||||
char *p; |
||||
int ret = vasprintf(&p, fmt, ap); |
||||
|
||||
if (output) { |
||||
output = realloc(output, strlen(output) + strlen(p) + 1); |
||||
strcat(output, p); |
||||
free(p); |
||||
} else |
||||
output = p; |
||||
return ret; |
||||
} |
||||
|
||||
static void save_and_jump(int ecode, const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
|
||||
va_start(ap, fmt); |
||||
saved_vprintf(fmt, ap); |
||||
va_end(ap); |
||||
longjmp(exited, ecode + 1); |
||||
} |
||||
|
||||
static void reset(void) |
||||
{ |
||||
free(output); |
||||
output = NULL; |
||||
free(opt_table); |
||||
opt_table = NULL; |
||||
opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int exitval; |
||||
|
||||
plan_tests(14); |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
/* Bad type. */ |
||||
_opt_register("-a", OPT_SUBTABLE, (void *)opt_version_and_exit, |
||||
NULL, NULL, "1.2.3", ""); |
||||
fail("_opt_register returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
ok1(strstr(output, "Option -a: unknown entry type")); |
||||
} |
||||
reset(); |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
/* NULL description. */ |
||||
opt_register_noarg("-a", test_noarg, "", NULL); |
||||
fail("_opt_register returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
ok1(strstr(output, "Option -a: description cannot be NULL")); |
||||
} |
||||
reset(); |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
/* Bad option name. */ |
||||
opt_register_noarg("a", test_noarg, "", ""); |
||||
fail("_opt_register returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
ok1(strstr(output, "Option a: does not begin with '-'")); |
||||
} |
||||
|
||||
reset(); |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
/* Bad option name. */ |
||||
opt_register_noarg("--", test_noarg, "", ""); |
||||
fail("_opt_register returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
ok1(strstr(output, "Option --: invalid long option '--'")); |
||||
} |
||||
|
||||
reset(); |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
/* Bad option name. */ |
||||
opt_register_noarg("--a|-aaa", test_noarg, "", ""); |
||||
fail("_opt_register returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
ok1(strstr(output, |
||||
"Option --a|-aaa: invalid short option '-aaa'")); |
||||
} |
||||
reset(); |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
/* Documentation for non-optios. */ |
||||
opt_register_noarg("--a foo", test_noarg, "", ""); |
||||
fail("_opt_register returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
ok1(strstr(output, |
||||
"Option --a foo: does not take arguments 'foo'")); |
||||
} |
||||
reset(); |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
/* Documentation for non-optios. */ |
||||
opt_register_noarg("--a=foo", test_noarg, "", ""); |
||||
fail("_opt_register returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
ok1(strstr(output, |
||||
"Option --a=foo: does not take arguments 'foo'")); |
||||
} |
||||
return exit_status(); |
||||
} |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
/* Make sure when multiple equivalent options, correct one is used for errors */ |
||||
|
||||
#include <ccan/tap/tap.h> |
||||
#include <stdlib.h> |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/usage.c> |
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/parse.c> |
||||
#include "utils.h" |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
plan_tests(12); |
||||
|
||||
/* --aaa without args. */ |
||||
opt_register_arg("-a|--aaa", test_arg, NULL, "aaa", ""); |
||||
ok1(!parse_args(&argc, &argv, "--aaa", NULL)); |
||||
ok1(strstr(err_output, ": --aaa: requires an argument")); |
||||
free(err_output); |
||||
err_output = NULL; |
||||
ok1(!parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(strstr(err_output, ": -a: requires an argument")); |
||||
free(err_output); |
||||
err_output = NULL; |
||||
|
||||
/* Multiple */ |
||||
opt_register_arg("--bbb|-b|-c|--ccc", test_arg, NULL, "aaa", ""); |
||||
ok1(!parse_args(&argc, &argv, "--bbb", NULL)); |
||||
ok1(strstr(err_output, ": --bbb: requires an argument")); |
||||
free(err_output); |
||||
err_output = NULL; |
||||
ok1(!parse_args(&argc, &argv, "-b", NULL)); |
||||
ok1(strstr(err_output, ": -b: requires an argument")); |
||||
free(err_output); |
||||
err_output = NULL; |
||||
ok1(!parse_args(&argc, &argv, "-c", NULL)); |
||||
ok1(strstr(err_output, ": -c: requires an argument")); |
||||
free(err_output); |
||||
err_output = NULL; |
||||
ok1(!parse_args(&argc, &argv, "--ccc", NULL)); |
||||
ok1(strstr(err_output, ": --ccc: requires an argument")); |
||||
free(err_output); |
||||
err_output = NULL; |
||||
|
||||
/* parse_args allocates argv */ |
||||
free(argv); |
||||
return exit_status(); |
||||
} |
||||
|
@ -0,0 +1,440 @@
@@ -0,0 +1,440 @@
|
||||
#include "config.h" |
||||
#include <stdio.h> |
||||
#include <ccan/tap/tap.h> |
||||
#include <setjmp.h> |
||||
#include <stdlib.h> |
||||
#include <limits.h> |
||||
#include "utils.h" |
||||
|
||||
/* We don't actually want it to exit... */ |
||||
static jmp_buf exited; |
||||
#define exit(status) longjmp(exited, (status) + 1) |
||||
|
||||
#define printf saved_printf |
||||
static int saved_printf(const char *fmt, ...); |
||||
|
||||
#define fprintf saved_fprintf |
||||
static int saved_fprintf(FILE *ignored, const char *fmt, ...); |
||||
|
||||
#define vfprintf(f, fmt, ap) saved_vprintf(fmt, ap) |
||||
static int saved_vprintf(const char *fmt, va_list ap); |
||||
|
||||
#define malloc(size) saved_malloc(size) |
||||
static void *saved_malloc(size_t size); |
||||
|
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/usage.c> |
||||
#include <ccan/opt/parse.c> |
||||
|
||||
static void reset_options(void) |
||||
{ |
||||
free(opt_table); |
||||
opt_table = NULL; |
||||
opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0; |
||||
} |
||||
|
||||
static char *output = NULL; |
||||
|
||||
static int saved_vprintf(const char *fmt, va_list ap) |
||||
{ |
||||
char *p; |
||||
int ret = vasprintf(&p, fmt, ap); |
||||
|
||||
if (output) { |
||||
output = realloc(output, strlen(output) + strlen(p) + 1); |
||||
strcat(output, p); |
||||
free(p); |
||||
} else |
||||
output = p; |
||||
return ret; |
||||
} |
||||
|
||||
static int saved_printf(const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
int ret; |
||||
|
||||
va_start(ap, fmt); |
||||
ret = saved_vprintf(fmt, ap); |
||||
va_end(ap); |
||||
return ret; |
||||
} |
||||
|
||||
static int saved_fprintf(FILE *ignored, const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
int ret; |
||||
|
||||
va_start(ap, fmt); |
||||
ret = saved_vprintf(fmt, ap); |
||||
va_end(ap); |
||||
return ret; |
||||
} |
||||
|
||||
#undef malloc |
||||
static void *last_allocation; |
||||
static void *saved_malloc(size_t size) |
||||
{ |
||||
return last_allocation = malloc(size); |
||||
} |
||||
|
||||
/* Test helpers. */ |
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
plan_tests(100); |
||||
|
||||
/* opt_set_bool */ |
||||
{ |
||||
bool arg = false; |
||||
reset_options(); |
||||
opt_register_noarg("-a", opt_set_bool, &arg, ""); |
||||
ok1(parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(arg); |
||||
opt_register_arg("-b", opt_set_bool_arg, NULL, &arg, ""); |
||||
ok1(parse_args(&argc, &argv, "-b", "no", NULL)); |
||||
ok1(!arg); |
||||
ok1(parse_args(&argc, &argv, "-b", "yes", NULL)); |
||||
ok1(arg); |
||||
ok1(parse_args(&argc, &argv, "-b", "false", NULL)); |
||||
ok1(!arg); |
||||
ok1(parse_args(&argc, &argv, "-b", "true", NULL)); |
||||
ok1(arg); |
||||
ok1(!parse_args(&argc, &argv, "-b", "unknown", NULL)); |
||||
ok1(arg); |
||||
ok1(strstr(err_output, ": -b: Invalid argument 'unknown'")); |
||||
} |
||||
/* opt_set_invbool */ |
||||
{ |
||||
bool arg = true; |
||||
reset_options(); |
||||
opt_register_noarg("-a", opt_set_invbool, &arg, ""); |
||||
ok1(parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(!arg); |
||||
opt_register_arg("-b", opt_set_invbool_arg, NULL, |
||||
&arg, ""); |
||||
ok1(parse_args(&argc, &argv, "-b", "no", NULL)); |
||||
ok1(arg); |
||||
ok1(parse_args(&argc, &argv, "-b", "yes", NULL)); |
||||
ok1(!arg); |
||||
ok1(parse_args(&argc, &argv, "-b", "false", NULL)); |
||||
ok1(arg); |
||||
ok1(parse_args(&argc, &argv, "-b", "true", NULL)); |
||||
ok1(!arg); |
||||
ok1(!parse_args(&argc, &argv, "-b", "unknown", NULL)); |
||||
ok1(!arg); |
||||
ok1(strstr(err_output, ": -b: Invalid argument 'unknown'")); |
||||
} |
||||
/* opt_set_charp */ |
||||
{ |
||||
char *arg = (char *)"wrong"; |
||||
reset_options(); |
||||
opt_register_arg("-a", opt_set_charp, NULL, &arg, "All"); |
||||
ok1(parse_args(&argc, &argv, "-a", "string", NULL)); |
||||
ok1(strcmp(arg, "string") == 0); |
||||
} |
||||
/* opt_set_intval */ |
||||
{ |
||||
int arg = 1000; |
||||
reset_options(); |
||||
opt_register_arg("-a", opt_set_intval, NULL, &arg, "All"); |
||||
ok1(parse_args(&argc, &argv, "-a", "9999", NULL)); |
||||
ok1(arg == 9999); |
||||
ok1(parse_args(&argc, &argv, "-a", "-9999", NULL)); |
||||
ok1(arg == -9999); |
||||
ok1(parse_args(&argc, &argv, "-a", "0", NULL)); |
||||
ok1(arg == 0); |
||||
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL)); |
||||
if (sizeof(int) == 4) |
||||
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL)); |
||||
else |
||||
fail("Handle other int sizes"); |
||||
} |
||||
/* opt_set_uintval */ |
||||
{ |
||||
unsigned int arg = 1000; |
||||
reset_options(); |
||||
opt_register_arg("-a", opt_set_uintval, NULL, &arg, "All"); |
||||
ok1(parse_args(&argc, &argv, "-a", "9999", NULL)); |
||||
ok1(arg == 9999); |
||||
ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL)); |
||||
ok1(parse_args(&argc, &argv, "-a", "0", NULL)); |
||||
ok1(arg == 0); |
||||
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL)); |
||||
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL)); |
||||
if (ULONG_MAX == UINT_MAX) { |
||||
pass("Can't test overflow"); |
||||
pass("Can't test error message"); |
||||
} else { |
||||
char buf[30]; |
||||
sprintf(buf, "%lu", ULONG_MAX); |
||||
ok1(!parse_args(&argc, &argv, "-a", buf, NULL)); |
||||
ok1(strstr(err_output, ": -a: value '") |
||||
&& strstr(err_output, buf) |
||||
&& strstr(err_output, "' does not fit into an integer")); |
||||
} |
||||
} |
||||
/* opt_set_longval */ |
||||
{ |
||||
long int arg = 1000; |
||||
reset_options(); |
||||
opt_register_arg("-a", opt_set_longval, NULL, &arg, "All"); |
||||
ok1(parse_args(&argc, &argv, "-a", "9999", NULL)); |
||||
ok1(arg == 9999); |
||||
ok1(parse_args(&argc, &argv, "-a", "-9999", NULL)); |
||||
ok1(arg == -9999); |
||||
ok1(parse_args(&argc, &argv, "-a", "0", NULL)); |
||||
ok1(arg == 0); |
||||
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL)); |
||||
if (sizeof(long) == 4) |
||||
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL)); |
||||
else if (sizeof(long)== 8) |
||||
ok1(!parse_args(&argc, &argv, "-a", "18446744073709551616", NULL)); |
||||
else |
||||
fail("FIXME: Handle other long sizes"); |
||||
} |
||||
/* opt_set_ulongval */ |
||||
{ |
||||
unsigned long int arg = 1000; |
||||
reset_options(); |
||||
opt_register_arg("-a", opt_set_ulongval, NULL, &arg, "All"); |
||||
ok1(parse_args(&argc, &argv, "-a", "9999", NULL)); |
||||
ok1(arg == 9999); |
||||
ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL)); |
||||
ok1(parse_args(&argc, &argv, "-a", "0", NULL)); |
||||
ok1(arg == 0); |
||||
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL)); |
||||
if (sizeof(long) == 4) |
||||
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL)); |
||||
else if (sizeof(long)== 8) |
||||
ok1(!parse_args(&argc, &argv, "-a", "18446744073709551616", NULL)); |
||||
else |
||||
fail("FIXME: Handle other long sizes"); |
||||
} |
||||
/* opt_inc_intval */ |
||||
{ |
||||
int arg = 1000; |
||||
reset_options(); |
||||
opt_register_noarg("-a", opt_inc_intval, &arg, ""); |
||||
ok1(parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(arg == 1001); |
||||
ok1(parse_args(&argc, &argv, "-a", "-a", NULL)); |
||||
ok1(arg == 1003); |
||||
ok1(parse_args(&argc, &argv, "-aa", NULL)); |
||||
ok1(arg == 1005); |
||||
} |
||||
|
||||
/* opt_show_version_and_exit. */ |
||||
{ |
||||
int exitval; |
||||
reset_options(); |
||||
opt_register_noarg("-a", |
||||
opt_version_and_exit, "1.2.3", ""); |
||||
/* parse_args allocates argv */ |
||||
free(argv); |
||||
|
||||
argc = 2; |
||||
argv = malloc(sizeof(argv[0]) * 3); |
||||
argv[0] = "thisprog"; |
||||
argv[1] = "-a"; |
||||
argv[2] = NULL; |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
opt_parse(&argc, argv, save_err_output); |
||||
fail("opt_show_version_and_exit returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 0); |
||||
} |
||||
ok1(strcmp(output, "1.2.3\n") == 0); |
||||
free(output); |
||||
free(argv); |
||||
output = NULL; |
||||
} |
||||
|
||||
/* opt_usage_and_exit. */ |
||||
{ |
||||
int exitval; |
||||
reset_options(); |
||||
opt_register_noarg("-a", |
||||
opt_usage_and_exit, "[args]", ""); |
||||
|
||||
argc = 2; |
||||
argv = malloc(sizeof(argv[0]) * 3); |
||||
argv[0] = "thisprog"; |
||||
argv[1] = "-a"; |
||||
argv[2] = NULL; |
||||
|
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
opt_parse(&argc, argv, save_err_output); |
||||
fail("opt_usage_and_exit returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 0); |
||||
} |
||||
ok1(strstr(output, "[args]")); |
||||
ok1(strstr(output, argv[0])); |
||||
ok1(strstr(output, "[-a]")); |
||||
free(output); |
||||
free(argv); |
||||
/* It exits without freeing usage string. */ |
||||
free(last_allocation); |
||||
output = NULL; |
||||
} |
||||
|
||||
/* opt_show_bool */ |
||||
{ |
||||
bool b; |
||||
char buf[OPT_SHOW_LEN+2] = { 0 }; |
||||
buf[OPT_SHOW_LEN] = '!'; |
||||
|
||||
b = true; |
||||
opt_show_bool(buf, &b); |
||||
ok1(strcmp(buf, "true") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
|
||||
b = false; |
||||
opt_show_bool(buf, &b); |
||||
ok1(strcmp(buf, "false") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
} |
||||
|
||||
/* opt_show_invbool */ |
||||
{ |
||||
bool b; |
||||
char buf[OPT_SHOW_LEN+2] = { 0 }; |
||||
buf[OPT_SHOW_LEN] = '!'; |
||||
|
||||
b = true; |
||||
opt_show_invbool(buf, &b); |
||||
ok1(strcmp(buf, "false") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
|
||||
b = false; |
||||
opt_show_invbool(buf, &b); |
||||
ok1(strcmp(buf, "true") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
} |
||||
|
||||
/* opt_show_charp */ |
||||
{ |
||||
char str[OPT_SHOW_LEN*2], *p; |
||||
char buf[OPT_SHOW_LEN+2] = { 0 }; |
||||
buf[OPT_SHOW_LEN] = '!'; |
||||
|
||||
/* Short test. */ |
||||
p = str; |
||||
strcpy(p, "short"); |
||||
opt_show_charp(buf, &p); |
||||
ok1(strcmp(buf, "\"short\"") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
|
||||
/* Truncate test. */ |
||||
memset(p, 'x', OPT_SHOW_LEN*2); |
||||
p[OPT_SHOW_LEN*2-1] = '\0'; |
||||
opt_show_charp(buf, &p); |
||||
ok1(buf[0] == '"'); |
||||
ok1(buf[OPT_SHOW_LEN-1] == '"'); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
ok1(strspn(buf+1, "x") == OPT_SHOW_LEN-2); |
||||
} |
||||
|
||||
/* opt_show_intval */ |
||||
{ |
||||
int i; |
||||
char buf[OPT_SHOW_LEN+2] = { 0 }; |
||||
buf[OPT_SHOW_LEN] = '!'; |
||||
|
||||
i = -77; |
||||
opt_show_intval(buf, &i); |
||||
ok1(strcmp(buf, "-77") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
|
||||
i = 77; |
||||
opt_show_intval(buf, &i); |
||||
ok1(strcmp(buf, "77") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
} |
||||
|
||||
/* opt_show_uintval */ |
||||
{ |
||||
unsigned int ui; |
||||
char buf[OPT_SHOW_LEN+2] = { 0 }; |
||||
buf[OPT_SHOW_LEN] = '!'; |
||||
|
||||
ui = 4294967295U; |
||||
opt_show_uintval(buf, &ui); |
||||
ok1(strcmp(buf, "4294967295") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
} |
||||
|
||||
/* opt_show_longval */ |
||||
{ |
||||
long l; |
||||
char buf[OPT_SHOW_LEN+2] = { 0 }; |
||||
buf[OPT_SHOW_LEN] = '!'; |
||||
|
||||
l = 1234567890L; |
||||
opt_show_longval(buf, &l); |
||||
ok1(strcmp(buf, "1234567890") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
} |
||||
|
||||
/* opt_show_ulongval */ |
||||
{ |
||||
unsigned long ul; |
||||
char buf[OPT_SHOW_LEN+2] = { 0 }; |
||||
buf[OPT_SHOW_LEN] = '!'; |
||||
|
||||
ul = 4294967295UL; |
||||
opt_show_ulongval(buf, &ul); |
||||
ok1(strcmp(buf, "4294967295") == 0); |
||||
ok1(buf[OPT_SHOW_LEN] == '!'); |
||||
} |
||||
|
||||
/* opt_log_stderr. */ |
||||
{ |
||||
reset_options(); |
||||
opt_register_noarg("-a", |
||||
opt_usage_and_exit, "[args]", ""); |
||||
|
||||
argc = 2; |
||||
argv = malloc(sizeof(argv[0]) * 3); |
||||
argv[0] = "thisprog"; |
||||
argv[1] = "--garbage"; |
||||
argv[2] = NULL; |
||||
ok1(!opt_parse(&argc, argv, opt_log_stderr)); |
||||
ok1(!strcmp(output, |
||||
"thisprog: --garbage: unrecognized option\n")); |
||||
free(output); |
||||
free(argv); |
||||
output = NULL; |
||||
} |
||||
|
||||
/* opt_log_stderr_exit. */ |
||||
{ |
||||
int exitval; |
||||
reset_options(); |
||||
opt_register_noarg("-a", |
||||
opt_usage_and_exit, "[args]", ""); |
||||
argc = 2; |
||||
argv = malloc(sizeof(argv[0]) * 3); |
||||
argv[0] = "thisprog"; |
||||
argv[1] = "--garbage"; |
||||
argv[2] = NULL; |
||||
exitval = setjmp(exited); |
||||
if (exitval == 0) { |
||||
opt_parse(&argc, argv, opt_log_stderr_exit); |
||||
fail("opt_log_stderr_exit returned?"); |
||||
} else { |
||||
ok1(exitval - 1 == 1); |
||||
} |
||||
free(argv); |
||||
ok1(!strcmp(output, |
||||
"thisprog: --garbage: unrecognized option\n")); |
||||
free(output); |
||||
output = NULL; |
||||
} |
||||
|
||||
return exit_status(); |
||||
} |
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
#include <ccan/tap/tap.h> |
||||
#include <stdarg.h> |
||||
#include <setjmp.h> |
||||
#include <stdlib.h> |
||||
#include <stdarg.h> |
||||
#include "utils.h" |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/usage.c> |
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/parse.c> |
||||
|
||||
static void reset_options(void) |
||||
{ |
||||
free(opt_table); |
||||
opt_table = NULL; |
||||
opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0; |
||||
} |
||||
|
||||
/* Test iterators. */ |
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
unsigned j, i, len = 0; |
||||
const char *p; |
||||
|
||||
plan_tests(37 * 2); |
||||
for (j = 0; j < 2; j ++) { |
||||
reset_options(); |
||||
/* Giving subtable a title makes an extra entry! */ |
||||
opt_register_table(subtables, j == 0 ? NULL : "subtable"); |
||||
|
||||
p = first_lopt(&i, &len); |
||||
ok1(i == j + 0); |
||||
ok1(len == 3); |
||||
ok1(strncmp(p, "jjj", len) == 0); |
||||
p = next_lopt(p, &i, &len); |
||||
ok1(i == j + 0); |
||||
ok1(len == 3); |
||||
ok1(strncmp(p, "lll", len) == 0); |
||||
p = next_lopt(p, &i, &len); |
||||
ok1(i == j + 1); |
||||
ok1(len == 3); |
||||
ok1(strncmp(p, "mmm", len) == 0); |
||||
p = next_lopt(p, &i, &len); |
||||
ok1(i == j + 5); |
||||
ok1(len == 3); |
||||
ok1(strncmp(p, "ddd", len) == 0); |
||||
p = next_lopt(p, &i, &len); |
||||
ok1(i == j + 6); |
||||
ok1(len == 3); |
||||
ok1(strncmp(p, "eee", len) == 0); |
||||
p = next_lopt(p, &i, &len); |
||||
ok1(i == j + 7); |
||||
ok1(len == 3); |
||||
ok1(strncmp(p, "ggg", len) == 0); |
||||
p = next_lopt(p, &i, &len); |
||||
ok1(i == j + 8); |
||||
ok1(len == 3); |
||||
ok1(strncmp(p, "hhh", len) == 0); |
||||
p = next_lopt(p, &i, &len); |
||||
ok1(!p); |
||||
|
||||
p = first_sopt(&i); |
||||
ok1(i == j + 0); |
||||
ok1(*p == 'j'); |
||||
p = next_sopt(p, &i); |
||||
ok1(i == j + 0); |
||||
ok1(*p == 'l'); |
||||
p = next_sopt(p, &i); |
||||
ok1(i == j + 1); |
||||
ok1(*p == 'm'); |
||||
p = next_sopt(p, &i); |
||||
ok1(i == j + 2); |
||||
ok1(*p == 'a'); |
||||
p = next_sopt(p, &i); |
||||
ok1(i == j + 3); |
||||
ok1(*p == 'b'); |
||||
p = next_sopt(p, &i); |
||||
ok1(i == j + 7); |
||||
ok1(*p == 'g'); |
||||
p = next_sopt(p, &i); |
||||
ok1(i == j + 8); |
||||
ok1(*p == 'h'); |
||||
p = next_sopt(p, &i); |
||||
ok1(!p); |
||||
} |
||||
|
||||
return exit_status(); |
||||
} |
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* Make sure we still work with no options registered */ |
||||
#include <ccan/tap/tap.h> |
||||
#include <stdlib.h> |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/usage.c> |
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/parse.c> |
||||
#include "utils.h" |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
const char *myname = argv[0]; |
||||
|
||||
plan_tests(7); |
||||
|
||||
/* Simple short arg.*/ |
||||
ok1(!parse_args(&argc, &argv, "-a", NULL)); |
||||
/* Simple long arg.*/ |
||||
ok1(!parse_args(&argc, &argv, "--aaa", NULL)); |
||||
|
||||
/* Extra arguments preserved. */ |
||||
ok1(parse_args(&argc, &argv, "extra", "args", NULL)); |
||||
ok1(argc == 3); |
||||
ok1(argv[0] == myname); |
||||
ok1(strcmp(argv[1], "extra") == 0); |
||||
ok1(strcmp(argv[2], "args") == 0); |
||||
|
||||
/* parse_args allocates argv */ |
||||
free(argv); |
||||
|
||||
return exit_status(); |
||||
} |
||||
|
@ -0,0 +1,112 @@
@@ -0,0 +1,112 @@
|
||||
#include <ccan/tap/tap.h> |
||||
#include <stdarg.h> |
||||
#include <setjmp.h> |
||||
#include <stdlib.h> |
||||
#include <stdarg.h> |
||||
#include "utils.h" |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/usage.c> |
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/parse.c> |
||||
|
||||
static char *my_cb(void *p) |
||||
{ |
||||
return NULL; |
||||
} |
||||
|
||||
static void reset_options(void) |
||||
{ |
||||
free(opt_table); |
||||
opt_table = NULL; |
||||
opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0; |
||||
} |
||||
|
||||
/* Test helpers. */ |
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
char *output; |
||||
char *longname = strdup("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); |
||||
char *shortname = strdup("shortname"); |
||||
|
||||
plan_tests(48); |
||||
opt_register_table(subtables, NULL); |
||||
opt_register_noarg("--kkk|-k", my_cb, NULL, "magic kkk option"); |
||||
opt_register_noarg("-?", opt_usage_and_exit, "<MyArgs>...", |
||||
"This message"); |
||||
opt_register_arg("--longname", opt_set_charp, opt_show_charp, |
||||
&longname, "a really long option default"); |
||||
opt_register_arg("--shortname", opt_set_charp, opt_show_charp, |
||||
&shortname, "a short option default"); |
||||
output = opt_usage("my name", "ExTrA Args"); |
||||
diag("%s", output); |
||||
ok1(strstr(output, "Usage: my name")); |
||||
ok1(strstr(output, "--jjj|-j|--lll|-l <arg>")); |
||||
ok1(strstr(output, "ExTrA Args")); |
||||
ok1(strstr(output, "-a ")); |
||||
ok1(strstr(output, " Description of a\n")); |
||||
ok1(strstr(output, "-b <arg>")); |
||||
ok1(strstr(output, " Description of b (default: b)\n")); |
||||
ok1(strstr(output, "--ddd ")); |
||||
ok1(strstr(output, " Description of ddd\n")); |
||||
ok1(strstr(output, "--eee <filename> ")); |
||||
ok1(strstr(output, " (default: eee)\n")); |
||||
ok1(strstr(output, "long table options:\n")); |
||||
ok1(strstr(output, "--ggg|-g ")); |
||||
ok1(strstr(output, " Description of ggg\n")); |
||||
ok1(strstr(output, "-h|--hhh <arg>")); |
||||
ok1(strstr(output, " Description of hhh\n")); |
||||
ok1(strstr(output, "--kkk|-k")); |
||||
ok1(strstr(output, "magic kkk option")); |
||||
/* This entry is hidden. */ |
||||
ok1(!strstr(output, "--mmm|-m")); |
||||
free(output); |
||||
|
||||
/* NULL should use string from registered options. */ |
||||
output = opt_usage("my name", NULL); |
||||
diag("%s", output); |
||||
ok1(strstr(output, "Usage: my name")); |
||||
ok1(strstr(output, "--jjj|-j|--lll|-l <arg>")); |
||||
ok1(strstr(output, "<MyArgs>...")); |
||||
ok1(strstr(output, "-a ")); |
||||
ok1(strstr(output, " Description of a\n")); |
||||
ok1(strstr(output, "-b <arg>")); |
||||
ok1(strstr(output, " Description of b (default: b)\n")); |
||||
ok1(strstr(output, "--ddd ")); |
||||
ok1(strstr(output, " Description of ddd\n")); |
||||
ok1(strstr(output, "--eee <filename> ")); |
||||
ok1(strstr(output, " (default: eee)\n")); |
||||
ok1(strstr(output, "long table options:\n")); |
||||
ok1(strstr(output, "--ggg|-g ")); |
||||
ok1(strstr(output, " Description of ggg\n")); |
||||
ok1(strstr(output, "-h|--hhh <arg>")); |
||||
ok1(strstr(output, " Description of hhh\n")); |
||||
ok1(strstr(output, "--kkk|-k")); |
||||
ok1(strstr(output, "magic kkk option")); |
||||
ok1(strstr(output, "--longname")); |
||||
ok1(strstr(output, "a really long option default")); |
||||
ok1(strstr(output, "(default: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"...)")); |
||||
ok1(strstr(output, "--shortname")); |
||||
ok1(strstr(output, "a short option default")); |
||||
ok1(strstr(output, "(default: \"shortname\")")); |
||||
/* This entry is hidden. */ |
||||
ok1(!strstr(output, "--mmm|-m")); |
||||
free(output); |
||||
|
||||
reset_options(); |
||||
/* Empty table test. */ |
||||
output = opt_usage("nothing", NULL); |
||||
ok1(strstr(output, "Usage: nothing \n")); |
||||
free(output); |
||||
|
||||
/* No short args. */ |
||||
opt_register_noarg("--aaa", test_noarg, NULL, "AAAAll"); |
||||
output = opt_usage("onearg", NULL); |
||||
ok1(strstr(output, "Usage: onearg \n")); |
||||
ok1(strstr(output, "--aaa")); |
||||
ok1(strstr(output, "AAAAll")); |
||||
free(output); |
||||
|
||||
free(shortname); |
||||
free(longname); |
||||
return exit_status(); |
||||
} |
@ -0,0 +1,297 @@
@@ -0,0 +1,297 @@
|
||||
#include <ccan/tap/tap.h> |
||||
#include <stdlib.h> |
||||
#include <ccan/opt/opt.c> |
||||
#include <ccan/opt/usage.c> |
||||
#include <ccan/opt/helpers.c> |
||||
#include <ccan/opt/parse.c> |
||||
#include "utils.h" |
||||
|
||||
static void reset_options(void) |
||||
{ |
||||
free(opt_table); |
||||
opt_table = NULL; |
||||
opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0; |
||||
free(err_output); |
||||
err_output = NULL; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
const char *myname = argv[0]; |
||||
|
||||
plan_tests(215); |
||||
|
||||
/* Simple short arg.*/ |
||||
opt_register_noarg("-a", test_noarg, NULL, "All"); |
||||
ok1(parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 1); |
||||
|
||||
/* Simple long arg. */ |
||||
opt_register_noarg("--aaa", test_noarg, NULL, "AAAAll"); |
||||
ok1(parse_args(&argc, &argv, "--aaa", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 2); |
||||
|
||||
/* Both long and short args. */ |
||||
opt_register_noarg("--aaa|-a", test_noarg, NULL, "AAAAAAll"); |
||||
ok1(parse_args(&argc, &argv, "--aaa", "-a", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 4); |
||||
|
||||
/* Extra arguments preserved. */ |
||||
ok1(parse_args(&argc, &argv, "--aaa", "-a", "extra", "args", NULL)); |
||||
ok1(argc == 3); |
||||
ok1(argv[0] == myname); |
||||
ok1(strcmp(argv[1], "extra") == 0); |
||||
ok1(strcmp(argv[2], "args") == 0); |
||||
ok1(test_cb_called == 6); |
||||
|
||||
/* Malformed versions. */ |
||||
ok1(!parse_args(&argc, &argv, "--aaa=arg", NULL)); |
||||
ok1(strstr(err_output, ": --aaa: doesn't allow an argument")); |
||||
ok1(!parse_args(&argc, &argv, "--aa", NULL)); |
||||
ok1(strstr(err_output, ": --aa: unrecognized option")); |
||||
ok1(!parse_args(&argc, &argv, "--aaargh", NULL)); |
||||
ok1(strstr(err_output, ": --aaargh: unrecognized option")); |
||||
|
||||
/* Argument variants. */ |
||||
reset_options(); |
||||
test_cb_called = 0; |
||||
opt_register_arg("-a|--aaa", test_arg, NULL, "aaa", "AAAAAAll"); |
||||
ok1(parse_args(&argc, &argv, "--aaa", "aaa", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(test_cb_called == 1); |
||||
|
||||
ok1(parse_args(&argc, &argv, "--aaa=aaa", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(test_cb_called == 2); |
||||
|
||||
ok1(parse_args(&argc, &argv, "-a", "aaa", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(test_cb_called == 3); |
||||
|
||||
/* Malformed versions. */ |
||||
ok1(!parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(strstr(err_output, ": -a: requires an argument")); |
||||
ok1(!parse_args(&argc, &argv, "--aaa", NULL)); |
||||
ok1(strstr(err_output, ": --aaa: requires an argument")); |
||||
ok1(!parse_args(&argc, &argv, "--aa", NULL)); |
||||
ok1(strstr(err_output, ": --aa: unrecognized option")); |
||||
ok1(!parse_args(&argc, &argv, "--aaargh", NULL)); |
||||
ok1(strstr(err_output, ": --aaargh: unrecognized option")); |
||||
|
||||
/* Now, tables. */ |
||||
/* Short table: */ |
||||
reset_options(); |
||||
test_cb_called = 0; |
||||
opt_register_table(short_table, NULL); |
||||
ok1(parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 1); |
||||
/* This one needs an arg. */ |
||||
ok1(parse_args(&argc, &argv, "-b", NULL) == false); |
||||
ok1(test_cb_called == 1); |
||||
ok1(parse_args(&argc, &argv, "-b", "b", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 2); |
||||
|
||||
/* Long table: */ |
||||
reset_options(); |
||||
test_cb_called = 0; |
||||
opt_register_table(long_table, NULL); |
||||
ok1(parse_args(&argc, &argv, "--ddd", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 1); |
||||
/* This one needs an arg. */ |
||||
ok1(parse_args(&argc, &argv, "--eee", NULL) == false); |
||||
ok1(test_cb_called == 1); |
||||
ok1(parse_args(&argc, &argv, "--eee", "eee", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 2); |
||||
|
||||
/* Short and long, both. */ |
||||
reset_options(); |
||||
test_cb_called = 0; |
||||
opt_register_table(long_and_short_table, NULL); |
||||
ok1(parse_args(&argc, &argv, "-g", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 1); |
||||
ok1(parse_args(&argc, &argv, "--ggg", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 2); |
||||
/* This one needs an arg. */ |
||||
ok1(parse_args(&argc, &argv, "-h", NULL) == false); |
||||
ok1(test_cb_called == 2); |
||||
ok1(parse_args(&argc, &argv, "-h", "hhh", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 3); |
||||
ok1(parse_args(&argc, &argv, "--hhh", NULL) == false); |
||||
ok1(test_cb_called == 3); |
||||
ok1(parse_args(&argc, &argv, "--hhh", "hhh", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 4); |
||||
|
||||
/* Those will all work as tables. */ |
||||
test_cb_called = 0; |
||||
reset_options(); |
||||
opt_register_table(subtables, NULL); |
||||
ok1(parse_args(&argc, &argv, "-a", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 1); |
||||
/* This one needs an arg. */ |
||||
ok1(parse_args(&argc, &argv, "-b", NULL) == false); |
||||
ok1(test_cb_called == 1); |
||||
ok1(parse_args(&argc, &argv, "-b", "b", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 2); |
||||
|
||||
ok1(parse_args(&argc, &argv, "--ddd", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 3); |
||||
/* This one needs an arg. */ |
||||
ok1(parse_args(&argc, &argv, "--eee", NULL) == false); |
||||
ok1(test_cb_called == 3); |
||||
ok1(parse_args(&argc, &argv, "--eee", "eee", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 4); |
||||
|
||||
/* Short and long, both. */ |
||||
ok1(parse_args(&argc, &argv, "-g", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 5); |
||||
ok1(parse_args(&argc, &argv, "--ggg", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 6); |
||||
/* This one needs an arg. */ |
||||
ok1(parse_args(&argc, &argv, "-h", NULL) == false); |
||||
ok1(test_cb_called == 6); |
||||
ok1(parse_args(&argc, &argv, "-h", "hhh", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 7); |
||||
ok1(parse_args(&argc, &argv, "--hhh", NULL) == false); |
||||
ok1(test_cb_called == 7); |
||||
ok1(parse_args(&argc, &argv, "--hhh", "hhh", NULL)); |
||||
ok1(argc == 1); |
||||
ok1(argv[0] == myname); |
||||
ok1(argv[1] == NULL); |
||||
ok1(test_cb_called == 8); |
||||
|
||||
/* Now the tricky one: -? must not be confused with an unknown option */ |
||||
test_cb_called = 0; |
||||
reset_options(); |
||||
|
||||
/* glibc's getopt does not handle ? with arguments. */ |
||||
opt_register_noarg("-?", test_noarg, NULL, "Help"); |
||||
ok1(parse_args(&argc, &argv, "-?", NULL)); |
||||
ok1(test_cb_called == 1); |
||||
ok1(parse_args(&argc, &argv, "-a", NULL) == false); |
||||
ok1(test_cb_called == 1); |
||||
ok1(strstr(err_output, ": -a: unrecognized option")); |
||||
ok1(parse_args(&argc, &argv, "--aaaa", NULL) == false); |
||||
ok1(test_cb_called == 1); |
||||
ok1(strstr(err_output, ": --aaaa: unrecognized option")); |
||||
|
||||
test_cb_called = 0; |
||||
reset_options(); |
||||
|
||||
/* Corner cases involving short arg parsing weirdness. */ |
||||
opt_register_noarg("-a|--aaa", test_noarg, NULL, "a"); |
||||
opt_register_arg("-b|--bbb", test_arg, NULL, "bbb", "b"); |
||||
opt_register_arg("-c|--ccc", test_arg, NULL, "aaa", "c"); |
||||
/* -aa == -a -a */ |
||||
ok1(parse_args(&argc, &argv, "-aa", NULL)); |
||||
ok1(test_cb_called == 2); |
||||
ok1(parse_args(&argc, &argv, "-aab", NULL) == false); |
||||
ok1(test_cb_called == 4); |
||||
ok1(strstr(err_output, ": -b: requires an argument")); |
||||
ok1(parse_args(&argc, &argv, "-bbbb", NULL)); |
||||
ok1(test_cb_called == 5); |
||||
ok1(parse_args(&argc, &argv, "-aabbbb", NULL)); |
||||
ok1(test_cb_called == 8); |
||||
ok1(parse_args(&argc, &argv, "-aabbbb", "-b", "bbb", NULL)); |
||||
ok1(test_cb_called == 12); |
||||
ok1(parse_args(&argc, &argv, "-aabbbb", "--bbb", "bbb", NULL)); |
||||
ok1(test_cb_called == 16); |
||||
ok1(parse_args(&argc, &argv, "-aabbbb", "--bbb=bbb", NULL)); |
||||
ok1(test_cb_called == 20); |
||||
ok1(parse_args(&argc, &argv, "-aacaaa", NULL)); |
||||
ok1(test_cb_called == 23); |
||||
ok1(parse_args(&argc, &argv, "-aacaaa", "-a", NULL)); |
||||
ok1(test_cb_called == 27); |
||||
ok1(parse_args(&argc, &argv, "-aacaaa", "--bbb", "bbb", "-aacaaa", |
||||
NULL)); |
||||
ok1(test_cb_called == 34); |
||||
|
||||
test_cb_called = 0; |
||||
reset_options(); |
||||
|
||||
/* -- and POSIXLY_CORRECT */ |
||||
opt_register_noarg("-a|--aaa", test_noarg, NULL, "a"); |
||||
ok1(parse_args(&argc, &argv, "-a", "--", "-a", NULL)); |
||||
ok1(test_cb_called == 1); |
||||
ok1(argc == 2); |
||||
ok1(strcmp(argv[1], "-a") == 0); |
||||
ok1(!argv[2]); |
||||
|
||||
unsetenv("POSIXLY_CORRECT"); |
||||
ok1(parse_args(&argc, &argv, "-a", "somearg", "-a", "--", "-a", NULL)); |
||||
ok1(test_cb_called == 3); |
||||
ok1(argc == 3); |
||||
ok1(strcmp(argv[1], "somearg") == 0); |
||||
ok1(strcmp(argv[2], "-a") == 0); |
||||
ok1(!argv[3]); |
||||
|
||||
setenv("POSIXLY_CORRECT", "1", 1); |
||||
ok1(parse_args(&argc, &argv, "-a", "somearg", "-a", "--", "-a", NULL)); |
||||
ok1(test_cb_called == 4); |
||||
ok1(argc == 5); |
||||
ok1(strcmp(argv[1], "somearg") == 0); |
||||
ok1(strcmp(argv[2], "-a") == 0); |
||||
ok1(strcmp(argv[3], "--") == 0); |
||||
ok1(strcmp(argv[4], "-a") == 0); |
||||
ok1(!argv[5]); |
||||
|
||||
/* parse_args allocates argv */ |
||||
free(argv); |
||||
return exit_status(); |
||||
} |
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
#include "config.h" |
||||
#include <ccan/tap/tap.h> |
||||
#include <stdarg.h> |
||||
#include <stdlib.h> |
||||
#include <ccan/opt/opt.h> |
||||
#include <getopt.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include "utils.h" |
||||
|
||||
unsigned int test_cb_called; |
||||
char *test_noarg(void *arg) |
||||
{ |
||||
test_cb_called++; |
||||
return NULL; |
||||
} |
||||
|
||||
char *test_arg(const char *optarg, const char *arg) |
||||
{ |
||||
test_cb_called++; |
||||
ok1(strcmp(optarg, arg) == 0); |
||||
return NULL; |
||||
} |
||||
|
||||
void show_arg(char buf[OPT_SHOW_LEN], const char *arg) |
||||
{ |
||||
strncpy(buf, arg, OPT_SHOW_LEN); |
||||
} |
||||
|
||||
char *err_output = NULL; |
||||
|
||||
void save_err_output(const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
char *p; |
||||
|
||||
va_start(ap, fmt); |
||||
/* Check return, for fascist gcc */ |
||||
if (vasprintf(&p, fmt, ap) == -1) |
||||
p = NULL; |
||||
va_end(ap); |
||||
|
||||
if (err_output) { |
||||
err_output = realloc(err_output, |
||||
strlen(err_output) + strlen(p) + 1); |
||||
strcat(err_output, p); |
||||
free(p); |
||||
} else |
||||
err_output = p; |
||||
} |
||||
|
||||
static bool allocated = false; |
||||
|
||||
bool parse_args(int *argc, char ***argv, ...) |
||||
{ |
||||
char **a; |
||||
va_list ap; |
||||
|
||||
va_start(ap, argv); |
||||
*argc = 1; |
||||
a = malloc(sizeof(*a) * (*argc + 1)); |
||||
a[0] = (*argv)[0]; |
||||
while ((a[*argc] = va_arg(ap, char *)) != NULL) { |
||||
(*argc)++; |
||||
a = realloc(a, sizeof(*a) * (*argc + 1)); |
||||
} |
||||
|
||||
if (allocated) |
||||
free(*argv); |
||||
|
||||
*argv = a; |
||||
allocated = true; |
||||
/* Re-set before parsing. */ |
||||
optind = 0; |
||||
|
||||
return opt_parse(argc, *argv, save_err_output); |
||||
} |
||||
|
||||
struct opt_table short_table[] = { |
||||
/* Short opts, different args. */ |
||||
OPT_WITHOUT_ARG("-a", test_noarg, "a", "Description of a"), |
||||
OPT_WITH_ARG("-b", test_arg, show_arg, "b", "Description of b"), |
||||
OPT_ENDTABLE |
||||
}; |
||||
|
||||
struct opt_table long_table[] = { |
||||
/* Long opts, different args. */ |
||||
OPT_WITHOUT_ARG("--ddd", test_noarg, "ddd", "Description of ddd"), |
||||
OPT_WITH_ARG("--eee <filename>", test_arg, show_arg, "eee", ""), |
||||
OPT_ENDTABLE |
||||
}; |
||||
|
||||
struct opt_table long_and_short_table[] = { |
||||
/* Short and long, different args. */ |
||||
OPT_WITHOUT_ARG("--ggg|-g", test_noarg, "ggg", "Description of ggg"), |
||||
OPT_WITH_ARG("-h|--hhh", test_arg, NULL, "hhh", "Description of hhh"), |
||||
OPT_ENDTABLE |
||||
}; |
||||
|
||||
/* Sub-table test. */ |
||||
struct opt_table subtables[] = { |
||||
/* Two short, and two long long, no description */ |
||||
OPT_WITH_ARG("--jjj|-j|--lll|-l", test_arg, show_arg, "jjj", ""), |
||||
/* Hidden option */ |
||||
OPT_WITH_ARG("--mmm|-m", test_arg, show_arg, "mmm", opt_hidden), |
||||
OPT_SUBTABLE(short_table, NULL), |
||||
OPT_SUBTABLE(long_table, "long table options"), |
||||
OPT_SUBTABLE(long_and_short_table, NULL), |
||||
OPT_ENDTABLE |
||||
}; |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
#ifndef CCAN_OPT_TEST_UTILS_H |
||||
#define CCAN_OPT_TEST_UTILS_H |
||||
#include <ccan/opt/opt.h> |
||||
#include <stdbool.h> |
||||
|
||||
bool parse_args(int *argc, char ***argv, ...); |
||||
extern char *err_output; |
||||
void save_err_output(const char *fmt, ...); |
||||
|
||||
extern unsigned int test_cb_called; |
||||
char *test_noarg(void *arg); |
||||
char *test_arg(const char *optarg, const char *arg); |
||||
void show_arg(char buf[OPT_SHOW_LEN], const char *arg); |
||||
|
||||
extern struct opt_table short_table[]; |
||||
extern struct opt_table long_table[]; |
||||
extern struct opt_table long_and_short_table[]; |
||||
extern struct opt_table subtables[]; |
||||
#endif /* CCAN_OPT_TEST_UTILS_H */ |
@ -0,0 +1,111 @@
@@ -0,0 +1,111 @@
|
||||
#include <ccan/opt/opt.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include "private.h" |
||||
|
||||
/* We only use this for pointer comparisons. */ |
||||
const char opt_hidden[1]; |
||||
|
||||
static unsigned write_short_options(char *str) |
||||
{ |
||||
unsigned int i, num = 0; |
||||
const char *p; |
||||
|
||||
for (p = first_sopt(&i); p; p = next_sopt(p, &i)) { |
||||
if (opt_table[i].desc != opt_hidden) |
||||
str[num++] = *p; |
||||
} |
||||
return num; |
||||
} |
||||
|
||||
#define OPT_SPACE_PAD " " |
||||
|
||||
/* FIXME: Get all purdy. */ |
||||
char *opt_usage(const char *argv0, const char *extra) |
||||
{ |
||||
unsigned int i, num, len; |
||||
char *ret, *p; |
||||
|
||||
if (!extra) { |
||||
extra = ""; |
||||
for (i = 0; i < opt_count; i++) { |
||||
if (opt_table[i].cb == (void *)opt_usage_and_exit |
||||
&& opt_table[i].u.carg) { |
||||
extra = opt_table[i].u.carg; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* An overestimate of our length. */ |
||||
len = strlen("Usage: %s ") + strlen(argv0) |
||||
+ strlen("[-%.*s]") + opt_num_short + 1 |
||||
+ strlen(" ") + strlen(extra) |
||||
+ strlen("\n"); |
||||
|
||||
for (i = 0; i < opt_count; i++) { |
||||
if (opt_table[i].type == OPT_SUBTABLE) { |
||||
len += strlen("\n") + strlen(opt_table[i].desc) |
||||
+ strlen(":\n"); |
||||
} else if (opt_table[i].desc != opt_hidden) { |
||||
len += strlen(opt_table[i].names) + strlen(" <arg>"); |
||||
len += strlen(OPT_SPACE_PAD) |
||||
+ strlen(opt_table[i].desc) + 1; |
||||
if (opt_table[i].show) { |
||||
len += strlen("(default: %s)") |
||||
+ OPT_SHOW_LEN + sizeof("..."); |
||||
} |
||||
len += strlen("\n"); |
||||
} |
||||
} |
||||
|
||||
p = ret = malloc(len); |
||||
if (!ret) |
||||
return NULL; |
||||
|
||||
p += sprintf(p, "Usage: %s", argv0); |
||||
p += sprintf(p, " [-"); |
||||
num = write_short_options(p); |
||||
if (num) { |
||||
p += num; |
||||
p += sprintf(p, "]"); |
||||
} else { |
||||
/* Remove start of single-entry options */ |
||||
p -= 3; |
||||
} |
||||
if (extra) |
||||
p += sprintf(p, " %s", extra); |
||||
p += sprintf(p, "\n"); |
||||
|
||||
for (i = 0; i < opt_count; i++) { |
||||
if (opt_table[i].desc == opt_hidden) |
||||
continue; |
||||
if (opt_table[i].type == OPT_SUBTABLE) { |
||||
p += sprintf(p, "%s:\n", opt_table[i].desc); |
||||
continue; |
||||
} |
||||
len = sprintf(p, "%s", opt_table[i].names); |
||||
if (opt_table[i].type == OPT_HASARG |
||||
&& !strchr(opt_table[i].names, ' ') |
||||
&& !strchr(opt_table[i].names, '=')) |
||||
len += sprintf(p + len, " <arg>"); |
||||
len += sprintf(p + len, "%.*s", |
||||
len < strlen(OPT_SPACE_PAD) |
||||
? (unsigned)strlen(OPT_SPACE_PAD) - len : 1, |
||||
OPT_SPACE_PAD); |
||||
|
||||
len += sprintf(p + len, "%s", opt_table[i].desc); |
||||
if (opt_table[i].show) { |
||||
char buf[OPT_SHOW_LEN + sizeof("...")]; |
||||
strcpy(buf + OPT_SHOW_LEN, "..."); |
||||
opt_table[i].show(buf, opt_table[i].u.arg); |
||||
len += sprintf(p + len, " (default: %s)", buf); |
||||
} |
||||
p += len; |
||||
p += sprintf(p, "\n"); |
||||
} |
||||
*p = '\0'; |
||||
return ret; |
||||
} |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
ccan/opt/usage.o: ccan/opt/usage.c ccan/opt/opt.h \ |
||||
ccan/compiler/compiler.h config.h ccan/typesafe_cb/typesafe_cb.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ |
||||
/usr/include/stdlib.h /usr/include/features.h \ |
||||
/usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ |
||||
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ |
||||
/usr/include/gnu/stubs-32.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ |
||||
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ |
||||
/usr/include/endian.h /usr/include/bits/endian.h \ |
||||
/usr/include/bits/byteswap.h /usr/include/xlocale.h \ |
||||
/usr/include/sys/types.h /usr/include/bits/types.h \ |
||||
/usr/include/bits/typesizes.h /usr/include/time.h \ |
||||
/usr/include/sys/select.h /usr/include/bits/select.h \ |
||||
/usr/include/bits/sigset.h /usr/include/bits/time.h \ |
||||
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ |
||||
/usr/include/alloca.h /usr/include/string.h /usr/include/stdio.h \ |
||||
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdarg.h \ |
||||
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ |
||||
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdint.h \ |
||||
/usr/include/stdint.h /usr/include/bits/wchar.h ccan/opt/private.h |
Binary file not shown.
@ -0,0 +1,151 @@
@@ -0,0 +1,151 @@
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include "config.h" |
||||
|
||||
/** |
||||
* typesafe_cb - macros for safe callbacks. |
||||
* |
||||
* The basis of the typesafe_cb header is typesafe_cb_cast(): a |
||||
* conditional cast macro. If an expression exactly matches a given |
||||
* type, it is cast to the target type, otherwise it is left alone. |
||||
* |
||||
* This allows us to create functions which take a small number of |
||||
* specific types, rather than being forced to use a void *. In |
||||
* particular, it is useful for creating typesafe callbacks as the |
||||
* helpers typesafe_cb(), typesafe_cb_preargs() and |
||||
* typesafe_cb_postargs() demonstrate. |
||||
* |
||||
* The standard way of passing arguments to callback functions in C is |
||||
* to use a void pointer, which the callback then casts back to the |
||||
* expected type. This unfortunately subverts the type checking the |
||||
* compiler would perform if it were a direct call. Here's an example: |
||||
* |
||||
* static void my_callback(void *_obj) |
||||
* { |
||||
* struct obj *obj = _obj; |
||||
* ... |
||||
* } |
||||
* ... |
||||
* register_callback(my_callback, &my_obj); |
||||
* |
||||
* If we wanted to use the natural type for my_callback (ie. "void |
||||
* my_callback(struct obj *obj)"), we could make register_callback() |
||||
* take a void * as its first argument, but this would subvert all |
||||
* type checking. We really want register_callback() to accept only |
||||
* the exactly correct function type to match the argument, or a |
||||
* function which takes a void *. |
||||
* |
||||
* This is where typesafe_cb() comes in: it uses typesafe_cb_cast() to |
||||
* cast the callback function if it matches the argument type: |
||||
* |
||||
* void _register_callback(void (*cb)(void *arg), void *arg); |
||||
* #define register_callback(cb, arg) \ |
||||
* _register_callback(typesafe_cb(void, void *, (cb), (arg)), \ |
||||
* (arg)) |
||||
* |
||||
* On compilers which don't support the extensions required |
||||
* typesafe_cb_cast() and friend become an unconditional cast, so your |
||||
* code will compile but you won't get type checking. |
||||
* |
||||
* Example: |
||||
* #include <ccan/typesafe_cb/typesafe_cb.h> |
||||
* #include <stdlib.h> |
||||
* #include <stdio.h> |
||||
* |
||||
* // Generic callback infrastructure. |
||||
* struct callback { |
||||
* struct callback *next; |
||||
* int value; |
||||
* int (*callback)(int value, void *arg); |
||||
* void *arg; |
||||
* }; |
||||
* static struct callback *callbacks; |
||||
* |
||||
* static void _register_callback(int value, int (*cb)(int, void *), |
||||
* void *arg) |
||||
* { |
||||
* struct callback *new = malloc(sizeof(*new)); |
||||
* new->next = callbacks; |
||||
* new->value = value; |
||||
* new->callback = cb; |
||||
* new->arg = arg; |
||||
* callbacks = new; |
||||
* } |
||||
* #define register_callback(value, cb, arg) \ |
||||
* _register_callback(value, \ |
||||
* typesafe_cb_preargs(int, void *, \ |
||||
* (cb), (arg), int),\ |
||||
* (arg)) |
||||
* |
||||
* static struct callback *find_callback(int value) |
||||
* { |
||||
* struct callback *i; |
||||
* |
||||
* for (i = callbacks; i; i = i->next) |
||||
* if (i->value == value) |
||||
* return i; |
||||
* return NULL; |
||||
* } |
||||
* |
||||
* // Define several silly callbacks. Note they don't use void *! |
||||
* #define DEF_CALLBACK(name, op) \ |
||||
* static int name(int val, int *arg) \ |
||||
* { \ |
||||
* printf("%s", #op); \ |
||||
* return val op *arg; \ |
||||
* } |
||||
* DEF_CALLBACK(multiply, *); |
||||
* DEF_CALLBACK(add, +); |
||||
* DEF_CALLBACK(divide, /); |
||||
* DEF_CALLBACK(sub, -); |
||||
* DEF_CALLBACK(or, |); |
||||
* DEF_CALLBACK(and, &); |
||||
* DEF_CALLBACK(xor, ^); |
||||
* DEF_CALLBACK(assign, =); |
||||
* |
||||
* // Silly game to find the longest chain of values. |
||||
* int main(int argc, char *argv[]) |
||||
* { |
||||
* int i, run = 1, num = argv[1] ? atoi(argv[1]) : 0; |
||||
* |
||||
* for (i = 1; i < 1024;) { |
||||
* // Since run is an int, compiler checks "add" does too. |
||||
* register_callback(i++, add, &run); |
||||
* register_callback(i++, divide, &run); |
||||
* register_callback(i++, sub, &run); |
||||
* register_callback(i++, multiply, &run); |
||||
* register_callback(i++, or, &run); |
||||
* register_callback(i++, and, &run); |
||||
* register_callback(i++, xor, &run); |
||||
* register_callback(i++, assign, &run); |
||||
* } |
||||
* |
||||
* printf("%i ", num); |
||||
* while (run < 56) { |
||||
* struct callback *cb = find_callback(num % i); |
||||
* if (!cb) { |
||||
* printf("-> STOP\n"); |
||||
* return 1; |
||||
* } |
||||
* num = cb->callback(num, cb->arg); |
||||
* printf("->%i ", num); |
||||
* run++; |
||||
* } |
||||
* printf("-> Winner!\n"); |
||||
* return 0; |
||||
* } |
||||
* |
||||
* License: LGPL (2 or any later version) |
||||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
||||
*/ |
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
if (argc != 2) |
||||
return 1; |
||||
|
||||
if (strcmp(argv[1], "depends") == 0) { |
||||
return 0; |
||||
} |
||||
|
||||
return 1; |
||||
} |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdbool.h> |
||||
|
||||
static void _set_some_value(void *val) |
||||
{ |
||||
} |
||||
|
||||
#define set_some_value(expr) \ |
||||
_set_some_value(typesafe_cb_cast(void *, long, (expr))) |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
#ifdef FAIL |
||||
bool x = 0; |
||||
#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P |
||||
#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." |
||||
#endif |
||||
#else |
||||
long x = 0; |
||||
#endif |
||||
set_some_value(x); |
||||
return 0; |
||||
} |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
void _callback(void (*fn)(void *arg), void *arg); |
||||
void _callback(void (*fn)(void *arg), void *arg) |
||||
{ |
||||
fn(arg); |
||||
} |
||||
|
||||
/* Callback is set up to warn if arg isn't a pointer (since it won't
|
||||
* pass cleanly to _callback's second arg. */ |
||||
#define callback(fn, arg) \ |
||||
_callback(typesafe_cb(void, (fn), (arg)), (arg)) |
||||
|
||||
void my_callback(int something); |
||||
void my_callback(int something) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
#ifdef FAIL |
||||
/* This fails due to arg, not due to cast. */ |
||||
callback(my_callback, 100); |
||||
#endif |
||||
return 0; |
||||
} |
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
static void _register_callback(void (*cb)(void *arg), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback(cb, arg) \ |
||||
_register_callback(typesafe_cb(void, void *, (cb), (arg)), (arg)) |
||||
|
||||
static void my_callback(char *p) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
char str[] = "hello world"; |
||||
#ifdef FAIL |
||||
int *p; |
||||
#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P |
||||
#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." |
||||
#endif |
||||
#else |
||||
char *p; |
||||
#endif |
||||
p = NULL; |
||||
|
||||
/* This should work always. */ |
||||
register_callback(my_callback, str); |
||||
|
||||
/* This will fail with FAIL defined */ |
||||
register_callback(my_callback, p); |
||||
return 0; |
||||
} |
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
struct foo { |
||||
int x; |
||||
}; |
||||
|
||||
struct bar { |
||||
int x; |
||||
}; |
||||
|
||||
struct baz { |
||||
int x; |
||||
}; |
||||
|
||||
struct any { |
||||
int x; |
||||
}; |
||||
|
||||
struct other { |
||||
int x; |
||||
}; |
||||
|
||||
static void take_any(struct any *any) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
#ifdef FAIL |
||||
struct other |
||||
#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P |
||||
#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." |
||||
#endif |
||||
#else |
||||
struct foo |
||||
#endif |
||||
*arg = NULL; |
||||
take_any(typesafe_cb_cast3(struct any *, |
||||
struct foo *, struct bar *, struct baz *, |
||||
arg)); |
||||
return 0; |
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
|
||||
void _set_some_value(void *val); |
||||
|
||||
void _set_some_value(void *val) |
||||
{ |
||||
} |
||||
|
||||
#define set_some_value(expr) \ |
||||
_set_some_value(typesafe_cb_cast(void *, unsigned long, (expr))) |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
#ifdef FAIL |
||||
int x = 0; |
||||
set_some_value(x); |
||||
#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P |
||||
#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." |
||||
#endif |
||||
#else |
||||
void *p = 0; |
||||
set_some_value(p); |
||||
#endif |
||||
return 0; |
||||
} |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
static void _register_callback(void (*cb)(void *arg, int x), void *arg) |
||||
{ |
||||
} |
||||
#define register_callback(cb, arg) \ |
||||
_register_callback(typesafe_cb_postargs(void, void *, (cb), (arg), int), (arg)) |
||||
|
||||
static void my_callback(char *p, int x) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
#ifdef FAIL |
||||
int *p; |
||||
#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P |
||||
#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." |
||||
#endif |
||||
#else |
||||
char *p; |
||||
#endif |
||||
p = NULL; |
||||
register_callback(my_callback, p); |
||||
return 0; |
||||
} |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
static void _register_callback(void (*cb)(int x, void *arg), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback(cb, arg) \ |
||||
_register_callback(typesafe_cb_preargs(void, void *, (cb), (arg), int), (arg)) |
||||
|
||||
static void my_callback(int x, char *p) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
#ifdef FAIL |
||||
int *p; |
||||
#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P |
||||
#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." |
||||
#endif |
||||
#else |
||||
char *p; |
||||
#endif |
||||
p = NULL; |
||||
register_callback(my_callback, p); |
||||
return 0; |
||||
} |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
/* NULL args for callback function should be OK for normal and _def. */ |
||||
|
||||
static void _register_callback(void (*cb)(const void *arg), const void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback(cb, arg) \ |
||||
_register_callback(typesafe_cb(void, const void *, (cb), (arg)), (arg)) |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
register_callback(NULL, "hello world"); |
||||
return 0; |
||||
} |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
/* const args in callbacks should be OK. */ |
||||
|
||||
static void _register_callback(void (*cb)(void *arg), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback(cb, arg) \ |
||||
_register_callback(typesafe_cb(void, void *, (cb), (arg)), (arg)) |
||||
|
||||
static void _register_callback_pre(void (*cb)(int x, void *arg), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback_pre(cb, arg) \ |
||||
_register_callback_pre(typesafe_cb_preargs(void, void *, (cb), (arg), int), (arg)) |
||||
|
||||
static void _register_callback_post(void (*cb)(void *arg, int x), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback_post(cb, arg) \ |
||||
_register_callback_post(typesafe_cb_postargs(void, void *, (cb), (arg), int), (arg)) |
||||
|
||||
struct undefined; |
||||
|
||||
static void my_callback(struct undefined *undef) |
||||
{ |
||||
} |
||||
|
||||
static void my_callback_pre(int x, struct undefined *undef) |
||||
{ |
||||
} |
||||
|
||||
static void my_callback_post(struct undefined *undef, int x) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
struct undefined *handle = NULL; |
||||
|
||||
register_callback(my_callback, handle); |
||||
register_callback_pre(my_callback_pre, handle); |
||||
register_callback_post(my_callback_post, handle); |
||||
return 0; |
||||
} |
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
/* const args in callbacks should be OK. */ |
||||
|
||||
static void _register_callback(void (*cb)(void *arg), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback(cb, arg) \ |
||||
_register_callback(typesafe_cb(void, void *, (cb), (arg)), (arg)) |
||||
|
||||
static void _register_callback_pre(void (*cb)(int x, void *arg), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback_pre(cb, arg) \ |
||||
_register_callback_pre(typesafe_cb_preargs(void, void *, (cb), (arg), int), (arg)) |
||||
|
||||
static void _register_callback_post(void (*cb)(void *arg, int x), void *arg) |
||||
{ |
||||
} |
||||
|
||||
#define register_callback_post(cb, arg) \ |
||||
_register_callback_post(typesafe_cb_postargs(void, void *, (cb), (arg), int), (arg)) |
||||
|
||||
struct undefined; |
||||
|
||||
static void my_callback(struct undefined *undef) |
||||
{ |
||||
} |
||||
|
||||
static void my_callback_pre(int x, struct undefined *undef) |
||||
{ |
||||
} |
||||
|
||||
static void my_callback_post(struct undefined *undef, int x) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
struct undefined *handle = NULL; |
||||
void (*cb)(struct undefined *undef) = my_callback; |
||||
void (*pre)(int x, struct undefined *undef) = my_callback_pre; |
||||
void (*post)(struct undefined *undef, int x) = my_callback_post; |
||||
|
||||
register_callback(cb, handle); |
||||
register_callback_pre(pre, handle); |
||||
register_callback_post(post, handle); |
||||
return 0; |
||||
} |
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <stdlib.h> |
||||
|
||||
struct foo { |
||||
int x; |
||||
}; |
||||
|
||||
struct bar { |
||||
int x; |
||||
}; |
||||
|
||||
struct baz { |
||||
int x; |
||||
}; |
||||
|
||||
struct any { |
||||
int x; |
||||
}; |
||||
|
||||
static void take_any(struct any *any) |
||||
{ |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
/* Otherwise we get unused warnings for these. */ |
||||
struct foo *foo = NULL; |
||||
struct bar *bar = NULL; |
||||
struct baz *baz = NULL; |
||||
|
||||
take_any(typesafe_cb_cast3(struct any *, |
||||
struct foo *, struct bar *, struct baz *, |
||||
foo)); |
||||
take_any(typesafe_cb_cast3(struct any *, |
||||
struct foo *, struct bar *, struct baz *, |
||||
bar)); |
||||
take_any(typesafe_cb_cast3(struct any *, |
||||
struct foo *, struct bar *, struct baz *, |
||||
baz)); |
||||
return 0; |
||||
} |
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
#include <string.h> |
||||
#include <stdint.h> |
||||
#include <ccan/tap/tap.h> |
||||
|
||||
static char dummy = 0; |
||||
|
||||
/* The example usage. */ |
||||
static void _set_some_value(void *val) |
||||
{ |
||||
ok1(val == &dummy); |
||||
} |
||||
|
||||
#define set_some_value(expr) \ |
||||
_set_some_value(typesafe_cb_cast(void *, unsigned long, (expr))) |
||||
|
||||
static void _callback_onearg(void (*fn)(void *arg), void *arg) |
||||
{ |
||||
fn(arg); |
||||
} |
||||
|
||||
static void _callback_preargs(void (*fn)(int a, int b, void *arg), void *arg) |
||||
{ |
||||
fn(1, 2, arg); |
||||
} |
||||
|
||||
static void _callback_postargs(void (*fn)(void *arg, int a, int b), void *arg) |
||||
{ |
||||
fn(arg, 1, 2); |
||||
} |
||||
|
||||
#define callback_onearg(cb, arg) \ |
||||
_callback_onearg(typesafe_cb(void, void *, (cb), (arg)), (arg)) |
||||
|
||||
#define callback_preargs(cb, arg) \ |
||||
_callback_preargs(typesafe_cb_preargs(void, void *, (cb), (arg), int, int), (arg)) |
||||
|
||||
#define callback_postargs(cb, arg) \ |
||||
_callback_postargs(typesafe_cb_postargs(void, void *, (cb), (arg), int, int), (arg)) |
||||
|
||||
static void my_callback_onearg(char *p) |
||||
{ |
||||
ok1(strcmp(p, "hello world") == 0); |
||||
} |
||||
|
||||
static void my_callback_preargs(int a, int b, char *p) |
||||
{ |
||||
ok1(a == 1); |
||||
ok1(b == 2); |
||||
ok1(strcmp(p, "hello world") == 0); |
||||
} |
||||
|
||||
static void my_callback_postargs(char *p, int a, int b) |
||||
{ |
||||
ok1(a == 1); |
||||
ok1(b == 2); |
||||
ok1(strcmp(p, "hello world") == 0); |
||||
} |
||||
|
||||
/* This is simply a compile test; we promised typesafe_cb_cast can be in a
|
||||
* static initializer. */ |
||||
struct callback_onearg |
||||
{ |
||||
void (*fn)(void *arg); |
||||
const void *arg; |
||||
}; |
||||
|
||||
struct callback_onearg cb_onearg |
||||
= { typesafe_cb(void, void *, my_callback_onearg, (char *)(intptr_t)"hello world"), |
||||
"hello world" }; |
||||
|
||||
struct callback_preargs |
||||
{ |
||||
void (*fn)(int a, int b, void *arg); |
||||
const void *arg; |
||||
}; |
||||
|
||||
struct callback_preargs cb_preargs |
||||
= { typesafe_cb_preargs(void, void *, my_callback_preargs, |
||||
(char *)(intptr_t)"hi", int, int), "hi" }; |
||||
|
||||
struct callback_postargs |
||||
{ |
||||
void (*fn)(void *arg, int a, int b); |
||||
const void *arg; |
||||
}; |
||||
|
||||
struct callback_postargs cb_postargs |
||||
= { typesafe_cb_postargs(void, void *, my_callback_postargs, |
||||
(char *)(intptr_t)"hi", int, int), "hi" }; |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
void *p = &dummy; |
||||
unsigned long l = (unsigned long)p; |
||||
char str[] = "hello world"; |
||||
|
||||
plan_tests(2 + 1 + 3 + 3); |
||||
set_some_value(p); |
||||
set_some_value(l); |
||||
|
||||
callback_onearg(my_callback_onearg, str); |
||||
|
||||
callback_preargs(my_callback_preargs, str); |
||||
|
||||
callback_postargs(my_callback_postargs, str); |
||||
|
||||
return exit_status(); |
||||
} |
@ -0,0 +1,133 @@
@@ -0,0 +1,133 @@
|
||||
#ifndef CCAN_TYPESAFE_CB_H |
||||
#define CCAN_TYPESAFE_CB_H |
||||
#include "config.h" |
||||
|
||||
#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P |
||||
/**
|
||||
* typesafe_cb_cast - only cast an expression if it matches a given type |
||||
* @desttype: the type to cast to |
||||
* @oktype: the type we allow |
||||
* @expr: the expression to cast |
||||
* |
||||
* This macro is used to create functions which allow multiple types. |
||||
* The result of this macro is used somewhere that a @desttype type is |
||||
* expected: if @expr is exactly of type @oktype, then it will be |
||||
* cast to @desttype type, otherwise left alone. |
||||
* |
||||
* This macro can be used in static initializers. |
||||
* |
||||
* This is merely useful for warnings: if the compiler does not |
||||
* support the primitives required for typesafe_cb_cast(), it becomes an |
||||
* unconditional cast, and the @oktype argument is not used. In |
||||
* particular, this means that @oktype can be a type which uses the |
||||
* "typeof": it will not be evaluated if typeof is not supported. |
||||
* |
||||
* Example: |
||||
* // We can take either an unsigned long or a void *.
|
||||
* void _set_some_value(void *val); |
||||
* #define set_some_value(e) \ |
||||
* _set_some_value(typesafe_cb_cast(void *, (e), unsigned long)) |
||||
*/ |
||||
#define typesafe_cb_cast(desttype, oktype, expr) \ |
||||
__builtin_choose_expr( \ |
||||
__builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \ |
||||
oktype), \ |
||||
(desttype)(expr), (expr)) |
||||
#else |
||||
#define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr)) |
||||
#endif |
||||
|
||||
/**
|
||||
* typesafe_cb_cast3 - only cast an expression if it matches given types |
||||
* @desttype: the type to cast to |
||||
* @ok1: the first type we allow |
||||
* @ok2: the second type we allow |
||||
* @ok3: the third type we allow |
||||
* @expr: the expression to cast |
||||
* |
||||
* This is a convenient wrapper for multiple typesafe_cb_cast() calls. |
||||
* You can chain them inside each other (ie. use typesafe_cb_cast() |
||||
* for expr) if you need more than 3 arguments. |
||||
* |
||||
* Example: |
||||
* // We can take either a long, unsigned long, void * or a const void *.
|
||||
* void _set_some_value(void *val); |
||||
* #define set_some_value(expr) \ |
||||
* _set_some_value(typesafe_cb_cast3(void *,, \ |
||||
* long, unsigned long, const void *,\ |
||||
* (expr))) |
||||
*/ |
||||
#define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \ |
||||
typesafe_cb_cast(desttype, ok1, \ |
||||
typesafe_cb_cast(desttype, ok2, \ |
||||
typesafe_cb_cast(desttype, ok3, \ |
||||
(expr)))) |
||||
|
||||
/**
|
||||
* typesafe_cb - cast a callback function if it matches the arg |
||||
* @rtype: the return type of the callback function |
||||
* @atype: the (pointer) type which the callback function expects. |
||||
* @fn: the callback function to cast |
||||
* @arg: the (pointer) argument to hand to the callback function. |
||||
* |
||||
* If a callback function takes a single argument, this macro does |
||||
* appropriate casts to a function which takes a single atype argument if the |
||||
* callback provided matches the @arg. |
||||
* |
||||
* It is assumed that @arg is of pointer type: usually @arg is passed |
||||
* or assigned to a void * elsewhere anyway. |
||||
* |
||||
* Example: |
||||
* void _register_callback(void (*fn)(void *arg), void *arg); |
||||
* #define register_callback(fn, arg) \ |
||||
* _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg)) |
||||
*/ |
||||
#define typesafe_cb(rtype, atype, fn, arg) \ |
||||
typesafe_cb_cast(rtype (*)(atype), \ |
||||
rtype (*)(__typeof__(arg)), \ |
||||
(fn)) |
||||
|
||||
/**
|
||||
* typesafe_cb_preargs - cast a callback function if it matches the arg |
||||
* @rtype: the return type of the callback function |
||||
* @atype: the (pointer) type which the callback function expects. |
||||
* @fn: the callback function to cast |
||||
* @arg: the (pointer) argument to hand to the callback function. |
||||
* |
||||
* This is a version of typesafe_cb() for callbacks that take other arguments |
||||
* before the @arg. |
||||
* |
||||
* Example: |
||||
* void _register_callback(void (*fn)(int, void *arg), void *arg); |
||||
* #define register_callback(fn, arg) \ |
||||
* _register_callback(typesafe_cb_preargs(void, (fn), void *, \ |
||||
* (arg), int), \ |
||||
* (arg)) |
||||
*/ |
||||
#define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \ |
||||
typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \ |
||||
rtype (*)(__VA_ARGS__, __typeof__(arg)), \ |
||||
(fn)) |
||||
|
||||
/**
|
||||
* typesafe_cb_postargs - cast a callback function if it matches the arg |
||||
* @rtype: the return type of the callback function |
||||
* @atype: the (pointer) type which the callback function expects. |
||||
* @fn: the callback function to cast |
||||
* @arg: the (pointer) argument to hand to the callback function. |
||||
* |
||||
* This is a version of typesafe_cb() for callbacks that take other arguments |
||||
* after the @arg. |
||||
* |
||||
* Example: |
||||
* void _register_callback(void (*fn)(void *arg, int), void *arg); |
||||
* #define register_callback(fn, arg) \ |
||||
* _register_callback(typesafe_cb_postargs(void, (fn), void *, \ |
||||
* (arg), int), \ |
||||
* (arg)) |
||||
*/ |
||||
#define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \ |
||||
typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \ |
||||
rtype (*)(__typeof__(arg), __VA_ARGS__), \ |
||||
(fn)) |
||||
#endif /* CCAN_CAST_IF_TYPE_H */ |
Loading…
Reference in new issue