// Includes
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "..\x_str.h"
// Global Variables
char* gps_output_write = "wb";
int gpb_output_append = false;
int gpi_match_text = 0;
int gpi_match_field = 0;
int gpi_project_field = 0;
// Type Defintions
// DBF Header Format
typedef struct struct_DBF_HEADER
{
char i_ver;
char i_year;
char i_mon;
char i_day;
int i_rec_count;
short i_header_size;
short i_rec_length;
} type_DBF_HEADER;
// DBF Field Defintion Formation
typedef struct struct_DBF_FIELDS
{
char s_name[11];
char s_type;
unsigned int i_fda;
unsigned char i_field_len;
unsigned char i_field_decimal;
char s_discard[14];
} type_DBF_FIELDS;
//----------------------------------------------------------------------------
// Functions
//
long ifn_file_slurp( char* ps_file_name, char** ps_buffer ) {
FILE* fp = fopen( ps_file_name, "rb" );
long i_file_len = 0;
if (fp != NULL) {
if (fseek(fp, 0L, SEEK_END) == 0) {
long i_bufsize = ftell(fp);
if (i_bufsize == -1) { fprintf( stderr, "Error reading file - i_bufsize !" ); }
if ( *ps_buffer != NULL ) { free(*ps_buffer); }
*ps_buffer = malloc(sizeof(char) * (i_bufsize + 1));
if (fseek(fp, 0L, SEEK_SET) != 0) { fputs("Error reading file - SEEK_SET !", stderr ); }
i_file_len = fread(*ps_buffer, sizeof(char), i_bufsize, fp);
if (i_file_len == 0) {
fprintf( stderr, "Error reading file - i_file_len !" );
} else {
(*ps_buffer)[++i_file_len] = '\0';
}
}
fclose(fp);
} else {
fprintf( stderr, "Error finding file - Input file doesn't exist !\n");
}
return (i_file_len);
}
//
//----------------------------------------------------------------------------
//
void fn_help() {
// ---------
printf("\nUsage: ci_dbf input_file.DBF output_file.TXT [<options>]\n\n");
printf("Options:\n");
printf("\t/m {value}\tOutputs records containing {value}.\n");
printf("\t/f {field}\tLimit match to {field}.\n");
printf("\t/app\t\tAppend to output file. Does not print field names.\n");
printf("\t/prj {project}\tAdds a PROJECT field. Each record has {project} include in the output.\n");
printf("\t/fmt\t\tFormat numeric fields - right align ..\n");
printf("\t/?\t\tThis help text.\n");
return;
}
//
//----------------------------------------------------------------------------
//
int main(int pi, char **ps ) {
printf("\nCI_DBF.EXE - v2025.08.09a : Convert DBF to TabTXT\n");
// Input Checks
int pi_field_match = -1;
// Options
int i = 1;
while( i < pi ) {
if (( strncmp("/?" , ps[i], 2) == 0)) { fn_help(); return(0); }
if (( strncmp("/app", ps[i], 4) == 0)) { gps_output_write = "ab"; gpb_output_append = true; }
if (( strncmp("/m" , ps[i], 2) == 0)) { gpi_match_text = i + 1; }
if (( strncmp("/f" , ps[i], 2) == 0)) { gpi_match_field = i + 1; }
if (( strncmp("/prj", ps[i], 4) == 0)) { gpi_project_field = i + 1; }
i++;
}
if ( gpi_match_text > 0 ) { if ( ps[gpi_match_text] ) { x_fn_str_upper( ps[gpi_match_text] ); }}
if ( gpi_match_field > 0) { if ( ps[gpi_match_field] ) { pi_field_match = atoi( ps[gpi_match_field] ); }}
// Main arguments
if ( !ps[1] ) { fprintf( stderr, "No input file !\n" ); return( -1 ); }
if ( !ps[2] ) { fprintf( stderr, "No output file !\n" ); return( -1 ); }
// Header
printf( "\nReading .. %s\n", ps[1] );
char* s_file = NULL;
long i_file_size_bytes = ifn_file_slurp( ps[1], &s_file );
if ( i_file_size_bytes < 1 ) { return( -1 ); }
type_DBF_HEADER* xo_dbf_header = (type_DBF_HEADER*) &s_file[0];
//xo_dbf_header = (type_DBF_HEADER*) &s_file[0];
printf( "\nVer: %d" , xo_dbf_header->i_ver );
printf( "\nLast Mod: %d-%02d-%02d" , (xo_dbf_header->i_year + 1900), xo_dbf_header->i_mon, xo_dbf_header->i_day );
printf( "\nNumber of Records: %ld" , xo_dbf_header->i_rec_count );
printf( "\nHeader Size: %d" , xo_dbf_header->i_header_size );
printf( "\nRecord Length: %d" , xo_dbf_header->i_rec_length );
printf( "\nDBF Size Length: %d" , xo_dbf_header->i_header_size + ( xo_dbf_header->i_rec_count * xo_dbf_header->i_rec_length ) );
// Columns -- Fields
printf( "\n\nWriting ..%s\n", ps[2] );
char s_EOL = 13;
FILE* fp = fopen( ps[2], gps_output_write );
type_DBF_FIELDS* xo_dbf_fields[128];
int i_field = 0;
long i_file_index = 32;
long i_buf = 0;
long i_fda_calc = 1;
char* s_buf;
s_buf = malloc( xo_dbf_header->i_rec_length + 50 );
if ( gpi_project_field == 0 ) {
i_buf = snprintf ( s_buf, 10, "#\tDEL\t" );
} else {
i_buf = snprintf ( s_buf, 60, "#\tPROJECT\tDEL\t" );
}
if ( !gpb_output_append ) { fwrite( s_buf, i_buf, 1, fp ); }
while ( s_file[i_file_index] != 0x0d ) {
xo_dbf_fields[i_field] = (type_DBF_FIELDS*) &s_file[i_file_index];
xo_dbf_fields[i_field]->i_fda = i_fda_calc;
printf ( "\n%d\t%10s\t%c\t%d\t%d\t%d"
, i_field
, xo_dbf_fields[i_field]->s_name
, xo_dbf_fields[i_field]->s_type
, xo_dbf_fields[i_field]->i_fda
, xo_dbf_fields[i_field]->i_field_len
, xo_dbf_fields[i_field]->i_field_decimal
);
i_fda_calc += xo_dbf_fields[i_field]->i_field_len;
i_buf = snprintf ( s_buf, 50, "%s (%c,%d)\t"
, xo_dbf_fields[i_field]->s_name
, xo_dbf_fields[i_field]->s_type
, xo_dbf_fields[i_field]->i_field_len
);
if ( !gpb_output_append ) { fwrite( s_buf, i_buf, 1, fp ); }
i_field++;
i_file_index += 32;
}
if ( !gpb_output_append ) { fwrite( &s_EOL, 1, 1, fp ); }
int i_field_count = i_field;
printf( "\n\n%d fields.", i_field_count );
// Rows -- Records
char* s_rec;
char* s_rec_upper;
long i_rec = 0;
long i_match = 0;
char* s_match;
char s_field[300]; // Each field can be a max of 254 characters
char* s_field_upper;
char* s_match_field;
int i_match_field;
int i_space;
s_rec = malloc( xo_dbf_header->i_rec_length + 1 );
while ( i_rec < xo_dbf_header->i_rec_count ) {
memcpy( s_rec, &s_file[xo_dbf_header->i_header_size + ( i_rec * xo_dbf_header->i_rec_length ) ], xo_dbf_header->i_rec_length );
s_rec[xo_dbf_header->i_rec_length] = '\0';
s_match = s_rec;
if ( gpi_match_text > 0 ) {
s_rec_upper = x_sfn_str_upper( s_rec );
s_match = strstr( s_rec_upper, ps[gpi_match_text] );
free( s_rec_upper );
}
if ( s_match ) {
if ( gpi_project_field == 0 ) {
i_buf = snprintf ( s_buf, 10, "%d\t%c\t", (i_rec + 1), s_rec[0] );
} else {
i_buf = snprintf ( s_buf, 60, "%d\t%s\t%c\t", (i_rec + 1), ps[gpi_project_field], s_rec[0] );
}
i_field = 0;
i_match_field = 0;
while ( i_field < i_field_count ) {
memcpy( s_field, &s_rec[xo_dbf_fields[i_field]->i_fda], xo_dbf_fields[i_field]->i_field_len );
// Trim trailing whitespace
i_space = xo_dbf_fields[i_field]->i_field_len;
s_field[i_space] = 0x020;
while (( s_field[i_space] == 0x020 ) && ( i_space >= 0 )) {
i_space--;
}
s_field[i_space + 1] = '\0';
// Check for matching field
s_match_field = s_field;
if ( pi_field_match == i_field ) {
s_field_upper = x_sfn_str_upper( s_field );
s_match_field = strstr( s_field_upper, ps[gpi_match_text] );
free( s_field_upper );
}
if ( s_match_field ) { i_match_field++; }
// Add field data to output buffer
i_buf += snprintf ( &s_buf[i_buf], xo_dbf_header->i_rec_length - i_buf, "%s\t" , s_field );
i_field++;
}
if ( i_match_field == i_field_count ) {
i_match++;
fwrite( s_buf, i_buf - 1, 1, fp );
fwrite( &s_EOL, 1, 1, fp );
}
}
i_rec++;
}
printf( "\n%d matched records.", i_match );
printf( "\n" );
// Program End
fclose( fp );
free( s_rec );
free( s_buf );
free( s_file );
return( 0 );
}
//
//----------------------------------------------------------------------------
Comments
0 B
|👍
/👎
0 B
|👍
/👎