/*
 * This file is part of the FEddi package
 *
 * Personal use allowed under the terms of the
 *
 *              GNU GENERAL PUBLIC LICENSE Version 2
 *              (see LICENSE for the complete text)
 *
 *-------------------------------------------------------------------
 *
 *    ENTER AT YOUR OWN RISK !!
 *
 * This source is without any documentation and can drive you mad.
 * In case of sudden epileptic seizures please call your doctor.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "structs.h"
#include "functs.h"
#include "proc.h"
#include "charset.h"
#include "mbhelp.h"
#include "colors.h"
#include "template.h"
#include "mbutil.h"
#include "inout.h"

#define BEEP {Beep(); wrefresh(wTxt);}

#define actLine  (*edtext)[firstLine+csl].line
#define actCR    (*edtext)[firstLine+csl].CR
#define actQuote (*edtext)[firstLine+csl].Quote
#define actCutOrigin (*edtext)[firstLine+csl].CutOrigin

extern int col;
extern sig_atomic_t show_time_now;
extern sigset_t allmask;

extern void redrawScreen();
extern void showtime();

void texthelp(WINDOW *);
void showtexted(WINDOW *, WINDOW *, LineListType *, int, int, int);
int insertchr(int, int, char);
int deletechr(int, int);
void writestr(char *line, int pos);
void insertline(int pos);
void deleteline(int pos);
int killlastspaces(char *line);
int breakline(char *, char *);
void floattext();
void floatpar(int *fl, int *x, int *y);
void inputfile(WINDOW *, int);
int piperegion(WINDOW *, int);
int realyQuit(WINDOW *);
void curmove(WINDOW *, WINDOW *, int, int, int);
void initsmilies(LineListType **, int *, LineListType **);

LineListType **edtext, *buffer;
LineListType *Smilies=NULL, *ShortKeys=NULL;
int Cols, Lines, XStart, YStart, txLines, bufLines, numSmilies=0;
int MarkLine=-1, MarkCol=-1, AppendMark=1;

int textedit(WINDOW *wTxt, WINDOW *wHlp, LineListType **text, int *maxLines,
		int x, int y)
{
	int ende=0, in, firstLine=0, csl, csc, i, j, k;
	char *d1, *d2, *d3;
	if (!wTxt) return 1;
	if (ShortKeys==NULL)
		initsmilies(&Smilies,&numSmilies,&ShortKeys);
	getmaxyx(wTxt,Lines,Cols);
	getbegyx(wTxt,YStart,XStart);
	csc=x;
	csl=y;
	if (csl>Lines)
	{
		firstLine=csl-Lines/2;
		csl=Lines/2;
	}	
	d1=(char *)malloc(Cols*2);
	d2=(char *)malloc(Cols*2);
	bufLines=0;
	buffer=NULL;
	edtext=text;
	txLines=*maxLines;
	if (!(*edtext))
	{
		(*edtext)=(LineListType *)malloc(LineListSize);
		(*edtext)[0].line=(char *)malloc(1);
		(*edtext)[0].line[0]=0;
		(*edtext)[0].Quote=0;
		(*edtext)[0].CutOrigin=0;
		(*edtext)[0].CR=1;
		txLines=1;
	}
	curs_set(CURSOR_ON);
	if (wHlp)
		texthelp(wHlp);
	floattext();
	showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
	while (!ende)
	{
		sigprocmask(SIG_UNBLOCK,&allmask,NULL);
		if (show_time_now) showtime();
		in=getchn();
		if (show_time_now) showtime();
		sigprocmask(SIG_BLOCK,&allmask,NULL);
		switch (in)
		{
			case 0x1b:
				switch ((in=getchn()))
				{
					case '0' ... '9':
						if (ShortKeys[in-'0'].line)
						{
							for (d3=ShortKeys[in-'0'].line; *d3; d3++)
								csc=insertchr(firstLine+csl,csc,*d3);
							floatpar(&firstLine,&csc,&csl);
							showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
							break;
						} else
							BEEP
						break;
					case 's':
						if (numSmilies)
						{
							if ((k=scrollchoice(Smilies,numSmilies,
									"Choose Macro to insert",NULL))>-1)
							{
								for (d3=Smilies[k].line+61; *d3; d3++)
									csc=insertchr(firstLine+csl,csc,*d3);
								floatpar(&firstLine,&csc,&csl);
								showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
							}
							touchwin(wTxt);
							wrefresh(wTxt);
						} else
							BEEP
						break;
					case 'b':
						if (bufLines)
						{
							scrolltext(buffer,bufLines,"Buffer",0);
							touchwin(wTxt);
							wrefresh(wTxt);
						} else
							BEEP
						break;
					case 'c':
						ConvertChars=!ConvertChars;
						curmove(wTxt,wHlp,firstLine,csl,csc);
						break;
					case 'h':
						showEditorHelp();
						showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
						break;
					case 'i':
						inputfile(wHlp,firstLine+csl);
						showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
						break;
					case 'x': ende=2; break;
					case 0x1b: ende=realyQuit(wTxt); break;
					case 0x5b:
						switch ((in=getchn()))
						{
							case 0x41: /*up*/
								if (firstLine+csl)
								{
									if (csl==0)
										firstLine--;
									else
										csl--;
									showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								} else
									BEEP
								break;
							case 0x42: /*down*/
								if (firstLine+csl<txLines-1)
								{
									if (csl==Lines-1)
										firstLine++;
									else
										csl++;
									showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								} else
									BEEP
								break;
							case 0x43: /*right*/
								if (csc>=Cols-1)
								{
									if (firstLine+csl==txLines-1)
									{
										BEEP
										break;
									}
									csc=0;
									if (csl<Lines-1)
										csl++;
									else
									{
										firstLine++;
										showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
									}
								} else
									csc++;
								curmove(wTxt,wHlp,firstLine,csl,csc);
								break;
							case 0x44: /*left*/
								if (csc==0)
								{
									if (firstLine+csl==0)
									{
										BEEP
										break;
									}
									if (csl)
										csl--;
									else
									{
										firstLine--;
										showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
									}
									csc=strlen(actLine);
								} else
									csc--;
								curmove(wTxt,wHlp,firstLine,csl,csc);
								break;
							case 0x35: /*pgup*/
								getch();
								if (firstLine+csl)
								{
									csl-=Lines/2;
									if (csl<0)
									{
										firstLine+=csl;
										csl=0;
										if (firstLine<0)
											firstLine=0;
									}
									showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								} else
									BEEP
								break;
							case 0x36: /*pgdown*/
								getch();
								if (firstLine+csl<txLines-1)
								{
									csl+=Lines/2;
									if (firstLine+csl>=txLines)
										csl=txLines-firstLine-1;
									if (csl>=Lines)
									{
										firstLine+=(csl-Lines+1);
										csl=Lines-1;
										if (firstLine+csl>=txLines-1)
											firstLine=txLines-Lines;
									}
									showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								} else
									BEEP
								break;
							case 0x31: /*pos1*/
								getch();
								if (csc)
								{
									csc=0;
									curmove(wTxt,wHlp,firstLine,csl,csc);
								} else
								{
									firstLine=csl=0;
									showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								}
								break;
							case 0x34: /*ende*/
								getch();
								if (csc==strlen(actLine))
								{
									firstLine=0;
									if (txLines>=Lines)
									{
										firstLine=txLines-Lines;
										csl=Lines-1;
									} else
										csl=txLines-1;
								}
								csc=strlen(actLine);
								showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								break;
							case 0x32: /*einfg*/
								getch();
								csc=insertchr(firstLine+csl,csc,32);
								floatpar(&firstLine,&csc,&csl);
								showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								break;
							case 0x33: /*entf*/
								getch();
								redel:
								if (csc<strlen(actLine))
									csc=deletechr(firstLine+csl,csc);
								else
								{
									if (actCR)
									{
										if (firstLine+csl==txLines-1)
										{
											BEEP
											break;
										}
										strcpy(d1,actLine);
										killlastspaces(d1);
										strcat(d1,(*edtext)[firstLine+csl+1].line);
										killlastspaces(d1);
										if (strlen(d1)==1 && *d1==32) *d1=0;
										writestr(d1,firstLine+csl);
										actCR=(*edtext)[firstLine+csl+1].CR;
										deleteline(firstLine+csl+1);
									} else
									{
										if (firstLine+csl==txLines-1)
										{
											BEEP
											break;
										}
										csc=0;
										if (csl<Lines-1)
											csl++;
										else
											firstLine++;
										goto redel;
									}
								}
								floatpar(&firstLine,&csc,&csl);
								showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								break;
						}
						break;
				}
				break;
			case 9:
				i=csc>strlen(actLine)?strlen(actLine):csc;
				do
				{
					csc=insertchr(firstLine+csl,csc,32);
					i++;
				}
				while (i%8);
				floatpar(&firstLine,&csc,&csl);
				showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				break;
			case 127: /* backspace */
				if (csc)
				{
					if (csc>strlen(actLine))
					{
						csc=strlen(actLine);
						curmove(wTxt,wHlp,firstLine,csl,csc);
					} else
					{
						csc--;
						csc=deletechr(firstLine+csl,csc);
						floatpar(&firstLine,&csc,&csl);
						showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
					}
				} else
					if (firstLine+csl)
					{
						strcpy(d1,(*edtext)[firstLine+csl-1].line);
						killlastspaces(d1);
						csc=strlen(d1);
						strcat(d1,actLine);
						killlastspaces(d1);
						writestr(d1,firstLine+csl);
						deleteline(firstLine+csl-1);
						csl--;
						floatpar(&firstLine,&csc,&csl);
						showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
					}
				break;
			case 1:  /* set mark */
				if (MarkLine==firstLine+csl)
					MarkLine=-1;
				else
					MarkLine=firstLine+csl;
				showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				break;
			case 11: /* C-k kill region */
				csc=0;
				if (MarkLine!=-1)
				{
					for (i=0; i<bufLines; i++)
						free(buffer[i].line);
					free(buffer);
					bufLines=abs(MarkLine-firstLine-csl)+1;
					buffer=(LineListType *)malloc(LineListSize*bufLines);
					j=MarkLine<firstLine+csl?MarkLine:firstLine+csl;
					for (i=0; i<bufLines;i++)
					{
						buffer[i].line=(char *)malloc(strlen((*edtext)[j+i].line)+1);
						strcpy(buffer[i].line,(*edtext)[j+i].line);
						buffer[i].CR=(*edtext)[j+i].CR;
						buffer[i].Quote=(*edtext)[j+i].Quote;
						buffer[i].CutOrigin=(*edtext)[j+1].CutOrigin;
					}
					for (i=0; i<bufLines; i++)
						if (txLines>1)
							deleteline(j);
						else
							writestr("",0);
					if (MarkLine<firstLine+csl)
					{
						csl-=(bufLines-1);
						if (csl<0)
						{
							firstLine+=csl;
							csl=0;
							if (firstLine<0)
								firstLine=0;
						}
					}
					MarkLine=-1;
					AppendMark=0;
				} else
				{
					if (bufLines)
					{
						for (i=0; i<bufLines; i++)
							free(buffer[i].line);
						free(buffer);
						buffer=NULL;
						bufLines=0;
					} else
						BEEP
				}
				showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				break;
			case 12: /* C-l kill to eol */
				if (csc>=strlen(actLine))
				{
					csc=strlen(actLine);
					strcpy(d1,actLine);
					d1[csc]=0;
					strcat(d1,(*edtext)[firstLine+csl+1].line);
					actCR=(*edtext)[firstLine+csl+1].CR;
					writestr(d1,firstLine+csl);
					deleteline(firstLine+csl+1);
				} else
					actLine[csc]=0;
				floatpar(&firstLine,&csc,&csl);
				showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				break;
			case 25: /* C-y kill line */
				csc=0;
				if (firstLine+csl!=txLines-1 ||
						(firstLine+csl==txLines-1 && strlen(actLine)))
				{
					if (!AppendMark)
					{
						for (i=0; i<bufLines; i++)
							free(buffer[i].line);
						free(buffer);
						buffer=NULL;
						bufLines=1;
						AppendMark=1;
					} else
						bufLines++;
					buffer=(LineListType *)realloc(buffer,LineListSize*bufLines);
					buffer[bufLines-1].line=(char *)malloc(strlen(actLine)+1);
					strcpy(buffer[bufLines-1].line,actLine);
					buffer[bufLines-1].Quote=actQuote;
					buffer[bufLines-1].CutOrigin=actCutOrigin;
					buffer[bufLines-1].CR=actCR;
					if (firstLine+csl!=txLines-1)
						deleteline(firstLine+csl);
					else
						writestr("",firstLine+csl);
				}
				showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				break;
			case 21: /* C-u yank out buffer */
				if (bufLines)
				{
					MarkLine=-1;
					for (i=bufLines-1; i>=0; i--)
					{
						insertline(firstLine+csl);
						writestr(buffer[i].line,firstLine+csl);
						actCR=buffer[i].CR;
					}
					AppendMark=0;
					showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				} else
				{
					BEEP
					break;
				}
				break;
			case 16: /* pipe region */
				if (!piperegion(wHlp,firstLine+csl)) BEEP
				showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				break;
			case 10: /* newline */
				insertline(firstLine+csl+1);
       	(*edtext)[firstLine+csl+1].CR=actCR;
       	for (; csc>strlen(actLine); csc--);
        if (csc<strlen(actLine))
        {
        	strncpy(d1,actLine,csc);
        	d1[csc]=0;
        	strcpy(d2,actLine+csc);
        	killlastspaces(d1);
        	killlastspaces(d2);
        	writestr(d1,firstLine+csl);
        	if ((d3=GetQuote(d1)))
        	{
        		if (*d3)
        		{
	        		strcpy(d1,d3);
  	      		if (*d2!=32) strcat(d1," ");
  	      	} else
  	      		strcpy(d1,"");
    	   		strcat(d1,d2);
	        	writestr(d1,firstLine+csl+1);
	        	free(d3);
	        } else
	        	writestr(d2,firstLine+csl+1);
        	i=0;
        } else
        {
   	    	i=0;
   	    	d2[0]=0;
        	writestr(d2,firstLine+csl+1);
        }
				actCR=1;
				floatpar(&firstLine,&csc,&csl);
				if (csl<Lines-1)
					csl++;
				else
					firstLine++;
				floatpar(&firstLine,&csc,&csl);
				csc=i;
				showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
				break;
			case 2:
				if (csc>strlen(actLine)) csc=strlen(actLine)+1;
				for (i=csc-1; i>=0; i--)
					if (isalpha(actLine[i])) break;
				for (; i>=0; i--)
					if (!isalpha(actLine[i])) break;
				if (i<0)
				{
					if (firstLine+csl)
					{
						if (csl==0)
						{
							firstLine--;
							csc=strlen(actLine);
							showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
						} else
						{
							csl--;
							csc=strlen(actLine);
							curmove(wTxt,wHlp,firstLine,csl,csc);
						}
					} else
					{
						csc=0;
						curmove(wTxt,wHlp,firstLine,csl,csc);
						BEEP
					}
				} else
				{
					csc=i;
					if (csc || !isalpha(actLine[csc])) csc++;
					curmove(wTxt,wHlp,firstLine,csl,csc);
				}
				break;
			case 6:
				for (i=csc+1; i<=strlen(actLine); i++)
					if (isalpha(actLine[i])) break;
				for (; i<=strlen(actLine); i++)
					if (!isalpha(actLine[i])) break;
				if (i>strlen(actLine))
				{
					if (firstLine+csl<txLines-1)
					{
						if (csl==Lines-1)
						{
							firstLine++;
							csc=0;
							showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
						} else
						{
							csl++;
							csc=0;
							curmove(wTxt,wHlp,firstLine,csl,csc);
						}
					} else
					{
						csc=strlen(actLine);
						curmove(wTxt,wHlp,firstLine,csl,csc);
						BEEP
					}
				} else
				{
					csc=i;
					curmove(wTxt,wHlp,firstLine,csl,csc);
				}
				break;
			case 4:
				redrawScreen();
				curs_set(CURSOR_ON);
				break;
			default:
				if (PRINTABLECHAR[in])
				{
					if (ConvertChars && PRINTABLECHAR[in]==2)
					{
						for (i=0; i<maxCONVERTCHAR; i++)
							if (CONVERTCHAR[i].code==in)
							{
								for (d3=(char *)CONVERTCHAR[i].conversion; *d3; d3++)
									csc=insertchr(firstLine+csl,csc,*d3);
								floatpar(&firstLine,&csc,&csl);
								showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
								break;
							}
					} else
					{
						csc=insertchr(firstLine+csl,csc,in);
						floatpar(&firstLine,&csc,&csl);
						showtexted(wTxt,wHlp,(*edtext),firstLine,csl,csc);
					}
					break;
				}
		}
	}
	curs_set(CURSOR_OFF);
	refresh();
	free(d1);
	free(d2);
	for (i=0; i<bufLines; i++)
		free(buffer[i].line);
	free(buffer);
	*maxLines=txLines;
	if (ende==1)
		return 1;
	return 0;
}

