/*
 * Copyright (C) 2015-2015 FAUcc Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifndef __FIX_EXECVP_WARNINGS_INCLUDED
#define __FIX_EXECVP_WARNINGS_INCLUDED

#include <unistd.h>

/*
 * This is a workaround for "warning: passing argument 2 of ‘execvp’ from
 * incompatible pointer type".
 *
 * Summary:
 *     execvp() and custom_execvp() are functionally equivalent.
 *
 *     In execvp(file, argv),        argv can be either: char **
 *                                                   or: char *const *
 *     In custom_execvp(file, argv), argv can be either: const char **
 *                                                   or: const char *const *
 *
 *
 * In detail:
 *
 * execvp is defined as:
 *     int execvp(const char *file, char *const argv[]);
 *
 * man 3p execvp says:
 *     The argv[] and envp[] arrays of pointers and the strings to which those
 *     arrays point shall not be modified by a call to one of the exec
 *     functions, except as a consequence of replacing the process image.
 *
 * and:
 *     The statement about argv[] and envp[] being constants  is  included  to
 *     make explicit to future writers of language bindings that these objects
 *     are completely constant. Due to a limitation of the ISO C standard,  it
 *     is not possible to state that idea in standard C. Specifying two levels
 *     of const- qualification for the argv[] and envp[]  parameters  for  the
 *     exec  functions  may  seem  to  be the natural choice, given that these
 *     functions do not modify either the array of pointers or the  characters
 *     to  which the function points, but this would disallow existing correct
 *     code. Instead, only the array of pointers is noted as constant. The ta‐
 *     ble  of  assignment  compatibility  for dst= src derived from the ISO C
 *     standard summarizes the compatibility:
 *
 *  dst:                char *[] const char *[] char *const[] const char *const[]
 *  src:
 *  char *[]            VALID    -              VALID         -
 *  const char *[]      -        VALID          -             VALID
 *  char * const []     -        -              VALID         -
 *  const char *const[] -        -              -             VALID
 *
 *     Since all existing code has a source type matching the first  row,  the
 *     column  that gives the most valid combinations is the third column. The
 *     only other possibility is the fourth column, but using it would require
 *     a cast on the argv or envp arguments. It is unfortunate that the fourth
 *     column cannot be used, because the declaration a non-expert would natu‐
 *     rally use would be that in the second row.
 *
 * To understand why ISO C has this limitation, see:
 *     http://c-faq.com/ansi/constmismatch.html
 *
 * Furthermore, an explicit cast
 *     execvp("cpp", (char *const *) cpp_param);
 * still produces a compiler warning due to [-Wcast-qual].
 *
 * This workaround attempts to:
 *     - remove warnings that might distract from real issues
 *     - confine the issue to a single location (this file)
 *     - avoid compiler specific tricks
 */
static inline __attribute__((__always_inline__)) int
custom_execvp(const char *file, const char *const argv[])
{
	union {
		const char *const *alternate;
		char *const *posix;
	} args;

	args.alternate = argv;
	return execvp(file, args.posix);
}

#endif /* __FIX_EXECVP_WARNINGS_INCLUDED */
