/* Copyright 1989-93 GROUPE BULL -- See license conditions in file COPYRIGHT */
/**************\
* *
* KlO String *
* BODY *
* *
\**************/
#include "EXTERN.h"
#include <ctype.h>
#include "klone.h"
#include "kl_number.h"
#include "kl_atom.h"
#include "kl_list.h"
#include "klgeneric.h"
#include "INTERN.h"
#include "kl_string.h"
char *KlReComp();
char *KlUnstripString(), *KlStripString();
static char *strings_temp_buffer;
static int strings_temp_buffer_size = 0;
static char *control_caret = "\x1e";
static char *quote_string = "\"";
static int KlUnstripStringLength; /* set by KlUnstripString */
extern KlO KlStringHash();
DECLARE_strchr;
/*
* Constructor:
* KlStringMake
* argument 1: the string, which will be COPIED.
*/
KlString
KlStringMake(s)
char *s; /* the string itself */
{
KlString object;
object = (KlString) KlOMake(KlStringType);
if (s) {
object->size = strlen(s);
object->string = (char *) Malloc((size_t) object->size + 1);
strcpy(object->string, s);
} else {
KlModStringSetLength(object, 0);
object->string = (char *) Malloc((size_t) 1);
object->string[0] = '\0';
}
return object;
}
/*
* Constructor:
* KlStringMakeFromBytes
* argument 1: the length of the string
* argument 2: the string, which will be COPIED.
*/
KlString
KlStringMakeFromBytes(l, s)
int l;
char *s; /* the string itself */
{
KlString object;
object = (KlString) KlOMake(KlStringType);
object->string = (char *) Malloc((size_t) l+1);
bcopy(s, object->string, l);
object->string[l] = '\0';
KlModStringSetLength(object, l);
return object;
}
/*
* Constructor:
* KlStringMakeNoCopy
* argument 1: the length of the string
* argument 2: the string, which will NOT be copied, and be freed by Klone GC
*/
KlString
KlStringMakeNoCopy(l, s)
int l;
char *s; /* the string itself */
{
KlString object;
object = (KlString) KlOMake(KlStringType);
object->string = s;
object->size = l;
return object;
}
/* KlStringNMake
* allocates a string with room for n chars (allocates one more for the
* terminating null byte)
* WARNING: do not forget to put a \0 yourself at the end after filling it!
*/
KlString
KlStringNMake(n)
int n;
{
KlString object = (KlString) KlOMake(KlStringType);
KlModStringSetLength(object, n);
object->string = (char *) Malloc((size_t) n + 1);
return object;
}
/* KlStringNMakeKl
* create a string from Klone, very useful
* (make-string number-of-chars [char])
* returns a string made of number-of-chars chars (defaults to space)
* (make-string 5 #\x) ==> "xxxxx"
*/
KlO
KlStringNMakeKl(argc, argv)
int argc;
KlNumber *argv;
{
int size;
KlString obj;
int fill_char = ' ';
if (argc == 2) {
KlMustBeNumber(argv[1], 1);
fill_char = argv[1]->number;
} else if (argc != 1) {
return KlBadNumberOfArguments((char *) argc);
}
KlMustBeNumber(argv[0], 0);
if ((size = argv[0]->number) > 0) {
obj = KlStringNMake(size);
KlMemSet(obj->string, fill_char, size);
obj->string[size] = '\0';
} else {
obj = KlStringMake(0);
}
return (KlO) obj;
}
/* KlCStringPrint is like KlStringPrint, but for C strings
* obeys KlPrintReadably et al...
*/
KlCStringPrint(len, string, stream)
int len;
char *string;
KlO stream;
{
if (KlPrintReadably) {
if (KlPrintAsRawStrings
&& KlStringIsRawPrintable(len, string)) {
KlSPutBytes(1, control_caret, stream);
KlSPutBytes(len, string, stream);
KlSPutBytes(1, control_caret, stream);
} else {
KlSPutBytes(1, quote_string, stream);
KlSPuts(KlUnstripString(len, string), stream);
KlSPutBytes(1, quote_string, stream);
}
} else {
if (KlPrintBinary) {
KlSPrintf(stream, "\001 \002%d\002", len);
}
KlSPutBytes(len, string, stream);
}
}
/*
* KlStringPrint:
* We print strings surrounded by double quotes.
*/
KlO
KlStringPrint(obj, stream)
KlString obj;
KlO stream;
{
KlCStringPrint(obj->size, obj->string, stream);
return (KlO) obj;
}
int
KlStringIsRawPrintable(size, string)
int size;
char *string;
{
char *end = string + size;
while (string < end)
if (*string++ == 30)
return 0;
return 1;
}
/* KlStringFree
*/
KlO
KlStringFree(obj)
KlString obj;
{
Free(obj->string);
Free(obj);
return (KlO) obj;
}
/* KlStringCopy
*/
KlO
KlStringCopy(obj)
KlString obj;
{
return (KlO) KlStringMakeFromBytes(KlModStringLength(obj), obj->string);
}
/*
* KlStringEqual
* tests 2 strings for equality (returns it if true)
*/
KlO
KlStringEqual(s1, s2)
KlString s1, s2;
{
if (!KlIsAString(s2)
|| s1->size != KlStringLength(s2)
|| KlIsASymbol(s2)
|| bcmp(s1->string, s2->string, s1->size))
return NIL;
else
return (KlO) s1;
}
KlO
KlStringLengthKl(s)
KlString s;
{
return (KlO) KlNumberMake(KlModStringLength(s));
}
/*********\
* *
* methods *
* *
\*********/
/* KlStringAdd
* concatenates strings
* tolerates nils (ignored) and numbers whose printed representations are used.
*/
KlO
KlStringAdd(argc, argv)
int argc;
KlString argv[];
{
int required_length = KlStringLength(argv[0]), i;
char *p;
/* check args & needed length */
for (i = 1; i < argc; i++) {
if (KlIsAString(argv[i]))
required_length += KlStringLength(argv[i]);
else if (KlFalseP(argv[i]))
;
else if (KlIsANumber(argv[i]))
required_length +=
KlStringLength(KlStringCoerce(KlStringType, argv[i]));
else
KlBadArgument(argv[i], i, KlTraitName(KlTrait_string));
}
/* verify we have room in temp space */
if (required_length >= strings_temp_buffer_size) {
if (!strings_temp_buffer) {
strings_temp_buffer = (char *)
Malloc(strings_temp_buffer_size = Max(required_length + 1, 256));
} else {
strings_temp_buffer_size = required_length + 1;
strings_temp_buffer = (char *)
Realloc(strings_temp_buffer, strings_temp_buffer_size);
}
}
/* do the concatenation */
strings_temp_buffer[0] = '\0';
for (i = 0, p = strings_temp_buffer; i < argc; i++) {
int l;
KlString kls = argv[i];
if (KlIsAString(kls))
;
else if (KlIsANumber(kls))
kls = (KlString) KlStringCoerce(KlStringType, argv[i]);
else
kls = KlNilString;
bcopy(kls->string, p, l = KlStringLength(kls));
p += l;
}
return (KlO) KlStringMakeFromBytes(required_length, strings_temp_buffer);
}
/* KlStringStrcat
* concatenates a C string at the end of a Klone one
* WARNING: Cstring must not contain null bytes (it is a C string...)
*/
KlString
KlStringStrcat(string, Cstring)
KlString string;
char *Cstring;
{
int required_length = KlModStringLength(string) + strlen(Cstring);
if (KlHasTrait(string, KlTrait_unreallocable)) {
return (KlString) KlError(KlE_NO_APPEND, string);
}
string->string = (char *) Realloc(string->string, required_length + 1);
/* do the concatenation */
strcat(string->string, Cstring);
KlModStringSetLength(string, required_length);
return string;
}
/* KlStringGet
* get a char at an index
*/
KlO
KlStringGet(obj, key, def)
KlUString obj;
KlNumber key;
KlO def;
{
int i, l;
if (KlIsANumber(key)) { /* array */
i = key->number;
l = KlStringLength(obj);
if (i < l) {
if (i < 0) {
if (l) {
i = l - 1;
} else {
return KlExecuteGetDefault(obj, key, def);
}
}
return (KlO) KlNumberMake(obj->string[i]);
} else {
return KlExecuteGetDefault(obj, key, def);
}
} else {
KlMustBeNumber(key, 1); /* expansion? */
return KlExecuteGetDefault(obj, key, def);
}
}
/* KlStringPut
* puts a char at an index
*/
KlO
KlStringPut(obj, key, val)
KlUString obj;
KlNumber key;
KlNumber val;
{
int i, l;
if (KlIsANumber(key)) { /* array */
i = key->number;
l = KlModStringLength(obj);
if (i < 0) { /* <0 means append to end */
i = l;
}
if (KlIsANumber(val)) {
if (i < l) {
obj->string[i] = val->number;
return (KlO) obj;
} else {
if (KlHasTrait(obj, KlTrait_unreallocable)) {
return KlError(KlE_NO_APPEND, obj);
}
obj->string = (unsigned char *) Realloc(obj->string, i + 2);
KlModStringSetLength(obj, i+1);
KlMemSet(obj->string + l, ' ', i - l);
obj->string[i] = val->number;
obj->string[i + 1] = '\0';
}
} else {
int inserted_len;
KlMustBeString(val, 2);
inserted_len = KlStringLength(val);
if ((i + inserted_len) > l) {
if (KlHasTrait(obj, KlTrait_unreallocable)) {
return KlError(KlE_NO_APPEND, obj);
}
obj->string = (unsigned char *) Realloc(obj->string,
i + inserted_len + 1);
obj->string[i + inserted_len] = '\0';
KlModStringSetLength(obj, i + inserted_len);
if (i > l) /* fill with blanks */
KlMemSet(obj->string + l, ' ', i - l);
}
bcopy(((KlString)val)->string, obj->string + i, inserted_len);
}
} else {
KlMustBeNumber(key, 1);
}
return (KlO) obj;
}
/* KlStringInsert
* puts a char at an index
*/
KlO
KlStringInsert(obj, key, val)
KlUString obj;
KlNumber key;
KlNumber val;
{
int i, l;
unsigned char *p, *q, *start;
int inserted_len;
if (KlHasTrait(obj, KlTrait_unreallocable)) {
return KlError(KlE_NO_APPEND, obj);
}
KlMustBeNumber(key, 1);
if (KlIsANumber(val)) {
inserted_len = 1;
} else {
KlMustBeString(val, 2);
inserted_len = KlStringLength(val);
}
i = key->number;
l = KlModStringLength(obj);
if (i < 0 || i >= l) { /* after end = Put */
return KlStringPut(obj, key, val);
}
obj->string = (unsigned char *) Realloc(obj->string, l + inserted_len + 1);
KlModStringSetLength(obj, l + inserted_len);
start = obj->string + i;
p = obj->string + l;
q = p + inserted_len;
while (p >= start) {
*q-- = *p--;
}
if (KlIsANumber(val)) {
obj->string[i] = val->number;
} else {
bcopy(((KlString) val)->string, obj->string + i, inserted_len);
}
return (KlO) obj;
}
/* KlStringDelete
* deletes char at an index
*/
KlO
KlStringDelete(obj, key)
KlUString obj;
KlNumber key;
{
int i, l;
unsigned char *p, *end;
if (!obj->string) {
return (KlO) obj;
}
if (KlIsANumber(key)) { /* array */
i = key->number;
l = KlModStringLength(obj);
if (i < 0) {
i = (l ? l - 1 : 0);
}
p = obj->string + i;
end = obj->string + l;
while (p < end) {
*p = *(p+1);
p++;
}
if (l && i < l && !KlIsASymbol(obj))
obj->size--;
} else {
KlMustBeNumber(key, 1);
}
return (KlO) obj;
}
/* KlStringCoerce
* number ==> does a printf into a string
*/
/*ARGSUSED*/
KlO
KlStringCoerce(totype, obj)
KlType totype;
KlO obj;
{
char tmp_str[20];
if (KlIsASymbol(obj)) {
return (KlO) KlStringMake(((KlString) obj)->string);
} else if (KlIsANumber(obj)) {
if (KlIsAReal(obj)) {
sprintf(tmp_str, "%g", ((KlReal) obj)->real);
if (!strchr(tmp_str, '.') && !strchr(tmp_str, 'e')) {
strcat(tmp_str, ".0"); /* adds a dot to show it is a real */
}
} else {
sprintf(tmp_str, "%d", ((KlNumber) obj)->number);
}
return (KlO) KlStringMake(tmp_str);
} else if (KlIsAList(obj)) {
int l = ((KlList) obj)->size;
KlO *q = ((KlList) obj)->list, *last = q + l;
KlString s = (KlString) KlStringNMake(l);
char *p = s->string;
int i;
while (q < last) {
KlMustBeNumber(*q, q - ((KlList) obj)->list);
*p++ = ((KlNumber) *q++)->number;
}
*p = '\0';
return (KlO) s;
} else if (KlIsAType(obj)) {
return (KlO) KlStringMake(KlTypeCName(((KlType)obj)));
}
return 0;
}
KlO
KlStringNth(obj, i, value)
KlUString obj;
UInt i;
KlNumber value;
{
if (i >= KlModStringLength(obj))
return NIL;
if (value) {
obj->string[i] = value->number;
return (KlO) obj;
} else {
return (KlO) KlNumberMake(obj->string[i]);
}
}
int
KlStringCompare(o1, o2)
KlString o1, o2;
{
if (o1 == o2) return 0;/* shortcut */
KlMustBeString(o2, 1);
return strcmp(o1->string, o2->string);
}
KlStringDolist(string, var, argc, argv)
KlString string;
KlO var;
int argc;
KlO *argv;
{
KlGCMark();
if (KlIsASymbol(string)) { /* no null chars embedded,
and not modifiable */
unsigned char *p = (unsigned char *) string->string;
while (*p) {
KlSend_setq(var, KlNumberMake(*p));
KlProgn(argc, argv);
KlGC();
p++;
}
} else {
int i;
for (i = 0; i < string->size; i++) {
KlSend_setq(var, KlNumberMake(((KlUString) string)->string[i]));
KlProgn(argc, argv);
KlGC();
}
}
}
/**************************************************************************\
* *
* the general match package *
* (match regular-expression string [level]) *
* returns the sub-string in the levelth enclosing \( and \) or NIL_STRING *
* or string or NIL if no level given *
* *
\**************************************************************************/
/* uses Henry Spencer's REGEXP package
*/
#include "klregexp.h"
/********************************************* private data type definitions */
typedef struct _KlRegexp {
KlKLONE_HEADER;
char *string; /* printable form, string compatible */
int size;
regexp *prog;
KlString matched_string; /* last regexec-ed string */
} *KlRegexp;
KlRegexp KlRegcomp();
KlO KlRegexec();
KlString KlRegsub();
KlType KlRegexpType;
#define KlIsARegexp(obj) ((obj)->type == KlRegexpType)
#define KlMustBeRegexp(o, n) KlArgumentMustBe(o, n, KlRegexpType)
/********************************************************************** body */
/* type management
*/
KlRegexp
KlRegexpMake(expr)
char *expr;
{
KlRegexp object;
regexp *prog = Klregcomp(expr);
object = (KlRegexp) KlOMake(KlRegexpType);
object->prog = prog;
object->size = strlen(expr);
object->string = (char *) Malloc(object->size + 1);
object->matched_string = 0;
strcpy(object->string, expr);
return (KlRegexp) object;
}
KlRegexpProgFree(prog)
regexp *prog;
{
free(prog->startp); /* lowercase free intentional */
if (prog->o_parnums) {
free(prog->o_parnums);
free(prog->c_parnums);
}
free(prog); /* lowercase free intentional */
}
KlO
KlRegexpFree(obj)
KlRegexp obj;
{
Free(obj->string);
KlDecRef(obj->matched_string);
KlRegexpProgFree(obj->prog);
Free(obj);
return (KlO) obj;
}
/* get: get the offsets of the N-th matched sub-expression
* (0 is the whole regexp, -1 is the last string matched to)
*/
KlO
KlRegexpGet(obj, key, def)
KlRegexp obj;
KlNumber key;
KlO def;
{
int offset;
if (KlIsANumber(key)) {
offset = key->number;
if (offset >= 0 && offset < obj->prog->nsubexp && obj->matched_string
&& (obj->prog->startp[offset] || obj->prog->endp[offset])) {
KlList result = KlListNMake(2);
KlListStore(result, 0, KlNumberMake(obj->prog->startp[offset]
- obj->matched_string->string));
KlListStore(result, 1, KlNumberMake(obj->prog->endp[offset]
- obj->matched_string->string));
return (KlO) result;
} else if (offset == -1) {
return obj->matched_string ? (KlO) obj->matched_string : NIL;
} else {
return KlExecuteGetDefault(obj, key, def);
}
} else if (key == (KlNumber) KlA_depth) {
return (KlO) KlNumberMake(obj->prog->nsubexp - 1);
} else {
KlMustBeNumber(key, 1);
}
}
/* regcomp
*/
KlRegexp
KlRegcomp(expr)
KlString expr;
{
KlMustBeString(expr, 0);
return KlRegexpMake(expr->string);
}
/* regexec
* regexec regexp source [source-offset]
*/
KlO
KlRegexec(argc, argv)
int argc;
KlString *argv;
{
int offset;
switch (argc) {
case 2:
offset = 0;
break;
case 3:
KlMustBeNumber(argv[2], 2);
offset = ((KlNumber)argv[2])->number;
if (offset < 0) offset = 0;
break;
default:
return KlBadNumberOfArguments(argc);
}
KlMustBeRegexp(argv[0], 0);
KlMustBeString(argv[1], 1);
KlDecRef(((KlRegexp)argv[0])->matched_string);
if (offset > KlStringLength(argv[1]))
offset = KlStringLength(argv[1]);
return Klregexec(((KlRegexp)argv[0])->prog, argv[1]->string + offset)
? (KlIncRef(((KlRegexp)argv[0])->matched_string = argv[1]), TRU)
: (((KlRegexp)argv[0])->matched_string = 0, NIL);
}
/* KlRegsub
* KlRegsub regexp source [source-offset]
*/
KlString
KlRegsub(argc, argv)
int argc;
KlString *argv;
{
int offset;
char *dest;
KlString result;
switch (argc) {
case 2:
offset = 0;
break;
case 3:
KlMustBeNumber(argv[2], 2);
offset = ((KlNumber)argv[2])->number;
break;
default:
return (KlString) KlBadNumberOfArguments(argc);
}
KlMustBeRegexp(argv[0], 0);
if (KlIsANumber(argv[1])) { /* just copy bytes */
int no = ((KlNumber) argv[1])->number;
KlRegexp obj = (KlRegexp) argv[0];
if (no >= 0 && no < obj->prog->nsubexp && obj->matched_string
&& (obj->prog->startp[no] || obj->prog->endp[no])) {
return KlStringMakeFromBytes
(obj->prog->endp[no] - obj->prog->startp[no],
obj->prog->startp[no]);
} else if (no == -1) { /* whole matched string */
return obj->matched_string ? obj->matched_string : KlStringMake(0);
} else {
return (KlString) KlStringMake(0);
}
} else { /* expands bytes in string */
int size;
KlMustBeString(argv[1],1 );
if (offset > KlStringLength(argv[1]))
offset = KlStringLength(argv[1]);
dest = Kl_regsub(((KlRegexp)argv[0])->prog, argv[1]->string + offset,
&size);
return KlStringMakeNoCopy(size, dest); /* no need to copy */
}
}
/* A shorthand: we can execute regexp, which means regexec or regsub
* if arg is string or number
* (regexp string [offset]) ==> (regexec regexp string [offset])
* (regexp number [offset]) ==> (regsub regexp number [offset])
*/
KlO
KlRegexpExecuteOrApply(obj, list, eval)
KlRegexp obj;
KlList list; /* the call list */
int eval; /* must we eval args? */
{
KlO arg = list->list[1];
KlNumber kloffset;
int offset;
switch (list->size) {
case 2: /* no offset */
offset = 0;
break;
case 3:
kloffset = (KlNumber)
(eval ? KlSend_eval(list->list[2]) : list->list[2]);
KlMustBeNumber(kloffset, 2);
offset = kloffset->number;
if (offset < 0) offset = 0;
break;
default:
return KlBadNumberOfArguments(list->size);
}
if (eval) {
arg = KlSend_eval(arg);
}
if (KlIsANumber(arg)) { /* code copied from regsub */
int no = ((KlNumber) arg)->number;
if (no >= 0 && no < obj->prog->nsubexp && obj->matched_string
&& (obj->prog->startp[no] || obj->prog->endp[no])) {
return (KlO) KlStringMakeFromBytes
(obj->prog->endp[no] - obj->prog->startp[no],
obj->prog->startp[no]);
} else if (no == -1) { /* whole matched string */
return obj->matched_string ?
(KlO) obj->matched_string : (KlO) KlStringMake(0);
} else {
return (KlO) KlStringMake(0);
}
} else if (KlIsAString(arg)) { /* code copied from regexec */
KlDecRef(obj->matched_string);
if (offset > KlStringLength(arg))
offset = KlStringLength(arg);
return (KlO) Klregexec(obj->prog, ((KlString)arg)->string + offset)
? (KlIncRef(obj->matched_string = (KlString) arg), TRU)
: (obj->matched_string = 0, NIL);
} else { /* unknown arg */
return KlBadArgument(arg, 0, KlTypeErr_StringOrNumber);
}
}
KlO
KlRegexpExecute(obj, list)
KlRegexp obj;
KlList list;
{
return KlRegexpExecuteOrApply(obj, list, 1);
}
KlO
KlRegexpApply(obj, list)
KlRegexp obj;
KlList list;
{
return KlRegexpExecuteOrApply(obj, list, 0);
}
/* match
* implemented with the preceding functions
*/
KlString
KlStringMatchAux(prog, offset)
regexp *prog;
int offset;
{
KlString str;
int len;
if (offset >= 0 && offset < prog->nsubexp
&& (prog->startp[offset] || prog->endp[offset])) {
len = prog->endp[offset] - prog->startp[offset];
str = KlStringNMake(len);
strncpy(str->string, prog->startp[offset], len);
} else {
len = 0;
str = KlStringNMake(0);
}
str->string[len] = '\0';
return str;
}
KlString
KlStringMatch(argc, argv)
int argc;
KlString argv[];
{
int i;
KlList kl_list;
regexp *prog;
int free_prog = 0;
if (argc < 2)
return (KlString) KlBadNumberOfArguments(argc);
if (KlIsARegexp(argv[0])) {
prog = ((KlRegexp) argv[0])->prog;
} else {
KlMustBeString(argv[0], 0);
/* compile reg. expr */
prog = Klregcomp(argv[0]->string);
free_prog = 1;
}
KlMustBeString(argv[1], 1);
if (Klregexec(prog, argv[1]->string)) {
switch (argc) {
case 2:
if (free_prog)
KlRegexpProgFree(prog);
return (KlString) argv[1];
case 3: {
KlString klstr;
KlMustBeNumber(argv[2], 2);
klstr = KlStringMatchAux(prog, ((KlNumber) argv[2])->number);
if (free_prog)
KlRegexpProgFree(prog);
return klstr;
}
default:
KlListNMakeZ(kl_list, argc - 2);
for (i = 2; i < argc; i++) {
KlMustBeNumber(argv[i], i);
KlListStore(kl_list, i - 2,
KlStringMatchAux(prog,
((KlNumber) argv[i])->number));
}
}
} else {
kl_list = (KlList) NIL;
}
if (free_prog)
KlRegexpProgFree(prog);
return (KlString) kl_list;
}
/* The error handler for regular expressions, called by regexp
* possible messages:
*
* for regexp:
*
* NULL parameter
* corrupted program
* memory corruption
* corrupted pointers
* internal foulup
* corrupted opcode
*
* for Kl_regsub:
*
* NULL parm to Kl_regsub
* damaged regexp fed to Kl_regsub
* damaged match string
*/
void
Kl_regerror(msg)
char *msg;
{
KlError1s(KlE_BAD_REGEXPR, msg);
}
/*
* modified version of Kl_regsub: (from Henry Spencer's Kl_regsub)
* returns dest which is malloced and expanded at will
* sets dest length into out parameter size
*/
#ifndef KLCHARBITS
#define UCHARAT(p) ((int)*(unsigned char *)(p))
#else
#define UCHARAT(p) ((int)*(p)&KLCHARBITS)
#endif
/*
- Kl_regsub - perform substitutions after a regexp match
*/
char *
Kl_regsub(prog, source, sizep)
regexp *prog;
char *source;
int *sizep; /* will be set to size of dest */
{
register char *src;
register char *dst;
register char c;
register int no;
register int len;
char *dest = (char *) Malloc(12);
char *lastdest = dest+11; /* last allowable - 1 */
if (prog == NULL || source == NULL) {
Kl_regerror("NULL parm to regsub");
/*NOTREACHED*/
}
if (UCHARAT(prog->program) != REGMAGIC) {
Kl_regerror("damaged regexp fed to regsub");
/*NOTREACHED*/
}
src = source;
dst = dest;
while ((c = *src++) != '\0') {
if (c == '&')
no = 0;
else if (c == '\\' && '0' <= *src && *src <= '9')
no = *src++ - '0';
else
no = -1;
if (no < 0) { /* Ordinary character. */
if (dst + 1 >= lastdest) {
char *olddest = dest;
int newlength = ((lastdest - dest) + 5) * 2 - 4;
dest = (char *) Realloc(dest, newlength);
lastdest = dest + (newlength - 1);
dst = dest + (dst - olddest);
}
*dst++ = c;
} else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
len = prog->endp[no] - prog->startp[no];
if (dst + len >= lastdest) {
char *olddest = dest;
int newlength = ((lastdest - dest) + 5) * 2 - 4;
while (newlength <= (dst - dest) + len)
newlength = ((newlength) + 5) * 2 - 4;
dest = (char *) Realloc(dest, newlength);
lastdest = dest + (newlength - 1);
dst = dest + (dst - olddest);
}
(void) strncpy(dst, prog->startp[no], len);
dst += len;
if (dst > dest && *(dst-1) == '\0') { /* strncpy hit NUL. */
Kl_regerror("damaged match string");
/*NOTREACHED*/
}
}
}
*sizep = (dst - dest);
*dst = '\0';
return dest;
}
#ifdef DEBUG
/* some debugging code from Klone */
extern int regnarrate;
extern void Klregdump();
KlO
KlRegdump(obj)
KlRegexp obj;
{
KlMustBeRegexp(obj, 0);
Klregdump(obj->prog);
return (KlO) obj;
}
#endif /* DEBUG */
/*****************************************************************************\
* string utils *
\*****************************************************************************/
/*
* KlUnstripString puts back \, ", etc... into string
* copies string raw_string to string stripped_string
* returns pointer to static storage
* Does not add the enclosing "
*/
static unsigned char *stripped_string;
static int stripped_string_limit;
#define KlUnstripStringMargin 6
char *
KlUnstripString(len, raw_string)
int len;
unsigned char *raw_string;
{
unsigned char *p, *q, *start, *limit, *end;
int i;
q = start = (unsigned char *) stripped_string;
end = (unsigned char *) raw_string + len;
limit = start + stripped_string_limit - KlUnstripStringMargin;
for (p = (unsigned char *) raw_string; p<end; p++, q++) {
if (q > limit) {
stripped_string_limit = stripped_string_limit ?
stripped_string_limit * 2 + 4 : 60;
stripped_string = (unsigned char *)
Realloc(stripped_string, stripped_string_limit);
q = (unsigned char *) stripped_string + (q - start);
limit = (unsigned char *) stripped_string + stripped_string_limit
- KlUnstripStringMargin;
start = (unsigned char *) stripped_string;
}
switch (*p) {
case '\\':
(*q++) = '\\';
*q = '\\';
break;
case '"':
(*q++) = '\\';
*q = '\"';
break;
case '\n':
if (KlQuoteNewlines) {
(*q++) = '\\';
*q = 'n';
} else {
*q = '\n';
}
break;
case '\r':
(*q++) = '\\';
*q = 'r';
break;
case '\t':
/* Old: we quoted tab, not necessary anymore
(*q++) = '\\';
*q = 't';
*/
*q = '\t';
break;
case '\033':
(*q++) = '\\';
*q = 'e';
break;
default:
if ((*p) < ' ' || (*p) > '~') {
/* not printable character */
(*q++) = '\\';
(*q++) = 'x';
i = ((int) (*p)) / 16;
(*q++) = (char) (i > 9 ? (i - 10) + 'a' : i + '0');
i = ((int) (*p)) % 16;
(*q) = (char) (i > 9 ? (i - 10) + 'a' : i + '0');
} else {
*q = *p;
}
}
}
KlUnstripStringLength = q - stripped_string;
(*q++) = '\0';
return (char *) stripped_string;
}
/*****************************************************************************\
* KlStripString *
\*****************************************************************************/
/* parses an external representation of a Klone string, and returns the byte
* array of its raw characters. The length is returned into the int
* pointed to by lenptr, and is necessary since null chars can be specified
* in the string!
* Returns a pointer to a statically allocated space.
*/
/* KlStripStringContents: the containing double quotes are NOT included in
* raw_string !!!
*/
char *
KlStripStringContents(len, raw_string, lenptr)
int len;
unsigned char *raw_string;
int *lenptr;
{
unsigned char *p = raw_string, *q, *end = p+len;
unsigned int num;
if (len > stripped_string_limit) {
/* check we have enough room in our work buffer */
stripped_string_limit = len;
stripped_string = (unsigned char *)
Realloc(stripped_string, stripped_string_limit + 1);
}
for (q = stripped_string; p < end; p++, q++) {
switch (*p) {
case '\\':
switch (*(++p)) {
case '\n':
q--;
break;
case 'n':
*q = '\n';
break;
case 'r':
*q = '\r';
break;
case 't':
*q = '\t';
break;
case 'e':
*q = '\033';
break;
case 'x':
num = 0;
p++;
if (isxdigit(*p)) {
num = (*p <= '9' ? *p - '0'
: (*p >= 'a' ? *p - 'W' : *p -'7'));
p++;
if (isxdigit(*p)) {
num <<= 4;
num += (*p <= '9' ? *p - '0'
: (*p >= 'a' ? *p - 'W' : *p -'7'));
} else {
p--;
}
*q = num;
} else {
*q = *(--p);
}
break;
default:
if ((*p <= '7') && (*p >= '0')) {
num = *p++ - '0';
if ((*p <= '7') && (*p >= '0')) {
num <<= 3;
num += *p++ - '0';
if ((*p <= '7') && (*p >= '0')) {
num <<= 3;
num += *p - '0';
} else {
p--;
}
} else {
p--;
}
*q = num;
} else {
*q = *p;
}
}
break;
default:
*q = *p;
}
}
*q = '\0';
*lenptr = (q - stripped_string);
return (char *) stripped_string;
}
/* old version for back-compat. here the enclosing double quotes are included
* in string
*/
char *
KlStripString(len, raw_string, lenptr)
int len;
unsigned char *raw_string;
int *lenptr;
{
return KlStripStringContents(len - 2, raw_string + 1, lenptr);
}
/* parses symbolic names of characters
* add names to KlSymbCharParseTable
*/
struct KlCharDefPair {
char *name;
int value;
};
static struct KlCharDefPair KlSymbCharParseTable[] = {
{"space", ' '},
{"newline", '\n'},
{"backspace", 8},
{"rubout", 127},
{"tab", 9},
{0, 0}
};
int
KlSymbCharParse(string)
char *string;
{
int i = 0;
while (KlSymbCharParseTable[i].name) {
if (!strcmp(string, KlSymbCharParseTable[i].name)) {
return KlSymbCharParseTable[i].value;
}
i++;
}
return -1;
}
/* KlStrdup
* a strdup-like, but with Klone's malloc
*/
char *
KlStrdup(s)
char *s;
{
char *duplicate = (char *) Malloc(strlen(s) + 1);
strcpy(duplicate, s);
return duplicate;
}
/*****************************************************************************\
* upperlower *
\*****************************************************************************/
KlO
KlStringToUpper(string)
KlString string;
{
KlString result;
char *p, *q, *end;
KlMustBeString(string, 0);
p = string->string;
end = p + KlStringLength(string);
result = KlStringNMake(end - p);
q = result->string;
while (p < end) {
if (islower(*p))
*q++ = *p++ - 32;
else
*q++ = *p++;
}
*q = *p; /* trailing 0 */
return (KlO) result;
}
KlO
KlStringToLower(string)
KlString string;
{
KlString result;
char *p, *q, *end;
KlMustBeString(string, 0);
p = string->string;
end = p + KlStringLength(string);
result = KlStringNMake(end - p);
q = result->string;
while (p < end) {
if (isupper(*p))
*q++ = *p++ + 32;
else
*q++ = *p++;
}
*q = *p; /* trailing 0 */
return (KlO) result;
}
#ifdef NO_MEMSET
KlMemSet(s, c, n)
char *s;
int c;
int n;
{
char *end = s + n;
while (s < end)
*s++ = c;
}
#endif /* NO_MEMSET */
/*****************************************************************************\
* Pointers to other string parts *
\*****************************************************************************/
/* should never be malloced / realloced */
KlStringPtr
KlStringPtrMake(l, s)
int l;
char *s; /* the string itself */
{
KlStringPtr object;
object = (KlStringPtr) KlOMake(KlStringPtrType);
object->string = s;
object->size = l;
object->refersto = 0; /* you should put there the
reffered string if any */
return object;
}
KlStringPtr
KlStringPtrMakeAndRefers(l, s, o)
int l;
char *s; /* the string itself */
KlO o; /* object we dont want to GC */
{
KlStringPtr object = KlStringPtrMake(l, s);
KlIncRef(object->refersto = o);
return object;
}
KlO
KlStringPtrFree(obj)
KlStringPtr obj;
{
KlDecRef(obj->refersto);
Free(obj);
return (KlO) obj;
}
KlO
KlStringPtrSub(argc, argv)
int argc;
KlString *argv;
{
int from, to;
switch (argc) {
case 3:
KlMustBeNumber(argv[2], 2);
to = ((KlNumber) argv[2])->number;
break;
case 2:
to = -1;
break;
default:
return KlBadNumberOfArguments(argc);
}
KlMustBeNumber(argv[1], 1);
KlMustBeString(argv[0], 0);
from = ((KlNumber) argv[1])->number;
if (to < 0)
to = KlStringLength(*argv);
return (KlO) KlStringPtrMakeAndRefers(to - from,
(*argv)->string + from, *argv);
}
/*****************************************************************************\
* TYPE INIT *
\*****************************************************************************/
KlStringInit()
{
stripped_string_limit = KlMAX_TEMP_STRING_SIZE;
stripped_string = (unsigned char *) Malloc(stripped_string_limit);
KlDeclareType(&KlStringType, "String", sizeof(struct _KlString));
KlDeclareIsTrait(KlStringType, KlTrait_string);
KlA_String = KlTypeName(KlStringType);
KlDeclareMethod1(KlStringType, KlSelPrint, KlStringPrint);
KlDeclareMethod1(KlStringType, KlSelFree, KlStringFree);
KlDeclareMethod1(KlStringType, KlSelEqual, KlStringEqual);
KlDeclareMethod1(KlStringType, KlSelAdd, KlStringAdd);
KlDeclareMethod1(KlStringType, KlSelCopy, KlStringCopy);
KlDeclareMethod1(KlStringType, KlSelGet, KlStringGet);
KlDeclareMethod1(KlStringType, KlSelPut, KlStringPut);
KlDeclareMethod1(KlStringType, KlSelInsert, KlStringInsert);
KlDeclareMethod1(KlStringType, KlSelDelete, KlStringDelete);
KlDeclareMethod1(KlStringType, KlSelNth, KlStringNth);
KlDeclareMethod1(KlStringType, KlSelHash, KlStringHash);
KlDeclareMethod1(KlStringType, KlSelLength, KlStringLengthKl);
KlDeclareMethod1(KlStringType, KlSelCompare, (KlMethod) KlStringCompare);
KlDeclareMethod1(KlStringType, KlSelDolist, (KlMethod) KlStringDolist);
/* bootstrap: make atoms sons of strings */
KlTypeFatherSet(KlAtomType, KlStringType);
KlDeclareSubr(KlStringMatch, "match", NARY);
KlDeclareSubr(KlStringToUpper, "toupper", 1);
KlDeclareSubr(KlStringToLower, "tolower", 1);
KlDeclareSubr(KlStringNMakeKl, "make-string", NARY);
KlIncRef(KlNilString = KlStringMake("")); /* NIL_STRING */
KlIncRef(KlPackage = KlNilString);
/* KlStringPtr is a KlString which does not free the C string at GC */
KlDeclareSubType(&KlStringPtrType, "StringPtr", KlStringType,
sizeof(struct _KlStringPtr));
KlDeclareTrait(KlStringPtrType, KlTrait_unreallocable);
KlDeclareMethod1(KlStringPtrType, KlSelFree, KlNumberFree);
KlDeclareSubr(KlStringPtrSub, "substring-ptr", NARY);
KlDeclareSubType(&KlRegexpType, "Regexp", KlStringType,
sizeof(struct _KlRegexp));
KlDeclareTrait(KlRegexpType, KlTrait_unreallocable);
KlDeclareMethod1(KlRegexpType, KlSelFree, KlRegexpFree);
KlDeclareMethod1(KlRegexpType, KlSelGet, KlRegexpGet);
KlDeclareMethodUndefined(KlRegexpType, KlSelPut);
KlDeclareMethodUndefined(KlRegexpType, KlSelDelete);
KlDeclareMethodUndefined(KlRegexpType, KlSelInsert);
KlDeclareMethod1(KlRegexpType, KlSelExecute, KlRegexpExecute);
KlDeclareMethod1(KlRegexpType, KlSelApply, KlRegexpApply);
KlDeclareSubr(KlRegcomp, "regcomp", 1);
KlDeclareSubr(KlRegexec, "regexec", NARY);
KlDeclareSubr(KlRegsub, "regsub", NARY);
#ifdef DEBUG
KlDeclareSubr(KlRegdump, "regdump", 1);
KlActivePointerToIntMake("regnarrate", ®narrate);
#endif /* DEBUG */
}
syntax highlighted by Code2HTML, v. 0.9.1