void texthelp(WINDOW *win)
{
	wkill(win,COL_StatusLine);
	mvwaddstr(win,0,1,bhelp_textedit);
	wrefresh(win);
}

void showtexted(WINDOW *win, WINDOW *wh, LineListType *t, int l, int yy, int xx)
{
	int i, mark=0, toggle=0;
	wkill(win,COL_NormalText);
	if (l>MarkLine && MarkLine!=-1) mark=1;
	for (i=0; i<Lines && i+l<txLines; i++)
	{
		if ((i==yy || i+l==MarkLine) && MarkLine!=-1) mark=1-(toggle=mark);
		if ((*edtext)[l+i].Quote>1)
			wcolon(win,mark||toggle?COL_QuoteTextHigh:COL_QuoteText);
		else
			if ((*edtext)[l+i].Quote==1)
				wcolon(win,mark||toggle?COL_FirstQuoteTextHigh:COL_FirstQuoteText);
			else
				if ((*edtext)[l+i].CutOrigin)
					wcolon(win,mark||toggle?COL_CutOriginTextHigh:COL_CutOriginText);
				else
					wcolon(win,mark||toggle?COL_NormalTextHigh:COL_NormalText);
		mvwaddstru(win,i,0,(*edtext)[l+i].line);
		if ((*edtext)[l+i].CR)
			waddch(win,HARDCRCHAR);
		if (i==yy && i+l==MarkLine && MarkLine!=-1) mark=1-mark;
		toggle=0;
	}
	touchwin(win);
	curmove(win,wh,l,yy,xx);
}

