/*
 *	$Source: /u1/X/xman/RCS/redisplay.c,v $
 *	$Header: redisplay.c,v 1.1 87/01/28 15:50:09 swick Exp $
 */

#ifndef lint
static char *rcsid_redisplay_c = "$Header: redisplay.c,v 1.1 87/01/28 15:50:09 swick Exp $";
#endif	lint

#include "xman.h"

/*
 * The icon
 */
#include "xman.icon"
#include "xman_mask.icon"

/*
 * Redisplay the text window, somewhat hairy.
 * NOTE: EVENTP may be NULL! NEVER USED! (maybe should undeclare.)
 */
/*ARGSUSED*/
void
ReDisplayProc(clientData,eventp) ClientData clientData; XEvent *eventp;
{
  int i;
  register int c;
  register char *bufp;
  char buf[BUFSIZ];
  int col;
  int italicflag = 0;
  FontInfo *f;
  int how;
  int first = 1;

  /*
   * Are we displaying the man sections?
   */
  if(!manualing) {
    putEntries(section);
    return;
  }

  /*
   * No, must be displaying a man or apropos file
   */
  XClear(w);
  /*
   * Expected client data is 1 for forward page, 0 for same page (eg first
   * call) and -1 for back page [1,-1 -> left/middle mouse buttons]
   * see buttons.c
   */
  how = (int) clientData;
  /*
   * The pagetell array is a "stack" of seek pointers for page
   * boundaries we build as we read.
   */
  if(feof(manfp) && (how > 0)) how = 0;
  if(how == 0)
    fseek(manfp,pagetell[curpage],0);
  else if(how > 0)
    pagetell[++curpage] = ftell(manfp);
  else /* how < 0 */
    fseek(manfp,pagetell[(curpage == 0) ? curpage : --curpage],0);

  /*
   * Ok, here's the more than mildly heuristic man page formatter.
   * We put chars into buf until either a font change or newline
   * occurs (at which time we flush it to the screen.)
   */
  buf[0] = '\0';
  for(i=0,bufp = buf,col=mincol;;)
    switch(c = getc(manfp)) {

    case EOF:
      return;

    case '\n':
      if(bufp > buf) {
	*bufp = '\0';
	
	if(italicflag) f = bodyitalic;
	else if(first) {		/* boldify first line [header] */
	  f = bodybold;
	  first = 0;
	}
	else if((col == mincol) && iskeyword(buf))
	  f = bodybold;			/* boldify "keywords" like NAME */
	else f = bodynormal;

	(void) putstr(w,col,(i+2)*bodyheight,buf,f,0);
      }
      /* end of page on screen? (note how we rely on 66 line pages!) */
      if(++i == NLINES) return;
      col = mincol;
      bufp = buf;
      *bufp = '\0';
      italicflag = 0;
      break;

    case '_':				/* look for underlining [italicize] */
      if((c = getc(manfp)) != BACKSPACE) {
	ungetc(c,manfp);
	c = '_';
	/* FALL THROUGH TO DEFAULT */
      }
      else {
	if(!italicflag) {		/* font change? */
	  *bufp = '\0';
	  col += putstr(w,col,(i+2)*bodyheight,buf,bodynormal,0);
	  bufp = buf;
	  *bufp = '\0';
	  italicflag = 1;
	}
	*bufp++ = getc(manfp);
      }
      break;

    case '\033':			/* ignore esc sequences for now */
      getc(manfp);			/* should always be esc-x */
      break;
    default:
      if(italicflag) {			/* font change? */
	*bufp = '\0';
	col += putstr(w,col,(i+2)*bodyheight,buf,bodyitalic,0);
	bufp = buf;
	*bufp = '\0';
	italicflag = 0;
      }
      *bufp++ = c;
      break;
    }
}
/*
 * The iconified redisplay routine
 */
/*ARGSUSED*/
void
ReIconProc(clientData,eventp) ClientData clientData; XEvent *eventp;
{
  XBitmapBitsPut(xicon,0,0,
		 xman_width,xman_height,xman_bits,
		 BlackPixel,WhitePixel,
		 0,
		 GXcopy,AllPlanes);
}
/*
 * Simplified interface to XText()
 */
putstr(win,x,y,str,font,inv)
Window win;
int x,y;
char *str;
FontInfo *font;
int inv;
{
  XText(win,x,y,str,strlen(str),font->id,
	inv ? WhitePixel : BlackPixel,
	inv ? BlackPixel : WhitePixel);
  return(XStringWidth(str,font,0,0));
}
/*
 * Pad to column, remove trailing .X (as in "cat.1")
 */
char *
prepEntry(sp,n) register char *sp; register int n;
{
  static char buf[100];
  register char *bp;
  char *ep;
  extern char *rindex();

  bp = buf;
  if((ep = rindex(sp,'.')) == NULL) {
    eprintf("Impossible error: %s\n",sp);
    exit(1);
  }
  while(n--)
    *bp++ = (sp == ep) ? ' ' : *sp++;
  *bp = '\0';
  return(buf);
}
/*
 * Make the sections pseudo-menu
 */
putEntries(which) int which;
{
  register struct manual *mp;
  struct entry *ep;
  int cols, colwidth, xcolwidth, col;
  int i,j,row;

  mp = &manual[which];
  ep = mp->entries;
  colwidth = mp->longest + 1;
  xcolwidth = bodynormal->width * colwidth;
  cols = (NCHARS/colwidth)+1;
  mp->width = xcolwidth;
  mp->height = bodyheight;
  mp->startx = mincol;
  mp->starty = minrow+bodyheight;
  mp->ncols = cols;
  mp->colpad = colwidth;

  for(row=0,i=0,col=0; i < mp->nentries; row++)
    if(row == (NLINES-1)) {
      eprintf("Too many lines\n");
      return;
    }
    else for(col=mincol,j=0;(j < cols) && (i < mp->nentries); j++,i++,ep++) {
      /*
       * Actually, I don't need width/height as it's constant
       * but I don't think the whole thing hurts and might need
       * it later.
       */
      putstr(w,col,row*bodyheight+mp->starty,
		    prepEntry(ep->label,colwidth),bodynormal,0);
      col += xcolwidth;
    }
}
/*
 * When displaying manual pages we look for keywords like
 * "NAME" or "SYNOPSIS" on a line by themselves to boldify
 */
iskeyword(sp) register char *sp;
{
  register char **keys;

  for(keys = keywords; *keys != NULL; keys++)
    if(strcmp(*keys,sp) == 0) return(1);
  return(0);
}
/*
 * Called when they mouse a particular manual section
 * (should probably be in buttons.c)
 */
/*ARGSUSED*/
void
SectionsProc(clientData,index,window)
ClientData clientData;
int index;
Window window;
{
  section = index;
  manualing = 0;
  XDefineCursor(w,xman_cursor);
  if(manfp != NULL) {
    fclose(manfp);
    manfp = NULL;
  }
  XClear(w);
  putEntries(section);  
}
char *
stralloc(sp) char *sp;
{
  char *ret;

  if((ret = (char *) malloc(strlen(sp)+1)) == NULL) {
    eprintf("Fatal: out of memory in stralloc()\n");
    exit(1);
  }
  strcpy(ret,sp);
  return(ret);
}
