/*
Copyright (C) 1997-2005 Erwin Waterlander

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "std_macro.h"
#include "structures.h"
#include "nameset.h"
#include "display.h"
#include "wcd.h"


/************************************************************************
 *
 *  swap(), ssort() and sort_list()
 *
 *  Sort a nameset list alphabeticly
 *
 ************************************************************************/

void swap(nameset list, int i, int j)
{  text temp;

   temp = list->array[i];
   list->array[i] = list->array[j];
   list->array[j] = temp;
}

void ssort (nameset list, int left, int right)
{
 int i, last;

  if (left >= right) return; /* fewer than 2 elements */

  swap(list, left, (left + right)/2);
  last = left;

  for (i = left+1; i <=right; i++)
	if  (strcmp(list->array[i],list->array[left])<0)
	   swap(list, ++last, i);

  swap(list, left, last);
  ssort(list, left, last-1);
  ssort(list, last+1, right);
}

void sort_list(nameset list)
{
 ssort(list,0,(list->size)-1);
}

/************************************************************************
 *
 *  maxLength()
 *  Get the longest string in a nameset list.
 *
 ************************************************************************/

#ifdef WCD_USECURSES
int maxLength(nameset list)
{
	int i,len,maxlen = 0;

	if (list == NULL)
	{
		fprintf(stderr,"Wcd: error in maxLength(), list == NULL\n");
		return 32 ;
	}

   for (i=0;i<list->size;i++)
   {
    if( (len=strlen(list->array[i])) > maxlen)
       maxlen=len;
   }
	if (maxlen > 32)
      return(maxlen);
	else
	   return 32 ;     /* minimal width for help screen */
}
int maxLengthStack(WcdStack s)
{
	int i,len,maxlen = 0;

	if (s == NULL)
	{
		fprintf(stderr,"Wcd: error in maxLengthStack(), s == NULL\n");
		return 32 ;
	}

   for (i=0;i<s->size;i++)
   {
    if( (len=strlen(s->dir[i])) > maxlen)
       maxlen=len;
   }
	if (maxlen > 32)
      return(maxlen);
	else
	   return 32 ;     /* minimal width for help screen */
}

#endif

/************************************************************************
 *
 *  display_list(nameset list)
 *
 *  Display a match list on screen.
 *
 *  There are three versions of the function:
 *
 *  1) stdout version
 *     This version will work on any platform. Default for Unix and Windows.
 *     Has to make use of the scroll-back capability of the terminal.
 *
 *  2) CONIO version
 *     Default used for DOS, optional for Windows NT.
 *     Scroll back is programmed in.
 *
 *  3) CURSES version
 *     Optional for Unix, DOS or Windows.
 *     Scroll back is programmed in.
 *
 ************************************************************************/

#ifdef WCD_USECONIO

void print_list_normal(nameset list, int top, int bottom, int use_numbers)
{
	int i;

	if (use_numbers == 0)
	{
		for (i=top;i<=bottom;i++)
			cprintf("%c  %s\n\r",(char)(((i-top)%SCROLL_WIN_HEIGHT) + 'a'),list->array[i]);
	}
	else
	{
		for (i=top;i<=bottom;i++)
			cprintf("%d  %s\n\r",((i-top)%SCROLL_WIN_HEIGHT) + 1,list->array[i]);
	}
}
/**************************************************/

void print_list_stack(WcdStack ws, int start, int top, int bottom, int use_numbers) 
{
	int i,j;

	if (use_numbers == 0)
	{
		for (i=top;i<=bottom;i++)
		{
		  j = (i + start)%(ws->size);
		  cprintf("%c  %s",(char)(((i-top)%SCROLL_WIN_HEIGHT) + 'a'),ws->dir[j]);
		  if (j == ws->current)
			  cprintf(" *");
		  cprintf("\n\r");
		}
	}
	else
	{
		for (i=top;i<=bottom;i++)
		{
		  j = (i + start)%(ws->size);
		  /* cprintf("%d  %s",i + 1,ws->dir[j]); */
		  cprintf("%d  %s",(i-top)%SCROLL_WIN_HEIGHT + 1,ws->dir[j]);
		  if (j == ws->current)
			  cprintf(" *");
		  cprintf("\n\r");
		}
	}
}