int insertchr(int line, int p, char c)
{
	int len=strlen((*edtext)[line].line);
	(*edtext)[line].line=(char *)realloc((*edtext)[line].line,len+2);
	if (p>=len)
		p=len;
	if (strlen((*edtext)[line].line)>p)
		memmove(&((*edtext)[line].line[p+1]),\
				&((*edtext)[line].line[p]),len-p+1);
	else
		(*edtext)[line].line[p+1]=0;
	(*edtext)[line].line[p]=c;

	(*edtext)[line].Quote=IsQuote((*edtext)[line].line);
	
	if (strncmp((*edtext)[line].line,"--- ",4)==0 ||
			strcmp((*edtext)[line].line,"---")==0)
		(*edtext)[line].CutOrigin=1;
	else
	{
		if (strncmp((*edtext)[line].line," * Origin:",10)==0)
			(*edtext)[line].CutOrigin=2;
		else
			(*edtext)[line].CutOrigin=0;
	}

	return p+1;
}

int deletechr(int line, int p)
{
	int len=strlen((*edtext)[line].line);
	if (p>len)
		return len;
	memmove(&((*edtext)[line].line[p]),&((*edtext)[line].line[p+1]),\
			strlen((*edtext)[line].line)-p+1);
	(*edtext)[line].line=(char *)realloc((*edtext)[line].line,\
			strlen((*edtext)[line].line)+1);
	(*edtext)[line].Quote=IsQuote((*edtext)[line].line);
	if (strncmp((*edtext)[line].line,"--- ",4)==0 ||
			strcmp((*edtext)[line].line,"---")==0)
		(*edtext)[line].CutOrigin=1;
	else
	{
		if (strncmp((*edtext)[line].line," * Origin:",10)==0)
			(*edtext)[line].CutOrigin=2;
		else
			(*edtext)[line].CutOrigin=0;
	}
	return p;
}

