diff -urN xbase64-3.1.2-old/bin/dumprecspg.cpp xbase64-3.1.2/bin/dumprecspg.cpp --- xbase64-3.1.2-old/bin/dumprecspg.cpp 1969-12-31 18:00:00.000000000 -0600 +++ xbase64-3.1.2/bin/dumprecspg.cpp 2008-01-11 13:17:01.000000000 -0600 @@ -0,0 +1,125 @@ +/* dumprecs.cpp + + This program dumps a dbf file contents + + Xbase64 project source code + + This sample program dumps Xbase records + + Copyright (C) 2006,2007,2008 Kirk Strauser + + This program is free software; you can redistribute it and/or modify + it under the terms of 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. + + 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 the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: + + Email: + + xbase64-devel@lists.sourceforge.net + xbase64-users@lists.sourceforge.net + + + Regular Mail: + + XBase Support + 149C South Main St + Keller Texas, 76248 + USA + +*/ +#include + +// next lines are helpful for debugging purposes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +int main(int ac,char** av) +{ + xbXBase x; + xbShort rc; + + if (ac <= 1) { + std::cout << "Usage: dumprecs filename [indexcolumn ...]" << std::endl; + return 1; + } + + char* filename = av[1]; + + xbDbf MyFile( &x ); + + MyFile.SetVersion( 4 ); + rc = MyFile.OpenDatabase(filename); + if( rc != XB_NO_ERROR) { + std::cout << "Could not open file " << filename << std::endl; + x.DisplayError( rc ); + return 1; + } + + char tablename[4096]; + MyFile.GetTableName( tablename ); + + // Start a transaction, then drop the table and recreate it + std::cout << "begin;" << std::endl; + std::cout << "drop table " << tablename << ";" << std::endl; + MyFile.PgDumpHeader(); + + // Dump the database contents + std::cout << "\\copy " << tablename << " from stdin" << std::endl; + + int row = 0; + while(row +char *reservedwords[] = { + "desc", + "from", + "group", + "to", + "user", + NULL, +}; + + /*! \file xbdbf.cpp */ @@ -739,8 +749,115 @@ std::cout << std::endl; return XB_NO_ERROR; } +/************************************************************************/ +//! Print header information in the format of a PostgreSQL "create table" command +/*! +*/ +xbShort xbDbf::PgDumpHeader() +{ + char fieldname[4096]; + char filename[4096]; + + GetTableName( filename ); + std::cout << "create table " << filename << " ("; + + int printed = 0; + for( int i = 0; i = 0; i-- ){ + if( filename[i] == '.' ){ + filename[i] = '\0'; + } + } + for( int i = 0; i < length; i++ ){ + if( filename[i] == '/' ){ + lastslash = i; + } + } + strcpy( Buf, filename + lastslash + 1 ); + return 0; +} +/************************************************************************/ //! Open the DBF file. /*! This method attempts to open the DBF file with the specified @@ -1471,6 +1588,107 @@ return XB_NO_ERROR; } /************************************************************************/ +//! PostgreSQL dump record +/*! + Dump the contents of the specified record to stdout in a format compatible + with PostgreSQL's "copy from" command. + + \param RecNo Record number of record to be dumped. + \returns An error code (same as GetRecord()). +*/ +xbShort xbDbf::PgDumpRecord( xbULong RecNo ) +{ + int i, j, printed, rc; + char buf[4096]; + char riskybuf[4096]; + + if( RecNo == 0 || RecNo > NoOfRecs ) + return XB_INVALID_RECORD; + + rc = GetRecord( RecNo ); + if( rc != XB_NO_ERROR ) + return rc; + + if( RecordDeleted() ) + return 0; + + printed = 0; + for( i = 0; i < NoOfFields; i++ ){ +#ifdef XB_MEMO_FIELDS + switch( SchemaPtr[i].Type ){ + case 'D': + // Handle datestamps + GetField( i, buf ); + if( !strcmp( buf, " " ) ){ + buf[0] = '\\'; + buf[1] = 'N'; + buf[2] = 0x00; + } + break; + case 'I': + // Handle packed integers + snprintf( buf, 4096, "%d", GetLongPackedField( i ) ); + break; + case 'L': + // Boolean values + GetField( i, buf ); + switch( buf[0] ){ + case 'T': + buf[0] = '1'; + break; + default: + buf[0] = '0'; + } + break; + case 'M': + // Handle memo fields + if( MemoFieldExists( i )){ + // memset( riskybuf, 0x00, 4095 ); + rc = GetMemoField(i, 4095, riskybuf, 0); + if(rc != XB_NO_ERROR) + return rc; + } else { + riskybuf[0] = 0x00; + } + PgEscapeField( riskybuf, buf, 4096 ); + break; + case 'T': + // Handle datetime values + GetDatetimeField( i, buf ); + if( !strcmp( buf, "11/25/1956 00:00:00" ) ){ + buf[0] = '\\'; + buf[1] = 'N'; + buf[2] = 0x00; + } + break; + case '0': + continue; + default: + // Escape the values in string fields + char riskybuf[4096]; + GetField( i, riskybuf ); + PgEscapeField( riskybuf, buf, 4096 ); + break; + } + + // Print a tab separator before every field after the first + if( printed ){ + std::cout << "\t"; + } + else{ + printed = 1; + } + + std::cout << buf; +#else + GetField( i, buf ); + std::cout << buf; +#endif + } + std::cout << std::endl; + return XB_NO_ERROR; +} +/************************************************************************/ //! Write the current record buffer to the current record in the data file. /*! Attempts to write the contents of the record buffer to the current diff -urN xbase64-3.1.2-old/xbase64/xbdbf.h xbase64-3.1.2/xbase64/xbdbf.h --- xbase64-3.1.2-old/xbase64/xbdbf.h 2006-07-17 11:54:50.000000000 -0500 +++ xbase64-3.1.2/xbase64/xbdbf.h 2008-01-11 13:17:01.000000000 -0600 @@ -213,7 +213,11 @@ #ifdef XBASE_DEBUG xbShort DumpHeader( xbShort ); #endif + xbShort PgDumpHeader(); + xbShort LowerCase( char * Buf ); + xbShort GetTableName( char * Buf ); xbShort DumpRecord( xbULong ); + xbShort PgDumpRecord( xbULong ); //! Return number of fields /*! */ @@ -294,6 +298,17 @@ xbShort ValidLogicalData( const char * ); xbShort ValidNumericData( const char * ); + xbShort GetDatetimeField( const char *FieldName, char *Buf) const; + xbShort GetDatetimeField( xbShort FieldNo, char *Buf) const; + + xbLong UnpackLong( const char *PackedValue ) const; + xbShort MakeDate( const xbLong DateValue, char *Buf ) const; + xbShort MakeTime( const xbLong TimeValue, char *Buf ) const; + xbShort EscapeCharacter( const char Src, char *Dest ) const; + xbShort PgEscapeField( const char *Src, char *Dest, const int maxsize ) const; + xbLong GetLongPackedField( const char *FieldName ) const; + xbLong GetLongPackedField( const xbShort FieldNo ) const; + xbLong GetLongField( const char *FieldName) const; xbLong GetLongField( const xbShort FieldNo) const; xbShort PutLongField( const xbShort, const xbLong ); diff -urN xbase64-3.1.2-old/xbase64/xbfields.cpp xbase64-3.1.2/xbase64/xbfields.cpp --- xbase64-3.1.2-old/xbase64/xbfields.cpp 2006-07-17 11:54:42.000000000 -0500 +++ xbase64-3.1.2/xbase64/xbfields.cpp 2008-01-11 13:17:01.000000000 -0600 @@ -480,6 +480,166 @@ return GetField(FieldNo, buf, 0); } /************************************************************************/ +//! Get the value of the specified field, where the value +//! in the field is a datetime string. +/*! +*/ +xbShort xbDbf::GetDatetimeField( xbShort FieldNo, char *Buf) const +{ + char localbuf[12]; + xbLong unpacked; + memset( localbuf, 0x00, 12 ); + GetField( FieldNo, localbuf ); + unpacked = UnpackLong( localbuf ); + MakeDate( unpacked, Buf ); + Buf[10] = ' '; + unpacked = UnpackLong( localbuf + 4 ); + MakeTime( unpacked, Buf + 11 ); + return 0; +} +/************************************************************************/ +//! Get the value of the specified field, where the value +//! in the field is a datetime string. +/*! +*/ +xbShort xbDbf::GetDatetimeField( const char *FieldName, char *Buf) const +{ + return( GetDatetimeField( GetFieldNo( FieldName ), Buf )); +} +/************************************************************************/ +//! Convert a 4-byte packed little-endian value into a long. +/*! +*/ +xbLong xbDbf::UnpackLong( const char *PackedValue ) const +{ + xbLong a = (PackedValue[3] & 255) << 24 | + (PackedValue[2] & 255) << 16 | + (PackedValue[1] & 255) << 8 | + (PackedValue[0] & 255); + return a; +} +/************************************************************************/ +//! Convert a long number of days since Jan. 1, 4713BC (?!?!?) to YYYY/MM/DD. +/*! +*/ +xbShort xbDbf::MakeDate( const xbLong DateValue, char *Buf ) const +{ + // XBase has the screwiest time base I've ever seen. So, subtract the + // number of days from XBase epoch to the Unix epoch and use POSIX + // time functions to calculate dates. + time_t SecondsSinceEpoch; + SecondsSinceEpoch = (DateValue - 2440588) * 86400; + strftime( Buf, 11, "%m/%d/%Y", gmtime( &SecondsSinceEpoch ) ); + return 0; +} +/************************************************************************/ +//! Convert a long number of milliseconds since midnight to HH:MM:SS. +/*! +*/ +xbShort xbDbf::MakeTime( const xbLong TimeValue, char *Buf ) const +{ + // FoxPro rounds down one millisecond, so account for that. + xbLong msec = TimeValue + 1; + xbShort hours = msec / 3600000; + msec = msec - hours * 3600000; + xbShort minutes = msec / 60000; + xbShort seconds = (msec - minutes * 60000) / 1000; + sprintf( Buf, "%02d:%02d:%02d", hours, minutes, seconds); + return 0; +} +/************************************************************************/ +//! Escape an entire string of untrusted data by removing characters +//! that might interfere with PostgreSQL's COPY FROM. +/*! +*/ +xbShort xbDbf::PgEscapeField( const char *Src, char *Dest, const int maxcopy ) const +{ + // An escaped character and its length + char escaped; + xbShort esclength = 0; + // Length of the new target string + xbShort destlength = 0; + // Convert a length to an index (length - 1) and leave room for the + // terminating zero. + xbShort highestindex = maxcopy - 2; + // Pointers to the source and target strings + const char *sp = Src; + char *tp = Dest; + + while( *sp != 0x00 ){ + switch( *sp ){ + case '\\': + escaped = '\\'; + esclength = 1; + break; + case '\n': + escaped = 'n'; + esclength = 1; + break; + case '\r': + escaped = 'r'; + esclength = 1; + break; + case '\t': + escaped = 't'; + esclength = 1; + break; + } + + // If the resulting string would be too long, exit + if( destlength + esclength > highestindex ){ + break; + } + + // If the character was not escaped, write it verbatim + if( !esclength ){ + *tp++ = *sp; + destlength += 1; + } else { + // Otherwise, write the escaped version + *tp++ = '\\'; + *tp++ = escaped; + destlength += 2; + // Reset esclength for the remaining iterations + esclength = 0; + } + sp++; + } + + // Terminate the string + *tp = 0x00; + + // Strip off trailing spaces by replacing them with end-of-string + // until we reach a non-space or the beginning of the string + while( tp != Dest && *--tp == ' ' ){ + *tp = 0x00; + destlength--; + } + + return destlength; +} +/************************************************************************/ +//! Get the long value of the specified field, where the value +//! in the field is a packed integer. +/*! +*/ +xbLong xbDbf::GetLongPackedField( xbShort FieldNo ) const +{ + char buf[18]; + memset( buf, 0x00, 18 ); + GetField( FieldNo, buf ); + return UnpackLong ( buf ); +} +/************************************************************************/ +//! Get the long value of the specified field, where the value +//! in the field is a packed integer. +/*! +*/ +xbLong xbDbf::GetLongPackedField( const char * FieldName ) const +{ + return( GetLongPackedField( GetFieldNo( FieldName ))); +} +/************************************************************************/ //! Get the long value of the specified field. /*! */ diff -urN xbase64-3.1.2-old/xbase64/xbmemo.cpp xbase64-3.1.2/xbase64/xbmemo.cpp --- xbase64-3.1.2-old/xbase64/xbmemo.cpp 2006-07-17 11:54:42.000000000 -0500 +++ xbase64-3.1.2/xbase64/xbmemo.cpp 2008-01-11 13:17:01.000000000 -0600 @@ -1096,10 +1096,23 @@ */ xbShort xbDbf::MemoFieldExists( xbShort FieldNo ) const { - if( GetLongField( FieldNo ) == 0L ) - return 0; - else - return 1; + xbLong BlockNo; + char buf[18]; + + if( Version == (char)0x30 ) { + memset( buf, 0x00, 18 ) ; + GetField( FieldNo, buf ); + BlockNo = xbase->GetLong((char*) buf); + } else { + BlockNo = GetLongField(FieldNo); + } + + if( BlockNo == 0L ){ + return 0; + } + else{ + return 1; + } } /***********************************************************************/ //! Short description diff -urN xbase64-3.1.2-old/xbase64/xbnode.cpp xbase64-3.1.2/xbase64/xbnode.cpp --- xbase64-3.1.2-old/xbase64/xbnode.cpp 2006-07-17 11:54:42.000000000 -0500 +++ xbase64-3.1.2/xbase64/xbnode.cpp 2008-01-11 13:17:01.000000000 -0600 @@ -1,4 +1,4 @@ -#include "xbNode.h" +#include "xbnode.h" void xbNodeLink::AddNode(xbNodeLink* node) { diff -urN xbase64-3.1.2-old/xbase64/xbtypes.h xbase64-3.1.2/xbase64/xbtypes.h --- xbase64-3.1.2-old/xbase64/xbtypes.h 2006-07-17 11:54:50.000000000 -0500 +++ xbase64-3.1.2/xbase64/xbtypes.h 2008-01-11 13:17:01.000000000 -0600 @@ -40,6 +40,7 @@ #define __XB_XTYPES_H__ #include +#include /*! \file xbtypes.h */