#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	README
#	buttons.c
#	config.h
#	copyright.h
#	dialogue.c
#	dialogue.cursor
#	dialogue_mask.cursor
#	extern.c
#	main.c
#	man.c
#	menus.c
#	redisplay.c
#	shar.sh
#	xman.h
#	xman.icon
#	xman.n
#	xman_mask.icon
#	diff-c.sxEntry
# This archive created: Fri Jan 16 12:59:25 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(355 characters)'
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
sed 's/^X//' << \SHAR_EOF > 'Makefile'
XCFLAGS=-O
XLDFLAGS=
XLIBES=-lSx -lX
XOBJS=main.o dialogue.o buttons.o man.o menus.o redisplay.o
X
Xxman:		${OBJS}
X		cc ${LDFLAGS} ${OBJS} -o xman ${LIBES}
Xmain.o:		main.c config.h xman.h extern.c
Xdialogue.o:	dialogue.c
Xbuttons.o:	buttons.c config.h xman.h
Xman.o:		man.c config.h xman.h
Xmenus.o:	menus.c config.h xman.h
Xredisplay.o:	redisplay.c config.h xman.h
SHAR_EOF
if test 355 -ne "`wc -c 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 355 characters)'
fi
echo shar: extracting "'README'" '(1577 characters)'
if test -f 'README'
then
	echo shar: over-writing existing file "'README'"
fi
sed 's/^X//' << \SHAR_EOF > 'README'
X
XThis is a preliminary version of 'xman', an X-windows oriented manual
Xtool. It uses the Sx library and was written using X Version 10
XRelease 4.
X
XUnfortunately it relies upon a bug fix in the Sx library, in file
XsxEntry.c it is assumed that XLookupMapping() returns a pointer to a
Xnull-terminated string which is utterly false.  I provide a diff -c in
Xfile 'diff-c.sxEntry.c' with this distribution.
X
XThere are numerous heuristics in this program which think they know
Xhow manual entries are arranged and formatted on a 4.2 system, if
Xthings don't work for you please send me mail trying to describe the
Xproblem and I'll think about what wasn't general enough. If you use a
XSYS/V or other non-4.2 manual directory setup you will, at a minimum,
Xhave to re-work 'man.c'. If you have formatted man pages on the system
Xwhich aren't 66 lines/page you may have to rework a few numbers in the
Xprogram. Fonts are a minor problem as the window barely fits on a SUN
Xscreen with a 10 point font, I have not tried this program on any
Xother bitmap screen, hopefully it will fit (otherwise may have to go
Xto an even smaller font, which might be uncomfortable, or implement
Xscroll-bars, ugh, it'll be a fair amount of work to little advantage
Xin my opinion.)
X
XYou may have to go into main.c and edit the paths in which cursors are
Xto be found, I use either standard X supplied cursors or something
Xlocal in this directory. This should be minor.
X
XOther than that, have fun, I've always thought something like this
Xought to exist.
X
X	-Barry Shein, Boston University (BZS@BU-CS.BU.EDU)
X	 1/7/87
SHAR_EOF
if test 1577 -ne "`wc -c 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1577 characters)'
fi
echo shar: extracting "'buttons.c'" '(5059 characters)'
if test -f 'buttons.c'
then
	echo shar: over-writing existing file "'buttons.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'buttons.c'
X#include "xman.h"
X
X/*
X * Various menu routines
X */
X
X/*
X * Called when a mouse button goes down in the TEXT window,
X * which is a pseudo-menu when displaying manual sections.
X */
X
X/*ARGSUSED*/
Xvoid
XMyButtonProc(clientData,eventp) ClientData clientData; XEvent *eventp;
X{
X  Window subw;
X  int mousex, mousey;
X  register struct manual *mp = &manual[section];
X  int x,y;
X  static int lastx, lasty;
X  short int state;
X  static struct entry *ep;
X  int i;
X  char manname[128];
X  extern char *prepEntry();
X
X  /* are we just displaying a man page? */
X  if(manualing) {
X    if(eventp->type == ButtonPressed) {
X      XQueryMouseButtons(w,&mousex,&mousey,&subw,&state);
X
X      /*
X       * 1  means try to go forward a page (left button)
X       * -1 means back a page (middle button)
X       */
X      if(state & LeftMask) {
X	ReDisplayProc((ClientData) 1,eventp);
X	return;
X      }
X      else if(state & MiddleMask) {
X	ReDisplayProc((ClientData) -1,eventp);
X	return;
X      }
X    }
X    return;
X  }
X  /*
X   * We have man SECTIONS in the window, treat as a menu
X   */
X  XQueryMouseButtons(w,&mousex,&mousey,&subw,&state);
X  /* find row and column mouse is in */
X  x = (mousex - mp->startx)/mp->width;
X  y = (mousey - mp->starty)/mp->height;
X  /*
X   * Left button down means a selection
X   */
X  if((eventp->type == ButtonPressed) || (eventp->type == MouseMoved)) {
X    if(!(state & LeftMask)) return; /* ignore other buttons for now */
X
X    if((mousex < mp->startx) || (mousey < mp->starty)
X       || ((i = x+y*mp->ncols) >= mp->nentries))
X      return;				/* mouse is out of range */
X    /*
X     * See if we need to uninvert a previous selection
X     */
X    if((ep != NULL) && (eventp->type == MouseMoved)) {
X      if(ep == &mp->entries[i])
X	return;				/* same as last pick */
X      putstr(w,
X	     lastx*mp->width+mp->startx,
X	     lasty*mp->height+mp->starty,
X	     prepEntry(ep->label,mp->colpad),bodynormal,0);
X    }
X    /*
X     * Ok, they selected something, invert it
X     */
X    ep = &mp->entries[i];
X    putstr(w,
X	   x*mp->width+mp->startx,
X	   y*mp->height+mp->starty,
X	   prepEntry(ep->label,mp->colpad),bodynormal,1);
X    lastx = x;
X    lasty = y;
X  }
X  else if((eventp->type == ButtonReleased) && (ep != NULL)) {
X    /*
X     * On button released actually invoke the selection (display man page)
X     */
X
X    /* uninvert for feedback */
X    putstr(w,
X	   lastx*mp->width+mp->startx,
X	   lasty*mp->height+mp->starty,
X	   prepEntry(ep->label,mp->colpad),bodynormal,0);
X    /*
X     * Whoops, out of range, treat it as a "cancel previous down button"
X     * so they can select and drag with mouse down to some ridiculous
X     * place to change their minds.
X     */
X    if((mousex < mp->startx) || (mousey < mp->starty)
X       || ((i = x+y*mp->ncols) >= mp->nentries))
X      return;				/* mouse is out of range */
X    /*
X     * Ok, we got one, see if it's cat'able
X     */
X    if(mp->cat) {
X      sprintf(manname,"%s/%s",mp->cat,ep->label);
X      if((manfp = fopen(manname,"r")) == NULL) {
X	XClear(w);
X	putstr(w,mincol,minrow,"Sorry, couldn't find that man page.",
X	       bodybold,0);
X	XFlush();
X	return;
X      }
X      mantmp[0] = '\0';
X    }
X    else {	/* have to format the man page */
X      char cmd[128];
X
X      XClear(w);
X      putstr(w,mincol,minrow,"Formatting entry...",bodybold,0);
X      XFlush();
X      sprintf(manname,"%s/%s",mp->man,ep->label);
X      strcpy(mantmp,TMPFILE);
X      mktemp(mantmp);
X      sprintf(cmd,MANFMT,manname,mantmp);
X      if((system(cmd) != 0) || (manfp = fopen(mantmp,"r")) == NULL) {
X	XClear(w);
X	putstr(w,mincol,minrow,"Something went wrong, sorry.",bodybold,0);
X	XFlush();
X	unlink(mantmp);
X	return;
X      }
X    }
X    manualing = 1;		/* need to remember current state of display */
X    pagetell[0] = 0;		/* first page @lseek location zero */
X    curpage = 0;
X    ep = NULL;			/* no entry currently selected */
X    XDefineCursor(w,xpage_cursor);
X    ReDisplayProc((ClientData) 0,eventp);
X    /* it's ok that it's still open, at least on UNIX */
X    if(mantmp[0] != '\0') unlink(mantmp);
X  }
X  return;
X}
X/*
X * Called when the user selects QUIT from the Options menu
X */
Xvoid
XFinis()
X{
X  exit(0);
X}
X/*
X * The apropos Option from the menu
X * Right now I just run apropos (various config dependant stuff
X * in config.h) into a file and paginate that to the display.
X * I guess we could re-implement a search of /usr/man/whatis ourselves,
X * I dunno...
X */
Xvoid
XApropos()
X{
X  char buf[APROPOSLEN+1];
X  char cmdbuf[100+APROPOSLEN+1];
X
X  buf[0] = '\0';
X  if(DialogueBox(w,"Apropos? ",buf,APROPOSLEN+1,NULL,NULL) == NULL)
X    return;
X  strcpy(mantmp,TMPFILE);
X  mktemp(mantmp);
X  sprintf(cmdbuf,"%s %s | %s > %s",APROPOS,buf,APROPOSFILTER,mantmp);
X  if(system(cmdbuf) != 0) {
X    eprintf("Something went wrong trying to run %s\n",cmdbuf);
X    return;
X  }
X  if(manfp != NULL)
X    fclose(manfp);
X  if((manfp = fopen(mantmp,"r")) == NULL) {
X    eprintf("lost temp file? out of temp space?\n");
X    return;
X  }
X  unlink(mantmp);
X  mantmp[0] = '\0';
X  manualing = 1;
X  pagetell[0] = 0;
X  curpage = 0;
X  XDefineCursor(w,xpage_cursor);
X  return;
X}
SHAR_EOF
if test 5059 -ne "`wc -c 'buttons.c'`"
then
	echo shar: error transmitting "'buttons.c'" '(should have been 5059 characters)'
