mirror of
https://github.com/php/php-src.git
synced 2024-12-16 13:26:19 +08:00
38dcee0beb
add test
294 lines
6.0 KiB
C
294 lines
6.0 KiB
C
/*
|
|
* Copyright (c) 1991, 1992, 1993 Brad Eacker,
|
|
* (Music, Intuition, Software, and Computers)
|
|
* All Rights Reserved
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "php.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, *tdbf;
|
|
int ret, nfields, offset, gf_retval;
|
|
|
|
if ((dbh = (dbhead_t *)calloc(1, sizeof(dbhead_t))) == NULL)
|
|
return NULL;
|
|
if (lseek(fd, 0, 0) < 0) {
|
|
free(dbh);
|
|
return NULL;
|
|
}
|
|
if ((ret = read(fd, &dbhead, sizeof(dbhead))) <= 0) {
|
|
free(dbh);
|
|
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]);
|
|
|
|
/* malloc enough memory for the maximum number of fields:
|
|
32 * 1024 = 32K dBase5 (for Win) seems to allow that many */
|
|
tdbf = (dbfield_t *)calloc(1, sizeof(dbfield_t)*1024);
|
|
|
|
offset = 1;
|
|
nfields = 0;
|
|
gf_retval = 0;
|
|
for (cur_f = tdbf; gf_retval < 2 && nfields < 1024; cur_f++) {
|
|
gf_retval = get_dbf_field(dbh, cur_f);
|
|
|
|
if (gf_retval < 0) {
|
|
free_dbf_head(dbh);
|
|
free(tdbf);
|
|
return NULL;
|
|
}
|
|
if (gf_retval != 2 ) {
|
|
cur_f->db_foffset = offset;
|
|
offset += cur_f->db_flen;
|
|
nfields++;
|
|
}
|
|
}
|
|
dbh->db_nfields = nfields;
|
|
|
|
/* malloc the right amount of space for records, copy and destroy old */
|
|
dbf = (dbfield_t *)malloc(sizeof(dbfield_t)*nfields);
|
|
memcpy(dbf, tdbf, sizeof(dbfield_t)*nfields);
|
|
free(tdbf);
|
|
|
|
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;
|
|
}
|
|
|
|
/* Check for the '0Dh' field terminator , if found return '2'
|
|
which will tell the loop we are at the end of fields */
|
|
if (dbfield.dbf_name[0]==0x0d) {
|
|
return 2;
|
|
}
|
|
|
|
/* 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':
|
|
case 'F':
|
|
dbf->db_flen = dbfield.dbf_flen[0];
|
|
dbf->db_fdc = dbfield.dbf_flen[1];
|
|
break;
|
|
default:
|
|
dbf->db_flen = get_short(dbfield.dbf_flen);
|
|
break;
|
|
}
|
|
|
|
if ((dbf->db_format = get_dbf_f_fmt(dbf)) == NULL) {
|
|
/* something went wrong, most likely this fieldtype is not supported */
|
|
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':
|
|
case 'F':
|
|
sprintf(format, "%%%ds", dbf->db_flen);
|
|
break;
|
|
case 'M':
|
|
strcpy(format, "%s");
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
return (char *)strdup(format);
|
|
}
|
|
|
|
dbhead_t *dbf_open(char *dp, int o_flags TSRMLS_DC)
|
|
{
|
|
int fd;
|
|
char *cp;
|
|
dbhead_t *dbh;
|
|
|
|
cp = dp;
|
|
if ((fd = VCWD_OPEN(cp, o_flags|O_BINARY)) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if ((dbh = get_dbf_head(fd)) == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: sw=4 ts=4 fdm=marker
|
|
* vim<600: sw=4 ts=4
|
|
*/
|