1 /*
2  * Mathomatic API, Copyright (C) 1996-2012 George Gesslein II.
3  *
4  * This file contains the required C functions and simple interface
5  * for developers to use the Mathomatic symbolic math library properly.
6  * These functions are included in the library.
7  * Refer to this, if you are going to use the Mathomatic code in other projects.
8  *
9  * Be sure to call matho_clear(3) to erase all equation spaces
10  * after completing each group of operations,
11  * otherwise the equation spaces will fill up.
12  */
13 
14 #include "../includes.h"
15 #include "mathomatic.h"
16 
17 /** 3
18  * matho_init - Initialize the Mathomatic symbolic math library
19  * Call this only once before calling any Mathomatic code.
20  * This must be called exactly once upon program startup and not again,
21  * unless free_mem() is called.
22  *
23  * Returns true if successful.
24  * If this returns false, there was not enough memory available
25  * and Mathomatic cannot be used.
26  */
27 int
matho_init(void)28 matho_init(void)
29 {
30 	init_gvars();
31 	default_out = stdout;	/* if default_out is a file that is not stdout, output is logged to that file */
32 	gfp = default_out;
33 	if (!init_mem()) {
34 		return false;
35 	}
36 	signal(SIGFPE, fphandler);	/* handle floating point exceptions, currently ignored */
37 	return true;
38 }
39 
40 /** 3
41  * matho_clear - Erase all equation spaces so they can be reused
42  * Mathomatic only has a limited number of equation spaces.
43  * Similar to a restart, recommended after each group of symbolic math operations.
44  * Currently this is the same as entering the command "clear all".
45  *
46  * matho_init(3) must have been called only one time before this
47  * to initialize the Mathomatic symbolic math engine.
48  */
49 void
matho_clear(void)50 matho_clear(void)
51 {
52 	clear_all();
53 }
54 
55 /** 3
56  * matho_process - Process Mathomatic command or expression input
57  * Process a Mathomatic command or enter an expression into an equation space.
58  * The command or expression ASCII string is given as "input",
59  * the resulting output string is stored in "*outputp".
60  *
61  * matho_init(3) must have been called only one time before this
62  * to initialize the Mathomatic symbolic math engine.
63  * Use matho_clear(3) as many times as you want to restart Mathomatic
64  * for the next group of operations.
65  *
66  * This function works just like typing something into the Mathomatic prompt.
67  * To only parse any expression or equation and store it, use matho-parse(3).
68  *
69  * If this returns true (non-zero), the command or input was successful,
70  * and the resulting expression output string is stored in "*outputp".
71  * That is a malloc()ed text string which must be free()d after use
72  * to return the memory used by the string.
73  * The equation number of the equation space that the output expression
74  * is additionally stored in (if any) is available in the global "result_en",
75  * otherwise result_en = -1.
76  *
77  * If this returns false, the command or input failed and a text error
78  * message is always stored in "*outputp".
79  * The error message is a constant string and should NOT be free()d.
80  *
81  * Some commands, like the set command, will return no output when successful,
82  * setting "*outputp" to NULL.
83  *
84  * The resulting output string can safely be ignored by calling
85  * this function with "outputp" set to NULL.
86  */
87 int
matho_process(char * input,char ** outputp)88 matho_process(char *input, char **outputp)
89 {
90 	int	i;
91 	int	rv;
92 
93 	if (outputp)
94 		*outputp = NULL;
95 	result_str = NULL;
96 	result_en = -1;
97 	error_str = NULL;
98 	warning_str = NULL;
99 	if (input == NULL)
100 		return false;
101 	input = strdup(input);
102 	if ((i = setjmp(jmp_save)) != 0) {
103 		clean_up();	/* Mathomatic processing was interrupted, so do a clean up. */
104 		if (i == 14) {
105 			error(_("Expression too large."));
106 		}
107 		if (outputp) {
108 			if (error_str) {
109 				*outputp = (char *) error_str;
110 			} else {
111 				*outputp = _("Processing was interrupted.");
112 			}
113 		}
114 		free_result_str();
115 		free(input);
116 		previous_return_value = 0;
117 		return false;
118 	}
119 	set_error_level(input);
120 	rv = process(input);
121 	if (rv) {
122 		if (outputp) {
123 			*outputp = result_str;
124 		} else {
125 			if (result_str) {
126 				free(result_str);
127 				result_str = NULL;
128 			}
129 		}
130 	} else {
131 		if (outputp) {
132 			if (error_str) {
133 				*outputp = (char *) error_str;
134 			} else {
135 				*outputp = _("Unknown error.");
136 			}
137 		}
138 		free_result_str();
139 	}
140 	free(input);
141 	return rv;
142 }
143 
144 /** 3
145  * matho_parse - Process Mathomatic expression or equation input
146  * Parse a mathematical equation or expression and store in the next available equation space,
147  * making it the current equation.
148  * Afterwards, it can be operated on by Mathomatic commands using matho_process(3).
149  *
150  * matho_init(3) must have been called only one time before this
151  * to initialize the Mathomatic symbolic math engine.
152  * Use matho_clear(3) as many times as you want to restart Mathomatic
153  * for the next group of operations.
154  *
155  * The input and output ASCII strings are expressions, if successful.
156  * The expression or equation string to enter is in "input",
157  * the resulting output string is stored in "*outputp".
158  * The equation number of the equation space that the output expression
159  * is additionally stored in (if any) is available in the global "result_en",
160  * otherwise result_en = -1.
161  *
162  * Works the same as matho_process(3), except commands are not allowed,
163  * so that variables are not ever confused with commands.
164  * In fact, this function is currently set to only allow
165  * entry and storage of expressions and equations.
166  *
167  * Returns true (non-zero) if successful.
168  */
169 int
matho_parse(char * input,char ** outputp)170 matho_parse(char *input, char **outputp)
171 {
172 	int	i;
173 	int	rv;
174 
175 	if (outputp)
176 		*outputp = NULL;
177 	result_str = NULL;
178 	result_en = -1;
179 	error_str = NULL;
180 	warning_str = NULL;
181 	if (input == NULL)
182 		return false;
183 	input = strdup(input);
184 	if ((i = setjmp(jmp_save)) != 0) {
185 		clean_up();	/* Mathomatic processing was interrupted, so do a clean up. */
186 		if (i == 14) {
187 			error(_("Expression too large."));
188 		}
189 		if (outputp) {
190 			if (error_str) {
191 				*outputp = (char *) error_str;
192 			} else {
193 				*outputp = _("Processing was interrupted.");
194 			}
195 		}
196 		free_result_str();
197 		free(input);
198 		return false;
199 	}
200 	set_error_level(input);
201 	i = next_espace();
202 #if	1	/* Leave this as 1 if you want to be able to enter single variable or constant expressions with no solving or selecting. */
203 	rv = parse(i, input);	/* All set auto options ignored. */
204 #else
205 	rv = process_parse(i, input);	/* All set auto options respected. */
206 #endif
207 	if (rv) {
208 		if (outputp) {
209 			*outputp = result_str;
210 		} else {
211 			if (result_str) {
212 				free(result_str);
213 				result_str = NULL;
214 			}
215 		}
216 	} else {
217 		if (outputp) {
218 			if (error_str) {
219 				*outputp = (char *) error_str;
220 			} else {
221 				*outputp = _("Unknown error.");
222 			}
223 		}
224 		free_result_str();
225 	}
226 	free(input);
227 	return rv;
228 }
229 
230 /*
231  * Floating point exception handler.
232  * Usually doesn't work in most operating systems, so just ignore it.
233  */
234 void
fphandler(int sig)235 fphandler(int sig)
236 {
237 /*	error(_("Floating point exception.")); */
238 }
239