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