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