Net2/usr/src/contrib/isode/dsap/common/parse.c

/* parse.c - */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/dsap/common/RCS/parse.c,v 7.3 91/02/22 09:19:51 mrose Interim $";
#endif

/* 
 * $Header: /f/osi/dsap/common/RCS/parse.c,v 7.3 91/02/22 09:19:51 mrose Interim $
 *
 *
 * $Log:	parse.c,v $
 * Revision 7.3  91/02/22  09:19:51  mrose
 * Interim 6.8
 * 
 * Revision 7.2  90/10/17  11:42:27  mrose
 * sync
 * 
 * Revision 7.1  90/07/09  14:34:54  mrose
 * sync
 * 
 * Revision 7.0  89/11/23  22:17:56  mrose
 * Release 6.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include "general.h"
#include "manifest.h"
#include "tailor.h"
#include "quipu/config.h"
#include "quipu/util.h"
#include "quipu/entry.h"
#include "quipu/ds_error.h"
#include "quipu/malloc.h"
#ifdef TURBO_DISK
#include <gdbm.h>
#endif

#define	CONT_CHAR	'\\'	/* Continueation character */


Entry database_root = NULLENTRY;
int local_master_size = 0;
int local_slave_size = 0;
int local_cache_size = 0;

extern LLog * log_dsap;
extern int dn_print ();

#ifdef TURBO_DISK
extern char	*parse_entry;
int		dbmeof;
int		dbmfirst = 1;
datum		turbo_header_key = { "HEADER", sizeof("HEADER") };
GDBM_FILE	save_db;
#endif

extern  time_t time ();
extern char	*unesc_char();
extern char	*unesc_cont();
extern char *getstring();
char *srealloc();
char	*brkl();

#ifdef TURBO_DISK

char *getline (db)
GDBM_FILE	db;
{
	static datum	newkey, key, dat;
	static char	*line, *next, *save;
	static int	new_entry;
	char		*TidyString();
	int		save_heap;

	save_db = db;

	save_heap = mem_heap;
	GENERAL_HEAP;

	if (dbmfirst) {
		dbmfirst = 0;
		key = gdbm_firstkey(db);
		parse_entry = key.dptr;
		new_entry = 1;
	} else if (line == NULLCP || *line == '\0') {
		newkey = gdbm_nextkey(db, key);
		free(key.dptr);
		key = newkey;
		parse_entry = key.dptr;
		new_entry = 1;
	}

	if (key.dptr == NULLCP) {
		dbmeof = 1;
		dbmfirst = 1;
		mem_heap = save_heap;
		return(NULLCP);
	}

	if (new_entry) {
		/* gross, but we have to skip the header datum */
		if (strcmp(key.dptr, turbo_header_key.dptr) == 0) {
			newkey = gdbm_nextkey(db, key);
			free(key.dptr);
			key = newkey;
			if (key.dptr == NULLCP) {
				parse_entry = key.dptr;
				dbmeof = 1;
				dbmfirst = 1;
				mem_heap = save_heap;
				return(NULLCP);
			}
		}

		new_entry = 0;
		parse_entry = key.dptr;
		dat = gdbm_fetch(db, key);

		if ((line = dat.dptr) == NULLCP) {
			parse_error("edb error - null dbm data");
			return(NULLCP);
		}
	}

	if (*line == '\n') {
		line = NULLCP;
		free(dat.dptr);
		mem_heap = save_heap;
		return("");
	}

	line = SkipSpace(line);
	while (*line == '#') {
		line = index(line, '\n') + 1;
		if (*line == '\0') {
			mem_heap = save_heap;
			return(NULLCP);
		}
		line = SkipSpace(line);
	}

	next = line;
	while (next = index(next, '\n')) {
		if (*(next - 1) == CONT_CHAR) {	/* XXX do this right XXX */
			*(next - 1) = ' ';
			*next = ' ';
		} else
			break;
	}
	if (next == NULL)
		return(NULLCP);
	*next++ = '\0';
	save = line;
	line = next;

	mem_heap = save_heap;
	return(TidyString(save));
}

char *getnextline ()
{
	return getline (save_db);
}


#endif /* TURBO_DISK */

#define PARSE_INCR 512
#define MAXLINE    130

