#include "defines.h"
/*     Bed a Binary EDitor for Linux and for Rxvt running under Linux.       */
/*     Copyright (C) 1998  Jaap Korthals Altes <jkaltes@hetnet.nl>      */
/*                                                                           */
/*     Bed 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.                                   */
/*                                                                           */
/*     Bed 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 bed; if not, write to the Free Software                    */
/*     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             */
/*                                                                           */
/* Sun Dec  6 18:34:27 1998                                                  */

#ifdef __CYGWIN__
#include <windows.h>
#endif
#include <features.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#undef isprint
#define isprint(x) ((x)>31&&(x)<127)
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
       #include <pwd.h>
              #include <sys/types.h>
              #include <grp.h>
#include "getfile.h"
#include "screen.h"
#include "system.h"
#include "readcolors.h"
#include "onlykey.h"
#include "keyinput.h"
#include "myalloc.h"
#define trefresh(x)
char space[240];

int zomaareenvar;

#define minnum( x,y) ((x)>(y)?(y):(x))
#define maxnum( een, twee) (((een)>(twee))?(een):(twee))
#ifdef CURSES

#if defined(TEST) || defined(TEST2) || defined(TEST3)
#define EENTEST
#endif

#ifdef EENTEST



Fieldcol fieldcolor[] = {
{"text",0,1},{"command",A_REVERSE,2},{"bar",A_REVERSE,3},
{"barkey",A_NORMAL,4},{"menu",A_REVERSE,5},{"menukey",A_NORMAL,6},
{"menusel",A_BOLD|A_UNDERLINE,7},
{"opentitle",A_BOLD,8}, {"openkey",A_BOLD,9},
{"opennormal",0,10},
{"openlist",A_REVERSE,11},{"openlistsel",A_NORMAL,12},
{"openlistact",A_NORMAL|A_BOLD,13},{"showback",A_BOLD,14},{"selection",A_REVERSE,15}, {"cursor",A_REVERSE,16}, {"selcursor",A_UNDERLINE|A_BOLD,17} };


#define REFRESH 12
int ggetch(WINDOW *w) {
	static int ch=0;
	int key;
	if(ch) {
		if(ch==27) {
			ch=0;

#ifndef EENTEST
			if(keystrokeout<keystrokein)
				key=keystrokes[keystrokein++];
			else 
#endif
{
				halfdelay(1);
				if((key=wgetch(w))== (-1) )
					key= 254 ;
				nocbreak();
				cbreak();
			}
				}
		else {
			key=ch;
			ch=0;
			}
		}
	else {
#ifndef EENTEST
			if(keystrokeout<keystrokein)
				key=keystrokes[keystrokein++];
			else
#endif
				key=wgetch(w);
			if((key)&0x80) {
				ch=key&0x7f;
				return 27;
				}
			else
				if(key==27)
					ch=27;
		}
	return key;
	}




//#define ggetch(x) wgetch(x)
#define thelines LINES
#define thecols COLS
int initscreen(void) {
	initscr();
	clearok(stdscr,FALSE);
	clearok(curscr,FALSE);

		noecho();
	   	cbreak();
	   	nonl();

	if(has_colors()) {
			short f,b;
			start_color();
			getfilecolors();
			}
		scrollok(stdscr,0);
	   	};
//#define SELSELATTR         SELATTR|A_REVERSE|A_BOLD
void getfilecolors(void) {
			init_pair(4,COLOR_RED,COLOR_BLUE);
			SELATTR=COLOR_PAIR(4)|A_BOLD;
			init_pair(5,COLOR_BLACK,COLOR_YELLOW);
			KEYATTR=COLOR_PAIR(5)|A_STANDOUT|A_BOLD;
			init_pair(6,COLOR_BLACK,COLOR_GREEN);
			TITLEATTR=COLOR_PAIR(6);
			init_pair(7,COLOR_WHITE,COLOR_BLACK);
			BACKATTR=COLOR_PAIR(7);
		}
#else
extern int thelines,thecols;
extern int ggetch(WINDOW *w);
#endif
/*
inline void cursoraway(void) {
	HIDECURSOR;
		move(thelines-1,thecols);
		refresh();
		}
*/
#define cursoraway() HIDECURSOR

	#define winb 48
	#define winh 15
WINDOW *takescr;
#define optionscreen takescr

#define	SELCOLOR wattrset(takescr,SELATTR)
#define	KEYCOLOR wattrset(takescr,KEYATTR)
#define	TITLECOLOR wattrset(takescr,TITLEATTR)
#define	SELSELCOLOR  wattrset(takescr,SELSELATTR)
#define	BACK wattrset(takescr,BACKATTR)
#define	NORMALCOLOR BACK
#define	UNSELCOLOR    wattrset(takescr,UNSELATTR)
#else
#ifdef CONIO
#include <conio.h>

#define	initscreen()
int  addnstr(char *x,int n) {
	int len=strlen(x);
	cwrite(x,minnum(len,n));
	}
#define addch putch
#define  waddstr(takescr,(x) cputs(x)
#define move(y,x) gotoxy(x+1,y+1)
#define endwin()
#define refresh()

#define clrtoeol() clreol()
#define	SELCOLOR textattr(LIGHTRED|(BLUE<<4))
#define	SELSELCOLOR textattr(LIGHTBLUE|(RED<<4))
#define	KEYCOLOR textattr(YELLOW|(BLACK<<4))
//#define	TITLECOLOR textattr(YELLOW|(RED<<4))
#define	TITLECOLOR textattr(BLACK|(CYAN<<4))
#define	BACK textattr(LIGHTMAGENTA|(BLACK<<4))
#define	NORMALCOLOR BACK
#define LINES tinfo.screenheight
#define COLS tinfo.screenwidth
#endif
#endif
	#define RETURN 0xff1
	#define NEXT 0xff2
	#define PREV 0xff3
	#define BEG 0xff4
	#define END 0xff5
	#define PGDN 0xff6
	#define PGUP 0xff7
	#define FILEPART 0xff8
	#define DIR 0xff9
	#define FIL 0xff10
	#define DOWN 0xff11
	#define UP 0xff12
	#define BACKSPACE 8
	#define DELETE 0xff13
	#define TAB  9
	#define SHIFTAB 0xff15
	#define REFRESH 12
	#define CLEAR  21
	#define NOP  0xff16
	#define QUIT 0xff17
	#define HELP 0xff18

