
/* Windows versions of DOS functions needed by PROMPTS.C */

#include <string.h>
#include <stdio.h>
#include <dos.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <fcntl.h>
#include <math.h>
#include "fractint.h"
#include "fractype.h"
#include "helpdefs.h"

/* routines in this module	*/
void movecursor(int row, int col);
void setattr(int row, int col, int attr, int count);
int  putstringcenter(int row, int col, int width, int attr, char far *msg);
void putstring(int row, int col, int attr, unsigned char far *buf);
int  fullscreen_choice(
	     int options, char far *hdg, char far *hdg2, char far *instr, int numchoices,
	     char **choices, int *attributes, int boxwidth, int boxdepth,
	     int colwidth, int current, void (*formatitem)(),
	     char *speedstring, int (*speedprompt)(), int (*checkkey)());
int  strncasecmp(char *s,char *t,int ct);
int  input_field(int options, int attr, char *fld, int len, int row, int col, int (*checkkey)(int) );
int  field_prompt(int options, char *hdg, char *instr, char *fld, int len, int (*checkkey)(int) );
void helptitle(void);
void stackscreen(void);
void unstackscreen(void);
void discardscreen(void);
void load_palette(void);
void save_palette(void);
void fractint_help(void);

extern  VOIDFARPTR cdecl farmemalloc(long);

/* faked/unimplemented routines */

struct videoinfo far *vidtbl;
int vidtbllen = 0;
int badconfig = 0;

int in_fractint_help = 0;

int win_release = 1821;
char far win_comment[] =
     {" "};                /*  publicly-released version */
/*   {"Test Version - Not for Release"};   /* interim test versions */
/*   {"'Public Beta' Release"};   /* interim test versions */

extern int time_to_resume;	     /* time to resume? */

int text_type = 0;
int textrow = 0, textcol = 0;
int textrbase = 0, textcbase = 0;
int lookatmouse;

/* fullscreen_choice options */
#define CHOICERETURNKEY 1
#define CHOICEMENU	2
#define CHOICEHELP	4

char speed_prompt[]="Speed key string";