void print_list(nameset list, WcdStack ws, int start, int top, int bottom, int use_numbers) 
{
	if (list != NULL)
		print_list_normal(list,top,bottom,use_numbers);
	else
		if (ws != NULL)
			print_list_stack(ws,start,top,bottom,use_numbers);
}

/****************************************************************************/

/* upper left corner is (1,1) */
int display_list_conio(nameset list,WcdStack ws, int perfect,int use_numbers)
{
int i, n=0, top, bottom, c=0, extended, gtxt=0;
int page ;
int start=0, size;
char number_str[WCD_MAX_INPSTR];
char *buffer;
struct text_info ti;

	gettextinfo(&ti);

	buffer = (char *) malloc(ti.screenwidth * ti.screenheight * 2);

	if (buffer!=NULL)   /* get total screen */
	  gtxt = gettext(1,1,ti.screenwidth,ti.screenheight,buffer);

	if (list != NULL)    /* normal list */
	{
		sort_list(list);
		size = list->size;
	}
	else
		if (ws != NULL)   /* stack */
		{
			if( ((ws->size) <= 0) || ((ws->size) > ws->maxsize) || ((ws->size) > ws->maxsize) )
				return(WCD_ERR_LIST); /* in case stack file was corrupt */
			else
			{
				size = ws->size;

				if (ws->size < ws->maxsize)
					start = 0;
				else
					start = ws->lastadded + 1;

				if (ws->lastadded >= ws->maxsize)
					start = 0;
			}
		}
		else
			return(WCD_ERR_LIST);  /* no list or stack */

	i= WCD_ERR_LIST;
	number_str[n] = '\0';

	if (size > SCROLL_WIN_HEIGHT )
	{
		top = 0;
		clrscr();

		bottom = size -1;
		top = size - SCROLL_WIN_HEIGHT;

		window(1,1,ti.screenwidth,SCROLL_WIN_HEIGHT+1);

		clrscr();

      print_list(list, ws, start, top, bottom, use_numbers);

		page = bottom / SCROLL_WIN_HEIGHT + 1 ;

		window (1,SCROLL_WIN_HEIGHT+1,ti.screenwidth,25);

		clrscr();

		cprintf("\n\r");
		if (list != NULL)
		{
			if(perfect)
				cprintf("Perfect ");
			else
				cprintf("Wild ");
			cprintf("match for %d directories.\n\r",size);
		}
		else
			cprintf("\n\r");

		cprintf("Please choose one (<Enter> to abort): ");
		fflush(stdout);
		gotoxy (PAGEOFFSET, 2);
		cprintf("w=up x=down  Page %d/%d      ",page,(size -1)/SCROLL_WIN_HEIGHT +1);
		gotoxy (OFFSET + n, 3);

		while ((c != 13 )&&(( c < 'a' ) || ( c > 'v' )))
		{

		  c = getch();

		  switch(c)
		  {
		  case 'x':
		  case 'w':
		  case 0:   /* extended key */

			if(c==0)
			  extended = getch();
			else
			{
			 if (c=='w')
				extended = 73;  /* Page Up */
			 else
				extended = 81;  /* Page Down */
			}


			if ((extended == 73) || /* Page Up */
				(extended == 72))   /* Arrow Up */
			{
			  window(1,1,ti.screenwidth,SCROLL_WIN_HEIGHT+1);
			  clrscr();

			  if(bottom > (SCROLL_WIN_HEIGHT -1))
			  {
				bottom = bottom - SCROLL_WIN_HEIGHT ;
				top = top - SCROLL_WIN_HEIGHT ;
			  }

			  if (top<0) top = 0;

			  if (bottom < (SCROLL_WIN_HEIGHT -1) )
			  gotoxy(1,SCROLL_WIN_HEIGHT-bottom);

           print_list(list, ws, start, top, bottom, use_numbers);

				page = bottom / SCROLL_WIN_HEIGHT + 1 ;

				window (1,SCROLL_WIN_HEIGHT+1,ti.screenwidth,25);
				gotoxy (PAGEOFFSET, 2);
				cprintf("w=up x=down  Page %d/%d      ",page,(size -1)/SCROLL_WIN_HEIGHT +1);
				gotoxy (OFFSET + n, 3);


			} /* Page Up */

			if ((extended == 81) || /* Page down */
				(extended == 80))   /* Arrow down */
			{
			  window(1,1,ti.screenwidth,SCROLL_WIN_HEIGHT+1);
			  clrscr();

			  if(bottom < (size -1 ))
			  {
				bottom = bottom + SCROLL_WIN_HEIGHT ;
				top = bottom - SCROLL_WIN_HEIGHT + 1;
			  }

           print_list(list, ws, start, top, bottom, use_numbers);

				page = bottom / SCROLL_WIN_HEIGHT + 1 ;

				window (1,SCROLL_WIN_HEIGHT+1,ti.screenwidth,25);
				gotoxy (PAGEOFFSET, 2);
				cprintf("w=up x=down  Page %d/%d      ",page,(size -1)/SCROLL_WIN_HEIGHT +1);
				gotoxy (OFFSET + n, 3);
			}/* Page down */

			window (1,SCROLL_WIN_HEIGHT+1,ti.screenwidth,25);
			gotoxy (OFFSET + n, 3);
		  break;
		  case 8:  /* backspace */
			window (1,SCROLL_WIN_HEIGHT+1,ti.screenwidth,25);
			if(n>0) n--;
	  		number_str[n] = '\0';
			gotoxy(OFFSET + n, 3);
			cprintf(" ");
			gotoxy(OFFSET + n, 3);
			break;
		  case 3:  /* Control-C */
		  case 27: /* Escape */
			c = 13;
			i = WCD_ERR_LIST;
			number_str[0] = '\0';
		   break;
		  case 13: /* Enter */
			c = 13;
			i = WCD_ERR_LIST;
			break;
		  default:
			if (( c >= '0') && ( c <= '9') && (n < WCD_MAX_INPSTR)) /* numbers */
			{
				number_str[n] = (char)c;
			   window (1,SCROLL_WIN_HEIGHT+1,ti.screenwidth,25);
			   gotoxy (OFFSET + n++, 3);
			   cprintf("%c",(char)c);
				number_str[n] = '\0';
			
				/* Notice that one has to choose a number from 1 to max 22 */
			if (((bottom - top) < 9) /* displayed list is 9 or less matches */
				 || (n == 2)           /* second number typed */
				 || (c >= '3')         /* 3-9 is typed */
				 || ((c == '2')&&((bottom - top) < 19)) /* displayed list is 19 or less matches */
				)
				c = 13;      /* do an <Enter> */
				
			}
			else
				i=c+top-'a'+1;
			 break;
		  }
		}
		window (1,1,ti.screenwidth,ti.screenheight);
		gotoxy (ti.curx, ti.cury);
	}
	else
	{
		top = 0;
		bottom = size - 1;
      print_list(list, ws, start, top, bottom, use_numbers);

		printf("\n");
		if (list != NULL)
		{
			if(perfect)
				printf("Perfect ");
			else
				printf("Wild ");
			printf("match for %d directories.\n",size);
		}
		printf("Please choose one (<Enter> to abort): ");
		fflush(stdout);


		while ((c != 13 )&&(( c < 'a' ) || ( c > ('a'+size -1) )))
		{
		  c = getch();

		  switch(c)
		  {
		  case 0:
			  extended = getch();
		  break;
		  case 8:  /* backspace */
			if(n>0) 
			{
				n--;
				number_str[n] = '\0';
				printf("%c",8);
				printf(" ");
				printf("%c",8);
				fflush(stdout);
			}
			break;
		  case 3:  /* Control-C */
		  case 27: /* Escape */
			c = 13;
			i = WCD_ERR_LIST;
			number_str[0] = '\0';
		   break;
		  case 13: /* Enter */
			c = 13;
			i = WCD_ERR_LIST;
			break;
		  default:
			if (( c >= '0') && ( c <= '9') && (n < WCD_MAX_INPSTR)) /* numbers */
			{
				number_str[n] = (char)c;
			   n++;
			   printf("%c",(char)c);
				fflush(stdout);
				number_str[n] = '\0';
			
				/* Notice that one has to choose a number from 1 to max 22 */
			if (((bottom - top) < 9) /* displayed list is 9 or less matches */
				 || (n == 2)           /* second number typed */
				 || (c >= '3')         /* 3-9 is typed */
				 || ((c == '2')&&((bottom - top) < 19)) /* displayed list is 19 or less matches */
				)
				c = 13;      /* do an <Enter> */
				
			}
			else
				i=c -'a'+1;
		  break;
		 }
		}
	}

	printf("\n");

	if (gtxt ==1)
	  puttext(1,1,ti.screenwidth,ti.screenheight,buffer);

	if (buffer!=NULL)
	  free(buffer);
/*
	cprintf("window left      %2d\r\n",ti.winleft);
	cprintf("window top       %2d\r\n",ti.wintop);
	cprintf("window right     %2d\r\n",ti.winright);
	cprintf("window bottom    %2d\r\n",ti.winbottom);
	cprintf("attribute        %2d\r\n",ti.attribute);
	cprintf("normal attribute %2d\r\n",ti.normattr);
	cprintf("current mode     %2d\r\n",ti.currmode);
	cprintf("screen height    %2d\r\n",ti.screenheight);
	cprintf("screen width     %2d\r\n",ti.screenwidth);

	cprintf("current x        %2d\r\n",ti.curx);
	cprintf("current y        %2d\r\n",ti.cury); */

	if (strcmp(number_str,"") != 0) /* a number was typed */
		i=atoi(number_str) + top; 

	if((ws != NULL)&&(list == NULL)) /* stack */
	{
		if (( i <=0)||(i > ws->size)) /* fail */
		{
		  return(WCD_ERR_LIST);
		 }
		else    /* succes */
		{
		  i = ( i - 1 + start)%(ws->size);
		  ws->current = i;
		}
	}
	return i;
}