#define keylabel(label,edit,menu,open) open,
int getfilesym[]= {
#include "keylist.h"
};
#undef keylabel

#include "glob.h"

void	attrall(WINDOW *takescr,int attrs) {
	int y,x,i;
	getmaxyx(takescr,y,x);
	char line[x+1];
	memset(line,' ',x);
	wattrset(takescr, attrs );
	wmove(takescr,0,0);
	for(i=0;i<y;i++) 
		waddnstr(takescr,line,x);
	}

void winsel::show(void) {
	int last=minnum(h,tot-beg);
	SELCOLOR;
	trefresh(stdscr);
	for(int i=0;i<h;i++) {
		wmove(takescr,i+y,x-1);
//		s/\<addnstr\>(/waddnstr(takescr,/g
		waddnstr(takescr,space,l+2);

		}
	for(int i=0;i<last;i++) {
		wmove(takescr,i+y,x);
		waddnstr(takescr,strings[beg+i],(l));
		}
	if(tot<1)
		return;
	if(sel>=last)
		sel=last-1;
	if(sel<0)
		sel=0;
	SELSELCOLOR;
	trefresh(takescr);
	wmove(takescr,y+sel,x);
	waddnstr(takescr,space,l);
	wmove(takescr,y+sel,x);
	waddnstr(takescr,strings[beg+sel],l);
	trefresh(takescr);
	trefresh(takescr);
	}
	/*
void winsel::showsel(int dir) {
	int oldpos=sel+beg;
	int newpos=oldpos+dir;
	int endscr=minnum(beg+h,tot);
	int newsel;
	if(newpos<0)
		newpos=0;
	if(newpos>=tot)
		newpos=tot-1;

	if(newpos<beg) {
		beg=newpos;
		sel=0;
		show();
		return;
		}
	else {
		if(newpos>=endscr) {
			sel=minnum(h,tot-beg)-1;
			beg=newpos-sel;
			show();
			return;
			}
		else
			newsel=sel+dir;
		}

	SELCOLOR;
	wmove(takescr,y+sel,x);
	waddnstr(takescr,space,l);
	wmove(takescr,y+sel,x);
	waddnstr(takescr,strings[beg+sel],l);
	sel=newsel;
	SELSELCOLOR;
//		s/\<refresh(/wrefresh(takescr
	trefresh(takescr);
	wmove(takescr,y+sel,x);
	waddnstr(takescr,space,l);
	wmove(takescr,y+sel,x);
	waddnstr(takescr,strings[beg+sel],l);
	trefresh(takescr);
	}

*/
void winsel::showsel(int dir) {
	if(tot<1)
		return;
	int newsel=sel+dir;
	int last=minnum(h,tot-beg);
	if(newsel>=last)  {
		if((newsel+beg)>=tot)  {
			beg=tot-last;
			sel=tot-1-beg;
			}
		else  {
			beg+=dir;
			}
		 show();
		 return;
		}
	if(newsel<0) {
		if(beg) {
			sel=beg+newsel;
			beg=maxnum(0,beg+dir);
			sel=maxnum(0,sel-beg);
			}
		else
			sel=0;
		show();
		return;
		}
	if((newsel+beg)>=(tot-1))  
		newsel=tot-beg-1;

		SELCOLOR;
		wmove(takescr,y+sel,x);
		waddnstr(takescr,space,l);
		wmove(takescr,y+sel,x);
		waddnstr(takescr,strings[beg+sel],l);
		sel=newsel;
		SELSELCOLOR;
//		s/\<refresh(/wrefresh(takescr
		trefresh(takescr);
		wmove(takescr,y+sel,x);
		waddnstr(takescr,space,l);
		wmove(takescr,y+sel,x);
		waddnstr(takescr,strings[beg+sel],l);
		trefresh(takescr);
	}
	void winsel::leave(void) {
		if(tot<1)
			return;
		UNSELCOLOR;
		trefresh(takescr);
		wmove(takescr,y+sel,x);
		waddnstr(takescr,space,l);
		wmove(takescr,y+sel,x);
		waddnstr(takescr,strings[beg+sel],l);
		trefresh(takescr);
		}	
#include "getlabel.h"
char *winsel::select(int key) {
	int ant;	
	if((ant=selectindex( key) )<0)
		return NULL;
	return strings[ant];
	}
