1 : /*
2 : * Copyright (c) 1991, 1992, 1993 Brad Eacker,
3 : * (Music, Intuition, Software, and Computers)
4 : * All Rights Reserved
5 : */
6 :
7 : #include <stdio.h>
8 : #include <fcntl.h>
9 :
10 : #include "php.h"
11 : #include "dbf.h"
12 :
13 : void free_dbf_head(dbhead_t *dbh);
14 : int get_dbf_field(dbhead_t *dbh, dbfield_t *dbf);
15 :
16 : /*
17 : * get the header info from the file
18 : * basic header info & field descriptions
19 : */
20 : dbhead_t *get_dbf_head(int fd)
21 6 : {
22 : dbhead_t *dbh;
23 : struct dbf_dhead dbhead;
24 : dbfield_t *dbf, *cur_f, *tdbf;
25 : int ret, nfields, offset, gf_retval;
26 :
27 6 : if ((dbh = (dbhead_t *)calloc(1, sizeof(dbhead_t))) == NULL)
28 0 : return NULL;
29 6 : if (lseek(fd, 0, 0) < 0) {
30 0 : free(dbh);
31 0 : return NULL;
32 : }
33 6 : if ((ret = read(fd, &dbhead, sizeof(dbhead))) <= 0) {
34 1 : free(dbh);
35 1 : return NULL;
36 : }
37 :
38 : /* build in core info */
39 5 : dbh->db_fd = fd;
40 5 : dbh->db_dbt = dbhead.dbh_dbt;
41 5 : dbh->db_records = get_long(dbhead.dbh_records);
42 5 : dbh->db_hlen = get_short(dbhead.dbh_hlen);
43 5 : dbh->db_rlen = get_short(dbhead.dbh_rlen);
44 :
45 5 : db_set_date(dbh->db_date, dbhead.dbh_date[DBH_DATE_YEAR] + 1900,
46 : dbhead.dbh_date[DBH_DATE_MONTH],
47 : dbhead.dbh_date[DBH_DATE_DAY]);
48 :
49 : /* malloc enough memory for the maximum number of fields:
50 : 32 * 1024 = 32K dBase5 (for Win) seems to allow that many */
51 5 : tdbf = (dbfield_t *)calloc(1, sizeof(dbfield_t)*1024);
52 :
53 5 : offset = 1;
54 5 : nfields = 0;
55 5 : gf_retval = 0;
56 31 : for (cur_f = tdbf; gf_retval < 2 && nfields < 1024; cur_f++) {
57 26 : gf_retval = get_dbf_field(dbh, cur_f);
58 :
59 26 : if (gf_retval < 0) {
60 0 : free_dbf_head(dbh);
61 0 : free(tdbf);
62 0 : return NULL;
63 : }
64 26 : if (gf_retval != 2 ) {
65 21 : cur_f->db_foffset = offset;
66 21 : offset += cur_f->db_flen;
67 21 : nfields++;
68 : }
69 : }
70 5 : dbh->db_nfields = nfields;
71 :
72 : /* malloc the right amount of space for records, copy and destroy old */
73 5 : dbf = (dbfield_t *)malloc(sizeof(dbfield_t)*nfields);
74 5 : memcpy(dbf, tdbf, sizeof(dbfield_t)*nfields);
75 5 : free(tdbf);
76 :
77 5 : dbh->db_fields = dbf;
78 :
79 5 : return dbh;
80 : }
81 :
82 : /*
83 : * free up the header info built above
84 : */
85 : void free_dbf_head(dbhead_t *dbh)
86 16 : {
87 : dbfield_t *dbf, *cur_f;
88 : int nfields;
89 :
90 16 : dbf = dbh->db_fields;
91 16 : nfields = dbh->db_nfields;
92 64 : for (cur_f = dbf; cur_f < &dbf[nfields]; cur_f++) {
93 48 : if (cur_f->db_format) {
94 45 : free(cur_f->db_format);
95 : }
96 : }
97 :
98 16 : free(dbf);
99 16 : free(dbh);
100 16 : }
101 :
102 : /*
103 : * put out the header info
104 : */
105 : int put_dbf_head(dbhead_t *dbh)
106 19 : {
107 19 : int fd = dbh->db_fd;
108 : struct dbf_dhead dbhead;
109 : int ret;
110 :
111 19 : memset (&dbhead, 0, sizeof(dbhead));
112 :
113 : /* build on disk info */
114 19 : dbhead.dbh_dbt = dbh->db_dbt;
115 19 : put_long(dbhead.dbh_records, dbh->db_records);
116 19 : put_short(dbhead.dbh_hlen, dbh->db_hlen);
117 19 : put_short(dbhead.dbh_rlen, dbh->db_rlen);
118 :
119 : /* put the date spec'd into the on disk header */
120 19 : dbhead.dbh_date[DBH_DATE_YEAR] =(char)(db_date_year(dbh->db_date) -
121 : 1900);
122 19 : dbhead.dbh_date[DBH_DATE_MONTH]=(char)(db_date_month(dbh->db_date));
123 19 : dbhead.dbh_date[DBH_DATE_DAY] =(char)(db_date_day(dbh->db_date));
124 :
125 19 : if (lseek(fd, 0, 0) < 0)
126 0 : return -1;
127 19 : if ((ret = write(fd, &dbhead, sizeof(dbhead))) <= 0)
128 0 : return -1;
129 19 : return ret;
130 : }
131 :
132 : /*
133 : * get a field off the disk from the current file offset
134 : */
135 : int get_dbf_field(dbhead_t *dbh, dbfield_t *dbf)
136 26 : {
137 : struct dbf_dfield dbfield;
138 : int ret;
139 :
140 26 : if ((ret = read(dbh->db_fd, &dbfield, sizeof(dbfield))) <= 0) {
141 0 : return ret;
142 : }
143 :
144 : /* Check for the '0Dh' field terminator , if found return '2'
145 : which will tell the loop we are at the end of fields */
146 26 : if (dbfield.dbf_name[0]==0x0d) {
147 5 : return 2;
148 : }
149 :
150 : /* build the field name */
151 21 : copy_crimp(dbf->db_fname, dbfield.dbf_name, DBF_NAMELEN);
152 :
153 21 : dbf->db_type = dbfield.dbf_type;
154 21 : switch (dbf->db_type) {
155 : case 'N':
156 : case 'F':
157 1 : dbf->db_flen = dbfield.dbf_flen[0];
158 1 : dbf->db_fdc = dbfield.dbf_flen[1];
159 1 : break;
160 : case 'D':
161 5 : dbf->db_flen = 8;
162 5 : break;
163 : case 'L':
164 5 : dbf->db_flen = 1;
165 5 : break;
166 : default:
167 10 : dbf->db_flen = get_short(dbfield.dbf_flen);
168 : break;
169 : }
170 :
171 21 : if ((dbf->db_format = get_dbf_f_fmt(dbf)) == NULL) {
172 : /* something went wrong, most likely this fieldtype is not supported */
173 0 : return -1;
174 : }
175 :
176 21 : return 0;
177 : }
178 :
179 : /*
180 : * put a field out on the disk at the current file offset
181 : */
182 : int put_dbf_field(dbhead_t *dbh, dbfield_t *dbf)
183 68 : {
184 : struct dbf_dfield dbfield;
185 : char *scp, *dcp;
186 : int ret;
187 :
188 68 : memset (&dbfield, 0, sizeof(dbfield));
189 :
190 : /* build the on disk field info */
191 68 : scp = dbf->db_fname; dcp = dbfield.dbf_name;
192 :
193 68 : strlcpy(dbfield.dbf_name, dbf->db_fname, DBF_NAMELEN + 1);
194 :
195 68 : dbfield.dbf_type = dbf->db_type;
196 68 : switch (dbf->db_type) {
197 : case 'N':
198 2 : dbfield.dbf_flen[0] = dbf->db_flen;
199 2 : dbfield.dbf_flen[1] = dbf->db_fdc;
200 2 : break;
201 : default:
202 66 : put_short(dbfield.dbf_flen, dbf->db_flen);
203 : }
204 :
205 : /* now write it out to disk */
206 68 : if ((ret = write(dbh->db_fd, &dbfield, sizeof(dbfield))) <= 0) {
207 0 : return ret;
208 : }
209 68 : return 1;
210 : }
211 :
212 : /*
213 : * put out all the info at the top of the file...
214 : */
215 : static char end_stuff[2] = {0x0d, 0};
216 :
217 : void put_dbf_info(dbhead_t *dbh)
218 19 : {
219 : dbfield_t *dbf;
220 : char *cp;
221 : int fcnt;
222 :
223 19 : if ((cp = db_cur_date(NULL))) {
224 19 : strlcpy(dbh->db_date, cp, 9);
225 19 : free(cp);
226 : }
227 19 : put_dbf_head(dbh);
228 19 : dbf = dbh->db_fields;
229 87 : for (fcnt = dbh->db_nfields; fcnt > 0; fcnt--, dbf++)
230 68 : put_dbf_field(dbh, dbf);
231 19 : write(dbh->db_fd, end_stuff, 1);
232 19 : }
233 :
234 : char *get_dbf_f_fmt(dbfield_t *dbf)
235 45 : {
236 : char format[100];
237 :
238 : /* build the field format for printf */
239 45 : switch (dbf->db_type) {
240 : case 'C':
241 20 : snprintf(format, sizeof(format), "%%-%ds", dbf->db_flen);
242 20 : break;
243 : case 'N':
244 : case 'L':
245 : case 'D':
246 : case 'F':
247 25 : snprintf(format, sizeof(format), "%%%ds", dbf->db_flen);
248 25 : break;
249 : case 'M':
250 0 : strlcpy(format, "%s", sizeof(format));
251 0 : break;
252 : default:
253 0 : return NULL;
254 : }
255 45 : return (char *)strdup(format);
256 : }
257 :
258 : dbhead_t *dbf_open(char *dp, int o_flags TSRMLS_DC)
259 7 : {
260 : int fd;
261 : char *cp;
262 : dbhead_t *dbh;
263 :
264 7 : cp = dp;
265 7 : if ((fd = VCWD_OPEN(cp, o_flags|O_BINARY)) < 0) {
266 1 : return NULL;
267 : }
268 :
269 6 : if ((dbh = get_dbf_head(fd)) == NULL) {
270 1 : return NULL;
271 : }
272 :
273 5 : dbh->db_cur_rec = 0;
274 5 : return dbh;
275 : }
276 :
277 : void dbf_head_info(dbhead_t *dbh)
278 0 : {
279 : int nfields;
280 : dbfield_t *dbf, *cur_f;
281 :
282 0 : nfields = dbh->db_nfields;
283 0 : printf("# fields: %d, record len: %d, total records %ld\n",
284 : nfields, dbh->db_rlen, dbh->db_records);
285 0 : dbf = dbh->db_fields;
286 0 : for (cur_f = dbf; cur_f < &dbf[nfields] ; cur_f++) {
287 0 : printf("# %s, %c, %d, %d\n", cur_f->db_fname,
288 : cur_f->db_type, cur_f->db_flen, cur_f->db_fdc);
289 : }
290 0 : }
291 :
292 : /*
293 : * Local variables:
294 : * tab-width: 4
295 : * c-basic-offset: 4
296 : * End:
297 : * vim600: sw=4 ts=4 fdm=marker
298 : * vim<600: sw=4 ts=4
299 : */
|