[comp.lang.perl] rolo users ? outline mode ...

aks@hub.ucsb.edu (Alan Stebbens) (08/08/90)

| Hi. I wrote a rolo(dex) mode for emacs about a year or so ago. I got
| a few patches and comments just after its release, and having been
| off the net for most of that time, I was just wondering if there
| is anyone still using rolo, and if anyone has developed it much.
| Just keeping up .... please use mail if you reply ...

I use it quite a bit, both within Emacs and without.  Of course, within
Emacs, I use the "rolo.el" and companion elisp code.  Many of my staff,
though, do not use Emacs, not matter how much I harass them; so, I wrote
a Perl script for them to make the ideas and "database" represented by
"rolo" available.  I know, I know: this is much like reinventing the
wheel in the Unix domain, since there are many nice rolodex tools which
use curses, X11, OpenLook and what-have-you.  However, there were no
tools which used a common rolodex database for both Emacs and non-Emacs
usage.  Now there is; the following code is given to the world, under
the GNU CopyLeft.  I know this is the "GNU Emacs" list, but, as Perl is
also distributed by GNU, and since this code dovetails with the
"rolo.el" code, I figured there might be someone else interested in it.

This code looks for a configurable directory pathname, from either the
envar ROLOPATH or, by default, /usr/local/lib/rolodex.  Any files within
this directory are assumed to be a rolodex-format file.  Each file may
have its own, possibly unique header, and configuration variables.
You can also have a private rolodex, ~/.rolodex{,.otl}.

Since each rolodex can have a header, which may or may not be identical
to the one from the previous rolodex file, I made the display code
recognize consecutively identical headers, and not redisplay the
succeeding ones unless they were really unique.

The alternate configuration strings, at the beginning of each rolodex
file has never been tested.  It seemed like a good idea to generalize
the design a little, but real work kept creeping back at me so I never
got to testing the parts that _I_ don't use much.  Let me know how it
goes with you, if you do try it.

I've thought about adding a network client/server mode of operation, so
the rolodex database can be centralized; but I figured it would be
better to get some feedback, if any.

A prettier output format might be nice, possibly using a "format"
definition from the rolodex file itself.  Also, perhaps it might be nice
to do highlighting or underlining via curses to enhance the display.

I'm sorry for not writing a "man" page (but not that sorry); someone
else can do so if they really want to.  The Perl code has many, many
comments which can form the basis for a man page.

The Perl code is immediately below, followed by a sample rolofile, with
a sample, bogus vendor, showing the heirarchy stuff, and then some real
vendors, with the personal contacts removed.

Enjoy..

Alan Stebbens       Computer Resource Manager
<aks@hub.ucsb.edu>  Center for Computational Sciences and Engineering (CCSE)
W:(805) 893-8135    University of California, Santa Barbara
F:(805) 893-8553    3111 Engineering I
		    Santa Barbara, CA 93106

============================= cut here ===================================
#!/bin/perl
# Copyright 1990, Alan K. Stebbens 
# This code is distributed under the GNU General Copyright License.
# The idea for the rolodex database was borrowed from Paul Davis' elisp
# code called "rolo.el".  In fact, this code should work with the _same_
# database file(s).
#
# rolo [opts] string ...
#
# Search the rolodex for "string"
#
# opts:
#  -l    list the filenames
#  -h    omit the file headers
#  -e    list the entries [default]
#  -t    don't print the level hierarchy (terse)
#  -w    match by word
#  -c    count and print just the number of matches
#
# The rolodex consists of the files
#
# 	~/.rolodex{.otl,}
# 	/usr/local/lib/rolodex/*
# 
# also if ROLOPATH is defined, it is used instead of /usr/local/lib/rolodex.
#
# The syntax of a rolodex file (hereafter called a "rolofile") is heirarchical
# and pretty simple.
#
# As configured by default, each rolofile can contain an initial "header" which 
# will be printed above any output produced from that file, the end of the header
# is recognized with a regular expression, called "RoloHeader".

# A new rolodex entry is recognized with a regular expression called "RoloEntry".

