[comp.sources.amiga] v91i074: Browser 1.7 - a programmer's "Workbench", Part01/01

amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (03/25/91)

Submitted-by: peter@taronga.hackercorp.com
Posting-number: Volume 91, Issue 074
Archive-name: utilities/browser-1.7/part01

Well, 1.4 is now 2.0, and it's almost here. So this is probably going to
be the last revision of Browser. I'm now using Workbench 2.0 on a daily
basis, and I find I'm not using Browser that much. It remains faster than
workbench and cleaner for quick jobs, but not enough for me to spend much
time on it. However, lots of people remain in a 1.3 environment, and with
the new release of the Aztec C compiler (5.0d) I've been able to clear up
several outstanding bugs in Browser. Thus, the new release.

	What Browser does allow you to do, easily and conveniently, is to
move, copy, rename, and delete files and directories. It will also let you
execute either Workbench or CLI programs, either directly by double-
clicking them or by selecting them from a menu. By combining these you can
set up a complete operating environment that will, to a large extent,
replace both Workbench and the CLI.

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  PatMatch.c browser.doc fonts.h goodies.readme menu.c
#   menu.h vollist.c
# Wrapped by tadguy@ab20 on Mon Mar 25 10:44:32 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'PatMatch.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'PatMatch.c'\"
else
echo shar: Extracting \"'PatMatch.c'\" \(5837 characters\)
sed "s/^X//" >'PatMatch.c' <<'END_OF_FILE'
X/* PatMatch.c - Implements AmigaDos Regular Expression Pattern Matching.
X**
X**  This program will test whether a string is an AmigaDos  regular expression
X**  It may be used to implement wild expressions such as:
X**
X**    "copy #?.c to <dir>" to copy any file ending in .c
X**
X**  The program has two entry points: CmplPat, and Match.
X**
X**    CmplPat - takes a pattern and returns an auxilliary integer vector
X**              which is used by Match.  The pattern is not modified in
X**              any way.  CmplPat returns 1 if no errors were detected
X**              while compiling the pattern; otherwise it returns 0;
X**
X**    Match   - takes the pattern, the auxilliary vector, and the string
X**              to be matched.  It returns 1 if the string matches the
X**              pattern; otherwise it returns 0;
X**
X**  Translated from BCPL by:
X**              Jeff Lydiatt
X**              Richmond B.C. Canada
X**              16 May 1986.
X**
X**  Source: "A Compact Function for Regular Expression Pattern Matching",
X**           Software - Practice and Experience, September 1979.
X**
X**  Useage:
X**     To test if "file.c" matches the regular expression "#?.c"
X**     char *Pat = "#?.c";
X**     char *Str = "file.c";
X**     WORD Aux[128];
X**
X**     if ( CmplPat( Pat, Aux ) == 0 )
X**        {
X**           printf("Bad Wildcard Expression\n");
X**           exit(1);
X**        }
X**     if ( Match( Pat, Aux, Str ) == 1 )
X**        printf("String matches the pattern\n");
X**     else
X**        printf("String does NOT match the pattern\n");
X**/
X
X/*--- Included files ----*/
X
X#include <stdio.h>
X#include <exec/types.h>
X#include <ctype.h>
X
X#define  EOS '\0'
X
X/*--- Global Variables  ---*/
X
Xstatic char     Ch;      /* The current character in Pattern */
Xstatic char     *Pat;    /* Pointer to the Pattern */
Xstatic WORD     *Aux;    /* Pointer to returned auxilliary vector */
Xstatic int      PatP;    /* Current position in Pat */
Xstatic int      Patlen;  /* strlen(pat) */
Xstatic BOOL     Errflag; /* TRUE if error */
Xstatic WORD     *Work;   /* Pointer to Active work area */
Xstatic int      Wp;      /* Current position in work */
Xstatic BOOL     Succflag;/* True if "str" matches "pat" */
X
X/*----------------------------------------------------------------*/
X/*                   The Interpreter                              */
X/*----------------------------------------------------------------*/
X
Xstatic void Put(int N)
X{
X   register WORD *ip;
X   register WORD *to;
X
X   if ( N == 0 )
X      Succflag = TRUE;
X   else
X      {
X	for ( ip = &Work[ 1 ], to = &Work[ Wp ]; ip <= to; ip++)
X	   if ( *ip == N )
X	      return;
X	Work[ ++Wp ] = N;
X      }
X}
X
Xint Match( char *Pat, WORD *Aux, char *Str )
X{
X   static WORD W[ 128 ];
X   int  S = 0;
X   int  I, N, Q, P, Strlength;
X   char K;
X   int  strlen();
X   void Put();
X
X   Work = W;
X   Wp = 0;
X   Succflag = FALSE;
X   Strlength = strlen( Str );
X   Put( 1 );
X
X   if ( Aux[ 0 ] != 0 )
X      Put( Aux[ 0 ] );
X
X   for(;;)
X      {
X        /* First complete the closure */
X        for( N=1; N <= Wp; N++ )
X          {
X	     P = Work[ N ];
X	     K = Pat[ P-1 ];
X	     Q = Aux[ P ];
X	     switch( K )
X	   	{
X		  case '#': Put( P + 1 );
X		  case '%': Put( Q );
X		  default : break;
X		  case '(':
X		  case '|': Put( P + 1);
X			    if ( Q != 0 )
X			       Put( Q );
X		}
X	   }
X
X	if ( S >= Strlength )
X	   return Succflag;
X	if ( Wp == 0 )
X	   return FALSE;
X	Ch = Str[ S++ ];
X
X	/* Now deal with the match items */
X
X	N = Wp;
X	Wp = 0;
X	Succflag = FALSE;
X
X	for ( I = 1; I <= N; I++)
X	  {
X	     P = Work[ I ];
X	     K = Pat[ P - 1 ];
X	     switch( K )
X	       {
X		 case '#':
X		 case '|':
X		 case '%':
X		 case '(': break;
X		 case '\'': K = Pat[ P ];
X		 default : if ( _toupper( Ch ) != _toupper( K ) )
X			      break;
X		 case '?': /* Successful match */
X		 	   Put ( Aux[ P ] );
X		} /* End Switch */
X	  } /* End For I */
X     } /* End for(;;) */
X}
X
X
X/*----------------------------------------------------------------*/
X/*                     The Compiler                               */
X/*----------------------------------------------------------------*/
X
Xstatic void  Rch(void) /* Read next character from Pat */
X{
X   if ( PatP >= Patlen )
X      Ch = EOS;
X   else
X      Ch = Pat[ PatP++ ];
X}
X
Xstatic void Nextitem(void) /* Get next char from Pat; recognize the ' escape char */
X{
X   if ( Ch == '\'' )
X      Rch();
X   Rch();
X}
X
Xstatic void Setexits( int List, int Val )
X{
X   int A;
X
X   do
X     {
X	A = Aux[ List ];
X	Aux[ List ] = Val;
X	List = A;
X     }
X	while ( List != 0 );
X}
X
Xstatic int Join( int A, int B )
X{
X    int T = A;
X
X    if ( A == 0 )
X	return B;
X    while ( Aux[ A ] != 0 )
X	A = Aux[ A ];
X    Aux[ A ] = B;
X    return T;
X}
X
Xstatic int Prim(void)      /* Parse a Prim symbol */
X{
X   int   A = PatP;
X   char Op = Ch;
X   int  Exp();
X   void Setexits(), Nextitem();
X
X   Nextitem();
X   switch( Op )
X     {
X        case EOS:
X        case ')':
X        case '|': Errflag = TRUE;
X        default : return A;
X        case '#': Setexits( Prim(), A ); return A;
X        case '(': A = Exp( A );
X		  if ( Ch != ')' )
X		    {
X			Errflag = TRUE;
X		    }
X		  Nextitem();
X		  return A;
X     }
X}
X
Xstatic int Exp( int AltP )    /* Parse an expression */
X{
X   int Exits = 0;
X   int A;
X   int Prim(), Exits(), Join();
X   void Nextitem(), Setexits();
X
X   for (;;)
X	{
X	   A = Prim();
X	   if ( Ch == '|' || Ch == ')' || Ch == EOS )
X	      {
X		Exits = Join( Exits, A );
X		if ( Ch != '|' )
X		   return Exits;
X		Aux[ AltP ] = PatP;
X		AltP = PatP;
X		Nextitem();
X	      }
X	   else
X	      Setexits( A, PatP );
X	}
X}
X
Xint CmplPat( char *Pattern, WORD *CmplPattern)
X{
X   int i, strlen();
X   void Rch(), Setexits();
X
X   Pat = Pattern;
X   Aux = CmplPattern;
X   PatP = 0;
X   Patlen = strlen( Pat );
X   Errflag = FALSE;
X
X   for ( i = 0; i <= Patlen; i++ )
X      Aux[ i ] = 0;
X   Rch();
X   Setexits( Exp(0), 0 );
X   return (!Errflag);
X}
END_OF_FILE
if test 5837 -ne `wc -c <'PatMatch.c'`; then
    echo shar: \"'PatMatch.c'\" unpacked with wrong size!
