dbf2mysql-1.14a/0000755000175000017500000000000010375471667013143 5ustar vorlonvorlondbf2mysql-1.14a/dbf.c0000640000175000017500000006365707740605443014050 0ustar vorlonvorlon/* Routines to read and write xBase-files (.dbf) By Maarten Boekhold, 29th of oktober 1995 Modified by Frank Koormann (fkoorman@usf.uni-osnabrueck.de), Jun 10 1996 prepare dataarea with memset get systemtime and set filedate set formatstring for real numbers Mod by Bob Schulze (bob@yipp.de) Added Handling for DBF D (Date) fields. */ #include #include #include #include #include #include #include #include #include #include "dbf.h" static int dbf_get_memo_data(dbhead *dbh, field *fldp, u_long blknum); struct _dbf_file_signatures { unsigned char sig; unsigned char hasMemo; unsigned char indexValid; char *description; }; static struct _dbf_file_signatures valid_dbf_types[] = { {0x03,DBF_MTYPE_NONE,0,"dBASE III w/o memo file"}, {0x04,DBF_MTYPE_NONE,1,"dBASE IV or IV w/o memo file"}, {0x05,DBF_MTYPE_NONE,1,"dBASE V w/o memo file"}, {0x83,DBF_MTYPE_DBT3,0,"dBASE III+ with memo file"}, {0xF5,DBF_MTYPE_FPT ,0,"FoxPro w. memo file"}, {0x8B,DBF_MTYPE_DBT4,1,"dBASE IV w. memo"}, {0x8E,DBF_MTYPE_NONE,1,"dBASE IV w. SQL table"}, {0x30,DBF_MTYPE_FPT ,1,"Visual FoxPro w. DBC"}, {0x7B,DBF_MTYPE_DBT4,1,"dBASE IV with memo"} }; static u_char days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* open a dbf-file, get it's field-info and store this information */ dbhead *dbf_open(char *file, int flags) { int file_no; dbhead *dbh; f_descr *fields; dbf_header *head; dbf_field *fieldc; int t; int i; char *sp; int memofound; dbf_memo_header *dbmh; if ((dbh = (dbhead *)calloc(1, sizeof(dbhead))) == NULL) { return (dbhead *)DBF_ERROR; } if ((head = (dbf_header *)malloc(sizeof(dbf_header))) == NULL) { free(dbh); return (dbhead *)DBF_ERROR; } if ((fieldc = (dbf_field *)malloc(sizeof(dbf_field))) == NULL) { free(head); free(dbh); return (dbhead *)DBF_ERROR; } if ((file_no = open(file, flags)) == -1) { free(fieldc); free(head); free(dbh); return (dbhead *)DBF_ERROR; } /* read in the disk-header */ if (read(file_no, head, sizeof(dbf_header)) == -1) { close(file_no); free(fieldc); free(head); free(dbh); return (dbhead *)DBF_ERROR; } for (t = 0; t < sizeof(valid_dbf_types)/sizeof(valid_dbf_types[0]); t++) if (valid_dbf_types[t].sig == head->dbh_dbt) break; if (t == sizeof(valid_dbf_types)/sizeof(valid_dbf_types[0])) { close(file_no); fprintf(stderr,"Header value %02x not valid\n", head->dbh_dbt); free(fieldc); free(head); free(dbh); return (dbhead *)DBF_ERROR; } dbh->db_description = valid_dbf_types[t].description; if (valid_dbf_types[t].hasMemo != DBF_MTYPE_NONE) { dbh->db_memo = valid_dbf_types[t].hasMemo; } else { dbh->db_memo = 0; } dbh->db_fd = file_no; dbh->db_year = head->dbh_year; dbh->db_month = head->dbh_month; dbh->db_day = head->dbh_day; dbh->db_hlen = get_short((u_char *)&head->dbh_hlen); dbh->db_records = get_long((u_char *)&head->dbh_records); dbh->db_currec = 0; dbh->db_rlen = get_short((u_char *)&head->dbh_rlen); dbh->db_nfields = (dbh->db_hlen - sizeof(dbf_header)) / sizeof(dbf_field); if ((dbh->db_buff = (u_char *)malloc(dbh->db_rlen)) == NULL) { close(file_no); free(fieldc); free(head); free(dbh); return (dbhead *)DBF_ERROR; } /* dbh->db_hlen - sizeof(dbf_header) isn't the correct size, cos dbh->hlen is in fact a little more cos of the 0x0D (and possibly another byte, 0x4E, I have seen this somewhere). Because of rounding everything turns out right :) */ if ((fields = (f_descr *)calloc(dbh->db_nfields, sizeof(f_descr))) == NULL) { close(file_no); free(fieldc); free(head); free(dbh); return (dbhead *)DBF_ERROR; } memofound = 0; for (t = 0; t < dbh->db_nfields; t++) { read(file_no, fieldc, sizeof(dbf_field)); if (fieldc->dbf_type == 0x00) { dbh->db_nfields = t; break; } strncpy(fields[t].db_name, fieldc->dbf_name, DBF_NAMELEN); fields[t].db_type = fieldc->dbf_type; fields[t].db_flen = fieldc->dbf_flen; fields[t].db_dec = fieldc->dbf_dec; fields[t].db_idx = fieldc->dbf_isIndexed; if (fields[t].db_type == 'M') memofound++; } dbh->db_offset = dbh->db_hlen; dbh->db_fields = fields; free(fieldc); free(head); if (memofound == 0) { dbh->db_memo = DBF_MTYPE_NONE; } else { dbh->mb_blksiz = DBF_DBT_BLOCK_SIZE; dbh->mb_bufsiz = dbh->mb_blksiz * 2; if ((dbh->mb_buffer = malloc(dbh->mb_bufsiz)) == NULL) { perror("malloc"); dbf_close(&dbh); return (dbhead *)DBF_ERROR; } dbmh = (dbf_memo_header *)dbh->mb_buffer; sp = strdup(file); i = strlen(sp)-1; switch (dbh->db_memo) { case DBF_MTYPE_FPT: if (isupper(sp[i])) strcpy(&sp[i-2],"FPT"); else strcpy(&sp[i-2],"fpt"); if ((dbh->db_memofd = open(sp, flags)) == -1) { if (isupper(sp[i])) strcpy(&sp[i-2],"fpt"); else strcpy(&sp[i-2],"FPT"); if ((dbh->db_memofd = open(sp, flags)) == -1) { char msg[256]; int saverrno = errno; if (isupper(sp[i])) strcpy(&sp[i-2],"fpt"); else strcpy(&sp[i-2],"FPT"); snprintf(msg, sizeof(msg), "couldn't find required memo data file: %s - (%d)", sp, saverrno); msg[sizeof(msg)-1] = 0; errno = saverrno; perror(msg); dbf_close(&dbh); free(sp); return (dbhead *)DBF_ERROR; } } if (read(dbh->db_memofd, dbh->mb_buffer, sizeof(dbf_memo_header)) != sizeof(dbf_memo_header)) { perror("memo file read"); dbf_close(&dbh); free(sp); return (dbhead *)DBF_ERROR; } dbh->mb_next_blk = (dbmh->fpt.next_block[0]<<24) + (dbmh->fpt.next_block[1]<<16) + (dbmh->fpt.next_block[2]<<8) + (dbmh->fpt.next_block[3]<<0); dbh->mb_blksiz = (dbmh->fpt.blocksize[0]<<8) + dbmh->fpt.blocksize[1]; #if 0 fprintf(stderr, "Visual FoxPro memo file block size of %lu, next %lu\n", dbh->mb_blksiz,dbh->mb_next_blk); #endif if (dbh->mb_blksiz > dbh->mb_bufsiz) { int newsiz = (((dbh->mb_blksiz * 2 + 4095)/4096)+1)*4096-16; void *tmpptr = realloc(dbh->mb_buffer, newsiz); if (tmpptr != NULL) { dbh->mb_buffer = tmpptr; dbh->mb_bufsiz = newsiz; } } break; case DBF_MTYPE_DBT3: case DBF_MTYPE_DBT4: if (isupper(sp[i])) strcpy(&sp[i-2],"DBT"); else strcpy(&sp[i-2],"dbt"); if ((dbh->db_memofd = open(sp, flags)) == -1) { if (isupper(sp[i])) strcpy(&sp[i-2],"dbt"); else strcpy(&sp[i-2],"DBT"); if ((dbh->db_memofd = open(sp, flags)) == -1) { char msg[256]; int saverrno = errno; if (isupper(sp[i])) strcpy(&sp[i-2],"dbt"); else strcpy(&sp[i-2],"DBT"); snprintf(msg, sizeof(msg), "couldn't find required memo data file: %s - (%d)", sp, saverrno); msg[sizeof(msg)-1] = 0; errno = saverrno; perror(msg); dbf_close(&dbh); free(sp); return (dbhead *)DBF_ERROR; } } if (read(dbh->db_memofd, dbh->mb_buffer, sizeof(dbf_memo_header)) != sizeof(dbf_memo_header)) { perror("memo file read"); dbf_close(&dbh); free(sp); return (dbhead *)DBF_ERROR; } /* Visual FoxPro V6.0 when told to write a DB IV format actually creates a DB III+ file however leaves the version field zero like a DB IV one, try to account for this */ if (dbmh->dbiii.version == 0x00 && get_short(dbmh->dbiv.blocklen) == 0 && dbmh->dbiv.filename[0] == '\0') dbmh->dbiii.version = 0x03; switch (dbmh->dbiii.version) { case 0x03: dbh->db_memo = DBF_MTYPE_DBT3; /* Set the real type */ dbh->mb_next_blk = get_long(dbmh->dbiii.next_block); dbh->mb_blksiz = DBF_DBT_BLOCK_SIZE; #if 0 fprintf(stderr, "DB III memo file block size of %lu, next %lu\n", dbh->mb_blksiz, dbh->mb_next_blk); #endif break; case 0x00: dbh->db_memo = DBF_MTYPE_DBT4; /* Set the real type */ dbh->mb_next_blk = get_long(dbmh->dbiv.next_block); dbh->mb_blksiz = get_short(dbmh->dbiv.blocklen); #if 0 fprintf(stderr, "DB IV memo file block size of %lu, next %lu\n", dbh->mb_blksiz, dbh->mb_next_blk); #endif break; default: fprintf(stderr,"DB III+/DB IV bad memo file version %02x\n", dbmh->dbiii.version); dbf_close(&dbh); free(sp); return (dbhead *)DBF_ERROR; } if (dbh->mb_blksiz > dbh->mb_bufsiz) { int newsiz = (((dbh->mb_blksiz * 2 + 4095)/4096)+1)*4096-16; void *tmpptr = realloc(dbh->mb_buffer, newsiz); if (tmpptr != NULL) { dbh->mb_buffer = tmpptr; dbh->mb_bufsiz = newsiz; } } break; case DBF_MTYPE_NONE: default: fprintf(stderr,"Found memo field in table of type (%s) which isn't supported yet\n", dbh->db_description); dbf_close(&dbh); free(sp); return (dbhead *)DBF_ERROR; break; } free(sp); } return dbh; } int dbf_write_head(dbhead *dbh) { dbf_header head; time_t now; struct tm *dbf_time; if (lseek(dbh->db_fd, 0, SEEK_SET) == -1) { return DBF_ERROR; } /* fill up the diskheader */ /* Set dataarea of head to '\0' */ memset(&head,'\0',sizeof(dbf_header)); head.dbh_dbt = DBH_NORMAL; if (dbh->db_memo) head.dbh_dbt = DBH_MEMO; now = time((time_t *)NULL); dbf_time = localtime(&now); head.dbh_year = dbf_time->tm_year; head.dbh_month = dbf_time->tm_mon + 1; /* Months since January + 1 */ head.dbh_day = dbf_time->tm_mday; put_long(head.dbh_records, dbh->db_records); put_short(head.dbh_hlen, dbh->db_hlen); put_short(head.dbh_rlen, dbh->db_rlen); if (write(dbh->db_fd, &head, sizeof(dbf_header)) == -1 ) { return DBF_ERROR; } return 0; } int dbf_put_fields(dbhead *dbh) { dbf_field field; u_long t; u_char end = 0x0D; if (lseek(dbh->db_fd, sizeof(dbf_header), SEEK_SET) == -1) { return DBF_ERROR; } /* Set dataarea of field to '\0' */ memset(&field,'\0',sizeof(dbf_field)); for (t = 0; t < dbh->db_nfields; t++) { strncpy(field.dbf_name, dbh->db_fields[t].db_name, DBF_NAMELEN - 1); field.dbf_type = dbh->db_fields[t].db_type; field.dbf_flen = dbh->db_fields[t].db_flen; field.dbf_dec = dbh->db_fields[t].db_dec; if (write(dbh->db_fd, &field, sizeof(dbf_field)) == -1) { return DBF_ERROR; } } if (write(dbh->db_fd, &end, 1) == -1) { return DBF_ERROR; } return 0; } int dbf_add_field(dbhead *dbh, char *name, u_char type, u_char length, u_char dec) { f_descr *ptr; u_char *foo; u_long size, field_no; size = (dbh->db_nfields + 1) * sizeof(f_descr); if (!(ptr = (f_descr *) realloc(dbh->db_fields, size))) { return DBF_ERROR; } dbh->db_fields = ptr; field_no = dbh->db_nfields; strncpy(dbh->db_fields[field_no].db_name, name, DBF_NAMELEN); dbh->db_fields[field_no].db_type = type; dbh->db_fields[field_no].db_flen = length; dbh->db_fields[field_no].db_dec = dec; dbh->db_nfields++; dbh->db_hlen += sizeof(dbf_field); dbh->db_rlen += length; if (!(foo = (u_char *) realloc(dbh->db_buff, dbh->db_rlen))) { return DBF_ERROR; } dbh->db_buff = foo; return 0; } dbhead *dbf_open_new(char *name, int flags) { dbhead *dbh; if (!(dbh = (dbhead *)malloc(sizeof(dbhead)))) { return (dbhead *)DBF_ERROR; } if (flags & O_CREAT) { if ((dbh->db_fd = open(name, flags, DBF_FILE_MODE)) == -1) { free(dbh); return (dbhead *)DBF_ERROR; } } else { if ((dbh->db_fd = open(name, flags)) == -1) { free(dbh); return (dbhead *)DBF_ERROR; } } dbh->db_offset = 0; dbh->db_memo = 0; dbh->db_year = 0; dbh->db_month = 0; dbh->db_day = 0; dbh->db_hlen = sizeof(dbf_header) + 1; dbh->db_records = 0; dbh->db_currec = 0; dbh->db_rlen = 1; dbh->db_nfields = 0; dbh->db_buff = NULL; dbh->db_fields = (f_descr *)NULL; return dbh; } void dbf_close(dbhead **dbhp) { close((*dbhp)->db_fd); free((*dbhp)->db_fields); (*dbhp)->db_fields = NULL; /* Defend against getting called twice */ free((*dbhp)->db_buff); (*dbhp)->db_buff = NULL; if ((*dbhp)->db_memo != DBF_MTYPE_NONE) { /* since memo files aren't on stdin this works */ if ((*dbhp)->db_memofd > 0) close((*dbhp)->db_memofd); (*dbhp)->db_memofd = 0; free((*dbhp)->mb_buffer); (*dbhp)->mb_buffer = NULL; (*dbhp)->mb_bufsiz = 0; } free(*dbhp); *dbhp = NULL; } int dbf_get_record(dbhead *dbh, field *fields, u_long rec) { int t, i; u_char *dbffield; char *end, *sp; double dblval; long long int8val; long int4val; u_int hh, mm, ss, month, day, year; u_int daynum, leap_day, day_of_year, days_in_year; u_char *days_per_month; u_long blknum; /* calculate at which offset we have to read. *DON'T* forget the 0x0D which seperates field-descriptions from records! Note (april 5 1996): This turns out to be included in db_hlen */ i = dbh->db_hlen + (rec * dbh->db_rlen); if (lseek(dbh->db_fd, i, SEEK_SET) == -1) { lseek(dbh->db_fd, 0, SEEK_SET); dbh->db_offset = 0; return DBF_ERROR; } dbh->db_offset = i; dbh->db_currec = rec; read(dbh->db_fd, dbh->db_buff, dbh->db_rlen); if (dbh->db_buff[0] == DBF_DELETED) { return DBF_DELETED; } dbffield = &dbh->db_buff[1]; for (t = 0; t < dbh->db_nfields; t++) { switch(fields[t].db_type) { case 'C': /* Character data */ end = (char *)&dbffield[fields[t].db_flen - 1]; i = fields[t].db_flen; while (( i > 0) && ((*end < 0x21)/* || (*end > 0x7E)*/)) { end--; i--; } strncpy(fields[t].db_contents, (char *)dbffield, i); fields[t].db_contents[i] = '\0'; break; case 'B': /* Binary data - 8 byte field - ???Endian Alert??? */ memcpy(&dblval, dbffield, sizeof(dblval)); snprintf(fields[t].db_contents, fields[t].db_blen, "%.*f", fields[t].db_dec, dblval); fields[t].db_contents[fields[t].db_blen-1] = '\0'; break; case 'M': /* Memo field */ case 'G': /* OLE field */ switch(dbh->db_memo) { case DBF_MTYPE_FPT: blknum = get_long(dbffield); break; case DBF_MTYPE_DBT3: case DBF_MTYPE_DBT4: strncpy(fields[t].db_contents, (char *)dbffield, fields[t].db_flen); fields[t].db_contents[fields[t].db_flen] = '\0'; blknum = atol(fields[t].db_contents); memset(fields[t].db_contents, 0, fields[t].db_flen); break; default: blknum = 0; } if (blknum != 0) dbf_get_memo_data(dbh, &fields[t], blknum); else memset(fields[t].db_contents, '\0', fields[t].db_blen); break; case 'Y': /* Currency 8 byte field - ???Endian Alert??? */ memcpy(&int8val, dbffield, sizeof(int8val)); snprintf(fields[t].db_contents, fields[t].db_blen, "%0*Ld", fields[t].db_dec+1, int8val); fields[t].db_contents[fields[t].db_blen-1] = '\0'; end = fields[t].db_contents + strlen(fields[t].db_contents) + 1; *end-- = '\0'; sp = end - 1; for (i=0; i= 3652500) { /* Only allow 0001-01-01 through 9999-12-31 */ year = month = day = 0; } else { year = daynum * 100 / 36525; day_of_year = (daynum - year * 365) - (year-1) / 4 + (((year - 1) / 100 + 1) * 3) / 4; while (day_of_year > (days_in_year = ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)) ? 366 : 365))) { day_of_year -= days_in_year; year++; } leap_day = 0; if (days_in_year == 366) { if (day_of_year > 31 + 28) { day_of_year--; if (day_of_year == 31 + 28) leap_day = 1; /* Handle leapyear's leapday */ } } month = 1; days_per_month = days_in_month; while (day_of_year > *days_per_month) { month++; day_of_year -= *days_per_month++; } day = day_of_year + leap_day; } memcpy(&int4val, &dbffield[4], sizeof(int4val)); int4val = int4val / 1000; /* Discard millseconds */ ss = int4val % 60; mm = (int4val / 60) % 60; hh = int4val / (60 * 60); snprintf(fields[t].db_contents, fields[t].db_blen, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hh, mm, ss); fields[t].db_contents[fields[t].db_blen-1] = '\0'; break; case 'I': /* Integer 8 byte field - ???Endian Alert??? */ memcpy(&int4val, dbffield, sizeof(int4val)); snprintf(fields[t].db_contents, fields[t].db_blen, "%ld", int4val); fields[t].db_contents[fields[t].db_blen-1] = '\0'; break; default: end = (char *)dbffield; i = fields[t].db_flen; while (( i > 0) && ((*end < 0x21)/* || (*end > 0x7E)*/)) { end++; i--; } strncpy(fields[t].db_contents, end, i); fields[t].db_contents[i] = '\0'; break; } dbffield += fields[t].db_flen; } dbh->db_offset += dbh->db_rlen; return DBF_VALID; } field *dbf_build_record(dbhead *dbh) { int t; field *fields; if (!(fields = (field *)calloc(dbh->db_nfields, sizeof(field)))) { return (field *)DBF_ERROR; } for ( t = 0; t < dbh->db_nfields; t++) { switch(dbh->db_fields[t].db_type) { case 'M': fields[t].db_blen = dbh->mb_blksiz + 1; break; case 'B': case 'Y': fields[t].db_blen = 26; break; case 'T': fields[t].db_blen = 24; break; case 'I': fields[t].db_blen = 16; break; case 'G': case 'P': fields[t].db_blen = dbh->mb_blksiz * 2 + 2; /* Binary to hex representation */ break; default: fields[t].db_blen = dbh->db_fields[t].db_flen + 1; } if (!(fields[t].db_contents = (char *)malloc(fields[t].db_blen))) { int i; for (i = 0; i < t; i++) if (fields[i].db_contents != 0) free(fields[i].db_contents); free(fields); return (field *)DBF_ERROR; } strncpy(fields[t].db_name, dbh->db_fields[t].db_name, DBF_NAMELEN); fields[t].db_type = dbh->db_fields[t].db_type; //printf("TYPE: %d NAME: %s LEN: %d\n",dbh->db_fields[t].db_type, dbh->db_fields[t].db_name,dbh->db_fields[t].db_flen); fields[t].db_flen = dbh->db_fields[t].db_flen; fields[t].db_dec = dbh->db_fields[t].db_dec; } return fields; } void dbf_free_record(dbhead *dbh, field *rec) { int t; for ( t = 0; t < dbh->db_nfields; t++) { free(rec[t].db_contents); } free(rec); } int dbf_put_record(dbhead *dbh, field *rec, u_long where) { u_long offset, new, idx, t, h, length; u_char *data; double fl; char foo[128], format[32]; int i,j; // for type D char newdate[10]; /* offset: offset in file for this record new: real offset after lseek idx: index to which place we are inside the 'hardcore'-data for this record t: field-counter data: the hardcore-data that is put on disk h: index into the field-part in the hardcore-data length: length of the data to copy fl: a float used to get the right precision with real numbers foo: copy of db_contents when field is not 'C' format: sprintf format-string to get the right precision with real numbers NOTE: this declaration of 'foo' can cause overflow when the contents-field is longer the 127 chars (which is highly unlikely, cos it is not used in text-fields). */ if (where > dbh->db_records) { if ((new = lseek(dbh->db_fd, 0, SEEK_END)) == -1) { return DBF_ERROR; } dbh->db_records++; } else { offset = dbh->db_hlen + (where * dbh->db_rlen); if ((new = lseek(dbh->db_fd, offset, SEEK_SET)) == -1) { return DBF_ERROR; } } dbh->db_offset = new; data = dbh->db_buff; /* Set dataarea of data to ' ' (space) */ memset(data,' ',dbh->db_rlen); data[0] = DBF_VALID; idx = 1; for (t = 0; t < dbh->db_nfields; t++) { /* if field is empty, don't do a thing */ if (rec[t].db_contents[0] != '\0') { /* Handle text */ if (rec[t].db_type == 'C') { if (strlen(rec[t].db_contents) > rec[t].db_flen) { length = rec[t].db_flen; } else { length = strlen(rec[t].db_contents); } strncpy((char *)&data[idx], rec[t].db_contents, length); } else if (rec[t].db_type == 'D' ) { /* handle date fields: make 1999-12-31...to 19991231 **/ j = 0; for (i = 0; i < 10; i++) { if (rec[t].db_contents[i] != '-') { newdate[j++] = rec[t].db_contents[i]; } } newdate[j++] = '\000'; //printf("DATE: %s -> %s\n",rec[t].db_contents, newdate ); strncpy((char *)&data[idx], newdate, 8); } else { /* Handle the rest */ /* Numeric is special, because of real numbers */ if ((rec[t].db_type == 'N') && (rec[t].db_dec != 0)) { fl = atof(rec[t].db_contents); sprintf(format, "%%.%df", rec[t].db_dec); sprintf(foo, format, fl); } else { strcpy(foo, rec[t].db_contents); } if (strlen(foo) > rec[t].db_flen) { length = rec[t].db_flen; } else { length = strlen(foo); } h = rec[t].db_flen - length; strncpy((char *)&data[idx+h], foo, length); } //printf("ii6\n");printf("is %d\n",t); } //printf("iii5"); idx += rec[t].db_flen; } //printf("iii4\n"); if (write(dbh->db_fd, data, dbh->db_rlen) == -1) { return DBF_ERROR; } dbh->db_offset += dbh->db_rlen; return 0; } static int dbf_get_memo_data(dbhead *dbh, field *fldp, u_long blknum) { u_long offset; u_long req_offset; u_long len; u_long typ; u_char *sp; int done; int i; req_offset = blknum * dbh->mb_blksiz; if ((offset = lseek(dbh->db_memofd, req_offset, SEEK_SET)) == -1) { perror("memofile lseek"); return 1; } if (offset != req_offset) { char msg[256]; int saverrno = errno; snprintf(msg, sizeof(msg), "memofile lseek failed, block %lu expected %lu actual %lu code %d", blknum, req_offset, offset, saverrno); msg[sizeof(msg)-1] = 0; errno = saverrno; perror(msg); memset(fldp->db_contents, 0, fldp->db_blen); return 1; } switch(dbh->db_memo) { case DBF_MTYPE_FPT: if ((read(dbh->db_memofd, dbh->mb_buffer, sizeof(dbf_memo_block_header))) < 0) { perror("memofile read"); return 1; } sp = ((dbf_memo_block_header *)(dbh->mb_buffer))->header; typ = (sp[0]<<24) + (sp[1]<<16) + (sp[2]<<8) + (sp[3]<<0); sp = ((dbf_memo_block_header *)(dbh->mb_buffer))->length; len = (sp[0]<<24) + (sp[1]<<16) + (sp[2]<<8) + (sp[3]<<0); #if 0 printf("memo-read blk: %3lu offset %5lu(0x%04lx) type %2lx size %3ld(0x%03lx)", blknum, offset, offset, typ, len, len); #endif if (dbh->mb_bufsiz < len) { int newsiz = (((len + 4095)/4096)+1)*4096-16; void *tmpptr = realloc(dbh->mb_buffer, newsiz); if (tmpptr != NULL) { dbh->mb_buffer = tmpptr; dbh->mb_bufsiz = newsiz; } } len = (len < dbh->mb_bufsiz) ? len : dbh->mb_bufsiz; if ((read(dbh->db_memofd, dbh->mb_buffer, len)) < 0) { perror("memofile read"); return 1; } switch(typ) { case 0x00: /* Picture type */ case 0x02: /* Object type */ fldp->db_contents[0] = '\0'; break; case 0x01: /* Memo type */ if (fldp->db_blen <= len) { void *tmpptr = realloc(fldp->db_contents, len + 1); if (tmpptr != NULL) { fldp->db_contents = tmpptr; fldp->db_blen = len + 1; } } len = (len < fldp->db_blen) ? len : fldp->db_blen - 1; strncpy(fldp->db_contents, (char *)dbh->mb_buffer, len); fldp->db_contents[len] = '\0'; #if 0 printf(" '%s'\n", fldp->db_contents); #endif break; default: /* Something wrong */ break; } break; case DBF_MTYPE_DBT3: done = 0; len = 0; sp = dbh->mb_buffer; while(!done) { if (dbh->mb_bufsiz < len + DBF_DBT_BLOCK_SIZE) { int newsiz = len + DBF_DBT_BLOCK_SIZE * 4; void *tmpptr = realloc(dbh->mb_buffer, newsiz); if (tmpptr != NULL) { dbh->mb_buffer = tmpptr; dbh->mb_bufsiz = newsiz; sp = dbh->mb_buffer + len; } else { perror("dbIII memo field malloc failure"); exit(1); } } if (read(dbh->db_memofd, sp, DBF_DBT_BLOCK_SIZE) < DBF_DBT_BLOCK_SIZE) { perror("memofile read"); fldp->db_contents[0] = '\0'; return 1; } for (i = 0; i < DBF_DBT_BLOCK_SIZE; i++) { if (*sp != 0x1a) { len++; sp++; } else { done = 1; break; } } } *sp = '\0'; if (fldp->db_blen <= len) { void *tmpptr = realloc(fldp->db_contents, len + 1); if (tmpptr != NULL) { fldp->db_contents = tmpptr; fldp->db_blen = len + 1; } } len = (len < fldp->db_blen) ? len : fldp->db_blen - 1; strncpy(fldp->db_contents, (char *)dbh->mb_buffer, len); fldp->db_contents[len] = '\0'; break; case DBF_MTYPE_DBT4: if ((read(dbh->db_memofd, dbh->mb_buffer, sizeof(dbf_memo_block_header))) < 0) { perror("memofile read"); return 1; } sp = ((dbf_memo_block_header *)(dbh->mb_buffer))->header; typ = (sp[0]<<24) + (sp[1]<<16) + (sp[2]<<8) + (sp[3]<<0); len = get_long(((dbf_memo_block_header *)(dbh->mb_buffer))->length); if (typ != 0xFFFF0800) { fprintf(stderr, "corrupt memo header in field %s memo block %lu\n", fldp->db_name, blknum); memset(fldp->db_contents, 0, fldp->db_blen); return 1; } if (dbh->mb_bufsiz < len) { int newsiz = (((len + 4095)/4096)+1)*4096-16; void *tmpptr = realloc(dbh->mb_buffer, newsiz); if (tmpptr != NULL) { dbh->mb_buffer = tmpptr; dbh->mb_bufsiz = newsiz; } } len = (len < dbh->mb_bufsiz) ? len : dbh->mb_bufsiz; if ((read(dbh->db_memofd, dbh->mb_buffer, len)) < 0) { perror("memofile read"); return 1; } if (fldp->db_blen <= len) { void *tmpptr = realloc(fldp->db_contents, len + 1); if (tmpptr != NULL) { fldp->db_contents = tmpptr; fldp->db_blen = len + 1; } } len = (len < fldp->db_blen) ? len : fldp->db_blen - 1; strncpy(fldp->db_contents, (char *)dbh->mb_buffer, len); fldp->db_contents[len] = '\0'; break; case DBF_MTYPE_NONE: fldp->db_contents[0] = '\0'; break; default: fprintf(stderr, "Sorry don't support memo fields on this database type yet\n"); dbh->db_memo = DBF_MTYPE_NONE; return 1; } return 0; } dbf2mysql-1.14a/dbf.h0000640000175000017500000001256007131162154014027 0ustar vorlonvorlon/* header-file for dbf.c declares routines for reading and writing xBase-files (.dbf), and associated structures Maarten Boekhold (boekhold@cindy.et.tudelft.nl) 29 oktober 1995 */ #ifndef _DBF_H #define _DBF_H #include /********************************************************************** The DBF-part ***********************************************************************/ #define DBF_FILE_MODE 0644 /* byte offsets for date in dbh_date */ #define DBH_DATE_YEAR 0 #define DBH_DATE_MONTH 1 #define DBH_DATE_DAY 2 /* maximum fieldname-length */ #define DBF_NAMELEN 11 /* magic-cookies for the file */ #define DBH_NORMAL 0x03 #define DBH_MEMO 0x83 /* magic-cookies for the fields */ #define DBF_ERROR -1 #define DBF_VALID 0x20 #define DBF_DELETED 0x2A #define DBF_EOF 0x1A /* Types of MEMO files; normal dbase III+,IV:DBT, FoxPro:FPT */ #define DBF_MTYPE_NONE 0 #define DBF_MTYPE_DBT3 1 #define DBF_MTYPE_DBT4 2 #define DBF_MTYPE_DBT5 3 #define DBF_MTYPE_FPT 4 #define DBF_DBT_BLOCK_SIZE 512 /* diskheader */ typedef struct { u_char dbh_dbt; /* indentification field */ u_char dbh_year; /* last modification-date */ u_char dbh_month; u_char dbh_day; u_char dbh_records[4]; /* number of records */ u_char dbh_hlen[2]; /* length of this header */ u_char dbh_rlen[2]; /* length of a record */ u_char dbh_stub[20]; /* misc stuff we don't need */ } dbf_header; /* disk field-description */ typedef struct { char dbf_name[DBF_NAMELEN]; /* field-name terminated with \0 */ u_char dbf_type; /* field-type */ u_char dbf_reserved[4]; /* some reserved stuff */ u_char dbf_flen; /* field-length */ u_char dbf_dec; /* number of decimal positions if type is 'N' */ u_char dbf_stub[13]; /* stuff we don't need */ u_char dbf_isIndexed; /* exists in index flag */ } dbf_field; /* disk data structures for working with memo files */ typedef union { struct { u_char next_block[4]; u_char reserve1[4]; u_char reserve2[8]; u_char version; } dbiii; struct { u_char next_block[4]; u_char blocksize[4]; u_char filename[8]; u_char version; u_char reserve1[3]; u_char blocklen[2]; } dbiv; struct { u_char next_block[4]; u_char reserve1[2]; u_char blocksize[2]; } fpt; } dbf_memo_header; typedef struct { u_char header[4]; u_char length[4]; } dbf_memo_block_header; /* memory field-description */ typedef struct { char db_name[DBF_NAMELEN]; /* field-name terminated with \0 */ u_char db_type; /* field-type */ u_char db_flen; /* field-length */ u_char db_dec; /* number of decimal positions */ u_char db_idx; /* exists in index flag */ } f_descr; /* memory dfb-header */ typedef struct { int db_fd; /* file-descriptor */ u_long db_offset; /* current offset in file */ u_char db_memo; /* memo-file present (and type) */ u_char db_year; /* last update as YYMMDD */ u_char db_month; u_char db_day; u_long db_hlen; /* length of the diskheader, for calculating the offsets */ u_long db_records; /* number of records */ u_long db_currec; /* current record-number starting at 0 */ u_short db_rlen; /* length of the record */ u_char db_nfields; /* number of fields */ u_char *db_buff; /* record-buffer to save malloc()'s */ f_descr *db_fields; /* pointer to an array of field-descriptions */ char *db_description; /* Pointer to string description of table type */ int db_memofd; /* memo file-descriptor */ u_char *mb_buffer; /* memo block buffer to save malloc()'s */ u_long mb_bufsiz; /* Current size of memo block buffer */ u_long mb_blksiz; /* memo file block size */ u_long mb_curr_blk; /* memo file current block number */ u_long mb_next_blk; /* memo file next used block number */ u_long mb_free_blk; /* memo file next free block number */ } dbhead; /* structure that contains everything a user wants from a field, including the contents (in ASCII). Warning! db_flen may be bigger than the actual length of db_name! This is because a field doesn't have to be completely filled */ typedef struct { char db_name[DBF_NAMELEN]; /* field-name terminated with \0 */ u_char db_type; /* field-type */ u_char db_flen; /* field-length */ u_char db_dec; /* number of decimal positions */ u_long db_blen; /* Length of db_contents Buffer */ char* db_contents; /* contents of the field in ASCII */ } field; /* prototypes for functions */ extern dbhead* dbf_open(char *file ,int flags); extern int dbf_write_head(dbhead *dbh); extern int dbf_put_fields(dbhead *dbh); extern int dbf_add_field(dbhead *dbh, char *name, u_char type, u_char length, u_char dec); extern dbhead * dbf_open_new(char *name, int flags); extern void dbf_close(dbhead **dbh); extern int dbf_get_record(dbhead *dbh, field *fields, u_long rec); extern field* dbf_build_record(dbhead *dbh); extern void dbf_free_record(dbhead *dbh, field* fields); extern int dbf_put_record(dbhead *dbh, field *rec, u_long where); /********************************************************************* The endian-part ***********************************************************************/ extern long get_long(u_char *cp); extern void put_long(u_char *cp, long lval); extern short get_short(u_char *cp); extern void put_short(u_char *cp, short lval); #endif /* _DBF_H */ dbf2mysql-1.14a/dbf2mysql.c0000640000175000017500000004345407740605443015211 0ustar vorlonvorlon/* This program reads in an xbase-dbf file and sends 'inserts' to an MySQL-server with the records in the xbase-file M. Boekhold (boekhold@cindy.et.tudelft.nl) okt. 1995 Patched for MySQL by Michael Widenius (monty@analytikerna.se) 96.11.03 GLC - Gerald L. Clark (gerald_clark@sns.ca) june 1998 Added Date and Boolean field conversions. Fixxed Quick mode insert for blank Numeric fields Modified to use -x flag to add _rec and _timestamp fields to start of record. ( only those lines immediately affect by if(express) (and getopt) ) */ #include #include #include #include #include #include #include #include #include #include "dbf.h" int verbose=0, upper=0, lower=0, create=0, fieldlow=0, var_chars=1; int express=0; int null_fields=0, trim=0, quick=0; char primary[11]; char *host = NULL; char *dbase = "test"; char *table = "test"; char *pass = NULL; char *user = NULL; char *subarg = NULL; char *flist = NULL; char *indexes = NULL; char *convert = NULL; void do_onlyfields (char *flist, dbhead *dbh); void do_substitute(char *subarg, dbhead *dbh); inline void strtoupper(char *string); inline void strtolower(char *string); void do_create(MYSQL *, char*, dbhead*); void do_inserts(MYSQL *, char*, dbhead*); int check_table(MYSQL *, char*); void usage(void); inline void strtoupper(char *string) { while(*string != '\0') { *string = toupper(*string); string++; } } inline void strtolower(char *string) { while(*string != '\0') { *string = tolower(*string); string++; } } int check_table(MYSQL *sock, char *table) { MYSQL_RES *result; MYSQL_ROW row; if ( (result = mysql_list_tables (sock,NULL)) == NULL ) return 0; while ( (row = mysql_fetch_row(result)) != NULL) { if ( strcmp((char *) row[0], table) == 0) { mysql_free_result(result); return 1; } } mysql_free_result(result); return 0; } void usage(void){ printf("dbf2mysql %s\n", VERSION); printf("usage: dbf2mysql [-h hostname] [-d dbase] [-t table] [-p primary key]\n"); printf(" [-o field[,field]] [-s oldname=newname[,oldname=newname]]\n"); printf(" [-i field[,field]] [-c] [-f] [-F] [-n] [-r] [-u|-l] \n"); printf(" [-v[v]] [-x] [-q] [-P password] [-U user] dbf-file\n"); } /* patch by Mindaugas Riauba */ /* Nulls non specified field names */ void do_onlyfields (char *flist, dbhead *dbh) { char *s, *flist2; int i, match; if (flist == NULL) return; if (verbose > 2) printf ("Removing not specified fields\n"); if ( (flist2 = malloc (strlen(flist)*sizeof(char) + 1)) == NULL) { fprintf (stderr, "Memory allocation error in function do_onlyfields\n"); dbf_close(&dbh); exit(1); } if (verbose > 2) printf ("Used fields: "); for (i = 0; i < dbh -> db_nfields; i++) { strcpy (flist2, flist); match = 0; for (s = strtok (flist2, ","); s != NULL; s = strtok (NULL, ",")) { if ( strcasecmp (s, dbh -> db_fields[i].db_name) == 0 ) { match = 1; if (verbose>1) printf ("%s", s); } } if ( match == 0 ) dbh -> db_fields[i].db_name[0] = '\0'; } if (verbose > 2) printf ("\n"); free (flist2); } /* do_onlyfields */ /* patch submitted by Jeffrey Y. Sue */ /* Provides functionallity for substituting dBase-fieldnames for others */ /* Mainly for avoiding conflicts between fieldnames and MySQL-reserved */ /* keywords */ void do_substitute(char *subarg, dbhead *dbh) { /* NOTE: subarg is modified in this function */ int i,bad; char *p,*oldname,*newname; if (subarg == NULL) return; if (verbose>1) { printf("Substituting new field names\n"); } /* use strstr instead of strtok because of possible empty tokens */ oldname = subarg; while (oldname && strlen(oldname) && (p=strstr(oldname,"=")) ) { *p = '\0'; /* mark end of oldname */ newname = ++p; /* point past \0 of oldname */ if (strlen(newname)) { /* if not an empty string */ p = strstr(newname,","); if (p) { *p = '\0'; /* mark end of newname */ p++; /* point past where the comma was */ } } if (strlen(newname)>=DBF_NAMELEN) { printf("Truncating new field name %s to %d chars\n", newname,DBF_NAMELEN-1); newname[DBF_NAMELEN-1] = '\0'; } bad = 1; for (i=0;idb_nfields;i++) { if (strcmp(dbh->db_fields[i].db_name,oldname)==0) { bad = 0; strcpy(dbh->db_fields[i].db_name,newname); if (verbose>1) { printf("Substitute old:%s new:%s\n", oldname,newname); } break; } } if (bad) { printf("Warning: old field name %s not found\n", oldname); } oldname = p; } } /* do_substitute */ void do_create(MYSQL *SQLsock, char *table, dbhead *dbh) { /* Patched by GLC to support date and boolean fields */ /* Patched by WKV to support Visual FoxPro fields */ char *query, *s; char t[20]; int i, first_done; if (verbose > 2) { printf("Building CREATE-clause\n"); } if (!(query = (char *)malloc( ( express * 100 ) + (dbh->db_nfields * 60) + 29 + strlen(table)))) { fprintf(stderr, "Memory allocation error in function do_create\n"); mysql_close(SQLsock); dbf_close(&dbh); exit(1); } sprintf(query, "CREATE TABLE %s (", table); if(express) { strcat (query, "_rec int(10) unsigned DEFAULT '0' NOT NULL auto_increment PRIMARY KEY,\n"); strcat (query,"_timestamp timestamp(14),\n"); } first_done = 0; for ( i = 0; i < dbh->db_nfields; i++) { if (!strlen(dbh->db_fields[i].db_name)) { continue; /* skip field if length of name == 0 */ } if (first_done) { strcat(query, ",\n\t"); } first_done = 1; if (fieldlow) strtolower(dbh->db_fields[i].db_name); strcat(query, dbh->db_fields[i].db_name); switch(dbh->db_fields[i].db_type) { case 'C': if (var_chars) strcat(query, " varchar"); else strcat(query, " char"); sprintf(t,"(%d)",dbh->db_fields[i].db_flen); strcat(query, t); break; case 'N': if (dbh->db_fields[i].db_dec != 0) { strcat(query, " real"); /* decimal the better choice? */ } else { strcat(query, " int"); } break; case 'L': /* strcat(query, " char (1)"); */ strcat(query, " enum('F','T')"); break; case 'D': strcat(query, " date"); break; case 'M': strcat(query, " text"); break; case 'F': strcat(query, " double"); break; case 'B': /* ?Depends on DB vs FoxPro? Former is memo, latter is Binary */ sprintf(t," decimal(15,%d)",dbh->db_fields[i].db_dec); strcat(query, t); break; case 'G': strcat(query, " blob"); break; case 'P': strcat(query, " blob"); break; case 'Y': strcat(query, " decimal(21,4)"); break; case 'T': strcat(query, " datetime"); break; case 'I': strcat(query, " int"); break; } if (strcmp(dbh->db_fields[i].db_name, primary) == 0) { strcat(query, " not null primary key"); } else if (!null_fields) strcat(query," not null"); } if (indexes) /* add INDEX statements */ { for (s = strtok (indexes, ","); s != NULL; s = strtok (NULL, ",")) { strcat (query, ",INDEX("); strcat (query, s); strcat (query, ")"); } } strcat(query, ")\n"); if (verbose > 2) { printf("Sending create-clause\n"); printf("%s\n", query); printf ("fields in dbh %d, allocated mem for query %d, query size %d\n", dbh->db_nfields, (dbh->db_nfields * 60) + 29 + strlen(table), strlen(query)); } if (mysql_query(SQLsock, query) == -1) { fprintf(stderr, "Error creating table!\n"); fprintf(stderr, "Detailed report: %s\n", mysql_error(SQLsock)); dbf_close(&dbh); free(query); mysql_close(SQLsock); exit(1); } free(query); } /* Patched by GLC to fix quick mode Numeric fields */ void do_inserts(MYSQL *SQLsock, char *table, dbhead *dbh) { int result, i, j, nc = 0, h; field *fields; char *query, *vpos, *pos; char str[257], *cvt = NULL, *s; u_long val_len = 0; char *datafile = NULL; FILE *fconv, *tempfile = NULL; int quote_field; u_long val_used; int base_pos; /* Max Number of characters that can be stored before checking buffer size */ #define VAL_EXTRA 16 if (convert != NULL) /* If specified conversion table */ { if ( (fconv = fopen (convert, "rt")) == NULL ) fprintf (stderr, "Cannot open convert file '%s'.\n", convert); else { nc = atoi (fgets (str, 256, fconv)); if (verbose > 2) printf ("Using conversion table '%s' with %d entries\n", convert, nc); if ( (cvt = (char *) malloc (nc*2 + 1)) == NULL ) { fprintf(stderr, "Memory allocation error in do_inserts (cvt)\n"); mysql_close(SQLsock); dbf_close(&dbh); exit(1); } for (i = 0, fgets (str, 256, fconv); (i < nc * 2) && (str != NULL); i++) { cvt[i++] = atoi (strtok (str, " \t")); cvt[i] = atoi (strtok (NULL, " \t")); fgets (str, 256, fconv); } cvt[i] = '\0'; } } if (verbose > 2) { printf("Inserting records\n"); } for ( i = 0 ; i < dbh->db_nfields ; i++ ) { switch(dbh->db_fields[i].db_type) { case 'M': case 'G': val_len += 2048; break; case 'T': val_len += 23; break; default: val_len += dbh->db_fields[i].db_flen*2 + 3; } } if (!(query = (char *)malloc( (express*10) + 26 + strlen(table) + val_len + VAL_EXTRA))) { fprintf(stderr, "Memory allocation error in function do_inserts (query)\n"); mysql_close(SQLsock); dbf_close(&dbh); exit(1); } if (!quick) { sprintf(query, "INSERT INTO %s VALUES (",table); } else if (express) strcat(query, "NULL,NULL,"); else /* if specified -q create file for 'LOAD DATA' */ { datafile = tempnam ("/tmp", "d2my"); tempfile = fdopen (open (datafile, O_WRONLY | O_CREAT | O_EXCL, 0600), "wt"); if (tempfile == NULL || datafile == NULL) { fprintf (stderr, "Cannot open file '%s' for writing\n", datafile); return; } query[0] = '\0'; } base_pos = strlen(query); if ((fields = dbf_build_record(dbh)) == (field *)DBF_ERROR) { fprintf(stderr, "Couldn't create memory structure for record\n"); return; } for ( i = 0; i < dbh->db_records; i++) { result = dbf_get_record(dbh, fields, i); if (result == DBF_VALID) { vpos = query + base_pos; val_used = 0; for (h = 0; h < dbh->db_nfields; h++) { /* if length of fieldname==0, skip it */ if (!strlen(fields[h].db_name)) continue; if (fields[h].db_type == 'N' || fields[h].db_type == 'F' || fields[h].db_type == 'B' || fields[h].db_type == 'Y' || fields[h].db_type == 'I') quote_field = 0; else quote_field = 1; if (vpos != query + base_pos) { *vpos++= ','; val_used++; } if (quick || quote_field) { *vpos++= '\''; val_used++; } if (trim && quote_field) /* trim leading spaces */ { for (pos = fields[h].db_contents; isspace(*pos) && (*pos != '\0'); pos++); memmove (fields[h].db_contents, pos, strlen (pos) + 1); } if ( (nc > 0) && (fields[h].db_type == 'C')) { for (j = 0; fields[h].db_contents[j] != '\0'; j++) { if ( (s = strchr (cvt, fields[h].db_contents[j])) != NULL ) if ( (s - cvt) % 2 == 0 ) fields[h].db_contents[j] = s[1]; } } if (upper) strtoupper(fields[h].db_contents); if (lower) strtolower(fields[h].db_contents); for (pos = fields[h].db_contents ; *pos ; pos++) { if (*pos == '\\' || *pos == '\'') { *vpos++='\\'; val_used++; } *vpos++= *pos; val_used++; if (val_used >= val_len) { // int newsiz = (((val_used + strlen(pos) + VAL_EXTRA + base_pos + 4095)/4096)+1)*4096-16; int newsiz = base_pos + val_used + strlen(pos) + VAL_EXTRA; void *tmpptr = realloc(query, newsiz); if (tmpptr == NULL) { perror("out of memory in do_inserts"); mysql_close(SQLsock); dbf_close(&dbh); exit(1); } query = tmpptr; vpos = query + base_pos + val_used; val_len = newsiz - base_pos - VAL_EXTRA; } } if (quote_field && !quick) { *vpos++= '\''; val_used++; } else { if (!fields[h].db_contents[0]) { /* Numeric field is null */ if (null_fields) { strcpy(vpos, "NULL"); vpos += 4; val_used += 4; } else { if (!quote_field) { *vpos++ = '0'; val_used++; } } } } if (quick) { *vpos++= '\''; val_used++; } } if (!quick) { vpos[0]=')'; /* End of values */ vpos[1]=0; /* End of query */ } else vpos[0] = '\0'; if ((verbose == 3) && ((i % 100) == 0)) { printf("Inserting record %d\n", i); } if (verbose > 3) { printf("Record %4d: %s\n", i, query); } if (!quick) { if (mysql_query(SQLsock, query) == -1) { fprintf(stderr, "Error sending INSERT in record %04d\n", i); fprintf(stderr, "Detailed report: %s\n", mysql_error(SQLsock)); if (verbose > 1) { fprintf(stderr, "%s\n", query); } } } else { if (express) fprintf (tempfile, "NULL,NULL,%s\n", query); else fprintf (tempfile, "%s\n", query); } } } dbf_free_record(dbh, fields); free(query); if (nc > 0) free (cvt); if (quick) { fclose (tempfile); query=str; sprintf (query, "LOAD DATA LOCAL INFILE '%s' REPLACE INTO table %s fields terminated by ',' enclosed by ''''", datafile, table); if ( verbose > 1 ) { fprintf (stderr, "%s\n", query); } if (mysql_query(SQLsock, query) == -1) { fprintf(stderr, "Error sending LOAD DATA INFILE from file '%s'\n", datafile); fprintf(stderr, "Detailed report: %s\n", mysql_error(SQLsock)); } if ( unlink (datafile) == -1 ) { fprintf (stderr, "Error while removing temporary file '%s'.\n", datafile); } free (datafile); } } int main(int argc, char **argv) { int i; MYSQL *SQLsock,mysql; extern int optind; extern char *optarg; char *query; dbhead *dbh; primary[0] = '\0'; while ((i = getopt(argc, argv, "xqfFrne:lucvi:h:p:d:t:s:o:U:P:")) != EOF) { switch (i) { case 'P': pass = (char *)strdup(optarg); break; case 'U': user = (char *)strdup(optarg); break; case 'x': express=1; break; case 'f': fieldlow=1; break; case 'F': var_chars=0; break; case 'r': trim = 1; break; case 'n': null_fields=1; break; case 'v': verbose++; break; case 'c': create++; break; case 'l': lower=1; break; case 'u': if (lower) { usage(); printf("Can't use -u and -l at the same time!\n"); exit(1); } upper=1; break; case 'e': convert = (char *)strdup (optarg); break; case 'h': host = (char *)strdup(optarg); break; case 'q': quick = 1; break; case 'p': strncpy(primary, optarg, 11); break; case 'd': dbase = (char *)strdup(optarg); break; case 't': table = (char *)strdup(optarg); break; case 'i': indexes = (char *)strdup(optarg); break; case 's': subarg = (char *)strdup(optarg); break; case 'o': flist = (char *)strdup(optarg); break; case ':': usage(); printf("missing argument!\n"); exit(1); case '?': usage(); printf("unknown argument: %s\n", argv[0]); exit(1); default: break; } } argc -= optind; argv = &argv[optind]; if (argc != 1) { usage(); exit(1); } if (verbose > 2) { printf("Opening dbf-file %s\n", argv[0]); } if ((dbh = dbf_open(argv[0], O_RDONLY)) == (dbhead *)-1) { fprintf(stderr, "Couldn't open xbase-file %s\n", argv[0]); exit(1); } if (verbose) { printf("dbf-file: %s - %s, MySQL-dbase: %s, MySQL-table: %s\n", argv[0], dbh->db_description, dbase, table); printf("Number of records: %ld\n", dbh->db_records); } if (verbose > 1) { printf("Name\t\t Length\tDisplay\t Type\n"); printf("-------------------------------------\n"); for (i = 0; i < dbh->db_nfields ; i++) { printf("%-12s\t%7d\t%5d\t%3c\n", dbh->db_fields[i].db_name, dbh->db_fields[i].db_flen, dbh->db_fields[i].db_dec, dbh->db_fields[i].db_type); } } if (verbose > 2) { printf("Making connection to MySQL-server\n"); } if (!(SQLsock = mysql_connect(&mysql,host,user,pass))) { fprintf(stderr, "Couldn't get a connection with the "); fprintf(stderr, "designated host!\n"); fprintf(stderr, "Detailed report: %s\n", mysql_error(&mysql)); dbf_close(&dbh); exit(1); } if (verbose > 2) { printf("Selecting database '%s'\n", dbase); } if ((mysql_select_db(SQLsock, dbase)) == -1) { fprintf(stderr, "Couldn't select database %s.\n", dbase); fprintf(stderr, "Detailed report: %s\n", mysql_error(SQLsock)); mysql_close(SQLsock); dbf_close(&dbh); exit(1); } /* Substitute field names */ do_onlyfields(flist, dbh); do_substitute(subarg, dbh); if (!create) { if (!check_table(SQLsock, table)) { printf("Table does not exist!\n"); exit(1); } } else { if (verbose > 2) { printf("Dropping original table (if one exists)\n"); } if (!(query = (char *)malloc(12 + strlen(table)))) { printf("Memory-allocation error in main (drop)!\n"); mysql_close(SQLsock); dbf_close(&dbh); exit(1); } sprintf(query, "DROP TABLE %s", table); mysql_query(SQLsock, query); free(query); /* Build a CREATE-clause */ do_create(SQLsock, table, dbh); } /* Build an INSERT-clause */ if (create < 2) do_inserts(SQLsock, table, dbh); if (verbose > 2) { printf("Closing up....\n"); } mysql_close(SQLsock); dbf_close(&dbh); exit(0); } dbf2mysql-1.14a/endian.c0000640000175000017500000000147006761242724014535 0ustar vorlonvorlon/* Maarten Boekhold (boekhold@cindy.et.tudelft.nl) oktober 1995 */ #include #include "dbf.h" /* * routine to change little endian long to host long */ long get_long(u_char *cp) { long ret; ret = *cp++; ret += ((*cp++)<<8); ret += ((*cp++)<<16); ret += ((*cp++)<<24); return ret; } void put_long(u_char *cp, long lval) { cp[0] = lval & 0xff; cp[1] = (lval >> 8) & 0xff; cp[2] = (lval >> 16) & 0xff; cp[3] = (lval >> 24) & 0xff; } /* * routine to change little endian short to host short */ short get_short(u_char *cp) { short ret; ret = *cp++; ret += ((*cp++)<<8); return ret; } void put_short(u_char *cp, short sval) { cp[0] = sval & 0xff; cp[1] = (sval >> 8) & 0xff; } dbf2mysql-1.14a/mysql2dbf.c0000640000175000017500000001561506761242724015210 0ustar vorlonvorlon/* utility to read out an mySQL-table, and store it into a DBF-file M. Boekhold (boekhold@cindy.et.tudelft.nl) April 1996 */ #include #include #include #include #include #include #include #include #include "dbf.h" int verbose = 0, upper = 0, lower = 0, create = 0; long precision = 6; char *host = NULL; char *dbase = NULL; char *table = NULL; char *pass = NULL; char *user = NULL; inline void strtoupper(char *string); inline void strtolower(char *string); void usage(void); inline void strtoupper(char *string) { while(*string != '\0') { *string = toupper(*string); string++; } } inline void strtolower(char *string) { while(*string != '\0') { *string = tolower(*string); string++; } } void usage(void) { printf("mysql2dbf %s\n", VERSION); printf("usage:\tmysql2dbf [-h host] [-u | -l] [-v[v]]\n"); printf("\t\t\t[-q query] [-P password] [-U user] -d dbase -t table dbf-file\n"); } int main(int argc, char **argv) { int i; MYSQL *SQLsock,mysql; extern int optind; extern char *optarg; char *query = NULL; dbhead *dbh; field *rec; MYSQL_RES *qres; MYSQL_ROW qrow; MYSQL_FIELD *qfield; u_long numfields, numrows, t; while ((i = getopt(argc, argv, "lucvq:h:d:t:p:U:P:")) != EOF) { switch(i) { case 'q': query = strdup(optarg); break; case 'v': verbose++; break; case 'c': create = 1; break; case 'l': if (upper) { usage(); printf("Can't use -u and -l at the same time!\n"); exit(1); } lower = 1; break; case 'u': if (lower) { usage(); printf("Can't use -u and -l at the same time!\n"); exit(1); } upper = 1; break; case 'h': host = (char *)strdup(optarg); break; case 'd': dbase = (char *)strdup(optarg); break; case 't': table = (char *)strdup(optarg); break; case 'P': pass = (char *)strdup(optarg); break; case 'U': user = (char *)strdup(optarg); break; case ':': usage(); printf("Missing argument!\n"); exit(1); case '?': usage(); printf("Unknown argument: %s\n", argv[0]); exit(1); default: break; } } argc -= optind; argv = &argv[optind]; if (argc != 1) { usage(); exit(1); } if ((dbase == NULL) || ((table == NULL) && (query == NULL))) { usage(); printf("Dbase and table *must* be specified!\n"); exit(1); } if (query == NULL) { query = (char *)malloc(14+strlen(table)); sprintf(query, "SELECT * FROM %s", table); } if (verbose > 1) { printf("Opening %s for writing (previous contents will be lost)\n", argv[0]); } if ((dbh = dbf_open_new(argv[0], O_WRONLY | O_CREAT | O_TRUNC)) == (dbhead *)DBF_ERROR) { fprintf(stderr, "Couldn't open xbase-file for writing: %s\n", argv[0]); exit(1); } if (verbose > 1) { printf("Making connection with mySQL-server\n"); } if (!(SQLsock = mysql_connect(&mysql,host,user,pass))) { fprintf(stderr, "Couldn't get a connection with the "); fprintf(stderr, "designated host!\n"); fprintf(stderr, "Detailed report: %s\n", mysql_error(&mysql)); close(dbh->db_fd); free(dbh); exit(1); } if (verbose > 1) { printf("Selecting database\n"); } if ((mysql_select_db(SQLsock, dbase)) == -1) { fprintf(stderr, "Couldn't select database %s.\n", dbase); fprintf(stderr, "Detailed report: %s\n", mysql_error(SQLsock)); close(dbh->db_fd); free(dbh); mysql_close(SQLsock); exit(1); } if (verbose > 1) { printf("Sending query\n"); } if (mysql_query(SQLsock, query) == -1) { fprintf(stderr, "Error sending query.\nDetailed report: %s\n", mysql_error(SQLsock)); if (verbose > 1) { fprintf(stderr, "%s\n", query); } mysql_close(SQLsock); close(dbh->db_fd); free(dbh); exit(1); } qres = mysql_store_result(SQLsock); numfields = mysql_num_fields(qres); numrows = mysql_num_rows(qres); while ((qfield = mysql_fetch_field(qres))) { strtoupper(qfield->name); switch (qfield->type) { /* assume INT's have a max. of 10 digits (4^32 has 10 digits) */ case FIELD_TYPE_CHAR: case FIELD_TYPE_SHORT: case FIELD_TYPE_LONG: dbf_add_field(dbh, qfield->name, 'N', 10, 0); if (verbose > 1) { printf("Adding field: %s, INT_TYPE, %d\n", qfield->name, qfield->length); } break; /* do we have to make the same assumption here? */ case FIELD_TYPE_DOUBLE: case FIELD_TYPE_FLOAT: case FIELD_TYPE_DECIMAL: dbf_add_field(dbh, qfield->name, 'N', qfield->length, qfield->decimals); if (verbose > 1) { printf("Adding field: %s, INT_REAL, %d\n", qfield->name, qfield->length); } break; case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: case FIELD_TYPE_BLOB: case FIELD_TYPE_TINY_BLOB: case FIELD_TYPE_MEDIUM_BLOB: case FIELD_TYPE_LONG_BLOB: dbf_add_field(dbh, qfield->name, 'C', qfield->length, 0); if (verbose > 1) { printf("Adding field: %s, INT_CHAR, %d\n", qfield->name, qfield->length); } break; case FIELD_TYPE_DATETIME: case FIELD_TYPE_TIMESTAMP: dbf_add_field(dbh, qfield->name, 'T', qfield->length, 0); if (verbose > 1) { printf("Adding field: %s, FIELD_TYPE_DATETIME, %d\n", qfield->name, qfield->length); } break; case FIELD_TYPE_DATE: case FIELD_TYPE_NEWDATE: //dbf_add_field(dbh, qfield->name, 'D', qfield->length, 0); dbf_add_field(dbh, qfield->name, 'D', 8, 0); // date is 8 in dbf, Mysql returns 10 ?! if (verbose > 1) { printf("Adding field: %s, FIELD_TYPE_DATE, %d\n", qfield->name,8); //qfield->length); } break; default: break; } } if (verbose > 1) { printf("Writing out header\n"); } dbf_write_head(dbh); if (verbose > 1) { printf("Writing out field-descriptions\n"); } dbf_put_fields(dbh); if (verbose > 1) { printf("Writing out data\n"); } if (numrows) { while ((qrow = mysql_fetch_row(qres)) != NULL) { if ((rec = dbf_build_record(dbh)) != (field *)DBF_ERROR) { for (t = 0; t < numfields; t++) { //printf("ROW: %s\n",qrow[t]); if (qrow[t] != 0) { strcpy(rec[t].db_contents, qrow[t]); } else { rec[t].db_contents[0] = '\0'; } if (upper) { strtoupper(rec[t].db_contents); } if (lower) { strtolower(rec[t].db_contents); } } dbf_put_record(dbh, rec, dbh->db_records + 1); dbf_free_record(dbh, rec); } } } if (verbose > 1) { printf("Writing out header\n"); } dbf_write_head(dbh); if (verbose > 1) { printf("Closing up\n"); } mysql_free_result(qres); mysql_close(SQLsock); close(dbh->db_fd); free(dbh); exit(0); } dbf2mysql-1.14a/Makefile0000640000175000017500000000540207131471607014566 0ustar vorlonvorlon# Makefile for the dbf2mysql-utility # Maarten Boekhold (boekhold@cindy.et.tudelft.nl) 1995 # Set this to your C-compiler CC=gcc # set this to your install-program (what does Solaris have # in /usr/sbin/install? SYSV install?) INSTALL=/usr/bin/install #AR=/usr/bin/ar AR=ar # Set this to whatever your compiler accepts. Nothing special is needed #CFLAGS=-g -Wall -pedantic -include /usr/include/mpatrol.h #CFLAGS=-g -Wall CFLAGS=-O2 -Wall # Set this to make smaller binaries #STRIP= STRIP=-s # Set this to your MySQL installation-path MYSQLINC=-I/usr/include/mysql MYSQLLIB=-L/usr/lib/mysql # Set this to where you want the binary (no man-page yet, don't know # how to write them) INSTALLDIR=/usr/local/bin # Set this if your system needs extra libraries # # For Solaris use: #EXTRALIBS= -lmysys -lmystrings -lmysqlclient -lm # For mpatrol use (see http://www.cbmamiga.demon.co.uk/mpatrol/) #EXTRALIBS= -lmpatrol -lbfd -liberty -lmysqlclient -lm EXTRALIBS= -lmysqlclient -lm # You should not have to change this unless your system doesn't have gzip # or doesn't have it in the standard place (/usr/local/bin for ex.). # Anyways, it is not needed for just a simple compile and install RM=/bin/rm -f GZIP=/bin/gzip TAR=/bin/tar BZIP2=/usr/bin/bzip2 VERSION=1.14 OBJS=dbf.o endian.o libdbf.a dbf2mysql.o mysql2dbf.o all: dbf2mysql mysql2dbf libdbf.a: dbf.o endian.o $(AR) rcs libdbf.a dbf.o endian.o dbf2mysql: dbf2mysql.o libdbf.a $(CC) $(CFLAGS) $(STRIP) -L. $(MYSQLLIB) -o $@ dbf2mysql.o -ldbf \ $(EXTRALIBS) mysql2dbf: mysql2dbf.o libdbf.a $(CC) $(CFLAGS) $(STRIP) -L. $(MYSQLLIB) -o $@ mysql2dbf.o -ldbf \ $(EXTRALIBS) dbf.o: dbf.c dbf.h $(CC) $(CFLAGS) -c -o $@ dbf.c endian.o: endian.c $(CC) $(CFLAGS) -c -o $@ endian.c dbf2mysql.o: dbf2mysql.c dbf.h $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" $(MYSQLINC) -c -o $@ dbf2mysql.c mysql2dbf.o: mysql2dbf.c dbf.h $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" $(MYSQLINC) -c -o $@ mysql2dbf.c install: dbf2mysql $(INSTALL) -m 0755 -s dbf2mysql $(INSTALLDIR) $(INSTALL) -m 0755 -s mysql2dbf $(INSTALLDIR) clean: $(RM) $(OBJS) dbf2mysql mysql2dbf # the 'expand' is just for me, I use a tabstop of 4 for my editor, which # makes lines in the README very long and ugly for people using 8, so # I just expand them to spaces dist: # -expand -4 README.tab > README (cd .. ; $(TAR) cf dbf2mysql-$(VERSION).tar dbf2mysql-$(VERSION)/*.[ch] \ dbf2mysql-$(VERSION)/Makefile dbf2mysql-$(VERSION)/README \ dbf2mysql-$(VERSION)/kbl2win.cvt ; \ $(GZIP) -f9 dbf2mysql-$(VERSION).tar) distbz2: # -expand -4 README.tab > README (cd .. ; $(TAR) cf dbf2mysql-$(VERSION).tar dbf2mysql-$(VERSION)/*.[ch] \ dbf2mysql-$(VERSION)/Makefile dbf2mysql-$(VERSION)/README \ dbf2mysql-$(VERSION)/kbl2win.cvt ; \ $(BZIP2) dbf2mysql-$(VERSION).tar) dbf2mysql-1.14a/README0000640000175000017500000002640207740605443014014 0ustar vorlonvorlondbf2mysql v1.14 Patched and enchanted to mysql by Michael Widenius OVERVIEW: This package now consists of two programs: the old dbf2mysql, and the new, alpha-code mysql2dbf, which makes it possible to dump an mySQL-table to a dbf-file. dbf2msql: This program takes an xBase-file and sends queries to an mySQL-server to insert it into an mysql-table. It takes a number of arguments to set its behaviour: -v verbose: Produce some status-output -vv more verbose: -vvv more verbose: Also produce progress-report. -f field-lowercase: translate all field-names in the xbase-file to lowercase -u uppercase: Translate all text in the xbase-file to uppercase -l lowercase: Translate all text in the xbase-file to lowercase -n allow NULL fields: 'NOT NULL' will be not added in table creation statement. -o list fields to insert into mySQL database. Primary use is to make easier import of complex dbf files into mySQL where we want only few fields. NOTE: -o is processed before substitution (-s). So you have to use dbf field names here. -e conversion file: Specify file for char fields conversion. File format is: 1st line: number of characters to convert (number of lines). Further lines: . -s substitute: Takes a list of fieldname/newfieldname pairs. Primary use is to avoid conflicts between fieldnames and mySQL reserved keywords. When the new fieldname is empty, the field is skipped in both the CREATE-clause and the INSERT-clauses, in common words: it will not be present in the mySQL-table example: -s ORDER=HORDER,REMARKS=,STAT1=STATUS1 -i list fields to be indexed. mySQL field names should be listed here. -d database: Select the database to insert into. Default is 'test' -t table: Select the table to insert into. Default is 'test' -c create: Create table if it not exists. If the table already exists, drop it and build a new one. The default is to insert all data into the named table. If -cc is specified then no records will be inserted. -p primary: Select the primary key. You have to give the exact field-name. -h host: Select the host where to insert into. Untested. -F Fixed length records (Else chars is saved as varchar) -n Allow NULL values in fields -q "quick" mode. Inserts data via temporary file using 'LOAD DATA INFILE' mySQL statement. This increased insertion speed on my PC 2-2.5 times. Also note that during whole 'LOAD DATA' affected table is locked. -r Trim trailing and leading whitspaces from CHAR type fields data Rudimentary read-only support for Visual FoxPro, DB III+, and DB IV memo fields/files has been added. mysql2dbf: This takes basically the same arguments as dbf2mysql, only [-p] has changed. -v verbose -vv more verbose -u translate all field-contents to uppercase -l translate all field-contents to lowercase -d select database from where to read -t select table from where to read -q specifies custom-query to use -p specify precision to use in case of REAL-fields THIS IS ALPHA-CODE!!!!!!!!!! INSTALL: To build it, take a look at the Makefile. You might have to change a few things. First of all, there's the compiler you use. Then you have to tell where your 'install' program is. I use the syntax as in Solaris /usr/sbin/install, and I don't know if this is the one with the most standard arguments, so please bare with me if you have to fiddle with it. Then, tell what compiler-options you want (probably optimizing :). The next step is important: tell where your Minerva/mSQL is installed, since this needs include-files and libraries from there. Next, tell where you want the binary to be installed (directory-name). Some operating-systems require extra libraries to be linked against, Solaris for example needs -lsocket and -lnsl to compile this cleanly. Specify this in EXTRALIBS. Then you're probably set to go. There are 3 more options you can change, but you only need them if you want to do a 'make dist'. These are 'RM', 'GZIP' and 'TAR'. Of these, probably the only one that _could_ give trouble is gzip, but you probably already have this, else you wouldn't have succeeded in reading this document :). COPYRIGHT: Use this piece of software as you want, modify it to suit your needs, but please leave my name in place ok? :) DISCLAIMER: I do not accept any responsibility for possible damage you get as result of using this program. KNOWN BUGS: - It can't write memo-files at this time. OTHER BUGS: Possibly incorrect field-lengths for REAL-numbers. CHANGES mysql2dbf v1.14 07-Jul-2000 William Volkman - Updated to work with Visual FoxPro dbf files. - Capability to read memo files/fields for Visual FoxPro, DB III+, and DB IV has been implemented (Only tested with VFP V6.0 and Paradox 9.0 generated files, YMMV). - Minor bug and memory leak fixes. Tweaked documentation. Useful reference is Erik Bachmann's xbase page (you can find it at http://www.e-bachmann/docs/xbase.htm) mysql2dbf v1.13 Bob Schulze (bob@yipp.de) - added Date field handling tp mysql2dbf. - added -P (passwd) and -U (User) options to mysql2dbf and dfb2mysl dbf2mysql v1.12 Patch by Gerald Clark : - Change of LOAD DATA INFILE to LOAD DATA LOCAL INFLE - Fix of memory allocation bug dbf2mysql v1.11 Patch by Gerald Clark : - It adds a -x option to start each table with _rec and _timestamp fields, adds date fields, and converts boolean to enum fields. It also fixes a problem with quick mode inserts for blank numeric fields. dbf2mysql-1.10d: (1997.10.30) - Fixed insertion of characters from 2nd part of ASCII table (char codes >127). Don't know if that's correct. Will try to find correct solution. dbf2mysql-1.10c: (1997.10.20) - Corrected README about available command line options. - Expanded -c behavior. If more than one c is specified ( -cc ) then no data will be inserted. Only table will be created. dbf2mysql-1.10b: (1997.06.18) - Still fixing bugs left after porting dbf2sql to mySQL. This time bug which could screw program's execution after create-clause. - Fixed quite fatal bug in check_table which could prevent existing table name detection. Mindaugas Riauba dbf2mysql-1.10: (1997.06.13) - Added -q flag to use "quick" insertion mode via temporary file and 'LOAD DATA INFILE' statement. This increased speed 2-2.5 times on my PC running Linux 2.0.29. Mindaugas Riauba dbf2mysql-1.06: (1997.05.02) - Added -e flag to specify file for char fields conversion. I'm using this to convert strings from one code page to other one. - Found, enabled and documented -n flag, which allows NULL fields. - Fixed bug which prevented data insertion without table creation. You reviewed and tested this code or not Michael? ;) Mindaugas Riauba dbf2mysql-1.05: (1997.04.23) - Added -o flag to list fields to be processed. That was made to ease import of complex .dbf files where we want only few fields. Read note about relationship with -s. - Someone forgot to include F command line option to getopt ;). - Adjusted Makefile to Linux and new mySQL libraries (libmysqlclient instead of libmysql, etc.). - Added -i flag to specify fields to index. - Added -r flag t trim leading spaces from strings. Mindaugas Riauba dbf2msql-1.04: - Fixed bug introduced in version 1.03 that calculated the header-length (it was only correct by incident, when I added a pointer to a struct this broke). - Added a check when reading in the field-descriptions for end-of-header. Could fix some problems. Patch from Aaron Kardell . - Made numeric fields 10 long (4^32 has 10 chars....) dbf2msql-1.03 (never publically released): - Changed dbf.c to use a standard buffer to read the record in, as opposed to allocating one everytime we call dbf_get_record(). This will save time in reading and writing records. With dbf2msql and msql2dbf you won't notice much difference, cos the most time-consuming action is the communication with msqld, however, when you use these routines for something else it should make a difference. dbf2msql-1.02b: - Fixed a typo in msql2dbf.c - Forgot to mention in the README of 1.02 that I also fixed a memory- leak, and I mean a major one..... (in dbf_get_record()) - set *query = NULL in main() in msql2dbf.c. OSF on Alpha's chokes if you don't do this - changed strtoupper() and strtolower(), explicitly make it clear to the compiler *when* to increase the pointer. dbf2msql-1.02: - Added a patch from Jeffrey Y. Sue to 'rename' fieldnames. This also makes it possible to skip fields altogether - Added some patches from Frank Koormann to initialize the different data-area's to their correct values, to set the dbf-time correctly and to use the correct format for real-values in dbf_put_record() dbf2msql-1.01: - Changed every occurence of FILE to file_no. FILE reportedly caused trouble on some systems. - Changed dbf2msql.c so that when inserting an empty INT-field, an NULL text is inserted in the INSERT-clause instead of nothing. Suggestion by Jeffrey Y. Sue (jysue@aloha.net). - Same for REAL-fields (comes automagically with the change above). - When an error occurs during an INSERT-query, the values of that query are displayed when -vv is set. Suggestion by Jeffrey Y. Sue (jysue@aloha.net). - Added alpha-support for writing dbf-files from msql-tables by means of the program msql2dbf dbf2msql-0.5: - Added the -f flag to translate fieldnames to lowercase. Suggestion by David Perry (deperry@nerosworld.com). dbf2msql-0.4: - fixed a little offset-bug. I came across a file that had an extra char inserted after the header. However, the headerlength-field was correct, so I changed the program to use this instead of calculating the headerlength ourself. Should have done this in the first place. Bugreport from David Perry (deperry@nerosworld.com). dbf2msql-0.3: - moved call to do_create() to inside the check if to create the table or import it into an existing one dbf2msql-0.2: - Reorganized the code, cleaned up main(), moved building and sending of 'create-clause' to do_create() and moved building and sending of 'insert-clauses' to do_inserts. - Changed allocation of (char *)query in do_create() from static to dynamic, thus avoiding overruns. - Changed allocation of (char *)query, (char *)keys and (char *)vals in do_inserts() from static to dynamic, thus preventing overruns. - Fixed a nasty little bug in freeing allocated memory in dbf_free_record(). This was stupid, and only showed up *after* the code-reorganization. Don't know why I didn't notice it before. If you had *very* large dbases (with large fields), this could fill up your memory completely. - Added the -l option on suggestion from David Perry (deperry@zeus.nerosworld.com) - Added the -c option (dito) - Added the -vv option - Enhanced documentation (this little doc) dbf2msql-0.1: - Initial release Maarten Boekhold (boekhold@cindy.et.tudelft.nl) dbf2mysql-1.14a/kbl2win.cvt0000640000175000017500000000031206761242724015213 0ustar vorlonvorlon18 220 192 Ü 221 224 Ý 222 200 Þ 223 232 ß 240 198 ð 241 230 ñ 242 203 ò 243 235 ó 244 193 ô 245 225 õ 246 208 ö 247 240 ÷ 248 216 ø 249 248 ù 250 219 ú 251 251 û 252 222 ü 253 254 ý