/*
 * Copyright (c) 1993 Brad Eacker,
 *              (Music, Intuition, Software, and Computers)
 * All Rights Reserved
 */

#include <stdio.h>
#include <fcntl.h>

#include "dbf.h"

/*
 * get a record off the database
 */
u_char *
get_dbf_record(dbh, rec_num)
dbhead_t *dbh;
long rec_num;
{
	long	offset;
	u_char	*cp;

	if ((cp = (u_char *)malloc(dbh->db_rlen)) == NULL) {
		return NULL;
	}
	if (rec_num > dbh->db_records) {
		return NULL;
	}

	/* go to the correct spot on the file */
	offset = dbh->db_hlen + (rec_num - 1) * dbh->db_rlen;

	if ( lseek(dbh->db_fd, offset, 0) < 0 ) {
		free(cp);
		return NULL;
	}

	/* read the record into the allocated space */
	if ( read(dbh->db_fd, cp, dbh->db_rlen) < 0 ) {
		free(cp);
		return NULL;
	}

	return cp;
}

/*
 * get a record off the database
 */
put_dbf_record(dbh, rec_num, cp)
dbhead_t *dbh;
long rec_num;
u_char *cp;
{
	long	offset;

	if (rec_num == 0) {
		rec_num = dbh->db_records;
	}
	if (rec_num > dbh->db_records) {
		return NULL;
	}
	/* go to the correct spot on the file */
	offset = dbh->db_hlen + (rec_num - 1) * dbh->db_rlen;

	if ( lseek(dbh->db_fd, offset, 0) < 0 ) {
		return -1;
	}

	/* write the record into the file */
	if ( write(dbh->db_fd, cp, dbh->db_rlen) < 0 ) {
		return -1;
	}

	return rec_num;
}

del_dbf_record(dbh, rec_num)
dbhead_t *dbh;
long rec_num;
{
	int ret;
	u_char *cp;

	if (rec_num > dbh->db_records)
		return -1;
	if (cp = get_dbf_record(dbh, rec_num)) {
		*cp = DELETED_RECORD;
		if ( (ret = put_dbf_record(dbh, rec_num, cp)) < 0 ) {
			return ret;
		}
	}
	return 0;
}

pack_dbf(dbh)
dbhead_t *dbh;
{
	long	out_off, in_off;
	int	rec_cnt, new_cnt;
	u_char	*cp;

	if ((cp = (u_char *)malloc(dbh->db_rlen)) == NULL) {
		return -1;
	}
	in_off = out_off = dbh->db_hlen;

	new_cnt = 0;
	rec_cnt = dbh->db_records;
	while (rec_cnt > 0) {
		if ( lseek(dbh->db_fd, in_off, 0) < 0 )
			break;
		if ( read(dbh->db_fd, cp, dbh->db_rlen) < 0 )
			break;

		if (*cp != DELETED_RECORD) {
			/* write the record into the file */
			if ( lseek(dbh->db_fd, out_off, 0) < 0 )
				break;
			if ( write(dbh->db_fd, cp, dbh->db_rlen) < 0 )
				break;
			out_off += dbh->db_rlen;
			new_cnt++;
		}
		in_off += dbh->db_rlen;
		rec_cnt--;
	}
	free(cp);
	if (rec_cnt == 0)
		dbh->db_records = new_cnt;
}
