[BACK]Return to viewer.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / othersrc / dist / cdk

File: [cvs.NetBSD.org] / othersrc / dist / cdk / viewer.c (download)

Revision 1.3, Sun Mar 26 21:38:43 2006 UTC (8 years, 4 months ago) by christos
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +3 -3 lines

Coverity CID 972: Someone confused && and || again.

#include <cdk.h>

/*
 * $Author: christos $
 * $Date: 2006/03/26 21:38:43 $
 * $Revision: 1.3 $
 */

/*
 * Declare some local definitions.
 */
#define		DOWN		0
#define		UP		1

/*
 * Declare file local prototypes.
 */
static int searchForWord (CDKVIEWER *viewer, char *pattern, int direction);
static int jumpToLine (CDKVIEWER *viewer);
static void popUpLabel (CDKVIEWER *viewer, char *mesg);
static void getAndStorePattern (CDKSCREEN *screen);
static void drawCDKViewerButtons (CDKVIEWER *viewer);
static void drawCDKViewerInfo (CDKVIEWER *viewer);

/*
 * Declare file local variables.
 */
static char *	SearchPattern	= 0;
int		SearchDirection = DOWN;

DeclareCDKObjects(my_funcs, Viewer);

/*
 * This function creates a new viewer object.
 */
CDKVIEWER *newCDKViewer (CDKSCREEN *cdkscreen, int xplace, int yplace, int height, int width, char **buttonLabel, int buttonCount, chtype buttonHighlight, boolean Box, boolean shadow)
{
   /* Declare local variables. */
   CDKVIEWER *viewer	= newCDKObject(CDKVIEWER, &my_funcs);
   int parentWidth	= getmaxx(cdkscreen->window);
   int parentHeight	= getmaxy(cdkscreen->window);
   int boxWidth		= width;
   int boxHeight	= height;
   int xpos		= xplace;
   int ypos		= yplace;
   int buttonWidth, buttonPos, buttonAdj;
   int x, junk2;

   /*
    * If the height is a negative value, the height will
    * be ROWS-height, otherwise, the height will be the
    * given height.
    */
   boxHeight = setWidgetDimension (parentHeight, height, 0);

   /*
    * If the width is a negative value, the width will
    * be COLS-width, otherwise, the width will be the
    * given width.
    */
   boxWidth = setWidgetDimension (parentWidth, width, 0);

   /* Translate the button label char * to a chtype * */
   buttonWidth = 0;
   for (x=0; x < buttonCount; x++)
   {
      viewer->buttonLabel[x]	= char2Chtype (buttonLabel[x], &viewer->buttonLen[x], &junk2);
      buttonWidth		+= viewer->buttonLen[x] + 1;
   }
   buttonWidth--;

   /* Determine the final dimensions of the box. */
   boxWidth	= MAXIMUM (boxWidth, buttonWidth + 2);

   viewer->fieldWidth	= boxWidth - 2;
   if (buttonCount > 0)
   {
      viewer->viewSize	= boxHeight - 4;
   }
   else
   {
      viewer->viewSize	= boxHeight - 2;
   }

   /* Rejustify the x and y positions if we need to. */
   alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);

   /* Make the viewer window. */
   viewer->win = newwin (boxHeight + !!shadow, boxWidth + !!shadow, ypos, xpos);

   /* Is the window null? */
   if (viewer->win == 0)
   {
      /* Clean up any used memory. */
      for (x=0; x < viewer->buttonCount; x++)
      {
	 freeChtype (viewer->buttonLabel[x]);
      }
      free (viewer);

      /* Return a null pointer. */
      return (0);
   }
   keypad (viewer->win, TRUE);
   leaveok (viewer->win, TRUE);

   /* Make the info window. */
   viewer->infoWin	= subwin (viewer->win,
				viewer->viewSize, viewer->fieldWidth,
				ypos + 1, xpos + 1);

   /* Make the button window. */
   if (buttonCount > 0)
   {
      viewer->buttonWin	= subwin (viewer->win,
				1, boxWidth - 2,
				ypos + viewer->viewSize + 2, xpos + 1);
   }

   /* Set the rest of the variables */
   ScreenOf(viewer)		= cdkscreen;
   viewer->parent		= cdkscreen->window;
   viewer->buttonCount		= buttonCount;
   viewer->buttonHighlight	= buttonHighlight;
   viewer->currentButton	= 0;
   viewer->boxHeight		= boxHeight;
   viewer->boxWidth		= boxWidth - 2;
   viewer->exitType		= vNEVER_ACTIVATED;
   ObjOf(viewer)->box		= Box;
   viewer->shadow		= shadow;
   viewer->currentTop		= 0;
   viewer->length		= 0;
   viewer->leftChar		= 0;
   viewer->maxLeftChar		= 0;
   viewer->maxTopLine		= 0;
   viewer->characters		= 0;
   viewer->infoSize		= 0;
   viewer->showLineInfo		= 1;
   viewer->titleLines		= 0;
   viewer->ULChar		= ACS_ULCORNER;
   viewer->URChar		= ACS_URCORNER;
   viewer->LLChar		= ACS_LLCORNER;
   viewer->LRChar		= ACS_LRCORNER;
   viewer->HChar		= ACS_HLINE;
   viewer->VChar		= ACS_VLINE;
   viewer->BoxAttrib		= A_NORMAL;

   /* Create the buttons. */
   buttonAdj = (boxWidth - 2 - buttonWidth) / (buttonCount + 1);
   buttonPos = buttonAdj;
   for (x=0; x < buttonCount; x++)
   {
      viewer->buttonPos[x]	= buttonPos;
      buttonPos			+= viewer->buttonLen[x] + buttonAdj;
   }

   /* Clean the key bindings. */
   cleanCDKObjectBindings (vVIEWER, viewer);

   /* Register this baby. */
   registerCDKObject (cdkscreen, vVIEWER, viewer);

   /* Return the viewer object. */
   return (viewer);
}