void writestr(char *line, int pos)
{
	(*edtext)[pos].line=(char *)realloc((*edtext)[pos].line,strlen(line)+1);
	strcpy((*edtext)[pos].line,line);
	(*edtext)[pos].Quote=IsQuote((*edtext)[pos].line);
	if (strncmp((*edtext)[pos].line,"--- ",4)==0 ||
			strcmp((*edtext)[pos].line,"---")==0)
		(*edtext)[pos].CutOrigin=1;
	else
	{
		if (strncmp((*edtext)[pos].line," * Origin:",10)==0)
			(*edtext)[pos].CutOrigin=2;
		else
			(*edtext)[pos].CutOrigin=0;
	}
}

void insertline(int pos)
{
	txLines++;
	(*edtext)=(LineListType *)realloc((*edtext),LineListSize*txLines);
	if (pos!=txLines)
		memmove(&((*edtext)[pos+1]),&((*edtext)[pos]),LineListSize*(txLines-pos-1));
	(*edtext)[pos].line=(char *)malloc(1);
	(*edtext)[pos].line[0]=0;
	(*edtext)[pos].Quote=0;
	(*edtext)[pos].CutOrigin=0;
	(*edtext)[pos].CR=0;
}

void deleteline(int pos)
{
	free((*edtext)[pos].line);
	if (pos!=txLines-1)
		memmove(&((*edtext)[pos]),&((*edtext)[pos+1]),\
				LineListSize*(txLines-pos-1));
	txLines--;
	(*edtext)=(LineListType *)realloc((*edtext),LineListSize*txLines);
}