#endif

#ifdef WCD_USECURSES

void printLine(WINDOW *win, nameset n, int i, int y, int xoffset, int *use_numbers)
{
   wcd_char *s;
   int len, j, nr_offset;

   s = n->array[i];

   if (s != NULL)
   {
      len = strlen(s);
		if (*use_numbers == 0)
			nr_offset = 2;
		else
			nr_offset = 3;

		wmove(win,y,nr_offset);

      for(j=xoffset;(j<len)&&((nr_offset+j-xoffset)<(COLS-1));j++)
      {
         waddch(win,s[j]);
      }
   }
}

void printStackLine(WINDOW *win, WcdStack ws, int i, int y, int xoffset, int *use_numbers)
{
   wcd_char *s;
   int len, j, nr_offset;

   s = ws->dir[i];

   if (s != NULL)
   {
      len = strlen(s);
		if (*use_numbers == 0)
			nr_offset = 2;
		else
			nr_offset = 3;

		wmove(win,y,nr_offset);

      for(j=xoffset;(j<len)&&((nr_offset+j-xoffset)<(COLS-1));j++)
      {
         waddch(win,s[j]);
      }
		if ((i == ws->current) && ((nr_offset+j-xoffset+2)<(COLS-1)))
			  wprintw(win," *");
   }
}
/**************************************************/

