1/*
2 * Copyright 2008 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// A calculator example used to demonstrate the cmockery testing library.
18
19#include <assert.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24// If this is being built for a unit test.
25#if UNIT_TESTING
26
27/* Redirect printf to a function in the test application so it's possible to
28 * test the standard output. */
29#ifdef printf
30#undef printf
31#endif // printf
32#define printf example_test_printf
33
34extern void print_message(const char *format, ...);
35
36/* Redirect fprintf to a function in the test application so it's possible to
37 * test error messages. */
38#ifdef fprintf
39#undef fprintf
40#endif // fprintf
41#define fprintf example_test_fprintf
42
43extern int example_test_fprintf(FILE * const file, const char *format, ...);
44
45// Redirect assert to mock_assert() so assertions can be caught by cmockery.
46#ifdef assert
47#undef assert
48#endif // assert
49#define assert(expression) \
50	mock_assert((int)(expression), #expression, __FILE__, __LINE__)
51void mock_assert(const int result, const char* expression, const char *file,
52                 const int line);
53
54/* Redirect calloc and free to test_calloc() and test_free() so cmockery can
55 * check for memory leaks. */
56#ifdef calloc
57#undef calloc
58#endif // calloc
59#define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__)
60#ifdef free
61#undef free
62#endif // free
63#define free(ptr) _test_free(ptr, __FILE__, __LINE__)
64void* _test_calloc(const size_t number_of_elements, const size_t size,
65                   const char* file, const int line);
66void _test_free(void* const ptr, const char* file, const int line);
67
68/* main is defined in the unit test so redefine name of the the main function
69 * here. */
70#define main example_main
71
72/* All functions in this object need to be exposed to the test application,
73 * so redefine static to nothing. */
74#define static
75
76#endif // UNIT_TESTING
77
78
79// A binary arithmetic integer operation (add, subtract etc.)
80typedef int (*BinaryOperator)(int a, int b);
81
82// Structure which maps operator strings to functions.
83typedef struct OperatorFunction {
84	const char* operator;
85	BinaryOperator function;
86} OperatorFunction;
87
88
89static int add(int a, int b);
90static int subtract(int a, int b);
91static int multiply(int a, int b);
92static int divide(int a, int b);
93
94// Associate operator strings to functions.
95static OperatorFunction operator_function_map[] = {
96	{"+", add},
97	{"-", subtract},
98	{"*", multiply},
99	{"/", divide},
100};
101
102static int add(int a, int b) {
103	return a + b;
104}
105
106static int subtract(int a, int b) {
107	return a - b;
108}
109
110static int multiply(int a, int b) {
111	return a * b;
112}
113
114static int divide(int a, int b) {
115	assert(b);  // Check for divde by zero.
116	return a / b;
117}
118
119/* Searches the specified array of operator_functions for the function
120 * associated with the specified operator_string.  This function returns the
121 * function associated with operator_string if successful, NULL otherwise.
122 */
123static BinaryOperator find_operator_function_by_string(
124        const size_t number_of_operator_functions,
125        const OperatorFunction * const operator_functions,
126        const char* const operator_string) {
127	size_t i;
128	assert(!number_of_operator_functions || operator_functions);
129	assert(operator_string);
130
131	for (i = 0; i < number_of_operator_functions; i++) {
132		const OperatorFunction *const operator_function =
133		    &operator_functions[i];
134		if (strcmp(operator_function->operator, operator_string) == 0) {
135			return operator_function->function;
136		}
137	}
138	return NULL;
139}
140
141/* Perform a series of binary arithmetic integer operations with no operator
142 * precedence.
143 *
144 * The input expression is specified by arguments which is an array of
145 * containing number_of_arguments strings.  Operators invoked by the expression
146 * are specified by the array operator_functions containing
147 * number_of_operator_functions, OperatorFunction structures.  The value of
148 * each binary operation is stored in a pointer returned to intermediate_values
149 * which is allocated by malloc().
150 *
151 * If successful, this function returns the integer result of the operations.
152 * If an error occurs while performing the operation error_occurred is set to
153 * 1, the operation is aborted and 0 is returned.
154 */
155static int perform_operation(
156        int number_of_arguments, char *arguments[],
157        const size_t number_of_operator_functions,
158        const OperatorFunction * const operator_functions,
159        int * const number_of_intermediate_values,
160        int ** const intermediate_values, int * const error_occurred) {
161	char *end_of_integer;
162	int value;
163	unsigned int i;
164	assert(!number_of_arguments || arguments);
165	assert(!number_of_operator_functions || operator_functions);
166	assert(error_occurred);
167	assert(number_of_intermediate_values);
168	assert(intermediate_values);
169
170	*error_occurred = 0;
171	*number_of_intermediate_values = 0;
172	*intermediate_values = NULL;
173	if (!number_of_arguments)
174		return 0;
175
176	// Parse the first value.
177	value = (int)strtol(arguments[0], &end_of_integer, 10);
178	if (end_of_integer == arguments[0]) {
179		// If an error occurred while parsing the integer.
180		fprintf(stderr, "Unable to parse integer from argument %s\n",
181		        arguments[0]);
182		*error_occurred = 1;
183		return 0;
184	}
185
186	// Allocate an array for the output values.
187	*intermediate_values = calloc(((number_of_arguments - 1) / 2),
188	                              sizeof(**intermediate_values));
189
190	i = 1;
191	while (i < number_of_arguments) {
192		int other_value;
193		const char* const operator_string = arguments[i];
194		const BinaryOperator function = find_operator_function_by_string(
195		    number_of_operator_functions, operator_functions, operator_string);
196		int * const intermediate_value =
197		    &((*intermediate_values)[*number_of_intermediate_values]);
198		(*number_of_intermediate_values) ++;
199
200		if (!function) {
201			fprintf(stderr, "Unknown operator %s, argument %d\n",
202			        operator_string, i);
203			*error_occurred = 1;
204			break;
205		}
206		i ++;
207
208		if (i == number_of_arguments) {
209			fprintf(stderr, "Binary operator %s missing argument\n",
210			        operator_string);
211			*error_occurred = 1;
212			break;
213		}
214
215		other_value = (int)strtol(arguments[i], &end_of_integer, 10);
216		if (end_of_integer == arguments[i]) {
217			// If an error occurred while parsing the integer.
218			fprintf(stderr, "Unable to parse integer %s of argument %d\n",
219			        arguments[i], i);
220			*error_occurred = 1;
221			break;
222		}
223		i ++;
224
225		// Perform the operation and store the intermediate value.
226		*intermediate_value = function(value, other_value);
227		value = *intermediate_value;
228	}
229	if (*error_occurred) {
230		free(*intermediate_values);
231		*intermediate_values = NULL;
232		*number_of_intermediate_values = 0;
233		return 0;
234	}
235	return value;
236}
237
238int main(int argc, char *argv[]) {
239	int return_value;
240	int number_of_intermediate_values;
241	int *intermediate_values;
242	// Peform the operation.
243	const int result = perform_operation(
244	    argc - 1, &argv[1],
245	    sizeof(operator_function_map) / sizeof(operator_function_map[0]),
246	    operator_function_map, &number_of_intermediate_values,
247	    &intermediate_values, &return_value);
248
249	// If no errors occurred display the result.
250	if (!return_value && argc > 1) {
251		unsigned int i;
252		unsigned int intermediate_value_index = 0;
253		printf("%s\n", argv[1]);
254		for (i = 2; i < argc; i += 2) {
255			assert(intermediate_value_index < number_of_intermediate_values);
256			printf("  %s %s = %d\n", argv[i], argv[i + 1],
257			       intermediate_values[intermediate_value_index++]);
258		}
259		printf("= %d\n", result);
260	}
261	if (intermediate_values) {
262		free(intermediate_values);
263	}
264
265	return return_value;
266}
267