/* MINCE.C      This is the Mince screen editor

	MINCE - Mince Is Not Complete Emacs

	This is the main body of the screen editor. It contains the
command entry and command decoder.      This editor is a compatible subset
of EMACS a la ITS or MULTICS as much as is possible. There are about
sixty basic commands. */

#include "mince.gbl"

main(argc,argv)	 /* This is the Mince command line entry point */
	int argc;
	char *argv[];

{
	setup(argc,argv);	       /* Interpret command line arguments */
	edit();			 /* Do the actual editing */
	ClrEcho();
	TSetPoint(TMaxRow()-2,0);
	TForce();
	TFini();
	exec("MENU", buffs[cbuff].fname);
	exec("A:MENU", buffs[cbuff].fname);
	_exit();
}

edit()			  /* This does the actual editing, we assume
						that the buffer is initialized. */
{
	abort=FALSE;
	while(!abort) {
		if (!TKbRdy()) IncrDsp();/* Update display */
		KbWait();
		cmnd=TGetKb();		  /* accept a command character */
		MapFuncKey();
		arg=1;
		argp=FALSE;
		while(arg) {
			(*functs[cmnd])();      /* execute selected function */
			lfunct=functs[cmnd];
			TKbChk();
			if (--arg<0) arg=0;
			}
		}
	}

setup(iargc,iargv)	      /* Program initialization: interpret the command
						line and init the buffer */
	int iargc;
	char *iargv[];
{
	int swpfd, newflag;
	char tbname[BUFNAMMAX], tfname[FILMAX];

	*strarg = *namearg = '\0';

	fillwidth=FILLINIT;
	indentcol=INDENTINIT;
	tabincr=INITTABS;
	prefrow=PREFLINE;
	delaycnt = 300;
	mhz = 5;
	if(iargc > 1 && !strcmp(iargv[1], "-swap")){
		iargc--;
		iargv++;
		if(isdigit(*iargv[1])){
			stcd_i(iargv[1], &npages);
			npages = npages / 8 * 8;
			iargc--;
			iargv++;
		}
		else
			npages = 64;
		if((swpfd = creat(SWAPFNAM, UPDATE)) < 0)
			puts("Can't create swap file\n");
		else{
			puts("Creating swap file...\n");
			if(write(swpfd, &npages, (int) SWAPBASE) != SWAPBASE){
				puts("Error in creating swap file!!");
				exit(1);
			}
			for(tmp = 0; tmp < npages; tmp++)
				if(write(swpfd, &npages, PSIZE) != PSIZE){
				puts("Error in creating swap file!!");
				exit(1);
				}
			close(swpfd);
		}
	}
	swpfd=open(SWAPFNAM, UPDATE);
	if(swpfd < 0 && (swpfd=open(SWAP1FNAM, UPDATE)) < 0){
		swpfd = -1;
		npages = 48;
	}
	else
		read(swpfd, &npages, sizeof(npages));
	TermInit();					/* Set up terminal */
	BInit(swpfd);
	del_buff=BCreate();
	newflag = FALSE;
	for (cnt=BUFFSMAX-1; cnt>=0; --cnt) buffs[cnt].bbuff=NULL;
	cbuff = -1;
	def_mode = 'f';				/* bring up fill mode */
	if (iargc>1) {
		if(*iargv[1] == '-'){
			def_mode = CheckMode(&iargv[1][1]); 
			iargv++;
			iargc--;
		}
		if(iargc > 1){
			if (strlen(iargv[1])>=FILMAX)
				iargv[1][FILMAX-1]='\0';
			strcpy(tfname, iargv[1]);
			strip(tbname,tfname);
			dfltext(tfname, MSS);
			UpCase(tfname);
			LowCase(tbname);
			cbuff=CMakeBuff(tbname,tfname);
			newflag=!BReadFile(tfname);
		}
	}
	if(cbuff == -1)
		cbuff=CMakeBuff("name","NAME.ME");

	topp=TRUE;			      /* one window at the top */
	divide=TMaxRow()-2;
	sstart=BCreMrk();
	psstart=BCreMrk();
	send=BCreMrk();
	Echo("(c) 1983, Perfect Software Inc. -- Type ESC ? for help");
	CSwitchTo(cbuff);
/*	
	if (newflag) Echo ("New File");
*/
	}

