/****************************************************************************
**
*W  string.h                    GAP source                   Martin Schönert
**
**
*Y  Copyright (C)  1996,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
*Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
*Y  Copyright (C) 2002 The GAP Group
**
**  This file declares the functions which mainly deal with strings.
**
**  A *string* is a  list that  has no  holes, and  whose  elements  are  all
**  characters.  For the full definition of strings see chapter  "Strings" in
**  the {\GAP} manual.  Read also "More about Strings" about the  string flag
**  and the compact representation of strings.
**
**  Strings in compact representation  can be accessed and handled through
**  the  macros     'NEW_STRING',   `CHARS_STRING'  (and   'CSTR_STRING'),
**  'GET_LEN_STRING',   `SET_LEN_STRING', `GROW_STRING',  'GET_ELM_STRING'
**  and `SET_ELM_STRING'.
**  
**  This  package also contains the   list  function  for ranges, which   are
**  installed in the appropriate tables by 'InitString'.
*/

#ifndef libGAP_GAP_STRING_H
#define libGAP_GAP_STRING_H

#include <string.h>  /* for memcpy */

/****************************************************************************
**

*F * * * * * * * * * * * * * * character functions  * * * * * * * * * * * * *
*/

/****************************************************************************
**


*V  ObjsChar[<chr>] . . . . . . . . . . . . . . . . table of character values
**
**  'ObjsChar' contains all the character values.  That way we do not need to
**  allocate new bags for new characters.
*/
extern libGAP_Obj libGAP_ObjsChar [256];


/****************************************************************************
**

*F * * * * * * * * * * * * * * * string functions * * * * * * * * * * * * * *
*/

/****************************************************************************
**
*F  SIZEBAG_STRINGLEN( <len> ) . . . . size of Bag for string of length <len>
**  
*/
#define libGAP_SIZEBAG_STRINGLEN(len)         ((len) + 1 + sizeof(libGAP_UInt))

/****************************************************************************
**
*F  CSTR_STRING( <list> ) . . . . . . . . . . . . . . .  C string of a string
*F  CHARS_STRING( <list> ) . . . . . . . . . . . . . .   same pointer 
**
**  'CSTR_STRING'  returns the (address  of the)  C  character string of  the
**  string <list>. Note that the string as C string is truncated before the
**  first null character. Try to avoid this and use CHARS_STRING.
**
**  Note that 'CSTR_STRING' is a macro, so do not call it with arguments that
**  have side effects.
*/
#define libGAP_CSTR_STRING(list)            ((libGAP_Char*)libGAP_ADDR_OBJ(list) + sizeof(libGAP_UInt))
#define libGAP_CHARS_STRING(list)           ((libGAP_UChar*)libGAP_ADDR_OBJ(list) + sizeof(libGAP_UInt))

/****************************************************************************
**
*F  GET_LEN_STRING( <list> )  . . . . . . . . . . . . . .  length of a string
**
**  'GET_LEN_STRING' returns the length of the string <list>, as a C integer.
**
**  Note that  'GET_LEN_STRING' is a macro, so  do not call it with arguments
**  that have side effects.
*/
#define libGAP_GET_LEN_STRING(list)            (*((libGAP_UInt*)libGAP_ADDR_OBJ(list)))

/****************************************************************************
**
*F  SET_LEN_STRING( <list>, <len> ) . . . . . . . . . set length of a string
**
**  'SET_LEN_STRING' sets length of the string <list> to C integer <len>.
**
**  Note that  'SET_LEN_STRING' is a macro, so  do not call it with arguments
**  that have side effects.
*/
#define libGAP_SET_LEN_STRING(list,len)     (*((libGAP_UInt*)libGAP_ADDR_OBJ(list)) = (libGAP_UInt)(len))

/****************************************************************************
**
*F  NEW_STRING( <len> ) . . . . . . . . . . . . . . . . . . make a new string
**
**  'NEW_STRING' returns a new string with room for <len> characters. It also
**  sets its length to len. 
**
*/
extern libGAP_Obj libGAP_NEW_STRING(libGAP_Int len);

/****************************************************************************
**
*F  GROW_STRING(<list>, <len>) . . . .  make sure a string is large enough
**
**  'GROW_STRING' grows  the string <list>  if necessary to ensure that it
**  has room for at least <len> elements.
**
**  Note that 'GROW_STRING' is a macro, so do not call it with arguments that
**  have side effects.
*/
#define libGAP_GROW_STRING(list,len)   ( ((len) + sizeof(libGAP_UInt) < libGAP_SIZE_OBJ(list)) ? \
                                 0L : libGAP_GrowString(list,len) )

