cadical 0.9.0

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 (171) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +26 -0
  3. data/README.md +101 -0
  4. data/ext/cadical/cadical/LICENSE +28 -0
  5. data/ext/cadical/cadical/README.md +65 -0
  6. data/ext/cadical/cadical/VERSION +1 -0
  7. data/ext/cadical/cadical/src/analyze.cpp +1360 -0
  8. data/ext/cadical/cadical/src/arena.cpp +30 -0
  9. data/ext/cadical/cadical/src/arena.hpp +105 -0
  10. data/ext/cadical/cadical/src/assume.cpp +616 -0
  11. data/ext/cadical/cadical/src/averages.cpp +34 -0
  12. data/ext/cadical/cadical/src/averages.hpp +37 -0
  13. data/ext/cadical/cadical/src/backbone.cpp +631 -0
  14. data/ext/cadical/cadical/src/backtrack.cpp +177 -0
  15. data/ext/cadical/cadical/src/backward.cpp +231 -0
  16. data/ext/cadical/cadical/src/bins.cpp +22 -0
  17. data/ext/cadical/cadical/src/bins.hpp +22 -0
  18. data/ext/cadical/cadical/src/block.cpp +824 -0
  19. data/ext/cadical/cadical/src/block.hpp +37 -0
  20. data/ext/cadical/cadical/src/cadical.cpp +1026 -0
  21. data/ext/cadical/cadical/src/cadical.hpp +1419 -0
  22. data/ext/cadical/cadical/src/ccadical.cpp +208 -0
  23. data/ext/cadical/cadical/src/ccadical.h +74 -0
  24. data/ext/cadical/cadical/src/checker.cpp +649 -0
  25. data/ext/cadical/cadical/src/checker.hpp +173 -0
  26. data/ext/cadical/cadical/src/clause.cpp +689 -0
  27. data/ext/cadical/cadical/src/clause.hpp +190 -0
  28. data/ext/cadical/cadical/src/collect.cpp +545 -0
  29. data/ext/cadical/cadical/src/compact.cpp +550 -0
  30. data/ext/cadical/cadical/src/condition.cpp +940 -0
  31. data/ext/cadical/cadical/src/config.cpp +101 -0
  32. data/ext/cadical/cadical/src/config.hpp +20 -0
  33. data/ext/cadical/cadical/src/congruence.cpp +7880 -0
  34. data/ext/cadical/cadical/src/congruence.hpp +757 -0
  35. data/ext/cadical/cadical/src/constrain.cpp +64 -0
  36. data/ext/cadical/cadical/src/contract.cpp +27 -0
  37. data/ext/cadical/cadical/src/contract.hpp +139 -0
  38. data/ext/cadical/cadical/src/cover.cpp +704 -0
  39. data/ext/cadical/cadical/src/cover.hpp +34 -0
  40. data/ext/cadical/cadical/src/decide.cpp +347 -0
  41. data/ext/cadical/cadical/src/decompose.cpp +738 -0
  42. data/ext/cadical/cadical/src/decompose.hpp +23 -0
  43. data/ext/cadical/cadical/src/deduplicate.cpp +275 -0
  44. data/ext/cadical/cadical/src/definition.cpp +283 -0
  45. data/ext/cadical/cadical/src/delay.hpp +38 -0
  46. data/ext/cadical/cadical/src/drattracer.cpp +153 -0
  47. data/ext/cadical/cadical/src/drattracer.hpp +55 -0
  48. data/ext/cadical/cadical/src/elim.cpp +1171 -0
  49. data/ext/cadical/cadical/src/elim.hpp +53 -0
  50. data/ext/cadical/cadical/src/elimfast.cpp +570 -0
  51. data/ext/cadical/cadical/src/ema.cpp +95 -0
  52. data/ext/cadical/cadical/src/ema.hpp +68 -0
  53. data/ext/cadical/cadical/src/extend.cpp +289 -0
  54. data/ext/cadical/cadical/src/external.cpp +1034 -0
  55. data/ext/cadical/cadical/src/external.hpp +487 -0
  56. data/ext/cadical/cadical/src/external_propagate.cpp +1316 -0
  57. data/ext/cadical/cadical/src/factor.cpp +1011 -0
  58. data/ext/cadical/cadical/src/factor.hpp +54 -0
  59. data/ext/cadical/cadical/src/file.cpp +506 -0
  60. data/ext/cadical/cadical/src/file.hpp +210 -0
  61. data/ext/cadical/cadical/src/flags.cpp +135 -0
  62. data/ext/cadical/cadical/src/flags.hpp +93 -0
  63. data/ext/cadical/cadical/src/flip.cpp +269 -0
  64. data/ext/cadical/cadical/src/format.cpp +89 -0
  65. data/ext/cadical/cadical/src/format.hpp +36 -0
  66. data/ext/cadical/cadical/src/frattracer.cpp +277 -0
  67. data/ext/cadical/cadical/src/frattracer.hpp +67 -0
  68. data/ext/cadical/cadical/src/gates.cpp +766 -0
  69. data/ext/cadical/cadical/src/heap.hpp +212 -0
  70. data/ext/cadical/cadical/src/idruptracer.cpp +566 -0
  71. data/ext/cadical/cadical/src/idruptracer.hpp +112 -0
  72. data/ext/cadical/cadical/src/instantiate.cpp +365 -0
  73. data/ext/cadical/cadical/src/instantiate.hpp +45 -0
  74. data/ext/cadical/cadical/src/internal.cpp +1265 -0
  75. data/ext/cadical/cadical/src/internal.hpp +1941 -0
  76. data/ext/cadical/cadical/src/inttypes.hpp +34 -0
  77. data/ext/cadical/cadical/src/ipasir.cpp +47 -0
  78. data/ext/cadical/cadical/src/ipasir.h +37 -0
  79. data/ext/cadical/cadical/src/kitten.c +2599 -0
  80. data/ext/cadical/cadical/src/kitten.h +97 -0
  81. data/ext/cadical/cadical/src/level.hpp +33 -0
  82. data/ext/cadical/cadical/src/lidruptracer.cpp +657 -0
  83. data/ext/cadical/cadical/src/lidruptracer.hpp +122 -0
  84. data/ext/cadical/cadical/src/limit.cpp +146 -0
  85. data/ext/cadical/cadical/src/limit.hpp +168 -0
  86. data/ext/cadical/cadical/src/logging.cpp +214 -0
  87. data/ext/cadical/cadical/src/logging.hpp +98 -0
  88. data/ext/cadical/cadical/src/lookahead.cpp +520 -0
  89. data/ext/cadical/cadical/src/lratchecker.cpp +833 -0
  90. data/ext/cadical/cadical/src/lratchecker.hpp +168 -0
  91. data/ext/cadical/cadical/src/lrattracer.cpp +200 -0
  92. data/ext/cadical/cadical/src/lrattracer.hpp +61 -0
  93. data/ext/cadical/cadical/src/lucky.cpp +506 -0
  94. data/ext/cadical/cadical/src/message.cpp +218 -0
  95. data/ext/cadical/cadical/src/message.hpp +65 -0
  96. data/ext/cadical/cadical/src/minimize.cpp +224 -0
  97. data/ext/cadical/cadical/src/mobical.cpp +5588 -0
  98. data/ext/cadical/cadical/src/occs.cpp +52 -0
  99. data/ext/cadical/cadical/src/occs.hpp +36 -0
  100. data/ext/cadical/cadical/src/options.cpp +359 -0
  101. data/ext/cadical/cadical/src/options.hpp +442 -0
  102. data/ext/cadical/cadical/src/parse.cpp +471 -0
  103. data/ext/cadical/cadical/src/parse.hpp +75 -0
  104. data/ext/cadical/cadical/src/phases.cpp +56 -0
  105. data/ext/cadical/cadical/src/phases.hpp +19 -0
  106. data/ext/cadical/cadical/src/probe.cpp +990 -0
  107. data/ext/cadical/cadical/src/profile.cpp +107 -0
  108. data/ext/cadical/cadical/src/profile.hpp +283 -0
  109. data/ext/cadical/cadical/src/proof.cpp +691 -0
  110. data/ext/cadical/cadical/src/proof.hpp +125 -0
  111. data/ext/cadical/cadical/src/propagate.cpp +584 -0
  112. data/ext/cadical/cadical/src/queue.cpp +90 -0
  113. data/ext/cadical/cadical/src/queue.hpp +74 -0
  114. data/ext/cadical/cadical/src/radix.hpp +180 -0
  115. data/ext/cadical/cadical/src/random.cpp +207 -0
  116. data/ext/cadical/cadical/src/random.h +44 -0
  117. data/ext/cadical/cadical/src/random.hpp +98 -0
  118. data/ext/cadical/cadical/src/range.hpp +125 -0
  119. data/ext/cadical/cadical/src/reap.cpp +127 -0
  120. data/ext/cadical/cadical/src/reap.hpp +28 -0
  121. data/ext/cadical/cadical/src/reduce.cpp +278 -0
  122. data/ext/cadical/cadical/src/reluctant.hpp +82 -0
  123. data/ext/cadical/cadical/src/rephase.cpp +402 -0
  124. data/ext/cadical/cadical/src/report.cpp +313 -0
  125. data/ext/cadical/cadical/src/resources.cpp +160 -0
  126. data/ext/cadical/cadical/src/resources.hpp +16 -0
  127. data/ext/cadical/cadical/src/restart.cpp +178 -0
  128. data/ext/cadical/cadical/src/restore.cpp +267 -0
  129. data/ext/cadical/cadical/src/score.cpp +51 -0
  130. data/ext/cadical/cadical/src/score.hpp +16 -0
  131. data/ext/cadical/cadical/src/shrink.cpp +507 -0
  132. data/ext/cadical/cadical/src/signal.cpp +136 -0
  133. data/ext/cadical/cadical/src/signal.hpp +33 -0
  134. data/ext/cadical/cadical/src/solution.cpp +50 -0
  135. data/ext/cadical/cadical/src/solver.cpp +1871 -0
  136. data/ext/cadical/cadical/src/stable.cpp +31 -0
  137. data/ext/cadical/cadical/src/stack.h +110 -0
  138. data/ext/cadical/cadical/src/stats.cpp +920 -0
  139. data/ext/cadical/cadical/src/stats.hpp +418 -0
  140. data/ext/cadical/cadical/src/subsume.cpp +645 -0
  141. data/ext/cadical/cadical/src/sweep.cpp +1960 -0
  142. data/ext/cadical/cadical/src/sweep.hpp +61 -0
  143. data/ext/cadical/cadical/src/terminal.cpp +38 -0
  144. data/ext/cadical/cadical/src/terminal.hpp +96 -0
  145. data/ext/cadical/cadical/src/ternary.cpp +450 -0
  146. data/ext/cadical/cadical/src/testing.hpp +24 -0
  147. data/ext/cadical/cadical/src/tier.cpp +189 -0
  148. data/ext/cadical/cadical/src/tracer.hpp +186 -0
  149. data/ext/cadical/cadical/src/transred.cpp +253 -0
  150. data/ext/cadical/cadical/src/unstable.cpp +29 -0
  151. data/ext/cadical/cadical/src/util.cpp +129 -0
  152. data/ext/cadical/cadical/src/util.hpp +181 -0
  153. data/ext/cadical/cadical/src/var.cpp +39 -0
  154. data/ext/cadical/cadical/src/var.hpp +22 -0
  155. data/ext/cadical/cadical/src/veripbtracer.cpp +427 -0
  156. data/ext/cadical/cadical/src/veripbtracer.hpp +106 -0
  157. data/ext/cadical/cadical/src/version.cpp +107 -0
  158. data/ext/cadical/cadical/src/version.hpp +13 -0
  159. data/ext/cadical/cadical/src/vivify.cpp +1893 -0
  160. data/ext/cadical/cadical/src/vivify.hpp +50 -0
  161. data/ext/cadical/cadical/src/walk.cpp +1088 -0
  162. data/ext/cadical/cadical/src/walk.hpp +91 -0
  163. data/ext/cadical/cadical/src/walk_full_occs.cpp +966 -0
  164. data/ext/cadical/cadical/src/warmup.cpp +403 -0
  165. data/ext/cadical/cadical/src/watch.cpp +126 -0
  166. data/ext/cadical/cadical/src/watch.hpp +77 -0
  167. data/ext/cadical/cadical_ext.c +778 -0
  168. data/ext/cadical/extconf.rb +26 -0
  169. data/lib/cadical/version.rb +3 -0
  170. data/lib/cadical.rb +12 -0
  171. metadata +218 -0