void print_list_normal(WINDOW *scrollWin, int lines_per_page,int line, nameset list, int top, int bottom, int use_numbers, int xoffset) 
{
	int i;

	for (i=top;i<=bottom;i++)
	{
		if (use_numbers == 0)
	  		mvwprintw(scrollWin,line,0,"%c ",(char)(((i-top)%lines_per_page) + 'a'));
		else
	  		mvwprintw(scrollWin,line,0,"%2d ",((i-top)%lines_per_page) + 1);
		printLine(scrollWin, list, i, line, xoffset, &use_numbers);
		line++;
	}
}

/**************************************************/

void print_list_stack(WINDOW *scrollWin, int lines_per_page,int line, WcdStack ws, int start, int top, int bottom, int use_numbers, int xoffset) 
{
	int i,j;

	if (use_numbers == 0)
	{
		for (i=top;i<=bottom;i++)
		{
		  j = (i + start)%(ws->size);
		  mvwprintw(scrollWin,line,0,"%c ",(char)(((i-top)%lines_per_page) + 'a'));
		  printStackLine(scrollWin, ws, j, line, xoffset, &use_numbers);
		  line++;
		}
	}
	else
	{
		for (i=top;i<=bottom;i++)
		{
		  j = (i + start)%(ws->size);
		  /* mvwprintw(scrollWin,line,0,"%d  %s",i + 1,ws->dir[j]); */
		  mvwprintw(scrollWin,line,0,"%2d ",(i-top)%lines_per_page + 1);
		  printStackLine(scrollWin, ws, j, line, xoffset, &use_numbers);
		  line++;
		}
	}
}

