home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / dos / fraktale / frasr192.exe / MISCOVL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-21  |  63.3 KB  |  2,048 lines

  1. /*
  2.     Overlayed odds and ends that don't fit anywhere else.
  3. */
  4.  
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <ctype.h>
  9. #ifndef XFRACT
  10. #include <malloc.h>
  11. #include <process.h>
  12. #include <dos.h>
  13. #include <stdarg.h>
  14. #include <io.h>
  15. #else
  16. #include <varargs.h>
  17. #endif
  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 void write_batch_parms(char *colorinf,int maxcolor);
  26.  
  27. #ifndef XFRACT
  28. static void put_parm(char *parm,...);
  29. #else
  30. static void put_parm();
  31. #endif
  32.  
  33. static void put_parm_line(void);
  34. static int getprec(double,double,double);
  35. extern int getprecbf(int);
  36. static void put_float(int,double,int);
  37. static void put_bf(int slash,bf_t r, int prec);
  38. static void put_filename(char *keyword,char *fname);
  39. static int check_modekey(int curkey,int choice);
  40. static int entcompare(VOIDCONSTPTR p1,VOIDCONSTPTR p2);
  41. static void update_fractint_cfg(void);
  42.  
  43. /* fullscreen_choice options */
  44. #define CHOICERETURNKEY 1
  45. #define CHOICEMENU    2
  46. #define CHOICEHELP    4
  47.  
  48. char s_yes[]      = "yes";
  49. char s_no[]       = "no";
  50. char s_seqs[]     = " %s=%s";
  51. char s_seqd[]     = " %s=%d";
  52. char s_seqdd[]    = " %s=%d/%d";
  53. char s_seqddd[]   = " %s=%d/%d/%d";
  54. char s_seqdddd[]  = " %s=%d/%d/%d/%d";
  55. char s_x[]        = "x";
  56. char s_y[]        = "y";
  57. char s_z[]        = "z";
  58.  
  59. /* JIIM */
  60.  
  61. FILE *parmfile;
  62.  
  63. #define PAR_KEY(x)  ( x < 10 ? '0' + x : 'a' - 10 + x)
  64.  
  65. #ifdef C6
  66. #pragma optimize("e",off)  /* MSC 6.00A messes up next rtn with "e" on */
  67. #endif
  68.  
  69. #define LOADBATCHPROMPTS(X)     {\
  70.    static FCODE tmp[] = { X };\
  71.    far_strcpy(ptr,tmp);\
  72.    choices[promptnum]= ptr;\
  73.    ptr += sizeof(tmp);\
  74.    }
  75.  
  76.  
  77. void make_batch_file()
  78. {
  79. #define MAXPROMPTS 18
  80.    static char far hdg[]={"Save Current Parameters"};
  81.    /** added for pieces feature **/
  82.    double pdelx;
  83.    double pdely;
  84.    double pdelx2;
  85.    double pdely2;
  86.    unsigned int j, pxdots, pydots, xm, ym;
  87.    double pxxmin, pyymax;
  88.    char vidmde[4];
  89.    int promptnum;
  90.    int piecespromts;
  91.    int have3rd;
  92.    /****/
  93.  
  94.    int i;
  95.    char far *inpcommandfile, far *inpcommandname;
  96.    char far *inpcomment1, far *inpcomment2, far *inpcomment3, far *inpcomment4;
  97.    struct fullscreenvalues paramvalues[18];
  98.    char far * choices[MAXPROMPTS];
  99.    char far *ptr;
  100.    int gotinfile;
  101.    char outname[81], buf[256], buf2[128];
  102.    FILE *infile;
  103.    FILE *fpbat = NULL;
  104.    char colorspec[14];
  105.    int maxcolor;
  106.    int maxcolorindex;
  107.    char *sptr, *sptr2;
  108.    int oldhelpmode;
  109.  
  110.    /* put comment storage in extraseg */
  111.    inpcommandfile = MK_FP(extraseg,0);
  112.    inpcommandname = inpcommandfile+80;
  113.    inpcomment1    = inpcommandname+(ITEMNAMELEN + 1);
  114.    inpcomment2    = inpcomment1 + 57;
  115.    inpcomment3    = inpcomment2 + 57;
  116.    inpcomment4    = inpcomment3 + 57;
  117.    
  118.    /* steal existing array for "choices" */
  119.    ptr = (char far *)(inpcomment4 + 57);
  120.    stackscreen();
  121.    oldhelpmode = helpmode;
  122.    helpmode = HELPPARMFILE;
  123.  
  124.    strcpy(colorspec, "n");
  125.    maxcolor = colors;
  126.    if (gotrealdac && !reallyega)
  127.    {
  128.       --maxcolor;
  129. /*    if (maxit < maxcolor)  remove 2 lines */
  130. /*       maxcolor = maxit;   so that whole palette is always saved */
  131.       if (inside > 0 && inside > maxcolor)
  132.          maxcolor = inside;
  133.       if (outside > 0 && outside > maxcolor)
  134.          maxcolor = outside;
  135.       if (distest < 0 && 0 - distest > maxcolor)
  136.          maxcolor = 0 - distest;
  137.       if (decomp[0] > maxcolor)
  138.          maxcolor = decomp[0] - 1;
  139.       if (potflag && potparam[0] >= maxcolor)
  140.          maxcolor = (int)potparam[0];
  141.       if (++maxcolor > 256)
  142.          maxcolor = 256;
  143.       if (colorstate == 0)
  144.       {                         /* default colors */
  145.          if (mapdacbox)
  146.          {
  147.             colorspec[0] = '@';
  148.             sptr = MAP_name;
  149.          }
  150.       }
  151.       else
  152.       if (colorstate == 2)
  153.       {                         /* colors match colorfile */
  154.          colorspec[0] = '@';
  155.          sptr = colorfile;
  156.       }
  157.       else                      /* colors match no .map that we know of */
  158.          colorspec[0] = 'y';
  159.       if (colorspec[0] == '@')
  160.       {
  161.          if ((sptr2 = strrchr(sptr, SLASHC)) != NULL)
  162.             sptr = sptr2 + 1;
  163.          if ((sptr2 = strrchr(sptr, ':')) != NULL)
  164.             sptr = sptr2 + 1;
  165.          strncpy(&colorspec[1], sptr, 12);
  166.          colorspec[13] = 0;
  167.       }
  168.    }
  169.    far_strcpy(inpcommandfile, CommandFile);
  170.    far_strcpy(inpcommandname, CommandName);
  171.    far_strcpy(inpcomment1, CommandComment1);
  172.    far_strcpy(inpcomment2, CommandComment2);
  173.    far_strcpy(inpcomment3, CommandComment3);
  174.    far_strcpy(inpcomment4, CommandComment4);
  175.    if (CommandName[0] == 0)
  176.       far_strcpy(inpcommandname, "test");
  177.       /* TW added these  - and Bert moved them */
  178.       pxdots = xdots;
  179.       pydots = ydots;
  180.       vidmode_keyname(videoentry.keynum, vidmde);
  181.  
  182.       xm = ym = 1;
  183.  
  184.    for(;;)
  185.    {
  186. prompt_user:
  187.       promptnum = 0;
  188.       LOADBATCHPROMPTS("Parameter file");
  189.       paramvalues[promptnum].type = 0x100 + 56;
  190.       paramvalues[promptnum++].uval.sbuf = inpcommandfile;
  191.       LOADBATCHPROMPTS("Name");
  192.       paramvalues[promptnum].type = 0x100 + ITEMNAMELEN;
  193.       paramvalues[promptnum++].uval.sbuf = inpcommandname;
  194.       LOADBATCHPROMPTS("Main comment");
  195.       paramvalues[promptnum].type = 0x100 + 56;
  196.       paramvalues[promptnum++].uval.sbuf = inpcomment1;
  197.       LOADBATCHPROMPTS("Second comment");
  198.       paramvalues[promptnum].type = 0x100 + 56;;
  199.       paramvalues[promptnum++].uval.sbuf = inpcomment2;
  200.       LOADBATCHPROMPTS("Third comment");
  201.       paramvalues[promptnum].type = 0x100 + 56;;
  202.       paramvalues[promptnum++].uval.sbuf = inpcomment3;
  203.       LOADBATCHPROMPTS("Fourth comment");
  204.       paramvalues[promptnum].type = 0x100 + 56;;
  205.       paramvalues[promptnum++].uval.sbuf = inpcomment4;
  206.       if (gotrealdac && !reallyega)
  207.       {
  208.          LOADBATCHPROMPTS("Record colors?");
  209.          paramvalues[promptnum].type = 0x100 + 13;
  210.          paramvalues[promptnum++].uval.sbuf = colorspec;
  211.          LOADBATCHPROMPTS("    (no | yes for full info | @filename to point to a map file)");
  212.          paramvalues[promptnum++].type = '*';
  213.          LOADBATCHPROMPTS("# of colors");
  214.          maxcolorindex = promptnum;
  215.          paramvalues[promptnum].type = 'i';
  216.          paramvalues[promptnum++].uval.ival = maxcolor;
  217.          LOADBATCHPROMPTS("    (if recording full color info)");
  218.          paramvalues[promptnum++].type = '*';
  219.       }
  220.       LOADBATCHPROMPTS("");
  221.       paramvalues[promptnum++].type = '*';
  222.       LOADBATCHPROMPTS("    **** The following is for generating images in pieces ****");
  223.       paramvalues[promptnum++].type = '*';
  224.       LOADBATCHPROMPTS("X Multiples");
  225.       piecespromts = promptnum;
  226.       paramvalues[promptnum].type = 'i';
  227.       paramvalues[promptnum++].uval.ival = xm;
  228.       LOADBATCHPROMPTS("Y Multiples");
  229.       paramvalues[promptnum].type = 'i';
  230.       paramvalues[promptnum++].uval.ival = ym;
  231. #ifndef XFRACT
  232.       LOADBATCHPROMPTS("Video mode");
  233.       paramvalues[promptnum].type = 0x100 + 4;
  234.       paramvalues[promptnum++].uval.sbuf = vidmde;
  235. #endif
  236.  
  237.       if (fullscreen_prompt(hdg,promptnum, choices, paramvalues, 0, NULL) < 0)
  238.          break;
  239.  
  240.       far_strcpy(CommandFile, inpcommandfile);
  241.       if (has_ext(CommandFile) == NULL)
  242.          strcat(CommandFile, ".par");   /* default extension .par */
  243.       far_strcpy(CommandName, inpcommandname);
  244.       far_strcpy(CommandComment1, inpcomment1);
  245.       far_strcpy(CommandComment2, inpcomment2);
  246.       far_strcpy(CommandComment3, inpcomment3);
  247.       far_strcpy(CommandComment4, inpcomment4);
  248.       if (gotrealdac && !reallyega)
  249.          if (paramvalues[maxcolorindex].uval.ival > 0 &&
  250.              paramvalues[maxcolorindex].uval.ival <= 256)
  251.             maxcolor = paramvalues[maxcolorindex].uval.ival;
  252.  
  253.       promptnum = piecespromts;
  254.       xm = paramvalues[promptnum++].uval.ival;
  255.  
  256.       ym = paramvalues[promptnum++].uval.ival;
  257.  
  258.       /* sanity checks */
  259.       {
  260.       int i;
  261.       long xtotal, ytotal;
  262.  
  263.       /* get resolution from the video name (which must be valid) */
  264. #ifndef XFRACT
  265.       pxdots = pydots = 0;
  266.       if ((i = check_vidmode_keyname(vidmde)) > 0)
  267.           if ((i = check_vidmode_key(0, i)) >= 0) {
  268.               /* get the resolution of this video mode */
  269.               pxdots = videotable[i].xdots;
  270.               pydots = videotable[i].ydots;
  271.               }
  272.       if (pxdots == 0 && (xm > 1 || ym > 1)) {
  273.           /* no corresponding video mode! */
  274.           static FCODE msg[] = {"Invalid video mode entry!"};
  275.           stopmsg(0,msg);
  276.           goto prompt_user;
  277.           }
  278. #endif
  279.  
  280.       /* bounds range on xm, ym */
  281.       if (xm < 1 || xm > 36 || ym < 1 || ym > 36) {
  282.           static FCODE msg[] = {"X and Y components must be 1 to 36"};
  283.           stopmsg(0,msg);
  284.           goto prompt_user;
  285.           }
  286.  
  287.       /* another sanity check: total resolution cannot exceed 65535 */
  288.       xtotal = xm;  ytotal = ym;
  289.       xtotal *= pxdots;  ytotal *= pydots;
  290.       if (xtotal > 65535L || ytotal > 65535L) {
  291.       static FCODE msg[] = {"Total resolution (X or Y) cannot exceed 65535"};
  292.           stopmsg(0,msg);
  293.           goto prompt_user;
  294.           }
  295.       }
  296.  
  297.       strcpy(outname, CommandFile);
  298.       gotinfile = 0;
  299.       if (access(CommandFile, 0) == 0)
  300.       {                         /* file exists */
  301.          gotinfile = 1;
  302.          if (access(CommandFile, 6))
  303.          {
  304.             sprintf(buf, s_cantwrite, CommandFile);
  305.             stopmsg(0, buf);
  306.             continue;
  307.          }
  308.          i = strlen(outname);
  309.          while (--i >= 0 && outname[i] != SLASHC)
  310.             outname[i] = 0;
  311.          strcat(outname, "fractint.tmp");
  312.          infile = fopen(CommandFile, "rt");
  313. #ifndef XFRACT
  314.          setvbuf(infile, tstack, _IOFBF, 4096); /* improves speed */
  315. #endif
  316.       }
  317.       if ((parmfile = fopen(outname, "wt")) == NULL)
  318.       {
  319.          sprintf(buf, s_cantcreate, outname);
  320.          stopmsg(0, buf);
  321.          if (gotinfile)
  322.             fclose(infile);
  323.          continue;
  324.       }
  325.  
  326.       if (gotinfile)
  327.       {
  328.          while (file_gets(buf, 255, infile) >= 0)
  329.          {
  330.             if (strchr(buf, '{')/* entry heading? */
  331.                 && sscanf(buf, " %40[^ \t({]", buf2)
  332.                 && stricmp(buf2, CommandName) == 0)
  333.             {                   /* entry with same name */
  334.                static FCODE s1[] = {"File already has an entry named "};
  335.                static FCODE s2[] = {"\n\
  336. Continue to replace it, Cancel to back out"};
  337.                far_strcpy(buf2,s1);
  338.                far_strcat(buf2,CommandName);
  339.                far_strcat(buf2,s2);
  340.                if (stopmsg(18, buf2) < 0)
  341.                {                /* cancel */
  342.                   fclose(infile);
  343.                   fclose(parmfile);
  344.                   unlink(outname);
  345.                   goto prompt_user;
  346.                }
  347.                while (strchr(buf, '}') == NULL
  348.                       && file_gets(buf, 255, infile) > 0)
  349.                   ; /* skip to end of set */
  350.                break;
  351.             }
  352.             fputs(buf, parmfile);
  353.             fputc('\n', parmfile);
  354.          }
  355.       }
  356. /***** start here*/
  357.       if (xm > 1 || ym > 1)
  358.       {
  359.          if (xxmin != xx3rd || yymin != yy3rd)
  360.             have3rd = 1;
  361.          else
  362.             have3rd = 0;
  363.          if ((fpbat = dir_fopen(workdir,"makemig.bat", "w")) == NULL)
  364.             xm = ym = 0;
  365.          pdelx  = (xxmax - xx3rd) / (xm * pxdots - 1);   /* calculate stepsizes */
  366.          pdely  = (yymax - yy3rd) / (ym * pydots - 1);
  367.          pdelx2 = (xx3rd - xxmin) / (ym * pydots - 1);
  368.          pdely2 = (yy3rd - yymin) / (xm * pxdots - 1);
  369.  
  370.          /* save corners */
  371.          pxxmin = xxmin;
  372.          pyymax = yymax;
  373.       }
  374.       for (i = 0; i < (int)xm; i++)  /* columns */
  375.       for (j = 0; j < (unsigned int)ym; j++)  /* rows    */
  376.       {
  377.          if (xm > 1 || ym > 1)
  378.          {
  379.             int w;
  380.             char c;
  381.             char PCommandName[80];
  382.             w=0;
  383.             while(w < (int)strlen(CommandName))
  384.             {
  385.                c = CommandName[w];
  386.                if(isspace(c) || c == 0)
  387.                   break;
  388.                PCommandName[w] = c;
  389.                w++;
  390.             }
  391.             PCommandName[w] = 0;
  392.             {
  393.                char buf[20];
  394.                sprintf(buf,"_%c%c",PAR_KEY(i),PAR_KEY(j));
  395.                strcat(PCommandName,buf);
  396.             }
  397.             fprintf(parmfile, "%-19s{",PCommandName);
  398.             xxmin = pxxmin + pdelx*(i*pxdots) + pdelx2*(j*pydots);
  399.             xxmax = pxxmin + pdelx*((i+1)*pxdots - 1) + pdelx2*((j+1)*pydots - 1);
  400.             yymin = pyymax - pdely*((j+1)*pydots - 1) - pdely2*((i+1)*pxdots - 1);
  401.             yymax = pyymax - pdely*(j*pydots) - pdely2*(i*pxdots);
  402.             if (have3rd)
  403.             {
  404.                xx3rd = pxxmin + pdelx*(i*pxdots) + pdelx2*((j+1)*pydots - 1);
  405.                yy3rd = pyymax - pdely*((j+1)*pydots - 1) - pdely2*(i*pxdots);
  406.             }
  407.             else
  408.             {
  409.                xx3rd = xxmin;
  410.                yy3rd = yymin;
  411.             }
  412.             fprintf(fpbat,"Fractint batch=yes overwrite=yes @%s/%s\n",CommandFile,PCommandName);
  413.             fprintf(fpbat,"If Errorlevel 2 goto oops\n");
  414.          }
  415.          else
  416.             fprintf(parmfile, "%-19s{", CommandName);
  417.          if (CommandComment1[0])
  418.             fprintf(parmfile, " ; %s", CommandComment1);
  419.          fputc('\n', parmfile);
  420.          {
  421.             char buf[25];
  422.             memset(buf, ' ', 23);
  423.             buf[23] = 0;
  424.             buf[21] = ';';
  425.             if (CommandComment2[0])
  426.                fprintf(parmfile, "%s%s\n", buf, CommandComment2);
  427.             if (CommandComment3[0])
  428.                fprintf(parmfile, "%s%s\n", buf, CommandComment3);
  429.             if (CommandComment4[0])
  430.                fprintf(parmfile, "%s%s\n", buf, CommandComment4);
  431.          }
  432.          write_batch_parms(colorspec, maxcolor);   /* write the parameters */
  433.          if(xm > 1 || ym > 1)
  434.          {
  435.             fprintf(parmfile,"  video=%s", vidmde);
  436.             fprintf(parmfile," savename=frmig_%c%c\n", PAR_KEY(i), PAR_KEY(j));
  437.          }
  438.          fprintf(parmfile, "  }\n\n");
  439.       }
  440.       if(xm > 1 || ym > 1)
  441.          {
  442.          fprintf(fpbat,"Fractint makemig=%d/%d\n",xm,ym);
  443.          fprintf(fpbat,"Rem Simplgif fractmig.gif simplgif.gif  in case you need it\n");
  444.          fprintf(fpbat,":oops\n");
  445.          fclose(fpbat);
  446.          }
  447. /*******end here */
  448.  
  449.       if (gotinfile)
  450.       {                         /* copy the rest of the file */
  451.          while ((i = file_gets(buf, 255, infile)) == 0)
  452.             ; /* skip blanks */
  453.          while (i >= 0)
  454.          {
  455.             fputs(buf, parmfile);
  456.             fputc('\n', parmfile);
  457.             i = file_gets(buf, 255, infile);
  458.          }
  459.          fclose(infile);
  460.       }
  461.       fclose(parmfile);
  462.       if (gotinfile)
  463.       {                         /* replace the original file with the new */
  464.          unlink(CommandFile);   /* success assumed on these lines       */
  465.          rename(outname, CommandFile);  /* since we checked earlier with
  466.                                          * access */
  467.       }
  468.       break;
  469.    }
  470.    helpmode = oldhelpmode;
  471.    unstackscreen();
  472. }
  473. #ifdef C6
  474. #pragma optimize("e",on)  /* back to normal */
  475. #endif
  476.  
  477. static struct write_batch_data { /* buffer for parms to break lines nicely */
  478.    int len;
  479.    char *buf;
  480.    } *wbdata;
  481.  
  482. static void write_batch_parms(char *colorinf,int maxcolor)
  483. {
  484.    char far *saveshared;
  485.    int i,j,k;
  486.    double Xctr, Yctr;
  487.    LDBL Magnification;
  488.    double Xmagfactor, Rotation, Skew;
  489.    struct write_batch_data wb_data;
  490.    char *sptr;
  491.    char buf[81];
  492.    bf_t bfXctr=NULL, bfYctr=NULL;
  493.    int saved;
  494.    saved = save_stack();
  495.    if(bf_math)
  496.    {
  497.       bfXctr = alloc_stack(bflength+2);
  498.       bfYctr = alloc_stack(bflength+2);
  499.    }
  500.    wbdata = &wb_data;
  501.    wb_data.len = 0; /* force first parm to start on new line */
  502.  
  503.    /* Using near string boxx for buffer after saving to extraseg */
  504.  
  505.    saveshared = MK_FP(extraseg,0);
  506.    far_memcpy(saveshared,boxx,10000);
  507.    far_memset(boxx,0,10000);
  508.    wb_data.buf = (char *)boxx;
  509.  
  510.    if (display3d <= 0) { /* a fractal was generated */
  511.  
  512.       /****** fractal only parameters in this section *******/
  513.       put_parm(" reset"); /* the following should match code in ENCODER.C */
  514.       if (fractype == LYAPUNOV ||
  515.           fractype == FROTH || fractype == FROTHFP ||
  516.           fix_bof() || fix_period_bof() || use_old_distest || decomp[0] == 2)
  517.         put_parm("=%d",min(save_release,release));
  518.       else
  519.         put_parm("=%d",release);
  520.  
  521.       if (*(sptr = curfractalspecific->name) == '*') ++sptr;
  522.       put_parm( s_seqs,s_type,sptr);
  523.  
  524.       if (fractype == JULIBROT || fractype == JULIBROTFP)
  525.       {
  526.            put_parm(" %s=%.15g/%.15g/%.15g/%.15g",
  527.                s_julibrotfromto,mxmaxfp,mxminfp,mymaxfp,myminfp);
  528.          /* these rarely change */
  529.          if(originfp != 8 || heightfp != 7 || widthfp != 10 || distfp != 24
  530.                           || depthfp != 8 || zdots != 128)
  531.             put_parm(" %s=%d/%g/%g/%g/%g/%g",s_julibrot3d,
  532.                 zdots, originfp, depthfp, heightfp, widthfp,distfp);
  533.          if(eyesfp != 0)
  534.             put_parm(" %s=%g",s_julibroteyes,eyesfp);
  535.          if(neworbittype != JULIA)
  536.          {
  537.             char *name;
  538.             name = fractalspecific[neworbittype].name;
  539.             if(*name=='*')
  540.                name++;
  541.             put_parm(s_seqs,s_orbitname,name);
  542.          }
  543.          if(juli3Dmode != 0)
  544.             put_parm(s_seqs,s_3dmode,juli3Doptions[juli3Dmode]);
  545.       }
  546.       if (fractype == FORMULA || fractype == FFORMULA)
  547.       {
  548.      put_filename(s_formulafile,FormFileName);
  549.      put_parm( s_seqs,s_formulaname,FormName);
  550.       }
  551.       if (fractype == LSYSTEM)
  552.       {
  553.      put_filename(s_lfile,LFileName);
  554.      put_parm( s_seqs,s_lname,LName);
  555.       }
  556.       if (fractype == IFS || fractype == IFS3D)
  557.       {
  558.      put_filename(s_ifsfile,IFSFileName);
  559.      put_parm( s_seqs,s_ifs,IFSName);
  560.       }
  561.       if (fractype == INVERSEJULIA || fractype == INVERSEJULIAFP)
  562.      put_parm( " %s=%s/%s",s_miim,JIIMmethod[major_method], JIIMleftright[minor_method]);
  563.  
  564.       showtrig(buf); /* this function is in miscres.c */
  565.       if (buf[0])
  566.      put_parm(buf);
  567.  
  568.       if (usr_stdcalcmode != 'g')
  569.      put_parm(" %s=%c",s_passes,usr_stdcalcmode);
  570.  
  571.       if (usemag)
  572.       {
  573.          if (bf_math)
  574.          {
  575.             int digits;
  576.             cvtcentermagbf(bfXctr, bfYctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  577.             digits = getprecbf(MAXREZ);
  578.             put_parm(" %s=",s_centermag);
  579.             put_bf(0,bfXctr,digits);
  580.             put_bf(1,bfYctr,digits);
  581.          }
  582.          else /* !bf_math */
  583.          {
  584.             cvtcentermag(&Xctr, &Yctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  585.             put_parm(" %s=",s_centermag);
  586.             put_parm((delmin > 1000) ? "%g/%g" : "%+20.17lf/%+20.17lf", Xctr, Yctr);
  587.          }
  588. #ifdef USE_LONG_DOUBLE
  589.          put_parm("/%.7Lg",Magnification); /* precision of magnification not critical, but magnitude is */
  590. #else
  591.          put_parm("/%.7lg",Magnification); /* precision of magnification not critical, but magnitude is */
  592. #endif
  593.          /* Round to avoid ugly decimals, precision here is not critical */
  594.          /* Don't round Xmagfactor if it's small */
  595.          if (fabs(Xmagfactor) > 0.5) /* or so, exact value isn't important */
  596.             Xmagfactor = (sign(Xmagfactor) * (long)(fabs(Xmagfactor) * 1e4 + 0.5)) / 1e4;
  597.          /* Just truncate these angles.  Who cares about 1/1000 of a degree */
  598.          Rotation   = (long)(Rotation   * 1e3)/1e3;
  599.          Skew       = (long)(Skew       * 1e3)/1e3;
  600.          if (Xmagfactor != 1 || Rotation != 0 || Skew != 0)
  601.          { /* Only put what is necessary */
  602.             /* The difference with Xmagfactor is that it is normally */
  603.             /* near 1 while the others are normally near 0 */
  604.             if (fabs(Xmagfactor) >= 1)
  605.                put_float(1,Xmagfactor,5); /* put_float() uses %g */
  606.             else /* abs(Xmagfactor) is < 1 */
  607.                put_float(1,Xmagfactor,4); /* put_float() uses %g */
  608.             if (Rotation != 0 || Skew != 0)
  609.             {
  610.                /* Use precision=6 here.  These angle have already been rounded        */
  611.                /* to 3 decimal places, but angles like 123.456 degrees need 6         */
  612.                /* sig figs to get 3 decimal places.  Trailing 0's are dropped anyway. */
  613.                put_float(1,Rotation,6);
  614.                if (Skew != 0)
  615.                {
  616.                   put_float(1,Skew,6);
  617.                }
  618.             }
  619.          }
  620.       }
  621.       else /* not usemag */
  622.       {         
  623.          put_parm( " %s=",s_corners);
  624.          if(bf_math)
  625.          {
  626.             int digits;
  627.             digits = getprecbf(MAXREZ);
  628.             put_bf(0,bfxmin,digits);
  629.         put_bf(1,bfxmax,digits);
  630.         put_bf(1,bfymin,digits);
  631.         put_bf(1,bfymax,digits);
  632.         if (cmp_bf(bfx3rd,bfxmin) || cmp_bf(bfy3rd,bfymin)) 
  633.         {
  634.            put_bf(1,bfx3rd,digits);
  635.            put_bf(1,bfy3rd,digits);
  636.         }
  637.      }   
  638.          else 
  639.          {
  640.             int xdigits,ydigits;
  641.             xdigits = getprec(xxmin,xxmax,xx3rd);
  642.             ydigits = getprec(yymin,yymax,yy3rd);
  643.         put_float(0,xxmin,xdigits);
  644.         put_float(1,xxmax,xdigits);
  645.         put_float(1,yymin,ydigits);
  646.         put_float(1,yymax,ydigits);
  647.         if (xx3rd != xxmin || yy3rd != yymin) 
  648.         {
  649.            put_float(1,xx3rd,xdigits);
  650.            put_float(1,yy3rd,ydigits);
  651.         }
  652.          }
  653.       }   
  654.  
  655.       for(i = (MAXPARAMS-1); i >= 0; --i)
  656.           if(typehasparm((fractype==JULIBROT || fractype==JULIBROTFP)
  657.                           ?neworbittype:fractype,i) != NULL) break;
  658.  
  659.       if (i >= 0) {
  660.         if (fractype == CELLULAR)
  661.           put_parm(" %s=%.1f",s_params,param[0]);
  662.         else
  663.         {
  664. #ifdef USE_LONG_DOUBLE
  665.           if(debugflag == 750)
  666.              put_parm(" %s=%.17Lg",s_params,(long double)param[0]);
  667.           else
  668. #endif
  669.           put_parm(" %s=%.17g",s_params,param[0]);
  670.         }
  671.         for (j = 1; j <= i; ++j)
  672.         if (fractype == CELLULAR)
  673.           put_parm("/%.1f",param[j]);
  674.         else
  675.         {
  676. #ifdef USE_LONG_DOUBLE
  677.           if(debugflag == 750)
  678.              put_parm("/%.17Lg",(long double)param[j]);
  679.           else
  680. #endif
  681.           put_parm("/%.17g",param[j]);
  682.         }
  683.       }
  684.  
  685.       if(useinitorbit == 2)
  686.      put_parm( " %s=pixel",s_initorbit);
  687.       else if(useinitorbit == 1)
  688.      put_parm( " %s=%.15g/%.15g",s_initorbit,initorbit.x,initorbit.y);
  689.  
  690.       if (floatflag)
  691.      put_parm( " %s=y",s_float);
  692.  
  693.       if (maxit != 150)
  694.      put_parm(" %s=%ld",s_maxiter,maxit);
  695.  
  696.       if(bailout && (potflag == 0 || potparam[2] == 0.0))
  697.      put_parm(" %s=%ld",s_bailout,bailout);
  698.  
  699.       if(bailoutest != Mod && (potflag == 0 || potparam[2] == 0.0)) {
  700.      put_parm(" %s=",s_bailoutest);
  701.      if (bailoutest == Real)
  702.         put_parm( s_real);
  703.      else if (bailoutest == Imag)
  704.         put_parm(s_imag);
  705.      else if (bailoutest == Or)
  706.         put_parm(s_or);
  707.      else if (bailoutest == And)
  708.         put_parm(s_and);
  709.      else
  710.         put_parm(s_mod); /* default, just in case */
  711.       }
  712.       if(fillcolor != -1) {
  713.        put_parm(" %s=",s_fillcolor);
  714.     put_parm( "%d",fillcolor);
  715.       }
  716.       if (inside != 1) {
  717.      put_parm(" %s=",s_inside);
  718.      if (inside == -1)
  719.         put_parm( s_maxiter);
  720.      else if (inside == -59)
  721.         put_parm(s_zmag);
  722.      else if (inside == -60)
  723.         put_parm(s_bof60);
  724.      else if (inside == -61)
  725.         put_parm(s_bof61);
  726.      else if (inside == -100)
  727.         put_parm(s_epscross);
  728.      else if (inside == -101)
  729.         put_parm(s_startrail);
  730.      else if (inside == -102)
  731.         put_parm(s_period);
  732.      else
  733.         put_parm( "%d",inside);
  734.      }
  735.       if (outside != -1)
  736.       {
  737.      put_parm(" %s=",s_outside);
  738.      if (outside == -2)
  739.         put_parm(s_real);
  740.      else if (outside == -3)
  741.         put_parm(s_imag);
  742.      else if (outside == -4)
  743.         put_parm(s_mult);
  744.      else if (outside == -5)
  745.         put_parm(s_sum);
  746.      else if (outside == -6)
  747.         put_parm(s_atan);
  748.      else
  749.         put_parm( "%d",outside);
  750.       }
  751.  
  752.       if(LogFlag) {
  753.      put_parm( " %s=",s_logmap);
  754.      if(LogFlag == -1)
  755.         put_parm( "old");
  756.      else if(LogFlag == 1)
  757.         put_parm( s_yes);
  758.      else
  759.         put_parm( "%d", LogFlag);
  760.      }
  761.  
  762.       if (potflag) {
  763.        put_parm( " %s=%d/%g/%d",s_potential,
  764.            (int)potparam[0],potparam[1],(int)potparam[2]);
  765.        if(pot16bit)
  766.         put_parm( "/%s",s_16bit);
  767.      }
  768.       if (invert)
  769.      put_parm( " %s=%g/%g/%g",s_invert,
  770.          inversion[0], inversion[1], inversion[2]);
  771.       if (decomp[0])
  772.      put_parm( s_seqd,s_decomp, decomp[0]);
  773.       if (distest) {
  774.      put_parm( s_seqdddd,s_distest, distest, distestwidth,
  775.                  pseudox?pseudox:xdots,pseudoy?pseudoy:ydots);
  776.       }
  777.       if (old_demm_colors)
  778.      put_parm( s_olddemmcolors, old_demm_colors);
  779.       if (usr_biomorph != -1)
  780.      put_parm( s_seqd,s_biomorph, usr_biomorph);
  781.       if (finattract)
  782.      put_parm(" %s=y",s_finattract);
  783.  
  784.       if (forcesymmetry != 999) {
  785.          static FCODE msg[] = 
  786.             {"Regenerate before <b> to get correct symmetry"};
  787.          if(forcesymmetry == 1000)
  788.             stopmsg(0,msg);
  789.      put_parm( " %s=",s_symmetry);
  790.      if (forcesymmetry==XAXIS)
  791.         put_parm(s_xaxis);
  792.      else if(forcesymmetry==YAXIS)
  793.         put_parm(s_yaxis);
  794.      else if(forcesymmetry==XYAXIS)
  795.         put_parm(s_xyaxis);
  796.      else if(forcesymmetry==ORIGIN)
  797.         put_parm(s_origin);
  798.      else if(forcesymmetry==PI_SYM)
  799.         put_parm(s_pi);
  800.      else
  801.         put_parm(s_none);
  802.      }
  803.  
  804.       if (periodicitycheck != 1)
  805.      put_parm( s_seqd,s_periodicity,periodicitycheck);
  806.  
  807.       if (rflag)
  808.      put_parm( s_seqd,s_rseed,rseed);
  809.  
  810.       if (rangeslen) {
  811.      put_parm(" %s=",s_ranges);
  812.      i = 0;
  813.      while (i < rangeslen) {
  814.         if (i)
  815.            put_parm("/");
  816.         if (ranges[i] == -1) {
  817.            put_parm("-%d/",ranges[++i]);
  818.            ++i;
  819.            }
  820.         put_parm("%d",ranges[i++]);
  821.         }
  822.      }
  823.       }
  824.  
  825.    if (display3d >= 1) {
  826.       /***** 3d transform only parameters in this section *****/
  827.       if(display3d == 2)
  828.          put_parm( s_seqs,s_3d,s_overlay);
  829.       else
  830.       put_parm( s_seqs,s_3d,s_yes);
  831.       if (loaded3d == 0)
  832.      put_filename(s_filename,readname);
  833.       if (SPHERE) {
  834.      put_parm( " %s=y",s_sphere);
  835.      put_parm( s_seqdd,s_latitude, THETA1, THETA2);
  836.      put_parm( s_seqdd,s_longitude, PHI1, PHI2);
  837.      put_parm( s_seqd,s_radius, RADIUS);
  838.      }
  839.       put_parm( s_seqdd,s_scalexyz, XSCALE, YSCALE);
  840.       put_parm( s_seqd,s_roughness, ROUGH);
  841.       put_parm( s_seqd,s_waterline, WATERLINE);
  842.       if (FILLTYPE)
  843.      put_parm( s_seqd,s_filltype, FILLTYPE);
  844.       if (transparent[0] || transparent[1])
  845.      put_parm( s_seqdd,s_transparent, transparent[0],transparent[1]);
  846.       if (preview) {
  847.      put_parm( s_seqs,s_preview,s_yes);
  848.      if (showbox)
  849.         put_parm( s_seqs,s_showbox,s_yes);
  850.      put_parm( s_seqd,s_coarse,previewfactor);
  851.      }
  852.       if (RAY) {
  853.      put_parm( s_seqd,s_ray,RAY);
  854.      if (BRIEF)
  855.         put_parm(" %s=y",s_brief);
  856.      }
  857.       if (FILLTYPE > 4) {
  858.      put_parm( s_seqddd,s_lightsource, XLIGHT, YLIGHT, ZLIGHT);
  859.      if (LIGHTAVG)
  860.         put_parm( " %=%d",s_smoothing, LIGHTAVG);
  861.      }
  862.       if (RANDOMIZE)
  863.      put_parm( s_seqd,s_randomize,RANDOMIZE);
  864.       if (Targa_Out)
  865.      put_parm( " %s=y",s_fullcolor);
  866.       if (grayflag)
  867.      put_parm( " %s=y",s_usegrayscale);
  868.       if (Ambient)
  869.      put_parm( s_seqd,s_ambient,Ambient);
  870.       if (haze)
  871.      put_parm( s_seqd,s_haze,haze);
  872.       }
  873.  
  874.    if (display3d) {        /* universal 3d */
  875.       /***** common (fractal & transform) 3d parameters in this section *****/
  876.       if (!SPHERE || display3d < 0)
  877.      put_parm( s_seqddd,s_rotation, XROT, YROT, ZROT);
  878.       put_parm( s_seqd,s_perspective, ZVIEWER);
  879.       put_parm( s_seqdd,s_xyshift, XSHIFT, YSHIFT);
  880.       if(xtrans || ytrans)
  881.      put_parm( s_seqdd,s_xyadjust,xtrans,ytrans);
  882.       if(glassestype) {
  883.      put_parm( s_seqd,s_stereo,glassestype);
  884.      put_parm( s_seqd,s_interocular,eyeseparation);
  885.      put_parm( s_seqd,s_converge,xadjust);
  886.      put_parm( " %s=%d/%d/%d/%d",s_crop,
  887.          red_crop_left,red_crop_right,blue_crop_left,blue_crop_right);
  888.      put_parm( s_seqdd,s_bright,
  889.          red_bright,blue_bright);
  890.      }
  891.       }
  892.  
  893.    /***** universal parameters in this section *****/
  894.  
  895.    if(viewwindow == 1)
  896.    {
  897.       put_parm(" %s=%g/%g",s_viewwindows,viewreduction,finalaspectratio);
  898.       if(viewcrop)
  899.          put_parm("/%s",s_yes);
  900.       else
  901.          put_parm("/%s",s_no);
  902.       put_parm("/%d/%d",viewxdots,viewydots);
  903.    }
  904.    if (*colorinf != 'n') {
  905.       put_parm(" %s=",s_colors);
  906.       if (*colorinf == '@')
  907.      put_parm(colorinf);
  908.       else {
  909.      int curc,scanc,force,diffmag = -1;
  910.      int delta,diff1[4][3],diff2[4][3];
  911.      curc = force = 0;
  912.      for(;;) {
  913.         /* emit color in rgb 3 char encoded form */
  914.         for (j = 0; j < 3; ++j) {
  915.            if ((k = dacbox[curc][j]) < 10) k += '0';
  916.            else if (k < 36)            k += ('A' - 10);
  917.            else                   k += ('_' - 36);
  918.            buf[j] = (char)k;
  919.            }
  920.         buf[3] = 0;
  921.         put_parm(buf);
  922.         if (++curc >= maxcolor)     /* quit if done last color */
  923.            break;
  924.         /* Next a P Branderhorst special, a tricky scan for smooth-shaded
  925.            ranges which can be written as <nn> to compress .par file entry.
  926.            Method used is to check net change in each color value over
  927.            spans of 2 to 5 color numbers.  First time for each span size
  928.            the value change is noted.  After first time the change is
  929.            checked against noted change.  First time it differs, a
  930.            a difference of 1 is tolerated and noted as an alternate
  931.            acceptable change.  When change is not one of the tolerated
  932.            values, loop exits. */
  933.         if (force) {
  934.            --force;
  935.            continue;
  936.            }
  937.         scanc = curc;
  938.         while (scanc < maxcolor) {     /* scan while same diff to next */
  939.            if ((i = scanc - curc) > 3) /* check spans up to 4 steps */
  940.           i = 3;
  941.            for (k = 0; k <= i; ++k) {
  942.           for (j = 0; j < 3; ++j) { /* check pattern of chg per color */
  943.              delta = (int)dacbox[scanc][j] - (int)dacbox[scanc-k-1][j];
  944.              if (k == scanc - curc)
  945.             diff1[k][j] = diff2[k][j] = delta;
  946.              else
  947.             if (delta != diff1[k][j] && delta != diff2[k][j]) {
  948.                diffmag = abs(delta - diff1[k][j]);
  949.                if (diff1[k][j] != diff2[k][j] || diffmag != 1)
  950.                   break;
  951.                diff2[k][j] = delta;
  952.                }
  953.              }
  954.           if (j < 3) break; /* must've exited from inner loop above */
  955.           }
  956.            if (k <= i) break;   /* must've exited from inner loop above */
  957.            ++scanc;
  958.            }
  959.         /* now scanc-1 is next color which must be written explicitly */
  960.         if (scanc - curc > 2) { /* good, we have a shaded range */
  961.            if (scanc != maxcolor) {
  962.                   static FCODE msg[] = {"Tell Tim Wegner to check diffmag MISCOVL.C"};
  963.                   if(diffmag < 0) stopmsg(0,msg);
  964.           if (diffmag < 3) {  /* not a sharp slope change? */
  965.              force = 2;       /* force more between ranges, to stop  */
  966.              --scanc;          /* "drift" when load/store/load/store/ */
  967.              }
  968.           if (k) {          /* more of the same             */
  969.              force += k;
  970.              --scanc;
  971.              }
  972.           }
  973.            if (--scanc - curc > 1) {
  974.           put_parm("<%d>",scanc-curc);
  975.           curc = scanc;
  976.           }
  977.            else           /* changed our mind */
  978.           force = 0;
  979.            }
  980.         }
  981.      }
  982.       }
  983.  
  984.    if (rotate_lo != 1 || rotate_hi != 255)
  985.       put_parm( s_seqdd,s_cyclerange,rotate_lo,rotate_hi);
  986.  
  987.    while (wbdata->len) /* flush the buffer */
  988.       put_parm_line();
  989.    /* restore previous boxx data from extraseg */
  990.    far_memcpy(boxx, saveshared, 10000);
  991.    restore_stack(saved);
  992. }
  993.  
  994. static void put_filename(char *keyword,char *fname)
  995. {
  996.    char *p;
  997.    if (*fname && !endswithslash(fname)) {
  998.       if ((p = strrchr(fname, SLASHC)) != NULL)
  999.      if (*(fname = p+1) == 0) return;
  1000.       put_parm(s_seqs,keyword,fname);
  1001.       }
  1002. }
  1003.  
  1004. #ifndef XFRACT
  1005. static void put_parm(char *parm,...)
  1006. #else
  1007. static void put_parm(va_alist)
  1008. va_dcl
  1009. #endif
  1010. {
  1011.    char *bufptr;
  1012.    va_list args;
  1013.  
  1014. #ifndef XFRACT
  1015.    va_start(args,parm);
  1016. #else
  1017.    char * parm;
  1018.  
  1019.    va_start(args);
  1020.    parm = va_arg(args,char *);
  1021. #endif
  1022.    if (*parm == ' '             /* starting a new parm */
  1023.      && wbdata->len == 0)    /* skip leading space */
  1024.       ++parm;
  1025.    bufptr = wbdata->buf + wbdata->len;
  1026.    vsprintf(bufptr,parm,args);
  1027.    while (*(bufptr++))
  1028.       ++wbdata->len;
  1029.    while (wbdata->len > 200)
  1030.       put_parm_line();
  1031. }
  1032.  
  1033. #define NICELINELEN 68
  1034. #define MAXLINELEN  72
  1035.  
  1036. static void put_parm_line()
  1037. {
  1038.    int len,c;
  1039.    if ((len = wbdata->len) > NICELINELEN) {
  1040.       len = NICELINELEN+1;
  1041.       while (--len != 0 && wbdata->buf[len] != ' ') { }
  1042.       if (len == 0) {
  1043.      len = NICELINELEN-1;
  1044.      while (++len < MAXLINELEN
  1045.        && wbdata->buf[len] && wbdata->buf[len] != ' ') { }
  1046.      }
  1047.       }
  1048.    c = wbdata->buf[len];
  1049.    wbdata->buf[len] = 0;
  1050.    fputs("  ",parmfile);
  1051.    fputs(wbdata->buf,parmfile);
  1052.    if (c && c != ' ')
  1053.       fputc('\\',parmfile);
  1054.    fputc('\n',parmfile);
  1055.    if ((wbdata->buf[len] = (char)c) == ' ')
  1056.       ++len;
  1057.    wbdata->len -= len;
  1058.    strcpy(wbdata->buf,wbdata->buf+len);
  1059. }
  1060.  
  1061. int getprecbf_mag()
  1062. {
  1063.    double Xmagfactor, Rotation, Skew;
  1064.    LDBL Magnification;
  1065.    bf_t bXctr, bYctr;
  1066.    int saved,dec;
  1067.  
  1068.    saved = save_stack();
  1069.    bXctr            = alloc_stack(bflength+2);
  1070.    bYctr            = alloc_stack(bflength+2);
  1071.    /* this is just to find Magnification */
  1072.    cvtcentermagbf(bXctr, bYctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  1073.    restore_stack(saved);
  1074.  
  1075.    /* I don't know if this is portable, but something needs to */
  1076.    /* be used in case compiler's LDBL_MAX is not big enough    */
  1077.    if (Magnification > LDBL_MAX || Magnification < -LDBL_MAX)
  1078.       return(-1);
  1079.  
  1080.    dec = getpower10(Magnification) + 4; /* 4 digits of padding sounds good */
  1081.    return(dec);
  1082. }   
  1083.  
  1084. static int getprec(double a,double b,double c)
  1085. {
  1086.    double diff,temp;
  1087.    int digits;
  1088.    double highv = 1.0E20;
  1089.    if ((diff = fabs(a - b)) == 0.0) diff = highv;
  1090.    if ((temp = fabs(a - c)) == 0.0) temp = highv;
  1091.    if (temp < diff) diff = temp;
  1092.    if ((temp = fabs(b - c)) == 0.0) temp = highv;
  1093.    if (temp < diff) diff = temp;
  1094.    digits = 7;
  1095.    if(debugflag >= 700 && debugflag < 720 )
  1096.       digits =  debugflag - 700;
  1097.    while (diff < 1.0 && digits <= DBL_DIG+1) {
  1098.       diff *= 10;
  1099.       ++digits;
  1100.       }
  1101.    return(digits);
  1102. }
  1103.  
  1104. /* This function calculates the precision needed to distiguish adjacent
  1105.    pixels at Fractint's maximum resolution of MAXPIXELS by MAXPIXELS 
  1106.    (if rez==MAXREZ) or at current resolution (if rez==CURRENTREZ)    */
  1107. int getprecbf(int rezflag)
  1108. {
  1109.    bf_t del1,del2, one, bfxxdel, bfxxdel2, bfyydel, bfyydel2;
  1110.    int digits,dec;
  1111.    int saved;
  1112.    int rez;
  1113.    saved    = save_stack();
  1114.    del1     = alloc_stack(bflength+2);
  1115.    del2     = alloc_stack(bflength+2);
  1116.    one      = alloc_stack(bflength+2);
  1117.    bfxxdel   = alloc_stack(bflength+2);
  1118.    bfxxdel2  = alloc_stack(bflength+2);
  1119.    bfyydel   = alloc_stack(bflength+2);
  1120.    bfyydel2  = alloc_stack(bflength+2);
  1121.    floattobf(one,1.0);
  1122.    if(rezflag == MAXREZ)
  1123.       rez = MAXPIXELS -1;
  1124.    else
  1125.       rez = xdots-1;   
  1126.  
  1127.    /* bfxxdel = (bfxmax - bfx3rd)/(xdots-1) */
  1128.    sub_bf(bfxxdel, bfxmax, bfx3rd);
  1129.    div_a_bf_int(bfxxdel, (U16)rez);
  1130.  
  1131.    /* bfyydel2 = (bfy3rd - bfymin)/(xdots-1) */
  1132.    sub_bf(bfyydel2, bfy3rd, bfymin);
  1133.    div_a_bf_int(bfyydel2, (U16)rez);
  1134.  
  1135.    if(rezflag == CURRENTREZ)
  1136.       rez = ydots-1;   
  1137.  
  1138.    /* bfyydel = (bfymax - bfy3rd)/(ydots-1) */
  1139.    sub_bf(bfyydel, bfymax, bfy3rd);
  1140.    div_a_bf_int(bfyydel, (U16)rez);
  1141.  
  1142.    /* bfxxdel2 = (bfx3rd - bfxmin)/(ydots-1) */
  1143.    sub_bf(bfxxdel2, bfx3rd, bfxmin);
  1144.    div_a_bf_int(bfxxdel2, (U16)rez);
  1145.  
  1146.    abs_a_bf(add_bf(del1,bfxxdel,bfxxdel2));
  1147.    abs_a_bf(add_bf(del2,bfyydel,bfyydel2));
  1148.    if(cmp_bf(del2,del1) < 0)
  1149.        copy_bf(del1, del2);
  1150.    if(cmp_bf(del1,clear_bf(del2)) == 0)
  1151.    {
  1152.       restore_stack(saved);
  1153.       return(-1);
  1154.    }
  1155.    digits = 1;
  1156.    while(cmp_bf(del1,one) < 0)
  1157.    {
  1158.       digits++;
  1159.       mult_a_bf_int(del1,10);
  1160.    }   
  1161.    digits = max(digits,3);
  1162.    restore_stack(saved);
  1163.    dec = getprecbf_mag();
  1164.    return(max(digits,dec));
  1165. }
  1166.  
  1167. /* This function calculates the precision needed to distiguish adjacent
  1168.    pixels at Fractint's maximum resolution of MAXPIXELS by MAXPIXELS 
  1169.    (if rez==MAXREZ) or at current resolution (if rez==CURRENTREZ)    */
  1170. int getprecdbl(int rezflag)
  1171. {
  1172.    LDBL del1,del2, xdel, xdel2, ydel, ydel2;
  1173.    int digits;
  1174.    LDBL rez;
  1175.    if(rezflag == MAXREZ)
  1176.       rez = MAXPIXELS -1;
  1177.    else
  1178.       rez = xdots-1;   
  1179.       
  1180.    xdel =  ((LDBL)xxmax - (LDBL)xx3rd)/rez;
  1181.    ydel2 = ((LDBL)yy3rd - (LDBL)yymin)/rez;
  1182.  
  1183.    if(rezflag == CURRENTREZ)
  1184.       rez = ydots-1;   
  1185.  
  1186.    ydel = ((LDBL)yymax - (LDBL)yy3rd)/rez;
  1187.    xdel2 = ((LDBL)xx3rd - (LDBL)xxmin)/rez;
  1188.  
  1189.    del1 = fabsl(xdel) + fabsl(xdel2);
  1190.    del2 = fabsl(ydel) + fabsl(ydel2);
  1191.    if(del2 < del1)
  1192.        del1 = del2;
  1193.    if(del1 == 0)
  1194.    {
  1195. #ifdef DEBUG
  1196.       showcornersdbl("getprecdbl");
  1197. #endif
  1198.       return(-1);
  1199.    }
  1200.    digits = 1;
  1201.    while(del1 < 1.0)
  1202.    {
  1203.       digits++;
  1204.       del1 *= 10;
  1205.    }   
  1206.    digits = max(digits,3);
  1207.    return(digits);
  1208. }
  1209.  
  1210. static void put_float(int slash,double fnum,int prec)
  1211. {  char buf[40];
  1212.    char *bptr, *dptr;
  1213.    bptr = buf;
  1214.    if (slash)
  1215.       *(bptr++) = '/';
  1216. /*   sprintf(bptr,"%1.*f",prec,fnum); */
  1217. #ifdef USE_LONG_DOUBLE
  1218.      /* Idea of long double cast is to squeeze out another digit or two
  1219.         which might be needed (we have found cases where this digit makes
  1220.         a difference.) But lets not do this at lower precision */
  1221.      if(prec > 15) 
  1222.         sprintf(bptr,"%1.*Lg",prec,(long double)fnum);
  1223.      else
  1224. #endif
  1225.      sprintf(bptr,"%1.*g",prec,(double)fnum);
  1226.  
  1227.    if ((dptr = strchr(bptr,'.')) != 0) {
  1228.       ++dptr;
  1229.       bptr = buf + strlen(buf);
  1230.       while (--bptr > dptr && *bptr == '0')
  1231.      *bptr = 0;
  1232.       }
  1233.    put_parm(buf);
  1234. }
  1235.  
  1236. static void put_bf(int slash,bf_t r, int prec)
  1237. {  
  1238.    char *buf; /* "/-1.xxxxxxE-1234" */
  1239.    char *bptr, *dptr, *exptr;
  1240.    /* buf = malloc(decimals+11); */
  1241.    buf = wbdata->buf+5000;  /* end of use suffix buffer, 5000 bytes safe */
  1242.    bptr = buf;
  1243.    if (slash)
  1244.       *(bptr++) = '/';
  1245.    bftostr(bptr, prec, r);
  1246.  
  1247.    if ((dptr = strchr(bptr,'.')) != 0) {
  1248.       ++dptr;
  1249.       if ((exptr = strchr(buf,'e')) !=0)  /* scientific notation with 'e'? */
  1250.          bptr = exptr;
  1251.       else
  1252.          bptr = buf + strlen(buf);
  1253.       while (--bptr > dptr && *bptr == '0')
  1254.      *bptr = 0;
  1255.       if(exptr && bptr < exptr -1) 
  1256.         strcat(buf,exptr);
  1257.    }     
  1258.    put_parm(buf);
  1259. }
  1260.  
  1261. #ifndef XFRACT
  1262. #include <direct.h>
  1263. void shell_to_dos()
  1264. {
  1265.    int drv;
  1266.    char *comspec;
  1267.    char curdir[80],*s;
  1268.    if ((comspec = getenv("COMSPEC")) == NULL)
  1269.       printf("Cannot find COMMAND.COM.\n");
  1270.    else {
  1271.       putenv("PROMPT='EXIT' returns to FRACTINT.$_$p$g");
  1272.       s = getcwd(curdir,100);
  1273.       drv = _getdrive();
  1274.       spawnl(P_WAIT, comspec, NULL);
  1275.       if(drv)
  1276.          _chdrive(drv);
  1277.       if(s)
  1278.          chdir(s);
  1279.       }
  1280. }
  1281.  
  1282. size_t showstack(void)
  1283. {
  1284. #ifdef _MSC_VER
  1285. #if (_MSC_VER == 700 || _MSC_VER == 800)
  1286.    return(_stackavail());
  1287. /* add other implementations here */
  1288. #elif (_MSC_VER == 600)
  1289.    return(stackavail());
  1290. #endif
  1291. #else   
  1292.    return(-1);
  1293. #endif
  1294. }
  1295.  
  1296. long fr_farfree(void)
  1297. {
  1298.    long j,j2; 
  1299.    BYTE huge *fartempptr;
  1300.    j = 0;
  1301.    j2 = 0x80000L;
  1302.    while ((j2 >>= 1) != 0)
  1303.       if ((fartempptr = (BYTE huge *)farmemalloc(j+j2)) != NULL) {
  1304.      farmemfree((void far*)fartempptr);
  1305.      j += j2;
  1306.      }
  1307.    return(j);
  1308. }
  1309.  
  1310. void showfreemem(void)
  1311. {
  1312.    char *tempptr;
  1313.    unsigned i,i2;
  1314.  
  1315.    char adapter_name[8];      /* entry lenth from VIDEO.ASM */
  1316.    char *adapter_ptr;
  1317.  
  1318.    printf("\n CPU type: %d  FPU type: %d  IIT FPU: %d  Video: %d",
  1319.       cpu, fpu, iit, video_type);
  1320.          
  1321.    adapter_ptr = &supervga_list;
  1322.    
  1323.    for(i = 0 ; ; i++) {        /* find the SuperVGA entry */
  1324.        int j;
  1325.        memcpy(adapter_name , adapter_ptr, 8);
  1326.        adapter_ptr += 8;
  1327.        if (adapter_name[0] == ' ') break;    /* end-of-the-list */
  1328.        if (adapter_name[6] == 0) continue;    /* not our adapter */
  1329.        adapter_name[6] = ' ';
  1330.        for (j = 0; j < 8; j++)
  1331.            if(adapter_name[j] == ' ')
  1332.                adapter_name[j] = 0;
  1333.        printf("  Video chip: %d (%s)",i+1,adapter_name);
  1334.        }
  1335.    printf("\n\n");
  1336.  
  1337.    i = 0;
  1338.    i2 = 0x8000;
  1339.    while ((i2 >>= 1) != 0)
  1340.       if ((tempptr = malloc(i+i2)) != NULL) {
  1341.      free(tempptr);
  1342.      i += i2;
  1343.      }
  1344.    printf(" %d NEAR bytes free \n", i);
  1345.  
  1346.    printf(" %ld FAR bytes free ", fr_farfree());
  1347.    {
  1348.       size_t stack;
  1349.       stack = showstack();
  1350. /*      if(stack >= 0) */ /* stack is unsigned */
  1351.          printf("\n %u STACK bytes free",stack);
  1352.    }
  1353.    printf("\n %ld used by HISTORY structure",
  1354.       sizeof(HISTORY)*(unsigned long)maxhistory);
  1355.    printf("\n %d video table used",showvidlength());
  1356.    printf("\n\n %Fs...\n",s_pressanykeytocontinue);
  1357.    getakey();
  1358. }
  1359. #endif
  1360.  
  1361. edit_text_colors()
  1362. {
  1363.    int save_debugflag,save_lookatmouse;
  1364.    int row,col,bkgrd;
  1365.    int rowf,colf,rowt,colt;
  1366.    char far *vidmem;
  1367.    char far *savescreen;
  1368.    char far *farp1; char far *farp2;
  1369.    int i,j,k;
  1370.    save_debugflag = debugflag;
  1371.    save_lookatmouse = lookatmouse;
  1372.    debugflag = 0;   /* don't get called recursively */
  1373.    lookatmouse = 2; /* text mouse sensitivity */
  1374.    row = col = bkgrd = rowt = rowf = colt = colf = 0;
  1375.    vidmem = MK_FP(0xB800,0);
  1376.    for(;;) {
  1377.       if (row < 0)  row = 0;
  1378.       if (row > 24) row = 24;
  1379.       if (col < 0)  col = 0;
  1380.       if (col > 79) col = 79;
  1381.       movecursor(row,col);
  1382.       i = getakey();
  1383.       if (i >= 'a' && i <= 'z') i -= 32; /* uppercase */
  1384.       switch (i) {
  1385.      case 27: /* esc */
  1386.         debugflag = save_debugflag;
  1387.         lookatmouse = save_lookatmouse;
  1388.         movecursor(25,80);
  1389.         return 0;
  1390.      case '/':
  1391.         farp1 = savescreen = farmemalloc(4000L);
  1392.         farp2 = vidmem;
  1393.         for (i = 0; i < 4000; ++i) { /* save and blank */
  1394.            *(farp1++) = *farp2;
  1395.            *(farp2++) = 0;
  1396.            }
  1397.         for (i = 0; i < 8; ++i)      /* 8 bkgrd attrs */
  1398.            for (j = 0; j < 16; ++j) { /* 16 fgrd attrs */
  1399.           k = i*16 + j;
  1400.           farp1 = vidmem + i*320 + j*10;
  1401.           *(farp1++) = ' '; *(farp1++) = (char)k;
  1402.           *(farp1++) = (char)(i+'0'); *(farp1++) = (char)k;
  1403.           *(farp1++) = (char)((j < 10) ? j+'0' : j+'A'-10); *(farp1++) = (char)k;
  1404.           *(farp1++) = ' '; *(farp1++) = (char)k;
  1405.           }
  1406.         getakey();
  1407.         farp1 = vidmem;
  1408.         farp2 = savescreen;
  1409.         for (i = 0; i < 4000; ++i) /* restore */
  1410.            *(farp1++) = *(farp2++);
  1411.         farmemfree(savescreen);
  1412.         break;
  1413.      case ',':
  1414.         rowf = row; colf = col; break;
  1415.      case '.':
  1416.         rowt = row; colt = col; break;
  1417.      case ' ': /* next color is background */
  1418.         bkgrd = 1; break;
  1419.      case 1075: /* cursor left  */
  1420.         --col; break;
  1421.      case 1077: /* cursor right */
  1422.         ++col; break;
  1423.      case 1072: /* cursor up    */
  1424.         --row; break;
  1425.      case 1080: /* cursor down  */
  1426.         ++row; break;
  1427.      case 13:   /* enter */
  1428.         *(vidmem + row*160 + col*2) = (char)getakey();
  1429.         break;
  1430.      default:
  1431.         if (i >= '0' && i <= '9')      i -= '0';
  1432.         else if (i >= 'A' && i <= 'F') i -= 'A'-10;
  1433.         else break;
  1434.         for (j = rowf; j <= rowt; ++j)
  1435.            for (k = colf; k <= colt; ++k) {
  1436.           farp1 = vidmem + j*160 + k*2 + 1;
  1437.           if (bkgrd) *farp1 = (char)((*farp1 & 15) + i * 16);
  1438.           else         *farp1 = (char)((*farp1 & 0xf0) + i);
  1439.           }
  1440.         bkgrd = 0;
  1441.      }
  1442.       }
  1443. }
  1444.  
  1445. static int *entsptr;
  1446. static int modes_changed;
  1447.  
  1448. int select_video_mode(int curmode)
  1449. {
  1450.    static FCODE o_hdg2[]={"key...name......................xdot.ydot.colr.comment.................."};
  1451.    static FCODE o_hdg1[]={"Select Video Mode"};
  1452.    char hdg2[sizeof(o_hdg2)];
  1453.    char hdg1[sizeof(o_hdg1)];
  1454.    
  1455.    int entnums[MAXVIDEOMODES];
  1456.    int attributes[MAXVIDEOMODES];
  1457.    int i,j,k,ret;
  1458.    int oldtabmode,oldhelpmode;
  1459.  
  1460.    load_fractint_cfg(0);    /* load fractint.cfg to extraseg */
  1461.  
  1462.    far_strcpy(hdg1,o_hdg1);
  1463.    far_strcpy(hdg2,o_hdg2);
  1464.  
  1465.    for (i = 0; i < vidtbllen; ++i) { /* init tables */
  1466.       entnums[i] = i;
  1467.       attributes[i] = 1;
  1468.       }
  1469.    entsptr = entnums;        /* for indirectly called subroutines */
  1470.  
  1471.    qsort(entnums,vidtbllen,sizeof(entnums[0]),entcompare); /* sort modes */
  1472.  
  1473.    /* pick default mode */
  1474.    if (curmode < 0) {
  1475.       switch (video_type) { /* set up a reasonable default (we hope) */
  1476.      case 1:  videoentry.videomodeax = 8;    /* hgc */
  1477.           videoentry.colors = 2;
  1478.           break;
  1479.      case 2:  videoentry.videomodeax = 4;    /* cga */
  1480.           videoentry.colors = 4;
  1481.           break;
  1482.      case 3:  videoentry.videomodeax = 16;    /* ega */
  1483.           videoentry.colors = 16;
  1484.           if (mode7text) {        /* egamono */
  1485.              videoentry.videomodeax = 15;
  1486.              videoentry.colors = 2;
  1487.              }
  1488.           break;
  1489.      default: videoentry.videomodeax = 19;    /* mcga/vga? */
  1490.           videoentry.colors = 256;
  1491.           break;
  1492.      }
  1493.       }
  1494.    else
  1495.       far_memcpy((char far *)&videoentry,(char far *)&videotable[curmode],
  1496.          sizeof(videoentry));
  1497. #ifndef XFRACT
  1498.    for (i = 0; i < vidtbllen; ++i) { /* find default mode */
  1499.       if ( videoentry.videomodeax == vidtbl[entnums[i]].videomodeax
  1500.     && videoentry.colors      == vidtbl[entnums[i]].colors
  1501.     && (curmode < 0
  1502.         || far_memcmp((char far *)&videoentry,(char far *)&vidtbl[entnums[i]],
  1503.               sizeof(videoentry)) == 0))
  1504.      break;
  1505.       }
  1506.    if (i >= vidtbllen) /* no match, default to first entry */
  1507.       i = 0;
  1508.  
  1509.    oldtabmode = tabmode;
  1510.    oldhelpmode = helpmode;
  1511.    modes_changed = 0;
  1512.    tabmode = 0;
  1513.    helpmode = HELPVIDSEL;
  1514.    i = fullscreen_choice(CHOICEHELP,hdg1,hdg2,NULL,vidtbllen,NULL,attributes,
  1515.                          1,16,72,i,format_vid_table,NULL,NULL,check_modekey);
  1516.    tabmode = oldtabmode;
  1517.    helpmode = oldhelpmode;
  1518.    if (i == -1) {
  1519.    static FCODE msg[]={"Save new function key assignments or cancel changes?"};
  1520.       if (modes_changed /* update fractint.cfg for new key assignments */
  1521.     && badconfig == 0
  1522.     && stopmsg(22,msg) == 0)
  1523.      update_fractint_cfg();
  1524.       return(-1);
  1525.       }
  1526.    if (i < 0)    /* picked by function key */
  1527.       i = -1 - i;
  1528.    else     /* picked by Enter key */
  1529.       i = entnums[i];
  1530. #endif
  1531.    far_memcpy((char far *)&videoentry,(char far *)&vidtbl[i],
  1532.           sizeof(videoentry));  /* the selected entry now in videoentry */
  1533.  
  1534. #ifndef XFRACT
  1535.    /* copy fractint.cfg table to resident table, note selected entry */
  1536.    j = k = 0;
  1537.    far_memset((char far *)videotable,0,sizeof(*vidtbl)*MAXVIDEOTABLE);
  1538.    for (i = 0; i < vidtbllen; ++i) {
  1539.       if (vidtbl[i].keynum > 0) {
  1540.      far_memcpy((char far *)&videotable[j],(char far *)&vidtbl[i],
  1541.             sizeof(*vidtbl));
  1542.      if (far_memcmp((char far *)&videoentry,(char far *)&vidtbl[i],
  1543.             sizeof(videoentry)) == 0)
  1544.         k = vidtbl[i].keynum;
  1545.      if (++j >= MAXVIDEOTABLE-1)
  1546.         break;
  1547.      }
  1548.       }
  1549. #else
  1550.     k = vidtbl[0].keynum;
  1551. #endif
  1552.    if ((ret = k) == 0) { /* selected entry not a copied (assigned to key) one */
  1553.       far_memcpy((char far *)&videotable[MAXVIDEOTABLE-1],
  1554.          (char far *)&videoentry,sizeof(*vidtbl));
  1555.       ret = 1400; /* special value for check_vidmode_key */
  1556.       }
  1557.  
  1558.    if (modes_changed /* update fractint.cfg for new key assignments */
  1559.      && badconfig == 0)
  1560.       update_fractint_cfg();
  1561.  
  1562.    return(ret);
  1563. }
  1564.  
  1565. void format_vid_table(int choice,char *buf)
  1566. {
  1567.    char kname[5];
  1568.    char biosflag;
  1569.    far_memcpy((char far *)&videoentry,(char far *)&vidtbl[entsptr[choice]],
  1570.           sizeof(videoentry));
  1571.    vidmode_keyname(videoentry.keynum,kname);
  1572.    biosflag = (char)((videoentry.dotmode % 100 == 1) ? 'B' : ' ');
  1573.    sprintf(buf,"%-5s %-25s %4d %4d %3d%c %-25s",  /* 72 chars */
  1574.        kname, videoentry.name, videoentry.xdots, videoentry.ydots,
  1575.        videoentry.colors, biosflag, videoentry.comment);
  1576. }
  1577.  
  1578. static int check_modekey(int curkey,int choice)
  1579. {
  1580.    int i,j,k,ret;
  1581.    if ((i = check_vidmode_key(1,curkey)) >= 0)
  1582.       return(-1-i);
  1583.    i = entsptr[choice];
  1584.    ret = 0;
  1585.    if ( (curkey == '-' || curkey == '+')
  1586.      && (vidtbl[i].keynum == 0 || vidtbl[i].keynum >= 1084)) {
  1587.       static FCODE msg[]={"Missing or bad FRACTINT.CFG file. Can't reassign keys."};
  1588.       if (badconfig)
  1589.      stopmsg(0,msg);
  1590.       else {
  1591.      if (curkey == '-') {                   /* deassign key? */
  1592.         if (vidtbl[i].keynum >= 1084) {
  1593.            vidtbl[i].keynum = 0;
  1594.            modes_changed = 1;
  1595.            }
  1596.         }
  1597.      else {                 /* assign key? */
  1598.         j = getakeynohelp();
  1599.         if (j >= 1084 && j <= 1113) {
  1600.            for (k = 0; k < vidtbllen; ++k) {
  1601.           if (vidtbl[k].keynum == j) {
  1602.              vidtbl[k].keynum = 0;
  1603.              ret = -1; /* force redisplay */
  1604.              }
  1605.           }
  1606.            vidtbl[i].keynum = j;
  1607.            modes_changed = 1;
  1608.            }
  1609.         }
  1610.      }
  1611.       }
  1612.    return(ret);
  1613. }
  1614.  
  1615. static int entcompare(VOIDCONSTPTR p1,VOIDCONSTPTR p2)
  1616. {
  1617.    int i,j;
  1618.    if ((i = vidtbl[*((int *)p1)].keynum) == 0) i = 9999;
  1619.    if ((j = vidtbl[*((int *)p2)].keynum) == 0) j = 9999;
  1620.    if (i < j || (i == j && *((int *)p1) < *((int *)p2)))
  1621.       return(-1);
  1622.    return(1);
  1623. }
  1624.  
  1625. static void update_fractint_cfg()
  1626. {
  1627. #ifndef XFRACT
  1628.    char cfgname[100],outname[100],buf[121],kname[5];
  1629.    FILE *cfgfile,*outfile;
  1630.    int far *cfglinenums;
  1631.    int i,j,linenum,nextlinenum,nextmode;
  1632.    struct videoinfo vident;
  1633.  
  1634.    findpath("fractint.cfg",cfgname);
  1635.  
  1636.    if (access(cfgname,6)) {
  1637.       sprintf(buf,s_cantwrite,cfgname);
  1638.       stopmsg(0,buf);
  1639.       return;
  1640.       }
  1641.    strcpy(outname,cfgname);
  1642.    i = strlen(outname);
  1643.    while (--i >= 0 && outname[i] != SLASHC)
  1644.    outname[i] = 0;
  1645.    strcat(outname,"fractint.tmp");
  1646.    if ((outfile = fopen(outname,"w")) == NULL) {
  1647.       sprintf(buf,s_cantcreate,outname);
  1648.       stopmsg(0,buf);
  1649.       return;
  1650.       }
  1651.    cfgfile = fopen(cfgname,"r");
  1652.  
  1653.    cfglinenums = (int far *)(&vidtbl[MAXVIDEOMODES]);
  1654.    linenum = nextmode = 0;
  1655.    nextlinenum = cfglinenums[0];
  1656.    while (fgets(buf,120,cfgfile)) {
  1657.       ++linenum;
  1658.       if (linenum == nextlinenum) { /* replace this line */
  1659.      far_memcpy((char far *)&vident,(char far *)&vidtbl[nextmode],
  1660.             sizeof(videoentry));
  1661.      vidmode_keyname(vident.keynum,kname);
  1662.      strcpy(buf,vident.name);
  1663.      i = strlen(buf);
  1664.      while (i && buf[i-1] == ' ') /* strip trailing spaces to compress */
  1665.         --i;
  1666.      j = i + 5;
  1667.      while (j < 32) {        /* tab to column 33 */
  1668.         buf[i++] = '\t';
  1669.         j += 8;
  1670.         }
  1671.      buf[i] = 0;
  1672.      fprintf(outfile,"%-4s,%s,%4x,%4x,%4x,%4x,%4d,%4d,%4d,%3d,%s\n",
  1673.         kname,
  1674.         buf,
  1675.         vident.videomodeax,
  1676.         vident.videomodebx,
  1677.         vident.videomodecx,
  1678.         vident.videomodedx,
  1679.         vident.dotmode,
  1680.         vident.xdots,
  1681.         vident.ydots,
  1682.         vident.colors,
  1683.         vident.comment);
  1684.      if (++nextmode >= vidtbllen)
  1685.         nextlinenum = 32767;
  1686.      else
  1687.         nextlinenum = cfglinenums[nextmode];
  1688.      }
  1689.       else
  1690.      fputs(buf,outfile);
  1691.       }
  1692.  
  1693.    fclose(cfgfile);
  1694.    fclose(outfile);
  1695.    unlink(cfgname);        /* success assumed on these lines        */
  1696.    rename(outname,cfgname); /* since we checked earlier with access */
  1697. #endif
  1698. }
  1699.  
  1700. /* make_mig() takes a collection of individual GIF images (all
  1701.    presumably the same resolution and all presumably generated
  1702.    by Fractint and its "divide and conquer" algorithm) and builds
  1703.    a single multiple-image GIF out of them.  This routine is
  1704.    invoked by the "batch=stitchmode/x/y" option, and is called
  1705.    with the 'x' and 'y' parameters
  1706. */
  1707.  
  1708. void make_mig(unsigned int xmult, unsigned int ymult)
  1709. {
  1710. unsigned int xstep, ystep;
  1711. unsigned int xres, yres;
  1712. unsigned int allxres, allyres, xtot, ytot;
  1713. unsigned int xloc, yloc;
  1714. unsigned char ichar;
  1715. unsigned int allitbl, itbl;
  1716. unsigned int i;
  1717. char gifin[15], gifout[15];
  1718. int errorflag, inputerrorflag;
  1719. unsigned char *temp;
  1720. FILE *out, *in;
  1721. char msgbuf[81];
  1722.  
  1723. errorflag = 0;                /* no errors so far */
  1724. inputerrorflag = 0;
  1725. allxres = allyres = allitbl = 0;
  1726. out = in = NULL;
  1727.  
  1728. strcpy(gifout,"fractmig.gif");
  1729.  
  1730. temp= &olddacbox[0][0];            /* a safe place for our temp data */
  1731.  
  1732. gif87a_flag = 1;            /* for now, force this */
  1733.  
  1734. /* process each input image, one at a time */
  1735. for (ystep = 0; ystep < ymult; ystep++) {
  1736.     for (xstep = 0; xstep < xmult; xstep++) {
  1737.  
  1738. if (xstep == 0 && ystep == 0) {        /* first time through? */
  1739.     static FCODE msg1[] = "Cannot create output file %s!\n";
  1740.     static FCODE msg2[] = " \n Generating multi-image GIF file %s using";
  1741.     static FCODE msg3[] = " %d X and %d Y components\n\n";
  1742.     far_strcpy(msgbuf, msg2);
  1743.     printf(msgbuf, gifout);
  1744.     far_strcpy(msgbuf, msg3);
  1745.     printf(msgbuf, xmult, ymult);
  1746.     /* attempt to create the output file */
  1747.     if ((out = fopen(gifout,"wb")) == NULL) {
  1748.         far_strcpy(msgbuf, msg1);
  1749.         printf(msgbuf, gifout);
  1750.         exit(1);
  1751.         }
  1752.     }
  1753.  
  1754.         sprintf(gifin, "frmig_%c%c.gif", PAR_KEY(xstep), PAR_KEY(ystep));
  1755.  
  1756.         if ((in = fopen(gifin,"rb")) == NULL) {
  1757.             static FCODE msg1[] = "Can't open file %s!\n";
  1758.             far_strcpy(msgbuf, msg1);
  1759.             printf(msgbuf, gifin);
  1760.             exit(1);
  1761.             }
  1762.  
  1763.         /* (read, but only copy this if it's the first time through) */
  1764.         if (fread(temp,13,1,in) != 1)    /* read the header and LDS */
  1765.             inputerrorflag = 1;
  1766.         memcpy(&xres, &temp[6], 2);    /* X-resolution */
  1767.         memcpy(&yres, &temp[8], 2);    /* Y-resolution */
  1768.  
  1769.         if (xstep == 0 && ystep == 0) {    /* first time through? */
  1770.             allxres = xres;        /* save the "master" resolution */
  1771.             allyres = yres;
  1772.             xtot = xres * xmult;    /* adjust the image size */
  1773.             ytot = yres * ymult;
  1774.             memcpy(&temp[6], &xtot, 2);
  1775.             memcpy(&temp[8], &ytot, 2);
  1776.             if (gif87a_flag) {
  1777.                 temp[3] = '8';
  1778.                 temp[4] = '7';
  1779.                 temp[5] = 'a';
  1780.                 }
  1781.             if (fwrite(temp,13,1,out) != 1)    /* write out the header */
  1782.                 errorflag = 1;
  1783.             }                /* end of first-time-through */
  1784.  
  1785.  
  1786.         ichar = (char)(temp[10] & 0x07);    /* find the color table size */
  1787.         itbl = 1 << (++ichar);
  1788.         ichar = (char)(temp[10] & 0x80);    /* is there a global color table? */
  1789.         if (xstep == 0 && ystep == 0)    /* first time through? */
  1790.             allitbl = itbl;        /* save the color table size */
  1791.         if (ichar != 0) {        /* yup */
  1792.             /* (read, but only copy this if it's the first time through) */
  1793.             if(fread(temp,3*itbl,1,in) != 1)    /* read the global color table */
  1794.                 inputerrorflag = 2;
  1795.             if (xstep == 0 && ystep == 0)    /* first time through? */
  1796.                 if (fwrite(temp,3*itbl,1,out) != 1)    /* write out the GCT */
  1797.                     errorflag = 2;
  1798.             }
  1799.  
  1800.         if (xres != allxres || yres != allyres || itbl != allitbl) {
  1801.             /* Oops - our pieces don't match */
  1802.             static FCODE msg1[] = "File %s doesn't have the same resolution as its predecessors!\n";
  1803.             far_strcpy(msgbuf, msg1);
  1804.             printf(msgbuf, gifin);
  1805.             exit(1);
  1806.             }
  1807.  
  1808.         for (;;) {            /* process each information block */
  1809.         if (fread(temp,1,1,in) != 1)    /* read the block identifier */
  1810.             inputerrorflag = 3;
  1811.  
  1812.         if (temp[0] == 0x2c) {        /* image descriptor block */
  1813.             if (fread(&temp[1],9,1,in) != 1)    /* read the Image Descriptor */
  1814.                 inputerrorflag = 4;
  1815.             memcpy(&xloc, &temp[1], 2);    /* X-location */
  1816.             memcpy(&yloc, &temp[3], 2);    /* Y-location */
  1817.             xloc += (xstep * xres);    /* adjust the locations */
  1818.             yloc += (ystep * yres);
  1819.             memcpy(&temp[1], &xloc, 2);
  1820.             memcpy(&temp[3], &yloc, 2);
  1821.             if (fwrite(temp,10,1,out) != 1)    /* write out the Image Descriptor */
  1822.                 errorflag = 4;
  1823.  
  1824.             ichar = (char)(temp[9] & 0x80);    /* is there a local color table? */
  1825.             if (ichar != 0) {        /* yup */
  1826.                 if (fread(temp,3*itbl,1,in) != 1)    /* read the local color table */
  1827.                     inputerrorflag = 5;
  1828.                 if (fwrite(temp,3*itbl,1,out) != 1)    /* write out the LCT */
  1829.                     errorflag = 5;
  1830.                 }
  1831.  
  1832.             if (fread(temp,1,1,in) != 1)    /* LZH table size */
  1833.                 inputerrorflag = 6;
  1834.             if (fwrite(temp,1,1,out) != 1)
  1835.                 errorflag = 6;
  1836.             for(;;) {
  1837.                 if (errorflag != 0 || inputerrorflag != 0)    /* oops - did something go wrong? */
  1838.                     break;
  1839.                 if (fread(temp,1,1,in) != 1)    /* block size */
  1840.                     inputerrorflag = 7;
  1841.                 if (fwrite(temp,1,1,out) != 1)
  1842.                     errorflag = 7;
  1843.                 if ((i = temp[0]) == 0)
  1844.                     break;
  1845.                 if (fread(temp,i,1,in) != 1)    /* LZH data block */
  1846.                     inputerrorflag = 8;
  1847.                 if (fwrite(temp,i,1,out) != 1)
  1848.                     errorflag = 8;
  1849.                 }
  1850.             }
  1851.  
  1852.         if (temp[0] == 0x21) {        /* extension block */
  1853.             /* (read, but only copy this if it's the last time through) */
  1854.             if (fread(&temp[2],1,1,in) != 1)    /* read the block type */
  1855.                 inputerrorflag = 9;
  1856.             if ((!gif87a_flag) && xstep == xmult-1 && ystep == ymult-1)
  1857.                 if (fwrite(temp,2,1,out) != 1)
  1858.                     errorflag = 9;
  1859.             for(;;) {
  1860.                 if (errorflag != 0 || inputerrorflag != 0)    /* oops - did something go wrong? */
  1861.                     break;
  1862.                 if (fread(temp,1,1,in) != 1)    /* block size */
  1863.                     inputerrorflag = 10;
  1864.                 if ((!gif87a_flag) && xstep == xmult-1 && ystep == ymult-1)
  1865.                     if (fwrite(temp,1,1,out) != 1)
  1866.                         errorflag = 10;
  1867.                 if ((i = temp[0]) == 0)
  1868.                     break;
  1869.                 if (fread(temp,i,1,in) != 1)    /* data block */
  1870.                     inputerrorflag = 11;
  1871.                 if ((!gif87a_flag) && xstep == xmult-1 && ystep == ymult-1)
  1872.                     if (fwrite(temp,i,1,out) != 1)
  1873.                         errorflag = 11;
  1874.                 }
  1875.             }
  1876.  
  1877.         if (temp[0] == 0x3b) {        /* end-of-stream indicator */
  1878.             break;            /* done with this file */
  1879.             }
  1880.  
  1881.         if (errorflag != 0 || inputerrorflag != 0)    /* oops - did something go wrong? */
  1882.             break;
  1883.  
  1884.         }
  1885.         fclose(in);            /* done with an input GIF */
  1886.  
  1887.         if (errorflag != 0 || inputerrorflag != 0)    /* oops - did something go wrong? */
  1888.             break;
  1889.         }
  1890.  
  1891.     if (errorflag != 0 || inputerrorflag != 0)    /* oops - did something go wrong? */
  1892.         break;
  1893.     }
  1894.  
  1895. temp[0] = 0x3b;            /* end-of-stream indicator */
  1896. if (fwrite(temp,1,1,out) != 1)
  1897.     errorflag = 12;
  1898. fclose(out);            /* done with the output GIF */
  1899.  
  1900. if (inputerrorflag != 0) {    /* uh-oh - something failed */
  1901.     static FCODE msg1[] = "\007 Process failed = early EOF on input file %s\n";
  1902.     far_strcpy(msgbuf, msg1);
  1903.     printf(msgbuf, gifin);
  1904. /* following line was for debugging
  1905.     printf("inputerrorflag = %d\n", inputerrorflag);
  1906. */
  1907.     }
  1908.  
  1909. if (errorflag != 0) {        /* uh-oh - something failed */
  1910.     static FCODE msg1[] = "\007 Process failed = out of disk space?\n";
  1911.     far_strcpy(msgbuf, msg1);
  1912.     printf(msgbuf);
  1913. /* following line was for debugging
  1914.     printf("errorflag = %d\n", errorflag);
  1915. */
  1916.     }
  1917.  
  1918. /* now delete each input image, one at a time */
  1919. if (errorflag == 0 && inputerrorflag == 0)
  1920.   for (ystep = 0; ystep < ymult; ystep++) {
  1921.     for (xstep = 0; xstep < xmult; xstep++) {
  1922.         sprintf(gifin, "frmig_%c%c.gif", PAR_KEY(xstep), PAR_KEY(ystep));
  1923.         remove(gifin);
  1924.         }
  1925.     }
  1926.  
  1927. /* tell the world we're done */
  1928. if (errorflag == 0 && inputerrorflag == 0) {
  1929.     static FCODE msg1[] = "File %s has been created (and its component files deleted)\n";
  1930.     far_strcpy(msgbuf, msg1);
  1931.     printf(msgbuf, gifout);
  1932.     }
  1933. }
  1934.  
  1935. /* This routine copies the current screen to by flipping x-axis, y-axis,
  1936.    or both. Refuses to work if calculation in progress or if fractal
  1937.    non-resumable. Clears zoombox if any. Resets corners so resulting fractal
  1938.    is still valid. */
  1939. void flip_image(int key)
  1940. {
  1941.    int i, j, ixhalf, iyhalf, tempdot;
  1942.  
  1943.    /* fractal must be rotate-able and be finished */
  1944.    if ((curfractalspecific->flags&NOROTATE) != 0 
  1945.        || calc_status == 1   
  1946.        || calc_status == 2)  
  1947.       return;
  1948.    if(bf_math)
  1949.        clear_zoombox(); /* clear, don't copy, the zoombox */
  1950.    ixhalf = xdots / 2;  
  1951.    iyhalf = ydots / 2;
  1952.    switch(key)
  1953.    {
  1954.    case 24:            /* control-X - reverse X-axis */
  1955.       for (i = 0; i < ixhalf; i++) 
  1956.       {
  1957.          if(keypressed())
  1958.             break;
  1959.          for (j = 0; j < ydots; j++) 
  1960.          {
  1961.             tempdot=getcolor(i,j);
  1962.             putcolor(i, j, getcolor(xdots-1-i,j));
  1963.             putcolor(xdots-1-i, j, tempdot);
  1964.          }
  1965.       }
  1966.       sxmin = xxmax + xxmin - xx3rd;
  1967.       symax = yymax + yymin - yy3rd;
  1968.       sxmax = xx3rd;
  1969.       symin = yy3rd;
  1970.       sx3rd = xxmax;
  1971.       sy3rd = yymin;
  1972.       if(bf_math)
  1973.       {
  1974.          add_bf(bfsxmin, bfxmax, bfxmin); /* sxmin = xxmax + xxmin - xx3rd; */
  1975.          sub_a_bf(bfsxmin, bfx3rd);
  1976.          add_bf(bfsymax, bfymax, bfymin); /* symax = yymax + yymin - yy3rd; */
  1977.          sub_a_bf(bfsymax, bfy3rd);
  1978.          copy_bf(bfsxmax, bfx3rd);        /* sxmax = xx3rd; */
  1979.          copy_bf(bfsymin, bfy3rd);        /* symin = yy3rd; */
  1980.          copy_bf(bfsx3rd, bfxmax);        /* sx3rd = xxmax; */
  1981.          copy_bf(bfsy3rd, bfymin);        /* sy3rd = yymin; */
  1982.       }
  1983.       break;
  1984.    case 25:            /* control-Y - reverse Y-aXis */
  1985.       for (j = 0; j < iyhalf; j++)
  1986.       {
  1987.          if(keypressed())
  1988.             break;
  1989.          for (i = 0; i < xdots; i++) 
  1990.          {
  1991.             tempdot=getcolor(i,j);
  1992.             putcolor(i, j, getcolor(i,ydots-1-j));
  1993.             putcolor(i,ydots-1-j, tempdot);
  1994.          }
  1995.       }
  1996.       sxmin = xx3rd;
  1997.       symax = yy3rd;
  1998.       sxmax = xxmax + xxmin - xx3rd;
  1999.       symin = yymax + yymin - yy3rd;
  2000.       sx3rd = xxmin;
  2001.       sy3rd = yymax;
  2002.       if(bf_math)
  2003.       {
  2004.          copy_bf(bfsxmin, bfx3rd);        /* sxmin = xx3rd; */
  2005.          copy_bf(bfsymax, bfy3rd);        /* symax = yy3rd; */
  2006.          add_bf(bfsxmax, bfxmax, bfxmin); /* sxmax = xxmax + xxmin - xx3rd; */
  2007.          sub_a_bf(bfsxmax, bfx3rd);
  2008.          add_bf(bfsymin, bfymax, bfymin); /* symin = yymax + yymin - yy3rd; */
  2009.          sub_a_bf(bfsymin, bfy3rd);
  2010.          copy_bf(bfsx3rd, bfxmin);        /* sx3rd = xxmin; */
  2011.          copy_bf(bfsy3rd, bfymax);        /* sy3rd = yymax; */
  2012.       }
  2013.       break;
  2014.    case 26:            /* control-Z - reverse X and Y aXis */
  2015.       for (i = 0; i < ixhalf; i++) 
  2016.       {
  2017.          if(keypressed())
  2018.             break;
  2019.          for (j = 0; j < ydots; j++) 
  2020.          {
  2021.             tempdot=getcolor(i,j);
  2022.             putcolor(i, j, getcolor(xdots-1-i,ydots-1-j));
  2023.             putcolor(xdots-1-i, ydots-1-j, tempdot);
  2024.          }
  2025.       }
  2026.       sxmin = xxmax;
  2027.       symax = yymin;
  2028.       sxmax = xxmin;
  2029.       symin = yymax;
  2030.       sx3rd = xxmax + xxmin - xx3rd;
  2031.       sy3rd = yymax + yymin - yy3rd;
  2032.       if(bf_math)
  2033.       {
  2034.          copy_bf(bfsxmin, bfxmax);        /* sxmin = xxmax; */
  2035.          copy_bf(bfsymax, bfymin);        /* symax = yymin; */
  2036.          copy_bf(bfsxmax, bfxmin);        /* sxmax = xxmin; */
  2037.          copy_bf(bfsymin, bfymax);        /* symin = yymax; */
  2038.          add_bf(bfsx3rd, bfxmax, bfxmin); /* sx3rd = xxmax + xxmin - xx3rd; */
  2039.          sub_a_bf(bfsx3rd, bfx3rd);
  2040.          add_bf(bfsy3rd, bfymax, bfymin); /* sy3rd = yymax + yymin - yy3rd; */
  2041.          sub_a_bf(bfsy3rd, bfy3rd);
  2042.       }
  2043.       break;
  2044.    }
  2045.    reset_zoom_corners();
  2046.    calc_status = 0;
  2047. }
  2048.