/* Testing
#define PARSE_INCR 5
#define MAXLINE    3
*/
    static char *parse_buffer = NULLCP;
    static int	parse_len = 0;
    static char	*buf;
    static int	buflen;
    static int	curlen;
    static int	size;

/*
 * get a physical line - handle arbitary long physical line
 */
static char *
getphyline (file)
FILE * file;
{
    extern int parse_line;
    extern char * TidyString ();


    buf = parse_buffer;
    buflen = parse_len;
    curlen = 0;

    for (;;) {
	if ( buflen <= MAXLINE) {
	    if (parse_len <= 0) {
		buflen = parse_len = PARSE_INCR;
		buf = parse_buffer = smalloc(PARSE_INCR);
	    } else {
		parse_len += PARSE_INCR;
		buflen += PARSE_INCR;
		if ((parse_buffer = realloc(parse_buffer, (unsigned)parse_len)) == NULLCP)
		    exit (2);	/* ??? */
		buf = parse_buffer + curlen;
	    }
	}

	if (fgets (buf, buflen,file) == NULLCP)
	    return (NULLCP);

	size = strlen(buf);
	if (buf[size - 1] == '\n') {
	    buf[--size] = '\0';
	    break;
	}
	buf += size;
	buflen -= size;
	curlen += size;

    }

    parse_line++;
    return (parse_buffer);

}

/*
 * Append the next physical line to the current physical line
 * Assuming that only characters from buf onwards have been
 * altered. We recalculate the end of buffer from buf
 */
static char *
catphyline (file, str)
FILE * file;
char	*str;
{
    extern int parse_line;
    extern char * TidyString ();


    if (str && str > parse_buffer) {
	/* size will be negative if a long line has been trimmed back
	 * beyond the last buffer length
	 */
	size = str - buf;	/* saves us calling strlen here */
	buf += size;
	buflen -= size;
	curlen += size;
    } else {
	buf = parse_buffer;
	buflen = parse_len;
	curlen = 0;
    }

    for (;;) {
	if ( buflen <= MAXLINE) {
	    if (parse_len <= 0) {
		buflen = parse_len = PARSE_INCR;
		buf = parse_buffer = smalloc(PARSE_INCR);
	    } else {
		parse_len += PARSE_INCR;
		buflen += PARSE_INCR;
		if ((parse_buffer = realloc(parse_buffer, (unsigned)parse_len)) == NULLCP)
		    exit (2);	/* ??? */
		buf = parse_buffer + curlen;
	    }
	}

	if (fgets (buf, buflen,file) == NULLCP)
	    return (NULLCP);

	size = strlen(buf);
	if (buf[size - 1] == '\n') {
	    buf[--size] = '\0';
	    break;
	}
	buf += size;
	buflen -= size;
	curlen += size;

    }

    parse_line++;
    return (parse_buffer);

}

extern char	*unesc_cont();
FILE * savefile;

#ifdef TURBO_DISK
char * fgetline (file)
#else
char * getline (file)
#endif
FILE * file;
{
    extern char * TidyString ();

    int		len;
    int		ocurlen;
    char	*p;
    char	*npart;

    savefile = file;

    do {
	if ((p = getphyline(file)) == NULLCP)
	    return (NULLCP);

    } while (*SkipSpace (buf) == '#');

    len = curlen + size;

    npart = p;
    while ((npart = unesc_cont(npart, len))) {/* continued line keep going */
	ocurlen = npart - p;
	if ((p = catphyline(file, npart)) == NULLCP)
	    return (NULLCP);
	len = curlen + size - ocurlen;
	npart = p + ocurlen;
    }

    return (TidyString(p));

}

#ifdef TURBO_DISK
char * fgetnextline ()
#else
char * getnextline ()
#endif
{
	return getline (savefile);
}

/*
 * un-escape a continued line and return pointer to end of the buffer
 * if the line is continued
 */
char	*
unesc_cont(ptr, len)
char	*ptr;
int	len;
{
    char	*p;
    int		cnt;

    for (cnt = 0, p = ptr + len - 1; p >= ptr; p--) {
	if (*p != CONT_CHAR)
	    break;
       cnt++;
    }
    if (cnt) {
	p += (cnt / 2) + 1;
	*p = '\0';
    }

    return (cnt % 2 ? p : NULLCP);

}