extern  libGAP_Int             libGAP_GrowString (
            libGAP_Obj                 list,
            libGAP_UInt                need );

/****************************************************************************
**
*F  SHRINK_STRING(<list>) . . . . . . . . .  shrink a string to minimal size
**
**  'SHRINK_STRING' gives back not needed memory allocated by string.
**
**  Note that 'SHRINK_STRING' is a macro, so do not call it with arguments that
**  have side effects.
*/
#define libGAP_SHRINK_STRING(list)   libGAP_ResizeBag((list),\
                            (libGAP_SIZEBAG_STRINGLEN(libGAP_GET_LEN_STRING((list)))));

/****************************************************************************
**
*F  GET_ELM_STRING( <list>, <pos> ) . . . . . . select an element of a string
**
**  'GET_ELM_STRING'  returns the  <pos>-th  element  of  the string  <list>.
**  <pos> must be  a positive integer  less than  or  equal to  the length of
**  <list>.
**
**  Note that 'GET_ELM_STRING' is a  macro, so do not  call it with arguments
**  that have side effects.
*/
#define libGAP_GET_ELM_STRING(list,pos)        (libGAP_ObjsChar[ \
                         (((libGAP_UInt1*)libGAP_ADDR_OBJ(list))[(pos) + sizeof(libGAP_UInt) - 1])])

/****************************************************************************
**
*F  SET_ELM_STRING( <list>, <pos>, <val> ) . . . . set a character of a string
**
**  'SET_ELM_STRING'  sets the  <pos>-th  character  of  the string  <list>.
**  <val> must be a character and <list> stay a string after the assignment.
**
**  Note that 'SET_ELM_STRING' is a  macro, so do not  call it with arguments
**  that have side effects.
*/
#define libGAP_SET_ELM_STRING(list,pos,val)      (((libGAP_UInt1*)libGAP_ADDR_OBJ(list))\
[(pos) + sizeof(libGAP_UInt) - 1] = *((libGAP_UInt1*)libGAP_ADDR_OBJ(val)))

/****************************************************************************
**
*F  COPY_CHARS( <str>, <charpnt>, <n> ) . . . copies <n> chars, starting
**  from character pointer <charpnt>, to beginning of string
**  
**  This is a   macro. It assumes  that the  data  area in  <str> is  large
**  enough. It does not add a terminating null character and not change the
**  length of the string.
**
*/
#define libGAP_COPY_CHARS(str,pnt,n)         (memcpy(libGAP_CHARS_STRING(str), pnt, n));

/****************************************************************************
**
*F  PrintString( <list> ) . . . . . . . . . . . . . . . . . .  print a string
**
**  'PrintString' prints the string with the handle <list>.
**
**  No  linebreaks are allowed,  if one must be  inserted  anyhow, it must be
** escaped by a backslash '\', which is done in 'Pr'.  */
extern void libGAP_PrintString (
    libGAP_Obj                 list );


/****************************************************************************
**
*F  PrintString1( <list> )  . . . . . . . . . . .  print a string for 'Print'
**
**  'PrintString1' prints the string  constant  in  the  format  used  by  the
**  'Print' and 'PrintTo' function.
*/
extern void libGAP_PrintString1 (
            libGAP_Obj                 list );


/****************************************************************************
**

*F  IS_STRING( <obj> )  . . . . . . . . . . . . test if an object is a string
**
**  'IS_STRING' returns 1  if the object <obj>  is a string  and 0 otherwise.
**  It does not change the representation of <obj>.
**
**  Note that 'IS_STRING' is a  macro, so do not call  it with arguments that
**  have side effects.
*/
#define libGAP_IS_STRING(obj)  ((*libGAP_IsStringFuncs[ libGAP_TNUM_OBJ( obj ) ])( obj ))

extern  libGAP_Int             (*libGAP_IsStringFuncs [libGAP_LAST_REAL_TNUM+1]) ( libGAP_Obj obj );


/****************************************************************************
**
*F  IS_STRING_REP( <list> ) . . . . . . . .  check if <list> is in string rep
*/
#define libGAP_IS_STRING_REP(list)  \
  (libGAP_T_STRING <= libGAP_TNUM_OBJ(list) && libGAP_TNUM_OBJ(list) <= libGAP_T_STRING_SSORT+libGAP_IMMUTABLE)


