1#include <sys/types.h>
2#include <sys/time.h>
3
4#include <assert.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9
10#include "queue.h"
11#include "shqueue.h"
12
13typedef enum {
14	FORWARD_WALK_FAILED = 1,
15	FOREACH_WALK_FAILED,
16	LIST_END_NOT_MARKED_FAILURE,
17	PREV_WALK_FAILED,
18	REVERSE_FOREACH_WALK_FAILED,
19	EXPECTED_HEAD_FAILED
20} FAILURE_REASON;
21
22const char *failure_reason_names[] = {
23	"",
24	"walking the list using the _NEXT forward failed",
25	"walking the list using the _FOREACH macro failed",
26	"what was expected to be the last element wasn't marked as such",
27	"walking the list using the _PREV macro failed",
28	"walking the list using the _REVERSE_FOREACH macro failed",
29	"expected to be at the head of the list"
30};
31
32SH_LIST_HEAD(sh_lq);
33struct sh_le {
34	char content;
35	SH_LIST_ENTRY sh_les;
36};
37
38/* create a string from the content of a list queue */
39char *
40sh_l_as_string(l)
41	struct sh_lq *l;
42{
43	static char buf[1024];
44	struct sh_le *ele = SH_LIST_FIRST(l, sh_le);
45	int i = 1;
46
47	buf[0] = '"';
48	while (ele != NULL) {
49		buf[i] = ele->content;
50		ele = SH_LIST_NEXT(ele, sh_les, sh_le);
51		if (ele != NULL)
52			buf[++i] = ' ';
53		i++;
54	}
55	buf[i++] = '"';
56	buf[i] = '\0';
57	return buf;
58}
59
60/* init a list queue */
61struct sh_lq *
62sh_l_init(items)
63	const char *items;
64{
65	const char *c = items;
66	struct sh_le *ele = NULL, *last_ele = (struct sh_le*)-1;
67	struct sh_lq *l = calloc(1, sizeof(struct sh_lq));
68
69	SH_LIST_INIT(l);
70
71	while (*c != '\0') {
72		if (c[0] != ' ') {
73			last_ele = ele;
74			ele = calloc(1, sizeof(struct sh_le));
75			ele->content = c[0];
76			if (SH_LIST_EMPTY(l))
77				SH_LIST_INSERT_HEAD(l, ele, sh_les, sh_le);
78			else
79				SH_LIST_INSERT_AFTER(
80				    last_ele, ele, sh_les, sh_le);
81		}
82		c++;
83	}
84	return (l);
85}
86
87struct sh_lq *
88sh_l_remove_head(l)
89	struct sh_lq *l;
90{
91	struct sh_le *ele = SH_LIST_FIRST(l, sh_le);
92
93	SH_LIST_REMOVE_HEAD(l, sh_les, sh_le);
94	if (ele != NULL)
95		free(ele);
96
97	return (l);
98}
99
100struct sh_lq *
101sh_l_remove_tail(l)
102	struct sh_lq *l;
103{
104	struct sh_le *ele = SH_LIST_FIRST(l, sh_le);
105
106	if (SH_LIST_EMPTY(l))
107		return (l);
108
109	while (SH_LIST_NEXT(ele, sh_les, sh_le) != NULL)
110		ele = SH_LIST_NEXT(ele, sh_les, sh_le);
111
112	if (ele) {
113		SH_LIST_REMOVE(ele, sh_les, sh_le);
114		free(ele);
115	}
116	return (l);
117}
118
119struct sh_lq *
120sh_l_remove_item(l, item)
121	struct sh_lq *l;
122	const char *item;
123{
124	struct sh_le *ele = SH_LIST_FIRST(l, sh_le);
125
126	while (ele != NULL) {
127		if (ele->content == item[0])
128			break;
129		ele = SH_LIST_NEXT(ele, sh_les, sh_le);
130	}
131	if (ele)
132		SH_LIST_REMOVE(ele, sh_les, sh_le);
133	return (l);
134}
135
136struct sh_lq *
137sh_l_insert_head(l, item)
138	struct sh_lq *l;
139	const char *item;
140{
141	struct sh_le *ele = calloc(1, sizeof(struct sh_le));
142
143	ele->content = item[0];
144	SH_LIST_INSERT_HEAD(l, ele, sh_les, sh_le);
145
146	return (l);
147}
148
149struct sh_lq *
150sh_l_insert_tail(l, item)
151	struct sh_lq *l;
152	const char *item;
153{
154	struct sh_le *ele = NULL;
155	struct sh_le *last_ele = SH_LIST_FIRST(l, sh_le);
156
157	if (last_ele != NULL)
158		while (SH_LIST_NEXT(last_ele, sh_les, sh_le) != NULL)
159			last_ele = SH_LIST_NEXT(last_ele, sh_les, sh_le);
160
161	if (last_ele == NULL) {
162		ele = calloc(1, sizeof(struct sh_le));
163		ele->content = item[0];
164		SH_LIST_INSERT_HEAD(l, ele, sh_les, sh_le);
165	} else {
166		ele = calloc(1, sizeof(struct sh_le));
167		ele->content = item[0];
168		SH_LIST_INSERT_AFTER(last_ele, ele, sh_les, sh_le);
169	}
170
171	return (l);
172}
173
174struct sh_lq *
175sh_l_insert_before(l, item, before_item)
176	struct sh_lq *l;
177	const char *item;
178	const char *before_item;
179{
180	struct sh_le *ele = NULL;
181	struct sh_le *before_ele = SH_LIST_FIRST(l, sh_le);
182
183	while (before_ele != NULL) {
184		if (before_ele->content == before_item[0])
185			break;
186		before_ele = SH_LIST_NEXT(before_ele, sh_les, sh_le);
187	}
188	if (before_ele != NULL) {
189		ele = calloc(1, sizeof(struct sh_le));
190		ele->content = item[0];
191		SH_LIST_INSERT_BEFORE(l, before_ele, ele, sh_les, sh_le);
192	}
193	return (l);
194}
195
196struct sh_lq *
197sh_l_insert_after(l, item, after_item)
198	struct sh_lq *l;
199	const char *item;
200	const char *after_item;
201{
202	struct sh_le *ele = NULL;
203	struct sh_le *after_ele = SH_LIST_FIRST(l, sh_le);
204
205	while (after_ele != NULL) {
206		if (after_ele->content == after_item[0])
207			break;
208		after_ele = SH_LIST_NEXT(after_ele, sh_les, sh_le);
209	}
210	if (after_ele != NULL) {
211		ele = calloc(1, sizeof(struct sh_le));
212		ele->content = item[0];
213		SH_LIST_INSERT_AFTER(after_ele, ele, sh_les, sh_le);
214	}
215	return (l);
216}
217
218void
219sh_l_discard(l)
220	struct sh_lq *l;
221{
222	struct sh_le *ele = NULL;
223
224	while ((ele = SH_LIST_FIRST(l, sh_le)) != NULL) {
225		SH_LIST_REMOVE(ele, sh_les, sh_le);
226		free(ele);
227	}
228
229	free(l);
230}
231
232int
233sh_l_verify(l, items)
234	struct sh_lq *l;
235	const char *items;
236{
237	const char *c = items;
238	struct sh_le *ele = NULL, *lele = NULL;
239	int i = 0, nele = 0;
240
241	while (*c != '\0') {
242		if (c[0] != ' ')
243			nele++;
244		c++;
245	}
246
247	/* use the FOREACH macro to walk the list */
248	c = items;
249	i = 0;
250	SH_LIST_FOREACH(ele, l, sh_les, sh_le) {
251		if (ele->content != c[0])
252			return (FOREACH_WALK_FAILED);
253		i++;
254		c +=2;
255	}
256	if (i != nele)
257		return (FOREACH_WALK_FAILED);
258	i = 0;
259	if (items[0] != '\0') {
260		/* walk the list forward */
261		c = items;
262		ele = SH_LIST_FIRST(l, sh_le);
263		while (*c != '\0') {
264			lele = ele;
265			if (c[0] != ' ') {
266				if (ele->content != c[0])
267					  return (FORWARD_WALK_FAILED);
268				i++;
269				ele = SH_LIST_NEXT(ele, sh_les, sh_le);
270			}
271			c++;
272		}
273		ele = lele;
274
275		if (i != nele)
276			return (FOREACH_WALK_FAILED);
277
278		/* ele should be the last element in the list... */
279		/* ... so sle_next should be -1 */
280		if (ele->sh_les.sle_next != -1)
281			return (LIST_END_NOT_MARKED_FAILURE);
282
283		/* and NEXT needs to be NULL */
284		if (SH_LIST_NEXT(ele, sh_les, sh_le) != NULL)
285			return (LIST_END_NOT_MARKED_FAILURE);
286
287		/*
288		 * walk the list backwards using PREV macro, first move c
289		 * back a bit
290		 */
291		c--;
292		i = 0;
293		while (c >= items) {
294			if (c[0] != ' ') {
295				lele = ele;
296				if (ele->content != c[0])
297					return (PREV_WALK_FAILED);
298				ele = SH_LIST_PREV(ele, sh_les, sh_le);
299				i++;
300			}
301			c--;
302		}
303		ele = lele;
304
305		if (i != nele)
306			return (PREV_WALK_FAILED);
307
308		if (ele != SH_LIST_FIRST(l, sh_le))
309			return (EXPECTED_HEAD_FAILED);
310	}
311	return (0);
312}
313
314SH_TAILQ_HEAD(sh_tq);
315struct sh_te {
316	char content;
317	SH_TAILQ_ENTRY sh_tes;
318};
319
320/* create a string from the content of a list queue */
321char *
322sh_t_as_string(l)
323	struct sh_tq *l;
324{
325	static char buf[1024];
326	struct sh_te *ele = SH_TAILQ_FIRST(l, sh_te);
327	int i = 1;
328
329	buf[0] = '"';
330	while (ele != NULL) {
331		buf[i] = ele->content;
332		ele = SH_TAILQ_NEXT(ele, sh_tes, sh_te);
333		if (ele != NULL)
334			buf[++i] = ' ';
335		i++;
336	}
337	buf[i++] = '"';
338	buf[i] = '\0';
339	return (buf);
340}
341
342/* init a tail queue */
343struct sh_tq *
344sh_t_init(items)
345	const char *items;
346{
347	const char *c = items;
348	struct sh_te *ele = NULL, *last_ele = (struct sh_te*)-1;
349	struct sh_tq *l = calloc(1, sizeof(struct sh_tq));
350
351	SH_TAILQ_INIT(l);
352
353	while (*c != '\0') {
354		if (c[0] != ' ') {
355			ele = calloc(1, sizeof(struct sh_te));
356			ele->content = c[0];
357
358			if (SH_TAILQ_EMPTY(l))
359				SH_TAILQ_INSERT_HEAD(l, ele, sh_tes, sh_te);
360			else
361				SH_TAILQ_INSERT_AFTER(
362				    l, last_ele, ele, sh_tes, sh_te);
363			last_ele = ele;
364		}
365		c++;
366	}
367	return (l);
368}
369
370struct sh_tq *
371sh_t_remove_head(l)
372	struct sh_tq *l;
373{
374	struct sh_te *ele = SH_TAILQ_FIRST(l, sh_te);
375
376	if (ele != NULL)
377		SH_TAILQ_REMOVE(l, ele, sh_tes, sh_te);
378
379	free(ele);
380
381	return (l);
382}
383
384struct sh_tq *
385sh_t_remove_tail(l)
386	struct sh_tq *l;
387{
388	struct sh_te *ele = SH_TAILQ_FIRST(l, sh_te);
389
390	if (SH_TAILQ_EMPTY(l))
391		return (l);
392
393	while (SH_TAILQ_NEXT(ele, sh_tes, sh_te) != NULL)
394		ele = SH_TAILQ_NEXT(ele, sh_tes, sh_te);
395
396	if (ele != NULL) {
397		SH_TAILQ_REMOVE(l, ele, sh_tes, sh_te);
398		free(ele);
399	}
400
401	return (l);
402}
403
404struct sh_tq *
405sh_t_remove_item(l, item)
406	struct sh_tq *l;
407	const char *item;
408{
409	struct sh_te *ele = SH_TAILQ_FIRST(l, sh_te);
410
411	while (ele != NULL) {
412		if (ele->content == item[0])
413			break;
414		ele = SH_TAILQ_NEXT(ele, sh_tes, sh_te);
415	}
416	if (ele != NULL)
417		SH_TAILQ_REMOVE(l, ele, sh_tes, sh_te);
418
419	return (l);
420}
421
422struct sh_tq *
423sh_t_insert_head(l, item)
424	struct sh_tq *l;
425	const char *item;
426{
427	struct sh_te *ele = calloc(1, sizeof(struct sh_te));
428
429	ele->content = item[0];
430	SH_TAILQ_INSERT_HEAD(l, ele, sh_tes, sh_te);
431
432	return (l);
433}
434
435struct sh_tq *
436sh_t_insert_tail(l, item)
437	struct sh_tq *l;
438	const char *item;
439{
440	struct sh_te *ele = 0;
441	ele = calloc(1, sizeof(struct sh_te));
442	ele->content = item[0];
443	SH_TAILQ_INSERT_TAIL(l, ele, sh_tes);
444	return l;
445}
446
447struct sh_tq *
448sh_t_insert_before(l, item, before_item)
449	struct sh_tq *l;
450	const char *item;
451	const char *before_item;
452{
453	struct sh_te *ele = NULL;
454	struct sh_te *before_ele = SH_TAILQ_FIRST(l, sh_te);
455
456	while (before_ele != NULL) {
457		if (before_ele->content == before_item[0])
458			break;
459		before_ele = SH_TAILQ_NEXT(before_ele, sh_tes, sh_te);
460	}
461
462	if (before_ele != NULL) {
463		ele = calloc(1, sizeof(struct sh_te));
464		ele->content = item[0];
465		SH_TAILQ_INSERT_BEFORE(l, before_ele, ele, sh_tes, sh_te);
466	}
467
468	return (l);
469}
470
471struct sh_tq *
472sh_t_insert_after(l, item, after_item)
473	struct sh_tq *l;
474	const char *item;
475	const char *after_item;
476{
477	struct sh_te *ele = NULL;
478	struct sh_te *after_ele = SH_TAILQ_FIRST(l, sh_te);
479
480	while (after_ele != NULL) {
481		if (after_ele->content == after_item[0])
482			break;
483		after_ele = SH_TAILQ_NEXT(after_ele, sh_tes, sh_te);
484	}
485
486	if (after_ele != NULL) {
487		ele = calloc(1, sizeof(struct sh_te));
488		ele->content = item[0];
489		SH_TAILQ_INSERT_AFTER(l, after_ele, ele, sh_tes, sh_te);
490	}
491
492	return (l);
493}
494
495void
496sh_t_discard(l)
497	struct sh_tq *l;
498{
499	struct sh_te *ele = NULL;
500
501	while ((ele = SH_TAILQ_FIRST(l, sh_te)) != NULL) {
502		SH_TAILQ_REMOVE(l, ele, sh_tes, sh_te);
503		free(ele);
504	}
505	free(l);
506}
507
508int
509sh_t_verify(l, items)
510	struct sh_tq *l;
511	const char *items;
512{
513	const char *c = items, *b = NULL;
514	struct sh_te *ele = NULL, *lele = NULL;
515	int i = 0, nele = 0;
516
517	while (*c != '\0') {
518		if (c[0] != ' ')
519			nele++;
520		c++;
521	}
522
523	/* use the FOREACH macro to walk the list */
524	c = items;
525	i = 0;
526	SH_TAILQ_FOREACH(ele, l, sh_tes, sh_te) {
527		if (ele->content != c[0])
528			return (FOREACH_WALK_FAILED);
529		i++;
530		c +=2;
531	}
532	if (i != nele)
533		return (FOREACH_WALK_FAILED);
534	i = 0;
535	if (items[0] != '\0') {
536		/* walk the list forward */
537		c = items;
538		ele = SH_TAILQ_FIRST(l, sh_te);
539		while (*c != '\0') {
540			lele = ele;
541			if (c[0] != ' ') {
542				if (ele->content != c[0])
543					return (FORWARD_WALK_FAILED);
544				i++;
545				ele = SH_TAILQ_NEXT(ele, sh_tes, sh_te);
546			}
547			c++;
548		}
549
550		if (i != nele)
551			return (FOREACH_WALK_FAILED);
552
553		if (lele != SH_TAILQ_LAST(l, sh_tes, sh_te))
554			return (LIST_END_NOT_MARKED_FAILURE);
555		ele = lele;
556
557		/* ele should be the last element in the list... */
558		/* ... so sle_next should be -1 */
559		if (ele->sh_tes.stqe_next != -1)
560			return (LIST_END_NOT_MARKED_FAILURE);
561
562		/* and NEXT needs to be NULL */
563		if (SH_TAILQ_NEXT(ele, sh_tes, sh_te) != NULL)
564			return (LIST_END_NOT_MARKED_FAILURE);
565
566		/* walk the list backwards using SH_LIST_PREV macro */
567		c--;
568		b = c;
569		i = 0;
570		while (c >= items) {
571			if (c[0] != ' ') {
572				lele = ele;
573				if (ele->content != c[0])
574					return (PREV_WALK_FAILED);
575				ele = SH_TAILQ_PREV(l, ele, sh_tes, sh_te);
576				i++;
577			}
578			c--;
579		}
580		ele = lele;
581
582		if (i != nele)
583			return (PREV_WALK_FAILED);
584
585		if (ele != SH_TAILQ_FIRST(l, sh_te))
586			return (-1);
587
588		/* c should be the last character in the array, walk backwards
589		from here using FOREACH_REVERSE and check the values again */
590		c = b;
591		i = 0;
592		ele = SH_TAILQ_LAST(l, sh_tes, sh_te);
593		SH_TAILQ_FOREACH_REVERSE(ele, l, sh_tes, sh_te) {
594			if (ele->content != c[0])
595				return (REVERSE_FOREACH_WALK_FAILED);
596			i++;
597			c -=2;
598		}
599		if (i != nele)
600			return (REVERSE_FOREACH_WALK_FAILED);
601	}
602	return (0);
603}
604
605int
606sh_t_verify_TAILQ_LAST(l, items)
607	struct sh_tq *l;
608	const char *items;
609{
610	const char *c = items;
611	struct sh_te *ele = NULL;
612
613	c = items;
614	while (*c != '\0') {
615		c++;
616	}
617	if (c == items) {
618	  /* items is empty, so last should be NULL */
619	  if (SH_TAILQ_LAST(l, sh_tes, sh_te) != NULL)
620		return (-1);
621	} else {
622		c--;
623		ele = SH_TAILQ_LAST(l, sh_tes, sh_te);
624		if (ele->content != c[0])
625			return (-1);
626	}
627	return (0);
628}
629
630typedef void *qds_t;
631struct {
632	const char *name;
633	qds_t *(*f_init)(const char *);
634	qds_t *(*f_remove_head)(qds_t *);
635	qds_t *(*f_remove_tail)(qds_t *);
636	qds_t *(*f_remove_item)(qds_t *, const char *);
637	qds_t *(*f_insert_head)(qds_t *, const char *);
638	qds_t *(*f_insert_tail)(qds_t *, const char *);
639	qds_t *(*f_insert_before)(qds_t *, const char *, const char *);
640	qds_t *(*f_insert_after)(qds_t *, const char *, const char *);
641	qds_t *(*f_discard)(qds_t *);
642	char *(*f_as_string)(qds_t *);
643	int (*f_verify)(qds_t *, const char *);
644} qfns[]= {
645{	"sh_list",
646	(qds_t*(*)(const char *))sh_l_init,
647	(qds_t*(*)(qds_t *))sh_l_remove_head,
648	(qds_t*(*)(qds_t *))sh_l_remove_tail,
649	(qds_t*(*)(qds_t *, const char *))sh_l_remove_item,
650	(qds_t*(*)(qds_t *, const char *))sh_l_insert_head,
651	(qds_t*(*)(qds_t *, const char *))sh_l_insert_tail,
652	(qds_t*(*)(qds_t *, const char *, const char *))sh_l_insert_before,
653	(qds_t*(*)(qds_t *, const char *, const char *))sh_l_insert_after,
654	(qds_t*(*)(qds_t *))sh_l_discard,
655	(char *(*)(qds_t *))sh_l_as_string,
656	(int(*)(qds_t *, const char *))sh_l_verify },
657{	"sh_tailq",
658	(qds_t*(*)(const char *))sh_t_init,
659	(qds_t*(*)(qds_t *))sh_t_remove_head,
660	(qds_t*(*)(qds_t *))sh_t_remove_tail,
661	(qds_t*(*)(qds_t *, const char *))sh_t_remove_item,
662	(qds_t*(*)(qds_t *, const char *))sh_t_insert_head,
663	(qds_t*(*)(qds_t *, const char *))sh_t_insert_tail,
664	(qds_t*(*)(qds_t *, const char *, const char *))sh_t_insert_before,
665	(qds_t*(*)(qds_t *, const char *, const char *))sh_t_insert_after,
666	(qds_t*(*)(qds_t *))sh_t_discard,
667	(char *(*)(qds_t *))sh_t_as_string,
668	(int(*)(qds_t *, const char *))sh_t_verify }
669};
670
671typedef enum {
672	INSERT_BEFORE,
673	INSERT_AFTER,
674	INSERT_HEAD,
675	INSERT_TAIL,
676	REMOVE_HEAD,
677	REMOVE_ITEM,
678	REMOVE_TAIL,
679} OP;
680
681const char *op_names[] = {
682	"INSERT_BEFORE",
683	"INSERT_AFTER",
684	"INSERT_HEAD",
685	"INSERT_TAIL",
686	"REMOVE_HEAD",
687	"REMOVE_ITEM",
688	"REMOVE_TAIL" };
689
690struct {
691	char *init;		/* initial state. */
692	char *final;		/* final state. */
693	char *elem;		/* element to operate on */
694	char *insert;		/* element to insert */
695	OP	op;		/* operation. */
696} ops[] = {
697
698	/* most operations on a empty list */
699	{ "", "", NULL, NULL, REMOVE_HEAD },
700	{ "", "", NULL, NULL, REMOVE_TAIL },
701	{ "", "A", NULL, "A", INSERT_HEAD },
702	{ "", "A", NULL, "A", INSERT_TAIL },
703
704	/* all operations on a one element list */
705	{ "A", "", NULL, NULL, REMOVE_HEAD },
706	{ "A", "", NULL, NULL, REMOVE_TAIL },
707	{ "A", "", "A", NULL, REMOVE_ITEM },
708	{ "B", "A B", NULL, "A", INSERT_HEAD },
709	{ "A", "A B", NULL, "B", INSERT_TAIL },
710	{ "B", "A B", "B", "A", INSERT_BEFORE },
711	{ "A", "A B", "A", "B", INSERT_AFTER },
712
713	/* all operations on a two element list */
714	{ "A B", "B", NULL, NULL, REMOVE_HEAD },
715	{ "A B", "A", NULL, NULL, REMOVE_TAIL },
716	{ "A B", "A", "B", NULL, REMOVE_ITEM },
717	{ "A B", "B", "A", NULL, REMOVE_ITEM },
718	{ "B C", "A B C", NULL, "A", INSERT_HEAD },
719	{ "A B", "A B C", NULL, "C", INSERT_TAIL },
720	{ "B C", "A B C", "B", "A", INSERT_BEFORE },
721	{ "A C", "A B C", "C", "B", INSERT_BEFORE },
722	{ "A C", "A B C", "A", "B", INSERT_AFTER },
723	{ "A C", "A C B", "C", "B", INSERT_AFTER },
724
725	/* all operations on a three element list */
726
727	{ "A B C", "B C", NULL, NULL, REMOVE_HEAD },
728	{ "A B C", "A B", NULL, NULL, REMOVE_TAIL },
729	{ "A B C", "A B", "C", NULL, REMOVE_ITEM },
730	{ "A B C", "A C", "B", NULL, REMOVE_ITEM },
731	{ "A B C", "B C", "A", NULL, REMOVE_ITEM },
732	{ "B C D", "A B C D", NULL, "A", INSERT_HEAD },
733	{ "A B C", "A B C D", NULL, "D", INSERT_TAIL },
734	{ "A B C", "X A B C", "A", "X", INSERT_BEFORE },
735	{ "A B C", "A X B C", "B", "X", INSERT_BEFORE },
736	{ "A B C", "A B X C", "C", "X", INSERT_BEFORE },
737	{ "A B C", "A X B C", "A", "X", INSERT_AFTER },
738	{ "A B C", "A B X C", "B", "X", INSERT_AFTER },
739	{ "A B C", "A B C X", "C", "X", INSERT_AFTER },
740};
741
742int
743main(argc, argv)
744	int argc;
745	char *argv[];
746{
747	void *list;
748	int fc, tc;		/* tc is total count, fc is failed count */
749	int eval, i, t, result;
750
751	eval = 0;
752	for (t = 0; t < sizeof(qfns) / sizeof(qfns[0]); ++t) {
753		fc = tc = 0;
754		printf("TESTING: %s\n", qfns[t].name);
755
756		for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++) {
757			list = qfns[t].f_init(ops[i].init);
758			result = qfns[t].f_verify(list, ops[i].init);
759			if (result == 0) {
760				fc++;
761				putchar('.');
762			} else {
763				putchar('+'); /* + means failed before op */
764				printf("\nVerify failed: %s\n",
765				    failure_reason_names[result]);
766				eval = 1;
767			}
768			if (!strcmp("sh_tailq", qfns[t].name)) {
769				result =
770				    sh_t_verify_TAILQ_LAST(list, ops[i].init);
771			}
772#ifdef VERBOSE
773			printf("\ncase %d %s in %s init: \"%s\" desired: \"%s\" elem: \"%s\" insert: \"%s\"\n",
774			    i, op_names[ops[i].op], qfns[t].name,
775			    ops[i].init, ops[i].final,
776			    ops[i].elem, ops[i].insert);
777			fflush(stdout);
778#endif
779			tc++;
780			switch (ops[i].op) {
781			case REMOVE_HEAD:
782				qfns[t].f_remove_head(list);
783				break;
784			case REMOVE_TAIL:
785				qfns[t].f_remove_tail(list);
786				break;
787			case REMOVE_ITEM:
788				qfns[t].f_remove_item(list, ops[i].elem);
789				break;
790			case INSERT_HEAD:
791				qfns[t].f_insert_head(list, ops[i].insert);
792				break;
793			case INSERT_TAIL:
794				qfns[t].f_insert_tail(list, ops[i].insert);
795				break;
796			case INSERT_BEFORE:
797				qfns[t].f_insert_before(
798				    list, ops[i].insert, ops[i].elem);
799				break;
800			case INSERT_AFTER:
801				qfns[t].f_insert_after(
802				    list, ops[i].insert, ops[i].elem);
803				break;
804			}
805			if (!strcmp("sh_tailq", op_names[ops[i].op])) {
806				result = sh_t_verify_TAILQ_LAST(list,
807				    ops[i].final);
808			}
809			if (result == 0)
810				result = qfns[t].f_verify(list, ops[i].final);
811			if (result == 0) {
812				fc++;
813				putchar('.');
814			} else {
815				putchar('*'); /* * means failed after op */
816				printf("\ncase %d %s in %s init: \"%s\" desired: \"%s\" elem: \"%s\" insert: \"%s\" got: %s - %s\n",
817				    i, op_names[ops[i].op], qfns[t].name,
818				    ops[i].init, ops[i].final,
819				    ops[i].elem, ops[i].insert,
820				    qfns[t].f_as_string(list),
821				    failure_reason_names[result]);
822				fflush(stdout);
823				eval = 1;
824			}
825
826			tc++;
827			qfns[t].f_discard(list);
828		}
829
830		printf("\t%0.2f%% passed (%d/%d).\n",
831		    (((double)fc/tc) * 100), fc, tc);
832	}
833	return (eval);
834}
835