2
votes

I have a rather simple Pascal program, that is to call some C functions I have written.

My C code:

void connect_default(int* errorcode)
{
    // Connects the default user and places any error code in errorcode
}

void connect(char user[129], char password[129], int* errorcode)
{
    // Connects the given user and places any error code in errorcode
}

I'm trying to call these two functions in my Pascal application. This works fine:

program pascaltest(INPUT, OUTPUT);
procedure connect_default(var errorcode: integer); external;

var
errorcode : integer := 0;

begin
    connect_default(errorcode);
    if errorcode <> 0 then
        writeln('Failed to connect with error code ', errorcode);
end.

But I have a hard time finding out what data type to use in Pascal, that corresponds to a null terminated char array in C. A Pascal string does not seem to be it, because this passes nothing to the C function.

program pascaltest(INPUT, OUTPUT);
procedure connect(user : string, password : string, var errorcode: integer); external;

var
errorcode : integer := 0;

begin
    connect('MyUser', 'MyPassword', errorcode);
    if errorcode <> 0 then
        writeln('Failed to connect with error code ', errorcode);
end.

What datatype in Pascal corresponds to a null terminated C char array? My environment is a HP OpenVMS machine and not Free Pascal, meaning that I do not have access to the types pchar and ansistring that I have read about.

The C functions need to stay as general as possible and I cannot make any changes to them, creating custom structs (like what is described here Declaring Pascal-style strings in C), as the C functions are already successfully called by similar programs written in C, Fortran and Cobol, where I managed to find the data types needed.

2
Respect for keeping the platform alive! :D - cxw
Wasn't Pascal string length stored to the first byte of the array? Couldn't you just move the whole string with memmove one byte left, and set the terminating '\0' to the end. - Janne Tuukkanen
@JanneTuukkanen as described at the end of the post, I cannot make any changes to the C functions. Such a solution would probably work for Pascal, but then I would mess the C functions up for the calling Fortran and Cobol programs, that do not store the string length in the first byte. - Helena
Some pascal compilers can use the PChar type, which is a null terminated character array. connect(PChar('MyUser'), ... - LU RD
It seems the OpenVMS Pascal has a C_STR_T type, which holds a null terminated array of char, and some helper functions, for example MALLOC_C_STR(), which allocates a C_STR_T from a string and returns a pointer to the structure. - LU RD

2 Answers

2
votes

As you can see in official HP documentation, you Pascal version supports null-terminated strings: http://h41379.www4.hpe.com/doc/82final/6083/6083pro_005.html#null_strings

2.7 Null-Terminated Strings

HP Pascal includes routines and a built-in type to better coexist with null-terminated strings in the C language. The C_STR_T datatype is equivalent to:

C_STR_T = ^ ARRAY [0..0] OF CHAR;

C_STR_T is a pointer to an ARRAY OF CHARs. It does not allocate memory for any character data. C_STR_T behaves like a normal pointer type in that you can assign NIL into it and the optional pointer checking code will check for dereferencing of a NIL pointer. The individual characters can be used by dereferencing the pointer and using an array index.

In these cases, no bounds checking will be performed even if array bounds checking is enabled. However, you cannot dereference a C_STR_T pointer without also indexing a single character. If you want to access an entire null-terminated string, see the PAS_STR function.

Then you can use that C-style strings as a read-only references or convert them into standalone Pascal strings via PAS_STR function: http://h41379.www4.hpe.com/doc/82final/6083/6083pro_016.html#pas_str_func

And PAS_STRCPY would do opposite thing right away: http://h41379.www4.hpe.com/doc/82final/6083/6083pro_016.html#pas_strcpy

1
votes

I found a workaround for now that does not affect my C code at all, but is not very dynamic. In my specific case, the user name and password are hard-coded.

I simply use a character array in Pascal, and set the characters one by one. It is however not a good solution in the general case, and I want to accept Yury Schkatula's answer as the correct one. That is the intended use. I cannot, however, since I never got it to work. I will update this thread if I find out why.

program pascaltest(INPUT, OUTPUT);

type username = array [0..6] of char;
type password = array [0..10] of char;

procedure connect(var user : username, var pass : password, var errorcode: integer); external;

var
errorcode : integer := 0;
user : username;
pass : password;

begin
   user[0] := 'M';
   user[1] := 'y';
   user[2] := 'U';
   user[3] := 's';
   user[4] := 'e';
   user[5] := 'r';
   user[6] := chr(0);

   pass[0] := 'M';
   pass[1] := 'y';
   pass[2] := 'P';
   pass[3] := 'a';
   pass[4] := 's';
   pass[5] := 's';
   pass[6] := 'w';
   pass[7] := 'o';
   pass[8] := 'r';
   pass[9] := 'd';
   pass[10] := chr(0);

   connect(user, pass, errorcode);
   if errorcode <> 0 then
      writeln('Failed to connect with error code ', errorcode);
end.