mathematical 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/Rakefile +4 -0
  4. data/ext/mathematical/extconf.rb +9 -15
  5. data/ext/mathematical/mtex2MML/build/mtex2MML.h +73 -0
  6. data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/utarray.h +0 -0
  7. data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/uthash.h +0 -0
  8. data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/utlist.h +0 -0
  9. data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/utstring.h +0 -0
  10. data/ext/mathematical/mtex2MML/src/color_definitions.c +1 -1
  11. data/ext/mathematical/mtex2MML/src/lex.yy.c +1100 -1098
  12. data/ext/mathematical/mtex2MML/src/main.c +137 -0
  13. data/ext/mathematical/mtex2MML/src/mtex2MML.h +11 -1
  14. data/ext/mathematical/mtex2MML/src/parse_extras.c +2 -2
  15. data/ext/mathematical/mtex2MML/src/parse_extras.h +36 -36
  16. data/ext/mathematical/mtex2MML/src/string_extras.c +0 -6
  17. data/ext/mathematical/mtex2MML/src/string_extras.h +1 -1
  18. data/ext/mathematical/mtex2MML/src/y.tab.c +3904 -3583
  19. data/ext/mathematical/mtex2MML/tests/array.c +127 -0
  20. data/ext/mathematical/mtex2MML/tests/basic.c +85 -0
  21. data/ext/mathematical/mtex2MML/tests/clar.c +642 -0
  22. data/ext/mathematical/mtex2MML/tests/clar.h +163 -0
  23. data/ext/mathematical/mtex2MML/tests/clar/fixtures.h +38 -0
  24. data/ext/mathematical/mtex2MML/tests/clar/fs.h +333 -0
  25. data/ext/mathematical/mtex2MML/tests/clar/print.h +66 -0
  26. data/ext/mathematical/mtex2MML/tests/clar/sandbox.h +139 -0
  27. data/ext/mathematical/mtex2MML/tests/clar_test.h +20 -0
  28. data/ext/mathematical/mtex2MML/tests/cornercases.c +45 -0
  29. data/ext/mathematical/mtex2MML/tests/deps/file2str/file2str.c +64 -0
  30. data/ext/mathematical/mtex2MML/tests/deps/file2str/file2str.h +12 -0
  31. data/ext/mathematical/mtex2MML/tests/deps/trim/trim.c +24 -0
  32. data/ext/mathematical/mtex2MML/tests/deps/trim/trim.h +7 -0
  33. data/ext/mathematical/mtex2MML/tests/env.c +333 -0
  34. data/ext/mathematical/mtex2MML/tests/functions.c +45 -0
  35. data/ext/mathematical/mtex2MML/tests/helpers.c +27 -0
  36. data/ext/mathematical/mtex2MML/tests/helpers.h +8 -0
  37. data/ext/mathematical/mtex2MML/tests/main.c +35 -0
  38. data/ext/mathematical/mtex2MML/tests/maliciousness.c +82 -0
  39. data/ext/mathematical/mtex2MML/tests/mathjax.c +2030 -0
  40. data/ext/mathematical/mtex2MML/tests/numbered_equations.c +47 -0
  41. data/lib/mathematical.rb +3 -48
  42. data/lib/mathematical/validator.rb +52 -0
  43. data/lib/mathematical/version.rb +1 -1
  44. data/test/mathematical/basic_test.rb +7 -0
  45. data/test/mathematical/maliciousness_test.rb +26 -1
  46. data/test/mathematical/mathjax_test.rb +2 -2
  47. metadata +31 -7
  48. data/ext/mathematical/mtex2MML/ext/extconf.rb +0 -4
