EMDL Manual,
Version 0.7.0

CONTENTS

Executive Summary

At its simplest, EMDL is a quick and easy way to configure UMENU menu hierarchies.

EMDL stands for Easy Menu Definition Language. It's a quick and easy way to define, modify and maintain an entire menu system. It is implemented as an outline.

Currently we provide an EMDL parser program, called emdlparser.pl, to parse EMDL and convert it to UMENU .mnu menu definition files. It would not be difficult to provide conversion to other menu systems, such as IceWM.

The emdlparser.pl program requires a tool called Node.pm, which is available at http://www.troubleshooters.com/projects/Node/index.htm. Install it as per its straightforward instructions. Basically, you just untar it into a directory, and remember that directory.

The emdlparser.pl program is all that is needed to configure a UMENU menu system using EMDL, assuming the user is conversant with various copy and delete commands in Linux, as well as Perl's -I option. To make life easier for those who just want to use this tool without all the sysadmin, we provide several wrapper scripts. The top wrapper script, emdlinit.sh, defines the locations of several files and directories. The user must set those locations. Once that is done, most EMDL tasks can be done with simple commands front ended by emdlinit.sh and other simple scripts.

EMDL authoring is simple, especially if you start out with a known good EMDL file, such as the a.emdl file that ships with the EMDL distribution. It is a simple outline. If you want the ultimate authoring speed, consider using the VimOutliner outline processor, available at http://www.vimoutliner.org.

This version of the EMDL package adds facilities for specifying environment variables, multiple command lines, and a UMENU to EMDL converter.

License

The programs, scripts and documentation shipped with the EMDL package are copyright (C) 2003-2004 by Steve Litt, all rights reserved.

All programs and scripts shipped with the EMDL package are licensed with the GNU General Public License, version 2. It is available at http://www.gnu.org/licenses/gpl.txt. Please note that we offer NO WARRANTY with the EMDL program, so USE IT AT YOUR OWN RISK.

Installation

Installing the EMDL package is simple. First install the Node.pm package, available at http://www.troubleshooters.com/projects/Node. Basically, just untar the Node.pm tarball into a directory, and remember its location.

Next, download and untar the EMDL package. It untars into a directory called emdl beneath the current directory. What many people with single user computers do is to go to their home directory, untar the tarball, and then rename the emdl subdirectory to .emdl, so that the path to the EMDL programs is /home/username/.emdl.

Now you configure EMDL.

Configuration

Edit the emdlinit.sh program. At the top of this script, seven environment variables are defined:
  1. Directory containing the emdlparser.pl program (EMDL_DIRECTORY)
  2. Top level UMENU directory (UMENU_DIRECTORY)
  3. Directory containing the Node.pm tool (NODE_DIRECTORY)
  4. The EMDL configuration file (EMDL_CONFIG). Typically this is emdl.cfg located in $EMDL_DIRECTORY.
  5. Directory containing the UMENU menu definition files (UMENU_MENUDIR)
  6. Directory containing the UMENU programs (UMENU_PROGRAMDIR)
  7. Directory in which to temporarily store UMENU menu definition files (EMDL_TEMP)
Edit these seven environment variables to reflect the file and directory locations on your system. When possible, define variables in terms of $EMDL_DIRECTORY, $UMENU_DIRECTORY, $NODE_DIRECTORY, OR $HOME. However, it is important that directories once evaluated, all directories are either absolute or relative to $HOME. Otherwise, the EMDL programs and scripts will not work without user intervention.

Note that all these environment variables must point to files and directories readable by the EMDL user. The $EMDL_TEMP directory must be writeable by the EMDL user, as must the $UMENU_MENUDIR directory. The $UMENU_DIRECTORY, $UMENU_MENUDIR, and $UMENU_PROGRAMDIR directories must be readable by the user of the UMENU program.

In addition, you must edit the emdl.cnf file. It should contain a line like this:
nodedir=/directory/containing/NodeDotPm
You change the directory after the equal sign to whatever directory contains the Node.pm file.

Finally, copy the emdlinit.sh file to a place on the path.

First Use

