Logo Search packages:      
Sourcecode: gambas version File versions  Download package

gbx_subr_string.c

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

  subr_string.c

  The String management subroutines

  (c) 2000-2004 Beno� Minisini <gambas@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 1, or (at your option)
  any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

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

#include "gb_common.h"
#include "gb_common_buffer.h"
#include "gb_common_case.h"

#include <ctype.h>
#include <regex.h>

#include "gb_pcode.h"
#include "gbx_value.h"
#include "gbx_subr.h"
#include "gbx_regexp.h"
#include "gbx_class.h"
#include "gbx_string.h"
#include "gbx_c_array.h"


PUBLIC void SUBR_cat(void)
{
  int i;
  long len, len_cat;
  char *str, *ptr;

  SUBR_ENTER();

  len_cat = 0;

  for (i = 0; i < NPARAM; i++)
  {
    VALUE_conv(&PARAM[i], T_STRING);
    /*BORROW(&PARAM[i]);*/
    len_cat += PARAM[i]._string.len;
  }

  STRING_new_temp(&str, NULL, len_cat);
  ptr = str;

  for (i = 0; i < NPARAM; i++)
  {
    len = PARAM[i]._string.len;
    if (len > 0)
    {
      /*printf("add %p ", PARAM[i]._string.addr + PARAM[i]._string.start); fflush(NULL);
      printf("%.*s\n", (int)len, PARAM[i]._string.addr + PARAM[i]._string.start);*/
      memcpy(ptr, PARAM[i]._string.addr + PARAM[i]._string.start, len);
      ptr += len;
    }
  }

  /*printf("\n");*/

  RETURN->type = T_STRING;
  RETURN->_string.addr = str;
  RETURN->_string.start = 0;
  RETURN->_string.len = len_cat;

  SUBR_LEAVE();
}


PUBLIC void SUBR_file(void)
{
  int i;
  long length;
  char *addr;
  long len;
  char *str, *ptr;
  boolean slash;

  SUBR_ENTER();

  length = 0;
  slash = FALSE;

  for (i = 0; i < NPARAM; i++)
  {
    /*VALUE_conv(&PARAM[i], T_STRING);*/
    SUBR_get_string_len(&PARAM[i], &addr, &len);

    if (len > 0)
    {
      if (length > 0)
      {
        if (!slash && (addr[0] != '/'))
          length++;
      }

      slash = addr[len - 1] == '/';

      length += len;
    }

  }

  STRING_new_temp(&str, NULL, length);
  ptr = str;

  for (i = 0; i < NPARAM; i++)
  {
    VALUE_get_string(&PARAM[i], &addr, &len);
    if (len > 0)
    {
      if ((ptr > str) && (ptr[-1] != '/') && (*addr != '/'))
        *ptr++ = '/';
      memcpy(ptr, addr, len);
      ptr += len;
    }
  }

  RETURN->type = T_STRING;
  RETURN->_string.addr = str;
  RETURN->_string.start = 0;
  RETURN->_string.len = length;

  SUBR_LEAVE();
}



PUBLIC void SUBR_left(void)
{
  long val;

  SUBR_ENTER();

  if (SUBR_check_string(PARAM))
    goto _FIN;

  if (NPARAM == 1)
    val = 1;
  else
  {
    VALUE_conv(&PARAM[1], T_INTEGER);
    val = PARAM[1]._integer.value;
  }

  if (val < 0)
    val += PARAM->_string.len;

  PARAM->_string.len = MinMax(val, 0, PARAM->_string.len);

_FIN:

  SP -= NPARAM;
  SP++;
}



PUBLIC void SUBR_right(void)
{
  long val;
  long new_len;

  SUBR_ENTER();

  if (SUBR_check_string(PARAM))
    goto _FIN;

  if (NPARAM == 1)
    val = 1;
  else
  {
    VALUE_conv(&PARAM[1], T_INTEGER);
    val = PARAM[1]._integer.value;
  }

  if (val < 0)
    val += PARAM->_string.len;

  new_len = MinMax(val, 0, PARAM->_string.len);

  PARAM->_string.start += PARAM->_string.len - new_len;
  PARAM->_string.len = new_len;

_FIN:

  SP -= NPARAM;
  SP++;
}