fi
echo shar: extracting "'config.h'" '(3002 characters)'
if test -f 'config.h'
then
	echo shar: over-writing existing file "'config.h'"
fi
sed 's/^X//' << \SHAR_EOF > 'config.h'
X/*
X * Easily configurable options to xman, see also extern.c
X */
X
X#define MANDIR "/usr/man/"	/* root directory for manuals */
X#define MAXSECT 12		/* maximum sections such as 1,2,3,n,l */
X#define MAXENTRY 500		/* max individual man entries like cat.1 */
X#define MAXPAGES 100		/* max pages in an entry */
X#define MAN "man"		/* manual directory prefix (man1,man2...) */
X#define LMAN 3			/* length for strcmpn */
X#define CAT "cat"		/* preformatted dir prefix (cat1,cat2...) */
X#define LCAT 3			/* length for strcmpn */
X
X#define WHATIS "/usr/man/whatis"/* for apropos */
X#define APROPOS_LABEL "Keyword: "
X
X#define TITLEFONT "helv12b"	/* font used for title bar */
X#define TITLEBORDER 1		/* border width of title bar */
X
X#define MENUFONT "helv12"	/* font used in the pull-down menus */
X
X/*
X * These are the fonts used in displaying both manual pages and
X * the menu of manual pages. Consequently, it's not as changeable
X * as one might hope. 12 point or larger just won't allow the entire
X * thing to fit in a window. I suppose one could use scrollable windows
X * but I think if you add that you'll find it's still not quite what you
X * want (it's annoying to read something scrolling 1/3 of a page up/down.)
X * Of course, a different 10 point (or smaller) font should be fine, so I
X * put this here.
X */
X#define BODYNORMAL "timrom10"
X#define BODYBOLD "timrom10b"
X#define BODYITALIC "timrom10i"
X
X/*
X * In order to make the cat'd man pages look "pretty" we look for
X * lines which only contain one of the following strings (case dependant)
X * and display them in bold. You might want to modify the list, I should
X * probably write a sed script or something that just plucks these out
X * of the .SH macros definitions. Anyhow, it doesn't much matter if you
X * miss one, so it won't be bold, so what.
X */
Xextern char *keywords[];	/* in extern.c */
X
X/*
X * This is actually tuned so that both the menus and pages will fit
X * in the same window, you might want to make the whole thing more
X * sophisticated, but this is it for now. It would be harmless to make
X * it wider (NCHARS) but narrower will mean that the menus may not fit
X * and shorter/longer will screw up the paging.
X */
X#define NLINES 66
X#define NCHARS 100
X
X#define BACKSPACE 010	/* I doubt you'll need to change this */
X#define MINCOL 15	/* indent text a little */
X
X#define SECTION "Section"	/* what the section menu item will say */
X#define OPTIONS "Options"	/* what the options menu item will say */
X
X/* the following is for building the Section menu */
X
X/*
X * As we find manx or catx directories we will look in here
X * for suggested pull-down menu labels
X */
X
Xextern struct sectionNames {
X  char *dirname;
X  char *label;
X} sectionNames[];	/* init in extern.c */
X
X#define DEF_FOREGROUND	BlackPixmap
X#define DEF_BACKGROUND	WhitePixmap
X
X#define TMPFILE "/tmp/t.MANXXXXXX"
X
X/*
X * The command to format a man page, sprintf'd with
X * the input and output (tmp) file (in that order) then
X * passed to system().
X */
X
X#define MANFMT "nroff -man %s > %s"
SHAR_EOF
if test 3002 -ne "`wc -c 'config.h'`"
then
	echo shar: error transmitting "'config.h'" '(should have been 3002 characters)'
fi
echo shar: extracting "'copyright.h'" '(303 characters)'
if test -f 'copyright.h'
then
	echo shar: over-writing existing file "'copyright.h'"
fi
sed 's/^X//' << \SHAR_EOF > 'copyright.h'
X/*
X * Copyright (c) 1987 Barry Shein (BZS@BU-CS.BU.EDU)
X * Right is hereby granted to distribute either modified
X * or unmodified versions of this program in source form
X * as long as this copyright notice is intact. May not
X * be re-sold for profit without explicit arrangement
X * with the author.
X */
SHAR_EOF
if test 303 -ne "`wc -c 'copyright.h'`"
then
	echo shar: error transmitting "'copyright.h'" '(should have been 303 characters)'
fi
echo shar: extracting "'dialogue.c'" '(9252 characters)'
if test -f 'dialogue.c'
then
	echo shar: over-writing existing file "'dialogue.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'dialogue.c'
