string.c revision f14f4646
15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2001 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
30f14f4646Smrg/* $XdotOrg: xc/programs/xedit/lisp/string.c,v 1.2 2004/04/23 19:54:44 eich Exp $ */
315dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/string.c,v 1.24tsi Exp $ */
325dfecf96Smrg
335dfecf96Smrg#include "lisp/helper.h"
345dfecf96Smrg#include "lisp/read.h"
355dfecf96Smrg#include "lisp/string.h"
365dfecf96Smrg#include "lisp/private.h"
375dfecf96Smrg#include <ctype.h>
385dfecf96Smrg
395dfecf96Smrg#define CHAR_LESS		1
405dfecf96Smrg#define CHAR_LESS_EQUAL		2
415dfecf96Smrg#define CHAR_EQUAL		3
425dfecf96Smrg#define CHAR_GREATER_EQUAL	4
435dfecf96Smrg#define CHAR_GREATER		5
445dfecf96Smrg#define CHAR_NOT_EQUAL		6
455dfecf96Smrg
465dfecf96Smrg#define CHAR_ALPHAP		1
475dfecf96Smrg#define CHAR_DOWNCASE		2
485dfecf96Smrg#define CHAR_UPCASE		3
495dfecf96Smrg#define CHAR_INT		4
505dfecf96Smrg#define CHAR_BOTHP		5
515dfecf96Smrg#define CHAR_UPPERP		6
525dfecf96Smrg#define CHAR_LOWERP		7
535dfecf96Smrg#define CHAR_GRAPHICP		8
545dfecf96Smrg
555dfecf96Smrg#ifndef MIN
565dfecf96Smrg#define MIN(a, b)		((a) < (b) ? (a) : (b))
575dfecf96Smrg#endif
585dfecf96Smrg
595dfecf96Smrg/*
605dfecf96Smrg * Prototypes
615dfecf96Smrg */
625dfecf96Smrgstatic LispObj *LispCharCompare(LispBuiltin*, int, int);
635dfecf96Smrgstatic LispObj *LispStringCompare(LispBuiltin*, int, int);
645dfecf96Smrgstatic LispObj *LispCharOp(LispBuiltin*, int);
655dfecf96Smrgstatic LispObj *LispStringTrim(LispBuiltin*, int, int, int);
665dfecf96Smrgstatic LispObj *LispStringUpcase(LispBuiltin*, int);
675dfecf96Smrgstatic LispObj *LispStringDowncase(LispBuiltin*, int);
685dfecf96Smrgstatic LispObj *LispStringCapitalize(LispBuiltin*, int);
695dfecf96Smrg
705dfecf96Smrg/*
715dfecf96Smrg * Implementation
725dfecf96Smrg */
735dfecf96Smrgstatic LispObj *
745dfecf96SmrgLispCharCompare(LispBuiltin *builtin, int operation, int ignore_case)
755dfecf96Smrg{
765dfecf96Smrg    LispObj *object;
775dfecf96Smrg    int cmp, value, next_value;
785dfecf96Smrg
795dfecf96Smrg    LispObj *character, *more_characters;
805dfecf96Smrg
815dfecf96Smrg    more_characters = ARGUMENT(1);
825dfecf96Smrg    character = ARGUMENT(0);
835dfecf96Smrg
845dfecf96Smrg    CHECK_SCHAR(character);
855dfecf96Smrg    value = SCHAR_VALUE(character);
865dfecf96Smrg    if (ignore_case && islower(value))
875dfecf96Smrg	value = toupper(value);
885dfecf96Smrg
895dfecf96Smrg    if (!CONSP(more_characters))
905dfecf96Smrg	return (T);
915dfecf96Smrg
925dfecf96Smrg    /* First check if all parameters are characters */
935dfecf96Smrg    for (object = more_characters; CONSP(object); object = CDR(object))
945dfecf96Smrg	CHECK_SCHAR(CAR(object));
955dfecf96Smrg
965dfecf96Smrg    /* All characters in list must be different */
975dfecf96Smrg    if (operation == CHAR_NOT_EQUAL) {
985dfecf96Smrg	/* Compare all characters */
995dfecf96Smrg	do {
1005dfecf96Smrg	    for (object = more_characters; CONSP(object); object = CDR(object)) {
1015dfecf96Smrg		character = CAR(object);
1025dfecf96Smrg		next_value = SCHAR_VALUE(character);
1035dfecf96Smrg		if (ignore_case && islower(next_value))
1045dfecf96Smrg		    next_value = toupper(next_value);
1055dfecf96Smrg		if (value == next_value)
1065dfecf96Smrg		    return (NIL);
1075dfecf96Smrg	    }
1085dfecf96Smrg	    value = SCHAR_VALUE(CAR(more_characters));
1095dfecf96Smrg	    if (ignore_case && islower(value))
1105dfecf96Smrg		value = toupper(value);
1115dfecf96Smrg	    more_characters = CDR(more_characters);
1125dfecf96Smrg	} while (CONSP(more_characters));
1135dfecf96Smrg
1145dfecf96Smrg	return (T);
1155dfecf96Smrg    }
1165dfecf96Smrg
1175dfecf96Smrg    /* Linearly compare characters */
1185dfecf96Smrg    for (; CONSP(more_characters); more_characters = CDR(more_characters)) {
1195dfecf96Smrg	character = CAR(more_characters);
1205dfecf96Smrg	next_value = SCHAR_VALUE(character);
1215dfecf96Smrg	if (ignore_case && islower(next_value))
1225dfecf96Smrg	    next_value = toupper(next_value);
1235dfecf96Smrg
1245dfecf96Smrg	switch (operation) {
1255dfecf96Smrg	    case CHAR_LESS:		cmp = value < next_value;	break;
1265dfecf96Smrg	    case CHAR_LESS_EQUAL:	cmp = value <= next_value;	break;
1275dfecf96Smrg	    case CHAR_EQUAL:		cmp = value == next_value;	break;
1285dfecf96Smrg	    case CHAR_GREATER_EQUAL:	cmp = value >= next_value;	break;
1295dfecf96Smrg	    case CHAR_GREATER:		cmp = value > next_value;	break;
1305dfecf96Smrg	    default:			cmp = 0;			break;
1315dfecf96Smrg	}
1325dfecf96Smrg
1335dfecf96Smrg	if (!cmp)
1345dfecf96Smrg	    return (NIL);
1355dfecf96Smrg	value = next_value;
1365dfecf96Smrg    }
1375dfecf96Smrg
1385dfecf96Smrg    return (T);
1395dfecf96Smrg}
1405dfecf96Smrg
1415dfecf96SmrgLispObj *
1425dfecf96SmrgLisp_CharLess(LispBuiltin *builtin)
1435dfecf96Smrg/*
1445dfecf96Smrg char< character &rest more-characters
1455dfecf96Smrg */
1465dfecf96Smrg{
1475dfecf96Smrg    return (LispCharCompare(builtin, CHAR_LESS, 0));
1485dfecf96Smrg}
1495dfecf96Smrg
1505dfecf96SmrgLispObj *
1515dfecf96SmrgLisp_CharLessEqual(LispBuiltin *builtin)
1525dfecf96Smrg/*
1535dfecf96Smrg char<= character &rest more-characters
1545dfecf96Smrg */
1555dfecf96Smrg{
1565dfecf96Smrg    return (LispCharCompare(builtin, CHAR_LESS_EQUAL, 0));
1575dfecf96Smrg}
1585dfecf96Smrg
1595dfecf96SmrgLispObj *
1605dfecf96SmrgLisp_CharEqual_(LispBuiltin *builtin)
1615dfecf96Smrg/*
1625dfecf96Smrg char= character &rest more-characters
1635dfecf96Smrg */
1645dfecf96Smrg{
1655dfecf96Smrg    return (LispCharCompare(builtin, CHAR_EQUAL, 0));
1665dfecf96Smrg}
1675dfecf96Smrg
1685dfecf96SmrgLispObj *
1695dfecf96SmrgLisp_CharGreater(LispBuiltin *builtin)
1705dfecf96Smrg/*
1715dfecf96Smrg char> character &rest more-characters
1725dfecf96Smrg */
1735dfecf96Smrg{
1745dfecf96Smrg    return (LispCharCompare(builtin, CHAR_GREATER, 0));
1755dfecf96Smrg}
1765dfecf96Smrg
1775dfecf96SmrgLispObj *
1785dfecf96SmrgLisp_CharGreaterEqual(LispBuiltin *builtin)
1795dfecf96Smrg/*
1805dfecf96Smrg char>= character &rest more-characters
1815dfecf96Smrg */
1825dfecf96Smrg{
1835dfecf96Smrg    return (LispCharCompare(builtin, CHAR_GREATER_EQUAL, 0));
1845dfecf96Smrg}
1855dfecf96Smrg
1865dfecf96SmrgLispObj *
1875dfecf96SmrgLisp_CharNotEqual_(LispBuiltin *builtin)
1885dfecf96Smrg/*
1895dfecf96Smrg char/= character &rest more-characters
1905dfecf96Smrg */
1915dfecf96Smrg{
1925dfecf96Smrg    return (LispCharCompare(builtin, CHAR_NOT_EQUAL, 0));
1935dfecf96Smrg}
1945dfecf96Smrg
1955dfecf96SmrgLispObj *
1965dfecf96SmrgLisp_CharLessp(LispBuiltin *builtin)
1975dfecf96Smrg/*
1985dfecf96Smrg char-lessp character &rest more-characters
1995dfecf96Smrg */
2005dfecf96Smrg{
2015dfecf96Smrg    return (LispCharCompare(builtin, CHAR_LESS, 1));
2025dfecf96Smrg}
2035dfecf96Smrg
2045dfecf96SmrgLispObj *
2055dfecf96SmrgLisp_CharNotGreaterp(LispBuiltin *builtin)
2065dfecf96Smrg/*
2075dfecf96Smrg char-not-greaterp character &rest more-characters
2085dfecf96Smrg */
2095dfecf96Smrg{
2105dfecf96Smrg    return (LispCharCompare(builtin, CHAR_LESS_EQUAL, 1));
2115dfecf96Smrg}
2125dfecf96Smrg
2135dfecf96SmrgLispObj *
2145dfecf96SmrgLisp_CharEqual(LispBuiltin *builtin)
2155dfecf96Smrg/*
2165dfecf96Smrg char-equalp character &rest more-characters
2175dfecf96Smrg */
2185dfecf96Smrg{
2195dfecf96Smrg    return (LispCharCompare(builtin, CHAR_EQUAL, 1));
2205dfecf96Smrg}
2215dfecf96Smrg
2225dfecf96SmrgLispObj *
2235dfecf96SmrgLisp_CharGreaterp(LispBuiltin *builtin)
2245dfecf96Smrg/*
2255dfecf96Smrg char-greaterp character &rest more-characters
2265dfecf96Smrg */
2275dfecf96Smrg{
2285dfecf96Smrg    return (LispCharCompare(builtin, CHAR_GREATER, 1));
2295dfecf96Smrg}
2305dfecf96Smrg
2315dfecf96SmrgLispObj *
2325dfecf96SmrgLisp_CharNotLessp(LispBuiltin *builtin)
2335dfecf96Smrg/*
2345dfecf96Smrg char-not-lessp &rest more-characters
2355dfecf96Smrg */
2365dfecf96Smrg{
2375dfecf96Smrg    return (LispCharCompare(builtin, CHAR_GREATER_EQUAL, 1));
2385dfecf96Smrg}
2395dfecf96Smrg
2405dfecf96SmrgLispObj *
2415dfecf96SmrgLisp_CharNotEqual(LispBuiltin *builtin)
2425dfecf96Smrg/*
2435dfecf96Smrg char-not-equal character &rest more-characters
2445dfecf96Smrg */
2455dfecf96Smrg{
2465dfecf96Smrg    return (LispCharCompare(builtin, CHAR_NOT_EQUAL, 1));
2475dfecf96Smrg}
2485dfecf96Smrg
2495dfecf96Smrgstatic LispObj *
2505dfecf96SmrgLispCharOp(LispBuiltin *builtin, int operation)
2515dfecf96Smrg{
2525dfecf96Smrg    int value;
2535dfecf96Smrg    LispObj *result, *character;
2545dfecf96Smrg
2555dfecf96Smrg    character = ARGUMENT(0);
2565dfecf96Smrg    CHECK_SCHAR(character);
2575dfecf96Smrg    value = (int)SCHAR_VALUE(character);
2585dfecf96Smrg
2595dfecf96Smrg    switch (operation) {
2605dfecf96Smrg	case CHAR_ALPHAP:
2615dfecf96Smrg	    result = isalpha(value) ? T : NIL;
2625dfecf96Smrg	    break;
2635dfecf96Smrg	case CHAR_DOWNCASE:
2645dfecf96Smrg	    result = SCHAR(tolower(value));
2655dfecf96Smrg	    break;
2665dfecf96Smrg	case CHAR_UPCASE:
2675dfecf96Smrg	    result = SCHAR(toupper(value));
2685dfecf96Smrg	    break;
2695dfecf96Smrg	case CHAR_INT:
2705dfecf96Smrg	    result = FIXNUM(value);
2715dfecf96Smrg	    break;
2725dfecf96Smrg	case CHAR_BOTHP:
2735dfecf96Smrg	    result = isupper(value) || islower(value) ? T : NIL;
2745dfecf96Smrg	    break;
2755dfecf96Smrg	case CHAR_UPPERP:
2765dfecf96Smrg	    result = isupper(value) ? T : NIL;
2775dfecf96Smrg	    break;
2785dfecf96Smrg	case CHAR_LOWERP:
2795dfecf96Smrg	    result = islower(value) ? T : NIL;
2805dfecf96Smrg	    break;
2815dfecf96Smrg	case CHAR_GRAPHICP:
2825dfecf96Smrg	    result = value == ' ' || isgraph(value) ? T : NIL;
2835dfecf96Smrg	    break;
2845dfecf96Smrg	default:
2855dfecf96Smrg	    result = NIL;
2865dfecf96Smrg	    break;
2875dfecf96Smrg    }
2885dfecf96Smrg
2895dfecf96Smrg    return (result);
2905dfecf96Smrg}
2915dfecf96Smrg
2925dfecf96SmrgLispObj *
2935dfecf96SmrgLisp_AlphaCharP(LispBuiltin *builtin)
2945dfecf96Smrg/*
2955dfecf96Smrg alpha-char-p char
2965dfecf96Smrg */
2975dfecf96Smrg{
2985dfecf96Smrg    return (LispCharOp(builtin, CHAR_ALPHAP));
2995dfecf96Smrg}
3005dfecf96Smrg
3015dfecf96SmrgLispObj *
3025dfecf96SmrgLisp_CharDowncase(LispBuiltin *builtin)
3035dfecf96Smrg/*
3045dfecf96Smrg char-downcase character
3055dfecf96Smrg */
3065dfecf96Smrg{
3075dfecf96Smrg    return (LispCharOp(builtin, CHAR_DOWNCASE));
3085dfecf96Smrg}
3095dfecf96Smrg
3105dfecf96SmrgLispObj *
3115dfecf96SmrgLisp_CharInt(LispBuiltin *builtin)
3125dfecf96Smrg/*
3135dfecf96Smrg char-int character
3145dfecf96Smrg char-code character
3155dfecf96Smrg */
3165dfecf96Smrg{
3175dfecf96Smrg    return (LispCharOp(builtin, CHAR_INT));
3185dfecf96Smrg}
3195dfecf96Smrg
3205dfecf96SmrgLispObj *
3215dfecf96SmrgLisp_CharUpcase(LispBuiltin *builtin)
3225dfecf96Smrg/*
3235dfecf96Smrg char-upcase character
3245dfecf96Smrg */
3255dfecf96Smrg{
3265dfecf96Smrg    return (LispCharOp(builtin, CHAR_UPCASE));
3275dfecf96Smrg}
3285dfecf96Smrg
3295dfecf96SmrgLispObj *
3305dfecf96SmrgLisp_BothCaseP(LispBuiltin *builtin)
3315dfecf96Smrg/*
3325dfecf96Smrg both-case-p character
3335dfecf96Smrg */
3345dfecf96Smrg{
3355dfecf96Smrg    return (LispCharOp(builtin, CHAR_BOTHP));
3365dfecf96Smrg}
3375dfecf96Smrg
3385dfecf96SmrgLispObj *
3395dfecf96SmrgLisp_UpperCaseP(LispBuiltin *builtin)
3405dfecf96Smrg/*
3415dfecf96Smrg upper-case-p character
3425dfecf96Smrg */
3435dfecf96Smrg{
3445dfecf96Smrg    return (LispCharOp(builtin, CHAR_UPPERP));
3455dfecf96Smrg}
3465dfecf96Smrg
3475dfecf96SmrgLispObj *
3485dfecf96SmrgLisp_LowerCaseP(LispBuiltin *builtin)
3495dfecf96Smrg/*
3505dfecf96Smrg upper-case-p character
3515dfecf96Smrg */
3525dfecf96Smrg{
3535dfecf96Smrg    return (LispCharOp(builtin, CHAR_LOWERP));
3545dfecf96Smrg}
3555dfecf96Smrg
3565dfecf96SmrgLispObj *
3575dfecf96SmrgLisp_GraphicCharP(LispBuiltin *builtin)
3585dfecf96Smrg/*
3595dfecf96Smrg graphic-char-p char
3605dfecf96Smrg */
3615dfecf96Smrg{
3625dfecf96Smrg    return (LispCharOp(builtin, CHAR_GRAPHICP));
3635dfecf96Smrg}
3645dfecf96Smrg
3655dfecf96SmrgLispObj *
3665dfecf96SmrgLisp_Char(LispBuiltin *builtin)
3675dfecf96Smrg/*
3685dfecf96Smrg char string index
3695dfecf96Smrg schar simple-string index
3705dfecf96Smrg */
3715dfecf96Smrg{
3725dfecf96Smrg    unsigned char *string;
3735dfecf96Smrg    long offset, length;
3745dfecf96Smrg
3755dfecf96Smrg    LispObj *ostring, *oindex;
3765dfecf96Smrg
3775dfecf96Smrg    oindex = ARGUMENT(1);
3785dfecf96Smrg    ostring = ARGUMENT(0);
3795dfecf96Smrg
3805dfecf96Smrg    CHECK_STRING(ostring);
3815dfecf96Smrg    CHECK_INDEX(oindex);
3825dfecf96Smrg    offset = FIXNUM_VALUE(oindex);
3835dfecf96Smrg    string = (unsigned char*)THESTR(ostring);
3845dfecf96Smrg    length = STRLEN(ostring);
3855dfecf96Smrg
3865dfecf96Smrg    if (offset >= length)
3875dfecf96Smrg	LispDestroy("%s: index %ld too large for string length %ld",
3885dfecf96Smrg		    STRFUN(builtin), offset, length);
3895dfecf96Smrg
3905dfecf96Smrg    return (SCHAR(string[offset]));
3915dfecf96Smrg}
3925dfecf96Smrg
3935dfecf96Smrg/* helper function for setf
3945dfecf96Smrg *	DONT explicitly call. Non standard function
3955dfecf96Smrg */
3965dfecf96SmrgLispObj *
3975dfecf96SmrgLisp_XeditCharStore(LispBuiltin *builtin)
3985dfecf96Smrg/*
3995dfecf96Smrg xedit::char-store string index value
4005dfecf96Smrg */
4015dfecf96Smrg{
4025dfecf96Smrg    int character;
4035dfecf96Smrg    long offset, length;
4045dfecf96Smrg    LispObj *ostring, *oindex, *ovalue;
4055dfecf96Smrg
4065dfecf96Smrg    ovalue = ARGUMENT(2);
4075dfecf96Smrg    oindex = ARGUMENT(1);
4085dfecf96Smrg    ostring = ARGUMENT(0);
4095dfecf96Smrg
4105dfecf96Smrg    CHECK_STRING(ostring);
4115dfecf96Smrg    CHECK_INDEX(oindex);
4125dfecf96Smrg    length = STRLEN(ostring);
4135dfecf96Smrg    offset = FIXNUM_VALUE(oindex);
4145dfecf96Smrg    if (offset >= length)
4155dfecf96Smrg	LispDestroy("%s: index %ld too large for string length %ld",
4165dfecf96Smrg		    STRFUN(builtin), offset, length);
4175dfecf96Smrg    CHECK_SCHAR(ovalue);
4185dfecf96Smrg    CHECK_STRING_WRITABLE(ostring);
4195dfecf96Smrg
4205dfecf96Smrg    character = SCHAR_VALUE(ovalue);
4215dfecf96Smrg
4225dfecf96Smrg    if (character < 0 || character > 255)
4235dfecf96Smrg	LispDestroy("%s: cannot represent character %d",
4245dfecf96Smrg		    STRFUN(builtin), character);
4255dfecf96Smrg
4265dfecf96Smrg    THESTR(ostring)[offset] = character;
4275dfecf96Smrg
4285dfecf96Smrg    return (ovalue);
4295dfecf96Smrg}
4305dfecf96Smrg
4315dfecf96SmrgLispObj *
4325dfecf96SmrgLisp_Character(LispBuiltin *builtin)
4335dfecf96Smrg/*
4345dfecf96Smrg character object
4355dfecf96Smrg */
4365dfecf96Smrg{
4375dfecf96Smrg    LispObj *object;
4385dfecf96Smrg
4395dfecf96Smrg    object = ARGUMENT(0);
4405dfecf96Smrg
4415dfecf96Smrg    return (LispCharacterCoerce(builtin, object));
4425dfecf96Smrg}
4435dfecf96Smrg
4445dfecf96SmrgLispObj *
4455dfecf96SmrgLisp_Characterp(LispBuiltin *builtin)
4465dfecf96Smrg/*
4475dfecf96Smrg characterp object
4485dfecf96Smrg */
4495dfecf96Smrg{
4505dfecf96Smrg    LispObj *object;
4515dfecf96Smrg
4525dfecf96Smrg    object = ARGUMENT(0);
4535dfecf96Smrg
4545dfecf96Smrg    return (SCHARP(object) ? T : NIL);
4555dfecf96Smrg}
4565dfecf96Smrg
4575dfecf96SmrgLispObj *
4585dfecf96SmrgLisp_DigitChar(LispBuiltin *builtin)
4595dfecf96Smrg/*
4605dfecf96Smrg digit-char weight &optional radix
4615dfecf96Smrg */
4625dfecf96Smrg{
4635dfecf96Smrg    long radix = 10, weight;
4645dfecf96Smrg    LispObj *oweight, *oradix, *result = NIL;
4655dfecf96Smrg
4665dfecf96Smrg    oradix = ARGUMENT(1);
4675dfecf96Smrg    oweight = ARGUMENT(0);
4685dfecf96Smrg
4695dfecf96Smrg    CHECK_FIXNUM(oweight);
4705dfecf96Smrg    weight = FIXNUM_VALUE(oweight);
4715dfecf96Smrg
4725dfecf96Smrg    if (oradix != UNSPEC) {
4735dfecf96Smrg	CHECK_INDEX(oradix);
4745dfecf96Smrg	radix = FIXNUM_VALUE(oradix);
4755dfecf96Smrg    }
4765dfecf96Smrg    if (radix < 2 || radix > 36)
4775dfecf96Smrg	LispDestroy("%s: radix must be >= 2 and <= 36, not %ld",
4785dfecf96Smrg		    STRFUN(builtin), radix);
4795dfecf96Smrg
4805dfecf96Smrg    if (weight >= 0 && weight < radix) {
4815dfecf96Smrg	if (weight < 9)
4825dfecf96Smrg	    weight += '0';
4835dfecf96Smrg	else
4845dfecf96Smrg	    weight += 'A' - 10;
4855dfecf96Smrg	result = SCHAR(weight);
4865dfecf96Smrg    }
4875dfecf96Smrg
4885dfecf96Smrg    return (result);
4895dfecf96Smrg}
4905dfecf96Smrg
4915dfecf96SmrgLispObj *
4925dfecf96SmrgLisp_DigitCharP(LispBuiltin *builtin)
4935dfecf96Smrg/*
4945dfecf96Smrg digit-char-p character &optional radix
4955dfecf96Smrg */
4965dfecf96Smrg{
4975dfecf96Smrg    long radix = 10, character;
4985dfecf96Smrg    LispObj *ochar, *oradix, *result = NIL;
4995dfecf96Smrg
5005dfecf96Smrg    oradix = ARGUMENT(1);
5015dfecf96Smrg    ochar = ARGUMENT(0);
5025dfecf96Smrg
5035dfecf96Smrg    CHECK_SCHAR(ochar);
5045dfecf96Smrg    character = SCHAR_VALUE(ochar);
5055dfecf96Smrg    if (oradix != UNSPEC) {
5065dfecf96Smrg	CHECK_INDEX(oradix);
5075dfecf96Smrg	radix = FIXNUM_VALUE(oradix);
5085dfecf96Smrg    }
5095dfecf96Smrg    if (radix < 2 || radix > 36)
5105dfecf96Smrg	LispDestroy("%s: radix must be >= 2 and <= 36, not %ld",
5115dfecf96Smrg		    STRFUN(builtin), radix);
5125dfecf96Smrg
5135dfecf96Smrg    if (character >= '0' && character <= '9')
5145dfecf96Smrg	character -= '0';
5155dfecf96Smrg    else if (character >= 'A' && character <= 'Z')
5165dfecf96Smrg	character -= 'A' - 10;
5175dfecf96Smrg    else if (character >= 'a' && character <= 'z')
5185dfecf96Smrg	character -= 'a' - 10;
5195dfecf96Smrg    if (character < radix)
5205dfecf96Smrg	result = FIXNUM(character);
5215dfecf96Smrg
5225dfecf96Smrg    return (result);
5235dfecf96Smrg}
5245dfecf96Smrg
5255dfecf96SmrgLispObj *
5265dfecf96SmrgLisp_IntChar(LispBuiltin *builtin)
5275dfecf96Smrg/*
5285dfecf96Smrg int-char integer
5295dfecf96Smrg code-char integer
5305dfecf96Smrg */
5315dfecf96Smrg{
5325dfecf96Smrg    long character = 0;
5335dfecf96Smrg    LispObj *integer;
5345dfecf96Smrg
5355dfecf96Smrg    integer = ARGUMENT(0);
5365dfecf96Smrg
5375dfecf96Smrg    CHECK_FIXNUM(integer);
5385dfecf96Smrg    character = FIXNUM_VALUE(integer);
5395dfecf96Smrg
5405dfecf96Smrg    return (character >= 0 && character < 0xff ? SCHAR(character) : NIL);
5415dfecf96Smrg}
5425dfecf96Smrg
5435dfecf96Smrg/* XXX ignoring element-type */
5445dfecf96SmrgLispObj *
5455dfecf96SmrgLisp_MakeString(LispBuiltin *builtin)
5465dfecf96Smrg/*
5475dfecf96Smrg make-string size &key initial-element element-type
5485dfecf96Smrg */
5495dfecf96Smrg{
5505dfecf96Smrg    long length;
5515dfecf96Smrg    char *string, initial;
5525dfecf96Smrg
5535dfecf96Smrg    LispObj *size, *initial_element;
5545dfecf96Smrg
5555dfecf96Smrg    initial_element = ARGUMENT(1);
5565dfecf96Smrg    size = ARGUMENT(0);
5575dfecf96Smrg
5585dfecf96Smrg    CHECK_INDEX(size);
5595dfecf96Smrg    length = FIXNUM_VALUE(size);
5605dfecf96Smrg    if (initial_element != UNSPEC) {
5615dfecf96Smrg	CHECK_SCHAR(initial_element);
5625dfecf96Smrg	initial = SCHAR_VALUE(initial_element);
5635dfecf96Smrg    }
5645dfecf96Smrg    else
5655dfecf96Smrg	initial = 0;
5665dfecf96Smrg
5675dfecf96Smrg    string = LispMalloc(length + 1);
5685dfecf96Smrg    memset(string, initial, length);
5695dfecf96Smrg    string[length] = '\0';
5705dfecf96Smrg
5715dfecf96Smrg    return (LSTRING2(string, length));
5725dfecf96Smrg}
5735dfecf96Smrg
5745dfecf96SmrgLispObj *
5755dfecf96SmrgLisp_ParseInteger(LispBuiltin *builtin)
5765dfecf96Smrg/*
5775dfecf96Smrg parse-integer string &key start end radix junk-allowed
5785dfecf96Smrg */
5795dfecf96Smrg{
5805dfecf96Smrg    GC_ENTER();
5815dfecf96Smrg    char *ptr, *string;
5825dfecf96Smrg    int character, junk, sign, overflow;
5835dfecf96Smrg    long i, start, end, radix, length, integer, check;
5845dfecf96Smrg    LispObj *result;
5855dfecf96Smrg
5865dfecf96Smrg    LispObj *ostring, *ostart, *oend, *oradix, *junk_allowed;
5875dfecf96Smrg
5885dfecf96Smrg    junk_allowed = ARGUMENT(4);
5895dfecf96Smrg    oradix = ARGUMENT(3);
5905dfecf96Smrg    oend = ARGUMENT(2);
5915dfecf96Smrg    ostart = ARGUMENT(1);
5925dfecf96Smrg    ostring = ARGUMENT(0);
5935dfecf96Smrg
5945dfecf96Smrg    start = end = radix = 0;
5955dfecf96Smrg    result = NIL;
5965dfecf96Smrg
5975dfecf96Smrg    CHECK_STRING(ostring);
5985dfecf96Smrg    LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
5995dfecf96Smrg			      &start, &end, &length);
6005dfecf96Smrg    string = THESTR(ostring);
6015dfecf96Smrg    if (oradix == UNSPEC)
6025dfecf96Smrg	radix = 10;
6035dfecf96Smrg    else {
6045dfecf96Smrg	CHECK_INDEX(oradix);
6055dfecf96Smrg	radix = FIXNUM_VALUE(oradix);
6065dfecf96Smrg    }
6075dfecf96Smrg    if (radix < 2 || radix > 36)
6085dfecf96Smrg	LispDestroy("%s: :RADIX %ld must be in the range 2 to 36",
6095dfecf96Smrg		    STRFUN(builtin), radix);
6105dfecf96Smrg
6115dfecf96Smrg    integer = check = 0;
6125dfecf96Smrg    ptr = string + start;
6135dfecf96Smrg    sign = overflow = 0;
6145dfecf96Smrg
6155dfecf96Smrg    /* Skip leading white spaces */
6165dfecf96Smrg    for (i = start; i < end && *ptr && isspace(*ptr); ptr++, i++)
6175dfecf96Smrg	;
6185dfecf96Smrg
6195dfecf96Smrg    /* Check for sign specification */
6205dfecf96Smrg    if (i < end && (*ptr == '-' || *ptr == '+')) {
6215dfecf96Smrg	sign = *ptr == '-';
6225dfecf96Smrg	++ptr;
6235dfecf96Smrg	++i;
6245dfecf96Smrg    }
6255dfecf96Smrg
6265dfecf96Smrg    for (junk = 0; i < end; i++, ptr++) {
6275dfecf96Smrg	character = *ptr;
6285dfecf96Smrg	if (islower(character))
6295dfecf96Smrg	    character = toupper(character);
6305dfecf96Smrg	if (character >= '0' && character <= '9') {
6315dfecf96Smrg	    if (character - '0' >= radix)
6325dfecf96Smrg		junk = 1;
6335dfecf96Smrg	    else {
6345dfecf96Smrg		check = integer;
6355dfecf96Smrg		integer = integer * radix + character - '0';
6365dfecf96Smrg	    }
6375dfecf96Smrg	}
6385dfecf96Smrg	else if (character >= 'A' && character <= 'Z') {
6395dfecf96Smrg	    if (character - 'A' + 10 >= radix)
6405dfecf96Smrg		junk = 1;
6415dfecf96Smrg	    else {
6425dfecf96Smrg		check = integer;
6435dfecf96Smrg		integer = integer * radix + character - 'A' + 10;
6445dfecf96Smrg	    }
6455dfecf96Smrg	}
6465dfecf96Smrg	else {
6475dfecf96Smrg	    if (isspace(character))
6485dfecf96Smrg		break;
6495dfecf96Smrg	    junk = 1;
6505dfecf96Smrg	}
6515dfecf96Smrg
6525dfecf96Smrg	if (junk)
6535dfecf96Smrg	    break;
6545dfecf96Smrg
6555dfecf96Smrg	if (!overflow && check > integer)
6565dfecf96Smrg	    overflow = 1;
6575dfecf96Smrg	/* keep looping just to count read bytes */
6585dfecf96Smrg    }
6595dfecf96Smrg
6605dfecf96Smrg    if (!junk)
6615dfecf96Smrg	/* Skip white spaces */
6625dfecf96Smrg	for (; i < end && *ptr && isspace(*ptr); ptr++, i++)
6635dfecf96Smrg	    ;
6645dfecf96Smrg
6655dfecf96Smrg    if ((junk || ptr == string) &&
6665dfecf96Smrg	(junk_allowed == UNSPEC || junk_allowed == NIL))
6675dfecf96Smrg	LispDestroy("%s: %s has a bad integer representation",
6685dfecf96Smrg		    STRFUN(builtin), STROBJ(ostring));
6695dfecf96Smrg    else if (ptr == string)
6705dfecf96Smrg	result = NIL;
6715dfecf96Smrg    else if (overflow) {
6725dfecf96Smrg	mpi *bigi = LispMalloc(sizeof(mpi));
6735dfecf96Smrg	char *str;
6745dfecf96Smrg
6755dfecf96Smrg	length = end - start + sign;
6765dfecf96Smrg	str = LispMalloc(length + 1);
6775dfecf96Smrg
6785dfecf96Smrg	strncpy(str, string - sign, length + sign);
6795dfecf96Smrg	str[length + sign] = '\0';
6805dfecf96Smrg	mpi_init(bigi);
6815dfecf96Smrg	mpi_setstr(bigi, str, radix);
6825dfecf96Smrg	LispFree(str);
6835dfecf96Smrg	result = BIGNUM(bigi);
6845dfecf96Smrg    }
6855dfecf96Smrg    else
6865dfecf96Smrg	result = INTEGER(sign ? -integer : integer);
6875dfecf96Smrg
6885dfecf96Smrg    GC_PROTECT(result);
6895dfecf96Smrg    RETURN(0) = FIXNUM(i);
6905dfecf96Smrg    RETURN_COUNT = 1;
6915dfecf96Smrg    GC_LEAVE();
6925dfecf96Smrg
6935dfecf96Smrg    return (result);
6945dfecf96Smrg}
6955dfecf96Smrg
6965dfecf96SmrgLispObj *
6975dfecf96SmrgLisp_String(LispBuiltin *builtin)
6985dfecf96Smrg/*
6995dfecf96Smrg string object
7005dfecf96Smrg */
7015dfecf96Smrg{
7025dfecf96Smrg    LispObj *object;
7035dfecf96Smrg
7045dfecf96Smrg    object = ARGUMENT(0);
7055dfecf96Smrg
7065dfecf96Smrg    return (LispStringCoerce(builtin, object));
7075dfecf96Smrg}
7085dfecf96Smrg
7095dfecf96SmrgLispObj *
7105dfecf96SmrgLisp_Stringp(LispBuiltin *builtin)
7115dfecf96Smrg/*
7125dfecf96Smrg stringp object
7135dfecf96Smrg */
7145dfecf96Smrg{
7155dfecf96Smrg    LispObj *object;
7165dfecf96Smrg
7175dfecf96Smrg    object = ARGUMENT(0);
7185dfecf96Smrg
7195dfecf96Smrg    return (STRINGP(object) ? T : NIL);
7205dfecf96Smrg}
7215dfecf96Smrg
7225dfecf96Smrg/* XXX preserve-whitespace is being ignored */
7235dfecf96SmrgLispObj *
7245dfecf96SmrgLisp_ReadFromString(LispBuiltin *builtin)
7255dfecf96Smrg/*
7265dfecf96Smrg read-from-string string &optional eof-error-p eof-value &key start end preserve-whitespace
7275dfecf96Smrg */
7285dfecf96Smrg{
7295dfecf96Smrg    GC_ENTER();
7305dfecf96Smrg    char *string;
7315dfecf96Smrg    LispObj *stream, *result;
7325dfecf96Smrg    long length, start, end, bytes_read;
7335dfecf96Smrg
7345dfecf96Smrg    LispObj *ostring, *eof_error_p, *eof_value, *ostart, *oend;
7355dfecf96Smrg
7365dfecf96Smrg    oend = ARGUMENT(4);
7375dfecf96Smrg    ostart = ARGUMENT(3);
7385dfecf96Smrg    eof_value = ARGUMENT(2);
7395dfecf96Smrg    eof_error_p = ARGUMENT(1);
7405dfecf96Smrg    ostring = ARGUMENT(0);
7415dfecf96Smrg
7425dfecf96Smrg    CHECK_STRING(ostring);
7435dfecf96Smrg    string = THESTR(ostring);
7445dfecf96Smrg    LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
7455dfecf96Smrg			      &start, &end, &length);
7465dfecf96Smrg
7475dfecf96Smrg    if (start > 0 || end < length)
7485dfecf96Smrg	length = end - start;
7495dfecf96Smrg    stream = LSTRINGSTREAM(string + start, STREAM_READ, length);
7505dfecf96Smrg
7515dfecf96Smrg    if (eof_value == UNSPEC)
7525dfecf96Smrg	eof_value = NIL;
7535dfecf96Smrg
7545dfecf96Smrg    LispPushInput(stream);
7555dfecf96Smrg    result = LispRead();
7565dfecf96Smrg    /* stream->data.stream.source.string->input is
7575dfecf96Smrg     * the offset of the last byte read in string */
7585dfecf96Smrg    bytes_read = stream->data.stream.source.string->input;
7595dfecf96Smrg    LispPopInput(stream);
7605dfecf96Smrg
7615dfecf96Smrg    if (result == NULL) {
7625dfecf96Smrg	if (eof_error_p == NIL)
7635dfecf96Smrg	    result = eof_value;
7645dfecf96Smrg	else
7655dfecf96Smrg	    LispDestroy("%s: unexpected end of input", STRFUN(builtin));
7665dfecf96Smrg    }
7675dfecf96Smrg
7685dfecf96Smrg    GC_PROTECT(result);
7695dfecf96Smrg    RETURN(0) = FIXNUM(start + bytes_read);
7705dfecf96Smrg    RETURN_COUNT = 1;
7715dfecf96Smrg    GC_LEAVE();
7725dfecf96Smrg
7735dfecf96Smrg    return (result);
7745dfecf96Smrg}
7755dfecf96Smrg
7765dfecf96Smrgstatic LispObj *
7775dfecf96SmrgLispStringTrim(LispBuiltin *builtin, int left, int right, int inplace)
7785dfecf96Smrg/*
7795dfecf96Smrg string-{,left-,right-}trim character-bag string
7805dfecf96Smrg*/
7815dfecf96Smrg{
7825dfecf96Smrg    unsigned char *string;
7835dfecf96Smrg    long start, end, length;
7845dfecf96Smrg
7855dfecf96Smrg    LispObj *ochars, *ostring;
7865dfecf96Smrg
7875dfecf96Smrg    ostring = ARGUMENT(1);
7885dfecf96Smrg    ochars = ARGUMENT(0);
7895dfecf96Smrg
7905dfecf96Smrg    if (!POINTERP(ochars) || !(XSTRINGP(ochars) || XCONSP(ochars))) {
7915dfecf96Smrg	if (ARRAYP(ochars) && ochars->data.array.rank == 1)
7925dfecf96Smrg	    ochars = ochars->data.array.list;
7935dfecf96Smrg	else
7945dfecf96Smrg	    LispDestroy("%s: %s is not a sequence",
7955dfecf96Smrg			STRFUN(builtin), STROBJ(ochars));
7965dfecf96Smrg    }
7975dfecf96Smrg    CHECK_STRING(ostring);
7985dfecf96Smrg
7995dfecf96Smrg    string = (unsigned char*)THESTR(ostring);
8005dfecf96Smrg    length = STRLEN(ostring);
8015dfecf96Smrg
8025dfecf96Smrg    start = 0;
8035dfecf96Smrg    end = length;
8045dfecf96Smrg
8055dfecf96Smrg    if (XSTRINGP(ochars)) {
8065dfecf96Smrg	unsigned char *chars = (unsigned char*)THESTR(ochars);
8075dfecf96Smrg	long i, clength = STRLEN(ochars);
8085dfecf96Smrg
8095dfecf96Smrg	if (left) {
8105dfecf96Smrg	    for (; start < end; start++) {
8115dfecf96Smrg		for (i = 0; i < clength; i++)
8125dfecf96Smrg		    if (string[start] == chars[i])
8135dfecf96Smrg			break;
8145dfecf96Smrg		if (i >= clength)
8155dfecf96Smrg		    break;
8165dfecf96Smrg	    }
8175dfecf96Smrg	}
8185dfecf96Smrg	if (right) {
8195dfecf96Smrg	    for (--end; end >= 0; end--) {
8205dfecf96Smrg		for (i = 0; i < clength; i++)
8215dfecf96Smrg		    if (string[end] == chars[i])
8225dfecf96Smrg			break;
8235dfecf96Smrg		if (i >= clength)
8245dfecf96Smrg		    break;
8255dfecf96Smrg	    }
8265dfecf96Smrg	    ++end;
8275dfecf96Smrg	}
8285dfecf96Smrg    }
8295dfecf96Smrg    else {
8305dfecf96Smrg	LispObj *ochar, *list;
8315dfecf96Smrg
8325dfecf96Smrg	if (left) {
8335dfecf96Smrg	    for (; start < end; start++) {
8345dfecf96Smrg		for (list = ochars; CONSP(list); list = CDR(list)) {
8355dfecf96Smrg		    ochar = CAR(list);
8365dfecf96Smrg		    if (SCHARP(ochar) && string[start] == SCHAR_VALUE(ochar))
8375dfecf96Smrg			break;
8385dfecf96Smrg		}
8395dfecf96Smrg		if (!CONSP(list))
8405dfecf96Smrg		    break;
8415dfecf96Smrg	    }
8425dfecf96Smrg	}
8435dfecf96Smrg	if (right) {
8445dfecf96Smrg	    for (--end; end >= 0; end--) {
8455dfecf96Smrg		for (list = ochars; CONSP(list); list = CDR(list)) {
8465dfecf96Smrg		    ochar = CAR(list);
8475dfecf96Smrg		    if (SCHARP(ochar) && string[end] == SCHAR_VALUE(ochar))
8485dfecf96Smrg			break;
8495dfecf96Smrg		}
8505dfecf96Smrg		if (!CONSP(list))
8515dfecf96Smrg		    break;
8525dfecf96Smrg	    }
8535dfecf96Smrg	    ++end;
8545dfecf96Smrg	}
8555dfecf96Smrg    }
8565dfecf96Smrg
8575dfecf96Smrg    if (start == 0 && end == length)
8585dfecf96Smrg	return (ostring);
8595dfecf96Smrg
8605dfecf96Smrg    length = end - start;
8615dfecf96Smrg
8625dfecf96Smrg    if (inplace) {
8635dfecf96Smrg	CHECK_STRING_WRITABLE(ostring);
8645dfecf96Smrg	memmove(string, string + start, length);
8655dfecf96Smrg	string[length] = '\0';
8665dfecf96Smrg	STRLEN(ostring) = length;
8675dfecf96Smrg    }
8685dfecf96Smrg    else {
8695dfecf96Smrg	string = LispMalloc(length + 1);
8705dfecf96Smrg	memcpy(string, THESTR(ostring) + start, length);
8715dfecf96Smrg	string[length] = '\0';
8725dfecf96Smrg	ostring = LSTRING2((char*)string, length);
8735dfecf96Smrg    }
8745dfecf96Smrg
8755dfecf96Smrg    return (ostring);
8765dfecf96Smrg}
8775dfecf96Smrg
8785dfecf96SmrgLispObj *
8795dfecf96SmrgLisp_StringTrim(LispBuiltin *builtin)
8805dfecf96Smrg/*
8815dfecf96Smrg string-trim character-bag string
8825dfecf96Smrg */
8835dfecf96Smrg{
8845dfecf96Smrg    return (LispStringTrim(builtin, 1, 1, 0));
8855dfecf96Smrg}
8865dfecf96Smrg
8875dfecf96SmrgLispObj *
8885dfecf96SmrgLisp_NstringTrim(LispBuiltin *builtin)
8895dfecf96Smrg/*
8905dfecf96Smrg ext::nstring-trim character-bag string
8915dfecf96Smrg */
8925dfecf96Smrg{
8935dfecf96Smrg    return (LispStringTrim(builtin, 1, 1, 1));
8945dfecf96Smrg}
8955dfecf96Smrg
8965dfecf96SmrgLispObj *
8975dfecf96SmrgLisp_StringLeftTrim(LispBuiltin *builtin)
8985dfecf96Smrg/*
8995dfecf96Smrg string-left-trim character-bag string
9005dfecf96Smrg */
9015dfecf96Smrg{
9025dfecf96Smrg    return (LispStringTrim(builtin, 1, 0, 0));
9035dfecf96Smrg}
9045dfecf96Smrg
9055dfecf96SmrgLispObj *
9065dfecf96SmrgLisp_NstringLeftTrim(LispBuiltin *builtin)
9075dfecf96Smrg/*
9085dfecf96Smrg ext::nstring-left-trim character-bag string
9095dfecf96Smrg */
9105dfecf96Smrg{
9115dfecf96Smrg    return (LispStringTrim(builtin, 1, 0, 1));
9125dfecf96Smrg}
9135dfecf96Smrg
9145dfecf96SmrgLispObj *
9155dfecf96SmrgLisp_StringRightTrim(LispBuiltin *builtin)
9165dfecf96Smrg/*
9175dfecf96Smrg string-right-trim character-bag string
9185dfecf96Smrg */
9195dfecf96Smrg{
9205dfecf96Smrg    return (LispStringTrim(builtin, 0, 1, 0));
9215dfecf96Smrg}
9225dfecf96Smrg
9235dfecf96SmrgLispObj *
9245dfecf96SmrgLisp_NstringRightTrim(LispBuiltin *builtin)
9255dfecf96Smrg/*
9265dfecf96Smrg ext::nstring-right-trim character-bag string
9275dfecf96Smrg */
9285dfecf96Smrg{
9295dfecf96Smrg    return (LispStringTrim(builtin, 0, 1, 1));
9305dfecf96Smrg}
9315dfecf96Smrg
9325dfecf96Smrgstatic LispObj *
9335dfecf96SmrgLispStringCompare(LispBuiltin *builtin, int function, int ignore_case)
9345dfecf96Smrg{
9355dfecf96Smrg    int cmp1, cmp2;
9365dfecf96Smrg    LispObj *fixnum;
9375dfecf96Smrg    unsigned char *string1, *string2;
9385dfecf96Smrg    long start1, end1, start2, end2, offset, length;
9395dfecf96Smrg
9405dfecf96Smrg    LispGetStringArgs(builtin, (char**)&string1, (char**)&string2,
9415dfecf96Smrg		      &start1, &end1, &start2, &end2);
9425dfecf96Smrg
9435dfecf96Smrg    string1 += start1;
9445dfecf96Smrg    string2 += start2;
9455dfecf96Smrg
9465dfecf96Smrg    if (function == CHAR_EQUAL) {
9475dfecf96Smrg	length = end1 - start1;
9485dfecf96Smrg
9495dfecf96Smrg	if (length != (end2 - start2))
9505dfecf96Smrg	    return (NIL);
9515dfecf96Smrg
9525dfecf96Smrg	if (!ignore_case)
9535dfecf96Smrg	    return (memcmp(string1, string2, length) ? NIL : T);
9545dfecf96Smrg
9555dfecf96Smrg	for (; length; length--, string1++, string2++)
9565dfecf96Smrg	    if (toupper(*string1) != toupper(*string2))
9575dfecf96Smrg		return (NIL);
9585dfecf96Smrg	return (T);
9595dfecf96Smrg    }
9605dfecf96Smrg
9615dfecf96Smrg    end1 -= start1;
9625dfecf96Smrg    end2 -= start2;
9635dfecf96Smrg    length = MIN(end1, end2);
9645dfecf96Smrg    for (offset = 0;
9655dfecf96Smrg	 offset < length;
9665dfecf96Smrg	 string1++, string2++, offset++, start1++, start2++) {
9675dfecf96Smrg	cmp1 = *string1;
9685dfecf96Smrg	cmp2 = *string2;
9695dfecf96Smrg	if (ignore_case) {
9705dfecf96Smrg	    cmp1 = toupper(cmp1);
9715dfecf96Smrg	    cmp2 = toupper(cmp2);
9725dfecf96Smrg	}
9735dfecf96Smrg	if (cmp1 != cmp2) {
9745dfecf96Smrg	    fixnum = FIXNUM(start1);
9755dfecf96Smrg	    switch (function) {
9765dfecf96Smrg		case CHAR_LESS:
9775dfecf96Smrg		    return ((cmp1 < cmp2) ? fixnum : NIL);
9785dfecf96Smrg		case CHAR_LESS_EQUAL:
9795dfecf96Smrg		    return ((cmp1 <= cmp2) ? fixnum : NIL);
9805dfecf96Smrg		case CHAR_NOT_EQUAL:
9815dfecf96Smrg		    return (fixnum);
9825dfecf96Smrg		case CHAR_GREATER_EQUAL:
9835dfecf96Smrg		    return ((cmp1 >= cmp2) ? fixnum : NIL);
9845dfecf96Smrg		case CHAR_GREATER:
9855dfecf96Smrg		    return ((cmp1 > cmp2) ? fixnum : NIL);
9865dfecf96Smrg	    }
9875dfecf96Smrg	}
9885dfecf96Smrg    }
9895dfecf96Smrg
9905dfecf96Smrg    fixnum = FIXNUM(start1);
9915dfecf96Smrg    switch (function) {
9925dfecf96Smrg	case CHAR_LESS:
9935dfecf96Smrg	    return (start1 >= end1 && start2 < end2 ? fixnum : NIL);
9945dfecf96Smrg	case CHAR_LESS_EQUAL:
9955dfecf96Smrg	    return (start1 >= end1 ? fixnum : NIL);
9965dfecf96Smrg	case CHAR_NOT_EQUAL:
9975dfecf96Smrg	    return (start1 >= end1 && start2 >= end2 ? NIL : fixnum);
9985dfecf96Smrg	case CHAR_GREATER_EQUAL:
9995dfecf96Smrg	    return (start2 >= end2 ? fixnum : NIL);
10005dfecf96Smrg	case CHAR_GREATER:
10015dfecf96Smrg	    return (start2 >= end2 && start1 < end1 ? fixnum : NIL);
10025dfecf96Smrg    }
10035dfecf96Smrg
10045dfecf96Smrg    return (NIL);
10055dfecf96Smrg}
10065dfecf96Smrg
10075dfecf96SmrgLispObj *
10085dfecf96SmrgLisp_StringEqual_(LispBuiltin *builtin)
10095dfecf96Smrg/*
10105dfecf96Smrg string= string1 string2 &key start1 end1 start2 end2
10115dfecf96Smrg */
10125dfecf96Smrg{
10135dfecf96Smrg    return (LispStringCompare(builtin, CHAR_EQUAL, 0));
10145dfecf96Smrg}
10155dfecf96Smrg
10165dfecf96SmrgLispObj *
10175dfecf96SmrgLisp_StringLess(LispBuiltin *builtin)
10185dfecf96Smrg/*
10195dfecf96Smrg string< string1 string2 &key start1 end1 start2 end2
10205dfecf96Smrg */
10215dfecf96Smrg{
10225dfecf96Smrg    return (LispStringCompare(builtin, CHAR_LESS, 0));
10235dfecf96Smrg}
10245dfecf96Smrg
10255dfecf96SmrgLispObj *
10265dfecf96SmrgLisp_StringGreater(LispBuiltin *builtin)
10275dfecf96Smrg/*
10285dfecf96Smrg string> string1 string2 &key start1 end1 start2 end2
10295dfecf96Smrg */
10305dfecf96Smrg{
10315dfecf96Smrg    return (LispStringCompare(builtin, CHAR_GREATER, 0));
10325dfecf96Smrg}
10335dfecf96Smrg
10345dfecf96SmrgLispObj *
10355dfecf96SmrgLisp_StringLessEqual(LispBuiltin *builtin)
10365dfecf96Smrg/*
10375dfecf96Smrg string<= string1 string2 &key start1 end1 start2 end2
10385dfecf96Smrg */
10395dfecf96Smrg{
10405dfecf96Smrg    return (LispStringCompare(builtin, CHAR_LESS_EQUAL, 0));
10415dfecf96Smrg}
10425dfecf96Smrg
10435dfecf96SmrgLispObj *
10445dfecf96SmrgLisp_StringGreaterEqual(LispBuiltin *builtin)
10455dfecf96Smrg/*
10465dfecf96Smrg string>= string1 string2 &key start1 end1 start2 end2
10475dfecf96Smrg */
10485dfecf96Smrg{
10495dfecf96Smrg    return (LispStringCompare(builtin, CHAR_GREATER_EQUAL, 0));
10505dfecf96Smrg}
10515dfecf96Smrg
10525dfecf96SmrgLispObj *
10535dfecf96SmrgLisp_StringNotEqual_(LispBuiltin *builtin)
10545dfecf96Smrg/*
10555dfecf96Smrg string/= string1 string2 &key start1 end1 start2 end2
10565dfecf96Smrg */
10575dfecf96Smrg{
10585dfecf96Smrg    return (LispStringCompare(builtin, CHAR_NOT_EQUAL, 0));
10595dfecf96Smrg}
10605dfecf96Smrg
10615dfecf96SmrgLispObj *
10625dfecf96SmrgLisp_StringEqual(LispBuiltin *builtin)
10635dfecf96Smrg/*
10645dfecf96Smrg string-equal string1 string2 &key start1 end1 start2 end2
10655dfecf96Smrg */
10665dfecf96Smrg{
10675dfecf96Smrg    return (LispStringCompare(builtin, CHAR_EQUAL, 1));
10685dfecf96Smrg}
10695dfecf96Smrg
10705dfecf96SmrgLispObj *
10715dfecf96SmrgLisp_StringLessp(LispBuiltin *builtin)
10725dfecf96Smrg/*
10735dfecf96Smrg string-lessp string1 string2 &key start1 end1 start2 end2
10745dfecf96Smrg */
10755dfecf96Smrg{
10765dfecf96Smrg    return (LispStringCompare(builtin, CHAR_LESS, 1));
10775dfecf96Smrg}
10785dfecf96Smrg
10795dfecf96SmrgLispObj *
10805dfecf96SmrgLisp_StringGreaterp(LispBuiltin *builtin)
10815dfecf96Smrg/*
10825dfecf96Smrg string-greaterp string1 string2 &key start1 end1 start2 end2
10835dfecf96Smrg */
10845dfecf96Smrg{
10855dfecf96Smrg    return (LispStringCompare(builtin, CHAR_GREATER, 1));
10865dfecf96Smrg}
10875dfecf96Smrg
10885dfecf96SmrgLispObj *
10895dfecf96SmrgLisp_StringNotGreaterp(LispBuiltin *builtin)
10905dfecf96Smrg/*
10915dfecf96Smrg string-not-greaterp string1 string2 &key start1 end1 start2 end2
10925dfecf96Smrg */
10935dfecf96Smrg{
10945dfecf96Smrg    return (LispStringCompare(builtin, CHAR_LESS_EQUAL, 1));
10955dfecf96Smrg}
10965dfecf96Smrg
10975dfecf96SmrgLispObj *
10985dfecf96SmrgLisp_StringNotLessp(LispBuiltin *builtin)
10995dfecf96Smrg/*
11005dfecf96Smrg string-not-lessp string1 string2 &key start1 end1 start2 end2
11015dfecf96Smrg */
11025dfecf96Smrg{
11035dfecf96Smrg    return (LispStringCompare(builtin, CHAR_GREATER_EQUAL, 1));
11045dfecf96Smrg}
11055dfecf96Smrg
11065dfecf96SmrgLispObj *
11075dfecf96SmrgLisp_StringNotEqual(LispBuiltin *builtin)
11085dfecf96Smrg/*
11095dfecf96Smrg string-not-equal string1 string2 &key start1 end1 start2 end2
11105dfecf96Smrg */
11115dfecf96Smrg{
11125dfecf96Smrg    return (LispStringCompare(builtin, CHAR_NOT_EQUAL, 1));
11135dfecf96Smrg}
11145dfecf96Smrg
11155dfecf96SmrgLispObj *
11165dfecf96SmrgLispStringUpcase(LispBuiltin *builtin, int inplace)
11175dfecf96Smrg/*
11185dfecf96Smrg string-upcase string &key start end
11195dfecf96Smrg nstring-upcase string &key start end
11205dfecf96Smrg */
11215dfecf96Smrg{
11225dfecf96Smrg    LispObj *result;
11235dfecf96Smrg    char *string, *newstring;
11245dfecf96Smrg    long start, end, length, offset;
11255dfecf96Smrg
11265dfecf96Smrg    LispObj *ostring, *ostart, *oend;
11275dfecf96Smrg
11285dfecf96Smrg    oend = ARGUMENT(2);
11295dfecf96Smrg    ostart = ARGUMENT(1);
11305dfecf96Smrg    ostring = ARGUMENT(0);
11315dfecf96Smrg    CHECK_STRING(ostring);
11325dfecf96Smrg    LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
11335dfecf96Smrg			      &start, &end, &offset);
11345dfecf96Smrg    result = ostring;
11355dfecf96Smrg    string = THESTR(ostring);
11365dfecf96Smrg    length = STRLEN(ostring);
11375dfecf96Smrg
11385dfecf96Smrg    /* first check if something need to be done */
11395dfecf96Smrg    for (offset = start; offset < end; offset++)
11405dfecf96Smrg	if (string[offset] != toupper(string[offset]))
11415dfecf96Smrg	    break;
11425dfecf96Smrg
11435dfecf96Smrg    if (offset >= end)
11445dfecf96Smrg	return (result);
11455dfecf96Smrg
11465dfecf96Smrg    if (inplace) {
11475dfecf96Smrg	CHECK_STRING_WRITABLE(ostring);
11485dfecf96Smrg	newstring = string;
11495dfecf96Smrg    }
11505dfecf96Smrg    else {
11515dfecf96Smrg	/* upcase a copy of argument */
11525dfecf96Smrg	newstring = LispMalloc(length + 1);
11535dfecf96Smrg	if (offset)
11545dfecf96Smrg	    memcpy(newstring, string, offset);
11555dfecf96Smrg	if (length > end)
11565dfecf96Smrg	    memcpy(newstring + end, string + end, length - end);
11575dfecf96Smrg	newstring[length] = '\0';
11585dfecf96Smrg    }
11595dfecf96Smrg
11605dfecf96Smrg    for (; offset < end; offset++)
11615dfecf96Smrg	newstring[offset] = toupper(string[offset]);
11625dfecf96Smrg
11635dfecf96Smrg    if (!inplace)
11645dfecf96Smrg	result = LSTRING2(newstring, length);
11655dfecf96Smrg
11665dfecf96Smrg    return (result);
11675dfecf96Smrg}
11685dfecf96Smrg
11695dfecf96SmrgLispObj *
11705dfecf96SmrgLisp_StringUpcase(LispBuiltin *builtin)
11715dfecf96Smrg/*
11725dfecf96Smrg string-upcase string &key start end
11735dfecf96Smrg */
11745dfecf96Smrg{
11755dfecf96Smrg    return (LispStringUpcase(builtin, 0));
11765dfecf96Smrg}
11775dfecf96Smrg
11785dfecf96SmrgLispObj *
11795dfecf96SmrgLisp_NstringUpcase(LispBuiltin *builtin)
11805dfecf96Smrg/*
11815dfecf96Smrg nstring-upcase string &key start end
11825dfecf96Smrg */
11835dfecf96Smrg{
11845dfecf96Smrg    return (LispStringUpcase(builtin, 1));
11855dfecf96Smrg}
11865dfecf96Smrg
11875dfecf96SmrgLispObj *
11885dfecf96SmrgLispStringDowncase(LispBuiltin *builtin, int inplace)
11895dfecf96Smrg/*
11905dfecf96Smrg string-downcase string &key start end
11915dfecf96Smrg nstring-downcase string &key start end
11925dfecf96Smrg */
11935dfecf96Smrg{
11945dfecf96Smrg    LispObj *result;
11955dfecf96Smrg    char *string, *newstring;
11965dfecf96Smrg    long start, end, length, offset;
11975dfecf96Smrg
11985dfecf96Smrg    LispObj *ostring, *ostart, *oend;
11995dfecf96Smrg
12005dfecf96Smrg    oend = ARGUMENT(2);
12015dfecf96Smrg    ostart = ARGUMENT(1);
12025dfecf96Smrg    ostring = ARGUMENT(0);
12035dfecf96Smrg    CHECK_STRING(ostring);
12045dfecf96Smrg    LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
12055dfecf96Smrg			      &start, &end, &offset);
12065dfecf96Smrg    result = ostring;
12075dfecf96Smrg    string = THESTR(ostring);
12085dfecf96Smrg    length = STRLEN(ostring);
12095dfecf96Smrg
12105dfecf96Smrg    /* first check if something need to be done */
12115dfecf96Smrg    for (offset = start; offset < end; offset++)
12125dfecf96Smrg	if (string[offset] != tolower(string[offset]))
12135dfecf96Smrg	    break;
12145dfecf96Smrg
12155dfecf96Smrg    if (offset >= end)
12165dfecf96Smrg	return (result);
12175dfecf96Smrg
12185dfecf96Smrg    if (inplace) {
12195dfecf96Smrg	CHECK_STRING_WRITABLE(ostring);
12205dfecf96Smrg	newstring = string;
12215dfecf96Smrg    }
12225dfecf96Smrg    else {
12235dfecf96Smrg	/* downcase a copy of argument */
12245dfecf96Smrg	newstring = LispMalloc(length + 1);
12255dfecf96Smrg	if (offset)
12265dfecf96Smrg	    memcpy(newstring, string, offset);
12275dfecf96Smrg	if (length > end)
12285dfecf96Smrg	    memcpy(newstring + end, string + end, length - end);
12295dfecf96Smrg	newstring[length] = '\0';
12305dfecf96Smrg    }
12315dfecf96Smrg    for (; offset < end; offset++)
12325dfecf96Smrg	newstring[offset] = tolower(string[offset]);
12335dfecf96Smrg
12345dfecf96Smrg    if (!inplace)
12355dfecf96Smrg	result = LSTRING2(newstring, length);
12365dfecf96Smrg
12375dfecf96Smrg    return (result);
12385dfecf96Smrg}
12395dfecf96Smrg
12405dfecf96SmrgLispObj *
12415dfecf96SmrgLisp_StringDowncase(LispBuiltin *builtin)
12425dfecf96Smrg/*
12435dfecf96Smrg string-downcase string &key start end
12445dfecf96Smrg */
12455dfecf96Smrg{
12465dfecf96Smrg    return (LispStringDowncase(builtin, 0));
12475dfecf96Smrg}
12485dfecf96Smrg
12495dfecf96SmrgLispObj *
12505dfecf96SmrgLisp_NstringDowncase(LispBuiltin *builtin)
12515dfecf96Smrg/*
12525dfecf96Smrg nstring-downcase string &key start end
12535dfecf96Smrg */
12545dfecf96Smrg{
12555dfecf96Smrg    return (LispStringDowncase(builtin, 1));
12565dfecf96Smrg}
12575dfecf96Smrg
12585dfecf96SmrgLispObj *
12595dfecf96SmrgLispStringCapitalize(LispBuiltin *builtin, int inplace)
12605dfecf96Smrg/*
12615dfecf96Smrg string-capitalize string &key start end
12625dfecf96Smrg nstring-capitalize string &key start end
12635dfecf96Smrg */
12645dfecf96Smrg{
12655dfecf96Smrg    LispObj *result;
12665dfecf96Smrg    char *string, *newstring;
12675dfecf96Smrg    long start, end, length, offset, upcase;
12685dfecf96Smrg
12695dfecf96Smrg    LispObj *ostring, *ostart, *oend;
12705dfecf96Smrg
12715dfecf96Smrg    oend = ARGUMENT(2);
12725dfecf96Smrg    ostart = ARGUMENT(1);
12735dfecf96Smrg    ostring = ARGUMENT(0);
12745dfecf96Smrg    CHECK_STRING(ostring);
12755dfecf96Smrg    LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
12765dfecf96Smrg			      &start, &end, &offset);
12775dfecf96Smrg    result = ostring;
12785dfecf96Smrg    string = THESTR(ostring);
12795dfecf96Smrg    length = STRLEN(ostring);
12805dfecf96Smrg
12815dfecf96Smrg    /* first check if something need to be done */
12825dfecf96Smrg    for (upcase = 1, offset = start; offset < end; offset++) {
12835dfecf96Smrg	if (upcase) {
12845dfecf96Smrg	    if (!isalnum(string[offset]))
12855dfecf96Smrg		continue;
12865dfecf96Smrg	    if (string[offset] != toupper(string[offset]))
12875dfecf96Smrg		break;
12885dfecf96Smrg	    upcase = 0;
12895dfecf96Smrg	}
12905dfecf96Smrg	else {
12915dfecf96Smrg	    if (isalnum(string[offset])) {
12925dfecf96Smrg		if (string[offset] != tolower(string[offset]))
12935dfecf96Smrg		    break;
12945dfecf96Smrg	    }
12955dfecf96Smrg	    else
12965dfecf96Smrg		upcase = 1;
12975dfecf96Smrg	}
12985dfecf96Smrg    }
12995dfecf96Smrg
13005dfecf96Smrg    if (offset >= end)
13015dfecf96Smrg	return (result);
13025dfecf96Smrg
13035dfecf96Smrg    if (inplace) {
13045dfecf96Smrg	CHECK_STRING_WRITABLE(ostring);
13055dfecf96Smrg	newstring = string;
13065dfecf96Smrg    }
13075dfecf96Smrg    else {
13085dfecf96Smrg	/* capitalize a copy of argument */
13095dfecf96Smrg	newstring = LispMalloc(length + 1);
13105dfecf96Smrg	memcpy(newstring, string, length);
13115dfecf96Smrg	newstring[length] = '\0';
13125dfecf96Smrg    }
13135dfecf96Smrg    for (; offset < end; offset++) {
13145dfecf96Smrg	if (upcase) {
13155dfecf96Smrg	    if (!isalnum(string[offset]))
13165dfecf96Smrg		continue;
13175dfecf96Smrg	    newstring[offset] = toupper(string[offset]);
13185dfecf96Smrg	    upcase = 0;
13195dfecf96Smrg	}
13205dfecf96Smrg	else {
13215dfecf96Smrg	    if (isalnum(newstring[offset]))
13225dfecf96Smrg		newstring[offset] = tolower(string[offset]);
13235dfecf96Smrg	    else
13245dfecf96Smrg		upcase = 1;
13255dfecf96Smrg	}
13265dfecf96Smrg    }
13275dfecf96Smrg
13285dfecf96Smrg    if (!inplace)
13295dfecf96Smrg	result = LSTRING2(newstring, length);
13305dfecf96Smrg
13315dfecf96Smrg    return (result);
13325dfecf96Smrg}
13335dfecf96Smrg
13345dfecf96SmrgLispObj *
13355dfecf96SmrgLisp_StringCapitalize(LispBuiltin *builtin)
13365dfecf96Smrg/*
13375dfecf96Smrg string-capitalize string &key start end
13385dfecf96Smrg */
13395dfecf96Smrg{
13405dfecf96Smrg    return (LispStringCapitalize(builtin, 0));
13415dfecf96Smrg}
13425dfecf96Smrg
13435dfecf96SmrgLispObj *
13445dfecf96SmrgLisp_NstringCapitalize(LispBuiltin *builtin)
13455dfecf96Smrg/*
13465dfecf96Smrg nstring-capitalize string &key start end
13475dfecf96Smrg */
13485dfecf96Smrg{
13495dfecf96Smrg    return (LispStringCapitalize(builtin, 1));
13505dfecf96Smrg}
13515dfecf96Smrg
13525dfecf96SmrgLispObj *
13535dfecf96SmrgLisp_StringConcat(LispBuiltin *builtin)
13545dfecf96Smrg/*
13555dfecf96Smrg string-concat &rest strings
13565dfecf96Smrg */
13575dfecf96Smrg{
13585dfecf96Smrg    char *buffer;
13595dfecf96Smrg    long size, length;
13605dfecf96Smrg    LispObj *object, *string;
13615dfecf96Smrg
13625dfecf96Smrg    LispObj *strings;
13635dfecf96Smrg
13645dfecf96Smrg    strings = ARGUMENT(0);
13655dfecf96Smrg
13665dfecf96Smrg    if (strings == NIL)
13675dfecf96Smrg	return (STRING(""));
13685dfecf96Smrg
13695dfecf96Smrg    for (length = 1, object = strings; CONSP(object); object = CDR(object)) {
13705dfecf96Smrg	string = CAR(object);
13715dfecf96Smrg	CHECK_STRING(string);
13725dfecf96Smrg	length += STRLEN(string);
13735dfecf96Smrg    }
13745dfecf96Smrg
13755dfecf96Smrg    buffer = LispMalloc(length);
13765dfecf96Smrg
13775dfecf96Smrg    for (length = 0, object = strings; CONSP(object); object = CDR(object)) {
13785dfecf96Smrg	string = CAR(object);
13795dfecf96Smrg	size = STRLEN(string);
13805dfecf96Smrg	memcpy(buffer + length, THESTR(string), size);
13815dfecf96Smrg	length += size;
13825dfecf96Smrg    }
13835dfecf96Smrg    buffer[length] = '\0';
13845dfecf96Smrg    object = LSTRING2(buffer, length);
13855dfecf96Smrg
13865dfecf96Smrg    return (object);
13875dfecf96Smrg}
1388