/*****************************************************************************
   Major portions of this software are copyrighted by the Medical College
   of Wisconsin, 1994-2000, and are released under the Gnu General Public
   License, Version 2.  See the file README.Copyright for details.
******************************************************************************/

#include "parser.h"
#include <ctype.h>

#undef USE_READLINE
#ifdef USE_READLINE
#include "readline.h"
#endif
enum { CCALC_DOUBLE = 1, CCALC_NICE, CCALC_INT, CCALC_FINT, CCALC_CINT, CCALC_CUSTOM};
#define AFNI_EOL '\n'

int main( int argc , char * argv[] )
{
   PARSER_code * pcode ;
   char expr[9000] , * cexp ;
   double atoz[26] , value ;
   int ii , kvar, kar, brk, strt, oform , len;
   int DoOnce;
   char *formatstr, *strptr;
   char ch;

   DoOnce = 0;

   kar = 1;
   brk = 0;
   DoOnce = 0; /* flag used to indicate that program is running in batch or command line modes */
   expr[0] = '\0';
   oform = CCALC_DOUBLE; /* double is default */
   while (kar < argc) {
      if (strcmp(argv[1],"-help") == 0 ){
         printf("Usage: ccalc [-form FORM] [-eval 'expr']\n"
                "Usage mode 1: Interactive numerical calculator\n"
                "    Interactive numerical calculator, using the \n"
                "    same expression syntax as 3dcalc. \n"
                "    No command line parameters are permitted in\n"
                "    usage 1 mode.\n"
                "Usage mode 2: Command line expression calculator\n"
                "    Evaluate an expression specified on command\n"
                "    line, return answer and quit.\n"
                "    Optional parameters: (must come first)\n"
                "    -form FORM: Format output in a nice form\n"
                "                Choose from:\n"
                "                double: Macho numbers (default).\n"
                "                nice: Metrosexual output.\n"
                "                int (or rint): Rounded to nearest integer.\n"
                "                cint: Rounded up.\n"
                "                fint: Rounded down.\n"
                "                %%n.mf: custom format string, used as in printf.\n"
                "                   format string can contain %%%%, \\n and other\n"
                "                   regular characters.\n"
                "                   See man fprintf and man printf for details.\n"
                "    Mandatory parameter: (must come last on command line)\n"
                "    -eval EXPR: EXPR is the expression to evaluate.\n" 
                "                Example: ccalc -eval '3 + 5 * sin(22)' \n"
                "                     or: ccalc -eval 3 +5 '*' 'sin(22)'\n"
                "                You can not use variables in EXPR\n"
                "                as you do with 3dcalc.\n"
                "    Example with formatting:\n"
                "        ccalc -form '********\\n%%6.4f%%%%\\n********' -eval '100*328/457'\n" 
                "    gives:\n"
                "        ********\n"
                "        0.7177%%\n"
                "        ********\n\n"
                "    SECRET: You don't need to use -eval if you are \n"
                "            not using any other options. I hate typing\n"
                "            it for quick command line calculations. \n"
                "            But that feature might be removed in the\n"
                "            future, so always use -eval when you are \n"
                "            using this program in your scripts.\n" 
                ) ;
         exit(0) ;
      }

      if ( !brk && strcmp(argv[kar],"-form") == 0 ) {
         ++kar;
         if (kar >= argc)  {
	         fprintf (stderr, "need argument after -form ");
	         exit (1);
         }
         if (strcmp(argv[kar],"double") == 0 ) oform = CCALC_DOUBLE;
         else if (strcmp(argv[kar],"nice") == 0 ) oform = CCALC_NICE;
         else if (strcmp(argv[kar],"int") == 0 ) oform = CCALC_INT;
         else if (strcmp(argv[kar],"rint") == 0 ) oform = CCALC_INT;
         else if (strcmp(argv[kar],"fint") == 0 ) oform = CCALC_FINT;
         else if (strcmp(argv[kar],"cint") == 0 ) oform = CCALC_CINT;
         else if (strlen(argv[kar])<=256) {
            oform = CCALC_CUSTOM;
            formatstr = argv[kar];
         }
         else {
            fprintf (stderr, "Format type '%s' not supported.\nSee -help for details.\n", argv[kar]);
            exit (1);
         }
         DoOnce = 1;
         brk = 1;
      }
      if( !brk &&  ( strcmp(argv[kar],"-eval") == 0 || strcmp(argv[kar],"-expr") == 0) ){
         ++kar;
         if (kar >= argc)  {
	         fprintf (stderr, "need argument after -eval (or -expr) ");
	         exit (1);
         }
         /* anything after eval gets put into an expression */
         while (kar < argc)  {
            if (  strcmp(argv[kar],"-eval") == 0 || 
                  strcmp(argv[kar],"-expr") == 0 ||
                  strcmp(argv[kar],"-form") == 0   ) {
               fprintf (stderr,  "Error:\n"
                                 "You have optional parameters (%s) following \n"
                                 "the expression to evaluate.\n"
                                 "Stop it!\n", argv[kar]);
		         exit (1);      
            } 
            sprintf(expr,"%s %s", expr, argv[kar]);
            ++ kar;
         }
         /* fprintf (stdout, "%s\n", expr);*/
         DoOnce = 1;
         brk = 1;
      }

      if (!brk) {
         /* if nothing is understood, assume the expression follows, instead of moaning and quitting*/
         while (kar < argc)  {
            if (  strcmp(argv[kar],"-eval") == 0 || 
                  strcmp(argv[kar],"-expr") == 0 ||
                  strcmp(argv[kar],"-form") == 0   ) {
               fprintf (stderr,  "Error:\n"
                                 "You have optional parameters (%s) following \n"
                                 "the expression to evaluate.\n"
                                 "Stop it!\n", argv[kar]);
		         exit (1);      
            } 
            sprintf(expr,"%s %s", expr, argv[kar]);
            ++ kar;
         }
         /* fprintf (stdout, "%s\n", expr);*/
         DoOnce = 1;
         brk = 1;
	   }
      
      if (!brk) {
		   fprintf (stderr,"Error: Option %s not understood. Try -help for usage\n", argv[kar]);
		   exit (1); 
	   } else {	
		   brk = 0;
		   kar ++;
	   }
		
   }

   for( ii=0 ; ii < 25 ; ii++ ) atoz[ii] = 0.0 ;

   do{
      if (!DoOnce){
#ifdef USE_READLINE
         { char *lin = readline("ccalc> ") ;
           if(  lin == NULL ) continue ;
           if( *lin == '\0' ){ free(lin); continue; }
           add_history(lin) ;
           strncpy(expr,lin,899); expr[899]='\0'; free(lin);
         }
#else
         printf("calc> ") ; fflush(stdout) ;
         fgets(expr,900,stdin) ;
#endif
      }

      if( strlen(expr) == 0 ) continue ;
      if( strstr(expr,"quit") != NULL ) exit(0) ;

      if( strstr(expr,"=") != NULL ){
         kvar = toupper(expr[0]) - 'A' ;
         cexp = strstr(expr,"=") + 1 ;
      } else {
         kvar = -1 ;
         cexp = expr ;
      }

      pcode = PARSER_generate_code( cexp ) ;
      if( pcode == NULL ){
         printf("parser error!\n") ; fflush(stdout) ;
         if (!DoOnce) continue ;
            else exit(1);
      }

#if 0
      if( PARSER_has_symbol( "I" , pcode ) )
         printf("  [contains symbol I]\n") ;
#endif

      value = PARSER_evaluate_one( pcode , atoz ) ; free(pcode) ;

      if (!DoOnce) {
         if( kvar >= 0 && kvar < 26 ){
           printf("%c", kvar+'A' ) ;
           atoz[kvar] = value ;
         } else {
           printf(" ") ;
         }
         printf(" = %g\n",value) ; fflush(stdout) ;
      } else {
         switch (oform) {
            case CCALC_DOUBLE: /* double */
               printf("%f\n",value) ;
               break;
            case CCALC_NICE:
               printf("%g\n",value) ;
               break;
            case CCALC_INT:
               if ( (value - (int)value) < 0.5) value = (int)value;
               else value = (int)value + 1;
               printf("%d\n",(int)value) ;
               break;
            case CCALC_FINT:
               printf("%d\n",(int)value) ;
               break;
            case CCALC_CINT:
               printf("%d\n",(int)ceil(value)) ;
               break;
  	    case CCALC_CUSTOM:           /* use user customized format */
	      /* add check for integer output %d */
	      strptr = strchr(formatstr, '%');
              if(strptr==NULL) {
               printf("%f\n",value) ;
              }
              else {
		len = strlen(strptr);
                for(ii=1;ii<len;ii++) {
                  ch = *(++strptr);
  	          switch(ch) {
		  case 'd':  case 'i': case 'c': case 'o': case 'u': case 'x': case 'X':
		    value = (int)value;              /* integer (no decimal) type output */
                       ii = len + 1;
                       break;

                  case 'e': case 'E':         /* floating point output types */
		  case 'f': case 'F':
                  case 'g': case 'G':
                  case 'a': case 'A':
                    ii = len+1;
		    break;
                  case '%':
                    strptr = strchr(strptr, '%'); /* find next % symbol */
                  default:
		    break;
                  }
                }
		if(ii==len) {
		    printf("unknown format specifier. Try %%d, %%c, %%f or %%g instead.\n");
                    exit(1);
		}
                strptr = (char *) 1;
                while(strptr) {
	  	  strptr = strstr(formatstr, "\\n");
                  if(strptr) {
                    *strptr = ' ';
                    *(strptr+1) = AFNI_EOL;
		  }
                }
               
               printf(formatstr,value) ;
               printf("\n");
              }
               break;
            default:
               printf("%f\n",value) ;
               break; 
         }
         exit (0);
      }
   } while(1) ;
}


syntax highlighted by Code2HTML, v. 0.9.1