X#include <stdio.h>
X#include <X/Xlib.h>
X#include <Sx/sx.h>
X
X/*
X * Copyright (c) 1987 Barry Shein (BZS@BU-CS.BU.EDU)
X * Right is hereby granted to distribute either modified
X * or unmodified versions of this program in source form
X * as long as this copyright notice is intact. May not
X * be re-sold for profit without explicit arrangement
X * with the author.
X */
X
X/*
X * char *
X * DialogueBox(relw,label,input,maxinput,entryfont,buttonfont)
X * Window relw;
X * char *label;
X * char *input;
X * int maxinput;
X * FontInfo *entryfont, *buttonfont;
X *
X * Where:
X *   relw:	position of dialogue box is calculated relative to this window
X *   label:	Label to give entry area, such as "Name? "
X *   input:	An input buffer, any string in input buffer will be used as
X *		a starting value (see Sx_CreateEntry())
X *   maxinput:	Maximum chars, including terminating null, to accept
X *   entryfont, buttonfont:
X *		fonts to use for respective fields, defaults are used
X *		if supplied as NULL.
X *
X * Note that until a button is pressed the mouse and server are "grabbed",
X * see Sx_Notify for a similar facility. Returns either the original buffer
X * pointer if user clicks ok (which holds result) or NULL meaning user hit
X * the CANCEL button.
X *
X * Example:
X *	char buf[40];
X *
X *	if(DialogueBox(RootWindow,"Name:",buf,40,NULL,NULL,NULL) != NULL)
X *		printf("User typed %s\n",buf);
X *
X * Author: Barry Shein, BZS@BU-CS.BU.EDU
X * Date: 1/6/86
X */
X
X/*
X * Todo:
X *	more sane placement of dialogue window
X */
X/*
X * Cursor to use while mouse is grabbed, small version of xterm.cursor
X */
X#include "dialogue.cursor"
X#include "dialogue_mask.cursor"
X
X/*
X * These are the default fonts to use if user passes NULLs, change at will
X */
X#define DEF_ENTRY_FONT "9x15"
X#define DEF_BUTTON_FONT "timrom12b"
X
X/*
X * Put the dialogue box down and to the left this %age
X * (that is, divide by these)
X */
X#define XRIGHT 10
X#define XDOWN 10
X
X/*
X * Make the text entry box this much more
X * (ie. (maxinput*font->width)+((maxinput*font->width)/ENTRYSLOP))
X * see the code, it's a hack.
X */
X#define ENTRYSLOP 5
X/*
X * A few little macros to clean up the looks of some code
X */
X#define max(x,y) (((x) > (y)) ? (x) : (y))
X#define min(x,y) (((x) < (y)) ? (x) : (y))
X#define ifnull(x,y) (((x) == NULL) ? y : x)
X
X/*
X * This is the text for the two buttons
X */
X#define OK	"OK"
X#define CANCEL	"CANCEL"
X/*
X * Used internally, zero means no button pressed yet
X */
X#define OKVAL 1
X#define CANCELVAL 2
X/*
X * I dunno, aesthetics, minimum window width/height
X */
X#define MINX 200
X#define MINY 100
X/*
X * Offsets from relative window (another kludge)
X */
X#define OFFX 50
X#define OFFY 50
X/*
X * Used variously to spread things out a little
X */
X#define XSLOP 10
X#define YSLOP 10
X
X/*
X * Most of these are static globals for the convenience
X * of writing some subrs and/or redisplay.
X */
X
Xstatic Window okbut, canbut;		/* the two button windows */
Xstatic int okxoff, okyoff;		/* button window offsets */
Xstatic int canxoff, canyoff;
Xstatic int butht, butwd;		/* both buttons same size */
X
Xstatic int okinvert = 0;		/* is OK window inverted? */
Xstatic int caninvert = 0;		/* is CANCEL window inverted? */
X
Xstatic FontInfo *bfont;			/* button font, for re-display */
X/*
X * Redraw the OK button (inv != 0 ? Reverse)
X */
X#define putOk(inv) \
X  XPixSet(okbut,0,0,butwd,butht,inv ? BlackPixel : WhitePixel); \
X  putButton(okbut,okxoff,okyoff,OK,bfont,inv);
X
X/*
X * Redraw the CANCEL button (inv != 0 ? Reverse)
X */
X#define putCan(inv) \
X  XPixSet(canbut,0,0,butwd,butht,inv ? BlackPixel : WhitePixel); \
X  putButton(canbut,canxoff,canyoff,CANCEL,bfont,inv);
X
X/*
X * Redraw some button
X */
Xstatic void
XputButton(but,x,y,str,font,inv)
XWindow but; int x,y; char *str; FontInfo *font; int inv;
X{
X  XText(but,x,y,str,strlen(str),font->id,
X	inv ? WhitePixel : BlackPixel,
X	inv ? BlackPixel : WhitePixel);
X}
X
X/*
X * Redisplay the window (Exposure)
X */
Xstatic void
XReWindowProc()
X{
X  putOk(okinvert);
X  putCan(caninvert);
X}
X
X/*
X * The main routine
X */
Xchar *
XDialogueBox(relw,label,input,maxinput,entryfont,buttonfont)
XWindow relw;
Xchar *label;
Xchar *input;
Xint maxinput;
XFontInfo *entryfont,*buttonfont;
X{
X  WindowInfo r_info;	/* Info about the relative window passed */
X  Window w;		/* The main dialogue window */
X  int i;
X  int wd, ht;		/* width and height of dialogue window */
X  int x,y;		/* x/y position of dialogue window */
X
X  /*
X   * This is the cursor while grabbed, static
X   * so we only calculate it once
X   */
X  static Cursor wcursor = (Cursor) NULL;
X
X  /* position in main window of buttons */
X
X  int mx, my;		/* for getting mouse coordinates */
X  Window mw;		/* subwindow mouse may be in */
X  int buttonpressed;	/* have they pressed a button yet? which? */
X  int lxoff, lyoff;	/* position of label */
X
X  /* fonts finally decided upon */
X  FontInfo *efont;	/* bfont has to be external */
X
X  efont = ifnull(entryfont,XOpenFont(DEF_ENTRY_FONT));
X  bfont = ifnull(buttonfont,XOpenFont(DEF_BUTTON_FONT));
X
X  if((efont == NULL) || (bfont == NULL)) {
X    fprintf(stderr,"Font problems?\n");
X    return(NULL);
X  }
X
X  /* Find position of window this is to be realitive to */
X  XQueryWindow(relw,&r_info);
X
X  /*
X   * I found that just allowing maxinput*efont->width
X   * was never quite enough so up it a little, ugh, call it
X   * a heuristic...
X   */
X  i = (maxinput+(maxinput/ENTRYSLOP))*efont->width;
X  i += XStringWidth(label,efont,0,0);
X  wd = max(i,MINX)+2*XSLOP;		/* main window width */
X
X  /* main window height */
X  ht = (YSLOP+bfont->height)+(YSLOP+max(efont->height,efont->height))+2*YSLOP;
X  ht = max(ht,MINY);
X
X  /* label position */
X  lxoff = XSLOP;
X  lyoff = YSLOP+bfont->height+2*YSLOP;
X
X  /*
X   * This should be fixed, position a little down and to the right
X   * of the window suggested by the caller.
X   */
X  x = r_info.x + (r_info.width/XRIGHT);
X  y = r_info.y + (r_info.height/XDOWN);
X
X  /* create cursor to use while mouse is grabbed, only once */
X  if(wcursor == ((Cursor) NULL))
X    wcursor = XCreateCursor(dialogue_width,dialogue_height,
X			    dialogue_bits,dialogue_mask_bits,
X			    dialogue_x_hot,dialogue_y_hot,
X			    BlackPixel,WhitePixel,GXcopy);
X
X  /* make main window */
X  w = XCreateWindow(RootWindow,x,y,wd,ht,4,BlackPixmap,WhitePixmap);
X
X  /*
X   * Obviously we know that CANCEL is longer, if this becomes
X   * dynamic it would be easy enough to change to
X   * max(strlen(OK),strlen(CANCEL)) or something equivalent.
X   */
X  butwd = XStringWidth(CANCEL,bfont,0,0) + 2*XSLOP;
X  butht = bfont->height;
X
X  /* create the two button windows */
X  okbut = XCreateWindow(w,XSLOP,YSLOP,
X			butwd,butht,
X			2,BlackPixmap,WhitePixmap);
X  canbut = XCreateWindow(w,XSLOP+butwd+XSLOP,YSLOP,
X			 butwd,butht,
X			 2,BlackPixmap,WhitePixmap);
X
X  /* Position of strings within the button windows (centered) */
X  okxoff = (butwd/2) - (XStringWidth(OK,bfont,0,0)/2);
X  okyoff = 0;
X  canxoff = (butwd/2) - (XStringWidth(CANCEL,bfont,0,0)/2);
X  canyoff = okyoff;
X
X  /* The text entry window */
X  Sx_EntryCreate(w,
X		 lxoff,lyoff,
X		 wd-2*XSLOP,max(bfont->height,efont->height),
X		 1,
X		 label,efont,
X		 BlackPixel,WhitePixel,
X		 input,maxinput);
X
X  XSelectInput(w,ExposeWindow|MouseMoved|ButtonPressed);
X  XGrabMouse(w,wcursor,ExposeWindow|MouseMoved|ButtonPressed);
X  XGrabServer();
X  XMapWindow(w);
X  XMapSubwindows(w);
X
X  /*
X   * Loop until they press a button, text entry automatically
X   * taken care of by Sx_Entry
X   */
X  for(buttonpressed = 0; buttonpressed == 0;) {
X    XEvent xevent;
X
X    XNextEvent(&xevent);
X    switch(xevent.type) {
X
X    case ExposeWindow:
X      ReWindowProc();
X      /* Needed to update the Entry window */
X      Sx_HandleEvent(&xevent);
X      break;
X
X    case MouseMoved:
X      XQueryMouse(w,&mx,&my,&mw);	/* get mouse position */
X
X      /*
X       * mw will be the subwindow the mouse is in if any,
X       * see if it is in one of the button windows. If so
X       * then invert the button (and, if necessary, uninvert other etc.)
X       */
X      if(mw != 0) {
X	if(mw == okbut) {
X	  if(!okinvert) {
X	    putOk(1);
X	    okinvert = 1;
X	  }
X	  if(caninvert) {
X	    putCan(0);
X	    caninvert = 0;
X	  }
X	}
X	else if(mw == canbut) {	/* it better be */
X	  if(!caninvert) {
X	    putCan(1);
X	    caninvert = 1;
X	  }
X	  if(okinvert) {
X	    putOk(0);
X	    okinvert = 0;
X	  }
X	}
X      }
X      else {	/* not in any subwindow */
X	if(okinvert) {
X	  putOk(0);
X	  okinvert = 0;
X	}
X	if(caninvert) {
X	  putCan(0);
X	  caninvert = 0;
X	}
X      }
X      break;
X
X    case ButtonPressed:
X      /* See if pressed while in button window */
X      XQueryMouse(w,&mx,&my,&mw);
X      if(mw == 0) break;
X      if(mw == okbut) {
X	buttonpressed = OKVAL;
X	putOk(0);
X	okinvert = 0; /* not necessary */
X	break;
X      }
X      else if(mw == canbut) {
X	buttonpressed = CANCELVAL;
X	putCan(0);
X	caninvert = 0; /* not necessary */
X	break;
X      }
X
X    default:
X      Sx_HandleEvent(&xevent);
X      break;
X    }
X  }
X  XUngrabMouse();
X  XUngrabServer();
X  XDestroyWindow(w);
X  return((buttonpressed == OKVAL) ? input : NULL);
X}
X#ifdef notdef
Xmain()
X{
X  char buf[BUFSIZ];
X
X  if(XOpenDisplay(NULL) == NULL) {
X    fprintf(stderr,"No X?\n");
X    exit(1);
X  }
X  buf[0] = '\0';
X  if(DialogueBox(RootWindow,"Test: ",buf,40,NULL,NULL) != NULL)
X    printf("You entered '%s'\n",buf);
X  else printf("CANCELLED\n");
X  exit(0);
X}
X#endif
SHAR_EOF
if test 9252 -ne "`wc -c 'dialogue.c'`"
then
	echo shar: error transmitting "'dialogue.c'" '(should have been 9252 characters)'
