{"id":11144,"date":"2026-01-26T15:53:44","date_gmt":"2026-01-26T13:53:44","guid":{"rendered":"https:\/\/blue.pri.ee\/ttu\/?page_id=11144"},"modified":"2026-03-05T16:04:22","modified_gmt":"2026-03-05T14:04:22","slug":"applying-enumeration-and-header-file-to-calculator","status":"publish","type":"page","link":"https:\/\/blue.pri.ee\/ttu\/programming-ii\/code-samples\/applying-enumeration-and-header-file-to-calculator\/","title":{"rendered":"Applying enumeration and header file to calculator"},"content":{"rendered":"<p>The purpose of the following example is to how to use enumerations in a code that&#8217;s already familiar from Programming 1. There are three enumeration types declared:<\/p>\n<ol>\n<li>Specifying command line argument position<\/li>\n<li>Encoding error codes<\/li>\n<li>Encoding mathematical operations<\/li>\n<\/ol>\n<p>The example is provided to you in three variations, suitable for different times in the course<\/p>\n<ol>\n<li><strong>Calculator basic<\/strong> is suitable for <strong>week #2.<\/strong> It only adds enumerations.<\/li>\n<li><strong>Calculator + struct<\/strong> is suitable for <strong>week #3<\/strong>. It adds a struct that matches together the expected character symbols to the expected enumerated values, that allows for nicer matching using a loop and a predefined lookup table.<\/li>\n<li><strong>Calculator + header<\/strong> is suitable for <strong>week #4<\/strong>. It takes the previous code and divides it into two files &#8211; a header and code file. This is also very close to the minimum requirements of homework 1.<\/li>\n<\/ol>\n<div class=\"su-tabs su-tabs-style-default su-tabs-mobile-stack\" data-active=\"1\" data-scroll-offset=\"0\" data-anchor-in-url=\"yes\"><div class=\"su-tabs-nav\"><span class=\"\" data-url=\"\" data-target=\"blank\" tabindex=\"0\" role=\"button\">Calculator basic<\/span><span class=\"\" data-url=\"\" data-target=\"blank\" tabindex=\"0\" role=\"button\">Calculator + struct<\/span><span class=\"\" data-url=\"\" data-target=\"blank\" tabindex=\"0\" role=\"button\">Calculator + header<\/span><\/div><div class=\"su-tabs-panes\"><div class=\"su-tabs-pane su-u-clearfix su-u-trim\" data-title=\"Calculator basic\">\n<pre class=\"lang:c decode:true\">\/**\r\n * File:        calc_enum.c\r\n * Author:      Risto Heinsar\r\n * Created:     25.01.2026\r\n * Edited:      05.02.2026\r\n *\r\n * Description: Example program that's based on Programming 1 calculator lab.\r\n *              Introduces simple use cases for enum type.\r\n *\/\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;ctype.h&gt;\r\n#include &lt;string.h&gt;\r\n\r\n#define DEBUG 0\r\n\r\n#define ARGS_CNT_EXPECTED 4\r\n\r\nenum ArgsPosition { ARGS_EXEC, ARGS_OPERAND_1, ARGS_OPERATION, ARGS_OPERAND_2 };\r\nenum MathOperation { OP_ADD, OP_SUB, OP_MULT, OP_DIV, OP_UNKNOWN };\r\n\r\nenum ErrorCode\r\n{\r\n    ERR_ARG_CNT = 0,\r\n    ERR_UNRECOGNIZED_ARG,\r\n    ERR_OPERATION_INVALID,\r\n    ERR_OPERAND_MULT_SEPARATOR,\r\n    ERR_OPERAND_UNKNOWN_SYMBOL,\r\n    ERR_DIV_ZERO\r\n};\r\n\r\n\r\ndouble Calculate(double val1, double val2, enum MathOperation op);\r\nvoid ErrorHandler(enum ErrorCode code);\r\nvoid DebugArgs(int argc, char **argv);\r\ndouble EvalOperand(const char *operand);\r\nenum MathOperation GetOperation(const char *op);\r\nvoid Usage();\r\nvoid CheckArgs(int argc, char **argv);\r\n\r\n\/\/ Contains argv[0] to print exec path in Usage() for guidance \r\nconst char *execName;\r\n\r\nint main(int argc, char **argv)\r\n{\r\n    execName = argv[ARGS_EXEC];\r\n\r\n    CheckArgs(argc, argv);\r\n    \r\n    if (DEBUG) DebugArgs(argc, argv);\r\n\r\n    double val1 = EvalOperand(argv[ARGS_OPERAND_1]);\r\n    double val2 = EvalOperand(argv[ARGS_OPERAND_2]);\r\n\r\n    enum MathOperation op = GetOperation(argv[ARGS_OPERATION]);\r\n\r\n    printf(\"&gt; %.2f\\n\", Calculate(val1, val2, op));\r\n\r\n    return EXIT_SUCCESS;\r\n}\r\n\r\n\/**\r\n * Description:   Calculates the mathematical equation and returns the answer\r\n * \r\n * Parameters:    val1 - first operand\r\n *                val2 - second operand\r\n *                op - mathematical operation coded value\r\n * \r\n * Return:        result of the mathematical operation\r\n *\/\r\ndouble Calculate(double val1, double val2, enum MathOperation op)\r\n{\r\n    \/\/ Note: all cases either return or exit using ErrorHandler()\r\n    switch (op)\r\n    {\r\n        case OP_ADD:\r\n            return val1 + val2;\r\n        case OP_SUB:\r\n            return val1 - val2;\r\n        case OP_MULT:\r\n            return val1 * val2;\r\n        case OP_DIV:\r\n            if (val2 == 0)\r\n                ErrorHandler(ERR_DIV_ZERO);\r\n                \r\n            return val1 \/ val2;\r\n        default:\r\n            ErrorHandler(ERR_OPERATION_INVALID);\r\n    }\r\n    \r\n    \/\/ This should never be reached\r\n    return 0.0;\r\n}\r\n\r\n\/**\r\n * Description:   Checks if the operation passed is supported and decodes it to\r\n *                enum value\r\n * \r\n * Parameters:    op - mathematical operation as a string, to be checked\r\n * \r\n * Return:        enum value representing the decoded mathematical operation\r\n *\/\r\nenum MathOperation GetOperation(const char *op)\r\n{\r\n    \/\/ Safety check for empty arg, support single character operations only  \r\n    if (op[0] == '\\0' || op[1] != '\\0')\r\n        ErrorHandler(ERR_OPERATION_INVALID);\r\n    \r\n    \/\/ Grab the character representing the operation\r\n    char opCode = op[0];\r\n    \r\n    switch (opCode)\r\n    {\r\n        case '+':\r\n            return OP_ADD;\r\n        case '-':\r\n            return OP_SUB;\r\n        case '\/':\r\n            return OP_DIV;\r\n        case '*':\r\n        case 'x':\r\n            return OP_MULT;\r\n        default:\r\n            return OP_UNKNOWN;\r\n    }\r\n}\r\n\r\n\/**\r\n * Description:   Checks if the operand is a decimal number, converts it to\r\n *                a double and returns it\r\n * \r\n * Parameters:    operand - operand being checked as string\r\n * \r\n * Return:        operand converted to double\r\n *\/\r\ndouble EvalOperand(const char *operand)\r\n{\r\n    \/\/ Used to keep track of the char currently being checked for validity\r\n    const char *p = operand;\r\n\r\n    \/\/ Skip first char if it's a sign\r\n    if (*p == '-' || *p == '+')\r\n        p++;\r\n    \r\n    int commaCount = 0;\r\n    while (*p)\r\n    {\r\n        if (*p == '.')\r\n        {\r\n            commaCount++;\r\n            if (commaCount &gt; 1)\r\n                ErrorHandler(ERR_OPERAND_MULT_SEPARATOR);\r\n        }\r\n        \r\n        \/\/ Checks 0 .. 9\r\n        if (!isdigit((unsigned char)*p))\r\n            ErrorHandler(ERR_OPERAND_UNKNOWN_SYMBOL);\r\n        \r\n        \/\/ Move to next character\r\n        p++;\r\n    }\r\n    \r\n    return atof(operand);\r\n}\r\n\r\n\/**\r\n * Description:   Prints error message, usage help and terminates the program\r\n * \r\n * Parameters:    code - error code that triggered exit condition\r\n * \r\n * Return:        -\r\n *\/\r\nvoid ErrorHandler(enum ErrorCode code)\r\n{\r\n    const char *errorPrintableText[] = \r\n    {\r\n        [ERR_ARG_CNT] = \"Invalid argument count\",\r\n        [ERR_UNRECOGNIZED_ARG] = \"Unrecognized argument\",\r\n        [ERR_OPERATION_INVALID] = \"Invalid operation\",\r\n        [ERR_OPERAND_MULT_SEPARATOR] = \"Invalid operand, unexpected decimal separator\",\r\n        [ERR_OPERAND_UNKNOWN_SYMBOL] = \"Invalid operand, not a number\",\r\n        [ERR_DIV_ZERO] = \"Dividing by zero\"\r\n    };\r\n    \r\n    fprintf(stderr, \"Error %d: \", code);\r\n    fprintf(stderr, \"%s\\n\", errorPrintableText[code]);\r\n\r\n    Usage();\r\n    exit(EXIT_FAILURE);\r\n}\r\n\r\n\/**\r\n * Description:   Prints program usage information\r\n * \r\n * Parameters:    -\r\n * \r\n * Return:        -\r\n *\/\r\nvoid Usage()\r\n{\r\n    printf(\"\\nUsage: %s operand operation operand\\n\\n\", execName);\r\n    printf(\"Possible operations: \\n\");\r\n    printf(\"\\t+ add\\n\");\r\n    printf(\"\\t- subtract\\n\");\r\n    printf(\"\\t* multiply\\n\");\r\n    printf(\"\\t\/ divide\\n\");\r\n    printf(\"\\nNote, that due to how shell works, \\n\"\r\n           \"the multiplication operator has to be encased in quotes\\n\"\r\n           \"e.g. 2 \\\"*\\\" 3.5\\n\");\r\n}\r\n\r\n\/**\r\n * Description:   Checks for the help argument, triggers usage help\r\n *                Checks if all arguments required for calculation are present\r\n * \r\n * Parameters:    argc - number of command line arguments\r\n *                argv - arguments that were passed\r\n * \r\n * Return:        -\r\n *\/\r\nvoid CheckArgs(int argc, char **argv)\r\n{\r\n    \/\/ Check for help argument\r\n    if (argc == 2)\r\n    {\r\n        if (!strcmp(argv[1], \"--help\"))\r\n        {\r\n            Usage();\r\n            exit(EXIT_SUCCESS);\r\n        }\r\n        ErrorHandler(ERR_UNRECOGNIZED_ARG);\r\n    }\r\n    \r\n    \/\/ Check expected arg count for calculator\r\n    if (argc != ARGS_CNT_EXPECTED)\r\n        ErrorHandler(ERR_ARG_CNT);\r\n}\r\n\r\n\/**\r\n * Description:   Prints out all command line arguments, for debugging purposes\r\n * \r\n * Parameters:    argc - number of command line arguments\r\n *                argv - arguments that were passed\r\n * \r\n * Return:        -\r\n *\/\r\nvoid DebugArgs(int argc, char **argv)\r\n{\r\n    printf(\"Total arguments: %d\\n\", argc);\r\n    for (int i = 0; i &lt; argc; i++)\r\n    {\r\n        printf(\"argv[%d] = %s\\n\", i, argv[i]);\r\n    }\r\n}\r\n<\/pre>\n<\/div>\n<div class=\"su-tabs-pane su-u-clearfix su-u-trim\" data-title=\"Calculator + struct\">\n<pre class=\"lang:c decode:true\">\/**\r\n * File:        calc_struct.c\r\n * Author:      Risto Heinsar\r\n * Created:     25.01.2026\r\n * Edited:      26.01.2026\r\n *\r\n * Description: Example program that's based on Programming 1 calculator lab.\r\n *              Introduces simple use cases for enum type.\r\n *\/\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;ctype.h&gt;\r\n#include &lt;string.h&gt;\r\n\r\n#define DEBUG 0\r\n\r\n#define ARGS_CNT_EXPECTED 4\r\n\r\nenum ArgsPosition { ARGS_EXEC, ARGS_OPERAND_1, ARGS_OPERATION, ARGS_OPERAND_2 };\r\nenum MathOperation { OP_ADD, OP_SUB, OP_MULT, OP_DIV, OP_UNKNOWN };\r\n\r\nenum ErrorCode\r\n{\r\n    ERR_ARG_CNT = 0,\r\n    ERR_UNRECOGNIZED_ARG,\r\n    ERR_OPERATION_INVALID,\r\n    ERR_OPERAND_MULT_SEPARATOR,\r\n    ERR_OPERAND_UNKNOWN_SYMBOL,\r\n    ERR_DIV_ZERO\r\n};\r\n\r\nstruct MathOperationEncoding\r\n{\r\n    char opCode;                        \/\/ opcodes as '+' etc\r\n    enum MathOperation operation;       \/\/ opcodes as OP_ADD etc\r\n};\r\n\r\nconst struct MathOperationEncoding mathOperations[] = {{'+', OP_ADD},\r\n                                                       {'-', OP_SUB},\r\n                                                       {'*', OP_MULT},\r\n                                                       {'x', OP_MULT},\r\n                                                       {'\/', OP_DIV }};\r\n\r\n\r\ndouble Calculate(double val1, double val2, enum MathOperation op);\r\nvoid ErrorHandler(enum ErrorCode code);\r\nvoid DebugArgs(int argc, char **argv);\r\ndouble EvalOperand(const char *operand);\r\nenum MathOperation GetOperation(const char *op);\r\nvoid Usage();\r\nvoid CheckArgs(int argc, char **argv);\r\n\r\n\/\/ Contains argv[0] to print exec path in Usage() for guidance \r\nconst char *execName;\r\n\r\nint main(int argc, char **argv)\r\n{\r\n    execName = argv[ARGS_EXEC];\r\n\r\n    CheckArgs(argc, argv);\r\n    \r\n    if (DEBUG) DebugArgs(argc, argv);\r\n\r\n    double val1 = EvalOperand(argv[ARGS_OPERAND_1]);\r\n    double val2 = EvalOperand(argv[ARGS_OPERAND_2]);\r\n\r\n    enum MathOperation op = GetOperation(argv[ARGS_OPERATION]);\r\n\r\n    printf(\"&gt; %.2f\\n\", Calculate(val1, val2, op));\r\n\r\n    return EXIT_SUCCESS;\r\n}\r\n\r\n\/**\r\n * Description:   Calculates the mathematical equation and returns the answer\r\n * \r\n * Parameters:    val1 - first operand\r\n *                val2 - second operand\r\n *                op - mathematical operation coded value\r\n * \r\n * Return:        result of the mathematical operation\r\n *\/\r\ndouble Calculate(double val1, double val2, enum MathOperation op)\r\n{\r\n    \/\/ Note: all cases either return or exit using ErrorHandler()\r\n    switch (op)\r\n    {\r\n        case OP_ADD:\r\n            return val1 + val2;\r\n        case OP_SUB:\r\n            return val1 - val2;\r\n        case OP_MULT:\r\n            return val1 * val2;\r\n        case OP_DIV:\r\n            if (val2 == 0)\r\n                ErrorHandler(ERR_DIV_ZERO);\r\n                \r\n            return val1 \/ val2;\r\n        default:\r\n            ErrorHandler(ERR_OPERATION_INVALID);\r\n    }\r\n    \r\n    \/\/ This should never be reached\r\n    return 0.0;\r\n}\r\n\r\n\/**\r\n * Description:   Checks if the operation passed is supported and decodes it to\r\n *                enum value\r\n * \r\n * Parameters:    op - mathematical operation as a string, to be checked\r\n * \r\n * Return:        enum value representing the decoded mathematical operation\r\n *\/\r\nenum MathOperation GetOperation(const char *op)\r\n{\r\n    \/\/ Safety check for empty arg, support single character operations only  \r\n    if (op[0] == '\\0' || op[1] != '\\0')\r\n        ErrorHandler(ERR_OPERATION_INVALID);\r\n    \r\n    \/\/ Grab the character representing the operation\r\n    char opCode = op[0];\r\n    \r\n    \/\/ Compare against the list of known operations\r\n    size_t opCount = sizeof(mathOperations) \/ sizeof(mathOperations[0]);\r\n    for (size_t i = 0; i &lt; opCount; i++)\r\n    {\r\n        if (opCode == mathOperations[i].opCode)\r\n            return mathOperations[i].operation;\r\n    }\r\n    \r\n    \/\/ No operation codes matched\r\n    return OP_UNKNOWN;\r\n}\r\n\r\n\/**\r\n * Description:   Checks if the operand is a decimal number, converts it to\r\n *                a double and returns it\r\n * \r\n * Parameters:    operand - operand being checked as string\r\n * \r\n * Return:        operand converted to double\r\n *\/\r\ndouble EvalOperand(const char *operand)\r\n{\r\n    \/\/ Used to keep track of the char currently being checked for validity\r\n    const char *p = operand;\r\n\r\n    \/\/ Skip first char if it's a sign\r\n    if (*p == '-' || *p == '+')\r\n        p++;\r\n    \r\n    int commaCount = 0;\r\n    while (*p)\r\n    {\r\n        if (*p == '.')\r\n        {\r\n            commaCount++;\r\n            if (commaCount &gt; 1)\r\n                ErrorHandler(ERR_OPERAND_MULT_SEPARATOR);\r\n        }\r\n        \r\n        \/\/ Checks 0 .. 9\r\n        if (!isdigit((unsigned char)*p))\r\n            ErrorHandler(ERR_OPERAND_UNKNOWN_SYMBOL);\r\n        \r\n        \/\/ Move to next character\r\n        p++;\r\n    }\r\n    \r\n    return atof(operand);\r\n}\r\n\r\n\/**\r\n * Description:   Prints error message, usage help and terminates the program\r\n * \r\n * Parameters:    code - error code that triggered exit condition\r\n * \r\n * Return:        -\r\n *\/\r\nvoid ErrorHandler(enum ErrorCode code)\r\n{\r\n    const char *errorPrintableText[] = \r\n    {\r\n        [ERR_ARG_CNT] = \"Invalid argument count\",\r\n        [ERR_UNRECOGNIZED_ARG] = \"Unrecognized argument\",\r\n        [ERR_OPERATION_INVALID] = \"Invalid operation\",\r\n        [ERR_OPERAND_MULT_SEPARATOR] = \"Invalid operand, unexpected decimal separator\",\r\n        [ERR_OPERAND_UNKNOWN_SYMBOL] = \"Invalid operand, not a number\",\r\n        [ERR_DIV_ZERO] = \"Dividing by zero\"\r\n    };\r\n    \r\n    fprintf(stderr, \"Error %d: \", code);\r\n    fprintf(stderr, \"%s\\n\", errorPrintableText[code]);\r\n\r\n    Usage();\r\n    exit(EXIT_FAILURE);\r\n}\r\n\r\n\/**\r\n * Description:   Prints program usage information\r\n * \r\n * Parameters:    -\r\n * \r\n * Return:        -\r\n *\/\r\nvoid Usage()\r\n{\r\n    printf(\"\\nUsage: %s operand operation operand\\n\\n\", execName);\r\n    printf(\"Possible operations: \\n\");\r\n    printf(\"\\t+ add\\n\");\r\n    printf(\"\\t- subtract\\n\");\r\n    printf(\"\\t* multiply\\n\");\r\n    printf(\"\\t\/ divide\\n\");\r\n    printf(\"\\nNote, that due to how shell works, \\n\"\r\n           \"the multiplication operator has to be encased in quotes\\n\"\r\n           \"e.g. 2 \\\"*\\\" 3.5\\n\");\r\n}\r\n\r\n\/**\r\n * Description:   Checks for the help argument, triggers usage help\r\n *                Checks if all arguments required for calculation are present\r\n * \r\n * Parameters:    argc - number of command line arguments\r\n *                argv - arguments that were passed\r\n * \r\n * Return:        -\r\n *\/\r\nvoid CheckArgs(int argc, char **argv)\r\n{\r\n    \/\/ Check for help argument\r\n    if (argc == 2)\r\n    {\r\n        if (!strcmp(argv[1], \"--help\"))\r\n        {\r\n            Usage();\r\n            exit(EXIT_SUCCESS);\r\n        }\r\n        ErrorHandler(ERR_UNRECOGNIZED_ARG);\r\n    }\r\n    \r\n    \/\/ Check expected arg count for calculator\r\n    if (argc != ARGS_CNT_EXPECTED)\r\n        ErrorHandler(ERR_ARG_CNT);\r\n}\r\n\r\n\/**\r\n * Description:   Prints out all command line arguments, for debugging purposes\r\n * \r\n * Parameters:    argc - number of command line arguments\r\n *                argv - arguments that were passed\r\n * \r\n * Return:        -\r\n *\/\r\nvoid DebugArgs(int argc, char **argv)\r\n{\r\n    printf(\"Total arguments: %d\\n\", argc);\r\n    for (int i = 0; i &lt; argc; i++)\r\n    {\r\n        printf(\"argv[%d] = %s\\n\", i, argv[i]);\r\n    }\r\n}\r\n<\/pre>\n<\/div>\n<div class=\"su-tabs-pane su-u-clearfix su-u-trim\" data-title=\"Calculator + header\">\n<p>The following example contains two files. Both must be placed in the same directory. The name of the header is dependent on the <span class=\"lang:c highlight:0 decode:true crayon-inline \">#include<\/span>\u00a0 statement in <span class=\"lang:c highlight:0 decode:true crayon-inline\">calc_enum.h<\/span> . It is a common practice to keep the header and source file name the same, but with a different extension.<\/p>\n<p>The following has been transferred from the code file to the header file:<\/p>\n<ul>\n<li>Comments that are directed for developers using the functions<\/li>\n<li>Macros<\/li>\n<li>Structure and enumeration declarations<\/li>\n<li>Function prototypes (declarations)<\/li>\n<\/ul>\n<p>Additionally, short comments intended for developers of that file were added to the code file and header guard was added to the header file to avoid multiple conflicting declarations.<\/p>\n<pre class=\"lang:c decode:true \">\/**\r\n * File:        calc_struct_header.h\r\n * Author:      Risto Heinsar\r\n * Created:     25.01.2026\r\n * Edited:      05.03.2026\r\n *\r\n * Description: Example program that's based on Programming 1 calculator lab.\r\n *              Introduces simple use cases for enum type.\r\n *\/\r\n\r\n#ifndef CALC_STRUCT_HEADER_H\r\n#define CALC_STRUCT_HEADER_H\r\n\r\n#define DEBUG 0\r\n\r\n#define ARGS_CNT_EXPECTED 4\r\n\r\nenum ArgsPosition { ARGS_EXEC, ARGS_OPERAND_1, ARGS_OPERATION, ARGS_OPERAND_2 };\r\nenum MathOperation { OP_ADD, OP_SUB, OP_MULT, OP_DIV, OP_UNKNOWN };\r\n\r\nenum ErrorCode\r\n{\r\n    ERR_ARG_CNT = 0,\r\n    ERR_UNRECOGNIZED_ARG,\r\n    ERR_OPERATION_INVALID,\r\n    ERR_OPERAND_MULT_SEPARATOR,\r\n    ERR_OPERAND_UNKNOWN_SYMBOL,\r\n    ERR_DIV_ZERO\r\n};\r\n\r\nstruct MathOperationEncoding\r\n{\r\n    char opCode;                        \/\/ opcodes as '+' etc\r\n    enum MathOperation operation;       \/\/ opcodes as OP_ADD etc\r\n};\r\n\r\n\r\n\r\n\/**\r\n * Description:   Calculates the mathematical equation and returns the answer\r\n * \r\n * Parameters:    val1 - first operand\r\n *                val2 - second operand\r\n *                op - mathematical operation coded value\r\n * \r\n * Return:        result of the mathematical operation\r\n *\/\r\ndouble Calculate(double val1, double val2, enum MathOperation op);\r\n\r\n\r\n \/**\r\n * Description:   Checks if the operation passed is supported and decodes it to\r\n *                enum value\r\n * \r\n * Parameters:    op - mathematical operation as a string, to be checked\r\n * \r\n * Return:        enum value representing the decoded mathematical operation\r\n *\/\r\nenum MathOperation GetOperation(const char *op);\r\n\r\n\r\n \/**\r\n * Description:   Checks if the operand is a decimal number, converts it to\r\n *                a double and returns it\r\n * \r\n * Parameters:    operand - operand being checked as string\r\n * \r\n * Return:        operand converted to double\r\n *\/\r\ndouble EvalOperand(const char *operand);\r\n\r\n\r\n\/**\r\n * Description:   Prints error message, usage help and terminates the program\r\n * \r\n * Parameters:    code - error code that triggered exit condition\r\n * \r\n * Return:        -\r\n *\/\r\nvoid ErrorHandler(enum ErrorCode code);\r\n\r\n\r\n \/**\r\n * Description:   Prints program usage information\r\n * \r\n * Parameters:    -\r\n * \r\n * Return:        -\r\n *\/\r\nvoid Usage();\r\n\r\n\r\n\/**\r\n * Description:   Checks for the help argument, triggers usage help\r\n *                Checks if all arguments required for calculation are present\r\n * \r\n * Parameters:    argc - number of command line arguments\r\n *                argv - arguments that were passed\r\n * \r\n * Return:        -\r\n *\/\r\nvoid CheckArgs(int argc, char **argv);\r\n\r\n\r\n \/**\r\n * Description:   Prints out all command line arguments, for debugging purposes\r\n * \r\n * Parameters:    argc - number of command line arguments\r\n *                argv - arguments that were passed\r\n * \r\n * Return:        -\r\n *\/\r\nvoid DebugArgs(int argc, char **argv);\r\n\r\n#endif \/\/ CALC_STRUCT_HEADER_H\r\n<\/pre>\n<p>&nbsp;<\/p>\n<pre class=\"lang:c decode:true\">\/**\r\n * File:        calc_struct_header.c\r\n * Author:      Risto Heinsar\r\n * Created:     25.01.2026\r\n * Edited:      05.03.2026\r\n *\r\n * Description: Example program that's based on Programming 1 calculator lab.\r\n *              Introduces simple use cases for enum type.\r\n *\/\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;ctype.h&gt;\r\n#include &lt;string.h&gt;\r\n#include \"calc_struct_header.h.h\"\r\n\r\nconst struct MathOperationEncoding mathOperations[] = {{'+', OP_ADD},\r\n                                                       {'-', OP_SUB},\r\n                                                       {'*', OP_MULT},\r\n                                                       {'x', OP_MULT},\r\n                                                       {'\/', OP_DIV}};\r\n\r\n\r\n\/\/ Contains argv[0] to print exec path in Usage() for guidance \r\nconst char *execName;\r\n\r\nint main(int argc, char **argv)\r\n{\r\n    execName = argv[ARGS_EXEC];\r\n\r\n    CheckArgs(argc, argv);\r\n    \r\n    if (DEBUG) DebugArgs(argc, argv);\r\n\r\n    double val1 = EvalOperand(argv[ARGS_OPERAND_1]);\r\n    double val2 = EvalOperand(argv[ARGS_OPERAND_2]);\r\n\r\n    enum MathOperation op = GetOperation(argv[ARGS_OPERATION]);\r\n\r\n    printf(\"&gt; %.2f\\n\", Calculate(val1, val2, op));\r\n\r\n    return EXIT_SUCCESS;\r\n}\r\n\r\n\/**\r\n * Calculates the result, can cause exit on errors\r\n *\/\r\ndouble Calculate(double val1, double val2, enum MathOperation op)\r\n{\r\n    \/\/ Note: all cases either return or exit using ErrorHandler()\r\n    switch (op)\r\n    {\r\n        case OP_ADD:\r\n            return val1 + val2;\r\n        case OP_SUB:\r\n            return val1 - val2;\r\n        case OP_MULT:\r\n            return val1 * val2;\r\n        case OP_DIV:\r\n            if (val2 == 0)\r\n                ErrorHandler(ERR_DIV_ZERO);\r\n                \r\n            return val1 \/ val2;\r\n        default:\r\n            ErrorHandler(ERR_OPERATION_INVALID);\r\n    }\r\n    \r\n    \/\/ This should never be reached\r\n    return 0.0;\r\n}\r\n\r\n\/**\r\n * Checks the operation symbol, can throw errors that will exit\r\n *\/\r\nenum MathOperation GetOperation(const char *op)\r\n{\r\n    \/\/ Safety check for empty arg, support single character operations only  \r\n    if (op[0] == '\\0' || op[1] != '\\0')\r\n        ErrorHandler(ERR_OPERATION_INVALID);\r\n    \r\n    \/\/ Grab the character representing the operation\r\n    char opCode = op[0];\r\n    \r\n    \/\/ Compare against the list of known operations\r\n    size_t opCount = sizeof(mathOperations) \/ sizeof(mathOperations[0]);\r\n    for (size_t i = 0; i &lt; opCount; i++)\r\n    {\r\n        if (opCode == mathOperations[i].opCode)\r\n            return mathOperations[i].operation;\r\n    }\r\n    \r\n    \/\/ No operation codes matched\r\n    return OP_UNKNOWN;\r\n}\r\n\r\n\/**\r\n * Checks validity of the numeric string, can throw errors that will exit\r\n *\/\r\ndouble EvalOperand(const char *operand)\r\n{\r\n    \/\/ Used to keep track of the char currently being checked for validity\r\n    const char *p = operand;\r\n\r\n    \/\/ Skip first char if it's a sign\r\n    if (*p == '-' || *p == '+')\r\n        p++;\r\n    \r\n    int commaCount = 0;\r\n    while (*p)\r\n    {\r\n        if (*p == '.')\r\n        {\r\n            commaCount++;\r\n            if (commaCount &gt; 1)\r\n                ErrorHandler(ERR_OPERAND_MULT_SEPARATOR);\r\n        }\r\n        \r\n        \/\/ Checks 0 .. 9\r\n        if (!isdigit((unsigned char)*p))\r\n            ErrorHandler(ERR_OPERAND_UNKNOWN_SYMBOL);\r\n        \r\n        \/\/ Move to next character\r\n        p++;\r\n    }\r\n    \r\n    return atof(operand);\r\n}\r\n\r\n\/**\r\n * Prints error text and terminates the program\r\n *\/\r\nvoid ErrorHandler(enum ErrorCode code)\r\n{\r\n    const char *errorPrintableText[] = \r\n    {\r\n        [ERR_ARG_CNT] = \"Invalid argument count\",\r\n        [ERR_UNRECOGNIZED_ARG] = \"Unrecognized argument\",\r\n        [ERR_OPERATION_INVALID] = \"Invalid operation\",\r\n        [ERR_OPERAND_MULT_SEPARATOR] = \"Invalid operand, unexpected decimal separator\",\r\n        [ERR_OPERAND_UNKNOWN_SYMBOL] = \"Invalid operand, not a number\",\r\n        [ERR_DIV_ZERO] = \"Dividing by zero\"\r\n    };\r\n    \r\n    fprintf(stderr, \"Error %d: \", code);\r\n    fprintf(stderr, \"%s\\n\", errorPrintableText[code]);\r\n\r\n    Usage();\r\n    exit(EXIT_FAILURE);\r\n}\r\n\r\n\/**\r\n * Prints usage guide\r\n *\/\r\nvoid Usage()\r\n{\r\n    printf(\"\\nUsage: %s operand operation operand\\n\\n\", execName);\r\n    printf(\"Possible operations: \\n\");\r\n    printf(\"\\t+ add\\n\");\r\n    printf(\"\\t- subtract\\n\");\r\n    printf(\"\\t* multiply\\n\");\r\n    printf(\"\\t\/ divide\\n\");\r\n    printf(\"\\nNote, that due to how shell works, \\n\"\r\n           \"the multiplication operator has to be encased in quotes\\n\"\r\n           \"e.g. 2 \\\"*\\\" 3.5\\n\");\r\n}\r\n\r\n\r\n\/**\r\n * Checks command line arg count and --help, can throw errors to exit\r\n *\/\r\nvoid CheckArgs(int argc, char **argv)\r\n{\r\n    \/\/ Check for help argument\r\n    if (argc == 2)\r\n    {\r\n        if (!strcmp(argv[1], \"--help\"))\r\n        {\r\n            Usage();\r\n            exit(EXIT_SUCCESS);\r\n        }\r\n        ErrorHandler(ERR_UNRECOGNIZED_ARG);\r\n    }\r\n    \r\n    \/\/ Check expected arg count for calculator\r\n    if (argc != ARGS_CNT_EXPECTED)\r\n        ErrorHandler(ERR_ARG_CNT);\r\n}\r\n\r\n\/**\r\n * Prints list of passed command line arguments\r\n *\/\r\nvoid DebugArgs(int argc, char **argv)\r\n{\r\n    printf(\"Total arguments: %d\\n\", argc);\r\n    for (int i = 0; i &lt; argc; i++)\r\n    {\r\n        printf(\"argv[%d] = %s\\n\", i, argv[i]);\r\n    }\r\n}\r\n<\/pre>\n<\/div><\/div><\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The purpose of the following example is to how to use enumerations in a code that&#8217;s already familiar from Programming 1. There are three enumeration types declared: Specifying command line argument position Encoding error codes Encoding mathematical operations The example is provided to you in three variations, suitable for different times in the course Calculator &hellip; <a href=\"https:\/\/blue.pri.ee\/ttu\/programming-ii\/code-samples\/applying-enumeration-and-header-file-to-calculator\/\" class=\"more-link\">Loe edasi <span class=\"screen-reader-text\">Applying enumeration and header file to calculator<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":2361,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-templates\/code-width-wide.php","meta":{"footnotes":""},"class_list":["post-11144","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/pages\/11144","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/comments?post=11144"}],"version-history":[{"count":7,"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/pages\/11144\/revisions"}],"predecessor-version":[{"id":11281,"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/pages\/11144\/revisions\/11281"}],"up":[{"embeddable":true,"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/pages\/2361"}],"wp:attachment":[{"href":"https:\/\/blue.pri.ee\/ttu\/wp-json\/wp\/v2\/media?parent=11144"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}