int fullscreen_choice(
	int options,	     /* &2 use menu coloring scheme	       */
			     /* &4 include F1 for help in instructions */
			     /* &8 add caller's instr after normal set */
	char far *hdg,	     /* heading info, \n delimited	       */
	char far *hdg2,	     /* column heading or NULL		       */
	char far *instr,     /* instructions, \n delimited, or NULL    */
	int numchoices,      /* How many choices in list	       */
	char **choices,      /* array of choice strings 	       */
	int *attributes,     /* &3: 0 normal color, 1,3 highlight      */
			     /* &256 marks a dummy entry	       */
	int boxwidth,	     /* box width, 0 for calc (in items)       */
	int boxdepth,	     /* box depth, 0 for calc, 99 for max      */
	int colwidth,	     /* data width of a column, 0 for calc     */
	int current,	     /* start with this item		       */
	void (*formatitem)(),/* routine to display an item or NULL     */
	char *speedstring,   /* returned speed key value, or NULL >[30]*/
	int (*speedprompt)(),/* routine to display prompt or NULL      */
	int (*checkkey)()    /* routine to check keystroke or NULL     */
)
   /* return is: n>=0 for choice n selected,
		 -1 for escape
		  k for checkkey routine return value k (if not 0 nor -1)
      speedstring[0] != 0 on return if string is present
      */
{
static char far choiceinstr1a[]="Use the cursor keys to highlight your selection";
static char far choiceinstr1b[]="Use the cursor keys or type a value to make a selection";
static char far choiceinstr2a[]="Press ENTER for highlighted choice, or ESCAPE to back out";
static char far choiceinstr2b[]="Press ENTER for highlighted choice, ESCAPE to back out, or F1 for help";
static char far choiceinstr2c[]="Press ENTER for highlighted choice, or F1 for help";

   int titlelines,titlewidth;
   int reqdrows;
   int topleftrow,topleftcol;
   int topleftchoice;
   int speedrow;  /* speed key prompt */
   int boxitems;  /* boxwidth*boxdepth */
   int curkey,increment,rev_increment;
   int redisplay;
   int i,j,k;
   char far *charptr;
   char buf[81];
   int speed_match = 0;
   char curitem[81];
   char *itemptr;
   int ret,savelookatmouse;

   savelookatmouse = lookatmouse;
   lookatmouse = 0;
   ret = -1;
   if (speedstring
     && (i = strlen(speedstring)) > 0) { /* preset current to passed string */
      current = 0;
      while (current < numchoices
	&& (k = strncasecmp(speedstring,choices[current],i)) > 0)
	 ++current;
      if (k < 0 && current > 0)  /* oops - overshot */
	 --current;
      if (current >= numchoices) /* bumped end of list */
	 current = numchoices - 1;
      }

   while (1) {
      if (current >= numchoices)  /* no real choice in the list? */
	 goto fs_choice_end;
      if ((attributes[current] & 256) == 0)
	 break;
      ++current;		  /* scan for a real choice */
      }

   titlelines = titlewidth = 0;
   if (hdg) {
      charptr = hdg;		  /* count title lines, find widest */
      i = 0;
      titlelines = 1;
      while (*charptr) {
	 if (*(charptr++) == '\n') {
	    ++titlelines;
	    i = -1;
	    }
	 if (++i > titlewidth)
	    titlewidth = i;
	 }
      }

   if (colwidth == 0)		  /* find widest column */
      for (i = 0; i < numchoices; ++i)
	 if (strlen(choices[i]) > colwidth)
	    colwidth = strlen(choices[i]);

   /* title(1), blank(1), hdg(n), blank(1), body(n), blank(1), instr(?) */
   reqdrows = 3;		  /* calc rows available */
   if (hdg)
      reqdrows += titlelines + 1;
   if (instr) { 		  /* count instructions lines */
      charptr = instr;
      ++reqdrows;
      while (*charptr)
	 if (*(charptr++) == '\n')
	    ++reqdrows;
      if ((options & 8))	  /* show std instr too */
	 reqdrows += 2;
      }
   else
      reqdrows += 2;		  /* standard instructions */
   if (speedstring) ++reqdrows;   /* a row for speedkey prompt */
   if (boxdepth > (i = 25 - reqdrows)) /* limit the depth to max */
      boxdepth = i;
   if (boxwidth == 0) { 	  /* pick box width and depth */
      if (numchoices <= i - 2) {  /* single column is 1st choice if we can */
	 boxdepth = numchoices;
	 boxwidth = 1;
	 }
      else {			  /* sort-of-wide is 2nd choice */
	 boxwidth = 60 / (colwidth + 1);
	 if (boxwidth == 0
	   || (boxdepth = (numchoices+boxwidth-1)/boxwidth) > i - 2) {
	    boxwidth = 80 / (colwidth + 1); /* last gasp, full width */
	    if ((boxdepth = (numchoices+boxwidth-1)/boxwidth) > i)
	       boxdepth = i;
	    }
	 }
      }
   if ((i = 77 / boxwidth - colwidth) > 3) /* spaces to add @ left each choice */
      i = 3;
   j = boxwidth * (colwidth += i) + i;	   /* overall width of box */
   if (j < titlewidth+2)
      j = titlewidth + 2;
   if (j > 80)
      j = 80;
   if (j <= 70 && boxwidth == 2) {	   /* special case makes menus nicer */
      ++j;
      ++colwidth;
      }
   k = (80 - j) / 2;			   /* center the box */
   k -= (90 - j) / 20;
   topleftcol = k + i;			   /* column of topleft choice */
   i = (25 - reqdrows - boxdepth) / 2;
   i -= i / 4;				   /* higher is better if lots extra */
   topleftrow = 3 + titlelines + i;	   /* row of topleft choice */

   /* now set up the overall display */
   helptitle(); 			   /* clear, display title line */
   setattr(1,0,C_PROMPT_BKGRD,24*80);	   /* init rest to background */
   for (i = topleftrow-1-titlelines; i < topleftrow+boxdepth+1; ++i)
      setattr(i,k,C_PROMPT_LO,j);	   /* draw empty box */
   if (hdg) {
      textcbase = (80 - titlewidth) / 2;   /* set left margin for putstring */
      textcbase -= (90 - titlewidth) / 20; /* put heading into box */
      putstring(topleftrow-titlelines-1,0,C_PROMPT_HI,hdg);
      textcbase = 0;
      }
   if (hdg2)				   /* display 2nd heading */
      putstring(topleftrow-1,topleftcol,C_PROMPT_MED,hdg2);
   i = topleftrow + boxdepth + 1;
   if (instr == NULL || (options & 8)) {   /* display default instructions */
      if (i < 20) ++i;
      if (speedstring) {
	 speedrow = i;
	 *speedstring = 0;
	 if (++i < 22) ++i;
	 }
      putstringcenter(i++,0,80,C_PROMPT_BKGRD,
	    (speedstring) ? choiceinstr1b : choiceinstr1a);
      putstringcenter(i++,0,80,C_PROMPT_BKGRD,
	    (options&CHOICEMENU) ? choiceinstr2c
	    : ((options&CHOICEHELP) ? choiceinstr2b : choiceinstr2a));
      }
   if (instr) { 			   /* display caller's instructions */
      charptr = instr;
      j = -1;
      while ((buf[++j] = *(charptr++)))
	 if (buf[j] == '\n') {
	    buf[j] = 0;
	    putstringcenter(i++,0,80,C_PROMPT_BKGRD,buf);
	    j = -1;
	    }
      putstringcenter(i,0,80,C_PROMPT_BKGRD,buf);
      }

   boxitems = boxwidth * boxdepth;
   topleftchoice = 0;			   /* pick topleft for init display */
   while (current - topleftchoice >= boxitems
     || (current - topleftchoice > boxitems/2
	 && topleftchoice + boxitems < numchoices))
      topleftchoice += boxwidth;
   redisplay = 1;

   while (1) { /* main loop */

      if (redisplay) {			     /* display the current choices */
	 if ((options & CHOICEMENU) == 0) {
	    memset(buf,' ',80);
	    buf[boxwidth*colwidth] = 0;
	    for (i = (hdg2) ? 0 : -1; i <= boxdepth; ++i)  /* blank the box */
	       putstring(topleftrow+i,topleftcol,C_PROMPT_LO,buf);
	    }
	 for (i = 0; i+topleftchoice < numchoices && i < boxitems; ++i) {
	    /* display the choices */
	    if ((k = attributes[j = i+topleftchoice] & 3) == 1)
	       k = C_PROMPT_LO;
	    else if (k == 3)
	       k = C_PROMPT_HI;
	    else
	       k = C_PROMPT_MED;
	    if (formatitem)
	       (*formatitem)(j,charptr=buf);
	    else
	       charptr = choices[j];
	    putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
		      k,charptr);
	    }
	 /***
	 ... format differs for summary/detail, whups, force box width to
	 ...  be 72 when detail toggle available?  (2 grey margin each
	 ...  side, 1 blue margin each side)
	 ***/
	 if (topleftchoice > 0 && hdg2 == NULL)
	    putstring(topleftrow-1,topleftcol,C_PROMPT_LO,"(more)");
	 if (topleftchoice + boxitems < numchoices)
	    putstring(topleftrow+boxdepth,topleftcol,C_PROMPT_LO,"(more)");
	 redisplay = 0;
	 }

      i = current - topleftchoice;	     /* highlight the current choice */
      if (formatitem)
	 (*formatitem)(current,itemptr=curitem);
      else
	 itemptr = choices[current];
      putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
		C_CHOICE_CURRENT,itemptr);

      if (speedstring) {		     /* show speedstring if any */
	 memset(buf,' ',80);
	 buf[80] = 0;
	 putstring(speedrow,0,C_PROMPT_BKGRD,buf);
	 if (*speedstring) {		     /* got a speedstring on the go */
	    putstring(speedrow,15,C_CHOICE_SP_INSTR," ");
	    if (speedprompt)
	       j = speedprompt(speedrow,16,C_CHOICE_SP_INSTR,speedstring,speed_match);
	    else {
	       putstring(speedrow,16,C_CHOICE_SP_INSTR,speed_prompt);
	       j = strlen(speed_prompt);
	       }
	    strcpy(buf,speedstring);
	    i = strlen(buf);
	    while (i < 30)
	       buf[i++] = ' ';
	    buf[i] = 0;
	    putstring(speedrow,16+j,C_CHOICE_SP_INSTR," ");
	    putstring(speedrow,17+j,C_CHOICE_SP_KEYIN,buf);
	    movecursor(speedrow,17+j+strlen(speedstring));
	    }
	 else
	    movecursor(25,80);
	 }
      else
	 movecursor(25,80);

