summaryrefslogtreecommitdiff
path: root/src/tet3/tcc/scen3.c
blob: 1953068df75c6b209784caf421138523bd915f94 (plain)
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
/*
 *	SCCS: @(#)scen3.c	1.4 (97/03/27)
 *
 *	UniSoft Ltd., London, England
 *
 * (C) Copyright 1996 X/Open Company Limited
 *
 * All rights reserved.  No part of this source code may be reproduced,
 * stored in a retrieval system, or transmitted, in any form or by any
 * means, electronic, mechanical, photocopying, recording or otherwise,
 * except as stated in the end-user licence agreement, without the prior
 * permission of the copyright owners.
 * A copy of the end-user licence agreement is contained in the file
 * Licence which accompanies this distribution.
 * 
 * X/Open and the 'X' symbol are trademarks of X/Open Company Limited in
 * the UK and other countries.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/************************************************************************

SCCS:   	@(#)scen3.c	1.4 97/03/27 TETware release 3.3
NAME:		scen3.c
PRODUCT:	TETware
AUTHOR:		Andrew Dingwall, UniSoft Ltd.
DATE CREATED:	August 1996

DESCRIPTION:
	scenario parser stage 3 - prune and manipulate the scenario tree

MODIFICATIONS:
	Andrew Dingwall, UniSoft Ltd., March 1997
	in remove_unneeded_scenarios(), restart the "for" loop after
	removing a scenario

************************************************************************/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include "dtmac.h"
#include "error.h"
#include "scentab.h"
#include "dirtab.h"
#include "tcc.h"

#ifndef NOTRACE
#include "ltoa.h"
#endif


/* static function declarations */
static void add_scenrefs PROTOLIST((struct scentab *));
static void copy_r2 PROTOLIST((struct scentab *, struct scentab *,
	struct scentab **));
static void mark_needed_scenarios PROTOLIST((struct scentab *));
static void proc3refscen PROTOLIST((struct scentab *));
static void remove_unneeded_scenarios PROTOLIST((void));
static void rus2 PROTOLIST((struct scentab *));
static void ynp2 PROTOLIST((struct scentab *, int));


/*
**	proc3sctree() - perform scenario processing pass 3
**
**	the scenario tree at *sctree is manipulated in various ways
**	during this stage of processing
**
**	return 0 if successful or -1 on error
**	(at present - always returns 0)
*/

int proc3sctree(scenario)
char *scenario;
{
	register struct scentab *ep;
	struct scentab *myscen = (struct scentab *) 0;
	int cwd_prefix;

	/* If the scenario has the current directory "./" prefix,
	 * also check for the non-prefixed name */
	cwd_prefix = (!strncmp(scenario, "./", 2)) ? 1 : 0;

	/* set the SCF_NEEDED flag in the chosen scenario */
	TRACE1(tet_Tscen, 1, "proc3sctree(): marking needed scenarios");
	for (ep = sctree; ep; ep = ep->sc_forw) {
		ASSERT(ep->sc_magic == SC_MAGIC);
		ASSERT(ep->sc_type == SC_SCENARIO);
		if (!strcmp(ep->sc_scenario, scenario) ||
		    (cwd_prefix && !strcmp(ep->sc_scenario, &scenario[2]))) {
			TRACE2(tet_Tscen, 6, "chosen scenario %s is needed",
				ep->sc_scenario);
			ep->sc_flags |= SCF_NEEDED;
			myscen = ep;
			break;
		}
	}

	if (!myscen) {
		scenerrors++;
		fatal(0, "chosen scenario not defined:", scenario);
	}

	/* decend the tree below the chosen scenario, 
		identifying other needed scenarios */
	TRACE2(tet_Tscen, 4, "mark TOP: descend tree below scenario %s",
		myscen->sc_scenario);
	mark_needed_scenarios(myscen->sc_child);

	/* remove un-needed scenario trees */
	TRACE1(tet_Tscen, 1,
		"proc3sctree(): removing un-needed scenario trees 1");
	remove_unneeded_scenarios();

	/* copy referenced scenarios into the chosen tree */
	TRACE1(tet_Tscen, 1, "proc3sctree(): copying referenced scenarios");
	proc3refscen(myscen);

	/* mark all the other scenarios as un-needed and remove them */
	for (ep = sctree; ep; ep = ep->sc_forw) {
		ASSERT(ep->sc_magic == SC_MAGIC);
		ASSERT(ep->sc_type == SC_SCENARIO);
		if (ep != myscen)
			ep->sc_flags &= ~SCF_NEEDED;
	}
	TRACE1(tet_Tscen, 1,
		"proc3sctree(): removing un-needed scenario trees 2");
	remove_unneeded_scenarios();

	/* here there should only be one scenario (the chosen scenario) */
	ASSERT(sctree->sc_magic == SC_MAGIC);
	ASSERT(sctree->sc_type == SC_SCENARIO);
	ASSERT(sctree->sc_forw == (struct scentab *) 0);
	ASSERT(sctree == myscen);

	/* add the scenario reference numbers */
	TRACE1(tet_Tscen, 1,
		"proc3sctree(): adding scenario reference numbers");
	sctree->sc_ref = 0L;
	add_scenrefs(sctree->sc_child);
	

	return(0);
}

