Files
harbour-core/harbour/source/rtl/dbdelim.prg
Przemyslaw Czerpak 268c9d28dc 2006-05-30 12:15 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/include/hbver.h
    * changed version number and ChangeLog entry

  * harbour/make_tgz.sh
    ! fixed creating PP in DJGPP builds

  * harbour/contrib/dot/pp.prg
    ! minor fix in parameter checking

  * harbour/contrib/libmisc/hb_f.c
    ! fixed bug in record numbering after reaching EOF position and
      backward skipping

  * harbour/include/hbrdddel.h
  * harbour/source/rdd/delim1.c
    + implemented DELIM RDD. It should be fully Clipper compatible
      in comma files parsing. If you will find any difference, please
      inform me and I'll update it. Unlike in Clipper in [x]Harbour
      these RDD can be used also in direct import operations with
      APPEND FROM ... VIA "DELIM"
      These RDD also support whole record transfering between RDDs
      if they support the same record format and field representation
      and can translate extended field types like "I", "B", "V3", "V4",
      etc.

  * harbour/source/rtl/dbdelim.prg
    * replaced old code of __dbDelim() function with simple calls to
      __dbCopy()/__dbApp() - it should fix most of the reported
      incompatibilities in DELIM import/export operations and
      increase their speed many times

  * harbour/include/hbrddsdf.h
  * harbour/source/rdd/sdf1.c
    + implemented SDF RDD. It should be fully Clipper compatible
      in SDF files parsing. If you will find any difference, please
      inform me and I'll update it. Unlike in Clipper in [x]Harbour
      these RDD can be used also in direct import operations with
      APPEND FROM ... VIA "SDF"
      These RDD also support whole record transfering between RDDs
      if they support the same record format and field representation
      and can translate extended field types like "I", "B", "V3", "V4",
      etc.

  * harbour/source/rtl/dbsdf.prg
    * replaced old code of __dbSDF() function with simple calls to
      __dbCopy()/__dbApp() - it should fix most of the reported
      incompatibilities in SDF import/export operations and
      increase their speed many times

  * harbour/source/rdd/dbcmd.c
    + added support for table structure inheriting in transfer RDDs.
    + added eleventh parameter with delimiter to __dbCopy()/__dbApp()

  * harbour/source/rdd/dbf1.c
    * force 10 bytes size for memo fields in DBF and SMT memos.
    * some minor clean-up.

  * harbour/source/rdd/workarea.c
    * added some dummy DBI_* actions in base RDD level
2006-05-30 10:28:42 +00:00

392 lines
13 KiB
Plaintext