/*    while (!keypressed()) { } /* enables help */
/*      curkey = getakey(); */
      curkey = keycursor(-2,-2);

      i = current - topleftchoice;	     /* unhighlight current choice */
      if ((k = attributes[current] & 3) == 1)
	 k = C_PROMPT_LO;
      else if (k == 3)
	 k = C_PROMPT_HI;
      else
	 k = C_PROMPT_MED;
      putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
		k,itemptr);

      increment = 0;
      switch (curkey) { 		     /* deal with input key */
	 case ENTER:
	 case ENTER_2:
	    ret = current;
	    goto fs_choice_end;
	 case ESC:
	    goto fs_choice_end;
	 case DOWN_ARROW:
	 case DOWN_ARROW_2:
	    rev_increment = 0 - (increment = boxwidth);
	    break;
	 case UP_ARROW:
	 case UP_ARROW_2:
	    increment = 0 - (rev_increment = boxwidth);
	    break;
	 case RIGHT_ARROW:
	 case RIGHT_ARROW_2:
	    if (boxwidth == 1) break;
	    increment = 1; rev_increment = -1;
	    break;
	 case LEFT_ARROW:
	 case LEFT_ARROW_2:
	    if (boxwidth == 1) break;
	    increment = -1; rev_increment = 1;
	    break;
	 case PAGE_UP:
	    if (numchoices > boxitems) {
	       topleftchoice -= boxitems;
	       increment = -boxitems;
	       rev_increment = boxwidth;
	       redisplay = 1;
	       }
	    break;
	 case PAGE_DOWN:
	    if (numchoices > boxitems) {
	       topleftchoice += boxitems;
	       increment = boxitems;
	       rev_increment = -boxwidth;
	       redisplay = 1;
	       }
	    break;
	 case CTL_HOME:
	    current = -1;
	    increment = rev_increment = 1;
	    break;
	 case CTL_END:
	    current = numchoices;
	    increment = rev_increment = -1;
	    break;
	 default:
	    if (checkkey) {
	       if ((ret = (*checkkey)(curkey,current)) < -1 || ret > 0)
		  goto fs_choice_end;
	       if (ret == -1)
		  redisplay = -1;
	       }
	    ret = -1;
	    if (speedstring) {
	       i = strlen(speedstring);
	       if (curkey == 8 && i > 0) /* backspace */
		  speedstring[--i] = 0;
	       if (33 <= curkey && curkey <= 126 && i < 30) {
		  curkey = tolower(curkey);
		  speedstring[i] = curkey;
		  speedstring[++i] = 0;
		  }
	       if (i > 0) {		 /* locate matching type */
		  current = 0;
		  while (current < numchoices
		    && (speed_match = strncasecmp(speedstring,choices[current],i)) > 0)
		     ++current;
		  if (speed_match < 0 && current > 0)  /* oops - overshot */
		     --current;
		  if (current >= numchoices) /* bumped end of list */
		     current = numchoices - 1;
		  }
	       }
	    break;
	 }

      if (increment) {			/* apply cursor movement */
	 current += increment;
	 if (speedstring)		/* zap speedstring */
	    speedstring[0] = 0;
	 }
      while (1) {			/* adjust to a non-comment choice */
	 if (current < 0 || current >= numchoices)
	     increment = rev_increment;
	 else if ((attributes[current] & 256) == 0)
	     break;
	 current += increment;
	 }
      if (topleftchoice > numchoices - boxitems)
	 topleftchoice = ((numchoices+boxwidth-1)/boxwidth)*boxwidth - boxitems;
      if (topleftchoice < 0)
	 topleftchoice = 0;
      while (current < topleftchoice) {
	 topleftchoice -= boxwidth;
	 redisplay = 1;
	 }
      while (current >= topleftchoice + boxitems) {
	 topleftchoice += boxwidth;
	 redisplay = 1;
	 }
      }