void print_list(WINDOW *scrollWin, int lines_per_page,int line, nameset list, WcdStack ws, int start, int top, int bottom, int use_numbers, int xoffset) 
{
	wclear(scrollWin);
	if (list != NULL)
		print_list_normal(scrollWin,lines_per_page,line,list,top,bottom,use_numbers,xoffset);
	else
		if (ws != NULL)
			print_list_stack(scrollWin,lines_per_page,line,ws,start,top,bottom,use_numbers,xoffset);
}

/* ****************************************************************** */
/* upper left corner is (0,0) */
/* ****************************************************************** */

#define Key_CTRL(x)      ((x) & 31)

int display_list_curses(nameset list, WcdStack ws, int perfect,int use_numbers)
{
  int i, n=0, line, top, bottom, c=0;
  int start=0, size,displayed_list;
  int scrollWinHeight, page, len, shift=0, err ;
  int inputWinLen ;
  int lines_per_page ; /* number of lines to print per page */
  char number_str[WCD_MAX_INPSTR];
  WINDOW *scrollWin, *inputWin ;
#ifndef __PDCURSES__
  SCREEN *sp;
#endif

/* Notice that list->size > 1 when this function is called. */

	if (list != NULL)    /* normal list */
	{
		sort_list(list);
		size = list->size;
	}
	else
		if (ws != NULL)   /* stack */
		{
			if( ((ws->size) <= 0) || ((ws->size) > ws->maxsize) || ((ws->size) > ws->maxsize) )
				return(WCD_ERR_LIST); /* in case stack file was corrupt */
			else
			{
				size = ws->size;

				if (ws->size < ws->maxsize)
					start = 0;
				else
					start = ws->lastadded + 1;

				if (ws->lastadded >= ws->maxsize)
					start = 0;
			}
		}
		else
			return(WCD_ERR_LIST);  /* no list or stack */

	i= WCD_ERR_LIST;
	number_str[n] = '\0';

#ifdef __PDCURSES__
	initscr();
#else
	sp = newterm(NULL,stdout,stdin);
	if (sp == NULL)
	{  
		fprintf(stderr,"Wcd: warning: Error opening terminal, falling back to stdout.\n");
		return WCD_ERR_CURSES;
	}
#endif

   keypad(stdscr, TRUE);
   intrflush(stdscr, FALSE);
   cbreak();
   noecho();
   nonl();
	scrollok(stdscr, TRUE);	/* enable scrolling */

   if (LINES < 4)
   {
      endwin();
#ifdef XCURSES
      XCursesExit();
#endif
      fprintf(stderr,"Wcd: error: screen height must be > 3.\n");
      return WCD_ERR_CURSES;
   }

   scrollWinHeight = LINES - INPUT_WIN_HEIGHT;
   lines_per_page = scrollWinHeight;
	if (use_numbers == 0)
	{
		if (scrollWinHeight > SCROLL_WIN_HEIGHT)
			lines_per_page = SCROLL_WIN_HEIGHT;
	}
	else
	{
		if (scrollWinHeight > 99)
			lines_per_page = 99; /* stay below 3 digits */
	}

	if (list != NULL)
		len = maxLength(list);
	else
		if (ws != NULL)
			len = maxLengthStack(ws);
		else
			return(WCD_ERR_LIST);
			
   refresh();

   scrollWin = newpad(scrollWinHeight,COLS);
   if (scrollWin == NULL)
   {
      endwin();
#ifdef XCURSES
      XCursesExit();
#endif
      fprintf(stderr,"Wcd: error creating scroll window.\n");
      return WCD_ERR_CURSES;
   }

   scrollok(scrollWin, TRUE);

	bottom = size -1; /* lowest match to print */
	top = size - lines_per_page; /* top match to print */
	if (top < 0)
		top = 0;

	if (bottom < (lines_per_page -1) )
      line = scrollWinHeight - bottom - 1; /* screen line nr. where to start printing */
   else
      line = scrollWinHeight - lines_per_page;

	print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);


   if (COLS < INPUT_WIN_LEN)
      inputWinLen = INPUT_WIN_LEN;
   else 
      inputWinLen = COLS;

   inputWin = newpad(INPUT_WIN_HEIGHT,inputWinLen);
   if (inputWin == NULL)
   {
      endwin();
#ifdef XCURSES
      XCursesExit();
#endif
      fprintf(stderr,"Wcd: error creating input window.\n");
      return WCD_ERR_CURSES;
   }

	wclear(inputWin);
   scrollok(inputWin, TRUE);

	if (list != NULL)
	{
		if(perfect)
		  mvwprintw(inputWin,1,0,"Perfect ");
		else
		  mvwprintw(inputWin,1,0,"Wild ");
		wprintw(inputWin,"match for %d directories.",size);
	}
	mvwprintw(inputWin,2,0,"Please choose one (<Enter> to abort): ");

	page = bottom / lines_per_page + 1 ;

	wmove (inputWin, 1, PAGEOFFSET);
	wprintw(inputWin,"w=up x=down ?=help  Page %d/%d      ",page,(size -1)/lines_per_page +1);
	wmove (inputWin, 2, OFFSET);
   err = prefresh(scrollWin,0,0,0,0,scrollWinHeight-1,COLS-1);
   err = prefresh(inputWin,0,0,scrollWinHeight,0,scrollWinHeight+INPUT_WIN_HEIGHT-1,COLS-1);

	while ((c != 13 )&&(( c < 'a' ) || ( c > ('a'+scrollWinHeight-1) || ( c > 'v' ) )))
	{

	  c = getch();

	  switch(c)
	  {
	  case 'w':
	  case KEY_UP:  /* Arrow Up */
     case KEY_PPAGE: /* Page Up */

		  if(bottom > (lines_per_page -1))
		  {
			bottom = bottom - lines_per_page ;
			top = top - lines_per_page ;
		  }

		  if (top<0) top = 0;

	     if (bottom < (lines_per_page -1) )
           line = scrollWinHeight - bottom - 1;
        else
           line = scrollWinHeight - lines_per_page;

			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);

		   page = bottom / lines_per_page + 1 ;

			wmove (inputWin, 1, PAGEOFFSET);
			wprintw(inputWin,"w=up x=down ?=help  Page %d/%d      ",page,(size -1)/lines_per_page +1);
			wmove (inputWin, 2, OFFSET + n);

			break;

		case 'x':
		case KEY_DOWN: /* Arrow down */
      case KEY_NPAGE: /* Page down */

		  if(bottom < (size - 1))
		  {
			bottom = bottom + lines_per_page ;
			top = bottom - lines_per_page + 1;
		  }

	     if (bottom < (lines_per_page -1) )
           line = scrollWinHeight - bottom - 1;
        else
           line = scrollWinHeight - lines_per_page;

			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);

			page = bottom / lines_per_page + 1 ;

			wmove (inputWin, 1, PAGEOFFSET);
			wprintw(inputWin,"w=up x=down ?=help  Page %d/%d      ",page,(size -1)/lines_per_page +1);
			wmove (inputWin, 2, OFFSET + n);
	  break;

      case ',':
      case KEY_LEFT:
          if (shift > 0)
             shift--;
			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);
         break;
      case '.':
      case KEY_RIGHT:
         if (shift < len)
            shift++;
			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);
         break;
       case '<':
       case '[':
          shift -=10;
          if (shift < 0)
             shift=0;
			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);
         break;
      case ']':
      case '>':
         shift +=10;
         if (shift > len)
            shift=len;
			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);
         break;
      case Key_CTRL ('a'):
      case KEY_HOME:
         shift = 0;
			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);
         break;
      case Key_CTRL ('e'):
