dslinux/user/pixil/sys/par/lib Makefile data.c database.c database.h db_api.c index.c io.c par_api.c tree.c

amadeus dslinux_amadeus at user.in-berlin.de
Tue Oct 3 13:27:10 CEST 2006


Update of /cvsroot/dslinux/dslinux/user/pixil/sys/par/lib
In directory antilope:/tmp/cvs-serv11916/sys/par/lib

Added Files:
	Makefile data.c database.c database.h db_api.c index.c io.c 
	par_api.c tree.c 
Log Message:
adding pristine copy of pixil to HEAD so I can branch from it

--- NEW FILE: database.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <par/pardb.h>
#include "database.h"

/* A local function used to grab the name off the top of the list */

char *
strip_keyword(char **name)
{
    char *keyword = *name;

    char *ptr = strchr(*name, '.');

    if (!ptr) {
	*name = 0;
    } else {
	*ptr = 0;
	*name = ptr + 1;
	if (!*name)
	    *name = 0;
    }

    return (keyword);
}

/* Recursively add the node (and any non existent parent nodes) to the database */

int
db_recursiveAdd(db_handle * db, index_t * parent, char *name,
		void *data, ushort size, ushort type)
{

    int ret;

    char *pointer = name;
    char *keyword = strip_keyword(&pointer);

    index_t *index = db_getChild(db, parent);
    index_t *prev = 0;

    while (index) {

	if (strcmp(index->keyword, keyword) == 0) {

	    /* If the node already exists, then just set the data and bail */
	    if (!pointer) {
		ret = db_setData(db, index, data, size, type);
	    } else {
		ret = db_recursiveAdd(db, index, pointer, data, size, type);
	    }

	    return (ret);
	}

	prev = index;
	index = db_getPeer(db, index);
    }

    /* If we get this far, the node doesn't exist */

    if (!prev) {
	index = db_addChild(db, parent, keyword);
    } else {
	index = db_addPeer(db, prev, keyword);
    }

    if (!index)
	return (-1);

    if (!pointer) {
	ret = db_setData(db, index, data, size, type);
    } else
	ret = db_recursiveAdd(db, index, pointer, data, size, type);

    return (ret);
}

/* Recursively search the database looking for the named node */

index_t *
db_recursiveFind(db_handle * db, index_t * parent, char *name)
{

    char *pointer = name;
    char *keyword = strip_keyword(&pointer);

    index_t *index = db_getChild(db, parent);

    while (index) {


	if (strcmp(index->keyword, keyword) == 0) {

	    /* Found it, return the node */
	    if (!pointer) {
		SET_ERRNO(PARDB_SUCCESS);
		return (index);
	    }

	    /* Move down a level */
	    return (db_recursiveFind(db, index, pointer));
	}

	index = db_getPeer(db, index);
    }

    SET_ERRNO(PARDB_NOTFOUND);
    return (0);
}

static void
db_recursiveKill(db_handle * db, index_t * parent)
{

    index_t *index = db_getChild(db, parent);
    index_t *next = 0;

    while (index) {
	db_recursiveKill(db, index);

	next = db_getPeer(db, index);
	db_removeIndex(db, index);	/* Kill the index and data */
	index = next;
    }
}

/* Recursively search the database looking for the named node */
/* When found, kill the entire tree below it and remove this  */
/* node from the chain                                        */

int
db_recursiveDel(db_handle * db, index_t * parent, char *name)
{

    char *pointer = name;
    char *keyword = strip_keyword(&pointer);

    index_t *index = db_getChild(db, parent);
    index_t *prev = 0;

    while (index) {
	if (strcmp(index->keyword, keyword) == 0) {

	    /* Once we find the pointer, then we recursively kill everything below it */

	    if (!pointer) {
		db_recursiveKill(db, index);

		if (prev)
		    db_setPeer(db, prev, db_getPeer(db, index));
		else
		    db_setChild(db, prev, db_getPeer(db, index));

		db_removeIndex(db, index);	/* Kill the "parent" of the doomed tree */
		return (0);
	    }

	    /* Move down a level */
	    return (db_recursiveDel(db, index, pointer));
	}

	prev = index;
	index = db_getPeer(db, index);
    }

    SET_ERRNO(PARDB_SUCCESS);
    return (0);
}

void
db_freeDB(db_handle * db)
{
    int i;

    if (!db)
	return;

    for (i = 0; i < db->mapSize; i++)
	db_unmapBlock(db, i);

    free(db->map);
    free(db);
}

db_handle *
db_allocDB(int fd, int bsize, int length)
{

    db_handle *local;

    if (!(local = (db_handle *) calloc(sizeof(db_handle), 1))) {
	SET_ERRNO(PARDB_MEMERR);
	return (0);
    }

    local->fd = fd;
    local->blkSize = bsize;
    local->length = length;

    if (!length) {
	/* Make the inital hash */
	local->map = (db_map_t *) calloc(16 * sizeof(db_map_t), 1);
	if (!local->map) {
	    free(local);
	    SET_ERRNO(PARDB_MEMERR);
	    return (0);
	}

	local->mapSize = 16;
    } else {
	/* Alloate only enough items to hold the database */

	local->map =
	    (db_map_t *) calloc((length / bsize) * sizeof(db_map_t), 1);
	if (!local->map) {
	    free(local);
	    SET_ERRNO(PARDB_MEMERR);
	    return (0);
	}

	local->mapSize = (length / bsize);
    }

    SET_ERRNO(PARDB_SUCCESS);
    return (local);
}

--- NEW FILE: io.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

#include <sys/mman.h>

#include <par/pardb.h>
#include "database.h"

#define CALC_BLOCK_NUM(db, offset) (offset / db->blkSize)

/* db_mapBlock() */

/* Given an offset into the file, either map it, 
   or return the address of a previous mapping 
*/

void *
db_mapBlock(db_handle * db, int offset)
{

    int bnum = CALC_BLOCK_NUM(db, offset);
    int i, mode;

    if (offset >= db->length) {
	SET_ERRNO(PARDB_BADOFFSET);
	return (0);
    }

    if (bnum >= db->mapSize) {
	db_map_t *temp =
	    (db_map_t *) realloc(db->map, (bnum + 8) * sizeof(db_map_t));

	if (!temp) {
	    SET_ERRNO(PARDB_MEMERR);
	    return (0);
	}
	db->map = temp;

	/* Zero the new items */
	for (i = db->mapSize; i < bnum + 8; i++)
	    bzero(&db->map[i], sizeof(db_map_t));

	db->mapSize = bnum + 8;
    }

    if (db->map[bnum].addr && db->map[bnum].mode == db->mode) {
	db->map[bnum].usage++;
	SET_ERRNO(PARDB_SUCCESS);

	return (db->map[bnum].addr);
    }

    if (db->map[bnum].addr && db->map[bnum].usage) {
	SET_ERRNO(PARDB_BLOCKINUSE);
	return (0);
    }

    /* Map the block */

    if (db->mode == PAR_DB_READ_BLOCK || db->access == PAR_DB_MODE_RDONLY)
	mode = PROT_READ;
    else
	mode = PROT_READ | PROT_WRITE;

#ifndef HAVE_MMAPBUG
    db->map[bnum].addr =
	mmap(0, db->blkSize, mode, MAP_SHARED, db->fd, db->blkSize * bnum);
#else
    if (db->mode == PAR_DB_READ_BLOCK)
	db->map[bnum].addr = mmap(0, db->blkSize, mode,
				  MAP_SHARED, db->fd, db->blkSize * bnum);
    else {
	int ret;

	db->map[bnum].addr = (void *) malloc(db->blkSize);

	if (db->map[bnum].addr) {
	    lseek(db->fd, db->blkSize * bnum, SEEK_SET);
	    ret =
		read(db->fd, (unsigned char *) db->map[bnum].addr,
		     db->blkSize);
	    if (ret != db->blkSize)
		db->map[bnum].addr = MAP_FAILED;
	} else
	    db->map[bnum].addr = MAP_FAILED;
    }
#endif

    if (db->map[bnum].addr == MAP_FAILED) {
	bzero(&db->map[bnum], sizeof(db_map_t));
	SET_ERRNO(PARDB_BADMAP);
	return (0);
    }

    db->map[bnum].mode = db->mode;
    db->map[bnum].usage = 1;

    SET_ERRNO(PARDB_SUCCESS);
    return (db->map[bnum].addr);
}

