[comp.sources.misc] v20i026: ivinfo - InterViews emacs info file browser in C++, Part01/04

tom@hcx2.ssd.csd.harris.com (Tom Horsley) (05/30/91)

Submitted-by: Tom Horsley <tom@hcx2.ssd.csd.harris.com>
Posting-number: Volume 20, Issue 26
Archive-name: ivinfo/part01

I made the mistake of mentioning I had written this stuff over in
comp.windows.interviews and I have since been assailed with pleas for it as
if I was the only water vendor in the Sahara desert :-).

This is an emacs info file browser written in C++. The centerpiece is really
the info.c and info.h files that make up a C++ info browser class. The rest
of the stuff is a wrapper around it to make an X window info browser using
InterViews (version 2.6).

Initially, I didn't think I would be allowed to post this since I wrote it
as part of a project here at Harris, and I would like to thank the folks
Harris for giving me permission to post it after seeing the kind of demand
it generated. Feel free to use this any way you want to -- just don't try to
copyright it and then prevent me from using it.

It has been tested only on a Harris Night Hawk 4400 (an 88k based machine) 
where it was developed.  It was tested with the GNU g++ compiler (version 
1.37.2.2 from Data General) using InterViews 2.6.

I made a brief attempt to get it to build with AT&T CC and InterViews 3.0,
but there have been too many changes to InterViews for it to be simple to
compile (mostly because of some of the nasty low-level tricks I used to get
at some of the X stuff not normally visible from InterViews), so I gave up.
I will probably go back to it someday, but so many folks were clamoring for
this, I figured I should go ahead and release it.