#ifdef KEY_END
      case KEY_END:
#endif
         shift = len - COLS/2;
          if (shift < 0)
             shift=0;
			print_list(scrollWin,lines_per_page,line,list,ws,start,top,bottom,use_numbers,shift);
         break;
      case KEY_F (1):
      case '?':

         wclear(scrollWin);
         if (scrollWinHeight < 17)
				mvwprintw(scrollWin,0,0,"Screenheight must be > 20 for help.");
         else
         {
				mvwprintw(scrollWin, 0,0,"w or <Up>         Page Up.");
				mvwprintw(scrollWin, 1,0,"x or <Down>       Page Down.");
				mvwprintw(scrollWin, 2,0,", or <Left>       Scroll 1 left.");
				mvwprintw(scrollWin, 3,0,". or <Right>      Scroll 1 right.");
				mvwprintw(scrollWin, 4,0,"< or [            Scroll 10 left.");
				mvwprintw(scrollWin, 5,0,"> or ]            Scroll 10 right.");
				mvwprintw(scrollWin, 6,0,"CTRL-a or <HOME>  Scroll to beginning.");
				mvwprintw(scrollWin, 7,0,"CTRL-e or <END>   Scroll to end.");
				mvwprintw(scrollWin, 8,0,"CTRL-c or <Esc>   Abort.");
				mvwprintw(scrollWin, 9,0,"<Enter>           Abort.");
				mvwprintw(scrollWin,11,0,"Type w or x to quit help.");
         }
	      break;
	  case 3:  /* Control-C */
	  case 27: /* Escape */
		c = 13;
		i = WCD_ERR_LIST;
		number_str[0] = '\0';
		break;
	  case 13: /* Enter */
	  case KEY_ENTER:
		c = 13;
		i = WCD_ERR_LIST;
		break;
	  case 8:  /* backspace */
	  case KEY_BACKSPACE:
	  case 127: /* delete */
				if(n>0) n--;
	  			number_str[n] = '\0';
				wmove (inputWin, 2, OFFSET + n);
				wprintw(inputWin," ");
				wmove (inputWin, 2, OFFSET + n);
	  break;
	  default:
			if (( c >= '0') && ( c <= '9') && (n < WCD_MAX_INPSTR)) /* numbers */
			{
			   number_str[n] = (char)c;
				wmove (inputWin, 2, OFFSET + n++);
				number_str[n] = '\0';
				wprintw(inputWin,"%c",(char)c);
			
				displayed_list = bottom - top;
				/* Notice that one has to choose a number from 1 to max 99 */
			if ((displayed_list < 9) /* displayed list is 9 or less matches */
				 || (n == 2)           /* second number typed */
				 || ((c == '2')&&( displayed_list < 19)) /* displayed list is 19 or less matches */
				 || ((c == '3')&&( displayed_list < 29)) /* displayed list is 29 or less matches */
				 || ((c == '4')&&( displayed_list < 39)) /* displayed list is 39 or less matches */
				 || ((c == '5')&&( displayed_list < 49)) /* displayed list is 49 or less matches */
				 || ((c == '6')&&( displayed_list < 59)) /* displayed list is 59 or less matches */
				 || ((c == '7')&&( displayed_list < 69)) /* displayed list is 69 or less matches */
				 || ((c == '8')&&( displayed_list < 79)) /* displayed list is 79 or less matches */
				 || ((c == '9')&&( displayed_list < 89)) /* displayed list is 89 or less matches */
				)
				c = 13;      /* do an <Enter> */
				
			}
			else
				i=c+top-'a'+1;

	  break;
	  }
     err = prefresh(scrollWin,0,0,0,0,scrollWinHeight-1,COLS-1);
     err = prefresh(inputWin,0,0,scrollWinHeight,0,scrollWinHeight+INPUT_WIN_HEIGHT-1,COLS-1);
	}

   endwin();
