16 #define STR(x) STR2(x)
18 #define L(x) __FILE__ ":" STR(__LINE__) ": " x
19 #define UNUSED(x) (void) (sizeof(x))
21 #define BOUNDARY_NODE ((node *) 0)
22 #define NODE_NAME(n) ((n) ? ((n)->name) : ("BOUNDARY"))
23 #define NODE_COLOR(n) ((n) ? ((n)->c) : (C_BOUNDARY))
25 typedef enum { C_BLACK
, C_WHITE
, C_BOUNDARY
} color
;
26 typedef enum { D_LEFT
, D_RIGHT
} dir
;
27 typedef enum { R_AWAY
, R_TO
} relative_dir
;
40 unsigned int fix_depth
;
51 add_new_node(graph
*g
,
62 if (n
> INT_MAX
/ 2) {
63 fprintf(stderr
, "Absurdly long node name\n");
67 if (!strncmp(s
, "BOUNDARY", n
) &&
69 fprintf(stderr
, "The node name `BOUNDARY' is forbidden\n");
73 for (p
= s
; p
< s
+ n
; ++p
) {
79 "Node names are not allowed to contain `[', "
85 for (j
= 0; j
< g
->nodes_num
; ++j
) {
86 if (!strncmp(s
, g
->nodes
[j
].name
, n
) &&
87 g
->nodes
[j
].name_len
== n
) {
88 fprintf(stderr
, "Duplicate node %s\n",
94 if (!(newmem
= realloc(g
->nodes
, (g
->nodes_num
+ 1) *
100 if (!(sd
= strndup(s
, n
+ 1))) {
101 perror(L("strndup"));
107 g
->nodes
[g
->nodes_num
] = (node
) { .name
= sd
, .name_len
= n
, .c
= c
};
119 add_new_edge(graph
*g
,
132 if (n1
> INT_MAX
/ 2 ||
134 fprintf(stderr
, "Absurdly long node name\n");
138 for (j
= 0; j
< g
->nodes_num
; ++j
) {
139 if (!strncmp(s1
, g
->nodes
[j
].name
, n1
) &&
140 g
->nodes
[j
].name_len
== n1
) {
146 for (j
= 0; j
< g
->nodes_num
; ++j
) {
147 if (!strncmp(s2
, g
->nodes
[j
].name
, n2
) &&
148 g
->nodes
[j
].name_len
== n2
) {
155 if (strncmp(s1
, "BOUNDARY", n1
) ||
157 fprintf(stderr
, "Unknown node `%.*s'\n", (int) n1
, s1
);
163 if (strncmp(s2
, "BOUNDARY", n2
) ||
165 fprintf(stderr
, "Unknown node `%.*s'\n", (int) n2
, s2
);
171 fprintf(stderr
, "Illegal node (%s, %s)\n", NODE_NAME(v1
),
176 for (j
= 0; j
< g
->edges_num
; ++j
) {
183 fprintf(stderr
, "Duplicate edge (%s, %s)\n", NODE_NAME(
184 e
->l
), NODE_NAME(e
->r
));
189 if (!(newmem
= realloc(g
->edges
, (g
->edges_num
+ 1) *
190 sizeof *g
->edges
))) {
191 perror(L("realloc"));
196 g
->edges
[g
->edges_num
] = (edge
) { .l
= v1
, .r
= v2
, .fix_depth
= -1 };
207 * Order edges first by their left component, then by their right
208 * component. This ensures that the edges representing boundary nodes
212 comp_edge(const void *a
,
215 edge
*pa
= (edge
*) a
;
216 edge
*pb
= (edge
*) b
;
231 d
= strcmp(pa
->l
->name
, pb
->l
->name
);
238 return strcmp(pa
->r
->name
, pb
->r
->name
);
242 * Returns the address of the first byte of a [non-]whitespace character
243 * beyond s, or 0 on error, or terminus on exhaustion.
246 next_wchar_of_certain_type(const char *s
,
247 const char *terminus
,
248 char want_whitespace
)
251 mbstate_t ps
= { 0 };
259 while (p
< terminus
) {
260 switch ((e
= mbrtowc(&wc
, p
, (terminus
- p
) + 1, &ps
))) {
263 perror(L("mbrtowc"));
273 if ((!!want_whitespace
== !!iswspace(wc
)) &&
286 read_file(const char *path
,
292 const char *contents_end
= 0;
301 if ((fd
= open(path
, O_RDONLY
)) < 0) {
306 if (fstat(fd
, &sb
) < 0) {
314 fprintf(stderr
, "File is not well-formed\n");
318 if ((contents
= mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) ==
324 contents_end
= contents
+ (length
- 1);
326 if (!(p
= memchr(contents
, '[', length
)) ||
327 strncmp(p
, "[W]", 3)) {
328 fprintf(stderr
, "File does not contain `[W]' marker\n");
333 r
= memchr(q
, '[', contents_end
- q
);
336 strncmp(r
, "[B]", 3)) {
337 fprintf(stderr
, "File does not contain `[B]' marker\n");
341 p
= next_wchar_of_certain_type(q
, r
, 0);
342 q
= next_wchar_of_certain_type(p
, r
, 1);
347 if (add_new_node(g
, C_WHITE
, p
, q
- p
) < 0) {
352 p
= next_wchar_of_certain_type(q
, contents_end
, 0);
353 q
= next_wchar_of_certain_type(p
, contents_end
, 1);
357 r
= memchr(p
, '[', contents_end
- q
);
360 strncmp(r
, "[E]", 3)) {
361 fprintf(stderr
, "File does not contain `[E]' marker\n");
365 p
= next_wchar_of_certain_type(p
, r
, 0);
366 q
= next_wchar_of_certain_type(p
, r
, 1);
371 if (add_new_node(g
, C_BLACK
, p
, q
- p
) < 0) {
376 p
= next_wchar_of_certain_type(q
, contents_end
, 0);
377 q
= next_wchar_of_certain_type(p
, contents_end
, 1);
383 if (!(p
= memchr(s
, '(', contents_end
- s
))) {
387 if (!(p
= next_wchar_of_certain_type(p
, contents_end
, 0))) {
391 if (!(q
= next_wchar_of_certain_type(p
, contents_end
, 1))) {
395 if (!(r
= next_wchar_of_certain_type(q
, contents_end
, 0))) {
399 if (!(s
= next_wchar_of_certain_type(r
, contents_end
, 1))) {
403 if (!(t
= memchr(r
, ')', contents_end
- r
))) {
409 if (add_new_edge(g
, p
, q
- p
, r
, s
- r
) < 0) {
422 munmap(contents
, length
);
429 * Modify graph g so that all edges containing v point away from (to)
430 * node v when away==1 (0), except the specified exception edge. If a
431 * contradiction is encountered, *proven_wrong is set. If anything is
432 * done, *changed is set.
435 ensure_all_pointing_right_dir(graph
*g
,
452 for (j
= 0; j
< g
->edges_num
; ++j
) {
453 if ((e
= &g
->edges
[j
]) == except
) {
458 if (e
->fix_depth
<= depth
&&
459 e
->d
== (rd
== R_AWAY
? D_LEFT
: D_RIGHT
)) {
465 if (e
->fix_depth
> depth
) {
467 e
->fix_depth
= depth
;
468 e
->d
= (rd
== R_AWAY
? D_RIGHT
: D_LEFT
);
470 } else if (e
->r
== v
) {
471 if (e
->fix_depth
<= depth
&&
472 e
->d
== (rd
== R_AWAY
? D_RIGHT
: D_LEFT
)) {
478 if (e
->fix_depth
> depth
) {
480 e
->fix_depth
= depth
;
481 e
->d
= (rd
== R_AWAY
? D_LEFT
: D_RIGHT
);
488 * Check graph g to ensure that there is at least one edge containing
489 * v which is able to be set to point away from (to) node v when
490 * away==1 (0). If none is found, *proven_wrong is set. If exactly one
491 * is found, it is fixed with the appropriate depth and *changed is
495 ensure_one_left_to_point_right(graph
*g
,
512 for (j
= 0; j
< g
->edges_num
; ++j
) {
515 if (e
->fix_depth
<= depth
) {
517 e
->d
== (rd
== R_AWAY
? D_RIGHT
: D_LEFT
)) &&
519 e
->d
== (rd
== R_AWAY
? D_LEFT
: D_RIGHT
))) {
521 * Ignore fixed nodes that don't have
522 * right orientation and endpoint
528 * We don't just have a candidate, we have an
529 * actual fixed edge. Don't bother checking
530 * for the error case of two edges, or
531 * forcibly setting all other edges to the
532 * right direction, those actions are handled
533 * in ensure_all_pointing_right_dir().
536 } else if (e
->l
== v
||
541 * There are multiple candidates, so
542 * we can't set anything
553 * There's nothing that could save us - this
554 * configuration is impossible.
562 candidate
->fix_depth
= depth
;
564 if ((candidate
->l
== v
&&
566 (candidate
->r
== v
&&
568 candidate
->d
= D_RIGHT
;
570 candidate
->d
= D_LEFT
;
575 update_for_newly_fixed_edge(graph
*g
,
589 switch (NODE_COLOR(e
->l
)) {
591 ensure_all_pointing_right_dir(g
, e
->l
, R_AWAY
, depth
, e
,
592 changed
, proven_wrong
);
595 ensure_one_left_to_point_right(g
, e
->l
, R_AWAY
, depth
,
596 changed
, proven_wrong
);
606 switch (NODE_COLOR(e
->r
)) {
608 ensure_one_left_to_point_right(g
, e
->r
, R_TO
, depth
,
609 changed
, proven_wrong
);
612 ensure_all_pointing_right_dir(g
, e
->r
, R_TO
, depth
, e
,
613 changed
, proven_wrong
);
622 switch (NODE_COLOR(e
->l
)) {
624 ensure_one_left_to_point_right(g
, e
->l
, R_TO
, depth
,
625 changed
, proven_wrong
);
628 ensure_all_pointing_right_dir(g
, e
->l
, R_TO
, depth
, e
,
629 changed
, proven_wrong
);
639 switch (NODE_COLOR(e
->r
)) {
641 ensure_all_pointing_right_dir(g
, e
->r
, R_AWAY
, depth
, e
,
642 changed
, proven_wrong
);
645 ensure_one_left_to_point_right(g
, e
->r
, 1, depth
,
646 changed
, proven_wrong
);
657 * Repeatedly call update_for_newly_fixed_edge on all edges of a given
658 * depth, possibly fixing more choices of edge directions at that
662 update_to_fixed_point(graph
*g
,
665 char allow_scan_below_depth
)
675 for (j
= 0; j
< g
->edges_num
; ++j
) {
678 if (e
->fix_depth
== depth
||
679 (allow_scan_below_depth
&&
680 e
->fix_depth
<= depth
)) {
681 update_for_newly_fixed_edge(g
, e
, depth
,
689 admits_perfect_orientation(graph
*g
,
693 edge
*chosen_to_fix
= 0;
697 if (depth
>= (unsigned int) -3) {
698 fprintf(stderr
, "Absurd depth encountered - bailing\n");
703 for (j
= 0; j
< g
->edges_num
; ++j
) {
706 if (e
->fix_depth
> depth
) {
708 * In the case that some edges were tested
709 * before for other configurations, we wish to
710 * avoid the situation in which such a branch
711 * was tested at depth depth+1, and is not
712 * selected as the unfixed branch here. For
713 * then it would, in any speculation arising
714 * from this position, magically appear to be
715 * fixed, when it really should not be.
717 e
->fix_depth
= (unsigned int) -1;
723 chosen_to_fix
->d
= D_LEFT
;
726 * We start out at depth + 2 so that, if this doesn't
727 * work out, the ramifications will be nicely hidden
728 * by moving to only depth + 1 in the next step
730 chosen_to_fix
->fix_depth
= depth
+ 2;
731 update_to_fixed_point(g
, depth
+ 2, &broken
, 0);
734 admits_perfect_orientation(g
, depth
+ 2)) {
739 * Evidently setting that direction to LEFT resulted
740 * in a contradiction. So we may freely set it to
741 * RIGHT. We could really set the depth to `depth'
742 * here, but that doesn't really gain anything.
744 chosen_to_fix
->d
= D_RIGHT
;
745 chosen_to_fix
->fix_depth
= depth
+ 1;
747 update_to_fixed_point(g
, depth
+ 1, &broken
, 0);
750 admits_perfect_orientation(g
, depth
+ 1)) {
755 * There was a choice we could make, and each choice
756 * led to a contradiction.
762 * At this point, there's nothing we may choose. Just check
763 * whether our choices made sense.
765 for (j
= 0; j
< g
->nodes_num
; ++j
) {
766 g
->nodes
[j
].check_res
= 0;
769 for (j
= 0; j
< g
->edges_num
; ++j
) {
776 e
->l
->c
== C_WHITE
) {
783 e
->r
->c
== C_BLACK
) {
793 e
->l
->c
== C_BLACK
) {
800 e
->r
->c
== C_WHITE
) {
814 for (j
= 0; j
< g
->nodes_num
; ++j
) {
816 !g
->nodes
[j
].check_res
;
828 char printing_first_elt
= 0;
829 char printing_first_base
= 0;
833 size_t num_edge_nodes
= 0;
835 setlocale(LC_ALL
, "");
838 printf("Usage: %s INPUT_FILE\n", argv
[0]);
843 if (read_file(argv
[1], &g
) < 0) {
847 /* Tidy up the edges */
848 for (j
= 0; j
< g
.edges_num
; ++j
) {
857 strcmp(e
->l
->name
, e
->r
->name
) > 0) {
864 qsort(g
.edges
, g
.edges_num
, sizeof *g
.edges
, comp_edge
);
867 * Now all the border nodes (the 0s) are at the front - how
868 * many are there? While we're here, fix the boundary edges as
869 * LEFT at initial depth 0.
871 for (j
= 0; j
< g
.edges_num
; ++j
) {
879 e
->fix_depth
= (unsigned int) -1;
884 * Count upwards through the possible start source/sink
885 * configurations, in binary
888 printing_first_base
= 1;
890 for (j
= num_edge_nodes
; j
< g
.edges_num
; ++j
) {
891 g
.edges
[j
].fix_depth
= (unsigned int) -1;
895 update_to_fixed_point(&g
, 0, &broken
, 1);
898 admits_perfect_orientation(&g
, 1)) {
899 if (!printing_first_base
) {
903 printing_first_base
= 0;
905 printing_first_elt
= 1;
907 for (j
= 0; j
< num_edge_nodes
; ++j
) {
908 if (g
.edges
[j
].d
== D_LEFT
) {
909 if (!printing_first_elt
) {
912 printf("%s", NODE_NAME(g
.edges
[j
].r
));
913 printing_first_elt
= 0;
920 if (g
.edges
[0].d
== D_LEFT
) {
921 g
.edges
[0].d
= D_RIGHT
;
925 while (j
< num_edge_nodes
) {
926 if (g
.edges
[j
].d
== D_RIGHT
) {
927 g
.edges
[j
].d
= D_LEFT
;
929 g
.edges
[j
].d
= D_RIGHT
;
936 if (j
>= num_edge_nodes
) {
937 /* Must have tried all configurations */
946 for (j
= 0; j
< g
.nodes_num
; ++j
) {
947 free(g
.nodes
[j
].name
);