xenocara/app/xedit/lisp/string.c
2006-11-25 20:07:29 +00:00

1388 lines
29 KiB
C

/*
* Copyright (c) 2001 by The XFree86 Project, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the XFree86 Project shall
* not be used in advertising or otherwise to promote the sale, use or other
* dealings in this Software without prior written authorization from the
* XFree86 Project.
*
* Author: Paulo César Pereira de Andrade
*/
/* $XdotOrg: app/xedit/lisp/string.c,v 1.3 2004/12/04 00:43:13 kuhn Exp $ */
/* $XFree86: xc/programs/xedit/lisp/string.c,v 1.24tsi Exp $ */
#include "lisp/helper.h"
#include "lisp/read.h"
#include "lisp/string.h"
#include "lisp/private.h"
#include <ctype.h>
#define CHAR_LESS 1
#define CHAR_LESS_EQUAL 2
#define CHAR_EQUAL 3
#define CHAR_GREATER_EQUAL 4
#define CHAR_GREATER 5
#define CHAR_NOT_EQUAL 6
#define CHAR_ALPHAP 1
#define CHAR_DOWNCASE 2
#define CHAR_UPCASE 3
#define CHAR_INT 4
#define CHAR_BOTHP 5
#define CHAR_UPPERP 6
#define CHAR_LOWERP 7
#define CHAR_GRAPHICP 8
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/*
* Prototypes
*/
static LispObj *LispCharCompare(LispBuiltin*, int, int);
static LispObj *LispStringCompare(LispBuiltin*, int, int);
static LispObj *LispCharOp(LispBuiltin*, int);
static LispObj *LispStringTrim(LispBuiltin*, int, int, int);
static LispObj *LispStringUpcase(LispBuiltin*, int);
static LispObj *LispStringDowncase(LispBuiltin*, int);
static LispObj *LispStringCapitalize(LispBuiltin*, int);
/*
* Implementation
*/
static LispObj *
LispCharCompare(LispBuiltin *builtin, int operation, int ignore_case)
{
LispObj *object;
int cmp, value, next_value;
LispObj *character, *more_characters;
more_characters = ARGUMENT(1);
character = ARGUMENT(0);
CHECK_SCHAR(character);
value = SCHAR_VALUE(character);
if (ignore_case && islower(value))
value = toupper(value);
if (!CONSP(more_characters))
return (T);
/* First check if all parameters are characters */
for (object = more_characters; CONSP(object); object = CDR(object))
CHECK_SCHAR(CAR(object));
/* All characters in list must be different */
if (operation == CHAR_NOT_EQUAL) {
/* Compare all characters */
do {
for (object = more_characters; CONSP(object); object = CDR(object)) {
character = CAR(object);
next_value = SCHAR_VALUE(character);
if (ignore_case && islower(next_value))
next_value = toupper(next_value);
if (value == next_value)
return (NIL);
}
value = SCHAR_VALUE(CAR(more_characters));
if (ignore_case && islower(value))
value = toupper(value);
more_characters = CDR(more_characters);
} while (CONSP(more_characters));
return (T);
}
/* Linearly compare characters */
for (; CONSP(more_characters); more_characters = CDR(more_characters)) {
character = CAR(more_characters);
next_value = SCHAR_VALUE(character);
if (ignore_case && islower(next_value))
next_value = toupper(next_value);
switch (operation) {
case CHAR_LESS: cmp = value < next_value; break;
case CHAR_LESS_EQUAL: cmp = value <= next_value; break;
case CHAR_EQUAL: cmp = value == next_value; break;
case CHAR_GREATER_EQUAL: cmp = value >= next_value; break;
case CHAR_GREATER: cmp = value > next_value; break;
default: cmp = 0; break;
}
if (!cmp)
return (NIL);
value = next_value;
}
return (T);
}
LispObj *
Lisp_CharLess(LispBuiltin *builtin)
/*
char< character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_LESS, 0));
}
LispObj *
Lisp_CharLessEqual(LispBuiltin *builtin)
/*
char<= character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_LESS_EQUAL, 0));
}
LispObj *
Lisp_CharEqual_(LispBuiltin *builtin)
/*
char= character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_EQUAL, 0));
}
LispObj *
Lisp_CharGreater(LispBuiltin *builtin)
/*
char> character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_GREATER, 0));
}
LispObj *
Lisp_CharGreaterEqual(LispBuiltin *builtin)
/*
char>= character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_GREATER_EQUAL, 0));
}
LispObj *
Lisp_CharNotEqual_(LispBuiltin *builtin)
/*
char/= character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_NOT_EQUAL, 0));
}
LispObj *
Lisp_CharLessp(LispBuiltin *builtin)
/*
char-lessp character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_LESS, 1));
}
LispObj *
Lisp_CharNotGreaterp(LispBuiltin *builtin)
/*
char-not-greaterp character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_LESS_EQUAL, 1));
}
LispObj *
Lisp_CharEqual(LispBuiltin *builtin)
/*
char-equalp character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_EQUAL, 1));
}
LispObj *
Lisp_CharGreaterp(LispBuiltin *builtin)
/*
char-greaterp character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_GREATER, 1));
}
LispObj *
Lisp_CharNotLessp(LispBuiltin *builtin)
/*
char-not-lessp &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_GREATER_EQUAL, 1));
}
LispObj *
Lisp_CharNotEqual(LispBuiltin *builtin)
/*
char-not-equal character &rest more-characters
*/
{
return (LispCharCompare(builtin, CHAR_NOT_EQUAL, 1));
}
static LispObj *
LispCharOp(LispBuiltin *builtin, int operation)
{
int value;
LispObj *result, *character;
character = ARGUMENT(0);
CHECK_SCHAR(character);
value = (int)SCHAR_VALUE(character);
switch (operation) {
case CHAR_ALPHAP:
result = isalpha(value) ? T : NIL;
break;
case CHAR_DOWNCASE:
result = SCHAR(tolower(value));
break;
case CHAR_UPCASE:
result = SCHAR(toupper(value));
break;
case CHAR_INT:
result = FIXNUM(value);
break;
case CHAR_BOTHP:
result = isupper(value) || islower(value) ? T : NIL;
break;
case CHAR_UPPERP:
result = isupper(value) ? T : NIL;
break;
case CHAR_LOWERP:
result = islower(value) ? T : NIL;
break;
case CHAR_GRAPHICP:
result = value == ' ' || isgraph(value) ? T : NIL;
break;
default:
result = NIL;
break;
}
return (result);
}
LispObj *
Lisp_AlphaCharP(LispBuiltin *builtin)
/*
alpha-char-p char
*/
{
return (LispCharOp(builtin, CHAR_ALPHAP));
}
LispObj *
Lisp_CharDowncase(LispBuiltin *builtin)
/*
char-downcase character
*/
{
return (LispCharOp(builtin, CHAR_DOWNCASE));
}
LispObj *
Lisp_CharInt(LispBuiltin *builtin)
/*
char-int character
char-code character
*/
{
return (LispCharOp(builtin, CHAR_INT));
}
LispObj *
Lisp_CharUpcase(LispBuiltin *builtin)
/*
char-upcase character
*/
{
return (LispCharOp(builtin, CHAR_UPCASE));
}
LispObj *
Lisp_BothCaseP(LispBuiltin *builtin)
/*
both-case-p character
*/
{
return (LispCharOp(builtin, CHAR_BOTHP));
}
LispObj *
Lisp_UpperCaseP(LispBuiltin *builtin)
/*
upper-case-p character
*/
{
return (LispCharOp(builtin, CHAR_UPPERP));
}
LispObj *
Lisp_LowerCaseP(LispBuiltin *builtin)
/*
upper-case-p character
*/
{
return (LispCharOp(builtin, CHAR_LOWERP));
}
LispObj *
Lisp_GraphicCharP(LispBuiltin *builtin)
/*
graphic-char-p char
*/
{
return (LispCharOp(builtin, CHAR_GRAPHICP));
}
LispObj *
Lisp_Char(LispBuiltin *builtin)
/*
char string index
schar simple-string index
*/
{
unsigned char *string;
long offset, length;
LispObj *ostring, *oindex;
oindex = ARGUMENT(1);
ostring = ARGUMENT(0);
CHECK_STRING(ostring);
CHECK_INDEX(oindex);
offset = FIXNUM_VALUE(oindex);
string = (unsigned char*)THESTR(ostring);
length = STRLEN(ostring);
if (offset >= length)
LispDestroy("%s: index %ld too large for string length %ld",
STRFUN(builtin), offset, length);
return (SCHAR(string[offset]));
}
/* helper function for setf
* DONT explicitly call. Non standard function
*/
LispObj *
Lisp_XeditCharStore(LispBuiltin *builtin)
/*
xedit::char-store string index value
*/
{
int character;
long offset, length;
LispObj *ostring, *oindex, *ovalue;
ovalue = ARGUMENT(2);
oindex = ARGUMENT(1);
ostring = ARGUMENT(0);
CHECK_STRING(ostring);
CHECK_INDEX(oindex);
length = STRLEN(ostring);
offset = FIXNUM_VALUE(oindex);
if (offset >= length)
LispDestroy("%s: index %ld too large for string length %ld",
STRFUN(builtin), offset, length);
CHECK_SCHAR(ovalue);
CHECK_STRING_WRITABLE(ostring);
character = SCHAR_VALUE(ovalue);
if (character < 0 || character > 255)
LispDestroy("%s: cannot represent character %d",
STRFUN(builtin), character);
THESTR(ostring)[offset] = character;
return (ovalue);
}
LispObj *
Lisp_Character(LispBuiltin *builtin)
/*
character object
*/
{
LispObj *object;
object = ARGUMENT(0);
return (LispCharacterCoerce(builtin, object));
}
LispObj *
Lisp_Characterp(LispBuiltin *builtin)
/*
characterp object
*/
{
LispObj *object;
object = ARGUMENT(0);
return (SCHARP(object) ? T : NIL);
}
LispObj *
Lisp_DigitChar(LispBuiltin *builtin)
/*
digit-char weight &optional radix
*/
{
long radix = 10, weight;
LispObj *oweight, *oradix, *result = NIL;
oradix = ARGUMENT(1);
oweight = ARGUMENT(0);
CHECK_FIXNUM(oweight);
weight = FIXNUM_VALUE(oweight);
if (oradix != UNSPEC) {
CHECK_INDEX(oradix);
radix = FIXNUM_VALUE(oradix);
}
if (radix < 2 || radix > 36)
LispDestroy("%s: radix must be >= 2 and <= 36, not %ld",
STRFUN(builtin), radix);
if (weight >= 0 && weight < radix) {
if (weight < 9)
weight += '0';
else
weight += 'A' - 10;
result = SCHAR(weight);
}
return (result);
}
LispObj *
Lisp_DigitCharP(LispBuiltin *builtin)
/*
digit-char-p character &optional radix
*/
{
long radix = 10, character;
LispObj *ochar, *oradix, *result = NIL;
oradix = ARGUMENT(1);
ochar = ARGUMENT(0);
CHECK_SCHAR(ochar);
character = SCHAR_VALUE(ochar);
if (oradix != UNSPEC) {
CHECK_INDEX(oradix);
radix = FIXNUM_VALUE(oradix);
}
if (radix < 2 || radix > 36)
LispDestroy("%s: radix must be >= 2 and <= 36, not %ld",
STRFUN(builtin), radix);
if (character >= '0' && character <= '9')
character -= '0';
else if (character >= 'A' && character <= 'Z')
character -= 'A' - 10;
else if (character >= 'a' && character <= 'z')
character -= 'a' - 10;
if (character < radix)
result = FIXNUM(character);
return (result);
}
LispObj *
Lisp_IntChar(LispBuiltin *builtin)
/*
int-char integer
code-char integer
*/
{
long character = 0;
LispObj *integer;
integer = ARGUMENT(0);
CHECK_FIXNUM(integer);
character = FIXNUM_VALUE(integer);
return (character >= 0 && character < 0xff ? SCHAR(character) : NIL);
}
/* XXX ignoring element-type */
LispObj *
Lisp_MakeString(LispBuiltin *builtin)
/*
make-string size &key initial-element element-type
*/
{
long length;
char *string, initial;
LispObj *size, *initial_element;
initial_element = ARGUMENT(1);
size = ARGUMENT(0);
CHECK_INDEX(size);
length = FIXNUM_VALUE(size);
if (initial_element != UNSPEC) {
CHECK_SCHAR(initial_element);
initial = SCHAR_VALUE(initial_element);
}
else
initial = 0;
string = LispMalloc(length + 1);
memset(string, initial, length);
string[length] = '\0';
return (LSTRING2(string, length));
}
LispObj *
Lisp_ParseInteger(LispBuiltin *builtin)
/*
parse-integer string &key start end radix junk-allowed
*/
{
GC_ENTER();
char *ptr, *string;
int character, junk, sign, overflow;
long i, start, end, radix, length, integer, check;
LispObj *result;
LispObj *ostring, *ostart, *oend, *oradix, *junk_allowed;
junk_allowed = ARGUMENT(4);
oradix = ARGUMENT(3);
oend = ARGUMENT(2);
ostart = ARGUMENT(1);
ostring = ARGUMENT(0);
start = end = radix = 0;
result = NIL;
CHECK_STRING(ostring);
LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
&start, &end, &length);
string = THESTR(ostring);
if (oradix == UNSPEC)
radix = 10;
else {
CHECK_INDEX(oradix);
radix = FIXNUM_VALUE(oradix);
}
if (radix < 2 || radix > 36)
LispDestroy("%s: :RADIX %ld must be in the range 2 to 36",
STRFUN(builtin), radix);
integer = check = 0;
ptr = string + start;
sign = overflow = 0;
/* Skip leading white spaces */
for (i = start; i < end && *ptr && isspace(*ptr); ptr++, i++)
;
/* Check for sign specification */
if (i < end && (*ptr == '-' || *ptr == '+')) {
sign = *ptr == '-';
++ptr;
++i;
}
for (junk = 0; i < end; i++, ptr++) {
character = *ptr;
if (islower(character))
character = toupper(character);
if (character >= '0' && character <= '9') {
if (character - '0' >= radix)
junk = 1;
else {
check = integer;
integer = integer * radix + character - '0';
}
}
else if (character >= 'A' && character <= 'Z') {
if (character - 'A' + 10 >= radix)
junk = 1;
else {
check = integer;
integer = integer * radix + character - 'A' + 10;
}
}
else {
if (isspace(character))
break;
junk = 1;
}
if (junk)
break;
if (!overflow && check > integer)
overflow = 1;
/* keep looping just to count read bytes */
}
if (!junk)
/* Skip white spaces */
for (; i < end && *ptr && isspace(*ptr); ptr++, i++)
;
if ((junk || ptr == string) &&
(junk_allowed == UNSPEC || junk_allowed == NIL))
LispDestroy("%s: %s has a bad integer representation",
STRFUN(builtin), STROBJ(ostring));
else if (ptr == string)
result = NIL;
else if (overflow) {
mpi *bigi = LispMalloc(sizeof(mpi));
char *str;
length = end - start + sign;
str = LispMalloc(length + 1);
strncpy(str, string - sign, length + sign);
str[length + sign] = '\0';
mpi_init(bigi);
mpi_setstr(bigi, str, radix);
LispFree(str);
result = BIGNUM(bigi);
}
else
result = INTEGER(sign ? -integer : integer);
GC_PROTECT(result);
RETURN(0) = FIXNUM(i);
RETURN_COUNT = 1;
GC_LEAVE();
return (result);
}
LispObj *
Lisp_String(LispBuiltin *builtin)
/*
string object
*/
{
LispObj *object;
object = ARGUMENT(0);
return (LispStringCoerce(builtin, object));
}
LispObj *
Lisp_Stringp(LispBuiltin *builtin)
/*
stringp object
*/
{
LispObj *object;
object = ARGUMENT(0);
return (STRINGP(object) ? T : NIL);
}
/* XXX preserve-whitespace is being ignored */
LispObj *
Lisp_ReadFromString(LispBuiltin *builtin)
/*
read-from-string string &optional eof-error-p eof-value &key start end preserve-whitespace
*/
{
GC_ENTER();
char *string;
LispObj *stream, *result;
long length, start, end, bytes_read;
LispObj *ostring, *eof_error_p, *eof_value, *ostart, *oend;
oend = ARGUMENT(4);
ostart = ARGUMENT(3);
eof_value = ARGUMENT(2);
eof_error_p = ARGUMENT(1);
ostring = ARGUMENT(0);
CHECK_STRING(ostring);
string = THESTR(ostring);
LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
&start, &end, &length);
if (start > 0 || end < length)
length = end - start;
stream = LSTRINGSTREAM(string + start, STREAM_READ, length);
if (eof_value == UNSPEC)
eof_value = NIL;
LispPushInput(stream);
result = LispRead();
/* stream->data.stream.source.string->input is
* the offset of the last byte read in string */
bytes_read = stream->data.stream.source.string->input;
LispPopInput(stream);
if (result == NULL) {
if (eof_error_p == NIL)
result = eof_value;
else
LispDestroy("%s: unexpected end of input", STRFUN(builtin));
}
GC_PROTECT(result);
RETURN(0) = FIXNUM(start + bytes_read);
RETURN_COUNT = 1;
GC_LEAVE();
return (result);
}
static LispObj *
LispStringTrim(LispBuiltin *builtin, int left, int right, int inplace)
/*
string-{,left-,right-}trim character-bag string
*/
{
unsigned char *string;
long start, end, length;
LispObj *ochars, *ostring;
ostring = ARGUMENT(1);
ochars = ARGUMENT(0);
if (!POINTERP(ochars) || !(XSTRINGP(ochars) || XCONSP(ochars))) {
if (ARRAYP(ochars) && ochars->data.array.rank == 1)
ochars = ochars->data.array.list;
else
LispDestroy("%s: %s is not a sequence",
STRFUN(builtin), STROBJ(ochars));
}
CHECK_STRING(ostring);
string = (unsigned char*)THESTR(ostring);
length = STRLEN(ostring);
start = 0;
end = length;
if (XSTRINGP(ochars)) {
unsigned char *chars = (unsigned char*)THESTR(ochars);
long i, clength = STRLEN(ochars);
if (left) {
for (; start < end; start++) {
for (i = 0; i < clength; i++)
if (string[start] == chars[i])
break;
if (i >= clength)
break;
}
}
if (right) {
for (--end; end >= 0; end--) {
for (i = 0; i < clength; i++)
if (string[end] == chars[i])
break;
if (i >= clength)
break;
}
++end;
}
}
else {
LispObj *ochar, *list;
if (left) {
for (; start < end; start++) {
for (list = ochars; CONSP(list); list = CDR(list)) {
ochar = CAR(list);
if (SCHARP(ochar) && string[start] == SCHAR_VALUE(ochar))
break;
}
if (!CONSP(list))
break;
}
}
if (right) {
for (--end; end >= 0; end--) {
for (list = ochars; CONSP(list); list = CDR(list)) {
ochar = CAR(list);
if (SCHARP(ochar) && string[end] == SCHAR_VALUE(ochar))
break;
}
if (!CONSP(list))
break;
}
++end;
}
}
if (start == 0 && end == length)
return (ostring);
length = end - start;
if (inplace) {
CHECK_STRING_WRITABLE(ostring);
memmove(string, string + start, length);
string[length] = '\0';
STRLEN(ostring) = length;
}
else {
string = LispMalloc(length + 1);
memcpy(string, THESTR(ostring) + start, length);
string[length] = '\0';
ostring = LSTRING2((char*)string, length);
}
return (ostring);
}
LispObj *
Lisp_StringTrim(LispBuiltin *builtin)
/*
string-trim character-bag string
*/
{
return (LispStringTrim(builtin, 1, 1, 0));
}
LispObj *
Lisp_NstringTrim(LispBuiltin *builtin)
/*
ext::nstring-trim character-bag string
*/
{
return (LispStringTrim(builtin, 1, 1, 1));
}
LispObj *
Lisp_StringLeftTrim(LispBuiltin *builtin)
/*
string-left-trim character-bag string
*/
{
return (LispStringTrim(builtin, 1, 0, 0));
}
LispObj *
Lisp_NstringLeftTrim(LispBuiltin *builtin)
/*
ext::nstring-left-trim character-bag string
*/
{
return (LispStringTrim(builtin, 1, 0, 1));
}
LispObj *
Lisp_StringRightTrim(LispBuiltin *builtin)
/*
string-right-trim character-bag string
*/
{
return (LispStringTrim(builtin, 0, 1, 0));
}
LispObj *
Lisp_NstringRightTrim(LispBuiltin *builtin)
/*
ext::nstring-right-trim character-bag string
*/
{
return (LispStringTrim(builtin, 0, 1, 1));
}
static LispObj *
LispStringCompare(LispBuiltin *builtin, int function, int ignore_case)
{
int cmp1, cmp2;
LispObj *fixnum;
unsigned char *string1, *string2;
long start1, end1, start2, end2, offset, length;
LispGetStringArgs(builtin, (char**)&string1, (char**)&string2,
&start1, &end1, &start2, &end2);
string1 += start1;
string2 += start2;
if (function == CHAR_EQUAL) {
length = end1 - start1;
if (length != (end2 - start2))
return (NIL);
if (!ignore_case)
return (memcmp(string1, string2, length) ? NIL : T);
for (; length; length--, string1++, string2++)
if (toupper(*string1) != toupper(*string2))
return (NIL);
return (T);
}
end1 -= start1;
end2 -= start2;
length = MIN(end1, end2);
for (offset = 0;
offset < length;
string1++, string2++, offset++, start1++, start2++) {
cmp1 = *string1;
cmp2 = *string2;
if (ignore_case) {
cmp1 = toupper(cmp1);
cmp2 = toupper(cmp2);
}
if (cmp1 != cmp2) {
fixnum = FIXNUM(start1);
switch (function) {
case CHAR_LESS:
return ((cmp1 < cmp2) ? fixnum : NIL);
case CHAR_LESS_EQUAL:
return ((cmp1 <= cmp2) ? fixnum : NIL);
case CHAR_NOT_EQUAL:
return (fixnum);
case CHAR_GREATER_EQUAL:
return ((cmp1 >= cmp2) ? fixnum : NIL);
case CHAR_GREATER:
return ((cmp1 > cmp2) ? fixnum : NIL);
}
}
}
fixnum = FIXNUM(start1);
switch (function) {
case CHAR_LESS:
return (start1 >= end1 && start2 < end2 ? fixnum : NIL);
case CHAR_LESS_EQUAL:
return (start1 >= end1 ? fixnum : NIL);
case CHAR_NOT_EQUAL:
return (start1 >= end1 && start2 >= end2 ? NIL : fixnum);
case CHAR_GREATER_EQUAL:
return (start2 >= end2 ? fixnum : NIL);
case CHAR_GREATER:
return (start2 >= end2 && start1 < end1 ? fixnum : NIL);
}
return (NIL);
}
LispObj *
Lisp_StringEqual_(LispBuiltin *builtin)
/*
string= string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_EQUAL, 0));
}
LispObj *
Lisp_StringLess(LispBuiltin *builtin)
/*
string< string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_LESS, 0));
}
LispObj *
Lisp_StringGreater(LispBuiltin *builtin)
/*
string> string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_GREATER, 0));
}
LispObj *
Lisp_StringLessEqual(LispBuiltin *builtin)
/*
string<= string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_LESS_EQUAL, 0));
}
LispObj *
Lisp_StringGreaterEqual(LispBuiltin *builtin)
/*
string>= string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_GREATER_EQUAL, 0));
}
LispObj *
Lisp_StringNotEqual_(LispBuiltin *builtin)
/*
string/= string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_NOT_EQUAL, 0));
}
LispObj *
Lisp_StringEqual(LispBuiltin *builtin)
/*
string-equal string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_EQUAL, 1));
}
LispObj *
Lisp_StringLessp(LispBuiltin *builtin)
/*
string-lessp string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_LESS, 1));
}
LispObj *
Lisp_StringGreaterp(LispBuiltin *builtin)
/*
string-greaterp string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_GREATER, 1));
}
LispObj *
Lisp_StringNotGreaterp(LispBuiltin *builtin)
/*
string-not-greaterp string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_LESS_EQUAL, 1));
}
LispObj *
Lisp_StringNotLessp(LispBuiltin *builtin)
/*
string-not-lessp string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_GREATER_EQUAL, 1));
}
LispObj *
Lisp_StringNotEqual(LispBuiltin *builtin)
/*
string-not-equal string1 string2 &key start1 end1 start2 end2
*/
{
return (LispStringCompare(builtin, CHAR_NOT_EQUAL, 1));
}
LispObj *
LispStringUpcase(LispBuiltin *builtin, int inplace)
/*
string-upcase string &key start end
nstring-upcase string &key start end
*/
{
LispObj *result;
char *string, *newstring;
long start, end, length, offset;
LispObj *ostring, *ostart, *oend;
oend = ARGUMENT(2);
ostart = ARGUMENT(1);
ostring = ARGUMENT(0);
CHECK_STRING(ostring);
LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
&start, &end, &offset);
result = ostring;
string = THESTR(ostring);
length = STRLEN(ostring);
/* first check if something need to be done */
for (offset = start; offset < end; offset++)
if (string[offset] != toupper(string[offset]))
break;
if (offset >= end)
return (result);
if (inplace) {
CHECK_STRING_WRITABLE(ostring);
newstring = string;
}
else {
/* upcase a copy of argument */
newstring = LispMalloc(length + 1);
if (offset)
memcpy(newstring, string, offset);
if (length > end)
memcpy(newstring + end, string + end, length - end);
newstring[length] = '\0';
}
for (; offset < end; offset++)
newstring[offset] = toupper(string[offset]);
if (!inplace)
result = LSTRING2(newstring, length);
return (result);
}
LispObj *
Lisp_StringUpcase(LispBuiltin *builtin)
/*
string-upcase string &key start end
*/
{
return (LispStringUpcase(builtin, 0));
}
LispObj *
Lisp_NstringUpcase(LispBuiltin *builtin)
/*
nstring-upcase string &key start end
*/
{
return (LispStringUpcase(builtin, 1));
}
LispObj *
LispStringDowncase(LispBuiltin *builtin, int inplace)
/*
string-downcase string &key start end
nstring-downcase string &key start end
*/
{
LispObj *result;
char *string, *newstring;
long start, end, length, offset;
LispObj *ostring, *ostart, *oend;
oend = ARGUMENT(2);
ostart = ARGUMENT(1);
ostring = ARGUMENT(0);
CHECK_STRING(ostring);
LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
&start, &end, &offset);
result = ostring;
string = THESTR(ostring);
length = STRLEN(ostring);
/* first check if something need to be done */
for (offset = start; offset < end; offset++)
if (string[offset] != tolower(string[offset]))
break;
if (offset >= end)
return (result);
if (inplace) {
CHECK_STRING_WRITABLE(ostring);
newstring = string;
}
else {
/* downcase a copy of argument */
newstring = LispMalloc(length + 1);
if (offset)
memcpy(newstring, string, offset);
if (length > end)
memcpy(newstring + end, string + end, length - end);
newstring[length] = '\0';
}
for (; offset < end; offset++)
newstring[offset] = tolower(string[offset]);
if (!inplace)
result = LSTRING2(newstring, length);
return (result);
}
LispObj *
Lisp_StringDowncase(LispBuiltin *builtin)
/*
string-downcase string &key start end
*/
{
return (LispStringDowncase(builtin, 0));
}
LispObj *
Lisp_NstringDowncase(LispBuiltin *builtin)
/*
nstring-downcase string &key start end
*/
{
return (LispStringDowncase(builtin, 1));
}
LispObj *
LispStringCapitalize(LispBuiltin *builtin, int inplace)
/*
string-capitalize string &key start end
nstring-capitalize string &key start end
*/
{
LispObj *result;
char *string, *newstring;
long start, end, length, offset, upcase;
LispObj *ostring, *ostart, *oend;
oend = ARGUMENT(2);
ostart = ARGUMENT(1);
ostring = ARGUMENT(0);
CHECK_STRING(ostring);
LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
&start, &end, &offset);
result = ostring;
string = THESTR(ostring);
length = STRLEN(ostring);
/* first check if something need to be done */
for (upcase = 1, offset = start; offset < end; offset++) {
if (upcase) {
if (!isalnum(string[offset]))
continue;
if (string[offset] != toupper(string[offset]))
break;
upcase = 0;
}
else {
if (isalnum(string[offset])) {
if (string[offset] != tolower(string[offset]))
break;
}
else
upcase = 1;
}
}
if (offset >= end)
return (result);
if (inplace) {
CHECK_STRING_WRITABLE(ostring);
newstring = string;
}
else {
/* capitalize a copy of argument */
newstring = LispMalloc(length + 1);
memcpy(newstring, string, length);
newstring[length] = '\0';
}
for (; offset < end; offset++) {
if (upcase) {
if (!isalnum(string[offset]))
continue;
newstring[offset] = toupper(string[offset]);
upcase = 0;
}
else {
if (isalnum(newstring[offset]))
newstring[offset] = tolower(string[offset]);
else
upcase = 1;
}
}
if (!inplace)
result = LSTRING2(newstring, length);
return (result);
}
LispObj *
Lisp_StringCapitalize(LispBuiltin *builtin)
/*
string-capitalize string &key start end
*/
{
return (LispStringCapitalize(builtin, 0));
}
LispObj *
Lisp_NstringCapitalize(LispBuiltin *builtin)
/*
nstring-capitalize string &key start end
*/
{
return (LispStringCapitalize(builtin, 1));
}
LispObj *
Lisp_StringConcat(LispBuiltin *builtin)
/*
string-concat &rest strings
*/
{
char *buffer;
long size, length;
LispObj *object, *string;
LispObj *strings;
strings = ARGUMENT(0);
if (strings == NIL)
return (STRING(""));
for (length = 1, object = strings; CONSP(object); object = CDR(object)) {
string = CAR(object);
CHECK_STRING(string);
length += STRLEN(string);
}
buffer = LispMalloc(length);
for (length = 0, object = strings; CONSP(object); object = CDR(object)) {
string = CAR(object);
size = STRLEN(string);
memcpy(buffer + length, THESTR(string), size);
length += size;
}
buffer[length] = '\0';
object = LSTRING2(buffer, length);
return (object);
}