/*
 * This function sets various attributes of the widget.
 */
int setCDKViewer (CDKVIEWER *viewer, char *title, char **info, int infoSize, chtype buttonHighlight, boolean attrInterp, boolean showLineInfo, boolean Box)
{
   setCDKViewerTitle (viewer, title);
   setCDKViewerHighlight (viewer, buttonHighlight);
   setCDKViewerInfoLine (viewer, showLineInfo);
   setCDKViewerBox (viewer, Box);
   return setCDKViewerInfo (viewer, info, infoSize, attrInterp);
}

/*
 * This sets the title of the viewer. (A null title is allowed.
 * It just means that the viewer will not have a title when drawn.)
 */
void setCDKViewerTitle (CDKVIEWER *viewer, char *title)
{
   char **temp;
   int x;

   /* Clean out the old title. */
   if (viewer->titleLines > 0)
   {
      for (x=0; x < viewer->titleLines; x++)
      {
	 freeChtype (viewer->title[x]);
      }
      delwin (viewer->titleWin);
   }

   /* Create the new title if there is one. */
   if (title != 0)
   {
      temp = CDKsplitString (title, '\n');
      viewer->titleLines = CDKcountStrings (temp);

      /* For each line in the title, convert from char * to chtype * */
      for (x=0; x < viewer->titleLines; x++)
      {
	 viewer->title[x]	= char2Chtype (temp[x],
					&viewer->titleLen[x],
					&viewer->titlePos[x]);
	 viewer->titlePos[x]	= justifyString (viewer->boxWidth - 2,
					viewer->titleLen[x],
					viewer->titlePos[x]);
      }

      CDKfreeStrings(temp);
   }
   else
   {
      /* No title? Set the required variables. */
      viewer->titleLines = 0;
   }

   /* Set the rest of the variables. */
   if (viewer->buttonCount > 0)
   {
      viewer->viewSize	= viewer->boxHeight - 4 - viewer->titleLines;
   }
   else
   {
      viewer->viewSize	= viewer->boxHeight - 2 - viewer->titleLines;
   }

   if (viewer->titleLines > 0)
   {
      viewer->titleWin	= subwin (viewer->win,
				viewer->titleLines, viewer->boxWidth - 2,
				getbegy (viewer->win) + 1,
				getbegx (viewer->win) + 1);
   }

   delwin (viewer->infoWin);
   viewer->infoWin	= subwin (viewer->win,
				viewer->viewSize, viewer->fieldWidth,
				getbegy (viewer->win) + viewer->titleLines + 1,
				getbegx (viewer->win) + 1);
}
chtype **getCDKViewerTitle (CDKVIEWER *viewer)
{
   return viewer->title;
}

/*
 * This function sets the contents of the viewer.
 */