Verify that there is no a menu currently in UMENU. You can do that by performing the following command within the UMENU program directory:
./umenu.pl a
If there is an existing a menu, move a*.mnu away from the UMENU's menu directory. The purpose of doing this is to verify that the a menu is created by EMDL, and not simply left over from an earlier time.

Run the following command as a regular user.
emdlinit.sh ./pumpprimer_a.sh
Verify that you now have an a menu, and it corresponds to the structure of the a.emdl that ships with the EMDL package. If so, the basics are working.

If the basics do not work, it's time to troubleshoot.

Compiling and Transferring EMDL Within UMENU

By far the most memorable and user friendly way to reconfigure menus is to do so within UMENU itself. Like every other program, the EMDL scripts are easier to remember and run out of a menu. For that reason, the EMDL distribution has provisions for running EMDL environment aware UMENU instances. Here's how you do it:
emdlinit.sh ./emdlrunmenu.sh a
Then press C for Configuration, and U for Umenu. Then press M for "Maintain a.emdl file" and a.emdl is brought up in the gvim editor. Once you've made the necessary changes, you can go back to UMENU and press C for "Compile a.emdl file" and look for errors or warnings. If there are none, press T for "Transfer a*.mnu files", and UMENU is updated. The next time you select a choice or go back to a previous menu or go to the top level (by pressing the equal sign), UMENU reflects those updates.

There are other ways of invoking an EMDL aware UMENU. On my box I have a shellscript called mmm that switches to the UMENU program directory and then runs ./umenu.pl with whatever arguments I gave mmm. I could do this:
emdlinit.sh mmm a
Or I could modify mmm like this:

#!/bin/sh
emdlinit.sh ./emdlrunmenu.sh $1 $2 $3 $4 $5 $6

In that case, mmm itself invokes an EMDL aware UMENU.

Once again, the value of an EMDL aware UMENU is that you can edit compile and transfer EMDL files from within the UMENU environment, without setting any specific directories within UMENU. This makes it great for distribution to various shops differing in directory structure.

Troubleshooting

This section discusses several tests to narrow down the root cause scope.

Test emdlparser.pl alone

From within the EMDL distribution directory, try this command:
cat ./a.emdl | ./emdlparser.pl
If the preceding runs, tells you there are no errors and no warnings, and produces a bunch of a*.mnu files in the current directory, you've proven the following:
  1. a.emdl exists and is a well structured EMDL file.
  2. The emdl.cnf file in the EMDL distribution directory is correctly configured.
  3. Node.pm is correctly installed in directory defined in emdl.cnf.
  4. emdlparser.pl works properly.
  5. The problem's root cause resides either in the shellscripts, or UMENU, or user permissions, or the copy of emdlinit.sh that exists on the path, or the command you executed.
If the preceding yields an @INC error as follows you have a Node.pm problem:

[slitt@mydesk emdl]$ cat ./a.emdl | ./emdlparser.pl
Seeking config file ./emdl.cnf.
Using config file ./emdl.cnf.
Can't locate Node.pm in @INC (@INC contains: /directory/containing/NodeDotPm
 /usr/lib/perl5/5.8.1/i386-linux-thread-multi
/usr/lib/perl5/5.8.1
/usr/lib/perl5/site_perl/5.8.1/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.1 /usr/lib/perl5/site_perl
/usr/lib/perl5/vendor_perl/5.8.1/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.1
/usr/lib/perl5/vendor_perl/5.8.0
/usr/lib/perl5/vendor_perl .) at ./emdlparser.pl line 706.
[slitt@mydesk emdl]$

If the program bombs in a manner similar to the preceding:
If the program runs but issues warnings or errors you have an a.emdl problem:
[slitt@mydesk emdl]$ cat ./a.emdl | ./emdlparser.pl
Seeking config file ./emdl.cnf.
Using config file ./emdl.cnf.
Multiple indent at line 753, "C: ksirtet", terminating.
[slitt@mydesk emdl]$

The preceding is emdlparser.pl gracefully handling an error in a.emdl, in this case there's a missing param line for the command choice "ksirtet" on line 753. The missing "param" line means that there's a double indent, which is illegal in a menu.

If the program bombs in other ways, you might need to actually debug the source code.