/****************************************************************************
**
*F  IsString( <obj> ) . . . . . . . . . . . . . test if an object is a string
**
**  'IsString' returns 1 if the object <obj> is a string and 0 otherwise.  It
**  does not change the representation of <obj>.
*/
extern libGAP_Int libGAP_IsString (
            libGAP_Obj                 obj );


/****************************************************************************
**
*F  CopyToStringRep( <string> )  . . copy a string to the string representation
**
**  'CopyToStringRep' copies the string <string> to a new string in string
**  representation.
*/
extern libGAP_Obj libGAP_CopyToStringRep(
            libGAP_Obj                 string );


/****************************************************************************
**
*F  ConvString( <string> )  . . convert a string to the string representation
**
**  'ConvString' converts the string <list> to the string representation.
*/
extern void libGAP_ConvString (
            libGAP_Obj                 string );


/****************************************************************************
**
*F  IsStringConv( <obj> ) . . . . . test if an object is a string and convert
**
**  'IsStringConv'   returns 1  if   the object <obj>  is   a  string,  and 0
**  otherwise.   If <obj> is a  string it  changes  its representation to the
**  string representation.
*/
extern libGAP_Int libGAP_IsStringConv (
            libGAP_Obj                 obj );


/****************************************************************************
**
*F  C_NEW_STRING( <string>, <len>, <cstring> )  . . . . . . create GAP string
*/
#define libGAP_C_NEW_STRING(string,len,cstr) \
  do { \
    size_t tmp_len = (len); \
    string = libGAP_NEW_STRING( tmp_len ); \
    memcpy( libGAP_CHARS_STRING(string), (cstr), tmp_len ); \
  } while ( 0 );

/****************************************************************************
**
*F  MakeImmutableString(  <str> ) make a string immutable in place
**
*/

void libGAP_MakeImmutableString(libGAP_Obj str);


libGAP_Obj libGAP_MakeString(libGAP_Char *cstr);
libGAP_Obj libGAP_MakeString2(libGAP_Char *cstr1, libGAP_Char *cstr2);
libGAP_Obj libGAP_MakeString3(libGAP_Char *cstr1, libGAP_Char *cstr2, libGAP_Char *cstr3);
libGAP_Obj libGAP_MakeImmString(libGAP_Char *cstr);
libGAP_Obj libGAP_MakeImmString2(libGAP_Char *cstr1, libGAP_Char *cstr2);
libGAP_Obj libGAP_MakeImmString3(libGAP_Char *cstr1, libGAP_Char *cstr2, libGAP_Char *cstr3);
libGAP_Obj libGAP_ConvImmString(libGAP_Obj str);


/****************************************************************************
**
*F  C_NEW_STRING_DYN( <string>, <cstring> ) . . . . . . . . create GAP string
**
** The cstring is assumed to be allocated on the heap, hence its length
** is dynamic and must be computed during runtime using strlen.
*/
#define libGAP_C_NEW_STRING_DYN(string,cstr) \
  libGAP_C_NEW_STRING(string, strlen(cstr), cstr)

/****************************************************************************
**
*F  C_NEW_STRING_CONST( <string>, <cstring> ) . . . . . . . . create GAP string
**
** The cstring is assumed to be a literal constant (like this: "string").
** Hence its length is constant and can be computed during compilation.
*/
#define libGAP_C_NEW_STRING_CONST(string,cstr) \
  libGAP_C_NEW_STRING(string, sizeof(cstr)-1, cstr)

/****************************************************************************
**
*F  SINT_CHAR(a)
**
**  'SINT_CHAR' converts the character a (a UInt1) into a signed (C) integer.
*/
#define libGAP_SINT_CHAR(a)    (((libGAP_UInt1)a)<128 ? (libGAP_Int)a : (libGAP_Int)a-256)

/****************************************************************************
**
*F  CHAR_SINT(n)
**
**  'CHAR_SINT' converts the signed (C) integer n into an (UInt1) character.
*/
#define libGAP_CHAR_SINT(n)    (libGAP_UInt1)(n>=0 ? n : n+256)

/****************************************************************************
**

*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  InitInfoString()  . . . . . . . . . . . . . . . . table of init functions
*/
libGAP_StructInitInfo * libGAP_InitInfoString ( void );


#endif // GAP_STRING_H

/****************************************************************************
**

*E  string.h  . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
*/