fs_choice_end:
   lookatmouse = savelookatmouse;
   return(ret);

}

int input_field(
	int options,	      /* &1 numeric, &2 integer, &4 double */
	int attr,	      /* display attribute */
	char *fld,	      /* the field itself */
	int len,	      /* field length (declare as 1 larger for \0) */
	int row,	      /* display row */
	int col,	      /* display column */
	int (*checkkey)(int)  /* routine to check non data keys, or NULL */
	)
{
   char savefld[81];
   char buf[81];
   int insert, started, offset, curkey, display;
   int i, j;
   int ret,savelookatmouse;
   savelookatmouse = lookatmouse;
   lookatmouse = 0;
   ret = -1;
   strcpy(savefld,fld);
   insert = started = offset = 0;
   display = 1;
   while (1) {
      strcpy(buf,fld);
      i = strlen(buf);
      while (i < len)
	 buf[i++] = ' ';
      buf[len] = 0;
      if (display) {				    /* display current value */
	 putstring(row,col,attr,buf);
	 display = 0;
	 }
      curkey = keycursor(row+insert,col+offset);  /* get a keystroke */
      switch (curkey) {
	 case ENTER:
	 case ENTER_2:
	    ret = 0;
	    goto inpfld_end;
	 case ESC:
	    goto inpfld_end;
	 case RIGHT_ARROW:
	 case RIGHT_ARROW_2:
	    if (offset < len) ++offset;
	    started = 1;
	    break;
	 case LEFT_ARROW:
	 case LEFT_ARROW_2:
	    if (offset > 0) --offset;
	    started = 1;
	    break;
	 case HOME:
	    offset = 0;
	    started = 1;
	    break;
	 case END:
	    offset = strlen(fld);
	    started = 1;
	    break;
	 case 8:
	 case 127:				/* backspace */
	    if (offset > 0) {
	       j = strlen(fld);
	       for (i = offset-1; i < j; ++i)
		  fld[i] = fld[i+1];
	       --offset;
	       }
	    started = display = 1;
	    break;
	 case DELETE:				/* delete */
	    j = strlen(fld);
	    for (i = offset; i < j; ++i)
	       fld[i] = fld[i+1];
	    started = display = 1;
	    break;
	 case 1082:				/* insert */
	    insert ^= 0x8000;
	    started = 1;
	    break;
	 case F5:
	    strcpy(fld,savefld);
	    insert = started = offset = 0;
	    display = 1;
	    break;
	 default:
	    if (curkey < 32 || curkey >= 127) {
	       if (checkkey && (ret = (*checkkey)(curkey)))
		  goto inpfld_end;
	       break;				     /* non alphanum char */
	       }
	    if (offset >= len) break;		     /* at end of field */
	    if (insert && started && strlen(fld) >= len)
	       break;				     /* insert & full */
	    if ((options & 1)
	      && (curkey < '0' || curkey > '9')
	      && curkey != '+' && curkey != '-') {
	       if ((options & 2))
		  break;
	       /* allow scientific notation, and specials "e" and "p" */
	       if ( ((curkey != 'e' && curkey != 'E') || offset >= 18)
		 && ((curkey != 'p' && curkey != 'P') || offset != 0 )
		 && curkey != '.')
		  break;
	       }
	    if (started == 0) /* first char is data, zap field */
	       fld[0] = 0;
	    if (insert) {
	       j = strlen(fld);
	       while (j >= offset) {
		  fld[j+1] = fld[j];
		  --j;
		  }
	       }
	    if (offset >= strlen(fld))
	       fld[offset+1] = 0;
	    fld[offset++] = curkey;
	    /* if "e" or "p" in first col make number e or pi */
	    if ((options & 3) == 1) { /* floating point */
	       double tmpd;
	       int specialv;
	       char tmpfld[30];
	       specialv = 0;
	       if (*fld == 'e' || *fld == 'E') {
		  tmpd = exp(1.0);
		  specialv = 1;
		  }
	       if (*fld == 'p' || *fld == 'P') {
		  tmpd = atan(1.0) * 4;
		  specialv = 1;
		  }
	       if (specialv) {
		  if ((options & 4) == 0)
		     roundfloatd(&tmpd);
		  sprintf(tmpfld,"%.15g",tmpd);
		  tmpfld[len-1] = 0; /* safety, field should be long enough */
		  strcpy(fld,tmpfld);
		  offset = 0;
		  }
	       }
	    started = display = 1;
	 }
      }
inpfld_end:
   lookatmouse = savelookatmouse;
   return(ret);
}