/*
		switch(key) {
			case RETURN: in=0;
				if(tot>0)
					return strings[beg+sel];
				break;
			case DOWN: showsel(1);;break;
			case UP: showsel(-1);;break;
			case END: showsel(tot);break;
			case BEG: showsel(-tot);break;
			case PGDN: showsel(h-1);break;
			case PGUP: showsel(1-h);break;
			default:
				if((key<0xff)&&isprint(key)) {
					int start,pos;
					if(!in)
						start=0;
					else
						start=sel+beg;
					al[in++]=key;
					al[in]='\0';
					pos=getunderlabeli(strings+start,tot-start,al,icase);
					showsel(pos+start-(sel+beg));
					return NULL;
					}
			};
		in=0;
		return NULL;
		}
*/;
int winsel::selectindex(int key) {
		switch(key) {
			case RETURN: in=0; 
			if(tot>0)
					return beg+sel;
			break;
			case DOWN: showsel(1);;break;
			case UP: showsel(-1);;break;
			case END: showsel(tot);break;
			case BEG: showsel(-tot);break;
			case PGDN: showsel(h-1);break;
			case PGUP: showsel(1-h);break;
			default:
			if((key<0xff)&&isprint(key)) {
				int start,pos;
				if(!in)
					start=0;
				else
					start=sel+beg;
				al[in++]=key;
				al[in]='\0';
				pos=getunderlabeli(strings+start,tot-start,al,icase);
				showsel(pos+start-(sel+beg));
				return -1;
				}
			};
		in=0;
		return -1;
		}

		/*
char *winsel::select(void) {
	int key;
	while(1) {
		while((key=input.keyseq(ggetch(takescr)))==-1)
			trefresh(takescr);
		switch(key) {
			case RETURN: return strings[beg+sel];
			case NEXT: showsel(1);;break;
			case PREV: showsel(-1);;break;
			case END: showsel(tot);break;
			case BEG: showsel(-tot);break;
			case PGDN: showsel(h-1);break;
			case PGUP: showsel(1-h);break;
			};
		wmove(takescr,-1,-1);
		trefresh(takescr);
		}
	}
	*/

	itemlist::itemlist(const char *txt,char **str,int nr,int ypos,int xpos,int &a,int begin,int hight,int len):
	item(txt,ypos,xpos),
	ant(a),
	wins(str,nr,xpos+1,ypos+1,begin, hight,len)
 {
		};
	itemlist::~itemlist() {
		}
	void itemlist::show(void) {
		SELCOLOR;
		wmove(optionscreen,y,x);
		waddstr(optionscreen,text);
		KEYCOLOR;
		waddch(optionscreen,ch);
		SELCOLOR;
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x);
		wins.show();
		}
	void itemlist::select(void) {
		SELSELCOLOR;
		wmove(optionscreen,y,x);
		waddstr(optionscreen,text);
		KEYCOLOR;
		waddch(optionscreen,ch);
		SELSELCOLOR;
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x);
		wins.showsel(0);
		}
	int itemlist::switchvar(void) {
		return wins.selectindex(' ');
		}
	int itemlist::save(void) {
		ant= wins.beg+wins.sel;
		return 0;
		}
	int itemlist::saveall(void) {
			save();
			return 2;
			;}
	int itemlist::change(int key) {
		return wins.selectindex(key);
		};
#include "varmacro.h"
#ifdef OLDGCCVARMACRO
#define	keydef(sym,keys...) input.putseq(sym,sizeof((unsigned char [])##keys),(unsigned char []) ##keys)  VARMACRO
#define	seqput(sym,keys...) keyinp->putseq(sym,sizeof((unsigned char [])##keys),(unsigned char []) ##keys) VARMACRO
#else
#define	keydef(sym,...) input.putseq(sym,sizeof((unsigned char [])__VA_ARGS__),(unsigned char []) __VA_ARGS__)  
#define	seqput(sym,...) keyinp->putseq(sym,sizeof((unsigned char [])__VA_ARGS__),(unsigned char []) __VA_ARGS__) 
#endif
void putkeys(class keyinput *keyinp) {
		seqput(RETURN,{13});
		seqput(RETURN,{10});
#ifdef NCURSES_VERSION
		seqput(DOWN,{27,91,66});
		seqput(UP,{27,91,65});
		seqput(END,{27,91,52,126});
		seqput(BEG,{27,91,49,126});
		seqput(PGUP,{27,91,53,126});
		seqput(PGDN,{27,91,54,126});
		seqput(NEXT,{27,91,67});
		seqput(PREV,{27,91,68});
		seqput(DELETE,{27,91,51,126});
		seqput(SHIFTAB,{27,91,90});
#endif

		seqput(QUIT,{27,254});
		seqput(QUIT,{27,120});
		seqput(REFRESH,{REFRESH});
		seqput(BACKSPACE,{BACKSPACE});

		seqput(CLEAR,  {21});
		seqput(TAB,{9});

		seqput(FILEPART,{27,102});
		seqput(DIR,{27,100});
		seqput(FIL,{27,110});
		memset(space,' ',240);
		space[239]='\0';
		}