int setCDKViewerInfo (CDKVIEWER *viewer, char **info, int infoSize, boolean interpret)
{
   /* Declare local variables. */
   char filename[512];
   int widestLine	= -1;
   int currentLine	= 0;
   int x		= 0;

   /* Clean out the old viewer info. (if there is any) */
   for (x=0; x < viewer->infoSize; x++)
   {
      freeChtype (viewer->info[x]);
      viewer->info[x] = 0;
   }
   memset (filename, '\0', 512);

   /* Keep some semi-perinant info. */
   viewer->interpret = interpret;

   /* Copy the information given. */
   currentLine = 0;
   for (x=0; x < infoSize; x++)
   {
      if (info[x] == 0)
      {
	 viewer->info[currentLine]	= 0;
	 viewer->infoLen[currentLine]	= 0;
	 viewer->infoPos[currentLine]	= 0;
	 currentLine++;
      }
      else
      {
	 /* Check if we have a file link in this line. */
	 if (checkForLink (info[x], filename) == 1)
	 {
	    /* We have a link, open the file. */
	    char *fileContents[MAX_LINES], temp[256];
	    int fileLen		= 0;
	    int fileLine	= 0;

	    /* Open the file and put it into the viewer. */
	    fileLen = readFile (filename, fileContents, MAX_LINES);
	    if (fileLen == -1)
	    {
		int adj		= 0;
		int len		= 0;

	       /* Could not open the file. */
#ifdef HAVE_START_COLOR
	       sprintf (temp, "<C></16>Link Failed: Could not open the file %s", filename);
#else
	       sprintf (temp, "<C></K>Link Failed: Could not open the file %s", filename);
#endif
	       viewer->info[currentLine]	= char2Chtype (temp, &len, &adj);
	       viewer->infoPos[currentLine]	= justifyString (viewer->boxWidth, len, adj);
	       viewer->infoLen[currentLine]	= len;
	       widestLine = MAXIMUM (widestLine, viewer->infoLen[currentLine]);
	       currentLine++;
	    }
	    else
	    {
	       /* For each line read, copy it into the viewer. */
	       for (fileLine=0; fileLine < fileLen ; fileLine++)
	       {
		  int len = (int)strlen (fileContents[fileLine]);
		  int y;

		  /* Init memory and clean it. */
		  viewer->info[currentLine] = (chtype *)malloc (sizeof(chtype) * (len + 3));
		  cleanChtype (viewer->info[currentLine], len + 3, '\0');

		  /* Copy from one to the other. */
		  for (y=0; y < len; y++)
		  {
		     viewer->info[currentLine][y] = fileContents[fileLine][y];
		  }
		  viewer->infoLen[currentLine]	= len;
		  viewer->infoPos[currentLine]	= 0;
		  widestLine			= MAXIMUM(widestLine, len);
		  viewer->characters		+= len;
		  freeChar (fileContents[fileLine]);
		  currentLine++;
	       }
	    }
	 }
	 else
	 {
	    /* Did they ask for attribute interpretation? */
	    if (!viewer->interpret)
	    {
	       int len = (int)strlen (info[x]);
	       int y;

	       /* Init memory and clean it. */
	       viewer->info[currentLine] = (chtype *)malloc (sizeof(chtype) * (len + 3));
	       cleanChtype (viewer->info[currentLine], len + 3, '\0');

	       /* Copy from one to the other. */
	       for (y=0; y < len; y++)
	       {
		  viewer->info[currentLine][y] = info[x][y];
	       }
	       viewer->infoLen[currentLine]	= len;
	       viewer->infoPos[currentLine]	= 0;
	       widestLine			= MAXIMUM(widestLine, len);
	       viewer->characters		+= len;
	       currentLine++;
	    }
	    else
	    {
	       viewer->info[currentLine] = char2Chtype (info[x],
						&viewer->infoLen[currentLine],
						&viewer->infoPos[currentLine]);
	       viewer->infoPos[currentLine] = justifyString (viewer->boxWidth,
						viewer->infoLen[currentLine],
						viewer->infoPos[currentLine]);
	       widestLine = MAXIMUM(widestLine, viewer->infoLen[currentLine]);
	       viewer->characters += viewer->infoLen[currentLine];
	       currentLine++;
	    }
	 }
      }
   }

  /*
   * Determine how many characters we can shift to the right
   * before all the items have been viewer off the screen.
   */
   viewer->maxLeftChar = MAXIMUM (0, widestLine - viewer->boxWidth);

   /* Set up the needed vars for the viewer list. */
   viewer->infoSize = currentLine;
   viewer->maxTopLine = MAXIMUM (0, viewer->infoSize - viewer->viewSize);

   return viewer->infoSize;
}
chtype **getCDKViewerInfo (CDKVIEWER *viewer, int *size)
{
   (*size) = viewer->infoSize;
   return viewer->info;
}

