/* -*- mode: C; mode: fold; -*- */
/* string manipulation functions for S-Lang. */
/* Copyright (c) 1992, 1999, 2001 John E. Davis
* This file is part of the S-Lang library.
*
* You may distribute under the terms of either the GNU General Public
* License or the Perl Artistic License.
*/
#include "slinclud.h"
/*{{{ Include Files */
#include <time.h>
#ifndef __QNX__
# if defined(__GO32__) || defined(__WATCOMC__)
# include <dos.h>
# include <bios.h>
# endif
#endif
#if SLANG_HAS_FLOAT
#include <math.h>
#endif
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#ifndef isdigit
# define isdigit(x) (((x) >= '0') && ((x) <= '9'))
#endif
#include "slang.h"
#include "_slang.h"
/*}}}*/
#define USE_ALLOC_STSTRING 1
/*{{{ Utility Functions */
static char Utility_Char_Table [256];
static unsigned char WhiteSpace_Lut[256];
static void set_utility_char_table (char *pos) /*{{{*/
{
register char *t = Utility_Char_Table, *tmax;
register unsigned char ch;
tmax = t + 256;
while (t < tmax) *t++ = 0;
t = Utility_Char_Table;
while ((ch = (unsigned char) *pos++) != 0) t[ch] = 1;
}
/*}}}*/
_INLINE_
static unsigned char *make_whitespace_lut (void)
{
if (WhiteSpace_Lut[' '] != 1)
{
WhiteSpace_Lut[' '] = WhiteSpace_Lut['\r']
= WhiteSpace_Lut ['\n'] = WhiteSpace_Lut['\t']
= WhiteSpace_Lut ['\f'] = 1;
}
return WhiteSpace_Lut;
}
static unsigned char *make_lut (unsigned char *s, unsigned char *lut)
{
int reverse = 0;
if (*s == '^')
{
reverse = 1;
s++;
}
SLmake_lut (lut, s, reverse);
return lut;
}
static unsigned int do_trim (char **beg, int do_beg,
char **end, int do_end,
char *white) /*{{{*/
{
unsigned int len;
char *a, *b;
set_utility_char_table (white);
a = *beg;
len = strlen (a);
b = a + len;
if (do_beg)
while (Utility_Char_Table[(unsigned char) *a]) a++;
if (do_end)
{
b--;
while ((b >= a) && (Utility_Char_Table[(unsigned char) *b])) b--;
b++;
}
len = (unsigned int) (b - a);
*beg = a;
*end = b;
return len;
}
/*}}}*/
/*}}}*/
static int pop_3_strings (char **a, char **b, char **c)
{
*a = *b = *c = NULL;
if (-1 == SLpop_string (c))
return -1;
if (-1 == SLpop_string (b))
{
SLfree (*c);
*c = NULL;
return -1;
}
if (-1 == SLpop_string (a))
{
SLfree (*b);
SLfree (*c);
*b = *c = NULL;
return -1;
}
return 0;
}
static void free_3_strings (char *a, char *b, char *c)
{
SLfree (a);
SLfree (b);
SLfree (c);
}
static void strcat_cmd (void) /*{{{*/
{
char *c, *c1;
int nargs;
int i;
char **ptrs;
unsigned int len;
#if !USE_ALLOC_STSTRING
char buf[256];
#endif
nargs = SLang_Num_Function_Args;
if (nargs <= 0) nargs = 2;
if (NULL == (ptrs = (char **)SLmalloc (nargs * sizeof (char *))))
return;
memset ((char *) ptrs, 0, sizeof (char *) * nargs);
c = NULL;
i = nargs;
len = 0;
while (i != 0)
{
char *s;
i--;
if (-1 == SLang_pop_slstring (&s))
goto free_and_return;
ptrs[i] = s;
len += strlen (s);
}
#if USE_ALLOC_STSTRING
if (NULL == (c = _SLallocate_slstring (len)))
goto free_and_return;
#else
len++; /* \0 char */
if (len <= sizeof (buf))
c = buf;
else if (NULL == (c = SLmalloc (len)))
goto free_and_return;
#endif
c1 = c;
for (i = 0; i < nargs; i++)
{
strcpy (c1, ptrs[i]);
c1 += strlen (c1);
}
free_and_return:
for (i = 0; i < nargs; i++)
SLang_free_slstring (ptrs[i]);
SLfree ((char *) ptrs);
#if USE_ALLOC_STSTRING
(void) _SLpush_alloced_slstring (c, len);
#else
if (c != buf)
(void) SLang_push_malloced_string (c); /* NULL ok */
else
(void) SLang_push_string (c);
#endif
}
/*}}}*/
static int _SLang_push_nstring (char *a, unsigned int len)
{
a = SLang_create_nslstring (a, len);
if (a == NULL)
return -1;
return _SLang_push_slstring (a);
}
static void strtrim_cmd_internal (char *str, int do_beg, int do_end)
{
char *beg, *end, *white;
int free_str;
unsigned int len;
/* Go through SLpop_string to get a private copy since it will be
* modified.
*/
free_str = 0;
if (SLang_Num_Function_Args == 2)
{
white = str;
if (-1 == SLang_pop_slstring (&str))
return;
free_str = 1;
}
else white = " \t\f\r\n";
beg = str;
len = do_trim (&beg, do_beg, &end, do_end, white);
(void) _SLang_push_nstring (beg, len);
if (free_str)
SLang_free_slstring (str);
}
static void strtrim_cmd (char *str)
{
strtrim_cmd_internal (str, 1, 1);
}
static void strtrim_beg_cmd (char *str)
{
strtrim_cmd_internal (str, 1, 0);
}
static void strtrim_end_cmd (char *str)
{
strtrim_cmd_internal (str, 0, 1);
}
static void strcompress_cmd (void) /*{{{*/
{
char *str, *white, *c;
unsigned char *s, *beg, *end;
unsigned int len;
char pref_char;
if (SLpop_string (&white)) return;
if (SLpop_string (&str))
{
SLfree (white);
return;
}
/* The first character of white is the preferred whitespace character */
pref_char = *white;
beg = (unsigned char *) str;
(void) do_trim ((char **) &beg, 1, (char **) &end, 1, white);
SLfree (white);
/* Determine the effective length */
len = 0;
s = (unsigned char *) beg;
while (s < end)
{
len++;
if (Utility_Char_Table[*s++])
{
while ((s < end) && Utility_Char_Table[*s]) s++;
}
}
#if USE_ALLOC_STSTRING
c = _SLallocate_slstring (len);
#else
c = SLmalloc (len + 1);
#endif
if (c == NULL)
{
SLfree (str);
return;
}
s = (unsigned char *) c;
while (beg < end)
{
unsigned char ch = *beg++;
if (0 == Utility_Char_Table[ch])
{
*s++ = ch;
continue;
}
*s++ = (unsigned char) pref_char;
while ((beg < end) && Utility_Char_Table[*beg])
beg++;
}
*s = 0;
#if USE_ALLOC_STSTRING
(void) _SLpush_alloced_slstring (c, len);
#else
SLang_push_malloced_string(c);
#endif
SLfree(str);
}
/*}}}*/
static int str_replace_cmd_1 (char *orig, char *match, char *rep, unsigned int max_num_replaces,
char **new_strp) /*{{{*/
{
char *s, *t, *new_str;
unsigned int rep_len, match_len, new_len;
unsigned int num_replaces;
*new_strp = NULL;
match_len = strlen (match);
if (match_len == 0)
return 0;
num_replaces = 0;
s = orig;
while (num_replaces < max_num_replaces)
{
s = strstr (s, match);
if (s == NULL)
break;
s += match_len;
num_replaces++;
}
if (num_replaces == 0)
return 0;
max_num_replaces = num_replaces;
rep_len = strlen (rep);
new_len = (strlen (orig) - num_replaces * match_len) + num_replaces * rep_len;
new_str = SLmalloc (new_len + 1);
if (new_str == NULL)
return -1;
s = orig;
t = new_str;
for (num_replaces = 0; num_replaces < max_num_replaces; num_replaces++)
{
char *next_s;
unsigned int len;
|