
#ifndef CSTR_INC_PAS
#define CSTR_INC_PAS

{  -*- mode: pascal; … -*-

  c string functions for pascal p5x
  ---------------------------------

NB: you may prefer to use the pascal string functions in string.inc.pas

to use these string functions, declare these c string pointer types:

   cstring  =  array[1..maxint] of char;
   cstringPtr  =  ^cstring;

and declare some variables:

    myString : packed array[1..MaxStringSize] of char;
    sp       : cstringPtr;       -- use this to access the c library

The c library uses pointers to strings, so to get a pointer to myString,
do someting like this:

     sp := getcstrPtr(myString);

Now sp points to myString, and sp^[1] is the same as myString[1]. It's not a
copy it's 2 different ways of seeing the same string - if you change one
you'll see the new value in the other.

Note:
- in pascal, strings index from 1, so the first character of a cstringptr
  is also index 1. As mentioned above myString[1] refers to the same
  character as sp^[1].  If you've ever programmed in c you'll see that
  pascal does not use the c convention where strings start at index 0.

- c strings are null terminated, ie chr(0) indicates the end of the string.
  You need to put this in yourself

- you need to make sure that the string you are using is big enough to hold
  the text you are putting into it.

- a c string is a pointer to memory that has not been allocated with new.
  pascal's memory debug identifies this as rouge memory and issues a fatal
  error whenever it sees a cstring being used.
  You can use c strings only with pascal memory debug disabled, ie when
  debug is disabled where the program keyword is.  See the memory debug
  description in the user guide for more information.

You can now use the c string pointer for the arguments to the c library
functions.

simple example:

   myString := 'abc       ';     -- pascal mystring is packed array of 10 chars
   sp := getcstrPtr(myString);
   sp^[4] := chr(0);             -- null terminate string after 3rd char
   writeln('string length is ', strlen(sp^[1]) );

Notes:
- to null terminate the string, we could just as well have written

      myString[4] := chr(0);        -- another way of doing the same thing

- the argument to the string function (strlen in this example) is the first
  character where we want to start using the string - it need not be the
  start of the buffer.  If you want to copy text into the middle of a string,
  say to copy characters spSrc[2...] of the source to characters spDest[6...]
  of the destination, use code like this

    strcpy(spDest^[6], spSrc^[2]);

- it is your responsibility to ensure that the argument to the string
  function is the first character of a valid string.  Nothing will stop
  you calling you calling the function with a character on its own - no
  compiler warnings, no runtime diagnostics, nothing.  Your program will
  very likely crash, of course, possibly with no indication as to why.
  This is the c world, and it is assumed you know what you are doing.

there is some test code in the file tclib.pas you can use as examples.

}

type
   cstring  =  array[1..maxint] of char;
   cstringPtr  =  ^cstring;


{: return a c string pointer that points to a pascal string}
function getcstrPtr(var ps : packed array[lo..hi :integer] of char) : cstringPtr {@@ inline @@};
begin
   getcstrPtr := nil;   {redundant, but compiler error if function result not assigned}
{@@
 return ps_2c;
@@}
end;

{: return the length of a c string - how many characters up to the null character?}
Function Strlen(var firstCh : char) : integer; external;
{@@
inline int Strlen(unsigned char *s) {return strlen(s);}
@@}

{: copy a c string from source to destination.
   src & dst are the first charcters of the strings}
procedure Strcpy(var dst, src : char)  {@@ inline @@} ;
begin
{@@
    (void)strcpy(dst_2, src_2);
@@}
end { Strcpy };


{: append a c string from source to the end of destination.
   src & dst are the first charcters of the strings}
procedure Strcat(var dst, src : char) {@@ inline @@} ;
begin
{@@
    (void)strcat(dst_2, src_2);
@@}
end { Strcat };


{: compare 2 c strings, return
        0  : the strings are identical
        1  : s1 > s2
        -1 : s1 < s2
   s1 and s2 are the first charcters of the strings}
function Strcmp(var s1, s2 : char) : integer {@@ inline @@} ;
begin
      Strcmp := 0;  {dead code, prevents compiler error}
{@@
    return strcmp(s1_2, s2_2);
@@}
end { Strcat };


#endif // CSTR_INC_PAS

