]> granicus.if.org Git - php/commitdiff
moved dbase into ext/ along with the bundled library
authorStig Bakken <ssb@php.net>
Mon, 19 Apr 1999 13:56:50 +0000 (13:56 +0000)
committerStig Bakken <ssb@php.net>
Mon, 19 Apr 1999 13:56:50 +0000 (13:56 +0000)
dbase programs are no longer included

14 files changed:
ext/dbase/Makefile.am [new file with mode: 0644]
ext/dbase/config.m4 [new file with mode: 0644]
ext/dbase/dbase.c [new file with mode: 0644]
ext/dbase/dbase.h [new file with mode: 0644]
ext/dbase/dbf.h [new file with mode: 0644]
ext/dbase/dbf_head.c [new file with mode: 0644]
ext/dbase/dbf_head.h [new file with mode: 0644]
ext/dbase/dbf_misc.c [new file with mode: 0644]
ext/dbase/dbf_misc.h [new file with mode: 0644]
ext/dbase/dbf_ndx.c [new file with mode: 0644]
ext/dbase/dbf_ndx.h [new file with mode: 0644]
ext/dbase/dbf_rec.c [new file with mode: 0644]
ext/dbase/dbf_rec.h [new file with mode: 0644]
ext/dbase/setup.stub [new file with mode: 0644]

diff --git a/ext/dbase/Makefile.am b/ext/dbase/Makefile.am
new file mode 100644 (file)
index 0000000..c04a5cc
--- /dev/null
@@ -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 (file)
index 0000000..29f5492
--- /dev/null
@@ -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 (file)
index 0000000..46b1162
--- /dev/null
@@ -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 (file)
index 0000000..bcc0b57
--- /dev/null
@@ -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 (file)
index 0000000..08bc70d
--- /dev/null
@@ -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 (file)
index 0000000..1f104e3
--- /dev/null
@@ -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 (file)
index 0000000..481e085
--- /dev/null
@@ -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 (file)
index 0000000..84573e4
--- /dev/null
@@ -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 (file)
index 0000000..ce2e80d
--- /dev/null
@@ -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 (file)
index 0000000..9263b02
--- /dev/null
@@ -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 (file)
index 0000000..3faff04
--- /dev/null
@@ -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 (file)
index 0000000..fa34200
--- /dev/null
@@ -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 (file)
index 0000000..6eb4045
--- /dev/null
@@ -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 (file)
index 0000000..427ecf0
--- /dev/null
@@ -0,0 +1,4 @@
+# $Id$ -*- sh -*-
+
+define_option with-dbase 'dBase support? ' yesno no \
+'    Whether to use the bundled dbase library.'