/*
 * write no more than wl characters of the line out escaping any
 * characters at the end to a file pointer.
 */
fpwr_esc(fp, line, wl)
FILE	*fp;
char	*line;
int	wl;
{
    int		len;	/* length of line left */
    int		pos;	/* position we are going to break line at */
    int		m;	/* number of CONT_CHARs at end of string */
    int		n;	/* number of CONT_CHARs we can put on this line */
    int		i;

    len = strlen(line);
    while (len > 0) {
	if (len < wl)
	    pos = len;
	else
	    pos = wl;
	
	m = cnt_escp(line, pos);

	if (m > 0) {
	    if (pos + 2*m <= wl) {	/* can fit them in the line */
		n = m;	/* need an extra escape for each one */
	    } else  {
		n = (wl - 1 - pos + m)/2;
		pos -= m - n;
		n++;	/* Need an extra one to make the line continue */
	    }
	} else
	    n = 0;
	for (i = pos; i > 0; i--, line++)
	    (void) putc(*line, fp);
	for (i = n; i > 0; i--)
	    (void) putc(CONT_CHAR, fp);
	(void) putc('\n', fp);
	len -= pos;
    }
}
/*
 * write no more than wl characters of the line out escaping any
 * characters at the end.
 */
pswr_esc(ps, line, wl)
PS	ps;
char	*line;
int	wl;
{
    int		len;	/* length of line left */
    int		pos;	/* position we are going to break line at */
    int		m;	/* number of CONT_CHARs at end of string */
    int		n;	/* number of CONT_CHARs we can put on this line */
    int		i;

    len = strlen(line);
    while (len > 0) {
	if (len < wl)
	    pos = len;
	else
	    pos = wl;
	
	m = cnt_escp(line, pos);

	if (m > 0) {
	    if (pos + 2*m <= wl) {	/* can fit them in the line */
		n = m;	/* need an extra escape for each one */
	    } else  {
		n = (wl - 1 - pos + m)/2;
		pos -= m - n;
		n++;	/* Need an extra one to make the line continue */
	    }
	} else
	    n = 0;
	(void) ps_write(ps, (PElementData)line, pos);
	if (n > 0) {
	    char nbuf[MAXLINE];

	    /* unlikely this will ever be run but just in case */
	    while (n + 1 > MAXLINE) {
		for (i = MAXLINE - 2; i >= 0; i--)
		    nbuf[i] = CONT_CHAR;
		nbuf[MAXLINE - 1] = '\n';
		(void) ps_write(ps, (PElementData)line, pos);
		n -= MAXLINE;
	    }
	    for (i = n - 1; i >= 0; i--)
		nbuf[i] = CONT_CHAR;
	    nbuf[n] = '\n';
	    (void) ps_write(ps, (PElementData)line, pos);
	}
	len -= pos;
    }
}

cnt_escp(ptr, len)
register char	*ptr;
int	len;
{
    register char	*p;
    register int		cnt;

    for (cnt = 0, p = ptr + len - 1; p >= ptr; p--) {
	if (*p != CONT_CHAR)
	    break;
       cnt++;
    }
    return (cnt);
}

char *
srealloc(p, nsize)
char	*p;
int     nsize;
{
        register char *ptr;

        if ((ptr = realloc(p, (unsigned) nsize)) == NULL){
            LLOG (compat_log,LLOG_FATAL, ("realloc() failure"));
            abort ();
            /* NOTREACHED */
        }

        return(ptr);
}

#ifdef TURBO_DISK

Attr_Sequence fget_attributes_aux (file)
FILE * file;
{
register Attr_Sequence as = NULLATTR;
Attr_Sequence as_combine ();
register char * ptr;

	if ((ptr = fgetline (file)) == NULLCP)
		return (NULLATTR);

	while ( *ptr != 0 ) {
		as = as_combine (as,ptr,FALSE);
		if ((ptr = fgetline (file)) == NULLCP)
			break;
	}
	return (as);
}

Attr_Sequence fget_attributes (file)
FILE * file;
{
extern int parse_status;
extern int parse_line;

	parse_status = 0;
	parse_line   = 0;

	return (fget_attributes_aux (file));
}

