337 lines
8.8 KiB
C
337 lines
8.8 KiB
C
/* string.c
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright 1990, 1991, 1992, 1993, 1994, 1995, Oliver Laumann, Berlin
|
|
* Copyright 2002, 2003 Sam Hocevar <sam@zoy.org>, Paris
|
|
*
|
|
* This software was derived from Elk 1.2, which was Copyright 1987, 1988,
|
|
* 1989, Nixdorf Computer AG and TELES GmbH, Berlin (Elk 1.2 has been written
|
|
* by Oliver Laumann for TELES Telematic Services, Berlin, in a joint project
|
|
* between TELES and Nixdorf Microprocessor Engineering, Berlin).
|
|
*
|
|
* Oliver Laumann, TELES GmbH, Nixdorf Computer AG and Sam Hocevar, as co-
|
|
* owners or individual owners of copyright in this software, grant to any
|
|
* person or company a worldwide, royalty free, license to
|
|
*
|
|
* i) copy this software,
|
|
* ii) prepare derivative works based on this software,
|
|
* iii) distribute copies of this software or derivative works,
|
|
* iv) perform this software, or
|
|
* v) display this software,
|
|
*
|
|
* provided that this notice is not removed and that neither Oliver Laumann
|
|
* nor Teles nor Nixdorf are deemed to have made any representations as to
|
|
* the suitability of this software for any purpose nor are held responsible
|
|
* for any defects of this software.
|
|
*
|
|
* THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "kernel.h"
|
|
|
|
extern int Get_Index (Object, Object);
|
|
|
|
char Char_Map[256];
|
|
|
|
void Init_String () {
|
|
register int i;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
Char_Map[i] = i;
|
|
for (i = 'A'; i <= 'Z'; i++)
|
|
Char_Map[i] = tolower (i);
|
|
}
|
|
|
|
Object General_Make_String (char const *s, int len, int konst) {
|
|
Object str;
|
|
|
|
str = Alloc_Object (len + sizeof (struct S_String) - 1, T_String, konst);
|
|
STRING(str)->tag = Null;
|
|
STRING(str)->size = len;
|
|
if (s)
|
|
memcpy (STRING(str)->data, s, len);
|
|
return str;
|
|
}
|
|
|
|
Object Make_String (char const *s, int len) {
|
|
return General_Make_String (s, len, 0);
|
|
}
|
|
|
|
Object Make_Const_String (char const *s, int len) {
|
|
return General_Make_String (s, len, 1);
|
|
}
|
|
|
|
Object P_Stringp (Object s) {
|
|
return TYPE(s) == T_String ? True : False;
|
|
}
|
|
|
|
Object P_Make_String (int argc, Object *argv) {
|
|
register int len, c = ' ';
|
|
Object str;
|
|
register char *p;
|
|
|
|
if ((len = Get_Exact_Integer (argv[0])) < 0)
|
|
Range_Error (argv[0]);
|
|
if (argc == 2) {
|
|
Check_Type (argv[1], T_Character);
|
|
c = CHAR(argv[1]);
|
|
}
|
|
str = Make_String ((char *)0, len);
|
|
for (p = STRING(str)->data; len; len--) *p++ = c;
|
|
return str;
|
|
}
|
|
|
|
Object P_String (int argc, Object *argv) {
|
|
Object str;
|
|
register int i;
|
|
|
|
str = Make_String ((char *)0, argc);
|
|
for (i = 0; i < argc; i++) {
|
|
Check_Type (argv[i], T_Character);
|
|
STRING(str)->data[i] = CHAR(argv[i]);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
Object P_String_To_Number (int argc, Object *argv) {
|
|
Object ret;
|
|
char *b;
|
|
register struct S_String *p;
|
|
int radix = 10;
|
|
Alloca_Begin;
|
|
|
|
Check_Type (argv[0], T_String);
|
|
if (argc == 2) {
|
|
radix = Get_Exact_Integer (argv[1]);
|
|
switch (radix) {
|
|
case 2: case 8: case 10: case 16:
|
|
break;
|
|
default:
|
|
Primitive_Error ("invalid radix: ~s", argv[1]);
|
|
}
|
|
}
|
|
p = STRING(argv[0]);
|
|
Alloca (b, char*, p->size+1);
|
|
memcpy (b, p->data, p->size);
|
|
b[p->size] = '\0';
|
|
ret = Parse_Number (Null, b, radix);
|
|
Alloca_End;
|
|
return Nullp (ret) ? False : ret;
|
|
}
|
|
|
|
Object P_String_Length (Object s) {
|
|
Check_Type (s, T_String);
|
|
return Make_Integer (STRING(s)->size);
|
|
}
|
|
|
|
Object P_String_Ref (Object s, Object n) {
|
|
Check_Type (s, T_String);
|
|
return Make_Char (STRING(s)->data[Get_Index (n, s)]);
|
|
}
|
|
|
|
Object P_String_Set (Object s, Object n, Object new) {
|
|
register int i, old;
|
|
|
|
Check_Type (s, T_String);
|
|
Check_Mutable (s);
|
|
Check_Type (new, T_Character);
|
|
old = STRING(s)->data[i = Get_Index (n, s)];
|
|
STRING(s)->data[i] = CHAR(new);
|
|
return Make_Char (old);
|
|
}
|
|
|
|
Object P_Substring (Object s, Object a, Object b) {
|
|
register int i, j;
|
|
|
|
Check_Type (s, T_String);
|
|
if ((i = Get_Exact_Integer (a)) < 0 || i > STRING(s)->size)
|
|
Range_Error (a);
|
|
if ((j = Get_Exact_Integer (b)) < 0 || j > STRING(s)->size)
|
|
Range_Error (b);
|
|
if (i > j)
|
|
Primitive_Error ("`end' less than `start'");
|
|
return Make_String (&STRING(s)->data[i], j-i);
|
|
}
|
|
|
|
Object P_String_Copy (Object s) {
|
|
Check_Type (s, T_String);
|
|
return Make_String (STRING(s)->data, STRING(s)->size);
|
|
}
|
|
|
|
Object P_String_Append (int argc, Object *argv) {
|
|
register int i, len;
|
|
Object s, str;
|
|
|
|
for (len = i = 0; i < argc; i++) {
|
|
Check_Type (argv[i], T_String);
|
|
len += STRING(argv[i])->size;
|
|
}
|
|
str = Make_String ((char *)0, len);
|
|
for (len = i = 0; i < argc; i++) {
|
|
s = argv[i];
|
|
memcpy (&STRING(str)->data[len], STRING(s)->data, STRING(s)->size);
|
|
len += STRING(s)->size;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
Object P_List_To_String (Object list) {
|
|
Object str, len;
|
|
register int i;
|
|
GC_Node;
|
|
|
|
GC_Link (list);
|
|
len = P_Length (list);
|
|
str = Make_String ((char *)0, FIXNUM(len));
|
|
for (i = 0; i < FIXNUM(len); i++, list = Cdr (list)) {
|
|
Check_Type (Car (list), T_Character);
|
|
STRING(str)->data[i] = CHAR(Car (list));
|
|
}
|
|
GC_Unlink;
|
|
return str;
|
|
}
|
|
|
|
Object P_String_To_List (Object s) {
|
|
register int i;
|
|
Object list, tail, cell;
|
|
GC_Node3;
|
|
|
|
Check_Type (s, T_String);
|
|
list = tail = Null;
|
|
GC_Link3 (s, list, tail);
|
|
for (i = 0; i < STRING(s)->size; i++, tail = cell) {
|
|
cell = Cons (Make_Char (STRING(s)->data[i]), Null);
|
|
if (Nullp (list))
|
|
list = cell;
|
|
else
|
|
(void)P_Set_Cdr (tail, cell);
|
|
}
|
|
GC_Unlink;
|
|
return list;
|
|
}
|
|
|
|
Object P_Substring_Fill (Object s, Object a, Object b, Object c) {
|
|
register int i, j;
|
|
|
|
Check_Type (s, T_String);
|
|
Check_Mutable (s);
|
|
Check_Type (c, T_Character);
|
|
i = Get_Index (a, s);
|
|
if ((j = Get_Exact_Integer (b)) < 0 || j > STRING(s)->size)
|
|
Range_Error (b);
|
|
if (i > j)
|
|
Primitive_Error ("`end' less than `start'");
|
|
while (i < j)
|
|
STRING(s)->data[i++] = CHAR(c);
|
|
return s;
|
|
}
|
|
|
|
Object P_String_Fill (Object s, Object c) {
|
|
Object ret;
|
|
GC_Node2;
|
|
|
|
Check_Type (s, T_String);
|
|
Check_Mutable (s);
|
|
GC_Link2 (s, c);
|
|
ret = P_Substring_Fill (s, Make_Integer (0),
|
|
Make_Integer (STRING(s)->size), c);
|
|
GC_Unlink;
|
|
return ret;
|
|
}
|
|
|
|
Object General_Substringp (Object s1, Object s2, register int ci) {
|
|
register int n, l1, l2;
|
|
register char *p1, *p2, *p3, *map;
|
|
|
|
Check_Type (s1, T_String);
|
|
Check_Type (s2, T_String);
|
|
l1 = STRING(s1)->size;
|
|
l2 = STRING(s2)->size;
|
|
map = Char_Map;
|
|
for (p2 = STRING(s2)->data; l2 >= l1; p2++, l2--) {
|
|
for (p1 = STRING(s1)->data, p3 = p2, n = l1; n; n--, p1++, p3++) {
|
|
if (ci) {
|
|
if (map[(int)*p1] != map[(int)*p3]) goto fail;
|
|
} else
|
|
if (*p1 != *p3) goto fail;
|
|
}
|
|
return Make_Integer (STRING(s2)->size - l2);
|
|
fail: ;
|
|
}
|
|
return False;
|
|
}
|
|
|
|
Object P_Substringp (Object s1, Object s2) {
|
|
return General_Substringp (s1, s2, 0);
|
|
}
|
|
|
|
Object P_CI_Substringp (Object s1, Object s2) {
|
|
return General_Substringp (s1, s2, 1);
|
|
}
|
|
|
|
int General_Strcmp (Object s1, Object s2, register int ci) {
|
|
register int n, l1, l2;
|
|
register char *p1, *p2, *map;
|
|
|
|
Check_Type (s1, T_String);
|
|
Check_Type (s2, T_String);
|
|
l1 = STRING(s1)->size; l2 = STRING(s2)->size;
|
|
n = l1 > l2 ? l2 : l1;
|
|
p1 = STRING(s1)->data; p2 = STRING(s2)->data;
|
|
for (map = Char_Map; --n >= 0; p1++, p2++) {
|
|
if (ci) {
|
|
if (map[(int)*p1] != map[(int)*p2]) break;
|
|
} else
|
|
if (*p1 != *p2) break;
|
|
}
|
|
if (n < 0)
|
|
return l1 - l2;
|
|
return ci ? map[(int)*p1] - map[(int)*p2] : *p1 - *p2;
|
|
}
|
|
|
|
Object P_String_Eq (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 0) ? False : True;
|
|
}
|
|
|
|
Object P_String_Less (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 0) < 0 ? True : False;
|
|
}
|
|
|
|
Object P_String_Greater (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 0) > 0 ? True : False;
|
|
}
|
|
|
|
Object P_String_Eq_Less (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 0) <= 0 ? True : False;
|
|
}
|
|
|
|
Object P_String_Eq_Greater (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 0) >= 0 ? True : False;
|
|
}
|
|
|
|
Object P_String_CI_Eq (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 1) ? False : True;
|
|
}
|
|
|
|
Object P_String_CI_Less (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 1) < 0 ? True : False;
|
|
}
|
|
|
|
Object P_String_CI_Greater (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 1) > 0 ? True : False;
|
|
}
|
|
|
|
Object P_String_CI_Eq_Less (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 1) <= 0 ? True : False;
|
|
}
|
|
|
|
Object P_String_CI_Eq_Greater (Object s1, Object s2) {
|
|
return General_Strcmp (s1, s2, 1) >= 0 ? True : False;
|
|
}
|