On 07/23/2013 04:24 PM, Daniel Santos wrote:
On 07/23/2013 10:55 AM, Bernhard Voelker wrote:
Is there already something available in gnulib like
err_exclusive_options() in util-linux [1] to automatically
catch mutual exclusiveness of options inside the getopt loop?
After spending an inordinate amount of time experimenting with gcc's
compile-time constant support, I'm bet that its possible to write an
inline function that will generate a compile-time error for this!
Basically, something like this:
extern int _getopt (int ___argc, char *const *___argv, const char
*__shortopts) __THROW;
static inline void __validate_opts(const char *__shortopts) {
/* insert magic here */
}
static inline int getopt (int ___argc, char *const *___argv, const
char *__shortopts) {
if (__builtin_constant_p(*__shortopts))
__validate_opts(__shortopts);
return _getopt (___argc, ___argv, __shortopts);
}
When __validate_opts() is called, we know that they have passed a
compile-time constant value, so we can process the shortopts w/o
worrying about a run-time overhead. I would have to experiment
further to figure the rest out and then see what the oldest version of
gcc is that would treat it all as compile-time.
Daniel
Well, it does seem possible indeed, but I haven't figured out a way to
get gcc to unroll a loop the way I need it to so that I can avoid using
static offsets. Short of doing so, the compile-time check would require
repetitive code that supplies static offsets. Here is an example that
will detect a dupe for up to 8 characters. It could be modified to
check up to as many characters as you like, but becoming increasingly
large (in source code at least)
extern void break_build(void) __attribute__((error ("die")));
static inline __attribute__((always_inline)) void
__check_dupe(const char *str, unsigned a, unsigned b) {
if (__builtin_constant_p(str[a]) && __builtin_constant_p(str[b])
&& str[a] && str[a] != ':' && str[a] == str[b])
break_build();
}
static inline __attribute__((always_inline)) void
__validate_opts(const char *str) {
if (__builtin_constant_p(*str)) {
__check_dupe(str, 0, 1);
__check_dupe(str, 0, 2);
__check_dupe(str, 0, 3);
__check_dupe(str, 0, 4);
__check_dupe(str, 0, 5);
__check_dupe(str, 0, 6);
__check_dupe(str, 0, 7);
__check_dupe(str, 0, 8);
__check_dupe(str, 1, 2);
__check_dupe(str, 1, 3);
__check_dupe(str, 1, 4);
__check_dupe(str, 1, 5);
__check_dupe(str, 1, 6);
__check_dupe(str, 1, 7);
__check_dupe(str, 1, 8);
__check_dupe(str, 2, 3);
__check_dupe(str, 2, 4);
__check_dupe(str, 2, 5);
__check_dupe(str, 2, 6);
__check_dupe(str, 2, 7);
__check_dupe(str, 2, 8);
__check_dupe(str, 3, 4);
__check_dupe(str, 3, 5);
__check_dupe(str, 3, 6);
__check_dupe(str, 3, 7);
__check_dupe(str, 3, 8);
__check_dupe(str, 4, 5);
__check_dupe(str, 4, 6);
__check_dupe(str, 4, 7);
__check_dupe(str, 4, 8);
__check_dupe(str, 5, 6);
__check_dupe(str, 5, 7);
__check_dupe(str, 5, 8);
__check_dupe(str, 6, 7);
__check_dupe(str, 6, 8);
__check_dupe(str, 7, 8);
}
}
int main(int argc, char *argv[]) {
__validate_opts("asdfghd");
}
Of course, it will need a no-op version of __validate_opts if the
preprocessor detects that we aren't using gcc or that optimizations
aren't enabled. And this __validate_opts generates zero instructions
when compiled -O2.
Daniel