/*
**	mark_needed_scenarios() - set the NEEDED flag in the element at the
**		top of each of the needed scenarios
*/

static void mark_needed_scenarios(ep)
register struct scentab *ep;
{
	/*
	** traverse the tree at this level, descending referenced scenario
	** and directive trees
	*/
	for (; ep; ep = ep->sc_forw) {
		ASSERT(ep->sc_magic == SC_MAGIC);
		switch (ep->sc_type) {
		case SC_SCEN_NAME:
			ASSERT(ep->sc_scenptr->sc_magic == SC_MAGIC);
			TRACE2(tet_Tscen, 6, "scenario %s is needed",
				ep->sc_scenptr->sc_scenario);
			ep->sc_scenptr->sc_flags |= SCF_NEEDED;
			TRACE2(tet_Tscen, 5, "descend tree below scenario %s",
				ep->sc_scenptr->sc_scenario);
			mark_needed_scenarios(ep->sc_scenptr->sc_child);
			break;
		case SC_DIRECTIVE:
			TRACE2(tet_Tscen, 5, "descend tree below %s directive",
				prscdir(ep->sc_directive));
			mark_needed_scenarios(ep->sc_child);
			break;
		}
	}
}

/*
**	remove_unneeded_scenarios() - remove all unneeded scenarios
**		from the scenario tree
*/

static void remove_unneeded_scenarios()
{
	register struct scentab *ep;
	register int done;

	/*
	** remove each scenario which does not have the NEEDED flag set;
	** we must restart when a scenario is removed because the act
	** of removing a scenario breaks the forward pointer chain
	*/
	done = 0;
	do {
		done = 1;
		for (ep = sctree; ep; ep = ep->sc_forw) {
			ASSERT(ep->sc_magic == SC_MAGIC);
			if (ep->sc_flags & SCF_NEEDED)
				continue;
			done = 0;
			TRACE2(tet_Tscen, 6, "remove unneeded scenario %s",
				ep->sc_scenario);
			if (ep->sc_forw)
				ep->sc_forw->sc_back = ep->sc_back;
			if (ep->sc_back)
				ep->sc_back->sc_forw = ep->sc_forw;
			else {
				ASSERT(ep == sctree);
				sctree = ep->sc_forw;
			}
			if (ep->sc_child)
				rus2(ep->sc_child);
			scfree(ep);
			break;
		}
	} while (!done);
}

/*
**	rus2() - extend the remove_unneeded_scenario() processing
**
**	remove the tree at this level and below
*/

static void rus2(ep)
register struct scentab *ep;
{
	register struct scentab *forw;

	/* remove this level of the tree */
	while (ep) {
		ASSERT(ep->sc_magic == SC_MAGIC);
		forw = ep->sc_forw;
		switch (ep->sc_type) {
		case SC_SCENARIO:
		case SC_DIRECTIVE:
			if (ep->sc_child)
				rus2(ep->sc_child);
			break;
		}
		scfree(ep);
		ep = forw;
	}
}

/*
**	proc3refscen() - replace scenario references with the scenarios
**		themselves
*/ 

static void proc3refscen(parent)
struct scentab *parent;
{
	register struct scentab *ep;
	register int done;

	/*
	** traverse the tree at this level, copying in referenced
	** scenarios and descending directive trees;
	** we must restart the process after a scenario is copied in
	** because the act of copying breaks the forward pointer chain
	*/
	done = 0;
	do {
		done = 1;
		ASSERT(parent->sc_magic == SC_MAGIC);
		for (ep = parent->sc_child; ep; ep = ep->sc_forw) {
			ASSERT(ep->sc_magic == SC_MAGIC);
			switch (ep->sc_type) {
			case SC_SCEN_NAME:
				copy_refscen(ep, parent);
				done = 0;
				break;
			case SC_DIRECTIVE:
				TRACE2(tet_Tscen, 5,
					"descend tree below %s directive",
					prscdir(ep->sc_directive));
				proc3refscen(ep);
				break;
			}
			if (!done)
				break;
		}
	} while (!done);
}