fi
# end of 'PatMatch.c'
fi
if test -f 'browser.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'browser.doc'\"
else
echo shar: Extracting \"'browser.doc'\" \(12580 characters\)
sed "s/^X//" >'browser.doc' <<'END_OF_FILE'
XBrowser -- a programmer's "Workbench". Release 1.7
X
X) 1990 Peter da Silva
X
XIntroduction
X
X	In earlier versions of Browser, I opened this document with the
Xsomewhat confident comment:
X
X	The Amiga "Workbench" has some serious deficiencies as
X	a working environment. The most important one is that
X	it doesn't let you operate on just any file (this is
X	rumored to be fixed in 1.4, by the way), but there are
X	others. It's designed to be easy to learn and use, but
X	it just isn't very powerful.
X
XWell, 1.4 is now 2.0, and it's almost here. So this is probably going to
Xbe the last revision of Browser. I'm now using Workbench 2.0 on a daily
Xbasis, and I find I'm not using Browser that much. It remains faster than
Xworkbench and cleaner for quick jobs, but not enough for me to spend much
Xtime on it. However, lots of people remain in a 1.3 environment, and with
Xthe new release of the Aztec C compiler (5.0d) I've been able to clear up
Xseveral outstanding bugs in Browser. Thus, the new release.
X
X	This program is an attempt to deal with limitations in earlier
Xversions of the Workbench. It runs under all versions of AmigaOS, including
X2.0, but is expected to be most useful for people running 1.3 and earlier.
XIt is not a complete replacement for Workbench, nor is it intended to be.
XThere is no attempt to support icons, and there are no disk-oriented
Xfunctions (formatting, copying, etc...).
X
X	What Browser does allow you to do, easily and conveniently, is to
Xmove, copy, rename, and delete files and directories. It will also let you
Xexecute either Workbench or CLI programs, either directly by double-
Xclicking them or by selecting them from a menu. By combining these you can
Xset up a complete operating environment that will, to a large extent,
Xreplace both Workbench and the CLI.
X
X	Browser presents you with a set of windows, representing directories,
Xwith all the files and directories within each listed in alphabetical
Xorder. Directories, displayed in color 2 (red/orange), are listed first,
Xfollowed by the files. Selected files are displayed in inverse video.
X
XSelecting Files
X
X	You can select individual files three ways. First, just click on
Xa file name. This will select that file and deselect all others. If you
Xhold down the shift key when you click on the file, it will be selected
Xwithout deselecting other files. This way you can build a list of files
Xto operate on. So far this is just like Workbench, but if you click a
Xselected file while holding down the shift key, it will be deselected
Xwithout affecting other selected files. This lets you take back mistakes.
X
X	Finally, you can use the menu items "Sel All" and "Sel Match" to
Xselect a group of files at once. "Sel All" will select all files in the
Xactive window. "Sel Match" will allow you to enter a pattern and then
Xselect only files matching that pattern in the active window. These
Xnormally act as toggles... if you have any selected files in the active
Xwindow they will be deselected if they match.
X
XActions
X
X	There are, again, three ways to manipulate selected files. First,
Xyou can drag a file or selected files to another window by holding down the
Xleft mouse button while you move the mouse. When you release the button,
XBrowser will attempt to move the files to the location you indicate. This
Xis just like the Workbench.
X
X	Secondly, double-clicking a file will open it. If it's a directory,
Xit will be opened and files in it will be displayed. If it's a program
Xwith an accompanying '.info' file, it will be launched as a Workbench task.
XThis will also work with Projects, if the accompanying .info file specifies
Xa tool. Finally, Browser will ask you if you want to launch it as a CLI
Xprogram.
X
X	Any other files selected will be passed to the new program, either
Xon the CLI command line or in the Workbench Args structure. This is the
Xnormal Workbench shift-double-click method.
X
X	Third, you can select a menu item.
X
XMenus
X
X	There are two main Browser menus. The first, "Browser", relates to
Xthe browser environment itself. The second, "Actions", relates to the files
Xand directories displayed in Browser's windows. Menu items act either on
Xselected files or on the currently active window. There are additional
Xmenus (called Tools Menus) that can be set up by the user.
X
XBrowser Menu
X
X	Open
X
X		This entry is equivalent to double-clicking the selected
X	file. It is included for consistency with Workbench. Strictly
X	speaking it should be in the Actions menu, but it seems to fit
X	here better.
X
X	Close
X
X		This entry is equivalent to clicking the active window's
X	close gadget.  Again, it's included for consistency with the
X	Workbench.
X
X	Rescan
X
X		This entry requests Browser to re-scan the directory displayed
X	in the active window. This is equivalent to, but a lot more convenient
X	than, closing and re-opening the window. I suppose I could poll the
X	disk for these, but if you use floppies much this becomes slightly
X	inconvenient.
X
X	Show >
X
X		This entry selects whether files, files and sizes, or full
X	file information is displayed for the current window. It has been
X	extended since 1.6a and is now provides a full set of options.
X
X	Sel All
X
X		This selects all files in the active window. Actually, it
X	toggles the selection of each file. Currently selected files will
X	be deselected.
X
X	Sel Match...
X
X		This is the same as Sel All, except that a pattern may be
X	provided to further restrict the selection.
X
X	Options
X
X		This allows you to modify the global behaviour of Browser
X	to some extent:
X
X		X Toggle Selections
X
X			This affects whether a selection through the menu,
X		or a shift-click, will deselect an already selected file.
X
X		X Move files into subdirectories
X
X			This effects whether you can move files into a
X		subdirectory by dragging them to it and releasing the mouse
X		button when the mouse is over the directory's name. If this
X		is not set you have to open the directory first.
X
X		X Ask before moving into subdirectories
X
X			If you permit files to be moved into subdirectories,
X		this determines if Browser will prompt you beforehand.
X
X	Quit
X
X		This selection closes all windows and terminates Browser.
X
XActions Menu
X
X	The entries in this menu act on files rather than changing the state
Xof Browser.
X
X	WB Tool
X
X		The currently selected file (singular) is entered into the
X	Tools menu as a workbench tool.
X
X	CLI Tool...
X
X		The currently selected file (singular) is entered into the
X	Tools menu as a CLI tool. Browser will pop up a requestor and allow
X	you to add additional arguments.
X
X	Rename...
X
X		The currently selected file (singular) is renamed. Browser
X	will pop up a requestor and allow you to enter the new name.
X
X	Duplicate...
X
X		The currently selected file (singular) is duplicated. Browser
X	will pop up a requestor and allow you to edit the new name (generated
X	by BumpRevision: "file" becomes "copy of file", and so on).
X
X	Make Dir...
X
X		Creates a new directory in the currently active window.
X	Browser will pop up a requestor and allow you to specify the name of
X	the new directory.
X
X	Delete
X
X		Deletes all selected files. This will only delete directories
X	if they happen to be empty.
X
X	Delete All
X
X		Deletes all selected files AND directories, recursively.
X
XTools Menus
X
X	These menus (starting with Tools) are initially empty. They are filled
Xin by selecting "Add * Tool" or from the file "s:browser.inittab". When you
Xselect an entry in these menus they're run (either as workbench or CLI
Xprograms) with all selected files being passed to the program. If you have
Xa choice, you should make a program run under the Workbench... it's MUCH
Xmore reliable.
X
XEnvironment
X
X	Browser can itself be run from either the Workbench or the CLI. The
Xseparate "bgbrowser" program no longer exists... use "runback" or some
Xequivalent program if you want to run browser in a detached mode.
X
X	Browser uses a file, "s:browser.inittab", to pre-load the command
Xmenus. Each line in the file is a separate menu item, made up of 5 fields
Xseparated by semicolons:
X
X	name;environment;command;stack;window
X
X	The first field is the name that is to appear in the menu. This
Xname can be preceded by the name of the menu to insert it in followed by
Xa period. If the menu name is left off, the "Tools" menu will be used.
XFor example, "Applications.Terminal Emulator" will create a menu entry
Xfor "Terminal Emulator" and install it in the "Applications" menu. If the
Xmenu doesn't already exist, it will be created.
X
X	The two environments currently supported are the CLI and the
XWorkbench. Project files (such as AmigaBasic programs) aren't supported
Xthrough the menu system at this time, though they may be at a later date.
XThey do work just fine when you double-click them.
X
X	If our terminal emulator was to be run as a Workbench program, then
Xthis field should contain "Workbench". If it can't run under the Workbench,
Xthen it should contain "CLI". It is better, if possible, to run programs
Xunder the Workbench. It's a cleaner environment, and you don't get extra
Xwindows cluttering up your display.
X
X	The next field is the name of the command. This should contain the
Xfull path name to the program. If the command is a CLI command, additional
Xarguments can be included at this point. The names of any files highlighted
Xwhen this menu is selected will be added to the end. If the command is
Xa Workbench command, this should just be the program name. Highlighted
Xfiles will be passed to the program in the Workbench Args structure.
X
X	The next field is the stack size. It may be left off, and will
Xdefault to 8K.
X
X	The last field is the window. For a CLI command, this is the
Xwindow that will be opened to run the CLI in. For a Workbench command,
Xthis is the ToolWindow that will be passed to it. If it's left off a
Xdefault will be used.
X
X	Applications.Terminal Emulator;Workbench;sys:system/Termulator
X
XLimitations:
X
X	The CLI capability occasionally leaves you in an interactive CLI
Xafter you exit the program. This is caused by using one of the BREAK keys
Xwhile you're in the program. I had to leave this in to get finicky CLI
Xprograms, such as Manx 'Z' editor, to work properly.
X
X	If you're copying a file to disk and you get a disk error,
Xoccasionally browser will appear to ignore disk errors and keep on trying
Xto write. Actually, Browser handles all disk errors that get reported to
Xit. For some reason AmigaDOS doesn't report errors promptly. I suspect
Xthis is related to requesting writes larger than a disk buffer, but I
Xdon't plan on having Browser do anything about this in the near future.
X
X	Browser seems to run just fine with only the standard 4K stack. The
Xminimum environment you need to run browser is:
X
X     libs (dir)
X       icon.library
X
XIf you also want to run CLI programs, you also need:
X
X     c (dir)
X       cd                               EndCLI
X       Failat                           NewCLI
X       Run                              Stack
X     l (dir)
X       Ram-Handler
X
XThese are needed to run the little scripts Browser builds in RAM: when you
Xrun a CLI program.
X
XAuthor:
X
X	Peter da Silva
X
X	U.S.Mail:
X		15770 Bellaire Blvd. #107
X		Houston, TX  77083
X
X	Phone:
X		+1 713 568 0480	(data: Taronga Park)
X		+1 713 274 5180 (work)
X
X	Internet:
X		peter@taronga.hackercorp.com
X	Compuserve:
X		>internet:peter@taronga.hackercorp.com (preferred)
X		70216,1076
X
X	I'm currently getting a new domain name, so if your mail to
Xtaronga.hackercorp.com bounces or is delayed, try taronga.com. If all
Xelse fails I'm currently working at Ferranti International Controls
XCorporation, so try peter@ferranti.com.
X
XDonations:
X
X	If you find this program useful, you may send a donation to the
Xauthor, Peter da Silva. For a donation of thirty dollars or more you will
Xreceive the latest version of Browser (or, if you prefer, the next version
Xif it ever comes out... as I said, 1.7 is likely to be the ultimate release).
X
X	If you have been waiting for the next release and it hasn't got
Xto you, call me or send me email. With this release I'm sending all the
Xfolks who contributed the program and a copy of the source. You should get
Xa copy in the mail soon.
X
XSponsors:
X
X	The following people have donated money, and are willing to have
Xtheir names up in lights. Thanks, folks. In no particular order...
X
X	<CB>
X	Kent and Judy Polk
X	Burkard S. Kr|ger
X	D. Ballinger
X	Ron Harper
X	Steven D. Kapplin
X	David Allen
X	Glen Fullmer
X	Ed Vishoot
X	Jeff Van Epps
X	P. Wright
X	Heinz Mathalm
X	Blaine Gardner
X	Liam Healy
X	Johan Widin
X	D. Ratliff
X	T. J. Pagano
X	J|rgen Klawitter
X	Ulrich Denker
X	Rick Jones
X	Guenther Engelhardt
X
XAnd special thanks to my wife, Stephanie, who talked me into doing this
Xrelease.
END_OF_FILE
if test 12580 -ne `wc -c <'browser.doc'`; then
    echo shar: \"'browser.doc'\" unpacked with wrong size!
