[comp.sources.atari.st] v01i064: poplib -- shared libraries, with examples

koreth@ssyx.ucsc.edu (Steven Grimm) (07/18/88)

Submitted-by: uunet!unido!sbsvax!roeder (Edgar Roeder)
Posting-number: Volume 1, Issue 64
Archive-name: poplib

[This package allows you to add subroutine libraries that are external
 to the calling program, and independent of that program's language.
 Examples are provided; the author did not wish to release the source
 to his popup library, which is being posted to the binaries group. -sg]

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#                                                                          
#                                                                          
#
#	Run the following text with /bin/sh to create:
#	  README
#	  README.POP
#	  MAKEFILE
#	  DEBUG.H
#	  LIBS.C
#	  LIBS.H
#	  POPTEST.C
#	  POPUP.H
#	  XLIB.C
#	  XLIB.H
#	  XTEST.C
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
sed 's/^X//' << 'SHAR_EOF' > README &&
XShared Library Support - Experimental
X-------------------------------------
X
XThe included files make up the pieces you need to create and use
Xshared libraries on the Atari ST.  Note that this is a experimental
Xversion.  I would like your feedback, especially constructive
Xcomments! :-)
X
XShared libraries are a useful way of factoring the common code out of
Xyour programs.  If you have a number of programs that use many of the
Xsame routines then you may want to use a shared library.
X
XIn this scheme, shared libraries are installed at boot time.  Each
Xlibrary maintains an array of pointers to it's externally accessible
Xentry points.  Programs that use a shared library acquire a pointer to
Xthe library's entry points.  An entry point is called by jumping
Xthrough the array.  
X
XThe program LIBS.PRG (containing the basic shared library support)
Xshould be placed in your AUTO folder, followed by the shared libraries
Xthemselves.  An example library XLIB.PRG is included in this
Xdistribution.  At boot time GEM will execute LIBS.PRG, installing the
Xneeded shared libraries support.  As each library is executed it will
Xperform any needed initialization and install itself in memory.
X
XNote that the order of the files in the AUTO folder is critical.  The
Xprogram LIBS.PRG must preceed any libraries.  Also note that if a
Xlibrary is dependent on the presence of another library, then the
Xlibrary on which it depends must be installed first.
X
XOne of the interested possibilities offered by this scheme is the
Xability to easily make incremental changes to existing libraries to
Xwhich you may not have the source.  If there is a known bug in a
Xlibrary, you could come up with a 'patch' that replaces the offending
Xentry in the library's jump table with a pointer to your own routine.
X
XSupport routines
X----------------
X
X-- int InitLibSupport()
X
XCalled by any program using shared libraries to initialize the shared
Xlibrary support.  Returns 0 if the shared library support is NOT
Xinstalled.
X
X-- InstallLibrary(lib_link,keep)
X
XCalled by a library to install itself.
X
X-- Library FindLibrary(lib_name,lib_version)
X
XCalled by a program to find an installed library.  Returns 0 if the
Xlibrary is not found, or a pointer to the library's array of entry
Xpoints.
X
XThis distribution contains the following:
X
X	LIBS.H		- included by all code using shared libraries
X	LIBS.C		- terminate & stay resident library support
X	LIB_INIT.C	- module linked in by programs using libraries
X	LIB_INST.C	- module linked in by installable libraries
X	
X	XLIB.H		- interface to example library
X	XLIB.C		- example library
X	
X	XTEST.C		- program that uses example library 
X	
X	MAKEFILE	- to put all of the above together
X
XThis code was developed using Mark Williams C.
SHAR_EOF
chmod 0600 README || echo "restore of README fails"
sed 's/^X//' << 'SHAR_EOF' > README.POP &&
XWhat is in this package ?
X
XThis posting contains a shared library for creating popup menus in all Atari-
Xprograms (not only GEM-Applications, but no accessories). It is based on the
Xshared library framework of Preston L. Bannister. He had an excellant idea.
XPlease read the original readme file from his distribution.
XThere is no easy way to use AES-Calls in a library started at boot-time. So i
Xchoosed the accessory form for this library. The popup.acc does not provide a
Xmenu-entry. It can only be called from inside of other programs.
X
X
XWhat is a popup menu ?
X
XIt is like an usual GEM-menu in the menu-bar except that it pops up wherever
Xthe mouse cursor is located when you call it. You can then select in the usual
Xway by clicking with the left mouse button when the desired item is highlighted.
XSubmenus are indicated by an arrow on the left side of the entry-text. If you
Xselect a submenu, it pops up at the current cursor location and the process of
Xselection is repeated. You can also cancel the actual menu level by clicking
Xthe right mouse button. If you press the Help-key you'll get some help on the
Xcurrent entry (or popup menus in general, if no entry is selected).
X
X
XHow can i use these menus ?
X
XYou can use them inside your own programs. Perhaps you should first look at the
Xexample source poptest.c . Normally you create a popup-menu by calling the
Xfunction DefineMenu("<menu-text>"), where <menu-text> is a list of entries, all
Xseperated by the pipe-symbol `|'. For more advanced formats you should look at
Xpopup.h, the interface documentation for popup.acc . As return value of the
Xfunction DoMenu(), which does the entire dialog, you get the number of the
Xselected entry.
X
X
XHow can i provide my own (help) functions ?
X
XThe format-specification in DefineMenu() is used like the C-function printf().
XTo specify a function to be called, when an entry is selected (the Help-key is
Xpressed), you can use the format %f (%h) and provide the function-address as
Xparameter to DefineMenu(). An example:
X
X	beep()
X	{
X		putchar(7);
X	}
X
X	menu_selection()
X	{
X			menu	my_menu;
X
X			my_menu = DefineMenu(" hello world ! %f",beep);
X			DoMenu(my_menu);
X			FreeMenu(my_menu);
X	}
X
XThe function is called with three parameters:
X	- the current GEM-handle of the virtual workstation of popup.acc
X	- the default return value of this item
X	- the string-entry of the current item
XIf you don't use AES-calls anywhere else in your program, you can use the
XFormAlert()-function to display GEM-alerts on the screen (with the usual
Xparameters of form_alert()). So you need not to link the whole GEM-stuff to
Xyour program.
X
XAny comments and suggestions are always welcome. Please mail to one of the
Xaddresses given in the popup.h file or when getting the generic-help message.
X
XEdgar Roeder
SHAR_EOF
chmod 0600 README.POP || echo "restore of README.POP fails"
sed 's/^X//' << 'SHAR_EOF' > MAKEFILE &&
X# makefile for loadable library code
X
XDEBUG	= -DDEBUGGING
XCFLAGS	= $(DEBUG)
XCOMPILE	= $(CC) $(CFLAGS)
X
Xall : libs.prg xlib.prg xtest.prg poptest.prg
X
X# Shared library support code - installed at boot time
Xlibs.prg : libs.c
X	$(COMPILE) libs.c
X
X# Example shared library
Xxlib.prg : xlib.o lib_inst.o
X	$(COMPILE) xlib.o lib_inst.o
X
X# Example program that uses the example shared library
Xxtest.prg : xtest.o lib_init.o
X	$(COMPILE) xtest.o lib_init.o
X
X# Example program that uses the popup menu shared library
Xpoptest.prg : poptest.o lib_init.o
X	$(COMPILE) poptest.o lib_init.o
X
Xlibs.prg xlib.o xtest.o lib_inst.o lib_init.o : libs.h
X
X# Note!  The order of installation is very important!
Xinstall	: libs.prg xlib.prg
X	-rm c:\auto\libs.prg c:\auto\xlib.prg
X	cp libs.prg xlib.prg c:\auto
X
XSRC	= \include\debug.h libs.h libs.c xlib.h xlib.c xtest.c popup.h poptest.c
X
Xshar	: 
X	shar readme makefile $(SRC) > libs.sh
X	
XBIN	= libs.prg xlib.prg xtest.prg popup.acc poptest.prg
X
Xarc	: $(BIN)
X	arc -u libs.arc readme makefile $(SRC) $(BIN)
X
Xclean	:
X	$(RM) *.o *.prg libs.arc libs.sh
SHAR_EOF
chmod 0600 MAKEFILE || echo "restore of MAKEFILE fails"
sed 's/^X//' << 'SHAR_EOF' > DEBUG.H &&
X#ifdef DEBUGGING
X#define DEBUG(x)	printf x
X#define ENTER(x)	printf("entering: %s\n","x")
X#define LEAVE(x)	printf("leaving: %s\n","x")
X#else
X#define DEBUG(x)
X#define ENTER(x)
X#define LEAVE(x)
X#endif
SHAR_EOF
chmod 0600 DEBUG.H || echo "restore of DEBUG.H fails"
sed 's/^X//' << 'SHAR_EOF' > LIBS.C &&
X/*
X	Shared library support.
X	written October, 1987
X	by Preston L. Bannister
X*/
X
X#include <osbind.h>
X#include <bios.h>
X#include <basepage.h>
X#include <debug.h>
X#define LIBSUPPORT_IMPLEMENTATION
X#include "libs.h"
X
XLibLink *Libraries;
X
X
X/*===== entry points =====*/
X
X
X/*
X	Add a new library to the list of installed libraries.
X*/
X
Xvoid
XAddLibrary (lib)
X  LibLink *lib;		/* IN a new library link */
X{
X  ENTER(AddLibrary);
X  lib->next = Libraries;
X  Libraries = lib;
X  LEAVE(AddLibrary);
X}
X
X
X/*
X	Find an installed library to match the given name and version.
X	Returns a NULL pointer if the library was not found or if the
X	entrance routine of the library itself decided it was not 
X	compatible with the given version.
X*/
X
XLibrary
XFindLibrary (name,version)
X  char *name;		/* IN name of the library to find */
X  int version;		/* IN version number of library */
X{
X  LibLink *p = Libraries;
X  ENTER(FindLibrary);
X  DEBUG(("Looking for '%s'\n",name));
X  for (p=Libraries; p; p=p->next)
X  {
X    DEBUG(("Examining '%s'\n",p->name));
X    if (strcmp(name,p->name)==0)
X    {
X      LEAVE(FindLibrary:FoundIt);
X      return ((*p->entrance)(version));
X    }
X  }
X  LEAVE(FindLibrary:NotFound);
X  return 0L;
X}
X
X
X/*
X	For each installed library, call the given procedure with a pointer 
X	to the given data and a pointer to the library link structure.
X*/
X
Xvoid
XForEachLibrary (proc,data)
X  int (*proc)();
X  int *data;
X{
X  LibLink *p = Libraries;
X  ENTER(ForEachLibrary);
X  for (p=Libraries; p; p=p->next)
X  {
X    if ((*proc)(data,p))
X      break;
X  }
X  LEAVE(ForEachLibrary);
X}
X
X
X/*===== =====*/
X
X
XProcedure LibSupportBase[] = {
X  AddLibrary,
X  FindLibrary,
X  ForEachLibrary
X};
X
X
X/* Called when client finds this library */
X
XLibrary
XEntrance (version)
X  int version;
X{
X  DEBUG(("In LibSupport Entrance\n"));
X  switch (version)
X  {
X    case LIBSUPPORT_VERSION:
X      return LibSupportBase;
X  }
X  return 0L;
X}
X
X
XLibLink LibSupport = {
X  0L,
X  LIBSUPPORT_NAME,
X  LIBSUPPORT_VERSION,
X  Entrance
X};
X
X
Xmain ()
X{
X  extern int end[];
X
X  DEBUG(("\nInstalling LibSupport\n"));
X  Libraries = &LibSupport;
X  Setexc(LIB_FIND_VECTOR,FindLibrary);
X  DEBUG(("LibSupport vector 0x%04x set to 0x%08X FindLibrary\n",
X          LIB_FIND_VECTOR,FindLibrary));
X  Setexc(LIB_ADD_VECTOR,AddLibrary);
X  DEBUG(("LibSupport vector 0x%04x set to 0x%08X AddLibrary\n",
X          LIB_ADD_VECTOR,AddLibrary));
X  Ptermres((long)end-(long)BP,0);
X  DEBUG(("LibSupport installation failed!\n"));
X  return 1;
X}
SHAR_EOF
chmod 0600 LIBS.C || echo "restore of LIBS.C fails"
sed 's/^X//' << 'SHAR_EOF' > LIBS.H &&
X/* 
X	Definitions for shared library support 
X	written November, 1987
X	by Preston L. Bannister
X*/
X
X#define LIBSUPPORT_NAME		"LibSupport"
X#define LIBSUPPORT_VERSION	1
X
X#define LIB_FIND_VECTOR	0x200
X#define LIB_ADD_VECTOR	0x201
X
Xtypedef long (*Procedure)();
Xtypedef Procedure * Library;
Xtypedef Library (*GetLibraryFunction)();
X
Xtypedef struct _LibLink {
X  struct _LibLink *next;
X  char *name;
X  int version;
X  GetLibraryFunction entrance;
X} LibLink;
X
Xextern Library LibSupportBase;
X
Xextern void InstallLibrary(/*lib,keep*/);
Xextern int  InitLibSupport();
X
X#ifndef LIBSUPPORT_IMPLEMENTATION
X
X#define AddLibrary	(*LibSupportBase[0])
X#define FindLibrary	(*LibSupportBase[1])
X#define ForEachLibrary	(*LibSupportBase[2])
X
X#endif
SHAR_EOF
chmod 0600 LIBS.H || echo "restore of LIBS.H fails"
sed 's/^X//' << 'SHAR_EOF' > POPTEST.C &&
X#include <osbind.h>
X#include "libs.h"
X#include "popup.h"
X
XLibrary PopupLibBase;	/* points to popup menu library */
X
XValue
Xbeep(handle,i)
X{
X	Bconout(2,7);
X	return(42);
X}
X
Xhelp(handle,i,str)
Xchar	*str;
X{
X	char	out[256];
X
X	sprintf(out,"[0][ If you select | '%s' | you'll hear the bell ][ OK ]",
X		str);
X	FormAlert(1,out);
X}
X
Xmain ()
X{
X	menu	test_menu;
X	menu	sub_menu;
X	Value result;
X	char	out[80];
X	char	out_str[256];
X
X	if (InitLibSupport()) {
X		if (PopupLibBase = (Library)
X				FindLibrary(POPUP_LIB,POPUP_VERSION)) {
X			sprintf(out_str,"[3][ Library | '%s' ][ 0x%08X ]",
X				POPUP_LIB,PopupLibBase);
X			FormAlert(1,out_str);
X			ConfigRows(2);
X			sub_menu =
X			DefineMenu(" Submenu %s%t| five %v| Beep %h%f",
X				5,help,beep);
X			test_menu =
X			DefineMenu(" test %s%t| one | two | Submenu %o%m",
X				sub_menu);
X			result = DoMenu(test_menu);
X			out[0] = '\0';
X			switch(result) {
X				case -2 : strcat(out,"cancelled");
X				case -1 : strcat(out,"| no selection"); break;
X				default : sprintf(out,"you selected %d",result);
X			}
X			sprintf(out_str,"[0][ %s ][ OK ]",out);
X			FormAlert(1,out_str);
X			FreeMenu(test_menu);
X			FreeMenu(sub_menu);
X			exit(0);
X		} else {
X			printf("PopupLib not available\n");
X		}
X	} else printf("no library support\n");
X	exit(1);
X}
SHAR_EOF
chmod 0600 POPTEST.C || echo "restore of POPTEST.C fails"
sed 's/^X//' << 'SHAR_EOF' > POPUP.H &&
X/******************************************************************************/
X/* @(#)	popup.h	   1.0 -- standard include file for popup menu usage 09.07.88 */
X/*									      */
X/* This header file and the corresponding shared library are in the public    */
X/* domain. They can be copied and distributed for non-commercial usage.       */
X/*									      */
X/* (c) 10/1987 by	Edgar Roeder					      */
X/*			Liesbet-Dill-Str. 3				      */
X/*			D-6602 Dudweiler				      */
X/*			W-Germany					      */
X/* 			E-mail: roeder@sbsvax.UUCP or			      */
X/* 				roeder@eansb.informatik.uni-saarland.dbp&de   */
X/******************************************************************************/
X
X#define POPUP_LIB	"popup menus"
X#define POPUP_VERSION	1
X
X/*
X * usage of this package:
X *
X * menu_id = DefineMenu(str,args);
X * value = DoMenu(menu_id);
X * err = FreeMenu(menu_id);
X *
X * example:
X *
X * long	menu_id;
X * menu_id = DefineMenu(" testmenu %t| first | second | third ");
X * switch(DoMenu(menu_id)) {
X * 	case -2 : printf("Right mouse cancelled menu\n"); break;
X * 	case -1 : printf("No menu item selected\n"); break;
X * ...
X * }
X * if(FreeMenu(menu_id)) fprintf(stderr,"Cannot free this menu");
X *
X */
X
Xtypedef long	menu;
Xtypedef int	Value;
X
X/******************************************************************************
X *                                                                            *
X * DefineMenu   returns a new menu id, which can be used to display the       *
X *              defined menu or 0 if an error occured                         *
X * DoMenu       returns as standard value the number of the selected item     *
X *              -2 is returned if the button is pressed outside the menu      *
X *              -1 is returned if no selection was made                       *
X *               0 is returned if there was an error                          *
X * FreeMenu     returns 0 if no error occured (menu_id is deleted)            *
X * ConfigRows   sets the maximum number of rows in a column (default is 5)    *
X *              and returns the old value for this                            *
X * ConfigScreen sets the border of the screen usable to display popup menus   *
X *              (the default values are: 0, 0, 639, 399 for mono screen)      *
X *                                                                            *
X *    complete definition of advanced menu formats (decreasing priority):     *
X *                                                                            *
X * format modifier |  required arguments  |          effect                   *
X * ----------------+----------------------+---------------------------------- *
X *       %t        | no additional args   | make a non selectable menu title  *
X * ----------------+----------------------+---------------------------------- *
X *       %v        | one int argument     | supply non standard return value  *
X *                 |                      |                                   *
X * ----------------+----------------------+---------------------------------- *
X *       %m        | one menu identifier  | invoke submenu                    *
X *                 |                      |                                   *
X * ----------------+----------------------+---------------------------------- *
X *       %c        | no additional args   | continue with menu if this item   *
X *                 |                      | is selected or no selection       *
X * ----------------+----------------------+---------------------------------- *
X *       %x        | no additional args   | continue with menu if no entry    *
X *                 |                      | selected                          *
X * ----------------+----------------------+---------------------------------- *
X *       %s        | no additional args   | selection required in this part   *
X * ----------------+----------------------+---------------------------------- *
X *       %o        | no additional args   | overlay this submenu (or all)     *
X * ----------------+----------------------+---------------------------------- *
X *       %f        | one function pointer | call function with standard       *
X *                 |                      | value as single argument          *
X * ----------------+----------------------+---------------------------------- *
X *       %h        | one function pointer | call function if user pressed     *
X *                 |                      | the Help key                      *
X *                                                                            *
X * if more than one format is given, the effects are occuring in order of     *
X * decreasing priority (you could attach a function to a whole menu with      *
X * %f and %m given in any order, or invoke the function with a non standard   *
X * value given with %v %f, in %m %v format the non standard value overrides   *
X * a return value of -1 if no selection occured during submenu invocation)    *
X *                                                                            *
X ******************************************************************************/
X
X#ifdef LATTICE
Xextern Procedure *PopupLibBase;
X#else
Xextern Library PopupLibBase;
X#endif LATTICE
X
X#ifdef POPUP_IMPLEMENTATION
Xextern menu	DefineMenu();	/* define a popup menu                        */
Xextern long	FreeMenu();	/* free the given menu                        */
Xextern Value	DoMenu();	/* display the given menu and handle input    */
Xextern int	ConfigMenu();	/* configure display parameters for defined   */
X				/* menus				      */
X
X/* this function is used by DoMenu with the actual mouse coordinates as input */
Xextern Value	DoXYMenu();	/* display menu at given coordinates          */
X				/* usage: DoXYMenu(screen_handle,menu_id,x,y) */
X#else
X#define DefineMenu		(*PopupLibBase[0])
X#define DoMenu			(*PopupLibBase[1])
X#define FreeMenu		(*PopupLibBase[2])
X#define DoXYMenu		(*PopupLibBase[3])
X#define ConfigMenu		(*PopupLibBase[4])
X#define ConfigRows(r)		ConfigMenu(r)
X#define ConfigScreen(x,y,w,h)	ConfigMenu(0,x,y,w,h)
X#define FormAlert		(*PopupLibBase[5])
X#endif
SHAR_EOF
chmod 0600 POPUP.H || echo "restore of POPUP.H fails"
sed 's/^X//' << 'SHAR_EOF' > XLIB.C &&
X/* Test Library Implementation */
X
X#include "libs.h"
X#define XLIB_IMPLEMENTATION
X#include "xlib.h"
X#include <debug.h>
X
X
X/*===== Library Entry Points =====*/
X
X
Xvoid XLibP0 () { DEBUG(("in XLibP0\n")); }
Xvoid XLibP1 () { DEBUG(("in XLibP1\n")); }
Xvoid XLibP2 () { DEBUG(("in XLibP2\n")); }
X
X
X/*===== Overhead =====*/
X
X
X/* array of entry points for this library */
X
XProcedure XLibBase[] = {
X  XLibP0,
X  XLibP1,
X  XLibP2
X};
X
X
X/*
X	This routine is called by FindLibrary when a program wants
X	to use the library.  If the version number given by the caller
X	is not acceptable we will return NULL.  If we wanted to support
X	more than one version with the same library, we could choose to
X	return a different library base pointer for some versions. 
X*/
X
XLibrary
XEntrance (version)
X  int version;
X{
X  DEBUG(("XLib Entrance with version %d\n",version)); 
X  if (version==XLIB_VERSION)
X    return XLibBase;
X  return 0L;
X}
X
X
X/* The link for this library */
X
XLibLink XLib = {
X  0L,
X  XLIB_NAME,
X  XLIB_VERSION,
X  Entrance
X};
X
X
X/* initialization code for library */
X
Xint
Xmain ()
X{
X  /* install this library */
X  return InstallLibrary(&XLib,0L);
X}
SHAR_EOF
chmod 0600 XLIB.C || echo "restore of XLIB.C fails"
sed 's/^X//' << 'SHAR_EOF' > XLIB.H &&
X/* Example Library Interface */
X
X#define XLIB_NAME	"XLib"
X#define XLIB_VERSION	1
X
Xextern Library XLibBase;
X
X#ifndef XLIB_IMPLEMENTATION
X
X#define XLibP0	(*XLibBase[0])
X#define XLibP1	(*XLibBase[1])
X#define XLibP2	(*XLibBase[2])
X
X#endif
SHAR_EOF
chmod 0600 XLIB.H || echo "restore of XLIB.H fails"
sed 's/^X//' << 'SHAR_EOF' > XTEST.C &&
X/*
X	Shared library test
X	written November, 1987
X	by Preston L. Bannister
X*/
X
X#include <debug.h>
X#include "libs.h"
X#include "xlib.h"
X
XLibrary XLibBase;	/* points to our example library */
X
Xmain ()
X{
X  if (InitLibSupport())
X  {
X    printf("Attempting to find library '%s'\n",XLIB_NAME);
X    if (XLibBase = (Library)FindLibrary(XLIB_NAME,XLIB_VERSION))
X    {
X      printf("XLibBase 0x%08X\n",XLibBase);
X      DEBUG(("Calling XLibP0 @ 0x%08X\n",XLibBase[0]));
X      XLibP0();
X      DEBUG(("Calling XLibP1 @ 0x%08X\n",XLibBase[1]));
X      XLibP1();
X      DEBUG(("Calling XLibP2 @ 0x%08X\n",XLibBase[2]));
X      (void)XLibP2();
X    }
X    else
X    {
X      printf("XLib not availible??\n");
X    }
X  }
X  exit(0);
X}
SHAR_EOF
chmod 0600 XTEST.C || echo "restore of XTEST.C fails"
exit 0