Various Datatypes.
[AROS-Contrib.git] / fish / eval / eval.c
blob4239afdd3583d2422055efcfa5a05b0c5979f650
1 /*
2 **
3 ** EVAL.C A floating point expression evaluator.
4 ** Main source module.
5 **
6 ** Eval is a floating point expression evaluator.
7 ** This is version 1.12
8 ** Copyright (C) 1993 Will Menninger
9 **
10 ** To add a new constant to the Eval program
11 ** -----------------------------------------
12 ** 1. Update the size of MAXC in eval.h
13 ** 2. Add your constant to the clist[] array below. Please keep the
14 ** list in alphabetic order, and make sure that your contant's
15 ** name does not exceed MAXNAMELEN (from eval.h)
16 ** 3. If your constant is a physical constant with no indication
17 ** of units in the name, either make sure it is in SI units, or change
18 ** the print statement that claims all constants are in SI units.
19 ** 4. Recompile ALL source modules.
22 ** This program is free software; you can redistribute it and/or modify it
23 ** under the terms of the GNU General Public License as published by the
24 ** Free Software Foundation; either version 2 of the License, or any
25 ** later version.
27 ** This program is distributed in the hope that it will be useful, but
28 ** WITHOUT ANY WARRANTY; without even the implied warranty of
29 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 ** General Public License for more details.
32 ** You should have received a copy of the GNU General Public License along
33 ** with this program; if not, write to the Free Software Foundation, Inc.,
34 ** 675 Mass Ave, Cambridge, MA 02139, USA.
36 ** The author until 9/93 can be contacted at:
37 ** e-mail: willus@ilm.pfc.mit.edu
38 ** U.S. mail: Will Menninger, 45 River St., #2, Boston, MA 02108-1124
41 ** Originally written 5/89 in ANSI C
45 #include "eval.h"
47 static char tempname[80];
48 static char wdir[100];
49 static char rpath[200];
50 static FILE *tempfile;
51 static int linecount;
53 static VAR clist[MAXC]= {
54 {"_acres_per_sq_km",247.1},
55 {"_air_density",1.293},
56 {"_air_mol_mass",.02897},
57 {"_atm_per_psi",.06804},
58 {"_avagadro",6.0220e23},
59 {"_boltzmann",1.3807e-23},
60 {"_c",2.997925e8},
61 {"_cm_per_in",2.54},
62 {"_coulomb_const",8.98755e9},
63 {"_deg_per_rad",57.2958},
64 {"_earth_esc_spd",1.12e4},
65 {"_earth_grav",9.80665},
66 {"_earth_mass",5.98e24},
67 {"_earth_radius",6.37e6},
68 {"_earth_to_moon",3.844e8},
69 {"_earth_to_sun",1.496e11},
70 {"_eps0",8.85419e-12},
71 {"_erg_per_joule",1e7},
72 {"_eulers_const",.57721566490153286061},
73 {"_ft_per_m",3.280839895},
74 {"_g",6.672e-11},
75 {"_gas_const",8.314},
76 {"_gauss_per_tesla",1e4},
77 {"_gm_per_oz",28.34952313},
78 {"_golden_ratio",1.6180339887498948482},
79 {"_h",6.6262e-34},
80 {"_hbar",1.05459e-34},
81 {"_joule_per_btu",1054.35},
82 {"_joule_per_cal",4.184},
83 {"_joule_per_ftlb",1.356},
84 {"_joule_per_kwh",3.6e6},
85 {"_kg_per_slug",14.59},
86 {"_km_per_mi",1.609344},
87 {"_knots_per_mph",.86897624},
88 {"_lbs_per_kg",2.204622622},
89 {"_lit_per_gal",3.785411784},
90 {"_me",9.1095e-31},
91 {"_mn",1.67495e-27},
92 {"_moon_grav",1.62},
93 {"_moon_mass",7.35e22},
94 {"_moon_period",2360448.},
95 {"_moon_radius",1.738e6},
96 {"_mp",1.67265e-27},
97 {"_mu0",1.256637e-6},
98 {"_oz_per_gal",128.},
99 {"_pasc_per_atm",101325.},
100 {"_pasc_per_psi",6895.},
101 {"_pasc_per_torr",133.32},
102 {"_pi",3.14159265358979323846},
103 {"_qe",1.60219e-19},
104 {"_solar_const",1350.},
105 {"_speed_sound",331.},
106 {"_sun_mass",1.99e30},
107 {"_sun_radius",6.96e8},
108 {"_watts_per_hp",745.712},
109 {"_zero_deg_cels",273.15}
112 static char *license =
113 "Eval, a floating point expression evaluator, version %s\n"
114 "Copyright (C) 1993 Will Menninger\n"
115 "This program is freely redistributable under certain restrictions.\n"
116 "It comes with absolutely no warranty.\n"
117 "Type '\x3f\x3f' for more information, or '?' for brief help.\n";
120 static int process_file(char *filename,int bequiet,VARPTR vlist,VARPTR clist);
121 static BOOLEAN process_line(FILE *stream,int showinp,int showout,VARPTR vlist,
122 VARPTR clist);
123 static void init_varlist(VARPTR vlist);
124 static void var_copy(VARPTR dest,VARPTR source);
125 static int print_help(FILE *stream,int extended,int page,char *s);
126 static int more(char *text,char *input,int pause);
127 static void print_oplist(void);
128 static int print_varlist(FILE *s,char *input,VARPTR list,int max);
129 static void print_stats(void);
130 static int nextline(char *s,FILE *stream);
131 static void close_temp(int showout);
132 static int srchpath(char *name);
133 static void cwdir(char *name);
136 int main(int argc,char *argv[])
139 VAR vlist[MAXV];
140 char scriptfile[80];
141 int status;
144 printf(license,VERSION);
145 init_varlist(vlist);
146 wdir[0]=EOS;
147 rpath[0]=EOS;
148 setobase(10);
149 setibase(10);
150 set_scinote(0);
151 set_fix(0);
152 set_sigfig(10);
153 set_dplace(10);
154 set_maxexp(5);
155 tempfile=NULL;
156 if (argc>1)
157 strcpy(scriptfile,argv[1]);
158 else
159 scriptfile[0]=EOS;
160 if (scriptfile[0]!=EOS)
161 status=process_file(scriptfile,0,vlist,clist);
162 else
163 status=0;
164 if (!status)
165 while (!process_line(stdin,0,1,vlist,clist));
166 close_temp(1);
167 return(0);
172 ** process_file
174 ** Sends all of the lines from file, filename, to Eval for processing.
176 ** Returns 1 if a quit was encountered in the file, 0 otherwise
180 static int process_file(char *filename,int bequiet,VARPTR vlist,VARPTR clist)
183 FILE *s;
184 int status;
186 s=fopen(filename,"r");
187 if (s==NULL)
189 printf("File %s not found.\n",filename);
190 return(0);
192 while (1)
194 status=process_line(s,!bequiet,!bequiet,vlist,clist);
195 if (status==1 || status==2)
196 break;
198 fclose(s);
199 return(status==1 ? 1 : 0);
204 ** process_line
206 ** Processes one line of input from stream.
207 ** If showinp is NZ, the input is printed to stdout.
208 ** If showout is NZ, all output is printed to stdout.
210 ** Returns: 1 if "quit" (or similar command) is read.
211 ** 2 if end of file
212 ** 0 otherwise.
216 static BOOLEAN process_line(FILE *stream,int showinp,int showout,VARPTR vlist,
217 VARPTR clist)
220 char rname[100];
221 char input[MAXINPUT+1];
222 int bequiet,i,m0,m1=0,m2=0,n=0,nargs;
224 input[0]=EOS;
225 if (!nextline(input,stream))
226 return(2);
228 while (1)
230 if (input[0]=='@')
232 bequiet=1;
233 for (i=1;input[i]==' ' || input[i]=='\t';i++);
235 else
237 bequiet=0;
238 i=0;
240 if (input[i]!='<' && input[i]!='>' && tempfile!=NULL)
242 fprintf(tempfile,"%s\n",&input[i]);
243 linecount++;
245 if (showinp && !bequiet && input[i]!=EOS)
246 printf("%s%s\n",PROMPT,input);
247 if (!strcmp(&input[i],"stop") || !strcmp(&input[i],"quit") ||
248 !strcmp(&input[i],"exit") || !strcmp(&input[i],"end"))
249 return(1);
250 if (input[i]==EOS)
252 if (!showinp && !bequiet && showout)
253 printf("Type '?' or 'help' for help.\n");
254 return(0);
256 if (!strncmp(&input[i],"help",4) &&
257 (input[i+4]==' ' || input[i+4]=='\t' || input[i+4]==EOS))
259 if (input[i+4]!=EOS)
260 n=atoi(&input[i+4]);
261 else
262 n=0;
263 if (showout && !bequiet && print_help(stream,1,n,input))
264 continue;
265 else
266 break;
268 if (input[i]=='<' || input[i]=='>')
270 n=input[i];
271 for (i++;input[i]==' ' || input[i]=='\t';i++);
272 if (n=='<')
274 if (input[i]==EOS)
276 printf("Must specify a file name after <.\n");
277 return(0);
279 strcpy(rname,&input[i]);
280 if (!srchpath(rname))
282 printf("Cannot find %s in read path.\n",rname);
283 return(0);
285 return(process_file(rname,bequiet || !showout,vlist,clist));
287 close_temp(showout && !bequiet);
288 if (input[i]!=EOS)
290 strcpy(tempname,&input[i]);
291 cwdir(tempname);
292 tempfile=fopen(tempname,"w");
293 linecount=0;
294 if (tempfile==NULL)
295 printf("Cannot open %s for output.\n",tempname);
296 else
297 if (showout && !bequiet)
298 printf("Script file %s begun.\n",tempname);
300 return(0);
302 nargs=1;
303 m0=i;
304 showout=(showout && !bequiet);
305 while (1)
307 for (;!isspace(input[i]) && input[i]!=EOS;i++);
308 if (nargs==1)
309 m1=i-m0;
310 if (input[i]==EOS)
311 break;
312 for (;isspace(input[i]);i++);
313 if (input[i]==EOS)
314 break;
315 nargs++;
316 if (nargs==2)
317 m2=i;
318 if (nargs>2)
319 break;
321 if (nargs==2)
322 n=atoi(&input[m2]);
323 if (!strncmp(&input[m0],"rpath",m1))
325 if (nargs==2)
327 strcpy(rpath,&input[m2]);
328 printf("Read path set to %s\n",rpath);
330 else
332 rpath[0]=EOS;
333 printf("Read path cleared.\n");
335 break;
337 if (!strncmp(&input[m0],"wdir",m1))
339 if (nargs==2)
341 strcpy(wdir,&input[m2]);
342 printf("Write dir set to %s\n",wdir);
344 else
346 wdir[0]=EOS;
347 printf("Write dir set to current dir.\n");
349 break;
351 if (!strncmp(&input[m0],"obase",m1) && nargs==2 && n>0)
353 if (n<2 || n>36)
355 printf("Output base must be between 2 and 36.\n");
356 break;
358 setobase(n);
359 if (showout)
360 printf("Output base set to %d.\n",n);
361 break;
363 if (!strncmp(&input[m0],"ibase",m1) && nargs==2 && n>0)
365 if (n<2 || n>36)
367 printf("Input base must be between 2 and 36.\n");
368 break;
370 setibase(n);
371 if (showout)
372 printf("Input base set to %d.\n",n);
373 break;
375 if (!strncmp(&input[m0],"sci",m1) && nargs<2)
377 set_scinote(!get_scinote());
378 if (showout)
379 printf("Scientific notation %s.\n",get_scinote() ? "ON":"OFF");
380 break;
382 if (!strncmp(&input[m0],"fix",m1) && nargs<2)
384 set_fix(!get_fix());
385 if (showout)
386 printf("Fixed precision %s.\n",get_fix() ? "ON":"OFF");
387 break;
389 if (!strncmp(&input[m0],"sigfig",m1) && nargs==2)
391 if (n>DBL_MANT_DIG)
392 printf("Significant figures limited to %d.\n",
393 DBL_MANT_DIG);
394 else
396 set_sigfig(n);
397 if (showout)
399 printf("Significant figures = ");
400 if (n>0)
401 printf("%d\n",n);
402 else
403 printf("max\n");
406 break;
408 if (!strncmp(&input[m0],"maxexp",m1) && nargs==2)
410 set_maxexp(n);
411 if (showout)
413 if (n<0)
414 printf("Exponent limit turned off.\n");
415 else
416 printf("Exponent limit = %d\n",n);
418 break;
420 if (!strncmp(&input[m0],"dplace",m1) && nargs==2)
422 if (n<-70 || n>70)
423 printf("Decimal place must be between -70 and 70.\n");
424 else
426 set_dplace(n);
427 if (showout)
428 printf("Decimal place = %d\n",n);
430 break;
432 if (input[m0]!='?')
434 evaluate(&input[m0],showout,vlist,clist);
435 break;
437 if (!strcmp(&input[m0],"?")) {
438 if (showout && print_help(stream,0,0,input))
439 continue;
440 else
441 break;
443 for (i=m0+1;isspace(input[i]);i++);
444 if (input[i]=='?')
446 if (input[i+1]!=EOS)
447 n=atoi(&input[i+1]);
448 else
449 n=0;
450 if (showout && print_help(stream,1,n,input))
451 continue;
452 else
453 break;
455 switch (tolower((int)input[i]))
457 case 'v':
458 if (showout && print_varlist(stream,input,vlist,MAXV))
459 continue;
460 break;
461 case 'c':
462 if (showout)
464 printf("All physical constants are in SI units unless the "
465 "name of the variable\nindicates otherwise.\n");
466 if (print_varlist(stream,input,clist,MAXC))
467 continue;
469 break;
470 case 'f':
471 if (showout)
472 if (print_funclist(stream,input,tolower((int)input[i+1])=='l'))
473 continue;
474 break;
475 case 'o':
476 if (showout)
477 print_oplist();
478 break;
479 case 's':
480 if (showout)
481 print_stats();
482 break;
483 default:
484 printf("\"%s\" is an unknown query.\n",&input[i]);
485 break;
487 break;
489 return(0);
494 ** insert_var(VARPTR new,VARPTR vlist)
496 ** Inserts a the new variable into the current list of variables.
497 ** Returns 1 if successful, 0 if list is full.
501 BOOLEAN insert_var(VARPTR new,VARPTR vlist)
504 BOOLEAN found;
505 int i,j,k;
507 found=search_varlist(new,vlist,&i,MAXV);
508 if (!found && vlist[MAXV-1].name[0]!=EOS)
509 return(0);
510 if (found)
511 var_copy(&vlist[i],new);
512 else
514 for (j=i;j<MAXV-1 && vlist[j].name[0]!=EOS;j++);
515 for (k=j;k>i;k--)
516 var_copy(&vlist[k],&vlist[k-1]);
517 var_copy(&vlist[i],new);
519 return(1);
524 ** init_varlist(VARPTR vlist)
526 ** Sets all variable names to EOS, representing empty spaces
530 static void init_varlist(VARPTR vlist)
533 int i;
535 for (i=0;i<MAXV;i++)
536 vlist[i].name[0]=EOS;
540 ** var_copy(VARPTR dest,VARPTR source)
542 ** copies one variable to another
546 static void var_copy(VARPTR dest,VARPTR source)
549 strcpy(dest->name,source->name);
550 dest->value=source->value;
555 ** search_varlist(VARPTR var,VARPTR vlist,int *n,int max)
557 ** Searches through a variable list for the variable specified. If
558 ** found, returns 1 else returns 0. The position for insertion is
559 ** returned in (*n). The search is binary for fast response.
563 BOOLEAN search_varlist(VARPTR var,VARPTR vlist,int *n,int max)
566 int step,c;
568 (*n)=step=max>>1;
569 while (1)
571 if (step>1)
572 step>>=1;
573 if (vlist[(*n)].name[0]==EOS)
575 if ((*n)==0)
576 return(0);
577 (*n)=(*n)-step;
578 continue;
580 if (!(c=strcmp(var->name,vlist[(*n)].name)))
581 break;
582 if (c>0)
584 if ((*n)==max-2 || vlist[(*n)+1].name[0]==EOS)
586 (*n)=(*n)+1;
587 if (vlist[(*n)].name[0]!=EOS)
588 return(!strcmp(var->name,vlist[(*n)].name));
589 else
590 return(0);
592 (*n)=(*n)+step;
593 continue;
595 if ((*n)==0 || strcmp(var->name,vlist[(*n)-1].name)>0)
596 return(0);
597 (*n)=(*n)-step;
599 return(1);
604 ** print_help(void)
606 ** Prints instructions on how to use the expression evaluator.
610 static int print_help(FILE *stream,int extended,int page,char *s)
613 extern char *bhelp;
614 extern char *ehelp;
615 int i,j;
617 if (extended)
618 for (i=0,j=0;ehelp[j]!=EOS && i<page-1;j++)
619 if (ehelp[j]=='\f')
621 j++;
622 i++;
625 return (more(extended ? &ehelp[j] : bhelp,s,stream==stdin));
629 static int more(char *text,char *input,int pause)
632 int nl;
633 int c,in,istart;
635 in=-1;
636 while (1)
638 istart=in+1;
639 for (nl=0;nl<NLINES;nl++)
641 for (in++;text[in]!='\f' && text[in]!='\n' && text[in]!=EOS;in++);
642 if (text[in]==EOS || text[in]=='\f')
643 break;
645 if (text[in]==EOS || text[in+1]==EOS)
647 printf("%s\n",&text[istart]);
648 break;
650 if (text[in]=='\f')
651 in--;
652 c=text[in+1];
653 text[in+1]=EOS;
654 printf("%s\n",&text[istart]);
655 text[in+1]=c;
656 if (pause)
658 printf("Press <ENTER> for more...\n");
659 input[0]=EOS;
660 nextline(input,stdin);
661 if (input[0]!=EOS)
662 return(1);
663 printf("\n");
665 if (c=='\f')
666 in+=2;
668 return(0);
673 ** print_oplist(void)
675 ** Prints list of operands
679 static void print_oplist(void)
682 static char *oplist =
683 "\nUnary operators:\n"
684 " + positive\n"
685 " - negative\n"
686 " ~ bit-wise NOT\n\n"
687 "Binary operators: (in order of precedence)\n"
688 " ^ power*\n"
689 " * / % multiply, divide, modulo\n"
690 " + - add, subtract\n"
691 " << >> bit-shift left, right\n"
692 " & bit-wise AND\n"
693 " ? bit-wise XOR*\n"
694 " | bit-wise OR\n\n"
695 "* - different from C\n\n";
696 printf("%s",oplist);
701 ** print_varlist(VARPTR list,int max)
703 ** Prints out a list of constants or variables and their values
707 static int print_varlist(FILE *s,char *input,VARPTR list,int max)
710 char bigbuf[MAXOUTLEN];
711 char bigline[MAXOUTLEN];
712 int i,j,k,l,n,m1,m2,nc,cw,nr,li,c;
714 for (m1=m2=0,i=0;i<max && list[i].name[0]!=EOS;i++)
716 if ((l=strlen(list[i].name))>m1)
717 m1=l;
718 baseconv(list[i].value,bigbuf);
719 if ((l=strlen(bigbuf))>m2)
720 m2=l;
722 n=i;
723 if (!n)
725 printf("There are no currently assigned variables.\n");
726 return(0);
728 cw=m1+m2+7;
729 nc=(SCRWIDTH+3)/cw;
730 if (nc<=0)
731 nc=1;
732 nr=(i+nc-1)/nc;
733 for (i=0;i<nr;i++)
735 li=0;
736 for (j=0;j<nc;j++)
738 k=i+j*nr;
739 if (k>=n)
740 break;
741 for (l=0;(c=list[k].name[l])!=EOS;l++)
742 bigline[li++]=c;
743 for (;l<m1;l++)
744 bigline[li++]=' ';
745 baseconv(list[k].value,bigbuf);
746 bigline[li++]=' ';
747 bigline[li++]='=';
748 bigline[li++]=' ';
749 for (l=0;(c=bigbuf[l])!=EOS;l++)
750 bigline[li++]=c;
751 if (j<nc-1)
752 for (;l<m2+4;l++)
753 bigline[li++]=' ';
755 bigline[li]=EOS;
756 printf("%s\n",bigline);
757 if (s==stdin && i!=nr-1 && ((i+3)%NLINES)==0)
759 printf("\nPress <ENTER> for more...\n");
760 input[0]=EOS;
761 nextline(input,s);
762 if (input[0]!=EOS)
763 return(1);
764 printf("\n");
767 printf("\n");
768 return(0);
772 static void print_stats(void)
775 int ib,ob;
777 ib=getibase();
778 ob=getobase();
779 printf("\nExpression evaluator, version %s\n",VERSION);
780 print_outtype();
781 printf("Default input base: %d\n",ib);
782 printf("Default output base: %d\n\n",ob);
783 printf("Base %d accuracy: %d digits\n",ib,precision(ib));
784 if (ob!=ib)
785 printf("Base %d accuracy: %d digits\n",ob,precision(ob));
786 printf("\n");
787 printf("Read path: %s\n",rpath[0]==EOS ? "None" : rpath);
788 printf("Write dir: %s\n",wdir[0]==EOS ? "Current dir" : wdir);
789 printf("\n");
794 ** void fixup(char *s)
796 ** Removes white space from beginning and end of string. Also removes
797 ** \n from end of string, and converts entire string to lower case.
801 void fixup(char *s)
804 int i,j;
806 for (i=0;isspace(s[i]);i++);
807 for (j=0;s[i]!='\n' && s[i]!=EOS;j++,i++)
808 s[j]=tolower((int)s[i]);
809 for (j--;j>=0 && isspace(s[j]);j--);
810 s[j+1]=EOS;
814 static int nextline(char *s,FILE *stream)
817 while (1)
820 if (stream==stdin)
821 printf("%s",PROMPT);
822 if (fgets(s,MAXINPUT,stream)==NULL)
823 return(0);
824 fixup(s);
825 if (s[0]!=';')
826 break;
828 return(1);
832 static void close_temp(int showout)
835 if (tempfile!=NULL)
837 fclose(tempfile);
838 tempfile=NULL;
839 if (showout)
840 printf("%d lines written to %s.\n",linecount,tempname);
845 static int srchpath(char *name)
848 char buf[100];
849 int i,j;
850 int checked;
851 FILE *f;
853 i=0;
854 strcpy(buf,name);
855 checked=0;
856 while (1)
858 for (j=0;rpath[i]!=EOS && rpath[i]!=';';i++,j++)
859 buf[j]=rpath[i];
860 buf[j]=EOS;
861 if (checked && !j && rpath[i]==EOS)
862 return(0);
863 while (rpath[i]==';')
864 i++;
865 strcat(buf,name);
866 if (j || !checked)
868 if (!j)
869 checked=1;
870 f=fopen(buf,"r");
871 if (f!=NULL)
872 break;
875 fclose(f);
876 strcpy(name,buf);
877 return(1);
881 static void cwdir(char *name)
884 char buf[100];
885 FILE *f;
887 strcpy(buf,wdir);
888 strcat(buf,name);
889 f=fopen(buf,"w");
890 if (f==NULL)
891 return;
892 fclose(f);
893 strcpy(name,buf);