From e14dfcbedc84a426e751c440cd051660368bb8b2 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" <kpfleming@digium.com> Date: Wed, 26 Nov 2008 21:20:50 +0000 Subject: [PATCH] improve handling of API calls provided by loaded modules through use of some GCC features; this makes app_stack's usage of AGI APIs even cleaner, and will allow it to work 'as expected' either with or without res_agi being loaded reviewed at http://reviewboard.digium.com/r/62 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@159631 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_stack.c | 17 +- autoconf/ast_gcc_attribute.m4 | 20 +- configure | 692 +++++++++++++++++++++++++++++-- configure.ac | 1 + contrib/asterisk-ng-doxygen | 4 +- include/asterisk/agi.h | 60 ++- include/asterisk/autoconfig.h.in | 3 + include/asterisk/optional_api.h | 123 ++++++ res/res_agi.c | 4 +- 9 files changed, 848 insertions(+), 76 deletions(-) create mode 100644 include/asterisk/optional_api.h diff --git a/apps/app_stack.c b/apps/app_stack.c index cebe161afd..0a911e5ecf 100644 --- a/apps/app_stack.c +++ b/apps/app_stack.c @@ -38,9 +38,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/manager.h" #include "asterisk/channel.h" - -/* usage of AGI is optional, so indicate that to the header file */ -#define ASTERISK_AGI_OPTIONAL #include "asterisk/agi.h" /*** DOCUMENTATION @@ -576,9 +573,7 @@ static int unload_module(void) { struct ast_context *con; - if (ast_agi_unregister) { - ast_agi_unregister(ast_module_info->self, &gosub_agi_command); - + if (ast_agi_unregister(ast_module_info->self, &gosub_agi_command) == 1) { if ((con = ast_context_find("app_stack_gosub_virtual_context"))) { ast_context_remove_extension2(con, "s", 1, NULL, 0); ast_context_destroy(con, "app_stack"); /* leave nothing behind */ @@ -598,19 +593,13 @@ static int load_module(void) { struct ast_context *con; - /* usage of AGI is optional, so check to see if the ast_agi_register() - function is available; if so, use it. - */ - if (ast_agi_register) { - con = ast_context_find_or_create(NULL, NULL, "app_stack_gosub_virtual_context", "app_stack"); - if (!con) { + if (ast_agi_register(ast_module_info->self, &gosub_agi_command) == 1) { + if (!(con = ast_context_find_or_create(NULL, NULL, "app_stack_gosub_virtual_context", "app_stack"))) { ast_log(LOG_ERROR, "Virtual context 'app_stack_gosub_virtual_context' does not exist and unable to create\n"); return AST_MODULE_LOAD_DECLINE; } else { ast_add_extension2(con, 1, "s", 1, NULL, NULL, "KeepAlive", ast_strdup(""), ast_free_ptr, "app_stack"); } - - ast_agi_register(ast_module_info->self, &gosub_agi_command); } ast_register_application_xml(app_pop, pop_exec); diff --git a/autoconf/ast_gcc_attribute.m4 b/autoconf/ast_gcc_attribute.m4 index 167bb4e79d..c4488454d9 100644 --- a/autoconf/ast_gcc_attribute.m4 +++ b/autoconf/ast_gcc_attribute.m4 @@ -1,17 +1,31 @@ # Helper function to check for gcc attributes. -# AST_GCC_ATTRIBUTE([attribute name]) +# AST_GCC_ATTRIBUTE([attribute name], [attribute syntax]) AC_DEFUN([AST_GCC_ATTRIBUTE], [ AC_MSG_CHECKING(for compiler 'attribute $1' support) saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" + +if test "x$2" = "x" +then AC_COMPILE_IFELSE( AC_LANG_PROGRAM([void __attribute__(($1)) *test(void *muffin, ...) {}], []), AC_MSG_RESULT(yes) AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]), - AC_MSG_RESULT(no)) -] + AC_MSG_RESULT(no) +) +else +AC_COMPILE_IFELSE( + AC_LANG_PROGRAM([void __attribute__(($2)) *test(void *muffin, ...) {}], + []), + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]), + AC_MSG_RESULT(no) +) +fi + CFLAGS="$saved_CFLAGS" +] ) diff --git a/configure b/configure index e78c697300..de4cc7c00f 100755 --- a/configure +++ b/configure @@ -17093,6 +17093,9 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ echo $ECHO_N "checking for compiler 'attribute pure' support... $ECHO_C" >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -17138,17 +17141,73 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__(()) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_pure 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi CFLAGS="$saved_CFLAGS" + { echo "$as_me:$LINENO: checking for compiler 'attribute malloc' support" >&5 echo $ECHO_N "checking for compiler 'attribute malloc' support... $ECHO_C" >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -17194,17 +17253,73 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__(()) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_malloc 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi CFLAGS="$saved_CFLAGS" + { echo "$as_me:$LINENO: checking for compiler 'attribute const' support" >&5 echo $ECHO_N "checking for compiler 'attribute const' support... $ECHO_C" >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -17250,17 +17365,73 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__(()) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_const 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi CFLAGS="$saved_CFLAGS" + { echo "$as_me:$LINENO: checking for compiler 'attribute unused' support" >&5 echo $ECHO_N "checking for compiler 'attribute unused' support... $ECHO_C" >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -17306,24 +17477,18 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -CFLAGS="$saved_CFLAGS" - - -{ echo "$as_me:$LINENO: checking for compiler 'attribute always_inline' support" >&5 -echo $ECHO_N "checking for compiler 'attribute always_inline' support... $ECHO_C" >&6; } -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -Werror" +else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -void __attribute__((always_inline)) *test(void *muffin, ...) {} +void __attribute__(()) *test(void *muffin, ...) {} int main () { @@ -17353,7 +17518,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<_ACEOF -#define HAVE_ATTRIBUTE_always_inline 1 +#define HAVE_ATTRIBUTE_unused 1 _ACEOF else @@ -17362,24 +17527,30 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi CFLAGS="$saved_CFLAGS" -{ echo "$as_me:$LINENO: checking for compiler 'attribute deprecated' support" >&5 -echo $ECHO_N "checking for compiler 'attribute deprecated' support... $ECHO_C" >&6; } + +{ echo "$as_me:$LINENO: checking for compiler 'attribute always_inline' support" >&5 +echo $ECHO_N "checking for compiler 'attribute always_inline' support... $ECHO_C" >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -void __attribute__((deprecated)) *test(void *muffin, ...) {} +void __attribute__((always_inline)) *test(void *muffin, ...) {} int main () { @@ -17409,7 +17580,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<_ACEOF -#define HAVE_ATTRIBUTE_deprecated 1 +#define HAVE_ATTRIBUTE_always_inline 1 _ACEOF else @@ -17418,24 +17589,18 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -CFLAGS="$saved_CFLAGS" - - -{ echo "$as_me:$LINENO: checking for compiler 'attribute sentinel' support" >&5 -echo $ECHO_N "checking for compiler 'attribute sentinel' support... $ECHO_C" >&6; } -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -Werror" +else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -void __attribute__((sentinel)) *test(void *muffin, ...) {} +void __attribute__(()) *test(void *muffin, ...) {} int main () { @@ -17465,7 +17630,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<_ACEOF -#define HAVE_ATTRIBUTE_sentinel 1 +#define HAVE_ATTRIBUTE_always_inline 1 _ACEOF else @@ -17474,24 +17639,30 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi CFLAGS="$saved_CFLAGS" -{ echo "$as_me:$LINENO: checking for compiler 'attribute warn_unused_result' support" >&5 -echo $ECHO_N "checking for compiler 'attribute warn_unused_result' support... $ECHO_C" >&6; } + +{ echo "$as_me:$LINENO: checking for compiler 'attribute deprecated' support" >&5 +echo $ECHO_N "checking for compiler 'attribute deprecated' support... $ECHO_C" >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -void __attribute__((warn_unused_result)) *test(void *muffin, ...) {} +void __attribute__((deprecated)) *test(void *muffin, ...) {} int main () { @@ -17521,7 +17692,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<_ACEOF -#define HAVE_ATTRIBUTE_warn_unused_result 1 +#define HAVE_ATTRIBUTE_deprecated 1 _ACEOF else @@ -17530,24 +17701,18 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -CFLAGS="$saved_CFLAGS" - - -{ echo "$as_me:$LINENO: checking for compiler 'attribute weak' support" >&5 -echo $ECHO_N "checking for compiler 'attribute weak' support... $ECHO_C" >&6; } -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -Werror" +else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -void __attribute__((weak)) *test(void *muffin, ...) {} +void __attribute__(()) *test(void *muffin, ...) {} int main () { @@ -17577,7 +17742,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<_ACEOF -#define HAVE_ATTRIBUTE_weak 1 +#define HAVE_ATTRIBUTE_deprecated 1 _ACEOF else @@ -17586,13 +17751,464 @@ sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi CFLAGS="$saved_CFLAGS" + +{ echo "$as_me:$LINENO: checking for compiler 'attribute sentinel' support" >&5 +echo $ECHO_N "checking for compiler 'attribute sentinel' support... $ECHO_C" >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__((sentinel)) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_sentinel 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__(()) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_sentinel 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +CFLAGS="$saved_CFLAGS" + + + +{ echo "$as_me:$LINENO: checking for compiler 'attribute warn_unused_result' support" >&5 +echo $ECHO_N "checking for compiler 'attribute warn_unused_result' support... $ECHO_C" >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__((warn_unused_result)) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_warn_unused_result 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__(()) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_warn_unused_result 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +CFLAGS="$saved_CFLAGS" + + + +{ echo "$as_me:$LINENO: checking for compiler 'attribute weak' support" >&5 +echo $ECHO_N "checking for compiler 'attribute weak' support... $ECHO_C" >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror" + +if test "x" = "x" +then +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__((weak)) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_weak 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__(()) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_weak 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +CFLAGS="$saved_CFLAGS" + + + +{ echo "$as_me:$LINENO: checking for compiler 'attribute alias' support" >&5 +echo $ECHO_N "checking for compiler 'attribute alias' support... $ECHO_C" >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror" + +if test "xalias("foo")" = "x" +then +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__((alias)) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_alias 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +void __attribute__((alias("foo"))) *test(void *muffin, ...) {} +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_alias 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +CFLAGS="$saved_CFLAGS" + + + { echo "$as_me:$LINENO: checking for -ffunction-sections support" >&5 echo $ECHO_N "checking for -ffunction-sections support... $ECHO_C" >&6; } saved_CFLAGS="${CFLAGS}" diff --git a/configure.ac b/configure.ac index 37b192284e..30113c1544 100644 --- a/configure.ac +++ b/configure.ac @@ -480,6 +480,7 @@ AST_GCC_ATTRIBUTE(deprecated) AST_GCC_ATTRIBUTE(sentinel) AST_GCC_ATTRIBUTE(warn_unused_result) AST_GCC_ATTRIBUTE(weak) +AST_GCC_ATTRIBUTE(alias, [alias("foo")]) AC_MSG_CHECKING(for -ffunction-sections support) saved_CFLAGS="${CFLAGS}" diff --git a/contrib/asterisk-ng-doxygen b/contrib/asterisk-ng-doxygen index ef96f0d362..0c34ba14ae 100644 --- a/contrib/asterisk-ng-doxygen +++ b/contrib/asterisk-ng-doxygen @@ -1098,7 +1098,9 @@ EXPAND_AS_DEFINED = \ AST_RWDLLIST_HEAD_STATIC \ AST_DLLIST_ENTRY \ AST_RWDLLIST_ENTRY \ - AST_CLI_DEFINE + AST_CLI_DEFINE \ + AST_OPTIONAL_API \ + AST_OPTIONAL_API_ATTR # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone diff --git a/include/asterisk/agi.h b/include/asterisk/agi.h index c92ab3c665..9c77595760 100644 --- a/include/asterisk/agi.h +++ b/include/asterisk/agi.h @@ -28,6 +28,7 @@ extern "C" { #endif #include "asterisk/cli.h" +#include "asterisk/optional_api.h" typedef struct agi_state { int fd; /*!< FD for general output */ @@ -60,26 +61,31 @@ typedef struct agi_command { AST_LIST_ENTRY(agi_command) list; } agi_command; -#if defined(ASTERISK_AGI_OPTIONAL) -#define AGI_WEAK attribute_weak -#else -#define AGI_WEAK -#endif +/*! + * \brief + * + * Registers an AGI command. + * + * \param mod Pointer to the module_info structure for the module that is registering the command + * \param cmd Pointer to the descriptor for the command + * \return 1 on success, 0 if the command is already registered + * + */ +AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd), + { return AST_OPTIONAL_API_UNAVAILABLE; }); /*! * \brief * - * Sends a string of text to an application connected via AGI. + * Unregisters an AGI command. * - * \param fd The file descriptor for the AGI session (from struct agi_state) - * \param chan Pointer to an associated Asterisk channel, if any - * \param fmt printf-style format string - * \return 0 for success, -1 for failure + * \param mod Pointer to the module_info structure for the module that is unregistering the command + * \param cmd Pointer to the descriptor for the command + * \return 1 on success, 0 if the command was not already registered * */ -int AGI_WEAK ast_agi_send(int fd, struct ast_channel *chan, char *fmt, ...) __attribute__((format(printf, 3, 4))); -int AGI_WEAK ast_agi_register(struct ast_module *mod, agi_command *cmd); -int AGI_WEAK ast_agi_unregister(struct ast_module *mod, agi_command *cmd); +AST_OPTIONAL_API(int, ast_agi_unregister, (struct ast_module *mod, agi_command *cmd), + { return AST_OPTIONAL_API_UNAVAILABLE; }); /*! * \brief @@ -88,15 +94,16 @@ int AGI_WEAK ast_agi_unregister(struct ast_module *mod, agi_command *cmd); * entries. * * \param mod Pointer to the module_info structure for the module that is registering the commands - * \param cmd Pointer to the first entry in the array of commands + * \param cmd Pointer to the first entry in the array of command descriptors * \param len Length of the array (use the ARRAY_LEN macro to determine this easily) - * \return 0 on success, -1 on failure + * \return 0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded * * \note If any command fails to register, all commands previously registered during the operation * will be unregistered. In other words, this function registers all the provided commands, or none * of them. */ -int AGI_WEAK ast_agi_register_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len); +AST_OPTIONAL_API(int, ast_agi_register_multiple, (struct ast_module *mod, struct agi_command *cmd, unsigned int len), + { return AST_OPTIONAL_API_UNAVAILABLE; }); /*! * \brief @@ -105,14 +112,29 @@ int AGI_WEAK ast_agi_register_multiple(struct ast_module *mod, struct agi_comman * entries. * * \param mod Pointer to the module_info structure for the module that is unregistering the commands - * \param cmd Pointer to the first entry in the array of commands + * \param cmd Pointer to the first entry in the array of command descriptors * \param len Length of the array (use the ARRAY_LEN macro to determine this easily) - * \return 0 on success, -1 on failure + * \return 0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded * * \note If any command fails to unregister, this function will continue to unregister the * remaining commands in the array; it will not reregister the already-unregistered commands. */ -int AGI_WEAK ast_agi_unregister_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len); +AST_OPTIONAL_API(int, ast_agi_unregister_multiple, (struct ast_module *mod, struct agi_command *cmd, unsigned int len), + { return AST_OPTIONAL_API_UNAVAILABLE; }); + +/*! + * \brief + * + * Sends a string of text to an application connected via AGI. + * + * \param fd The file descriptor for the AGI session (from struct agi_state) + * \param chan Pointer to an associated Asterisk channel, if any + * \param fmt printf-style format string + * \return 0 for success, -1 for failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded + * + */ +AST_OPTIONAL_API_ATTR(int, format(printf, 3, 4), ast_agi_send, (int fd, struct ast_channel *chan, char *fmt, ...), + { return AST_OPTIONAL_API_UNAVAILABLE; }); #if defined(__cplusplus) || defined(c_plusplus) } diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 0f032b5ba2..d6b3f89712 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -91,6 +91,9 @@ /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT +/* Define to 1 if your GCC C compiler supports the 'alias' attribute. */ +#undef HAVE_ATTRIBUTE_alias + /* Define to 1 if your GCC C compiler supports the 'always_inline' attribute. */ #undef HAVE_ATTRIBUTE_always_inline diff --git a/include/asterisk/optional_api.h b/include/asterisk/optional_api.h new file mode 100644 index 0000000000..ad7169cc4a --- /dev/null +++ b/include/asterisk/optional_api.h @@ -0,0 +1,123 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2008, Digium, Inc. + * + * Kevin P. Fleming <kpfleming@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef __ASTERISK_OPTIONAL_API_H +#define __ASTERISK_OPTIONAL_API_H + +/*! + * \file + * \brief Optional API function macros + * + * Some Asterisk API functions are provided by loadable modules, thus, + * they may or may not be available at run time depending on whether the + * providing module has been loaded or not. In addition, there are some + * modules that are consumers of these APIs that *optionally* use them; they + * have only a part of their functionality dependent on the APIs, and can + * provide the remainder even if the APIs are not available. + * + * To accomodate this situation, the AST_OPTIONAL_API macro allows an API + * function to be declared in a special way, if Asterisk being built on a + * platform that supports the GCC 'weak' and 'alias' attributes. If so, + * the API function is actually a weak symbol, which means if the provider + * of the API is not loaded, the symbol can still be referenced (unlike a + * strong symbol, which would cause an immediate fault if not defined when + * referenced), but it will return NULL signifying the linker/loader was + * not able to resolve the symbol. In addition, the macro defines a hidden + * 'stub' version of the API call, using a provided function body, and uses + * the alias attribute to make the API function symbol actually resolve to + * that hidden stub, but only when the *real* provider of the symbol has + * not been found. + * + * An example can be found in agi.h: + * + * \code + * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd), + * { return AST_OPTIONAL_API_UNAVAILABLE; }); + * \endcode + * + * This defines the 'ast_agi_register' function as an optional API; if a + * consumer of this API is loaded when there is no provider of it, then + * calling this function will actually call the hidden stub, and return + * the value AST_OPTIONAL_API_UNAVAILABLE. This allows the consumer to + * safely know that the API is not available, and to avoid using any + * other APIs from the not-present provider. + * + * In the module providing the API, the AST_OPTIONAL_API macro must + * be informed that it should not build the hidden stub function or + * apply special aliases to the function prototype; this can be done + * by defining AST_API_MODULE just before including the header file + * containing the AST_OPTIONAL_API macro calls. + * + * \note If the GCC 'weak' and 'alias' attributes are not available, + * then the AST_OPTIONAL_API macro will result in a non-optional function + * definition; this means that any consumers of the API functions so + * defined will require that the provider of the API functions be + * loaded before they can reference the symbols. + */ + +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) + +/*! + * \brief A common value for optional API stub functions to return + * + * This value is defined as INT_MIN, the minimum value for an integer + * (maximum negative value), which can be used by any optional API + * functions that return a signed integer value and would not be + * able to return such a value under normal circumstances. + */ +#define AST_OPTIONAL_API_UNAVAILABLE INT_MIN + +#if defined(HAVE_ATTRIBUTE_weak) && defined(HAVE_ATTRIBUTE_alias) && !defined(AST_API_MODULE) +#define AST_OPTIONAL_API(result, name, proto, stub) \ + static result __##name proto stub; \ + result __attribute__((weak, alias("__" __stringify(name)))) name proto; +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + static result __attribute__((attr)) __##name proto stub; \ + result __attribute__((weak, alias("__" __stringify(name)), attr)) name proto; +#else +/*! + * \brief Define an optional API function + * + * \param result The type of result the function returns + * \param name The name of the function + * \param proto The prototype (arguments) of the function + * \param stub The code block that will be used by the hidden stub when needed + * + * Example usage: + * \code + * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd), + * { return AST_OPTIONAL_API_UNAVAILABLE; }); + * \endcode + */ +#define AST_OPTIONAL_API(result, name, proto, stub) result name proto; +/*! + * \brief Define an optional API function with compiler attributes + * + * \param result The type of result the function returns + * \param attr Any compiler attributes to be applied to the function (without the __attribute__ wrapper) + * \param name The name of the function + * \param proto The prototype (arguments) of the function + * \param stub The code block that will be used by the hidden stub when needed + */ +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result __attribute__((attr)) name proto; +#endif + +#undef AST_API_MODULE + +#endif /* __ASTERISK_OPTIONAL_API_H */ diff --git a/res/res_agi.c b/res/res_agi.c index ac6a8f85ce..4ce871ec2e 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -51,7 +51,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/lock.h" #include "asterisk/strings.h" -#include "asterisk/agi.h" #include "asterisk/manager.h" #include "asterisk/ast_version.h" #include "asterisk/speech.h" @@ -60,6 +59,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/term.h" #include "asterisk/xmldoc.h" +#define AST_API_MODULE +#include "asterisk/agi.h" + /*** DOCUMENTATION <agi name="answer" language="en_US"> <synopsis> -- GitLab