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