@@ -0,0 +1,54 @@
1
+ #ifndef _factor_hpp_INCLUDED
2
+ #define _factor_hpp_INCLUDED
3
+
4
+ #include "clause.hpp"
5
+ #include "heap.hpp"
6
+
7
+ namespace CaDiCaL {
8
+
9
+ struct Internal;
10
+
11
+ struct factor_occs_size {
12
+ Internal *internal;
13
+ factor_occs_size (Internal *i) : internal (i) {}
14
+ bool operator() (unsigned a, unsigned b);
15
+ };
16
+
17
+ struct Quotient {
18
+ Quotient (int f) : factor (f) {}
19
+ ~Quotient () {}
20
+ int factor;
21
+ size_t id;
22
+ int64_t bid; // for LRAT
23
+ Quotient *prev, *next;
24
+ vector<Clause *> qlauses;
25
+ vector<size_t> matches;
26
+ size_t matched;
27
+ };
28
+
29
+ typedef heap<factor_occs_size> FactorSchedule;
30
+
31
+ struct Factoring {
32
+ Factoring (Internal *, int64_t);
33
+ ~Factoring ();
34
+
35
+ // These are initialized by the constructor
36
+ Internal *internal;
37
+ int64_t limit;
38
+ FactorSchedule schedule;
39
+
40
+ int initial;
41
+ int bound;
42
+ vector<unsigned> count;
43
+ vector<int> fresh;
44
+ vector<int> counted;
45
+ vector<int> nounted;
46
+ vector<Clause *> flauses;
47
+ struct {
48
+ Quotient *first, *last;
49
+ } quotients;
50
+ };
51
+
52
+ } // namespace CaDiCaL
53
+
54
+ #endif
@@ -0,0 +1,506 @@
1
+ #include "internal.hpp"
2
+
3
+ /*------------------------------------------------------------------------*/
4
+
5
+ // Some more low-level 'C' headers.
6
+
7
+ extern "C" {
8
+ #include <errno.h>
9
+ #include <fcntl.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+ #include <sys/stat.h>
13
+ #include <sys/types.h>
14
+ #include <unistd.h>
15
+ }
16
+
17
+ #ifndef _WIN32
18
+
19
+ extern "C" {
20
+ #include <sys/wait.h>
21
+ }
22
+
23
+ #endif
24
+
25
+ #if defined(__APPLE__) || defined(__MACH__)
26
+
27
+ extern "C" {
28
+ #include <libproc.h>
29
+ #include <sys/proc_info.h>
30
+ }
31
+
32
+ #include <mutex>
33
+
34
+ #endif
35
+
36
+ /*------------------------------------------------------------------------*/
37
+
38
+ namespace CaDiCaL {
39
+
40
+ /*------------------------------------------------------------------------*/
41
+
42
+ // Private constructor.
43
+
44
+ File::File (Internal *i, bool w, int c, int p, FILE *f, const char *n)
45
+ : internal (i),
46
+ #if !defined(QUIET) || !defined(NDEBUG)
47
+ writing (w),
48
+ #endif
49
+ close_file (c), child_pid (p), file (f), _name (strdup (n)),
50
+ _lineno (1), _bytes (0) {
51
+ (void) w;
52
+ assert (f), assert (n);
53
+ }
54
+
55
+ /*------------------------------------------------------------------------*/
56
+
57
+ bool File::exists (const char *path) {
58
+ struct stat buf;
59
+ if (stat (path, &buf))
60
+ return false;
61
+ if (access (path, R_OK))
62
+ return false;
63
+ return true;
64
+ }
65
+
66
+ bool File::writable (const char *path) {
67
+ int res;
68
+ if (!path)
69
+ res = 1;
70
+ else if (!strcmp (path, "/dev/null"))
71
+ res = 0;
72
+ else {
73
+ if (!*path)
74
+ res = 2;
75
+ else {
76
+ struct stat buf;
77
+ const char *p = strrchr (path, '/');
78
+ if (!p) {
79
+ if (stat (path, &buf))
80
+ res = ((errno == ENOENT) ? 0 : -2);
81
+ else if (S_ISDIR (buf.st_mode))
82
+ res = 3;
83
+ else
84
+ res = (access (path, W_OK) ? 4 : 0);
85
+ } else if (!p[1])
86
+ res = 5;
87
+ else {
88
+ size_t len = p - path;
89
+ char *dirname = new char[len + 1];
90
+ strncpy (dirname, path, len);
91
+ dirname[len] = 0;
92
+ if (stat (dirname, &buf))
93
+ res = 6;
94
+ else if (!S_ISDIR (buf.st_mode))
95
+ res = 7;
96
+ else if (access (dirname, W_OK))
97
+ res = 8;
98
+ else if (stat (path, &buf))
99
+ res = (errno == ENOENT) ? 0 : -3;
100
+ else
101
+ res = access (path, W_OK) ? 9 : 0;
102
+ delete[] dirname;
103
+ }
104
+ }
105
+ }
106
+ return !res;
107
+ }
108
+
109
+ bool File::piping () {
110
+ struct stat stat;
111
+ int fd = fileno (file);
112
+ if (fstat (fd, &stat))
113
+ return true;
114
+ return S_ISFIFO (stat.st_mode);
115
+ }
116
+
117
+ // These are signatures for supported compressed file types. In 2018 the
118
+ // SAT Competition was running on StarExec and used internally 'bzip2'
119
+ // compressed files, but gave them uncompressed to the solver using exactly
120
+ // the same path (with '.bz2' suffix). Then 'CaDiCaL' tried to read that
121
+ // actually uncompressed file through 'bzip2', which of course failed. Now
122
+ // we double check and fall back to reading the file as is, if the signature
123
+ // does not match after issuing a warning.
124
+
125
+ static int xzsig[] = {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, EOF};
126
+ static int bz2sig[] = {0x42, 0x5A, 0x68, EOF};
127
+ static int gzsig[] = {0x1F, 0x8B, EOF};
128
+ static int sig7z[] = {0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C, EOF};
129
+ static int lzmasig[] = {0x5D, EOF};
130
+
131
+ bool File::match (Internal *internal, const char *path, const int *sig) {
132
+ assert (path);
133
+ FILE *tmp = fopen (path, "r");
134
+ if (!tmp) {
135
+ WARNING ("failed to open '%s' to check signature", path);
136
+ return false;
137
+ }
138
+ bool res = true;
139
+ for (const int *p = sig; res && (*p != EOF); p++)
140
+ res = (cadical_getc_unlocked (tmp) == *p);
141
+ fclose (tmp);
142
+ if (!res)
143
+ WARNING ("file type signature check for '%s' failed", path);
144
+ return res;
145
+ }
146
+
147
+ size_t File::size (const char *path) {
148
+ struct stat buf;
149
+ if (stat (path, &buf))
150
+ return 0;
151
+ return (size_t) buf.st_size;
152
+ }
153
+
154
+ // Check that 'prg' is in the 'PATH' and thus can be found if executed
155
+ // through 'popen' or 'exec'.
156
+
157
+ char *File::find_program (const char *prg) {
158
+ size_t prglen = strlen (prg);
159
+ const char *c = getenv ("PATH");
160
+ if (!c)
161
+ return 0;
162
+ size_t len = strlen (c);
163
+ char *e = new char[len + 1];
164
+ strcpy (e, c);
165
+ char *res = 0;
166
+ for (char *p = e, *q; !res && p < e + len; p = q) {
167
+ for (q = p; *q && *q != ':'; q++)
168
+ ;
169
+ *q++ = 0;
170
+ size_t pathlen = (q - p) + prglen;
171
+ char *path = new char[pathlen + 1];
172
+ snprintf (path, pathlen + 1, "%s/%s", p, prg);
173
+ assert (strlen (path) == pathlen);
174
+ if (exists (path))
175
+ res = path;
176
+ else
177
+ delete[] path;
178
+ }
179
+ delete[] e;
180
+ return res;
181
+ }
182
+
183
+ /*------------------------------------------------------------------------*/
184
+
185
+ FILE *File::open_file (Internal *internal, const char *path,
186
+ const char *mode) {
187
+ (void) internal;
188
+ return fopen (path, mode);
189
+ }
190
+
191
+ FILE *File::read_file (Internal *internal, const char *path) {
192
+ MSG ("opening file to read '%s'", path);
193
+ return open_file (internal, path, "r");
194
+ }
195
+
196
+ FILE *File::write_file (Internal *internal, const char *path) {
197
+ MSG ("opening file to write '%s'", path);
198
+ return open_file (internal, path, "wb");
199
+ }
200
+
201
+ /*------------------------------------------------------------------------*/
202
+
203
+ void File::split_str (const char *command, std::vector<char *> &argv) {
204
+ const char *c = command;
205
+ while (*c && *c == ' ')
206
+ c++;
207
+ while (*c) {
208
+ const char *p = c;
209
+ while (*p && *p != ' ')
210
+ p++;
211
+ const size_t bytes = p - c;
212
+ char *arg = new char[bytes + 1];
213
+ (void) strncpy (arg, c, bytes);
214
+ arg[bytes] = 0;
215
+ argv.push_back (arg);
216
+ while (*p && *p == ' ')
217
+ p++;
218
+ c = p;
219
+ }
220
+ }
221
+
222
+ void File::delete_str_vector (std::vector<char *> &argv) {
223
+ for (auto str : argv)
224
+ delete[] str;
225
+ }
226
+
227
+ FILE *File::open_pipe (Internal *internal, const char *fmt,
228
+ const char *path, const char *mode) {
229
+ #ifdef QUIET
230
+ (void) internal;
231
+ #endif
232
+ size_t prglen = 0;
233
+ while (fmt[prglen] && fmt[prglen] != ' ')
234
+ prglen++;
235
+ char *prg = new char[prglen + 1];
236
+ strncpy (prg, fmt, prglen);
237
+ prg[prglen] = 0;
238
+ char *found = find_program (prg);
239
+ if (found)
240
+ MSG ("found '%s' in path for '%s'", found, prg);
241
+ if (!found)
242
+ MSG ("did not find '%s' in path", prg);
243
+ delete[] prg;
244
+ if (!found)
245
+ return 0;
246
+ delete[] found;
247
+ size_t cmd_size = strlen (fmt) + strlen (path);
248
+ char *cmd = new char[cmd_size];
249
+ snprintf (cmd, cmd_size, fmt, path);
250
+ FILE *res = popen (cmd, mode);
251
+ delete[] cmd;
252
+ return res;
253
+ }
254
+
255
+ FILE *File::read_pipe (Internal *internal, const char *fmt, const int *sig,
256
+ const char *path) {
257
+ if (!File::exists (path)) {
258
+ LOG ("file '%s' does not exist", path);
259
+ return 0;
260
+ }
261
+ LOG ("file '%s' exists", path);
262
+ if (sig && !File::match (internal, path, sig))
263
+ return 0;
264
+ LOG ("file '%s' matches signature for '%s'", path, fmt);
265
+ MSG ("opening pipe to read '%s'", path);
266
+ return open_pipe (internal, fmt, path, "r");
267
+ }
268
+
269
+ #ifndef _WIN32
270
+
271
+ #if defined(__APPLE__) || defined(__MACH__)
272
+ static std::mutex compressed_file_writing_mutex;
273
+ #endif
274
+
275
+ FILE *File::write_pipe (Internal *internal, const char *command,
276
+ const char *path, int &child_pid) {
277
+ assert (command[0] && command[0] != ' ');
278
+ MSG ("writing through command '%s' to '%s'", command, path);
279
+ #ifdef QUIET
280
+ (void) internal;
281
+ #endif
282
+ std::vector<char *> args;
283
+ split_str (command, args);
284
+ assert (!args.empty ());
285
+ args.push_back (0);
286
+ char **argv = args.data ();
287
+ char *absolute_command_path = find_program (argv[0]);
288
+ int pipe_fds[2], out;
289
+ FILE *res = 0;
290
+ #if defined(__APPLE__) || defined(__MACH__)
291
+ compressed_file_writing_mutex.lock ();
292
+ #endif
293
+ if (!absolute_command_path)
294
+ MSG ("could not find '%s' in 'PATH' environment variable", argv[0]);
295
+ else if (::pipe (pipe_fds) < 0)
296
+ MSG ("could not generate pipe to '%s' command", command);
297
+ else if ((out = ::open (path, O_CREAT | O_TRUNC | O_WRONLY, 0644)) < 0)
298
+ MSG ("could not open '%s' for writing", path);
299
+ else if ((child_pid = ::fork ()) < 0) {
300
+ MSG ("could not fork process to execute '%s' command", command);
301
+ ::close (out);
302
+ } else if (child_pid) {
303
+ ::close (pipe_fds[0]);
304
+ res = ::fdopen (pipe_fds[1], "wb");
305
+ } else {
306
+
307
+ // Connect stdin and stdout in child
308
+
309
+ ::dup2 (pipe_fds[0], 0);
310
+ ::dup2 (out, 1);
311
+
312
+ // Make sure to close all non-required fds to not cause hangs.
313
+ // This is handled now by closefrom and remains for documentation
314
+ // purposes:
315
+ //
316
+ // ::close (pipe_fds[0]);
317
+ // ::close (pipe_fds[1]);
318
+ // ::close (out);
319
+
320
+ // Surpress '7z' verbose output on 'stderr'.
321
+
322
+ if (command[0] == '7') {
323
+ ::close (2);
324
+ }
325
+
326
+ // Before the fork another thread could have created more fds. These
327
+ // fds are cloned into the child process. As this inhibits pipes to
328
+ // be closed by the parent process we have to close all of the
329
+ // erroneously cloned fds here.
330
+
331
+ #ifndef NCLOSEFROM
332
+ ::closefrom (3);
333
+ #else
334
+ // Simplistic replacement on Unix without 'closefrom'.
335
+ for (int fd = 3; fd != FD_SETSIZE; fd++)
336
+ ::close (fd);
337
+ #endif
338
+ execv (absolute_command_path, argv);
339
+ _exit (1);
340
+ }
341
+ if (absolute_command_path)
342
+ delete[] absolute_command_path;
343
+ delete_str_vector (args);
344
+ #ifdef QUIET
345
+ (void) internal;
346
+ #endif
347
+ #if defined(__APPLE__) || defined(__MACH__)
348
+ if (!res)
349
+ compressed_file_writing_mutex.unlock ();
350
+ #endif
351
+ return res;
352
+ }
353
+
354
+ #endif
355
+
356
+ /*------------------------------------------------------------------------*/
357
+
358
+ File *File::read (Internal *internal, FILE *f, const char *n) {
359
+ return new File (internal, false, 0, 0, f, n);
360
+ }
361
+
362
+ File *File::write (Internal *internal, FILE *f, const char *n) {
363
+ return new File (internal, true, 0, 0, f, n);
364
+ }
365
+
366
+ File *File::read (Internal *internal, const char *path) {
367
+ FILE *file;
368
+ int close_input = 2;
369
+ if (has_suffix (path, ".xz")) {
370
+ file = read_pipe (internal, "xz -c -d %s", xzsig, path);
371
+ if (!file)
372
+ goto READ_FILE;
373
+ } else if (has_suffix (path, ".lzma")) {
374
+ file = read_pipe (internal, "lzma -c -d %s", lzmasig, path);
375
+ if (!file)
376
+ goto READ_FILE;
377
+ } else if (has_suffix (path, ".bz2")) {
378
+ file = read_pipe (internal, "bzip2 -c -d %s", bz2sig, path);
379
+ if (!file)
380
+ goto READ_FILE;
381
+ } else if (has_suffix (path, ".gz")) {
382
+ file = read_pipe (internal, "gzip -c -d %s", gzsig, path);
383
+ if (!file)
384
+ goto READ_FILE;
385
+ } else if (has_suffix (path, ".7z")) {
386
+ file = read_pipe (internal, "7z x -so %s 2>/dev/null", sig7z, path);
387
+ if (!file)
388
+ goto READ_FILE;
389
+ } else {
390
+ READ_FILE:
391
+ file = read_file (internal, path);
392
+ close_input = 1;
393
+ }
394
+
395
+ if (!file)
396
+ return 0;
397
+
398
+ return new File (internal, false, close_input, 0, file, path);
399
+ }
400
+
401
+ File *File::write (Internal *internal, const char *path) {
402
+ FILE *file;
403
+ int close_output = 3, child_pid = 0;
404
+ #ifndef _WIN32
405
+ if (has_suffix (path, ".xz"))
406
+ file = write_pipe (internal, "xz -c", path, child_pid);
407
+ else if (has_suffix (path, ".bz2"))
408
+ file = write_pipe (internal, "bzip2 -c", path, child_pid);
409
+ else if (has_suffix (path, ".gz"))
410
+ file = write_pipe (internal, "gzip -c", path, child_pid);
411
+ else if (has_suffix (path, ".7z"))
412
+ file = write_pipe (internal, "7z a -an -txz -si -so", path, child_pid);
413
+ else
414
+ #endif
415
+ file = write_file (internal, path), close_output = 1;
416
+
417
+ if (!file)
418
+ return 0;
419
+
420
+ return new File (internal, true, close_output, child_pid, file, path);
421
+ }
422
+
423
+ void File::close (bool print) {
424
+ assert (file);
425
+ #ifndef QUIET
426
+ if (internal->opts.quiet)
427
+ print = false;
428
+ else if (internal->opts.verbose > 0)
429
+ print = true;
430
+ #endif
431
+ if (close_file == 0) {
432
+ if (print)
433
+ MSG ("disconnecting from '%s'", name ());
434
+ }
435
+ if (close_file == 1) {
436
+ if (print)
437
+ MSG ("closing file '%s'", name ());
438
+ fclose (file);
439
+ }
440
+ if (close_file == 2) {
441
+ if (print)
442
+ MSG ("closing input pipe to read '%s'", name ());
443
+ pclose (file);
444
+ }
445
+ #ifndef _WIN32
446
+ if (close_file == 3) {
447
+ if (print)
448
+ MSG ("closing output pipe to write '%s'", name ());
449
+ fclose (file);
450
+ waitpid (child_pid, 0, 0);
451
+ #if defined(__APPLE__) || defined(__MACH__)
452
+ compressed_file_writing_mutex.unlock ();
453
+ #endif
454
+ }
455
+ #endif
456
+ file = 0; // mark as closed
457
+
458
+ // TODO what about error checking for 'fclose', 'pclose' or 'waitpid'?
459
+
460
+ #ifndef QUIET
461
+ if (print) {
462
+ if (writing) {
463
+ uint64_t written_bytes = bytes ();
464
+ double written_mb = written_bytes / (double) (1 << 20);
465
+ MSG ("after writing %" PRIu64 " bytes %.1f MB", written_bytes,
466
+ written_mb);
467
+ if (close_file == 3) {
468
+ size_t actual_bytes = size (name ());
469
+ if (actual_bytes) {
470
+ double actual_mb = actual_bytes / (double) (1 << 20);
471
+ MSG ("deflated to %zd bytes %.1f MB", actual_bytes, actual_mb);
472
+ MSG ("factor %.2f (%.2f%% compression)",
473
+ relative (written_bytes, actual_bytes),
474
+ percent (actual_bytes, written_bytes));
475
+ } else
476
+ MSG ("but could not determine actual size of written file");
477
+ }
478
+ } else {
479
+ uint64_t read_bytes = bytes ();
480
+ double read_mb = read_bytes / (double) (1 << 20);
481
+ MSG ("after reading %" PRIu64 " bytes %.1f MB", read_bytes, read_mb);
482
+ if (close_file == 2) {
483
+ size_t actual_bytes = size (name ());
484
+ double actual_mb = actual_bytes / (double) (1 << 20);
485
+ MSG ("inflated from %zd bytes %.1f MB", actual_bytes, actual_mb);
486
+ MSG ("factor %.2f (%.2f%% compression)",
487
+ relative (read_bytes, actual_bytes),
488
+ percent (actual_bytes, read_bytes));
489
+ }
490
+ }
491
+ }
492
+ #endif
493
+ }
494
+
495
+ void File::flush () {
496
+ assert (file);
497
+ fflush (file);
498
+ }
499
+
500
+ File::~File () {
501
+ if (file)
502
+ close ();
503
+ free (_name);
504
+ }
505
+
506
+ } // namespace CaDiCaL