From 6094128afeacfa87d35d1246610a3010654b052f Mon Sep 17 00:00:00 2001 From: Stig Bakken Date: Mon, 19 Apr 1999 13:56:50 +0000 Subject: [PATCH] moved dbase into ext/ along with the bundled library dbase programs are no longer included --- ext/dbase/Makefile.am | 5 + ext/dbase/config.m4 | 21 ++ ext/dbase/dbase.c | 686 ++++++++++++++++++++++++++++++++++++++++++ ext/dbase/dbase.h | 52 ++++ ext/dbase/dbf.h | 94 ++++++ ext/dbase/dbf_head.c | 261 ++++++++++++++++ ext/dbase/dbf_head.h | 9 + ext/dbase/dbf_misc.c | 168 +++++++++++ ext/dbase/dbf_misc.h | 13 + ext/dbase/dbf_ndx.c | 183 +++++++++++ ext/dbase/dbf_ndx.h | 98 ++++++ ext/dbase/dbf_rec.c | 182 +++++++++++ ext/dbase/dbf_rec.h | 10 + ext/dbase/setup.stub | 4 + 14 files changed, 1786 insertions(+) create mode 100644 ext/dbase/Makefile.am create mode 100644 ext/dbase/config.m4 create mode 100644 ext/dbase/dbase.c create mode 100644 ext/dbase/dbase.h create mode 100644 ext/dbase/dbf.h create mode 100644 ext/dbase/dbf_head.c create mode 100644 ext/dbase/dbf_head.h create mode 100644 ext/dbase/dbf_misc.c create mode 100644 ext/dbase/dbf_misc.h create mode 100644 ext/dbase/dbf_ndx.c create mode 100644 ext/dbase/dbf_ndx.h create mode 100644 ext/dbase/dbf_rec.c create mode 100644 ext/dbase/dbf_rec.h create mode 100644 ext/dbase/setup.stub 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 + +#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 +#include + + +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 */ +/* {{{ 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 +#include +#ifdef WIN32 +#include +#else +#include +#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 +#include + +#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 +#include +#include + +#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 + +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 +#include + +#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 +#include + +#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.' -- 2.40.0