fi
echo shar: extracting "'dialogue.cursor'" '(260 characters)'
if test -f 'dialogue.cursor'
then
	echo shar: over-writing existing file "'dialogue.cursor'"
fi
sed 's/^X//' << \SHAR_EOF > 'dialogue.cursor'
X#define dialogue_width 7
X#define dialogue_height 14
X#define dialogue_x_hot 3
X#define dialogue_y_hot 6
Xstatic short dialogue_bits[] = {
X   0x0000, 0x0063, 0x0014, 0x0008,
X   0x0008, 0x0008, 0x0008, 0x0008,
X   0x0008, 0x0008, 0x0008, 0x0014,
X   0x0063, 0x0000};
SHAR_EOF
if test 260 -ne "`wc -c 'dialogue.cursor'`"
then
	echo shar: error transmitting "'dialogue.cursor'" '(should have been 260 characters)'
fi
echo shar: extracting "'dialogue_mask.cursor'" '(225 characters)'
if test -f 'dialogue_mask.cursor'
then
	echo shar: over-writing existing file "'dialogue_mask.cursor'"
fi
sed 's/^X//' << \SHAR_EOF > 'dialogue_mask.cursor'
X#define dialogue_mask_width 7
X#define dialogue_mask_height 14
Xstatic short dialogue_mask_bits[] = {
X   0x0077, 0x007f, 0x003e, 0x001c,
X   0x001c, 0x001c, 0x001c, 0x001c,
X   0x001c, 0x001c, 0x001c, 0x003e,
X   0x007f, 0x0077};
SHAR_EOF
if test 225 -ne "`wc -c 'dialogue_mask.cursor'`"
then
	echo shar: error transmitting "'dialogue_mask.cursor'" '(should have been 225 characters)'
fi
echo shar: extracting "'extern.c'" '(868 characters)'
if test -f 'extern.c'
then
	echo shar: over-writing existing file "'extern.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'extern.c'
X
XSx_MenuEntry options[] ={
X  {"Apropos",NULL,NULL,-1,Apropos,(ClientData) NULL},
X  {"Quit",NULL,NULL,-1,Finis,(ClientData) NULL}
X};
X
Xchar *keywords[] = {
X  "NAME",
X  "SYNOPSIS",
X  "OPTIONS",
X  "DESCRIPTION",
X  "BUGS",
X  "AUTHOR",
X  "DATE",
X  "SEE ALSO",
X  "FILES",
X  "EXAMPLE",
X  "EXAMPLES",
X  "USAGE",
X  "DIAGNOSTICS",
X  "CAVEAT",
X  "CAVEATS",
X  "COMMANDS",
X  "RESTRICTION",
X  "RESTRICTIONS",
X  "LIMITATION",
X  "LIMITATIONS",
X  NULL
X  };
X
Xstruct sectionNames sectionNames[] = {
X  {"1", "User Commands (1)"},
X  {"2", "System Calls (2)"},
X  {"3", "Subroutines (3)"},
X  {"4", "Devices (4)"},
X  {"5", "File Formats (5)"},
X  {"6", "Games (6)"},
X  {"7", "Miscellaneous (7)"},
X  {"8", "System Administration (8)"},
X  /* Stanford PUP folks started this, I dunno, no harm tho */
X  {"9", "Pup and other errata (9)"},
X  {"n", "New (n)"},
X  {"l", "Local (l)"},
X  {NULL, NULL}
X};
SHAR_EOF
if test 868 -ne "`wc -c 'extern.c'`"
then
	echo shar: error transmitting "'extern.c'" '(should have been 868 characters)'
fi
echo shar: extracting "'main.c'" '(6026 characters)'
if test -f 'main.c'
then
	echo shar: over-writing existing file "'main.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'main.c'
