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

gbx_string.c

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

  String.c

  The String management routines

  (c) 2000-2004 Benoît 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.

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

#define __STRING_C

#include "gb_common.h"
#include "gb_common_buffer.h"
#include "gb_error.h"
#include "gbx_value.h"
#include "gbx_debug.h"
#include "gbx_local.h"

#include <ctype.h>
#include <iconv.h>

#include "gbx_string.h"

#if DEBUG_STRING
#define DEBUG_ME
#endif

#define STRING_last_count 32
PRIVATE char *STRING_last[STRING_last_count] = { 0 };

PRIVATE char _char_string[512] = { 0 };
PRIVATE int _index = 0;

void STRING_new(char **ptr, const char *src, int len)
{
  STRING *str;

  if (len <= 0 && src != NULL)
    len = strlen(src);

  if (len <= 0)
  {
    *ptr = NULL;
    return;
  }

  ALLOC(&str, len + 1 + sizeof(STRING), "STRING_new");

  str->len = len;
  str->ref = 1;

  if (src != NULL)
    memcpy(str->data, src, len);

  str->data[len] = 0;

  *ptr = str->data;

  #ifdef DEBUG_ME
  TRACE_where();
  printf("STRING_new %p ( 0 ) \"%.*s\"\n", *ptr, len, src);
  fflush(NULL);
  #endif
}

PRIVATE void post_free(char *ptr)
{
  /*if (NLast >= MAX_LAST_STRING)
    THROW(E_STRING);*/

  #ifdef DEBUG_ME
  if (STRING_last[_index])
  {
    TRACE_where();
    printf("STRING: release temp: %p '%s'\n", STRING_last[_index], STRING_last[_index]);
    fflush(NULL);
  }
  #endif

  STRING_unref(&STRING_last[_index]);

  #ifdef DEBUG_ME
  printf("STRING: post temp: %p '%s'\n", ptr, ptr);
  fflush(NULL);
  #endif

  STRING_last[_index] = ptr;

  _index++;

  if (_index >= STRING_last_count)
    _index = 0;
}


PUBLIC long STRING_get_free_index(void)
{
  return _index;
}

void STRING_new_temp(char **ptr, const char *src, int len)
{
  STRING_new(ptr, src, len);
  if (*ptr)
    post_free(*ptr);
}


void STRING_exit(void)
{
  int i;

  for (i = 0; i < STRING_last_count; i++)
  {
    /*if (STRING_last[i])
      printf("release temp %p '%s'\n", STRING_last[i], STRING_last[i]);*/
    STRING_unref(&STRING_last[i]);
    STRING_last[i] = NULL;
  }

  _index = 0;
}


void STRING_extend(char **ptr, int new_len)
{
  STRING *str;
  long len = STRING_length(*ptr);

  if (new_len == len)
    return;

  if (new_len == 0)
  {
    STRING_free(ptr);
    return;
  }

  if (len == 0)
  {
    ALLOC(&str, new_len + 1 + sizeof(STRING), "STRING_extend");
    str->ref = 1;
  }
  else
  {
    str = STRING_from_ptr(*ptr);
    REALLOC(&str, new_len + 1 + sizeof(STRING), "STRING_extend");
  }

  str->len = new_len;

  *ptr = str->data;
}


void STRING_extend_end(char **ptr)
{
  if (*ptr)
  {
    (*ptr)[STRING_length(*ptr)] = 0;
    post_free(*ptr);
  }
}


void STRING_copy_from_value_temp(char **ptr, VALUE *value)
{
  if (value->_string.len == 0)
    *ptr = NULL;
  else if (value->type == T_STRING && value->_string.start == 0 && value->_string.len == STRING_length(value->_string.addr))
    *ptr = value->_string.addr;
  else
    STRING_new_temp(ptr, &value->_string.addr[value->_string.start], value->_string.len);
}


/* Attention ! Contrairement à STRING_new, STRING_new_temp_value crée des
   chaînes temporaires.
*/

void STRING_new_temp_value(VALUE *value, const char *src, int len)
{
  STRING_new_temp(&(value->_string.addr), src, len);

  value->_string.len = STRING_length(value->_string.addr);
  value->_string.start = 0;
  value->type = T_STRING;
}


void STRING_new_constant_value(VALUE *value, const char *src, int len)
{
  value->_string.addr = (char *)src;
  value->_string.len = ((len < 0) ? strlen(src) : len);
  value->_string.start = 0;
  value->type = T_CSTRING;
}


void STRING_void_value(VALUE *value)
{
  value->type = T_CSTRING;
  value->_string.addr = NULL;
  value->_string.start = 0;
  value->_string.len = 0;
}


void STRING_char_value(VALUE *value, uchar car)
{
  char *addr = &_char_string[(int)car * 2];

  value->type = T_CSTRING;
  value->_string.addr = addr;
  value->_string.start = 0;
  value->_string.len = 1;

  *addr = car;
}


void STRING_free(char **ptr)
{
  STRING *str;

  if (*ptr == NULL)
    return;

  str = STRING_from_ptr(*ptr);

  #ifdef DEBUG_ME
  TRACE_where();
  printf("STRING_free %p %p\n", *ptr, ptr);
  fflush(NULL);
  #endif

  str->ref = 1000000000L;

  FREE(&str, "STRING_free");
  *ptr = NULL;

  #ifdef DEBUG_ME
  printf("OK\n");
  #endif
}