void
db_unmapBlock(db_handle * db, int block)
{

    if (db->map[block].usage > 0)
	db->map[block].usage--;

    if (db->map[block].addr && !db->map[block].usage) {
#ifndef HAVE_MMAPBUG
	munmap(db->map[block].addr, db->blkSize);
#else
	if (db->map[block].mode == PAR_DB_READ_BLOCK)
	    munmap(db->map[block].addr, db->blkSize);
	else {
	    int ret;

	    lseek(db->fd, db->blkSize * block, SEEK_SET);
	    ret = write(db->fd, db->map[block].addr, db->blkSize);

	    free(db->map[block].addr);
	}
#endif
    }

    bzero(&db->map[block], sizeof(db_map_t));
}

void
db_flushWrite(db_handle * db)
{

    int i;

    /* Flush all of the existing write blocks to the disk */
    /* this may be painful if there are lingering links to the memory addresses */

    for (i = 0; i < db->mapSize; i++) {
	if (db->map[i].mode != PAR_DB_WRITE_BLOCK)
	    continue;

	db->map[i].usage = 0;
	db_unmapBlock(db, i);
    }
}

/* db_mapBlock() */
/* Add a new physical block to the database */

int
db_addBlock(db_handle * db)
{

    int end = db->length;

    if (db->mode != PAR_DB_MODE_RW) {
	SET_ERRNO(PARDB_BADMODE);
	return (-1);
    }

    if (lseek(db->fd, db->blkSize, SEEK_END) == -1) {
	SET_ERRNO(PARDB_IOERR);
	return (-1);
    }

    if (write(db->fd, "", 1) == -1) {
	SET_ERRNO(PARDB_IOERR);
	return (-1);
    }

    db->length += db->blkSize;

    SET_ERRNO(PARDB_SUCCESS);
    return (end);
}

unsigned long
db_getFileOffset(db_handle * db, void *ptr)
{

    int i;
    unsigned long offset;

    if (!db) {
	SET_ERRNO(PARDB_BADHANDLE);
	return (0);
    }

    /* Search the list of blocks and get the correct block */

    for (i = 0; i < db->mapSize; i++) {
	if (!db->map[i].addr)
	    continue;

	if (ptr < db->map[i].addr)
	    continue;

	offset = ((unsigned long) ptr) - ((unsigned long) db->map[i].addr);

	/* If the block pointers match, then return the file offset */

	if (BLOCK_POINTER_START(db, ptr) == db->map[i].addr) {
	    SET_ERRNO(PARDB_SUCCESS);
	    return ((unsigned long) ((i * db->blkSize) + offset));
	}
    }

    SET_ERRNO(PARDB_BADOFFSET);
    return (0);
}

void *
db_getBlockStart(db_handle * db, void *ptr)
{

    int i;
    unsigned long val = (unsigned long) ptr;

    for (i = 0; i < db->mapSize; i++) {
	unsigned long pos;

	if (!db->map[i].addr)
	    continue;
	pos = (unsigned long) db->map[i].addr;
	if (val >= pos && val < pos + db->blkSize)
	    return (db->map[i].addr);
    }

    return (0);
}

unsigned long
db_getBlockOffset(db_handle * db, void *ptr)
{

    int i;
    unsigned long val = (unsigned long) ptr;

    for (i = 0; i < db->mapSize; i++) {
	unsigned long pos;

	if (!db->map[i].addr)
	    continue;

	pos = (unsigned long) db->map[i].addr;
	if (val >= pos && val < pos + db->blkSize)
	    return ((unsigned long) (val - pos));
    }

    return (0);
}

void
db_lockDB(db_handle * db)
{
    struct flock lock = { F_WRLCK, 0, SEEK_SET, 0 };
    fcntl(db->fd, F_SETLKW, &lock);
}

void
db_unlockDB(db_handle * db)
{
    struct flock lock = { F_UNLCK, 0, SEEK_SET, 0 };
    fcntl(db->fd, F_SETLKW, &lock);
}

--- NEW FILE: index.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */



/* Given a new index, this will format the block for inital use */

#include <stdlib.h>
#include <string.h>

#include <par/pardb.h>
#include "database.h"

#ifdef DEBUG
#define DPRINT(str, args...) printf("DEBUG: " str, ## args)
#else
#define DPRINT(str, args...)
#endif

#define GET_INDEX_INFO(block) ((index_info_t *) block)

void
db_formatIndex(db_handle * db, void *block, int offset, int size)
{

    index_t *ptr = 0;

    void *start = (void *) ((ulong) block + offset);

    int pos;

    int next;
    index_info_t *info = (index_info_t *) start;

    bzero(start, size);

    info->ident = DB_INDEX_BLOCK;
    info->free = offset + sizeof(index_info_t);
    info->next = 0;

    pos = info->free;
    next = pos + sizeof(index_t);

    while ((size - pos) > sizeof(index_t)) {
	ptr = (index_t *) (block + pos);
	ptr->peer = next;
	pos += sizeof(index_t);
	next += sizeof(index_t);
    }

    if (ptr)
	ptr->peer = 0;
}

static index_t *
db_newIndexNode(db_handle * db, index_t * hint, char *keyword)
{

    void *block;
    index_t *index;
    index_info_t *info = 0;
    int offset;

    if (hint)
	offset = db_getFileOffset(db, hint);
    else
	offset = db->index;

    if (!offset)
	return (0);

    while (offset) {
	int start = GET_BLOCK(db, offset);
	DPRINT("Mapping the block %d in db_newIndexMode()\n",
	       GET_BLOCK(db, offset));

	if (!(block = db_mapBlock(db, GET_BLOCK(db, offset))))
	    return (0);

	if (start == 0)
	    info = GET_INDEX_INFO((void *) ((ulong) block + db->index));
	else
	    info = GET_INDEX_INFO(block);

	if (info->free)
	    goto initIndex;
	offset = info->next;
    }

    if (!(info->next = db_addBlock(db)))
	return (0);


    DPRINT("Mapping block %d in db_newIndexMode()\n",
	   GET_BLOCK(db, info->next));

    block = db_mapBlock(db, GET_BLOCK(db, info->next));

    if (!block)
	return (0);

    /* Format the new index block */
    db_formatIndex(db, block, 0, db->blkSize);

    info = GET_INDEX_INFO(block);

  initIndex:

    index = (index_t *) (block + info->free);
    info->free = index->peer;
    bzero(index, sizeof(index_t));

    strncpy(index->keyword, keyword, PAR_DB_KEYWORD_SIZE);
    index->keyword[PAR_DB_KEYWORD_SIZE] = 0;

    SET_ERRNO(PARDB_SUCCESS);
    return (index);
}

/* Return the first index node in the system (which is always the first index of the first block) */

index_t *
db_getFirstIndex(db_handle * db)
{

    index_t *index;
    void *block;

    if (!db->index) {
	SET_ERRNO(PARDB_BADDB);
	return (0);
    }
    DPRINT("Mapping block %d in db_getFirstIndex()\n",
	   GET_BLOCK(db, db->index));
    block = db_mapBlock(db, GET_BLOCK(db, db->index));
    if (!block)
	return (0);

    index =
	(index_t *) (block + GET_BLOCK_OFFSET(db, db->index) +
		     sizeof(index_info_t));
    if (index->keyword[0] == 0) {
	SET_ERRNO(PARDB_NOTFOUND);
	return (0);
    }

    SET_ERRNO(PARDB_SUCCESS);
    return (index);
}