int killlastspaces(char *line)
{
	char i;
	int o;
	for (i=0; i; i++) if (line[i]!=32) break;
	if (i)
	{
		for (i=strlen(line)-1, o=0; line[i]==32; line[i--]=0, o++);
		if (o>0) line[i+1]=32;
		if (o<2) return 0;
		return o-1;
	}
	return 0;
}

/*int killlastspaces(char *line)
{
	char *d1;
	int i, o;
	if ((d1=strchr(line,32)))
	{
		for (i=strlen(line)-1, o=0; line[i]==32 && i>0; line[i--]=0, o++);
		if (o>0) line[i+1]=32;
		if (o<2) return 0;
		return o-1;
	}
	return 0;
}*/

int breakline(char *line, char *rest)
{
	int i, ks;
	if (strlen(line)>Cols-2)
	{
		for (i=Cols-2; !strloc(line[i]," -,") && i>=0; i--);
		if (i==-1)
		{
			strcpy(rest,line+Cols-1);
			line[Cols-1]=0;
			ks=killlastspaces(rest);
		} else
		{
			strcpy(rest,line+i+1);
			line[i+1]=0;
			ks=killlastspaces(line)+killlastspaces(rest);
		}
		return ks;
	}
	return -1;
}

void tabtospace(int l)
{
	char *db, *s;
	int i=0, dl=strlen((*edtext)[l].line)+1;
	db=(char *)malloc(dl);
	for (s=(*edtext)[l].line; *s;)
		if (*s==9)
		{
			dl+=8;
			db=(char *)realloc(db,dl);
			do
				db[i++]=32;
			while (i%8);
			s++;
		} else
			db[i++]=*s++;
	db[i++]=0;
	(*edtext)[l].line=(char *)realloc((*edtext)[l].line,i);
	strcpy((*edtext)[l].line,db);
	free(db);
}