X#include "xman.h"
X#include "extern.c"
X
X/*
X * These are standard cursors from X
X */
X#include <X/cursors/center_ptr.cursor>
X#include <X/cursors/center_ptr_mask.cursor>
X#include <X/cursors/double_arrow.cursor>
X#include <X/cursors/double_arrow_mask.cursor>
X#include <X/cursors/target.cursor>
X#include <X/cursors/target_mask.cursor>
X/*
X * The icon
X */
X#include "xman.icon"
X#include "xman_mask.icon"
X
X/*ARGSUSED*/
XFatal(disp) Display *disp;
X{
X  perror("Fatal:");
X  exit(1);
X}
X/*ARGSUSED*/
XWarning(disp,err) Display *disp; XErrorEvent *err;
X{
X  eprintf("Warning: %s\n",XErrDescrip(err->error_code));
X  return;
X}
Xeprintf(fmt,a,b,c,d,e,f,g,h) char *fmt; char *a,*b,*c,*d,*e,*f,*g,*h;
X{
X  if(errorfp == NULL) errorfp = stderr;
X  fprintf(stderr,fmt,a,b,c,d,e,f,g,h);
X}
X/*ARGSUSED*/
Xmain(argc,argv) int argc; char **argv;
X{
X  char *def;
X  Color color_def;
X  OpaqueFrame frame;
X  int minwidth, minheight;
X  char geom_buf[100];
X
X  if((prog = rindex(argv[0],'/')) != NULL)
X    ++prog;
X  else prog = argv[0];
X
X  /*
X   * Set default X error handlers so we get a message
X   */
X  XIOErrorHandler(Fatal);
X  XErrorHandler(Warning);
X  /*
X   * Give namei a break
X   */
X  if(chdir(MANDIR) < 0) {
X    eprintf("Can't chdir to %s?\n",MANDIR);
X    exit(1);
X  }
X  /*
X   * Analyze the manual area
X   */
X  man();
X  /*
X   * If you enable this it will print what man() figured out
X   * on the stdout.
X   */
X#ifdef notdef
X  printman();
X  exit(0);
X#endif
X  if(XOpenDisplay(NULL) == NULL) {
X    eprintf("No X?!\n");
X    exit(1);
X  }
X  /*
X   * Process defaults (boy is this crufty)
X   */
X  if(((def = XGetDefault(prog,"Foreground")) != NULL) &&
X     (XParseColor(def,&color_def)) && (XGetHardwareColor(&color_def)))
X    fg = color_def.pixel;
X  else fg = DEF_FOREGROUND;
X
X  if(((def = XGetDefault(prog,"Background")) != NULL) &&
X     (XParseColor(def,&color_def)) && (XGetHardwareColor(&color_def)))
X    bg = color_def.pixel;
X  else bg = DEF_BACKGROUND;
X
X  if((def = XGetDefault(prog,"Reverse")) != NULL) {
X    Pixmap tmp;
X
X    tmp = fg;
X    fg = bg;
X    bg = tmp;
X  }
X  /* There should probably be more */
X
X  /*
X   * Set up the fonts (see notes in config.h as to why we can't
X   * really let the user just choose fonts
X   */
X  if((bodynormal = XOpenFont(BODYNORMAL)) == NULL) {
X    eprintf("could not open font %s\n",BODYNORMAL);
X    exit(1);
X  }
X  if((bodybold = XOpenFont(BODYBOLD)) == NULL) {
X    eprintf("Could not open font %s\n",BODYBOLD);
X    exit(1);
X  }
X  if((bodyitalic = XOpenFont(BODYITALIC)) == NULL) {
X    eprintf("Could not open font %s\n",BODYITALIC);
X    exit(1);
X  }
X  if((menufont = XOpenFont(MENUFONT)) == NULL) {
X    eprintf("Could not open font %s\n",MENUFONT);
X    exit(1);
X  }
X  bodyheight = bodynormal->height;
X  
X  /* The main window */
X  /*
X   * Due to various size restrictions inherent in the application
X   * we encourage the user to only place it and use default sizes.
X   */
X  mincol = MINCOL;
X  bzero(&frame,sizeof(frame));
X  frame.bdrwidth = 2;
X  frame.border = fg;
X  frame.background = bg;
X  minwidth = NCHARS*bodybold->width+mincol;
X  minheight = NLINES*bodynormal->height;
X  sprintf(geom_buf,"%dx%d",minwidth,minheight);
X  w = XCreate("Manual Browser",
X	      prog,
X	      "",geom_buf,
X	      &frame,
X	      minwidth,minheight);
X  /*
X   * The icon, we'll set the xy position later
X   */
X  xicon = XCreateWindow(RootWindow,0,0,xman_width,xman_height,0,fg,bg);
X  XSetIconWindow(w,xicon);
X  /* redisplay handler, also called for
X   * mouse events indirectly when in manual page mode
X   */
X  Sx_HandlerCreate(w,ExposeWindow,ReDisplayProc,(ClientData) 0);
X  Sx_HandlerCreate(xicon,ExposeWindow,ReIconProc,(ClientData) 0);
X  /*
X   * This is the main man page pseudo-menu handler, also calls out
X   * to ReDisplayProc() to page forward and backwards when we are
X   * displaying a man page(s)
X   */
X  Sx_HandlerCreate(w,ButtonPressed|ButtonReleased|MouseMoved,
X		   MyButtonProc,(ClientData) NULL);
X
X  /*
X   * Set up the top title bar
X   */
X  if((titlefont = XOpenFont(TITLEFONT)) == NULL) {
X    XDestroyWindow(w);
X    Sx_Panic("Couldn't open a font!");
X  }
X  titleheight = Sx_DefaultHeight(titlefont);
X  title = Sx_TitleCreate(w,SX_TOP,
X			 titleheight,TITLEBORDER,titlefont,
X			 WhitePixel,BlackPixel,NULL,
X			 "Manual Browser",NULL);
X  /*
X   * The section pull-down, mostly set up dynamically
X   */
X  setupSections();
X  menubar = Sx_CreatePacked(w,SX_TOP,titleheight,1,(Window)NULL,
X			    (Window)NULL,fg,bg);
X  sectionMenu = Sx_MenuCreate(menubar,SECTION,nsections,sections,menufont,
X			      BlackPixel,WhitePixel);
X  optionsMenu = Sx_MenuCreate(menubar,OPTIONS,NOPTIONS,options,menufont,
X			      BlackPixel,WhitePixel);
X  /*
X   * Set up cursors
X   */
X  xman_cursor = XCreateCursor(center_ptr_width,center_ptr_height,
X			      center_ptr_bits,center_ptr_mask_bits,
X			      center_ptr_x_hot,center_ptr_y_hot,
X			      BlackPixel,WhitePixel,GXcopy);
X  xpage_cursor = XCreateCursor(double_arrow_width,double_arrow_height,
X			      double_arrow_bits,double_arrow_mask_bits,
X			      double_arrow_x_hot,double_arrow_y_hot,
X			      BlackPixel,WhitePixel,GXcopy);
X  xicon_cursor = XCreateCursor(target_width,target_height,
X			       target_bits,target_mask_bits,
X			       target_x_hot,target_y_hot,
X			       BlackPixel,WhitePixel,GXcopy);
X  XDefineCursor(w,xman_cursor);
X  XDefineCursor(xicon,xicon_cursor);
X  XMapWindow(w);
X  XQueryWindow(w,&w_info);
X  /*
X   * Put the icon at the upper-left corner of the main window
X   */
X  XMoveWindow(xicon,w_info.x,w_info.y);
X  XQueryWindow(title,&title_info);
X  XQueryWindow(menubar,&menubar_info);
X  /*
X   * The problem here is I need to know where to start putting
X   * text in the window after the title and menu bars, I notice
X   * he punts (uses a constant) in sxDemo.c, I sort of punt.
X   */
X#ifdef notdef
X  /* doesn't work, why? */
X  minrow = title_info.height+2*title_info.bdrwidth
X    +menubar_info.height+2*menubar_info.bdrwidth;
X#endif
X  minrow = 2 * titleheight;
X  /*
X   * MAIN LOOP
X   */
X  for(;;) {
X    XEvent event;
X
X    XNextEvent(&event);
X    Sx_HandleEvent(&event);
X  }
X}
SHAR_EOF
if test 6026 -ne "`wc -c 'main.c'`"
then
	echo shar: error transmitting "'main.c'" '(should have been 6026 characters)'
fi
echo shar: extracting "'man.c'" '(3970 characters)'
if test -f 'man.c'
then
	echo shar: over-writing existing file "'man.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'man.c'