/* Utility function to get a node living at the specified offset */
static index_t *
db_getIndexNode(db_handle * db, int offset)
{

    int start = GET_BLOCK(db, offset);
    index_info_t *info;
    void *block;

    DPRINT("Mapping block %d in db_getIndexNode()\n", start);
    block = db_mapBlock(db, start);
    if (!block)
	return (0);

    if (start == 0)
	info = GET_INDEX_INFO((void *) ((ulong) block + db->index));
    else
	info = GET_INDEX_INFO(block);

    if (info->ident != DB_INDEX_BLOCK) {
	SET_ERRNO(PARDB_BADBLOCK);
	return (0);
    }

    SET_ERRNO(PARDB_SUCCESS);
    return ((index_t *) (block + GET_BLOCK_OFFSET(db, offset)));
}

/* Get the child of the given index */
index_t *
db_getChild(db_handle * db, index_t * node)
{
    if (!node || !node->child)
	return (0);
    return (db_getIndexNode(db, node->child));
}

index_t *
db_getPeer(db_handle * db, index_t * node)
{
    if (!node || !node->peer) {
	SET_ERRNO(PARDB_NOTFOUND);
	return (0);
    }
    SET_ERRNO(PARDB_SUCCESS);
    return (db_getIndexNode(db, node->peer));
}

/* Set the specified index to be the child of the specified parent */

void
db_setChild(db_handle * db, index_t * node, index_t * index)
{

    if (!node)
	return;

    if (!index)
	node->child = 0;
    else
	node->child = db_getFileOffset(db, index);
}

/* Set the specified index to be the peer of the specified node */

void
db_setPeer(db_handle * db, index_t * node, index_t * index)
{

    if (!node)
	return;

    if (!index)
	node->peer = 0;
    else
	node->peer = db_getFileOffset(db, index);
}

index_t *
db_addFirstIndex(db_handle * db, char *keyword)
{

    index_t *index;
    index_info_t *info;
    int offset;
    void *block, *iptr;

    if (!db->index) {
	SET_ERRNO(PARDB_BADDB);
	return (0);
    }

    DPRINT("Mapping block %d in db_addFirstIndex()\n",
	   GET_BLOCK(db, db->index));
    block = db_mapBlock(db, GET_BLOCK(db, db->index));

    if (!block)
	return (0);

    offset = GET_BLOCK_OFFSET(db, db->index) + sizeof(index_info_t);

    iptr = (void *) ((ulong) block + GET_BLOCK_OFFSET(db, db->index));

    info = GET_INDEX_INFO(iptr);

    index = (index_t *) (block + offset);

    if (index->keyword[0]) {
	SET_ERRNO(PARDB_DATAEXISTS);
	return (0);		/* If the first index is set, return 0 */
    }

    if (info->free != offset) {
	SET_ERRNO(PARDB_BADBLOCK);
	return (0);
    }

    info->free = index->peer;
    bzero(index, sizeof(index_t));

    strncpy(index->keyword, keyword, PAR_DB_KEYWORD_SIZE);
    index->keyword[PAR_DB_KEYWORD_SIZE] = 0;

    SET_ERRNO(PARDB_SUCCESS);
    return (index);
}

index_t *
db_addPeer(db_handle * db, index_t * prev, char *keyword)
{
    index_t *index = db_newIndexNode(db, prev, keyword);

    if (!index) {
	SET_ERRNO(PARDB_NOTFOUND);
	return (0);
    }
    db_setPeer(db, prev, index);

    SET_ERRNO(PARDB_SUCCESS);
    return (index);
}

index_t *
db_addChild(db_handle * db, index_t * parent, char *keyword)
{

    index_t *index = db_newIndexNode(db, parent, keyword);

    if (!index) {
	SET_ERRNO(PARDB_NOTFOUND);
	return (0);
    }
    db_setChild(db, parent, index);

    SET_ERRNO(PARDB_SUCCESS);
    return (index);
}

int
db_setIndexDataOffset(db_handle * db, int offset, int data)
{

    index_t *index = db_getIndexNode(db, offset);
    if (!index) {
	SET_ERRNO(PARDB_NOTFOUND);
	return (-1);
    }

    DPRINT("Setting data for %s to %d\n", index->keyword, data);

    index->data = data;
    SET_ERRNO(PARDB_SUCCESS);
    return (0);
}

int
db_removeIndex(db_handle * db, index_t * index)
{

    index_info_t *info;
    if (!index) {
	SET_ERRNO(PARDB_NOTFOUND);
	return (-1);
    }

    info = GET_INDEX_INFO(BLOCK_POINTER_START(db, index));

    /* Remove the data block */
    db_removeData(db, index->data);

    /* Now, clear out the index */
    bzero(index, sizeof(index_t));

    /* Set the pointer to the next free space */
    index->peer = info->free;
    info->free = BLOCK_POINTER_OFFSET(db, index);

    SET_ERRNO(PARDB_SUCCESS);
    return (0);
}

--- NEW FILE: tree.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <par/pardb.h>
#include "database.h"

void
tree_addData(tree_t * node, void *data, ushort size, ushort type)
{

    unsigned short lsize = size;
    if (size == 0)
	return;

    /* Add a byte for the NULL */
    if (type == PAR_TEXT) {
	if (((unsigned char *) data)[size - 1] != 0)
	    lsize = size + 1;
    }

    if (node->size && node->data) {
	if (node->size != lsize) {
	    void *ptr = realloc(node->data, lsize);
	    if (!ptr)
		return;
	    node->data = ptr;
	}
    } else {
	node->data = (void *) calloc(lsize, 1);
    }

    node->size = lsize;
    node->type = type;

    if (node->data) {
	if (type == PAR_TEXT)
	    strncpy((char *) node->data, data, size);
	else
	    memcpy(node->data, data, size);
    }
}

tree_t *
tree_addNode(tree_t * parent, char *keyword)
{

    tree_t *node;

    if (!parent) {
	SET_ERRNO(PARDB_BADNODE);
	return (0);
    }

    if (!parent->child)
	node = parent->child = (tree_t *) calloc(sizeof(tree_t), 1);
    else {
	tree_t *ptr = parent->child;
	while (ptr->peer)
	    ptr = ptr->peer;

	node = ptr->peer = (tree_t *) calloc(sizeof(tree_t), 1);
    }

    if (!node) {
	SET_ERRNO(PARDB_MEMERR);
	return (0);
    }

    node->peer = 0;
    node->child = 0;

    strncpy(node->keyword, keyword, sizeof(node->keyword) - 1);

    SET_ERRNO(PARDB_SUCCESS);
    return (node);
}

tree_t *
tree_findChildNode(tree_t * parent, char *keyword)
{

    tree_t *node;
    if (!parent) {
	SET_ERRNO(PARDB_BADNODE);
	return (0);
    }

    node = parent->child;
    while (node) {
	if (!strcmp(node->keyword, keyword))
	    return (node);
	node = node->peer;
    }

    return (0);
}

int
tree_recursiveBuild(db_handle * db, index_t * top, tree_t * tree)
{

    int ret;
    index_t *node = top;

    /* At this point we are succesful.  */
    SET_ERRNO(PARDB_SUCCESS);

    while (node) {

	ushort type;
	ushort size;

	tree_t *local;
	index_t *child;
	unsigned char *data;

	ret = db_getDataInfo(db, node, &size, 0);
	if (ret == -1 && pardb_errno != PARDB_NODATA)
	    return -1;

	local = tree_addNode(tree, node->keyword);

	if (ret > 0) {
	    if (!(data = alloca(size + 1))) {
		SET_ERRNO(PARDB_MEMERR);
		return (-1);
	    }

	    bzero(data, size + 1);

	    ret = db_getData(db, node, (void *) data, size, &type);
	    if (ret == -1)
		return -1;

	    tree_addData(local, data, ret, type);
	}

	child = db_getChild(db, node);
	if (child)
	    ret = tree_recursiveBuild(db, db_getChild(db, node), local);

	if (ret == -1)
	    return (-1);

	node = db_getPeer(db, node);
    }

    return (0);
}