#endif

Attr_Sequence get_attributes_aux (file)
#ifdef TURBO_DISK
GDBM_FILE	file;
#else
FILE * file;
#endif
{
register Attr_Sequence as = NULLATTR;
Attr_Sequence as_combine ();
register char * ptr;

	if ((ptr = getline (file)) == NULLCP)
		return (NULLATTR);

	while ( *ptr != 0 ) {
		as = as_combine (as,ptr,FALSE);
		if ((ptr = getline (file)) == NULLCP)
			break;
	}
	return (as);
}

Attr_Sequence get_attributes (file)
#ifdef TURBO_DISK
GDBM_FILE	file;
#else
FILE * file;
#endif
{
extern int parse_status;
extern int parse_line;

	parse_status = 0;
	parse_line   = 0;

	return (get_attributes_aux (file));
}


Entry get_entry_aux (file,parent,dtype)
#ifdef TURBO_DISK
GDBM_FILE	file;
#else
FILE * file;
#endif
Entry parent;
int dtype;
{
Entry eptr;
char * ptr;
extern RDN parse_rdn;
struct DSError err;
extern int print_parse_errors;
extern int parse_line;
int save; 
extern PS opt;
char check = TRUE;

	DATABASE_HEAP;

	eptr = get_default_entry (parent);
	eptr->e_data = dtype;

	if ((ptr = getline (file)) == NULLCP) {
		GENERAL_HEAP;
		return (NULLENTRY);
	}
		
	while (*ptr == 0)
		if ((ptr = getline (file)) == NULLCP) {
			GENERAL_HEAP;
			return (NULLENTRY);
		}

	if ((eptr->e_name = str2rdn (ptr)) == NULLRDN) {
		parse_error ("invalid rdn %s",ptr);
		check = FALSE;
	}
	
	parse_rdn = eptr->e_name;
	eptr->e_attributes = get_attributes_aux (file);

	if (check) {
		save = parse_line;
		parse_line = 0;
		if (unravel_attribute (eptr,&err) != OK) {
			parse_error ("Error in entry ending line %d...",(char *) save);
			if (print_parse_errors)
				ds_error (opt,&err);
		} 
		if (check_schema (eptr,NULLATTR,&err) != OK) {
			parse_error ("Schema error in entry ending line %d...",(char *) save);
			if (print_parse_errors)
				ds_error (opt,&err);
		} 
		parse_line = save;
	}
	parse_rdn = NULLRDN;

	GENERAL_HEAP;

	switch (dtype) {
	case E_TYPE_SLAVE:
		local_slave_size++; break;
	case E_DATA_MASTER:
		local_master_size++; break;
	case E_TYPE_CACHE_FROM_MASTER:
		eptr->e_age = time ((time_t *)0);
		local_cache_size++; break;
	}

	return (eptr);
}


Entry get_entry (file,parent,dtype)
#ifdef TURBO_DISK
GDBM_FILE	file;
#else
FILE * file;
#endif
Entry parent;
int dtype;
{
extern int parse_status;
extern int parse_line;

	parse_status = 0;
	parse_line   = 0;

	return (get_entry_aux (file,parent,dtype));
}


Entry new_constructor (parent)
Entry parent;
{
Entry constructor;

	constructor = get_default_entry (parent);
#ifdef TURBO_AVL
	constructor->e_children = NULLAVL;
#endif
	constructor->e_leaf = FALSE;
	constructor->e_allchildrenpresent = FALSE;
	constructor->e_complete = FALSE;
	constructor->e_data = E_TYPE_CONSTRUCTOR;
	constructor->e_acl = acl_alloc ();
	constructor->e_acl->ac_child = acl_dflt ();
	constructor->e_acl->ac_entry = acl_dflt ();
	constructor->e_acl->ac_default = acl_dflt ();
	constructor->e_acl->ac_attributes = NULLACL_ATTR;
	return (constructor);
}