X#include "xman.h"
X/*
X * This would have to be reworked for SYS/V etc.
X */
X
X/*
X * Strange, overblown routine to handle reading in the manual
X * entries. Doesn't even begin to consider "non-standard" (eg. SYS/V)
X * manual directory setup tho it would be fairly easy to extrapolate to.
X */
X
X/*
X * The basic goal is to simply build a list of all manual directories
X * and the file names of the sections w/in those directories into the
X * manual structure (see xman.h).
X *
X * TODO:
X *   This assumes manual sections are either formatted (the "catX" dir
X *   exists) or aren't (only the "manX" dir) on a per DIRECTORY basis.
X *   Thus, if you only format some of your manual pages within a section
X *   this won't quite work right (however, if some dirs are formatted and
X *   some not it should pick this up fine.) It would simply require
X *   saving a bit for each page entry (whether in the "man" section thus
X *   needing to be formatted on the fly or in the "cat" section.)
X */
Xman() {
X  DIR *dir;
X  register struct direct *dp;
X  char *mans[MAXSECT], *cats[MAXSECT];
X  int nmans, ncats;
X  int i;
X  struct stat sb;
X  char *entries[MAXENTRY];
X  int nentries;
X  struct manual *mp;
X  extern char *rindex(), *malloc();
X  extern int cmpstrp();
X
X  if((dir = opendir(".")) == NULL) {	/* should be chdir'd to MANDIR now */
X    perror(MANDIR);
X    exit(1);
X  }
X  nmanual = nmans = ncats = 0;
X  /*
X   * Read through this directory and save up any directory name
X   * which begins with "man" or "cat"
X   */
X  while((dp = readdir(dir)) != NULL) {
X    if((dp->d_namlen >= LMAN) && (strncmp(dp->d_name,MAN,LMAN) == 0)) {
X      if(nmans == MAXSECT) goto toomany;
X      if((stat(dp->d_name,&sb) >= 0) && (sb.st_mode & S_IFDIR))
X	mans[nmans++] = stralloc(dp->d_name);
X    }
X    else if((dp->d_namlen >= LCAT) && (strncmp(dp->d_name,CAT,LCAT) == 0)) {
X      if(ncats == MAXSECT) goto toomany;
X      if((stat(dp->d_name,&sb) >= 0) && (sb.st_mode & S_IFDIR))
X	cats[ncats++] = stralloc(dp->d_name);
X    }
X  }
X  closedir(dir);
X  /*
X   * sort the manual section "man" names, useful later
X   */
X  qsort(mans,nmans,sizeof(mans[0]),cmpstrp);
X  /*
X   * Now, match up with cat sections if they exist
X   */
X  for(i=0; i < nmans ; i++) {
X    int j;
X
X    manual[nmanual].man = mans[i];
X    manual[nmanual].cat = NULL;
X    for(j=0; j < ncats; j++)
X      if(mans[i][LMAN] == cats[j][LCAT]) {
X	manual[nmanual].cat = cats[j];
X	break;
X      }
X    nmanual++;
X  }
X  /*
X   * Go through each manual directory saving up the individual
X   * page entries.
X   * Demand that a page entry not start with a '.' but have
X   * a dot somewhere.
X   */
X  for(i=0,mp=manual ; i < nmanual; i++,mp++) {
X    int j, longest;
X    char **cpp, *cp;
X    char *sect;
X    struct entry *ep;
X
X    sect = (mp->cat == NULL) ? mp->man : mp->cat;
X    chdir(sect);
X    dir = opendir(".");
X    if(dir == NULL) {
X      chdir("..");
X      continue;
X    }
X    nentries = 0;
X    cpp = entries;
X    longest = 0;
X    while((dp = readdir(dir)) != NULL) {
X      if(nentries == MAXENTRY) {
X	eprintf("Too many manual pages in %s\n",sect);
X	eprintf("Try recompiling with larger allocations\n");
X	exit(1);
X      }
X      /* starts with a dot? no dot in name? */
X      if((dp->d_name[0] == '.') || ((cp = rindex(dp->d_name,'.')) == NULL))
X	continue;
X      *cpp++ = stralloc(dp->d_name);
X      if((j = (cp - dp->d_name)) > longest) longest = j;
X      nentries++;
X    }
X    closedir(dir);
X    chdir("..");
X    qsort(entries,nentries,sizeof(entries[0]),cmpstrp);
X    /*
X     * Now allocate and copy into structure
X     */
X    mp->entries = (struct entry *) malloc(nentries * sizeof(struct entry));
X    for(j=0,cpp=entries,ep = mp->entries; j < nentries; j++,cpp++,ep++)
X      ep->label = *cpp;
X    mp->longest = longest+1;
X    mp->nentries = nentries;
X  }
X  return;
X toomany:
X  eprintf("Too many manual sections, recompile with larger allocations\n");
X  exit(1);
X}
X/*
X * used by qsort() above
X */
Xcmpstrp(p1,p2) char **p1, **p2;
X{
X  return(strcmp(*p1,*p2));
X}
SHAR_EOF
if test 3970 -ne "`wc -c 'man.c'`"
then
	echo shar: error transmitting "'man.c'" '(should have been 3970 characters)'
fi
echo shar: extracting "'menus.c'" '(1083 characters)'
if test -f 'menus.c'
then
	echo shar: over-writing existing file "'menus.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'menus.c'
X#include "xman.h"
X
X/*
X * Dynamically set up the section pull-down menu
X */
XsetupSections()
X{
X  int i;
X  register struct sectionNames *sectp;
X  register Sx_MenuEntry *sp;
X  struct manual *manp;
X  char *manname;
X  char *malloc();
X
X  nsections = 0;
X  sp = sections = (Sx_MenuEntry *) malloc(nmanual * sizeof(Sx_MenuEntry));
X  for(i=0,manp = manual; i < nmanual; i++,manp++) {
X    sp->centerText = NULL;
X    sp->rightText = NULL;
X    sp->background = -1;
X    sp->proc = SectionsProc;
X    sp->clientData = NULL;
X    /*
X     * Now the hard part, try pick a menu label
X     */
X    if(manp->man != NULL)
X      manname = &manp->man[LMAN];
X    else if(manp->cat != NULL)
X      manname = &manp->cat[LCAT];
X    else continue; /* ?foo? */
X    sp->leftText = NULL;
X    for(sectp = sectionNames; sectp->dirname != NULL; sectp++)
X      if(strcmp(manname,sectp->dirname) == 0) {
X	sp->leftText = sectp->label;
X	break;
X      }
X    if(sp->leftText == NULL) {
X      char buf[50];
X
X      sprintf(buf,"Manual Section %s",manname);
X      sp->leftText = stralloc(buf);
X    }
X    sp++;
X    nsections++;
X  }
X}
SHAR_EOF
if test 1083 -ne "`wc -c 'menus.c'`"
then
	echo shar: error transmitting "'menus.c'" '(should have been 1083 characters)'
fi
echo shar: extracting "'redisplay.c'" '(5544 characters)'
if test -f 'redisplay.c'
then
	echo shar: over-writing existing file "'redisplay.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'redisplay.c'
