new command: base
authorLaurent Mazet <mazet@softndesign.org>
Mon, 27 Feb 2023 21:37:57 +0000 (22:37 +0100)
committerLaurent Mazet <mazet@softndesign.org>
Mon, 27 Feb 2023 21:37:57 +0000 (22:37 +0100)
calc.c
element.h
format.c
format.h
parser.c

diff --git a/calc.c b/calc.c
index 6043346c3d97ac7c97ae18505b592a58d94343f3..cadb186f4d1a68deab1d34471c188549a228f610 100644 (file)
--- a/calc.c
+++ b/calc.c
@@ -43,7 +43,7 @@ int usage (int ret)
     FILE *fid = ret ? stderr : stdout;
     fprintf (fid, "usage: %s\n", progname);
     fprintf (fid, " -h : help message\n");
-    fprintf (fid, " -b : in/out-put base (%d-%d)\n", ibase, obase);
+    fprintf (fid, " -b : in/out-put base (%s)\n", show_base ());
     fprintf (fid, " -n : no readline mode (%s)\n", mode ? "yes" : "no");
     fprintf (fid, " -n : no readline mode (%s)\n", mode ? "yes" : "no");
     fprintf (fid, " -o : output prompt (%s)\n", oprompt);
@@ -105,7 +105,7 @@ int main (int argc, char *argv[])
 {
     char *buffer = NULL;
     char buffer_static[BUFFER_SIZE + 1] = {0};
-    int i = 0, nb = 1;
+    int i = 0, nb = 1, in, out;
     int ret = 0;
 
     /* program name */
@@ -128,6 +128,7 @@ int main (int argc, char *argv[])
             VERBOSE (ERROR, fprintf (stderr, "%s: invalid option -- '%s'\n", progname, arg); usage (1));
             return 1;
         }
+        char *pt = NULL;
         char c = arg[1];
         switch (c) {
         case 'b':
@@ -136,7 +137,17 @@ int main (int argc, char *argv[])
                 VERBOSE (ERROR, fprintf (stderr, "%s: missing base definition\n", progname); usage (1));
                 return 1;
             }
-            ibase = obase = atoi (arg);
+            in = out = strtol (arg, &pt, 10);
+            if ((*pt == ' ') || (*pt == ',') || (*pt == '-')) {
+                pt++;
+                if (*pt == '\0') {
+                    VERBOSE (ERROR, fprintf (stderr, "%s: missing output base definition\n", progname); usage (1));
+                    return 1;
+                } else {
+                    out = atoi (pt);
+                }
+            }
+            set_base (in, out);
             break;
         case 'i':
             arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
@@ -281,6 +292,10 @@ int main (int argc, char *argv[])
 // test: calc.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
 // test: calc.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
 // test: calc.exe error 2>&1 | grep -q 'invalid option'
+// test: calc.exe -b 2>&1 | grep -q 'missing base'
+// test: calc.exe -b 10, 2>&1 | grep -q 'missing output base'
+// test: calc.exe -b 10- 2>&1 | grep -q 'missing output base'
+// test: calc.exe -b '10 ' 2>&1 | grep -q 'missing output base'
 // test: calc.exe -i 2>&1 | grep -q 'missing input prompt'
 // test: calc.exe -o 2>&1 | grep -q 'missing output prompt'
 // test: calc.exe -p 2>&1 | grep -q 'missing precision'
@@ -441,6 +456,10 @@ int main (int argc, char *argv[])
 // test: echo -e 'ff + ff' | calc.exe -b 16 | grep -q '=> 1fe'
 // test: echo -e '60 / 4' | calc.exe -b 8 | grep -q '=> 14'
 // test: echo -e 'z00-z0+1-2*z+20x' | calc.exe -b 36 | grep -q '=> 1000'