int field_prompt(
	int options,	    /* &1 numeric value, &2 integer */
	char *hdg,	    /* heading, \n delimited lines */
	char *instr,	    /* additional instructions or NULL */
	char *fld,	    /* the field itself */
	int len,	    /* field length (declare as 1 larger for \0) */
	int (*checkkey)(int)   /* routine to check non data keys, or NULL */
	)
{
   char *charptr;
   int boxwidth,titlelines,titlecol,titlerow;
   int promptcol;
   int i,j;
   char buf[81];
   helptitle(); 			  /* clear screen, display title */
   setattr(1,0,C_PROMPT_BKGRD,24*80);	  /* init rest to background */
   charptr = hdg;			  /* count title lines, find widest */
   i = boxwidth = 0;
   titlelines = 1;
   while (*charptr) {
      if (*(charptr++) == '\n') {
	 ++titlelines;
	 i = -1;
	 }
      if (++i > boxwidth)
	 boxwidth = i;
      }
   if (len > boxwidth)
      boxwidth = len;
   i = titlelines + 4;			  /* total rows in box */
   titlerow = (25 - i) / 2;		  /* top row of it all when centered */
   titlerow -= titlerow / 4;		  /* higher is better if lots extra */
   titlecol = (80 - boxwidth) / 2;	  /* center the box */
   titlecol -= (90 - boxwidth) / 20;
   promptcol = titlecol - (boxwidth-len)/2;
   j = titlecol;			  /* add margin at each side of box */
   if ((i = (82-boxwidth)/4) > 3)
      i = 3;
   j -= i;
   boxwidth += i * 2;
   for (i = -1; i < titlelines+3; ++i)	  /* draw empty box */
      setattr(titlerow+i,j,C_PROMPT_LO,boxwidth);
   textcbase = titlecol;		  /* set left margin for putstring */
   putstring(titlerow,0,C_PROMPT_HI,hdg); /* display heading */
   textcbase = 0;
   i = titlerow + titlelines + 4;
   if (instr) { 			  /* display caller's instructions */
      charptr = instr;
      j = -1;
      while ((buf[++j] = *(charptr++)))
	 if (buf[j] == '\n') {
	    buf[j] = 0;
	    putstringcenter(i++,0,80,C_PROMPT_BKGRD,buf);
	    j = -1;
	    }
      putstringcenter(i,0,80,C_PROMPT_BKGRD,buf);
      }
   else 				  /* default instructions */
      putstringcenter(i,0,80,C_PROMPT_BKGRD,
	      "Press ENTER when finished (or ESCAPE to back out)");
   return(input_field(options,C_PROMPT_INPUT,fld,len,
		      titlerow+titlelines+1,promptcol,checkkey));
}