X#include "xman.h"
X
X/*
X * The icon
X */
X#include "xman.icon"
X#include "xman_mask.icon"
X
X/*
X * Redisplay the text window, somewhat hairy.
X * NOTE: EVENTP may be NULL! NEVER USED! (maybe should undeclare.)
X */
X/*ARGSUSED*/
Xvoid
XReDisplayProc(clientData,eventp) ClientData clientData; XEvent *eventp;
X{
X  int i;
X  register int c;
X  register char *bufp;
X  char buf[BUFSIZ];
X  int col;
X  int italicflag = 0;
X  FontInfo *f;
X  int how;
X  int first = 1;
X
X  /*
X   * Are we displaying the man sections?
X   */
X  if(!manualing) {
X    putEntries(section);
X    return;
X  }
X
X  /*
X   * No, must be displaying a man or apropos file
X   */
X  XClear(w);
X  /*
X   * Expected client data is 1 for forward page, 0 for same page (eg first
X   * call) and -1 for back page [1,-1 -> left/middle mouse buttons]
X   * see buttons.c
X   */
X  how = (int) clientData;
X  /*
X   * The pagetell array is a "stack" of seek pointers for page
X   * boundaries we build as we read.
X   */
X  if(feof(manfp) && (how > 0)) how = 0;
X  if(how == 0)
X    fseek(manfp,pagetell[curpage],0);
X  else if(how > 0)
X    pagetell[++curpage] = ftell(manfp);
X  else /* how < 0 */
X    fseek(manfp,pagetell[(curpage == 0) ? curpage : --curpage],0);
X
X  /*
X   * Ok, here's the more than mildly heuristic man page formatter.
X   * We put chars into buf until either a font change or newline
X   * occurs (at which time we flush it to the screen.)
X   */
X  buf[0] = '\0';
X  for(i=0,bufp = buf,col=mincol;;)
X    switch(c = getc(manfp)) {
X
X    case EOF:
X      return;
X
X    case '\n':
X      if(bufp > buf) {
X	*bufp = '\0';
X	
X	if(italicflag) f = bodyitalic;
X	else if(first) {		/* boldify first line [header] */
X	  f = bodybold;
X	  first = 0;
X	}
X	else if((col == mincol) && iskeyword(buf))
X	  f = bodybold;			/* boldify "keywords" like NAME */
X	else f = bodynormal;
X
X	(void) putstr(w,col,(i+2)*bodyheight,buf,f,0);
X      }
X      /* end of page on screen? (note how we rely on 66 line pages!) */
X      if(++i == NLINES) return;
X      col = mincol;
X      bufp = buf;
X      *bufp = '\0';
X      italicflag = 0;
X      break;
X
X    case '_':				/* look for underlining [italicize] */
X      if((c = getc(manfp)) != BACKSPACE) {
X	ungetc(c,manfp);
X	c = '_';
X	/* FALL THROUGH TO DEFAULT */
X      }
X      else {
X	if(!italicflag) {		/* font change? */
X	  *bufp = '\0';
X	  col += putstr(w,col,(i+2)*bodyheight,buf,bodynormal,0);
X	  bufp = buf;
X	  *bufp = '\0';
X	  italicflag = 1;
X	}
X	*bufp++ = getc(manfp);
X      }
X      break;
X
X    case '\033':			/* ignore esc sequences for now */
X      getc(manfp);			/* should always be esc-x */
X      break;
X    default:
X      if(italicflag) {			/* font change? */
X	*bufp = '\0';
X	col += putstr(w,col,(i+2)*bodyheight,buf,bodyitalic,0);
X	bufp = buf;
X	*bufp = '\0';
X	italicflag = 0;
X      }
X      *bufp++ = c;
X      break;
X    }
X}
X/*
X * The iconified redisplay routine
X */
X/*ARGSUSED*/
Xvoid
XReIconProc(clientData,eventp) ClientData clientData; XEvent *eventp;
X{
X  XBitmapBitsPut(xicon,0,0,
X		 xman_width,xman_height,xman_bits,
X		 BlackPixel,WhitePixel,
X		 0,
X		 GXcopy,AllPlanes);
X}
X/*
X * Simplified interface to XText()
X */
Xputstr(win,x,y,str,font,inv)
XWindow win;
Xint x,y;
Xchar *str;
XFontInfo *font;
Xint inv;
X{
X  XText(win,x,y,str,strlen(str),font->id,
X	inv ? WhitePixel : BlackPixel,
X	inv ? BlackPixel : WhitePixel);
X  return(XStringWidth(str,font,0,0));
X}
X/*
X * Pad to column, remove trailing .X (as in "cat.1")
X */
Xchar *
XprepEntry(sp,n) register char *sp; register int n;
X{
X  static char buf[100];
X  register char *bp;
X  char *ep;
X  extern char *rindex();
X
X  bp = buf;
X  if((ep = rindex(sp,'.')) == NULL) {
X    eprintf("Impossible error: %s\n",sp);
X    exit(1);
X  }
X  while(n--)
X    *bp++ = (sp == ep) ? ' ' : *sp++;
X  *bp = '\0';
X  return(buf);
X}
X/*
X * Make the sections pseudo-menu
X */
XputEntries(which) int which;
X{
X  register struct manual *mp;
X  struct entry *ep;
X  int cols, colwidth, xcolwidth, col;
X  int i,j,row;
X
X  mp = &manual[which];
X  ep = mp->entries;
X  colwidth = mp->longest + 1;
X  xcolwidth = bodynormal->width * colwidth;
X  cols = (NCHARS/colwidth)+1;
X  mp->width = xcolwidth;
X  mp->height = bodyheight;
X  mp->startx = mincol;
X  mp->starty = minrow+bodyheight;
X  mp->ncols = cols;
X  mp->colpad = colwidth;
X
X  for(row=0,i=0,col=0; i < mp->nentries; row++)
X    if(row == (NLINES-1)) {
X      eprintf("Too many lines\n");
X      return;
X    }
X    else for(col=mincol,j=0;(j < cols) && (i < mp->nentries); j++,i++,ep++) {
X      /*
X       * Actually, I don't need width/height as it's constant
X       * but I don't think the whole thing hurts and might need
X       * it later.
X       */
X      putstr(w,col,row*bodyheight+mp->starty,
X		    prepEntry(ep->label,colwidth),bodynormal,0);
X      col += xcolwidth;
X    }
X}
X/*
X * When displaying manual pages we look for keywords like
X * "NAME" or "SYNOPSIS" on a line by themselves to boldify
X */
Xiskeyword(sp) register char *sp;
X{
X  register char **keys;
X
X  for(keys = keywords; *keys != NULL; keys++)
X    if(strcmp(*keys,sp) == 0) return(1);
X  return(0);
X}
X/*
X * Called when they mouse a particular manual section
X * (should probably be in buttons.c)
X */
X/*ARGSUSED*/
Xvoid
XSectionsProc(clientData,index,window)
XClientData clientData;
Xint index;
XWindow window;
X{
X  section = index;
X  manualing = 0;
X  XDefineCursor(w,xman_cursor);
X  if(manfp != NULL) {
X    fclose(manfp);
X    manfp = NULL;
X  }
X  XClear(w);
X  putEntries(section);  
X}
Xchar *
Xstralloc(sp) char *sp;
X{
X  char *ret;
X
X  if((ret = (char *) malloc(strlen(sp)+1)) == NULL) {
X    eprintf("Fatal: out of memory in stralloc()\n");
X    exit(1);
X  }
X  strcpy(ret,sp);
X  return(ret);
X}
SHAR_EOF
if test 5544 -ne "`wc -c 'redisplay.c'`"
then
	echo shar: error transmitting "'redisplay.c'" '(should have been 5544 characters)'
fi
echo shar: extracting "'shar.sh'" '(219 characters)'
if test -f 'shar.sh'
then
	echo shar: over-writing existing file "'shar.sh'"
fi
sed 's/^X//' << \SHAR_EOF > 'shar.sh'
Xshar -a Makefile README buttons.c config.h copyright.h dialogue.c dialogue.cursor dialogue_mask.cursor extern.c main.c man.c menus.c redisplay.c shar.sh xman.h xman.icon xman.n xman_mask.icon diff-c.sxEntry > xman.shar
SHAR_EOF
if test 219 -ne "`wc -c 'shar.sh'`"
then
	echo shar: error transmitting "'shar.sh'" '(should have been 219 characters)'
fi
chmod +x 'shar.sh'
echo shar: extracting "'xman.h'" '(3002 characters)'
if test -f 'xman.h'
then
	echo shar: over-writing existing file "'xman.h'"
