# $Id$ $VERSION{''.__FILE__} = '$Revision$'; # # >>Title:: Dictionary Library # # >>Copyright:: # Copyright (c) 1992-1996, Ian Clatworthy (ianc@mincom.com). # You may distribute under the terms specified in the LICENSE file. # # >>History:: # ----------------------------------------------------------------------- # Date Who Change # 04-Oct-97 ianc Fixed bug with * in reports # 29-Feb-96 ianc SDF 2.000 # ----------------------------------------------------------------------- # # >>Purpose:: # This library provides support for reading and processing # dictionaries stored in text files. # # >>Description:: # A dictionary is a collection of items where each item has: # # * a unique key # * a description # # >>Limitations:: # # >>Resources:: # # >>Implementation:: # ##### Constants ##### # # >>Description:: # {{Y:DICT_DFLT_REPORT}} is the default report for {{Y:DictPrint}}. It: # # * outputs items in the order found, separated by blank lines # * outputs each item as: # - key on one line # - description on the next # @DICT_DFLT_REPORT = &TableParse ( 'Key Format', '* "$key\n$data\n\n"', ); ##### Variables ##### # # >>Description:: # {{Y:dict_rest}} is the set of lines in the last file processed # by {{Y:DictFetch}} which are not in the dictionary. # @dict_rest = (); $_dict_cnt = 0; $_dict_debug = 0; ##### Routines ##### # # >>Description:: # {{Y:DictFetch}} inputs filename as a dictionary. # sub DictFetch { local($file, $begin, $delimiter, $end, $prefix) = @_; local($success); local($strm, $line, $key, @desc, $new_key, $rest, $ch); local($Buffers); local(@bufferlist) = 'main'; # array of buffer names local($get_scope) = 0; local($doc_scope) = 0; # scope of doco to be extracted local($bufref); # initialise the default buffer entry $Buffers = new Sdfget; # set the scope for the documentation to be extracted $get_scope = $Buffers->getScope($scope); # Open the input stream $strm = sprintf("dct_s%d", $_dict_cnt++); open($strm, $file) || return (0, ()); # Input the data @dict_rest = (); line: while (<$strm>) { # Handle the line prefix, if any $line = $_; if ($prefix && ! s/^$prefix//) { # Save away the previous record, if any. if ($key) { print STDERR "Key: $key - Text: @desc...\n" if $_dict_debug; $Buffers->addText ($key, \@desc, @bufferlist); $key = ""; @desc = (); } push(@dict_rest, $line); next line; } # Check for end line. Note that this test must be before # the "check for begin line", so that things work as expected. # (Thanks to Keith Ponting for fixing this.) if (/^$end/) { # Save away the previous record, if any. if ($key) { print STDERR "Key: $key - Text: @desc...\n" if $_dict_debug; $Buffers->addText($key, \@desc, @bufferlist); $key = ""; @desc = (); } } # process possible `sdfget' directives if ( /^$begin!use .*$/ ) { print STDERR "In use...line: $line\n" if $_dict_debug; ($doc_scope, @bufferlist) = &Sdfget::UseArgs($line); while ($doc_scope > $get_scope ) { # terminate processing of there is no more input last line if ! $doc_scope; # consume the rest of this section ($doc_scope, @bufferlist) = $Buffers->NextSection ($strm); } next line; } # Check for begin line elsif (/^$begin(.+)$delimiter(.*)$/) { $new_key = $1; $rest = $2; print STDERR "Key: $key - Text: @desc...\n" if $key && $_dict_debug; # Save away the previous record, if any. $Buffers->addText($key, \@desc, @bufferlist) if $key; # Check for description on same line if ($rest) { # Save away the new record @desc = ($rest); print STDERR "Key: $new_key - Text: @desc...\n" if $_dict_debug; $Buffers->addText($new_key, \@desc, @bufferlist); $key = ""; @desc = (); } else { $key = $new_key; @desc = (); } } # Check for description line elsif ($key) { push(@desc, $_); } # Otherwise, not part of dictionary else { push(@dict_rest, $line); } } close($strm); # Save away the previous record, if any. if ($key) { print STDERR "Key: $key - Text: @desc...\n" if $_dict_debug; $Buffers->addText($key, \@desc, \@bufferlist); } # trim the trailing new-line on each description $Buffers->TrimDesc(); # return results return (1, $Buffers); } # # >>Description:: # {{Y:DictPrint}} outputs a dictionary using report. If no # report is specified, {{Y:DICT_DFLT_REPORT}} is used. # sub DictPrint { local($strm, $level, $buffer_name, $bufref, @report) = @_; local($ok); local(@item, $itemarrayref, %item, $itemhashref); local(@rep_field, %val, @local_report); local($key, $fmt, $err); local($dict_ref, $dict_hash, $dict_keys); local($alt_buffer); # Init things ($itemarrayref, $itemhashref) = $bufref->Sdfget::getKeysDocs($buffer_name); @item = @$itemarrayref; %item = %$itemhashref; @report = @DICT_DFLT_REPORT unless @report; @my_report = @report; # Check report table has required fields @rep_field = &TableFields(shift(@my_report)); return 0 unless grep(/^Key$/, @rep_field); return 0 unless grep(/^Format$/, @rep_field); # Output report for $report (@my_report) { %val = &TableRecSplit(*rep_field, $report); $key = $val{'Key'}; $fmt = $val{'Format'}; # Handle 'all remaining' if ($key eq '*') { for $item (@item) { if (defined $item{$item}) { $err += &_DictItemFmt($strm, $fmt, $item, $item{$item}); } } } # Handle free text elsif ($key eq '-') { $err += &_DictItemFmt($strm, $fmt); } elsif ($key =~ /\+.*/ && ! $level) { $key =~ /\+(.*)/; if ($1 eq '*') { foreach $alt_buffer (keys %$bufref){ next if ( $alt_buffer eq 'main'); print $strm "# Buffer: $alt_buffer\n"; print $strm "!slide_down\n"; &DictPrint($strm, ++$level, $alt_buffer, $bufref, @report); print $strm "!slide_up\n"; } } else { print $strm "!slide_down\n"; print $strm "Buffer: $alt_buffer\n"; &DictPrint($strm, ++$level, $1, $bufref, @report); print $strm "!slide_up\n"; } } # Handle this item else { if ($fmt && $item{$key}) { $err += &_DictItemFmt($strm, $fmt, $key, $item{$key}); } delete $item{$key}; } } # Return result return $err == 0; } # # >>_Description:: # {{Y:_DictItemFmt}} formats and prints an item on a stream. # {{$fmt}} is a Perl string to be evaluated. # {{$key}} and {{$data}} are the key and description of the item. # {{$ARGV}} is assumed to be the current file. # sub _DictItemFmt { local($strm, $fmt, $key, $data) = @_; local($err); local($str); local($dir, $base, $ext, $short); # Get file info ($dir, $base, $ext, $short) = &NameSplit($ARGV); # Print item $str = eval $fmt; if ($@) { &AppMsg('error', $@); return 1; } print $strm $str; # Return result return 0; } # package return value 1;