1 
2 /**************************************************************************
3 
4         util2.c
5         Colin Ramsay (cram@itee.uq.edu.au)
6         6 Dec 00
7 
8         ADVANCED COSET ENUMERATOR, Version 3.001
9 
10         Copyright 2000
11         Centre for Discrete Mathematics and Computing,
12         Department of Mathematics and
13           Department of Computer Science & Electrical Engineering,
14         The University of Queensland, QLD 4072.
15 	(http://staff.itee.uq.edu.au/havas)
16 
17 These are the utilities for Level 2 of ACE.
18 
19 **************************************************************************/
20 
21 #include "al2.h"
22 
23 #include <string.h>
24 #include <ctype.h>
25 #include <sys/types.h>
26 #include <time.h>
27 
28         /******************************************************************
29         void al2_init(void)
30 
31         One-off initialisation of the Level 2 stuff, and all lower levels.
32 	Note that there is no need to initialise, for example, intarr[].
33         ******************************************************************/
34 
al2_init(void)35 void al2_init(void)
36   {
37   al1_init();
38 
39   okstart = okcont   = okredo = FALSE;
40   tabinfo = tabindex = FALSE;
41   lresult = -8192;			/* invalid mode ! */
42 
43   echo   = FALSE;
44   skipnl = TRUE;
45 
46   currip = currkey[0] = currname[0] = '\0';
47 
48   currword = NULL;
49   currsiz  = currexp = 0;
50 
51   intcnt = 0;
52 
53   srand((unsigned int)time(NULL));	/* Seed rand() with time */
54   }
55 
56 	/******************************************************************
57         char *al2_strdup(char *s)
58 
59         strdup() is not ANSI C, so this is our version.  Should we regard
60 	an error as fatal, and abort?
61 	******************************************************************/
62 
al2_strdup(char * s)63 char *al2_strdup(char *s)
64   {
65   char *t;
66 
67   if ((t = malloc(strlen(s)+1)) == NULL)
68     { al2_continue("out of memory in al2_strdup()"); }
69 
70   return(strcpy(t,s));
71   }
72 
73 	/******************************************************************
74         int al2_outlen(int i)
75 
76 	Returns the print-length of an integer i (i.e., ~ $\log_{10}i$).
77 	The int i is assumed to satisfy i >= 0.
78 	******************************************************************/
79 
al2_outlen(int i)80 int al2_outlen(int i)
81   {
82   int len = 1;
83 
84   while ((i /= 10) != 0)
85     { len++; }
86 
87   return(len);
88   }
89 
90 /**************************************************************************
91 All Level 2 errors are filtered by one of the following three handlers.
92 These take the appropriate action, and then jump back to the top-level
93 main() routine; ie, the outermost level of Level 2.  We swallow the
94 remainder of any input line (possibly losing some commands); so multi-line
95 commands in error may not be properly tidied-up. The question of what
96 exactly to do if fip/fop are not stdin/stdout is put in the `too hard'
97 basket; we simply switch them both back to their defaults.  Note that,
98 although the code for _continue() & _restart() is the same, they return to
99 different points (& do different things) in main().
100 
101 Warning: The error-handling is fairly basic, since it's not our intent to
102 develop a fully-fledged interactive interface.  We simply tidy-up the best
103 we can and carry on.
104 **************************************************************************/
105 
106 	/******************************************************************
107 	void al2_continue(char *msg)
108 
109 	An error has occurred, but it doesn't affected the ok... flags, or
110 	the table's validity.
111         ******************************************************************/
112 
al2_continue(char * msg)113 void al2_continue(char *msg)
114   {
115   if (fop != stdout)
116     {
117     if (fop != NULL)
118       { fclose(fop); }
119     fop = stdout;
120     }
121   if (fip != stdin)
122     {
123     if (fip != NULL)
124       { fclose(fip); }
125     fip = stdin;
126     currip = '\0';
127     }
128 
129   fflush(fop);
130   fprintf(fop, "** ERROR (continuing with next line)\n");
131   fprintf(fop, "   %s\n", msg);
132 
133   while ( !(currip == '\n' || currip == '\r' || currip == EOF) )
134     { al2_nextip(); }
135 
136   longjmp(env,1);
137   }
138 
139 	/******************************************************************
140 	void al2_restart(char *msg)
141 
142 	Something nasty has happened & we'll be disallowing continue/redo.
143         ******************************************************************/
144 
al2_restart(char * msg)145 void al2_restart(char *msg)
146   {
147   if (fop != stdout)
148     {
149     if (fop != NULL)
150       { fclose(fop); }
151     fop = stdout;
152     }
153   if (fip != stdin)
154     {
155     if (fip != NULL)
156       { fclose(fip); }
157     fip = stdin;
158     currip = '\0';
159     }
160 
161   fflush(fop);
162   fprintf(fop, "** ERROR (restarting with next line)\n");
163   fprintf(fop, "   %s\n", msg);
164 
165   while ( !(currip == '\n' || currip == '\r' || currip == EOF) )
166     { al2_nextip(); }
167 
168   longjmp(env,2);
169   }
170 
171 	/******************************************************************
172 	void al2_abort(char *msg)
173 
174 	No point in being clever here, we're going to stop.
175         ******************************************************************/
176 
al2_abort(char * msg)177 void al2_abort(char *msg)
178   {
179   if (fop != stdout)
180     {
181     if (fop != NULL)
182       { fclose(fop); }
183     fop = stdout;
184     }
185   if (fip != stdin)
186     {
187     if (fip != NULL)
188       { fclose(fip); }
189     fip = stdin;
190     currip = '\0';
191     }
192 
193   fflush(fop);
194   fprintf(fop, "** ERROR (aborting)\n");
195   fprintf(fop, "   %s\n", msg);
196 
197   longjmp(env,3);
198   }
199 
200         /******************************************************************
201 	void al2_aip(char *name)
202 
203 	Switch to a new input file.  We abort via _restart() if this is not
204 	possible, and that call will reset fip/fop properly.
205         ******************************************************************/
206 
al2_aip(char * name)207 void al2_aip(char *name)
208   {
209   /* Close the current input file (unless it is 'stdin'). */
210 
211   if (fip != stdin && fip != NULL)
212     { fclose(fip); }
213   fip = NULL;
214 
215   /* Try to open the new input file (unless it is 'stdin'). */
216 
217   if (strcmp(name, "stdin") != 0)
218     {
219     if ((fip = fopen(name, "r")) == NULL)
220       { al2_restart("can't open new input, using 'stdin'"); }
221     }
222   else
223     { fip = stdin; }
224 
225   currip = '\0'; 			/* Initialise current i/p char. */
226   }
227 
228         /******************************************************************
229 	void al2_aop(char *name)
230 
231 	Switch to a new output file.  We abort via _restart() if this is
232 	not possible, and that call will reset fip/fop properly.  Note
233 	that there is no need to run setvbuf() on stdout, since this was
234 	done in the call to al0_init().
235         ******************************************************************/
236 
al2_aop(char * name)237 void al2_aop(char *name)
238   {
239   /* Close the current output file (unless it is 'stdout'). */
240 
241   if (fop != stdout && fop != NULL)
242     { fclose(fop); }
243   fop = NULL;
244 
245   /* Try to open the new output file (unless it is 'stdout'). */
246 
247   if (strcmp(name, "stdout") != 0)
248     {
249     if ((fop = fopen(name, "w")) == NULL)
250       {
251       fop = stdout;
252       fprintf(fop, "can't open new output, using 'stdout'");
253       }
254     else
255       { setvbuf(fop, NULL, _IOLBF, 0); }	/* line buffered o/p */
256     }
257   else
258     { fop = stdout; }
259   }
260 
261         /******************************************************************
262         void al2_dump(Logic allofit)
263 
264         Dump out the internals of Level 2 of ACE, working through al2.h
265         more or less in order.
266         ******************************************************************/
267 
al2_dump(Logic allofit)268 void al2_dump(Logic allofit)
269   {
270   int i;
271 
272   fprintf(fop, "  #---- %s: Level 2 Dump ----\n", ACE_VER);
273 
274 	/* env; - nothing (meaningful) we can do here! */
275 
276 	/* okstart, okcont, okredo; */
277   fprintf(fop, "okstart=%d okcont=%d okredo=%d\n",
278                 okstart,   okcont,   okredo);
279 
280 	/* tabinfo, tabindex, lresult */
281   fprintf(fop, "tabinfo=%d tabindex=%d lresult=%d\n",
282                 tabinfo,   tabindex,   lresult);
283 
284 	/* echo, skipnl, currip, currkey, currname; */
285   fprintf(fop, "echo=%d skipnl=%d currip=%d", echo, skipnl, currip);
286   if (isprint(currip))
287     { fprintf(fop, "(%c)\n", currip); }
288   else
289     { fprintf(fop, "\n"); }
290   fprintf(fop, "currkey=%s\n", currkey);
291   fprintf(fop, "currname=%s\n", currname);
292 
293 	/* *currword, currsiz, currexp; */
294   fprintf(fop, "currsize=%d currexp=%d currword=", currsiz, currexp);
295   if (currword == NULL)
296     { fprintf(fop, "NULL"); }
297   else
298     {
299     if (allofit)
300       {
301       for (i = 0; i < currsiz; i++)
302         { fprintf(fop, "%d ", currword[i]); }
303       }
304     else
305       { fprintf(fop, "non-NULL"); }
306     }
307   fprintf(fop, "\n");
308 
309 	/* intcnt, intarr[32]; */
310   if (intcnt == 0)
311     { fprintf(fop, "intcnt=0 (empty)\n"); }
312   else
313     {
314     fprintf(fop, "intcnt=%d intarr[]=", intcnt);
315     for (i = 0; i < intcnt; i++)
316       { fprintf(fop, "%d ", intarr[i]); }
317     fprintf(fop, "\n");
318     }
319 
320   fprintf(fop, "  #---------------------------------\n");
321   }
322 
323         /******************************************************************
324 	void al2_opt(void)
325 
326 	Pretty-print the date of compilation and all the various options
327 	included in this build.
328         ******************************************************************/
329 
al2_opt(void)330 void al2_opt(void)
331   {
332   fprintf(fop, "%s executable\n", ACE_VER);
333 
334   fprintf(fop, "Level 0 options:\n");
335 #ifdef AL0_STAT
336   fprintf(fop, "  statistics package = on\n");
337 #else
338   fprintf(fop, "  statistics package = off\n");
339 #endif
340 #ifdef AL0_CC
341   fprintf(fop, "  coinc processing messages = on\n");
342 #else
343   fprintf(fop, "  coinc processing messages = off\n");
344 #endif
345 #ifdef AL0_DD
346   fprintf(fop, "  dedn processing messages = on\n");
347 #else
348   fprintf(fop, "  dedn processing messages = off\n");
349 #endif
350 
351   fprintf(fop, "Level 1 options:\n");
352 #ifdef AL1_BINARY
353   fprintf(fop, "  workspace multipliers = binary\n");
354 #else
355   fprintf(fop, "  workspace multipliers = decimal\n");
356 #endif
357 
358   fprintf(fop, "Level 2 options:\n");
359 #ifdef AL2_HINFO
360   fprintf(fop, "  host info = on\n");
361 #else
362   fprintf(fop, "  host info = off\n");
363 #endif
364   }
365 
366         /******************************************************************
367 	void al2_help(void)
368         ******************************************************************/
369 
al2_help(void)370 void al2_help(void)
371   {
372   fprintf(fop, "  #---- %s: Level 2 Help ----\n", ACE_VER);
373   fprintf(fop, "add gen[erators] / sg : <word list> ;\n");
374   fprintf(fop, "add rel[ators] / rl : <relation list> ;\n");
375   fprintf(fop, "aep : 1..7 ;\n");
376   fprintf(fop, "ai / alter i[nput] : [<filename>] ;\n");
377   fprintf(fop, "ao / alter o[utput] : [<filename>] ;\n");
378   fprintf(fop, "as[is] : [0/1] ;\n");
379   fprintf(fop, "beg[in] / end / start ;\n");
380   fprintf(fop, "bye / exit / q[uit] ;\n");
381   fprintf(fop, "cc / coset coinc[idence] : int ;\n");
382   fprintf(fop, "c[factor] / ct[ factor] : [int] ;\n");
383   fprintf(fop, "check / redo ;\n");
384   fprintf(fop, "com[paction] : [0..100] ;\n");
385   fprintf(fop, "cont[inue] ;\n");
386   fprintf(fop, "cy[cles] ;\n");
387   fprintf(fop, "ded mo[de] / dmod[e] : [0..4] ;\n");
388   fprintf(fop, "ded si[ze] / dsiz[e] : [0/1..] ;\n");
389   fprintf(fop, "def[ault] ;\n");
390   fprintf(fop, "del gen[erators] / ds : <int list> ;\n");
391   fprintf(fop, "del rel[ators] / dr : <int list> ;\n");
392   fprintf(fop, "d[ump] : [0/1/2[,0/1]] ;\n");
393   fprintf(fop, "easy ;\n");
394   fprintf(fop, "echo : [0/1] ;\n");
395   fprintf(fop, "enum[eration] / group name : <string> ;\n");
396   fprintf(fop, "fel[sch] : [0/1] ;\n");
397   fprintf(fop, "f[factor] / fi[ll factor] : [0/1..] ;\n");
398   fprintf(fop, "gen[erators] / subgroup gen[erators] : <word list> ;\n");
399   fprintf(fop, "gr[oup generators]: [<letter list> / int] ;\n");
400   fprintf(fop, "group relators / rel[ators] : <relation list> ;\n");
401   fprintf(fop, "hard ;\n");
402   fprintf(fop, "h[elp] ;\n");
403   fprintf(fop, "hlt ;\n");
404   fprintf(fop, "ho[le limit] : [-1/0..100] ;\n");
405   fprintf(fop, "look[ahead] : [0/1..4] ;\n");
406   fprintf(fop, "loop[ limit] : [0/1..] ;\n");
407   fprintf(fop, "max[ cosets] : [0/2..] ;\n");
408   fprintf(fop, "mend[elsohn] : [0/1] ;\n");
409   fprintf(fop, "mess[ages] / mon[itor] : [int] ;\n");
410   fprintf(fop, "mo[de] ;\n");
411   fprintf(fop, "nc / normal[ closure] : [0/1] ;\n");
412   fprintf(fop, "no[ relators in subgroup] : [-1/0/1..] ;\n");
413   fprintf(fop, "oo / order[ option] : int ;\n");
414   fprintf(fop, "opt[ions] ;\n");
415   fprintf(fop, "par[ameters] ; - old option (ignored)\n");
416   fprintf(fop, "path[ compression] : [0/1] ;\n");
417   fprintf(fop, "pd mo[de] / pmod[e] : [0/1..3] ;\n");
418   fprintf(fop, "pd si[ze] / psiz[e] : [0/2/4/8/...] ;\n");
419   fprintf(fop, "print det[ails] / sr : [int] ;\n");
420   fprintf(fop, "pr[int table] : [[-]int[,int[,int]]] ;\n");
421   fprintf(fop, "pure c[t] ;\n");
422   fprintf(fop, "pure r[t] ;\n");
423   fprintf(fop, "rc / random coinc[idences]: int[,int] ;\n");
424   fprintf(fop, "rec[over] / contig[uous] ;\n");
425   fprintf(fop, "rep : 1..7[,int] ;\n");
426   fprintf(fop, "restart ; - old option (ignored)\n");
427   fprintf(fop, "r[factor] / rt[ factor] : [int] ;\n");
428   fprintf(fop, "row[ filling] : [0/1] ;\n");
429   fprintf(fop, "sc / stabil[ising cosets] : int ;\n");
430   fprintf(fop, "sims : 1/3/5/7/9 ;\n");
431   fprintf(fop, "st[andard table] ;\n");
432 #ifdef AL0_STAT
433   fprintf(fop, "stat[istics] / stats ;\n");
434 #endif
435   fprintf(fop, "style ;\n");
436   fprintf(fop, "subg[roup name] : <string> ;\n");
437   fprintf(fop, "sys[tem] : <string> ;\n");
438   fprintf(fop, "text : <string> ;\n");
439   fprintf(fop, "ti[me limit] : [-1/0/1..] ;\n");
440   fprintf(fop, "tw / trace[ word] : int,<word> ;\n");
441   fprintf(fop, "wo[rkspace] : [int[k/m/g]] ;\n");
442   fprintf(fop, "# ... <newline> - a comment (ignored)\n");
443   fprintf(fop, "  #---------------------------------\n");
444   }
445 
446         /******************************************************************
447 	void al2_nextip(void)
448 
449 	Primes currip with the next character from fip, if we're not at the
450 	end-of-file.  Echoes the character if echo is on.
451         ******************************************************************/
452 
al2_nextip(void)453 void al2_nextip(void)
454   {
455   if (currip != EOF)
456     {
457     currip = fgetc(fip);
458 
459     if (echo && currip != EOF)
460       { fputc(currip, fop); }
461     }
462   }
463 
464         /******************************************************************
465 	void al2_skipws(void)
466 
467 	Skip all whitespace characters.
468         ******************************************************************/
469 
al2_skipws(void)470 void al2_skipws(void)
471   {
472   Logic comment = (currip == '#');
473 
474   while ( currip == ' ' || currip == '\t' || comment ||
475           (skipnl && (currip == '\n' || currip == '\r')) )
476     {
477     al2_nextip();
478     comment = (currip == '#' ||
479            (comment && currip != '\n' && currip != '\r' && currip != EOF));
480     }
481   }
482 
483         /******************************************************************
484 	void al2_nextnw(void)
485 
486 	Skip to the next non-whitespace character.
487         ******************************************************************/
488 
al2_nextnw(void)489 void al2_nextnw(void)
490   {
491   al2_nextip();
492   al2_skipws();
493   }
494 
495 
496