/* Test.prg Convert GuestRequest.csv file to dbf table with Libre Office. Question by Chris Faulkner ( GuestRequest.csv ) : http://news.dbase.com/newsgroups.php?art_group=dbase.programming&article_id=69386 My code post ( GuestRequest.csv ) : http://news.dbase.com/newsgroups.php?art_group=dbase.programming&article_id=69425 Using dBase 2.01, Windows 10, Libre Office 7.5.3.2, fr date format ( DD/MM/YYYY ) This code is a basic sample for tests. For csv type, look page 42 of : https://www.openoffice.org/api/basic/man/tutorial/tutorial.pdf For encoding : https://www.iana.org/assignments/character-sets/character-sets.xhtml Fields array options. aFields.[ i, 1 ] = Types for Calc. aFields.[ i, 2 ] = Field name for new table. aFields.[ i, 3 ] = Field type for new table. aFields.[ i, 4 ] = Field len for new table. aFields.[ i, 5 ] = Field dec for new table. aFields.[ i, 6 ] = Date and Timestamp = format ( en, fr, sql ) Numeric = Decimal separator ( < . > or < , > ) aFields.[ i, 7 ] = Free for later. This code is a basic sample. */ // Select the csv file to convert. #define CSV_GUESTREQUEST // Csv file to convert -> GuestRequest.csv //#define CSV_MYFILE_CSV // My csv file to test -> MyFile.csv local tTimeStart parameter cPath // Its only for me. try ; set directory to &cPath // Its only for me. catch (exception e) ; endtry ; release cPath // Its only for me. tTimeStart = datetime() // Begin execution time. // pub_lDisplay = true // Display Calc : true = yes, false = no. pub_lError = false // Error found when execute. pub_lWarning = false // Warning found when execute. pub_aFields = new array() // Fields array options. pub_cTableTmp = set( "directory" ) + "\_Result_Table_Tmp.dbf" // Dbf Temp table. pub_cTableOut = set( "directory" ) + "\_Result_Table_Out.dbf" // Dbf table created. pub_cFileLog = set( "directory" ) + "\_Result_log.log" // Log file. #ifdef CSV_GUESTREQUEST pub_cFileCsv = set( "directory" ) + "\GuestRequest.csv" // Csv file to open. // Csv options. pub_cListSeparator = 44 // ASCII Field separator : 44 = commas. pub_cFieldDelimiter = 34 // ASCII Text field delimiter : 34 = double quotes. pub_cEncoding = 76 // Encoding : 76 = Unicode (UTF-8). pub_cFirstLine = 1 // First line to be treated in csv file. // Fields array options. bd_aadd( pub_aFields, { 1, "entry_id" , "numeric" , 9, 0, "" , "" } ) // Col 1 - A type 1 = NUMERIC, Entry Id -> ENTRY_ID bd_aadd( pub_aFields, { 2, "entry_date" , "timestamp", 0, 0, "sql", "" } ) // Col 2 - B type 2 = TEXT , Entry Date -> ENTRY_DATE bd_aadd( pub_aFields, { 1, "sponsor_member_ID", "numeric" , 9, 0, "" , "" } ) // Col 3 - C type 1 = NUMERIC, Sponsor's Member ID -> SPONSOR_S_ bd_aadd( pub_aFields, { 2, "sponsor_name" , "char" , 24, 0, "" , "" } ) // Col 4 - D type 2 = TEXT , Sponsor's Name -> SPONSOR_S2 bd_aadd( pub_aFields, { 2, "sponsor_phone" , "char" , 17, 0, "" , "" } ) // Col 5 - E type 2 = TEXT , Sponsor's Phone -> SPONSOR_S3 bd_aadd( pub_aFields, { 2, "sponsor_email" , "char" , 64, 0, "" , "" } ) // Col 6 - F type 2 = TEXT , Sponsor's Email -> SPONSOR_S4 bd_aadd( pub_aFields, { 2, "arrival_date" , "date" , 0, 0, "en" , "" } ) // Col 7 - G type 2 = TEXT , Arrival Date -> ARRIVAL_DA bd_aadd( pub_aFields, { 2, "leave_date" , "date" , 0, 0, "en" , "" } ) // Col 8 - H type 2 = TEXT , Leave Date -> LEAVE_DATE bd_aadd( pub_aFields, { 1, "vacation_days" , "numeric" , 4, 0, "" , "" } ) // Col 9 - I type 1 = NUMERIC, Vacation Days -> VACATION_D bd_aadd( pub_aFields, { 2, "guest_name" , "char" , 24, 0, "" , "" } ) // Col 10 - J type 2 = TEXT , Guest Name -> GUEST_NAME bd_aadd( pub_aFields, { 2, "guest_email" , "char" , 64, 0, "" , "" } ) // Col 11 - K type 2 = TEXT , Guest Email -> GUEST_EMAI bd_aadd( pub_aFields, { 2, "card_status" , "char" , 5, 0, "" , "" } ) // Col 12 - L type 2 = TEXT , Card Status -> CARD_STATU bd_aadd( pub_aFields, { 2, "consent" , "char" , 8, 0, "" , "" } ) // Col 13 - M type 2 = TEXT , Consent -> CONSENT #endif // CSV_GUESTREQUEST #ifdef CSV_MYFILE_CSV // Works with french country. pub_cFileCsv = set( "directory" ) + "\MyFile.csv" // Csv file to open. set procedure to MyFileCsvCreate.cc additive MyFileCsvCreate( pub_cFileCsv ) // Csv options. pub_cListSeparator = 59 // ASCII Field separator : 59 = Semicolon. pub_cFieldDelimiter = 34 // ASCII Text field delimiter : 34 = double quotes. pub_cEncoding = 1 // Encoding : 1 = maybe ANSI ? or Windows1252/WinLatin1 ? or default system ?. pub_cFirstLine = 1 // First line to be treated in csv file. // Fields array options. bd_aadd( pub_aFields, { 2, "text_ascii_sup" , "char" , 16, 0, "" , "" } ) // Col 1 - A type 2 = TEXT , TextAsciiSup -> TEXTASCIIS bd_aadd( pub_aFields, { 1, "number_decimal_fr" , "numeric", 12, 4, "" , "" } ) // Col 2 - B type 1 = NUMERIC, NumberDecimalFR -> NUMBERDECI bd_aadd( pub_aFields, { 2, "number_dec_text_fr", "numeric", 12, 4, "," , "" } ) // Col 3 - C type 2 = TEXT , NumberDecTextFR -> NUMBERDEC2 bd_aadd( pub_aFields, { 4, "date_fr_date" , "date" , 0, 0, "" , "" } ) // Col 4 - D type 4 = DATE FR, DateFrDate -> DATEFRDATE bd_aadd( pub_aFields, { 2, "date_fr_text" , "date" , 0, 0, "fr", "" } ) // Col 5 - E type 2 = TEXT , DateFrText -> DATEFRTEXT #endif // CSV_MYFILE_CSV // bd_tErase( pub_cTableTmp ) bd_tErase( pub_cTableOut ) bd_fErase( pub_cFileLog ) ? set alte to &pub_cFileLog set alte on ? "Convert csv file to dbf7 table." ? ? "File csv in : " + pub_cFileCsv ? "Table dbf7 out : " + pub_cTableOut ? if not new file().exists( pub_cFileCsv ) ? "***Error, file not exists : " + pub_cFileCsv pub_lError := true endif if not pub_lError ca_CsvToDbf3_GetDbf() endif if not pub_lError ca_TableTransform() endif ? ? "Execution time : " + bd_DTNtoDMHdiff( datetime() - tTimeStart ) ? set alte off set alte to if pub_lError or pub_lWarning bd_ShellExecute( pub_cFileLog ) endif return // Tools library functions Work only for GuestRequest.csv file. // Convert a table dbf3 created from a csv file with Libre Office Calc to a table dbf7. function ca_TableTransform // Works only for GuestRequest.csv file. local i // Numeric count. local cCreate // String for create the table. local nRecord // Record in use. local qIn // Table created by calc Query object. local qOut // Table out for use Query object. local xValue // Field value read for write. cCreate = 'Create table "' + pub_cTableOut + '" (' for i = 1 to alen( pub_aFields, 1 ) cCreate += pub_aFields[ i, 2 ] + " " // Field name. do case case pub_aFields[ i, 3 ] == "char" cCreate += "char(" + bd_ntos( pub_aFields[ i, 4 ] ) + ")," case pub_aFields[ i, 3 ] == "numeric" cCreate += "numeric(" + bd_ntos( pub_aFields[ i, 4 ] ) + "," + bd_ntos( pub_aFields[ i, 5 ] ) + ")," case pub_aFields[ i, 3 ] == "date" cCreate += "date"+ "," case pub_aFields[ i, 3 ] == "timestamp" cCreate += "timestamp"+ "," otherwise ? "***Error to create the field " + bd_ntos( i ) endcase endfor cCreate := left( cCreate, len( cCreate ) - 1 ) + ")" // Remove the last << , >>. ? "Creation table options :" ? cCreate ? try _app.databases[ 1 ].executeSql( cCreate ) catch (exception e) ? "***Error to create table : " + e.message ? "** " + cCreate pub_lError := true endtry cCreate := "" if not pub_lError nRecord = 0 use "&pub_cTableOut" list structure use qIn = new Query() qIn.sql := "select * from '" + pub_cTableTmp + "'" qIn.active := true qOut = new Query() qOut.sql := "select * from '" + pub_cTableOut + "'" qOut.active := true do while not qIn.Rowset.endOfSet nRecord++ qOut.rowset.beginAppend() for i = 1 to alen( pub_aFields, 1 ) xValue = qIn.rowset.fields[ i ].value do case case pub_aFields[ i, 3 ] == "char" if not pub_aFields[ i, 1 ] == 2 xValue := null endif case pub_aFields[ i, 3 ] == "date" if pub_aFields[ i, 1 ] == 4 // Date FR, do nothing. elseif pub_aFields[ i, 1 ] == 2 // Text. xValue := bd_dStrWithOptToD( xValue, pub_aFields[ i, 6 ] ) else xValue := null endif case pub_aFields[ i, 3 ] == "numeric" if pub_aFields[ i, 1 ] == 1 // Do nothing. elseif pub_aFields[ i, 1 ] == 2 // Numeric value in text. xValue := bd_nStrWithOptToN( xValue, pub_aFields[ i, 6 ] ) else xValue := null endif case pub_aFields[ i, 3 ] == "timestamp" if pub_aFields[ i, 1 ] == 2 xValue := bd_tStrWithOptToT( xValue, pub_aFields[ i, 6 ] ) else xValue := null endif otherwise xValue := null endcase if not xValue == null qOut.rowset.fields[ i ].value := xValue else pub_lWarning := true ? "$$$Warning in field " + bd_ntos( i ) + " record " + bd_ntos( nRecord ) + " cell " + bd_IntToCell( i, nRecord + 1 ) endif endfor qIn.rowset.next() enddo qOut.rowset.Save() qOut.active := false qIn.active := false endif return // Create a dbf3 table from a csv file with Apache Libre Offic Calc. // Using public variable for parameters. function ca_CsvToDbf3_GetDbf() local oVb // VBScript object. local cOptions // Options to save to dbf table 3. local i // Count variable. oVb = new OleAutoClient( "msscriptcontrol.scriptcontrol" ) oVb.language := "vbscript" // Open Libre Office. oVb.addcode( 'Set oServiceManager = CreateObject( "com.sun.star.serviceManager" )' ) oVb.addcode( 'Set Desktop = oServiceManager.createInstance( "com.sun.star.frame.Desktop" )' ) // Config for open a csv file. oVb.addcode( 'Dim args(2)' ) // Array for Desktop. oVb.addcode( 'Set args(0) = oServiceManager.Bridge_GetStruct( "com.sun.star.beans.PropertyValue" )' ) oVb.addcode( 'args(0).name = "Hidden"' ) // Create a bridge for display or hide. oVb.addcode( 'args(0).value = ' + iif( not pub_lDisplay, "true", "false" ) ) // true = display ( default ), false = hide. oVb.addcode( 'Set args(1) = oServiceManager.Bridge_GetStruct( "com.sun.star.beans.PropertyValue" )' ) oVb.addcode( 'args(1).Name = "FilterName"' ) oVb.addcode( 'args(1).Value = "Text - txt - csv (StarCalc)"' ) oVb.addcode( 'Set args(2) = oServiceManager.Bridge_GetStruct( "com.sun.star.beans.PropertyValue" )' ) oVb.addcode( 'args(2).Name = "FilterOptions"' ) // Create the options for open the csv file. cOptions = bd_ntos( pub_cListSeparator ) + ',' cOptions += bd_ntos( pub_cFieldDelimiter ) + ',' cOptions += bd_ntos( pub_cEncoding ) + ',' cOptions += bd_ntos( pub_cFirstLine ) + ',' for i = 1 to alen( pub_aFields, 1 ) cOptions += bd_ntos( i ) + "/" + bd_ntos( pub_aFields[ i, 1 ] ) + iif( i == alen( pub_aFields, 1 ), "", "/" ) endfor ? "CSV options string for open the csv file :" ? cOptions ? oVb.addcode( 'args(2).Value = "' + cOptions + '"' ) // Test_csv.csv try oVb.addcode( 'Set oDoc = Desktop.loadComponentFromURL("' ; + bd_FileToUrl( pub_cFileCsv ) +'", "_blank", 0, args )' ) catch ( exception e ) ? "***Error " + e.message + chr( 10 ) + "***File : " + pub_cFileCsv + " not open." pub_lError := true endtry if not pub_lError // Save dbf table config. oVb.addcode( 'Dim args_SaveDbf(0)' ) // Array for Save dbf files. oVb.addcode( 'Set args_SaveDbf(0) = oServiceManager.Bridge_GetStruct( "com.sun.star.beans.PropertyValue" )' ) oVb.addcode( 'args_SaveDbf(0).Name = "FilterName"' ) oVb.addcode( 'args_SaveDbf(0).Value = "dBase"' ) try oVb.addcode( 'oDoc.storeAsURL "' + bd_FileToUrl( pub_cTableTmp ) + '", args_SaveDbf' ) catch ( exception e ) ? "***Error " + e.message + chr( 10 ) + "***Table : " + pub_cTableTmp + " not save" pub_lError := true endtry endif oVb.addcode( 'oDoc.Close( True )' ) oVb.addcode( 'Desktop.Terminate()' ) oVb := null if not pub_lError use "&pub_cTableTmp" list structure use endif return // Transform a str date to a date ignore international options. function bd_dStrWithOptToD( cValue, cOption ) local nYear, nMonth, nDay, tReturn nYear = val( subs( cValue, 7, 4 ) ) do case case cOption == "en" // Format MM/DD/YYYY nMonth = val( subs( cValue, 1, 2 ) ) - 1 nDay = val( subs( cValue, 4, 2 ) ) case cOption == "fr" // Format DD/MM/YYYY nMonth = val( subs( cValue, 4, 2 ) ) - 1 nDay = val( subs( cValue, 1, 2 ) ) otherwise return null endcase tReturn = dttod( new date( nYear, nMonth, nDay ) ) return tReturn // Transform a str numeric value to a number ignore international options. function bd_nStrWithOptToN( cValue, cOption ) local c, i, cReturn cReturn = "" for i = 1 to len( cValue ) c = subs( cValue, i, 1 ) do case case c$"-0123456789" cReturn += c case c == cOption cReturn += set( "point" ) endcase endfor return val( cReturn ) // Transform a str timestamp to a timestamp ignore international options. function bd_tStrWithOptToT( cValue, cOption ) local nYear, nMonth, nDay, nHour, nMinute, nSeconds, tReturn do case case cOption == "sql" // Format YYYY-MM-DD hh:mm:ss nYear = val( subs( cValue, 1, 4 ) ) nMonth = val( subs( cValue, 6, 2 ) ) - 1 nDay = val( subs( cValue, 9, 2 ) ) nHour = val( subs( cValue, 12, 2 ) ) nMinute = val( subs( cValue, 15, 2 ) ) nSecond = val( subs( cValue, 18, 2 ) ) otherwise return null endcase tReturn = new date( nYear, nMonth, nDay, nHour, nMinute, nSecond ) return tReturn // Tools library functions. // Add one row to an array. function bd_aadd( aArray, xData ) local i local l local n if bd_valtype( xData ) == "A" l = xData.size n = ( aArray.size / l ) + 1 aArray.resize( n, l ) for i = 1 to l aArray[ n, i ] := xData[ i ] endfor else aArray.add( xData ) endif return // Transform a directory name with ("..\") in string ("c:\"). function bd_DirPointToString( cDir ) local f // File object. local cReturn // Directory name transformed. local cFileBat // File name of the batch file. local cFileDos // File created with Dos. cFileBat = set( "directory" ) + "\DirPointToString_" + bd_Millisec( true ) + ".bat" cFileDos = set( "directory" ) + "\DirPointToString_" + bd_Millisec( true ) + ".fbm" f = new File() f.delete( cFileBat ) f.delete( cFileDos ) f.create( cFileBat, "A" ) f.puts( "cd " + cDir ) f.puts( "echo %cd% >" + cFileDos ) f.close() bd_RunVBs('cmd /K "' + cFileBat + '" &exit', 0, true ) f.delete( cFileBat ) f.open( cFileDos, "R" ) cReturn = trim( f.gets() ) f.close() f.delete( cFileDos ) return cReturn // Convert datetime() difference in day(s), hour(s), minute(s), second(s) and milliSecond(s). function bd_DTNtoDMHdiff( nDiff ) local wDiff local cReturn local nTemp wDiff = nDiff cReturn = "" nTemp = int( wDiff ) if nTemp > 0 cReturn += bd_ntos( nTemp ) + " day" + iif( nTemp > 1, "s ", " " ) endif wDiff := wDiff - int( wDiff ) nTemp := int( wDiff * 24 ) if nTemp > 0 cReturn += bd_ntos( nTemp ) + " hour" + iif( nTemp > 1, "s ", " " ) endif wDiff := wDiff - ( nTemp / 24 ) nTemp := int( wDiff * 24 * 60 ) if nTemp > 0 cReturn += bd_ntos( nTemp ) + " minute" + iif( nTemp > 1, "s ", " " ) endif wDiff := wDiff - ( nTemp / ( 24 * 60 ) ) nTemp := int( wDiff * 24 * 60 * 60 ) if nTemp > 0 cReturn += bd_ntos( nTemp ) + " second" + iif( nTemp > 1, "s ", " " ) endif wDiff := wDiff - ( nTemp / ( 24 * 60 * 60 ) ) nTemp := int( wDiff * 24 * 60 * 60 * 1000 ) if nTemp > 0 cReturn += bd_ntos( nTemp ) + " millisecond" + iif( nTemp > 1, "s ", " " ) endif return cReturn // Erase a File. function bd_fErase( cTable ) if new file().exists( cTable ) new file().delete( cTable ) endif return // Transform a file name with ("..\") in string ("c:\"). function bd_FilePointToString( cFile ) local cReturn // File name transformed. local sFile // Name of the file without directory. sFile = bd_StringExtractRight( cFile, "\" ) cReturn = bd_StringExtractLeft( cFile, "\" ) cReturn = bd_DirPointToString( cReturn ) cReturn += "\" + sFile return cReturn // Convert a file name to Url. function bd_FileToUrl( cFile ) local i // Count variable. local cReturn // Return Url name. local wFile // File to transform in work. if at( "/", cFile ) > 0 // Nothing to do. return cFile endif i = 1 cReturn = "" wFile = ( cFile ) if at( "\", wFile) = 0 // Not back slash. wFile := set( "directory") + "\" + wFile endif if at( "..\", wFile ) > 0 wFile := bd_FilePointToString( wFile ) endif do while i <= len( wFile ) if subs( wFile, i, 1 ) = "\" cReturn += "/" else cReturn += subs( wFile, i, 1 ) endif i++ enddo cReturn = "file:///" + cReturn return cReturn // Convert number Column and number Row in letter columns and number row. function bd_IntToCell( nRow, nCol, lLong ) local n local cReturn if argcount() < 3 lLong = false endif cReturn = "" n = abs( nCol ) do while n > 0 if mod( n, 26 ) = 0 // For the "Z" character. cReturn := "Z" + cReturn n = int( n / 26 ) - 1 else cReturn := chr( 64 + mod( n, 26 ) ) + cReturn n = int( n / 26 ) endif enddo cReturn += bd_ntos( nRow ) + iif( not lLong, "", " (" + bd_ntos( nRow ) + "," + bd_ntos( nCol ) + ")" ) return cReturn // Returns the milli seconds of the hour. function bd_MilliSec( lString ) local d local xReturn if argcount() = 0 lString = false endif d = new Date() xReturn = right( str( d.getTime(), 20, 0 ), 3 ) if not lString xReturn = val( xReturn ) endif return xReturn // Convert a number in string without space before. function bd_ntos( nNum, nInt, nDec ) if argcount() < 2 nInt := 16 endif if argcount() < 3 nDec := 0 endif return ltrim( str( nNum, nInt, nDec ) ) // Run a command with options hidden and/or stop dBase. function bd_RunVBs( cCommand, nDisplay, lStop ) local oVBscript // Object for VBscript. if argcount() < 3 lStop = true // true = Stop dBasePLUS, false = not stop dBasePlus. endif if argcount() < 2 nDisplay = 1 // 1 = Display normal cExe, 0 = Hidden. endif oVBscript = new OleAutoClient( "WScript.Shell" ) oVBscript.Run( cCommand, nDisplay, lStop ) oVBscript := null return // Execute a command with options. function bd_ShellExecute( xHorCom, cOp, cFile, cPara, cDir, nShow ) if type( "ShellExecuteA" ) <> "FP" extern CHANDLE ShellExecuteA( CHANDLE, CSTRING, CSTRING, CSTRING, CSTRING, CINT ) Shell32.dll endif if argcount() == 1 ShellExecuteA( null , "open", xHorCom, null , null, 1 ) else ShellExecuteA( xHorCom, cOp , cFile , cPara, cDir, nShow ) endif return // Return the left string before 1 selected char( eg. directory name ). function bd_StringExtractLeft( sString, cComma ) local cReturn local nRat nRat = rat( cComma, sString ) cReturn = left( sString, nRat - 1 ) return cReturn // Return the right string after 1 string Comma ( eg. file name ). function bd_StringExtractRight( sString, cComma ) return right( sString, len( sString ) - rat( cComma, sString ) - len( cComma ) + 1 ) // Erase a table and his files. function bd_tErase( cTable ) if _app.databases[ 1 ].tableExists( cTable ) _app.databases[ 1 ].dropTable( cTable ) endif return // Return the type of a value or a variable. function bd_ValType( xData ) local cReturn private PRIVATE_xData PRIVATE_xData = xData cReturn = type( "PRIVATE_xData" ) PRIVATE_xData := null release PRIVATE_xData return cReturn