keyinput input(putkeys);

	line::line(char *name,int xpos,int ypos,int s,int maxgegs):endptr(end) {
		buf=new char[maxgegs];
		size=s;
		bij=0;
		x=xpos;y=ypos;
		pos=end=strlen(name);
		memmove(buf,name,end);
		bufgegsize=maxgegs-1;
		};
	line::line(char *name,int &p, int xpos,int ypos,int s,int maxgegs):endptr(p) {
		end=p;
		buf=new char[maxgegs];
		bufgegsize=maxgegs-1;
		if(p>maxgegs)
			p=bufgegsize;
		size=s;
		bij=0;
		x=xpos;y=ypos;
		pos=end;
		memmove(buf,name,end);
		};
	char *line::setvalue(char *name,int len) {
		end=len;
		memmove(buf,name,end);
		bij=0;
		pos=end;
		return buf;
		}
	line::~line() {
		delete buf;
		};
	void line::show(void) {
		SELCOLOR ;
		wmove(takescr,y,x);
		for(int i=0;i<(size+2);i++)
			waddch(takescr,' ');
		wmove(takescr,y,x+1);
		for(char *i=buf+bij;i<(buf+bij+minnum(end-bij,size));i++)
			waddch(takescr,*i);
		
	//	waddnstr(takescr,buf+bij,minnum(end-bij,size));
		wmove(takescr,y,x+pos-bij+1);
		}
	void line::add(int key) {
		SELCOLOR ;
		cursor();
		pos++;
		waddch(takescr,key);
		}
	void line::take(void) {
		start=1;
		pos=0;
		show();
		KEYCOLOR;
		wmove(takescr,y,x+1);

		for(char *i=buf+bij;i<(buf+bij+minnum(end-bij,size));i++)
			waddch(takescr,*i);
//		waddnstr(takescr,buf+bij,minnum(end-bij,size));
		cursor();
		}
	char *line::change(int key) {
		switch(key) {
			case RETURN: buf[end]='\0';endptr=end;return buf;
			case NEXT: 
				if(start)
					show();
				if(pos<end) {
					pos++;
					if(pos>=(bij+size)) {
						bij++;
						show();
						}
					else
						cursor();
					}
				else
					beep();
				break;
			case PREV: 
				if(pos>0) {
					pos--; 
					if(pos<bij) {
						bij--;
						show();
						}
					else {
						if(start)
							show();
						else
							cursor();
						}

					}
				else {
					beep();
					if(start)
						show();
					}
				break;
			case BEG:  bij=0;pos=0; show();break;
			case END:  
				if((end-bij)>=size)
				   {
					bij=end-size+1;
					}
				pos=end; 
				show();
				break;
			case BACKSPACE: 
					if(pos>0) {
						end--;
						pos--;

						memmove(buf+pos,buf+pos+1,end-pos);
						if(pos<bij) {
							bij--;
							}
						show();
						}
					else {
						if(start)
							show();
						};
					break;
			case DELETE: 
				if(!start) {
					if(pos<end) {
							end--;
							memmove(buf+pos,buf+pos+1,end-pos);
							cursor();
							show();
							}
					break;
					}
			case CLEAR:
				memmove(buf,buf+pos,end-pos);
				end-=pos;
				pos=0;bij=0;
				show();
			default:
			if(start) {
				bij=pos=end=0;
				start=0;
				show();
				}
			if((key<0xff)&&isprint(key)) {
				if(end<bufgegsize) {
					if(pos<end) {
						memmove(buf+pos+1,buf+pos,end-pos);
						end++;
						buf[pos++]=key;
						if(pos>=(bij+size))
							bij++;
						show();
						}
					else {
						buf[pos]=key;
						pos++;
						if(pos>end)
							end=pos;
						if(pos>=(bij+size)) {
							bij++;
							show();
							}
						else {
							pos--;
							add(key);
							}
						}
					}
				return NULL;
				}
		}
		start=0;
		return NULL;
	}


#define perms(x,el) ((x&(1<<el))?(permsym[el]):'-')

                     #include <time.h>
//char timestr[]="%b %d %Y %X";
void filegeg(char *name,char *buf) {
	struct tm *tp;
	int j=0;
	struct stat st;
	char timestr[]=" %b %d %Y %H:%M",*ptr;
	if(stat(name,&st)<0) {
		buf[0]='\0';
		return;
		}
#ifndef WIN32
	snprintf(buf,MAXPATHLEN,"%d ",st.st_nlink);
	j=strlen(buf);
#endif
	if(S_ISDIR(st.st_mode))
		buf[j++]='d';
	else
		buf[j++]='-';
	char permsym[]="xwrxwrxwr";
#ifndef _WIN32
	int endperm=0;
#else
	int endperm=6;
#endif
	for(int i=8;i>=endperm;i--)
		buf[j++]=perms(st.st_mode,i);

#ifndef _WIN32
	char *user;
	struct passwd *pas;
	if((pas=getpwuid(st.st_uid)))
		user=pas->pw_name;
	else
		user="????";
#else
	buf[j++]=' ';
#endif

	tp=localtime(&st.st_mtime);

	ptr=buf+j;
	strftime(ptr,80,timestr,tp);
#ifndef _WIN32
	sprintf(strlen(ptr)+ptr," %s %ld",user,st.st_size);
#else
	sprintf(strlen(ptr)+ptr,"  %ld",st.st_size);
#endif
	}
#undef perms
/*
char * selectitem(char *prompt,char **files,int nr,int start) {
		int key;
		char *name;

		int xpos=1;
		int ypos=1;
		int l=minnum(11,thelines),c=(40,thecols);
		int begy=(thelines-l)/2;
		int begx=(thecols-c)/2;
		if(!takescr)
			takescr=newwin(l,c,maxnum(begy,0),maxnum(begx,0));
		else {
			int x,y;
			 getbegyx(takescr,y,x);
			if(((y!=begy)||(x!=begx))) {
				delwin(takescr);
				takescr=newwin(l,c,maxnum(begy,0),maxnum(begx,0));
				}
			}
		if(!takescr)
			return NULL;
		werase(takescr);
		trefresh(takescr);
		winsel fil(files,nr,xpos,ypos,maxnum((start-l+1),0),l-1,c-2);
		TITLECOLOR ;
		wmove(takescr,ypos-1,xpos-1);
		waddnstr(takescr,space,42);
		wmove(takescr,ypos-1,xpos);
		waddnstr(takescr,prompt,41);
		fil.sel=start-fil.beg;
		fil.show();
		while(1){
			key=ggetch(takescr);
			while((key=input.keyseq(key))==-1)
					key=ggetch(takescr);
			switch(key) {
				case	REFRESH: return (char *)1;
				case 	QUIT: return NULL;
				default: if((name=fil.select(key))) {
					return name;
					}
				};
			}
		}
		*/
WINDOW *rightwin(int l,int c,int by,int bx) {
		if(l>LINES) {
			l=LINES;
			by=0;
			}
		if(c>COLS)	 {
			c=COLS;
			bx=0;
			}
		if(!takescr)
			takescr=newwin(l,c,by,bx);
		else {
			int x,y;
			 getbegyx(takescr,y,x);
			if(((y!=by)||(x!=bx))||(getmaxyx(takescr,y,x), (y!=l)||(x!=c))) {
				delwin(takescr);
				takescr=newwin(l,c,by,bx);
				}
			else
				touchwin(takescr);
			}
		return takescr;
		}

WINDOW *getshowwin(int l,int c,int by,int bx) {
	WINDOW *awin=rightwin(l,c,by,bx);
	if(awin) {
//	werase(awin);
		attrall(awin,SHOWBACK); 
		}
	return awin;
	}

