home *** CD-ROM | disk | FTP | other *** search
/ Chestnut's Multimedia Mania / MM_MANIA.ISO / windows / winfrac / miscres.c < prev    next >
C/C++ Source or Header  |  1992-03-12  |  24KB  |  844 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 <stdarg.h>
  11. #include <math.h>
  12. #ifdef __TURBOC__
  13. #include <dir.h>
  14. #endif
  15. #include "fractint.h"
  16. #include "fractype.h"
  17. #include "helpdefs.h"
  18.  
  19. /* routines in this module    */
  20.  
  21. extern    void restore_active_ovly(void );
  22. extern    void findpath(char *filename,char *fullpathname);
  23. extern    void notdiskmsg(void );
  24. extern    int cvtcentermag(double *Xctr,double *Yctr,double *Magnification);
  25. extern    void updatesavename(char *name);
  26. extern    int check_writefile(char *name,char *ext);
  27. extern    int check_key(void );
  28. extern    int timer(int timertype,int(*subrtn)(),...);
  29. extern    void showtrig(char *buf);
  30. extern    int set_trig_array(int k,char *name);
  31. extern    void set_trig_pointers(int which);
  32. extern    int tab_display(void );
  33. extern    int endswithslash(char *fl);
  34. extern    int ifsload(void);
  35. extern    int find_file_item(char *filename,char *itemname,FILE **infile);
  36. extern    int file_gets(char *buf,int maxlen,FILE *infile);
  37. extern    void roundfloatd(double *);
  38.  
  39. static    void trigdetails(char *);
  40.  
  41. int active_ovly = -1;
  42. long timer_start,timer_interval;    /* timer(...) start & total */
  43.  
  44. extern char IFSFileName[80];
  45. extern char IFSName[40];
  46. extern float far *ifs_defn;
  47. extern int  ifs_changed;
  48. extern int  ifs_type;
  49.  
  50. extern char temp[], temp1[256];   /* temporary strings          */
  51.  
  52. extern int  active_ovly;
  53. extern int  xdots, ydots;
  54. extern int  dotmode;
  55. extern int  show_orbit;
  56. extern int  timerflag;
  57. extern int  debugflag;
  58. extern int  maxit;
  59. extern int  fractype;
  60. extern int  got_status,curpass,totpasses,currow,curcol;
  61. extern int  fileydots;
  62. extern int  xxstart,xxstop,yystart,yystop;
  63. extern int  display3d;
  64. extern char overwrite;
  65.  
  66.  
  67. /* TW's static string consolidation campaign to help brain-dead compilers */
  68. char s_cantopen[]       = {"Can't open %s"};
  69. char s_cantwrite[]      = {"Can't write %s"};
  70. char s_cantcreate[]     = {"Can't create %s"};
  71. char s_cantunderstand[] = {"Can't understand %s"};
  72. char s_cantfind[]       = {"Can't find %s"};
  73.  
  74. /* call next when returning from resident routine and unsure whether
  75.    caller is an overlay which has been displaced */
  76. void restore_active_ovly()
  77. {
  78.    switch (active_ovly) {
  79.       case OVLY_MISCOVL:  miscovl_overlay();  break;
  80.       case OVLY_CMDFILES: cmdfiles_overlay(); break;
  81.       case OVLY_HELP:      help_overlay();     break;
  82.       case OVLY_PROMPTS:  prompts_overlay();  break;
  83.       case OVLY_LOADFILE: loadfile_overlay(); break;
  84.       case OVLY_ROTATE:   rotate_overlay();   break;
  85.       case OVLY_PRINTER:  printer_overlay();  break;
  86.       case OVLY_LINE3D:   line3d_overlay();   break;
  87.       case OVLY_ENCODER:  encoder_overlay();  break;
  88.       case OVLY_CALCFRAC: calcfrac_overlay(); break;
  89.       case OVLY_INTRO:      intro_overlay();    break;
  90.       }
  91. }
  92.  
  93.  
  94. void findpath(char *filename, char *fullpathname) /* return full pathnames */
  95. {
  96.    if (filename[0] == '\\'
  97.      || (filename[0] && filename[1] == ':')) {
  98.       strcpy(fullpathname,filename);
  99.       return;
  100.       }
  101.    fullpathname[0] = 0;             /* indicate none found */
  102. #ifdef __TURBOC__                /* look for the file */
  103.    strcpy(fullpathname,searchpath(filename));
  104. #else
  105.    _searchenv(filename,"PATH",fullpathname);
  106. #endif
  107.    if (fullpathname[0] != 0)            /* found it! */
  108.       if (strncmp(&fullpathname[2],"\\\\",2) == 0) /* stupid klooge! */
  109.      strcpy(&fullpathname[3],filename);
  110. }
  111.  
  112.  
  113. void notdiskmsg()
  114. {
  115. static char far sorrymsg[]={
  116. "I'm sorry, but because of its random-screen-access algorithms, this\n"
  117. "type cannot be created using a real-disk based 'video' mode."};
  118.    stopmsg(1,sorrymsg);
  119. }
  120.  
  121.  
  122. /* convert corners to center/mag */
  123. int cvtcentermag(double *Xctr, double *Yctr, double *Magnification)
  124. {
  125.    extern double xxmax,xxmin,yymax,yymin,xx3rd,yy3rd;
  126.    double Width, Height, Radius, Ratio;
  127.    Width  = xxmax - xxmin;
  128.    Height = yymax - yymin;
  129.    Ratio = Height / Width;
  130.    if(xx3rd != xxmin || yy3rd != yymin || Width < 0
  131.      || (Width > 1e-8 && (Ratio <= 0.74 || Ratio >= 0.76))
  132.      || Ratio < 0.66 || Ratio > 0.84)
  133.       return(0);
  134.    /* calculate center and magnification */
  135.    Radius = Height / 2.0;
  136.    *Xctr = xxmin + (Width / 2.0);
  137.    *Yctr = yymin + Radius;
  138.    *Magnification = 1.0 / Radius;
  139.    return(1);
  140. }
  141.  
  142.  
  143. void updatesavename(char *filename) /* go to the next file name */
  144. {
  145.    char *save, *hold;
  146.    char name[80],suffix[80];
  147.    char *dotptr;
  148.  
  149.    strcpy(name,filename);
  150.    suffix[0] = 0;
  151.    if ((dotptr = strrchr(name,'.')) != NULL
  152.      && dotptr > strrchr(name,'\\')) {
  153.       strcpy(suffix,dotptr);
  154.       *dotptr = 0;
  155.       }
  156.  
  157.    hold = name + strlen(name) - 1; /* start at the end */
  158.    while(hold >= name && (*hold == ' ' || isdigit(*hold))) /* skip backwards */
  159.       hold--;
  160.    hold++;            /* recover first digit */
  161.    while (*hold == '0')         /* skip leading zeros */
  162.       hold++;
  163.    save = hold;
  164.    while (*save) {        /* check for all nines */
  165.       if (*save != '9')
  166.      break;
  167.       save++;
  168.       }
  169.    if (!*save)            /* if the whole thing is nines then back */
  170.       save = hold - 1;        /* up one place. Note that this will eat */
  171.                 /* your last letter if you go to far.     */
  172.    else
  173.       save = hold;
  174.    sprintf(save,"%d",atoi(hold)+1); /* increment the number */
  175.    strcpy(filename,name);
  176.    strcat(filename,suffix);
  177. }
  178.  
  179. int check_writefile(char *name,char *ext)
  180. {
  181.  /* after v16 release, change encoder.c to also use this routine */
  182.    char openfile[80];
  183.    char opentype[20];
  184.    int i;
  185. nextname:
  186.    strcpy(openfile,name);
  187.    strcpy(opentype,ext);
  188.    for (i = 0; i < strlen(openfile); i++)
  189.       if (openfile[i] == '.') {
  190.      strcpy(opentype,&openfile[i]);
  191.      openfile[i] = 0;
  192.      }
  193.    strcat(openfile,opentype);
  194.    if (access(openfile,0) != 0) /* file doesn't exist */
  195.    {
  196.       strcpy(name,openfile);
  197.       return 0;
  198.     }
  199.    /* file already exists */
  200.    if (overwrite == 0) {
  201.       updatesavename(name);
  202.       goto nextname;
  203.       }
  204.    return 1;
  205. }
  206.  
  207.  
  208. int check_key()
  209. {
  210.    int key;
  211.    if((key = keypressed()) != 0) {
  212.       if(key != 'o' && key != 'O')
  213.      return(-1);
  214.       getakey();
  215.       if (dotmode != 11)
  216.      show_orbit = 1 - show_orbit;
  217.    }
  218.    return(0);
  219. }
  220.  
  221.  
  222. /* timer function:
  223.      timer(0,(*fractal)())        fractal engine
  224.      timer(1,NULL,int width)        decoder
  225.      timer(2)                encoder
  226.   */
  227. int timer(int timertype,int(*subrtn)(),...)
  228. {
  229.    va_list arg_marker;    /* variable arg list */
  230.    char *timestring;
  231.    time_t ltime;
  232.    FILE *fp;
  233.    int out;
  234.    int i;
  235.    int do_bench;
  236.  
  237.    va_start(arg_marker,subrtn);
  238.    do_bench = timerflag; /* record time? */
  239.    if (timertype == 2)     /* encoder, record time only if debug=200 */
  240.       do_bench = (debugflag == 200);
  241.    if(do_bench)
  242.       fp=fopen("bench","a");
  243.    timer_start = clock();
  244.    switch(timertype) {
  245.       case 0:
  246.      out = (*subrtn)();
  247.      break;
  248.       case 1:
  249.      i = va_arg(arg_marker,int);
  250.      out = decoder(i);         /* not indirect, safer with overlays */
  251.      break;
  252.       case 2:
  253.      out = encoder();         /* not indirect, safer with overlays */
  254.      break;
  255.       }
  256.    /* next assumes CLK_TCK is 10^n, n>=2 */
  257.    timer_interval = (clock() - timer_start) / (CLK_TCK/100);
  258.  
  259.    if(do_bench) {
  260.       time(<ime);
  261.       timestring = ctime(<ime);
  262.       timestring[24] = 0; /*clobber newline in time string */
  263.       switch(timertype) {
  264.      case 1:
  265.         fprintf(fp,"decode ");
  266.         break;
  267.      case 2:
  268.         fprintf(fp,"encode ");
  269.         break;
  270.      }
  271.       fprintf(fp,"%s type=%s resolution = %dx%d maxiter=%d",
  272.       timestring,
  273.       curfractalspecific->name,
  274.       xdots,
  275.       ydots,
  276.       maxit);
  277.       fprintf(fp," time= %ld.%02ld secs\n",timer_interval/100,timer_interval%100);
  278.       if(fp != NULL)
  279.      fclose(fp);
  280.       }
  281.    return(out);
  282. }
  283.  
  284.  
  285. extern void lStkSin(void) ,dStkSin(void) ,mStkSin(void) ;
  286. extern void lStkCos(void) ,dStkCos(void) ,mStkCos(void) ;
  287. extern void lStkSinh(void),dStkSinh(void),mStkSinh(void);
  288. extern void lStkCosh(void),dStkCosh(void),mStkCosh(void);
  289. extern void lStkExp(void) ,dStkExp(void) ,mStkExp(void) ;
  290. extern void lStkLog(void) ,dStkLog(void) ,mStkLog(void) ;
  291. extern void lStkSqr(void) ,dStkSqr(void) ,mStkSqr(void) ;
  292. extern void lStkRecip(void) ,dStkRecip(void) ,mStkRecip(void) ;
  293. extern void StkIdent(void);
  294. extern void lStkTan(void) ,dStkTan(void) ,mStkTan(void) ;
  295. extern void lStkTanh(void),dStkTanh(void),mStkTanh(void);
  296. extern void lStkCoTan(void),dStkCoTan(void),mStkCoTan(void);
  297. extern void lStkCoTanh(void),dStkCoTanh(void),mStkCoTanh(void);
  298. extern void lStkCosXX(void) ,dStkCosXX(void) ,mStkCosXX(void) ;
  299.  
  300. unsigned char trigndx[] = {SIN,SQR,SINH,COSH};
  301. void (*ltrig0)() = lStkSin;
  302. void (*ltrig1)() = lStkSqr;
  303. void (*ltrig2)() = lStkSinh;
  304. void (*ltrig3)() = lStkCosh;
  305. void (*dtrig0)() = dStkSin;
  306. void (*dtrig1)() = dStkSqr;
  307. void (*dtrig2)() = dStkSinh;
  308. void (*dtrig3)() = dStkCosh;
  309. void (*mtrig0)() = mStkSin;
  310. void (*mtrig1)() = mStkSqr;
  311. void (*mtrig2)() = mStkSinh;
  312. void (*mtrig3)() = mStkCosh;
  313.  
  314. struct trig_funct_lst trigfn[] =
  315. /* changing the order of these alters meaning of *.fra file */
  316. /* maximum 6 characters in function names or recheck all related code */
  317. {
  318.    {"sin",   lStkSin,   dStkSin,   mStkSin   },
  319.    {"cosxx", lStkCosXX, dStkCosXX, mStkCosXX },
  320.    {"sinh",  lStkSinh,  dStkSinh,  mStkSinh  },
  321.    {"cosh",  lStkCosh,  dStkCosh,  mStkCosh  },
  322.    {"exp",   lStkExp,   dStkExp,   mStkExp   },
  323.    {"log",   lStkLog,   dStkLog,   mStkLog   },
  324.    {"sqr",   lStkSqr,   dStkSqr,   mStkSqr   },
  325.    {"recip", lStkRecip, dStkRecip, mStkRecip }, /* from recip on new in v16 */
  326.    {"ident", StkIdent,  StkIdent,  StkIdent  },
  327.    {"cos",   lStkCos,   dStkCos,   mStkCos   },
  328.    {"tan",   lStkTan,   dStkTan,   mStkTan   },
  329.    {"tanh",  lStkTanh,  dStkTanh,  mStkTanh  },
  330.    {"cotan", lStkCoTan, dStkCoTan, mStkCoTan },
  331.    {"cotanh",lStkCoTanh,dStkCoTanh,mStkCoTanh},
  332. };
  333. int numtrigfn = sizeof(trigfn)/sizeof(struct trig_funct_lst);
  334.  
  335. void showtrig(char *buf) /* return display form of active trig functions */
  336. {
  337.    char tmpbuf[30];
  338.    *buf = 0; /* null string if none */
  339.    trigdetails(tmpbuf);
  340.    if (tmpbuf[0])
  341.       sprintf(buf," function=%s",tmpbuf);
  342. }
  343.  
  344. static void trigdetails(char *buf)
  345. {
  346.    extern char maxfn;
  347.    int i, numfn;
  348.    char tmpbuf[20];
  349.    numfn = (curfractalspecific->flags >> 6) & 7;
  350.    if(curfractalspecific == &fractalspecific[FORMULA] ||
  351.       curfractalspecific == &fractalspecific[FFORMULA]    )
  352.       numfn = maxfn;
  353.    *buf = 0; /* null string if none */
  354.    if (numfn>0) {
  355.       strcpy(buf,trigfn[trigndx[0]].name);
  356.       i = 0;
  357.       while(++i < numfn) {
  358.      sprintf(tmpbuf,"/%s",trigfn[trigndx[i]].name);
  359.      strcat(buf,tmpbuf);
  360.      }
  361.       }
  362. }
  363.  
  364. /* set array of trig function indices according to "function=" command */
  365. int set_trig_array(int k, char *name)
  366. {
  367.    char trigname[10];
  368.    int i;
  369.    char *slash;
  370.    strncpy(trigname,name,6);
  371.    trigname[6] = 0; /* safety first */
  372.  
  373.    if ((slash = strchr(trigname,'/')))
  374.       *slash = 0;
  375.  
  376.    strlwr(trigname);
  377.  
  378.    for(i=0;i<numtrigfn;i++)
  379.    {
  380.       if(strcmp(trigname,trigfn[i].name)==0)
  381.       {
  382.      trigndx[k] = i;
  383.      set_trig_pointers(k);
  384.      break;
  385.       }
  386.    }
  387.    return(0);
  388. }
  389. void set_trig_pointers(int which)
  390. {
  391.   /* set trig variable functions to avoid array lookup time */
  392.    int i;
  393.    switch(which)
  394.    {
  395.    case 0:
  396.       ltrig0 = trigfn[trigndx[0]].lfunct;
  397.       dtrig0 = trigfn[trigndx[0]].dfunct;
  398.       mtrig0 = trigfn[trigndx[0]].mfunct;
  399.       break;
  400.    case 1:
  401.       ltrig1 = trigfn[trigndx[1]].lfunct;
  402.       dtrig1 = trigfn[trigndx[1]].dfunct;
  403.       mtrig1 = trigfn[trigndx[1]].mfunct;
  404.       break;
  405.    case 2:
  406.       ltrig2 = trigfn[trigndx[2]].lfunct;
  407.       dtrig2 = trigfn[trigndx[2]].dfunct;
  408.       mtrig2 = trigfn[trigndx[2]].mfunct;
  409.       break;
  410.    case 3:
  411.       ltrig3 = trigfn[trigndx[3]].lfunct;
  412.       dtrig3 = trigfn[trigndx[3]].dfunct;
  413.       mtrig3 = trigfn[trigndx[3]].mfunct;
  414.       break;
  415.    default: /* do 'em all */
  416.       for(i=0;i<4;i++)
  417.      set_trig_pointers(i);
  418.       break;
  419.    }
  420. }
  421.  
  422.  
  423. int tab_display()    /* display the status of the current image */
  424. {
  425.    extern char floatflag;
  426.    extern char usr_floatflag;
  427.    extern double xxmin, xxmax, xx3rd, yymin, yymax, yy3rd;
  428.    extern double param[4];
  429.    extern double rqlim;
  430.    extern long calctime, timer_start;
  431.    extern int  calc_status;
  432.    extern char FormName[];
  433.    extern char LName[];
  434.    extern char IFSName[];
  435.    extern int  rseed;
  436.    extern int  invert;
  437.    int row, i, j;
  438.    double Xctr, Yctr, Magnification;
  439.    char msg[81];
  440.    char *msgptr;
  441.  
  442.    if (calc_status < 0)     /* no active fractal image */
  443.       return(0);        /* (no TAB on the credits screen) */
  444.    if (calc_status == 1)    /* next assumes CLK_TCK is 10^n, n>=2 */
  445.       calctime += (clock() - timer_start) / (CLK_TCK/100);
  446.    stackscreen();
  447.    helptitle();
  448.    setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
  449.  
  450.    row = 2;
  451.    putstring(row,2,C_GENERAL_MED,"Fractal type:");
  452.    if (display3d > 0)
  453.       putstring(row,16,C_GENERAL_HI,"3D Transform");
  454.    else {
  455.       putstring(row,16,C_GENERAL_HI,
  456.        curfractalspecific->name[0] == '*' ?
  457.          &curfractalspecific->name[1] :
  458.          curfractalspecific->name);
  459.       i = 0;
  460.       if (fractype == FORMULA || fractype == FFORMULA)
  461.       {
  462.      putstring(row+1,16,C_GENERAL_HI,FormName);
  463.       i = strlen(FormName)+1;
  464.       }
  465.       trigdetails(msg);
  466.       putstring(row+1,16+i,C_GENERAL_HI,msg);
  467.       if (fractype == LSYSTEM)
  468.      putstring(row+1,16,C_GENERAL_HI,LName);
  469.       if (fractype == IFS || fractype == IFS3D)
  470.      putstring(row+1,16,C_GENERAL_HI,IFSName);
  471.       }
  472.    switch (calc_status) {
  473.       case 0:  msgptr = "Parms chgd since generated";
  474.            break;
  475.       case 1:  msgptr = "Still being generated";
  476.            break;
  477.       case 2:  msgptr = "Interrupted, resumable";
  478.            break;
  479.       case 3:  msgptr = "Interrupted, non-resumable";
  480.            break;
  481.       case 4:  msgptr = "Image completed";
  482.            break;
  483.       default: msgptr = "";
  484.       }
  485.    putstring(row,45,C_GENERAL_HI,msgptr);
  486.    if (helpmode == HELPCYCLING)
  487.       putstring(row+1,45,C_GENERAL_HI,"You are in color-cycling mode");
  488.    row += 2;
  489.  
  490.     i = j = 0;
  491.     if (display3d > 0) {
  492.        if (usr_floatflag)
  493.       j = 1;
  494.        }
  495.     else
  496.        if (floatflag)
  497.       j = (usr_floatflag) ? 1 : 2;
  498.     if (j) {
  499.        putstring(row,45,C_GENERAL_HI,"Floating-point");
  500.        putstring(-1,-1,C_GENERAL_HI,(j == 1) ? " flag is activated"
  501.                          : " in use (required)");
  502.       i = 1;
  503.       }
  504.    if (calc_status == 1 || calc_status == 2)
  505.       if (curfractalspecific->flags&INFCALC) {
  506.      putstring(row,2,C_GENERAL_HI,"Note: this type runs forever.");
  507.      i = 1;
  508.      }
  509.    row += i;
  510.  
  511.    if (calc_status == 1 || calc_status == 2)
  512.       if (curfractalspecific->flags&NORESUME)
  513.       {
  514.      static char far msg[] = {"Note: can't resume this type after interrupts other than <tab> and <F1>"};
  515.      putstring(row++,2,C_GENERAL_HI,msg);
  516.       }
  517.    ++row;
  518.  
  519.    if (got_status >= 0 && (calc_status == 1 || calc_status == 2)) {
  520.       switch (got_status) {
  521.      case 0:
  522.         sprintf(msg,"%d Pass Mode",totpasses);
  523.         putstring(row,2,C_GENERAL_HI,msg);
  524.         break;
  525.      case 1:
  526.         putstring(row,2,C_GENERAL_HI,"Solid Guessing");
  527.         break;
  528.      case 2:
  529.         putstring(row,2,C_GENERAL_HI,"Boundary Tracing");
  530.         break;
  531.      case 3:
  532.         sprintf(msg,"Processing row %d (of %d) of input image",currow,fileydots);
  533.         putstring(row,2,C_GENERAL_HI,msg);
  534.         break;
  535.      case 4:
  536.         putstring(row,2,C_GENERAL_HI,"Tesseral");
  537.         break;
  538.      }
  539.       ++row;
  540.       if (got_status != 3) {
  541.      sprintf(msg,"Working on block (y,x) [%d,%d]...[%d,%d], ",
  542.         yystart,xxstart,yystop,xxstop);
  543.      putstring(row,2,C_GENERAL_MED,msg);
  544.      if (got_status == 2 || got_status == 4) { /* btm or tesseral */
  545.         putstring(-1,-1,C_GENERAL_MED,"at ");
  546.         sprintf(msg,"[%d,%d]",currow,curcol);
  547.         putstring(-1,-1,C_GENERAL_HI,msg);
  548.         }
  549.      else {
  550.         if (totpasses > 1) {
  551.            putstring(-1,-1,C_GENERAL_MED,"pass ");
  552.            sprintf(msg,"%d",curpass);
  553.            putstring(-1,-1,C_GENERAL_HI,msg);
  554.            putstring(-1,-1,C_GENERAL_MED," of ");
  555.            sprintf(msg,"%d",totpasses);
  556.            putstring(-1,-1,C_GENERAL_HI,msg);
  557.            putstring(-1,-1,C_GENERAL_MED,", ");
  558.            }
  559.         putstring(-1,-1,C_GENERAL_MED,"at row ");
  560.         sprintf(msg,"%d",currow);
  561.         putstring(-1,-1,C_GENERAL_HI,msg);
  562.         }
  563.      ++row;
  564.      }
  565.       }
  566.    putstring(row,2,C_GENERAL_MED,"Calculation time:");
  567.    sprintf(msg,"%3ld:%02ld:%02ld.%02ld", calctime/360000,
  568.       (calctime%360000)/6000, (calctime%6000)/100, calctime%100);
  569.    putstring(-1,-1,C_GENERAL_HI,msg);
  570.    row += 2;
  571.  
  572.    if (videoentry.xdots) {
  573.       sprintf(msg,"Video: %dx%dx%d %s %s",
  574.           videoentry.xdots, videoentry.ydots, videoentry.colors,
  575.           videoentry.name, videoentry.comment);
  576.       putstring(row,2,C_GENERAL_MED,msg);
  577.       }
  578.    ++row;
  579.  
  580.    putstring(row,2,C_GENERAL_MED,"Corners:                X                     Y");
  581.    putstring(++row,3,C_GENERAL_MED,"top-left");
  582.    sprintf(msg,"%20.16f  %20.16f",xxmin,yymax);
  583.    putstring(-1,17,C_GENERAL_HI,msg);
  584.    putstring(++row,3,C_GENERAL_MED,"bottom-right");
  585.    sprintf(msg,"%20.16f  %20.16f",xxmax,yymin);
  586.    putstring(-1,17,C_GENERAL_HI,msg);
  587.    adjust_corner(); /* make bottom left exact if very near exact */
  588.    if (cvtcentermag(&Xctr, &Yctr, &Magnification)) {
  589.       putstring(row+=2,2,C_GENERAL_MED,"Center: ");
  590.       sprintf(msg,"%20.16f %20.16f",Xctr,Yctr);
  591.       putstring(-1,-1,C_GENERAL_HI,msg);
  592.       putstring(-1,-1,C_GENERAL_MED,"  Mag: ");
  593.       if (Magnification < 1e6)
  594.      sprintf(msg,"%20.14f",Magnification);
  595.       else if (Magnification < 1e12)
  596.      sprintf(msg,"%20.8f",Magnification);
  597.       else
  598.      sprintf(msg,"%20.2f",Magnification);
  599.       putstring(-1,-1,C_GENERAL_HI,msg);
  600.       }
  601.    else if (xxmin != xx3rd || yymin != yy3rd) {
  602.       putstring(++row,3,C_GENERAL_MED,"bottom-left");
  603.       sprintf(msg,"%20.16f  %20.16f",xx3rd,yy3rd);
  604.       putstring(-1,17,C_GENERAL_HI,msg);
  605.       }
  606.    putstring(row+=2,2,C_GENERAL_MED,"Params,");
  607.    for (i = 0; i < 4; i++) {
  608.       sprintf(msg,"%3d: ",i+1);
  609.       putstring(-1,-1,C_GENERAL_MED,msg);
  610.       sprintf(msg,"%12.9f",param[i]);
  611.       putstring(-1,-1,C_GENERAL_HI,msg);
  612.       }
  613.  
  614.    putstring(row+=2,2,C_GENERAL_MED,"Iteration maximum: ");
  615.    sprintf(msg,"%d",maxit);
  616.    putstring(-1,-1,C_GENERAL_HI,msg);
  617.    putstring(-1,-1,C_GENERAL_MED,"     Effective bailout: ");
  618.    sprintf(msg,"%f",rqlim);
  619.    putstring(-1,-1,C_GENERAL_HI,msg);
  620.  
  621.    if (fractype == PLASMA) {
  622.       putstring(++row,2,C_GENERAL_MED,"Current 'rseed': ");
  623.       sprintf(msg,"%d",rseed);
  624.       putstring(-1,-1,C_GENERAL_HI,msg);
  625.       }
  626.  
  627.    if(invert) {
  628.       extern double f_radius,f_xcenter,f_ycenter;
  629.       putstring(++row,2,C_GENERAL_MED,"Inversion radius: ");
  630.       sprintf(msg,"%12.9f",f_radius);
  631.       putstring(-1,-1,C_GENERAL_HI,msg);
  632.       putstring(-1,-1,C_GENERAL_MED,"  xcenter: ");
  633.       sprintf(msg,"%12.9f",f_xcenter);
  634.       putstring(-1,-1,C_GENERAL_HI,msg);
  635.       putstring(-1,-1,C_GENERAL_MED,"  ycenter: ");
  636.       sprintf(msg,"%12.9f",f_ycenter);
  637.       putstring(-1,-1,C_GENERAL_HI,msg);
  638.       }
  639.  
  640.    if ((row += 2) < 23) ++row;
  641.    putstringcenter(row,0,80,C_GENERAL_LO,"...Press any key to continue...");
  642.    movecursor(25,80);
  643.    getakeynohelp();
  644.    unstackscreen();
  645.    timer_start = clock(); /* tab display was "time out" */
  646.    return(0);
  647. }
  648.  
  649.  
  650. int endswithslash(char *fl)
  651. {
  652.    int len;
  653.    len = strlen(fl);
  654.    if(len)
  655.       if(fl[--len]=='\\')
  656.      return(1);
  657.    return(0);
  658. }
  659.  
  660. /* --------------------------------------------------------------------- */
  661.  
  662. int ifsload()            /* read in IFS parameters */
  663. {
  664.    int i;
  665.    FILE *ifsfile;
  666.    char buf[201];
  667.    char *bufptr;
  668. #ifdef WINFRACT
  669. extern float suffix[4096];
  670. #else
  671. extern float dstack[4096];
  672. #endif
  673.    int ret,rowsize;
  674.  
  675.    if (ifs_defn) { /* release prior parms */
  676.       farmemfree((char far *)ifs_defn);
  677.       ifs_defn = NULL;
  678.       }
  679.  
  680.    ifs_changed = ifs_type = 0;
  681.    rowsize = IFSPARM;
  682.    if (find_file_item(IFSFileName,IFSName,&ifsfile) < 0)
  683.       return(-1);
  684.  
  685.    fgets(buf,200,ifsfile);
  686.    strlwr(buf);
  687.    bufptr = &buf[0];
  688.    while (*bufptr) {
  689.       if (strncmp(bufptr,"(3d)",4) == 0) {
  690.      ifs_type = 1;
  691.      rowsize = IFS3DPARM;
  692.      }
  693.       ++bufptr;
  694.       }
  695.  
  696.    for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  697.       suffix[i] = 0.0;
  698.    i = ret = 0;
  699.    while (fscanf(ifsfile," %f ",&suffix[i])) {
  700.       if (++i >= NUMIFS*rowsize) {
  701.       static char far msg[]={"IFS definition has too many lines"};
  702.      stopmsg(0,msg);
  703.      ret = -1;
  704.      break;
  705.      }
  706.       }
  707.    if ((i % rowsize) != 0 || getc(ifsfile) != '}') {
  708.       static char far msg[]={"invalid IFS definition"};
  709.       stopmsg(0,msg);
  710.       ret = -1;
  711.       }
  712.    if (i == 0 && ret == 0) {
  713.       static char far msg[]={"Empty IFS definition"};
  714.       stopmsg(0,msg);
  715.       ret = -1;
  716.       }
  717.    fclose(ifsfile);
  718.  
  719.    if (ret == 0)
  720.       if ((ifs_defn = (float far *)farmemalloc(
  721.             (long)((NUMIFS+1)*IFS3DPARM*sizeof(float)))) == NULL) {
  722.      static char far msg[]={"Insufficient memory for IFS"};
  723.      stopmsg(0,msg);
  724.      ret = -1;
  725.      }
  726.       else
  727.      for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  728.         ifs_defn[i] = suffix[i];
  729.  
  730.    return(ret);
  731. }
  732.  
  733. int find_file_item(char *filename,char *itemname,FILE **infile)
  734. {
  735.    char tmpname[41];
  736.    long notepoint;
  737.    char buf[201];
  738.    int c;
  739.    if ((*infile = fopen(filename,"rt")) == NULL) {
  740.       sprintf(buf,s_cantopen,filename);
  741.       stopmsg(0,buf);
  742.       return(-1);
  743.       }
  744.  
  745.    while (1) {
  746.       while ((c = getc(*infile)) == ' ' || c == '\t' || c == '\n') { }
  747.       if (c == EOF) break;
  748.       if (c == ';') {
  749.      while ((c = fgetc(*infile)) != '\n' && c != EOF) { }
  750.      if (c == EOF) break;
  751.      continue;
  752.      }
  753.       notepoint = ftell(*infile) - 1;
  754.       ungetc(c,*infile);
  755.       if (fscanf(*infile," %40[^ \n\t({]",tmpname) == EOF) break;
  756.       while ((c = getc(*infile)) != EOF && c != '{' && c != '\n') { }
  757.       if (c == EOF) break;
  758.       if (c == '{') {
  759.      if (stricmp(tmpname,itemname) == 0) {
  760.         fseek(*infile,notepoint,SEEK_SET);
  761.         return(0);
  762.         }
  763.      while ((c = getc(*infile)) != '}' && c != EOF) { }
  764.      if (c == EOF) break;
  765.      }
  766.       }
  767.    fclose(*infile);
  768.    sprintf(buf,"'%s' definition not found",itemname);
  769.    stopmsg(0,buf);
  770.    return(-1);
  771. }
  772.  
  773. int file_gets(char *buf,int maxlen,FILE *infile)
  774. {
  775.    int len,c;
  776.    /* similar to 'fgets', but file may be in either text or binary mode */
  777.    /* returns -1 at eof, length of string otherwise */
  778.    if (feof(infile)) return -1;
  779.    len = 0;
  780.    while (len < maxlen) {
  781.       if ((c = getc(infile)) == EOF || c == '\x1a') {
  782.      if (len) break;
  783.      return -1;
  784.      }
  785.       if (c == '\n') break;             /* linefeed is end of line */
  786.       if (c != '\r') buf[len++] = c;    /* ignore c/r */
  787.       }
  788.    buf[len] = 0;
  789.    return len;
  790. }
  791.  
  792. #ifdef WINFRACT
  793. /* call this something else to dodge the QC4WIN bullet... */
  794. int win_matherr( struct exception *except )
  795. #else
  796. int matherr( struct exception *except )
  797. #endif
  798. {
  799.     extern int debugflag;
  800.     if(debugflag)
  801.     {
  802.        static int ct = 0;
  803.        static FILE *fp=NULL;
  804.        if(fp==NULL)
  805.       fp = fopen("matherr","w");
  806.        if(ct++ < 100)
  807.        {
  808.       fprintf(fp,"err:  %d\nname: %s\narg:  %le\n",
  809.           except->type, except->name, except->arg1);
  810.       fflush(fp);
  811.        }
  812.     }
  813.     if( except->type == DOMAIN )
  814.     {
  815.     char buf[40];
  816.     sprintf(buf,"%le",except->arg1);
  817.     /* This test may be unnecessary - from my experiments if the
  818.        argument is too large or small the error is TLOSS not DOMAIN */
  819.     if(strstr(buf,"IN")||strstr(buf,"NAN"))  /* trashed arg? */
  820.                /* "IND" with MSC, "INF" with BC++ */
  821.     {
  822.        if( strcmp( except->name, "sin" ) == 0 )
  823.        {
  824.           except->retval = 0.0;
  825.           return(1);
  826.        }
  827.        else if( strcmp( except->name, "cos" ) == 0 )
  828.        {
  829.           except->retval = 1.0;
  830.           return(1);
  831.        }
  832.        }
  833.     }
  834.     return (0);
  835. }
  836.  
  837. void roundfloatd(double *x) /* make double converted from float look ok */
  838. {
  839.    char buf[30];
  840.    sprintf(buf,"%-10.7g",*x);
  841.    *x = atof(buf);
  842. }
  843.  
  844.