mathematical 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -9
  3. data/Rakefile +5 -24
  4. data/ext/mathematical/extconf.rb +8 -3
  5. data/ext/mathematical/lasem/src/lsmdomparser.c +7 -7
  6. data/ext/mathematical/lasem/src/lsmdomparser.h +2 -2
  7. data/ext/mathematical/lasem/src/lsmitex.c +8 -5
  8. data/ext/mathematical/lasem/src/lsmitex.h +1 -1
  9. data/ext/mathematical/lasem/src/lsmmathmldocument.c +2 -2
  10. data/ext/mathematical/lasem/src/lsmmathmldocument.h +1 -1
  11. data/ext/mathematical/lasem/tests/lsmtest.c +2 -2
  12. data/ext/mathematical/mathematical.c +119 -10
  13. data/ext/mathematical/mtex2MML/ext/extconf.rb +4 -0
  14. data/ext/mathematical/mtex2MML/src/lex.yy.c +6791 -0
  15. data/ext/mathematical/mtex2MML/src/mtex2MML.h +59 -0
  16. data/ext/mathematical/mtex2MML/src/parse_extras.c +306 -0
  17. data/ext/mathematical/mtex2MML/src/parse_extras.h +78 -0
  18. data/ext/mathematical/mtex2MML/src/stack.c +80 -0
  19. data/ext/mathematical/mtex2MML/src/stack.h +101 -0
  20. data/ext/mathematical/mtex2MML/src/string_extras.c +211 -0
  21. data/ext/mathematical/mtex2MML/src/string_extras.h +46 -0
  22. data/ext/mathematical/mtex2MML/src/y.tab.c +7090 -0
  23. data/ext/mathematical/mtex2MML/src/y.tab.h +393 -0
  24. data/lib/mathematical.rb +1 -0
  25. data/lib/mathematical/corrections.rb +34 -0
  26. data/lib/mathematical/render.rb +21 -12
  27. data/lib/mathematical/version.rb +1 -1
  28. data/mathematical.gemspec +2 -2
  29. data/test/mathematical/corrections_test.rb +56 -0
  30. data/test/mathematical/fixtures/png/pmatrix.png +0 -0
  31. data/test/mathematical/fixtures_test.rb +11 -1
  32. data/test/mathematical/maliciousness_test.rb +10 -2
  33. data/test/mathematical/mathml_test.rb +22 -0
  34. data/test/mathematical/png_test.rb +26 -0
  35. data/test/test_helper.rb +13 -0
  36. metadata +150 -134
  37. data/ext/mathematical/itexToMML/itex2MML.h +0 -63
  38. data/ext/mathematical/itexToMML/lex.yy.c +0 -6548
  39. data/ext/mathematical/itexToMML/y.tab.c +0 -6179
  40. data/ext/mathematical/itexToMML/y.tab.h +0 -389