Testing the emdlinit.sh script

Once emdlparser.pl works correctly, you've isolated the problem's root cause to the scripts, the command you ran, or arcane stuff like permissions. Try the following commands:
The proceding should produce results similar to the following, with your own directories indicated:

[slitt@mydesk slitt]$ emdlinit.sh | env | grep EMDL
EMDL_DIRECTORY=/home/slitt/.emdl
EMDL_TEMP=/home/slitt/.emdl/temp
[slitt@mydesk slitt]$

[slitt@mydesk slitt]$ emdlinit.sh | env | grep UMENU
UMENU_DIRECTORY=/home/slitt/.umenu
UMENU_MENUDIR=/home/slitt/.umenu/menudir
UMENU_PROGRAMDIR=/home/slitt/.umenu/program
[slitt@mydesk slitt]$

[slitt@mydesk slitt]$ emdlinit.sh | env | grep NODE 
NODE_DIRECTORY=/data/scripts/Node
[slitt@mydesk slitt]$


Be sure that every indicated environment variable is accurate, because if it is not, then EMDL will not work without serious human intervention.

Running a Test Compile

Perform the following command from within a directory not associated with EMDL, UMENU or Node.pm:
emdlinit.sh ./emdlcompile.sh ./a.emdl
If the preceding succeeds, the resulting screen looks like this:

[slitt@mydesk slitt]$ emdlinit.sh ./emdlcompile.sh ./a.emdl
Seeking config file /home/slitt/.emdl/emdl.cfg.
There are no errors.


There are no warnings.
[slitt@mydesk slitt]$

Additionally, the temp directory ($EMDL_TEMP) should now be full of a*.mnu files produced just seconds ago.

If this does not happen, troubleshoot. Read all onscreen messages and follow up. Verify that the temp directory is writeable by you. Reverify that the tests for emdlparser.pl and emdlinit.sh worked correctly.

Running a Test Transfer

You might wonder why the compile step doesn't also transfer the files to the UMENU menu directory. The answer is simple enough. If the compile fails, you do not want to overwrite the last correct .mnu files.

Assuming the compile succeeded, to transfer the newly created .mnu files to the UMENU menu directory, perform the following command:
emdlinit.sh ./emdltransfer.sh a
The preceding tells it to transfer all .mnu files beginning with the letter a out of $EMDL_TEMP and into $UMENU_MENUDIR.

If the preceding succeeds, the resulting screen looks like this:

[slitt@mydesk emdl]$ emdlinit.sh ./emdltransfer.sh a
[slitt@mydesk emdl]$

If there are no matching .mnu files in the temp directory, it will tell you there are "no files to transfer":


[slitt@mydesk emdl]$ emdlinit.sh ./emdltransfer.sh z
No files to transfer.
[slitt@mydesk emdl]$

In the preceding, either the previous compile failed, or you're using the wrong letter argument to emdltransfer.sh. Investigate.

Once both emdlcompile.sh and emdltransfer.sh work, the pump primer scripts should work.

Compiling and Transferring within the UMENU Environment

Last but not least, the compile and transfer can be performed from within the UMENU environment. This has the advantage of being more user friendly and easier to remember. However, in order to have UMENU recognize EMDL's environment variables, it must be run as an argument to the emdlinit.sh script:

emdlinit.sh ./emdlrunmenu.sh a
The preceding runs UMENU with awareness of all the EMDL environment variables, meaning that those variables can be in the EMDL file and will be respected. This enables the menu system to be self-compiling and self editing.

If the preceding command doesn't work, make sure the a*.mnu files are in the right place. Perform this command:
emdlinit.sh ./pumpprimer_a.sh
Then try the emdlrunmenu.sh command again. If it still doesn't work, run UMENU manually. Switch to the UMENU program directory and run the following command:
./umenu.pl a
If the preceding works, exploit the differences between it and the emdlrunmenu.sh command. If the preceding does not work, troubleshoot UMENU.

Note that there are other EMDL aware ways to run UMENU. Many sites have scripts on the path to switch to the UMENU program directory and then run umenu.pl. Such scripts can be run straight from emdlinit.pl, without the need for emdlrunmenu.pl.