fi
# end of 'browser.doc'
fi
if test -f 'fonts.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fonts.h'\"
else
echo shar: Extracting \"'fonts.h'\" \(355 characters\)
sed "s/^X//" >'fonts.h' <<'END_OF_FILE'
X#ifndef FONTS_H
X#define FONTS_H
X#ifndef GRAPHICS_GFXBASE_H
X#include <graphics/gfxbase.h>
X#endif
X#ifndef GRAPHICS_TEXT_H
X#include <graphics/text.h>
X#endif
X
Xextern struct GfxBase *GfxBase;
X
X#define FONTWIDTH (GfxBase->DefaultFont->tf_XSize)
X#define FONTHEIGHT (GfxBase->DefaultFont->tf_YSize)
X#define FONTBASELINE (GfxBase->DefaultFont->tf_Baseline)
X#endif
END_OF_FILE
if test 355 -ne `wc -c <'fonts.h'`; then
    echo shar: \"'fonts.h'\" unpacked with wrong size!
fi
# end of 'fonts.h'
fi
if test -f 'goodies.readme' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'goodies.readme'\"
else
echo shar: Extracting \"'goodies.readme'\" \(451 characters\)
sed "s/^X//" >'goodies.readme' <<'END_OF_FILE'
XThe 'goodies' are sections of the source to Browser that I have previously
Xreleased into the public domain, or that I got from the public domain. I
Xfigure that you folks should benefit from them:
X
X	PatMatch.c	A very nice AmigaDOS-compatible regular expression parser.
X	menu.c	A fairly clean way of dealing with lots of silly menus.
X		menu.h	Needed for menu.c
X		fonts.h	Needed for menu.c
X	vollist.c	An Examine/ExNext type interface to the device list.
END_OF_FILE
if test 451 -ne `wc -c <'goodies.readme'`; then
    echo shar: \"'goodies.readme'\" unpacked with wrong size!