void helptitle()
{
   char msg[80],buf[10];
   setclear(); /* clear the screen */
   sprintf(msg,"WINFRACT  Version %d.%01d",win_release/100,
       (win_release%100)/10);
   if (win_release%10) {
      sprintf(buf,"%01d",win_release%10);
      strcat(msg,buf);
      }
   putstringcenter(0,0,80,C_TITLE,msg);
/* uncomment next for production executable: */
/* return; */
   putstring(0,2,C_TITLE_DEV,"Development Version"); 
/* putstring(0,2,C_TITLE_DEV,"'Public-Beta' Release"); */
/* replace above by next after creating production release, for release source */
/* putstring(0,3,C_TITLE_DEV, "Customized Version"); */
   putstring(0,53,C_TITLE_DEV,"Not for Public Release");
}

static int screenctr=-1;
#define MAXSCREENS 3
static unsigned char far *savescreen[MAXSCREENS];
static int saverc[MAXSCREENS+1];
static FILE *savescf=NULL;
static char scsvfile[]="fractscr.tmp";

void stackscreen()
{
   extern unsigned char far wintext_chars[25][80];
   extern unsigned char far wintext_attrs[25][80];
   int savebytes;
   int i;
   unsigned char far *ptr;
   char buf[100];
   saverc[screenctr+1] = textrow*80 + textcol;
   if (++screenctr) { /* already have some stacked */
	 static char far msg[]={"stackscreen overflow"};
      if ((i = screenctr - 1) >= MAXSCREENS) { /* bug, missing unstack? */
	 stopmsg(1,msg);
	 exit(1);
	 }
      savebytes = 25*80;
      if ((ptr = savescreen[i] = farmemalloc((long)(2*savebytes)))) {
	 far_memcpy(ptr,wintext_chars,savebytes);
	 far_memcpy(ptr+savebytes,wintext_attrs,savebytes);
	 }
      else {
	    static char far msg[]={"insufficient memory, aborting"};
fileproblem:   stopmsg(1,msg);
	       exit(1);
	 }
      setclear();
      }
   else
      setfortext();
}

void unstackscreen()
{
   extern unsigned char far wintext_chars[25][80];
   extern unsigned char far wintext_attrs[25][80];
   int savebytes;
   unsigned char far *ptr;
   textrow = saverc[screenctr] / 80;
   textcol = saverc[screenctr] % 80;
   if (--screenctr >= 0) { /* unstack */
      savebytes = 25*80;
      if ((ptr = savescreen[screenctr])) {
	 far_memcpy(wintext_chars,ptr,savebytes);
	 far_memcpy(wintext_attrs,ptr+savebytes,savebytes);
         wintext_paintscreen(0,80,0,25);
	 farmemfree(ptr);
	 }
      }
   else
      setforgraphics();
   movecursor(-1,-1);
}

void discardscreen()
{
   if (--screenctr >= 0) { /* unstack */
      if (savescreen[screenctr])
	 farmemfree(savescreen[screenctr]);
      }
   else
      discardgraphics();
}

int discardgraphics()
{
}

setfortext()
{
wintext_texton();
}

setforgraphics()
{
wintext_textoff();
}

setclear()
{
extern int far wintext_buffer_init;

    wintext_buffer_init = 0;
    wintext_paintscreen(0,80,0,25);
}

int putstringcenter(int row, int col, int width, int attr, char far *msg)
{
   char buf[81];
   int i,j,k;
   i = 0;
   while (msg[i]) ++i; /* strlen for a far */
   if (i == 0) return(-1);
   j = (width - i) / 2;
   j -= (width + 10 - i) / 20; /* when wide a bit left of center looks better */
   memset(buf,' ',width);
   buf[width] = 0;
   i = 0;
   k = j;
   while (msg[i]) buf[k++] = msg[i++]; /* strcpy for a far */
   putstring(row,col,attr,buf);
   return j;
}

void putstring(int row, int col, int attr, unsigned char far *buf)
{
    extern unsigned char far wintext_chars[25][80];
    extern unsigned char far wintext_attrs[25][80];
    int i, j, k, maxrow, maxcol;
    char xc, xa;

    if (row == -1) row = textrow;
    if (col == -1) col = textcol;

    j = maxrow = row;
    k = maxcol = col-1;

    for (i = 0; (xc = buf[i]) != 0; i++) {
        if (xc == 13 || xc == 10) {
            j++;
            k = -1;
            }
        else {
            if ((++k) + textcbase >= 80) {
                j++;
                k = 0;
                }
            if (j+textrbase >= 25) j = 24-textrbase;
            if (k+textcbase >= 80) k = 79-textcbase;
            if (maxrow < j) maxrow = j;
            if (maxcol < k) maxcol = k;
            xa = (attr & 0x0ff);
            wintext_chars[j+textrbase][k+textcbase] = xc;
            wintext_attrs[j+textrbase][k+textcbase] = xa;
            }
        }
    if (i > 0) {
        textrow = j;
        textcol = k + 1;
        wintext_paintscreen(
            col+textcbase, maxcol+textcbase,
            row+textrbase, maxrow+textrbase);
        }
}

