home *** CD-ROM | disk | FTP | other *** search
/ Computerworld 1996 March / Computerworld_1996-03_cd.bin / idg_cd3 / grafika / fraktaly / frasr192 / realdos.c < prev    next >
Text File  |  1995-04-11  |  57KB  |  1,892 lines

  1. /*
  2.     Miscellaneous C routines used only in DOS Fractint.
  3. */
  4.  
  5. #include <string.h>
  6. #include <stdio.h>
  7. #ifndef XFRACT
  8. #include <dos.h>
  9. #include <io.h>
  10. #include <process.h>
  11. #endif
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <fcntl.h>
  15. #include <math.h>
  16. #include <stdlib.h>
  17. #include <ctype.h>
  18. #include "fractint.h"
  19. #include "fractype.h"
  20. #include "helpdefs.h"
  21. #include "prototyp.h"
  22.  
  23. static int menu_checkkey(int curkey,int choice);
  24.  
  25. /* uncomment following for production version */
  26. /* #define PRODUCTION */ 
  27.  
  28. int release=1920; /* this has 2 implied decimals; increment it every synch */
  29. int patchlevel=0; /* patchlevel for DOS version */
  30. #ifdef XFRACT
  31. int xrelease=300;
  32. #endif
  33.  
  34. /* fullscreen_choice options */
  35. #define CHOICERETURNKEY 1
  36. #define CHOICEMENU    2
  37. #define CHOICEHELP    4
  38. #define CHOICESCRUNCH    16
  39. #define CHOICESNOTSORTED 32
  40.  
  41. /* int stopmsg(flags,message) displays message and waits for a key:
  42.      message should be a max of 9 lines with \n's separating them;
  43.        no leading or trailing \n's in message;
  44.        no line longer than 76 chars for best appearance;
  45.      flag options:
  46.        &1 if already in text display mode, stackscreen is not called
  47.       and message is displayed at (12,0) instead of (4,0)
  48.        &2 if continue/cancel indication is to be returned;
  49.       when not set, "Any key to continue..." is displayed
  50.       when set, "Escape to cancel, any other key to continue..."
  51.       -1 is returned for cancel, 0 for continue
  52.        &4 set to suppress buzzer
  53.        &8 for Fractint for Windows & parser - use a fixed pitch font
  54.       &16 for info only message (green box instead of red in DOS vsn)
  55.    */
  56. #ifdef XFRACT   
  57. static char far s_errorstart[] = {"*** Error during startup:"};   
  58. #endif
  59. static char far s_escape_cancel[] = {"Escape to cancel, any other key to continue..."};
  60. static char far s_anykey[] = {"Any key to continue..."};
  61. #ifndef PRODUCTION
  62. static char far s_custom[] = {"Customized Version"}; 
  63. static char far s_notpublic[] = {"Not for Public Release"};
  64. #endif
  65. int stopmsg (int flags, char far *msg)
  66. {
  67.    int ret,toprow,color,savelookatmouse;
  68.    static unsigned char batchmode = 0;
  69.    if(debugflag != 0 || initbatch >= 1)
  70.    {
  71.       static FILE *fp = NULL;
  72.       if(fp==NULL && initbatch == 0)
  73.          fp=dir_fopen(workdir,"stopmsg.txt","w");
  74.       else
  75.          fp=dir_fopen(workdir,"stopmsg.txt","a");
  76.       if(fp != NULL)
  77. #ifndef XRACT
  78.       fprintf(fp,"%Fs\n",msg);
  79. #else
  80.       fprintf(fp,"%s\n",msg);
  81. #endif    
  82.       fclose(fp);
  83.    }
  84.    if (active_system == 0 /* DOS */
  85.      && first_init) {      /* & cmdfiles hasn't finished 1st try */
  86. #ifdef XFRACT
  87.       setvideotext();
  88.       buzzer(2);
  89.       putstring(0,0,15,s_errorstart);
  90.       putstring(2,0,15,msg);
  91.       movecursor(8,0);
  92.       sleep(1);
  93.       UnixDone();
  94.       exit(1);
  95. #else
  96.       printf("%Fs\n",msg);
  97.       dopause(1); /* pause deferred until after cmdfiles */
  98.       return(0);
  99. #endif
  100.       }
  101.    if (initbatch >= 1 || batchmode) { /* in batch mode */
  102.       initbatch = 4; /* used to set errorlevel */
  103.       batchmode = 1; /* fixes *second* stopmsg in batch mode bug */
  104.       return (-1);
  105.       }
  106.    ret = 0;
  107.    savelookatmouse = lookatmouse;
  108.    lookatmouse = -13;
  109.    if ((flags & 1))
  110.       blankrows(toprow=12,10,7);
  111.    else {
  112.       stackscreen();
  113.       toprow = 4;
  114.       movecursor(4,0);
  115.       }
  116.    textcbase = 2; /* left margin is 2 */
  117.    putstring(toprow,0,7,msg);
  118.    if (flags & 2)
  119.       putstring(textrow+2,0,7,s_escape_cancel);
  120.    else
  121.       putstring(textrow+2,0,7,s_anykey);
  122.    textcbase = 0; /* back to full line */
  123.    color = (flags & 16) ? C_STOP_INFO : C_STOP_ERR;
  124.    setattr(toprow,0,color,(textrow+1-toprow)*80);
  125.    movecursor(25,80);    /* cursor off */
  126.    if ((flags & 4) == 0)
  127.       buzzer((flags & 16) ? 0 : 2);
  128.    while (keypressed()) /* flush any keyahead */
  129.       getakey();
  130.    if(debugflag != 324)
  131.       if (getakeynohelp() == ESC)
  132.          ret = -1;
  133.    if ((flags & 1))
  134.       blankrows(toprow,10,7);
  135.    else
  136.       unstackscreen();
  137.    lookatmouse = savelookatmouse;
  138.    return ret;
  139. }
  140.  
  141.  
  142. static char far *temptextsave = NULL;
  143. static int  textxdots,textydots;
  144.  
  145. /* texttempmsg(msg) displays a text message of up to 40 characters, waits
  146.       for a key press, restores the prior display, and returns (without
  147.       eating the key).
  148.       It works in almost any video mode - does nothing in some very odd cases
  149.       (HCGA hi-res with old bios), or when there isn't 10k of temp mem free. */
  150. int texttempmsg(char far *msgparm)
  151. {
  152.    if (showtempmsg(msgparm))
  153.       return(-1);
  154. #ifndef XFRACT
  155.    while (!keypressed()) ; /* wait for a keystroke but don't eat it */
  156. #else
  157.    waitkeypressed(0); /* wait for a keystroke but don't eat it */
  158. #endif
  159.    cleartempmsg();
  160.    return(0);
  161. }
  162.  
  163. void freetempmsg()
  164. {
  165.    if(temptextsave != NULL)
  166.       farmemfree(temptextsave);
  167.    temptextsave = NULL;
  168. }
  169.  
  170. int showtempmsg(char far *msgparm)
  171. {
  172.    static long size = 0;
  173.    char msg[41];
  174.    BYTE buffer[640];
  175.    char far *fartmp;
  176.    BYTE far *fontptr;
  177.    BYTE *bufptr;
  178.    int i,j,k,fontchar,charnum;
  179.    int xrepeat = 0;
  180.    int yrepeat = 0;
  181.    int save_sxoffs,save_syoffs;
  182.    far_strncpy(msg,msgparm,40);
  183.    msg[40] = 0; /* ensure max message len of 40 chars */
  184.    if (dotmode == 11) { /* disk video, screen in text mode, easy */
  185.       dvid_status(0,msg);
  186.       return(0);
  187.       }
  188.    if (active_system == 0 /* DOS */
  189.      && first_init) {      /* & cmdfiles hasn't finished 1st try */
  190.       printf("%s\n",msg);
  191.       return(0);
  192.       }
  193.  
  194.    if ((fontptr = findfont(0)) == NULL) { /* old bios, no font table? */
  195.       if (oktoprint == 0           /* can't printf */
  196.     || sxdots > 640 || sydots > 200) /* not willing to trust char cell size */
  197.      return(-1); /* sorry, message not displayed */
  198.       textydots = 8;
  199.       textxdots = sxdots;
  200.       }
  201.    else {
  202.       xrepeat = (sxdots >= 640) ? 2 : 1;
  203.       yrepeat = (sydots >= 300) ? 2 : 1;
  204.       textxdots = strlen(msg) * xrepeat * 8;
  205.       textydots = yrepeat * 8;
  206.       }
  207.    /* worst case needs 10k */
  208.    if(temptextsave != NULL)
  209.       if(size != (long)textxdots * (long)textydots)
  210.          freetempmsg();
  211.    size = (long)textxdots * (long)textydots;
  212.    save_sxoffs = sxoffs;
  213.    save_syoffs = syoffs;
  214.    sxoffs = syoffs = 0;
  215.    if(temptextsave == NULL) /* only save screen first time called */
  216.    {
  217.       if ((temptextsave = farmemalloc(size)) == NULL)
  218.          return(-1); /* sorry, message not displayed */
  219.       fartmp = temptextsave;
  220.       for (i = 0; i < textydots; ++i) {
  221.          get_line(i,0,textxdots-1,buffer);
  222.          for (j = 0; j < textxdots; ++j) /* copy it out to far memory */
  223.          *(fartmp++) = buffer[j];
  224.          }
  225.       }
  226.    if (fontptr == NULL) { /* bios must do it for us */
  227.       home();
  228.       printf(msg);
  229.       }
  230.    else { /* generate the characters */
  231.       find_special_colors(); /* get color_dark & color_medium set */
  232.       for (i = 0; i < 8; ++i) {
  233.      memset(buffer,color_dark,640);
  234.      bufptr = buffer;
  235.      charnum = -1;
  236.      while (msg[++charnum] != 0) {
  237.         fontchar = *(fontptr + msg[charnum]*8 + i);
  238.         for (j = 0; j < 8; ++j) {
  239.            for (k = 0; k < xrepeat; ++k) {
  240.           if ((fontchar & 0x80) != 0)
  241.              *bufptr = (BYTE)color_medium;
  242.           ++bufptr;
  243.           }
  244.            fontchar <<= 1;
  245.            }
  246.         }
  247.      for (j = 0; j < yrepeat; ++j)
  248.         put_line(i*yrepeat+j,0,textxdots-1,buffer);
  249.      }
  250.       }
  251.    sxoffs = save_sxoffs;
  252.    syoffs = save_syoffs;
  253.    return(0);
  254. }
  255.  
  256. void cleartempmsg()
  257. {
  258.    BYTE buffer[640];
  259.    char far *fartmp;
  260.    int i,j;
  261.    int save_sxoffs,save_syoffs;
  262.    if (dotmode == 11) /* disk video, easy */
  263.       dvid_status(0,"");
  264.    else if (temptextsave != NULL) {
  265.       save_sxoffs = sxoffs;
  266.       save_syoffs = syoffs;
  267.       sxoffs = syoffs = 0;
  268.       fartmp = temptextsave;
  269.       for (i = 0; i < textydots; ++i) {
  270.      for (j = 0; j < textxdots; ++j) /* copy back from far memory */
  271.         buffer[j] = *(fartmp++);
  272.      put_line(i,0,textxdots-1,buffer);
  273.      }
  274.      if(using_jiim == 0)  /* jiim frees memory with freetempmsg() */
  275.      {
  276.          farmemfree(temptextsave);
  277.          temptextsave = NULL;
  278.       }
  279.       sxoffs = save_sxoffs;
  280.       syoffs = save_syoffs;
  281.       }
  282. }
  283.  
  284.  
  285. void blankrows(int row,int rows,int attr)
  286. {
  287.    char buf[81];
  288.    memset(buf,' ',80);
  289.    buf[80] = 0;
  290.    while (--rows >= 0)
  291.       putstring(row++,0,attr,buf);
  292.    }
  293.  
  294.  
  295. void helptitle()
  296. {
  297.    char msg[80],buf[80];
  298.    setclear(); /* clear the screen */
  299. #ifdef XFRACT
  300.    sprintf(msg,"XFRACTINT  Version %d.%02d (FRACTINT Version %d.%02d)",
  301.            xrelease/100,xrelease%100, release/100,release%100);
  302.    putstringcenter(0,0,80,C_TITLE,msg);
  303. #else
  304. #ifdef WAITE
  305.    release=1900;
  306.    patchlevel = 0;
  307. #endif
  308.    sprintf(msg,"FRACTINT Version %d.%01d",release/100,(release%100)/10);
  309.    if (release%10) {
  310.       sprintf(buf,"%01d",release%10);
  311.       strcat(msg,buf);
  312.       }
  313. #ifndef XFRACT
  314.    if (patchlevel) {
  315.       sprintf(buf," Patch %d",patchlevel);
  316.       strcat(msg,buf);
  317.       }
  318. #endif
  319. #if 0 /*WAITE*/ /* realdos.c */
  320.    strcat(msg," for the Waite Group's Image Lab 2nd Edition");
  321. #endif /* WAITE - realdos.c */
  322.    putstringcenter(0,0,80,C_TITLE,msg);
  323. #ifdef WAITE
  324.    return;
  325. #endif
  326. #endif
  327. /* uncomment next for production executable: */
  328. #ifdef PRODUCTION
  329.     return;
  330.    /*NOTREACHED*/
  331. #else   
  332.    if (debugflag == 3002) return;
  333. #ifdef DEVELOPMENT   
  334.    putstring(0,2,C_TITLE_DEV,"Development Version"); 
  335. #else
  336.    putstring(0,3,C_TITLE_DEV, s_custom); 
  337. #endif   
  338.    putstring(0,55,C_TITLE_DEV,s_notpublic);
  339. #endif
  340. }
  341.  
  342.  
  343. int putstringcenter(int row, int col, int width, int attr, char far *msg)
  344. {
  345.    char buf[81];
  346.    int i,j,k;
  347.    i = 0;
  348. #ifdef XFRACT
  349.    if (width==80) width=79; /* Some systems choke in column 80 */
  350. #endif
  351.    while (msg[i]) ++i; /* strlen for a far */
  352.    if (i == 0) return(-1);
  353.    j = (width - i) / 2;
  354.    j -= (width + 10 - i) / 20; /* when wide a bit left of center looks better */
  355.    memset(buf,' ',width);
  356.    buf[width] = 0;
  357.    i = 0;
  358.    k = j;
  359.    while (msg[i]) buf[k++] = msg[i++]; /* strcpy for a far */
  360.    putstring(row,col,attr,buf);
  361.    return j;
  362. }
  363.  
  364.  
  365. #ifndef XFRACT
  366. static int screenctr = -1;
  367. #else
  368. static int screenctr = 0;
  369. #endif
  370. #define MAXSCREENS 3
  371. static BYTE far *savescreen[MAXSCREENS];
  372. static int saverc[MAXSCREENS+1];
  373. static FILE *savescf = NULL;
  374. static char scsvfile[]="fractscr.tmp";
  375.  
  376. void stackscreen()
  377. {
  378. #ifndef XFRACT
  379.    BYTE far *vidmem;
  380.    int savebytes;
  381.    int i;
  382.    BYTE far *ptr;
  383.    char buf[256];
  384.    memcpy(buf,suffix,256);
  385.    saverc[screenctr+1] = textrow*80 + textcol;
  386.    if (++screenctr) { /* already have some stacked */
  387.      static char far msg[]={"stackscreen overflow"};
  388.       if ((i = screenctr - 1) >= MAXSCREENS) { /* bug, missing unstack? */
  389.      stopmsg(1,msg);
  390.      exit(1);
  391.      }
  392.       vidmem = MK_FP(textaddr,0);
  393.       savebytes = (text_type == 0) ? 4000 : 16384;
  394.       if ((ptr = savescreen[i] = farmemalloc((long)savebytes)) != NULL)
  395.      far_memcpy(ptr,vidmem,savebytes);
  396.       else {
  397.      if (savescf == NULL) { /* create file just once */
  398.         if ((savescf = dir_fopen(tempdir,scsvfile,"wb")) == NULL)
  399.            goto fileproblem;
  400.         if (fwrite(buf,MAXSCREENS,16384,savescf) != 16384)
  401.            goto fileproblem;
  402.         fclose(savescf);
  403.         if ((savescf = dir_fopen(tempdir,scsvfile,"r+b")) == NULL) {
  404.         static char far msg[]={"insufficient memory, aborting"};
  405. fileproblem:   stopmsg(1,msg);
  406.            exit(1);
  407.            }
  408.         }
  409.      fseek(savescf,(long)(savebytes*i),SEEK_SET);
  410.      while (--savebytes >= 0)
  411.         putc(*(vidmem++),savescf);
  412.      }
  413.       setclear();
  414.       }
  415.    else
  416.       setfortext();
  417.    memcpy(suffix,buf,256);
  418. #else
  419.    int i;
  420.    BYTE far *ptr;
  421.    saverc[screenctr+1] = textrow*80 + textcol;
  422.    if (++screenctr) { /* already have some stacked */
  423.          static char far msg[]={"stackscreen overflow"};
  424.       if ((i = screenctr - 1) >= MAXSCREENS) { /* bug, missing unstack? */
  425.          stopmsg(1,msg);
  426.          exit(1);
  427.          }
  428.       if (ptr = savescreen[i] = farmemalloc(sizeof(int *)))
  429.          savecurses(ptr);
  430.       else {
  431.          stopmsg(1,msg);
  432.          exit(1);
  433.         }
  434.       setclear();
  435.       }
  436.    else
  437.       setfortext();
  438. #endif
  439. }
  440.  
  441. void unstackscreen()
  442. {
  443. #ifndef XFRACT
  444.    char far *vidmem;
  445.    int savebytes;
  446.    BYTE far *ptr;
  447.    char buf[256];
  448.    memcpy(buf,suffix,256);
  449.    textrow = saverc[screenctr] / 80;
  450.    textcol = saverc[screenctr] % 80;
  451.    if (--screenctr >= 0) { /* unstack */
  452.       vidmem = MK_FP(textaddr,0);
  453.       savebytes = (text_type == 0) ? 4000 : 16384;
  454.       if ((ptr = savescreen[screenctr]) != NULL) {
  455.      far_memcpy(vidmem,ptr,savebytes);
  456.      farmemfree(ptr);
  457.      }
  458.       else {
  459.      fseek(savescf,(long)(savebytes*screenctr),SEEK_SET);
  460.      while (--savebytes >= 0)
  461.         *(vidmem++) = (BYTE)getc(savescf);
  462.      }
  463.       }
  464.    else
  465.       setforgraphics();
  466.    movecursor(-1,-1);
  467.    memcpy(suffix,buf,256);
  468. #else
  469.    BYTE far *ptr;
  470.    textrow = saverc[screenctr] / 80;
  471.    textcol = saverc[screenctr] % 80;
  472.    if (--screenctr >= 0) { /* unstack */
  473.       ptr = savescreen[screenctr];
  474.       restorecurses(ptr);
  475.       farmemfree(ptr);
  476.       }
  477.    else
  478.       setforgraphics();
  479.    movecursor(-1,-1);
  480. #endif
  481. }
  482.  
  483. void discardscreen()
  484. {
  485.    if (--screenctr >= 0) { /* unstack */
  486.       if (savescreen[screenctr])
  487.      farmemfree(savescreen[screenctr]);
  488.       }
  489.    else
  490.       discardgraphics();
  491. }
  492.  
  493.  
  494. /* ------------------------------------------------------------------------ */
  495.  
  496. char speed_prompt[]="Speed key string";
  497.  
  498. int fullscreen_choice(
  499.     int options,              /* &2 use menu coloring scheme            */
  500.                                   /* &4 include F1 for help in instructions */
  501.                                   /* &8 add caller's instr after normal set */
  502.                                   /* &16 menu items up one line             */
  503.     char far *hdg,              /* heading info, \n delimited             */
  504.     char far *hdg2,              /* column heading or NULL                 */
  505.     char far *instr,              /* instructions, \n delimited, or NULL    */
  506.     int numchoices,               /* How many choices in list               */
  507.     char far*far*choices,         /* array of choice strings                */
  508.     int far *attributes,          /* &3: 0 normal color, 1,3 highlight      */
  509.                                   /* &256 marks a dummy entry               */
  510.     int boxwidth,              /* box width, 0 for calc (in items)       */
  511.     int boxdepth,              /* box depth, 0 for calc, 99 for max      */
  512.     int colwidth,              /* data width of a column, 0 for calc     */
  513.     int current,                  /* start with this item                   */
  514.     void (*formatitem)(int,char*),/* routine to display an item or NULL     */
  515.     char *speedstring,            /* returned speed key value, or NULL      */
  516.     int (*speedprompt)(int,int,int,char *,int),/* routine to display prompt or NULL      */
  517.     int (*checkkey)(int,int)      /* routine to check keystroke or NULL     */
  518. )
  519.     /* return is: n>=0 for choice n selected,
  520.                   -1 for escape
  521.                   k for checkkey routine return value k (if not 0 nor -1)
  522.                   speedstring[0] != 0 on return if string is present
  523.     */
  524. {
  525. static char far choiceinstr1a[]="Use the cursor keys to highlight your selection";
  526. static char far choiceinstr1b[]="Use the cursor keys or type a value to make a selection";
  527. static char far choiceinstr2a[]="Press ENTER for highlighted choice, or ESCAPE to back out";
  528. static char far choiceinstr2b[]="Press ENTER for highlighted choice, ESCAPE to back out, or F1 for help";
  529. static char far choiceinstr2c[]="Press ENTER for highlighted choice, or F1 for help";
  530.  
  531.    int titlelines,titlewidth;
  532.    int reqdrows;
  533.    int topleftrow,topleftcol;
  534.    int topleftchoice;
  535.    int speedrow = 0;  /* speed key prompt */
  536.    int boxitems;      /* boxwidth*boxdepth */
  537.    int curkey,increment,rev_increment = 0;
  538.    int redisplay;
  539.    int i,j,k = 0;
  540.    char far *charptr;
  541.    char buf[81];
  542.    int speed_match = 0;
  543.    char curitem[81];
  544.    char far *itemptr;
  545.    int ret,savelookatmouse;
  546.    int scrunch;  /* scrunch up a line */
  547.  
  548.    if(options&CHOICESCRUNCH)
  549.       scrunch = 1;
  550.    else
  551.       scrunch = 0;
  552.    savelookatmouse = lookatmouse;
  553.    lookatmouse = 0;
  554.    ret = -1;
  555.    if (speedstring
  556.      && (i = strlen(speedstring)) > 0) { /* preset current to passed string */
  557.       current = 0;
  558.       if(options&CHOICESNOTSORTED)
  559.       { 
  560.          while (current < numchoices
  561.          && (k = strncasecmp(speedstring,choices[current],i)) != 0)
  562.         ++current;
  563.          if(k != 0)
  564.             current = 0;
  565.       }
  566.       else
  567.       {
  568.          while (current < numchoices
  569.          && (k = strncasecmp(speedstring,choices[current],i)) > 0)
  570.         ++current;
  571.          if (k < 0 && current > 0)  /* oops - overshot */
  572.         --current;
  573.       }
  574.       if (current >= numchoices) /* bumped end of list */
  575.      current = numchoices - 1;
  576.    }
  577.  
  578.    for(;;) {
  579.       if (current >= numchoices)  /* no real choice in the list? */
  580.      goto fs_choice_end;
  581.       if ((attributes[current] & 256) == 0)
  582.      break;
  583.       ++current;          /* scan for a real choice */
  584.       }
  585.  
  586.    titlelines = titlewidth = 0;
  587.    if (hdg) {
  588.       charptr = hdg;          /* count title lines, find widest */
  589.       i = 0;
  590.       titlelines = 1;
  591.       while (*charptr) {
  592.      if (*(charptr++) == '\n') {
  593.         ++titlelines;
  594.         i = -1;
  595.         }
  596.      if (++i > titlewidth)
  597.         titlewidth = i;
  598.      }
  599.       }
  600.  
  601.    if (colwidth == 0)          /* find widest column */
  602.       for (i = 0; i < numchoices; ++i)
  603.       {
  604.          int len;
  605.      if ((len=far_strlen(choices[i])) > colwidth)
  606.         colwidth = len;
  607.       }
  608.    /* title(1), blank(1), hdg(n), blank(1), body(n), blank(1), instr(?) */
  609.    reqdrows = 3 - scrunch;          /* calc rows available */
  610.    if (hdg)
  611.       reqdrows += titlelines + 1;
  612.    if (instr) {           /* count instructions lines */
  613.       charptr = instr;
  614.       ++reqdrows;
  615.       while (*charptr)
  616.      if (*(charptr++) == '\n')
  617.         ++reqdrows;
  618.       if ((options & 8))      /* show std instr too */
  619.      reqdrows += 2;
  620.       }
  621.    else
  622.       reqdrows += 2;          /* standard instructions */
  623.    if (speedstring) ++reqdrows;   /* a row for speedkey prompt */
  624.    if (boxdepth > (i = 25 - reqdrows)) /* limit the depth to max */
  625.       boxdepth = i;
  626.    if (boxwidth == 0) {       /* pick box width and depth */
  627.       if (numchoices <= i - 2) {  /* single column is 1st choice if we can */
  628.      boxdepth = numchoices;
  629.      boxwidth = 1;
  630.      }
  631.       else {              /* sort-of-wide is 2nd choice */
  632.      boxwidth = 60 / (colwidth + 1);
  633.      if (boxwidth == 0
  634.        || (boxdepth = (numchoices+boxwidth-1)/boxwidth) > i - 2) {
  635.         boxwidth = 80 / (colwidth + 1); /* last gasp, full width */
  636.         if ((boxdepth = (numchoices+boxwidth-1)/boxwidth) > i)
  637.            boxdepth = i;
  638.         }
  639.      }
  640.       }
  641.    if ((i = 77 / boxwidth - colwidth) > 3) /* spaces to add @ left each choice */
  642.       i = 3;
  643.    j = boxwidth * (colwidth += i) + i;       /* overall width of box */
  644.    if (j < titlewidth+2)
  645.       j = titlewidth + 2;
  646.    if (j > 80)
  647.       j = 80;
  648.    if (j <= 70 && boxwidth == 2) {       /* special case makes menus nicer */
  649.       ++j;
  650.       ++colwidth;
  651.       }
  652.    k = (80 - j) / 2;               /* center the box */
  653.    k -= (90 - j) / 20;
  654.    topleftcol = k + i;               /* column of topleft choice */
  655.    i = (25 - reqdrows - boxdepth) / 2;
  656.    i -= i / 4;                   /* higher is better if lots extra */
  657.    topleftrow = 3 + titlelines + i;       /* row of topleft choice */
  658.     
  659.    /* now set up the overall display */
  660.    helptitle();                /* clear, display title line */
  661.    setattr(1,0,C_PROMPT_BKGRD,24*80);       /* init rest to background */
  662.    for (i = topleftrow-1-titlelines; i < topleftrow+boxdepth+1; ++i)
  663.       setattr(i,k,C_PROMPT_LO,j);       /* draw empty box */
  664.    if (hdg) {
  665.       textcbase = (80 - titlewidth) / 2;   /* set left margin for putstring */
  666.       textcbase -= (90 - titlewidth) / 20; /* put heading into box */
  667.       putstring(topleftrow-titlelines-1,0,C_PROMPT_HI,hdg);
  668.       textcbase = 0;
  669.       }
  670.    if (hdg2)                   /* display 2nd heading */
  671.       putstring(topleftrow-1,topleftcol,C_PROMPT_MED,hdg2);
  672.    i = topleftrow + boxdepth + 1;
  673.    if (instr == NULL || (options & 8)) {   /* display default instructions */
  674.       if (i < 20) ++i;
  675.       if (speedstring) {
  676.      speedrow = i;
  677.      *speedstring = 0;
  678.      if (++i < 22) ++i;
  679.      }
  680.       i -= scrunch;
  681.       putstringcenter(i++,0,80,C_PROMPT_BKGRD,
  682.         (speedstring) ? choiceinstr1b : choiceinstr1a);
  683.       putstringcenter(i++,0,80,C_PROMPT_BKGRD,
  684.         (options&CHOICEMENU) ? choiceinstr2c
  685.         : ((options&CHOICEHELP) ? choiceinstr2b : choiceinstr2a));
  686.       }
  687.    if (instr) {                /* display caller's instructions */
  688.       charptr = instr;
  689.       j = -1;
  690.       while ((buf[++j] = *(charptr++)) != 0)
  691.      if (buf[j] == '\n') {
  692.         buf[j] = 0;
  693.         putstringcenter(i++,0,80,C_PROMPT_BKGRD,buf);
  694.         j = -1;
  695.         }
  696.       putstringcenter(i,0,80,C_PROMPT_BKGRD,buf);
  697.       }
  698.  
  699.    boxitems = boxwidth * boxdepth;
  700.    topleftchoice = 0;               /* pick topleft for init display */
  701.    while (current - topleftchoice >= boxitems
  702.      || (current - topleftchoice > boxitems/2
  703.      && topleftchoice + boxitems < numchoices))
  704.       topleftchoice += boxwidth;
  705.    redisplay = 1;
  706.    topleftrow -= scrunch;
  707.    for(;;) { /* main loop */
  708.  
  709.       if (redisplay) {                 /* display the current choices */
  710.      if ((options & CHOICEMENU) == 0) {
  711.         memset(buf,' ',80);
  712.         buf[boxwidth*colwidth] = 0;
  713.         for (i = (hdg2) ? 0 : -1; i <= boxdepth; ++i)  /* blank the box */
  714.            putstring(topleftrow+i,topleftcol,C_PROMPT_LO,buf);
  715.         }
  716.      for (i = 0; i+topleftchoice < numchoices && i < boxitems; ++i) {
  717.         /* display the choices */
  718.         if ((k = attributes[j = i+topleftchoice] & 3) == 1)
  719.            k = C_PROMPT_LO;
  720.         else if (k == 3)
  721.            k = C_PROMPT_HI;
  722.         else
  723.            k = C_PROMPT_MED;
  724.         if (formatitem)
  725.         {
  726.            (*formatitem)(j,buf);
  727.            charptr=buf;
  728.         }   
  729.         else
  730.            charptr = choices[j];
  731.         putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
  732.               k,charptr);
  733.         }
  734.      /***
  735.      ... format differs for summary/detail, whups, force box width to
  736.      ...  be 72 when detail toggle available?  (2 grey margin each
  737.      ...  side, 1 blue margin each side)
  738.      ***/
  739.      if (topleftchoice > 0 && hdg2 == NULL)
  740.         putstring(topleftrow-1,topleftcol,C_PROMPT_LO,"(more)");
  741.      if (topleftchoice + boxitems < numchoices)
  742.         putstring(topleftrow+boxdepth,topleftcol,C_PROMPT_LO,"(more)");
  743.      redisplay = 0;
  744.      }
  745.  
  746.       i = current - topleftchoice;         /* highlight the current choice */
  747.       if (formatitem)
  748.       {
  749.      (*formatitem)(current,curitem);
  750.      itemptr=curitem;
  751.       }
  752.       else
  753.      itemptr = choices[current];
  754.       putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
  755.         C_CHOICE_CURRENT,itemptr);
  756.  
  757.       if (speedstring) {             /* show speedstring if any */
  758.      memset(buf,' ',80);
  759.      buf[80] = 0;
  760.      putstring(speedrow,0,C_PROMPT_BKGRD,buf);
  761.      if (*speedstring) {             /* got a speedstring on the go */
  762.         putstring(speedrow,15,C_CHOICE_SP_INSTR," ");
  763.         if (speedprompt)
  764.            j = speedprompt(speedrow,16,C_CHOICE_SP_INSTR,speedstring,speed_match);
  765.         else {
  766.            putstring(speedrow,16,C_CHOICE_SP_INSTR,speed_prompt);
  767.            j = strlen(speed_prompt);
  768.            }
  769.         strcpy(buf,speedstring);
  770.         i = strlen(buf);
  771.         while (i < 30)
  772.            buf[i++] = ' ';
  773.         buf[i] = 0;
  774.         putstring(speedrow,16+j,C_CHOICE_SP_INSTR," ");
  775.         putstring(speedrow,17+j,C_CHOICE_SP_KEYIN,buf);
  776.         movecursor(speedrow,17+j+strlen(speedstring));
  777.         }
  778.      else
  779.         movecursor(25,80);
  780.      }
  781.       else
  782.      movecursor(25,80);
  783.  
  784. #ifndef XFRACT
  785.       while (!keypressed()) { } /* enables help */
  786. #else
  787.       waitkeypressed(0); /* enables help */
  788. #endif
  789.       curkey = getakey();
  790. #ifdef XFRACT
  791.       if (curkey==F10) curkey=')';
  792.       if (curkey==F9) curkey='(';
  793.       if (curkey==F8) curkey='*';
  794. #endif
  795.  
  796.       i = current - topleftchoice;         /* unhighlight current choice */
  797.       if ((k = attributes[current] & 3) == 1)
  798.      k = C_PROMPT_LO;
  799.       else if (k == 3)
  800.      k = C_PROMPT_HI;
  801.       else
  802.      k = C_PROMPT_MED;
  803.       putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
  804.         k,itemptr);
  805.  
  806.       increment = 0;
  807.       switch (curkey) {              /* deal with input key */
  808.      case ENTER:
  809.      case ENTER_2:
  810.         ret = current;
  811.         goto fs_choice_end;
  812.      case ESC:
  813.         goto fs_choice_end;
  814.      case DOWN_ARROW:
  815.      case DOWN_ARROW_2:
  816.         rev_increment = 0 - (increment = boxwidth);
  817.         break;
  818.      case UP_ARROW:
  819.      case UP_ARROW_2:
  820.         increment = 0 - (rev_increment = boxwidth);
  821.         break;
  822.      case RIGHT_ARROW:
  823.      case RIGHT_ARROW_2:
  824.         if (boxwidth == 1) break;
  825.         increment = 1; rev_increment = -1;
  826.         break;
  827.      case LEFT_ARROW:
  828.      case LEFT_ARROW_2:
  829.         if (boxwidth == 1) break;
  830.         increment = -1; rev_increment = 1;
  831.         break;
  832.      case PAGE_UP:
  833.         if (numchoices > boxitems) {
  834.            topleftchoice -= boxitems;
  835.            increment = -boxitems;
  836.            rev_increment = boxwidth;
  837.            redisplay = 1;
  838.            }
  839.         break;
  840.      case PAGE_DOWN:
  841.         if (numchoices > boxitems) {
  842.            topleftchoice += boxitems;
  843.            increment = boxitems;
  844.            rev_increment = -boxwidth;
  845.            redisplay = 1;
  846.            }
  847.         break;
  848.      case CTL_HOME:
  849.      case HOME:
  850.         current = -1;
  851.         increment = rev_increment = 1;
  852.         break;
  853.      case CTL_END:
  854.      case END:
  855.         current = numchoices;
  856.         increment = rev_increment = -1;
  857.         break;
  858.      default:
  859.         if (checkkey) {
  860.            if ((ret = (*checkkey)(curkey,current)) < -1 || ret > 0)
  861.           goto fs_choice_end;
  862.            if (ret == -1)
  863.           redisplay = -1;
  864.            }
  865.         ret = -1;
  866.         if (speedstring) {
  867.            i = strlen(speedstring);
  868.            if (curkey == 8 && i > 0) /* backspace */
  869.           speedstring[--i] = 0;
  870.            if (33 <= curkey && curkey <= 126 && i < 30) {
  871.           curkey = tolower(curkey);
  872.           speedstring[i] = (char)curkey;
  873.           speedstring[++i] = 0;
  874.           }
  875.            if (i > 0) {         /* locate matching type */
  876.           current = 0;
  877.           while (current < numchoices
  878.             && (speed_match = strncasecmp(speedstring,choices[current],i)) > 0)
  879.              ++current;
  880.           if (speed_match < 0 && current > 0)  /* oops - overshot */
  881.              --current;
  882.           if (current >= numchoices) /* bumped end of list */
  883.              current = numchoices - 1;
  884.           }
  885.            }
  886.         break;
  887.      }
  888.  
  889.       if (increment) {            /* apply cursor movement */
  890.      current += increment;
  891.      if (speedstring)        /* zap speedstring */
  892.         speedstring[0] = 0;
  893.      }
  894.       for(;;) {            /* adjust to a non-comment choice */
  895.      if (current < 0 || current >= numchoices)
  896.          increment = rev_increment;
  897.      else if ((attributes[current] & 256) == 0)
  898.          break;
  899.      current += increment;
  900.      }
  901.       if (topleftchoice > numchoices - boxitems)
  902.      topleftchoice = ((numchoices+boxwidth-1)/boxwidth)*boxwidth - boxitems;
  903.       if (topleftchoice < 0)
  904.      topleftchoice = 0;
  905.       while (current < topleftchoice) {
  906.      topleftchoice -= boxwidth;
  907.      redisplay = 1;
  908.      }
  909.       while (current >= topleftchoice + boxitems) {
  910.      topleftchoice += boxwidth;
  911.      redisplay = 1;
  912.      }
  913.       }
  914.  
  915. fs_choice_end:
  916.    lookatmouse = savelookatmouse;
  917.    return(ret);
  918.  
  919. }
  920.  
  921. #if (_MSC_VER >= 700)
  922. #pragma code_seg ("realdos1_text")     /* place following in an overlay */
  923. #endif
  924.  
  925. /* squeeze space out of string */
  926. char *despace(char *str)
  927. {
  928.       char *obuf, *nbuf;
  929.  
  930.       for (obuf = str, nbuf = str; *obuf && obuf; ++obuf)
  931.       {
  932.             if (!isspace(*obuf))
  933.                   *nbuf++ = *obuf;
  934.       }
  935.       *nbuf = 0;
  936.       return str;
  937. }
  938.  
  939. #ifndef XFRACT
  940. /* case independent version of strncmp */
  941. int strncasecmp(char far *s,char far *t,int ct)
  942. {
  943.    for(; (tolower(*s) == tolower(*t)) && --ct ; s++,t++)
  944.       if(*s == '\0')
  945.      return(0);
  946.    return(tolower(*s) - tolower(*t));
  947. }
  948. #endif
  949.  
  950. #define LOADPROMPTSCHOICES(X,Y)     {\
  951.    static FCODE tmp[] = { Y };\
  952.    choices[X]= (char far *)tmp;\
  953.    }
  954.  
  955. static int menutype;
  956. #define MENU_HDG 3
  957. #define MENU_ITEM 1
  958.  
  959. int main_menu(int fullmenu)
  960. {
  961.    char far *choices[44]; /* 2 columns * 22 rows */
  962.    int attributes[44];
  963.    int choicekey[44];
  964.    int i;
  965.    int nextleft,nextright;
  966.    int oldtabmode /* ,oldhelpmode */;
  967.    static char far MAIN_MENU[] = {"MAIN MENU"};
  968.    int showjuliatoggle; 
  969.    oldtabmode = tabmode;
  970.    /* oldhelpmode = helpmode; */
  971. top:
  972.    menutype = fullmenu;
  973.    tabmode = 0;
  974.    showjuliatoggle = 0;
  975.    for (i = 0; i < 44; ++i) {
  976.       attributes[i] = 256;
  977.       choices[i] = "";
  978.       choicekey[i] = -1;
  979.       }
  980.    nextleft = -2;
  981.    nextright = -1;
  982.  
  983.    if (fullmenu) {
  984.       LOADPROMPTSCHOICES(nextleft+=2,"      CURRENT IMAGE");
  985.       attributes[nextleft] = 256+MENU_HDG;
  986.       choicekey[nextleft+=2] = 13; /* enter */
  987.       attributes[nextleft] = MENU_ITEM;
  988.       if (calc_status == 2)
  989.       {
  990.      LOADPROMPTSCHOICES(nextleft,"continue calculation");
  991.       }
  992.       else
  993.       {
  994.      LOADPROMPTSCHOICES(nextleft,"return to image");
  995.       }
  996.       choicekey[nextleft+=2] = 9; /* tab */
  997.       attributes[nextleft] = MENU_ITEM;
  998.       LOADPROMPTSCHOICES(nextleft,"info about image      <tab>");
  999.       choicekey[nextleft+=2] = -10;
  1000.       attributes[nextleft] = MENU_ITEM;
  1001.       LOADPROMPTSCHOICES(nextleft,"zoom box functions...");
  1002.       choicekey[nextleft+=2] = 'o';
  1003.       attributes[nextleft] = MENU_ITEM;
  1004.       LOADPROMPTSCHOICES(nextleft,"orbits window          <o>");
  1005.       if(!(fractype==JULIA || fractype==JULIAFP || fractype==INVERSEJULIA))
  1006.           nextleft+=2; 
  1007.       }
  1008.    LOADPROMPTSCHOICES(nextleft+=2,"      NEW IMAGE");
  1009.    attributes[nextleft] = 256+MENU_HDG;
  1010.    choicekey[nextleft+=2] = DELETE;
  1011.    attributes[nextleft] = MENU_ITEM;
  1012.    LOADPROMPTSCHOICES(nextleft,"select video mode...  <del>");
  1013.    choicekey[nextleft+=2] = 't';
  1014.    attributes[nextleft] = MENU_ITEM;
  1015.    LOADPROMPTSCHOICES(nextleft,"select fractal type    <t>");
  1016.    if (fullmenu) {
  1017.       if ((curfractalspecific->tojulia != NOFRACTAL
  1018.       && param[0] == 0.0 && param[1] == 0.0)
  1019.       || curfractalspecific->tomandel != NOFRACTAL) {
  1020.          choicekey[nextleft+=2] = ' ';
  1021.          attributes[nextleft] = MENU_ITEM;
  1022.          LOADPROMPTSCHOICES(nextleft,"toggle to/from julia <space>");
  1023.              showjuliatoggle = 1;
  1024.       }    
  1025.       if(fractype==JULIA || fractype==JULIAFP || fractype==INVERSEJULIA) {
  1026.          choicekey[nextleft+=2] = 'j';
  1027.          attributes[nextleft] = MENU_ITEM;
  1028.          LOADPROMPTSCHOICES(nextleft,"toggle to/from inverse <j>");
  1029.          showjuliatoggle = 1;
  1030.       }
  1031.       choicekey[nextleft+=2] = 'h';
  1032.       attributes[nextleft] = MENU_ITEM;
  1033.       LOADPROMPTSCHOICES(nextleft,"return to prior image  <h>");
  1034.  
  1035.       choicekey[nextleft+=2] = 8;
  1036.       attributes[nextleft] = MENU_ITEM;
  1037.       LOADPROMPTSCHOICES(nextleft,"reverse thru history <ctl-h>");
  1038.    }
  1039.    else
  1040.       nextleft += 2;
  1041.    LOADPROMPTSCHOICES(nextleft+=2,"      OPTIONS");
  1042.    attributes[nextleft] = 256+MENU_HDG;
  1043.    choicekey[nextleft+=2] = 'x';
  1044.    attributes[nextleft] = MENU_ITEM;
  1045.    LOADPROMPTSCHOICES(nextleft,"basic options...       <x>");
  1046.    choicekey[nextleft+=2] = 'y';
  1047.    attributes[nextleft] = MENU_ITEM;
  1048.    LOADPROMPTSCHOICES(nextleft,"extended options...    <y>");
  1049.    choicekey[nextleft+=2] = 'z';
  1050.    attributes[nextleft] = MENU_ITEM;
  1051.    LOADPROMPTSCHOICES(nextleft,"type-specific parms... <z>");
  1052.    choicekey[nextleft+=2] = 'v';
  1053.    attributes[nextleft] = MENU_ITEM;
  1054.    LOADPROMPTSCHOICES(nextleft,"view window options... <v>");
  1055.    if(showjuliatoggle == 0)
  1056.    {
  1057.       choicekey[nextleft+=2] = 'i';
  1058.       attributes[nextleft] = MENU_ITEM;
  1059.       LOADPROMPTSCHOICES(nextleft,"fractal 3D parms...    <i>");
  1060.    }
  1061.    choicekey[nextleft+=2] = 2;
  1062.    attributes[nextleft] = MENU_ITEM;
  1063.    LOADPROMPTSCHOICES(nextleft,"browse parms...      <ctl-b>");
  1064.  
  1065.    LOADPROMPTSCHOICES(nextright+=2,"        FILE");
  1066.    attributes[nextright] = 256+MENU_HDG;
  1067.    choicekey[nextright+=2] = '@';
  1068.    attributes[nextright] = MENU_ITEM;
  1069.    LOADPROMPTSCHOICES(nextright,"run saved command set... <@>");
  1070.    if (fullmenu) {
  1071.       choicekey[nextright+=2] = 's';
  1072.       attributes[nextright] = MENU_ITEM;
  1073.       LOADPROMPTSCHOICES(nextright,"save image to file       <s>");
  1074.       }
  1075.    choicekey[nextright+=2] = 'r';
  1076.    attributes[nextright] = MENU_ITEM;
  1077.    LOADPROMPTSCHOICES(nextright,"load image from file...  <r>");
  1078.    choicekey[nextright+=2] = '3';
  1079.    attributes[nextright] = MENU_ITEM;
  1080.    LOADPROMPTSCHOICES(nextright,"3d transform from file...<3>");
  1081.    if (fullmenu) {
  1082.       choicekey[nextright+=2] = '#';
  1083.       attributes[nextright] = MENU_ITEM;
  1084.       LOADPROMPTSCHOICES(nextright,"3d overlay from file.....<#>");
  1085.       choicekey[nextright+=2] = 'b';
  1086.       attributes[nextright] = MENU_ITEM;
  1087.       LOADPROMPTSCHOICES(nextright,"save current parameters..<b>");
  1088.       choicekey[nextright+=2] = 'p';
  1089.       attributes[nextright] = MENU_ITEM;
  1090.       LOADPROMPTSCHOICES(nextright,"print image              <p>");
  1091.       }
  1092.    choicekey[nextright+=2] = 'd';
  1093.    attributes[nextright] = MENU_ITEM;
  1094.    LOADPROMPTSCHOICES(nextright,"shell to dos             <d>");
  1095.    choicekey[nextright+=2] = 'g';
  1096.    attributes[nextright] = MENU_ITEM;
  1097.    LOADPROMPTSCHOICES(nextright,"give command string      <g>");
  1098.    choicekey[nextright+=2] = ESC;
  1099.    attributes[nextright] = MENU_ITEM;
  1100.    LOADPROMPTSCHOICES(nextright,"quit Fractint           <esc>");
  1101.    choicekey[nextright+=2] = INSERT;
  1102.    attributes[nextright] = MENU_ITEM;
  1103.    LOADPROMPTSCHOICES(nextright,"restart Fractint        <ins>");
  1104.    if (fullmenu && gotrealdac && colors >= 16) {
  1105.       /* nextright += 2; */
  1106.       LOADPROMPTSCHOICES(nextright+=2,"       COLORS");
  1107.       attributes[nextright] = 256+MENU_HDG;
  1108.       choicekey[nextright+=2] = 'c';
  1109.       attributes[nextright] = MENU_ITEM;
  1110.       LOADPROMPTSCHOICES(nextright,"color cycling mode       <c>");
  1111.       choicekey[nextright+=2] = '+';
  1112.       attributes[nextright] = MENU_ITEM;
  1113.       LOADPROMPTSCHOICES(nextright,"rotate palette      <+>, <->");
  1114.       if (colors > 16) {
  1115.      if (!reallyega) {
  1116.         choicekey[nextright+=2] = 'e';
  1117.         attributes[nextright] = MENU_ITEM;
  1118.         LOADPROMPTSCHOICES(nextright,"palette editing mode     <e>");
  1119.         }
  1120.      choicekey[nextright+=2] = 'a';
  1121.      attributes[nextright] = MENU_ITEM;
  1122.      LOADPROMPTSCHOICES(nextright,"make starfield           <a>");
  1123.      }
  1124.       choicekey[nextright+=2] = 1;
  1125.       attributes[nextright] = MENU_ITEM;
  1126.       LOADPROMPTSCHOICES(nextright,   "ant automaton          <ctl-a>");
  1127.  
  1128.       choicekey[nextright+=2] = 19;
  1129.       attributes[nextright] = MENU_ITEM;
  1130.       LOADPROMPTSCHOICES(nextright,   "stereogram             <ctl-s>");
  1131.       }
  1132.  
  1133.    i = (keypressed()) ? getakey() : 0;
  1134.    if (menu_checkkey(i,0) == 0) {
  1135.       helpmode = HELPMAIN;       /* switch help modes */
  1136.       if ((nextleft += 2) < nextright)
  1137.      nextleft = nextright + 1;
  1138.       i = fullscreen_choice(CHOICEMENU+CHOICESCRUNCH,
  1139.       MAIN_MENU,
  1140.       NULL,NULL,nextleft,(char far * far *)choices,attributes,
  1141.       2,nextleft/2,29,0,NULL,NULL,NULL,menu_checkkey);
  1142.       if (i == -1)     /* escape */
  1143.      i = ESC;
  1144.       else if (i < 0)
  1145.      i = 0 - i;
  1146.       else {              /* user selected a choice */
  1147.      i = choicekey[i];
  1148.      switch (i) {          /* check for special cases */
  1149.         case -10:          /* zoombox functions */
  1150.            helpmode = HELPZOOM;
  1151.            help(0);
  1152.            i = 0;
  1153.            break;
  1154.         }
  1155.      }
  1156.       }
  1157.    if (i == ESC) {           /* escape from menu exits Fractint */
  1158.       static char far s[] = "Exit from Fractint (y/n)? y";
  1159.       helptitle();
  1160.       setattr(1,0,C_GENERAL_MED,24*80);
  1161.       for (i = 9; i <= 11; ++i)
  1162.      setattr(i,18,C_GENERAL_INPUT,40);
  1163.       putstringcenter(10,18,40,C_GENERAL_INPUT,s);
  1164.       movecursor(25,80);
  1165.       while ((i = getakey()) != 'y' && i != 'Y' && i != 13) {
  1166.      if (i == 'n' || i == 'N')
  1167.         goto top;
  1168.      }
  1169.       goodbye();
  1170.       }
  1171.    if (i == TAB) {
  1172.       tab_display();
  1173.       i = 0;
  1174.       }
  1175.    if (i == ENTER || i == ENTER_2)
  1176.       i = 0;             /* don't trigger new calc */
  1177.    tabmode = oldtabmode;
  1178.    return(i);
  1179. }
  1180.  
  1181. #if (_MSC_VER >= 700)
  1182. #pragma code_seg ()         /* back to normal segment */
  1183. #endif
  1184.  
  1185. static int menu_checkkey(int curkey,int choice)
  1186. { /* choice is dummy used by other routines called by fullscreen_choice() */
  1187.    int testkey;
  1188.    testkey = choice; /* for warning only */
  1189.    testkey = (curkey>='A' && curkey<='Z') ? curkey+('a'-'A') : curkey;
  1190. #ifdef XFRACT
  1191.    /* We use F2 for shift-@, annoyingly enough */
  1192.    if (testkey == F2) return(0-testkey);
  1193. #endif
  1194.    if(testkey == '2')
  1195.       testkey = '@';
  1196.    if (strchr("#@txyzgvir3dj",testkey) || testkey == INSERT
  1197.      || testkey == ESC || testkey == DELETE)
  1198.       return(0-testkey);
  1199.    if (menutype) {
  1200.       if (strchr("\\sobpkrh",testkey) || testkey == TAB)
  1201.      return(0-testkey);
  1202.       if (testkey == ' ')
  1203.      if ((curfractalspecific->tojulia != NOFRACTAL
  1204.           && param[0] == 0.0 && param[1] == 0.0)
  1205.        || curfractalspecific->tomandel != NOFRACTAL)
  1206.      return(0-testkey);
  1207.       if (gotrealdac && colors >= 16) {
  1208.      if (strchr("c+-",testkey))
  1209.         return(0-testkey);
  1210.      if (colors > 16
  1211.        && (testkey == 'a' || (!reallyega && testkey == 'e')))
  1212.         return(0-testkey);
  1213.      }
  1214.       /* Alt-A and Alt-S */
  1215.       if (testkey == 1030 || testkey == 1031 ) 
  1216.      return(0-testkey);
  1217.       }
  1218.    if (check_vidmode_key(0,testkey) >= 0)
  1219.       return(0-testkey);
  1220.    return(0);
  1221. }
  1222.  
  1223.  
  1224. int input_field(
  1225.     int options,          /* &1 numeric, &2 integer, &4 double */
  1226.     int attr,          /* display attribute */
  1227.     char *fld,          /* the field itself */
  1228.     int len,          /* field length (declare as 1 larger for \0) */
  1229.     int row,          /* display row */
  1230.     int col,          /* display column */
  1231.     int (*checkkey)(int)  /* routine to check non data keys, or NULL */
  1232.     )
  1233. {
  1234.    char savefld[81];
  1235.    char buf[81];
  1236.    int insert, started, offset, curkey, display;
  1237.    int i, j;
  1238.    int ret,savelookatmouse;
  1239.    savelookatmouse = lookatmouse;
  1240.    lookatmouse = 0;
  1241.    ret = -1;
  1242.    strcpy(savefld,fld);
  1243.    insert = started = offset = 0;
  1244.    display = 1;
  1245.    for(;;) {
  1246.       strcpy(buf,fld);
  1247.       i = strlen(buf);
  1248.       while (i < len)
  1249.      buf[i++] = ' ';
  1250.       buf[len] = 0;
  1251.       if (display) {                    /* display current value */
  1252.      putstring(row,col,attr,buf);
  1253.      display = 0;
  1254.      }
  1255.       curkey = keycursor(row+insert,col+offset);  /* get a keystroke */
  1256.       switch (curkey) {
  1257.      case ENTER:
  1258.      case ENTER_2:
  1259.         ret = 0;
  1260.         goto inpfld_end;
  1261.      case ESC:
  1262.         goto inpfld_end;
  1263.      case RIGHT_ARROW:
  1264.      case RIGHT_ARROW_2:
  1265.         if (offset < len-1) ++offset;
  1266.         started = 1;
  1267.         break;
  1268.      case LEFT_ARROW:
  1269.      case LEFT_ARROW_2:
  1270.         if (offset > 0) --offset;
  1271.         started = 1;
  1272.         break;
  1273.      case HOME:
  1274.         offset = 0;
  1275.         started = 1;
  1276.         break;
  1277.      case END:
  1278.         offset = strlen(fld);
  1279.         started = 1;
  1280.         break;
  1281.      case 8:
  1282.      case 127:                /* backspace */
  1283.         if (offset > 0) {
  1284.            j = strlen(fld);
  1285.            for (i = offset-1; i < j; ++i)
  1286.           fld[i] = fld[i+1];
  1287.            --offset;
  1288.            }
  1289.         started = display = 1;
  1290.         break;
  1291.      case DELETE:                /* delete */
  1292.         j = strlen(fld);
  1293.         for (i = offset; i < j; ++i)
  1294.            fld[i] = fld[i+1];
  1295.         started = display = 1;
  1296.         break;
  1297.      case INSERT:                /* insert */
  1298.         insert ^= 0x8000;
  1299.         started = 1;
  1300.         break;
  1301.      case F5:
  1302.         strcpy(fld,savefld);
  1303.         insert = started = offset = 0;
  1304.         display = 1;
  1305.         break;
  1306.      default:
  1307.             if (nonalpha(curkey)) {
  1308.            if (checkkey && (ret = (*checkkey)(curkey)) != 0)
  1309.           goto inpfld_end;
  1310.            break;                     /* non alphanum char */
  1311.            }
  1312.         if (offset >= len) break;             /* at end of field */
  1313.         if (insert && started && strlen(fld) >= (size_t)len)
  1314.            break;                     /* insert & full */
  1315.         if ((options & 1)
  1316.           && (curkey < '0' || curkey > '9')
  1317.           && curkey != '+' && curkey != '-') {
  1318.            if ((options & 2))
  1319.           break;
  1320.            /* allow scientific notation, and specials "e" and "p" */
  1321.            if ( ((curkey != 'e' && curkey != 'E') || offset >= 18)
  1322.          && ((curkey != 'p' && curkey != 'P') || offset != 0 )
  1323.          && curkey != '.')
  1324.           break;
  1325.            }
  1326.         if (started == 0) /* first char is data, zap field */
  1327.            fld[0] = 0;
  1328.         if (insert) {
  1329.            j = strlen(fld);
  1330.            while (j >= offset) {
  1331.           fld[j+1] = fld[j];
  1332.           --j;
  1333.           }
  1334.            }
  1335.         if ((size_t)offset >= strlen(fld))
  1336.            fld[offset+1] = 0;
  1337.         fld[offset++] = (char)curkey;
  1338.         /* if "e" or "p" in first col make number e or pi */
  1339.         if ((options & 3) == 1) { /* floating point */
  1340.            double tmpd;
  1341.            int specialv;
  1342.            char tmpfld[30];
  1343.            specialv = 0;
  1344.            if (*fld == 'e' || *fld == 'E') {
  1345.           tmpd = exp(1.0);
  1346.           specialv = 1;
  1347.           }
  1348.            if (*fld == 'p' || *fld == 'P') {
  1349.           tmpd = atan(1.0) * 4;
  1350.           specialv = 1;
  1351.           }
  1352.            if (specialv) {
  1353.           if ((options & 4) == 0)
  1354.              roundfloatd(&tmpd);
  1355.           sprintf(tmpfld,"%.15g",tmpd);
  1356.           tmpfld[len-1] = 0; /* safety, field should be long enough */
  1357.           strcpy(fld,tmpfld);
  1358.           offset = 0;
  1359.           }
  1360.            }
  1361.         started = display = 1;
  1362.      }
  1363.       }
  1364. inpfld_end:
  1365.    lookatmouse = savelookatmouse;
  1366.    return(ret);
  1367. }
  1368.  
  1369. int field_prompt(
  1370.     int options,        /* &1 numeric value, &2 integer */
  1371.     char far *hdg,        /* heading, \n delimited lines */
  1372.     char far *instr,    /* additional instructions or NULL */
  1373.     char *fld,        /* the field itself */
  1374.     int len,        /* field length (declare as 1 larger for \0) */
  1375.     int (*checkkey)(int)   /* routine to check non data keys, or NULL */
  1376.     )
  1377. {
  1378.    char far *charptr;
  1379.    int boxwidth,titlelines,titlecol,titlerow;
  1380.    int promptcol;
  1381.    int i,j;
  1382.    char buf[81];
  1383.    helptitle();               /* clear screen, display title */
  1384.    setattr(1,0,C_PROMPT_BKGRD,24*80);      /* init rest to background */
  1385.    charptr = hdg;              /* count title lines, find widest */
  1386.    i = boxwidth = 0;
  1387.    titlelines = 1;
  1388.    while (*charptr) {
  1389.       if (*(charptr++) == '\n') {
  1390.      ++titlelines;
  1391.      i = -1;
  1392.      }
  1393.       if (++i > boxwidth)
  1394.      boxwidth = i;
  1395.       }
  1396.    if (len > boxwidth)
  1397.       boxwidth = len;
  1398.    i = titlelines + 4;              /* total rows in box */
  1399.    titlerow = (25 - i) / 2;          /* top row of it all when centered */
  1400.    titlerow -= titlerow / 4;          /* higher is better if lots extra */
  1401.    titlecol = (80 - boxwidth) / 2;      /* center the box */
  1402.    titlecol -= (90 - boxwidth) / 20;
  1403.    promptcol = titlecol - (boxwidth-len)/2;
  1404.    j = titlecol;              /* add margin at each side of box */
  1405.    if ((i = (82-boxwidth)/4) > 3)
  1406.       i = 3;
  1407.    j -= i;
  1408.    boxwidth += i * 2;
  1409.    for (i = -1; i < titlelines+3; ++i)      /* draw empty box */
  1410.       setattr(titlerow+i,j,C_PROMPT_LO,boxwidth);
  1411.    textcbase = titlecol;          /* set left margin for putstring */
  1412.    putstring(titlerow,0,C_PROMPT_HI,hdg); /* display heading */
  1413.    textcbase = 0;
  1414.    i = titlerow + titlelines + 4;
  1415.    if (instr) {               /* display caller's instructions */
  1416.       charptr = instr;
  1417.       j = -1;
  1418.       while ((buf[++j] = *(charptr++)) != 0)
  1419.      if (buf[j] == '\n') {
  1420.         buf[j] = 0;
  1421.         putstringcenter(i++,0,80,C_PROMPT_BKGRD,buf);
  1422.         j = -1;
  1423.         }
  1424.       putstringcenter(i,0,80,C_PROMPT_BKGRD,buf);
  1425.       }
  1426.    else                   /* default instructions */
  1427.       putstringcenter(i,0,80,C_PROMPT_BKGRD,
  1428.           "Press ENTER when finished (or ESCAPE to back out)");
  1429.    return(input_field(options,C_PROMPT_INPUT,fld,len,
  1430.               titlerow+titlelines+1,promptcol,checkkey));
  1431. }
  1432.  
  1433.  
  1434. /* thinking(1,message):
  1435.       if thinking message not yet on display, it is displayed;
  1436.       otherwise the wheel is updated
  1437.       returns 0 to keep going, -1 if keystroke pending
  1438.    thinking(0,NULL):
  1439.       call this when thinking phase is done
  1440.    */
  1441.  
  1442. int thinking(int options,char *msg)
  1443. {
  1444.    static int thinkstate = -1;
  1445.    static char *wheel[] = {"-","\\","|","/"};
  1446.    static int thinkcol;
  1447.    static int count = 0;
  1448.    char buf[81];
  1449.    if (options == 0) {
  1450.       if (thinkstate >= 0) {
  1451.      thinkstate = -1;
  1452.      unstackscreen();
  1453.      }
  1454.       return(0);
  1455.       }
  1456.    if (thinkstate < 0) {
  1457.       stackscreen();
  1458.       thinkstate = 0;
  1459.       helptitle();
  1460.       strcpy(buf,"  ");
  1461.       strcat(buf,msg);
  1462.       strcat(buf,"    ");
  1463.       putstring(4,10,C_GENERAL_HI,buf);
  1464.       thinkcol = textcol - 3;
  1465.       count = 0;
  1466.       }
  1467.    if ((count++)<100) {
  1468.        return 0;
  1469.    }
  1470.    count = 0;
  1471.    putstring(4,thinkcol,C_GENERAL_HI,wheel[thinkstate]);
  1472.    movecursor(25,80); /* turn off cursor */
  1473.    thinkstate = (thinkstate + 1) & 3;
  1474.    return (keypressed());
  1475. }
  1476.  
  1477.  
  1478. void clear_screen(void)  /* a stub for a windows only subroutine */
  1479. {
  1480. }
  1481.  
  1482.  
  1483. /* savegraphics/restoregraphics: video.asm subroutines */
  1484.  
  1485. static BYTE far *swapsavebuf;
  1486. static unsigned int memhandle;
  1487. unsigned long swaptotlen;
  1488. unsigned long swapoffset;
  1489. BYTE far *swapvidbuf;
  1490. int swaplength;
  1491. static int swaptype = -1;
  1492. static int swapblklen; /* must be a power of 2 */
  1493. #ifdef XFRACT
  1494. BYTE suffix[4096];
  1495. #endif
  1496.  
  1497. #ifndef XFRACT
  1498.  
  1499. int savegraphics()
  1500. {
  1501.    int i;
  1502.    struct XMM_Move   xmmparms;
  1503.  
  1504.    discardgraphics(); /* if any emm/xmm in use from prior call, release it */
  1505.    swaptotlen = (long)(vxdots > sxdots ? vxdots : sxdots) * (long)sydots;
  1506.    i = colors;
  1507.    while (i <= 16) {
  1508.       swaptotlen >>= 1;
  1509.       i = i * i;
  1510.       }
  1511.    swapoffset = 0;
  1512.    if (debugflag != 420 && debugflag != 422 /* 422=xmm test, 420=disk test */
  1513.      && (swapsavebuf = emmquery()) != NULL
  1514.      && (memhandle = emmallocate((unsigned int)((swaptotlen + 16383) >> 14)))
  1515.      != 0) {
  1516.       swaptype = 0; /* use expanded memory */
  1517.       swapblklen = 16384;
  1518.       }
  1519.    else if (debugflag != 420
  1520.      && xmmquery() != 0
  1521.      && (memhandle = xmmallocate((unsigned int)((swaptotlen + 1023) >> 10)))
  1522.      != 0) {
  1523.       swaptype = 1; /* use extended memory */
  1524.       swapblklen = 16384;
  1525.       }
  1526.    else {
  1527.       swaptype = 2; /* use disk */
  1528.       swapblklen = 4096;
  1529.  
  1530.    /* MCP 7-7-91, If 'memhandle' is an 'unsigned int', how is it ever going
  1531.       to be equal to -1?
  1532.  
  1533.       if ((memhandle = dir_open(tempdir,diskfilename,O_CREAT|O_WRONLY|O_BINARY,S_IWRITE))
  1534.      == -1) {
  1535.    */
  1536.       if ((memhandle = dir_open(tempdir,diskfilename,O_CREAT|O_WRONLY|O_BINARY,S_IWRITE))
  1537.      == 0xffff) {
  1538.  
  1539.  
  1540. dskfile_error:
  1541.      setvideotext(); /* text mode */
  1542.      setclear();
  1543.          {
  1544.             static char far s1[] = {"error in temp file "};
  1545.             static char far s2[] = { " (disk full?) - aborted\n\n"};
  1546.         printf("%Fs%s%Fs",s1,diskfilename,s2);
  1547.      }   
  1548.      exit(1);
  1549.      }
  1550.       made_dsktemp = 1;
  1551.       }
  1552.    while (swapoffset < swaptotlen) {
  1553.       swaplength = swapblklen;
  1554.       if ((swapoffset & (swapblklen-1)) != 0)
  1555.      swaplength = (int)(swapblklen - (swapoffset & (swapblklen-1)));
  1556.       if ((unsigned long)swaplength > (swaptotlen - swapoffset))
  1557.      swaplength = (int)(swaptotlen - swapoffset);
  1558.       (*swapsetup)(); /* swapoffset,swaplength -> sets swapvidbuf,swaplength */
  1559.       switch(swaptype) {
  1560.      case 0:
  1561.         emmgetpage((unsigned int)(swapoffset>>14),memhandle);
  1562.         movewords(swaplength>>1,swapvidbuf,
  1563.               swapsavebuf+(swapoffset&(swapblklen-1)));
  1564.         break;
  1565.      case 1:
  1566.         xmmparms.Length = swaplength;
  1567.         xmmparms.SourceHandle = 0; /* Source is conventional memory */
  1568.         xmmparms.SourceOffset = (unsigned long)swapvidbuf;
  1569.         xmmparms.DestHandle = memhandle;
  1570.         xmmparms.DestOffset = swapoffset;
  1571.         xmmmoveextended(&xmmparms);
  1572.         break;
  1573.      default:
  1574.         movewords(swaplength>>1,swapvidbuf,(BYTE far *)suffix);
  1575.         if (write(memhandle,suffix,swaplength) == -1)
  1576.            goto dskfile_error;
  1577.      }
  1578.       swapoffset += swaplength;
  1579.       }
  1580.    if (swaptype == 2)
  1581.       close(memhandle);
  1582.    return 0;
  1583. }
  1584.  
  1585. int restoregraphics()
  1586. {
  1587.    struct XMM_Move   xmmparms;
  1588.  
  1589.    if(swaptype == -1)
  1590.       return(-1);
  1591.    swapoffset = 0;
  1592.    if (swaptype == 2)
  1593.       memhandle = dir_open(tempdir,diskfilename,O_RDONLY|O_BINARY,S_IREAD);
  1594.    swapvidbuf = MK_FP(extraseg+0x1000,0); /* for swapnormwrite case */
  1595.    while (swapoffset < swaptotlen) {
  1596.       swaplength = swapblklen;
  1597.       if ((swapoffset & (swapblklen-1)) != 0)
  1598.      swaplength = (int)(swapblklen - (swapoffset & (swapblklen-1)));
  1599.       if ((unsigned long)swaplength > (swaptotlen - swapoffset))
  1600.      swaplength = (int)(swaptotlen - swapoffset);
  1601.       if (swapsetup != swapnormread)
  1602.      (*swapsetup)(); /* swapoffset,swaplength -> sets swapvidbuf,swaplength */
  1603.       switch(swaptype) {
  1604.      case 0:
  1605.         emmgetpage((unsigned int)(swapoffset>>14),memhandle);
  1606.         movewords(swaplength>>1,swapsavebuf+(swapoffset&(swapblklen-1)),
  1607.               swapvidbuf);
  1608.         break;
  1609.      case 1:
  1610.         xmmparms.Length = swaplength;
  1611.         xmmparms.SourceHandle = memhandle;
  1612.         xmmparms.SourceOffset = swapoffset;
  1613.         xmmparms.DestHandle = 0; /* conventional memory */
  1614.         xmmparms.DestOffset = (unsigned long)swapvidbuf;
  1615.         xmmmoveextended(&xmmparms);
  1616.         break;
  1617.      default:
  1618.         read(memhandle,suffix,swaplength);
  1619.         movewords(swaplength>>1,(BYTE far *)suffix,swapvidbuf);
  1620.      }
  1621.       if (swapsetup == swapnormread)
  1622.      swapnormwrite();
  1623.       swapoffset += swaplength;
  1624.       }
  1625.    if (swaptype == 2)
  1626.       close(memhandle);
  1627.    discardgraphics();
  1628.    return(0);
  1629. }
  1630.  
  1631. #else
  1632. int savegraphics() {return 0;}
  1633. int restoregraphics() {return 0;}
  1634. #endif
  1635.  
  1636. void discardgraphics() /* release expanded/extended memory if any in use */
  1637. {
  1638. #ifndef XFRACT
  1639.    switch(swaptype) {
  1640.       case 0:
  1641.      emmdeallocate(memhandle);
  1642.      break;
  1643.       case 1:
  1644.      xmmdeallocate(memhandle);
  1645.       }
  1646.    swaptype = -1;
  1647. #endif
  1648. }
  1649.  
  1650. #if (_MSC_VER >= 700)
  1651. #pragma code_seg ("realdos1_text")     /* place following in an overlay */
  1652. #endif
  1653.  
  1654. VIDEOINFO *vidtbl;  /* temporarily loaded fractint.cfg info */
  1655. int vidtbllen;               /* number of entries in above           */
  1656.  
  1657. int showvidlength()
  1658. {
  1659.    int sz;
  1660.    sz = (sizeof(VIDEOINFO)+sizeof(int))*MAXVIDEOMODES;
  1661.    return(sz);
  1662. }
  1663.  
  1664. int load_fractint_cfg(int options)
  1665. {
  1666.    /* Reads fractint.cfg, loading videoinfo entries into extraseg. */
  1667.    /* Sets vidtbl pointing to the loaded table, and returns the    */
  1668.    /* number of entries (also sets vidtbllen to this).           */
  1669.    /* Past vidtbl, cfglinenums are stored for update_fractint_cfg. */
  1670.    /* If fractint.cfg is not found or invalid, issues a message    */
  1671.    /* (first time the problem occurs only, and only if options is  */
  1672.    /* zero) and uses the hard-coded table.               */
  1673.  
  1674.    FILE *cfgfile;
  1675.    VIDEOINFO *vident;
  1676.    int far *cfglinenums;
  1677.    int linenum;
  1678.    int i, j, keynum, ax, bx, cx, dx, dotmode, xdots, ydots, colors;
  1679.    int commas[10];
  1680.    int textsafe2;
  1681.    char tempstring[150];
  1682.  
  1683.    vidtbl = MK_FP(extraseg,0);
  1684.    cfglinenums = (int far *)(&vidtbl[MAXVIDEOMODES]);
  1685.  
  1686. #ifdef XFRACT
  1687.     badconfig = -1;
  1688. #endif
  1689.  
  1690.    if (badconfig)  /* fractint.cfg already known to be missing or bad */
  1691.       goto use_resident_table;
  1692.  
  1693.    findpath("fractint.cfg",tempstring);
  1694.    if (tempstring[0] == 0                 /* can't find the file */
  1695.      || (cfgfile = fopen(tempstring,"r")) == NULL)   /* can't open it */
  1696.       goto bad_fractint_cfg;
  1697.  
  1698.    vidtbllen = 0;
  1699.    linenum = 0;
  1700.    vident = vidtbl;
  1701.    while (vidtbllen < MAXVIDEOMODES
  1702.      && fgets(tempstring, 120, cfgfile)) {
  1703.       ++linenum;
  1704.       if (tempstring[0] == ';') continue;   /* comment line */
  1705.       tempstring[120] = 0;
  1706.       tempstring[strlen(tempstring)-1] = 0; /* zap trailing \n */
  1707.       memset(commas,0,20);
  1708.       i = j = -1;
  1709.       for(;;) {
  1710.      if (tempstring[++i] < ' ') {
  1711.         if (tempstring[i] == 0) break;
  1712.         tempstring[i] = ' '; /* convert tab (or whatever) to blank */
  1713.         }
  1714.      else if (tempstring[i] == ',' && ++j < 10) {
  1715.         commas[j] = i + 1;     /* remember start of next field */
  1716.         tempstring[i] = 0;     /* make field a separate string */
  1717.         }
  1718.      }
  1719.       keynum = check_vidmode_keyname(tempstring);
  1720.       sscanf(&tempstring[commas[1]],"%x",&ax);
  1721.       sscanf(&tempstring[commas[2]],"%x",&bx);
  1722.       sscanf(&tempstring[commas[3]],"%x",&cx);
  1723.       sscanf(&tempstring[commas[4]],"%x",&dx);
  1724.       dotmode      = atoi(&tempstring[commas[5]]);
  1725.       xdots      = atoi(&tempstring[commas[6]]);
  1726.       ydots      = atoi(&tempstring[commas[7]]);
  1727.       colors      = atoi(&tempstring[commas[8]]);
  1728.       textsafe2   = dotmode / 100;
  1729.       dotmode     %= 100;
  1730.       if (j != 9 ||
  1731.         keynum < 0 ||
  1732.         dotmode < 0 || dotmode > 30 ||
  1733.         textsafe2 < 0 || textsafe2 > 4 ||
  1734.         xdots < 160 || xdots > MAXPIXELS ||
  1735.         ydots < 160 || ydots > MAXPIXELS ||
  1736.         (colors != 0 && colors != 2 && colors != 4 && colors != 16 &&
  1737.          colors != 256)
  1738.        )
  1739.      goto bad_fractint_cfg;
  1740.       cfglinenums[vidtbllen] = linenum; /* for update_fractint_cfg */
  1741.       far_memcpy(vident->name,     (char far *)&tempstring[commas[0]],25);
  1742.       far_memcpy(vident->comment,(char far *)&tempstring[commas[9]],25);
  1743.       vident->name[25] = vident->comment[25] = 0;
  1744.       vident->keynum      = keynum;
  1745.       vident->videomodeax = ax;
  1746.       vident->videomodebx = bx;
  1747.       vident->videomodecx = cx;
  1748.       vident->videomodedx = dx;
  1749.       vident->dotmode      = textsafe2 * 100 + dotmode;
  1750.       vident->xdots      = xdots;
  1751.       vident->ydots      = ydots;
  1752.       vident->colors      = colors;
  1753.       ++vident;
  1754.       ++vidtbllen;
  1755.       }
  1756.    fclose(cfgfile);
  1757.    return (vidtbllen);
  1758.  
  1759. bad_fractint_cfg:
  1760.    badconfig = -1; /* bad, no message issued yet */
  1761.    if (options == 0)
  1762.       bad_fractint_cfg_msg();
  1763.  
  1764. use_resident_table:
  1765.    vidtbllen = 0;
  1766.    vident = vidtbl;
  1767.    for (i = 0; i < MAXVIDEOTABLE; ++i) {
  1768.       if (videotable[i].xdots) {
  1769.      far_memcpy((char far *)vident,(char far *)&videotable[i],
  1770.             sizeof(*vident));
  1771.      ++vident;
  1772.      ++vidtbllen;
  1773.      }
  1774.       }
  1775.    return (vidtbllen);
  1776.  
  1777. }
  1778.  
  1779. void bad_fractint_cfg_msg()
  1780. {
  1781. static char far badcfgmsg[]={"\
  1782. File FRACTINT.CFG is missing or invalid.\n\
  1783. See Hardware Support and Video Modes in the full documentation for help.\n\
  1784. I will continue with only the built-in video modes available."};
  1785.    stopmsg(0,badcfgmsg);
  1786.    badconfig = 1; /* bad, message issued */
  1787. }
  1788.  
  1789. void load_videotable(int options)
  1790. {
  1791.    /* Loads fractint.cfg and copies the video modes which are */
  1792.    /* assigned to function keys into videotable.          */
  1793.    int keyents,i;
  1794.    load_fractint_cfg(options); /* load fractint.cfg to extraseg */
  1795.    keyents = 0;
  1796.    far_memset((char far *)videotable,0,sizeof(*vidtbl)*MAXVIDEOTABLE);
  1797.    for (i = 0; i < vidtbllen; ++i) {
  1798.       if (vidtbl[i].keynum > 0) {
  1799.      far_memcpy((char far *)&videotable[keyents],(char far *)&vidtbl[i],
  1800.             sizeof(*vidtbl));
  1801.      if (++keyents >= MAXVIDEOTABLE)
  1802.         break;
  1803.      }
  1804.       }
  1805. }
  1806.  
  1807. int check_vidmode_key(int option,int k)
  1808. {
  1809.    int i;
  1810.    /* returns videotable entry number if the passed keystroke is a  */
  1811.    /* function key currently assigned to a video mode, -1 otherwise */
  1812.    if (k == 1400)           /* special value from select_vid_mode  */
  1813.       return(MAXVIDEOTABLE-1); /* for last entry with no key assigned */
  1814.    if (k != 0)
  1815.       if (option == 0) { /* check resident video mode table */
  1816.      for (i = 0; i < MAXVIDEOTABLE; ++i) {
  1817.         if (videotable[i].keynum == k)
  1818.            return(i);
  1819.         }
  1820.      }
  1821.       else { /* check full vidtbl */
  1822.      for (i = 0; i < vidtbllen; ++i) {
  1823.         if (vidtbl[i].keynum == k)
  1824.            return(i);
  1825.         }
  1826.      }
  1827.    return(-1);
  1828. }
  1829.  
  1830. int check_vidmode_keyname(char *kname)
  1831. {
  1832.    /* returns key number for the passed keyname, 0 if not a keyname */
  1833.    int i,keyset;
  1834.    keyset = 1058;
  1835.    if (*kname == 'S' || *kname == 's') {
  1836.       keyset = 1083;
  1837.       ++kname;
  1838.       }
  1839.    else if (*kname == 'C' || *kname == 'c') {
  1840.       keyset = 1093;
  1841.       ++kname;
  1842.       }
  1843.    else if (*kname == 'A' || *kname == 'a') {
  1844.       keyset = 1103;
  1845.       ++kname;
  1846.       }
  1847.    if (*kname != 'F' && *kname != 'f')
  1848.       return(0);
  1849.    if (*++kname < '1' || *kname > '9')
  1850.       return(0);
  1851.    i = *kname - '0';
  1852.    if (*++kname != 0 && *kname != ' ') {
  1853.       if (*kname != '0' || i != 1)
  1854.      return(0);
  1855.       i = 10;
  1856.       ++kname;
  1857.       }
  1858.    while (*kname)
  1859.       if (*(kname++) != ' ')
  1860.      return(0);
  1861.    if ((i += keyset) < 2)
  1862.       i = 0;
  1863.    return(i);
  1864. }
  1865.  
  1866. void vidmode_keyname(int k,char *buf)
  1867. {
  1868.    /* set buffer to name of passed key number */
  1869.    *buf = 0;
  1870.    if (k > 0) {
  1871.       if (k > 1103) {
  1872.      *(buf++) = 'A';
  1873.      k -= 1103;
  1874.      }
  1875.       else if (k > 1093) {
  1876.      *(buf++) = 'C';
  1877.      k -= 1093;
  1878.      }
  1879.       else if (k > 1083) {
  1880.      *(buf++) = 'S';
  1881.      k -= 1083;
  1882.      }
  1883.       else
  1884.      k -= 1058;
  1885.       sprintf(buf,"F%d",k);
  1886.       }
  1887. }
  1888.  
  1889. #if (_MSC_VER >= 700)
  1890. #pragma code_seg ()      /* back to normal segment */
  1891. #endif
  1892.