1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1994-2000, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 #include "mrilib.h"
8 #include "parser.h"
9 #include <ctype.h>
10 #include "cs.h"
11 #include <string.h>
12
13 #undef USE_READLINE
14 #ifdef USE_READLINE
15 #include "readline.h"
16 #endif
17
18 /*------------------------------------------------*/
Tsdup(char * str)19 static char * Tsdup( char *str ){ /* 20 Sep 2013 */
20 static char *Zork = NULL ;
21 if( str == NULL ) return NULL ;
22 if( Zork != NULL ){ free(Zork); Zork = NULL; }
23 Zork = strdup(str) ; return Zork ;
24 }
25 /*------------------------------------------------*/
26
main(int argc,char * argv[])27 int main( int argc , char * argv[] )
28 {
29 PARSER_code * pcode ;
30 char expr[9000] , * cexp ;
31 double atoz[26] , value ;
32 int ii , kvar, kar, brk, strt, oform , len;
33 int DoOnce;
34 char *formatstr=NULL, *strptr=NULL;
35 char ch;
36
37 DoOnce = 0;
38
39 kar = 1;
40 brk = 0;
41 DoOnce = 0; /* flag used to indicate that program is running in batch or command line modes */
42 expr[0] = '\0';
43 oform = CCALC_DOUBLE; /* double is default */
44 while (kar < argc) {
45 if (strcmp(argv[1],"-help") == 0 ){
46 printf(
47 "Usage: ccalc [-form FORM] [-eval 'expr']\n"
48 "Usage mode 1: Interactive numerical calculator\n"
49 " Interactive numerical calculator, using the \n"
50 " same expression syntax as 3dcalc. \n"
51 " No command line parameters are permitted in\n"
52 " usage 1 mode.\n"
53 "Usage mode 2: Command line expression calculator\n"
54 " Evaluate an expression specified on command\n"
55 " line, return answer and quit.\n"
56 " Optional parameters: (must come first)\n"
57 " -form FORM: Format output in a nice form\n"
58 " Choose from:\n"
59 " double: Macho numbers (default).\n"
60 " nice: Metrosexual output.\n"
61 " int (or rint): Rounded to nearest integer.\n"
62 " cint: Rounded up.\n"
63 " fint: Rounded down.\n"
64 " %%n.mf: custom format string, used as in printf.\n"
65 " format string can contain %%%%, \\n and other\n"
66 " regular characters.\n"
67 " See man fprintf and man printf for details.\n"
68 " You can also replace:\n"
69 " -form int with -i\n"
70 " -form nice with -n\n"
71 " -form double with -d\n"
72 " -form fint with -f\n" /* no float are evoked */
73 " -form cint with -c\n"
74 " Mandatory parameter: (must come last on command line)\n"
75 " -eval EXPR: EXPR is the expression to evaluate.\n"
76 " Example: ccalc -eval '3 + 5 * sin(22)' \n"
77 " or: ccalc -eval 3 +5 '*' 'sin(22)'\n"
78 " You can not use variables in EXPR\n"
79 " as you do with 3dcalc.\n"
80 " Example with formatting:\n"
81 " ccalc -form '********\\n%%6.4f%%%%\\n********' -eval '100*328/457'\n"
82 " gives:\n"
83 " ********\n"
84 " 0.7177%%\n"
85 " ********\n"
86 " Try also:\n"
87 " ccalc -i 3.6\n"
88 " ccalc -f 3.6\n"
89 " ccalc -c 3.6\n"
90 " ccalc -form '%%3.5d' 3.3\n"
91 " ccalc -form '**%%5d**' 3.3\n"
92 " ccalc -form '**%%-5d**' 3.3\n"
93 "\n"
94 " ** SECRET: You don't need to use -eval if you are \n"
95 " not using any other options. I hate typing\n"
96 " it for quick command line calculations. \n"
97 " But that feature might be removed in the\n"
98 " future, so always use -eval when you are \n"
99 " using this program in your scripts.\n"
100 ) ;
101 exit(0) ;
102 }
103
104 if ( !brk && strcmp(argv[kar],"-form") == 0 ) {
105 ++kar;
106 if (kar >= argc) ERROR_exit("need argument after -form ");
107 if (strcmp(argv[kar],"double") == 0 ) oform = CCALC_DOUBLE;
108 else if (strcmp(argv[kar],"nice") == 0 ) oform = CCALC_NICE;
109 else if (strcmp(argv[kar],"int") == 0 ) oform = CCALC_INT;
110 else if (strcmp(argv[kar],"rint") == 0 ) oform = CCALC_INT;
111 else if (strcmp(argv[kar],"fint") == 0 ) oform = CCALC_FINT;
112 else if (strcmp(argv[kar],"cint") == 0 ) oform = CCALC_CINT;
113 else if (strlen(argv[kar])<=256) {
114 oform = CCALC_CUSTOM;
115 formatstr = argv[kar];
116 }
117 else {
118 fprintf (stderr, "Format type '%s' not supported.\nSee -help for details.\n", argv[kar]);
119 exit (1);
120 }
121 DoOnce = 1;
122 brk = 1;
123 }
124
125 if (!brk && strncmp(argv[kar],"-d",2) == 0 ) {
126 oform = CCALC_DOUBLE;
127 brk = 1; DoOnce = 1;
128 }
129 if (!brk && strncmp(argv[kar],"-n",2) == 0 ) {
130 oform = CCALC_NICE;
131 brk = 1; DoOnce = 1;
132 }
133 if (!brk && strncmp(argv[kar],"-i",2) == 0 ) {
134 oform = CCALC_INT;
135 brk = 1; DoOnce = 1;
136 }
137 if (!brk && strncmp(argv[kar],"-r",2) == 0 ) {
138 oform = CCALC_INT;
139 brk = 1; DoOnce = 1;
140 }
141 if (!brk && strncmp(argv[kar],"-f",2) == 0 ) {
142 oform = CCALC_FINT;
143 brk = 1; DoOnce = 1;
144 }
145 if (!brk && strncmp(argv[kar],"-c",2) == 0 ) {
146 oform = CCALC_CINT;
147 brk = 1; DoOnce = 1;
148 }
149 if( !brk && ( strcmp(argv[kar],"-eval") == 0 || strcmp(argv[kar],"-expr") == 0) ){
150 ++kar;
151 if (kar >= argc) ERROR_exit("need argument after -eval (or -expr) ");
152 /* anything after eval gets put into an expression */
153 while (kar < argc) {
154 if ( strcmp(argv[kar],"-eval") == 0 ||
155 strcmp(argv[kar],"-expr") == 0 ||
156 strcmp(argv[kar],"-form") == 0 ) {
157 fprintf (stderr, "Error:\n"
158 "You have optional parameters (%s) following \n"
159 "the expression to evaluate.\n"
160 "Stop it!\n", argv[kar]);
161 exit (1);
162 }
163 sprintf(expr,"%s %s", Tsdup(expr), argv[kar]);
164 ++ kar;
165 }
166 /* fprintf (stdout, "%s\n", expr);*/
167 DoOnce = 1;
168 brk = 1;
169 }
170
171 if (!brk) {
172 /* if nothing is understood, assume the expression follows, instead of moaning and quitting*/
173 while (kar < argc) {
174 if ( strcmp(argv[kar],"-eval") == 0 ||
175 strcmp(argv[kar],"-expr") == 0 ||
176 strcmp(argv[kar],"-form") == 0 ) {
177 fprintf (stderr, "Error:\n"
178 "You have optional parameters (%s) following \n"
179 "the expression to evaluate.\n"
180 "Stop it!\n", argv[kar]);
181 exit (1);
182 }
183 sprintf(expr,"%s %s", Tsdup(expr), argv[kar]);
184 ++ kar;
185 }
186 /* fprintf (stdout, "%s\n", expr);*/
187 DoOnce = 1;
188 brk = 1;
189 }
190
191 if (!brk) {
192 ERROR_exit("Option %s not understood. Try -help for usage\n", argv[kar]);
193 } else {
194 brk = 0;
195 kar ++;
196 }
197
198 }
199
200 for( ii=0 ; ii < 25 ; ii++ ) atoz[ii] = 0.0 ;
201
202 do{
203 if (!DoOnce){
204 #ifdef USE_READLINE
205 { char *lin = readline("ccalc> ") ;
206 if( lin == NULL ) continue ;
207 if( *lin == '\0' ){ free(lin); continue; }
208 add_history(lin) ;
209 strncpy(expr,lin,899); expr[899]='\0'; free(lin);
210 }
211 #else
212 printf("calc> ") ; fflush(stdout) ;
213 if( afni_fgets(expr,900,stdin) == NULL ) { /* quit on ctrl-D */
214 putchar('\n') ;
215 exit(0) ;
216 }
217 #endif
218 }
219
220 if( strlen(expr) == 0 || *expr == '\n' ) continue ;
221 if( strcasestr(expr,"quit") != NULL ) exit(0) ;
222 if( strncmp (expr,":q",2) == 0 ) exit(0) ; /* 17 Nov 2010 */
223 if( strcasestr(expr,"exit") != NULL ) exit(0) ;
224 if( strcasestr(expr,"help") != NULL || expr[0] == '?' ){
225 printf(PARSER_HELP_STRING) ; continue ; /* 22 Jan 2008 */
226 }
227
228 if( strstr(expr,"=") != NULL ){
229 kvar = toupper(expr[0]) - 'A' ;
230 cexp = strstr(expr,"=") + 1 ;
231 } else {
232 kvar = 25 ; /* assign result to letter Z */
233 cexp = expr ;
234 }
235
236 PARSER_set_printout(1) ;
237 pcode = PARSER_generate_code( cexp ) ;
238 if( pcode == NULL ){
239 printf("parser error!\n") ; fflush(stdout) ;
240 if (!DoOnce) continue ;
241 else exit(1);
242 }
243
244 #if 0
245 if( PARSER_has_symbol( "I" , pcode ) )
246 printf(" [contains symbol I]\n") ;
247 #endif
248
249 value = PARSER_evaluate_one( pcode , atoz ) ; free(pcode) ;
250
251 if (!DoOnce) {
252 if( kvar >= 0 && kvar < 26 ){
253 printf("%c", kvar+'A' ) ;
254 atoz[kvar] = value ;
255 } else {
256 printf(" ") ;
257 }
258 printf(" = %g\n",value) ; fflush(stdout) ;
259 } else {
260 printf("%s\n", format_value_4print(value, oform, formatstr ));
261 exit (0);
262 }
263 } while(1) ;
264 }
265