PUBLIC void SUBR_mid(void)
{
  long start;
  long len;

  SUBR_ENTER();

  if (SUBR_check_string(PARAM))
    goto FIN;

  VALUE_conv(&PARAM[1], T_INTEGER);
  start = PARAM[1]._integer.value - 1;

  if (start < 0)
    THROW(E_ARG);

  if (start >= PARAM->_string.len)
  {
    RELEASE(PARAM);
    STRING_void_value(PARAM);
    goto FIN;
  }

  if (NPARAM == 2)
    len = PARAM->_string.len;
  else
  {
    VALUE_conv(&PARAM[2], T_INTEGER);
    len = PARAM[2]._integer.value;
  }

  if (len < 0)
    len = Max(0, PARAM->_string.len - start + len);

  len = MinMax(len, 0, PARAM->_string.len - start);

  if (len == 0)
  {
    RELEASE(PARAM);
    PARAM->_string.addr = NULL;
    PARAM->_string.start = 0;
  }
  else
    PARAM->_string.start += start;

  PARAM->_string.len = len;

FIN:

  SP -= NPARAM;
  SP++;
}



PUBLIC void SUBR_len(void)
{
  long len;

  SUBR_GET_PARAM(1);

  if (SUBR_check_string(PARAM))
    len = 0;
  else
    len = PARAM->_string.len;

  RELEASE(PARAM);

  PARAM->type = T_INTEGER;
  PARAM->_integer.value = len;
}


PUBLIC void SUBR_space(void)
{
  int len;

  SUBR_ENTER_PARAM(1);

  SUBR_check_integer(PARAM);
  len = PARAM->_integer.value;

  if (len < 0)
    THROW(E_ARG);

  if (len == 0)
  {
    STRING_void_value(RETURN);
  }
  else
  {
    STRING_new_temp_value(RETURN, NULL, len);
    memset(RETURN->_string.addr, ' ', len);
  }

  SUBR_LEAVE();
}



PUBLIC void SUBR_string(void)
{
  int i;
  char *d;
  char *s;
  long ld, ls;

  SUBR_ENTER_PARAM(2);

  SUBR_check_integer(PARAM);
  SUBR_get_string_len(&PARAM[1], &s, &ls);

  ld = PARAM->_integer.value * ls;
  if (ld < 0)
    THROW(E_ARG);

  if (ld == 0)
  {
    STRING_void_value(RETURN);
  }
  else
  {
    STRING_new_temp_value(RETURN, NULL, ld);
    d = RETURN->_string.addr;

    for (i = 0; i < PARAM->_integer.value; i++)
    {
      memcpy(d, s, ls);
      d += ls;
    }

    *d = 0;
  }

  SUBR_LEAVE();
}


PUBLIC void SUBR_trim(void)
{
  unsigned char *str;
  bool left, right;
  int code;

  SUBR_GET_PARAM(1);

  if (SUBR_check_string(PARAM))
    return;

  code = EXEC_code & 0x1F;
  left = (code == 0 || code == 1);
  right = (code == 0 || code == 2);

  if (!(left || right))
    THROW(E_ILLEGAL);


  if (PARAM->_string.len > 0)
  {
    str = (uchar *)&PARAM->_string.addr[PARAM->_string.start];

    if (left)
    {
      while (PARAM->_string.len > 0 && *str <= ' ')
      {
        PARAM->_string.start++;
        PARAM->_string.len--;
        str++;
      }
    }

    if (right)
    {
      while (PARAM->_string.len > 0 && str[PARAM->_string.len - 1] <= ' ')
      {
        PARAM->_string.len--;
      }
    }
  }
}




#define STRING_APPLY(_func) \
  char *str; \
  int len, i; \
  \
  SUBR_ENTER_PARAM(1); \
   \
  if (SUBR_check_string(PARAM)) \
    STRING_void_value(RETURN); \
  else \
  { \
    len = PARAM->_string.len; \
    if (len > 0) \
    { \
      STRING_new_temp(&str, &PARAM->_string.addr[PARAM->_string.start], PARAM->_string.len); \
      \
      for (i = 0; i < len; i++) \
        str[i] = _func(str[i]); \
        \
      RETURN->type = T_STRING; \
      RETURN->_string.addr = str; \
      RETURN->_string.start = 0; \
      RETURN->_string.len = len; \
    } \
  } \
  \
  SUBR_LEAVE();


