diff --git a/XSUB.h b/XSUB.h index 87893d4351..1fc27cd3ff 100644 --- a/XSUB.h +++ b/XSUB.h @@ -44,7 +44,7 @@ must be called prior to setup the C variable. =for apidoc Amn|Stack_off_t|items Variable which is setup by C to indicate the number of -items on the stack. See L. +items on the stack. See L. =for apidoc Amn|I32|ix Variable which is setup by C to indicate which of an diff --git a/dist/ExtUtils-ParseXS/lib/perlxs.pod b/dist/ExtUtils-ParseXS/lib/perlxs.pod index 3c624daf66..a038ae04c0 100644 --- a/dist/ExtUtils-ParseXS/lib/perlxs.pod +++ b/dist/ExtUtils-ParseXS/lib/perlxs.pod @@ -2350,93 +2350,174 @@ which could be called from perl as: =head3 Default Parameter Values -Default values for XSUB arguments can be specified by placing an -assignment statement in the parameter list. The default value may -be a number, a string or the special string C. Defaults should -always be used on the right-most parameters only. + int + foo(int i, char *s = "abc") -To allow the XSUB for rpcb_gettime() to have a default host -value the parameters to the XSUB could be rearranged. The -XSUB will then call the real rpcb_gettime() function with -the parameters in the correct order. This XSUB can be called -from Perl with either of the following statements: + int + bar(int i, int j = i + ')', char *s = "abc,)") - $status = rpcb_gettime($timep, $host); + int + baz(int i, char *s = NO_INIT) - $status = rpcb_gettime($timep); +Optional parameters can be indicated by appending C<= C_expression> to the +parameter declaration. The C expression will be evaluated if not enough +arguments are supplied. Parameters with default values should come after +any mandatory parameters (although this is currently not enforced by the +XS compiler). The value can be any valid compile-time or run-time C +expression (but see below), including the values of any parameters +declared to its left. The special value C indicates that the +parameter is kept uninitialised if there isn't a corresponding argument. -The XSUB will look like the code which follows. A CODE: -block is used to call the real rpcb_gettime() function with -the parameters in the correct order for that function. +The XS parser's handling of default expressions is rather simplistic. It +just wants to extract parameter declarations (including any optional +trailing default value) from a comma-separated list, but it doesn't +understand C syntax. It can handle commas and closing parentheses within a +quoted string, but currently not an escaped quote such as C<'\''> or +C<"\"">. Neither can it handle balanced parentheses such as C. - bool_t - rpcb_gettime(timep, host="localhost") - char *host - time_t timep = NO_INIT - CODE: - RETVAL = rpcb_gettime(host, &timep); - OUTPUT: - timep - RETVAL +Due to an implementation flaw, default value expressions are currently +evalled in double-quoted context during parsing, in a similar fashion to +typemap templates. So for example C is expanded to +C or similar. This behaviour may be fixed at some +point; in the meantime, it is best to avoid the C<$> and C<@> characters +within default value expressions. -=head3 The C Keyword +=head3 The C pseudo-parameter -If one of the input arguments to the C function is the length of a string -argument C, one can substitute the name of the length-argument by -C in the XSUB declaration. This argument must be omitted when -the generated Perl function is called. E.g., + int + foo(char *s, int length(s)) + +It is common for a C function to take a string pointer and length as two +arguments, while in Perl, string-valued SVs combine both the string and +length in a single value. To simplify generating the autocall code in such +situations, the C pseudo-parameter acts as the length of the +parameter C. It doesn't consume an argument or appear in the XSUB's +usage message, but it I passed to the autocalled C function. For +example, this XS: void - dump_chars(char *s, short l) + foo(char *s, short length(s), int t) + +translates to something similar to this C code: + + if (items != 2) + croak_xs_usage(cv, "s, t"); + { - short n = 0; - while (n < l) { - printf("s[%d] = \"\\%#03o\"\n", n, (int)s[n]); - n++; - } + STRLEN STRLEN_length_of_s; + short XSauto_length_of_s; + char * s = (char *)SvPV(ST(0), STRLEN_length_of_s); + int t = (int)SvIV(ST(1)); + + XSauto_length_of_s = STRLEN_length_of_s; + foo(s, XSauto_length_of_s, t); } - MODULE = x PACKAGE = x +and might be called from Perl as: - void dump_chars(char *s, short length(s)) + foo("abcd", 9999); -should be called as C. +The exact C code generated will vary over releases, but the important +things to note are: -This directive is supported with ANSI-type function declarations only. +=over -=head3 Variable-length Parameter Lists +=item * -XSUBs can have variable-length parameter lists by specifying an ellipsis -C<(...)> in the parameter list. This use of the ellipsis is similar to that -found in ANSI C. The programmer is able to determine the number of -arguments passed to the XSUB by examining the C variable which the -B compiler supplies for all XSUBs. By using this mechanism one can -create an XSUB which accepts a list of parameters of unknown length. +The auto variable C will be declared with the +specified type and will be passed to any autocall function, but it won't +appear in the usage message. This variable is available for use in C +blocks and similar. -The I parameter for the rpcb_gettime() XSUB can be -optional so the ellipsis can be used to indicate that the -XSUB will take a variable number of parameters. Perl should -be able to call this XSUB with either of the following statements. +=item * - $status = rpcb_gettime($timep, $host); +The auto variable C is used in addition to allow +conversion between the type expected by C and the type declared +for the length pseudo-parameter. - $status = rpcb_gettime($timep); +=item * -The XS code, with ellipsis, follows. +A length parameter can appear anywhere in the signature, even before the +string parameter of the same name; but its position in any autocall +matches its position in the signature. - bool_t - rpcb_gettime(timep, ...) - time_t timep = NO_INIT - PREINIT: - char *host = "localhost"; +=item * + +Each length parameter must match another parameter of the same name. That +parameter must be a string type (something which maps to the C +typemap type). + +=back + +=head3 Ellipsis: variable-length parameter lists + + int + foo(char *s, ...) + +An XSUB can have a variable-length parameter list by specifying an +ellipsis as the last parameter, similar to C function declarations. Its +main effect is to disable the error check for too many parameters. Any +declared parameters will still be processed as normal, but the programmer +will have to access any extra arguments manually, making use of the +C macro to access the nth item on the stack (counting from 0), and +the C variable, which indicates the total number of passed +arguments, including any fixed arguments. + +Note that currently XS doesn't provide any mechanism to autocall +variable-length C functions, so the ellipsis should only be used on XSUBs +which have a body. + +For example, consider this Perl subroutine which returns the sum of all +of its arguments which are within a specified range: + + sub minmax_sum { + my $min = shift; + my $max = shift; + my $RETVAL = 0; + $RETVAL += $_ for grep { $min <= $_ && $_ <= $max } @_; + return $RETVAL; + } + +This XSUB provides equivalent functionality: + + int + minmax_sum(int min, int max, ...) CODE: - if (items > 1) - host = (char *)SvPVbyte_nolen(ST(1)); - RETVAL = rpcb_gettime(host, &timep); + { + int i = 2; /* skip the two fixed arguments */ + RETVAL = 0; + + for (; i < items; i++) { + int val = (int)SvIV(ST(i)); + if (min <= val && val <= max) + RETVAL += val; + } + } OUTPUT: - timep RETVAL +It is possible to write an XSUB which both accepts and returns a list. For +example, this XSUB does the equivalent of the Perl C + + void + triple(...) + PPCODE: + SP += items; + { + int i; + for (i = 0; i < items; i++) { + int val = (int)SvIV(ST(i)); + ST(i) = sv_2mortal(newSViv(val*3)); + } + } + +Note that the L keyword, in comparison to +C, resets the local copy of the argument stack pointer, and relies +on the coder to place any return values on the stack. The example above +reclaims the passed arguments by setting C back to the top of the +stack, then replaces the items on the stack one by one. + =head2 The XSUB Input Part XXX TBC @@ -3247,7 +3328,7 @@ included in that case. A CASE: might switch via a parameter of the XSUB, via the C ALIAS: variable (see L<"The ALIAS: Keyword">), or maybe via the C variable -(see L<"Variable-length Parameter Lists">). The last CASE: becomes the +(see L<"Ellipsis: variable-length parameter lists">). The last CASE: becomes the B case if it is not associated with a conditional. The following example shows CASE switched via C with a function C having an alias C. When the function is called as