fi
# end of 'goodies.readme'
fi
if test -f 'menu.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'menu.c'\"
else
echo shar: Extracting \"'menu.c'\" \(8280 characters\)
sed "s/^X//" >'menu.c' <<'END_OF_FILE'
X/* easy menus: Copyright 1987 Peter da Silva, all rights reserved.
X *
X *	Permission is granted to use this in any application, so long as
X *	this notice is retained in the source. Permission is granted to
X *	modify the code as you like, so long as this notice (between the
X *	first line beginning "easy menus" and the end of this paragraph,
X *	inclusive) is retained intact.
X *
X * Usage:
X *
X *	#include "menu.h"
X *
X *	struct MenuPtr menudata;
X *	struct MenuPtr *menuptr = &menudata;
X *
X *	init_menus(menuptr);	/ * Just zero menu pointer out * /
X *
X *	for(each menu item) {
X *		add_menu(menuptr, menu, item, subitem, flags);
X *	}
X *
X *  Flags:
X *    SUBITEM_NOCHECK	-- subitem does not require a checkmark.
X *    SUBITEM_SELECTOR	-- subitem is a 1 of n selector, use mutual-exclude.
X *    SUBITEM_TOGGLE	-- subitem is a toggled flag.
X *    SUBITEM_SELECTED	-- defaults to checked.
X *
X *
X *	SetMenuStrip(yourwindow, menuptr->MenuBar);
X *
X *	...
X *
X *	ClearMenuStrip(yourwindow);
X *
X *	trash_menus(menuptr);
X *
X * Notes:
X *
X *	if you don't want any subitems, use zero for the subitem value.
X *
X *	subitem is always initialised as a CHECKIT item with all the other
X *	subitems mutually excluded.
X *
X *	it is intended that the menu be set up with all action items in
X *	the first level of the menu, and all toggles in the second level...
X *	this is a piece of blatant authoritarianism on my part. I've seen
X *	too many menus with no rhyme or reason. Look at AmigaTerm (the term
X *	program that comes with the Amiga modem) some time. Baud rate has
X *	an item all by itself, but word size is hidden off in a menu with
X *	things like bell sound.
X *
X *	the appearance of the menus produced by this is (in my humble
X *	opinion) good. I took some care making text centered in menu boxes,
X *	for example.
X */
X#include <exec/memory.h>
X#include <intuition/intuition.h>
X#include "menu.h"
X#include "fonts.h"
X
X/* Forward prototypes */
Xstatic void nudge(struct MenuItem *item, int delta);
Xstatic struct Menu *
X	new_menu(struct MenuPtr *menuptr, char *name);
Xstatic struct MenuItem *
X	new_item(struct MenuPtr *menuptr,
X		struct Menu *menu, UBYTE *name);
Xstatic struct MenuItem *
X	new_subitem(struct MenuPtr *menuptr,
X		struct MenuItem *item, UBYTE *name, long flags);
X
X/*
Xstruct MenuPtr {
X	struct Menu *MenuBar;
X	struct Remember *MenuMemory;
X};
X*/
X
Xchar *AllocRemember();
X
Xstatic struct Menu *new_menu();
Xstatic struct MenuItem *new_item(), *new_subitem();
X
X#define TOMENUNUM(i,j,k) (SHIFTMENU(i)|SHIFTITEM(j)|SHIFTSUB(k))
X#define TextLen(s) (strlen(s)*FONTWIDTH)
X
Xvoid trash_menus(struct MenuPtr *menuptr)
X{
X	FreeRemember(&menuptr->MenuMemory, 1);
X	menuptr->MenuMemory = 0;
X	menuptr->MenuBar = 0;
X}
X
Xvoid init_menus(struct MenuPtr *menuptr)
X{
X	menuptr->MenuMemory = 0;
X	menuptr->MenuBar = 0;
X}
X
Xint add_menu(
X	struct MenuPtr *menuptr,
X	char *menuname,
X	char *itemname,
X	char *subitemname,
X	long flags)
X{
X	int i, j, k;
X	struct Menu *menu;
X	struct MenuItem *item;
X	struct MenuItem *subitem;
X
X	if(menuptr->MenuBar) {
X		for(i = 0, menu = menuptr->MenuBar;
X		    menu;
X			menu = menu->NextMenu, i++
X		   )
X			if(strcmp(menuname, menu->MenuName)==0)
X				break;
X		if(!menu)
X			menu = new_menu(menuptr, menuname);
X		if(!menu)
X			return MENUNULL;
X	} else {
X		i = 0;
X		menu = new_menu(menuptr, menuname);
X		if(!menu)
X			return MENUNULL;
X	}
X	for(j = 0, item = menu->FirstItem;
X		item;
X		item = item->NextItem, j++
X	   ) {
X		struct IntuiText *text;
X		text = (struct IntuiText *)item->ItemFill;
X		if(strcmp(itemname, text->IText) == 0)
X			break;
X	}
X	if(subitemname) {
X		if(!item)
X			item = new_item(menuptr, menu, (UBYTE *)itemname);
X		if(!item)
X			return MENUNULL;
X		for(k = 0, subitem = item->SubItem;
X			subitem;
X			subitem = subitem->NextItem, k++
X		   ) {
X			struct IntuiText *text;
X			text = (struct IntuiText *)subitem->ItemFill;
X			if(strcmp(subitemname, text->IText) == 0)
X				break;
X		}
X		if(!subitem)
X			subitem = new_subitem(menuptr, item, (UBYTE *)subitemname, flags);
X		if(!subitem)
X			return MENUNULL;
X		return TOMENUNUM(i, j, k);
X	} else {
X		if(!item)
X			item = new_item(menuptr, menu, (UBYTE *)itemname);
X		if(!item)
X			return MENUNULL;
X		return TOMENUNUM(i, j, NOSUB);
X	}
X}
X
Xstatic struct Menu *
Xnew_menu(struct MenuPtr *menuptr, char *name)
X{
X	struct Menu *menu;
X
X	menu = (struct Menu *)AllocRemember(
X		&menuptr->MenuMemory,
X		sizeof(struct Menu),
X		MEMF_PUBLIC);
X	if(!menu)
X		return 0;
X	menu->NextMenu = NULL;
X	menu->LeftEdge = 0;
X	menu->TopEdge = 0;
X	menu->Width = TextLen(name)+FONTWIDTH;
X	menu->Height = 0;
X	menu->Flags = MENUENABLED;
X	menu->MenuName = name;
X	menu->FirstItem = 0;
X	if(menuptr->MenuBar) {
X		struct Menu *ptr, *prev;
X		for(ptr = menuptr->MenuBar; ptr; ptr=ptr->NextMenu) {
X			menu->LeftEdge += ptr->Width;
X			prev = ptr;
X		}
X		prev->NextMenu = menu;
X	} else {
X		menuptr->MenuBar = menu;
X	}
X
X	return menu;
X}
X
Xstatic struct MenuItem *
Xnew_item(struct MenuPtr *menuptr, struct Menu *menu, UBYTE *name)
X{
X	struct MenuItem *item;
X	struct IntuiText *text;
X
X	item = (struct MenuItem *)AllocRemember(
X		&menuptr->MenuMemory,
X		sizeof(struct MenuItem),
X		MEMF_PUBLIC);
X	if(!item)
X		return 0;
X	text = (struct IntuiText *)AllocRemember(
X		&menuptr->MenuMemory,
X		sizeof(struct IntuiText),
X		MEMF_PUBLIC);
X	if(!text)
X		return 0;
X
X	text->FrontPen = AUTOFRONTPEN;
X	text->BackPen = AUTOBACKPEN;
X	text->DrawMode = JAM2;
X	text->LeftEdge = 1;
X	text->TopEdge = 1;
X	text->ITextFont = NULL;
X	text->IText = name;
X	text->NextText = NULL;
X
X	item->NextItem = NULL;
X	item->LeftEdge = 0;
X	item->TopEdge = 0;
X	item->Width = IntuiTextLength(text)+2;
X	if(item->Width <= menu->Width)
X		item->Width = menu->Width+1;
X	item->Height = FONTHEIGHT+1;
X	item->Flags = ITEMTEXT|HIGHCOMP|ITEMENABLED;
X	item->MutualExclude = 0;
X	item->ItemFill = (APTR)text;
X	item->SelectFill = NULL;
X	item->Command = 0;
X	item->SubItem = NULL;
X	item->NextSelect = NULL;
X
X	if(menu->FirstItem) {
X		struct MenuItem *ptr, *prev;
X		for(ptr = menu->FirstItem; ptr; ptr=ptr->NextItem) {
X			if(item->Width > ptr->Width) {
X				if(ptr->SubItem)
X					nudge(ptr->SubItem, item->Width-ptr->Width);
X				ptr->Width = item->Width;
X			} else if(ptr->Width>item->Width)
X				item->Width = ptr->Width;
X			prev = ptr;
X		}
X		item->TopEdge = prev->TopEdge + prev->Height;
X		prev->NextItem = item;
X	} else {
X		menu->FirstItem = item;
X	}
X
X	return item;
X}
X
Xstatic void nudge(struct MenuItem *item, int delta)
X{
X	while(item) {
X		item->LeftEdge += delta;
X		item = item->NextItem;
X	}
X}
X
Xstatic struct MenuItem *
Xnew_subitem(
X	struct MenuPtr *menuptr,
X	struct MenuItem *item,
X	UBYTE *name,
X	long flags)
X{
X	struct MenuItem *subitem;
X	struct IntuiText *text;
X
X	subitem = (struct MenuItem *)AllocRemember(
X		&menuptr->MenuMemory,
X		sizeof(struct MenuItem),
X		MEMF_PUBLIC);
X	if(!subitem)
X		return 0;
X	text = (struct IntuiText *)AllocRemember(
X		&menuptr->MenuMemory,
X		sizeof(struct IntuiText),
X		MEMF_PUBLIC);
X	if(!text)
X		return 0;
X
X	text->FrontPen = AUTOFRONTPEN;
X	text->BackPen = AUTOBACKPEN;
X	text->DrawMode = JAM2;
X	text->LeftEdge = 1;
X	if(flags != SUBITEM_NOCHECK) text->LeftEdge += CHECKWIDTH;
X	text->TopEdge = 1;
X	text->ITextFont = NULL;
X	text->IText = name;
X	text->NextText = NULL;
X
X	subitem->NextItem = NULL;
X	subitem->LeftEdge = item->Width;
X	subitem->TopEdge = 0;
X	subitem->Width = IntuiTextLength(text)+2;
X	if(flags != SUBITEM_NOCHECK) subitem->Width += CHECKWIDTH;
X	subitem->Height = FONTHEIGHT+1;
X	subitem->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
X	subitem->MutualExclude = 0;
X	if(flags != SUBITEM_NOCHECK) {
X		subitem->Flags |= CHECKIT;
X		if(flags & SUBITEM_TOGGLE) subitem->Flags |= MENUTOGGLE;
X		if(flags & SUBITEM_SELECTED) subitem->Flags |= CHECKED;
X	}
X	subitem->ItemFill = (APTR)text;
X	subitem->SelectFill = NULL;
X	subitem->Command = 0;
X	subitem->SubItem = NULL;
X	subitem->NextSelect = NULL;
X
X	if(item->SubItem) {
X		struct MenuItem *ptr, *prev;
X		int i;
X		for(i=0, ptr = item->SubItem; ptr; i++, ptr=ptr->NextItem) {
X			if(subitem->Width > ptr->Width)
X				ptr->Width = subitem->Width;
X			else if(ptr->Width>subitem->Width)
X				subitem->Width = ptr->Width;
X			prev = ptr;
X		}
X		subitem->TopEdge = prev->TopEdge + prev->Height;
X		if(flags & SUBITEM_SELECTOR)
X			subitem->MutualExclude = ~(1<<i);
X		prev->NextItem = subitem;
X	} else {
X		item->SubItem = subitem;
X		if(flags & SUBITEM_SELECTOR)
X			subitem->MutualExclude = ~1;
X	}
X
X	return subitem;
X}
END_OF_FILE
if test 8280 -ne `wc -c <'menu.c'`; then
    echo shar: \"'menu.c'\" unpacked with wrong size!