PUBLIC void SUBR_upper(void)
{
  STRING_APPLY(toupper);
}

PUBLIC void SUBR_lower(void)
{
  STRING_APPLY(tolower);
}


PUBLIC void SUBR_chr(void)
{
  int car;

  SUBR_GET_PARAM(1);

  VALUE_conv(PARAM, T_INTEGER);
  /*SUBR_check_integer(PARAM);*/

  car = PARAM->_integer.value;
  if (car < 0 || car > 255)
    THROW(E_ARG);

  STRING_char_value(PARAM, car);
}



PUBLIC void SUBR_asc(void)
{
  int pos = 0;

  SUBR_ENTER();

  if (!SUBR_check_string(PARAM))
  {
    pos = 1;
    if (NPARAM == 2)
    {
      SUBR_check_integer(&PARAM[1]);
      pos = PARAM[1]._integer.value;
    }

    if (pos < 1 || pos > PARAM->_string.len)
      pos = 0;
    else
      pos = (unsigned char)PARAM->_string.addr[PARAM->_string.start + pos - 1];
  }

  RETURN->type = T_INTEGER;
  RETURN->_integer.value = pos;

  SUBR_LEAVE();
}


PRIVATE long instr(const char *ps, long ls, const char *pp, long lp, long is, boolean right)
{
  long pos = 0, ip;

  if (lp > ls)
    goto FOUND;

  ls = ls - lp + 1; /* Longueur du d�ut du texte o effectuer la recherche */

  if (is < 0)
    is = ls - is;
  else if (is == 0)
    is = right ? ls : 1;
  else if (is > ls)
    goto FOUND;

  is--;

  ps += is;

  if (right)
  {
    for (; is >= 0; is--, ps--)
    {
      for (ip = 0; ip < lp; ip++)
      {
        if (ps[ip] != pp[ip])
          goto NEXT_R;
      }

      pos = is + 1;
      goto FOUND;

  NEXT_R:
    ;
    }
  }
  else
  {
    for (; is < ls; is++, ps++)
    {
      for (ip = 0; ip < lp; ip++)
      {
        if (ps[ip] != pp[ip])
          goto NEXT_L;
      }

      pos = is + 1;
      goto FOUND;

  NEXT_L:
    ;
    }
  }

FOUND:

  return pos;
}


PUBLIC void SUBR_instr(void)
{
  boolean right;
  long is, pos;
  char *ps, *pp;
  long ls, lp;

  SUBR_ENTER();

  /* Knuth Morris Pratt un jour peut-�re ? */

  pos = 0;

  /* /!\ | et pas ||, car on veut que les deux fonctions soient ex�ut�s */

  if (SUBR_check_string(PARAM) | SUBR_check_string(&PARAM[1]))
    goto FOUND;

  lp = PARAM[1]._string.len;
  ls = PARAM->_string.len;

  right = ((EXEC_code >> 8) == CODE_RINSTR);

  if (lp > ls) goto FOUND;

  is = 0;

  if (NPARAM == 3)
  {
    SUBR_check_integer(&PARAM[2]);
    is = PARAM[2]._integer.value;
  }

  ps = PARAM->_string.addr + PARAM->_string.start;
  pp = PARAM[1]._string.addr + PARAM[1]._string.start;

  pos = instr(ps, ls, pp, lp, is, right);

FOUND:

  RETURN->type = T_INTEGER;
  RETURN->_integer.value = pos;

  SUBR_LEAVE();
}


PUBLIC void SUBR_like(void)
{
  char *pattern;
  char *string;
  long len_pattern, len_string;
  boolean ret;

  SUBR_ENTER_PARAM(2);

  SUBR_get_string_len(&PARAM[0], &string, &len_string);
  SUBR_get_string_len(&PARAM[1], &pattern, &len_pattern);

  ret = REGEXP_match(pattern, len_pattern, string, len_string) ? -1 : 0;

  RETURN->type = T_BOOLEAN;
  RETURN->_boolean.value = ret;

  SUBR_LEAVE();
}