int
tree_recursiveSave(db_handle * db, tree_t * head, char *name)
{

    tree_t *node = head;

    SET_ERRNO(PARDB_SUCCESS);

    while (node) {

	char *lname;

	if (!name) {
	    lname = alloca(strlen(node->keyword) + 1);
	    strcpy(lname, node->keyword);
	} else {
	    lname = alloca(strlen(name) + strlen(node->keyword) + 2);
	    sprintf(lname, "%s.%s", name, node->keyword);
	}

	if (db_addNode(db, lname, node->data, node->size, node->type) == -1)
	    return (-1);

	if (node->child)
	    if (tree_recursiveSave(db, node->child, lname) == -1)
		return (-1);

	node = node->peer;
    }

    return (0);
}

tree_t *
tree_newTree(void)
{
    tree_t *local = (tree_t *) calloc(sizeof(tree_t), 1);

    if (!local)
	SET_ERRNO(PARDB_MEMERR);
    else
	SET_ERRNO(PARDB_SUCCESS);

    return (local);
}

void
tree_recursiveFree(tree_t * tree)
{

    tree_t *node = tree->child;

    /* Free my children */

    while (node) {
	tree_t *peer = node->peer;
	tree_recursiveFree(node);
	node = peer;
    }

    /* Free my data */
    if (tree->data)
	free(tree->data);

    /* Finally, free this node */
    free(tree);
}

--- NEW FILE: data.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/* Given a new data block, this will format the block for inital use */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <par/pardb.h>
#include "database.h"

#ifdef DEBUG
#define DPRINT(str, args...) printf("DEBUG: " str, ## args)
#else
#define DPRINT(str, args...)
#endif

#define GET_DATA_INFO(block)  ((data_info_t *) block)
#define GET_FREE_SPACE(db, offset) (db->blkSize - offset)

void
db_formatData(db_handle * db, void *block, int offset, int size)
{

    void *start = (void *) (block + offset);
    data_info_t *info = (data_info_t *) start;

    bzero(start, size);

    info->ident = DB_DATA_BLOCK;
    info->free = offset + sizeof(data_info_t);
    info->next = 0;
}

/* Add a new data node to the system */

static data_t *
db_newDataNode(db_handle * db, index_t * index, unsigned short size,
	       unsigned short type)
{

    void *block;
    data_t *data;
    data_info_t *info = 0;

    int offset;

#ifdef HAVE_MMAPBUG
    /* We need to align the size so malloc accesses are correct */
    if ((size % 4))
	size += (4 - (size % 4));
#endif

    if (db->dataCache)
	offset = db->dataCache;
    else
	offset = db->data;

    while (offset) {
	DPRINT("Mapping block %d in db_newDataNode()\n",
	       GET_BLOCK(db, offset));

	if (!(block = db_mapBlock(db, GET_BLOCK(db, offset))))
	    return (0);

	info = GET_DATA_INFO(block);

	if (GET_FREE_SPACE(db, info->free) > (size + DATA_ITEM_LEN))
	    goto initData;

	offset = info->next;
    }

    if (!info)
	return (0);
    if (!(info->next = db_addBlock(db)))
	return (0);

    DPRINT("Mapping block %d in db_newDataNode()\n",
	   GET_BLOCK(db, info->next));
    block = db_mapBlock(db, GET_BLOCK(db, info->next));
    if (!block)
	return (0);

    /* Format the new index block */
    db_formatData(db, block, 0, db->blkSize);
    info = GET_DATA_INFO(block);

  initData:
    data = (data_t *) ((ulong) block + info->free);

    data->type = type;
    data->size = (unsigned short) size;

    data->index = db_getFileOffset(db, index);
    index->data = db_getFileOffset(db, data);

    info->free += size + DATA_ITEM_LEN;

    SET_ERRNO(PARDB_SUCCESS);
    return (data);
}

static data_t *
db_getDataNode(db_handle * db, int offset)
{

    void *block;

    if (!offset)
	return (0);

    DPRINT("Mapping block %d in db_getDataNode()\n", GET_BLOCK(db, offset));

    block = db_mapBlock(db, GET_BLOCK(db, offset));

    if (!block)
	return (0);


    SET_ERRNO(PARDB_SUCCESS);

    return ((data_t *) (block + GET_BLOCK_OFFSET(db, offset)));
}

/* Given a start and a offset, move the rest of the data block */

static void
db_moveData(db_handle * db, void *block, int start, int offset)
{

    int ptr = start;

    data_info_t *info = GET_DATA_INFO(block);

    int length;
    void *src, *dest;

    /* First, go through and update all of the index blocks */
    ptr = GET_BLOCK_OFFSET(db, start);

    while (ptr < info->free) {
	data_t *local = (data_t *) (block + ptr);
	db_setIndexDataOffset(db, local->index,
			      GET_BLOCK(db, start) + ptr + offset);
	ptr += (local->size + DATA_ITEM_LEN);
    }

    length = info->free - GET_BLOCK_OFFSET(db, start);
    src = (void *) (block + GET_BLOCK_OFFSET(db, start));
    dest = (void *) (block + GET_BLOCK_OFFSET(db, start) + offset);

    /* Now, actually move the block */
    memmove(dest, src, length);

    /* Update the free block here */
    info->free += offset;
}

int
db_removeData(db_handle * db, int offset)
{

    void *block;
    data_t *data;

    if (!offset) {
	SET_ERRNO(PARDB_BADOFFSET);
	return (-1);
    }
    DPRINT("Mapping block %d in db_removeData()\n", GET_BLOCK(db, offset));
    block = db_mapBlock(db, GET_BLOCK(db, offset));

    if (!block)
	return (-1);

    data = (data_t *) (block + GET_BLOCK_OFFSET(db, offset));

    db_moveData(db, block, offset + data->size + DATA_ITEM_LEN,
		-(data->size + DATA_ITEM_LEN));

    SET_ERRNO(PARDB_SUCCESS);
    return (0);
}

int
db_setData(db_handle * db, index_t * index, void *value, unsigned short size,
	   unsigned short type)
{

    data_t *data = 0;

    if (!index->data) {
	if (!(data = db_newDataNode(db, index, size, type)))
	    return (-1);
    } else {

	/* Try to modify the existing node */
	if (!(data = db_getDataNode(db, index->data)))
	    return (-1);

	if ((size > data->size)) {

	    int diff = size - data->size;
	    void *block = BLOCK_POINTER_START(db, data);
	    data_info_t *info = GET_DATA_INFO(block);

	    /* Check to see if we have the appropriate space available */
	    if (GET_FREE_SPACE(db, info->free) > diff) {
		db_moveData(db, block,
			    index->data + data->size + DATA_ITEM_LEN, diff);
		data->size = size;
	    } else {
		/* Delete the current data block */
		db_removeData(db, index->data);
		index->data = 0;

		/* And get a new one */
		data = db_newDataNode(db, index, size, type);
		if (!data)
		    return (-1);
	    }
	}
    }

    if ((data->type != type)) {
	SET_ERRNO(PARDB_BADTYPE);
	return (-1);
    }

    /* Zero out the existing space */

    if (size) {
	bzero((unsigned char *) &data->value, size);
	memcpy(&data->value, value, size);
    }

    SET_ERRNO(PARDB_SUCCESS);
    return (size);
}