@@ -0,0 +1,59 @@
1
+ #ifndef MTEX2MML_H
2
+ #define MTEX2MML_H
3
+
4
+ #define MTEX2MML_VERSION "1.0.0"
5
+
6
+ #ifdef __cplusplus
7
+ extern "C" {
8
+ #endif
9
+
10
+ /* Step 1. Parse a buffer with mtex source; return value is mathml, or 0 on failure (e.g., parse error).
11
+ */
12
+ extern char * mtex2MML_parse (const char * buffer, unsigned long length);
13
+
14
+ /* Step 2. Free the string from Step 1.
15
+ */
16
+ extern void mtex2MML_free_string (char * str);
17
+
18
+
19
+ /* Alternatively, to filter generic source and converting embedded equations, use:
20
+ */
21
+ extern int mtex2MML_filter (const char * buffer, unsigned long length);
22
+
23
+ extern int mtex2MML_html_filter (const char * buffer, unsigned long length);
24
+ extern int mtex2MML_strict_html_filter (const char * buffer, unsigned long length);
25
+
26
+
27
+ /* To change output methods:
28
+ *
29
+ * Note: If length is 0, then buffer is treated like a string; otherwise only length bytes are written.
30
+ */
31
+ extern void (*mtex2MML_write) (const char * buffer, unsigned long length); /* default writes to stdout */
32
+ extern void (*mtex2MML_write_mathml) (const char * mathml); /* default calls mtex2MML_write(mathml,0) */
33
+ extern void (*mtex2MML_error) (const char * msg); /* default writes to stderr */
34
+
35
+
36
+ /* Other stuff:
37
+ */
38
+ extern void mtex2MML_setup (const char * buffer, unsigned long length);
39
+
40
+ extern void mtex2MML_restart ();
41
+
42
+ extern char * mtex2MML_copy_string (const char * str);
43
+ extern char * mtex2MML_copy_string_extra (const char * str, unsigned extra);
44
+ extern char * mtex2MML_copy2 (const char * first, const char * second);
45
+ extern char * mtex2MML_copy3 (const char * first, const char * second, const char * third);
46
+ extern char * mtex2MML_copy_escaped (const char * str);
47
+
48
+ extern char * mtex2MML_empty_string;
49
+
50
+ extern int mtex2MML_lineno;
51
+
52
+ extern int mtex2MML_rowposn;
53
+ extern int mtex2MML_displaymode;
54
+
55
+ #ifdef __cplusplus
56
+ }
57
+ #endif
58
+
59
+ #endif /* ! MTEX2MML_H */
@@ -0,0 +1,306 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include "parse_extras.h"
5
+ #include "string_extras.h"
6
+ #include "stack.h"
7
+
8
+ #ifdef FLIP_OFFSET_VAL
9
+ #define OFFSET_VAL 0
10
+ #else
11
+ #define OFFSET_VAL 1
12
+ #endif
13
+
14
+ void initSymbolDataArray(symbolDataArray *a, size_t initialSize)
15
+ {
16
+ // Allocate initial space
17
+ a->array = (symbolData *)malloc(initialSize * sizeof(symbolData));
18
+
19
+ a->used = 0; // no elements used
20
+ a->size = initialSize; // available number of elements
21
+
22
+ // Initialize all elements of the array at once: they are contiguous
23
+ memset(&a->array[0], 0, sizeof(symbolData) * initialSize);
24
+ }
25
+
26
+ void insertSymbolDataArray(symbolDataArray *a, symbolData element)
27
+ {
28
+ if (a->used == a->size) {
29
+ a->size *= 2;
30
+ a->array = (symbolData *)realloc(a->array, a->size * sizeof(symbolData));
31
+ // Initialize the last/new elements of the reallocated array
32
+ memset(&a->array[a->used],0, sizeof(symbolData) * (a->size - a->used));
33
+ }
34
+
35
+ a->array[a->used].attribute = (char*)malloc(strlen(element.attribute) + 1);
36
+ strcpy(a->array[a->used].attribute, element.attribute);
37
+
38
+ a->array[a->used].offset_pos = element.offset_pos;
39
+
40
+ a->used++;
41
+ }
42
+
43
+ void sortSymbolDataArray(symbolDataArray *a) {
44
+ int i, j, n = a->used;
45
+
46
+ for(i = 1; i < n; i++) {
47
+ for(j = 0; j < n - i; j++) {
48
+ if(a->array[j].offset_pos < a->array[j+1].offset_pos) {
49
+ symbolData temp = a->array[j];
50
+ a->array[j] = a->array[j+1];
51
+ a->array[j+1] = temp;
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ void deleteSymbolDataArray(symbolDataArray *a)
58
+ {
59
+ int i;
60
+
61
+ // Free all name variables of each array element first
62
+ for(i = 0; i <a->used; i++)
63
+ {
64
+ free(a->array[i].attribute);
65
+ a->array[i].attribute = NULL;
66
+ }
67
+
68
+ // Now free the array
69
+ free(a->array);
70
+ a->array = NULL;
71
+
72
+ a->used = 0;
73
+ a->size = 0;
74
+ }
75
+
76
+ char * env_replacements(const char *string) {
77
+ stackT array_stack;
78
+ stackElementT stack_item, last_stack_item;
79
+
80
+ char *tok = NULL, *at_top = NULL;
81
+ char *new_environment = dupe_string(string), *dupe_str = dupe_string(string);
82
+ char *line = strtok(dupe_str, "\n");
83
+ char *attr_rowlines = "", *attr_rowspacing = "", *em_str, *temp = "";
84
+
85
+ const char *from = "\\begin", *until = "\\end", *hline = "\\hline", *hdashline = "\\hdashline",
86
+ *line_separator = "\\\\",
87
+ *em_pattern_begin = "\\[", *em_pattern_end = "]";
88
+
89
+ int start = 0, offset = 0, attr_rowlines_len = 0, str_len = 0, i = 0;
90
+ symbolDataArray hline_data_array;
91
+ symbolData hline_data;
92
+
93
+ symbolDataArray row_spacing_data_array;
94
+ symbolData row_spacing_data;
95
+
96
+ // set up the array stack
97
+ StackInit(&array_stack, strlen(new_environment));
98
+ initSymbolDataArray(&hline_data_array, 5);
99
+ initSymbolDataArray(&row_spacing_data_array, 1);
100
+
101
+ // if not an environment, don't bother going on
102
+ if ((strstr(string, from) == NULL && strstr(string, until) == NULL)) {
103
+ StackDestroy(&array_stack);
104
+ deleteSymbolDataArray(&hline_data_array);
105
+ deleteSymbolDataArray(&row_spacing_data_array);
106
+ free(dupe_str);
107
+
108
+ return string;
109
+ }
110
+
111
+ while (line != NULL) {
112
+ str_len = strlen(line) + 1;
113
+
114
+ stack_item.line = line;
115
+ stack_item.line_pos = start + 1;
116
+
117
+ start += str_len;
118
+
119
+ StackPush(&array_stack, stack_item);
120
+
121
+ if (strstr(line, until) != NULL) {
122
+ while (!StackIsEmpty(&array_stack)) {
123
+ last_stack_item = StackPop(&array_stack);
124
+ attr_rowlines_len = strlen(attr_rowlines);
125
+ at_top = strstr(last_stack_item.line, from);
126
+
127
+ // we've reached the top, but there looks like there might be some data
128
+ if (at_top != NULL && strstr(last_stack_item.line, line_separator) == NULL) {
129
+ break;
130
+ }
131
+
132
+ // looking for a line match
133
+ if (strstr(last_stack_item.line, hline) != NULL) {
134
+ if (attr_rowlines_len > 0)
135
+ remove_last_char(attr_rowlines);
136
+ attr_rowlines = join(attr_rowlines, "s");
137
+ }
138
+ else if (strstr(last_stack_item.line, hdashline) != NULL) {
139
+ if (attr_rowlines_len > 0)
140
+ remove_last_char(attr_rowlines);
141
+ attr_rowlines = join(attr_rowlines, "d");
142
+ }
143
+ else {
144
+ attr_rowlines = join(attr_rowlines, "0");
145
+ }
146
+
147
+ if (strstr(last_stack_item.line, line_separator) != NULL) {
148
+ if ( (tok = strstr(last_stack_item.line, em_pattern_begin)) != NULL) {
149
+ temp = tok + 2;
150
+ if ( (tok = strstr(temp, em_pattern_end)) != NULL) {
151
+ offset = (int)(tok - temp);
152
+ em_str = malloc(offset);
153
+ if (strlen(em_str) != 0) {
154
+ em_str = dupe_string_n(temp, offset);
155
+ // MathML always expectes "em" points
156
+ convertToEm(em_str);
157
+ row_spacing_data.attribute = em_str;
158
+ row_spacing_data.offset_pos = -1; // this value is not really important
159
+ insertSymbolDataArray(&row_spacing_data_array, row_spacing_data);
160
+ free(em_str);
161
+ }
162
+ }
163
+ }
164
+ else {
165
+ row_spacing_data.attribute = "0em";
166
+ row_spacing_data.offset_pos = -1; // this value is not really important
167
+ insertSymbolDataArray(&row_spacing_data_array, row_spacing_data);
168
+ }
169
+ }
170
+
171
+ // we've reached the top, so stop.
172
+ if (at_top != NULL)
173
+ break;
174
+ }
175
+
176
+ if (attr_rowlines_len != 0) {
177
+ // array is form of \begin{array}[t]{cc..c}
178
+ tok = strstr(last_stack_item.line, "]{");
179
+ if (tok == NULL) {
180
+ // array is form of \begin{array}{cc..c}
181
+ tok = strstr(last_stack_item.line, "}{");
182
+ }
183
+ if (tok == NULL) {
184
+ // not an array, but rather, some env, like \begin{cases}
185
+ tok = strstr(last_stack_item.line, "}");
186
+ }
187
+
188
+ offset = last_stack_item.line_pos + (tok - last_stack_item.line);
189
+ // we cut the last char because we can skip the first row
190
+ remove_last_char(attr_rowlines);
191
+
192
+ // we reverse the string, because we're going backwards
193
+ strrev(attr_rowlines);
194
+
195
+ // empty rowlines should be reset
196
+ if (strlen(attr_rowlines) == 0)
197
+ attr_rowlines = join(attr_rowlines, "0");
198
+
199
+ attr_rowlines = join(join("(", attr_rowlines), ")");
200
+
201
+ for (i = row_spacing_data_array.used - 1; i >= 0; i--) {
202
+ attr_rowspacing = join(join(attr_rowspacing, row_spacing_data_array.array[i].attribute), "|");
203
+ }
204
+
205
+ if (strlen(attr_rowspacing) > 0) {
206
+ if (empty_row_spacings(attr_rowspacing) == 1) {
207
+ attr_rowspacing = "0.5ex";
208
+ }
209
+ else {
210
+ // last char is a pipe (|)
211
+ remove_last_char(attr_rowspacing);
212
+ }
213
+
214
+ attr_rowspacing = join(join("<", attr_rowspacing), ">");
215
+ }
216
+
217
+ hline_data.attribute = join(attr_rowspacing, attr_rowlines);
218
+ hline_data.offset_pos = offset + OFFSET_VAL;
219
+ insertSymbolDataArray(&hline_data_array, hline_data);
220
+ }
221
+
222
+ attr_rowlines = "";
223
+ attr_rowspacing = "";
224
+ attr_rowlines_len = 0;
225
+ }
226
+
227
+ line = strtok(NULL, "\n");
228
+ }
229
+
230
+ // sort array by highest values first, so that we can insert to new_environment from
231
+ // the bottom to the top (ensuring line numbers don't shift)
232
+ sortSymbolDataArray(&hline_data_array);
233
+
234
+ for (i = 0; i < hline_data_array.used; i++) {
235
+ insert_substring(&new_environment, hline_data_array.array[i].attribute, hline_data_array.array[i].offset_pos);
236
+ }
237
+
238
+ StackDestroy(&array_stack);
239
+ deleteSymbolDataArray(&hline_data_array);
240
+ deleteSymbolDataArray(&row_spacing_data_array);
241
+ free(dupe_str);
242
+
243
+ return new_environment;
244
+ }
245
+
246
+ const char *vertical_pipe_extract(const char *string) {
247
+ char *orig = dupe_string(string);
248
+ char *columnlines = "", *previous_column = "";
249
+ int i = 0;
250
+
251
+ if (strncmp(orig, "s", 1) == 0) {
252
+ columnlines = "frame=\"solid\" columnlines=\"";
253
+ remove_first_char(orig);
254
+ }
255
+ else if (strncmp(orig, "d", 1) == 0) {
256
+ columnlines = "frame=\"dashed\" columnlines=\"";
257
+ remove_first_char(orig);
258
+ }
259
+ else {
260
+ columnlines = "columnlines=\"";
261
+ }
262
+
263
+ char *token = strtok(orig, " ");
264
+
265
+ while (token != NULL) {
266
+ if (strncmp(token, "s", 1) == 0) {
267
+ previous_column = "s";
268
+ columnlines = join(columnlines, "solid ");
269
+ }
270
+ else if (strncmp(token, "d", 1) == 0) {
271
+ previous_column = "d";
272
+ columnlines = join(columnlines, "dashed ");
273
+ }
274
+ else {
275
+ if (i >= 1) { // we must skip the first blank col
276
+ // only if there is no previous border should a border be considered, eg. "cc", not "c|c"
277
+ if (strncmp(previous_column, "s", 1) != 0 && strncmp(previous_column, "d", 1) != 0) {
278
+ columnlines = join(columnlines, "none ");
279
+ }
280
+ previous_column = "0";
281
+ }
282
+ }
283
+
284
+ i++;
285
+ token = strtok(NULL, " ");
286
+ }
287
+
288
+ // an empty string here angers Lasem
289
+ if (strncmp(columnlines, "columnlines=\"\0", 14) == 0)
290
+ columnlines = "columnlines=\"none";
291
+ // an empty space also angers Lasem
292
+ else
293
+ remove_last_char(columnlines);
294
+
295
+ free(orig);
296
+ return columnlines;
297
+ }
298
+
299
+ const char *remove_excess_pipe_chars(const char *string) {
300
+ char *dup = dupe_string(string);
301
+
302
+ dup = replace_str(dup, "s", "");
303
+ dup = replace_str(dup, "d", "");
304
+
305
+ return dup;
306
+ }
@@ -0,0 +1,78 @@
1
+ #ifndef PARSE_EXTRAS_H
2
+ #define PARSE_EXTRAS_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ typedef struct {
9
+ char *attribute;
10
+ int offset_pos;
11
+ } symbolData;
12
+
13
+ // array of structs
14
+ typedef struct
15
+ {
16
+ symbolData *array;
17
+ size_t used;
18
+ size_t size;
19
+ } symbolDataArray;
20
+
21
+ // set up array of symbols (like hlines)
22
+ extern void initSymbolDataArray(symbolDataArray *a, size_t initialSize);
23
+
24
+ // insert into symbol array
25
+ extern void insertSymbolDataArray(symbolDataArray *a, symbolData element);
26
+
27
+ // sort the array based on offset_pos
28
+ extern void sortSymbolDataArray(symbolDataArray *a);
29
+
30
+ // destroyes the array
31
+ extern void deleteSymbolDataArray(symbolDataArray *a);
32
+
33
+ // Move various symbols not easily supported inline with the `\begin` line
34
+ // This is so that the Bison parser can properly act on these. For example,
35
+ // `\hline`, `\hlinedash`, or `\\[2ex]` declerations.
36
+ //
37
+ // In order to properly address these situations, we need to parse them, find their symbols,
38
+ // and then modify the starting environment declaration to point out where those symbols are.
39
+ //
40
+ // Suppose there is an array like:
41
+ //
42
+ // \begin{array}{c:c}
43
+ // \begin{array}{c|cclc}
44
+ // \text{min} & 0 & 1 & 2 & 3\\\\
45
+ // \hline
46
+ // 0 & 0 & 0 & 0 & 0\\\\
47
+ // 1 & 0 & 1 & 1 & 1\\\\
48
+ // 2 & 0 & 1 & 2 & 2\\\\
49
+ // 3 & 0 & 1 & 2 & 3
50
+ // \end{array}
51
+ // &
52
+ // \begin{array}{c|cccl}
53
+ // \text{max}&0&1&2&3\\\\
54
+ // \hline
55
+ // 0 & 0 & 1 & 2 & 3\\\\
56
+ // 1 & 1 & 1 & 2 & 3\\\\
57
+ // 2 & 2 & 2 & 2 & 3\\\\
58
+ // 3 & 3 & 3 & 3 & 3
59
+ // \end{array}
60
+ // \end{array}
61
+ //
62
+ // The env_replacements function will push every line onto a stack. When an \end
63
+ // is detected, it starts popping off the stack until it reaches the corresponding
64
+ // \begin. It then modifies that line with attribute strings, an arrangement of the
65
+ // the symbols encountered while popping lines off.
66
+ extern char * env_replacements(const char *string);
67
+
68
+ // determines the column border arrangement from the array environment definition
69
+ extern const char *vertical_pipe_extract(const char *string);
70
+
71
+ // removes placeholder pipe characters from columnalign
72
+ extern const char *remove_excess_pipe_chars(const char *string);
73
+
74
+ #ifdef __cplusplus
75
+ }
76
+ #endif
77
+
78
+ #endif /* ! PARSE_EXTRAS_H */
@@ -0,0 +1,80 @@
1
+ /*
2
+ * File: stack.c
3
+ * Author: Robert I. Pitts <rip@cs.bu.edu>
4
+ * Last Modified: March 7, 2000
5
+ * Topic: Stack - Array Implementation
6
+ * ----------------------------------------------------------------
7
+ *
8
+ * This is an array implementation of a character stack.
9
+ */
10
+
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include "stack.h"
14
+
15
+ /************************ Function Definitions **********************/
16
+
17
+ void StackInit(stackT *stackP, int maxSize)
18
+ {
19
+ stackElementT *newContents;
20
+
21
+ /* Allocate a new array to hold the contents. */
22
+
23
+ newContents = (stackElementT *)malloc(sizeof(stackElementT) * maxSize);
24
+
25
+ if (newContents == NULL) {
26
+ fprintf(stderr, "Insufficient memory to initialize stack.\n");
27
+ exit(1); /* Exit, returning error code. */
28
+ }
29
+
30
+ stackP->contents = newContents;
31
+ stackP->maxSize = maxSize;
32
+ stackP->top = -1; /* I.e., empty */
33
+ }
34
+
35
+ void StackDestroy(stackT *stackP)
36
+ {
37
+ /* Get rid of array. */
38
+ free(stackP->contents);
39
+
40
+ stackP->contents = NULL;
41
+ stackP->maxSize = 0;
42
+ stackP->top = -1; /* I.e., empty */
43
+ }
44
+
45
+ void StackPush(stackT *stackP, stackElementT element)
46
+ {
47
+ if (StackIsFull(stackP)) {
48
+ fprintf(stderr, "Can't push element on stack: stack is full.\n");
49
+ exit(1); /* Exit, returning error code. */
50
+ }
51
+
52
+ /* Put information in array; update top. */
53
+
54
+ stackP->contents[++stackP->top] = element;
55
+ }
56
+
57
+ stackElementT StackPop(stackT *stackP)
58
+ {
59
+ if (StackIsEmpty(stackP)) {
60
+ fprintf(stderr, "Can't pop element from stack: stack is empty.\n");
61
+ exit(1); /* Exit, returning error code. */
62
+ }
63
+
64
+ return stackP->contents[stackP->top--];
65
+ }
66
+
67
+ int StackIsEmpty(stackT *stackP)
68
+ {
69
+ return stackP->top < 0;
70
+ }
71
+
72
+ int StackIsFull(stackT *stackP)
73
+ {
74
+ return stackP->top >= stackP->maxSize - 1;
75
+ }
76
+
77
+ stackElementT StackTop(stackT *stackP)
78
+ {
79
+ return stackP->contents[stackP->top];
80
+ }