fi
sed 's/^X//' << \SHAR_EOF > 'xman.h'
X#include <stdio.h>
X#include <X/Xlib.h>
X#include <Sx/sx.h>
X
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/stat.h>
X
X#include "config.h"
X#include "copyright.h"
X
X/*
X * Our name, for errors and defaults (derived from argv[0])
X */
Xchar *prog;
X
X/*
X * How we store each entry such as cat.1, sh.1 etc.
X */
Xstruct entry {
X  char *label;
X/* I keep thinking I may need something here eventually */
X};
X
X/*
X * The manual sections and entries
X */
Xstruct manual {
X  char *cat;		/* if we have the cat dir, else NULL */
X  char *man;		/* the manx dir */
X  struct entry *entries;/* the individual man page file names */
X  int nentries;		/* how many */
X  int longest;		/* we need to know the longest name for formatting */
X  /*
X   * All entries are formatted to the screen as equal sized
X   * fields so it's easy to use it like a menu.
X   */
X  short int width, height, startx, starty, ncols, colpad;
X} manual[MAXSECT];
Xint nmanual;		/* how many manual sections we found */
X
XFILE *manfp;		/* current open manual page (NULL if none) */
X
Xint section;		/* section they chose from menu */
Xint manualing;		/* are we displaying a manual page or menu? */
Xlong pagetell[MAXPAGES];	/* stack of page seek offsets */
Xint curpage;		/* stack index */
X
XWindow w;		/* the main working X-window object */
XWindowInfo w_info;	/* result of doing a query on w */
XWindow title;		/* Top title subwindow */
XWindowInfo title_info;	/* result of querying title subwindow */
X
XFontInfo *titlefont;	/* font to use on title (see config.h) */
Xint titleheight;	/* to help offset into text page */
X
XFontInfo *menufont;	/* font to use for pull-downs (see config.h) */
X
X/*
X * The text body fonts for man pages, menus also. See config.h for defaults.
X */
XFontInfo *bodynormal, *bodyitalic, *bodybold;
X
Xint bodyheight;		/* height for offsetting lines */
X
XPixmap bg, fg;		/* Background/Foreground for text window */
X
XFILE *errorfp;		/* where to send error msgs (stderr) */
X
Xvoid ReDisplayProc(), SectionsProc(), MyButtonProc();
Xchar *stralloc(), *rindex();
X
Xint minrow;		/* where to start writing text (see config.h)*/
Xint mincol;
X
XWindow menubar, sectionMenu;
XWindowInfo menubar_info;
X
X/*
X * The manual sections manual is dynamically allocated, see
X * also the sectionName stuff in config.h
X */
XSx_MenuEntry *sections;
Xint nsections;
X
X/*
X * If we only have the man section (no preformat) we need to
X * put it into a temp file
X */
Xchar mantmp[128];
X
XCursor xman_cursor, xpage_cursor;
XWindow xicon;
Xvoid ReIconProc();
XCursor xicon_cursor;
X
X/*
X * The options menu
X */
Xvoid Apropos(), Finis();
X/*
X * The command to invoke for apropos, perhaps 'man -k'? Could
X * just re-write, it's a simple algorithm.
X */
X#define APROPOS "apropos"
X/*
X * The command to use as a filter to make apropos look paginated
X */
X#define APROPOSFILTER "pr -h Apropos"
X/*
X * size of type-in window
X */
X#define APROPOSLEN 40
X
Xextern Sx_MenuEntry options[];	/* in extern.c */
X/*
X * Number of elements in options menu
X */
X#define NOPTIONS 2
X
XWindow optionsMenu;
Xchar *DialogueBox();
SHAR_EOF
if test 3002 -ne "`wc -c 'xman.h'`"
then
	echo shar: error transmitting "'xman.h'" '(should have been 3002 characters)'
fi
echo shar: extracting "'xman.icon'" '(915 characters)'
if test -f 'xman.icon'
then
	echo shar: over-writing existing file "'xman.icon'"
fi
sed 's/^X//' << \SHAR_EOF > 'xman.icon'
X#define xman_width 24
X#define xman_height 48
Xstatic short xman_bits[] = {
X   0xffff, 0xffff, 0xe7ff, 0xffff,
X   0xe7ff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0x0003, 0xffc0,
X   0x0003, 0xffc0, 0x9e8b, 0xffd0,
X   0xa28b, 0xffd9, 0xa28b, 0xffd9,
X   0xa28b, 0xffd6, 0x9e8b, 0xffd6,
X   0x828b, 0xffd0, 0x828b, 0xffd0,
X   0x828b, 0xffd0, 0x828b, 0xffd0,
X   0x8273, 0xffd0, 0x0003, 0xffc0,
X   0x0003, 0xffc0, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xe7ff, 0xffff, 0xe7ff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xe7ff, 0xffff,
X   0xe7ff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff};
SHAR_EOF
if test 915 -ne "`wc -c 'xman.icon'`"
then
	echo shar: error transmitting "'xman.icon'" '(should have been 915 characters)'
fi
echo shar: extracting "'xman.n'" '(1227 characters)'
if test -f 'xman.n'
then
	echo shar: over-writing existing file "'xman.n'"
fi
sed 's/^X//' << \SHAR_EOF > 'xman.n'
X.TH XMAN N "7 January 1987"
X.SH NAME
Xxman \- manual tool for X-windows
X.SH SYNOPSIS
X.B xman
X.SH DESCRIPTION
X\fIXman\fR is a simple manual browsing tool for X-windows. The user
Xcan view one of three items: A menu of all the topics available
Xin a manual section, a particular manual `page' or the result of
Xan apropos (man -k) request.
X.LP
XWhen sections are displayed the entire text area acts like a menu,
Xclick the left mouse button to view a particular topic.
X.LP
XWhen a page or apropos result is being displayed clicking the
Xleft button in the text
Xwindow advances one page, clicking the middle button goes back one
Xpage.
X.LP
XWhen the apropos menu item is clicked a dialogue box is popped up,
Xthe cursor has to be within the text entry box to type in a keyword
Xto be searched for. Clicking the left mouse button on OK invokes
Xthe apropos search, CANCEL causes the original request to be ignored.
X.SH "SEE ALSO"
Xapropos(1), man(1), pr(1) ,X(n), Sx(n)
X.SH BUGS
XThe program thinks it knows how your manual area is set up, this
Xmay or may not be true.
X.LP
XThere is a practical limit to the number of manual entries which can
Xbe comfortably displayed on a tall window.
X.SH AUTHOR
XBarry Shein, Boston University (bzs@bu-cs.bu.edu)
SHAR_EOF
if test 1227 -ne "`wc -c 'xman.n'`"
then
	echo shar: error transmitting "'xman.n'" '(should have been 1227 characters)'
fi
echo shar: extracting "'xman_mask.icon'" '(930 characters)'
if test -f 'xman_mask.icon'
then
	echo shar: over-writing existing file "'xman_mask.icon'"
fi
sed 's/^X//' << \SHAR_EOF > 'xman_mask.icon'
X#define xman_mask_width 24
X#define xman_mask_height 48
Xstatic short xman_mask_bits[] = {
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff,
X   0xffff, 0xffff, 0xffff, 0xffff};
SHAR_EOF
if test 930 -ne "`wc -c 'xman_mask.icon'`"
then
	echo shar: error transmitting "'xman_mask.icon'" '(should have been 930 characters)'
fi
echo shar: extracting "'diff-c.sxEntry'" '(1137 characters)'
if test -f 'diff-c.sxEntry'
then
	echo shar: over-writing existing file "'diff-c.sxEntry'"
fi
sed 's/^X//' << \SHAR_EOF > 'diff-c.sxEntry'
X*** sxEntry.c	Mon Jan  5 20:46:45 1987
X--- sxEntry.c.orig	Mon Jan  5 20:45:36 1987
X***************
X*** 652,659
X      }
X      insert[1] = 0;
X      EntryEraseCaret(entryPtr);
X-     /* BZS - the string returned by XLookupMapping is NOT null terminated
X-      *
X      for ( ; *keyString != 0; keyString++) {
X       */
X      for(; nBytes != 0 ; nBytes--,keyString++) {
X
X--- 652,657 -----
X      }
X      insert[1] = 0;
X      EntryEraseCaret(entryPtr);
X      for ( ; *keyString != 0; keyString++) {
X  	if (Char_IsPrint(*keyString)) {
X  	    insert[0] = *keyString;
X***************
X*** 655,662
X      /* BZS - the string returned by XLookupMapping is NOT null terminated
X       *
X      for ( ; *keyString != 0; keyString++) {
X-      */
X-     for(; nBytes != 0 ; nBytes--,keyString++) {
X  	if (Char_IsPrint(*keyString)) {
X  	    insert[0] = *keyString;
X  	    EntryInsert(entryPtr, insert, entryPtr->caret);
X
X--- 653,658 -----
X      insert[1] = 0;
X      EntryEraseCaret(entryPtr);
X      for ( ; *keyString != 0; keyString++) {
X  	if (Char_IsPrint(*keyString)) {
X  	    insert[0] = *keyString;
X  	    EntryInsert(entryPtr, insert, entryPtr->caret);
SHAR_EOF
if test 1137 -ne "`wc -c 'diff-c.sxEntry'`"
then
	echo shar: error transmitting "'diff-c.sxEntry'" '(should have been 1137 characters)'
fi
#	End of shell archive
exit 0