Entry make_path (dn)
DN dn;
{
Entry ptr;
register RDN    b_rdn;
#ifdef TURBO_AVL
Entry	parent, new;
Avlnode	*kids;
int	entryrdn_cmp(), entry_cmp();
#else
register RDN	a_rdn;
#endif

#ifdef TURBO_AVL
	if (database_root == NULLENTRY || database_root->e_children == NULLAVL) {
#else
	if ((database_root == NULLENTRY) || (database_root->e_child == NULLENTRY)) {
#endif
		database_root = new_constructor(NULLENTRY);
		ptr = database_root;
		for (; dn!= NULLDN; dn=dn->dn_parent) {
#ifdef TURBO_AVL
			new = new_constructor(ptr);
			new->e_name = rdn_cpy(dn->dn_rdn);
			(void) avl_insert(&ptr->e_children, (caddr_t) new, entry_cmp, avl_dup_error);
			ptr = (Entry) avl_getone(ptr->e_children);
#else
			ptr->e_child = new_constructor(ptr);
			ptr = ptr->e_child;
			ptr->e_name = rdn_cpy (dn->dn_rdn);
#endif /* TURBO_AVL */
		}
		return (ptr);
	} else {
		/* follow links as far as poss, then add new bits */

		if (dn == NULLDN)
			return (database_root);

#ifdef TURBO_AVL
		kids = database_root->e_children;
		parent = database_root;
#else
		ptr = database_root->e_child;
		a_rdn = ptr->e_name ;
#endif
		b_rdn = dn->dn_rdn;

		for(;;) { /* return out */
#ifdef TURBO_AVL
			if ((ptr = (Entry) avl_find(kids, (caddr_t) b_rdn, entryrdn_cmp))
			    == NULLENTRY ) {
				for (; dn != NULLDN; dn = dn->dn_parent) {
					new = new_constructor(parent);
					new->e_name = rdn_cpy(dn->dn_rdn);
					(void) avl_insert(&parent->e_children, (caddr_t) new,
					    entry_cmp, avl_dup_error);
					parent = (Entry) avl_find(parent->e_children, (caddr_t) dn->dn_rdn, entryrdn_cmp);
				}
				return(parent);
			}
#else
			while (rdn_cmp (a_rdn, b_rdn) != OK) {
				if (ptr->e_sibling == NULLENTRY) {
				   if ((ptr->e_data == E_DATA_MASTER) || 
					(ptr->e_data == E_TYPE_SLAVE)) {
					pslog(log_dsap, LLOG_EXCEPTIONS,
						"WARNING: Not loading entry that does not exist (any more)",
						dn_print, (caddr_t) dn);
					return NULLENTRY;
					}
				   ptr->e_sibling = new_constructor(ptr->e_parent);
				   ptr = ptr->e_sibling;
				   ptr->e_name = rdn_cpy (dn->dn_rdn);
				   for (dn=dn->dn_parent; dn!= NULLDN; dn=dn->dn_parent) {
					ptr->e_child = new_constructor(ptr);
					ptr = ptr->e_child;
					ptr->e_name = rdn_cpy (dn->dn_rdn);
				   }
				   return (ptr);
				}
				ptr = ptr->e_sibling;
				a_rdn = ptr->e_name ;
			}
#endif /* TURBO_AVL */

			if (dn->dn_parent == NULLDN)
				return (ptr);

			dn = dn->dn_parent;
			b_rdn = dn->dn_rdn;

#ifdef TURBO_AVL
			if (ptr->e_children == NULLAVL) {
				for (; dn!= NULLDN; dn=dn->dn_parent) {
					new = new_constructor(ptr);
					new->e_name = rdn_cpy(dn->dn_rdn);
					(void) avl_insert(&ptr->e_children, (caddr_t) new,
					    entry_cmp, avl_dup_error);
					ptr = (Entry) avl_find(ptr->e_children,
					    (caddr_t) dn->dn_rdn, entryrdn_cmp);
				}
				return(ptr);
			}

			kids = ptr->e_children;
			parent = ptr;
#else
			if ( ptr->e_child == NULLENTRY) {
				for (; dn!= NULLDN; dn=dn->dn_parent) {
					ptr->e_child = new_constructor(ptr);
					ptr = ptr->e_child;
					ptr->e_name = rdn_cpy (dn->dn_rdn);
				}
				return (ptr);
			}

			ptr = ptr->e_child;
			a_rdn = ptr->e_name;
#endif
		}

	}
	/* NOTREACHED */

}