# Since the rolodex entries are heirarchical, and since the RoloEntry is configurable,
# there needs to be a way to determine the depth of each entry, relative to the
# others.  The standard "RoloEntry" is to recognize leading asterisks; the standard
# level, then, is the length of the asterisk string.  If you change the RoloEntry,
# you must also change RoloDepth to be a Perl expression which returns the depth
# of the current RoloEntry.

# A possible alternative for both might be:
#
#  RoloEntry:   "^(\d+)."
#  RoloLevel:   "(0+$1)"
#
# Note that RoloLevel is eval'ed immediately after RoloEntry succeeds, allowing
# pattern match substrings ($1, $2, etc.) to be used in RoloLevel.

# Comment lines may be embedded anywhere within the rolodex file, even in the header
# by beginning them with the string recognized by the regular expression contained
# in the variable "RoloComment".

# These strings have standard default values, but may be overridden, in each 
# file, by the first lines containing the following text (the values shown below
# are the defaults).  The strings *must* be quoted; embedded quotes must be escaped
# with a backslash.

#
#  RoloHeader:  "^==="
#  RoloEntry:   "^\*+"
#  RoloComment: "^#"

$RoloPath = '/usr/local/lib/rolodex' unless $RoloPath = $ENV{'ROLOPATH'};
@RoloFiles = (grep(!/^#|[#~]$/,<~/.rolodex*>));
push(@RoloFiles,grep(!/^#|[#~]$/,eval("<$RoloPath/*>")));

$RoloHeader  = "^===";
$RoloEntry   = "^\\*+";
$RoloLevel   = "(/^(\\*+)/ && length(\$1))";
$RoloComment = '^#';

# Scan the arguments

$Headers = 1;			# on by default
$FileNames = 0;			# off by default
$Entries = 1;			# on by default
$LevelTree = 1;			# on by default
$CountMatches = 0;		# off by default
$WordMatch = 0; 		# match keywords as words

@Search = ();			# search patterns

if ($#ARGV < $[) {
    print STDERR "usage: rolo [options] keyword ...
Options are:
   -c    count and print just the number of matches
   -e    list the entries [default]
   -l    list the filenames
   -h    omit the file headers
   -p    match with the following REGEXP pattern
   -t    don't print the level hierarchy (terse)
   -w    match by word
";
    exit 1;
}

while ($_ = shift) {
    if (/^-/) {
	$Headers = 0                     if /^-.*h/;
	($Entries = 0,$FileNames = 1)    if /^-.*l/;
	($Entries = 0,$CountMatches = 1) if /^-.*c/;
	$Entries = 1                     if /^-.*e/;
	($Headers = 0,$LevelTree = 0)    if /^-.*t/;
	push(@Search,shift)              if /^-.*p/;
	$WordMatch = 1                   if /^-.*w/;
	next;
    }
    s/([^\w])/\\$1/g;		# escape funny chars
    $_ = '\b'.$_.'\b' if $WordMatch; # do word matching maybe
    push(@Search,$_);
}
$Matches = 0;
$MatchLevel = 0;    
$Header = '';
$OutHeader = '';
$OutFile = '';

# Scan the files now

foreach $File (@RoloFiles) {
    open(FILE,$File) || do {
	warn "Can't open rolodex file $File because $!\n";
	next;
    };
    while (<FILE>) {
	next if /$RoloComment/;	# until it's changed
	last unless /^(Rolo\w+):\s*(\S.*\S)\s*$/; # configuration?
	eval("\$$1 = ".$2.";");
	warn "$@\n" if $@;
    }
    @RoloData = ();
    $#RoloData = 10;
    $Header = /$RoloComment/ ? '' : $_;
    $MatchLevel = 0;
    while (<FILE>) {
	next if /$RoloComment/;
	$Header .= $_;
	last if /$RoloHeader/;
    }
    if ($OutHeader) {
	$OutHeader =~ s/\s+/ /g;
	($NewHeader = $Header) =~ s/\s+/ /g;
	$Header = '' if (length($NewHeader) == length($OutHeader) &&
		     $NewHeader eq $OutHeader);
    }
    # Now scan the file looking for rolodex entries
    $level = 0;
line:while (<FILE>) {
	next if /$RoloComment/;
	if (/$RoloEntry/) {	# new entry?
	    $lastlevel = $level;
	    $level = eval($RoloLevel);
	    if ($MatchLevel && $MatchLevel < $level) {
		$RoloData[$MatchLevel] .= $_;
	    } else {
		&ShowLevel($MatchLevel) if $MatchLevel >= $level;
		$RoloData[$level] = $_;
	    }
	} else {
	    $RoloData[$level] .= $_;
	}
	next if $MatchLevel;
	foreach $pat (@Search) {
	    if (/$pat/i) {
		if ($Entries == 0 && $FileNames) {
		    print $File."\n";
		    last line;
		}
		$MatchLevel = $level;
	    }
	}
    }
    &ShowLevel($MatchLevel) if $MatchLevel;
    close FILE;
}
printf "%d matches\n", $Matches if $CountMatches;
exit;

sub ShowLevel {
    local($level) = $_[0];
    if ($FileNames && $OutFile ne $File) {
	print ">>>File: $File <<<\n";
	$OutFile = $File;
    }
    if ($Headers && $Header && $Entries) {
	print $Header;
	$OutHeader = $Header;
	$Header = '';	# we only do this once per file
    }
    for ($i = $LevelTree ? 1 : $level; $i <= $level; $i++) {
	print $RoloData[$i] if $Entries;
	$RoloData[$i] = '';
    }
    $MatchLevel = '';
    $Matches++;
}

============================= cut here ===================================
============================================================================
			      GROUP ROLODEX
   <Last Name>, <First Name>   W:<Work #>  H:<Home #>	P:<Pager #>
			       F:<Fax #>   M:<Modem #>	C:<Cellular #>
                               E:<email #> X:<ext #>    R:<Other-radio #>
       <Address>	   <Miscellaneous Info, Key Words>
============================================================================
* Vendors
** ABC, Inc (Bogus Sample Vendor)	W:800-555-1212
	1234 Somestreet Way, Suite 13
	Somecity, ST  99999
	Product: Dingus with Bells & Whistles
*** Sales Department
**** Loser, Ima		W:800-555-1213	Salesman
**** Isuzi, Joe		W:800-555-1214	Salesman
*** Technical Support	W:800-555-2100	F:800-555-2101
**** Idunno, Gee	W:800-555-1215	System Engineer
**** Whatzat, Hank	W:800-555-1216	Product Engineer
** CACI, Inc.           W:619-457-9681
        3344 N. Torrey Pines Court, La Jolla, CA  92037
        Simscript (Simulation Software)
** Cabletron
	Ethernet, Networking
** Cisco		W:800-553-NETS(6387), -2447
	Gateways, Routers, Terminal Servers
** Clearpoint           W:818-706-1745  F:818-706-0503
        5655 Linder Canyon Rd., Bldg 700, Westlake Village, CA 91362
        Memory enhancements
** Dataram		W:800-822-0071
	Memory upgrades for Suns, SPARCs
** Fox Software         W:419-874-0162
        FoxBase: Relational database available on Unix, Mac's, & PC's.
** International Automations Assoc. (IAA)
	W:213-326-6008	F:213-326-6047
	3246 Sepulveda Blvd, #209, Torrance, CA  90505
	Reseller for 3Com Ethernet adapters
** Illinois Computer Cable Inc.         W:800-326-2320
** Mac Warehouse        W:800-255-6227
** MacConnection        W:800-622-5472
** MacZone              W:800-248-0800
** NeXT, Inc.           W:415-366-0900
** Novell/Kinetics
	2180 Fortune Dr., San Jose, CA 95131
	Networking for PC's and Mac's
** Oracle		W:916-641-5566
	Incredibly expensive, but highly functional databases
** Parity		W:408-378-1000
	Memory upgrades for Sun
** Proteon		W:508-898-3100
	2 Technology Drive, Westborough, MA 01581
	Routers
** R-Squared (R^2)	W:714-837-0960
	Disk drives & Enclosures (SCSI, SMD)
** SCO  Santa Cruz Operations, Inc.     W: 408-425-7222
        SCO Unix/386, FoxBase+ for Unix
** Technology Works, Inc.       W:800-622-2210
        4030 Braker Lane West, Suite 350, Austin, TX  78759
        Memory (SIMMs)