summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStig Bakken <ssb@php.net>1999-04-19 13:56:50 +0000
committerStig Bakken <ssb@php.net>1999-04-19 13:56:50 +0000
commit6094128afeacfa87d35d1246610a3010654b052f (patch)
tree369d029066cf2a735b6a638b94d4bdc529b6c373
parentb515f34dd1d5956aeb758cc3f636c183c8adcc73 (diff)
downloadphp-git-6094128afeacfa87d35d1246610a3010654b052f.tar.gz
moved dbase into ext/ along with the bundled library
dbase programs are no longer included
-rw-r--r--ext/dbase/Makefile.am5
-rw-r--r--ext/dbase/config.m421
-rw-r--r--ext/dbase/dbase.c686
-rw-r--r--ext/dbase/dbase.h52
-rw-r--r--ext/dbase/dbf.h94
-rw-r--r--ext/dbase/dbf_head.c261
-rw-r--r--ext/dbase/dbf_head.h9
-rw-r--r--ext/dbase/dbf_misc.c168
-rw-r--r--ext/dbase/dbf_misc.h13
-rw-r--r--ext/dbase/dbf_ndx.c183
-rw-r--r--ext/dbase/dbf_ndx.h98
-rw-r--r--ext/dbase/dbf_rec.c182
-rw-r--r--ext/dbase/dbf_rec.h10
-rw-r--r--ext/dbase/setup.stub4
14 files changed, 1786 insertions, 0 deletions
diff --git a/ext/dbase/Makefile.am b/ext/dbase/Makefile.am
new file mode 100644
index 0000000000..c04a5ccb86
--- /dev/null
+++ b/ext/dbase/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in -*- makefile -*-
+INCLUDES=@INCLUDES@ -I@top_srcdir@ -I@top_srcdir@/libzend
+noinst_LIBRARIES=libphpext_dbase.a
+libphpext_dbase_a_SOURCES=dbf_head.c dbf_rec.c dbf_misc.c dbf_ndx.c dbase.c
+
diff --git a/ext/dbase/config.m4 b/ext/dbase/config.m4
new file mode 100644
index 0000000000..29f54923bf
--- /dev/null
+++ b/ext/dbase/config.m4
@@ -0,0 +1,21 @@
+dnl $Id$
+
+AC_MSG_CHECKING(whether to include the bundled dbase library)
+AC_ARG_WITH(dbase,
+[ --with-dbase Include the bundled dbase library],
+[
+ if test "$withval" = "yes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(DBASE,1)
+ PHP_EXTENSION(dbase)
+ else
+ AC_MSG_RESULT(no)
+ AC_DEFINE(DBASE,0)
+ DBASE_LIB=
+ fi
+],[
+ AC_MSG_RESULT(no)
+ AC_DEFINE(DBASE,0)
+ DBASE_LIB=
+])
+AC_SUBST(DBASE_LIB)
diff --git a/ext/dbase/dbase.c b/ext/dbase/dbase.c
new file mode 100644
index 0000000000..46b1162583
--- /dev/null
+++ b/ext/dbase/dbase.c
@@ -0,0 +1,686 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP HTML Embedded Scripting Language Version 3.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997,1998 PHP Development Team (See Credits file) |
+ +----------------------------------------------------------------------+
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of one of the following licenses: |
+ | |
+ | A) the GNU General Public License as published by the Free Software |
+ | Foundation; either version 2 of the License, or (at your option) |
+ | any later version. |
+ | |
+ | B) the PHP License as published by the PHP Development Team and |
+ | included in the distribution in the file: LICENSE |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU General Public License for more details. |
+ | |
+ | You should have received a copy of both licenses referred to here. |
+ | If you did not, or have any questions about PHP licensing, please |
+ | contact core@php.net. |
+ +----------------------------------------------------------------------+
+ | Authors: Jim Winstead (jimw@php.net) |
+ +----------------------------------------------------------------------+
+ */
+#if defined(COMPILE_DL)
+#include "dl/phpdl.h"
+#endif
+
+#if defined(THREAD_SAFE)
+#include "tls.h"
+#endif
+#include <stdlib.h>
+
+#include "php.h"
+#include "safe_mode.h"
+#include "fopen-wrappers.h"
+#include "php_globals.h"
+
+#if DBASE
+#include "dbase.h"
+#include "../dbase/dbf.h"
+#if defined(THREAD_SAFE)
+DWORD DbaseTls;
+static int numthreads=0;
+void *dbase_mutex;
+
+typedef struct dbase_global_struct{
+ int le_dbhead;
+}dbase_global_struct;
+
+#define DBase_GLOBAL(a) dbase_globals->a
+
+#define DBase_TLS_VARS \
+ dbase_global_struct *dbase_globals; \
+ dbase_globals=TlsGetValue(DbaseTls);
+
+#else
+static int le_dbhead;
+#define DBase_GLOBAL(a) a
+#define DBase_TLS_VARS
+#endif
+
+#include <fcntl.h>
+#include <errno.h>
+
+
+static void _close_dbase(dbhead_t *dbhead)
+{
+ close(dbhead->db_fd);
+ free_dbf_head(dbhead);
+}
+
+
+int php3_minit_dbase(INIT_FUNC_ARGS)
+{
+#if defined(THREAD_SAFE)
+ dbase_global_struct *dbase_globals;
+#if !defined(COMPILE_DL)
+ CREATE_MUTEX(dbase_mutex,"DBase_TLS");
+ SET_MUTEX(dbase_mutex);
+ numthreads++;
+ if (numthreads==1){
+ if ((DbaseTls=TlsAlloc())==0xFFFFFFFF){
+ FREE_MUTEX(dbase_mutex);
+ return 0;
+ }}
+ FREE_MUTEX(dbase_mutex);
+#endif
+ dbase_globals = (dbase_global_struct *) LocalAlloc(LPTR, sizeof(dbase_global_struct));
+ TlsSetValue(DbaseTls, (void *) dbase_globals);
+#endif
+ DBase_GLOBAL(le_dbhead) = register_list_destructors(_close_dbase,NULL);
+ return SUCCESS;
+}
+
+static int php3_mend_dbase(void){
+#if defined(THREAD_SAFE)
+ dbase_global_struct *dbase_globals;
+ dbase_globals = TlsGetValue(DbaseTls);
+ if (dbase_globals != 0)
+ LocalFree((HLOCAL) dbase_globals);
+#if !defined(COMPILE_DL)
+ SET_MUTEX(dbase_mutex);
+ numthreads--;
+ if (!numthreads){
+ if (!TlsFree(DbaseTls)){
+ FREE_MUTEX(dbase_mutex);
+ return 0;
+ }}
+ FREE_MUTEX(dbase_mutex);
+#endif
+#endif
+ return SUCCESS;
+}
+
+/* {{{ proto int dbase_open(string name, int mode)
+ Opens a dBase-format database file */
+void php3_dbase_open(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbf_name, *options;
+ dbhead_t *dbh;
+ int handle;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&dbf_name,&options)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_string(dbf_name);
+ convert_to_long(options);
+
+ if (PG(safe_mode) && (!_php3_checkuid(dbf_name->value.str.val, 2))) {
+ RETURN_FALSE;
+ }
+
+ if (_php3_check_open_basedir(dbf_name->value.str.val)) {
+ RETURN_FALSE;
+ }
+
+ dbh = dbf_open(dbf_name->value.str.val, options->value.lval);
+ if (dbh == NULL) {
+ php3_error(E_WARNING, "unable to open database %s", dbf_name->value.str.val);
+ RETURN_FALSE;
+ }
+
+ handle = php3_list_insert(dbh, DBase_GLOBAL(le_dbhead));
+ RETURN_LONG(handle);
+}
+/* }}} */
+
+/* {{{ proto bool dbase_close(int identifier)
+ Closes an open dBase-format database file */
+void php3_dbase_close(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id;
+ dbhead_t *dbh;
+ int dbh_type;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht,1,&dbh_id)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ php3_list_delete(dbh_id->value.lval);
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int dbase_numrecords(int identifier)
+ Returns the number of records in the database */
+void php3_dbase_numrecords(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id;
+ dbhead_t *dbh;
+ int dbh_type;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht,1,&dbh_id)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(dbh->db_records);
+}
+/* }}} */
+
+/* {{{ proto int dbase_numfields(int identifier)
+ Returns the number of fields (columns) in the database */
+void php3_dbase_numfields(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id;
+ dbhead_t *dbh;
+ int dbh_type;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht,1,&dbh_id)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(dbh->db_nfields);
+}
+/* }}} */
+
+/* {{{ proto bool dbase_pack(int identifier)
+ Packs the database (deletes records marked for deletion) */
+void php3_dbase_pack(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id;
+ dbhead_t *dbh;
+ int dbh_type;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht,1,&dbh_id)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ pack_dbf(dbh);
+ put_dbf_info(dbh);
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool dbase_add_record(int identifier, array data)
+ Adds a record to the database */
+void php3_dbase_add_record(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id, *fields, *field;
+ dbhead_t *dbh;
+ int dbh_type;
+
+ int num_fields;
+ dbfield_t *dbf, *cur_f;
+ char *cp, *t_cp;
+ int i;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&dbh_id,&fields)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ if (fields->type != IS_ARRAY) {
+ php3_error(E_WARNING, "Expected array as second parameter");
+ RETURN_FALSE;
+ }
+
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ num_fields = _php3_hash_num_elements(fields->value.ht);
+
+ if (num_fields != dbh->db_nfields) {
+ php3_error(E_WARNING, "Wrong number of fields specified");
+ RETURN_FALSE;
+ }
+
+ cp = t_cp = (char *)emalloc(dbh->db_rlen + 1);
+ if (!cp) {
+ php3_error(E_WARNING, "unable to allocate memory");
+ RETURN_FALSE;
+ }
+ *t_cp++ = VALID_RECORD;
+
+ dbf = dbh->db_fields;
+ for (i = 0, cur_f = dbf; cur_f < &dbf[num_fields]; i++, cur_f++) {
+ if (_php3_hash_index_find(fields->value.ht, i, (void **)&field) == FAILURE) {
+ php3_error(E_WARNING, "unexpected error");
+ efree(cp);
+ RETURN_FALSE;
+ }
+ convert_to_string(field);
+ sprintf(t_cp, cur_f->db_format, field->value.str.val);
+ t_cp += cur_f->db_flen;
+ }
+
+ dbh->db_records++;
+ if (put_dbf_record(dbh, dbh->db_records, cp) < 0) {
+ php3_error(E_WARNING, "unable to put record at %ld", dbh->db_records);
+ efree(cp);
+ RETURN_FALSE;
+ }
+
+ put_dbf_info(dbh);
+ efree(cp);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool dbase_delete_record(int identifier, int record)
+ Marks a record to be deleted */
+void php3_dbase_delete_record(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id, *record;
+ dbhead_t *dbh;
+ int dbh_type;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&dbh_id,&record)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ convert_to_long(record);
+
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ if (del_dbf_record(dbh, record->value.lval) < 0) {
+ if (record->value.lval > dbh->db_records) {
+ php3_error(E_WARNING, "record %d out of bounds", record->value.lval);
+ } else {
+ php3_error(E_WARNING, "unable to delete record %d", record->value.lval);
+ }
+ RETURN_FALSE;
+ }
+
+ put_dbf_info(dbh);
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto array dbase_get_record(int identifier, int record)
+ Returns an array representing a record from the database */
+void php3_dbase_get_record(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id, *record;
+ dbhead_t *dbh;
+ int dbh_type;
+ dbfield_t *dbf, *cur_f;
+ char *data, *fnp, *str_value;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&dbh_id,&record)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ convert_to_long(record);
+
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ if ((data = get_dbf_record(dbh, record->value.lval)) == NULL) {
+ php3_error(E_WARNING, "Tried to read bad record %d", record->value.lval);
+ RETURN_FALSE;
+ }
+
+ dbf = dbh->db_fields;
+
+ if (array_init(return_value) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ fnp = (char *)emalloc(dbh->db_rlen);
+ for (cur_f = dbf; cur_f < &dbf[dbh->db_nfields]; cur_f++) {
+ /* get the value */
+ str_value = (char *)emalloc(cur_f->db_flen + 1);
+ sprintf(str_value, cur_f->db_format, get_field_val(data, cur_f, fnp));
+
+ /* now convert it to the right php internal type */
+ switch (cur_f->db_type) {
+ case 'C':
+ case 'D':
+ add_next_index_string(return_value,str_value,1);
+ break;
+ case 'N': /* FALLS THROUGH */
+ case 'L': /* FALLS THROUGH */
+ if (cur_f->db_fdc == 0) {
+ add_next_index_long(return_value, strtol(str_value, NULL, 10));
+ } else {
+ add_next_index_double(return_value, atof(str_value));
+ }
+ break;
+ case 'M':
+ /* this is a memo field. don't know how to deal with
+ this yet */
+ break;
+ default:
+ /* should deal with this in some way */
+ break;
+ }
+ efree(str_value);
+ }
+ efree(fnp);
+
+ /* mark whether this record was deleted */
+ if (data[0] == '*') {
+ add_assoc_long(return_value,"deleted",1);
+ }
+ else {
+ add_assoc_long(return_value,"deleted",0);
+ }
+
+ free(data);
+}
+/* }}} */
+
+/* From Martin Kuba <makub@aida.inet.cz> */
+/* {{{ proto array dbase_get_record_with_names(int identifier, int record)
+ Returns an associative array representing a record from the database */
+void php3_dbase_get_record_with_names(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *dbh_id, *record;
+ dbhead_t *dbh;
+ int dbh_type;
+ dbfield_t *dbf, *cur_f;
+ char *data, *fnp, *str_value;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&dbh_id,&record)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_long(dbh_id);
+ convert_to_long(record);
+
+ dbh = php3_list_find(dbh_id->value.lval, &dbh_type);
+ if (!dbh || dbh_type != DBase_GLOBAL(le_dbhead)) {
+ php3_error(E_WARNING, "Unable to find database for identifier %d", dbh_id->value.lval);
+ RETURN_FALSE;
+ }
+
+ if ((data = get_dbf_record(dbh, record->value.lval)) == NULL) {
+ php3_error(E_WARNING, "Tried to read bad record %d", record->value.lval);
+ RETURN_FALSE;
+ }
+
+ dbf = dbh->db_fields;
+
+ if (array_init(return_value) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ fnp = (char *)emalloc(dbh->db_rlen);
+ for (cur_f = dbf; cur_f < &dbf[dbh->db_nfields]; cur_f++) {
+ /* get the value */
+ str_value = (char *)emalloc(cur_f->db_flen + 1);
+ sprintf(str_value, cur_f->db_format, get_field_val(data, cur_f, fnp));
+
+ /* now convert it to the right php internal type */
+ switch (cur_f->db_type) {
+ case 'C':
+ case 'D':
+ add_assoc_string(return_value,cur_f->db_fname,str_value,1);
+ break;
+ case 'N': /* FALLS THROUGH */
+ case 'L': /* FALLS THROUGH */
+ if (cur_f->db_fdc == 0) {
+ add_assoc_long(return_value,cur_f->db_fname,strtol(str_value, NULL, 10));
+ } else {
+ add_assoc_double(return_value,cur_f->db_fname,atof(str_value));
+ }
+ break;
+ case 'M':
+ /* this is a memo field. don't know how to deal with this yet */
+ break;
+ default:
+ /* should deal with this in some way */
+ break;
+ }
+ efree(str_value);
+ }
+ efree(fnp);
+
+ /* mark whether this record was deleted */
+ if (data[0] == '*') {
+ add_assoc_long(return_value,"deleted",1);
+ } else {
+ add_assoc_long(return_value,"deleted",0);
+ }
+
+ free(data);
+}
+/* }}} */
+
+/* {{{ proto bool dbase_create(string filename, array fields)
+ Creates a new dBase-format database file */
+void php3_dbase_create(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *filename, *fields, *field, *value;
+ int fd;
+ dbhead_t *dbh;
+
+ int num_fields;
+ dbfield_t *dbf, *cur_f;
+ int i, rlen, handle;
+ DBase_TLS_VARS;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&filename,&fields)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_string(filename);
+
+ if (fields->type != IS_ARRAY) {
+ php3_error(E_WARNING, "Expected array as second parameter");
+ RETURN_FALSE;
+ }
+
+ if (PG(safe_mode) && (!_php3_checkuid(filename->value.str.val, 2))) {
+ RETURN_FALSE;
+ }
+
+ if (_php3_check_open_basedir(filename->value.str.val)) {
+ RETURN_FALSE;
+ }
+
+ if ((fd = open(filename->value.str.val, O_BINARY|O_RDWR|O_CREAT, 0644)) < 0) {
+ php3_error(E_WARNING, "Unable to create database (%d): %s", errno, strerror(errno));
+ RETURN_FALSE;
+ }
+
+ num_fields = _php3_hash_num_elements(fields->value.ht);
+
+ /* have to use regular malloc() because this gets free()d by
+ code in the dbase library */
+ dbh = (dbhead_t *)malloc(sizeof(dbhead_t));
+ dbf = (dbfield_t *)malloc(sizeof(dbfield_t) * num_fields);
+ if (!dbh || !dbf) {
+ php3_error(E_WARNING, "Unable to allocate memory for header info");
+ RETURN_FALSE;
+ }
+
+ /* initialize the header structure */
+ dbh->db_fields = dbf;
+ dbh->db_fd = fd;
+ dbh->db_dbt = DBH_TYPE_NORMAL;
+ strcpy(dbh->db_date, "19930818");
+ dbh->db_records = 0;
+ dbh->db_nfields = num_fields;
+ dbh->db_hlen = sizeof(struct dbf_dhead) + 2 + num_fields * sizeof(struct dbf_dfield);
+
+ rlen = 1;
+
+ for (i = 0, cur_f = dbf; i < num_fields; i++, cur_f++) {
+ /* look up the first field */
+ if (_php3_hash_index_find(fields->value.ht, i, (void **)&field) == FAILURE) {
+ php3_error(E_WARNING, "unable to find field %d", i);
+ free_dbf_head(dbh);
+ RETURN_FALSE;
+ }
+
+ if (field->type != IS_ARRAY) {
+ php3_error(E_WARNING, "second parameter must be array of arrays");
+ free_dbf_head(dbh);
+ RETURN_FALSE;
+ }
+
+ /* field name */
+ if (_php3_hash_index_find(field->value.ht, 0, (void **)&value) == FAILURE) {
+ php3_error(E_WARNING, "expected field name as first element of list in field %d", i);
+ free_dbf_head(dbh);
+ RETURN_FALSE;
+ }
+ convert_to_string(value);
+ if (value->value.str.len > 10 || value->value.str.len == 0) {
+ php3_error(E_WARNING, "invalid field name '%s' (must be non-empty and less than or equal to 10 characters)", value->value.str.val);
+ free_dbf_head(dbh);
+ RETURN_FALSE;
+ }
+ copy_crimp(cur_f->db_fname, value->value.str.val, value->value.str.len);
+
+ /* field type */
+ if (_php3_hash_index_find(field->value.ht,1,(void **)&value) == FAILURE) {
+ php3_error(E_WARNING, "expected field type as sececond element of list in field %d", i);
+ RETURN_FALSE;
+ }
+ convert_to_string(value);
+ cur_f->db_type = toupper(*value->value.str.val);
+
+ cur_f->db_fdc = 0;
+
+ /* verify the field length */
+ switch (cur_f->db_type) {
+ case 'L':
+ cur_f->db_flen = 1;
+ break;
+ case 'M':
+ cur_f->db_flen = 9;
+ dbh->db_dbt = DBH_TYPE_MEMO;
+ /* should create the memo file here, probably */
+ break;
+ case 'D':
+ cur_f->db_flen = 8;
+ break;
+ case 'N':
+ case 'C':
+ /* field length */
+ if (_php3_hash_index_find(field->value.ht,2,(void **)&value) == FAILURE) {
+ php3_error(E_WARNING, "expected field length as third element of list in field %d", i);
+ free_dbf_head(dbh);
+ RETURN_FALSE;
+ }
+ convert_to_long(value);
+ cur_f->db_flen = value->value.lval;
+
+ if (cur_f->db_type == 'N') {
+ if (_php3_hash_index_find(field->value.ht,3,(void **)&value) == FAILURE) {
+ php3_error(E_WARNING, "expected field precision as fourth element of list in field %d", i);
+ free_dbf_head(dbh);
+ RETURN_FALSE;
+ }
+ convert_to_long(value);
+ cur_f->db_fdc = value->value.lval;
+ }
+ break;
+ default:
+ php3_error(E_WARNING, "unknown field type '%c'", cur_f->db_type);
+ }
+ cur_f->db_foffset = rlen;
+ rlen += cur_f->db_flen;
+
+ cur_f->db_format = get_dbf_f_fmt(cur_f);
+ }
+
+ dbh->db_rlen = rlen;
+ put_dbf_info(dbh);
+
+ handle = php3_list_insert(dbh, DBase_GLOBAL(le_dbhead));
+ RETURN_LONG(handle);
+}
+/* }}} */
+
+function_entry dbase_functions[] = {
+ {"dbase_open", php3_dbase_open, NULL},
+ {"dbase_create", php3_dbase_create, NULL},
+ {"dbase_close", php3_dbase_close, NULL},
+ {"dbase_numrecords", php3_dbase_numrecords, NULL},
+ {"dbase_numfields", php3_dbase_numfields, NULL},
+ {"dbase_add_record", php3_dbase_add_record, NULL},
+ {"dbase_get_record", php3_dbase_get_record, NULL},
+ {"dbase_get_record_with_names", php3_dbase_get_record_with_names, NULL},
+ {"dbase_delete_record", php3_dbase_delete_record, NULL},
+ {"dbase_pack", php3_dbase_pack, NULL},
+ {NULL, NULL, NULL}
+};
+
+php3_module_entry dbase_module_entry = {
+ "DBase", dbase_functions, php3_minit_dbase, php3_mend_dbase, NULL, NULL, NULL, STANDARD_MODULE_PROPERTIES
+};
+
+
+#if defined(COMPILE_DL)
+DLEXPORT php3_module_entry *get_module(void) { return &dbase_module_entry; }
+
+#if (WIN32|WINNT) && defined(THREAD_SAFE)
+
+/*NOTE: You should have an odbc.def file where you
+export DllMain*/
+BOOL WINAPI DllMain(HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ return 1;
+}
+#endif
+#endif
+
+#endif
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/dbase/dbase.h b/ext/dbase/dbase.h
new file mode 100644
index 0000000000..bcc0b5777b
--- /dev/null
+++ b/ext/dbase/dbase.h
@@ -0,0 +1,52 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP HTML Embedded Scripting Language Version 3.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997,1998 PHP Development Team (See Credits file) |
+ +----------------------------------------------------------------------+
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of one of the following licenses: |
+ | |
+ | A) the GNU General Public License as published by the Free Software |
+ | Foundation; either version 2 of the License, or (at your option) |
+ | any later version. |
+ | |
+ | B) the PHP License as published by the PHP Development Team and |
+ | included in the distribution in the file: LICENSE |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU General Public License for more details. |
+ | |
+ | You should have received a copy of both licenses referred to here. |
+ | If you did not, or have any questions about PHP licensing, please |
+ | contact core@php.net. |
+ +----------------------------------------------------------------------+
+ | Authors: Jim Winstead (jimw@php.net) |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef _DBASE_H
+#define _DBASE_H
+#if DBASE
+extern php3_module_entry dbase_module_entry;
+#define dbase_module_ptr &dbase_module_entry
+
+extern int php3_minit_dbase(INIT_FUNC_ARGS);
+extern void php3_dbase_open(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_create(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_close(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_numrecords(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_numfields(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_add_record(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_get_record(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_delete_record(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_pack(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_dbase_get_record_with_names(INTERNAL_FUNCTION_PARAMETERS);
+#else
+#define dbase_module_ptr NULL
+#endif
+#endif /* _DBASE_H */
diff --git a/ext/dbase/dbf.h b/ext/dbase/dbf.h
new file mode 100644
index 0000000000..08bc70dd41
--- /dev/null
+++ b/ext/dbase/dbf.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1991, 1992, 1993 Brad Eacker,
+ * (Music, Intuition, Software, and Computers)
+ * All Rights Reserved
+ */
+
+/*
+ * dbf header structure on disk (pc dbase III)
+ *
+ * Basic info taken from:
+ * "File Formats for Popular PC Software"
+ * Jeff Walden
+ * (c) 1986 John Wiley & Sons, Inc.
+ */
+
+#ifndef _DBF_H_
+#define _DBF_H_
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+/* So we can use O_BINARY on non-Win32 systems. */
+#if !defined(O_BINARY) && !defined(WIN32)
+#define O_BINARY (0)
+#endif
+
+struct dbf_dhead {
+ char dbh_dbt; /* memo (dbt) file present */
+ char dbh_date[3]; /* last update YY, MM, DD */
+ char dbh_records[4]; /* number of records LE */
+ char dbh_hlen[2]; /* header length LE */
+ char dbh_rlen[2]; /* record length LE */
+ char dbh_res[20]; /* padding */
+};
+#define DBH_DATE_YEAR 0 /* byte offset for year in dbh_date */
+#define DBH_DATE_MONTH 1
+#define DBH_DATE_DAY 2
+
+/*
+ * field description on disk
+ */
+
+#define DBF_NAMELEN 11
+
+struct dbf_dfield {
+ char dbf_name[DBF_NAMELEN]; /* name of field */
+ char dbf_type; /* type of field */
+ char dbf_fda[4]; /* something for dbase III */
+ char dbf_flen[2]; /* field length [and decimal if N] */
+ char dbf_res[14]; /* padding */
+};
+
+struct db_field {
+ char db_fname[DBF_NAMELEN+1]; /* 0 terminated */
+ char db_type; /* type of field */
+ int db_flen; /* length of field */
+ int db_fdc; /* number of decimals in field */
+
+ char *db_format; /* format for printing %s etc */
+ int db_foffset; /* offset within record */
+};
+typedef struct db_field dbfield_t;
+
+struct db_head {
+ int db_fd;
+ unsigned char db_dbt; /* dbt present */
+ char db_date[9]; /* date of last update in db format */
+ long db_records; /* number of records */
+ int db_hlen; /* header length */
+ int db_rlen; /* record length */
+
+ int db_nfields; /* number of fields */
+ dbfield_t *db_fields; /* field info */
+ char *db_name; /* name of dbf file */
+ int db_cur_rec; /* current record */
+};
+typedef struct db_head dbhead_t;
+
+#define DBH_TYPE_NORMAL 0x03
+#define DBH_TYPE_MEMO 0x83
+
+#define VALID_RECORD ' '
+#define DELETED_RECORD '*'
+
+#include "dbf_head.h"
+#include "dbf_misc.h"
+#include "dbf_rec.h"
+
+#endif /* _DBF_H_ */
diff --git a/ext/dbase/dbf_head.c b/ext/dbase/dbf_head.c
new file mode 100644
index 0000000000..1f104e3d81
--- /dev/null
+++ b/ext/dbase/dbf_head.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 1991, 1992, 1993 Brad Eacker,
+ * (Music, Intuition, Software, and Computers)
+ * All Rights Reserved
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "dbf.h"
+
+void free_dbf_head(dbhead_t *dbh);
+int get_dbf_field(dbhead_t *dbh, dbfield_t *dbf);
+
+/*
+ * get the header info from the file
+ * basic header info & field descriptions
+ */
+dbhead_t *get_dbf_head(int fd)
+{
+ dbhead_t *dbh;
+ struct dbf_dhead dbhead;
+ dbfield_t *dbf, *cur_f;
+ int ret, nfields, offset;
+
+ if ((dbh = (dbhead_t *)malloc(sizeof(dbhead_t))) == NULL)
+ return NULL;
+ if (lseek(fd, 0, 0) < 0)
+ return NULL;
+ if ((ret = read(fd, &dbhead, sizeof(dbhead))) < 0)
+ return NULL;
+
+ /* build in core info */
+ dbh->db_fd = fd;
+ dbh->db_dbt = dbhead.dbh_dbt;
+ dbh->db_records = get_long(dbhead.dbh_records);
+ dbh->db_hlen = get_short(dbhead.dbh_hlen);
+ dbh->db_rlen = get_short(dbhead.dbh_rlen);
+
+ db_set_date(dbh->db_date, dbhead.dbh_date[DBH_DATE_YEAR] + 1900,
+ dbhead.dbh_date[DBH_DATE_MONTH],
+ dbhead.dbh_date[DBH_DATE_DAY]);
+
+ dbh->db_nfields = nfields = (dbh->db_hlen - sizeof(struct dbf_dhead)) /
+ sizeof(struct dbf_dfield);
+
+ /* get all the field info */
+ dbf = (dbfield_t *)malloc(sizeof(dbfield_t) * nfields);
+
+ offset = 1;
+ for (cur_f = dbf; cur_f < &dbf[nfields] ; cur_f++) {
+ if (get_dbf_field(dbh, cur_f) < 0) {
+ free_dbf_head(dbh);
+ return NULL;
+ }
+ cur_f->db_foffset = offset;
+ offset += cur_f->db_flen;
+ }
+ dbh->db_fields = dbf;
+
+ return dbh;
+}
+
+/*
+ * free up the header info built above
+ */
+void free_dbf_head(dbhead_t *dbh)
+{
+ dbfield_t *dbf, *cur_f;
+ int nfields;
+
+ dbf = dbh->db_fields;
+ nfields = dbh->db_nfields;
+ for (cur_f = dbf; cur_f < &dbf[nfields]; cur_f++) {
+ if (cur_f->db_format) {
+ free(cur_f->db_format);
+ }
+ }
+
+ free(dbf);
+ free(dbh);
+}
+
+/*
+ * put out the header info
+ */
+int put_dbf_head(dbhead_t *dbh)
+{
+ int fd = dbh->db_fd;
+ struct dbf_dhead dbhead;
+ int ret;
+
+ memset (&dbhead, 0, sizeof(dbhead));
+
+ /* build on disk info */
+ dbhead.dbh_dbt = dbh->db_dbt;
+ put_long(dbhead.dbh_records, dbh->db_records);
+ put_short(dbhead.dbh_hlen, dbh->db_hlen);
+ put_short(dbhead.dbh_rlen, dbh->db_rlen);
+
+ /* put the date spec'd into the on disk header */
+ dbhead.dbh_date[DBH_DATE_YEAR] =(char)(db_date_year(dbh->db_date) -
+ 1900);
+ dbhead.dbh_date[DBH_DATE_MONTH]=(char)(db_date_month(dbh->db_date));
+ dbhead.dbh_date[DBH_DATE_DAY] =(char)(db_date_day(dbh->db_date));
+
+ if (lseek(fd, 0, 0) < 0)
+ return -1;
+ if ((ret = write(fd, &dbhead, sizeof(dbhead))) < 0)
+ return -1;
+ return ret;
+}
+
+/*
+ * get a field off the disk from the current file offset
+ */
+int get_dbf_field(dbhead_t *dbh, dbfield_t *dbf)
+{
+ struct dbf_dfield dbfield;
+ int ret;
+
+ if ((ret = read(dbh->db_fd, &dbfield, sizeof(dbfield))) < 0) {
+ return ret;
+ }
+
+ /* build the field name */
+ copy_crimp(dbf->db_fname, dbfield.dbf_name, DBF_NAMELEN);
+
+ dbf->db_type = dbfield.dbf_type;
+ switch (dbf->db_type) {
+ case 'N':
+ dbf->db_flen = dbfield.dbf_flen[0];
+ dbf->db_fdc = dbfield.dbf_flen[1];
+ break;
+ default:
+ dbf->db_flen = get_short(dbfield.dbf_flen);
+ }
+
+ if ((dbf->db_format = get_dbf_f_fmt(dbf)) == NULL) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * put a field out on the disk at the current file offset
+ */
+int put_dbf_field(dbhead_t *dbh, dbfield_t *dbf)
+{
+ struct dbf_dfield dbfield;
+ char *scp, *dcp;
+ int ret;
+
+ memset (&dbfield, 0, sizeof(dbfield));
+
+ /* build the on disk field info */
+ scp = dbf->db_fname; dcp = dbfield.dbf_name;
+
+ strncpy(dbfield.dbf_name, dbf->db_fname, DBF_NAMELEN);
+
+ dbfield.dbf_type = dbf->db_type;
+ switch (dbf->db_type) {
+ case 'N':
+ dbfield.dbf_flen[0] = dbf->db_flen;
+ dbfield.dbf_flen[1] = dbf->db_fdc;
+ break;
+ default:
+ put_short(dbfield.dbf_flen, dbf->db_flen);
+ }
+
+ /* now write it out to disk */
+ if ((ret = write(dbh->db_fd, &dbfield, sizeof(dbfield))) < 0) {
+ return ret;
+ }
+ return 1;
+}
+
+/*
+ * put out all the info at the top of the file...
+ */
+static char end_stuff[2] = {0x0d, 0};
+
+void put_dbf_info(dbhead_t *dbh)
+{
+ dbfield_t *dbf;
+ char *cp;
+ int fcnt;
+
+ if ((cp = db_cur_date(NULL))) {
+ strncpy(dbh->db_date, cp, 8);
+ free(cp);
+ }
+ put_dbf_head(dbh);
+ dbf = dbh->db_fields;
+ for (fcnt = dbh->db_nfields; fcnt > 0; fcnt--, dbf++)
+ put_dbf_field(dbh, dbf);
+ write(dbh->db_fd, end_stuff, 1);
+}
+
+char *get_dbf_f_fmt(dbfield_t *dbf)
+{
+ char format[100];
+
+ /* build the field format for printf */
+ switch (dbf->db_type) {
+ case 'C':
+ sprintf(format, "%%-%ds", dbf->db_flen);
+ break;
+ case 'N':
+ case 'L':
+ case 'D':
+ sprintf(format, "%%%ds", dbf->db_flen);
+ break;
+ case 'M':
+ strcpy(format, "%s");
+ break;
+ }
+ return (char *)strdup(format);
+}
+
+dbhead_t *dbf_open(char *dp, int o_flags)
+{
+ int fd;
+ char *cp;
+ dbhead_t *dbh;
+
+ cp = dp;
+ if ((fd = open(cp, o_flags|O_BINARY)) < 0) {
+ cp = (char *)malloc(256);
+ strcpy(cp, dp); strcat(cp, ".dbf");
+ if ((fd = open(cp, o_flags)) < 0) {
+ perror("open");
+ return NULL;
+ }
+ }
+
+ if ((dbh = get_dbf_head(fd)) == 0) {
+ fprintf(stderr, "Unable to get header\n");
+ return NULL;
+ }
+ dbh->db_name = cp;
+ dbh->db_cur_rec = 0;
+
+ return dbh;
+}
+
+void dbf_head_info(dbhead_t *dbh)
+{
+ int nfields;
+ dbfield_t *dbf, *cur_f;
+
+ nfields = dbh->db_nfields;
+ printf("# fields: %d, record len: %d, total records %ld\n",
+ nfields, dbh->db_rlen, dbh->db_records);
+ dbf = dbh->db_fields;
+ for (cur_f = dbf; cur_f < &dbf[nfields] ; cur_f++) {
+ printf("# %s, %c, %d, %d\n", cur_f->db_fname,
+ cur_f->db_type, cur_f->db_flen, cur_f->db_fdc);
+ }
+}
diff --git a/ext/dbase/dbf_head.h b/ext/dbase/dbf_head.h
new file mode 100644
index 0000000000..481e085027
--- /dev/null
+++ b/ext/dbase/dbf_head.h
@@ -0,0 +1,9 @@
+extern dbhead_t *get_dbf_head(int fd);
+extern void free_dbf_head(dbhead_t *dbh);
+extern int put_dbf_head(dbhead_t *dbh);
+extern int get_dbf_field(dbhead_t *dbh, dbfield_t *dbf);
+extern int put_dbf_field(dbhead_t *dbh, dbfield_t *dbf);
+extern void put_dbf_info(dbhead_t *dbh);
+extern char *get_dbf_f_fmt(dbfield_t *dbf);
+extern dbhead_t *dbf_open(char *dp, int o_flags);
+extern void dbf_head_info(dbhead_t *dbh);
diff --git a/ext/dbase/dbf_misc.c b/ext/dbase/dbf_misc.c
new file mode 100644
index 0000000000..84573e47a4
--- /dev/null
+++ b/ext/dbase/dbf_misc.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1991, 1992, 1993 Brad Eacker,
+ * (Music, Intuition, Software, and Computers)
+ * All Rights Reserved
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "dbf_misc.h"
+
+/*
+ * routine to change little endian long to host long
+ */
+long get_long(char *cp)
+{
+ int ret;
+ unsigned char *source = (unsigned char *)cp;
+
+ ret = *source++;
+ ret += ((*source++)<<8);
+ ret += ((*source++)<<16);
+ ret += ((*source++)<<24);
+
+ return ret;
+}
+
+void put_long(char *cp, long lval)
+{
+ *cp++ = lval & 0xff;
+ *cp++ = (lval >> 8) & 0xff;
+ *cp++ = (lval >> 16) & 0xff;
+ *cp++ = (lval >> 24) & 0xff;
+}
+
+/*
+ * routine to change little endian short to host short
+ */
+int get_short(char *cp)
+{
+ int ret;
+ unsigned char *source = (unsigned char *)cp;
+
+ ret = *source++;
+ ret += ((*source++)<<8);
+
+ return ret;
+}
+
+void put_short(char *cp, int sval)
+{
+ *cp++ = sval & 0xff;
+ *cp++ = (sval >> 8) & 0xff;
+}
+
+double get_double(char *cp)
+{
+ double ret;
+ unsigned char *dp = (unsigned char *)&ret;
+
+ dp[7] = *cp++;
+ dp[6] = *cp++;
+ dp[5] = *cp++;
+ dp[4] = *cp++;
+ dp[3] = *cp++;
+ dp[2] = *cp++;
+ dp[1] = *cp++;
+ dp[0] = *cp++;
+
+ return ret;
+}
+
+void put_double(char *cp, double fval)
+{
+ unsigned char *dp = (unsigned char *)&fval;
+
+ cp[7] = *dp++;
+ cp[6] = *dp++;
+ cp[5] = *dp++;
+ cp[4] = *dp++;
+ cp[3] = *dp++;
+ cp[2] = *dp++;
+ cp[1] = *dp++;
+ cp[0] = *dp++;
+}
+
+void copy_fill(char *dp, char *sp, int len)
+{
+ while (*sp && len > 0) {
+ *dp++ = *sp++;
+ len--;
+ }
+ while (len-- > 0)
+ *dp++ = ' ';
+}
+
+void copy_crimp(char *dp, char *sp, int len)
+{
+ while (len-- > 0) {
+ *dp++ = *sp++;
+ }
+ *dp = 0;
+ for (dp-- ; *dp == ' '; dp--) {
+ *dp = 0;
+ }
+
+}
+
+void db_set_date(char *cp, int year, int month, int day)
+{
+ if (month > 12)
+ month = 0;
+ if (day > 31)
+ day = 0;
+ sprintf(cp, "%d", year);
+ cp[4] = month / 10 + '0';
+ cp[5] = month % 10 + '0';
+ cp[6] = day / 10 + '0';
+ cp[7] = day % 10 + '0';
+ cp[8] = 0;
+}
+
+int db_date_year(char *cp)
+{
+ int year, i;
+
+ for (year = 0, i = 0; i < 4; i++)
+ year = year * 10 + (cp[i] - '0');
+ return year;
+}
+
+int db_date_month(char *cp)
+{
+ int month, i;
+
+ for (month = 0, i = 4; i < 6; i++)
+ month = month * 10 + (cp[i] - '0');
+ return month;
+}
+
+int db_date_day(char *cp)
+{
+ int day, i;
+
+ for (day = 0, i = 6; i < 8; i++)
+ day = day * 10 + (cp[i] - '0');
+ return day;
+}
+
+#include <time.h>
+
+char *db_cur_date(char *cp)
+{
+ struct tm *ctm;
+ time_t c_time;
+
+ c_time = time((time_t *)NULL);
+ ctm = localtime(&c_time);
+ if (cp == NULL)
+ cp = (char *)malloc(9);
+
+ if (ctm == NULL || cp == NULL)
+ return NULL;
+
+ db_set_date(cp, ctm->tm_year + 1900, ctm->tm_mon + 1, ctm->tm_mday);
+
+ return cp;
+}
diff --git a/ext/dbase/dbf_misc.h b/ext/dbase/dbf_misc.h
new file mode 100644
index 0000000000..ce2e80d7a1
--- /dev/null
+++ b/ext/dbase/dbf_misc.h
@@ -0,0 +1,13 @@
+extern void put_long(char *cp, long lval);
+extern long get_long(char *cp);
+extern int get_short(char *cp);
+extern void put_short(char *cp, int sval);
+extern void put_double(char *cp, double fval);
+extern double get_double(char *cp);
+extern void copy_fill(char *dp, char *sp, int len);
+extern void copy_crimp(char *dp, char *sp, int len);
+extern void db_set_date(char *cp, int year, int month, int day);
+extern int db_date_year(char *cp);
+extern int db_date_month(char *cp);
+extern int db_date_day(char *cp);
+extern char *db_cur_date(char *cp);
diff --git a/ext/dbase/dbf_ndx.c b/ext/dbase/dbf_ndx.c
new file mode 100644
index 0000000000..9263b02b0c
--- /dev/null
+++ b/ext/dbase/dbf_ndx.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1991, 1992, 1993 Brad Eacker,
+ * (Music, Intuition, Software, and Computers)
+ * All Rights Reserved
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "dbf.h"
+#include "dbf_ndx.h"
+
+/*
+ * get the ndx header for this file
+ */
+ndx_header_t *ndx_get_header(int fd)
+{
+ dndx_header_t *dp;
+ ndx_header_t *np;
+
+ if ((dp = (dndx_header_t *)malloc(NDX_PAGE_SZ)) == NULL)
+ return NULL;
+ if ((np = (ndx_header_t *)malloc(sizeof(ndx_header_t))) == NULL) {
+ free(dp);
+ return NULL;
+ }
+ if ((lseek(fd, 0, 0) < 0) || (read(fd, dp, NDX_PAGE_SZ) < 0)) {
+ free(dp); free(np);
+ return NULL;
+ }
+ np->ndx_hpage = dp;
+ np->ndx_fd = fd;
+ np->ndx_start_pg = get_long(dp->dndx_st_pg);
+ np->ndx_total_pgs = get_long(dp->dndx_tot_pg);
+ np->ndx_key_len = get_short(dp->dndx_key_len);
+ np->ndx_keys_ppg = get_short(dp->dndx_keys_ppg);
+ np->ndx_key_type = get_short(dp->dndx_key_type);
+ np->ndx_key_size = get_long(dp->dndx_size_key);
+ np->ndx_key_name = dp->dndx_key_name;
+ np->ndx_unique = dp->dndx_unique;
+
+ np->ndx_fp = NULL;
+
+ return np;
+}
+
+static ndx_page_t *ndx_get_page(ndx_header_t *hp, int pageno)
+{
+ ndx_page_t *fp;
+ dndx_page_t *dp;
+ ndx_record_t *rp;
+
+#if DEBUG
+ printf("getting page %d", pageno);
+#endif
+ if ((fp = (ndx_page_t *)malloc(sizeof(ndx_page_t))) == NULL)
+ return NULL;
+ if ((dp = (dndx_page_t *)malloc(NDX_PAGE_SZ)) == NULL) {
+ free(fp);
+ return NULL;
+ }
+ if ((rp = (ndx_record_t *)malloc(sizeof(ndx_record_t) * hp->ndx_keys_ppg)) == NULL) {
+ free(dp); free(fp);
+ return NULL;
+ }
+ fp->ndxp_page_data = dp;
+ if ((lseek(hp->ndx_fd, pageno * NDX_PAGE_SZ, 0) < 0) ||
+ (read(hp->ndx_fd, dp, NDX_PAGE_SZ) < 0)) {
+ free(fp); free(dp);
+ return NULL;
+ }
+ fp->ndxp_parent = NULL;
+ fp->ndxp_page_no = pageno;
+ fp->ndxp_num_keys = get_long(dp->dndxp_num_keys);
+ memset(rp, 0, sizeof(ndx_record_t) * hp->ndx_keys_ppg);
+ fp->ndxp_records = rp;
+ fp->ndxp_header_p = hp;
+#if DEBUG
+ printf(", n_keys %ld\n", fp->ndxp_num_keys);
+#endif
+ return fp;
+}
+
+/*
+ * get the first entry for this ndx
+ */
+static ndx_page_t *ndx_get_first_pg(ndx_header_t *hp)
+{
+ ndx_page_t *fp;
+
+ if (hp->ndx_fp)
+ return hp->ndx_fp;
+ if ((fp = ndx_get_page(hp, hp->ndx_start_pg))) {
+ hp->ndx_fp = fp;
+ }
+ return fp;
+}
+
+static ndx_record_t *ndx_get_record(ndx_page_t *fp, int rec_no)
+{
+ ndx_record_t *rp;
+ ndx_header_t *hp = fp->ndxp_header_p;
+ struct dndx_record *drp;
+
+#if DEBUG
+ printf("page %ld, rec %d: ", fp->ndxp_page_no, rec_no);
+#endif
+ if (rec_no >= fp->ndxp_num_keys)
+ return NULL;
+ rp = &(fp->ndxp_records[rec_no]);
+ if (!rp->ndxr_page) {
+ rp->ndxr_page = fp;
+ drp = (dndx_record_t *)((char *)&fp->ndxp_page_data->dndx_rp
+ + rec_no * hp->ndx_key_size);
+ rp->ndxr_left = get_long(drp->dndx_left_pg);
+ rp->ndxr_rec = get_long(drp->dndx_dbf_rec);
+ rp->ndxr_key_data = &drp->dndx_key_data;
+ rp->ndxr_p_nrec = rec_no;
+ }
+#if DEBUG
+ printf("left %ld, dbf_rec %ld, data '%s'\n", rp->ndxr_left,
+ rp->ndxr_rec, rp->ndxr_key_data);
+#endif
+ return rp;
+}
+
+static ndx_record_t *ndx_scan_down(ndx_header_t *hp, ndx_page_t *fp, int recno)
+{
+ ndx_page_t *np;
+ ndx_record_t *rp;
+
+ while ((rp = ndx_get_record(fp, recno)) && (rp->ndxr_rec == 0)) {
+ np = ndx_get_page(hp, rp->ndxr_left);
+ np->ndxp_parent = fp;
+ np->ndxp_par_rno = recno;
+ fp = np;
+ recno = 0;
+ }
+ return rp;
+}
+
+static ndx_record_t *ndx_scan_up(ndx_header_t *hp, ndx_page_t *fp, int recno)
+{
+ ndx_record_t *rp;
+
+ if (fp == NULL)
+ rp = NULL;
+ else if (recno < fp->ndxp_num_keys) {
+ rp = ndx_scan_down(hp, fp, recno);
+ } else {
+ rp = ndx_scan_up(hp, fp->ndxp_parent, fp->ndxp_par_rno + 1);
+ }
+ return rp;
+}
+
+ndx_record_t *ndx_get_first_rec(ndx_header_t *hp)
+{
+ ndx_page_t *fp;
+ ndx_record_t *rp = NULL;
+
+ if ((fp = ndx_get_first_pg(hp))) {
+ fp->ndxp_last_key = 0;
+ rp = ndx_scan_down(hp, fp, 0);
+ }
+ hp->ndx_cur_rec = rp;
+ return rp;
+}
+
+ndx_record_t *ndx_get_next_rec(ndx_header_t *hp, ndx_record_t *rp)
+{
+ ndx_page_t *fp;
+ int rec_no;
+
+ fp = rp->ndxr_page;
+ rec_no = rp->ndxr_p_nrec + 1;
+ if (rec_no < fp->ndxp_num_keys) {
+ rp = ndx_scan_down(hp, fp, rec_no);
+ } else {
+ rp = ndx_scan_up(hp, fp->ndxp_parent, fp->ndxp_par_rno + 1);
+ }
+ return rp;
+}
+
diff --git a/ext/dbase/dbf_ndx.h b/ext/dbase/dbf_ndx.h
new file mode 100644
index 0000000000..3faff04025
--- /dev/null
+++ b/ext/dbase/dbf_ndx.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1993 Brad Eacker,
+ * (Music, Intuition, Software, and Computers)
+ * All Rights Reserved
+ */
+
+/*
+ * dbf .ndx header structure on disk and in memory
+ *
+ * Basic info taken from:
+ * "Clipper Programming Guide, 3rd Edition, Version 5.01"
+ * by Rick Spence
+ */
+
+#ifndef _DBF_NDX_H_
+#define _DBF_NDX_H_
+
+#include "dbf.h"
+
+#define NDX_PAGE_SZ 512
+
+/* on disk ndx header */
+struct dndx_header {
+ char dndx_st_pg[4]; /* starting page number */
+ char dndx_tot_pg[4]; /* total number of pages */
+ char dndx_filler1[4]; /* space */
+ char dndx_key_len[2]; /* key length */
+ char dndx_keys_ppg[2]; /* number of keys per page */
+ char dndx_key_type[2]; /* key type */
+ char dndx_size_key[4]; /* size of the key record */
+ char dndx_filler2; /* space */
+ char dndx_unique; /* whether or not done with unique */
+ char dndx_key_name[488]; /* string defining the key */
+};
+typedef struct dndx_header dndx_header_t;
+
+/* in memory ndx header */
+struct ndx_header {
+ long ndx_start_pg;
+ long ndx_total_pgs;
+ unsigned short ndx_key_len;
+ unsigned short ndx_keys_ppg;
+ unsigned short ndx_key_type;
+ char ndx_unique;
+ long ndx_key_size;
+ char *ndx_key_name;
+ int ndx_fd;
+ struct ndx_page *ndx_fp;
+ dndx_header_t *ndx_hpage;
+ struct ndx_record *ndx_cur_rec;
+};
+typedef struct ndx_header ndx_header_t;
+
+/* these are the possible values in the key type field */
+#define NDX_CHAR_TYPE 00
+#define NDX_NUM_TYPE 01
+
+/* on disk key record */
+struct dndx_record {
+ char dndx_left_pg[4]; /* number of left page */
+ char dndx_dbf_rec[4]; /* dbf record number */
+ char dndx_key_data; /* key data */
+};
+typedef struct dndx_record dndx_record_t;
+
+struct ndx_record {
+ long ndxr_left;
+ long ndxr_rec;
+ char *ndxr_key_data;
+ struct ndx_page *ndxr_page; /* page pointer to where we are from*/
+ int ndxr_p_nrec; /* number of the record within page */
+};
+typedef struct ndx_record ndx_record_t;
+
+struct dndx_page {
+ char dndxp_num_keys[4]; /* number of keys on this page */
+ struct dndx_record dndx_rp;
+};
+typedef struct dndx_page dndx_page_t;
+
+struct ndx_page {
+ long ndxp_page_no;
+ long ndxp_num_keys;
+ dndx_page_t *ndxp_page_data;
+ ndx_header_t *ndxp_header_p;
+ long ndxp_last_key;
+ struct ndx_page *ndxp_parent; /* parent page */
+ int ndxp_par_rno; /* record number within parent */
+ struct ndx_record *ndxp_records;
+};
+typedef struct ndx_page ndx_page_t;
+
+extern ndx_header_t *ndx_get_header(int);
+
+extern ndx_record_t *ndx_get_first_rec(ndx_header_t *);
+extern ndx_record_t *ndx_get_next_rec(ndx_header_t *, ndx_record_t *);
+
+#endif /* _DBF_NDX_H_ */
diff --git a/ext/dbase/dbf_rec.c b/ext/dbase/dbf_rec.c
new file mode 100644
index 0000000000..fa342005fb
--- /dev/null
+++ b/ext/dbase/dbf_rec.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1993 Brad Eacker,
+ * (Music, Intuition, Software, and Computers)
+ * All Rights Reserved
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "dbf.h"
+
+int get_piece(dbhead_t *dbh, long offset, char *cp, int len);
+int put_piece(dbhead_t *dbh, long offset, char *cp, int len);
+
+/*
+ * get a record off the database
+ */
+char *get_dbf_record(dbhead_t *dbh, long rec_num)
+{
+ long offset;
+ char *cp;
+
+ if (rec_num > dbh->db_records) {
+ return NULL;
+ }
+ if ((cp = (char *)malloc(dbh->db_rlen)) == NULL) {
+ return NULL;
+ }
+
+ /* go to the correct spot on the file */
+ offset = dbh->db_hlen + (rec_num - 1) * dbh->db_rlen;
+ if (get_piece(dbh, offset, cp, dbh->db_rlen) != dbh->db_rlen) {
+ free(cp);
+ cp = NULL;
+ }
+ if (cp)
+ dbh->db_cur_rec = rec_num;
+ return cp;
+}
+
+int
+get_piece(dbhead_t *dbh, long offset, char *cp, int len)
+{
+ /* go to the correct spot on the file */
+ if ( lseek(dbh->db_fd, offset, 0) < 0 ) {
+ return -1;
+ }
+
+ /* read the record into the allocated space */
+ return read(dbh->db_fd, cp, len);
+}
+
+/*
+ * put a record to the database
+ */
+long put_dbf_record(dbhead_t *dbh, long rec_num, char *cp)
+{
+ long offset;
+
+ if (rec_num == 0) {
+ rec_num = dbh->db_records;
+ }
+ if (rec_num > dbh->db_records) {
+ return 0L;
+ }
+ /* go to the correct spot on the file */
+ offset = dbh->db_hlen + (rec_num - 1) * dbh->db_rlen;
+ if (put_piece(dbh, offset, cp, dbh->db_rlen) != dbh->db_rlen) {
+ rec_num = -1;
+ }
+ return rec_num;
+}
+
+int put_piece(dbhead_t *dbh, long offset, char *cp, int len)
+{
+ /* go to the correct spot on the file */
+ if ( lseek(dbh->db_fd, offset, 0) < 0 ) {
+ return -1;
+ }
+
+ /* write the record into the file */
+ return write(dbh->db_fd, cp, len);
+}
+
+int del_dbf_record(dbhead_t *dbh, long rec_num)
+{
+ int ret = 0;
+ char *cp;
+
+ if (rec_num > dbh->db_records)
+ return -1;
+ if ((cp = get_dbf_record(dbh, rec_num))) {
+ *cp = DELETED_RECORD;
+ ret = put_dbf_record(dbh, rec_num, cp);
+ free(cp);
+ }
+ return ret;
+}
+
+void pack_dbf(dbhead_t *dbh)
+{
+ long out_off, in_off;
+ int rec_cnt, new_cnt;
+ char *cp;
+
+ if ((cp = (char *)malloc(dbh->db_rlen)) == NULL) {
+ return;
+ }
+ in_off = out_off = dbh->db_hlen;
+
+ new_cnt = 0;
+ rec_cnt = dbh->db_records;
+ while (rec_cnt > 0) {
+ if (get_piece(dbh, in_off, cp, dbh->db_rlen) < 0)
+ break;
+
+ if (*cp != DELETED_RECORD) {
+ /* write the record into the file */
+ if (put_piece(dbh, out_off, 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;
+}
+
+/* routine to get a field from a record */
+char *get_field_val(char *rp, dbfield_t *fldp, char *cp)
+{
+ int flen = fldp->db_flen;
+
+ if ( !cp )
+ cp = (char *)malloc(flen + 1);
+ if ( cp ) {
+ strncpy(cp, &rp[fldp->db_foffset], flen);
+ cp[flen] = 0;
+ }
+ return cp;
+}
+
+void put_field_val(char *rp, dbfield_t *fldp, char *cp)
+{
+ strncpy(&rp[fldp->db_foffset], cp, fldp->db_flen);
+}
+
+/*
+ * output a record
+ */
+void out_rec(dbhead_t *dbh, dbfield_t *dbf, char *cp)
+{
+ dbfield_t *cur_f;
+ int nfields = dbh->db_nfields;
+ char *fnp = (char *)malloc(dbh->db_rlen);
+
+ printf("%c", *cp);
+ for (cur_f = dbf; cur_f < &dbf[nfields] ; cur_f++) {
+ printf(" ");
+ printf(cur_f->db_format, get_field_val(cp, cur_f, fnp));
+ }
+ printf("\n");
+ free(fnp);
+}
+
+/* check for record validity */
+int is_valid_rec(char *cp)
+{
+ if (cp && (*cp == VALID_RECORD))
+ return 1;
+ else
+ return 0;
+}
+
+/* get the next record */
+char *dbf_get_next(dbhead_t *dbh)
+{
+ return get_dbf_record(dbh, dbh->db_cur_rec + 1);
+}
diff --git a/ext/dbase/dbf_rec.h b/ext/dbase/dbf_rec.h
new file mode 100644
index 0000000000..6eb40455a7
--- /dev/null
+++ b/ext/dbase/dbf_rec.h
@@ -0,0 +1,10 @@
+extern char *get_dbf_record(dbhead_t *dbh, long rec_num);
+extern long put_dbf_record(dbhead_t *dbh, long rec_num, char *cp);
+extern int put_piece(dbhead_t *dbh, long offset, char *cp, int len);
+extern int del_dbf_record(dbhead_t *dbh, long rec_num);
+extern void pack_dbf(dbhead_t *dbh);
+extern char *get_field_val(char *rp, dbfield_t *fldp, char *cp);
+extern void put_field_val(char *rp, dbfield_t *fldp, char *cp);
+extern void out_rec(dbhead_t *dbh, dbfield_t *dbf, char *cp);
+extern int is_valid_rec(char *cp);
+extern char *dbf_get_next(dbhead_t *dbh);
diff --git a/ext/dbase/setup.stub b/ext/dbase/setup.stub
new file mode 100644
index 0000000000..427ecf069d
--- /dev/null
+++ b/ext/dbase/setup.stub
@@ -0,0 +1,4 @@
+# $Id$ -*- sh -*-
+
+define_option with-dbase 'dBase support? ' yesno no \
+' Whether to use the bundled dbase library.'