summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Camera <skonfig@dtnr.ch>2022-08-25 22:02:18 +0200
committerDennis Camera <skonfig@dtnr.ch>2022-08-25 22:07:46 +0200
commit153d17961a746e389c8d0810ac932c0546122eb8 (patch)
tree4be8ed75e6a9278e18caaf39f8edc4d727114817
parent69892f64641a965a1bd586c916913018b54f7c71 (diff)
downloadskonfig-c-153d17961a746e389c8d0810ac932c0546122eb8.tar.gz
skonfig-c-153d17961a746e389c8d0810ac932c0546122eb8.zip
Use format __attribute__ instead of -Wformat-nonliteral hack
-rw-r--r--configure.ac16
-rw-r--r--m4/ax_c___attribute__.m466
-rw-r--r--m4/ax_gcc_func_attribute.m4243
-rw-r--r--src/log.c3
-rw-r--r--src/log.h3
-rw-r--r--src/rcopy.c8
6 files changed, 328 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac
index 8780d5b..d673e2d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,6 +6,7 @@ AC_INIT([skonfig-c],[0.1],[skonfig@dtnr.ch],[],[http://www.skonfig.li/])
AC_CONFIG_SRCDIR([src/skonfig.c])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_FILES([Makefile])
AM_INIT_AUTOMAKE([subdir-objects])
@@ -78,6 +79,21 @@ check_set_ccopt -fstack-protector-strong \
check_set_ccopt -fstack-clash-protection \
|| check_set_ccopt -fstack-check # fallback
+# Check compiler capabilities
+AX_C___ATTRIBUTE__
+
+if test x"${ax_cv___attribute__}" = x'yes'
+then
+ _sk_attribute='__attribute__ ((__VA_ARGS__))'
+
+ AX_GCC_FUNC_ATTRIBUTE([format])
+ if test x"${ax_cv_have_func_attribute_format}" = x'yes'
+ then
+ _sk_printf='SK_ATTRIBUTE(format (printf, i, j))'
+ fi
+fi
+AC_DEFINE_UNQUOTED([SK_ATTRIBUTE(...)], [${_sk_attribute:-/* attribute(x) */}], [Define to the compiler name of its __attribute__])
+AC_DEFINE_UNQUOTED([SK_PRINTF(i, j)], [${_sk_printf:-/* format(printf, i, j) */}], [Define to a code snippet your compiler uses for __attribute__ (format)])
# Checks for libraries.
diff --git a/m4/ax_c___attribute__.m4 b/m4/ax_c___attribute__.m4
new file mode 100644
index 0000000..c62b94a
--- /dev/null
+++ b/m4/ax_c___attribute__.m4
@@ -0,0 +1,66 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_C___ATTRIBUTE__
+#
+# DESCRIPTION
+#
+# Provides a test for the compiler support of __attribute__ extensions.
+# Defines HAVE___ATTRIBUTE__ if it is found.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Stepan Kasal <skasal@redhat.com>
+# Copyright (c) 2008 Christian Haggstrom
+# Copyright (c) 2008 Ryan McCabe <ryan@numb.org>
+#
+# 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 2 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 <https://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 9
+
+AC_DEFUN([AX_C___ATTRIBUTE__], [
+ AC_CACHE_CHECK([for __attribute__], [ax_cv___attribute__],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <stdlib.h>
+ static void foo(void) __attribute__ ((unused));
+ static void
+ foo(void) {
+ exit(1);
+ }
+ ]], [])],
+ [ax_cv___attribute__=yes],
+ [ax_cv___attribute__=no]
+ )
+ ])
+ if test "$ax_cv___attribute__" = "yes"; then
+ AC_DEFINE([HAVE___ATTRIBUTE__], 1, [Define if your compiler has __attribute__])
+ fi
+])
diff --git a/m4/ax_gcc_func_attribute.m4 b/m4/ax_gcc_func_attribute.m4
new file mode 100644
index 0000000..2fb3ddd
--- /dev/null
+++ b/m4/ax_gcc_func_attribute.m4
@@ -0,0 +1,243 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE)
+#
+# DESCRIPTION
+#
+# This macro checks if the compiler supports one of GCC's function
+# attributes; many other compilers also provide function attributes with
+# the same syntax. Compiler warnings are used to detect supported
+# attributes as unsupported ones are ignored by default so quieting
+# warnings when using this macro will yield false positives.
+#
+# The ATTRIBUTE parameter holds the name of the attribute to be checked.
+#
+# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_<ATTRIBUTE>.
+#
+# The macro caches its result in the ax_cv_have_func_attribute_<attribute>
+# variable.
+#
+# The macro currently supports the following function attributes:
+#
+# alias
+# aligned
+# alloc_size
+# always_inline
+# artificial
+# cold
+# const
+# constructor
+# constructor_priority for constructor attribute with priority
+# deprecated
+# destructor
+# dllexport
+# dllimport
+# error
+# externally_visible
+# fallthrough
+# flatten
+# format
+# format_arg
+# gnu_format
+# gnu_inline
+# hot
+# ifunc
+# leaf
+# malloc
+# noclone
+# noinline
+# nonnull
+# noreturn
+# nothrow
+# optimize
+# pure
+# sentinel
+# unused
+# used
+# visibility
+# warning
+# warn_unused_result
+# weak
+# weakref
+#
+# Unsupported function attributes will be tested with a prototype
+# returning an int and not accepting any arguments and the result of the
+# check might be wrong or meaningless so use with care.
+#
+# LICENSE
+#
+# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com>
+#
+# modifications for skonfig-c:
+# Copyright (c) 2022 Dennis Camera <skonfig at dtnr.ch>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 13
+
+AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [
+ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1])
+
+ AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([
+ m4_case([$1],
+ [alias], [
+ int foo( void ) { return 0; }
+ int bar( void ) __attribute__(($1("foo")));
+ ],
+ [aligned], [
+ int foo( void ) __attribute__(($1(32)));
+ ],
+ [alloc_size], [
+ void *foo(int a) __attribute__(($1(1)));
+ ],
+ [always_inline], [
+ inline __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [artificial], [
+ inline __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [cold], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [const], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [constructor_priority], [
+ int foo( void ) __attribute__((__constructor__(65535/2)));
+ ],
+ [constructor], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [deprecated], [
+ int foo( void ) __attribute__(($1("")));
+ ],
+ [destructor], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [dllexport], [
+ __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [dllimport], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [error], [
+ int foo( void ) __attribute__(($1("")));
+ ],
+ [externally_visible], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [fallthrough], [
+ void foo( int x ) {switch (x) { case 1: __attribute__(($1)); case 2: break ; }};
+ ],
+ [flatten], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [format], [
+ int foo(const char *p, ...) __attribute__(($1(printf, 1, 2)));
+ ],
+ [gnu_format], [
+ int foo(const char *p, ...) __attribute__((format(gnu_printf, 1, 2)));
+ ],
+ [format_arg], [
+ char *foo(const char *p) __attribute__(($1(1)));
+ ],
+ [gnu_inline], [
+ inline __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [hot], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [ifunc], [
+ int my_foo( void ) { return 0; }
+ static int (*resolve_foo(void))(void) { return my_foo; }
+ int foo( void ) __attribute__(($1("resolve_foo")));
+ ],
+ [leaf], [
+ __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [malloc], [
+ void *foo( void ) __attribute__(($1));
+ void *bar( void ) __attribute__(($1, $1 (free, 1)));
+ ],
+ [noclone], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [noinline], [
+ __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [nonnull], [
+ int foo(char *p) __attribute__(($1(1)));
+ ],
+ [noreturn], [
+ void foo( void ) __attribute__(($1));
+ ],
+ [nothrow], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [optimize], [
+ __attribute__(($1(3))) int foo( void ) { return 0; }
+ ],
+ [pure], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [sentinel], [
+ int foo(void *p, ...) __attribute__(($1));
+ int bar(void *p, ...) __attribute__(($1(0)));
+ ],
+ [returns_nonnull], [
+ void *foo( void ) __attribute__(($1));
+ ],
+ [unused], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [used], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [visibility], [
+ int foo_def( void ) __attribute__(($1("default")));
+ int foo_hid( void ) __attribute__(($1("hidden")));
+ int foo_int( void ) __attribute__(($1("internal")));
+ int foo_pro( void ) __attribute__(($1("protected")));
+ ],
+ [warning], [
+ int foo( void ) __attribute__(($1("")));
+ ],
+ [warn_unused_result], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [weak], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [weakref], [
+ static int foo( void ) { return 0; }
+ static int bar( void ) __attribute__(($1("foo")));
+ ],
+ [
+ m4_warn([syntax], [Unsupported attribute $1, the test may fail])
+ int foo( void ) __attribute__(($1));
+ ]
+ )], [])
+ ],
+ dnl GCC doesn't exit with an error if an unknown attribute is
+ dnl provided but only outputs a warning, so accept the attribute
+ dnl only if no warning were issued.
+ [AS_IF([grep -- -Wattributes conftest.err],
+ [AS_VAR_SET([ac_var], [no])],
+ [AS_VAR_SET([ac_var], [yes])])],
+ [AS_VAR_SET([ac_var], [no])])
+ ])
+
+ AS_IF([test yes = AS_VAR_GET([ac_var])],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1,
+ [Define to 1 if the system has the `$1' function attribute])], [])
+
+ AS_VAR_POPDEF([ac_var])
+])
diff --git a/src/log.c b/src/log.c
index c4e33b1..7a3bf3f 100644
--- a/src/log.c
+++ b/src/log.c
@@ -92,10 +92,7 @@ int sk_log(sk_log_level level, const char *restrict format, ...) {
va_list ap;
va_start(ap, format);
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-nonliteral"
int rv = vfprintf(stream, format, ap);
-#pragma clang diagnostic pop
va_end(ap);
fprintf(stream, SK_FONT_RESET "\n");
diff --git a/src/log.h b/src/log.h
index 9cee8c2..0e898f1 100644
--- a/src/log.h
+++ b/src/log.h
@@ -103,7 +103,8 @@ void sk_log_font_set(sk_font_map *restrict font);
* @return the number of bytes logged (0 if no message was logged due to
* "insufficient" log level, and a negative number if an error occurred)
*/
-int sk_log(sk_log_level level, const char *restrict format, ...);
+int sk_log(sk_log_level level, const char *restrict format, ...)
+ SK_PRINTF(2, 3);
/**
* sk_error:
diff --git a/src/rcopy.c b/src/rcopy.c
index 2b5f81d..dccf8d1 100644
--- a/src/rcopy.c
+++ b/src/rcopy.c
@@ -9,21 +9,15 @@
#include <stdlib.h>
#include <stdarg.h>
+static char *alloc_cmd(const char *restrict format, ...) SK_PRINTF(1,2);
static char *alloc_cmd(const char *restrict format, ...) {
va_list ap;
va_start(ap, format);
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-nonliteral"
int len = vsnprintf(NULL, 0, format, ap);
-#pragma clang diagnostic pop
- va_end(ap);
char *buf = malloc(len+1);
va_start(ap, format);
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-nonliteral"
(void)vsnprintf(buf, len+1, format, ap);
-#pragma clang diagnostic pop
va_end(ap);
return buf;