puts(string)
char *string;
{
	while(*string)
		putc(*string++, stdout);
}
NewDsp()				/* Put a new display on the screen */
{
	ScrnRange();
	TClrWind();	     /* Clear the window */
	ModeLine();
	for (cnt=0; cnt<TMaxRow()-2; ++cnt) BSetMod(BScrnMrk(cnt));
	tlrow = -1;
	}

ModeLine()		      /* Display the mode line */
{
	int cnt;

	TREV();
	TDisStr(TMaxRow()-2,0,"Perfect Writer Version 1.00 (");
	TPrntStr(mode);
	TPrntStr(") ");
	TPrntStr(buffs[cbuff].bname);
	TPrntStr(": ");
	TPrntStr(buffs[cbuff].fname);
/*
	TCLEOL();
*/
	stat_col=TGetCol();
	while(TGetCol() < TMaxCol())
		TPrntChar(' ');
	TNORM();
	DivideLine();
	}

DivideLine()
{

	if (divide<TMaxRow()-2) {
		TREV();
		TSetPoint(divide, 0);
		for (cnt=0; cnt < TMaxCol(); cnt++){
			if(cnt == indentcol || cnt == fillwidth)
				TPrntChar(186);
			else if(cnt % tabincr == 0)
				TPrntChar(254);
			else
				TPrntChar(249);
		}
		TNORM();
	}
}


DoIncrDsp(deep)	 /* Actually update the display from the buffer */
	int deep;
{
	int pnt_row, pmark, colhack;

	colhack=savecol;		/* !!!!! This is cheating */
	if (BIsBeforeMrk(sstart) || (sendp && !BIsBeforeMrk(send))) ScrnRange();
	pmark=BCreMrk();
	BPntToMrk(sstart);
	if (BIsAtMrk(psstart) && !BIsStart()) {
		BPntToMrk(pmark);
		ScrnRange();
		BPntToMrk(sstart);
		}
	pnt_row=InnerDsp(topp? 0 : divide+1, topp? divide : TMaxRow()-2, pmark);
	if (BIsBeforeMrk(pmark) && !TKbRdy()) {
		BPntToMrk(pmark);
		BKillMrk(pmark);
		DoScrnRange(deep);
		savecol=colhack;		/*!!!!! this is cheating */
		DoIncrDsp(TRUE);
		}
	else {
		if (!TKbRdy() && divide<TMaxRow()-2) {
			BPntToMrk(altstart);
			InnerDsp(topp? divide+1 : 0, topp? TMaxRow()-2 : divide, NULL);
			BPntToMrk(altpnt);
			}
		BPntToMrk(pmark);
		BKillMrk(pmark);
		savecol=colhack;		/*!!!!! this is cheating */
		ModeFlags();
		TSetPoint(pnt_row,BGetCol()%TMaxCol());
		TForce();
		}
	}

