File: merge_diff_funcs.c

package info (click to toggle)
cruft 0.9.31
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 35,520 kB
  • ctags: 129
  • sloc: ansic: 811; sh: 324; perl: 247; python: 75; makefile: 69
file content (138 lines) | stat: -rw-r--r-- 3,906 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "river.h"

/*
 * Please note that the adjective smaller/smallest in this program does not
 * have anything to do with its size. Instead it means "a river/stream, whose
 * line to be read on input compares as lexicographically smaller than lines to
 * be read from other rivers/streams".
 */

static void scroll_smallest(int *smallest, river *rivers)
{
	unsigned int idx;
	for (idx = 0; idx < NUM_RIVERS; idx++)
		if (smallest[idx])
			river_scroll(&rivers[idx]);
}

static int at_least_one_is(int *smallest)
{
	unsigned int idx;
	for (idx = 0; idx < NUM_RIVERS; idx++)
		if (smallest[idx])
			return 1;
	return 0;
}

static void debug_current_state(int *smallest, river *rivers)
{
	char *line = "?";
	unsigned int idx;
	for (idx = 0; idx < NUM_RIVERS; idx++) {
		cruft_debug("%c", smallest[idx] ? '*' : '-');
		if (smallest[idx])
			line = river_least_line(&rivers[idx]);
	}
	cruft_debug(" %s (", line);
	for (idx = 0; idx < NUM_RIVERS; idx++) {
		cruft_debug("%s%s", river_least_line(&rivers[idx]), idx == NUM_RIVERS - 1 ? "" : " ");
	}
	cruft_debug(")\n");
}

/*
 * Finds out which river(s) in rivers[] have the smallest line(s) on input and
 * sets matching elements of smallest[] appropriately.
 */
static void pick_smallest_rivers(int *smallest, river *rivers)
{
	int prev = -1;
	int cur;
	for (cur = 0; cur < NUM_RIVERS; cur++) {
		int smaller = rivers_compare(prev, cur, rivers);
		if (prev == smaller)
			; /* cur is larger, so nothing changes */
		else if (cur == smaller) {
			/* cur is smaller than anything before, so first wipe
			 * the table up and including the previous element */
			memset(smallest, 0, sizeof(int) * cur);
			/* and mark the new smallest one */
			smallest[cur] = 1;
			prev = smaller;
		} else
			/* prev and cur have the same line on input, so just
			 * mark cur as being smallest as well */
			smallest[cur] = 1;
			/* prev stays unchanged, as it matters in case of EOFs */
	}

	/* some assertions */
	{
		unsigned int idx;
		/* a river must not be smallest and empty at the same time */
		for (idx = 0; idx < NUM_RIVERS; idx++)
			assert(! (smallest[idx] && (! river_has_line(&rivers[idx]))));
		/* some river must be smallest, if at least one is not empty */
		assert(at_least_one_is(smallest));
	}
}

int merge_diff(char *spool_dir_name)
{
	river rivers[NUM_RIVERS] = {
		{ "file",           0, -1, { NULL }, { NULL }, "file_", "unex" },
		{ "may exist",      0, -1, { NULL }, { NULL }, "mayx_", "whte" },
		{ "must exist",     0, -1, { NULL }, { NULL }, "must_", "miss" },
		{ "must not exist", 0, -1, { NULL }, { NULL }, "msnt_", "frbn" }
	};

	if (! rivers_open_files(spool_dir_name, rivers))
		return EXIT_FAILURE;

	cruft_debug(DEBUG_HEADER);

	for(;;) {
		int smallest[NUM_RIVERS];
		memset(smallest, 0, sizeof(int) * NUM_RIVERS);

		if (! rivers_prepare_round(rivers))
			break;

		pick_smallest_rivers(smallest, rivers);

		debug_current_state(smallest, rivers);

		/* must be, but isn't */
		if (smallest[MUST_IDX] && ! smallest[FILE_IDX])
			if (! river_output_line(&rivers[MUST_IDX]))
				return EXIT_FAILURE;

		/* is, but not explained by must nor may */
		if (smallest[FILE_IDX] && (! smallest[MUST_IDX] && ! smallest[MAYX_IDX]))
			if (! river_output_line(&rivers[FILE_IDX]))
				return EXIT_FAILURE;

		/* must not be, but is */
		if (smallest[MSNT_IDX] && smallest[FILE_IDX])
			if (! river_output_line(&rivers[MSNT_IDX]))
				return EXIT_FAILURE;

		if (smallest[MSNT_IDX]) {
			if (smallest[MAYX_IDX])
				fprintf(stderr, "Explain script (may and mustn't) conflict: [%s]\n", river_least_line(&rivers[MSNT_IDX]));
			if (smallest[MUST_IDX])
				fprintf(stderr, "Explain script (must and mustn't) conflict: [%s]\n", river_least_line(&rivers[MSNT_IDX]));
		}

		scroll_smallest(smallest, rivers);
	}

	if (! rivers_close(rivers))
		return EXIT_FAILURE;

	return EXIT_SUCCESS;
}