# TEXTDB -- A module to read and write from a free form text database package Textdb; @ISA = qw (Exporter); @EXPORT = qw (read_dbase write_dbase); use strict; use Carp; use FileHandle; use Exporter (); #--------------------------------------------------------------------------- # Read a text database with records separated by double bars sub read_dbase { my $input = shift; my $in = ref ($input) ? $input : FileHandle->new ($input); croak "Cannot open $input:\n $!" unless defined ($in); flock ($in, 1); my $rec = {}; my (@rec, $oldname); while (<$in>) { if (/^\|\|\s*$/) { push (@rec, $rec) if %$rec; $oldname = ''; $rec = {}; } else { my ($name, $value) = split (/\s*\|\s*/, $_, 2); unless (defined $value) { $value = $name; $name = $oldname; } $value =~ s/\s+$//; if (exists $rec->{$name}) { $rec->{$name} .= "\n$value"; } else { $rec->{$name} = $value; } $oldname = $name; } } push (@rec, $rec) if %$rec; close ($in) unless ref ($input); return @rec; } #--------------------------------------------------------------------------- # Write a text database with records separated by double bars sub write_dbase { my ($output, @rec) = @_; my $out = ref ($output) ? $output : FileHandle->new (">$output"); croak "Cannot open $output:\n $!" unless defined ($out); flock ($out, 2); foreach my $rec (@rec) { while (my ($name, $value) = each %$rec) { print $out "$name|$value\n"; } print $out "\|\|\n"; } close ($out); } #--------------------------------------------------------------------------- # Module documentation =head1 NAME Textdb is a module that implements a simple text database. =head1 SYNOPSIS @db = read_dbase ($filename); for $rec (@db) { $rec->{date} = localtime; print "== Record ==\n"; for $field (keys %$rec) { print $field, " = ", $rec->{$field}, "\n"; } } write_dbase ($filename, @db); =head1 DESCRIPTION Textdb implements a simple text database and is intended for use with web programs. The file format is designed to be easy to create and update with a text editor. The database consists of a set of records and each record has fields that can vary from record to record. Records are separated from each other by a line containing only a double bar (C<||>). Fields have a name and a value. The name is separated from the value by a single bar (C<|>). Blank space immediately preceding and following the bar is ignored. Normally each field occupies a single line, but fields can extend onto following lines as long as these lines do not contain a bar character. The bar character was chosen as a delimeter as it does not normally occur in text. Here is an example of the database format. name| John Doe phone|555-1234 comment|John Doe appears to be very interested in this project || name| Mary Smith phone | 555-6789 comment| Mary will be helpful in getting us new funding. || The interface to the text database reads or writes the entire database. There is no way to access a single record without reading the entire file. The file is read into a list of hashes. Each hash is a database record and each key-value pair in the hash is a database field. In order to allow multiple users to access the same database, an flock call is done when opening the database file. The interface to this package is: =over 4 =item read_dbase $filename Read a text database file into memory. This function returns a list of hashes. =item write_dbase $filename @db Write an in memory database to a file. =back =head1 LICENSE Copyright 2005 by Bernard Simon. You may use this script as you wish as long as this license is not removed. =head1 AUTHOR Bernie Simon (http://carelesshand.net) =cut 1;