extern int lasthelp(void) ;
void helpwin(void) {
  WINDOW *tmpwin=takescr;
  takescr=NULL;
  lasthelp();
  if(takescr) delwin(takescr);
  takescr=tmpwin;
  touchwin(takescr);
 }
int  selectitemindex(char *prompt,char **files,int nr,int start,int &givehelp) {
		int key;
		int nameindex;

		int xpos=1;
		int ypos=1;
		int l=15,c=60;
		int begy=(thelines-l)/2;
		int begx=(thecols-c)/2;
		rightwin(l,c,maxnum(begy,0),maxnum(begx,0));

		if(!takescr)
			return LONG_MAX;
		givehelp=0;
//	werase(awin);
		werase(takescr);
		trefresh(takescr);
		winsel fil(files,nr,xpos,ypos,start,l-1,c-2);
		TITLECOLOR ;
		wmove(takescr,ypos-1,xpos-1);
		waddnstr(takescr,space,c+2);
		wmove(takescr,ypos-1,xpos);
		waddnstr(takescr,prompt,c+1);
//		fil.sel=start-fil.beg;
		fil.show();
		while(1){
			wrefresh(takescr);
			key=ggetch(takescr);
			if(!isprint(key)) {
				while((key=input.keyseq(key))==-1)
						key=ggetch(takescr);
				switch(key) {
					case -2: beep();continue;
					case HELP:
						  if(nr>0) {
							givehelp=1;
							 key=RETURN;
							 break;
						  	}
						  else {
							helpwin();
							continue;
						  }
					case 	QUIT: return LONG_MAX;
					case NOP:continue;
				  };
				}
			switch(key) {
				case	REFRESH: return (LONG_MAX-1);
				default: if((nameindex=fil.selectindex(key))>=0) {
					return nameindex;
					}
				};
			}
		}
int  selectitemindex(char *prompt,char **files,int nr,int start) {
	int givehelp;
	for(;;) {
	 start= selectitemindex(prompt,files, nr,start,givehelp) ;
	if(!givehelp)
		return start;
	helpwin();
	}

	}
//	qsort(files,len,sizeof(char *),strcmp);
void arraysorti(char **files,int len,int icase) {
	if(len<2)
		return;
	int half=len/2;
	char *pivot=files[half];
	int it1=0,it2=len-1,i;
	char **naar=myallocar(char *,len); 
	memmove(naar,files,len*sizeof(char *));
	for(i=0;i<half;i++){
		if((icase?strcmp(naar[i],pivot):strcasecmp(naar[i],pivot))<0) 
			files[it1++]=naar[i];
		else
			files[it2--]=naar[i];
		}
	for(i=half+1;i<len;i++){
		if((icase?strcmp(naar[i],pivot):strcasecmp(naar[i],pivot))<0) 
			files[it1++]=naar[i];
		else
			files[it2--]=naar[i];
		}
	 myfree(naar);
	arraysorti(files,it1,icase);
	arraysorti(files+it2+1,len-it1-1,icase);
	files[it1]=pivot;
	}
void arraysort(char **files,int len) {
 	arraysorti(files, len,1) ;
	}
/*
#define titlemaak(waar) \
	switch(waar) { \
		case 0:\
			wmove(takescr,ypos+1,xpos+1);\
			SELSELCOLOR ;\
			waddch(takescr,'F');\
			KEYCOLOR ;\
			waddstr(takescr,"iles: ");\
			break;\
		case 1:\
			wmove(takescr,ypos+1,xpos+25);\
			SELSELCOLOR ;\
			waddch(takescr,'D');\
			KEYCOLOR ;\
			waddstr(takescr,"irectories: ");\
			break;\
		case 2:\
		wmove(takescr,ypos+winh-2,xpos+1);\
			SELSELCOLOR ;\
			waddch(takescr,'N');\
			KEYCOLOR ;\
			waddstr(takescr,"ame: ");\
			break;\
		}

#define titleweg(waar) \
	switch(waar) { \
		case 0:\
			wmove(takescr,ypos+1,xpos+1);\
			KEYCOLOR ;\
			waddch(takescr,'F');\
			NORMALCOLOR ;\
			waddstr(takescr,"iles: ");\
			break;\
		case 1:\
			wmove(takescr,ypos+1,xpos+25);\
			KEYCOLOR ;\
			waddch(takescr,'D');\
			NORMALCOLOR ;\
			waddstr(takescr,"irectories: ");\
			break;\
		case 2:\
		wmove(takescr,ypos+winh-2,xpos+1);\
			KEYCOLOR ;\
			waddch(takescr,'N');\
			NORMALCOLOR ;\
			waddstr(takescr,"ame: ");\
			break;\
		}

		*/
#define titlemaak(waar) \
	switch(waar) { \
		case 0:\
			wmove(takescr,ypos+1,xpos+2);\
			SELSELCOLOR ;\
			waddstr(takescr,"iles");\
			break;\
		case 1:\
			wmove(takescr,ypos+1,xpos+26);\
			SELSELCOLOR ;\
			waddstr(takescr,"irectories");\
			break;\
		case 2:\
		wmove(takescr,ypos+winh-2,xpos+2);\
			SELSELCOLOR ;\
			waddstr(takescr,"ame");\
			break;\
		}
#define titleweg(waar) \
	switch(waar) { \
		case 0:\
			wmove(takescr,ypos+1,xpos+1);\
			KEYCOLOR ;\
			waddch(takescr,'F');\
			NORMALCOLOR ;\
			waddstr(takescr,"iles");\
			break;\
		case 1:\
			wmove(takescr,ypos+1,xpos+25);\
			KEYCOLOR ;\
			waddch(takescr,'D');\
			NORMALCOLOR ;\
			waddstr(takescr,"irectories");\
			break;\
		case 2:\
		wmove(takescr,ypos+winh-2,xpos+1);\
			KEYCOLOR ;\
			waddch(takescr,'N');\
			NORMALCOLOR ;\
			waddstr(takescr,"ame");\
			break;\
		}

