.\" cppawk: C preprocessor wrapper around awk .\" Copyright 2022 Kaz Kylheku .\" .\" BSD-2 License .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions are met: .\" .\" 1. Redistributions of source code must retain the above copyright notice, .\" this list of conditions and the following disclaimer. .\" .\" 2. Redistributions in binary form must reproduce the above copyright notice, .\" this list of conditions and the following disclaimer in the documentation .\" and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE .\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .de bk .IP " " .PP .. .TH CPPAWK-VARG 1 "19 April 2022" "cppawk Libraries" "Variadic Functions" .SH NAME varg \- support functions with optional and variadic parameters .SH SYNOPSIS .ft B #include present(\fIarg\fP) \fI// test whether arg is present\fP restargs \fI// declarator for variadic params\fP arg(\fIn\fP) \fI// access n-th arg, literal n\fP argcount(\fIfname\fP, restargs) \fI// count of variadic arguments\fP arglist(\fIfname\fP, restargs) \fI// list of variadic arguments\fP argarray(\fIfname\fP, \fIarr\fP, restargs) \fI// list of variadic arguments\fP .ft R .SH DESCRIPTION .bk The .B header provides some utilities for working with optional and variable arguments in Awk. In Awk, any function may be called with fewer than the declared number of arguments. The arguments which are not passed take on unassigned values. The .B present macro tests whether its argument .I arg is an undefined value, returning 1 if it is defined, otherwise 0. .B Example: .ft B #include function f(\fIa\fP, \fIb\fP) { if (present(\fIa\fP)) print "a is present, with value", \fIa\fP else print "a is missing" if (present(\fIb\fP)) print "b is present, with value", \fIb\fP else print "b is missing" } BEGIN { print "test1" f() print "test2" f(1) print "test3" f(1, 2) print "test4" f(undef, 2) } .ft R .B Output: .ft B test1 a is missing b is missing test2 a is present, with value 1 b is missing test3 a is present, with value 1 b is present, with value 2 test4 a is missing b is present, with value 2 .ft R Note the trick used in .BR test4 : the unassigned variable .B undef was used to explicitly pass the unset value as argument .IR a , while passing a defined value as .IR b . That concludes the topic of optional arguments. The remainder of the .B functionality revolves around variadic functions. A variadic function is defined by including the .B restargs macro in the argument list, as if it were an argument. The following function has two fixed parameters .I x and .IR y , followed by variadic arguments. .ft B #include fun f(\fIx\fP, \fIy\fP, restargs) { } .ft R The .B restarts "super parameter" is capable of capturing up to 32 arguments. Within a variadic function, the .B arg macro may be used to access a variadic argument by a positional number ranging from 1 to 32. The .B present macro may be used to check whether the argument is present, The argument of .B arg must be an decimal integer literal constant. Computed access to argument by position is not supported; but the arguments may be converted to an array or list: .ft B #include function f(\fIx\fP, \fIy\fP, restargs) { if (present(arg(3))) { print "variadic arg 3 is present, value = ", arg(3) } else { print "variadic arg 3 is missing" } } .ft R The .B argcount function calculates how many variadic arguments there are. The first argument of .B argcount is the name of the calling function, used for error reporting: .ft B #include function f(\fIx\fP, \fIy\fP, restargs, \fIcount\fP) { \fIcount\fP = argcount("f", restargs); print "f was called with", \fIcount\fP, "variadic arguments" } .ft P Note: .B argcount has no way to obtain the value directly from Awk. It works by receiving all of the arguments, and performing a binary search to find the first undefined one. The assumption is that there are no gaps among the variadic arguments. No undefined argument is followed by a defined one. The .B arglist function returns a list containing the arguments. Lists are defined in the header. Like in the case of .BR argcount , the first argument is the name of the calling function, used for error reporting: .ft B #include #include function f(\fIx\fP, \fIy\fP, restargs, \fIlist\fP) { \fIlist\fP = arglist("f", restargs); print "f was called with these trailing args", sexp(list) \fI// also return the list\fP return list } .ft R Lastly, the .B argarray function stuffs the variadic arguments into an associative array, which is indexed by the argument positions: 1, 2, 3, ... The first argument is the calling function's name, used for error reporting. The second argument is the destination array. The variadic arguments follow: .ft B #include #include function f(\fIx\fP, \fIy\fP, restargs, \fIarr\fP, \fIi\fP) { \fI// get arguments into arr\fP argarray("f", \fIarr\fP, restargs); print "f was called with these trailing args" for (i in arr) print "arg", i, "=", arr[i] } .ft R What happens if more than 32 arguments are passed? Those arguments will "crash" into the local variable area. All of the above functions provide error detection for this case, according to the following pattern: .ft B #include function f(\fIx\fP, \fIy\fP, restargs, \fIcount\fP) { \fIcount\fP = argcount("f", restargs, \fIcount\fP); print "f was called with", \fIcount\fP, "variadic arguments" } .ft R In the above example, the first local variable which follows the .B restargs list is .IR count . That variable is passed as an extra argument to the .B argcount function. The .B argcount function expects this extra argument to be undefined. If it has an assigned value, it will terminate Awk with a diagnostic message. The only way .I count can have an assigned value at the time .B argcount is called is if .B f was called with so many trailing parameters, that .I count was given a value in the function call, and so if that is the case, the 32 limit on the number of variadic arguments has been exceeded. If this issue is not caught, functions which rely on their local variables to be initially unassigned may malfunction. Also, variadic arguments beyond 32 will end up silently ignored: not taken into account by .B argcount and so forth. The .B arglist and .B argarray functions also take an extra argument for this purpose. If the extra argument is not passed, then there is no error checking. Functions which don't have any local variables after .B restargs don't require it. Awk itself will diagnose the situation when more than 32 variadic parameters are passed in that case. .SH "SEE ALSO" cppawk(1), cppawk-cons(1) .SH BUGS The 32 argument limitation is a flaw; ideally, there should be no such limitations. The argument overflow detection is only good up to 48 arguments. That is to say, if more than 32 arguments are passed, up to 48, the situation can be detected by .BR argcount , .B arglist and .B argarray using the extra argument mechanism. Beyond 48 variadic arguments, the behavior of these functions is unspecified. .SH AUTHOR Kaz Kylheku .SH COPYRIGHT Copyright 2022, BSD2 License.