int STRING_comp_value(VALUE *str1, VALUE *str2)
{
  long i;
  long len = Min(str1->_string.len, str2->_string.len);
  long diff = str1->_string.len - str2->_string.len;
  const char *s1;
  const char *s2;

  s1 = str1->_string.addr + str1->_string.start;
  s2 = str2->_string.addr + str2->_string.start;

  for (i = 0; i < len; i++)
  {
    if (*s1 > *s2) return 1;
    if (*s1 < *s2) return -1;
    s1++; s2++;
  }

  return (diff < 0) ? (-1) : (diff > 0) ? 1 : 0;
}


void STRING_ref(char *ptr)
{
  STRING *str;

  if (ptr == NULL)
    return;

  str = STRING_from_ptr(ptr);


  #ifdef DEBUG_ME
  TRACE_where();
  printf("STRING_ref %p ( %ld -> %ld )\n", ptr, str->ref, str->ref + 1);
  if (str->ref < 0 || str->ref > 10000)
    printf("*** BAD\n");
  fflush(NULL);
  #endif

  str->ref++;
}


void STRING_unref(char **ptr)
{
  STRING *str;

  if (*ptr == NULL)
    return;

  str = STRING_from_ptr(*ptr);

  #ifdef DEBUG_ME
  TRACE_where();
  printf("STRING_unref %p ( %ld -> %ld )\n", *ptr, str->ref, str->ref - 1);
  if (str->ref < 1 || str->ref > 10000)
    printf("*** BAD\n");
  fflush(NULL);
  #endif

  if ((--str->ref) <= 0)
    STRING_free(ptr);
}


void STRING_unref_keep(char **ptr)
{
  STRING *str;

  if (*ptr == NULL)
    return;

  str = STRING_from_ptr(*ptr);
  if (str->ref > 1)
    str->ref--;
  else
    post_free(*ptr);
}


PUBLIC char *STRING_subst(const char *string, long len, SUBST_FUNC get_param)
{
  const char *add;
  long len_add;
  unsigned char c;
  int np;
  char *par;
  long len_par;

  unsigned char next_char(void) { len--; return (unsigned char)*string++; }

  if (!string)
    return NULL;

  SUBST_init();

  if (len <= 0)
    len = strlen(string);

  if (len > 0)
  {
    add = string;
    len_add = 0;

    for(;;)
    {
      if (len == 0)
      {
        SUBST_add(add, len_add);
        break;
      }

      c = next_char();

      if (c != '&')
      {
        len_add++;
        continue;
      }

      SUBST_add(add, len_add);
      add = string;
      len_add = 0;

      c = next_char();

      if (!isdigit(c))
      {
        len_add += 2;
        continue;
      }
      
      np = (c - '0');

      c = *string;

      if (isdigit(c))
      {
        np = np * 10 + c - '0';
        next_char();
      }

      par = NULL;
      len_par = 0;

      (*get_param)(np, &par, &len_par);

      if (par)
        SUBST_add(par, len_par);
        
      add = string;
    }
  }

  /* Avant, les release de SUBR_subst s'effectuaient ici... */
  SUBST_exit();

  return SUBST_buffer();
}


PUBLIC void STRING_add(char **ptr, const char *src, int len)
{
  int old_len;

  if (len <= 0 && src != NULL)
    len = strlen(src);

  if (len <= 0)
    return;

  old_len = STRING_length(*ptr);

  STRING_extend(ptr, old_len + len);
  memcpy(&((*ptr)[old_len]), src, len);
  (*ptr)[old_len + len] = 0;
}


PUBLIC void STRING_conv(char **result, const char *str, long len, const char *src, const char *dst)
{
  iconv_t handle;
  bool err;
  const char *in;
  char *out;
  size_t in_len;
  size_t out_len;
  int ret;

  *result = NULL;

  in = str;
  in_len = len;

  if (len == 0)
    return;

  if (!dst || *dst == 0)
    dst = "ASCII";

  if (!src || *src == 0)
    src = "ASCII";

  handle = iconv_open(dst, src);
  if (handle == (iconv_t)(-1))
  {
    if (errno == EINVAL)
      THROW(E_UCONV);
    else
      THROW(E_CONV);
  }

  err = FALSE;

  for(;;)
  {
    out = COMMON_buffer;
    out_len = COMMON_BUF_MAX;

    #ifdef __sun__
    ret = iconv(handle, &in, &in_len, &out, &out_len);
    #else
    ret = iconv(handle, (char **)&in, &in_len, &out, &out_len);
    #endif

    if (ret != (size_t)(-1 ) || errno == E2BIG)
      STRING_add(result, COMMON_buffer, COMMON_BUF_MAX - out_len);

    if (ret != (size_t)(-1))
      break;

    if (errno != E2BIG)
    {
      err = TRUE;
      break;
    }
  }

  iconv_close(handle);

  STRING_extend_end(result);

  if (err)
    THROW(E_CONV);
}


PUBLIC char *STRING_conv_file_name(const char *name, long len)
{
  char *result = NULL;

  if (!name)
    return "";

  if (len <= 0)
    len = strlen(name);

  if (LOCAL_is_UTF8)
    STRING_new_temp(&result, name, len);
  else
    STRING_conv(&result, name, len, "UTF-8", LOCAL_encoding);

  if (result)
    return result;
  else
    return "";
}



Generated by  Doxygen 1.6.0   Back to index