cfastcgiadamod-fcgidmod-fastcgi

FastCGI with Ada


I found http://support.zeus.com/zws/examples/2005/12/16/hello_world_in_perl_and_c and this two examples are working.

Now I tried this for Ada and I can not get it done since 2 days.

fcgi_stdio.ads

with Interfaces.C;
with Interfaces.C.Strings;

package fcgi_stdio is
    function FCGI_Accept return Interfaces.C.int;
    pragma Import (C, FCGI_Accept, "FCGI_Accept");

    procedure FCGI_printf (str : Interfaces.C.Strings.chars_ptr);
    pragma Import (C, FCGI_printf, "FCGI_printf");
end fcgi_stdio;

test.adb

with fcgi_stdio;
with Interfaces.C;
with Interfaces.C.Strings;

procedure Test is
begin
    while Integer (fcgi_stdio.FCGI_Accept) >= 0 loop
        fcgi_stdio.FCGI_printf (Interfaces.C.Strings.New_String ("Content-Type: text/plain" & ASCII.LF & ASCII.LF));
        fcgi_stdio.FCGI_printf (Interfaces.C.Strings.New_String ("Hello World from Ada!" & ASCII.LF));
    end loop;
end Test;

When I run it in the console, I get following error:

$ ./test
raised STORAGE_ERROR : stack overflow or erroneous memory access

Apache error_log shows:

Premature end of script headers: test

Does anyone have an idea how I can get it working?


Solution

  • Experimenting on Mac OS X, it seems that the problem is that FCGI_printf() is a varargs function. It calls FCGI_fprintf(), also varargs:

    int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...)
    {
        va_list ap;
        int n = 0;
        va_start(ap, format);          <------ crash here
    

    Ada doesn't have a standard way of specifying varargs functions, and GNAT doesn't have an implementation-defined way either.

    The GNAT documentation says that the solution is to provide a C wrapper for the varargs function:

    #include <fcgi_stdio.h>
    int FCGI_printf_wrapper(const char *msg)
    {
      return FCGI_printf(msg);
    }
    

    and import the wrapper:

    procedure FCGI_printf (str : Interfaces.C.Strings.chars_ptr);
    pragma Import (C, FCGI_printf, "FCGI_printf_wrapper");
    

    Another problem with the program is that in Ada, unlike C and many other languages, "\n" is not a way of inserting a newline character in a string. Try

    fcgi_stdio.FCGI_printf
      (Interfaces.C.Strings.New_String ("Content-Type: text/plain" 
                                        & ASCII.LF & ASCII.LF));
    

    [edited 13.1.13]