void setattr(int row, int col, int attr, int count)
{
extern unsigned char far wintext_attrs[25][80];
    int i, j, k, maxrow, maxcol;
    char xc, xa;

    j = maxrow = row;
    k = maxcol = col-1;

    xa = (attr & 0x0ff);
    for (i = 0; i < count; i++) {
        if ((++k + textcbase) >= 80) {
            j++;
            k = 0;
            }
        if (j+textrbase >= 25) j = 24-textrbase;
        if (k+textcbase >= 80) k = 79-textcbase;
        if (maxrow < j) maxrow = j;
        if (maxcol < k) maxcol = k;
        wintext_attrs[j+textrbase][k+textcbase] = xa;
        }
    if (count > 0)
        wintext_paintscreen(
            col+textcbase, maxcol+textcbase,
            row+textrbase, maxrow+textrbase);
}

void movecursor(int row, int col)
{
int cursor_type;

    cursor_type = -1;
    if (row >= 25 || col >= 80) {
        row=1;
        col=1;
        cursor_type = 0;
        }
    if (row >= 0)
        textrow = row;
    if (col >= 0)
        textcol = col;
    wintext_cursor(col, row, -1);
}

int keycursor(int row, int col)
{
int i, cursor_style;

if (row == -2 && col == -2) 
    return(fractint_getkeypress(1));

if (row == -1)
    row = textrow;
if (col == -1)
    col = textcol;

cursor_style = 1;
if (row < 0) {
    cursor_style = 2;
    row = row & 0x7fff;
    }

i = fractint_getkeypress(0);
if (i == 0)
    wintext_cursor(col, row, cursor_style);
i = fractint_getkeypress(1);
wintext_cursor(col, row, 0);

return(i);

}

/* get a "fractint-style" keystroke, with "help" sensitivity */
int fractint_getkeypress(int option)
{
int i;

restart:
    i = wintext_getkeypress(option);
    if (i == 0)
        return(i);
    /* "fractint-i-size" the keystroke */
    if (i != 0 && (i & 255) == 0)  /* function key? */
        i = (i >> 8) + 1000;
    else
        i = (i & 255);
    if (i == F1) {    /* F1  - bring up Windows-style help */
        if (option == 0) wintext_getkeypress(1);
        winfract_help();
        goto restart;
        }
    if (i == (F1+35)) {  /* Control-F1  - bring up Fractint-style help */
        if (option == 0) wintext_getkeypress(1);
        if (! in_fractint_help) {
            fractint_help();
            goto restart;
            }
        }

return(i);

}

int getakeynohelp() {
return(fractint_getkeypress(1));
}

int strncasecmp(char *s,char *t,int ct)
{
   for(; (tolower(*s) == tolower(*t)) && --ct ; s++,t++)
      if(*s == '\0')
	 return(0);
   return(tolower(*s) - tolower(*t));
}

extern char temp1[];
extern	int	colors;
extern unsigned char dacbox[256][3];
extern unsigned char olddacbox[256][3];
extern int colorstate;
extern char	colorfile[];
char mapmask[13] = {"*.map"};

void save_palette()
{
   FILE *dacfile;
   int i,oldhelpmode;
   oldhelpmode = helpmode;
   stackscreen();
   temp1[0] = 0;
   helpmode = HELPCOLORMAP;
   i = field_prompt(0,"Name of map file to write",NULL,temp1,60,NULL);
   unstackscreen();
   if (i != -1 && temp1[0]) {
      if (strchr(temp1,'.') == NULL)
	 strcat(temp1,".map");
      dacfile = fopen(temp1,"w");
      if (dacfile == NULL)
	 buzzer(2);
      else {
	 for (i = 0; i < colors; i++)
	    fprintf(dacfile, "%3d %3d %3d\n",
		    dacbox[i][0] << 2,
		    dacbox[i][1] << 2,
		    dacbox[i][2] << 2);
	 memcpy(olddacbox,dacbox,256*3);
	 colorstate = 2;
	 strcpy(colorfile,temp1);
	 }
      fclose(dacfile);
      }
   helpmode = oldhelpmode;
}


void load_palette(void)
{
   int i,oldhelpmode;
   char filename[80];
   oldhelpmode = helpmode;
   strcpy(filename,colorfile);
   stackscreen();
   helpmode = HELPCOLORMAP;
   i = getafilename("Select a MAP File",mapmask,filename);
   unstackscreen();
   if (i >= 0)
      if (ValidateLuts(filename) == 0) {
	 memcpy(olddacbox,dacbox,256*3);
	 colorstate = 2;
	 strcpy(colorfile,filename);
	 }
   helpmode = oldhelpmode;
}