void mkfilescreen(int ypos,int xpos,const char *com) {
	int len=strlen(com);
	input.putseq(FILEPART,2,((unsigned char []){27,102}));
	input.putseq(DIR,2,((unsigned char []){27,100}));
	input.putseq(FIL,2,((unsigned char []){27,110}));
//	trefresh(takescr);
	TITLECOLOR ;
	wmove(takescr,ypos+0,xpos+0);
	waddnstr(takescr,space,winb);
	wmove(takescr,ypos+0,xpos+(23-(len/2)));
	waddstr(takescr,(char *)com);

	wmove(takescr,ypos+1,xpos+1);
	KEYCOLOR ;
	waddch(takescr,'F');
	NORMALCOLOR ;
	waddstr(takescr,"iles: ");
	wmove(takescr,ypos+1,xpos+25);
	KEYCOLOR ;
	waddch(takescr,'D');
	NORMALCOLOR ;
	waddstr(takescr,"irectories: ");

	wmove(takescr,ypos+winh-2,xpos+1);
	KEYCOLOR ;
	waddch(takescr,'N');
	NORMALCOLOR ;
	waddstr(takescr,"ame: ");
	}


static inline int	mygetcwd(char *name,int len) {
#ifdef __CYGWIN__
	GetCurrentDirectory(len,name);
#else
	getcwd(name,len);
#endif
	}

const char *mvtakefile(int ypos,int xpos,const char *com,const char *pat) {
	char *showstr;
	int end,eerste=1;
	char *fil;
	char filebuf[PATH_MAX];
	char **files,*lekt;
	int waar=2,len;
	
	mkfilescreen(ypos, xpos,com);
	line lin("",xpos+7,ypos+winh-2,35);

	const char *path=pat;
 back: {
	lekt=0;
	showstr="";
	expandfilename(filebuf,path);
	path=filebuf;
	if(chdir(path)<0) {
		if((fil=rindex(path,FILENAMESEP))) {
			*fil++='\0';
			int plen=strlen(fil);
			char *tmpstr=fil;
			fil=(char *)alloca(plen+1);
			memcpy(fil,tmpstr,plen+1);
			}
		else
			fil="*";
		nasplit:
		chdir(path);
		}
	else
		fil="*";
	TITLECOLOR ;
	wmove(takescr,ypos+winh-1,xpos);
	waddnstr(takescr,space,winb);
	wmove(takescr,ypos+winh-1,xpos+1);
	mygetcwd(filebuf,MAXPATHLEN);
	waddnstr(takescr,filebuf,winb-1);
	len=getfiles(fil,&files,&end);
	if(!eerste&&!len) {
		static char *s=NULL;
		int l=strlen(fil)+1;
		if(s)
			myfree( s);
		s=myallocar( char,l);

		strcpyn(s,fil,l);
		return s;
		};
#ifdef _WIN32
	arraysorti(files,end,0);
	arraysorti(&files[end],len-end,0);
#else
	arraysort(files,end);
	arraysort(&files[end],len-end);
#endif
	winsel sel(files,end,xpos+2,ypos+2);
	winsel dir(&files[end],len-end,xpos+26,ypos+2);
	winsel *vorig;
#ifdef _WIN32
	sel.icase=0;
	dir.icase=0;
#endif
	lin.setvalue(fil,strlen(fil));
	sel.show();
	dir.show();
	terug:
	lin.show();
	eerste=0;
	switch(waar) {
		case 0:
			dir.leave();
			vorig=&sel;
			sel.showsel(0);
			break;
		case 1:
			sel.leave();
			vorig=&dir;
			dir.showsel(0);
			break;
		case 2:
		default: 
			sel.leave();
			dir.leave();
			vorig=&sel;
			lin.take();
		};
	titlemaak(waar);
//	trefresh(takescr);
	while(1) {
		showstr=vorig->current();
		NORMALCOLOR;
		wmove(takescr,ypos+winh-3,xpos+1);
		waddnstr(takescr,space,winb-2);
		wmove(takescr,ypos+winh-3,xpos+1);
		if(showstr)
			filegeg(showstr,filebuf);
		waddnstr(takescr,filebuf,winb-2);
		lin.cursor();
		int key;
	keyagain:
		wrefresh(takescr);
		key=ggetch(takescr);
	DEBUGGING("Start: %d=ggetch()\n",key)
		if(!(isprint(key)) ) {
			while((key=input.keyseq(key))==-1) {
				key=ggetch(takescr);
				DEBUGGING("%d=ggetch()\n",key)
				}
			switch(key) {
				case HELP:helpwin();goto keyagain;
				case NOP:goto keyagain;
				case -2: beep(); goto keyagain;
				case QUIT: return NULL;
				case FILEPART:
					if(vorig!=&sel) {
						vorig->leave();
						vorig=&sel;
						}
					sel.showsel(0);
					titleweg(waar);
					waar=0;
					titlemaak(waar);
					continue;
				case DIR:
					if(vorig!=&dir) {
						vorig->leave();
						vorig=&dir;
						}
					titleweg(waar);
					dir.showsel(0);
					waar=1;
					titlemaak(waar);
					continue;


				case FIL: 

					titleweg(waar);
					vorig->leave();
					waar=2;lin.take();
					titlemaak(waar);
					continue;
				case SHIFTAB: titleweg(waar);waar--; if(waar<0) waar=2; goto terug;
				};
			}
	switch(key) {
		case REFRESH: return pat;
		case TAB: titleweg(waar);waar++;
			if(waar>2) 
				waar=0;
			goto terug;
			break;
		default: {
			lekt=NULL;
			switch(waar) {
				case 0: lekt=sel.select(key); 
					if(lekt)  {
						return lekt;
						}
					break;
				case 1: lekt=dir.select(key); 
					if(lekt)  {
							path=lekt;
							fil="*";
							goto nasplit;
							};
					break;
				case 2: lekt=lin.change(key); 
					if(lekt) {
						titleweg(waar);
						     waar=0;
						     /*
						     	if(lekt[0]=='~') {
								memmove(lekt+1,lekt,strlen(lekt)+1);
								lekt[0]='\\';
								}
								*/
							path=lekt;
							goto back;
							};
					break;
				};
			};
		};
	}
	}	
	}