int
db_getData(db_handle * db, index_t * index, void *value, unsigned short size,
	   unsigned short *type)
{

    unsigned short copy_size = 0;

    data_t *data = 0;

    if (!index->data) {
	SET_ERRNO(PARDB_NODATA);
	return (-1);
    }

    data = db_getDataNode(db, index->data);

    if (!data) {
	SET_ERRNO(PARDB_NODATA);
	return (-1);
    }

    /* If there is no data, than thats not an error */
    if (!value || !size) {
	SET_ERRNO(PARDB_SUCCESS);
	return (0);
    }

    if (data->size > size)
	copy_size = size;
    else
	copy_size = data->size;

    if (!copy_size) {
	SET_ERRNO(PARDB_SUCCESS);
	return (0);
    }

    memcpy(value, &data->value, copy_size);

    if (type)
	*type = data->type;

    SET_ERRNO(PARDB_SUCCESS);
    return (copy_size);
}

int
db_getDataInfo(db_handle * db, index_t * index, unsigned short *size,
	       unsigned short *type)
{

    data_t *data;

    if (!index->data) {
	SET_ERRNO(PARDB_NODATA);
	return (-1);
    }

    data = db_getDataNode(db, index->data);

    if (!data)
	return (-1);
    if (size)
	*size = data->size;
    if (type)
	*type = data->type;

    SET_ERRNO(PARDB_SUCCESS);
    return (0);
}

--- NEW FILE: Makefile ---
#par/lib/Makefile

LIB_STATIC=platform-objs/libpar.a
LIB_SHARED=platform-objs/libpar.so

NATIVE_LIB_STATIC=native-objs/libpar.a

PREBUILD_EXTRAS = $(CURDIR)/native-objs $(CURDIR)/platform-objs

SRC  := ${shell ls *.c}
OBJS := $(SRC:%.c=platform-objs/%.o)
NATIVE_OBJS := $(SRC:%.c=native-objs/%.o)

INCLUDES=-I./include

CFLAGS ?= 
CFLAGS +=-DHAVE_MMAPBUG -DDEFPARDB="\"$(PAR_DB)\""
NATIVE_CFLAGS=-DHAVE_MMAPBUG -DDEFPARDB="\"$(PAR_DB)\""

include $(BASE_DIR)/Rules.make

$(CURDIR)/platform-objs $(CURDIR)/native-objs:
	@ mkdir -p $@

clean:
	@ rm -rf $(CURDIR)/native-objs $(CURDIR)/platform-objs



--- NEW FILE: db_api.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */



#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <par/pardb.h>
#include "database.h"

/* This is the global error code variable */
int pardb_errno = PARDB_SUCCESS;

/* Add a new node to the system */

int
db_addNode(db_handle * db, char *name, void *data, unsigned short size,
	   unsigned short type)
{

    int ret = 0;

    char *localname, *pointer, *keyword;
    index_t *index = 0, *prev = 0;

    if (db_getAccess(db) != PAR_DB_MODE_RW) {
	SET_ERRNO(PARDB_BADMODE);
	return (-1);
    }

    /* Lock the whole database at this point */
    /* And set the system up for writing     */

    db_lockDB(db);
    db_setMode(db, PAR_DB_WRITE_BLOCK);

    index = db_getFirstIndex(db);

    /* The recursive function will mangle the name */
    /* so we need to save a backup */

    localname = (char *) malloc(strlen(name) + 1);
    pointer = strcpy(localname, name);

    /* The first keyword is the toplevel */
    keyword = strip_keyword(&pointer);

    /* Find the correct toplevel node */

    while (index) {

	if (index->keyword[0] == 0)
	    break;

	if (strcmp(index->keyword, keyword) == 0) {

	    if (pointer)
		ret = db_recursiveAdd(db, index, pointer, data, size, type);
	    else
		ret = db_setData(db, index, data, size, type);

	    free(localname);

	    /* Ensure that all of the open write blocks are freed at this point */

	    db_flushWrite(db);
	    db_setMode(db, PAR_DB_READ_BLOCK);
	    db_unlockDB(db);

	    return (ret);
	}

	prev = index;
	index = db_getPeer(db, index);
    }

    if (!prev)
	index = db_addFirstIndex(db, keyword);
    else
	index = db_addPeer(db, prev, keyword);

    if (!index)
	return (-1);

    if (pointer)
	ret = db_recursiveAdd(db, index, pointer, data, size, type);
    else
	ret = db_setData(db, index, data, size, type);

    free(localname);

    db_flushWrite(db);
    db_setMode(db, PAR_DB_READ_BLOCK);
    db_unlockDB(db);

    return (ret);
}

static index_t *
db_getNode(db_handle * db, char *name)
{

    char *local = name, *keyword;
    index_t *index = db_getFirstIndex(db);

    /* Find the toplevel node */
    keyword = strip_keyword(&local);

    while (index) {
	if (strcmp(index->keyword, keyword) == 0) {

	    if (local)
		return (db_recursiveFind(db, index, local));
	    else {
		SET_ERRNO(PARDB_SUCCESS);
		return (index);
	    }
	}

	index = db_getPeer(db, index);
    }

    SET_ERRNO(PARDB_NOTFOUND);
    return (0);
}

int
db_getChildCount(db_handle * db, char *parent)
{

    index_t *child, *index;
    int count = 0;
    char *localname = (char *) malloc(strlen(parent) + 1);

    strcpy(localname, parent);
    index = db_getNode(db, localname);
    free(localname);

    if (!index)
	return (-1);

    child = db_getChild(db, index);
    while (child) {
	count++;
	child = db_getPeer(db, child);
    }

    return (count);
}

int
db_getChildList(db_handle * db, char *parent, char **list, int maxsize)
{

    int count = 0;
    index_t *child, *index;
    char *localname = (char *) malloc(strlen(parent) + 1);

    strcpy(localname, parent);

    index = db_getNode(db, localname);
    free(localname);

    child = db_getChild(db, index);

    while (child && count < maxsize) {
	list[count] = (char *) calloc(strlen(child->keyword) + 1, 1);
	if (!list[count])
	    return (-1);

	strcpy(list[count], child->keyword);
	child = db_getPeer(db, child);
	count++;
    }

    return (count);
}

int
db_getFirstChild(db_handle * db, char *parent, char *name, int size)
{

    int csize;

    index_t *index, *child;
    char *localname = (char *) malloc(strlen(parent) + 1);
    strcpy(localname, parent);

    index = db_getNode(db, localname);
    free(localname);

    if (!index)
	return (-1);

    child = db_getChild(db, index);
    if (!child)
	return (0);

    if (size > strlen(child->keyword))
	csize = strlen(child->keyword);
    else
	csize = size;

    strncpy(name, child->keyword, csize);
    return (size);
}

int
db_getNextChild(db_handle * db, char *parent, char *child, char *name,
		int size)
{

    index_t *index, *cindex;
    char *localname = (char *) malloc(strlen(parent) + 1);

    strcpy(localname, parent);

    index = db_getNode(db, localname);
    free(localname);

    if (!index)
	return (-1);

    cindex = db_getChild(db, index);

    while (cindex) {
	int csize;

	if (strcmp(cindex->keyword, child) == 0) {
	    cindex = db_getPeer(db, cindex);
	    if (!cindex)
		return (0);
	    if (size > strlen(cindex->keyword))
		csize = strlen(cindex->keyword);
	    else
		csize = size;

	    strncpy(name, cindex->keyword, csize);
	    return (size);
	}

	cindex = db_getPeer(db, cindex);
    }

    return (0);
}

/* Search the database for the specified node */

int
db_findNode(db_handle * db, char *name, void *data,
	    unsigned short size, unsigned short *type)
{

    index_t *index;
    char *localname;

    /* Save the name because we will mangle it */

    localname = (char *) malloc(strlen(name) + 1);
    strcpy(localname, name);

    index = db_getNode(db, localname);
    free(localname);

    if (!index) {
	SET_ERRNO(PARDB_NOTFOUND);
	return (-1);
    }

    return (db_getData(db, index, data, size, type));
}