void floattext()
{
	int i;
	char *dummy=NULL, *rest=NULL;
	for (i=0; i<txLines-1; i++)
		tabtospace(i);
	for (i=0; i<txLines-1;)
	{
		dummy=(char *)malloc(strlen((*edtext)[i].line)+
				strlen((*edtext)[i+1].line)+256);
		rest=(char *)malloc(strlen((*edtext)[i].line)+
				strlen((*edtext)[i+1].line)+256);
		if (!(*edtext)[i].CR)
		{	
			strcpy(dummy,(*edtext)[i].line);
			strcat(dummy," ");
			strcat(dummy,(*edtext)[i+1].line);
			if (breakline(dummy,rest)!=-1)
			{
				writestr(dummy,i);
				writestr(rest,i+1);
				i++;
			} else
			{
				writestr(dummy,i);
				(*edtext)[i].CR=(*edtext)[i+1].CR;
				deleteline(i+1);
			}
		}	else
		{
			strcpy(dummy,(*edtext)[i].line);
			if (breakline(dummy,rest)!=-1)
			{
				writestr(dummy,i);
				(*edtext)[i].CR=0;
				i++;
				insertline(i);
				writestr(rest,i);
				(*edtext)[i].CR=1;
			}
			i++;
		}
		free(dummy);
		free(rest);
	}
}

void floatpar(int *fl, int *x, int *y)
{
	int i, ende, l=0, m, ks, ll;
	char *dummy, *rest;
	dummy=(char *)malloc(Cols*2);
	rest=(char *)malloc(Cols*2);
 	killlastspaces((*edtext)[*fl+*y].line);
  if (*x>strlen((*edtext)[*fl+*y].line))
  	(*x)=strlen((*edtext)[*fl+*y].line);
	for (i=*fl+*y-1; i>=0; i--)
		if ((*edtext)[i].CR)
			break;
		else
		{
			killlastspaces((*edtext)[i].line);
			*x+=strlen((*edtext)[i].line);
			l++;
		}
	if (i!=*fl+*y) i++;
	for (ll=l, m=i, ende=0; i<txLines;)
	{
		strcpy(dummy,(*edtext)[i].line);
		if ((*edtext)[i].CR || i==txLines-1)
			ende=1;
		else
			strcat(dummy,(*edtext)[i+1].line);
		if ((ks=breakline(dummy,rest))!=-1)
		{
			writestr(dummy,i);
			if (ende)
			{
				(*edtext)[i].CR=0;
				insertline(i+1);
				(*edtext)[i+1].CR=1;
			}
			writestr(rest,i+1);
			i++;
			if (ll>0) (*x)-=ks;
		} else
		{
			writestr(dummy,i);
			if (!ende)
			{
				(*edtext)[i].CR=(*edtext)[i+1].CR;
				deleteline(i+1);
			}
		}
		if (ende) break;
		ll--;
	}
	for (i=m; i<txLines-1; i++)
		if (*x<=strlen((*edtext)[i].line))
			break;
		else
		{
			*x-=strlen((*edtext)[i].line);
			l--;
		}
	if (l)
		*y-=l;
	if ((*y)<0)
	{
		(*fl)+=(*y);
		(*y)=0;
	}
	while ((*y)>=Lines)
	{
		(*fl)++;
		(*y)--;
	}
	free(dummy);
	free(rest);
}