/*
* $Id$
*/
/*
* Harbour Project source code:
* Copies the contents of a database to a delimited text file.
* Appends the contents of a delimited text file to a database.
*
* Copyright 2001-2003 David G. Holm <dholm@jsd-llc.com>
* www - http://www.harbour-project.org
* APPEND FROM code submitted by Marco Braida <marcobra@elart.it>
*
* Copyright 2006 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* function __dbDelim() replaced by the new one which uses
* DELIM RDD I've just created
*
* 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, 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
REQUEST DELIM
PROCEDURE __dbDelim( lExport, cFile, cDelimArg, aFields, bFor, bWhile, nNext, nRecord, lRest )
IF lExport
__dbCopy( cFile, aFields, bFor, bWhile, nNext, nRecord, lRest, "DELIM", , , cDelimArg )
ELSE
__dbApp( cFile, aFields, bFor, bWhile, nNext, nRecord, lRest, "DELIM", , , cDelimArg )
ENDIF
RETURN
#ifdef __DBDELIM_OLD_CODE__
#include "hbcommon.ch"
#include "fileio.ch"
#include "error.ch"
#include "set.ch"
HB_FILE_VER( "$Id$" )
#define AppendEOL( handle ) FWRITE( handle, CHR( 13 ) + CHR( 10 ) )
#define AppendEOF( handle ) FWRITE( handle, CHR( 26 ) )
#define AppendSep( handle, cSep ) FWRITE( handle, cSep )
PROCEDURE __dbDelim( lExport, cFile, cDelimArg, aFields, bFor, bWhile, nNext, nRecord, lRest )
LOCAL index, handle, lWriteSep, cFileName := cFile, nStart, nCount, oErr
LOCAL cSeparator := ",", cDelim := CHR( 34 )
//------------------
local Pos:=0
local nPosFl:=0
local nDimBuff:=65535
local cByte :=""
local lunghezze:={}
local eol:=chr(13)+chr(10)
local contacamp:=0
local primariga:=.t.
local offset:=0
local rig:=0
local cont_r:=""
local Lfinefile:=.f.
local nFileLen
local cCharEol:=HB_OSNewLine()
local nLenEol:=LEN(cCharEol)
local nPosLasteol
local lcisonoeol
local lErrResult
//------------------
// Process the delimiter argument.
IF !EMPTY( cDelimArg )
IF UPPER( cDelimArg ) == "BLANK"
cDelim := ""
cSeparator := " "
ELSE
cDelim := LEFT( cDelimArg, 1 )
END IF
END IF
// Process the file name argument.
index := RAT( ".", cFileName )
IF index > 0
// The file name might include a file extension.
IF RAT( "/", cFileName ) > index ;
.OR. RAT( "\", cFileName ) > index
// No, the file extension is in a directory name.
index := 0
END IF
END IF
IF index <= 0
// No file name extension, so provide the default.
cFileName += ".txt"
END IF
// Determine where to start and how many records to process.
IF nRecord != NIL
// The RECORD clause has the highest priority.
nStart := nRecord
nCount := 1
ELSEIF nNext != NIL
// The NEXT clause has the next highest priority.
nStart := -1
nCount := nNext
ELSEIF bWhile != NIL .OR. lRest
// The WHILE and REST clauses have equal priority.
nStart := -1
nCount := -1
ELSE
// Followed by the FOR clause or the ALL clause.
nStart := 0
nCount := -1
END IF
IF EMPTY( bFor )
// This simplifies the test that determines whether or not to
// use (i.e., import or export) any given processed record.
bFor := {||.T.}
END IF
IF lExport
// COPY TO DELIMITED
IF !USED()
oErr := ErrorNew()
oErr:severity := ES_ERROR
oErr:genCode := EG_NOTABLE
oErr:subSystem := "DELIM"
oErr:subCode := 2001
oErr:description := HB_LANGERRMSG( oErr:genCode )
oErr:canRetry := .F.
oErr:canDefault := .T.
Eval(ErrorBlock(), oErr)
handle := -1
ELSE
WHILE ( handle := FCREATE( cFileName ) ) == -1
oErr := ErrorNew()
oErr:severity := ES_ERROR
oErr:genCode := EG_CREATE
oErr:subSystem := "DELIM"
oErr:subCode := 1002
oErr:description := HB_LANGERRMSG( oErr:genCode )
oErr:canRetry := .T.
oErr:canDefault := .T.
oErr:fileName := cFileName
oErr:osCode := FERROR()
lErrResult := Eval(ErrorBlock(), oErr)
IF VALTYPE( lErrResult ) != "L" .OR. !lErrResult
EXIT
ENDIF
ENDDO
ENDIF
IF handle != -1
IF nStart > -1
// Only reposition if a starting record was specified or implied.
IF nStart == 0
GO TOP
ELSE
GO (nStart)
END IF
END IF
IF EMPTY( bWhile )
// This simplifies the looping logic.
bWhile := {||.T.}
END IF
// Set up for the start of the first record.
lWriteSep := .F.
// Process the records to copy delimited.
WHILE EVAL( bWhile ) .AND. ( nCount == -1 .OR. nCount > 0 ) ;
.AND. !BOF() .AND. !EOF()
IF EVAL( bFor )
IF EMPTY( aFields )
// Process all fields.
FOR index := 1 TO FCOUNT()
IF lWriteSep
AppendSep( handle, cSeparator )
END IF
lWriteSep := ExportVar( handle, FIELDGET( index ), cDelim )
NEXT index
ELSE
// Process the specified fields.
FOR index := 1 TO LEN( aFields )
IF lWriteSep
AppendSep( handle, cSeparator )
END IF
lWriteSep := ExportVar( handle, FIELDGET( FIELDPOS( aFields[ index ] ) ), cDelim )
NEXT index
END IF
// Set up for the start of the next record.
AppendEOL( handle )
lWriteSep := .F.
END IF
IF nCount != -1
nCount--
END IF
SKIP
END WHILE
IF SET(_SET_EOF)
AppendEOF( handle )
END IF
FCLOSE( handle )
END IF
ELSE
// APPEND FROM DELIMITED
handle := FOPEN( cFileName )
IF handle == -1
oErr := ErrorNew()
oErr:severity := ES_ERROR
oErr:genCode := EG_OPEN
oErr:subSystem := "DELIM"
oErr:subCode := 1001
oErr:description := HB_LANGERRMSG( oErr:genCode )
oErr:canRetry := .T.
oErr:canDefault := .T.
oErr:fileName := cFileName
oErr:osCode := FERROR()
Eval(ErrorBlock(), oErr)
ELSE
IF EMPTY( bWhile )
// This simplifies the looping logic.
bWhile := {||.T.}
ENDIF
// ---------------------------------------
// Please fill with the other test here
// Marco Braida 2002
// marcobra@elart.it
// ---------------------------------------
nFileLen:=FSEEK(handle,0,FS_END)
nDimBuff:=min(nFileLen,nDimBuff)
cByte:=space(nDimBuff)
FSEEK(handle,0)
// cCharEol:=chr(13)
nPosLastEol:=0
do while .not. lFineFile
fseek(handle,nPoslastEol,FS_SET) // forward the pointer
//we must not go after the eof
if nPosLastEol + nDimBuff > nFileLen
// change the buffer size
nDimBuff:=nFileLen-nPosLastEol
cByte:=space(nDimBuff)
Lfinefile:=.t.
endif
// fill the buffer
cByte:=space(nDimBuff)
fread(handle,@cByte,nDimBuff)
// with +1 there is a problem on large import of data
// for now we keep it remmed
// please test and test and test
nPoslastEol+=rat(cCharEol,cByte) // +1
//do this if in the buffer there are eol char
lcisonoeol:=.t.
do while lcisonoeol
// the position of the first eol
nposfl:=at(cCharEol,cByte)
lcisonoeol:=(nPosfl>0)
if lcisonoeol
// cut the row
Pos:=1
cont_r:=substr(cByte,Pos,nposfl-Pos)
appendtodb(cont_r,cSeparator,cDelim)
// skipping the line feed and now we are on a good char
pos:=nposfl+nLenEol
cont_r:=""
//cut the row
cByte:=substr(cByte,Pos)
endif
enddo
enddo
FCLOSE( handle )
END IF
END IF
RETURN
STATIC FUNCTION ExportVar( handle, xField, cDelim )
DO CASE
CASE VALTYPE( xField ) == "C"
FWRITE( handle, cDelim + TRIM( xField ) + cDelim )
CASE VALTYPE( xField ) == "D"
FWRITE( handle, DTOS( xField ) )
CASE VALTYPE( xField ) == "L"
FWRITE( handle, iif( xField, "T", "F" ) )
CASE VALTYPE( xField ) == "N"
FWRITE( handle, LTRIM( STR( xField ) ) )
OTHERWISE
RETURN .F.
END CASE
RETURN .T.
STATIC FUNCTION appendtodb(row,cSeparator,cDelim)
local lenrow:=len(row)
local aStruct:=DBSTRUCT()
local aMyVal:={}
local ii:=1
local nPosSep:=0, nPosNextSep:=0
local nDBFFields
local cBuffer, cUPbuffer
local vRes
local nPos1Deli, nPos2Deli
//if there is one field only there is no Separator and i put...
row:=row+cSeparator
nPosSep:=1
nPosNextSep:=at(cSeparator,row) // seek the first Separator eg. ,
nPos1Deli:=at(cDelim,row) // seek the first delimiter "
nPos2Deli:=at(cDelim+cSeparator,row,nPos1Deli+1) // seek the second delimiter "
if nPos1Deli > 0 .and. nPos2Deli > 0
if nPosNextSep>nPos1Deli .and. nPosNextSep<nPos2Deli
nPosSep:=nPos1Deli
nPosNextSep=nPos2Deli+1
endif
endif
aadd( aMyval,substr(row,nPosSep,nPosNextSep-1) )
nPosSep:=nPosNextSep
do while .t.
nPosNextSep:=at(cSeparator,row,nPosSep+1)
if nPosNextSep=0
exit
endif
nPos1Deli:=at(cDelim,row,nPosSep) // seek the first delimiter "
nPos2Deli:=at(cDelim+cSeparator,row,nPos1Deli+1) // seek the second delimiter "
if nPos1Deli > 0 .and. nPos2Deli > 0
if nPosNextSep>nPos1Deli .and. nPosNextSep<nPos2Deli
nPosSep=nPos1Deli
nPosNextSep=nPos2Deli+1
endif
endif
aadd( aMyVal,substr(row,nPosSep+1,nPosnextSep-nPosSep-1) )
nPosSep:=nPosNextSep
if nPosSep>lenrow
exit
endif
enddo
nDBFfields:=min(len(aMyVal),len(aStruct))
append blank
for ii:=1 to nDBFfields
cBuffer:=strtran(aMyval[ii],cDelim,'')
DO CASE
CASE aStruct[ ii,2 ] == "D"
vRes := HB_STOD( cBuffer )
CASE aStruct[ ii,2 ] == "L"
cUPbuffer:=upper(cBuffer)
vRes := iif( cUPBuffer == "T" .or. cUPBuffer== "1" .or. cUPBuffer=="Y",.T.,.F. )
CASE aStruct[ ii,2 ] == "N"
vRes := VAL( cBuffer )
OTHERWISE
vRes := cBuffer
END CASE
FIELDPUT(ii,vRes)
next
return .T.
#endif /* __DBDELIM_OLD_CODE__ */