int
db_nodeExists(db_handle * db, char *name)
{

    index_t *index;
    char *localname;

    /* Save the name because we will mangle it */

    localname = (char *) malloc(strlen(name) + 1);
    strcpy(localname, name);

    index = db_getNode(db, localname);
    free(localname);
    if (!index)
	return (0);
    return (1);
}

db_handle *
db_newDB(char *filename, int open_mode)
{

    int mode = 0;
    int perm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;

    db_info_t *info;
    db_handle *local;
    void *index, *data;

    int fd, offset;

    /* Get the optimal block size for this system */
    int blkSize = getpagesize();

    /* Create the exclusive file, and give it user and group write access */

    if (mode == PAR_DB_EXCLUSIVE)
	mode = O_RDWR | O_CREAT | O_EXCL;
    else
	mode = O_RDWR | O_CREAT | O_TRUNC;

    fd = open(filename, mode, perm);

    /* Set the appropriate error code */

    if (!fd) {
	switch (errno) {
	case EEXIST:
	    SET_ERRNO(PARDB_FILEEXISTS);
	    break;

	case EACCES:
	    SET_ERRNO(PARDB_FILEACCESS);
	    break;

	default:
	    SET_ERRNO(PARDB_FILEERR);
	    break;
	}

	return (0);
    }

    /* Allocate the database structure */

    if (!(local = db_allocDB(fd, blkSize, 0))) {
	close(fd);
	return (0);
    }

    /* When a new database is created, it is always read/write */
    db_setAccess(local, PAR_DB_MODE_RW);

    /* Lock it to be on the safe side */

    db_lockDB(local);
    db_setMode(local, PAR_DB_WRITE_BLOCK);

    /* Create and map the first index block */
    if ((offset = db_addBlock(local)) == -1)
	goto exitNewDB;
    if (!(index = db_mapBlock(local, offset)))
	goto exitNewDB;

    /* Now, add the inital header stuff for the first index block */

    info = (db_info_t *) index;

    info->magic = PARDB_MAGIC;
    info->blksize = blkSize;

    info->index = sizeof(db_info_t);

    if ((info->data = db_addBlock(local)) == -1)
	goto exitNewDB;

    if (!(data = db_mapBlock(local, info->data)))
	goto exitNewDB;

    /* Next, format the first index and data blocks */
    db_formatIndex(local, index, sizeof(db_info_t),
		   blkSize - sizeof(db_info_t));

    db_formatData(local, data, 0, blkSize);

    local->index = info->index;
    local->data = info->data;

    db_flushWrite(local);
    db_setMode(local, PAR_DB_READ_BLOCK);

    db_unlockDB(local);

    SET_ERRNO(PARDB_SUCCESS);
    return (local);

  exitNewDB:

    db_freeDB(local);
    close(fd);

    /* The errno will be set by the appropriate call */
    return (0);
}

db_handle *
db_openDB(char *filename, unsigned short mode)
{

    db_handle *local;
    db_info_t info;

    int fd;

    struct stat statt;

    /* Stat the file, make sure it exists and get a maximum file size */

    if (stat(filename, &statt) < 0) {
	SET_ERRNO(PARDB_NOFILE);
	return (0);
    }

    /* Open the file */
    if (mode == PAR_DB_MODE_RW)
	fd = open(filename, O_RDWR);
    else
	fd = open(filename, O_RDONLY);

    if (!fd) {
	SET_ERRNO(PARDB_FILEERR);
	return (0);
    }

    /* Read the first index info block */

    if (read(fd, &info, sizeof(info)) == -1) {
	SET_ERRNO(PARDB_IOERR);
	close(fd);
	return (0);
    }

    if (info.magic != PARDB_MAGIC) {
	SET_ERRNO(PARDB_BADDB);
	close(fd);
	return (0);
    }

    /* Allocate the database structure */

    if (!(local = db_allocDB(fd, info.blksize, statt.st_size))) {
	close(fd);
	return (0);
    }

    /* Set the pointers to the data */
    local->index = info.index;
    local->data = info.data;

    db_setAccess(local, mode);
    db_setMode(local, PAR_DB_READ_BLOCK);

    SET_ERRNO(PARDB_SUCCESS);
    return (local);
}

void
db_closeDB(db_handle * db)
{

    int i;

    if (!db)
	return;

    /* Close the database */
    /* First step, unmap all the mapped items */

    for (i = 0; i < db->mapSize; i++)
	if (db->map[i].addr)
	    db_unmapBlock(db, i);

    free(db->map);
    close(db->fd);
    free(db);
}

/* Search the database for the specified node */

int
db_delNode(db_handle * db, char *name)
{

    char *localname, *pointer, *keyword;
    index_t *index = 0, *prev = 0;

    if (db_getAccess(db) != PAR_DB_MODE_RW) {
	SET_ERRNO(PARDB_BADMODE);
	return (-1);
    }

    /* Lock the DB while we are doing this */

    db_lockDB(db);
    db_setMode(db, PAR_DB_WRITE_BLOCK);

    index = db_getFirstIndex(db);

    /* Save the name because we will mangle it */

    localname = (char *) malloc(strlen(name) + 1);
    pointer = strcpy(localname, name);

    /* Find the toplevel node */
    keyword = strip_keyword(&pointer);

    while (index) {

	if (strcmp(index->keyword, keyword) == 0) {

	    if (pointer)
		db_recursiveDel(db, index, pointer);
	    else {

		index_t *peer = db_getPeer(db, index);
		db_removeIndex(db, index);

		if (prev)
		    db_setPeer(db, prev, peer);
	    }

	    db_flushWrite(db);
	    db_setMode(db, PAR_DB_READ_BLOCK);
	    db_unlockDB(db);

	    free(localname);
	    return (0);
	}

	prev = index;
	index = db_getPeer(db, index);
    }

    db_flushWrite(db);
    db_setMode(db, PAR_DB_READ_BLOCK);
    db_unlockDB(db);

    free(localname);
    return (0);
}

/* Random utility functions */

char *
db_getDefaultDB(void)
{
    char *ptr = getenv("PARDB");
    return ptr ? ptr : DEFPARDB;
}

int
db_getDataSize(db_handle * db, char *name)
{

    unsigned short size = 0;
    index_t *index;
    char *localname = (char *) malloc(strlen(name) + 1);
    strcpy(localname, name);

    index = db_getNode(db, localname);
    free(localname);

    if (!index)
	return (-1);

    if (db_getDataInfo(db, index, &size, 0) == -1)
	return (-1);
    else
	return (size);
}

tree_t *
db_newTree(tree_t ** head)
{
    *head = tree_newTree();
    return (*head);
}

void
db_freeTree(tree_t * tree)
{
    tree_recursiveFree(tree);
}

/* Load the entire database into a tree */
/* The top node in the tree is just a place holder to unify */
/* all of the various toplevel nodes */

int
db_loadTree(db_handle * db, tree_t * head)
{
    return (tree_recursiveBuild(db, db_getFirstIndex(db), head));
}

/* Save a tree into the database file */

int
db_saveTree(db_handle * db, tree_t * head)
{
    int ret;
    tree_t *child = head->child;

    if (db_getAccess(db) != PAR_DB_MODE_RW) {
	SET_ERRNO(PARDB_BADMODE);
	return (-1);
    }
    if (!child)
	return (-1);

    db_lockDB(db);
    db_setMode(db, PAR_DB_WRITE_BLOCK);

    ret = tree_recursiveSave(db, child, 0);

    db_flushWrite(db);
    db_setMode(db, PAR_DB_READ_BLOCK);
    db_unlockDB(db);

    return (ret);
}

--- NEW FILE: database.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef _DATABASE_H_
#define _DATABASE_H_

#include <stddef.h>

#define PARDB_MAGIC 0x2323	/* FNORD! */

#undef DEBUG