void resetinput(void) {
				nocbreak();
				noecho();
				cbreak();
				nonl();
	}
const char *takefile(const char *com,const char *pat) {
	int l=winh,c=winb;
	int begy=(thelines-l)/2;
	int begx=(thecols-c)/2;
	rightwin(l,c,maxnum(begy,0),maxnum(begx,0));
	if(takescr) {
		attrall(takescr,BACKATTR);
		const char  *ret;
	SHOWCURSOR;
		ret=mvtakefile(0,0,com,pat);
		cursoraway();
		return ret;
		}
	return NULL;
	}




	item::item(const char *txt1,int ya,int xb) {
		strcpyn(text,txt1,80);
		if((after=index(text,'~'))) {
			*after++='\0';
			ch=*after++;
			}
		else {
			after="";
			ch=' ';
			}
		lowch=tolower(ch);
		x=xb;
		y=ya;
		};
/*
#define	SELCOLOR wattrset(takescr,SELATTR)
#define	KEYCOLOR wattrset(takescr,KEYATTR)
#define	SELSELCOLOR wattrset(takescr,SELATTR|A_REVERSE|A_BOLD)
#define	TITLECOLOR wattrset(takescr,TITLEATTR)
#define	BACK wattrset(takescr,BACKATTR)
#define	NORMALCOLOR BACK
#define	UNSELCOLOR  TITLECOLOR
*/
	void check::show(void) {
//		wattrset(optionscreen,CHECKCOLOR);
		SELCOLOR;
		wmove(optionscreen,y,x);
		waddch(optionscreen,'[');
		waddch(optionscreen,(var?'x':' '));
		waddch(optionscreen,']');
		waddch(optionscreen,' ');
		waddstr(optionscreen,text);
		KEYCOLOR;
//		wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
		SELCOLOR;
//		wattrset(optionscreen,CHECKCOLOR);
		waddstr(optionscreen,after);
		};
	void check::select(void) {
		SELSELCOLOR;
//		wattrset(optionscreen,SELCHECKCOLOR);
		wmove(optionscreen,y,x);
		waddch(optionscreen,'[');
		waddch(optionscreen,(var?'x':' '));
		waddch(optionscreen,']');
		waddch(optionscreen,' ');
		waddstr(optionscreen,text);
		KEYCOLOR;
//		wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
		SELSELCOLOR;
//		wattrset(optionscreen,SELCHECKCOLOR);
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x+1);
		};

	 int check::switchvar(void) {
		var=!var;
		SELSELCOLOR;
//		wattrset(optionscreen,SELCHECKCOLOR);
		wmove(optionscreen,y,x);
		waddch(optionscreen,'[');
		waddch(optionscreen,(var?'x':' '));
		waddch(optionscreen,']');
		wmove(optionscreen,y,x+1);
		return 0;
		};

	int Common::save(void) {
		old=last->val;
		return 0;
		}
	 void orcheck::sel(void) {
		wmove(optionscreen,y,x);
		waddch(optionscreen,'(');
		waddch(optionscreen,(com->last==this?'*':' '));
		waddch(optionscreen,')');
		}
	void orcheck::show(void) {
		SELCOLOR;
		sel();
		waddch(optionscreen,' ');
		waddstr(optionscreen,text);
		KEYCOLOR;
//		wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
		SELCOLOR;
//		wattrset(optionscreen,CHECKCOLOR);
		waddstr(optionscreen,after);
		};
	void orcheck::select(void) {
//		SELCOLOR;
		sel();
		waddch(optionscreen,' ');
		SELSELCOLOR;
		waddstr(optionscreen,text);
		KEYCOLOR;
//		wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
		SELSELCOLOR;
//		wattrset(optionscreen,SELCHECKCOLOR);
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x+1);
		};
	void orcheck::showvar(void) {
//		wattrset(optionscreen,CHECKCOLOR);
		SELCOLOR;
		sel();
		wmove(optionscreen,y,x+1);
		}
	void orcheck::selectvar(void) {
		SELSELCOLOR;
//		wattrset(optionscreen,SELCHECKCOLOR);
		sel();
		wmove(optionscreen,y,x+1);
		}

	 int orcheck::switchvar(void) {
	 	orcheck *was=com->last;
	 	if(was!=this) {
			com->last=this;
			was->showvar();
			selectvar();
			return 1;
			}
		return 0;
		};


	void action::show(void) {
		SELCOLOR;
	//	wattrset(optionscreen,CHECKCOLOR);
		wmove(optionscreen,y,x);
		waddstr(optionscreen,text);
		KEYCOLOR;
	//	wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
		SELCOLOR;
	//wattrset(optionscreen,CHECKCOLOR);
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x);
		};
	void action::select(void) {
		SELSELCOLOR;
	//	wattrset(optionscreen,SELCHECKCOLOR);
		wmove(optionscreen,y,x);
		waddstr(optionscreen,text);
		KEYCOLOR;
	//	wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
//		wattrset(optionscreen,SELCHECKCOLOR);
		SELSELCOLOR;
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x);
		};

	int ok::saveall(void) {
		var=1;
		return 2;
		}


	void lineitem::show(void) {
		SELCOLOR;
	//	wattrset(optionscreen,CHECKCOLOR);
		wmove(optionscreen,y,x);
		waddstr(optionscreen,text);
		KEYCOLOR;
	//	wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
		SELCOLOR;
	//wattrset(optionscreen,CHECKCOLOR);
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x);
		l.show();
		}
	void lineitem::select(void) { 
		SELSELCOLOR;
	//	wattrset(optionscreen,SELCHECKCOLOR);
		wmove(optionscreen,y,x);
		waddstr(optionscreen,text);
		KEYCOLOR;
	//	wattrset(optionscreen,KEYCHECKCOLOR);
		waddch(optionscreen,ch);
//		wattrset(optionscreen,SELCHECKCOLOR);
		SELSELCOLOR;
		waddstr(optionscreen,after);
		wmove(optionscreen,y,x);
		l.take();
		}

	int lineitem::saveall(void) {
		return 2;
		}

