1 /* gtools.c : Common routines for gtools programs. */
2 /* Version 4.2, Oct 2017. */
3 
4 /* Todo: size check if MAXN>0; option to free memory */
5 
6 #include "gtools.h"
7 
8 #ifndef SEEK_SET
9 #define SEEK_SET 0
10 #define SEEK_CUR 1
11 #define SEEK_END 2
12 #endif
13 
14 TLS_ATTR size_t ogf_linelen;
15 TLS_ATTR boolean is_pipe;
16 
17 #if HAVE_FSEEKO
18 #define FSEEK_VER fseeko
19 #define FTELL_VER ftello
20 #define OFF_T_VER off_t
21 #else
22 #if !FTELL_DEC
23 extern long ftell(FILE*);
24 extern int fseek(FILE*,long,int);
25 #endif
26 #define FSEEK_VER fseek
27 #define FTELL_VER ftell
28 #define OFF_T_VER long
29 #endif
30 
31 #if !POPEN_DEC
32 extern FILE *popen(const char*,const char*);
33 #endif
34 
35 /*
36   Version 1.1: Fixed sparse6 input for powers of 2.  May 9, 1998
37   Version 1.2: Added "cmd: ..." option for opengraphfile().
38                Fixed readg() bug (could not be invisible).  Oct 5, 1998
39   Version 1.3: Added "is_pipe".  June 20, 2002
40   Version 1.4: Stuff for autoconf.  August 30, 2002
41   Version 1.5: Unlocked stdio for efficiency.  October 31, 2004
42                Also fwrite() in place of fputs() for writeline().
43   Version 1.6: i/o for sparsegraph; use of s6len; improve allocations
44   Version 1.7: Add stringcounts()
45   	       Add very long size code (see formats.txt)
46   Version 1.8: Add gtools_check()
47   Version 1.9: Add writepc_sg(), readpc_sg() and readpcle_sg()
48                Add planar_code options to opengraphfile()
49   Version 2.4: Add writeec_sg(), readec_sg()  (MISSING!)
50                Add edge_code options to opengraphfile()
51   Version 2.5: Remove sortints(), not used
52   Version 2.6: Add sgtog6() and writeg6_sg()
53   Version 2.7: Add lots of explicit casts.
54                Fix planar code output for n > 255.
55   Version 3.0: Procedures for incremental sparse6 format.
56                Add checkgline()
57   Version 4.0: Procedures for digraph6 format.
58   Version 4.1: Made encodegraphsize() external.
59   Version 4.2: Fixes for null graphs; thanks to Kevin Ryde.
60 */
61 
62 #define B(i) (1 << ((i)-1))
63 #define M(i) ((1 << (i))-1)
64 
65 /*********************************************************************
66 opengraphfile(filename,codetype,assumefixed,position)
67           opens and positions a file for reading graphs.
68 
69   filename = the name of the file to open
70                 (NULL means stdin, assumed already open)
71              If filename starts with "cmd:", the remainder is taken
72              to be a command to open a subshell for, using a pipe.
73   codetype   = returns a code for the format.
74                 This is a combination of SPARSE6, GRAPH6, PLANARCODE,
75                 PLANARCODELE, PLANARCODEBE, EDGECODE, DIGRAPH6,
76                 UNKNOWN_TYPE and HAS_HEADER.
77                 If a header is present, that overrides the data.
78                 If there is no header, the first graph is examined.
79   assumefixed = nonzero if files other than stdin or pipes should be
80                 assumed to be seekable and have equal record sizes.
81                 Ignored if there is a sparse6 header or the first
82                 graph has sparse6 format.
83   position = the number of the record to position to
84                 (the first is number 1; 0 and -NOLIMIT also mean
85                 to position at start).  planar_code files can only
86                 be positioned at the start.
87 
88   If the file starts with ">", there must be a header.
89   Otherwise opengraphfile() fails.
90 
91   The value returned is a file pointer or NULL.
92   If assumedfixed is not zero and position > 1, the global variable
93   ogf_linelen is set to the length (including \n) of the length of the
94   first record.  UPDATE
95 
96   The global variable is_pipe is set to whether the input file is a pipe.
97 
98 **********************************************************************/
99 
100 FILE*
opengraphfile(char * filename,int * codetype,int assumefixed,long position)101 opengraphfile(char *filename, int *codetype, int assumefixed, long position)
102 {
103     FILE *f;
104     int c,bl,firstc;
105     long i,l;
106     OFF_T_VER pos,pos1,pos2;
107     boolean bad_header;
108 
109     is_pipe = FALSE;
110 
111     if (filename == NULL)
112     {
113         f = stdin;
114         assumefixed = FALSE;
115     }
116     else
117     {
118         if (filename[0] == 'c' && filename[1] == 'm'
119             && filename[2] == 'd' && filename[3] == ':')
120         {
121 #if !HAVE_POPEN
122             gt_abort
123                (">E The \"cmd:\" option is not available in this version.\n");
124 #else
125             filename += 4;
126             while (*filename == ' ') ++filename;
127             f = popen(filename,"r");
128 #endif
129             assumefixed = FALSE;
130             is_pipe = TRUE;
131         }
132         else
133             f = fopen(filename,"r");
134 
135         if (f == NULL)
136         {
137              fprintf(stderr,">E opengraphfile: can't open %s\n",filename);
138             return NULL;
139         }
140     }
141 
142     FLOCKFILE(f);
143     firstc = c = GETC(f);
144     if (c == EOF)
145     {
146         *codetype = GRAPH6;
147         FUNLOCKFILE(f);
148         return f;
149     }
150 
151     if (c != '>')
152     {
153         *codetype = firstc == ':' ? SPARSE6 : firstc == '&' ? DIGRAPH6 : GRAPH6;
154         ungetc(c,f);
155     }
156     else
157     {
158         bad_header = FALSE;
159         if ((c = GETC(f)) == EOF || c != '>')
160             bad_header = TRUE;
161         if (!bad_header && ((c = GETC(f)) == EOF ||
162 	         (c != 'g' && c != 's' && c != 'p' && c != 'd' && c != 'e')))
163             bad_header = TRUE;
164         if (!bad_header && c == 'g')
165         {
166             if ((c = GETC(f)) == EOF || c != 'r' ||
167                 (c = GETC(f)) == EOF || c != 'a' ||
168                 (c = GETC(f)) == EOF || c != 'p' ||
169                 (c = GETC(f)) == EOF || c != 'h' ||
170                 (c = GETC(f)) == EOF || c != '6' ||
171                 (c = GETC(f)) == EOF || c != '<' ||
172                 (c = GETC(f)) == EOF || c != '<')
173                     bad_header = TRUE;
174             else
175                 *codetype = GRAPH6 | HAS_HEADER;
176         }
177         else if (!bad_header && c == 'd')
178         {
179             if ((c = GETC(f)) == EOF || c != 'i' ||
180                 (c = GETC(f)) == EOF || c != 'g' ||
181                 (c = GETC(f)) == EOF || c != 'r' ||
182                 (c = GETC(f)) == EOF || c != 'a' ||
183                 (c = GETC(f)) == EOF || c != 'p' ||
184                 (c = GETC(f)) == EOF || c != 'h' ||
185                 (c = GETC(f)) == EOF || c != '6' ||
186                 (c = GETC(f)) == EOF || c != '<' ||
187                 (c = GETC(f)) == EOF || c != '<')
188                     bad_header = TRUE;
189             else
190                 *codetype = DIGRAPH6 | HAS_HEADER;
191         }
192         else if (!bad_header && c == 'e')
193         {
194             if ((c = GETC(f)) == EOF || c != 'd' ||
195                 (c = GETC(f)) == EOF || c != 'g' ||
196                 (c = GETC(f)) == EOF || c != 'e' ||
197                 (c = GETC(f)) == EOF || c != '_' ||
198                 (c = GETC(f)) == EOF || c != 'c' ||
199                 (c = GETC(f)) == EOF || c != 'o' ||
200                 (c = GETC(f)) == EOF || c != 'd' ||
201                 (c = GETC(f)) == EOF || c != 'e' ||
202                 (c = GETC(f)) == EOF || c != '<' ||
203                 (c = GETC(f)) == EOF || c != '<')
204                     bad_header = TRUE;
205             else
206                 *codetype = EDGECODE | HAS_HEADER;
207         }
208         else if (!bad_header && c == 's')
209         {
210             if ((c = GETC(f)) == EOF || c != 'p' ||
211                 (c = GETC(f)) == EOF || c != 'a' ||
212                 (c = GETC(f)) == EOF || c != 'r' ||
213                 (c = GETC(f)) == EOF || c != 's' ||
214                 (c = GETC(f)) == EOF || c != 'e' ||
215                 (c = GETC(f)) == EOF || c != '6' ||
216                 (c = GETC(f)) == EOF || c != '<' ||
217                 (c = GETC(f)) == EOF || c != '<')
218                     bad_header = TRUE;
219             else
220                 *codetype = SPARSE6 | HAS_HEADER;
221         }
222         else if (!bad_header && c == 'p')
223         {
224             if ((c = GETC(f)) == EOF || c != 'l' ||
225                 (c = GETC(f)) == EOF || c != 'a' ||
226                 (c = GETC(f)) == EOF || c != 'n' ||
227                 (c = GETC(f)) == EOF || c != 'a' ||
228                 (c = GETC(f)) == EOF || c != 'r' ||
229                 (c = GETC(f)) == EOF || c != '_' ||
230                 (c = GETC(f)) == EOF || c != 'c' ||
231                 (c = GETC(f)) == EOF || c != 'o' ||
232                 (c = GETC(f)) == EOF || c != 'd' ||
233                 (c = GETC(f)) == EOF || c != 'e')
234 		    bad_header = TRUE;
235 	    else
236 	    {
237 		if ((c = GETC(f)) == EOF)
238 		    bad_header = TRUE;
239 		else if (c == ' ')
240 		{
241 		    if ((bl = GETC(f)) == EOF || (bl != 'l' && bl != 'b') ||
242 			(c = GETC(f)) == EOF || c != 'e' ||
243 			(c = GETC(f)) == EOF || c != '<' ||
244 			(c = GETC(f)) == EOF || c != '<')
245 			    bad_header = TRUE;
246 		    else if (bl == 'l')
247                 	*codetype = PLANARCODELE | HAS_HEADER;
248 		    else
249                 	*codetype = PLANARCODEBE | HAS_HEADER;
250 		}
251 		else if (c == '<')
252 		{
253 		    if ((c = GETC(f)) == EOF || c != '<')
254 			    bad_header = TRUE;
255                     else
256                         *codetype = PLANARCODE | HAS_HEADER;
257 		}
258 		else
259                     bad_header = TRUE;
260 	    }
261         }
262 
263         if (bad_header)
264         {
265             fprintf(stderr,">E opengraphfile: illegal header in %s\n",
266                     filename == NULL ? "stdin" : filename);
267             *codetype = UNKNOWN_TYPE | HAS_HEADER;
268             FUNLOCKFILE(f);
269             return NULL;
270         }
271     }
272 
273     if (position <= 1) return f;
274 
275     if (*codetype&PLANARCODEANY)
276     {
277 	fprintf(stderr,
278       ">E opengraphfile: planar_code files can only be opened at the start\n");
279 	*codetype = UNKNOWN_TYPE | HAS_HEADER;
280             FUNLOCKFILE(f);
281 	    fclose(f);
282             return NULL;
283     }
284 
285     if (*codetype&EDGECODE)
286     {
287 	fprintf(stderr,
288       ">E opengraphfile: edge_code files can only be opened at the start\n");
289 	*codetype = UNKNOWN_TYPE | HAS_HEADER;
290             FUNLOCKFILE(f);
291 	    fclose(f);
292             return NULL;
293     }
294 
295     if (!assumefixed || (*codetype&SPARSE6) || firstc == ':')
296     {
297         l = 1;
298         while ((c = GETC(f)) != EOF)
299         {
300             if (c == '\n')
301             {
302                 ++l;
303                 if (l == position) break;
304             }
305         }
306         if (l == position) return f;
307 
308         fprintf(stderr,
309            ">E opengraphfile: can't find line %ld in %s\n",position,
310             filename == NULL ? "stdin" : filename);
311         return NULL;
312     }
313     else
314     {
315         pos1 = FTELL_VER(f);
316         if (pos1 < 0)
317         {
318             fprintf(stderr,">E opengraphfile: error on first ftell\n");
319             return NULL;
320         }
321 
322         for (i = 1; (c = GETC(f)) != EOF && c != '\n'; ++i) {}
323         ogf_linelen = i;
324 
325         if (c == EOF)
326         {
327             fprintf(stderr,
328                     ">E opengraphfile: required record no present\n");
329             FUNLOCKFILE(f);
330             return NULL;
331         }
332 
333         pos2 = FTELL_VER(f);
334         if (pos2 < 0)
335         {
336             fprintf(stderr,">E opengraphfile: error on second ftell\n");
337             return NULL;
338         }
339 
340         pos = pos1 + (position-1)*(pos2-pos1);
341         if (FSEEK_VER(f,pos,SEEK_SET) < 0)
342         {
343             fprintf(stderr,">E opengraphfile: seek failed\n");
344             return NULL;
345         }
346     }
347 
348     FUNLOCKFILE(f);
349     return f;
350 }
351 
352 /*********************************************************************/
353 
354 void
writeline(FILE * f,char * s)355 writeline(FILE *f, char *s)
356 /* write a line with error checking */
357 /* \n is not appended automatically */
358 {
359     size_t slen;
360 
361     slen = strlen(s);
362 
363     if (fwrite(s,1,slen,f) != slen || ferror(f))
364         gt_abort(">E writeline : error on writing\n");
365 }
366 
367 /*********************************************************************/
368 /* This function used to be called getline(), but this was changed due
369    to too much confusion with the GNU function of that name.
370 */
371 
372 char*
gtools_getline(FILE * f)373 gtools_getline(FILE *f)     /* read a line with error checking */
374 /* includes \n (if present) and \0.  Immediate EOF causes NULL return. */
375 {
376     DYNALLSTAT(char,s,s_sz);
377     int c;
378     long i;
379 
380     DYNALLOC1(char,s,s_sz,5000,"gtools_getline");
381 
382     FLOCKFILE(f);
383     i = 0;
384     while ((c = GETC(f)) != EOF && c != '\n')
385     {
386         if (i == s_sz-3)
387             DYNREALLOC(char,s,s_sz,3*(s_sz/2)+10000,"gtools_getline");
388         s[i++] = (char)c;
389     }
390     FUNLOCKFILE(f);
391 
392     if (i == 0 && c == EOF) return NULL;
393 
394     if (c == '\n') s[i++] = '\n';
395     s[i] = '\0';
396     return s;
397 }
398 
399 /****************************************************************************/
400 
401 char*
getecline(FILE * f)402 getecline(FILE *f)     /* read an edge_code line */
403 /* No trailing \n or \0 is added.  Immediate EOF causes NULL return. */
404 {
405     size_t headsize,bodysize;
406     int sizesize,edgesize;
407     int c1,c,i;
408     DYNALLSTAT(unsigned char,s,s_sz);
409 
410     FLOCKFILE(f);
411     if ((c1 = GETC(f)) == EOF) return NULL;
412 
413     if (c1 > 0)
414     {
415         bodysize = c1;
416         edgesize = 1;
417         headsize = 1;
418     }
419     else
420     {
421         if ((c = GETC(f)) == EOF)
422             gt_abort(">E Incomplete edge_code line\n");
423         else
424         {
425             sizesize = c >> 4;
426             edgesize = c & 0xF;
427             bodysize = 0;
428             for (i = 0; i < sizesize; ++i)
429             {
430                 if ((c = GETC(f)) == EOF)
431                     gt_abort(">E Incomplete edge_code line\n");
432                 else
433                     bodysize = (bodysize << 8) + c;
434             }
435             headsize = 2 + sizesize;
436         }
437     }
438 
439     DYNALLOC1(unsigned char,s,s_sz,headsize+bodysize,"getecline");
440 
441     s[0] = (unsigned char)c1;
442     if (c1 == 0)
443     {
444         s[1] = (char)((sizesize << 4) + edgesize);
445         for (i = 0; i < sizesize; ++i)
446             s[headsize-1-i] = (bodysize >> 8*i) & 0xFF;
447     }
448 
449     if (bodysize > 0 && fread(s+headsize,bodysize,1,f) != bodysize)
450         gt_abort(">E Incomplete edge_code line\n");
451 
452     FUNLOCKFILE(f);
453     return (char*)s;
454 }
455 
456 int
graphsize(char * s)457 graphsize(char *s)
458 /* Get size of graph out of graph6, digraph6 or sparse6 string. */
459 {
460     char *p;
461     int n;
462 
463     if (s[0] == ':' || s[0] == '&') p = s+1;
464     else                            p = s;
465     n = *p++ - BIAS6;
466 
467     if (n > SMALLN)
468     {
469         n = *p++ - BIAS6;
470         if (n > SMALLN)
471         {
472             n = *p++ - BIAS6;
473             n = (n << 6) | (*p++ - BIAS6);
474             n = (n << 6) | (*p++ - BIAS6);
475             n = (n << 6) | (*p++ - BIAS6);
476             n = (n << 6) | (*p++ - BIAS6);
477             n = (n << 6) | (*p++ - BIAS6);
478         }
479         else
480         {
481             n = (n << 6) | (*p++ - BIAS6);
482             n = (n << 6) | (*p++ - BIAS6);
483         }
484     }
485     return n;
486 }
487 
488 /****************************************************************************/
489 
490 void
encodegraphsize(int n,char ** pp)491 encodegraphsize(int n, char **pp)
492 /* Encode the size n in a string starting at **p, and reset **p
493    to point to the character after the size */
494 {
495     char *p;
496 
497     p = *pp;
498     if (n <= SMALLN)
499         *p++ = (char)(BIAS6 + n);
500     else if (n <= SMALLISHN)
501     {
502         *p++ = MAXBYTE;
503         *p++ = (char)(BIAS6 + (n >> 12));
504         *p++ = (char)(BIAS6 + ((n >> 6) & C6MASK));
505         *p++ = (char)(BIAS6 + (n & C6MASK));
506     }
507     else
508     {
509         *p++ = MAXBYTE;
510         *p++ = MAXBYTE;
511         *p++ = (char)(BIAS6 + (n >> 30));
512         *p++ = (char)(BIAS6 + ((n >> 24) & C6MASK));
513         *p++ = (char)(BIAS6 + ((n >> 18) & C6MASK));
514         *p++ = (char)(BIAS6 + ((n >> 12) & C6MASK));
515         *p++ = (char)(BIAS6 + ((n >> 6) & C6MASK));
516         *p++ = (char)(BIAS6 + (n & C6MASK));
517     }
518 
519     *pp = p;
520 }
521 
522 /****************************************************************************/
523 
524 void
stringcounts(char * s,int * pn,size_t * pe)525 stringcounts(char *s, int *pn, size_t *pe)
526 /* Determine number of edges of graph6, digraph6 or sparse6 string */
527 {
528     char *p;
529     int i,j,k,x,nb,v,n,need;
530     size_t count;
531     boolean done;
532 
533     n = graphsize(s);
534     *pn = n;
535 
536     p = s + (s[0] == ':' || s[0] == '&') + SIZELEN(n);
537 
538     if (s[0] == ':')  /* sparse6 */
539     {
540         count = 0;
541 
542         for (i = n-1, nb = 0; i > 0 ; i >>= 1, ++nb) {}
543         k = 0;
544         v = 0;
545         done = FALSE;
546         while (!done)
547         {
548             if (k == 0)
549             {
550                 x = *(p++);
551                 if (x == '\n' || x == '\0')
552                 {
553                     done = TRUE; continue;
554                 }
555                 else
556                 {
557                     x -= BIAS6; k = 6;
558                 }
559             }
560             if ((x & B(k))) ++v;
561             --k;
562 
563             need = nb;
564             j = 0;
565             while (need > 0 && !done)
566             {
567                 if (k == 0)
568                 {
569                     x = *(p++);
570                     if (x == '\n' || x == '\0')
571                     {
572                         done = TRUE; continue;
573                     }
574                     else
575                     {
576                         x -= BIAS6; k = 6;
577                     }
578                 }
579                 if (need >= k)
580                 {
581                     j = (j << k) | (x & M(k));
582                     need -= k; k = 0;
583                 }
584                 else
585                 {
586                     k -= need;
587                     j = (j << need) | ((x >> k) & M(need));
588                     need = 0;
589                 }
590             }
591             if (done) continue;
592 
593             if (j > v)
594                 v = j;
595             else if (v < n)
596                 ++count;
597 	}
598     }
599     else  /* graph6 or digraph6 */
600     {
601 	count = 0;
602 	for (; *p != '\n' && *p != '\0'; ++p)
603 	    count += bytecount[*p - BIAS6];
604     }
605 
606     *pe = count;
607 }
608 
609 /****************************************************************************/
610 
611 void
stringtograph(char * s,graph * g,int m)612 stringtograph(char *s, graph *g, int m)
613 /* Convert string (graph6, digraph6 or sparse6 format) to graph. */
614 /* Assumes g is big enough to hold it.   */
615 {
616     char *p;
617     int n,i,j,k,v,x,nb,need;
618     size_t ii;
619     set *gi,*gj;
620     boolean done;
621 
622     n = graphsize(s);
623     if (n == 0) return;
624 
625     p = s + (s[0] == ':' || s[0] == '&') + SIZELEN(n);
626 
627     if (TIMESWORDSIZE(m) < n)
628         gt_abort(">E stringtograph: impossible m value\n");
629 
630     for (ii = m*(size_t)n; --ii > 0;) g[ii] = 0;
631     g[0] = 0;
632 
633     if (s[0] != ':' && s[0] != '&')       /* graph6 format */
634     {
635         k = 1;
636         for (j = 1; j < n; ++j)
637         {
638             gj = GRAPHROW(g,j,m);
639 
640             for (i = 0; i < j; ++i)
641             {
642                 if (--k == 0)
643                 {
644                     k = 6;
645                     x = *(p++) - BIAS6;
646                 }
647 
648                 if ((x & TOPBIT6))
649                 {
650                     gi = GRAPHROW(g,i,m);
651                     ADDELEMENT(gi,j);
652                     ADDELEMENT(gj,i);
653                 }
654                 x <<= 1;
655             }
656         }
657     }
658     else if (s[0] == '&')
659     {
660         k = 1;
661         for (i = 0; i < n; ++i)
662         {
663             gi = GRAPHROW(g,i,m);
664 
665             for (j = 0; j < n; ++j)
666             {
667                 if (--k == 0)
668                 {
669                     k = 6;
670                     x = *(p++) - BIAS6;
671                 }
672 
673                 if ((x & TOPBIT6))
674                 {
675                     ADDELEMENT(gi,j);
676                 }
677                 x <<= 1;
678             }
679         }
680     }
681     else    /* sparse6 format */
682     {
683         for (i = n-1, nb = 0; i > 0 ; i >>= 1, ++nb) {}
684 
685         k = 0;
686         v = 0;
687 	done = FALSE;
688         while (!done)
689         {
690 	    if (k == 0)
691 	    {
692 		x = *(p++);
693 		if (x == '\n' || x == '\0')
694 		{
695 		    done = TRUE; continue;
696 		}
697 		else
698 		{
699 		    x -= BIAS6; k = 6;
700 		}
701 	    }
702 	    if ((x & B(k))) ++v;
703 	    --k;
704 
705 	    need = nb;
706 	    j = 0;
707 	    while (need > 0 && !done)
708 	    {
709 		if (k == 0)
710 		{
711 		    x = *(p++);
712 		    if (x == '\n' || x == '\0')
713 		    {
714 		        done = TRUE; continue;
715 		    }
716 		    else
717 		    {
718 		       	x -= BIAS6; k = 6;
719 		    }
720 		}
721 		if (need >= k)
722 		{
723 		    j = (j << k) | (x & M(k));
724 		    need -= k; k = 0;
725 		}
726 		else
727 		{
728 		    k -= need;
729 		    j = (j << need) | ((x >> k) & M(need));
730 		    need = 0;
731 		}
732 	    }
733 	    if (done) continue;
734 
735 	    if (j > v)
736 		v = j;
737 	    else if (v < n)
738 	    {
739 		ADDELEMENT(GRAPHROW(g,v,m),j);
740 		ADDELEMENT(GRAPHROW(g,j,m),v);
741 	    }
742         }
743     }
744 }
745 
746 /****************************************************************************/
747 
748 void
stringtograph_inc(char * s,graph * g,int m,graph * prevg,int prevn)749 stringtograph_inc(char *s, graph *g, int m,
750                   graph *prevg, int prevn)
751 /* Convert string (graph6, digraph6 or sparse6 format) to graph,
752    allowing incremental sparse6 format with a prior graph assumed
753    to have matching m,n values.
754    If prevg != NULL and type is is6, use prevg as prior graph.
755    Assumes g is big enough to hold it.
756    *digraph is set according to the graph type.
757 */
758 {
759     char *p;
760     int n,i,j,k,v,x,nb,need;
761     size_t ii;
762     set *gi,*gj;
763     boolean done;
764 
765     if (s[0] == ';' && !prevg)
766         gt_abort(">E stringtograph_inc missing prior graph\n");
767 
768     if (s[0] == ';')
769     {
770 	n = prevn;
771 	if (n == 0) return;
772 	p = s + 1;
773         for (ii = m*(size_t)n; --ii > 0;) g[ii] = prevg[ii];
774         g[0] = prevg[0];
775     }
776     else
777     {
778         n = graphsize(s);
779         if (n == 0) return;
780         p = s + (s[0] == ':' || s[0] == '&') + SIZELEN(n);
781         for (ii = m*(size_t)n; --ii > 0;) g[ii] = 0;
782         g[0] = 0;
783     }
784 
785     if (TIMESWORDSIZE(m) < n)
786         gt_abort(">E stringtograph_inc: impossible m value\n");
787 
788     if (s[0] != ':' && s[0] != ';' && s[0] != '&')   /* graph6 format */
789     {
790         k = 1;
791         for (j = 1; j < n; ++j)
792         {
793             gj = GRAPHROW(g,j,m);
794 
795             for (i = 0; i < j; ++i)
796             {
797                 if (--k == 0)
798                 {
799                     k = 6;
800                     x = *(p++) - BIAS6;
801                 }
802 
803                 if ((x & TOPBIT6))
804                 {
805                     gi = GRAPHROW(g,i,m);
806                     FLIPELEMENT(gi,j);
807                     if (i != j) FLIPELEMENT(gj,i);
808                 }
809                 x <<= 1;
810             }
811         }
812     }
813     else if (s[0] == '&')       /* digraph6 format */
814     {
815         k = 1;
816         for (j = 0; j < n; ++j)
817         {
818             gj = GRAPHROW(g,j,m);
819 
820             for (i = 0; i < n; ++i)
821             {
822                 if (--k == 0)
823                 {
824                     k = 6;
825                     x = *(p++) - BIAS6;
826                 }
827 
828                 if ((x & TOPBIT6))
829                 {
830                     FLIPELEMENT(gj,i);
831                 }
832                 x <<= 1;
833             }
834         }
835     }
836     else    /* sparse6 format */
837     {
838         for (i = n-1, nb = 0; i != 0 ; i >>= 1, ++nb) {}
839 
840         k = 0;
841         v = 0;
842 	done = FALSE;
843         while (!done)
844         {
845 	    if (k == 0)
846 	    {
847 		x = *(p++);
848 		if (x == '\n' || x == '\0')
849 		{
850 		    done = TRUE; continue;
851 		}
852 		else
853 		{
854 		    x -= BIAS6; k = 6;
855 		}
856 	    }
857 	    if ((x & B(k))) ++v;
858 	    --k;
859 
860 	    need = nb;
861 	    j = 0;
862 	    while (need > 0 && !done)
863 	    {
864 		if (k == 0)
865 		{
866 		    x = *(p++);
867 		    if (x == '\n' || x == '\0')
868 		    {
869 		        done = TRUE; continue;
870 		    }
871 		    else
872 		    {
873 		       	x -= BIAS6; k = 6;
874 		    }
875 		}
876 		if (need >= k)
877 		{
878 		    j = (j << k) | (x & M(k));
879 		    need -= k; k = 0;
880 		}
881 		else
882 		{
883 		    k -= need;
884 		    j = (j << need) | ((x >> k) & M(need));
885 		    need = 0;
886 		}
887 	    }
888 	    if (done) continue;
889 
890 	    if (j > v)
891 		v = j;
892 	    else if (v < n)
893 	    {
894 		FLIPELEMENT(GRAPHROW(g,v,m),j);
895 		if (j != v) FLIPELEMENT(GRAPHROW(g,j,m),v);
896 	    }
897         }
898     }
899 }
900 
901 /***********************************************************************/
902 
903 graph*                 /* read graph into nauty format */
readgg(FILE * f,graph * g,int reqm,int * pm,int * pn,boolean * digraph)904 readgg(FILE *f, graph *g, int reqm, int *pm, int *pn, boolean *digraph)
905 /* graph6, digraph6 and sparse6 formats are supported
906    f = an open file
907    g = place to put the answer (NULL for dynamic allocation)
908    reqm = the requested value of m (0 => compute from n)
909    *pm = the actual value of m
910    *pn = the value of n
911    *digraph = whether the input is a digraph
912 */
913 {
914     char *s,*p;
915     int m,n;
916 
917     if ((readg_line = gtools_getline(f)) == NULL) return NULL;
918 
919     s = readg_line;
920     if (s[0] == ':')
921     {
922         readg_code = SPARSE6;
923         *digraph = FALSE;
924         p = s + 1;
925     }
926     else if (s[0] == '&')
927     {
928 	readg_code = DIGRAPH6;
929         *digraph = TRUE;
930 	p = s + 1;
931     }
932     else
933     {
934         readg_code = GRAPH6;
935         *digraph = FALSE;
936         p = s;
937     }
938 
939     while (*p >= BIAS6 && *p <= MAXBYTE)
940         ++p;
941     if (*p == '\0')
942         gt_abort(">E readgg: missing newline\n");
943     else if (*p != '\n')
944         gt_abort(">E readgg: illegal character\n");
945 
946     n = graphsize(s);
947     if (readg_code == GRAPH6 && p - s != G6LEN(n))
948         gt_abort(">E readgg: truncated graph6 line\n");
949     if (readg_code == DIGRAPH6 && p - s != D6LEN(n))
950         gt_abort(">E readgg: truncated digraph6 line\n");
951 
952     if (reqm > 0 && TIMESWORDSIZE(reqm) < n)
953         gt_abort(">E readgg: reqm too small\n");
954     else if (reqm > 0)
955         m = reqm;
956     else
957         m = (n + WORDSIZE - 1) / WORDSIZE;
958 
959     if (g == NULL)
960     {
961         if ((g = (graph*)ALLOCS(n,m*sizeof(graph))) == NULL)
962             gt_abort(">E readgg: malloc failed\n");
963     }
964 
965     *pn = n;
966     *pm = m;
967 
968     stringtograph(s,g,m);
969     return g;
970 }
971 
972 /***********************************************************************/
973 
974 graph*                 /* read undirected graph into nauty format */
readg(FILE * f,graph * g,int reqm,int * pm,int * pn)975 readg(FILE *f, graph *g, int reqm, int *pm, int *pn)
976 /* graph6 and sparse6 formats are supported
977    f = an open file
978    g = place to put the answer (NULL for dynamic allocation)
979    reqm = the requested value of m (0 => compute from n)
980    *pm = the actual value of m
981    *pn = the value of n
982 
983    Only allows undirected graphs.
984 */
985 {
986     boolean digraph;
987     graph *gg;
988 
989     gg = readgg(f,g,reqm,pm,pn,&digraph);
990 
991     if (!gg) return NULL;
992     if (digraph)
993         gt_abort(">E readg() doesn't all digraphs; use readgg()\n");
994     return gg;
995 }
996 
997 /***********************************************************************/
998 
999 int
checkgline(char * s)1000 checkgline(char *s)
1001 /* Check if s[0..] appears to be a graph input line.  A complete check
1002    is not performed.  Note that graph input lines must end with \n.
1003    The value returned is 0 if no errors are found, otherwise:
1004      1 = missing newline
1005      2 = illegal character
1006      3 = graph6 or digraph6 line with wrong length
1007 */
1008 {
1009     char *p;
1010     int n,t;
1011 
1012     if (s[0] == ':' || s[0] == ';')
1013     {
1014 	t = SPARSE6;
1015 	p = s + 1;
1016     }
1017     else if (s[0] == '&')
1018     {
1019 	t = DIGRAPH6;
1020 	p = s + 1;
1021     }
1022     else
1023     {
1024 	t = GRAPH6;
1025 	p = s;
1026     }
1027 
1028     while (*p >= BIAS6 && *p <= MAXBYTE)
1029         ++p;
1030     if (*p == '\0')
1031         return 1;
1032     else if (*p != '\n')
1033         return 2;
1034 
1035     if (t == GRAPH6)
1036     {
1037 	n = graphsize(s);
1038 	if (p - s != G6LEN(n)) return 3;
1039     }
1040 
1041     if (t == DIGRAPH6)
1042     {
1043 	n = graphsize(s);
1044 	if (p - s != D6LEN(n)) return 3;
1045     }
1046 
1047     return 0;
1048 }
1049 
1050 /***********************************************************************/
1051 
1052 graph*                 /* read graph into nauty format */
readgg_inc(FILE * f,graph * g,int reqm,int * pm,int * pn,graph * prevg,int prevm,int prevn,boolean * digraph)1053 readgg_inc(FILE *f, graph *g, int reqm, int *pm, int *pn,
1054  	  graph *prevg, int prevm, int prevn, boolean *digraph)
1055 /* graph6, digraph6 and sparse6 formats are supported
1056    f = an open file
1057    g = place to put the answer (NULL for dynamic allocation)
1058    reqm = the requested value of m (0 => compute from n)
1059           This is ignored for an incremental input.
1060    *pm = the actual value of m
1061    *pn = the value of n
1062    *digraph = whether the input is a digraph
1063    If prevg!=NULL, it is a prior graph for use in case the next
1064    input is a sparse6 increment.
1065 */
1066 {
1067     char *s,*p;
1068     int m,n;
1069 
1070     if ((readg_line = gtools_getline(f)) == NULL) return NULL;
1071 
1072     s = readg_line;
1073     if (s[0] == ':')
1074     {
1075         readg_code = SPARSE6;
1076 	*digraph = FALSE;
1077         p = s + 1;
1078     }
1079     else if (s[0] == ';')
1080     {
1081         readg_code = INCSPARSE6;
1082 	*digraph = FALSE;
1083         p = s + 1;
1084     }
1085     else if (s[0] == '&')
1086     {
1087 	readg_code = DIGRAPH6;
1088 	*digraph = TRUE;
1089 	p = s + 1;
1090     }
1091     else
1092     {
1093         readg_code = GRAPH6;
1094 	*digraph = FALSE;
1095         p = s;
1096     }
1097 
1098     while (*p >= BIAS6 && *p <= MAXBYTE)
1099         ++p;
1100     if (*p == '\0')
1101         gt_abort(">E readg_inc: missing newline\n");
1102     else if (*p != '\n')
1103         gt_abort(">E readg_inc: illegal character\n");
1104 
1105     if (readg_code == INCSPARSE6)
1106     {
1107 	if (prevg == NULL) gt_abort(">E readg_inc: missing prior\n");
1108 	n = prevn;
1109 	m = prevm;
1110     }
1111     else
1112     {
1113         n = graphsize(s);
1114         if (readg_code == GRAPH6 && p - s != G6LEN(n))
1115             gt_abort(">E readg_inc: truncated graph6 line\n");
1116         if (readg_code == DIGRAPH6 && p - s != D6LEN(n))
1117             gt_abort(">E readg_inc: truncated digraph6 line\n");
1118 
1119         if (reqm > 0 && TIMESWORDSIZE(reqm) < n)
1120             gt_abort(">E readg_inc: reqm too small\n");
1121         else if (reqm > 0)
1122             m = reqm;
1123         else
1124             m = SETWORDSNEEDED(n);
1125     }
1126 
1127     if (g == NULL)
1128     {
1129         if ((g = (graph*)ALLOCS(n,m*sizeof(graph))) == NULL)
1130             gt_abort(">E readg_inc: malloc failed\n");
1131     }
1132 
1133     *pn = n;
1134     *pm = m;
1135 
1136     stringtograph_inc(s,g,m,prevg,prevn);
1137 
1138     return g;
1139 }
1140 
1141 /***********************************************************************/
1142 
1143 graph*              /* read undirected graph into nauty format */
readg_inc(FILE * f,graph * g,int reqm,int * pm,int * pn,graph * prevg,int prevm,int prevn)1144 readg_inc(FILE *f, graph *g, int reqm, int *pm, int *pn,
1145  	  graph *prevg, int prevm, int prevn)
1146 /* graph6 and sparse6 formats are supported
1147    f = an open file
1148    g = place to put the answer (NULL for dynamic allocation)
1149    reqm = the requested value of m (0 => compute from n)
1150           This is ignored for an incremental input.
1151    *pm = the actual value of m
1152    *pn = the value of n
1153    *digraph = whether the input is a digraph
1154    If prevg!=NULL, it is a prior graph for use in case the next
1155    input is a sparse6 increment.
1156 */
1157 {
1158     boolean digraph;
1159     graph *gg;
1160 
1161     gg = readgg_inc(f,g,reqm,pm,pn,prevg,prevm,prevn,&digraph);
1162 
1163     if (!gg) return NULL;
1164     if (digraph)
1165         gt_abort(">E readg_inc() doesn't all digraphs; use readgg_inc()\n");
1166     return gg;
1167 }
1168 
1169 /****************************************************************************/
1170 
1171 void
stringtosparsegraph(char * s,sparsegraph * sg,int * nloops)1172 stringtosparsegraph(char *s, sparsegraph *sg, int *nloops)
1173 /* Convert string (graph6, digraph6 or sparse6 format)
1174  * to sparse graph.
1175  * Assumes sg exists and is initialised
1176  * Also returns the number of loops  */
1177 {
1178     char *p,*q;
1179     int n,nde,i,j,k,vv,x,nb,need;
1180     int *d,*e;
1181     size_t *v;
1182     int loops;
1183     boolean done;
1184 
1185     n = graphsize(s);
1186 
1187     q = s + (s[0] == ':' || s[0] == '&') + SIZELEN(n);
1188 
1189     sg->nv = n;
1190 
1191     DYNALLOC1(size_t,sg->v,sg->vlen,n,"stringtosparsegraph");
1192     DYNALLOC1(int,sg->d,sg->dlen,n,"stringtosparsegraph");
1193 
1194     v = sg->v;
1195     d = sg->d;
1196     for (i = 0; i < n; ++i) d[i] = 0;
1197 
1198     if (s[0] != ':' && s[0] != '&')       /* graph6 format */
1199     {
1200         p = q;
1201         k = 1;
1202         for (j = 1; j < n; ++j)
1203         {
1204             for (i = 0; i < j; ++i)
1205             {
1206                 if (--k == 0)
1207                 {
1208                     k = 6;
1209                     x = *(p++) - BIAS6;
1210                 }
1211 
1212                 if ((x & TOPBIT6))
1213                 {
1214                     d[i]++;
1215                     d[j]++;
1216                 }
1217                 x <<= 1;
1218             }
1219         }
1220 
1221         nde = 0;
1222         for (i = 0; i < n; ++i)
1223         {
1224             v[i] = nde; nde += d[i]; d[i] = 0;
1225         }
1226         sg->nde = nde;
1227         DYNALLOC1(int,sg->e,sg->elen,nde,"stringtosparsegraph");
1228         e = sg->e;
1229 
1230         p = q;
1231         k = 1;
1232 
1233         for (j = 1; j < n; ++j)
1234         {
1235             for (i = 0; i < j; ++i)
1236             {
1237                 if (--k == 0)
1238                 {
1239                     k = 6;
1240                     x = *(p++) - BIAS6;
1241                 }
1242 
1243                 if ((x & TOPBIT6))
1244                 {
1245                     e[v[i]+d[i]++] = j;
1246                     e[v[j]+d[j]++] = i;
1247                 }
1248                 x <<= 1;
1249             }
1250         }
1251 
1252 	*nloops = 0;
1253     }
1254     else if (s[0] == '&')    /* digraph6 */
1255     {
1256         p = q;
1257         k = 1;
1258         for (j = 0; j < n; ++j)
1259         {
1260             for (i = 0; i < n; ++i)
1261             {
1262                 if (--k == 0)
1263                 {
1264                     k = 6;
1265                     x = *(p++) - BIAS6;
1266                 }
1267 
1268                 if ((x & TOPBIT6))
1269                     d[j]++;
1270                 x <<= 1;
1271             }
1272         }
1273 
1274         nde = 0;
1275         for (i = 0; i < n; ++i)
1276         {
1277             v[i] = nde; nde += d[i]; d[i] = 0;
1278         }
1279         sg->nde = nde;
1280         DYNALLOC1(int,sg->e,sg->elen,nde,"stringtosparsegraph");
1281         e = sg->e;
1282 
1283         p = q;
1284         k = 1;
1285 
1286 	*nloops = 0;
1287         for (j = 0; j < n; ++j)
1288         {
1289             for (i = 0; i < n; ++i)
1290             {
1291                 if (--k == 0)
1292                 {
1293                     k = 6;
1294                     x = *(p++) - BIAS6;
1295                 }
1296 
1297                 if ((x & TOPBIT6))
1298                 {
1299                     e[v[j]+d[j]++] = i;
1300 		    if (i == j) ++*nloops;
1301                 }
1302                 x <<= 1;
1303             }
1304         }
1305     }
1306     else    /* sparse6 format */
1307     {
1308         for (i = n-1, nb = 0; i > 0 ; i >>= 1, ++nb) {}
1309 
1310         p = q;
1311 
1312         k = 0;
1313         vv = 0;
1314         done = FALSE;
1315 	loops = 0;
1316         while (!done)
1317         {
1318             if (k == 0)
1319             {
1320                 x = *(p++);
1321                 if (x == '\n' || x == '\0')
1322                 {
1323                     done = TRUE; continue;
1324                 }
1325                 else
1326                 {
1327                     x -= BIAS6; k = 6;
1328                 }
1329             }
1330             if ((x & B(k))) ++vv;
1331             --k;
1332 
1333             need = nb;
1334             j = 0;
1335             while (need > 0 && !done)
1336             {
1337                 if (k == 0)
1338                 {
1339                     x = *(p++);
1340                     if (x == '\n' || x == '\0')
1341                     {
1342                         done = TRUE; continue;
1343                     }
1344                     else
1345                     {
1346                         x -= BIAS6; k = 6;
1347                     }
1348                 }
1349                 if (need >= k)
1350                 {
1351                     j = (j << k) | (x & M(k));
1352                     need -= k; k = 0;
1353                 }
1354                 else
1355                 {
1356                     k -= need;
1357                     j = (j << need) | ((x >> k) & M(need));
1358                     need = 0;
1359                 }
1360             }
1361             if (done) continue;
1362 
1363             if (j > vv)
1364                 vv = j;
1365             else if (vv < n)
1366             {
1367                 d[vv]++;
1368                 if (vv != j) d[j]++;
1369 		else         ++loops;
1370             }
1371         }
1372 
1373         nde = 0;
1374         for (i = 0; i < n; ++i)
1375         {
1376             v[i] = nde; nde += d[i]; d[i] = 0;
1377         }
1378         sg->nde = nde;
1379         DYNALLOC1(int,sg->e,sg->elen,nde,"stringtosparsegraph");
1380         e = sg->e;
1381 
1382 	p = q;
1383 
1384         k = 0;
1385         vv = 0;
1386         done = FALSE;
1387         while (!done)
1388         {
1389             if (k == 0)
1390             {
1391                 x = *(p++);
1392                 if (x == '\n' || x == '\0')
1393                 {
1394                     done = TRUE; continue;
1395                 }
1396                 else
1397                 {
1398                     x -= BIAS6; k = 6;
1399                 }
1400             }
1401             if ((x & B(k))) ++vv;
1402             --k;
1403 
1404             need = nb;
1405             j = 0;
1406             while (need > 0 && !done)
1407             {
1408                 if (k == 0)
1409                 {
1410                     x = *(p++);
1411                     if (x == '\n' || x == '\0')
1412                     {
1413                         done = TRUE; continue;
1414                     }
1415                     else
1416                     {
1417                         x -= BIAS6; k = 6;
1418                     }
1419                 }
1420                 if (need >= k)
1421                 {
1422                     j = (j << k) | (x & M(k));
1423                     need -= k; k = 0;
1424                 }
1425                 else
1426                 {
1427                     k -= need;
1428                     j = (j << need) | ((x >> k) & M(need));
1429                     need = 0;
1430                 }
1431             }
1432             if (done) continue;
1433 
1434             if (j > vv)
1435                 vv = j;
1436             else if (vv < n)
1437             {
1438                 e[v[vv]+d[vv]++] = j;
1439                 if (vv != j) e[v[j]+d[j]++] = vv;
1440             }
1441         }
1442 	*nloops = loops;
1443     }
1444 }
1445 
1446 /***********************************************************************/
1447 
1448 sparsegraph*               /* read graph into sparsegraph format */
read_sgg_loops(FILE * f,sparsegraph * sg,int * nloops,boolean * digraph)1449 read_sgg_loops(FILE *f, sparsegraph *sg, int *nloops, boolean *digraph)
1450 /* graph6, digraph6 and sparse6 formats are supported
1451  * f = an open file
1452  * sg = place to put the answer (NULL for dynamic allocation)
1453  *      - must be initialised if not NULL
1454  * nloops := number of loops (each loop in a sparse6 string
1455  *        gives one loop in the sparse representation)
1456  */
1457 {
1458     char *s,*p;
1459     int n,loops;
1460 
1461     if ((readg_line = gtools_getline(f)) == NULL) return NULL;
1462 
1463     s = readg_line;
1464     if (s[0] == ':')
1465     {
1466         readg_code = SPARSE6;
1467 	*digraph = FALSE;
1468         p = s + 1;
1469     }
1470     else if (s[0] == '&')
1471     {
1472 	readg_code = DIGRAPH6;
1473         *digraph = TRUE;
1474 	p = s + 1;
1475     }
1476     else
1477     {
1478         readg_code = GRAPH6;
1479         *digraph = FALSE;
1480         p = s;
1481     }
1482 
1483     while (*p >= BIAS6 && *p <= MAXBYTE)
1484         ++p;
1485     if (*p == '\0')
1486         gt_abort(">E read_sg: missing newline\n");
1487     else if (*p != '\n')
1488         gt_abort(">E read_sg: illegal character\n");
1489 
1490     n = graphsize(s);
1491     if (readg_code == GRAPH6 && p - s != G6LEN(n))
1492         gt_abort(">E read_sg: truncated graph6 line\n");
1493     if (readg_code == DIGRAPH6 && p - s != D6LEN(n))
1494         gt_abort(">E read_sg: truncated digraph6 line\n");
1495 
1496     if (sg == NULL)
1497     {
1498         if ((sg = (sparsegraph*)ALLOCS(1,sizeof(sparsegraph))) == NULL)
1499             gt_abort(">E read_sg: malloc failed\n");
1500         SG_INIT(*sg);
1501     }
1502 
1503     stringtosparsegraph(s,sg,&loops);
1504     *nloops = loops;
1505 
1506     return sg;
1507 }
1508 
1509 /***********************************************************************/
1510 
1511 sparsegraph*          /* read undirected graph into sparsegraph format */
read_sg_loops(FILE * f,sparsegraph * sg,int * nloops)1512 read_sg_loops(FILE *f, sparsegraph *sg, int *nloops)
1513 /* graph6 and sparse6 formats are supported
1514  * f = an open file
1515  * sg = place to put the answer (NULL for dynamic allocation)
1516  *      - must be initialised if not NULL
1517  * nloops := number of loops (each loop in a sparse6 string
1518  *        gives one loop in the sparse representation)
1519  * digraph = whether input line was a digraph
1520  */
1521 {
1522     sparsegraph *sgg;
1523     boolean digraph;
1524 
1525     sgg = read_sgg_loops(f,sg,nloops,&digraph);
1526     if (!sgg) return NULL;
1527     if (digraph) gt_abort(">E read_sg_loops() can't handle digraphs,"
1528                   " use read_sgg_loops()\n");
1529     return sgg;
1530 }
1531 
1532 /***********************************************************************/
1533 
1534 sparsegraph*                 /* read graph into sparsegraph format */
read_sg(FILE * f,sparsegraph * sg)1535 read_sg(FILE *f, sparsegraph *sg)
1536 /* graph6 and sparse6 formats are supported
1537  *  *f = an open file
1538  *  *sg = place to put the answer (NULL for dynamic allocation)
1539  *      - must be initialised if not NULL
1540  */
1541 {
1542     int loops;
1543     sparsegraph *sgg;
1544     boolean digraph;
1545 
1546     sgg = read_sgg_loops(f,sg,&loops,&digraph);
1547     if (!sgg) return NULL;
1548     if (digraph) gt_abort(">E read_sg() can't handle digraphs,"
1549                   " use read_sgg_loops()\n");
1550     return sgg;
1551 }
1552 
1553 /****************************************************************************/
1554 
1555 DYNALLSTAT(char,gcode,gcode_sz);  /* Used by ntog6, ntos6, ntod6 and sgtos6 */
1556 TLS_ATTR size_t s6len;
1557 TLS_ATTR int readg_code;
1558 TLS_ATTR char *readg_line;
1559 
1560 /****************************************************************************/
1561 
1562 char*
ntod6(graph * g,int m,int n)1563 ntod6(graph *g, int m, int n)
1564 /* convert nauty graph to digraph6 string, including \n and \0 */
1565 {
1566     int i,j,k;
1567     char *p,x;
1568     set *gj;
1569     size_t ii;
1570 
1571     ii = D6LEN(n)+3;
1572 
1573     DYNALLOC1(char,gcode,gcode_sz,ii,"ntod6");
1574 
1575     p = gcode;
1576     *p++ = '&';
1577     encodegraphsize(n,&p);
1578 
1579     k = 6;
1580     x = 0;
1581 
1582     for (j = 0; j < n; ++j)
1583     {
1584         gj = GRAPHROW(g,j,m);
1585         for (i = 0; i < n; ++i)
1586         {
1587             x <<= 1;
1588             if (ISELEMENT(gj,i)) x |= 1;
1589             if (--k == 0)
1590             {
1591                 *p++ = (char)(BIAS6 + x);
1592                 k = 6;
1593                 x = 0;
1594             }
1595         }
1596     }
1597 
1598     if (k != 6) *p++ = (char)(BIAS6 + (x << k));
1599 
1600     *p++ = '\n';
1601     *p = '\0';
1602 
1603     return gcode;
1604 }
1605 
1606 /****************************************************************************/
1607 
1608 char*
ntog6(graph * g,int m,int n)1609 ntog6(graph *g, int m, int n)
1610 /* convert nauty graph to graph6 string, including \n and \0 */
1611 {
1612     int i,j,k;
1613     char *p,x;
1614     set *gj;
1615     size_t ii;
1616 
1617     ii = G6LEN(n)+3;
1618 
1619     DYNALLOC1(char,gcode,gcode_sz,ii,"ntog6");
1620 
1621     p = gcode;
1622     encodegraphsize(n,&p);
1623 
1624     k = 6;
1625     x = 0;
1626 
1627     for (j = 1; j < n; ++j)
1628     {
1629         gj = GRAPHROW(g,j,m);
1630         for (i = 0; i < j; ++i)
1631         {
1632             x <<= 1;
1633             if (ISELEMENT(gj,i)) x |= 1;
1634             if (--k == 0)
1635             {
1636                 *p++ = (char)(BIAS6 + x);
1637                 k = 6;
1638                 x = 0;
1639             }
1640         }
1641     }
1642 
1643     if (k != 6) *p++ = (char)(BIAS6 + (x << k));
1644 
1645     *p++ = '\n';
1646     *p = '\0';
1647 
1648     return gcode;
1649 }
1650 
1651 /****************************************************************************/
1652 
1653 char*
ntos6(graph * g,int m,int n)1654 ntos6(graph *g, int m, int n)
1655 /* convert nauty graph to sparse6 string, including \n and \0 */
1656 {
1657     int i,j,k;
1658     char *p,x;
1659     set *gj;
1660     size_t ii;
1661     int r,rr,topbit,nb,lastj;
1662     char *plim;
1663 
1664     DYNALLOC1(char,gcode,gcode_sz,5000,"ntos6");
1665 
1666     plim = gcode + gcode_sz - 20;
1667 
1668     gcode[0] = ':';
1669     p = gcode+1;
1670     encodegraphsize(n,&p);
1671 
1672     for (i = n-1, nb = 0; i > 0 ; i >>= 1, ++nb)
1673     {}
1674     topbit = 1 << (nb-1);
1675     k = 6;
1676     x = 0;
1677 
1678     lastj = 0;
1679     for (j = 0; j < n; ++j)
1680     {
1681         gj = GRAPHROW(g,j,m);
1682         for (i = 0; i <= j; ++i)
1683         {
1684             if (ISELEMENT(gj,i))
1685             {
1686                 if (p >= plim)
1687                 {
1688                     ii = p - gcode;
1689                     DYNREALLOC(char,gcode,gcode_sz,
1690                                        3*(gcode_sz/2)+10000,"ntos6");
1691                     p = gcode + ii;
1692                     plim = gcode + gcode_sz - 20;
1693                 }
1694                 if (j == lastj)
1695                 {
1696                     x <<= 1;
1697                     if (--k == 0)
1698                     {
1699                         *p++ = (char)(BIAS6 + x);
1700                         k = 6;
1701                         x = 0;
1702                     }
1703                 }
1704                 else
1705                 {
1706                     x = (x << 1) | (char)1;
1707                     if (--k == 0)
1708                     {
1709                         *p++ = (char)(BIAS6 + x);
1710                         k = 6;
1711                         x = 0;
1712                     }
1713                     if (j > lastj+1)
1714                     {
1715                         for (r = 0, rr = j; r < nb; ++r, rr <<= 1)
1716                         {
1717                             if ((rr & topbit)) x = (x << 1) | (char)1;
1718                             else               x <<= 1;
1719                             if (--k == 0)
1720                             {
1721                                 *p++ = (char)(BIAS6 + x);
1722                                 k = 6;
1723                                 x = 0;
1724                             }
1725                         }
1726                         x <<= 1;
1727                         if (--k == 0)
1728                         {
1729                             *p++ = (char)(BIAS6 + x);
1730                             k = 6;
1731                             x = 0;
1732                         }
1733                     }
1734                     lastj = j;
1735                 }
1736                 for (r = 0, rr = i; r < nb; ++r, rr <<= 1)
1737                 {
1738                     if ((rr & topbit)) x = (x << 1) | (char)1;
1739                     else               x <<= 1;
1740                     if (--k == 0)
1741                     {
1742                         *p++ = (char)(BIAS6 + x);
1743                         k = 6;
1744                         x = 0;
1745                     }
1746                 }
1747             }
1748         }
1749     }
1750 
1751     if (k != 6)
1752     {
1753         if (k >= nb+1 && lastj == n-2 && n == (1<<nb))
1754 	    *p++ = (char)(BIAS6 + ((x << k) | ((1 << (k-1)) - 1)));
1755         else
1756 	    *p++ = (char)(BIAS6 + ((x << k) | ((1 << k) - 1)));
1757     }
1758 
1759     *p++ = '\n';
1760     *p = '\0';
1761     s6len = p - gcode;
1762     return gcode;
1763 }
1764 
1765 /****************************************************************************/
1766 
1767 char*
ntois6(graph * g,graph * prevg,int m,int n)1768 ntois6(graph *g, graph *prevg, int m, int n)
1769 /* convert nauty graph to incremental sparse6 string, including \n and \0.
1770    prevg == NULL implies there is no prior graph */
1771 {
1772     int i,j,k;
1773     char *p,x;
1774     set *gj,*pgj;
1775     setword gdiff;
1776     size_t ii;
1777     int r,rr,topbit,nb,lastj,iw,nwords;
1778     char *plim;
1779 
1780     if (!prevg) return ntos6(g,m,n);
1781 
1782     DYNALLOC1(char,gcode,gcode_sz,5000,"ntois6");
1783 
1784     plim = gcode + gcode_sz - 20;
1785 
1786     gcode[0] = ';';
1787     p = gcode+1;
1788 
1789     for (i = n-1, nb = 0; i > 0 ; i >>= 1, ++nb)
1790     {}
1791     topbit = 1 << (nb-1);
1792     k = 6;
1793     x = 0;
1794 
1795     lastj = 0;
1796     for (j = 0; j < n; ++j)
1797     {
1798         gj = GRAPHROW(g,j,m);
1799         pgj = GRAPHROW(prevg,j,m);
1800         nwords = SETWORDSNEEDED(j+1);
1801 	for (iw = 0; iw < nwords; ++iw)
1802         {
1803 	    gdiff = gj[iw] ^ pgj[iw];
1804             if (TIMESWORDSIZE(iw+1) > j+1) gdiff &= ALLMASK(SETBT(j+1));
1805 	    while (gdiff)
1806 	    {
1807 		TAKEBIT(i,gdiff);
1808 		i += TIMESWORDSIZE(iw);
1809 
1810                 if (p >= plim)
1811                 {
1812                     ii = p - gcode;
1813                     DYNREALLOC(char,gcode,gcode_sz,
1814                                        3*(gcode_sz/2)+10000,"ntois6");
1815                     p = gcode + ii;
1816                     plim = gcode + gcode_sz - 20;
1817                 }
1818                 if (j == lastj)
1819                 {
1820                     x <<= 1;
1821                     if (--k == 0)
1822                     {
1823                         *p++ = (char)(BIAS6 + x);
1824                         k = 6;
1825                         x = 0;
1826                     }
1827                 }
1828                 else
1829                 {
1830                     x = (x << 1) | (char)1;
1831                     if (--k == 0)
1832                     {
1833                         *p++ = (char)(BIAS6 + x);
1834                         k = 6;
1835                         x = 0;
1836                     }
1837                     if (j > lastj+1)
1838                     {
1839                         for (r = 0, rr = j; r < nb; ++r, rr <<= 1)
1840                         {
1841                             if ((rr & topbit)) x = (x << 1) | (char)1;
1842                             else               x <<= 1;
1843                             if (--k == 0)
1844                             {
1845                                 *p++ = (char)(BIAS6 + x);
1846                                 k = 6;
1847                                 x = 0;
1848                             }
1849                         }
1850                         x <<= 1;
1851                         if (--k == 0)
1852                         {
1853                             *p++ = (char)(BIAS6 + x);
1854                             k = 6;
1855                             x = 0;
1856                         }
1857                     }
1858                     lastj = j;
1859                 }
1860                 for (r = 0, rr = i; r < nb; ++r, rr <<= 1)
1861                 {
1862                     if ((rr & topbit)) x = (x << 1) | (char)1;
1863                     else               x <<= 1;
1864                     if (--k == 0)
1865                     {
1866                         *p++ = (char)(BIAS6 + x);
1867                         k = 6;
1868                         x = 0;
1869                     }
1870                 }
1871             }
1872         }
1873     }
1874 
1875     if (k != 6)
1876     {
1877         if (k >= nb+1 && lastj == n-2 && n == (1<<nb))
1878 	    *p++ = (char)(BIAS6 + ((x << k) | ((1 << (k-1)) - 1)));
1879         else
1880 	    *p++ = (char)(BIAS6 + ((x << k) | ((1 << k) - 1)));
1881     }
1882 
1883     *p++ = '\n';
1884     *p = '\0';
1885     s6len = p - gcode;
1886     return gcode;
1887 }
1888 
1889 /*************************************************************************/
1890 
1891 char*
sgtos6(sparsegraph * sg)1892 sgtos6(sparsegraph *sg)
1893 /* Convert undirected sparse graph to sparse6 string including '\n'.
1894   It is null-terminated and its address (static memory) is returned.
1895   The length, not including the null, is put in s6len. */
1896 {
1897     int *d,*e;
1898     int i,j,n;
1899     char *p,x,*plim;
1900     int nb,topbit;
1901     int dj,k,lastj;
1902     int r,rr;
1903     size_t ii,*v,vj,l;
1904 
1905     SG_VDE(sg,v,d,e);
1906     n = sg->nv;
1907     for (i = n-1, nb = 0; i > 0 ; i >>= 1, ++nb) {}
1908 
1909     ii = (size_t)(nb+1)*(n/6+sg->nde/3);
1910     DYNALLOC1(char,gcode,gcode_sz,ii+1000,"sgtos6");
1911     plim = gcode + gcode_sz - 20;
1912 
1913     p = gcode;
1914     *p++ = ':';
1915     encodegraphsize(n,&p);
1916 
1917     topbit = 1 << (nb-1);
1918     k = 6;
1919     x = 0;
1920 
1921     lastj = 0;
1922     for (j = 0; j < n; ++j)
1923     {
1924         vj = v[j];
1925         dj = d[j];
1926         for (l = 0; l < dj; ++l)
1927         {
1928             i = e[vj+l];
1929             if (i <= j)
1930             {
1931                 if (p >= plim)
1932                 {
1933                     ii = p - gcode;
1934                     DYNREALLOC(char,
1935                                gcode,gcode_sz,5*(gcode_sz/4)+1000,"sgtos6");
1936                     p = gcode + ii;
1937                     plim = gcode + gcode_sz - 20;
1938                 }
1939                 if (j == lastj)
1940                 {
1941                     x <<= 1;
1942                     if (--k == 0)
1943                     {
1944                         *p++ = (char)(BIAS6 + x);
1945                         k = 6;
1946                         x = 0;
1947                     }
1948                 }
1949                 else
1950                 {
1951                     x = (x << 1) | (char)1;
1952                     if (--k == 0)
1953                     {
1954                         *p++ = (char)(BIAS6 + x);
1955                         k = 6;
1956                         x = 0;
1957                     }
1958                     if (j > lastj+1)
1959                     {
1960                         for (r = 0, rr = j; r < nb; ++r, rr <<= 1)
1961                         {
1962                             if ((rr & topbit)) x = (x << 1) | (char)1;
1963                             else               x <<= 1;
1964                             if (--k == 0)
1965                             {
1966                                 *p++ = (char)(BIAS6 + x);
1967                                 k = 6;
1968                                 x = 0;
1969                             }
1970                         }
1971                             x <<= 1;
1972                         if (--k == 0)
1973                         {
1974                             *p++ = (char)(BIAS6 + x);
1975                             k = 6;
1976                             x = 0;
1977                         }
1978                     }
1979                     lastj = j;
1980                 }
1981                 for (r = 0, rr = i; r < nb; ++r, rr <<= 1)
1982                 {
1983                     if ((rr & topbit)) x = (x << 1) | (char)1;
1984                     else               x <<= 1;
1985                     if (--k == 0)
1986                     {
1987                         *p++ = (char)(BIAS6 + x);
1988                         k = 6;
1989                         x = 0;
1990                     }
1991                 }
1992             }
1993         }
1994     }
1995 
1996     if (k != 6)
1997     {
1998         if (k >= nb+1 && lastj == n-2 && n == (1<<nb))
1999 	    *p++ = (char)(BIAS6 + ((x << k) | ((1 << (k-1)) - 1)));
2000         else
2001 	    *p++ = (char)(BIAS6 + ((x << k) | ((1 << k) - 1)));
2002     }
2003 
2004     *p++ = '\n';
2005     *p = '\0';
2006     s6len = p - gcode;
2007     return gcode;
2008 }
2009 
2010 /*************************************************************************/
2011 
2012 char*
sgtog6(sparsegraph * sg)2013 sgtog6(sparsegraph *sg)
2014 /* Convert undirected sparse graph to graph6 string including '\n','\0'.
2015   It is null-terminated and its address (static memory) is returned. */
2016 {
2017     int *d,*e,*ei;
2018     int i,j,n;
2019     char *p;
2020     size_t ii,*v,bodylen,org;
2021     static char g6bit[] = {32,16,8,4,2,1};
2022 
2023     SG_VDE(sg,v,d,e);
2024     n = sg->nv;
2025 
2026     ii = G6LEN(n)+3;
2027 
2028     DYNALLOC1(char,gcode,gcode_sz,ii,"sgtog6");
2029 
2030     p = gcode;
2031     encodegraphsize(n,&p);
2032 
2033     bodylen = G6BODYLEN(n);
2034     for (ii = 0; ii < bodylen; ++ii) p[ii] = 0;
2035     p[bodylen] = '\n';
2036     p[bodylen+1] = '\0';
2037 
2038     for (i = 0, org = 0; i < n;  org += i, ++i)
2039     {
2040 	ei = e + v[i];
2041 	for (j = 0; j < d[i]; ++j)
2042 	    if (ei[j] < i)
2043 	    {
2044 		ii = ei[j] + org;
2045 		p[ii/6] |= g6bit[ii%6];
2046 	    }
2047     }
2048 
2049     for (ii = 0; ii < bodylen; ++ii) p[ii] += BIAS6;
2050 
2051     return gcode;
2052 }
2053 
2054 /*************************************************************************/
2055 
2056 char*
sgtod6(sparsegraph * sg)2057 sgtod6(sparsegraph *sg)
2058 /* Convert undirected sparse graph to digraph6 string including '\n','\0'.
2059   It is null-terminated and its address (static memory) is returned. */
2060 {
2061     int *d,*e,*ei;
2062     int i,j,n;
2063     char *p;
2064     size_t ii,*v,bodylen,org;
2065     static char g6bit[] = {32,16,8,4,2,1};
2066 
2067     SG_VDE(sg,v,d,e);
2068     n = sg->nv;
2069 
2070     ii = D6LEN(n)+3;
2071 
2072     DYNALLOC1(char,gcode,gcode_sz,ii,"sgtog6");
2073 
2074     p = gcode;
2075     *p++ = '&';
2076     encodegraphsize(n,&p);
2077 
2078     bodylen = D6BODYLEN(n);
2079     for (ii = 0; ii < bodylen; ++ii) p[ii] = 0;
2080     p[bodylen] = '\n';
2081     p[bodylen+1] = '\0';
2082 
2083     for (i = 0, org = 0; i < n;  org += n, ++i)
2084     {
2085 	ei = e + v[i];
2086 	for (j = 0; j < d[i]; ++j)
2087 	{
2088 	    ii = ei[j] + org;
2089 	    p[ii/6] |= g6bit[ii%6];
2090 	}
2091     }
2092 
2093     for (ii = 0; ii < bodylen; ++ii) p[ii] += BIAS6;
2094 
2095     return gcode;
2096 }
2097 
2098 /**************************************************************************/
2099 
2100 void
writeg6(FILE * f,graph * g,int m,int n)2101 writeg6(FILE *f, graph *g, int m, int n)
2102 /* write graph to file in graph6 format */
2103 {
2104     writeline(f,ntog6(g,m,n));
2105 }
2106 
2107 /**************************************************************************/
2108 
2109 void
writed6(FILE * f,graph * g,int m,int n)2110 writed6(FILE *f, graph *g, int m, int n)
2111 /* write graph to file in digraph6 format */
2112 {
2113     writeline(f,ntod6(g,m,n));
2114 }
2115 
2116 /**************************************************************************/
2117 
2118 void
writes6(FILE * f,graph * g,int m,int n)2119 writes6(FILE *f, graph *g, int m, int n)
2120 /* write graph to file in sparse6 format */
2121 {
2122     char *s;
2123 
2124     s = ntos6(g,m,n);
2125 
2126     if (fwrite(s,1,s6len,f) != s6len || ferror(f))
2127         gt_abort(">E writes6 : error on writing\n");
2128 }
2129 
2130 /**************************************************************************/
2131 
2132 void
writeis6(FILE * f,graph * g,graph * prevg,int m,int n)2133 writeis6(FILE *f, graph *g, graph *prevg, int m, int n)
2134 /* write graph to file in incremental sparse6 format
2135    prevg can be NULL if there is no previous graph */
2136 {
2137     char *s;
2138 
2139     s = ntois6(g,prevg,m,n);
2140 
2141     if (fwrite(s,1,s6len,f) != s6len || ferror(f))
2142         gt_abort(">E writeis6 : error on writing\n");
2143 }
2144 
2145 /**************************************************************************/
2146 
2147 void
writeg6_sg(FILE * f,sparsegraph * g)2148 writeg6_sg(FILE *f, sparsegraph *g)
2149 /* write undirected sparse graph to file in sparse6 format */
2150 {
2151     writeline(f,sgtog6(g));
2152 }
2153 
2154 /**************************************************************************/
2155 
2156 void
writed6_sg(FILE * f,sparsegraph * g)2157 writed6_sg(FILE *f, sparsegraph *g)
2158 /* write undirected sparse graph to file in sparse6 format */
2159 {
2160     writeline(f,sgtod6(g));
2161 }
2162 
2163 /**************************************************************************/
2164 
2165 void
writes6_sg(FILE * f,sparsegraph * g)2166 writes6_sg(FILE *f, sparsegraph *g)
2167 /* write undirected sparse graph to file in sparse6 format */
2168 {
2169     char *s;
2170 
2171     s = sgtos6(g);
2172 
2173     if (fwrite(s,1,s6len,f) != s6len || ferror(f))
2174         gt_abort(">E writes6 : error on writing\n");
2175 }
2176 
2177 /**************************************************************************/
2178 
2179 DYNALLSTAT(unsigned char,buff,buff_sz);
2180 
2181 void
writepc_sg(FILE * f,sparsegraph * sg)2182 writepc_sg(FILE *f, sparsegraph *sg)
2183 /* write a sparse graph in planar_code format
2184     *f = an open file
2185     *sg = the graph to write
2186 */
2187 {
2188     int bytes;
2189     size_t i,j,len,k,*v,vi;
2190     unsigned int w;
2191     int n,*d,*e,di;
2192 
2193 #define BEPUT1(x) buff[j++]=(unsigned char)(x);
2194 #define BEPUT2(x) w=(x); buff[j++]=(unsigned char)((w>>8)&0xFF); \
2195                 buff[j++]=(unsigned char)(w&0xff);
2196 #define BEPUT4(x) w=(x); buff[j++]=(unsigned char)((w>>24)&0xFF); \
2197           buff[j++]=(unsigned char)((w>>16)&0xff); \
2198           buff[j++]=(unsigned char)((w>>8)&0xFF); \
2199           buff[j++]=(unsigned char)(w&0xff);
2200 
2201     n = sg->nv;
2202     SG_VDE(sg,v,d,e);
2203 
2204     if (n <= 255)        bytes = 1;
2205     else if (n <= 65535) bytes = 2;
2206     else                 bytes = 4;
2207 
2208     len = bytes * (1 + n + (size_t)(sg->nde));
2209     if (bytes == 2)      len += 1;
2210     else if (bytes == 4) len += 3;
2211 
2212     DYNALLOC1(unsigned char,buff,buff_sz,len,"writepc_sg");
2213 
2214     if (bytes == 1)
2215     {
2216 	j = 0;
2217 	BEPUT1(n);
2218 	for (i = 0; i < n; ++i)
2219 	{
2220 	    vi = v[i];
2221 	    di = d[i];
2222 	    for (k = 0; k < di; ++k) { BEPUT1(e[vi+k]+1); }
2223 	    BEPUT1(0);
2224 	}
2225     }
2226     else if (bytes == 2)
2227     {
2228 	j = 0;
2229 	BEPUT1(n);
2230 	BEPUT2(n);
2231 	for (i = 0; i < n; ++i)
2232 	{
2233 	    vi = v[i];
2234 	    di = d[i];
2235 	    for (k = 0; k < di; ++k) { BEPUT2(e[vi+k]+1); }
2236 	    BEPUT2(0);
2237 	}
2238     }
2239     else /* bytes==4 */
2240     {
2241 	j = 0;
2242 	BEPUT1(n);
2243 	BEPUT2(n);
2244 	BEPUT4(n);
2245 	for (i = 0; i < n; ++i)
2246 	{
2247 	    vi = v[i];
2248 	    di = d[i];
2249 	    for (k = 0; k < di; ++k) { BEPUT4(e[vi+k]+1); }
2250 	    BEPUT4(0);
2251 	}
2252     }
2253 
2254     if (fwrite((void*)buff,1,j,f) != j)
2255         gt_abort(">E writepc_sg : error on writing\n");
2256 }
2257 
2258 /**************************************************************************/
2259 
2260 sparsegraph*
readpc_sg(FILE * f,sparsegraph * sg)2261 readpc_sg(FILE *f,sparsegraph *sg)
2262 /* read a planar_code graph into sparse graph format
2263     *f = an open file
2264     *sg = place to put the answer (NULL for dynamic allocation)
2265         - must be initialised if not NULL
2266 */
2267 {
2268 #define BEGET1(x) { x = GETC(f); }
2269 #define BEGET2(x) { w1=GETC(f); w2=GETC(f); if (w2==EOF) x = EOF; else \
2270                  x = (w1<<8) | w2; }
2271 #define BEGET4(x) { w1=GETC(f); w2=GETC(f); w3=GETC(f); w4=GETC(f); \
2272                  if (w4==EOF) x = EOF; \
2273                  else x = (w1<<24) | (w2<<16) | (w3<<8) | w4; }
2274     int w1,w2,w3,w4;
2275     int bytes,n;
2276     int i,j,*d,*e,di;
2277     size_t *v,vi;
2278 
2279     BEGET1(n);
2280     if (n == EOF || n < 0) return NULL;
2281     else if (n > 0)
2282 	bytes = 1;
2283     else
2284     {
2285 	BEGET2(n);
2286 	if (n == EOF || n < 0)
2287 	    gt_abort(">E readpc_sg : error 1 on reading\n");
2288 	else if (n > 0)
2289 	    bytes = 2;
2290 	else
2291 	{
2292 	    BEGET4(n);
2293 	    if (n == EOF || n < 0)
2294 	        gt_abort(">E readpc_sg : error 2 on reading\n");
2295 	    else if (n > 0)
2296 		bytes = 4;
2297 	    else
2298 	        gt_abort(">E readpc_sg : error 3 on reading\n");
2299 	}
2300     }
2301 
2302     if (sg == NULL)
2303     {
2304         if ((sg = (sparsegraph*)ALLOCS(1,sizeof(sparsegraph))) == NULL)
2305             gt_abort(">E readpc_sg: malloc failed\n");
2306         SG_INIT(*sg);
2307     }
2308 
2309     SG_ALLOC(*sg,n,2*(size_t)n,"readpc_sg");
2310     SG_VDE(sg,v,d,e);
2311 
2312     vi = 0;
2313     for (i = 0; i < n; ++i)
2314     {
2315 	v[i] = vi;
2316 	di = 0;
2317 	do
2318 	{
2319 	    if      (bytes == 1) BEGET1(j)
2320             else if (bytes == 2) BEGET2(j)
2321             else                 BEGET4(j);
2322 	    if (j == EOF) gt_abort(">E readpc_sg : error 4 on reading\n");
2323 
2324 	    if (j > 0)
2325 	    {
2326 		if (vi == sg->elen)
2327 		{
2328 		    DYNREALLOC(int,sg->e,sg->elen,2*sg->elen,"readpc_sg");
2329 		    e = sg->e;
2330 		}
2331 	        e[vi++] = j-1;
2332 		++di;
2333 	    }
2334 	    else if (j == 0)
2335 		d[i] = di;
2336 	    else
2337 		gt_abort(">E readpc_sg : error 5 on reading\n");
2338 	} while (j != 0);
2339     }
2340 
2341     sg->nv = n;
2342     sg->nde = vi;
2343     return sg;
2344 }
2345 
2346 /**************************************************************************/
2347 
2348 sparsegraph*
readpcle_sg(FILE * f,sparsegraph * sg)2349 readpcle_sg(FILE *f,sparsegraph *sg)
2350 /* read a planar_code graph into sparse graph format
2351     *f = an open file
2352     *sg = place to put the answer (NULL for dynamic allocation)
2353         - must be initialised if not NULL
2354 */
2355 {
2356 #define LEGET1(x) { x = GETC(f); }
2357 #define LEGET2(x) { w2=GETC(f); w1=GETC(f); if (w1==EOF) x = EOF; else \
2358                  x = (w1<<8) | w2; }
2359 #define LEGET4(x) { w4=GETC(f); w3=GETC(f); w2=GETC(f); w1=GETC(f); \
2360                  if (w1==EOF) x = EOF; \
2361                  else x = (w1<<24) | (w2<<16) | (w3<<8) | w4; }
2362     int w1,w2,w3,w4;
2363     int bytes,n;
2364     int i,j,*d,*e,di;
2365     size_t *v,vi;
2366 
2367     LEGET1(n);
2368     if (n == EOF || n < 0) return NULL;
2369     else if (n > 0)
2370 	bytes = 1;
2371     else
2372     {
2373 	LEGET2(n);
2374 	if (n == EOF || n < 0)
2375 	    gt_abort(">E readpcle_sg : error 1 on reading\n");
2376 	else if (n > 0)
2377 	    bytes = 2;
2378 	else
2379 	{
2380 	    LEGET4(n);
2381 	    if (n == EOF || n < 0)
2382 	        gt_abort(">E readpcle_sg : error 2 on reading\n");
2383 	    else if (n > 0)
2384 		bytes = 4;
2385 	    else
2386 	        gt_abort(">E readpcle_sg : error 3 on reading\n");
2387 	}
2388     }
2389 
2390     if (sg == NULL)
2391     {
2392         if ((sg = (sparsegraph*)ALLOCS(1,sizeof(sparsegraph))) == NULL)
2393             gt_abort(">E readpcle_sg: malloc failed\n");
2394         SG_INIT(*sg);
2395     }
2396 
2397     SG_ALLOC(*sg,n,2*(size_t)n,"readpcle_sg");
2398     SG_VDE(sg,v,d,e);
2399 
2400     vi = 0;
2401     for (i = 0; i < n; ++i)
2402     {
2403 	v[i] = vi;
2404 	di = 0;
2405 	do
2406 	{
2407 	    if (bytes == 1)      LEGET1(j)
2408             else if (bytes == 2) LEGET2(j)
2409             else                 LEGET4(j);
2410 	    if (j == EOF) gt_abort(">E readpcle_sg : error 4 on reading\n");
2411 
2412 	    if (j > 0)
2413 	    {
2414 		if (vi == sg->elen)
2415 		{
2416 		    DYNREALLOC(int,sg->e,sg->elen,2*sg->elen,"readpcle_sg");
2417 		    e = sg->e;
2418 		}
2419 	        e[vi++] = j-1;
2420 		++di;
2421 	    }
2422 	    else if (j == 0)
2423 		d[i] = di;
2424 	    else
2425 		gt_abort(">E readpcle_sg : error 5 on reading\n");
2426 	} while (j != 0);
2427     }
2428 
2429     sg->nv = n;
2430     sg->nde = vi;
2431     return sg;
2432 }
2433 
2434 /**************************************************************************/
2435 
2436 void
writelast(FILE * f)2437 writelast(FILE *f)
2438 /* write last graph read by readg() assuming no intervening gtools_getline() */
2439 {
2440     writeline(f,readg_line);
2441 }
2442 
2443 /**************************************************************************/
2444 
2445 int
longvalue(char ** ps,long * l)2446 longvalue(char **ps, long *l)
2447 {
2448     boolean neg,pos;
2449     long sofar,last;
2450     char *s;
2451 
2452     s = *ps;
2453     pos = neg = FALSE;
2454     if (*s == '-')
2455     {
2456         neg = TRUE;
2457         ++s;
2458     }
2459     else if (*s == '+')
2460     {
2461         pos = TRUE;
2462         ++s;
2463     }
2464 
2465     if (*s < '0' || *s > '9')
2466     {
2467         *ps = s;
2468         return (pos || neg) ? ARG_ILLEGAL : ARG_MISSING;
2469     }
2470 
2471     sofar = 0;
2472 
2473     for (; *s >= '0' && *s <= '9'; ++s)
2474     {
2475         last = sofar;
2476         sofar = sofar * 10 + (*s - '0');
2477         if (sofar < last || sofar > MAXARG)
2478         {
2479             *ps = s;
2480             return ARG_TOOBIG;
2481         }
2482     }
2483     *ps = s;
2484     *l = neg ? -sofar : sofar;
2485     return ARG_OK;
2486 }
2487 
2488 /**************************************************************************/
2489 
2490 int
doublevalue(char ** ps,double * l)2491 doublevalue(char **ps, double *l)
2492 {
2493     boolean neg,pos;
2494     double sofar,weight;
2495     char *s;
2496 
2497     s = *ps;
2498     pos = neg = FALSE;
2499     if (*s == '-')
2500     {
2501         neg = TRUE;
2502         ++s;
2503     }
2504     else if (*s == '+')
2505     {
2506         pos = TRUE;
2507         ++s;
2508     }
2509 
2510     if ((*s < '0' || *s > '9') && *s != '.')
2511     {
2512         *ps = s;
2513         return (pos || neg) ? ARG_ILLEGAL : ARG_MISSING;
2514     }
2515 
2516     sofar = 0.0;
2517 
2518     for (; *s >= '0' && *s <= '9'; ++s)
2519         sofar = sofar * 10 + (*s - '0');
2520 
2521     if (*s == '.')
2522     {
2523 	weight = 1.0;
2524 	for (++s; *s >= '0' && *s <= '9'; ++s)
2525 	{
2526 	    weight /= 10.0;
2527 	    sofar += weight * (*s - '0');
2528 	}
2529     }
2530 
2531     *ps = s;
2532     *l = neg ? -sofar : sofar;
2533     return ARG_OK;
2534 }
2535 
2536 /*************************************************************************/
2537 
2538 void
arg_long(char ** ps,long * val,char * id)2539 arg_long(char **ps, long *val, char *id)
2540 {
2541     int code;
2542 
2543     code = longvalue(ps,val);
2544     if (code == ARG_MISSING || code == ARG_ILLEGAL)
2545     {
2546         fprintf(stderr,">E %s: missing argument value\n",id);
2547         gt_abort(NULL);
2548     }
2549     else if (code == ARG_TOOBIG)
2550     {
2551         fprintf(stderr,">E %s: argument value too large\n",id);
2552         gt_abort(NULL);
2553     }
2554 }
2555 
2556 /*************************************************************************/
2557 
2558 void
arg_int(char ** ps,int * val,char * id)2559 arg_int(char **ps, int *val, char *id)
2560 {
2561     int code;
2562     long longval;
2563 
2564     code = longvalue(ps,&longval);
2565     *val = longval;
2566     if (code == ARG_MISSING || code == ARG_ILLEGAL)
2567     {
2568         fprintf(stderr,">E %s: missing argument value\n",id);
2569         gt_abort(NULL);
2570     }
2571     else if (code == ARG_TOOBIG || *val != longval)
2572     {
2573         fprintf(stderr,">E %s: argument value too large\n",id);
2574         gt_abort(NULL);
2575     }
2576 }
2577 
2578 /*************************************************************************/
2579 
2580 void
arg_double(char ** ps,double * val,char * id)2581 arg_double(char **ps, double *val, char *id)
2582 {
2583     int code;
2584 
2585     code = doublevalue(ps,val);
2586     if (code == ARG_MISSING || code == ARG_ILLEGAL)
2587     {
2588         fprintf(stderr,">E %s: missing argument value\n",id);
2589         gt_abort(NULL);
2590     }
2591 }
2592 
2593 /************************************************************************/
2594 
2595 boolean
strhaschar(char * s,int c)2596 strhaschar(char *s, int c)
2597 /* Check if s contains c.  Saves the bother of figuring out whether
2598   strchr() is available, or index() or whatever.  */
2599 {
2600     int i;
2601 
2602     for (i = 0; s[i] != '\0'; ++i)
2603         if (s[i] == c) return TRUE;
2604 
2605     return FALSE;
2606 }
2607 
2608 /************************************************************************/
2609 
2610 void
arg_range(char ** ps,char * sep,long * val1,long * val2,char * id)2611 arg_range(char **ps, char *sep, long *val1, long *val2, char *id)
2612 {
2613     int code;
2614     char *s;
2615 
2616     s = *ps;
2617     code = longvalue(&s,val1);
2618     if (code != ARG_MISSING)
2619     {
2620         if (code == ARG_ILLEGAL)
2621         {
2622             fprintf(stderr,">E %s: bad range\n",id);
2623             gt_abort(NULL);
2624         }
2625         else if (code == ARG_TOOBIG)
2626         {
2627             fprintf(stderr,">E %s: value too big\n",id);
2628             gt_abort(NULL);
2629         }
2630     }
2631     else if (*s == '\0' || !strhaschar(sep,*s))
2632     {
2633         fprintf(stderr,">E %s: missing value\n",id);
2634         gt_abort(NULL);
2635     }
2636     else
2637         *val1 = -NOLIMIT;
2638 
2639     if (*s != '\0' && strhaschar(sep,*s))
2640     {
2641         ++s;
2642         code = longvalue(&s,val2);
2643         if (code == ARG_MISSING)
2644             *val2 = NOLIMIT;
2645         else if (code == ARG_TOOBIG)
2646         {
2647             fprintf(stderr,">E %s: value too big\n",id);
2648             gt_abort(NULL);
2649         }
2650         else if (code == ARG_ILLEGAL)
2651         {
2652             fprintf(stderr,">E %s: illegal range\n",id);
2653             gt_abort(NULL);
2654         }
2655     }
2656     else
2657         *val2 = *val1;
2658 
2659     *ps = s;
2660 }
2661 
2662 /************************************************************************/
2663 
2664 void
arg_sequence(char ** ps,char * sep,long * val,int maxvals,int * numvals,char * id)2665 arg_sequence(char **ps, char *sep,
2666              long *val, int maxvals, int *numvals, char *id)
2667 {
2668     int code,ival;
2669     char *s;
2670 
2671     s = *ps;
2672 
2673     for (ival = 0; ival < maxvals; ++ival)
2674     {
2675         code = longvalue(&s,&val[ival]);
2676         if (code == ARG_ILLEGAL)
2677         {
2678             fprintf(stderr,">E %s: illegal value\n",id);
2679             gt_abort(NULL);
2680         }
2681         else if (code == ARG_TOOBIG)
2682         {
2683             fprintf(stderr,">E %s: value too big\n",id);
2684             gt_abort(NULL);
2685         }
2686 	else if (code == ARG_MISSING)
2687         {
2688             fprintf(stderr,">E %s: value missing\n",id);
2689             gt_abort(NULL);
2690         }
2691 
2692 	if (*s == '\0' || !strhaschar(sep,*s))
2693 	{
2694 	    *numvals = ival+1;
2695 	    *ps = s;
2696 	    return;
2697 	}
2698 	++s;
2699     }
2700     fprintf(stderr,">E %s: too many values\n",id);
2701     gt_abort(NULL);
2702 }
2703 
2704 /************************************************************************/
2705 
2706 void
arg_sequence_min(char ** ps,char * sep,long * val,int minvals,int maxvals,int * numvals,char * id)2707 arg_sequence_min(char **ps, char *sep,
2708              long *val, int minvals, int maxvals, int *numvals, char *id)
2709 {
2710     int code,ival;
2711     char *s;
2712 
2713     s = *ps;
2714 
2715     for (ival = 0; ival < maxvals; ++ival)
2716     {
2717         code = longvalue(&s,&val[ival]);
2718         if (code == ARG_ILLEGAL)
2719         {
2720             fprintf(stderr,">E %s: illegal value\n",id);
2721             gt_abort(NULL);
2722         }
2723         else if (code == ARG_TOOBIG)
2724         {
2725             fprintf(stderr,">E %s: value too big\n",id);
2726             gt_abort(NULL);
2727         }
2728 	else if (code == ARG_MISSING)
2729         {
2730             fprintf(stderr,">E %s: value missing\n",id);
2731             gt_abort(NULL);
2732         }
2733 
2734 	if (*s == '\0' || !strhaschar(sep,*s))
2735 	{
2736 	    *numvals = ival+1;
2737 	    *ps = s;
2738 	    if (*numvals < minvals)
2739 	    {
2740 		fprintf(stderr,">E %s: too few values\n",id);
2741 		gt_abort(NULL);
2742 	    }
2743 	    return;
2744 	}
2745 	++s;
2746     }
2747     fprintf(stderr,">E %s: too many values\n",id);
2748     gt_abort(NULL);
2749 }
2750 
2751 /************************************************************************/
2752 
2753 void
arg_doublerange(char ** ps,char * sep,double * val1,double * val2,char * id)2754 arg_doublerange(char **ps, char *sep, double *val1, double *val2, char *id)
2755 {
2756     int code;
2757     char *s;
2758 
2759     s = *ps;
2760     code = doublevalue(&s,val1);
2761     if (code != ARG_MISSING)
2762     {
2763         if (code == ARG_ILLEGAL)
2764         {
2765             fprintf(stderr,">E %s: bad range\n",id);
2766             gt_abort(NULL);
2767         }
2768     }
2769     else if (*s == '\0' || !strhaschar(sep,*s))
2770     {
2771         fprintf(stderr,">E %s: missing value\n",id);
2772         gt_abort(NULL);
2773     }
2774     else
2775         *val1 = -NOLIMIT;
2776 
2777     if (*s != '\0' && strhaschar(sep,*s))
2778     {
2779         ++s;
2780         code = doublevalue(&s,val2);
2781         if (code == ARG_MISSING)
2782             *val2 = NOLIMIT;
2783         else if (code == ARG_ILLEGAL)
2784         {
2785             fprintf(stderr,">E %s: illegal range\n",id);
2786             gt_abort(NULL);
2787         }
2788     }
2789     else
2790         *val2 = *val1;
2791 
2792     *ps = s;
2793 }
2794 
2795 /***********************************************************************/
2796 
2797 void
writerange(FILE * f,int c,long lo,long hi)2798 writerange(FILE *f, int c, long lo, long hi)    /* Write a range. */
2799 {
2800     if (c != '\0') fprintf(f,"%c",c);
2801     if (lo != -NOLIMIT) fprintf(f,"%ld",lo);
2802     if (lo != hi)
2803     {
2804         fprintf(stderr,":");
2805         if (hi != NOLIMIT) fprintf(f,"%ld",hi);
2806     }
2807 }
2808 
2809 /************************************************************************/
2810 
2811 void
gt_abort(const char * msg)2812 gt_abort(const char *msg)     /* Write message and halt. */
2813 {
2814     if (msg) fprintf(stderr,"%s",msg);
2815     ABORT(">E gtools");
2816 }
2817 
2818 /************************************************************************/
2819 
2820 char*
stringcopy(char * s)2821 stringcopy(char *s)   /* duplicate string */
2822 {
2823     char *scopy;
2824     size_t i,len;
2825 
2826     for (len = 0; s[len] != '\0'; ++len)
2827     {}
2828 
2829     if ((scopy = (char*)ALLOCS(len+1,1)) == NULL)
2830         gt_abort(">E stringcopy: malloc failed\n");
2831 
2832     for (i = 0; i <= len; ++i)
2833         scopy[i] = s[i];
2834 
2835     return scopy;
2836 }
2837 
2838 /*****************************************************************************
2839 *                                                                            *
2840 *  gtools_check() checks that this file is compiled compatibly with the      *
2841 *  given parameters.   If not, call exit(1).                                 *
2842 *                                                                            *
2843 *****************************************************************************/
2844 
2845 void
gtools_check(int wordsize,int m,int n,int version)2846 gtools_check(int wordsize, int m, int n, int version)
2847 {
2848     if (wordsize != WORDSIZE)
2849     {
2850         fprintf(ERRFILE,"Error: WORDSIZE mismatch in gtools.c\n");
2851         exit(1);
2852     }
2853 
2854 #if MAXN
2855     if (m > MAXM)
2856     {
2857         fprintf(ERRFILE,"Error: MAXM inadequate in gtools.c\n");
2858         exit(1);
2859     }
2860 
2861     if (n > MAXN)
2862     {
2863         fprintf(ERRFILE,"Error: MAXN inadequate in gtools.c\n");
2864         exit(1);
2865     }
2866 #endif
2867 
2868     if (version < NAUTYREQUIRED)
2869     {
2870         fprintf(ERRFILE,"Error: gtools.c version mismatch\n");
2871         exit(1);
2872     }
2873 }
2874