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