void label(int y,int x,const char *str) {
		SELCOLOR;
		wmove(takescr,y,x);
		waddstr(takescr,(char *)str);
		};

int show(item **al,int maxar,int old) {
	int i,news=(old<maxar?old:0),ch,res;

//	wattrset(takescr,SHOWBACK);
#ifdef LINEMENUS
	box(takescr,0,0);
#endif

startover:	
	unsigned char k[2];
	k[0]=27;
	for(i=0;i<maxar;i++) {
		al[i]->show();
		k[1]=al[i]->thekey();
		input.putseq(i|0xfff000,2,k);
		}
	k[1]=al[old]->thekey();
	input.putseq(old|0xfff000,2,k);
	al[old]->select();

	SHOWCURSOR;
	wrefresh(takescr);
	while(1){
	//	keyagain:
		ch=ggetch(takescr);
		if(!(isprint(ch)) ) {
			while((ch=input.keyseq(ch))==-1)
				ch=ggetch(takescr);
			 switch(ch) {
				 case HELP:helpwin();goto startover;
				case NOP: goto foundone;
				case -2: beep(); goto foundone;
				case QUIT : cursoraway(); return 0;
				case SHIFTAB: news--;if(news<0) news=maxar-1; goto foundone;
				case TAB:	news++;if(news>=maxar) news=0; ;
goto foundone;
				case RETURN: if((res=al[old]->saveall())) {
						if(res==2) {
							for( i=0;i<maxar;i++) {
								al[i]->save();
	//							delete al[i];
								}

							cursoraway();
							return old+1;
							}
						cursoraway();
						return old+1;
						}
					goto foundone;
				case REFRESH: 
					cursoraway();
					return LONG_MAX;
					  };
			  }
			if((0xfff000&ch)==0xfff000) {
				int key=ch&0xfff;
				if(key>=0&&key<maxar)
					news=key;
				else
					al[old]->change(ch);
				}
			else
				al[old]->change(ch);

foundone:
		if(old!=news) {
			al[old]->show();
			al[news]->select();
			old=news;
			}
		wrefresh(takescr);
		}
	}


#ifdef TEST5
void main(void) {
	int i,reg=0,cas=1,maxar=4;
	char get[256]="*";

	initscreen() ;

	int wlin=50,wcol=80;
	char *str[4];
	str[0]="een";
	str[1]="twee";
	str[2]="drie";
	char ant[80];
	while(1) {
		lcconfig(wlin,wcol,
			oke(2,5),
			act("C~ancel", 2,15),
			list("~File",4,5,str,3,ant));
		
		move(0,0);
		addstr(ant);
		refresh();
		}
	getch();
	endwin();
	}

#endif
#ifdef TEST2
void main(void) {
	int i,reg=0,cas=1,maxar=4;
	char get[256]="*";

	initscreen() ;

	int wlin=50,wcol=80;
	while(1) {

		Common combase(reg),*com=&combase;
		plcsconfig(wlin,wcol,2,com->last=(orcheck*)showformsarray[reg], ore("~Een",2,3,0,com),ore("~Twee",3,3,1,com), 
		ore("~Drie",4,3,2,com), 
		ore("~Vier",5,3,3,com), 
			liner("~Name",get,7,3),
			oke(12,5),
			act("C~ancel", 12,15)); 

		printw("reg=%d, cas=%d get=%s\n",reg,cas,get);
		refresh();
		}
	getch();
	endwin();
	}
#endif

#ifdef TEST
void main(int argc,char **argv) {
	int f,b;
	const char *file,*prompt,*orig;
	if(argc<3) {
		file="*";
		if(argc<2)
			prompt="Select file";
		else
			prompt=argv[1];
		}
	else  {
		 file=argv[2];
		 prompt=argv[1];
		 }
	orig=file;
	do {
		initscreen();
		file=takefile(prompt,file);
		endwin();
		} while(file==orig);
	if(file)
		write(3,file,strlen(file));
	}
#endif
#ifdef TEST3

const char *getfile(const char *prompt,const char *ask) {
	const char *file=ask;
			while(1) {
				if(!(file=takefile(prompt,ask))) {
					return NULL;
					}
				if(file!=ask)  {
					return file;
					}
				erase();
				}
			}
#include "offtypes.h"
int main(int argc,char **argv) {
	const char *file,*prompt;
	STATTYPE st;
	if(argc<3) {
		file="*";
		if(argc<2)
			prompt="Select file";
		else
			prompt=argv[1];
		}
	else  {
		 file=argv[2];
		 prompt=argv[1];
		 }
	char buf[MAXPATHLEN]="*";

	initscreen();
	strcpyn(buf,file,MAXPATHLEN);
		while(1) {
			if((file=getfile("Open file",buf))) {
				if(STAT(file,&st)==-1|| !(S_ISREG(st.st_mode))) {
					printw("Can not edit %s",file);
					wrefresh(stdscr);
					strcpyn(buf,file,MAXPATHLEN);
					continue;
					}
				else {
					if(file)
						write(3,file,strlen(file));
					endwin();
					return 0;
					}
				}
			else {
					endwin();
				return -1;
				}
			}
	endwin();
	return 0;
	}
#endif