fi
# end of 'menu.c'
fi
if test -f 'menu.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'menu.h'\"
else
echo shar: Extracting \"'menu.h'\" \(359 characters\)
sed "s/^X//" >'menu.h' <<'END_OF_FILE'
Xstruct MenuPtr {
X	struct Menu *MenuBar;
X	struct Remember *MenuMemory;
X	int next_id;
X};
X
X/* flags */
X#define SUBITEM_NOCHECK 	0x0 	/* subitem does not require a checkmark. */
X#define SUBITEM_SELECTOR	0x10	/* subitem is a 1 of n selector */
X#define SUBITEM_TOGGLE  	0x20	/* subitem is a toggled flag. */
X#define SUBITEM_SELECTED	0x01	/* defaults to checked. */
END_OF_FILE
if test 359 -ne `wc -c <'menu.h'`; then
    echo shar: \"'menu.h'\" unpacked with wrong size!
fi
# end of 'menu.h'
fi
if test -f 'vollist.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vollist.c'\"
else
echo shar: Extracting \"'vollist.c'\" \(1578 characters\)
sed "s/^X//" >'vollist.c' <<'END_OF_FILE'
X#include <libraries/dosextens.h>
X#include <stdio.h>
X#ifdef DEBUG
X#include "debug.h"
X#endif
X/* Fakes an Examine/ExNext interface to the device list. Call OpenVolList
X * first, then ReadVolList(fib), and finally CloseVolList. This last is
X * a dummy, but it's handy if you want to be safe and put a forbid/permit
X * around the whole thing.
X */
X
X#define toAPTR(b) ((b)<<2)
X#define toBPTR(a) ((a)>>2)
X
Xstruct DeviceList *list;
X
Xvoid OpenVolList(void)
X{
X	extern struct DosLibrary *DOSBase;
X	struct RootNode *root;
X	struct DosInfo *info;
X
X	root = (struct RootNode *)DOSBase -> dl_Root;
X	info = (struct DosInfo *)toAPTR(root->rn_Info);
X	list = (struct DeviceList *)toAPTR(info->di_DevInfo);
X}
X
Xint ReadVolList(struct FileInfoBlock *fib)
X{
X	struct DeviceList *next;
X
X	while(list) {
X		next = (struct DeviceList *)toAPTR(list->dl_Next);
X		if(list->dl_Type == DLT_VOLUME ||
X		   list->dl_Type == DLT_DIRECTORY) {
X			char *ptr;
X			int count;
X			ptr = (char *)toAPTR((BPTR)list->dl_Name);
X			count = *ptr++;
X			if(count > 106)
X				count = 106;
X			strncpy(fib->fib_FileName, ptr, count);
X			fib->fib_FileName[count++] = ':';
X			fib->fib_FileName[count] = 0;
X			if(strcmp(fib->fib_FileName, "RAM Disk:") == 0)
X				strcpy(fib->fib_FileName, "RAM:");
X			fib->fib_DiskKey = 0;
X			fib->fib_DirEntryType = list->dl_Type;
X			fib->fib_Protection = 0;
X			fib->fib_EntryType = list->dl_Type;
X			fib->fib_Size = 0;
X			fib->fib_NumBlocks = 0;
X			fib->fib_Date = list->dl_VolumeDate;
X			fib->fib_Comment[0] = 0;
X			list = next;
X			return 1;
X		}
X		list = next;
X	}
X	return 0;
X}
X
Xvoid CloseVolList(void)
X{
X}
END_OF_FILE
if test 1578 -ne `wc -c <'vollist.c'`; then
    echo shar: \"'vollist.c'\" unpacked with wrong size!
fi
# end of 'vollist.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.