1 /* Alternate implementation of singleton_simple.cpp, in pure C, stand-alone.
2
3 Usage: singleton_simple -col-max-index nnn -out xxx x y z.
4
5 (there is no -col-min-index option, all ideals are taken into account).
6 */
7
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <limits.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include "macros.h"
17 #include "portability.h"
18
19 #define MAX_SIZE 1024
20
21 #undef ASSERT_ALWAYS
22 #define ASSERT_ALWAYS assert
23
24 #define AB_BASE 16 /* base of a,b */
25
26 unsigned char *T;
27 unsigned long nrels = 0;
28
has_suffix(const char * path,const char * sfx)29 int has_suffix(const char * path, const char * sfx)
30 {
31 unsigned int lp = strlen(path);
32 unsigned int ls = strlen(sfx);
33 if (lp < ls) return 0;
34 return strcmp(path + lp - ls, sfx) == 0;
35 }
36
37 struct suffix_handler {
38 const char * suffix;
39 const char * pfmt_in;
40 const char * pfmt_out;
41 };
42
43 struct suffix_handler supported_compression_formats[] = {
44 { ".gz", "gzip -dc %s", "gzip -c --fast > %s", },
45 { ".bz2", "bzip2 -dc %s", "bzip2 -c --fast > %s", },
46 { ".lzma", "lzma -dc %s", "lzma -c -0 > %s", },
47 /* These two have to be present */
48 { "", NULL, NULL },
49 { NULL, NULL, NULL },
50 };
51
cado_popen(const char * command,const char * mode)52 static inline FILE * cado_popen(const char * command, const char * mode) { return popen(command, mode); }
53
cado_pclose(FILE * stream)54 static inline int cado_pclose(FILE * stream) { return pclose(stream); }
55
56 FILE*
fopen_maybe_compressed2(const char * name,const char * mode,int * p_pipeflag,char const ** suf)57 fopen_maybe_compressed2 (const char * name, const char * mode, int* p_pipeflag, char const ** suf)
58 {
59 const struct suffix_handler * r = supported_compression_formats;
60 FILE * f;
61
62 if (strchr(mode, 'r') && access(name, R_OK) != 0)
63 return NULL;
64
65 for( ; r->suffix ; r++) {
66 if (!has_suffix(name, r->suffix)) continue;
67 if (suf) *suf = r->suffix;
68 char * command = NULL;
69 if (strchr(mode, 'r') && r->pfmt_in) {
70 int ret = asprintf(&command, r->pfmt_in, name);
71 ASSERT_ALWAYS(ret >= 0);
72 } else if (strchr(mode, 'w') && r->pfmt_out) {
73 int ret = asprintf(&command, r->pfmt_out, name);
74 ASSERT_ALWAYS(ret >= 0);
75 }
76
77 if (command) {
78 /* apparently popen() under Linux does not accept the 'b' modifier */
79 char pmode[2] = "x";
80 pmode[0] = mode[0];
81 f = cado_popen(command, pmode);
82 if (p_pipeflag) *p_pipeflag = 1;
83 #ifdef F_SETPIPE_SZxxx
84 /* The pipe capacity is 2^16 by default; we can increase it,
85 * but it does not seem to make a difference, thus we don't
86 * change it by default (patch from Alain Filbois). */
87 fcntl (fileno (f), F_SETPIPE_SZ, 1UL << 20);
88 #endif
89 free(command);
90 } else {
91 f = fopen(name, mode);
92 if (p_pipeflag) *p_pipeflag = 0;
93 }
94 return f;
95 }
96 /* If we arrive here, it's because "" is not among the suffixes */
97 abort();
98 return NULL;
99 }
100
101 FILE*
fopen_maybe_compressed(const char * name,const char * mode)102 fopen_maybe_compressed (const char * name, const char * mode)
103 {
104 return fopen_maybe_compressed2(name, mode, NULL, NULL);
105 }
106
107 static int
fclose_maybe_compressed2(FILE * f,const char * name)108 fclose_maybe_compressed2 (FILE * f, const char * name)
109 {
110 const struct suffix_handler * r = supported_compression_formats;
111
112 for( ; r->suffix ; r++) {
113 if (!has_suffix(name, r->suffix)) continue;
114 /* It doesn't really make sense to imagine that one of these two
115 * may exist and not the other */
116 ASSERT_ALWAYS((r->pfmt_out == NULL) == (r->pfmt_in == NULL));
117 if (r->pfmt_in || r->pfmt_out) {
118 int status;
119 #ifdef HAVE_GETRUSAGE
120 if (rr)
121 status = cado_pclose(f);
122 else
123 #endif
124 status = cado_pclose(f);
125 #if defined(WIFEXITED) && defined(WEXITSTATUS)
126 /* Unless child process finished normally and with exit status 0,
127 we return an error */
128 if (status == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
129 return EOF;
130 #else
131 /* What do under MinGW? -1 definitely means an error, but how do
132 we parse the other possible status codes? */
133 return (status == -1) ? EOF : 0;
134 #endif
135 return 0;
136 } else {
137 #ifdef HAVE_GETRUSAGE
138 if (rr) memset(rr, 0, sizeof(*rr));
139 #endif
140 return fclose(f);
141 }
142 }
143 /* If we arrive here, it's because "" is not among the suffixes */
144 abort();
145 return EOF;
146 }
147
148 int
fclose_maybe_compressed(FILE * f,const char * name)149 fclose_maybe_compressed (FILE * f, const char * name)
150 {
151 return fclose_maybe_compressed2(f, name);
152 }
153
154 /* Pass 1: read relations and count ideal weight in T[p] (capped to 255) */
155 void
pass1(int argc,char * argv[],unsigned long col_max_index)156 pass1 (int argc, char *argv[], unsigned long col_max_index)
157 {
158 char s[MAX_SIZE], *end;
159 long a;
160 unsigned long b, p, lastp, nideals = 0;
161 int ret, e;
162 FILE *fp;
163
164 while (argc > 1)
165 {
166 printf ("Pass 1: read file %s\n", argv[1]);
167 fflush (stdout);
168 fp = fopen_maybe_compressed (argv[1], "r");
169 argc --;
170 argv ++;
171 while (fgets (s, MAX_SIZE, fp) != NULL)
172 {
173 ASSERT (s[0] != '\n');
174 /* ensure line ends with \n */
175 if (s[strlen(s)-1] != '\n')
176 sprintf (s + strlen(s), "\n");
177 if (s[0] != '#') /* not a comment */
178 {
179 a = strtol (s, &end, AB_BASE);
180 b = strtoul (end + 1, &end, AB_BASE);
181 lastp = ULONG_MAX;
182 while (*end != '\n')
183 {
184 p = strtoul (end + 1, &end, 16);
185 if (p != lastp)
186 {
187 if (lastp != ULONG_MAX && (e & 1))
188 {
189 ASSERT (lastp < col_max_index);
190 T[lastp] += (T[lastp] < 255);
191 }
192 e = 1;
193 lastp = p;
194 }
195 }
196 if (e & 1)
197 {
198 ASSERT (lastp < col_max_index);
199 T[lastp] += (T[lastp] < 255);
200 }
201 nrels ++;
202 if ((nrels & 0x7fffff) == 0)
203 {
204 printf ("Pass 1: read %lu relations\n", nrels);
205 fflush (stdout);
206 }
207 }
208 }
209 fclose (fp);
210 }
211 for (p = 0; p < col_max_index; p++)
212 nideals += (T[p] != 0);
213 printf ("Pass 1: read %lu relations on %lu ideals\n", nrels, nideals);
214 fflush (stdout);
215 }
216
217 /* Pass 2: output relations with no singleton */
218 void
pass2(int argc,char * argv[],char * out_file)219 pass2 (int argc, char *argv[], char *out_file)
220 {
221 char s[MAX_SIZE], *end;
222 long a;
223 unsigned long b, p;
224 int ret, e;
225 FILE *fp, *out;
226 unsigned long nrels_out = 0;
227
228 out = fopen (out_file, "w");
229 nrels = 0;
230 while (argc > 1)
231 {
232 printf ("Pass 2: read file %s\n", argv[1]);
233 fflush (stdout);
234 fp = fopen_maybe_compressed (argv[1], "r");
235 argc --;
236 argv ++;
237 while (fgets (s, MAX_SIZE, fp) != NULL)
238 {
239 ASSERT (s[0] != '\n');
240 /* ensure line ends with \n */
241 if (s[strlen(s)-1] != '\n')
242 sprintf (s + strlen(s), "\n");
243 if (s[0] != '#') /* not a comment */
244 {
245 int singleton = 0;
246 a = strtol (s, &end, AB_BASE);
247 b = strtoul (end + 1, &end, AB_BASE);
248 while (*end != '\n' && singleton == 0)
249 {
250 p = strtoul (end + 1, &end, 16);
251 ASSERT (T[p] != 0);
252 if (T[p] == 1)
253 singleton = 1;
254 }
255 nrels ++;
256 if (singleton == 0)
257 {
258 fprintf (out, s);
259 nrels_out ++;
260 }
261 if ((nrels & 0x7fffff) == 0)
262 {
263 printf ("Pass 2: read %lu relations\n", nrels);
264 fflush (stdout);
265 }
266 }
267 }
268 fclose (fp);
269 }
270 printf ("Pass 2: read %lu relations, output %lu\n", nrels, nrels_out);
271 fflush (stdout);
272 fclose (out);
273 }
274
275 int
main(int argc,char * argv[])276 main (int argc, char *argv[])
277 {
278 unsigned long col_max_index = 0;
279 char *out_file = NULL;
280
281 while (argc > 2 && argv[1][0] == '-')
282 {
283 if (strcmp (argv[1], "-col-max-index") == 0)
284 {
285 col_max_index = strtoul (argv[2], NULL, 10);
286 argv += 2;
287 argc -= 2;
288 }
289 else if (strcmp (argv[1], "-out") == 0)
290 {
291 out_file = argv[2];
292 argv += 2;
293 argc -= 2;
294 }
295 else
296 {
297 fprintf (stderr, "Error, unknown option %s\n", argv[2]);
298 exit (1);
299 }
300 }
301
302 if (col_max_index == 0)
303 {
304 fprintf (stderr, "Error, missing -col-max-index option\n");
305 exit (1);
306 }
307
308 T = malloc (col_max_index);
309 memset (T, 0, col_max_index);
310 pass1 (argc, argv, col_max_index);
311 pass2 (argc, argv, out_file);
312 free (T);
313 return 0;
314 }
315