#ifdef XCURSES
   XCursesExit();
#endif
	if (strcmp(number_str,"") != 0) /* a number was typed */
		i=atoi(number_str) + top; 

	printf("\n"); /* Extra newline for curses, pdcurses and when ncurses doesn't restore screen */

	if ((ws != NULL)&&(list == NULL)) /* stack */
	{
		if (( i <=0)||(i > ws->size)) /* fail */
		{
		  return(WCD_ERR_LIST);
		 }
		else    /* succes */
		{
		  i = ( i - 1 + start)%(ws->size);
		  ws->current = i;
		}
	}
   return i;
}

#endif


 /* stdout version */
int display_list_stdout(nameset list,WcdStack ws, int perfect, int use_stdout)
{
   int i;
	int k, start, j;

	if (list != NULL) /* normal list */
	{
		sort_list(list);

		if ( use_stdout & WCD_STDOUT_DUMP )
		{
		   for (i=0;i<list->size;i++)
			   printf("%s\n", list->array[i]);
		}
		else
		{
		   for (i=0;i<list->size;i++)
			   printf("%d  %s\n",i+1,list->array[i]);
		}

		if ( use_stdout & WCD_STDOUT_DUMP )
			return(WCD_ERR_LIST);
		else
		{
			if(perfect)
			  printf("\nPerfect ");
			else
			  printf("\nWild ");
			printf("match for %d directories.\n",list->size);
			printf("Please choose one (<Enter> to abort): ");
		}

		return wcd_get_int();
	}
	else
		if (ws != NULL)  /* stack */
		{
	/*	printWcdStack("XXX ", ws, stdout); */
		if(ws->maxsize <= 0)
			return (WCD_ERR_LIST);
		else
			if( ((ws->size) <= 0) || ((ws->size) > ws->maxsize) )
			return (WCD_ERR_LIST);
			else
			{

				if (ws->size < ws->maxsize)
					 start = 0;
				 else
					  start = ws->lastadded + 1;

				 if (ws->lastadded >= ws->maxsize)
					  start = 0;

				k=1;
				for(i=0; i < (ws->size) ; i++)
				{
					j = (i + start)%(ws->size);
					if ( !(use_stdout & WCD_STDOUT_DUMP) )
						printf("%2d ",k);
					k++;

					printf("%s",ws->dir[j]);
					if (j == ws->current)
						printf(" *");
					printf("\n");
				}

				if ( use_stdout & WCD_STDOUT_DUMP )
				  return(WCD_ERR_LIST);

				printf("\nPlease choose one (<Enter> to abort): ");
				i = wcd_get_int();

				if (( i <=0)||(i > ws->size)) /* fail */
				{
				  return(WCD_ERR_LIST);
				 }
				else    /* succes */
				{
				  i = ( i - 1 + start)%(ws->size);
				  ws->current = i;
				  return(i);
				}
			}
		}
		else
			return WCD_ERR_LIST;
}


int display_list(nameset list,int perfect, int use_numbers, int use_stdout)
{
#ifdef WCD_USECONIO
	if (use_stdout == WCD_STDOUT_NO)
		return display_list_conio(list,NULL,perfect,use_numbers);
	else
		return display_list_stdout(list,NULL,perfect, use_stdout);
#else
# ifdef WCD_USECURSES
	int i;
	if ((use_stdout == WCD_STDOUT_NO) && ((i = display_list_curses(list,NULL,perfect,use_numbers)) != WCD_ERR_CURSES))
		return i;
	else
		return display_list_stdout(list,NULL,perfect, use_stdout);
# else
	return display_list_stdout(list,NULL,perfect, use_stdout);
# endif
#endif
}
