**Description of the software** What: tdbf Where: http://sqlitestudio.one.pl/tdbf/tdbf.tcl.gz Description: [DBF] file reader/writter package. Dependencies: IncrTcl Licence: Tcl licence (BSD-like) Current version: 0.1 Updated: 11/2011 Author: Paweł Salawa (aka Googie). Contact: http://sqlitestudio.one.pl/index.rvt?act=contact It depends on [Itcl], but this is just for quick [namespace] creation bounded with handler command. It's easy to get rid of [Itcl] from the code, but I just prefer to use it. ---- **Features** * Written in [pure-Tcl] (with [Itcl]), so it's cross-platform, * Simple API (see below), * Reads and writes [dbf] memo (M, G, B, P types) fields, * Re-uses deleted records area for new inserted records, * Supports some unique features of FoxPro and Clipper variants. * Doesn't suppport dBASE 7, but it's in TODO. ---- **Demos** ***Read all records and print them*** ====== package require tdbf 0.1 tdbf::dbf myDbf myDbf open test1.dbf puts "Columns: [myDbf getColumnNames]" while {[set values [myDbf gets]] != ""} { puts $values } myDbf close ====== ***Read all records and print them - 2nd method*** ====== package require tdbf 0.1 tdbf::dbf myDbf myDbf open test1.dbf set columns [myDbf getColumnNames] puts "Columns: $columns" myDbf for value { foreach c $columns { puts -nonewline "$value($c) " } puts "" } myDbf close ====== ***Create dbf and put some data into it*** This script will create [dbf] file, add 2 columns, then add 3 new records and then replace second record with new value. ====== package require tdbf 0.1 tdbf::dbf myDbf file delete -force test2.dbf myDbf open test2.dbf myDbf addColumn "col1" "N" 3 ;# (numeric type, length = 3 digits) myDbf addColumn "col2" "C" 20 ;# (character/text type, 20 characters) for {set i 0} {$i < 3} {incr i} { myDbf insert [list $i "value $i"] } # Modify 2nd record myDbf update 1 [list 5 "xyz"] myDbf close ====== ---- **API** * '''constructor {{errorHandler ""}}''' The errorHandler code will be evaluated with literal error code appended (and optionally some other arguments). These errors are more like warnings. Dbf will still work but some limitations might be applied. Possible values for reading file are: &|DBT_DOESNT_EXIST|When the .dbt file (memo table) doesn't exist or it's not readable, but the database type requires it to exists. It can be ignored, but in this case the referenced memo values will be returned as empty strings.|& Possible values for writting file are: &|DBT_READ_ONLY|When .dbt file has read-only permissions or you cannot create the new .dbt file because of permissions.|& &|COLUMN_EXISTS|When trying to add column that already exist. Also column name is appended to error handler arguments. The [addColumn] will just skip this column.|& &|RECORDS_EXIST|When trying to add any column while there are already some records in DBF. Also column name is appended to error handler arguments. The [addColumn] will skip this column.|& &|COLUMN_NAME_TOO_LONG|When adding column with name longer than 10 characters (this is limited by DBF format). Column will still be added, but its name will be truncated to 10 characters.|& &|VALUE_TOO_LONG|May happen for columns with type N and C (in future maybe in others too). It means that you tried to insert value to DBF field that is longer than defined field length. Remember, that length of type N (number) means length of string used to represent the number.|& &|NO_RECORDS_WHILE_UPDATING|Tried to update (with [[dbf update]]) while there's not a single record in DBF.|& * '''Methods:''' %|Name|Arguments|Description|% &|open|file|Opens [DBF] file. If will be closed automatically at object destruction. It also opens DBT file (memo table) if it exists. If file doesn't exists, it creates new [DBF] file. If necessary (during writting data) might create also a DBT file.|& &|read|fd ?memoFd?|Reads [DBF] file from open channel. You can consider this method as a variant of [[dbf open]] accepting channels instead of file. Channel has to be readable (in any case) and writable (if you want to modify anything in file) and also switched to binary translation and non-blocking mode. Same requirements apply to memoFd. Channel for DBT (memo table) is optional.|& &|close||Closes file that was open with [[dbf open]] or passed to [[dbf read]].|& &|addColumn|name type ?length? ?precision?|Adds new column with given type (N, C, ...). Length is optional in most cases, except for types: N and C. Precision is always optional, but may be provided. Dbf cannot contain any records to add column.|& &|insert|values|Inserts new data record into [dbf]. Number of elements in 'values' has to be the same as number of columns, otherwis error will be raised. Values have to be in same format as returned from [[gets]]. It inserts record in place of first record marked as deleted or if there's no deleted record, then it appends record to the end of [DBF] file.|& &|delete|index|Marks record as deleted. Note that [DBF] records are not physically removed from file, they are just marked as deleted so they can be reused by [[insert]]. Use [[vacuum]] to force remove deleted records from file. Insert uses deleted record area to store new record in it. Returns true on success or false on failure (index out of range).|& &|update|index values ?columnName?|Updates all values of rercord with given index, or single column of that row if columnName is provided. See [[seek]] for index details. Returns true on success or false on failure (index out of range).|& &|getAllData||Returns all records in format {{row1field1Value row1field2Value ...} {row2field1Value row2field2Value} ...}. Excludes deleted records.|& &|for|arrName body|Iterates through all records and puts each record values into array named arrName with column names as keys. For each record the body is executed with arrName prepared.|& &|seek|index|Moves reading/writting pointer at given position. Index is record order number in [dbf] (excluding deleted records), which is in range from 0 to [[getDataCount]]-1. Can be end-N. Returns true on success, false on failure (index out of range).|& &|gets||Returns record at current index and increments index. Remember to [[seek]] to proper record if you called any other method from this class before the [[gets]]. May return empty list if no data was available.|& &|vacuum||Not implemented yet.|& &|getVersion||Returns database file version in 2 hex characters format.|& &|getVersionName||Returns human readable version description.|& &|getLastModificationDate||Returns last modification date in [[clock seconds]] format.|& &|getColumns||Returns list of columns, where each column is a Tcl dict with keys: name, type, length, precision, indexed.|& &|getColumnNames||Returns list of column names.|& &|getDataCount||Returns total number of records.|& &|getRecordSize||Returns size of single records in bytes|& **Datatypes translation map** ######################################################################### # Datatype translation. # # Use this datatype translation map to learn what value formats # can you expect to be returned when reading DBF and use same formats # to pass the data to DBF while writting DBF. ######################################################################### # DBF type <-> Tcl value format #------------------------------------------------------------------------ # C (characters) <-> Tcl string # N (number/numeric) <-> Tcl number (integer, float, double) # L (logical) <-> Tcl boolean value or empty string (DBF allows it to be undefined) # I, + (integer) <-> Tcl integer # D (date) <-> Unixtime (as from [clock seconds]). This Tcl format doesn't # support earlier dates (DBF "D" does), therefor requires some work. # M, G (memo, general) <-> Tcl string # # F (float) <-> Tcl float # B, P (binary, picture) <-> Binary data # O (double) <-> Tcl double # Y (currency) <-> Tcl string representing huge decimal number (from # -922337203685477.5807 to +922337203685477.5807), which cannot be # represented as Tcl double. # T (datetime) <-> Tcl list of {year month day hour second millisecond}. # V, X (varifield) <-> Depending on field length and database type (FlagShip attribute): # 2 (and flagship) <-> Tcl integer # 3 <-> Same as for type "D". # 4 <-> Tcl integer # 8 (and flagship) <-> Tcl double # 10 (and flagship) <-> This is special kind of DBF memo, so should # be a string, but this is not supported yet. # * <-> This also is special kind of DBF memo # and same thing as above applies here. # # @ (timestamp) <-> List of {date time}, which are integers. # The date is the number of days since 01/01/4713 BC. # Time is hours * 3600000 + minutes * 60000 + Seconds * 1000. # This requires some more work to format it to more usable format. ---- **Discussions** <> <>Package