EMDL Grammar


EMDL is an outline that defines a menu system. This works out well because both outlines and menu systems are hierarchies.

Blank lines are ignored in EMDL. Likewise, lines beginning with a pound sign (#) are ignored. There are four types of lines in EMDL:
  1. Menu choice lines
  2. Command choice lines
  3. Parameter head lines
  4. Parameter lines
Menu choice lines represent choices. Specifically, they represent choices that will, instead of executing a command, bring up a submenu. Menu choice lines contain three successive colons (:::), and have the following structure:
menu choice text ::: menu title text
The menu choice text is the text that appears on the original menu. The menu title text appears as the title of the submenu.

The very first nonblank, non comment line of a well formed EMDL file must be a special menu choice line whose menu choice text contains a single letter. That letter represents the prefix common to all generated *.mnu files. The menu title text represents the title of the main menu. This special menu choice line is not indented.

That line is followed by a  series of menu choice lines or command choice lines that appear on the main menu. These are also not indented. Any of these top level lines that are menu choice lines can have choices indented underneath them -- either menu choice lines, command choice lines, or a combination.

Line type
How defined
Syntax
Allowable parents
Allowable children
Function
Menu choice line
A triple colon
menu choice text ::: menu title text
Only other menu choice lines or no parent at all
  • menu choice lines
  • command choice lines
Describes a submenu to be run upon selection of this choice.
Parameter head
The word "param" or "params" alone on the line (can have leading and trailing whitespace)
^\s*params?\s*$
Only command choice lines
Only parameters
To group all parameters
Parameter
A line whose parent is a parameter head
^\s*(.).\s*(.*)
A single character followed by an irrelevant single character followed by optional space followed by the value of the parameter
Only parameter heads
None. Parameters cannot have children.
To describe a property of the command choice line that is its grandfather.
Command choice line
A line that isn't a menu choice line, a parameter head or a parameter
No specific syntax, although a leading carat (^) indicates "exit this menu level".
Only menu choice lines or no parent at all
Only a single parameter head
Describes a command to be run upon selection of this choice.

Menu Choice Lines


These describe a submenu and have three consecutive colons separating the text to appear on the parent menu from the text to appear in the title of the submenu. Valid parents are other menu choice lines or no parent. Valid children are other menu choice lines or command choice lines.

Command Choice Lines

These describe a command to be run when the user chooses this choice. The text appearing on the menu is the same as the text of this line. Different menus differ, but UMENU deduces the menu letter (the keystroke initiating this choice) to be the first uppercase character on the line. This is also true of menu choice lines.

The properties of the command, and how it is run, are contained in parameter lines subordinate to the parameter head line subordinate to this choice.

Command choice lines have no specific grammar, but UMENU assumes that any command choice beginning with a carat (^) indicates the need to "go up one level".

Parameter Head Lines

Parameter head lines consist of the single word "param" or "params" on a line, with or without leading and trailing whitespace, case insensitive. In other words:
/^\s*params?\s*/i
The sole purpose of a parameter head line is to act as the parent of parameters. The reason parameters are not directly below a command choice line is because there may come a time when other types of properties might be needed to fully describe a command choice line. Also, in the future, it is possible that menu choice items might have parameters, in which case the parameter head would be needed to differentiate between parameters and subordinate choices. But that's all in the future.

Today, parameter heads' only legal parent is a command choice line, and their only legal children are parameters. Note that a single command choice line can contain only one parameter head line.

Parameters

Parameters almost completely describe the command choice line that is their grandfather. Each parameter line is a key value pair, with the key being the first nonblank character, and the value being the first nonblank after the character after the first nonblank on the line. In other words:
my $line = /^\s*(.).\s*(.*)/;
my $key = $1;
my $value = $2;
Traditionally the second character is a colon, because that's very human readable, but that's just a tradition. Here is a list of traditional keys. These keys are used in UMENU:
Key
Meaning
Comments


L
Keystroke that will invoke this choice
Programs like UMENU do not require an L parameter, because they deduce the menu letter from the choice text.


C
Command that will be executed upon selection of this choice.
If there are multiple such command parameters, they are concatinated with spaces in between. This facilitates things like pipes. It also allows the EMDL file to substitute for simple scripts. So if they should truly be separate commands, they each should end in semicolons.


D
Directory to change to before executing this command.
Once again, this enables behavior which would otherwise require a simple script.


P
Directories to add to the FRONT of the path before running the command.
This allows easy execution of commands without adding a fully qualified filename, and also without tampering with the environment shared by all programs.

E
An environment variable to be set before running the command. Syntax is:
E: VAR=VALUE
There can be many E lines for a single command choice line. Once again, this the user to run complex commands directly from the menu program, without resorting to simple scripts to set up environment variables.


S
Stop the menu program from repainting after completion of the command.
This allows the user to view any messages to stdout. The user must press a key in order to repaint the menu. Without the S parameter, the menu repaints immediately upon completion of the command.

B
Run the program in the background.
The way this is actually accomplished is menu program specific.

I
Icon to represent this choice on the menu.
This is not used in UMENU, but is provided so that EMDL can be used with graphical menus.

Prompted Argument Substitution

Prompted argument substitution is the capability of some menu programs to request the user input certain command parameters at runtime. It is not supported directly by EMDL. However, in any menu program, such as UMENU, whose prompted argument substitution is defined entirely within the choice text, the choice text can simply be passed through to the menu program. However, this is one area where EMDL cannot portably create equivalent menus in different menu programs.

File Manifest

Program Syntax

The following table shows the syntax used to invoke all the programs in this package. Note that all the scripts must be used as arguments of emdlinit.sh, which sets all necessary environment variables.
Program
Syntax
emdlparser.pl cat emdlfile | ./emdlparser.pl
emdlviewer.pl cat emdlfile | ./emdlviewer.pl
findmults.pl cat emdlfile | ./findmults.pl
umenu2emdl.pl
./umenu2emdl.pl menuletter
emdlinit.sh
emdlinit.sh      program_to_run      arguments_for_that_program
emdlcompile.sh emdlinit.sh      ./emdlcompile.sh     emdlfile
emdltransfer.sh emdlinit.sh     ./emdltransfer.sh     menuletter
(transferred .mnu files will all begin with menuletter)
pumpprimer_a.sh emdlinit.sh     ./pumpprimer_a.sh
emdl_pumpprimer_general.sh emdlinit.sh     ./emdl_pumpprimer_general.sh     emdlfile     menuletter
emdlrunmenu.sh emdlinit.sh     ./emdlrunmenu.sh     menuletter
emdl_umenu2emdl.sh
emdlinit.sh     ./emdl_umenu2emdl.sh     menuletter
emdlparser_test.sh emdlinit.sh     ./emdlparser_test.sh     emdlfile

Changes

Added Features

This is the second version of an EMDL to UMENU converter. This version adds two sorely needed capabilities:
  • Define environment variables before running command
  • Multiple commands in command choice
  • A UMENU .mnu to EMDL converter
  • The text README has been replaced by README.html (this file)


  • The UMENU to EMDL converter is a long sought feature enabling you to create your first EMDL file based on your long-tweaked UMENU .mnu files, saving you hours of work in implementing EMDL.

    Changes to Program

    This is the second version of an EMDL to UMENU converter. The first version (0.5.0) was called emdl2umenu.pl. It worked perfectly, but was unbelieveably complex, to the point of unmaintainability. The current emdlparser.pl is a complete rewrite of that old program. Regression tests proved that this new version works identically to the old version under a wide variety of circumstances. The author has used the new version for several months with absolutely no problems.

    The new program is built around the Node.pm tool, resulting in a much simpler and maintainable program. The only downside is the program must know the location of Node.pm tool. This is accomplished by the emdl.cnf file, which contains a line like this:
    nodedir=/data/tools/Node
    The preceding tells emdlparser.pl where to find Node.pm.

    The advantages of the new program are:
    Another plus is the fact that the new version runs 7 times faster than the old one, because all operations are done in memory on simple, pointer oriented data structures provided by Node.pm.

    Other Documentation

    See also the EMDL project's web page at http://www.troubleshooters.com/projects/emdl/index.htm.