File:  [parser3project] / parser3 / src / lib / cord / cordxtra.c
Revision 1.19: download - view: text, annotated - select for diffs - revision graph
Tue Dec 15 00:11:23 2020 UTC (5 years, 6 months ago) by moko
Branches: MAIN
CVS tags: release_3_5_1, release_3_5_0, release_3_4_6, HEAD
cleanup: CORD_from_file* not used and thus removed

/*
 * 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: