/*
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*
* Author: Hans-J. Boehm (boehm@parc.xerox.com)
*/
/*
* These are functions on cords that do not need to understand their
* implementation. They serve also serve as example client code for
* cord_basics.
*/
/* Boehm, December 8, 1995 1:53 pm PST */
#include "pa_config_includes.h"
#include "include/cord.h"
#include "include/ec.h"
# define I_HIDE_POINTERS /* So we get access to allocation lock. */
/* We use this for lazy file reading, */
/* so that we remain independent */
/* of the threads primitives. */
/* For now we assume that pointer reads and writes are atomic, */
/* i.e. another thread always sees the state before or after */
/* a write. This might be false on a Motorola M68K with */
/* pointers that are not 32-bit aligned. But there probably */
/* aren't too many threads packages running on those. */
# define ATOMIC_WRITE(x,y) (x) = (y)
# define ATOMIC_READ(x) (*(x))
/* The standard says these are in stdio.h, but they aren't always: */
# ifndef SEEK_SET
# define SEEK_SET 0
# endif
# ifndef SEEK_END
# define SEEK_END 2
# endif
# define BUFSZ 2048 /* Size of stack allocated buffers when */
/* we want large buffers. */
typedef void (* oom_fn)(void);
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
ABORT("Out of memory\n"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
CORD CORD_cat_char(CORD x, char c)
{
register char * string;
if (c == '\0') return(CORD_cat(x, CORD_nul(1)));
string = GC_MALLOC_ATOMIC(2);
if (string == 0) OUT_OF_MEMORY;
string[0] = c;
string[1] = '\0';
return(CORD_cat_char_star(x, string, 1));
}
CORD CORD_catn(int nargs, ...)
{
register CORD result = CORD_EMPTY;
va_list args;
register int i;
va_start(args, nargs);
for (i = 0; i < nargs; i++) {
register CORD next = va_arg(args, CORD);
result = CORD_cat(result, next);
}
va_end(args);
return(result);
}
typedef struct {
size_t len;
size_t count;
char * buf;
} CORD_fill_data;
int CORD_fill_proc(char c, void * client_data)
{
register CORD_fill_data * d = (CORD_fill_data *)client_data;
register size_t count = d -> count;
(d -> buf)[count] = c;
d -> count = ++count;
if (count >= d -> len) {
return(1);
} else {
return(0);
}
}
int CORD_batched_fill_proc(const char* s, void * client_data)
{
register CORD_fill_data * d = (CORD_fill_data *)client_data;
register size_t count = d -> count;
register size_t max = d -> len;
register char * buf = d -> buf;
register const char* t = s;
while((buf[count] = *t++) != '\0') {
count++;
if (count >= max) {
d -> count = count;
return(1);
}
}
d -> count = count;
return(0);
}
/* Fill buf with len characters starting at i. */
/* Assumes len characters are available. */
void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
{
CORD_fill_data fd;
fd.len = len;
fd.buf = buf;
fd.count = 0;
(void)CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
}
int CORD_cmp(CORD x, CORD y)
{
CORD_pos xpos;
CORD_pos ypos;
register size_t avail, yavail;
if (y == CORD_EMPTY) return(x != CORD_EMPTY);
if (x == CORD_EMPTY) return(-1);
if (x == y) return (0);
if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
CORD_set_pos(xpos, x, 0);
CORD_set_pos(ypos, y, 0);
for(;;) {
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
return(-1);
} else {
return(0);
}
}
if (!CORD_pos_valid(ypos)) {
return(1);
}
if ((avail = CORD_pos_chars_left(xpos)) <= 0
|| (yavail = CORD_pos_chars_left(ypos)) <= 0) {
register char xcurrent = CORD_pos_fetch(xpos);
register char ycurrent = CORD_pos_fetch(ypos);
if (xcurrent != ycurrent) return(xcurrent - ycurrent);
CORD_next(xpos);
CORD_next(ypos);
} else {
/* process as many characters as we can */
register int result;
if (avail > yavail) avail = yavail;
result = strncmp(CORD_pos_cur_char_addr(xpos),
CORD_pos_cur_char_addr(ypos), avail);
if (result != 0) return(result);
CORD_pos_advance(xpos, avail);
CORD_pos_advance(ypos, avail);
}
}
}
int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
{
CORD_pos xpos;
CORD_pos ypos;
register size_t count;
register long avail, yavail;
CORD_set_pos(xpos, x, x_start);
CORD_set_pos(ypos, y, y_start);
for(count = 0; count < len;) {
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
return(-1);
} else {
return(0);
}
}
if (!CORD_pos_valid(ypos)) {
return(1);
}
if ((avail = CORD_pos_chars_left(xpos)) <= 0
|| (yavail = CORD_pos_chars_left(ypos)) <= 0) {
register char xcurrent = CORD_pos_fetch(xpos);
register char ycurrent = CORD_pos_fetch(ypos);
if (xcurrent != ycurrent) return(xcurrent - ycurrent);
CORD_next(xpos);
CORD_next(ypos);
count++;
} else {
/* process as many characters as we can */
register int result;
if (avail > yavail) avail = yavail;
count += avail;
if (count > len) avail -= (count - len);
result = strncmp(CORD_pos_cur_char_addr(xpos),
CORD_pos_cur_char_addr(ypos), (size_t)avail);
if (result != 0) return(result);
CORD_pos_advance(xpos, (size_t)avail);
CORD_pos_advance(ypos, (size_t)avail);
}
}
return(0);
}
char * CORD_to_char_star(CORD x, size_t len)
{
char * result;
if(0 == len) len = CORD_len(x);
result = GC_MALLOC_ATOMIC(len + 1);
if (result == 0) OUT_OF_MEMORY;
CORD_fill_buf(x, 0, len, result);
result[len] = '\0';
return(result);
}
CORD CORD_from_char_star(const char* s)
{
char * result;
size_t len = strlen(s);
if (0 == len) return(CORD_EMPTY);
result = GC_MALLOC_ATOMIC(len + 1);
if (result == 0) OUT_OF_MEMORY;
memcpy(result, s, len+1);
return(result);
}
const char* CORD_to_const_char_star(CORD x, size_t len)
{
if (x == 0) return("");
if (CORD_IS_STRING(x)) return((const char* )x);
return(CORD_to_char_star(x, len));
}
char CORD_fetch(CORD x, size_t i)
{
CORD_pos xpos;
CORD_set_pos(xpos, x, i);
if (!CORD_pos_valid(xpos)) ABORT("bad index?");
return(CORD_pos_fetch(xpos));
}
int CORD_put_proc(char c, void * client_data)
{
register FILE * f = (FILE *)client_data;
return(putc(c, f) == EOF);
}
int CORD_batched_put_proc(const char* s, void * client_data)
{
register FILE * f = (FILE *)client_data;
return(fputs(s, f) == EOF);
}
int CORD_put(CORD x, FILE * f)
{
if (CORD_iter5(x, 0, CORD_put_proc, CORD_batched_put_proc, f)) {
return(EOF);
} else {
return(1);
}
}
typedef struct {
size_t pos; /* Current position in the cord */
char target; /* Character we're looking for */
} chr_data;
int CORD_chr_proc(char c, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
if (c == d -> target) return(1);
(d -> pos) ++;
return(0);
}
int CORD_rchr_proc(char c, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
if (c == d -> target) return(1);
(d -> pos) --;
return(0);
}
int CORD_batched_chr_proc(const char* s, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
register char * occ = strchr(s, d -> target);
if (occ == 0) {
d -> pos += strlen(s);
return(0);
} else {
d -> pos += occ - s;
return(1);
}
}
size_t CORD_chr(CORD x, size_t i, int c)
{
chr_data d;
d.pos = i;
d.target = c;
if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
return(d.pos);
} else {
return(CORD_NOT_FOUND);
}
}
size_t CORD_rchr(CORD x, size_t i, int c)
{
chr_data d;
d.pos = i;
d.target = c;
if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
return(d.pos);
} else {
return(CORD_NOT_FOUND);
}
}
/* Find the first occurrence of s in x at position start or later. */
/* This uses an asymptotically poor algorithm, which should typically */
/* perform acceptably. We compare the first few characters directly, */
/* and call CORD_ncmp whenever there is a partial match. */
/* This has the advantage that we allocate very little, or not at all. */
/* It's very fast if there are few close misses. */
size_t CORD_str(CORD x, size_t start, CORD s, size_t xlen)
{
CORD_pos xpos;
size_t slen;
register size_t start_len;
const char* s_start;
unsigned long s_buf = 0; /* The first few characters of s */
unsigned long x_buf = 0; /* Start of candidate substring. */
/* Initialized only to make compilers */
/* happy. */
unsigned long mask = 0;
register size_t i;
register size_t match_pos;
if (s == CORD_EMPTY) return(start);
if (CORD_IS_STRING(s)) {
s_start = s;
slen = strlen(s);
} else {
s_start = CORD_to_char_star(CORD_substr(s, 0, sizeof(unsigned long), 0), 0);
slen = CORD_len(s);
}
if (xlen < start || xlen - start < slen) return(CORD_NOT_FOUND);
start_len = slen;
if (start_len > sizeof(unsigned long)) start_len = sizeof(unsigned long);
CORD_set_pos(xpos, x, start);
for (i = 0; i < start_len; i++) {
mask <<= 8;
mask |= 0xff;
s_buf <<= 8;
s_buf |= (unsigned char)s_start[i];
x_buf <<= 8;
x_buf |= (unsigned char)CORD_pos_fetch(xpos);
CORD_next(xpos);
}
for (match_pos = start; ; match_pos++) {
if ((x_buf & mask) == s_buf) {
if (slen == start_len ||
CORD_ncmp(x, match_pos + start_len,
s, start_len, slen - start_len) == 0) {
return(match_pos);
}
}
if ( match_pos == xlen - slen ) {
return(CORD_NOT_FOUND);
}
x_buf <<= 8;
x_buf |= (unsigned char)CORD_pos_fetch(xpos);
CORD_next(xpos);
}
}
void CORD_ec_flush_buf(CORD_ec x)
{
register size_t len = x[0].ec_bufptr - x[0].ec_buf;
char * s;
if (len == 0) return;
s = GC_MALLOC_ATOMIC(len+1);
if (s == 0) OUT_OF_MEMORY;
memcpy(s, x[0].ec_buf, len);
s[len] = '\0';
x[0].ec_cord = CORD_cat_char_star(x[0].ec_cord, s, len);
x[0].ec_bufptr = x[0].ec_buf;
}
void CORD_ec_append_cord(CORD_ec x, CORD s)
{
CORD_ec_flush_buf(x);
x[0].ec_cord = CORD_cat(x[0].ec_cord, s);
}
/*ARGSUSED*/
char CORD_nul_func(size_t i, void * client_data)
{
return((char)(unsigned long)client_data);
}
#ifdef CORD_CHARS_CACHE
static char* cord_chars_cache[256][15]={0};
#endif
CORD CORD_chars(char c, size_t i)
{
if (i>0 && i<16 /* SHORT_LIMIT */) {
register char* result;
#ifdef CORD_CHARS_CACHE
if(cord_chars_cache[(unsigned char)c][i])
return((CORD) cord_chars_cache[(unsigned char)c][i]);
#endif
result=GC_MALLOC_ATOMIC(i+1);
if(result==0) OUT_OF_MEMORY;
memset(result, c, i);
result[i] = '\0';
#ifdef CORD_CHARS_CACHE
cord_chars_cache[(unsigned char)c][i]=result;
#endif
return((CORD) result);
} else {
return(CORD_from_fn(CORD_nul_func, (void *)(unsigned long)c, i));
}
}
E-mail: