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