@@ -0,0 +1,163 @@
1
+ /*
2
+ * Copyright (c) Vicent Marti. All rights reserved.
3
+ *
4
+ * This file is part of clar, distributed under the ISC license.
5
+ * For full terms see the included COPYING file.
6
+ */
7
+ #ifndef __CLAR_TEST_H__
8
+ #define __CLAR_TEST_H__
9
+
10
+ #include <stdlib.h>
11
+
12
+ extern int global_test_counter;
13
+
14
+ enum cl_test_status {
15
+ CL_TEST_OK,
16
+ CL_TEST_FAILURE,
17
+ CL_TEST_SKIP
18
+ };
19
+
20
+ void clar_test_init(int argc, char *argv[]);
21
+ int clar_test_run(void);
22
+ void clar_test_shutdown(void);
23
+
24
+ int clar_test(int argc, char *argv[]);
25
+
26
+ const char *clar_sandbox_path(void);
27
+
28
+ void cl_set_cleanup(void (*cleanup)(void *), void *opaque);
29
+ void cl_fs_cleanup(void);
30
+
31
+ /**
32
+ * cl_trace_* is a hook to provide a simple global tracing
33
+ * mechanism.
34
+ *
35
+ * The goal here is to let main() provide clar-proper
36
+ * with a callback to optionally write log info for
37
+ * test operations into the same stream used by their
38
+ * actual tests. This would let them print test names
39
+ * and maybe performance data as they choose.
40
+ *
41
+ * The goal is NOT to alter the flow of control or to
42
+ * override test selection/skipping. (So the callback
43
+ * does not return a value.)
44
+ *
45
+ * The goal is NOT to duplicate the existing
46
+ * pass/fail/skip reporting. (So the callback
47
+ * does not accept a status/errorcode argument.)
48
+ *
49
+ */
50
+ typedef enum cl_trace_event {
51
+ CL_TRACE__SUITE_BEGIN,
52
+ CL_TRACE__SUITE_END,
53
+ CL_TRACE__TEST__BEGIN,
54
+ CL_TRACE__TEST__END,
55
+ CL_TRACE__TEST__RUN_BEGIN,
56
+ CL_TRACE__TEST__RUN_END,
57
+ CL_TRACE__TEST__LONGJMP,
58
+ } cl_trace_event;
59
+
60
+ typedef void (cl_trace_cb)(
61
+ cl_trace_event ev,
62
+ const char *suite_name,
63
+ const char *test_name,
64
+ void *payload);
65
+
66
+ /**
67
+ * Register a callback into CLAR to send global trace events.
68
+ * Pass NULL to disable.
69
+ */
70
+ void cl_trace_register(cl_trace_cb *cb, void *payload);
71
+
72
+
73
+ #ifdef CLAR_FIXTURE_PATH
74
+ const char *cl_fixture(const char *fixture_name);
75
+ void cl_fixture_sandbox(const char *fixture_name);
76
+ void cl_fixture_cleanup(const char *fixture_name);
77
+ #endif
78
+
79
+ /**
80
+ * Assertion macros with explicit error message
81
+ */
82
+ #define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 1)
83
+ #define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 1)
84
+ #define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 1)
85
+
86
+ /**
87
+ * Check macros with explicit error message
88
+ */
89
+ #define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 0)
90
+ #define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 0)
91
+ #define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 0)
92
+
93
+ /**
94
+ * Assertion macros with no error message
95
+ */
96
+ #define cl_must_pass(expr) cl_must_pass_(expr, NULL)
97
+ #define cl_must_fail(expr) cl_must_fail_(expr, NULL)
98
+ #define cl_assert(expr) cl_assert_(expr, NULL)
99
+
100
+ /**
101
+ * Check macros with no error message
102
+ */
103
+ #define cl_check_pass(expr) cl_check_pass_(expr, NULL)
104
+ #define cl_check_fail(expr) cl_check_fail_(expr, NULL)
105
+ #define cl_check(expr) cl_check_(expr, NULL)
106
+
107
+ /**
108
+ * Forced failure/warning
109
+ */
110
+ #define cl_fail(desc) clar__fail(__FILE__, __LINE__, "Test failed.", desc, 1)
111
+ #define cl_warning(desc) clar__fail(__FILE__, __LINE__, "Warning during test execution:", desc, 0)
112
+
113
+ #define cl_skip() clar__skip()
114
+
115
+ /**
116
+ * Typed assertion macros
117
+ */
118
+ #define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2))
119
+ #define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2))
120
+
121
+ #define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2))
122
+ #define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2))
123
+
124
+ #define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len))
125
+ #define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len))
126
+
127
+ #define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
128
+ #define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
129
+
130
+ #define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
131
+ #define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
132
+ #define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
133
+
134
+ #define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
135
+
136
+ #define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2))
137
+
138
+ void clar__skip(void);
139
+
140
+ void clar__fail(
141
+ const char *file,
142
+ int line,
143
+ const char *error,
144
+ const char *description,
145
+ int should_abort);
146
+
147
+ void clar__assert(
148
+ int condition,
149
+ const char *file,
150
+ int line,
151
+ const char *error,
152
+ const char *description,
153
+ int should_abort);
154
+
155
+ void clar__assert_equal(
156
+ const char *file,
157
+ int line,
158
+ const char *err,
159
+ int should_abort,
160
+ const char *fmt,
161
+ ...);
162
+
163
+ #endif
@@ -0,0 +1,38 @@
1
+ static const char *
2
+ fixture_path(const char *base, const char *fixture_name)
3
+ {
4
+ static char _path[4096];
5
+ size_t root_len;
6
+
7
+ root_len = strlen(base);
8
+ strncpy(_path, base, sizeof(_path));
9
+
10
+ if (_path[root_len - 1] != '/')
11
+ _path[root_len++] = '/';
12
+
13
+ if (fixture_name[0] == '/')
14
+ fixture_name++;
15
+
16
+ strncpy(_path + root_len,
17
+ fixture_name,
18
+ sizeof(_path) - root_len);
19
+
20
+ return _path;
21
+ }
22
+
23
+ #ifdef CLAR_FIXTURE_PATH
24
+ const char *cl_fixture(const char *fixture_name)
25
+ {
26
+ return fixture_path(CLAR_FIXTURE_PATH, fixture_name);
27
+ }
28
+
29
+ void cl_fixture_sandbox(const char *fixture_name)
30
+ {
31
+ fs_copy(cl_fixture(fixture_name), _clar_path);
32
+ }
33
+
34
+ void cl_fixture_cleanup(const char *fixture_name)
35
+ {
36
+ fs_rm(fixture_path(_clar_path, fixture_name));
37
+ }
38
+ #endif
@@ -0,0 +1,333 @@
1
+ #ifdef _WIN32
2
+
3
+ #define RM_RETRY_COUNT 5
4
+ #define RM_RETRY_DELAY 10
5
+
6
+ #ifdef __MINGW32__
7
+
8
+ /* These security-enhanced functions are not available
9
+ * in MinGW, so just use the vanilla ones */
10
+ #define wcscpy_s(a, b, c) wcscpy((a), (c))
11
+ #define wcscat_s(a, b, c) wcscat((a), (c))
12
+
13
+ #endif /* __MINGW32__ */
14
+
15
+ static int
16
+ fs__dotordotdot(WCHAR *_tocheck)
17
+ {
18
+ return _tocheck[0] == '.' &&
19
+ (_tocheck[1] == '\0' ||
20
+ (_tocheck[1] == '.' && _tocheck[2] == '\0'));
21
+ }
22
+
23
+ static int
24
+ fs_rmdir_rmdir(WCHAR *_wpath)
25
+ {
26
+ unsigned retries = 1;
27
+
28
+ while (!RemoveDirectoryW(_wpath)) {
29
+ /* Only retry when we have retries remaining, and the
30
+ * error was ERROR_DIR_NOT_EMPTY. */
31
+ if (retries++ > RM_RETRY_COUNT ||
32
+ ERROR_DIR_NOT_EMPTY != GetLastError())
33
+ return -1;
34
+
35
+ /* Give whatever has a handle to a child item some time
36
+ * to release it before trying again */
37
+ Sleep(RM_RETRY_DELAY * retries * retries);
38
+ }
39
+
40
+ return 0;
41
+ }
42
+
43
+ static void
44
+ fs_rmdir_helper(WCHAR *_wsource)
45
+ {
46
+ WCHAR buffer[MAX_PATH];
47
+ HANDLE find_handle;
48
+ WIN32_FIND_DATAW find_data;
49
+ size_t buffer_prefix_len;
50
+
51
+ /* Set up the buffer and capture the length */
52
+ wcscpy_s(buffer, MAX_PATH, _wsource);
53
+ wcscat_s(buffer, MAX_PATH, L"\\");
54
+ buffer_prefix_len = wcslen(buffer);
55
+
56
+ /* FindFirstFile needs a wildcard to match multiple items */
57
+ wcscat_s(buffer, MAX_PATH, L"*");
58
+ find_handle = FindFirstFileW(buffer, &find_data);
59
+ cl_assert(INVALID_HANDLE_VALUE != find_handle);
60
+
61
+ do {
62
+ /* FindFirstFile/FindNextFile gives back . and ..
63
+ * entries at the beginning */
64
+ if (fs__dotordotdot(find_data.cFileName))
65
+ continue;
66
+
67
+ wcscpy_s(buffer + buffer_prefix_len, MAX_PATH - buffer_prefix_len, find_data.cFileName);
68
+
69
+ if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
70
+ fs_rmdir_helper(buffer);
71
+ else {
72
+ /* If set, the +R bit must be cleared before deleting */
73
+ if (FILE_ATTRIBUTE_READONLY & find_data.dwFileAttributes)
74
+ cl_assert(SetFileAttributesW(buffer, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY));
75
+
76
+ cl_assert(DeleteFileW(buffer));
77
+ }
78
+ }
79
+ while (FindNextFileW(find_handle, &find_data));
80
+
81
+ /* Ensure that we successfully completed the enumeration */
82
+ cl_assert(ERROR_NO_MORE_FILES == GetLastError());
83
+
84
+ /* Close the find handle */
85
+ FindClose(find_handle);
86
+
87
+ /* Now that the directory is empty, remove it */
88
+ cl_assert(0 == fs_rmdir_rmdir(_wsource));
89
+ }
90
+
91
+ static int
92
+ fs_rm_wait(WCHAR *_wpath)
93
+ {
94
+ unsigned retries = 1;
95
+ DWORD last_error;
96
+
97
+ do {
98
+ if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(_wpath))
99
+ last_error = GetLastError();
100
+ else
101
+ last_error = ERROR_SUCCESS;
102
+
103
+ /* Is the item gone? */
104
+ if (ERROR_FILE_NOT_FOUND == last_error ||
105
+ ERROR_PATH_NOT_FOUND == last_error)
106
+ return 0;
107
+
108
+ Sleep(RM_RETRY_DELAY * retries * retries);
109
+ }
110
+ while (retries++ <= RM_RETRY_COUNT);
111
+
112
+ return -1;
113
+ }
114
+
115
+ static void
116
+ fs_rm(const char *_source)
117
+ {
118
+ WCHAR wsource[MAX_PATH];
119
+ DWORD attrs;
120
+
121
+ /* The input path is UTF-8. Convert it to wide characters
122
+ * for use with the Windows API */
123
+ cl_assert(MultiByteToWideChar(CP_UTF8,
124
+ MB_ERR_INVALID_CHARS,
125
+ _source,
126
+ -1, /* Indicates NULL termination */
127
+ wsource,
128
+ MAX_PATH));
129
+
130
+ /* Does the item exist? If not, we have no work to do */
131
+ attrs = GetFileAttributesW(wsource);
132
+
133
+ if (INVALID_FILE_ATTRIBUTES == attrs)
134
+ return;
135
+
136
+ if (FILE_ATTRIBUTE_DIRECTORY & attrs)
137
+ fs_rmdir_helper(wsource);
138
+ else {
139
+ /* The item is a file. Strip the +R bit */
140
+ if (FILE_ATTRIBUTE_READONLY & attrs)
141
+ cl_assert(SetFileAttributesW(wsource, attrs & ~FILE_ATTRIBUTE_READONLY));
142
+
143
+ cl_assert(DeleteFileW(wsource));
144
+ }
145
+
146
+ /* Wait for the DeleteFile or RemoveDirectory call to complete */
147
+ cl_assert(0 == fs_rm_wait(wsource));
148
+ }
149
+
150
+ static void
151
+ fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest)
152
+ {
153
+ WCHAR buf_source[MAX_PATH], buf_dest[MAX_PATH];
154
+ HANDLE find_handle;
155
+ WIN32_FIND_DATAW find_data;
156
+ size_t buf_source_prefix_len, buf_dest_prefix_len;
157
+
158
+ wcscpy_s(buf_source, MAX_PATH, _wsource);
159
+ wcscat_s(buf_source, MAX_PATH, L"\\");
160
+ buf_source_prefix_len = wcslen(buf_source);
161
+
162
+ wcscpy_s(buf_dest, MAX_PATH, _wdest);
163
+ wcscat_s(buf_dest, MAX_PATH, L"\\");
164
+ buf_dest_prefix_len = wcslen(buf_dest);
165
+
166
+ /* Get an enumerator for the items in the source. */
167
+ wcscat_s(buf_source, MAX_PATH, L"*");
168
+ find_handle = FindFirstFileW(buf_source, &find_data);
169
+ cl_assert(INVALID_HANDLE_VALUE != find_handle);
170
+
171
+ /* Create the target directory. */
172
+ cl_assert(CreateDirectoryW(_wdest, NULL));
173
+
174
+ do {
175
+ /* FindFirstFile/FindNextFile gives back . and ..
176
+ * entries at the beginning */
177
+ if (fs__dotordotdot(find_data.cFileName))
178
+ continue;
179
+
180
+ wcscpy_s(buf_source + buf_source_prefix_len, MAX_PATH - buf_source_prefix_len, find_data.cFileName);
181
+ wcscpy_s(buf_dest + buf_dest_prefix_len, MAX_PATH - buf_dest_prefix_len, find_data.cFileName);
182
+
183
+ if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
184
+ fs_copydir_helper(buf_source, buf_dest);
185
+ else
186
+ cl_assert(CopyFileW(buf_source, buf_dest, TRUE));
187
+ }
188
+ while (FindNextFileW(find_handle, &find_data));
189
+
190
+ /* Ensure that we successfully completed the enumeration */
191
+ cl_assert(ERROR_NO_MORE_FILES == GetLastError());
192
+
193
+ /* Close the find handle */
194
+ FindClose(find_handle);
195
+ }
196
+
197
+ static void
198
+ fs_copy(const char *_source, const char *_dest)
199
+ {
200
+ WCHAR wsource[MAX_PATH], wdest[MAX_PATH];
201
+ DWORD source_attrs, dest_attrs;
202
+ HANDLE find_handle;
203
+ WIN32_FIND_DATAW find_data;
204
+
205
+ /* The input paths are UTF-8. Convert them to wide characters
206
+ * for use with the Windows API. */
207
+ cl_assert(MultiByteToWideChar(CP_UTF8,
208
+ MB_ERR_INVALID_CHARS,
209
+ _source,
210
+ -1,
211
+ wsource,
212
+ MAX_PATH));
213
+
214
+ cl_assert(MultiByteToWideChar(CP_UTF8,
215
+ MB_ERR_INVALID_CHARS,
216
+ _dest,
217
+ -1,
218
+ wdest,
219
+ MAX_PATH));
220
+
221
+ /* Check the source for existence */
222
+ source_attrs = GetFileAttributesW(wsource);
223
+ cl_assert(INVALID_FILE_ATTRIBUTES != source_attrs);
224
+
225
+ /* Check the target for existence */
226
+ dest_attrs = GetFileAttributesW(wdest);
227
+
228
+ if (INVALID_FILE_ATTRIBUTES != dest_attrs) {
229
+ /* Target exists; append last path part of source to target.
230
+ * Use FindFirstFile to parse the path */
231
+ find_handle = FindFirstFileW(wsource, &find_data);
232
+ cl_assert(INVALID_HANDLE_VALUE != find_handle);
233
+ wcscat_s(wdest, MAX_PATH, L"\\");
234
+ wcscat_s(wdest, MAX_PATH, find_data.cFileName);
235
+ FindClose(find_handle);
236
+
237
+ /* Check the new target for existence */
238
+ cl_assert(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wdest));
239
+ }
240
+
241
+ if (FILE_ATTRIBUTE_DIRECTORY & source_attrs)
242
+ fs_copydir_helper(wsource, wdest);
243
+ else
244
+ cl_assert(CopyFileW(wsource, wdest, TRUE));
245
+ }
246
+
247
+ void
248
+ cl_fs_cleanup(void)
249
+ {
250
+ fs_rm(fixture_path(_clar_path, "*"));
251
+ }
252
+
253
+ #else
254
+
255
+ #include <errno.h>
256
+ #include <string.h>
257
+
258
+ static int
259
+ shell_out(char * const argv[])
260
+ {
261
+ int status, piderr;
262
+ pid_t pid;
263
+
264
+ pid = fork();
265
+
266
+ if (pid < 0) {
267
+ fprintf(stderr,
268
+ "System error: `fork()` call failed (%d) - %s\n",
269
+ errno, strerror(errno));
270
+ exit(-1);
271
+ }
272
+
273
+ if (pid == 0) {
274
+ execv(argv[0], argv);
275
+ }
276
+
277
+ do {
278
+ piderr = waitpid(pid, &status, WUNTRACED);
279
+ } while (piderr < 0 && (errno == EAGAIN || errno == EINTR));
280
+
281
+ return WEXITSTATUS(status);
282
+ }
283
+
284
+ static void
285
+ fs_copy(const char *_source, const char *dest)
286
+ {
287
+ char *argv[5];
288
+ char *source;
289
+ size_t source_len;
290
+
291
+ source = strdup(_source);
292
+ source_len = strlen(source);
293
+
294
+ if (source[source_len - 1] == '/')
295
+ source[source_len - 1] = 0;
296
+
297
+ argv[0] = "/bin/cp";
298
+ argv[1] = "-R";
299
+ argv[2] = source;
300
+ argv[3] = (char *)dest;
301
+ argv[4] = NULL;
302
+
303
+ cl_must_pass_(
304
+ shell_out(argv),
305
+ "Failed to copy test fixtures to sandbox"
306
+ );
307
+
308
+ free(source);
309
+ }
310
+
311
+ static void
312
+ fs_rm(const char *source)
313
+ {
314
+ char *argv[4];
315
+
316
+ argv[0] = "/bin/rm";
317
+ argv[1] = "-Rf";
318
+ argv[2] = (char *)source;
319
+ argv[3] = NULL;
320
+
321
+ cl_must_pass_(
322
+ shell_out(argv),
323
+ "Failed to cleanup the sandbox"
324
+ );
325
+ }
326
+
327
+ void
328
+ cl_fs_cleanup(void)
329
+ {
330
+ clar_unsandbox();
331
+ clar_sandbox();
332
+ }
333
+ #endif