+// test: echo -e '255' | calc.exe -b 10,16 | grep -q '=> ff'
+// test: echo -e 'base (-2)\nbase (16, 0)' | calc.exe | grep -c error | xargs test 2 =
+// test: echo -e 'base (10, 16)\n255' | calc.exe | grep -q '=> ff'
+// test: echo -e 'base' | calc.exe | grep -q 'base (I/O): 10/10'
 
 // Gauss sequence
 // test: echo -e '{sto (1, 0), sto (10, 0), while (inc (10) <= 100, {sto (1, rcl (1) + rcl (10)), print (rcl (1))})};' | calc.exe | grep -q '=> 5050'
index c2acb4dca61dab002177f2c5d5ebdc4884dc679e..0fd40f8bcfa218b1d2727af63bcdbf25e4edafb9 100644 (file)
--- a/element.h
+++ b/element.h
@@ -23,7 +23,7 @@ typedef enum {
     Prog, Arg, Call, List, Edit, Del,
     Get, Length, Pop, Push, Put, Set, Show,
     Max, Mean, Median, Min, Order, Prod, Sum, Variance,
-    Precision
+    Precision, Base
 } func_t;
 
 /* keyword type */
index 4b9e6cf5ebeefce69d9b085a3118cf7676579da0..e6b1fb609cfb90ae4d2d77f996c992f77dfc6e91 100644 (file)
--- a/format.c
+++ b/format.c
@@ -6,8 +6,8 @@
 
 /* global variables */
 
-int ibase = 10;
-int obase = 10;
+int _ibase = 10;
+int _obase = 10;
 
 #define DEFAULT_FORMAT "=> %.6g\n"
 char *_format = NULL;
@@ -70,6 +70,28 @@ void free_format ()
     }
 }
 
+void set_base (int in, int out)
+{
+    _ibase = in;
+    _obase = out;
+}
+
+int is_input_decimal ()
+{
+    return (_ibase == 10);
+}
+
+char *show_base ()
+{
+    static char str[16] = {0};
+    sprintf (str, "%d/%d", _ibase, _obase);
+    return str;
+}
+
+int get_ibase ()
+{
+    return _ibase;
+}
 
 char *itoa (unsigned long value)
 {
@@ -79,9 +101,9 @@ char *itoa (unsigned long value)
     char buffer[8 * sizeof (long) + 1] = {0};
     int size = 0;
     do {
-        char x = value % obase;
+        char x = value % _obase;
         buffer[size++] = (x > 9) ? 'a' + x - 10 : '0' + x;
-        value /= obase;
+        value /= _obase;
     } while (value != 0);
 
     /* revert */
@@ -94,14 +116,9 @@ char *itoa (unsigned long value)
     return str;
 }
 