#ifdef DEBUG
#include <stdio.h>

#define DPRINT(str, args...) printf("DEBUG: " str, ## args)
#else
#define DPRINT(str, args...)
#endif

#define DB_DATA_BLOCK  0x01
#define DB_INDEX_BLOCK 0x02

/* Contains all the important information about the database */

typedef struct
{
    unsigned short ident;
    short free;
    unsigned long next;
    unsigned long padding[6];
}
index_info_t;

typedef struct
{
    unsigned short ident;
    unsigned short free;
    unsigned long next;
}
data_info_t;


typedef struct
{
    char keyword[PAR_DB_KEYWORD_SIZE + 1];
    unsigned long peer;
    unsigned long child;
    unsigned long data;
}
index_t;

typedef struct
{
    unsigned short type;
    unsigned short size;
    unsigned long index;
    unsigned char value;
}
data_t;

/* This is the length of the "header" on data structure (not including the length) */

/* #define DATA_ITEM_LEN ( sizeof(unsigned short) + sizeof(unsigned short) + sizeof(unsigned long) */
#define DATA_ITEM_LEN ( offsetof(data_t, value) )

typedef struct
{
    unsigned short magic;
    unsigned short blksize;
    unsigned long index;
    unsigned long data;

    unsigned long padding[5];
}
db_info_t;

#ifdef HAVE_MMAPBUG
void *db_getBlockStart(db_handle * db, void *ptr);
unsigned long db_getBlockOffset(db_handle * db, void *ptr);
#endif

#ifdef HAVE_MMAPBUG
#define BLOCK_POINTER_START(db, value) (db_getBlockStart(db, value))
#else
#define BLOCK_POINTER_START(db, value) ((void *) ((ulong) value - ((ulong) value % db->blkSize)))
#endif

#ifdef HAVE_MMAPBUG
#define BLOCK_POINTER_OFFSET(db, value) (db_getBlockOffset(db, value))
#else
#define BLOCK_POINTER_OFFSET(db, value) ((unsigned long) value % db->blkSize)
#endif

#define GET_BLOCK(db, offset) (offset - (offset % db->blkSize))
#define GET_BLOCK_OFFSET(db, offset) (offset % db->blkSize)

/* Utilities */

char *strip_keyword(char **name);

#define db_setMode(db, m)   db->mode = m
#define db_setAccess(db, acc)  db->access = acc

#define db_getAccess(db)       (db->access)

/* database.c */

int db_recursiveAdd(db_handle *, index_t *, char *name, void *data,
		    ushort size, ushort type);
index_t *db_recursiveFind(db_handle *, index_t *, char *name);
int db_recursiveDel(db_handle *, index_t *, char *name);
void db_freeDB(db_handle * db);

db_handle *db_allocDB(int fd, int bsize, int length);


/* index.c */

index_t *db_getFirstIndex(db_handle * db);
index_t *db_getPeer(db_handle * db, index_t * peer);
index_t *db_getChild(db_handle * db, index_t * parent);
index_t *db_addChild(db_handle * db, index_t * parent, char *keyword);
index_t *db_addPeer(db_handle * db, index_t * prev, char *keyword);
index_t *db_addFirstIndex(db_handle * db, char *keyword);

void db_setPeer(db_handle * db, index_t * peer, index_t * index);
void db_setChild(db_handle * db, index_t * node, index_t * index);

void db_formatIndex(db_handle * db, void *block, int offset, int size);
int db_setIndexDataOffset(db_handle * db, int offset, int data);
int db_removeIndex(db_handle * db, index_t * index);

/* data.c */

void db_formatData(db_handle * db, void *block, int offset, int size);
int db_setData(db_handle * db, index_t * index, void *value, ushort size,
	       ushort type);
int db_getData(db_handle * db, index_t * index, void *value, ushort size,
	       ushort * type);
int db_removeData(db_handle * db, int offset);

int db_getDataInfo(db_handle * db, index_t * index, ushort * size,
		   ushort * type);

/* io.c */

int db_addBlock(db_handle * db);
void *db_mapBlock(db_handle * db, int offset);
void db_unmapBlock(db_handle * db, int block);
unsigned long db_getFileOffset(db_handle * db, void *ptr);

void db_flushWrite(db_handle * db);
void db_lockDB(db_handle * db);
void db_unlockDB(db_handle * db);

/* tree.c */

tree_t *tree_newTree(void);
void tree_freeTree(tree_t * tree);

int tree_recursiveBuild(db_handle * db, index_t * top, tree_t * tree);
int tree_recursiveSave(db_handle * db, tree_t * head, char *name);
void tree_recursiveFree(tree_t * tree);

tree_t *tree_addNode(tree_t * parent, char *keyword);
void tree_addData(tree_t * node, void *data, ushort size, ushort type);

tree_t *tree_findChildNode(tree_t * parent, char *keyword);

#endif

--- NEW FILE: par_api.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <par/pardb.h>
#include <par/par.h>

#define APPLICATION_NAME "application"
#define CAPABILITY_NAME  "capabilities"
#define SCREENTOP_NAME   "screentop"

#define GLOBAL_PREF_NAME "global.preferences"

/* Get a global preference from the system */

/* Size here is really only for the text type */

int
par_getGlobalPref(db_handle * db, char *category, char *keyword, int type,
		  void *dest, int size)
{

    int ret;

    unsigned short gsize;
    unsigned short gtype;

    char *name =
	alloca(strlen(GLOBAL_PREF_NAME) + strlen(category) + strlen(keyword) +
	       2 + 1);
    if (!name)
	return (-1);

    sprintf(name, "%s.%s.%s", GLOBAL_PREF_NAME, category, keyword);

    switch (type) {
    case PAR_TEXT:
	gsize = size;
	break;

    case PAR_INT:
	gsize = sizeof(int);
	break;

    case PAR_FLOAT:
	gsize = sizeof(double);
	break;

    case PAR_BOOL:
	gsize = sizeof(unsigned char);
	break;

    default:
	gsize = size;
    }

    ret = db_findNode(db, name, dest, gsize, &gtype);

    if (ret < 0)
	return (ret);
    if (gtype != type)
	return (-1);

    return (ret);
}

/* Add/modify a global preference */

int
par_setGlobalPref(db_handle * db, char *category, char *keyword, int type,
		  char *value, int size)
{

    char *name =
	alloca(strlen(GLOBAL_PREF_NAME) + strlen(category) + strlen(keyword) +
	       2 + 1);
    if (!name)
	return (-1);
    sprintf(name, "%s.%s.%s", GLOBAL_PREF_NAME, category, keyword);

    return (db_addNode(db, name, value, size, type));
}

int
par_removeGlobalPref(db_handle * db, char *category, char *keyword,
		     char *value, int size, int type)
{

    char *name =
	alloca(strlen(GLOBAL_PREF_NAME) + strlen(category) + strlen(keyword) +
	       2 + 1);
    if (!name)
	return (-1);
    sprintf(name, "%s.%s.%s", GLOBAL_PREF_NAME, category, keyword);

    return (db_delNode(db, name));
}

inline int
par_getGlobalColor(db_handle * db, char *keyword, unsigned long *dest)
{
    return (par_getGlobalPref
	    (db, "appcolors", keyword, PAR_COLOR, (void *) dest,
	     sizeof(unsigned long)));
}

int
par_getAppField(db_handle * db, char *app, char *keyword, void *data,
		int size)
{

    int ret;

    char *local =
	alloca(strlen(APPLICATION_NAME) + strlen(app) + strlen(keyword) + 3);

    if (!local)
	return (-1);

    sprintf(local, "%s.%s.%s", APPLICATION_NAME, app, keyword);

    bzero((char *) data, size);

    ret = db_findNode(db, local, data, size - 1, 0);
    return (ret);
}

#define GET_FIELD(db, app, title, field) \
par_getAppField(db, app, title, field, sizeof(field))