/*
 * This function sets the highlight type of the buttons.
 */
void setCDKViewerHighlight (CDKVIEWER *viewer, chtype buttonHighlight)
{
   viewer->buttonHighlight = buttonHighlight;
}
chtype getCDKViewerHighlight (CDKVIEWER *viewer)
{
   return viewer->buttonHighlight;
}

/*
 * This sets whether or not you want to set the viewer info line.
 */
void setCDKViewerInfoLine (CDKVIEWER *viewer, boolean showLineInfo)
{
   viewer->showLineInfo = showLineInfo;
}
boolean getCDKViewerInfoLine (CDKVIEWER *viewer)
{
   return viewer->showLineInfo;
}

/*
 * This sets the widgets box attribute.
 */
void setCDKViewerBox (CDKVIEWER *viewer, boolean Box)
{
   ObjOf(viewer)->box = Box;
}
boolean getCDKViewerBox (CDKVIEWER *viewer)
{
   return ObjOf(viewer)->box;
}

/*
 * This function actually controls the viewer...
 */
int activateCDKViewer (CDKVIEWER *viewer, chtype *actions GCC_UNUSED)
{
   /* Declare local variables. */
   CDKLABEL *fileInfoLabel;
   char *fileInfo[10], temp[500];
   chtype emptyString[256];
   chtype input;
   int x, REFRESH;

   /* Create a string full of spaces. */
   cleanChtype (emptyString, viewer->boxWidth-1, '\0');
   cleanChtype (emptyString, viewer->boxWidth-3, ' ');

   /* Create the information about the file stats. */
   sprintf (temp, "</5>      </U>File Statistics<!U>     <!5>");
   fileInfo[0] = copyChar(temp);
   sprintf (temp, "</5>                          <!5>");
   fileInfo[1] = copyChar(temp);
   sprintf (temp, "</5/R>Character Count:<!R> %-4d     <!5>", viewer->characters);
   fileInfo[2] = copyChar(temp);
   sprintf (temp, "</5/R>Line Count     :<!R> %-4d     <!5>", viewer->infoSize);
   fileInfo[3] = copyChar(temp);
   sprintf (temp, "</5>                          <!5>");
   fileInfo[4] = copyChar(temp);
   sprintf (temp, "<C></5>Press Any Key To Continue.<!5>");
   fileInfo[5] = copyChar(temp);

   /* Set the current button. */
   viewer->currentButton = 0;

   /* Draw the viewer list. */
   drawCDKViewer (viewer, ObjOf(viewer)->box);

   /* Do this until KEY_RETURN is hit. */
   for (;;)
   {
      /* Reset the refresh flag. */
      REFRESH = FALSE;

      /* Get the user input. */
      wrefresh (viewer->win);
      input = wgetch (viewer->win);
      if (! checkCDKObjectBind (vVIEWER, viewer, input))
      {
	 switch (input)
	 {
	    case KEY_TAB : case CDK_NEXT :
		 if (viewer->buttonCount > 1)
		 {
		    if (viewer->currentButton == (viewer->buttonCount - 1))
		    {
		       viewer->currentButton = 0;
		    }
		    else
		    {
		       viewer->currentButton++;
		    }

		    /* Redraw the buttons. */
		    drawCDKViewerButtons (viewer);
		 }
		 break;

	    case CDK_PREV :
		 if (viewer->buttonCount > 1)
		 {
		    if (viewer->currentButton == 0)
		    {
		       viewer->currentButton = viewer->buttonCount - 1;
		    }
		    else
		    {
		       viewer->currentButton--;
		    }

		    /* Redraw the buttons. */
		    drawCDKViewerButtons (viewer);
		 }
		 break;

	    case KEY_UP :
		 if (viewer->currentTop > 0)
		 {
		    viewer->currentTop--;
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_DOWN :
		 if (viewer->currentTop < viewer->maxTopLine)
		 {
		    viewer->currentTop++;
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_RIGHT :
		 if (viewer->leftChar < viewer->maxLeftChar)
		 {
		    viewer->leftChar++;
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_LEFT :
		 if (viewer->leftChar > 0)
		 {
		    viewer->leftChar--;
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_PPAGE : case CONTROL('B') : case 'b' : case 'B' :
		 if (viewer->currentTop > 0)
		 {
		    if ((viewer->currentTop - (viewer->viewSize-1)) > 0)
		    {
		       viewer->currentTop = viewer->currentTop - (viewer->viewSize - 1);
		    }
		    else
		    {
		       viewer->currentTop = 0;
		    }
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_NPAGE : case CONTROL('F') : case ' ' : case 'f' : case 'F' :
		 if (viewer->currentTop < viewer->maxTopLine)
		 {
		    if ((viewer->currentTop + viewer->viewSize) < viewer->maxTopLine)
		    {
		       viewer->currentTop = viewer->currentTop + (viewer->viewSize - 1);
		    }
		    else
		    {
		       viewer->currentTop = viewer->maxTopLine;
		    }
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_HOME : case '|' :
		 viewer->leftChar = 0;
		 REFRESH = TRUE;
		 break;

	    case KEY_END : case '$' :
		 viewer->leftChar = viewer->maxLeftChar;
		 REFRESH = TRUE;
		 break;

	    case 'g' : case '1' :
		 viewer->currentTop = 0;
		 REFRESH = TRUE;
		 break;

	    case 'G' :
		 viewer->currentTop = viewer->maxTopLine;
		 REFRESH = TRUE;
		 break;

	    case 'L' :
		 x = (int) ((viewer->infoSize + viewer->currentTop) / 2);
		 if (x < viewer->maxTopLine)
		 {
		    viewer->currentTop = x;
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case 'l' :
		 x = (int) (viewer->currentTop / 2);
		 if (x >= 0)
		 {
		    viewer->currentTop = x;
		    REFRESH = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case '?' :
		 SearchDirection = UP;
		 getAndStorePattern (ScreenOf(viewer));
		 if (! searchForWord(viewer, SearchPattern, SearchDirection))
		 {
		    sprintf (temp, "</U/5>Pattern '%s' not found.<!U!5>", SearchPattern);
		    popUpLabel (viewer, temp);
		 }
		 REFRESH = TRUE;
		 break;

	    case '/' :
		 SearchDirection = DOWN;
		 getAndStorePattern (ScreenOf(viewer));
		 if (! searchForWord(viewer, SearchPattern, SearchDirection))
		 {
		    sprintf (temp, "</U/5>Pattern '%s' not found.<!U!5>", SearchPattern);
		    popUpLabel (viewer, temp);
		 }
		 REFRESH = TRUE;
		 break;

	    case 'n' :
		 if (SearchPattern == 0)
		 {
		    popUpLabel (viewer, "</5>There is no pattern in the buffer.<!5>");
		 }
		 else
		 {
		    if (! searchForWord(viewer, SearchPattern, SearchDirection))
		    {
		       sprintf (temp, "</5>Pattern '%s' not found.<!5>", SearchPattern);
		       popUpLabel (viewer, temp);
		    }
		 }
		 REFRESH = TRUE;
		 break;

	    case ':' :
		 viewer->currentTop	= jumpToLine (viewer);
		 REFRESH		= TRUE;
		 break;

	    case 'i' : case 's' : case 'S' :
		 fileInfoLabel	= newCDKLabel (ScreenOf(viewer), CENTER, CENTER, fileInfo, 6, TRUE, FALSE);
		 drawCDKLabel (fileInfoLabel, TRUE);
		 waitCDKLabel (fileInfoLabel, 0);
		 destroyCDKLabel (fileInfoLabel);
		 REFRESH = TRUE;
		 break;

	    case KEY_ESC :
		 freeCharList (fileInfo, 6);
		 viewer->exitType = vESCAPE_HIT;
		 return -1;

	    case KEY_RETURN : case KEY_ENTER : case KEY_CR :
		 freeCharList (fileInfo, 6);
		 viewer->exitType = vNORMAL;
		 return viewer->currentButton;

	    case CDK_REFRESH :
		 eraseCDKScreen (ScreenOf(viewer));
		 refreshCDKScreen (ScreenOf(viewer));
		 break;

	    default :
		 Beep();
		 break;
	 }
      }

      /* Do we need to redraw the screen??? */
      if (REFRESH)
      {
	 drawCDKViewerInfo (viewer);
      }
   }
}

/*
 * This searches the document looking for the given word.
 */
static void getAndStorePattern (CDKSCREEN *screen)
{
   /* Declare local variables. */
   CDKENTRY *getPattern = 0;
   char *temp		= 0;
   char *info		= 0;

   /* Check the direction. */
   if (SearchDirection == UP)
   {
      temp = "</5>Search Up  : <!5>";
   }
   else
   {
      temp = "</5>Search Down: <!5>";
   }

   /* Pop up the entry field. */
   getPattern	= newCDKEntry (screen, CENTER, CENTER,
				0, temp,
				COLOR_PAIR(5)|A_BOLD,
				'.'|COLOR_PAIR(5)|A_BOLD,
				vMIXED, 10, 0, 256, TRUE, FALSE);

   /* Is there an old search pattern? */
   if (SearchPattern != 0)
   {
      setCDKEntry (getPattern, SearchPattern, getPattern->min, getPattern->max, ObjOf(getPattern)->box);
   }
   freeChar (SearchPattern);

   /* Activate this baby. */
   info = activateCDKEntry (getPattern, 0);

   /* Save the info. */
   if ((info != 0) && (strlen (info) != 0))
   {
      SearchPattern = copyChar (info);
   }

   /* Clean up. */
   destroyCDKEntry (getPattern);
}

/*
 * This searches for the word and realigns the value on the screen.
 */
static int searchForWord (CDKVIEWER *viewer, char *pattern, int direction)
{
   /* Declare local variables. */
   int x, y, pos, len, plen;

   /* If the pattern is null then return. */
   if (pattern == 0)
   {
      return(0);
   }
   plen = (int)strlen(pattern);

   /* Given the direction, start looking.... */
   if (direction == DOWN)
   {
      /* Start looking from 'here' down. */
      for (x = viewer->currentTop + 1; x < viewer->infoSize; x++)
      {
	/*
	 * Start looking. If we find it, then set the value of
	 * viewer->currentTop and possibly even leftChar...
	 */
	 len	= chlen (viewer->info[x]);
	 pos	= 0;
	 for (y=0; y < len; y++)
	 {
	    /* We have to tear the attributes from the chtype. */
	    char plainChar	= viewer->info[x][y] & A_CHARTEXT;

	    /* We have found the word at this point. */
	    if (pos == plen)
	    {
	       viewer->currentTop	= (x < viewer->maxTopLine  ? x : viewer->maxTopLine);
	       viewer->leftChar = (y < viewer->boxWidth ? 0 : viewer->maxLeftChar);
	       return (1);
	    }

	    /* Keep trudging along. */
	    if (pattern[pos++] != plainChar)
	    {
	       pos	= 0;
	    }
	 }
      }
   }
   else
   {
      /* Start looking from 'here' up. */
      for (x = viewer->currentTop - 1; x >= 0; x--)
      {
	/*
	 * Start looking. If we find it, then set the value of
	 * viewer->currentTop and possibly even leftChar...
	 */
	 len	= chlen (viewer->info[x]);
	 pos	= 0;
	 for (y=0; y < len; y++)
	 {
	    /* We have to tear the attributes from the chtype. */
	    char plainChar	= viewer->info[x][y] & A_CHARTEXT;

	    /* We have found the word at this point. */
	    if (pos == plen)
	    {
	       viewer->currentTop	= x;
	       viewer->leftChar = (y < viewer->boxWidth ? 0 : viewer->maxLeftChar);
	       return (1);
	    }

	    /* Keep trudging along. */
	    if (pattern[pos++] != plainChar)
	    {
	       pos	= 0;
	    }
	 }
      }
   }
   return(0);
}

/*
 * This allows us to 'jump' to a given line in the file.
 */
static int jumpToLine (CDKVIEWER *viewer)
{
   /* Declare local variables. */
   int line		= 0;
   CDKSCALE * newline	= newCDKScale (ScreenOf(viewer), CENTER, CENTER,
				"<C>Jump To Line", "</5>Line :", A_BOLD, 5,
				0, 0, viewer->maxTopLine + 1, 1, 10, TRUE, TRUE);
   line = activateCDKScale (newline, 0);
   destroyCDKScale (newline);
   return ((line-1));
}

/*
 * This pops a little message up on the screen.
 */
static void popUpLabel (CDKVIEWER *viewer, char *mesg)
{
   /* Declare local variables. */
   char *info[3];
   CDKLABEL *label;

   /* Set up variables. */
   info[0]	= mesg;
   label	= newCDKLabel (ScreenOf(viewer), CENTER, CENTER, info, 1, TRUE, FALSE);

   /* Draw the label and wait. */
   drawCDKLabel (label, TRUE);
   waitCDKLabel (label, 0);

   /* Clean up. */
   destroyCDKLabel (label);
}

/*
 * This moves the viewer field to the given location.
 */
static void _moveCDKViewer (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag)
{
   CDKVIEWER *viewer = (CDKVIEWER *)object;

   /*
    * If this is a relative move, then we will adjust where we want
    * to move to.
    */
   if (relative)
   {
      xplace += getbegx(viewer->win);
      yplace += getbegy(viewer->win);
   }

   /* Adjust the window if we need to. */
   alignxy (WindowOf(viewer), &xplace, &yplace, viewer->boxWidth, viewer->boxHeight);

   /* Move the window to the new location. */
   moveCursesWindow(viewer->win, xplace, yplace);

   /* Redraw the window, if they asked for it. */
   if (refresh_flag)
   {
      drawCDKViewer (viewer, ObjOf(viewer)->box);
   }
}

/*
 * This function draws the viewer widget.
 */
static void _drawCDKViewer (CDKOBJS *object, boolean Box)
{
   CDKVIEWER *viewer = (CDKVIEWER *)object;
   int x;

   /* Box it if it was asked for. */
   if (Box)
   {
      attrbox (viewer->win,
		viewer->ULChar, viewer->URChar,
		viewer->LLChar, viewer->LRChar,
		viewer->HChar,	viewer->VChar,
		viewer->BoxAttrib,
		viewer->shadow);
   }

   if (viewer->titleLines > 0)
   {
      /* Redraw the title. */
      for (x=0; x < viewer->titleLines; x++)
      {
	 writeChtype (viewer->titleWin,
			viewer->titlePos[x], x,
			viewer->title[x],
			HORIZONTAL, 0,
			viewer->titleLen[x]);
      }
      wnoutrefresh (viewer->titleWin);
   }

   /* Draw the info in the viewer. */
   drawCDKViewerInfo (viewer);
}

/*
 * This redraws the viewer buttons.
 */
static void drawCDKViewerButtons (CDKVIEWER *viewer)
{
   /* Declare local variables. */
   int x;

   if (viewer->buttonCount > 0)
   {
      for (x=0; x < viewer->buttonCount; x++)
      {
	 if (x == viewer->currentButton)
	 {
	    writeChtypeAttrib (viewer->buttonWin,
			viewer->buttonPos[x], 0,
			viewer->buttonLabel[x],
			viewer->buttonHighlight,
			HORIZONTAL, 0,
			viewer->buttonLen[x]);
	 }
	 else
	 {
	    writeChtype (viewer->buttonWin,
			viewer->buttonPos[x], 0,
			viewer->buttonLabel[x],
			HORIZONTAL, 0,
			viewer->buttonLen[x]);
	 }
      }

      wnoutrefresh (viewer->buttonWin);
   }

   wnoutrefresh (viewer->win);
}

/*
 * These functions set the drawing characters of the widget.
 */
void setCDKViewerULChar (CDKVIEWER *viewer, chtype character)
{
   viewer->ULChar = character;
}
void setCDKViewerURChar (CDKVIEWER *viewer, chtype character)
{
   viewer->URChar = character;
}
void setCDKViewerLLChar (CDKVIEWER *viewer, chtype character)
{
   viewer->LLChar = character;
}
void setCDKViewerLRChar (CDKVIEWER *viewer, chtype character)
{
   viewer->LRChar = character;
}
void setCDKViewerVerticalChar (CDKVIEWER *viewer, chtype character)
{
   viewer->VChar = character;
}
void setCDKViewerHorizontalChar (CDKVIEWER *viewer, chtype character)
{
   viewer->HChar = character;
}
void setCDKViewerBoxAttribute (CDKVIEWER *viewer, chtype character)
{
   viewer->BoxAttrib = character;
}

/*
 * This sets the background color of the widget.
 */
void setCDKViewerBackgroundColor (CDKVIEWER *viewer, char *color)
{
   chtype *holder = 0;
   int junk1, junk2;

   /* Make sure the color isn't null. */
   if (color == 0)
   {
      return;
   }

   /* Convert the value of the environment variable to a chtype. */
   holder = char2Chtype (color, &junk1, &junk2);

   /* Set the widgets background color. */
   wbkgd (viewer->win, holder[0]);

   /* Clean up. */
   freeChtype (holder);
}

/*
 * This function destroys the viewer widget.
 */
void destroyCDKViewer (CDKVIEWER *viewer)
{
   /* Declare local variables. */
   int x;

   /* Erase the object. */
   eraseCDKViewer (viewer);

   /* Clear up the char pointers. */
   for (x=0; x < viewer->titleLines; x++)
   {
      freeChtype (viewer->title[x]);
   }
   for (x=0; x < viewer->infoSize; x++)
   {
      freeChtype (viewer->info[x]);
   }
   for (x=0; x < viewer->buttonCount; x++)
   {
      freeChtype (viewer->buttonLabel[x]);
   }

   /* Clean up the windows. */
   deleteCursesWindow (viewer->win);

   /* Unregister this object. */
   unregisterCDKObject (vVIEWER, viewer);

   /* Finish cleaning up. */
   free (viewer);
}

/*
 * This function erases the viewer widget from the screen.
 */
static void _eraseCDKViewer (CDKOBJS *object)
{
   CDKVIEWER *viewer = (CDKVIEWER *)object;

   eraseCursesWindow (viewer->win);
}

/*
 * This draws the viewer info lines.
 */
static void drawCDKViewerInfo (CDKVIEWER *viewer)
{
   /* Declare some local vars */
   int infoAdjust	= 0;
   char temp[256];
   int screenPos, x;

   /* Clear the window. */
   werase (viewer->infoWin);

   /* Draw in the current line at the top. */
   if (viewer->showLineInfo == TRUE)
   {
      /* Set up the info line and draw it. */
      if (viewer->infoSize != 0)
      {
	 sprintf (temp, "%d/%d %2.0f%%",
			viewer->currentTop + 1,
			viewer->infoSize,
			(float)(viewer->currentTop + 1) / (float)viewer->infoSize * 100);
      }
      else
      {
	 sprintf (temp, "%d/%d %2.0f%%", 0, 0, 0.0);
      }

     /*
      * The infoAdjust variable tells us if we have to shift down
      * one line because the person asked for the line X of Y line
      * at the top of the screen. We only want to set this to 1 if
      * they asked for the info line and there is no title, or if the
      * two items overlap.
      */
      if (viewer->titleLines == 0
       || viewer->titlePos[0] < (int)strlen(temp) + 2)
      {
	 infoAdjust = 1;
      }
      writeChar (viewer->infoWin, 0, 0,
		 temp, HORIZONTAL, 0, (int)strlen(temp));
   }

   /* Redraw the list. */
   for (x=0; x < viewer->viewSize - infoAdjust; x++)
   {
      if (x + viewer->currentTop >= viewer->infoSize)
      {
	 break;
      }

      screenPos = viewer->infoPos[viewer->currentTop + x] - viewer->leftChar;

      if (screenPos >= 0)
      {
	 writeChtype (viewer->infoWin,
			screenPos, x + infoAdjust,
			viewer->info[x + viewer->currentTop],
			HORIZONTAL, 0,
			viewer->infoLen[x + viewer->currentTop]);
      }
      else
      {
	 writeChtype (viewer->infoWin,
			0, x + infoAdjust,
			viewer->info[x + viewer->currentTop],
			HORIZONTAL, -screenPos,
			viewer->infoLen[x + viewer->currentTop]);
      }
   }

   /* Draw the separation line. */
   if (viewer->buttonCount > 0)
   {
      mvwaddch (viewer->win, viewer->boxHeight-3, 0,
			ACS_LTEE | viewer->BoxAttrib);
      mvwhline (viewer->win, viewer->boxHeight-3, 1,
			viewer->HChar | viewer->BoxAttrib, viewer->boxWidth);
      mvwaddch (viewer->win, viewer->boxHeight-3,
			viewer->boxWidth+1,
			ACS_RTEE | viewer->BoxAttrib);
   }

   wnoutrefresh (viewer->infoWin);

   /* Draw the buttons. This will call refresh on the viewer win. */
   drawCDKViewerButtons (viewer);
}