home *** CD-ROM | disk | FTP | other *** search
/ Computerworld 1996 March / Computerworld_1996-03_cd.bin / idg_cd3 / grafika / fraktaly / frasr192 / miscres.c < prev    next >
C/C++ Source or Header  |  1995-04-08  |  48KB  |  1,571 lines

  1. /*
  2.     Resident odds and ends that don't fit anywhere else.
  3. */
  4.  
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <time.h>
  10. #include <malloc.h>
  11. #ifndef XFRACT
  12. #include <stdarg.h>
  13. #include <io.h>
  14. #include <dos.h>
  15. #else
  16. #include <varargs.h>
  17. #endif
  18. #include <math.h>
  19. /*#ifdef __TURBOC__
  20. #include <dir.h>
  21. #endif  */
  22.  
  23. #include "fractint.h"
  24. #include "fractype.h"
  25. #include "helpdefs.h"
  26. #include "prototyp.h"
  27.  
  28. /* routines in this module    */
  29.  
  30. static    void trigdetails(char *);
  31. static void area(void);
  32. static int find_one_file_item(char *, char *, FILE **);
  33.  
  34. /* TW's static string consolidation campaign to help brain-dead compilers */
  35. char s_cantwrite[]      = {"Can't write %s"};
  36. char s_cantcreate[]     = {"Can't create %s"};
  37. char s_cantunderstand[] = {"Can't understand %s"};
  38. char s_cantfind[]       = {"Can't find %s"};
  39.  
  40. #ifndef XFRACT
  41.  
  42. void findpath(char far *filename, char *fullpathname) /* return full pathnames */
  43. {
  44.    char fname[FILE_MAX_FNAME];
  45.    char ext[FILE_MAX_EXT];
  46.    char temp_path[FILE_MAX_PATH];
  47.  
  48.    splitpath(filename ,NULL,NULL,fname,ext);
  49.    makepath(temp_path,""   ,"" ,fname,ext);
  50.  
  51.    if(checkcurdir != 0 && access(temp_path,0)==0) {   /* file exists */
  52.       strcpy(fullpathname,temp_path);
  53.       return;
  54.    }
  55.  
  56.    far_strcpy(temp_path,filename);   /* avoid side effect changes to filename */
  57.  
  58.    if (temp_path[0] == SLASHC || (temp_path[0] && temp_path[1] == ':')) {
  59.       if(access(temp_path,0)==0) {   /* file exists */
  60.          strcpy(fullpathname,temp_path);
  61.          return;
  62.          }
  63.       else {
  64.          splitpath(temp_path ,NULL,NULL,fname,ext);
  65.          makepath(temp_path,""   ,"" ,fname,ext);
  66.          }
  67.       }
  68.    fullpathname[0] = 0;             /* indicate none found */
  69. /* #ifdef __TURBOC__ */                /* look for the file */
  70. /*   strcpy(fullpathname,searchpath(temp_path)); */
  71. /* #else */
  72.    _searchenv(temp_path,"PATH",fullpathname);
  73. /* #endif */
  74.    if (fullpathname[0] != 0)            /* found it! */
  75.       if (strncmp(&fullpathname[2],SLASHSLASH,2) == 0) /* stupid klooge! */
  76.      strcpy(&fullpathname[3],temp_path);
  77. }
  78. #endif
  79.  
  80.  
  81. void notdiskmsg()
  82. {
  83. static FCODE sorrymsg[]={
  84. "This type may be slow using a real-disk based 'video' mode, but may not \n\
  85. be too bad if you have enough expanded or extended memory. Press <Esc> to \n\
  86. abort if it appears that your disk drive is working too hard."};
  87.    stopmsg(0,sorrymsg);
  88. }
  89.  
  90. /* Wrapping version of putstring for long numbers                         */
  91. /* row     -- pointer to row variable, internally incremented if needed   */
  92. /* col1    -- starting column                                             */
  93. /* col2    -- last column                                                 */
  94. /* color   -- attribute (same as for putstring)                           */
  95. /* maxrow -- max number of rows to write                                 */
  96. /* returns 0 if success, 1 if hit maxrow before done                      */
  97. int putstringwrap(int *row,int col1,int col2,int color,char far *str,int maxrow)
  98. {
  99.     char save1, save2;
  100.     int length, decpt, padding, startrow, done;
  101.     done = 0;
  102.     startrow = *row;
  103.     length = far_strlen(str);
  104.     padding = 3; /* space between col1 and decimal. */
  105.     /* find decimal point */
  106.     for(decpt=0;decpt < length; decpt++)
  107.        if(str[decpt] == '.')
  108.           break;
  109.     if(decpt >= length)
  110.        decpt = 0;
  111.     if(decpt < padding)
  112.        padding -= decpt;   
  113.     else
  114.        padding = 0;
  115.     col1 += padding;   
  116.     decpt += col1+1; /* column just past where decimal is */         
  117.     while(length > 0)
  118.     {
  119.        if(col2-col1 < length)
  120.        {
  121.           if((*row - startrow + 1) >= maxrow)
  122.              done = 1;
  123.           else
  124.              done = 0;
  125.           save1 = str[col2-col1+1];
  126.           save2 = str[col2-col1+2];
  127.           if(done)
  128.              str[col2-col1+1]   = '+';
  129.           else
  130.              str[col2-col1+1]   = '\\';
  131.           str[col2-col1+2] = 0;
  132.           putstring(*row,col1,color,str);
  133.           if(done == 1)
  134.              break;
  135.           str[col2-col1+1] = save1;
  136.           str[col2-col1+2] = save2;
  137.           str += col2-col1;
  138.           (*row)++;
  139.        } else
  140.           putstring(*row,col1,color,str);
  141.        length -= col2-col1;
  142.        col1 = decpt; /* align with decimal */
  143.     }
  144.     return(done);
  145. }
  146.  
  147. #define rad_to_deg(x) ((x)*(180/PI)) /* most people "think" in degrees */
  148. #define deg_to_rad(x) ((x)*(PI/180))
  149. /*
  150. convert corners to center/mag
  151. Rotation angles indicate how much the IMAGE has been rotated, not the
  152. zoom box.  Same goes for the Skew angles
  153. */
  154.  
  155. #ifdef _MSC_VER
  156. #pragma optimize( "", off )
  157. #endif
  158.  
  159. void cvtcentermag(double *Xctr, double *Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
  160. {
  161.    double Width, Height;
  162.    double a, b; /* bottom, left, diagonal */
  163.    double a2, b2, c2; /* squares of above */
  164.    double tmpx, tmpy, tmpa; /* temporary x, y, angle */
  165.  
  166.    /* simple normal case first */
  167.    if (xx3rd == xxmin && yy3rd == yymin)
  168.    { /* no rotation or skewing, but stretching is allowed */
  169.       Width  = xxmax - xxmin;
  170.       Height = yymax - yymin;
  171.       *Xctr = (xxmin + xxmax)/2;
  172.       *Yctr = (yymin + yymax)/2;
  173.       *Magnification  = 2/Height;
  174.       *Xmagfactor =  Height / (DEFAULTASPECT * Width);
  175.       *Rotation = 0.0;
  176.       *Skew = 0.0;
  177.       if (*Magnification < 0)
  178.       {
  179.          *Magnification = -*Magnification;
  180.          *Rotation += 180;
  181.       }
  182.       return;
  183.    }
  184.  
  185.    /* set up triangle ABC, having sides abc */
  186.    /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
  187.    tmpx = xxmax - xx3rd;
  188.    tmpy = yymin - yy3rd;
  189.    a2 = tmpx*tmpx + tmpy*tmpy;
  190.    a = sqrt(a2);
  191.    *Rotation = -rad_to_deg(atan2( tmpy, tmpx )); /* negative for image rotation */
  192.  
  193.    tmpx = xxmin - xx3rd;
  194.    tmpy = yymax - yy3rd;
  195.    b2 = tmpx*tmpx + tmpy*tmpy;
  196.    b = sqrt(b2);
  197.  
  198.    tmpx = xxmax - xxmin;
  199.    tmpy = yymax - yymin;
  200.    c2 = tmpx*tmpx + tmpy*tmpy;
  201.  
  202.    tmpa = acos((a2+b2-c2)/(2*a*b)); /* save tmpa for later use */
  203.    *Skew = 90 - rad_to_deg(tmpa);
  204.  
  205.    *Xctr = (xxmin + xxmax)/2;
  206.    *Yctr = (yymin + yymax)/2;
  207.  
  208.    Height = b * sin(tmpa);
  209.    *Magnification  = 2/Height; /* 1/(h/2) */
  210.    *Xmagfactor = Height / (DEFAULTASPECT * a);
  211.    if (*Magnification < 0)
  212.       {
  213.       *Magnification = -*Magnification;
  214.       *Rotation += 180;
  215.       }
  216.    return;
  217. }
  218.  
  219. /* convert center/mag to corners */
  220. void cvtcorners(double Xctr, double Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
  221. {
  222.    double x, y;
  223.    double h, w; /* half height, width */
  224.    double tanskew, sinrot, cosrot;
  225.  
  226.    if (Xmagfactor == 0.0)
  227.       Xmagfactor = 1.0;
  228.  
  229.    h = (double)(1/Magnification);
  230.    w = h / (DEFAULTASPECT * Xmagfactor);
  231.  
  232.    if (Rotation == 0.0 && Skew == 0.0)
  233.       { /* simple, faster case */
  234.       xx3rd = xxmin = Xctr - w;
  235.       xxmax = Xctr + w;
  236.       yy3rd = yymin = Yctr - h;
  237.       yymax = Yctr + h;
  238.       return;
  239.       }
  240.  
  241.    /* in unrotated, untranslated coordinate system */
  242.    tanskew = tan(deg_to_rad(Skew));
  243.    xxmin = -w + h*tanskew;
  244.    xxmax =  w - h*tanskew;
  245.    xx3rd = -w - h*tanskew;
  246.    yymax = h;
  247.    yy3rd = yymin = -h;
  248.  
  249.    /* rotate coord system and then translate it */
  250.    Rotation = deg_to_rad(Rotation);
  251.    sinrot = sin(Rotation);
  252.    cosrot = cos(Rotation);
  253.  
  254.    /* top left */
  255.    x = xxmin * cosrot + yymax *  sinrot;
  256.    y = -xxmin * sinrot + yymax *  cosrot;
  257.    xxmin = x + Xctr;
  258.    yymax = y + Yctr;
  259.  
  260.    /* bottom right */
  261.    x = xxmax * cosrot + yymin *  sinrot;
  262.    y = -xxmax * sinrot + yymin *  cosrot;
  263.    xxmax = x + Xctr;
  264.    yymin = y + Yctr;
  265.  
  266.    /* bottom left */
  267.    x = xx3rd * cosrot + yy3rd *  sinrot;
  268.    y = -xx3rd * sinrot + yy3rd *  cosrot;
  269.    xx3rd = x + Xctr;
  270.    yy3rd = y + Yctr;
  271.  
  272.    return;
  273. }
  274.  
  275. /* convert corners to center/mag using bf */
  276. void cvtcentermagbf(bf_t Xctr, bf_t Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
  277. {
  278.    /* needs to be LDBL or won't work past 307 (-DBL_MIN_10_EXP) or so digits */
  279.    LDBL Width, Height;
  280.    LDBL a, b; /* bottom, left, diagonal */
  281.    LDBL a2, b2, c2; /* squares of above */
  282.    LDBL tmpx, tmpy;
  283.    double tmpa; /* temporary x, y, angle */
  284.    bf_t bfWidth, bfHeight;
  285.    bf_t bftmpx, bftmpy;
  286.    int saved;
  287.    int signx;
  288.  
  289.    saved = save_stack();
  290.  
  291.    /* simple normal case first */
  292.    /* if (xx3rd == xxmin && yy3rd == yymin) */
  293.    if(!cmp_bf(bfx3rd, bfxmin) && !cmp_bf(bfy3rd, bfymin))
  294.       { /* no rotation or skewing, but stretching is allowed */
  295.       bfWidth  = alloc_stack(bflength+2);
  296.       bfHeight = alloc_stack(bflength+2);
  297.       /* Width  = xxmax - xxmin; */
  298.       sub_bf(bfWidth, bfxmax, bfxmin);
  299.       Width  = bftofloat(bfWidth);
  300.       /* Height = yymax - yymin; */
  301.       sub_bf(bfHeight, bfymax, bfymin);
  302.       Height = bftofloat(bfHeight);
  303.       /* *Xctr = (xxmin + xxmax)/2; */
  304.       add_bf(Xctr, bfxmin, bfxmax);
  305.       half_a_bf(Xctr);
  306.       /* *Yctr = (yymin + yymax)/2; */
  307.       add_bf(Yctr, bfymin, bfymax);
  308.       half_a_bf(Yctr);
  309.       *Magnification  = 2/Height;
  310.       *Xmagfactor =  (double)(Height / (DEFAULTASPECT * Width));
  311.       *Rotation = 0.0;
  312.       *Skew = 0.0;
  313.       if (*Magnification < 0)
  314.          {
  315.          *Magnification = -*Magnification;
  316.          *Rotation += 180;
  317.          }
  318.       restore_stack(saved);
  319.       return;
  320.       }
  321.  
  322.    bftmpx = alloc_stack(bflength+2);
  323.    bftmpy = alloc_stack(bflength+2);
  324.  
  325.    /* set up triangle ABC, having sides abc */
  326.    /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
  327.    /* IMPORTANT: convert from bf AFTER subtracting */
  328.    /* tmpx = xxmax - xx3rd; */
  329.    sub_bf(bftmpx, bfxmax, bfx3rd);
  330.    tmpx = bftofloat(bftmpx);
  331.    /* tmpy = yymin - yy3rd; */
  332.    sub_bf(bftmpy, bfymin, bfy3rd);
  333.    tmpy = bftofloat(bftmpy);
  334.    a2 = tmpx*tmpx + tmpy*tmpy;
  335.    a = sqrtl(a2);
  336.  
  337.    /* divide tmpx and tmpy by |tmpx| so that double version of atan2() can be used */
  338.    /* atan2() only depends on the ratio, this puts it in double's range */
  339.    signx = sign(tmpx);
  340.    if(signx)
  341.       tmpy /= tmpx * signx;       /* tmpy = tmpy / |tmpx| */
  342.    *Rotation = (double)(-rad_to_deg(atan2( (double)tmpy, signx ))); /* negative for image rotation */
  343.  
  344.    /* tmpx = xxmin - xx3rd; */
  345.    sub_bf(bftmpx, bfxmin, bfx3rd);
  346.    tmpx = bftofloat(bftmpx);
  347.    /* tmpy = yymax - yy3rd; */
  348.    sub_bf(bftmpy, bfymax, bfy3rd);
  349.    tmpy = bftofloat(bftmpy);
  350.    b2 = tmpx*tmpx + tmpy*tmpy;
  351.    b = sqrtl(b2);
  352.  
  353.    /* tmpx = xxmax - xxmin; */
  354.    sub_bf(bftmpx, bfxmax, bfxmin);
  355.    tmpx = bftofloat(bftmpx);
  356.    /* tmpy = yymax - yymin; */
  357.    sub_bf(bftmpy, bfymax, bfymin);
  358.    tmpy = bftofloat(bftmpy);
  359.    c2 = tmpx*tmpx + tmpy*tmpy;
  360.  
  361.    tmpa = acos((double)((a2+b2-c2)/(2*a*b))); /* save tmpa for later use */
  362.    *Skew = 90 - rad_to_deg(tmpa);
  363.  
  364.    /* these are the only two variables that must be to big precision */
  365.    /* *Xctr = (xxmin + xxmax)/2; */
  366.    add_bf(Xctr, bfxmin, bfxmax);
  367.    half_a_bf(Xctr);
  368.    /* *Yctr = (yymin + yymax)/2; */
  369.    add_bf(Yctr, bfymin, bfymax);
  370.    half_a_bf(Yctr);
  371.  
  372.    Height = b * sin(tmpa);
  373.    *Magnification  = 2/Height; /* 1/(h/2) */
  374.    *Xmagfactor = (double)(Height / (DEFAULTASPECT * a));
  375.    if (*Magnification < 0)
  376.       {
  377.       *Magnification = -*Magnification;
  378.       *Rotation += 180;
  379.       }
  380.    restore_stack(saved);
  381.    return;
  382. }
  383.  
  384.  
  385. /* convert center/mag to corners using bf */
  386. void cvtcornersbf(bf_t Xctr, bf_t Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
  387. {
  388.    LDBL x, y;
  389.    LDBL h, w; /* half height, width */
  390.    LDBL xmin, ymin, xmax, ymax, x3rd, y3rd;
  391.    double tanskew, sinrot, cosrot;
  392.    bf_t bfh, bfw;
  393.    bf_t bftmp;
  394.    int saved;
  395.  
  396.    saved = save_stack();
  397.    bfh = alloc_stack(bflength+2);
  398.    bfw = alloc_stack(bflength+2);
  399.  
  400.    if (Xmagfactor == 0.0)
  401.       Xmagfactor = 1.0;
  402.  
  403.    h = 1/Magnification;
  404.    floattobf(bfh, h);
  405.    w = h / (DEFAULTASPECT * Xmagfactor);
  406.    floattobf(bfw, w);
  407.  
  408.    if (Rotation == 0.0 && Skew == 0.0)
  409.       { /* simple, faster case */
  410.       /* xx3rd = xxmin = Xctr - w; */
  411.       sub_bf(bfxmin, Xctr, bfw);
  412.       copy_bf(bfx3rd, bfxmin);
  413.       /* xxmax = Xctr + w; */
  414.       add_bf(bfxmax, Xctr, bfw);
  415.       /* yy3rd = yymin = Yctr - h; */
  416.       sub_bf(bfymin, Yctr, bfh);
  417.       copy_bf(bfy3rd, bfymin);
  418.       /* yymax = Yctr + h; */
  419.       add_bf(bfymax, Yctr, bfh);
  420.       restore_stack(saved);
  421.       return;
  422.       }
  423.  
  424.    bftmp = alloc_stack(bflength+2);
  425.    /* in unrotated, untranslated coordinate system */
  426.    tanskew = tan(deg_to_rad(Skew));
  427.    xmin = -w + h*tanskew;
  428.    xmax =  w - h*tanskew;
  429.    x3rd = -w - h*tanskew;
  430.    ymax = h;
  431.    y3rd = ymin = -h;
  432.  
  433.    /* rotate coord system and then translate it */
  434.    Rotation = deg_to_rad(Rotation);
  435.    sinrot = sin(Rotation);
  436.    cosrot = cos(Rotation);
  437.  
  438.    /* top left */
  439.    x =  xmin * cosrot + ymax *  sinrot;
  440.    y = -xmin * sinrot + ymax *  cosrot;
  441.    /* xxmin = x + Xctr; */
  442.    floattobf(bftmp, x);
  443.    add_bf(bfxmin, bftmp, Xctr);
  444.    /* yymax = y + Yctr; */
  445.    floattobf(bftmp, y);
  446.    add_bf(bfymax, bftmp, Yctr);
  447.  
  448.    /* bottom right */
  449.    x =  xmax * cosrot + ymin *  sinrot;
  450.    y = -xmax * sinrot + ymin *  cosrot;
  451.    /* xxmax = x + Xctr; */
  452.    floattobf(bftmp, x);
  453.    add_bf(bfxmax, bftmp, Xctr);
  454.    /* yymin = y + Yctr; */
  455.    floattobf(bftmp, y);
  456.    add_bf(bfymin, bftmp, Yctr);
  457.  
  458.    /* bottom left */
  459.    x =  x3rd * cosrot + y3rd *  sinrot;
  460.    y = -x3rd * sinrot + y3rd *  cosrot;
  461.    /* xx3rd = x + Xctr; */
  462.    floattobf(bftmp, x);
  463.    add_bf(bfx3rd, bftmp, Xctr);
  464.    /* yy3rd = y + Yctr; */
  465.    floattobf(bftmp, y);
  466.    add_bf(bfy3rd, bftmp, Yctr);
  467.  
  468.    restore_stack(saved);
  469.    return;
  470. }
  471.  
  472. #ifdef _MSC_VER
  473. #pragma optimize( "", on )
  474. #endif
  475.  
  476. void updatesavename(char *filename) /* go to the next file name */
  477. {
  478.    char *save, *hold;
  479.    char drive[FILE_MAX_DRIVE];
  480.    char dir[FILE_MAX_DIR];
  481.    char fname[FILE_MAX_FNAME];
  482.    char ext[FILE_MAX_EXT];
  483.  
  484.    splitpath(filename ,drive,dir,fname,ext);
  485.  
  486.    suffix[0] = 0;
  487.  
  488.    hold = fname + strlen(fname) - 1; /* start at the end */
  489.    while(hold >= fname && (*hold == ' ' || isdigit(*hold))) /* skip backwards */
  490.       hold--;
  491.    hold++;            /* recover first digit */
  492.    while (*hold == '0')         /* skip leading zeros */
  493.       hold++;
  494.    save = hold;
  495.    while (*save) {        /* check for all nines */
  496.       if (*save != '9')
  497.      break;
  498.       save++;
  499.       }
  500.    if (!*save)            /* if the whole thing is nines then back */
  501.       save = hold - 1;        /* up one place. Note that this will eat */
  502.                 /* your last letter if you go to far.     */
  503.    else
  504.       save = hold;
  505.    sprintf(save,"%d",atoi(hold)+1); /* increment the number */
  506.    makepath(filename,drive,dir,fname,ext);
  507. }
  508.  
  509. int check_writefile(char *name,char *ext)
  510. {
  511.  /* after v16 release, change encoder.c to also use this routine */
  512.    char openfile[80];
  513.    char opentype[20];
  514.  /* int i; */
  515.    char *period;
  516. nextname:
  517.    strcpy(openfile,name);
  518.    strcpy(opentype,ext);
  519. #if 0   
  520.    for (i = 0; i < (int)strlen(openfile); i++)
  521.       if (openfile[i] == '.') {
  522.      strcpy(opentype,&openfile[i]);
  523.      openfile[i] = 0;
  524.      }
  525. #endif
  526.    if((period = has_ext(openfile)) != NULL)
  527.    {
  528.       strcpy(opentype,period);
  529.       *period = 0;
  530.    }        
  531.    strcat(openfile,opentype);
  532.    if (access(openfile,0) != 0) /* file doesn't exist */
  533.    {
  534.       strcpy(name,openfile);
  535.       return 0;
  536.     }
  537.    /* file already exists */
  538.    if (overwrite == 0) {
  539.       updatesavename(name);
  540.       goto nextname;
  541.       }
  542.    return 1;
  543. }
  544.  
  545. /* ('check_key()' was moved to FRACTINT.C for MSC7-overlay speed purposes) */
  546. /* ('timer()'     was moved to FRACTINT.C for MSC7-overlay speed purposes) */
  547.  
  548. BYTE trigndx[] = {SIN,SQR,SINH,COSH};
  549. #ifndef XFRACT
  550. void (*ltrig0)(void) = lStkSin;
  551. void (*ltrig1)(void) = lStkSqr;
  552. void (*ltrig2)(void) = lStkSinh;
  553. void (*ltrig3)(void) = lStkCosh;
  554. void (*mtrig0)(void) = mStkSin;
  555. void (*mtrig1)(void) = mStkSqr;
  556. void (*mtrig2)(void) = mStkSinh;
  557. void (*mtrig3)(void) = mStkCosh;
  558. #endif
  559. void (*dtrig0)(void) = dStkSin;
  560. void (*dtrig1)(void) = dStkSqr;
  561. void (*dtrig2)(void) = dStkSinh;
  562. void (*dtrig3)(void) = dStkCosh;
  563.  
  564. struct trig_funct_lst trigfn[] =
  565. /* changing the order of these alters meaning of *.fra file */
  566. /* maximum 6 characters in function names or recheck all related code */
  567. {
  568. #ifndef XFRACT
  569.    {s_sin,   lStkSin,   dStkSin,   mStkSin   },
  570.    {s_cosxx, lStkCosXX, dStkCosXX, mStkCosXX },
  571.    {s_sinh,  lStkSinh,  dStkSinh,  mStkSinh  },
  572.    {s_cosh,  lStkCosh,  dStkCosh,  mStkCosh  },
  573.    {s_exp,   lStkExp,   dStkExp,   mStkExp   },
  574.    {s_log,   lStkLog,   dStkLog,   mStkLog   },
  575.    {s_sqr,   lStkSqr,   dStkSqr,   mStkSqr   },
  576.    {s_recip, lStkRecip, dStkRecip, mStkRecip }, /* from recip on new in v16 */
  577.    {s_ident, StkIdent,  StkIdent,  StkIdent  },
  578.    {s_cos,   lStkCos,   dStkCos,   mStkCos   },
  579.    {s_tan,   lStkTan,   dStkTan,   mStkTan   },
  580.    {s_tanh,  lStkTanh,  dStkTanh,  mStkTanh  },
  581.    {s_cotan, lStkCoTan, dStkCoTan, mStkCoTan },
  582.    {s_cotanh,lStkCoTanh,dStkCoTanh,mStkCoTanh},
  583.    {s_flip,  lStkFlip,  dStkFlip,  mStkFlip  },
  584.    {s_conj,  lStkConj,  dStkConj,  mStkConj  },
  585.    {s_zero,  lStkZero,  dStkZero,  mStkZero  },
  586.    {s_asin,  lStkASin,  dStkASin,  mStkASin  },
  587.    {s_asinh, lStkASinh, dStkASinh, mStkASinh },
  588.    {s_acos,  lStkACos,  dStkACos,  mStkACos  },
  589.    {s_acosh, lStkACosh, dStkACosh, mStkACosh },
  590.    {s_atan,  lStkATan,  dStkATan,  mStkATan  },
  591.    {s_atanh, lStkATanh, dStkATanh, mStkATanh },
  592.    {s_cabs,  lStkCAbs,  dStkCAbs,  mStkCAbs  },
  593.    {s_abs,   lStkAbs,   dStkAbs,   mStkAbs   },
  594.    {s_sqrt,  lStkSqrt,  dStkSqrt,  mStkSqrt  },
  595. #else
  596.    {s_sin,   dStkSin,   dStkSin,   dStkSin   },
  597.    {s_cosxx, dStkCosXX, dStkCosXX, dStkCosXX },
  598.    {s_sinh,  dStkSinh,  dStkSinh,  dStkSinh  },
  599.    {s_cosh,  dStkCosh,  dStkCosh,  dStkCosh  },
  600.    {s_exp,   dStkExp,   dStkExp,   dStkExp   },
  601.    {s_log,   dStkLog,   dStkLog,   dStkLog   },
  602.    {s_sqr,   dStkSqr,   dStkSqr,   dStkSqr   },
  603.    {s_recip, dStkRecip, dStkRecip, dStkRecip }, /* from recip on new in v16 */
  604.    {s_ident, StkIdent,  StkIdent,  StkIdent  },
  605.    {s_cos,   dStkCos,   dStkCos,   dStkCos   },
  606.    {s_tan,   dStkTan,   dStkTan,   dStkTan   },
  607.    {s_tanh,  dStkTanh,  dStkTanh,  dStkTanh  },
  608.    {s_cotan, dStkCoTan, dStkCoTan, dStkCoTan },
  609.    {s_cotanh,dStkCoTanh,dStkCoTanh,dStkCoTanh},
  610.    {s_flip,  dStkFlip,  dStkFlip,  dStkFlip  },
  611.    {s_conj,  dStkConj,  dStkConj,  dStkConj  },
  612.    {s_zero,  dStkZero,  dStkZero,  dStkZero  },
  613.    {s_asin,  dStkASin,  dStkASin,  dStkASin  },
  614.    {s_asinh, dStkASinh, dStkASinh, dStkASinh },
  615.    {s_acos,  dStkACos,  dStkACos,  dStkACos  },
  616.    {s_acosh, dStkACosh, dStkACosh, dStkACosh },
  617.    {s_atan,  dStkATan,  dStkATan,  dStkATan  },
  618.    {s_atanh, dStkATanh, dStkATanh, dStkATanh },
  619.    {s_cabs,  dStkCAbs,  dStkCAbs,  dStkCAbs  },
  620.    {s_abs,   dStkAbs,   dStkAbs,   dStkAbs   },
  621.    {s_sqrt,  dStkSqrt,  dStkSqrt,  dStkSqrt  },
  622. #endif
  623. };
  624. int numtrigfn = sizeof(trigfn)/sizeof(struct trig_funct_lst);
  625.  
  626. void showtrig(char *buf) /* return display form of active trig functions */
  627. {
  628.    char tmpbuf[30];
  629.    *buf = 0; /* null string if none */
  630.    trigdetails(tmpbuf);
  631.    if (tmpbuf[0])
  632.       sprintf(buf," function=%s",tmpbuf);
  633. }
  634.  
  635. static void trigdetails(char *buf)
  636. {
  637.    int i, numfn;
  638.    char tmpbuf[20];
  639.    if(fractype==JULIBROT || fractype==JULIBROTFP)
  640.       numfn = (fractalspecific[neworbittype].flags >> 6) & 7;
  641.    else
  642.       numfn = (curfractalspecific->flags >> 6) & 7;
  643.    if(curfractalspecific == &fractalspecific[FORMULA] ||
  644.       curfractalspecific == &fractalspecific[FFORMULA]    )
  645.       numfn = maxfn;
  646.    *buf = 0; /* null string if none */
  647.    if (numfn>0) {
  648.       strcpy(buf,trigfn[trigndx[0]].name);
  649.       i = 0;
  650.       while(++i < numfn) {
  651.      sprintf(tmpbuf,"/%s",trigfn[trigndx[i]].name);
  652.      strcat(buf,tmpbuf);
  653.      }
  654.       }
  655. }
  656.  
  657. /* set array of trig function indices according to "function=" command */
  658. int set_trig_array(int k, char *name)
  659. {
  660.    char trigname[10];
  661.    int i;
  662.    char *slash;
  663.    strncpy(trigname,name,6);
  664.    trigname[6] = 0; /* safety first */
  665.  
  666.    if ((slash = strchr(trigname,'/')) != NULL)
  667.       *slash = 0;
  668.  
  669.    strlwr(trigname);
  670.  
  671.    for(i=0;i<numtrigfn;i++)
  672.    {
  673.       if(strcmp(trigname,trigfn[i].name)==0)
  674.       {
  675.      trigndx[k] = (BYTE)i;
  676.      set_trig_pointers(k);
  677.      break;
  678.       }
  679.    }
  680.    return(0);
  681. }
  682. void set_trig_pointers(int which)
  683. {
  684.   /* set trig variable functions to avoid array lookup time */
  685.    int i;
  686.    switch(which)
  687.    {
  688.    case 0:
  689. #ifndef XFRACT
  690.       ltrig0 = trigfn[trigndx[0]].lfunct;
  691.       mtrig0 = trigfn[trigndx[0]].mfunct;
  692. #endif
  693.       dtrig0 = trigfn[trigndx[0]].dfunct;
  694.       break;
  695.    case 1:
  696. #ifndef XFRACT
  697.       ltrig1 = trigfn[trigndx[1]].lfunct;
  698.       mtrig1 = trigfn[trigndx[1]].mfunct;
  699. #endif
  700.       dtrig1 = trigfn[trigndx[1]].dfunct;
  701.       break;
  702.    case 2:
  703. #ifndef XFRACT
  704.       ltrig2 = trigfn[trigndx[2]].lfunct;
  705.       mtrig2 = trigfn[trigndx[2]].mfunct;
  706. #endif
  707.       dtrig2 = trigfn[trigndx[2]].dfunct;
  708.       break;
  709.    case 3:
  710. #ifndef XFRACT
  711.       ltrig3 = trigfn[trigndx[3]].lfunct;
  712.       mtrig3 = trigfn[trigndx[3]].mfunct;
  713. #endif
  714.       dtrig3 = trigfn[trigndx[3]].dfunct;
  715.       break;
  716.    default: /* do 'em all */
  717.       for(i=0;i<4;i++)
  718.      set_trig_pointers(i);
  719.       break;
  720.    }
  721. }
  722.  
  723. static FCODE sfractal_type[] =     {"Fractal type:"};
  724. static FCODE sitem_name[] =        {"Item name:"};
  725. static FCODE sitem_file[] =        {"Item file:"};
  726. static FCODE s3D_transform[] =     {"3D Transform"};
  727. static FCODE syou_are_cycling[] =  {"You are in color-cycling mode"};
  728. static FCODE sfloating_point[] =   {"Floating-point"};
  729. static FCODE ssolid_guessing[] =   {"Solid Guessing"};
  730. static FCODE sboundary_tracing[] = {"Boundary Tracing"};
  731. static FCODE stesseral[] =         {"Tesseral"};
  732. static FCODE scalculation_time[] = {"Calculation time:"};
  733. static FCODE siterations[] =       {" 1000's of points:"};
  734. static FCODE scornersxy[] =        {"Corners:                X                     Y"};
  735. static FCODE stop_left[] =         {"Top-l"};
  736. static FCODE sbottom_right[] =     {"Bot-r"};
  737. static FCODE sbottom_left[] =      {"Bot-l"};
  738. static FCODE scenter[] =           {"Ctr"};
  739. static FCODE struncate[] =         {"(Center values shown truncated to 320 decimals)"};
  740. static FCODE smag[] =              {"Mag"};
  741. static FCODE sxmag[] =             {"X-Mag-Factor"};
  742. static FCODE srot[] =              {"Rotation"};
  743. static FCODE sskew[] =             {"Skew"};
  744. static FCODE sparams[] =           {"Params "};
  745. static FCODE siteration_maximum[] ={"Iteration maximum: "};
  746. static FCODE seffective_bailout[] ={"     Effective bailout: "};
  747. static FCODE scurrent_rseed[] =    {"Current 'rseed': "};
  748. static FCODE sinversion_radius[] = {"Inversion radius: "};
  749. static FCODE sxcenter[] =          {"  xcenter: "};
  750. static FCODE sycenter[] =          {"  ycenter: "};
  751. static FCODE sparms_chgd[] = {"Parms chgd since generated"};
  752. static FCODE sstill_being[] = {"Still being generated"};
  753. static FCODE sinterrupted_resumable[] = {"Interrupted, resumable"};
  754. static FCODE sinterrupted_non_resumable[] = {"Interrupted, non-resumable"};
  755. static FCODE simage_completed[] = {"Image completed"};
  756. static FCODE sflag_is_activated[] = {" flag is activated"};
  757. static FCODE sinteger_math[]      = {"Integer math is in use"};
  758. static FCODE sin_use_required[] = {" in use (required)"};
  759. static FCODE sarbitrary_precision[] = {"Arbitrary precision "};
  760. static FCODE spressanykey[] = {"Press any key to continue, F6 for area, CTRL-TAB for next page"};
  761. static FCODE spressanykey1[] = {"Press any key to continue, Backspace for first screen"};
  762. static FCODE sbatch[] = {" (Batch mode)"};
  763. static FCODE ssavename[] = {"Savename: "};
  764. static FCODE sstopsecret[] = {"Top Secret Developer's Screen"};
  765. static FCODE sthreepass[] = {" (threepass)"};   
  766.  
  767. static void show_str_var(char *name, char *var, int *row, char *msg)
  768. {
  769.    if(var == NULL)
  770.       return;
  771.    if(*var != 0)
  772.    {
  773.       sprintf(msg,"%s=%s",name,var);
  774.       putstring((*row)++,2,C_GENERAL_HI,msg);
  775.    }
  776. }
  777.  
  778. int tab_display_2(char *msg)
  779. {
  780.    extern long maxptr, maxstack, startstack;
  781.    int row,key,ret=0;
  782.    helptitle();
  783.    setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
  784.  
  785.    row = 1;
  786.    putstringcenter(row++,0,80,C_PROMPT_HI, sstopsecret);
  787.    sprintf(msg,"%u bytes conventional stack free",stackavail());
  788.    putstring(++row,2,C_GENERAL_HI,msg);
  789.    sprintf(msg,"%ld of %ld bignum memory used",maxptr,maxstack);
  790.    putstring(++row,2,C_GENERAL_HI,msg);
  791.    sprintf(msg,"   %ld used for bignum globals", startstack);
  792.    putstring(++row,2,C_GENERAL_HI,msg);
  793.    sprintf(msg,"   %ld stack used == %ld variables of length %d",
  794.          maxptr-startstack,(long)((maxptr-startstack)/(rbflength+2)),rbflength+2);
  795.    putstring(++row,2,C_GENERAL_HI,msg);
  796.    if(bf_math)
  797.    {
  798.       sprintf(msg,"intlength %-d bflength %-d ",intlength, bflength);
  799.       putstring(++row,2,C_GENERAL_HI,msg);
  800.    }
  801.    row++;   
  802.    show_str_var(s_tempdir,    tempdir,      &row, msg);
  803.    show_str_var(s_workdir,    workdir,      &row, msg);
  804.    show_str_var(s_printfile,  PrintName,    &row, msg);
  805.    show_str_var(s_filename,   readname,     &row, msg);
  806.    show_str_var(s_formulafile,FormFileName, &row, msg);
  807.    show_str_var(s_savename,   savename,     &row, msg);
  808.    show_str_var(s_parmfile,   CommandFile,  &row, msg);
  809.    show_str_var(s_ifsfile,    IFSFileName,  &row, msg);
  810.    show_str_var(s_autokeyname,autoname,     &row, msg);
  811.    show_str_var(s_lightname,  light_name,   &row, msg);
  812.    show_str_var(s_map,        MAP_name,     &row, msg);
  813.    sprintf(msg,"Sizeof fractalspecific array %d",
  814.       num_fractal_types*(int)sizeof(struct fractalspecificstuff));
  815.    putstring(row++,2,C_GENERAL_HI,msg);
  816.    sprintf(msg,"checkcurdir %d",checkcurdir);
  817.    putstring(row++,2,C_GENERAL_HI,msg);
  818.    sprintf(msg,"calc_status %d",calc_status);
  819.    putstring(row++,2,C_GENERAL_HI,msg);
  820.  
  821.    putstringcenter(24,0,80,C_GENERAL_LO,spressanykey1);
  822.    key=getakeynohelp();
  823.    if(key == BACKSPACE)
  824.       ret = 1;
  825.    return(ret);      
  826. }
  827.  
  828. int tab_display()    /* display the status of the current image */
  829. {
  830.    int row, i, j, addrow=0;
  831.    double Xctr, Yctr;
  832.    LDBL Magnification;
  833.    double Xmagfactor, Rotation, Skew;
  834.    bf_t bfXctr=NULL, bfYctr=NULL;
  835.    char msg[350];
  836.    char far *msgptr;
  837.    int key;
  838.    int saved=0;
  839.    int dec;
  840.  
  841.    if (calc_status < 0) {     /* no active fractal image */
  842.       return(0);        /* (no TAB on the credits screen) */
  843.    }
  844.    if (calc_status == 1)    /* next assumes CLK_TCK is 10^n, n>=2 */
  845.       calctime += (clock_ticks() - timer_start) / (CLK_TCK/100);
  846.    stackscreen();
  847.    if(bf_math)
  848.    {
  849.       saved = save_stack();
  850.       bfXctr = alloc_stack(bflength+2);
  851.       bfYctr = alloc_stack(bflength+2);
  852.    }
  853. top:
  854.    helptitle();
  855.    setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
  856.    row = 2;
  857.    putstring(row,2,C_GENERAL_MED,sfractal_type);
  858.    if (display3d > 0)
  859.       putstring(row,16,C_GENERAL_HI,s3D_transform);
  860.    else {
  861.       putstring(row,16,C_GENERAL_HI,
  862.        curfractalspecific->name[0] == '*' ?
  863.          &curfractalspecific->name[1] :
  864.          curfractalspecific->name);
  865.       i = 0;
  866.       if (fractype == FORMULA || fractype == FFORMULA)
  867.       {
  868.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  869.      putstring(row+1,16,C_GENERAL_HI,FormName);
  870.          i = strlen(FormName)+1;
  871.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  872.          if(strlen(FormFileName) >= 29)
  873.             addrow = 1;
  874.          putstring(row+2+addrow,16,C_GENERAL_HI,FormFileName);
  875.       }
  876.       trigdetails(msg);
  877.       putstring(row+1,16+i,C_GENERAL_HI,msg);
  878.       if (fractype == LSYSTEM) 
  879.       {
  880.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  881.      putstring(row+1,16,C_GENERAL_HI,LName);
  882.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  883.          if(strlen(LFileName) >= 28)
  884.             addrow = 1;
  885.          putstring(row+2+addrow,16,C_GENERAL_HI,LFileName);
  886.       }
  887.       if (fractype == IFS || fractype == IFS3D) 
  888.       {
  889.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  890.      putstring(row+1,16,C_GENERAL_HI,IFSName);
  891.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  892.          if(strlen(IFSFileName) >= 28)
  893.             addrow = 1;
  894.          putstring(row+2+addrow,16,C_GENERAL_HI,IFSFileName);
  895.       }
  896.    }
  897.  
  898.    switch (calc_status) {
  899.       case 0:  msgptr = sparms_chgd;
  900.            break;
  901.       case 1:  msgptr = sstill_being;
  902.            break;
  903.       case 2:  msgptr = sinterrupted_resumable;
  904.            break;
  905.       case 3:  msgptr = sinterrupted_non_resumable;
  906.            break;
  907.       case 4:  msgptr = simage_completed;
  908.            break;
  909.       default: msgptr = "";
  910.       }
  911.    putstring(row,45,C_GENERAL_HI,msgptr);
  912.    if(initbatch && calc_status != 0)
  913.       putstring(-1,-1,C_GENERAL_HI,sbatch);
  914.    
  915.    if (helpmode == HELPCYCLING)
  916.       putstring(row+1,45,C_GENERAL_HI,syou_are_cycling);
  917.    ++row;
  918.    /* if(bf_math == 0) */ 
  919.      ++row;
  920.  
  921.     i = j = 0;
  922.     if (display3d > 0) {
  923.        if (usr_floatflag)
  924.       j = 1;
  925.        }
  926.     else
  927.        if (floatflag)
  928.       j = (usr_floatflag) ? 1 : 2;
  929.     if(bf_math==0)
  930.     {
  931.     if (j) {
  932.        putstring(row,45,C_GENERAL_HI,sfloating_point);
  933.  
  934.        putstring(-1,-1,C_GENERAL_HI,(j == 1) ? sflag_is_activated
  935.                          : sin_use_required );
  936.       i = 1;
  937.       }
  938.       else
  939.       {
  940.        putstring(row,45,C_GENERAL_HI,sinteger_math);
  941.       i = 1;
  942.       }
  943.    } else
  944.    {
  945.        sprintf(msg,"(%-d decimals)",decimals /*getprecbf(CURRENTREZ)*/);
  946.        putstring(row,45,C_GENERAL_HI,sarbitrary_precision);
  947.        putstring(-1,-1,C_GENERAL_HI,msg);
  948.  
  949.       i = 1;
  950.    }   
  951.  
  952.    row += i;
  953.  
  954.    if (calc_status == 1 || calc_status == 2)
  955.       if (curfractalspecific->flags&NORESUME)
  956.       {
  957.      static FCODE msg[] = {"Note: can't resume this type after interrupts other than <tab> and <F1>"};
  958.      putstring(row++,2,C_GENERAL_HI,msg);
  959.       }
  960.    row += addrow;
  961.    putstring(row,2,C_GENERAL_MED,ssavename);
  962.    putstring(row,-1,C_GENERAL_HI,savename);
  963.    
  964.    /* if(bf_math == 0) */
  965.      ++row;
  966.  
  967.    if (got_status >= 0 && (calc_status == 1 || calc_status == 2)) {
  968.       switch (got_status) {
  969.      case 0:
  970.         sprintf(msg,"%d Pass Mode",totpasses);
  971.         putstring(row,2,C_GENERAL_HI,msg);
  972.             if(usr_stdcalcmode=='3')
  973.                 putstring(row,-1,C_GENERAL_HI,sthreepass);
  974.         break;
  975.      case 1:
  976.         putstring(row,2,C_GENERAL_HI,ssolid_guessing);
  977.             if(usr_stdcalcmode=='3')
  978.                 putstring(row,-1,C_GENERAL_HI,sthreepass);
  979.         break;
  980.      case 2:
  981.         putstring(row,2,C_GENERAL_HI,sboundary_tracing);
  982.         break;
  983.      case 3:
  984.         sprintf(msg,"Processing row %d (of %d) of input image",currow,fileydots);
  985.         putstring(row,2,C_GENERAL_HI,msg);
  986.         break;
  987.      case 4:
  988.         putstring(row,2,C_GENERAL_HI,stesseral);
  989.         break;
  990.      }
  991.       ++row;
  992.       if (got_status != 3) {
  993.      sprintf(msg,"Working on block (y,x) [%d,%d]...[%d,%d], ",
  994.         yystart,xxstart,yystop,xxstop);
  995.      putstring(row,2,C_GENERAL_MED,msg);
  996.      if (got_status == 2 || got_status == 4) { /* btm or tesseral */
  997.         putstring(-1,-1,C_GENERAL_MED,"at ");
  998.         sprintf(msg,"[%d,%d]",currow,curcol);
  999.         putstring(-1,-1,C_GENERAL_HI,msg);
  1000.         }
  1001.      else {
  1002.         if (totpasses > 1) {
  1003.            putstring(-1,-1,C_GENERAL_MED,"pass ");
  1004.            sprintf(msg,"%d",curpass);
  1005.            putstring(-1,-1,C_GENERAL_HI,msg);
  1006.            putstring(-1,-1,C_GENERAL_MED," of ");
  1007.            sprintf(msg,"%d",totpasses);
  1008.            putstring(-1,-1,C_GENERAL_HI,msg);
  1009.            putstring(-1,-1,C_GENERAL_MED,", ");
  1010.            }
  1011.         putstring(-1,-1,C_GENERAL_MED,"at row ");
  1012.         sprintf(msg,"%d",currow);
  1013.         putstring(-1,-1,C_GENERAL_HI,msg);
  1014.         }
  1015.      ++row;
  1016.      }
  1017.       }
  1018.    putstring(row,2,C_GENERAL_MED,scalculation_time);
  1019.    if (calctime >= 0)
  1020.       sprintf(msg,"%3ld:%02ld:%02ld.%02ld", calctime/360000L,
  1021.              (calctime%360000L)/6000, (calctime%6000)/100, calctime%100);
  1022.    else
  1023.       sprintf(msg," A Really Long Time!!! (> 24.855 days)");
  1024.    putstring(-1,-1,C_GENERAL_HI,msg);
  1025.    /* XXX */
  1026.  
  1027.    if ((curfractalspecific->flags&INFCALC) && (coloriter != 0)) {
  1028.       putstring(row,-1,C_GENERAL_MED,siterations);
  1029.       sprintf(msg," %ld of %ld",coloriter-2,maxct);
  1030.       putstring(row,-1,C_GENERAL_HI,msg);
  1031.    }
  1032.    
  1033.    ++row;
  1034.    if(bf_math == 0)
  1035.      ++row;
  1036.    if (videoentry.xdots && bf_math==0) {
  1037.       sprintf(msg,"Video: %dx%dx%d %s %s",
  1038.           videoentry.xdots, videoentry.ydots, videoentry.colors,
  1039.           videoentry.name, videoentry.comment);
  1040.       putstring(row++,2,C_GENERAL_MED,msg);
  1041.       }
  1042.    if(!(curfractalspecific->flags&NOZOOM))
  1043.    {
  1044.    adjust_corner(); /* make bottom left exact if very near exact */
  1045.    if(bf_math)
  1046.    {
  1047.       int truncate, truncaterow;
  1048.       dec = min(320,decimals);
  1049.       adjust_cornerbf(); /* make bottom left exact if very near exact */
  1050.       cvtcentermagbf(bfXctr, bfYctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  1051.       /* find alignment information */
  1052.       msg[0] = 0;
  1053.       truncate = 0;
  1054.       if(dec < decimals)
  1055.          truncate = 1;
  1056.       truncaterow = row;
  1057.       putstring(++row,2,C_GENERAL_MED,scenter);
  1058.       putstring(row,8,C_GENERAL_MED,s_x);
  1059.       bftostr(msg,dec,bfXctr);
  1060.       if(putstringwrap(&row,10,78,C_GENERAL_HI,msg,5)==1)
  1061.          truncate = 1;
  1062.       putstring(++row,8,C_GENERAL_MED,s_y);
  1063.       bftostr(msg,dec,bfYctr);
  1064.       if(putstringwrap(&row,10,78,C_GENERAL_HI,msg,5)==1 || truncate)
  1065.          putstring(truncaterow,2,C_GENERAL_MED,struncate);
  1066.       putstring(++row,2,C_GENERAL_MED,smag);
  1067. #ifdef USE_LONG_DOUBLE
  1068.       sprintf(msg,"%10.8Le",Magnification);
  1069. #else
  1070.       sprintf(msg,"%10.8le",Magnification);
  1071. #endif
  1072.       putstring(-1,11,C_GENERAL_HI,msg);
  1073.       putstring(++row,2,C_GENERAL_MED,sxmag);
  1074.       sprintf(msg,"%11.4f   ",Xmagfactor);
  1075.       putstring(-1,-1,C_GENERAL_HI,msg);
  1076.       putstring(-1,-1,C_GENERAL_MED,srot);
  1077.       sprintf(msg,"%9.3f   ",Rotation);
  1078.       putstring(-1,-1,C_GENERAL_HI,msg);
  1079.       putstring(-1,-1,C_GENERAL_MED,sskew);
  1080.       sprintf(msg,"%9.3f",Skew);
  1081.       putstring(-1,-1,C_GENERAL_HI,msg);
  1082.    }
  1083.    else /* bf != 1 */
  1084.    {
  1085.       putstring(row,2,C_GENERAL_MED,scornersxy);
  1086.       putstring(++row,3,C_GENERAL_MED,stop_left);
  1087.       sprintf(msg,"%20.16f  %20.16f",xxmin,yymax);
  1088.       putstring(-1,17,C_GENERAL_HI,msg);
  1089.       putstring(++row,3,C_GENERAL_MED,sbottom_right);
  1090.       sprintf(msg,"%20.16f  %20.16f",xxmax,yymin);
  1091.       putstring(-1,17,C_GENERAL_HI,msg);
  1092.  
  1093.       if (xxmin != xx3rd || yymin != yy3rd)
  1094.       {
  1095.          putstring(++row,3,C_GENERAL_MED,sbottom_left);
  1096.          sprintf(msg,"%20.16f  %20.16f",xx3rd,yy3rd);
  1097.          putstring(-1,17,C_GENERAL_HI,msg);
  1098.       }
  1099.       cvtcentermag(&Xctr, &Yctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  1100.       putstring(row+=2,2,C_GENERAL_MED,scenter);
  1101.       sprintf(msg,"%20.16f %20.16f  ",Xctr,Yctr);
  1102.       putstring(-1,-1,C_GENERAL_HI,msg);
  1103.       putstring(-1,-1,C_GENERAL_MED,smag);
  1104. #ifdef USE_LONG_DOUBLE
  1105.       sprintf(msg," %10.8Le",Magnification);
  1106. #else
  1107.       sprintf(msg," %10.8le",Magnification);
  1108. #endif
  1109.       putstring(-1,-1,C_GENERAL_HI,msg);
  1110.       putstring(++row,2,C_GENERAL_MED,sxmag);
  1111.       sprintf(msg,"%11.4f   ",Xmagfactor);
  1112.       putstring(-1,-1,C_GENERAL_HI,msg);
  1113.       putstring(-1,-1,C_GENERAL_MED,srot);
  1114.       sprintf(msg,"%9.3f   ",Rotation);
  1115.       putstring(-1,-1,C_GENERAL_HI,msg);
  1116.       putstring(-1,-1,C_GENERAL_MED,sskew);
  1117.       sprintf(msg,"%9.3f",Skew);
  1118.       putstring(-1,-1,C_GENERAL_HI,msg);
  1119.  
  1120.    }
  1121.    }      
  1122.    for (i = 0; i < MAXPARAMS; i++)
  1123.    {
  1124.       char *p;
  1125.       int col;
  1126.       p = typehasparm(fractype,i);
  1127.       if(i%4 == 0)
  1128.       {
  1129.          row++;
  1130.          col = 9;
  1131.       }
  1132.       else
  1133.          col = -1;
  1134.       if(p)
  1135.       {
  1136.          if(i==0)
  1137.             putstring(++row,2,C_GENERAL_MED,sparams);
  1138.          sprintf(msg,"%3d: ",i+1);
  1139.          putstring(row,col,C_GENERAL_MED,msg);
  1140.          if(*p == '+')
  1141.             sprintf(msg,"%-12d",(int)param[i]);
  1142.          else if(*p == '#')
  1143.             sprintf(msg,"%-12lu",(U32)param[i]);
  1144.          else   
  1145.             sprintf(msg,"%-12.9f",param[i]);
  1146.          putstring(-1,-1,C_GENERAL_HI,msg);
  1147.       }
  1148.    }
  1149.    putstring(row+=2,2,C_GENERAL_MED,siteration_maximum);
  1150.    sprintf(msg,"%ld",maxit);
  1151.    putstring(-1,-1,C_GENERAL_HI,msg);
  1152.    putstring(-1,-1,C_GENERAL_MED,seffective_bailout);
  1153.    sprintf(msg,"%f",rqlim);
  1154.    putstring(-1,-1,C_GENERAL_HI,msg);
  1155.  
  1156.    if (fractype == PLASMA || fractype == ANT || fractype == CELLULAR) {
  1157.       putstring(++row,2,C_GENERAL_MED,scurrent_rseed);
  1158.       sprintf(msg,"%d",rseed);
  1159.       putstring(-1,-1,C_GENERAL_HI,msg);
  1160.       }
  1161.  
  1162.    if(invert) {
  1163.       putstring(++row,2,C_GENERAL_MED,sinversion_radius);
  1164.       sprintf(msg,"%12.9f",f_radius);
  1165.       putstring(-1,-1,C_GENERAL_HI,msg);
  1166.       putstring(-1,-1,C_GENERAL_MED,sxcenter);
  1167.       sprintf(msg,"%12.9f",f_xcenter);
  1168.       putstring(-1,-1,C_GENERAL_HI,msg);
  1169.       putstring(-1,-1,C_GENERAL_MED,sycenter);
  1170.       sprintf(msg,"%12.9f",f_ycenter);
  1171.       putstring(-1,-1,C_GENERAL_HI,msg);
  1172.       }
  1173.  
  1174.    if ((row += 2) < 23) ++row;
  1175. /*waitforkey:*/
  1176.    putstringcenter(/*row*/24,0,80,C_GENERAL_LO,spressanykey);
  1177.    movecursor(25,80);
  1178. #ifdef XFRACT
  1179.    while (keypressed()) {
  1180.        getakey();
  1181.    }
  1182. #endif
  1183.    key = getakeynohelp();
  1184.    if (key==F6) {
  1185.        unstackscreen();
  1186.        area();
  1187.        stackscreen();
  1188. /*       goto waitforkey;*/
  1189.         goto top;
  1190.    }
  1191.    else if(key==CTL_TAB) {    
  1192.       if(tab_display_2(msg))
  1193.          goto top;
  1194.    }
  1195.    unstackscreen();
  1196.    timer_start = clock_ticks(); /* tab display was "time out" */
  1197.    if(bf_math)
  1198.       restore_stack(saved);
  1199.    return(0);
  1200. }
  1201.  
  1202. static void area(void)
  1203. {
  1204.     /* apologies to UNIX folks, we PC guys have to save near space */
  1205.     static FCODE warning[] = {"Warning: inside may not be unique\n"};
  1206.     static FCODE total_area[] = {".  Total area "}; 
  1207.     char far *msg;
  1208.     int x,y;
  1209.     char buf[160];
  1210.     long cnt=0;
  1211.     if (inside<0) {
  1212.       static FCODE msg[] = {"Need solid inside to compute area"};
  1213.       stopmsg(0,msg);
  1214.       return;
  1215.     }
  1216.     for (y=0;y<ydots;y++) {
  1217.       for (x=0;x<xdots;x++) {
  1218.           if (getcolor(x,y)==inside) {
  1219.               cnt++;
  1220.           }
  1221.       }
  1222.     }
  1223.     if (inside>0 && outside<0 && maxit>inside) {
  1224.       msg = warning;
  1225.     } else {
  1226.       msg = (char far *)"";
  1227.     }
  1228. #ifndef XFRACT
  1229.       sprintf(buf,"%Fs%ld inside pixels of %ld%Fs%f",
  1230.               msg,cnt,(long)xdots*(long)ydots,(char far *)total_area,
  1231.               cnt/((float)xdots*(float)ydots)*(xxmax-xxmin)*(yymax-yymin));
  1232. #else
  1233.       sprintf(buf,"%s%ld inside pixels of %ld%s%f",
  1234.               msg,cnt,(long)xdots*(long)ydots,total_area,
  1235.               cnt/((float)xdots*(float)ydots)*(xxmax-xxmin)*(yymax-yymin));
  1236. #endif
  1237.     stopmsg(4,buf);
  1238. }
  1239.  
  1240. int endswithslash(char *fl)
  1241. {
  1242.    int len;
  1243.    len = strlen(fl);
  1244.    if(len)
  1245.       if(fl[--len] == SLASHC)
  1246.      return(1);
  1247.    return(0);
  1248. }
  1249.  
  1250. /* --------------------------------------------------------------------- */
  1251. static char seps[] = {"' ','\t',\n',\r'"};
  1252. char *get_ifs_token(char *buf,FILE *ifsfile)
  1253. {
  1254.    char *bufptr;
  1255.    for(;;)
  1256.    {
  1257.       if(file_gets(buf,200,ifsfile) < 0)
  1258.          return(NULL);
  1259.       else
  1260.       {
  1261.          if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
  1262.             *bufptr = 0;
  1263.          if((bufptr = strtok(buf, seps)) != NULL)
  1264.             return(bufptr);
  1265.       }
  1266.    }
  1267. }
  1268.  
  1269. FCODE insufficient_ifs_mem[]={"Insufficient memory for IFS"};
  1270. int numaffine;
  1271. int ifsload()            /* read in IFS parameters */
  1272. {
  1273.    int i;
  1274.    FILE *ifsfile;
  1275.    char buf[201];
  1276.    char *bufptr;
  1277.    int ret,rowsize;
  1278.  
  1279.    if (ifs_defn) { /* release prior parms */
  1280.       farmemfree((char far *)ifs_defn);
  1281.       ifs_defn = NULL;
  1282.       }
  1283.  
  1284.    ifs_type = 0;
  1285.    rowsize = IFSPARM;
  1286.    if (find_file_item(IFSFileName,IFSName,&ifsfile) < 0)
  1287.       return(-1);
  1288.  
  1289.    file_gets(buf,200,ifsfile);
  1290.    if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
  1291.       *bufptr = 0;
  1292.    
  1293.    strlwr(buf);
  1294.    bufptr = &buf[0];
  1295.    while (*bufptr) {
  1296.       if (strncmp(bufptr,"(3d)",4) == 0) {
  1297.      ifs_type = 1;
  1298.      rowsize = IFS3DPARM;
  1299.      }
  1300.       ++bufptr;
  1301.       }
  1302.  
  1303.    for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  1304.       ((float *)tstack)[i] = 0;
  1305.    i = ret = 0;
  1306.    bufptr = get_ifs_token(buf,ifsfile);
  1307.    while(bufptr != NULL)
  1308.    {
  1309.       if(sscanf(bufptr," %f ",&((float *)tstack)[i]) != 1)
  1310.          break ;
  1311.       if (++i >= NUMIFS*rowsize) 
  1312.       {
  1313.          static FCODE msg[]={"IFS definition has too many lines"};
  1314.         stopmsg(0,msg);
  1315.         ret = -1;
  1316.         break;
  1317.       }
  1318.       if((bufptr = strtok( NULL, seps ))==NULL)
  1319.       {
  1320.          if((bufptr = get_ifs_token(buf,ifsfile)) == NULL)
  1321.          {
  1322.             ret = -1;
  1323.             break;
  1324.          }   
  1325.       }
  1326.       if(ret == -1)
  1327.          break;
  1328.       if(*bufptr == '}')
  1329.          break;
  1330.    }
  1331.    
  1332.    if ((i % rowsize) != 0 || *bufptr != '}') {
  1333.       static FCODE msg[]={"invalid IFS definition"};
  1334.       stopmsg(0,msg);
  1335.       ret = -1;
  1336.       }
  1337.    if (i == 0 && ret == 0) {
  1338.       static FCODE msg[]={"Empty IFS definition"};
  1339.       stopmsg(0,msg);
  1340.       ret = -1;
  1341.       }
  1342.    fclose(ifsfile);
  1343.  
  1344.    if (ret == 0) {
  1345.       numaffine = i/rowsize;
  1346.       if ((ifs_defn = (float far *)farmemalloc(
  1347.             (long)((NUMIFS+1)*IFS3DPARM*sizeof(float)))) == NULL) {
  1348.      stopmsg(0,insufficient_ifs_mem);
  1349.      ret = -1;
  1350.      }
  1351.       else
  1352.      for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  1353.         ifs_defn[i] = ((float *)tstack)[i];
  1354.    }
  1355.    return(ret);
  1356. }
  1357. /* TW 5-31-94 - added search of current directory for entry files if
  1358.    entry item not found */
  1359.  
  1360. int find_file_item(char *filename,char *itemname,FILE **fileptr)
  1361. {
  1362.    FILE *infile=NULL;
  1363.    int found = 0;
  1364.    if((found=find_one_file_item(filename,itemname,&infile)) != 0) 
  1365.    {  /* search for file */
  1366.       int out;
  1367.       char drive[FILE_MAX_DRIVE];
  1368.       char dir[FILE_MAX_DIR];
  1369.       char fname[FILE_MAX_FNAME];
  1370.       char ext[FILE_MAX_EXT];
  1371.       char fullpath[FILE_MAX_PATH];
  1372.       splitpath(filename,drive,dir,fname,ext);
  1373.       makepath(fullpath,drive,dir,"*",ext);
  1374.       out = fr_findfirst(fullpath);
  1375.       found = 0;
  1376.       while(out == 0) 
  1377.       {
  1378.          char msg[200];
  1379.          DTA.filename[FILE_MAX_FNAME+FILE_MAX_EXT-2]=0;
  1380.          sprintf(msg,"Searching %13s for %s      ",DTA.filename,itemname);
  1381.          showtempmsg(msg);
  1382.          if(!(DTA.attribute & SUBDIR) && 
  1383.              strcmp(DTA.filename,".")&&
  1384.              strcmp(DTA.filename,"..")) {    
  1385. #ifndef XFRACT
  1386.             strlwr(DTA.filename);
  1387. #endif
  1388.             splitpath(DTA.filename,NULL,NULL,fname,ext);
  1389.             makepath(fullpath,drive,dir,fname,ext);
  1390.             if((found=find_one_file_item(fullpath,itemname,&infile)) == 0) 
  1391.             {
  1392.                strcpy(filename,fullpath);
  1393.                break;
  1394.             }   
  1395.          }   
  1396.          out = fr_findnext();
  1397.       }
  1398.       cleartempmsg();
  1399.       if(found != 0)
  1400.       {
  1401.          sprintf(fullpath,"'%s' file entry item not found",itemname);
  1402.          stopmsg(0,fullpath);
  1403.          return(-1);
  1404.       }
  1405.    }
  1406.    /* found file */   
  1407.    if(fileptr != NULL)
  1408.       *fileptr = infile;
  1409.    else if(infile != NULL)
  1410.       fclose(infile);   
  1411.    return(0);
  1412. }
  1413.  
  1414. static int find_one_file_item(char *filename,char *itemname,FILE **infile)
  1415. {
  1416.    char fullpathname[FILE_MAX_PATH];
  1417.    char fname[FILE_MAX_FNAME];
  1418.    char ext[FILE_MAX_EXT];
  1419.  
  1420.    splitpath(filename ,NULL,NULL,fname,ext);
  1421.    makepath(fullpathname,""   ,"" ,fname,ext);
  1422.  
  1423.    /* first try current directory */
  1424.    if(checkcurdir == 0 || access(fullpathname,0) != 0)
  1425.       strcpy(fullpathname,filename);   
  1426.    
  1427.    /* now binary node as of 2/95 TW */
  1428.    if ((*infile = fopen(fullpathname,"rb")) == NULL) {
  1429.        return(-1);
  1430.       }
  1431.    /* 
  1432.       Scan_entries() resuses code from gfe_choose_entry() in PROMPTS1.C. The
  1433.       original code used text mode, which made ftell() and fseek() unreliable
  1434.       in cases where files have garbage after the EOF.
  1435.     */
  1436.    if(scan_entries(*infile, NULL, itemname)<0)
  1437.       return(0);
  1438.    fclose(*infile);
  1439.    infile = NULL;
  1440.    return(-1);
  1441. }
  1442.  
  1443. int file_gets(char *buf,int maxlen,FILE *infile)
  1444. {
  1445.    int len,c;
  1446.    /* similar to 'fgets', but file may be in either text or binary mode */
  1447.    /* returns -1 at eof, length of string otherwise */
  1448.    if (feof(infile)) return -1;
  1449.    len = 0;
  1450.    while (len < maxlen) {
  1451.       if ((c = getc(infile)) == EOF || c == '\032') {
  1452.      if (len) break;
  1453.      return -1;
  1454.      }
  1455.       if (c == '\n') break;             /* linefeed is end of line */
  1456.       if (c != '\r') buf[len++] = (char)c;    /* ignore c/r */
  1457.       }
  1458.    buf[len] = 0;
  1459.    return len;
  1460. }
  1461.  
  1462. int first_err = 1;
  1463.  
  1464. #ifndef XFRACT
  1465. #ifdef WINFRACT
  1466. /* call this something else to dodge the QC4WIN bullet... */
  1467. int win_matherr( struct exception *except )
  1468. #else
  1469. int _cdecl matherr( struct exception *except )
  1470. #endif
  1471. {
  1472.     static FCODE msg[]={"Math error, but we'll try to keep going"};
  1473.     if(first_err)
  1474.     {
  1475.        if(debugflag == 4000 || debugflag == 3200)stopmsg(0,msg);
  1476.        first_err = 0;
  1477.     }
  1478.     if(debugflag)
  1479.     {
  1480.        static int ct = 0;
  1481.        static FILE *fp=NULL;
  1482.        if(fp==NULL)
  1483.       fp = fopen("matherr","w");
  1484.        if(ct++ < 100)
  1485.        {
  1486.       fprintf(fp,"err:  %d\nname: %s\narg:  %e\n",
  1487.           except->type, except->name, except->arg1);
  1488.       fflush(fp);
  1489.        }
  1490.     }
  1491.     if( except->type == DOMAIN )
  1492.     {
  1493.     char buf[40];
  1494.     sprintf(buf,"%e",except->arg1);
  1495.     /* This test may be unnecessary - from my experiments if the
  1496.        argument is too large or small the error is TLOSS not DOMAIN */
  1497.     if(strstr(buf,"IN")||strstr(buf,"NAN"))  /* trashed arg? */
  1498.                /* "IND" with MSC, "INF" with BC++ */
  1499.     {
  1500.        if( strcmp( except->name, s_sin ) == 0 )
  1501.        {
  1502.           except->retval = 0.0;
  1503.           return(1);
  1504.        }
  1505.        else if( strcmp( except->name, s_cos ) == 0 )
  1506.        {
  1507.           except->retval = 1.0;
  1508.           return(1);
  1509.        }
  1510.        else if( strcmp( except->name, s_log ) == 0 )
  1511.        {
  1512.           except->retval = 1.0;
  1513.           return(1);
  1514.        }
  1515.        }
  1516.     }
  1517.     if( except->type == TLOSS )
  1518.     {
  1519.        /* try valiantly to keep going */
  1520.        if( strcmp( except->name, s_sin ) == 0 )
  1521.        {
  1522.           except->retval = 0.5;
  1523.           return(1);
  1524.        }
  1525.        else if( strcmp( except->name, s_cos ) == 0 )
  1526.        {
  1527.           except->retval = 0.5;
  1528.           return(1);
  1529.        }
  1530.     }
  1531.     /* shucks, no idea what went wrong, but our motto is "keep going!" */
  1532.     except->retval = 1.0;
  1533.     return(1);
  1534. }
  1535. #endif
  1536.  
  1537. void roundfloatd(double *x) /* make double converted from float look ok */
  1538. {
  1539.    char buf[30];
  1540.    sprintf(buf,"%-10.7g",*x);
  1541.    *x = atof(buf);
  1542. }
  1543.  
  1544. /* fake a keystroke, returns old pending key */
  1545. int ungetakey(int key)
  1546. {
  1547.    int old;
  1548.    old = keybuffer;
  1549.    keybuffer = key;
  1550.    return(old);
  1551. }
  1552.  
  1553. #if _MSC_VER == 800
  1554. #ifdef FIXTAN_DEFINED
  1555. #undef tan
  1556. /* !!!!! stupid MSVC tan(x) bug fix !!!!!!!!            */
  1557. /* tan(x) can return -tan(x) if -pi/2 < x < pi/2       */
  1558. /* if tan(x) has been called before outside this range. */
  1559. double fixtan( double x )
  1560.    {
  1561.    double y;
  1562.  
  1563.    y = tan(x);
  1564.    if ((x > -PI/2 && x < 0 && y > 0) || (x > 0 && x < PI/2 && y < 0))
  1565.       y = -y;
  1566.    return y;
  1567.    }
  1568. #define tan fixtan
  1569. #endif
  1570. #endif
  1571.