void inputfile(WINDOW *wH, int line)
{
	WINDOW *win;
	char file[PATH_MAX], sys[PATH_MAX], *d1, **args;
	FILE *f=NULL, *rp, *wp;
	int pid, status, canr=1, canw=1;
	file[0]=0;
	if ((win=openask(4,Cols,YStart+Lines/2-2,0,"Insert File",\
			COL_Menu))!=NULL)
	{
		while (!inputline(win,wH,1,1,Cols-3,file,NULL,0,1))
		{
			extendhome(file);
			if ((f=fopen(file,"rt")))
				break;
			else
				mvwaddstr(win,2,2,"Can't stat this file! Try again!");
		}
		delwin(win);
		texthelp(wH);
		if (f)
		{
			args=(char **)malloc(3*sizeof(char *));
			args[0]=strdup(ImportText);
			args[1]=strdup(file);
			args[2]=NULL;
			if ((pid=pipecall(ImportText,args,&rp,&wp)))
			{
				while (canr || canw)
				{
					while (canr && canread(rp))
					{
						if (fgets(sys,PATH_MAX,rp))
						{
							insertline(line);
							if ((d1=strchr(sys,'\r'))) *d1=0;
							if ((d1=strchr(sys,'\n'))) *d1=0;
							transstr(sys,0);
							writestr(sys,line);
							(*edtext)[line].CR=1;
							(*edtext)[line].Quote=0;
							(*edtext)[line].CutOrigin=0;
							line++;
						} else
						{
							fclose(rp);
							canr=0;
						}
					}
					if (canw && canwrite(wp))
					{
						if (fgets(sys,PATH_MAX,f))
							fputs(sys,wp);
						else
						{
							fclose(wp);
							canw=0;
						}
					}
				}
				while (waitpid(pid,&status,WNOHANG)!=pid);
			} else
			{
				insertline(line);
				sprintf(sys,">>> File: %s <<<",file);
				writestr(sys,line);
				(*edtext)[line].CR=1;
				line++;
				while (fgets(sys,COLS,f))
				{
					insertline(line);
					if ((d1=strchr(sys,'\r'))) *d1=0;
					if ((d1=strchr(sys,'\n'))) *d1=0;
					transstr(sys,0);
					writestr(sys,line);
					(*edtext)[line].CR=1;
					line++;
				}
				insertline(line);
				writestr(">>> EndFile <<<",line);
				(*edtext)[line].CR=1;
			}
			fclose(f);
			free(args[0]);
			free(args[1]);
			free(args);
			floattext();
		}
	}
}

