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