int
par_getApplication(db_handle * db, char *app, par_app_t * local)
{
    int ret = 0;

    if (!app || !local)
      return -1;

    memset(local, 0, sizeof(par_app_t));

    /* It should not be an error not to have all the fields.  Really,
       isn't only exec needed? */

    /* So this has been changed.  If par_getAppField returns any error
       except "not found" then return an error.  Otherwise, ignore it.
    */

    ret = GET_FIELD(db, app, "title", local->title);
    if (ret == -1 && pardb_errno != PARDB_NOTFOUND) return -1;
   
    ret = GET_FIELD(db, app, "exec", local->path);
    if (ret == -1 && pardb_errno != PARDB_NOTFOUND) return -1;

    ret = GET_FIELD(db, app, "workdir", local->workdir);
    if (ret == -1 && pardb_errno != PARDB_NOTFOUND) return -1;

    ret = GET_FIELD(db, app, "icon", local->icon);
    if (ret == -1 && pardb_errno != PARDB_NOTFOUND) return -1;

    ret = GET_FIELD(db, app, "defargs", local->defargs);
    if (ret == -1 && pardb_errno != PARDB_NOTFOUND) return -1;

    return 0;
}

int
par_getAppPref(db_handle * db, char *application, char *category,
	       char *keyword, char *dest, unsigned short size)
{

    int len = strlen(APPLICATION_NAME) + strlen(application)
	+ strlen("preferences") + strlen(category) + strlen(keyword) + 4 + 1;

    char *name = alloca(len);

    if (!name)
	return (-1);

    sprintf(name, "%s.%s.preferences.%s.%s",
	    APPLICATION_NAME, application, category, keyword);

    return (db_findNode(db, name, dest, size, 0));
}

int
par_addAppPref(db_handle * db, char *application, char *category,
	       char *keyword, char *dest, unsigned short size,
	       unsigned short type)
{

    int len = strlen(APPLICATION_NAME) + strlen(application)
	+ strlen("preferences") + strlen(category) + strlen(keyword) + 4 + 1;

    char *name = alloca(len);

    if (!name)
	return (-1);

    sprintf(name, "%s.%s.preferences.%s.%s",
	    APPLICATION_NAME, application, category, keyword);

    return (db_addNode(db, name, dest, size, type));
}

int
par_delAppPref(db_handle * db, char *application, char *category,
	       char *keyword)
{

    int len = strlen(APPLICATION_NAME) + strlen(application)
	+ strlen("preferences") + strlen(category) + strlen(keyword) + 4 + 1;

    char *name = alloca(len);

    if (!name)
	return (-1);

    sprintf(name, "%s.%s.preferences.%s.%s",
	    APPLICATION_NAME, application, category, keyword);

    return (db_delNode(db, name));
}

int
par_getCapability(db_handle * db, char *capability, void **dest)
{

    int size;

    char *name = alloca(strlen(CAPABILITY_NAME) + strlen(capability) + 2);
    if (!name)
	return (-1);

    sprintf(name, "%s.%s", CAPABILITY_NAME, capability);

    size = db_getDataSize(db, name);

    if (size <= 0) {
	*dest = 0;
	return (size);
    }

    *dest = (char *) malloc(size);
    db_findNode(db, name, *dest, size, 0);

    return (size);
}

int
par_getScreentopSetting(db_handle * db, char *setting, void *dest, int size)
{

    char *name = alloca(strlen("screentop.settings.") + strlen(setting) + 1);
    if (!name)
	return (-1);

    sprintf(name, "screentop.settings.%s", setting);

    return (db_findNode(db, name, dest, size, 0));
}

int
par_getScreentopDir(db_handle * db, char *dir, char *dest, int size)
{

    int len = strlen("screentop.directories") + strlen(dir);
    char *name = alloca(len + 2);

    if (!name)
	return (-1);
    sprintf(name, "screentop.directories.%s", dir);

    return (db_findNode(db, name, dest, size, 0));
}

int
par_getScreentopInput(db_handle * db, char *input, par_input_t * data)
{

    int len = strlen("screentop.inputs") + strlen(input) + strlen("title");
    char *name = alloca(len + 3);

    if (!name)
	return (-1);

    sprintf(name, "screentop.inputs.%s.title", input);
    if (db_findNode(db, name, data->title, sizeof(data->title), 0) < 0)
	return (-1);

    sprintf(name, "screentop.inputs.%s.app", input);
    if (db_findNode(db, name, data->app, sizeof(data->app), 0) < 0)
	return (-1);

    sprintf(name, "screentop.inputs.%s.icon", input);
    if (db_findNode(db, name, data->icon, sizeof(data->icon), 0) < 0)
	return (-1);

    return (0);
}

int
par_getScreentopCategory(db_handle * db, char *category,
			 char **title, char **applist)
{

    int size;
    int len =
	strlen("screentop.categories") + strlen(category) + strlen("applist");
    char *name = alloca(len + 3);

    if (!name)
	return (-1);

    /* First, get the title */

    sprintf(name, "screentop.categories.%s.title", category);

    size = db_getDataSize(db, name);
    if (size <= 0)
	return (-1);

    *title = (char *) malloc(size);
    db_findNode(db, name, *title, size, 0);

    /* Next, get the full app list */
    sprintf(name, "screentop.categories.%s.applist", category);
    size = db_getDataSize(db, name);

    if (size <= 0) {
	*applist = 0;
	return (0);
    }

    *applist = (char *) malloc(size);
    db_findNode(db, name, *applist, size, 0);
    return (0);
}

/* List functions */

static int
local_getList(db_handle * db, char *name, itemlist_t * local)
{

    int count = db_getChildCount(db, name);

    if (count <= 0)
	return (count);

    local->list = (char **) calloc(count * sizeof(char *), 1);
    if (!local->list)
	return (-1);

    /* Now, send the list in and get the child names */

    local->count = db_getChildList(db, name, local->list, count);

    if (local->count == -1) {
	int i;

	for (i = 0; i < count; i++) {
	    if (local->list[i])
		free(local->list[i]);
	}

	free(local->list);
	local->list = 0;
    }

    return (local->count);
}

int
par_getList(db_handle * db, char *name, itemlist_t ** list)
{

    itemlist_t *local = (itemlist_t *) malloc(sizeof(itemlist_t));
    int ret = local_getList(db, name, local);

    if (ret == -1)
	free(local);
    else
	*list = local;

    return (ret);
}

void
par_freeItemList(itemlist_t * list)
{
    int i;

    if (!list)
	return;

    for (i = 0; i < list->count; i++) {
	if (list->list[i])
	    free(list->list[i]);
    }

    if (list->list)
	free(list->list);
    free(list);
}

int
par_getListItem(itemlist_t * list, int index, char *item, int *size)
{

    int lsize;

    if (!list)
	return (0);
    if (index >= list->count)
	return (0);

    if (*size > strlen(list->list[index]))
	lsize = strlen(list->list[index]);
    else
	lsize = *size;

    strncpy(item, list->list[index], lsize);

    *size = lsize;
    return (list->count > (index + 1) ? index + 1 : 0);
}

int
par_getStringListCount(char *str, char delim)
{

    int count = 1;
    char *p = str;

    if (!*p)
	return (0);

    while (1) {
	p = strchr(p, delim);
	if (!p)
	    return (count);

	while (*p == delim)
	    p++;
	if (!*p)
	    return (count);

	count++;
    }
}

char *
par_parseStringList(char **str, char delim)
{

    char *start, *n;

    if (!&str)
	return (0);

    start = *str;
    n = strchr(*str, delim);

    if (!n)
	*str = 0;
    else {
	char *p = n + 1;

	*n = 0;
	while (*p == delim)
	    p++;

	if (!*p)
	    *str = 0;
	else
	    *str = p;
    }

    return (start);
}




More information about the dslinux-commit mailing list