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