void fractint_help()
{
   int i,oldhelpmode;

   in_fractint_help = 1;
   oldhelpmode = helpmode;
   helpmode = HELP_INDEX;
   help(0);
   in_fractint_help = 0;
   helpmode = oldhelpmode;
}

extern FILE *parmfile;

int win_make_batch_file()
{
   int i,numparms;
   int gotinfile;
   char outname[81],buf[256],buf2[128];
   FILE *infile;
   char colorspec[14];
   int maxcolor;
   char *sptr,*sptr2;
   extern char CommandFile[];
   extern char CommandName[];
   extern char far CommandComment1[];
   extern char far CommandComment2[];
   extern int  colorstate;
   extern int win_temp1, win_temp2;
   extern char colorfile[];
   extern int  mapset;
   extern char MAP_name[];

#ifdef WINFRACT
extern char suffix[4096];
#else
extern char dstack[4096];
#endif
   extern char boxx[8192];
   extern char s_cantopen[];
   extern char s_cantwrite[];
   extern char s_cantcreate[];
   extern char s_cantunderstand[];
   extern char s_cantfind[];

      if (strchr(CommandFile,'.') == NULL)
         strcat(CommandFile,".par"); /* default extension .par */
      if (win_temp2 > 0 && win_temp2 <= 256)
   	 maxcolor = win_temp2;
      strcpy(colorspec,"n");
      if (win_temp1 == 0) {	  /* default colors */
	 }
      else if (win_temp1 == 2) { /* colors match colorfile */
	 colorspec[0] = '@';
	 sptr = colorfile;
	 }
      else			  /* colors match no .map that we know of */
	 colorspec[0] = 'y';
      if (colorspec[0] == '@') {
	 if ((sptr2 = strrchr(sptr,'\\'))) sptr = sptr2 + 1;
	 if ((sptr2 = strrchr(sptr,':')))  sptr = sptr2 + 1;
	 strncpy(&colorspec[1],sptr,12);
	 colorspec[13] = 0;
	 }

      strcpy(outname,CommandFile);
      gotinfile = 0;
      if (access(CommandFile,0) == 0) { /* file exists */
	 gotinfile = 1;
	 if (access(CommandFile,6)) {
	    sprintf(buf,s_cantwrite,CommandFile);
	    stopmsg(0,buf);
	    return(0);
	    }
	 i = strlen(outname);
	 while (--i >= 0 && outname[i] != '\\')
	 outname[i] = 0;
	 strcat(outname,"fractint.tmp");
	 infile = fopen(CommandFile,"rt");
	 setvbuf(infile,suffix,_IOFBF,4096); /* improves speed */
	 }
      if ((parmfile = fopen(outname,"wt")) == NULL) {
	 sprintf(buf,s_cantcreate,outname);
	 stopmsg(0,buf);
	 if (gotinfile) fclose(infile);
	 return(0);
	 }

      if (gotinfile) {
	 while (file_gets(buf,255,infile) >= 0) {
	    if (strchr(buf,'{')                    /* entry heading? */
	      && sscanf(buf," %40[^ \t({]",buf2)
	      && stricmp(buf2,CommandName) == 0) { /* entry with same name */
	       sprintf(buf2,"File already has an entry named %s\n\
Continue to replace it, Cancel to back out",CommandName);
	       if (stopmsg(18,buf2) < 0) {	    /* cancel */
		  fclose(infile);
		  fclose(parmfile);
		  unlink(outname);
		  return(0);
		  }
	       while (strchr(buf,'}') == NULL
		 && file_gets(buf,255,infile) > 0 ) { } /* skip to end of set */
	       break;
	       }
	    fputs(buf,parmfile);
	    fputc('\n',parmfile);
	    }
	 }

      fprintf(parmfile,"%-19s{",CommandName);
      if (CommandComment1[0]) fprintf(parmfile," ; %Fs",CommandComment1);
      fputc('\n',parmfile);
      if (CommandComment2[0])
	 fprintf(parmfile,"                     ; %Fs\n",CommandComment2);
      write_batch_parms(parmfile,colorspec,maxcolor); /* write the parameters */
      fprintf(parmfile,"  }\n\n");

      if (gotinfile) {	/* copy the rest of the file */
	 while ((i = file_gets(buf,255,infile)) == 0) { } /* skip blanks */
	 while (i >= 0) {
	    fputs(buf,parmfile);
	    fputc('\n',parmfile);
	    i = file_gets(buf,255,infile);
	    }
	 fclose(infile);
	 }
      fclose(parmfile);
      if (gotinfile) {	/* replace the original file with the new */
	 unlink(CommandFile);	      /* success assumed on these lines       */
	 rename(outname,CommandFile); /* since we checked earlier with access */
	 }

return(1);
}