PRIVATE int subst_nparam;
PRIVATE VALUE *subst_param;

PRIVATE void get_subst(int np, char **str, long *len)
{
  if (np > 0 && np < subst_nparam)
    VALUE_get_string(&subst_param[np], str, len);
  else
  {
    *str = NULL;
    *len = 0;
  }
}


PUBLIC void SUBR_subst(void)
{
  char *string;
  long len;
  int np;

  SUBR_ENTER();

  SUBR_get_string_len(&PARAM[0], &string, &len);

  for (np = 1; np < NPARAM; np++)
    VALUE_conv(&PARAM[np], T_STRING);

  subst_param = PARAM;
  subst_nparam = NPARAM;

  string = STRING_subst(string, len, get_subst);

  for (np = 0; np < NPARAM; np++)
    RELEASE_STRING(&PARAM[np]);

  RETURN->type = T_STRING;
  RETURN->_string.addr = (char *)string;
  RETURN->_string.start = 0;
  RETURN->_string.len = STRING_length(string);

  SUBR_LEAVE();
}



PUBLIC void SUBR_replace(void)
{
  char *ps;
  char *pp;
  char *pr;
  long ls, lp, lr;
  long is, pos;

  SUBR_ENTER_PARAM(3);

  SUBR_get_string_len(&PARAM[0], &ps, &ls);
  SUBR_get_string_len(&PARAM[1], &pp, &lp);
  SUBR_get_string_len(&PARAM[2], &pr, &lr);

  SUBST_init();

  if (ls)
  {
    is = 0;

    if (lp)
    {
      for(;;)
      {
        pos = instr(ps, ls, pp, lp, 1, FALSE);
        if (pos == 0)
          break;

        pos--;

        if (pos > 0)
          SUBST_add(ps, pos);

        SUBST_add(pr, lr);

        pos += lp;

        ps += pos;
        ls -= pos;

        if (ls <= 0)
          break;
      }
    }

    SUBST_add(ps, ls);
  }

  RETURN->type = T_STRING;
  RETURN->_string.addr = SUBST_buffer();
  RETURN->_string.start = 0;
  RETURN->_string.len = STRING_length(RETURN->_string.addr);

  SUBST_exit();

  SUBR_LEAVE();
}


PUBLIC void SUBR_split(void)
{
  CARRAY *array;
  char *str;
  char *sep = "";
  char *esc = "";

  SUBR_ENTER();

  str = SUBR_get_string(&PARAM[0]);
  if (NPARAM >= 2)
  {
    sep = SUBR_get_string(&PARAM[1]);
    if (NPARAM == 3)
      esc = SUBR_get_string(&PARAM[2]);
  }

  OBJECT_create((void **)&array, CLASS_StringArray, NULL, NULL, 0);

  if (*str)
  {
    STRING_ref(str);
    if (*sep) STRING_ref(sep);
    if (*esc) STRING_ref(esc);

    CARRAY_split(array, str, sep, esc);

    STRING_unref(&str);
    if (*sep) STRING_unref(&sep);
    if (*esc) STRING_unref(&esc);
  }

  RETURN->_object.class = CLASS_StringArray;
  RETURN->_object.object = array;

  SUBR_LEAVE();
}


PUBLIC void SUBR_sconv(void)
{
  char *str;
  const char *src;
  const char *dst;
  char *result;
  long len;

  SUBR_ENTER_PARAM(3);

  str = SUBR_get_string(&PARAM[0]);
  len = PARAM[0]._string.len;

  src = SUBR_get_string(&PARAM[1]);
  dst = SUBR_get_string(&PARAM[2]);

  STRING_conv(&result, str, len, src, dst);

  if (!result)
    RETURN->type = T_NULL;
  else
  {
    RETURN->type = T_STRING;
    RETURN->_string.addr = result;
    RETURN->_string.start = 0;
    RETURN->_string.len = STRING_length(result);
  }

  SUBR_LEAVE();
}

Generated by  Doxygen 1.6.0   Back to index