int piperegion(WINDOW *wHlp, int fl)
{
	FILE *rp, *wp;
	char line[PATH_MAX], cmd[80], *d1, **scripts=NULL, **args=NULL;
	int i, nscr=1, error=1, canr=1, canw=1, pid;
	WINDOW *win;
	scripts=(char **)malloc(sizeof(char *));
	scripts[0]=(char *)malloc(80);
	scripts[0][0]=cmd[0]=0;
	if (bufLines!=0)
	{
		if ((win=openask(3,Cols,YStart+Lines/2-1,0,"Pipe buffer through",\
				COL_Menu))!=NULL)
		{
			for (i=0; i<numUtility; i++)
				if (Utility[i].NeedsText &&
						!Utility[i].NeedsHeader &&
						!Utility[i].NeedsScreen &&
						!Utility[i].NeedsMsgBase &&
						!Utility[i].NeedsKludges &&
						!Utility[i].NeedsArea)
				{
					nscr++;
					scripts=(char **)realloc(scripts,sizeof(char *)*nscr);
					scripts[nscr-1]=(char *)malloc(strlen(Utility[i].CommandLine)+1);
					strcpy(scripts[nscr-1],Utility[i].CommandLine);
				}
			if (inputline(win,wHlp,1,1,Cols-3,cmd,scripts,nscr,1)<0)
			{
				delwin(win);
				texthelp(wHlp);
				goto ende;
			}
			extendhome(cmd);
			delwin(win);
			texthelp(wHlp);
			args=(char **)malloc(2*sizeof(char *));
			strcpy(line,cmd);
			for (d1=line; isspace(*d1); d1++);
			*d1=0;
			if ((d1=strrchr(line,'/'))) *d1++=0;
			args[0]=strdup(d1);
			args[1]=NULL;
			if ((pid=pipecall(cmd,args,&rp,&wp)))
			{
				for (i=0; canr || canw;)
				{
					if (canw && canwrite(wp))
						if (i<bufLines)
						{
							fputs(buffer[i].line,wp);
							if (buffer[i++].CR) fputc('\n',wp);
						} else
						{
							fclose(wp);
							canw=0;
						}
					while (canr && canread(rp))
						if (fgets(line,PATH_MAX,rp))
						{
							if ((d1=strchr(line,0xa))) *d1=0;
							insertline(fl);
							writestr(line,fl);
							(*edtext)[fl].CR=1;
							fl++;
						} else
						{
							fclose(rp);
							canr=0;
						}
				}
				while (waitpid(pid,&i,WNOHANG)!=pid);
			} else
				error=0;
			free(args[0]);
			free(args);
		} else error=0;
	} else error=0;
	ende:
	for (i=0; i<nscr; i++) free(scripts[i]);
	free(scripts);
	return error;
}

int realyQuit(WINDOW *wTxt)
{
	WINDOW *win;
	int in=0;
	if ((win=openask(9,44,LINES/2-4,COLS/2-22,"Warning",COL_Menu)))
	{
		curs_set(CURSOR_OFF);
		move(0,0);
		refresh();
		mvwaddstr(win,2,14,"You are about to");
		mvwaddstr(win,3,13,"exit WITHOUT save!");
		mvwaddstr(win,5,13,"Are you sure (y/n)?");
		mvwaddstr(win,7,1,"This is a contribution to all vi users ;-)");
		wrefresh(win);
		while (in!='y' && in!='n') in=tolower(getchn());
		delwin(win);
		curs_set(CURSOR_ON);
		touchwin(wTxt);
		wrefresh(wTxt);
	}
	return (in=='y');
}

void curmove(WINDOW *win, WINDOW *ws, int fl, int y, int x)
{
	mvwprintw(ws,0,COLS-26,"%s B %3u R %3u C %3u",
			ConvertChars?"CONVERT":"       ",bufLines,y+fl+1,x+1);
	wrefresh(ws);
	wmove(win,y,x);
	wrefresh(win);
}

void initsmilies(LineListType **sm, int *numsm, LineListType **shk)
{
	char name[PATH_MAX], *d1, line[PATH_MAX];
	FILE *f;
	int num, i;
	*shk=(LineListType *)malloc(10*LineListSize);
	memset(*shk,0,10*LineListSize);
	sprintf(name,"%smacros",BasePath);
	if ((f=fopen(name,"rt")))
	{
		while (fgets(name,PATH_MAX,f))
		{
			if ((d1=strchr(name,'\n'))) *d1=0;
			if (name[0]=='#' && isdigit(name[1]) && name[2]==0)
			{
				num=name[1]-'0';
				if (fgets(name,PATH_MAX,f))
				{
					if ((d1=strchr(name,'\n'))) *d1=0;
					free((*shk)[num].line);
					(*shk)[num].line=strdup(name);
				} else
					break;
			} else
			{
				if (fgets(line,PATH_MAX,f))
				{
					if ((d1=strchr(line,'\n'))) *d1=0;
					for (i=strlen(name); i<60; i++) name[i]=32;
					name[60]=0;
					(*numsm)++;
					(*sm)=(LineListType *)realloc((*sm),(*numsm)*LineListSize);
					(*sm)[(*numsm)-1].line=(char *)malloc(strlen(line)+62);
					sprintf((*sm)[(*numsm)-1].line,"%s %s",name,line);
				} else
					break;
			}
		}
		fclose(f);
	}
}