/*
**	copy_refscen() - replace a referenced scenario node with a copy
**		of the referenced scenario
*/

void copy_refscen(ep, parent)
struct scentab *ep, *parent;
{
	register struct scentab *scenptr, *forw;
	struct scentab *back;

	/* remember essential information from this node, then free it */
	back = ep->sc_back;
	forw = ep->sc_forw;
	scenptr = ep->sc_scenptr;
	if (parent->sc_child == ep)
		parent->sc_child = (struct scentab *) 0;
	scfree(ep);

	/* replace the node with the scenario that it referenced */
	ASSERT(scenptr->sc_magic == SC_MAGIC);
	TRACE4(tet_Tscen, 6, "copy_refscen(): replacing referenced scenario node at %s with a copy of scenario %s at %s",
		tet_i2x(ep), scenptr->sc_scenario, tet_i2x(scenptr));
	if (scenptr->sc_child)
		copy_r2(scenptr->sc_child, parent, &back);
	else if (!parent->sc_child)
		parent->sc_child = forw;
	if (back)
		back->sc_forw = forw;
	if (forw)
		forw->sc_back = back;
}

/*
**	copy_r2() - extend the copy_refscen() processing for a referenced
**		scenario
**
**	from points to the first element in the scenario to be copied in
**
**	scenario elements are copied in below the element at *parent and to
**	the right of the element at **sctp
**
**	*sctp is updated as copying progresses - on return, *sctp contains
**	the address of the last element copied in
*/

static void copy_r2(from, parent, sctp)
register struct scentab *from;
struct scentab *parent, **sctp;
{
	register struct scentab *ep;
	struct scentab *sctmp;

	TRACE3(tet_Tscen, 6, "copy_r2(): from = %s, parent = %s",
		tet_i2x(from), tet_i2x(parent));

	for (; from; from = from->sc_forw) {
		ASSERT(from->sc_magic == SC_MAGIC);
		ep = scalloc();
		*ep = *from;
		from->sc_flags |= SCF_DATA_USED;
		ep->sc_flags |= SCF_DATA_USED;
		scstore(ep, parent, sctp);
		if (from->sc_type == SC_DIRECTIVE) {
			TRACE3(tet_Tscen, 6, "copy_r2(): descend tree below %s directive at %s",
				prscdir(from->sc_directive), tet_i2x(from));
			sctmp = (struct scentab *) 0;
			copy_r2(from->sc_child, ep, &sctmp);
		}
	}

	TRACE1(tet_Tscen, 6, "copy_r2() RETURN");
}

/*
**	ynproc() - prune test cases from the scenario tree that are not
**		selected by -y and -n options
*/

void ynproc(flag)
int flag;
{
	TRACE2(tet_Tscen, 1,
		"ynproc(%s): prune scenario tree w.r.t -y/-n options",
		tet_i2a(flag));

	ynp2(sctree, flag);
}

/*
**	ynp2() - extend the ynproc() processing
*/

static void ynp2(ep, flag)
register struct scentab *ep;
int flag;
{
	register struct scentab *forw;

	for (; ep; ep = forw) {
		ASSERT(ep->sc_magic == SC_MAGIC);
		forw = ep->sc_forw;
		switch (ep->sc_type) {
		case SC_SCENARIO:
		case SC_DIRECTIVE:
			ynp2(ep->sc_child, flag);
			break;
		case SC_TESTCASE:
			if (!okstr(ep->sc_tcname, flag)) {
				TRACE2(tet_Tscen, 4,
					"-{y|n} removes this test case: %s",
					ep->sc_tcname);
				scrm_lnode(ep);
			}
			break;
		}
	}
}

/*
**	add_scenrefs() - add reference numbers to the scenario tree
*/

static void add_scenrefs(ep)
register struct scentab *ep;
{
	static long ref;

	for (; ep; ep = ep->sc_forw) {
		ASSERT(ep->sc_magic == SC_MAGIC);
		ASSERT(ep->sc_ref == 0L);
		ep->sc_ref = ++ref;
		switch (ep->sc_type) {
		case SC_DIRECTIVE:
			add_scenrefs(ep->sc_child);
			break;
		}
	}
}