-/* vim: set ts=4 sw=4 et: */
-
-
-
-
 double print (double value)
 {
-    if (obase == 10) {
+    if (_obase == 10) {
         fprintf (stdout, _format ? _format : DEFAULT_FORMAT, value);
     } else {
         fprintf (stdout, "%s%s\n", (_prompt) ? _prompt : DEFAULT_PROMPT, itoa ((unsigned int)value));
@@ -112,7 +129,7 @@ double print (double value)
 
 double printl (double value)
 {
-    if (obase == 10) {
+    if (_obase == 10) {
         fprintf (stdout, _minform ? _minform : DEFAULT_MINFORM, value);
     } else {
         fprintf (stdout, "%s%s", (_prompt) ? _prompt : DEFAULT_PROMPT, itoa ((unsigned int)value));
index d2f8f4ff0fc69fd655a41b125df4d1e30bbcf22b..b18b92d728e8ccb99d9e18a684fcd452ab9ade02 100644 (file)
--- a/format.h
+++ b/format.h
@@ -3,9 +3,6 @@
 
 /* global variables */
 
-extern int ibase;
-extern int obase;
-
 /* print function */
 
 void set_precision (int precision);
@@ -15,6 +12,11 @@ void set_format ();
 
 void free_format ();
 
+void set_base (int in, int out);
+int is_input_decimal ();
+char *show_base ();
+int get_ibase ();
+
 double print (double value);
 double printl (double value);
 
index 94f4c73fd0d752910b28d70ca02261c81446ea65..119733f9afb4e613347558d9db50cc0f367a9f06 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -62,7 +62,7 @@ keyword_t operators[NB_OPERATORS] = {
     { "|",   Or, 2, 1, -2}
 };
 
-#define NB_FUNCTIONS 51
+#define NB_FUNCTIONS 52
 keyword_t functions[NB_FUNCTIONS] = {
     { "sqrt", Sqr, 1, 4, 5},
     { "pow",  Pow, 2, 3, 5},
@@ -114,7 +114,8 @@ keyword_t functions[NB_FUNCTIONS] = {
     { "prod", Prod, 0, 4, 5},
     { "sum",  Sum, 0, 3, 5},
     { "var",  Variance, 2, 3, 5},
-    { "format", Precision, 1, 6, 9}
+    { "format", Precision, 1, 6, 9},
+    { "base", Base, 2, 4, 9}
 };
 
 #define NB_CONSTANTS 3
@@ -373,7 +374,7 @@ element_t *parser (char *str, char **next, int prio)
 
         VERBOSE (DEBUG, fprintf (stdout, "start processing value\n"));
         char *pt;
-        double value = (ibase == 10) ? strtod (str, &pt) : strtoul (str, &pt, ibase);
+        double value = (get_ibase () == 10) ? strtod (str, &pt) : strtoul (str, &pt, get_ibase ());
         VERBOSE (INFO, fprintf (stdout, "Value: %f\n", value));
         if (str != pt) {
             if ((root == NULL) || (root->prio == 6)) {
@@ -521,6 +522,7 @@ void print_element (element_t *root, int level)
     case Sum: func = "Sum"; break;
     case Variance: func = "Variance"; break;
     case Precision: func = "Precision"; break;
+    case Base: func = "Base"; break;
     }
 
     fprintf (stdout, "Function: %s\n", func);
@@ -616,11 +618,43 @@ void help (void)
     fprintf (stdout, "stack func.:");
     fprintf (stdout, " max mean med min ord prod sum var\n");
     fprintf (stdout, "control management:");
-    fprintf (stdout, " format help quit\n");
+    fprintf (stdout, " base format help quit\n");
     fprintf (stdout, "constants:");
     fprintf (stdout, " ans e pi\n");
 }
 
+/* format function */
+
+int format (int precision)
+{
+    if (precision > 0) {
+        set_precision (precision);
+        set_format ();
+    } else if (precision != -1) {
+        VERBOSE (WARNING, fprintf (stdout, "error incorrect precision (%d)\n", precision));
+        return 0;
+    }
+    return get_precision ();
+}
+
+/* base function */
+
+void base (int in, int out)
+{
+    if (in > 0) {
+        set_base (in, in);
+        if (out > 0) {
+            set_base (in, out);
+        } else if (out != - 1) {
+            VERBOSE (WARNING, fprintf (stdout, "error incorrect output base (%d)\n", out));
+        }
+    } else if (in != -1 ) {
+        VERBOSE (WARNING, fprintf (stdout, "error incorrect input base (%d)\n", in));
+    } else {
+        printf ("base (I/O): %s\n", show_base ());
+    }
+}
+
 /* evaluate element tree */
 
 #define MASK_SUB 0x1
@@ -777,6 +811,10 @@ double evaluate_element (element_t *root, char mask)
     case Precision:
         op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : -1;
         break;
+    case Base:
+        op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : -1;
+        op1 = (root->ops[1]) ? evaluate_element (root->ops[1], 0) : -1;
+        break;
     }
 
     switch (root->func) {
@@ -891,14 +929,10 @@ double evaluate_element (element_t *root, char mask)
         }
         return variance ();
     case Precision:
-        if (op0 > 0) {
-            set_precision ((int)op0);
-            set_format ();
-        } else if (op0 != -1) {
-            VERBOSE (WARNING, fprintf (stdout, "error incorrect precision (%g)\n", op0));
-            return 0;
-        }
-        return get_precision();
+        return format ((int)op0);
+    case Base:
+        base (op0, op1);
+        break;
     }
 
     return 0;