mathematical 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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