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