Please don't flame me for the lack of an IMakefile or any portability
problems, as I am posting this simply because the demand for it was high,
not because I think it is in terrific shape for posting (although hopefully
it won't be too hard for anyone to port).

Tom Horsley <hcx2.ssd.csd.harris.com!tom>
--------------
#! /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 4)."
# Contents:  MANIFEST Makefile README dialogbox.h filename.h
#   hypertext.c hypertext.h info.h istring.h yesorno.c yesorno.h
# Wrapped by tom@hcx2 on Wed May 29 10:48:50 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(610 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X Makefile                   1	
X README                     1	
X dialogbox.c                2	
X dialogbox.h                1	
X filename.c                 3	
X filename.h                 1	
X hypertext.c                1	
X hypertext.h                1	
X info.c                     4	
X info.h                     1	
X istring.h                  1	
X ivinfo.c                   3	
X ivinfo.texinfo             2	
X yesorno.c                  1	
X yesorno.h                  1	
END_OF_FILE
if test 610 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1360 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile for building a C++ program using InterViews. This file is
X# designed to build on a system where InterViews is not already installed in
X# all the right places. It will need work if you have IV installed already
X# (mostly just deleting stuff).
X#
X# This version of the Makefile uses InterViews 2.6 and the g++ compiler.
X
X# IVDIR is the directory that holds the interviews source tree. You definitely
X# have to change this to get this makefile to work.
XIVDIR=/hx2d9/ccg/tom/Interviews
X
X# MACH is the machine architecture (different machines have their libraries
X# stored in different directories).
XMACH=m88k
X
XIVLIB=$(IVDIR)/iv/src/libInterViews/$(MACH)/libInterViewsX11.a
X
XIVINC=-I$(IVDIR)/iv/src -I$(IVDIR)/iv/src/InterViews/Std
X
XCC=g++
X
XDBG=-g
X
XCFLAGS=$(DBG) $(IVINC)
X
XLIBS=$(IVLIB) -lX11 -lm /usr/local/lib/libg++.a -lc -lPW
X
XOBJS=ivinfo.o yesorno.o hypertext.o dialogbox.o filename.o info.o
X
Xall: ivinfo ivinfo-info
X
Xivinfo: $(OBJS) $(CLLIB)
X	$(CC) -o ivinfo $(OBJS) $(LIBS)
X
Xdialogbox.o : dialogbox.c dialogbox.h istring.h 
Xhypertext.o : hypertext.c hypertext.h 
Xyesorno.o : yesorno.c yesorno.h 
Xivinfo.o : ivinfo.c hypertext.h dialogbox.h info.h filename.h yesorno.h 
Xfilename.o : filename.c filename.h 
Xinfo.o : info.c info.h filename.h 
X
Xclean:
X	/bin/rm -f core a.out *.o ivinfo ivinfo-info
X
Xivinfo-info: ivinfo.texinfo
X	makeinfo ivinfo.texinfo
END_OF_FILE
if test 1360 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2009 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XGENERAL INFO:
X
XThis is a quick and dirty emacs info viewer written in C++ using the
XInterViews 2.6 library.
X
XThe ivinfo.c program is descended from the InterViews 'sted' utility.
X
XThe dialogbox files were copied from 'idraw'.
X
XThe info class (info.c and info.h) was written from scratch and can be used
Xindependently of the rest of this code.
X
XThe hypertext.[ch] files is a good example (well, an example anyway :-) of
Xhow to derive a new class with additional features based on an existing
Xclass (in this case, the InterViews texteditor class).
X
XBUILDING:
X
XTo build this, edit Makefile so it will work on your system (sorry, but I
Xfind it simpler to edit Makefiles than to attempt to write or read
XIMakefiles). It has been tested only on a Harris Night Hawk 4400 (an 88k
Xbased machine) where it was developed.  It was tested with the GNU g++
Xcompiler (version 1.37.2.2 from Data General) using InterViews 2.6.
X
XI made a brief attempt to get it to build with AT&T CC and InterViews 3.0,
Xbut there have been too many changes to InterViews for it to be simple to
Xcompile (mostly because of some of the nasty low-level tricks I used to get
Xat some of the X stuff not normally visible from InterViews), so I gave up.
XI will probably go back to it someday, but so many folks were clamoring for
Xthis, I figured I should go ahead and release it.
X
XINSTALLING:
X
XThis comes with its own help file (ivinfo.texinfo). You might want to
Xinstall it along with the other emacs info files. You might also need to
Xchange the default info path which is hardcoded in ivinfo.c as
X/usr/lib/emacs/info. At the bottom of ivinfo.texinfo there are some cross
Xreferences that point to some of the source files. You might want to stick
Xabsolute path names in there pointing to the source wherever you happen to
Xkeep it on your system.
X
XTODO:
X
XThe most useful addition to the info class would be adding code to check the
Xlast written time each time it moves from one file to another and update the
Xincore buffers if the file has changed.
END_OF_FILE
if test 2009 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'dialogbox.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dialogbox.h'\"
else
echo shar: Extracting \"'dialogbox.h'\" \(3876 characters\)
sed "s/^X//" >'dialogbox.h' <<'END_OF_FILE'
X/*
X * Copyright (c) 1987, 1988, 1989 Stanford University
X *
X * Permission to use, copy, modify, distribute, and sell this software and its
X * documentation for any purpose is hereby granted without fee, provided
X * that the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of Stanford not be used in advertising or
X * publicity pertaining to distribution of the software without specific,
X * written prior permission.  Stanford makes no representations about
X * the suitability of this software for any purpose.  It is provided "as is"
X * without express or implied warranty.
X *
X * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
X * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
X * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
X * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
X * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X */
X
X// $Header: dialogbox.h,v 1.12 90/01/25 16:29:11 interran Exp $
X// declares class DialogBox and DialogBox subclasses.
X
X#ifndef dialogbox_h
X#define dialogbox_h
X
X#include <InterViews/filechooser.h>
X
X// Declare imported types.
X
Xclass ButtonState;
Xclass IMessage;
Xclass StringEditor;
X
X// A DialogBox knows how to set its message and warning text and how
X// to pop up itself over the underlying Interactor.
X
Xclass DialogBox : public MonoScene {
Xpublic:
X
X    void SetMessage(const char* = nil, const char* = nil);
X    void SetWarning(const char* = nil, const char* = nil);
X    void SetUnderlying(Interactor*);
X
Xprotected:
X
X    DialogBox(Interactor*, const char* = nil);
X
X    void PopUp();
X    void Disappear();
X
X    IMessage* message;		// displays message text
X    IMessage* warning;		// displays warning text
X    Interactor* underlying;	// we'll insert ourselves into its parent
X
X};
X
X// A Messager displays a message until it's acknowledged.
X
Xclass Messager : public DialogBox {
Xpublic:
X
X    Messager(Interactor*, const char* = nil);
X    ~Messager();
X
X    void Display();
X
Xprotected:
X
X    void Init();
X    void Reconfig();
X
X    ButtonState* ok;		// stores status of "ok" button
X    Interactor* okbutton;	// displays "ok" button
X
X};
X
X// A Confirmer displays a message until it's confirmed or cancelled.
X
Xclass Confirmer : public DialogBox {
Xpublic:
X
X    Confirmer(Interactor*, const char* = nil);
X    ~Confirmer();
X
X    char Confirm();
X
Xprotected:
X
X    void Init();
X    void Reconfig();
X
X    ButtonState* yes;		// stores status of "yes" button
X    ButtonState* no;		// stores status of "no" button
X    ButtonState* cancel;	// stores status of "cancel" button
X    Interactor* yesbutton;	// displays "yes" button
X    Interactor* nobutton;	// displays "no" button
X    Interactor* cancelbutton;	// displays "cancel" button
X
X};
X
X// A Namer displays a string until it's edited or cancelled.
X
Xclass Namer : public DialogBox {
Xpublic:
X
X    Namer(Interactor*, const char* = nil);
X    ~Namer();
X
X    char* Edit(const char*);
X
Xprotected:
X
X    void Init();
X    void Reconfig();
X
X    ButtonState* accept;	// stores status of "accept" button
X    ButtonState* cancel;	// stores status of "cancel" button
X    Interactor* acceptbutton;	// displays "accept" button
X    Interactor* cancelbutton;	// displays "cancel" button
X    StringEditor* stringeditor;	// displays and edits a string
X
X};
X
X// A Finder browses the file system and returns a file name.
X
Xclass Finder : public FileChooser {
Xpublic:
X
X    Finder(Interactor*, const char*);
X
X    const char* Find();
X
Xprotected:
X
X    Interactor* Interior();
X    boolean Popup(Event&, boolean = true);
X
Xprotected:
X
X    Interactor* underlying;	// we'll insert ourselves into its parent
X
X};
X
X#endif
END_OF_FILE
if test 3876 -ne `wc -c <'dialogbox.h'`; then
    echo shar: \"'dialogbox.h'\" unpacked with wrong size!
fi
# end of 'dialogbox.h'
fi
if test -f 'filename.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'filename.h'\"
else
echo shar: Extracting \"'filename.h'\" \(4960 characters\)
sed "s/^X//" >'filename.h' <<'END_OF_FILE'
X#ifndef filename_h_
X#define filename_h_
X
X#ifndef NULL
X#define NULL 0
X#endif
X
X// The UnsafeFileName class is used internally by the FileName class.
X// Normally initializing a FileName requires making a copy of a string, but
X// many of the internal manipulations make strings which are known to be in
X// cannonical format already and whose lifetime is known to end when an
X// actual FileName is initialized. We can provide a FileName constructor
X// which simply inherits the pointer from an UnsafeFileName rather than
X// making a copy (thus saving the allocation and copy overhead).
Xclass UnsafeFileName {
Xpublic:
X   const char * filename;
X   UnsafeFileName(const char * name) : filename(name) {};
X};
X
X// The FileName class is a generally useful utility class for manipulation
X// of *nix file name strings. It knows nothing about any actual files on the
X// system, it merely (Ha!) manipulates the name strings. It always converts
X// the string to cannonical format (deleting ./, etc) when constructed.
X//
X// Besides the normal interpretation of . and .. and the simplification of
X// names that use them, it provides a special interpretation of multiple
X// slash characters appearing in sequence - all path name components prior
X// to the last / in a multi-slash sequence are discarded (the final / is
X// treated as root). This is consistent with the way GnuEmacs deals with
X// file names and has proven to be useful, so I adopted it here (since it
X// doesn't mean anything anyway, this is a better interpretation than most).
Xclass FileName {
Xprivate:
X   // The only data item stored in a FileName is a pointer to the
X   // string containing the cannonical representation of the filename
X   // (constructed at initialization time and never modified).
X   const char * filename;
X
X   // Initializer function used to build the cannonical name string
X   char * make_cannonical_rep(const char * name);
X
X   // Initializer function used to build string from separate directory
X   // and filename parts.
X   char * make_cannonical_rep(const char * dir, const char * name);
X
X   // Initializer function used to make a copy of a string
X   char * make_copy(const char * name);
X
X   // Inherit pointer from an UnsafeFileName
X   FileName(const UnsafeFileName& ufn) : filename(ufn.filename) {};
X
Xpublic:
X   // Construct a FileName
X   FileName(const char * name) : filename(make_cannonical_rep(name)) {};
X
X   // Construct FileName with name relative to specified directory (essentially
X   // just concat filename onto directory name with a slash in between).
X   FileName(const char * name, const char * curdir) :
X      filename(make_cannonical_rep(curdir, name)) {};
X
X   // Make a copy of another FileName known to be in cannonical format
X   FileName(const FileName& fn) : filename(make_copy(fn.filename)) {};
X
X   // Destroy a FileName and reclaim space.
X   ~FileName();
X
X   // Watch out for this one! Returns a pointer to the internal string rep,
X   // should not be used after the FileName object is destroyed! Also should
X   // not be modified by anyone else, typically you should make a copy right
X   // away if you need it for any peroid of time.
X   operator const char*() const { return filename; };
X
X   // Return the full name minus the last component (unless the name is '/'
X   // in which case '/' is returned).
X   FileName GetDirectory() const;
X
X   // Return just the base name minus any leading directory info (if name is
X   // '/', return '/').
X   FileName GetBasename() const;
X
X   // Look for the last '.' character in the basename and return that string
X   // (including the '.'). If there is no '.' return a pointer to an empty
X   // string (not a null pointer).
X   FileName GetSuffix() const;
X
X   // Return the basename (like previous function), but if the trailing part
X   // of the basename matches the specified suffix string then strip the
X   // suffix (the suffix string must include any "." you want to strip)
X   FileName GetBasename(const char * suffix) const;
X
X   // Given filename 'dir', generate a relative pathname string which would
X   // reference this file if the current directory were 'dir'
X   //
X   // If the first component of both names is not the same, then there is no
X   // common path to relate the names and we return a FileName with a NULL
X   // filename pointer (the Error() function will report TRUE).
X   FileName GetNameRelativeTo(const FileName& dir) const;
X
X   // Return TRUE if the name is in error (NULL or empty).
X   int Error() const {return ((filename == NULL) || (filename[0] == '\0')); };
X
X   // Return TRUE if the name is an absolute name (first char is '/').
X   int Absolute() const {return ((! Error()) && (filename[0] == '/')); };
X
X   // Return TRUE if the name is a relative name (first char is not '/').
X   int Relative() const {return ((! Error()) && (filename[0] != '/')); };
X
X   // Return TRUE if the filename matches the shell wildcard pattern
X   int WildMatch(const char * pattern) const;
X};
X
X#endif /* filename_h_ */
END_OF_FILE
if test 4960 -ne `wc -c <'filename.h'`; then
    echo shar: \"'filename.h'\" unpacked with wrong size!
fi
# end of 'filename.h'
fi
if test -f 'hypertext.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hypertext.c'\"
else
echo shar: Extracting \"'hypertext.c'\" \(5082 characters\)
sed "s/^X//" >'hypertext.c' <<'END_OF_FILE'
X#include <InterViews/textbuffer.h>
X#include <InterViews/textdisplay.h>
X#include <InterViews/event.h>
X#include "hypertext.h"
X
Xextern "C" void printf(const char *, ...);
X
Xvoid
XHyperTextLink::AddStyle()
X{
X   if (htep->text) {
X      htep->display->AddStyle(
X         htep->text->LineNumber(position),
X         htep->text->LineOffset(position),
X         htep->text->LineNumber(position + length - 1),
X         htep->text->LineOffset(position + length - 1),
X         style
X      );
X   }
X}
X
Xvoid
XHyperTextLink::RemoveStyle()
X{
X   if (htep->text) {
X      htep->display->RemoveStyle(
X         htep->text->LineNumber(position),
X         htep->text->LineOffset(position),
X         htep->text->LineNumber(position + length - 1),
X         htep->text->LineOffset(position + length - 1),
X         style
X      );
X   }
X}
X
XHyperTextLink::HyperTextLink(
X   HyperTextEditor * hte,
X   int p,
X   int l,
X   int s)
X{
X   htep = hte;
X   position = p;
X   length = l;
X   style = s;
X   next = *hte->link_list_end;
X   *hte->link_list_end = this;
X   hte->link_list_end = &next;
X   AddStyle();
X}
X
XHyperTextLink::~HyperTextLink()
X{
X   if (! htep->dying) RemoveStyle();
X   for (HyperTextLink ** cfp = &htep->link_list;
X        *cfp != nil; 
X        cfp = &(*cfp)->next) {
X      if (*cfp == this) {
X         *cfp = next;
X         return;
X      }
X   }
X}
X
Xvoid
XHyperTextEditor::InsertText(const char* stuff, int len)
X{
X   pre_edit_mods(Dot(), 0, len);
X   TextEditor::InsertText(stuff, len);
X   post_edit_mods();
X}
X
Xvoid
XHyperTextEditor::DeleteText(int len)
X{
X   int start = Dot();
X   int finish = start;
X   int c = len;
X   while (c > 0) {
X       finish = text->NextCharacter(finish);
X       --c;
X   }
X   while (c < 0) {
X       start = text->PreviousCharacter(start);
X       ++c;
X   }
X   int count = finish - start;
X   pre_edit_mods(start, count, 0);
X   TextEditor::DeleteText(len);
X   post_edit_mods();
X}
X
Xvoid
XHyperTextEditor::DeleteSelection()
X{
X   if (Mark() != Dot()) {
X       DeleteText(Mark() - Dot());
X   }
X}
X
Xint
XHyperTextEditor::FollowAllLinks(Event& ev)
X{
X   int followed_one = 0;
X   ev.target->GetRelative(ev.x, ev.y, this);
X   int curpos = Locate(ev.x, ev.y);
X   for (HyperTextLink * lp = link_list; lp != nil; lp = lp->next) {
X      if ((curpos >= lp->position) && (curpos < (lp->position + lp->length))) {
X         followed_one = 1;
X         lp->FollowLink();
X      }
X   }
X   if (followed_one) {
X      do {
X         Poll(ev);
X      } while (ev.leftmouse);
X   }
X   return followed_one;
X}
X
XHyperTextEditor::~HyperTextEditor()
X{
X   dying = 1;
X   while (link_list != nil) delete link_list;
X}
X
X// When editing a new buffer, destroy any existing links first...
Xvoid
XHyperTextEditor::Edit(TextBuffer* tbp, int x)
X{
X   dying = 1;
X   while (link_list != nil) delete link_list;
X   dying = 0;
X   init_hte();
X   TextEditor::Edit(tbp, x);
X}
X
Xvoid
XHyperTextEditor::pre_edit_mods(int pos, int oldlen, int newlen)
X{
X   HyperTextLink * np;
X   for (HyperTextLink * lp = link_list; lp != nil; lp = np) {
X      np = lp->next;
X      lp->re_style = 0;
X      if (lp->position + lp->length <= pos) {
X         /* this link comes totally prior to all edit activity,
X          * do nothing to it at all.
X          */
X         ;
X      } else if (lp->position >= pos + oldlen) {
X         /* this link occurs completely following the edit activity,
X          * adjust its position, but do nothing else.
X          *
X          * (I think this works, the question is: Does the textdisplay
X          * class correcly update the position of existing text displayed
X          * in other than the default style?).
X          */
X         lp->position -= oldlen - newlen;
X      } else {
X         /* This link overlaps the editing activity in some way. Remove
X          * any special styling associated with the link, then re-compute
X          * the extent of the link.
X          */
X         lp->RemoveStyle();
X         lp->re_style = 1;
X         if (pos <= lp->position &&
X             (lp->position + lp->length) <= (pos + oldlen)) {
X            /* The link is completely consumed by the editing
X             * operation, just delete it.
X             */
X            delete lp;
X         } else if (lp->position <= pos &&
X                    (pos + oldlen) <= (lp->position + lp->length)) {
X            /* The editing operation occurs entirely within the link,
X             * just change the size of the link.
X             */
X            lp->length -= oldlen;
X            lp->length += newlen;
X         } else if (pos <= lp->position) {
X            /* Need to chop the head off the link, moving up the
X             * position and decreasing the length.
X             */
X            int endpos = lp->position + lp->length;
X            lp->position = pos + oldlen;
X            lp->length = endpos - lp->position;
X         } else {
X            /* Need to chop the tail off the link, decreasing the length.
X             */
X            lp->length = pos - lp->position;
X         }
X      }
X   }
X}
X
Xvoid
XHyperTextEditor::post_edit_mods()
X{
X   for (HyperTextLink * lp = link_list; lp != nil; lp = lp->next) {
X      if (lp->re_style) lp->AddStyle();
X   }
X}
END_OF_FILE
if test 5082 -ne `wc -c <'hypertext.c'`; then
    echo shar: \"'hypertext.c'\" unpacked with wrong size!
fi
# end of 'hypertext.c'
fi
if test -f 'hypertext.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hypertext.h'\"
else
echo shar: Extracting \"'hypertext.h'\" \(2977 characters\)
sed "s/^X//" >'hypertext.h' <<'END_OF_FILE'
X#include <InterViews/texteditor.h>
X
Xclass HyperTextEditor;
Xclass Event;
X
X
X// A HyperTextLink is an abstract class used to track links in a
X// HyperTextEditor class. A button press on an area of text designated as a
X// link will invoke the FollowLink member function.
X//
X// To actually use a hypertext class you must make a customized version of
X// the HyperTextLink node that implements some action for FollowLink.
X
Xclass HyperTextLink {
X   friend class HyperTextEditor;
Xpublic:
X   virtual void FollowLink(void) = 0;
X
X   HyperTextLink(
X      HyperTextEditor * hte,
X      int p,
X      int l,
X      int s=(int)Plain
X   );
X
X   virtual ~HyperTextLink();
X
Xprivate:
X   // keep list of links for a HyperTextEditor
X   HyperTextLink *  next;
X
X   // point back to HyperTextEditor I am attached to.
X   HyperTextEditor * htep;
X
X   // Position and style information for the link itself.
X   int position;
X   int length;
X   int style;
X
X   int re_style;
X
X   void AddStyle();
X   void RemoveStyle();
X};
X
X
X// A HyperTextEditor is a class derived from a TextEditor. It provides all
X// the features of a TextEditor class, but adds a list of HyperTextLinks
X// which are represented as areas of text drawn in various styles.
X//
X// Inserts and deletes are automatically captured and the positions of
X// the HyperTextLinks are updated appropriately.
X
Xclass HyperTextEditor : public TextEditor {
X   friend class HyperTextLink;
Xpublic:
X   // Re-define the text insertion/deletion primitives (actually these
X   // should be virtual in the TextEditor, but they are not). These
X   // call the TextEditor:: versions, but also update the positions
X   // of any links that moved due to insertion or deletion...
X   //
X   // If a deletion includes every character in the span of a link, then the
X   // link is also deleted. If an insertion is within a link, then the link
X   // is expanded.
X   void InsertText(const char*, int);
X   void DeleteText(int);
X   void DeleteSelection();
X   void Edit(TextBuffer*, int index = 0);
X
X   // Given an event, follow any links that include the events (x,y)
X   // coordinates within their position and length. Return TRUE if
X   // any links were followed.
X   int FollowAllLinks(Event& ev);
X   int FollowAllLinks(Event * evp) {return FollowAllLinks(*evp);};
X
X   // Constructors work just like TextEditor, but also initialize
X   // the linked list of HyperTextLinks to empty.
X   HyperTextEditor(int rows, int cols, int tabsize, int highlight)
X      : TextEditor(rows, cols, tabsize, highlight)
X      { init_hte(); };
X   HyperTextEditor(const char* name, int r, int c, int t, int h)
X      : TextEditor(name, r, c, t, h)
X      { init_hte(); };
X
X   // The destructor destroys all of the links.
X   virtual ~HyperTextEditor();
Xprivate:
X   int dying;
X   HyperTextLink * link_list;
X   HyperTextLink ** link_list_end;
X   void init_hte()
X      { link_list = nil; link_list_end = &link_list; dying=0; };
X   void pre_edit_mods(int pos, int oldlen, int newlen);
X   void post_edit_mods();
X};
END_OF_FILE
if test 2977 -ne `wc -c <'hypertext.h'`; then
    echo shar: \"'hypertext.h'\" unpacked with wrong size!
fi
# end of 'hypertext.h'
fi
if test -f 'info.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'info.h'\"
else
echo shar: Extracting \"'info.h'\" \(9095 characters\)
sed "s/^X//" >'info.h' <<'END_OF_FILE'
X#ifndef info_h
X#define info_h
X
X// Class definitions for an emacs "info" format browser:
X//
X// Classes that should be of primary interest are:
X//
X//   InfoRoot - central point of access to info nodes.
X//      GetNode() - used to retrieve nodes from info system.
X//
X//   InfoNode - the GetNode function returns a pointer to one of these.
X//      Text() - access the body of the node.
X//      Length() - get the length of the node.
X//      FirstLink() - return first element in list of links to other nodes.
X//
X//   InfoLink - the FirstLink function returns a pointer to this.
X//      GetNode() - return offset of node reference within node body.
X//      GetNodeLength() - return length of node reference.
X//
X// various other things of interest may be found by browsing through the
X// rest of this file.
X
X#include "filename.h"
X
X#ifndef NULL
X#define NULL 0
X#endif
X
Xclass InfoFileBuffer {
Xpublic:
X   InfoFileBuffer(const FileName& fn) :
X      file_name(fn), status(0), point_max(0), text(NULL) {};
X   char * Text(int offset=0)
X      {
X         if (text == NULL) get_text();
X         if (offset < 0) offset = 0;
X         if (offset > point_max) offset=point_max;
X         return text + offset;
X      };
X   int ForwardChar(int offset, int count=1)
X      {
X         int newoff = offset + count;
X
X         if (newoff > PointMax()) {
X            newoff = PointMax();
X         } else if (newoff < 0) {
X            newoff = 0;
X         }
X         return newoff;
X      };
X   int BackwardChar(int offset, int count=1)
X      {
X         return ForwardChar(offset, - count);
X      };
X   int ForwardLine(int offset, int count=1);
X   int BackwardLine(int offset, int count=1);
X   int EndOfLine(int offset);
X   int BeginningOfLine(int offset);
X   int ForwardNode(int offset, int count=1);
X   int BackwardNode(int offset, int count=1);
X   int EndOfNode(int offset);
X   int BeginningOfNode(int offset);
X   int LookingAtNode(int offset);
X   int LookingAtNodeEnd(int offset);
X   int PointMin() { return 0; };
X   int PointMax() { if (text == NULL) get_text(); return point_max; };
X   char CharAfter(int offset) { return * Text(offset); };
X   int Ok() { return status == 0; };
X   const char * GetFileName() { return (const char *)file_name; };
X   int ScanHeader(int offset,
X      int& name_off, int& name_len,
X      int& prev_off, int& prev_len,
X      int& up_off,   int& up_len,
X      int& next_off, int& next_len,
X      const char * terminator="\t,\n");
X   ~InfoFileBuffer();
Xprotected:
X   FileName file_name;
X   int status;
Xprivate:
X   int point_max;
X   void get_text();
X   char * text;
X};
X
Xclass InfoSubFile : public InfoFileBuffer {
Xpublic:
X   InfoSubFile(const FileName& fn, int offset) :
X      InfoFileBuffer(fn), info_offset(offset), first_node_offset(-1) {};
X   int InfoOffset() { return info_offset; };
X   int FirstNodeOffset()
X      { if (first_node_offset == -1) get_first(); return first_node_offset; };
Xprivate:
X   int info_offset;
X   int first_node_offset;
X   void get_first() { first_node_offset = ForwardNode(0); };
X};
X
Xclass InfoNode;
Xclass InfoLink;
X
Xclass InfoFile : public InfoSubFile {
Xpublic:
X   InfoFile(const FileName& fn) :
X      InfoSubFile(fn, 0), last_scan_offset(-1), sub_file_count(0),
X      node_list(NULL), last_re(NULL)
X      { do_init(); };
X   InfoNode * GetNode(const char * node_name);
X   ~InfoFile();
X   int ReSearch(const char * re, InfoNode * & found_node, int & found_offset);
X   int ReSearchAgain(InfoNode * & found_node, int & found_offset);
Xprivate:
X   friend class InfoNode;
X   void do_init();
X   int sub_file_count;
X   InfoSubFile * * sub_file;
X   InfoNode * node_list;
X   int last_scan_offset;
X   int last_re_offset;
X   char * last_re;
X};
X
Xclass InfoNode {
Xpublic:
X   // Use this constructor to create a node from a tag table entry
X   // where we are not real sure of the address of the actual node
X   // in the file.
X   InfoNode(
X      InfoFile * root,
X      const char * name,
X      int tentative_offset,
X      InfoNode * n
X   );
X   // Use this constructor to create a node during an actual scan of
X   // an info file - it knows exactly where it is.
X   InfoNode(
X      InfoFile * root,
X      InfoSubFile * fil,
X      int node_offset,
X      int nameoff,
X      int namelen,
X      InfoNode * n
X   );
X   // Use this construction to select an entire file as a node (used
X   // for the node name "*").
X   InfoNode(
X      InfoFile * root,
X      InfoNode * n
X   );
X
X   // Return a pointer to the text of the node.
X   char * Text();
X
X   // Return the length (in bytes) of the node text string.
X   int Length();
X
X   // Return the first link in the list of links to other nodes.
X   InfoLink * FirstLink()
X   {
X      if (link_list == NULL) ScanLinks();
X      return link_list;
X   };
X   InfoNode * GetNext() { return next; };
X   char * GetName() { return node_name; };
X   const char * GetFileName() { return root_file->GetFileName(); };
X   ~InfoNode();
Xprivate:
X   InfoFile * root_file;
X   InfoSubFile * sub_file;
X   char * node_name;
X   int offset;
X   int length;
X   InfoNode * next;
X   void where_am_i();
X   void ScanLinks();
X   int ScanRef(
X      int foundoff,
X      int& nameoff,
X      int& namelen,
X      int& nodeoff,
X      int& nodelen,
X      int  isxref=0
X   );
X   InfoLink * link_list;
X   int missing;
X};
X
X// Each node may have a list of references to other nodes in it as
X// Up, Next, Previous pointers, menu items, or cross reference items.
X// This class is used to access the links.
Xenum InfoLinkKind
X   { InfoLinkUp, InfoLinkPrev, InfoLinkNext, InfoLinkMenu, InfoLinkNote };
Xclass InfoLink {
Xpublic:
X   // Use this when link name is terminated by length
X   InfoLink(const char * name, int nl, int node, int nol, InfoLink * nxt,
X            InfoLinkKind lk);
X   // Use this when link name is null terminated string
X   InfoLink(const char * name, int node, int nol, InfoLink * nxt,
X            InfoLinkKind lk);
X   ~InfoLink();
X
X   // Return the string name of the link
X   char * GetName() { return ref_name; };
X   // Return the offset of the node reference relative to the start of the node.
X   int    GetNode() { return ref_node; };
X   // Return the length of the node reference.
X   int    GetNodeLength() { return ref_node_len; };
X   // Return the next link in the list of links.
X   InfoLink * GetNext() { return next; };
X   // Return the kind of link this is.
X   InfoLinkKind GetLinkKind() { return link_kind; };
Xprivate:
X   char * ref_name;
X   int    ref_node;
X   int    ref_node_len;
X   InfoLinkKind link_kind;
X   InfoLink * next;
X};
X
Xclass InfoRoot;
X
Xclass InfoFileList {
Xfriend class InfoRoot;
X   InfoFileList(InfoFile * f, InfoFileList * n) :
X      next(n), file(f) {};
X   InfoFileList * next;
X   InfoFile *     file;
X};
X
Xclass InfoDirList {
Xfriend class InfoRoot;
X   InfoDirList(FileName d, InfoDirList * n) :
X      next(n), dir(d) {};
X   InfoDirList * next;
X   FileName      dir;
X};
X
Xclass InfoHistory {
Xpublic:
X   InfoHistory(InfoRoot *, InfoNode *);
X   ~InfoHistory();
X   // Get node at top of history list
X   InfoNode * GetNode();
Xprivate:
X   InfoRoot * history_root;
X   InfoHistory * prev;
X   char * node_name;
X};
X
X#define DEFAULT_INFO_PATH "/usr/lib/emacs/info:."
X#define INFO_PATH         "INFO_PATH"
X
X// InfoRoot is the root of the info tree. Typically the info browser is
X// used by declaring one InfoRoot instance then doing GetNode() calls on
X// it. It remembers the most recently referenced file, so node references
X// without a file specified part are looked up in the last file seen.
X//
X// If you want to maintain multiple threads and need more than one "last
X// file" you can declare multiple InfoRoot instances (but don't worry, they
X// all share the same file buffers, so you only read the file once).
X//
X// The browser finds info files (that are not absolute names) by looking
X// through a search list of directories. The default search list is defined
X// above (DEFAULT_INFO_PATH) and a different default may be given by setting
X// the INFO_PATH environment variable. New directories can be appended to
X// the search path using the AddInfoDirectory member function (the search
X// path is shared across all instances of InfoRoot, maybe it shouldn't be?).
X
Xclass InfoRoot {
Xfriend class InfoHistory;
Xpublic:
X   InfoRoot(const char * ipath = NULL);
X   ~InfoRoot();
X   // Add a directory name to the end of the info directory search path
X   void AddInfoDirectory(FileName& d);
X   // Parse a node specifier string and retrieve the node.
X   InfoNode * GetNode(const char * node_name);
X   // Pop an entry off path history
X   InfoNode * PopHistory();
X   // Search for RE from beginning of current file.
X   int ReSearch(const char * re, InfoNode * & found_node, int & found_offset);
X   // Search for same RE again from where the last search left off.
X   int ReSearchAgain(InfoNode * & found_node, int & found_offset);
X   // Return pointer to current node
X   InfoNode * GetLastNode() { return last_node; };
Xprivate:
X   static int root_count;
X   static InfoDirList *  info_dir_path;
X   static InfoFileList * info_file_list;
X   InfoFile *            last_file;
X   InfoHistory *         prev_node;
X   InfoNode *            last_node;
X};
X
X#endif /* info_h */
END_OF_FILE
if test 9095 -ne `wc -c <'info.h'`; then
    echo shar: \"'info.h'\" unpacked with wrong size!
fi
# end of 'info.h'
fi
if test -f 'istring.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'istring.h'\"
else
echo shar: Extracting \"'istring.h'\" \(1772 characters\)
sed "s/^X//" >'istring.h' <<'END_OF_FILE'
X/*
X * Copyright (c) 1987, 1988, 1989 Stanford University
X *
X * Permission to use, copy, modify, distribute, and sell this software and its
X * documentation for any purpose is hereby granted without fee, provided
X * that the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of Stanford not be used in advertising or
X * publicity pertaining to distribution of the software without specific,
X * written prior permission.  Stanford makes no representations about
X * the suitability of this software for any purpose.  It is provided "as is"
X * without express or implied warranty.
X *
X * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
X * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
X * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
X * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
X * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X */
X
X// $Header: istring.h,v 1.8 89/10/09 14:48:29 linton Exp $
X// extends <string.h> to define strdup and strndup too.
X
X#ifndef istring_h
X#define istring_h
X
X#include <string.h>
X
X// strdup allocates and returns a duplicate of the given string.
X
Xinline char* strdup (const char* s) {
X    char* dup = new char[strlen(s) + 1];
X    strcpy(dup, s);
X    return dup;
X}
X
X// strndup allocates and returns a duplicate of the first len
X// characters of the given string.
X
Xinline char* strndup (const char* s, int len) {
X    char* dup = new char[len + 1];
X    strncpy(dup, s, len);
X    dup[len] = '\0';
X    return dup;
X}
X
X#endif
END_OF_FILE
if test 1772 -ne `wc -c <'istring.h'`; then
    echo shar: \"'istring.h'\" unpacked with wrong size!
fi
# end of 'istring.h'
fi
if test -f 'yesorno.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'yesorno.c'\"
else
echo shar: Extracting \"'yesorno.c'\" \(1272 characters\)
sed "s/^X//" >'yesorno.c' <<'END_OF_FILE'
X// Provide a pop-up dialog for answering a yes or no question.
X
X#include <InterViews/button.h>
X#include <InterViews/box.h>
X#include <InterViews/dialog.h>
X#include <InterViews/glue.h>
X#include <InterViews/message.h>
X#include <InterViews/frame.h>
X
X#include "yesorno.h"
X
Xboolean
XYesOrNo(
X   Event&       e,
X   const char * question,
X   const char * yes_label,
X   const char * no_label,
X   boolean      ding)
X{
X   const char *  q = question ? question : "?";
X   ButtonState * answer = new ButtonState;
X   Dialog *      converse = new Dialog(answer,
X      new Frame(
X         new VBox(
X            new VGlue(round(.125*inch)),
X            new HBox(new HGlue(round(.125*inch), 0),
X                     new Message(q),
X                     new HGlue(round(.25*inch), hfil)
X            ),
X            new VGlue(round(.25*inch)),
X            new HBox(new HGlue(round(.25*inch), hfil),
X                     new PushButton(yes_label, answer, 1),
X                     new HGlue(round(.25*inch), 0),
X                     new PushButton(no_label, answer, -1),
X                     new HGlue(round(.125*inch), 0)
X            ),
X            new VGlue(round(.125*inch))
X         )
X      )
X   );
X   boolean rval = converse->Popup(e);
X   delete converse;
X   delete answer;
X   return rval;
X}
END_OF_FILE
if test 1272 -ne `wc -c <'yesorno.c'`; then
    echo shar: \"'yesorno.c'\" unpacked with wrong size!
fi
# end of 'yesorno.c'
fi
if test -f 'yesorno.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'yesorno.h'\"
else
echo shar: Extracting \"'yesorno.h'\" \(283 characters\)
sed "s/^X//" >'yesorno.h' <<'END_OF_FILE'
X// Interface to YesOrNo popup dialog box.
X
X#ifndef yesorno_h
X#define yesorno_h
X
Xclass Event;
X
Xextern boolean YesOrNo(
X   Event&       e,
X   const char * question,
X   const char * yes_label = "Yes",
X   const char * no_label = "No",
X   boolean      ding = 0
X);
X
X#endif /* yesorno_h */
END_OF_FILE
if test 283 -ne `wc -c <'yesorno.h'`; then
    echo shar: \"'yesorno.h'\" unpacked with wrong size!
fi
# end of 'yesorno.h'
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    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
======================================================================
domain: tahorsley@csd.harris.com       USMail: Tom Horsley
  uucp: ...!uunet!hcx1!tahorsley               511 Kingbird Circle
                                               Delray Beach, FL  33444
+==== Censorship is the only form of Obscenity ======================+
|     (Wait, I forgot government tobacco subsidies...)               |
+====================================================================+

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.