InnerDsp(from,to,pmark) /* Do the inner loop of the redisplay */
	int from, to, pmark;
{
	register int trow;
	register char *lindex;

	static char tline[COLMAX+1];
	static int pnt_row;

	int need_pnt;

	need_pnt=TRUE;
	for (trow=from; trow<to && !TKbRdy(); ++trow) {
		if (BTstMrk(BScrnMrk(trow)) || !BIsAtMrk(BScrnMrk(trow))) {
			BMrkToPnt(BScrnMrk(trow));
			TSetPoint(trow,0);
#ifdef CPM
			AsmDsp();
			*lindex = 254;	  /* need unused value */
#else
			lindex = tline;
			if (trow==tlrow) {
				while (!BIsEnd() && Buff() == *lindex++) {
					TSetPoint(trow,TGetCol()+TWidth(TGetCol(),Buff()));
					BMove(1);
					}
				if (!BIsEnd()) --lindex;
				}
			while (!BIsEnd() && Buff()!=NL &&
				 TGetCol()+TWidth(TGetCol(),Buff())<=TMaxCol()) {
				TPrntChar(Buff());
				*lindex++ = Buff();
				TKbChk();
				BMove(1);
				}
			*lindex = -1;
#endif
			TCLEOL();
			tlrow=trow;
			if (TGetCol()<TMaxCol())
				if (BIsEnd()) BShoveIt();
				else if (Buff()==NL) BMove(1);
			}
		else {
			BPntToMrk(BScrnMrk(trow+1));
			TKbChk();
			}
		if (pmark)
			if (BIsAfterMrk(pmark) && need_pnt) {
				pnt_row=trow;
				need_pnt=FALSE;
				}
		}
	if (TKbRdy() && !BIsAtMrk(BScrnMrk(trow))) BSetMod(BScrnMrk(trow));
	BMrkToPnt(BScrnMrk(trow));
	if (pmark && !TKbRdy()) {
		BMrkToPnt(send);
		sendp=TRUE;
		if (need_pnt) pnt_row=to;
		}
	return(pnt_row);
	}

WHeight()			       /* return the height of the current window */
{
	return(topp? divide : TMaxRow()-divide-3);
	}

PrefLine()		      /* return the current preferred line */
{
	return((prefrow*WHeight())/(TMaxRow()-2));
	}


DoScrnRange(deep)	       /* Work for centering redisplay */
	int deep;
{
	int pmark;		      /* Position of the point */

	pmark=BCreMrk();		/* save the point position */
	if (deep) {
		cnt=PrefLine()+1;
		do {
			cnt -= BGetCol()/TMaxCol()+1;
			} while (cnt>0 && RNLSrch());
		if (cnt<0) BMakeCol((-cnt)*TMaxCol());
		else ToBegLine();
		}
	else {
		for (cnt=PrefLine(); cnt>0; --cnt) RNLSrch();
		if (RNLSrch()) BMove(1);
		}
	BMrkToPnt(sstart);
	BMove(-1);
	BMrkToPnt(psstart);
	sendp=FALSE;
	BPntToMrk(pmark);
	BKillMrk(pmark);
	}

CMakeBuff(tbname,tfname)	/* create a buffer */
	char *tbname, *tfname;
{
#ifdef CPM
	int cntr;
#else
	register int cntr, cnt1;
#endif
	struct cbuffer *tcbuff;

	for (cntr=BUFFSMAX-1; cntr>=0 && buffs[cntr].bbuff; --cntr);
	TKbChk();
	if (cntr<0) Error("Too many buffers");
	else {
		tcbuff = &buffs[cntr];
		tcbuff->bbuff=BCreate();
		if (tcbuff->bbuff==NULL) return(-1);	    /* failure */
		BSwitchTo(tcbuff->bbuff);
		tcbuff->bmark=BCreMrk();
		strcpy(tcbuff->bname,tbname);
		for (cnt1=MAXMODES-1; cnt1>=0; --cnt1)
			tcbuff->bmodes[cnt1]='\0';
		strcpy(tcbuff->fname,tfname);
		tcbuff->bmodes[MAXMODES - 1] = def_mode;	/* setup mode from */
											/* command line */
		}
	return(cntr);
	}

CSwitchTo(cntr)		 /* switch to buffer cnt */
	int cntr;
{
	strcpy(namearg,buffs[cbuff].bname);
	cbuff=cntr;
	BSwitchTo(buffs[cbuff].bbuff);
	mark=buffs[cbuff].bmark;
	SetModes();
	}

CFindBuff(tbname)	       /* locate buffer */
	char *tbname;
{
	int cnt;

	for (cnt=BUFFSMAX-1; cnt>=0 && (buffs[cnt].bbuff==NULL ||
		strcmp(tbname,buffs[cnt].bname)); --cnt);
	return(cnt);
	}

/* END OF MINCE.C - editor top level */
