1 /*
2 This product contains certain software code or other information
3 ("AT&T Software") proprietary to AT&T Corp. ("AT&T").  The AT&T
4 Software is provided to you "AS IS".  YOU ASSUME TOTAL RESPONSIBILITY
5 AND RISK FOR USE OF THE AT&T SOFTWARE.  AT&T DOES NOT MAKE, AND
6 EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
7 WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
8 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
9 TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
10 WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
11 PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
12 WILL MEET YOUR REQUIREMENTS.
13 
14 Unless you accept a license to use the AT&T Software, you shall not
15 reverse compile, disassemble or otherwise reverse engineer this
16 product to ascertain the source code for any AT&T Software.
17 
18 (c) AT&T Corp. All rights reserved.  AT&T is a registered trademark of AT&T Corp.
19 
20 ***********************************************************************
21 
22 Description:
23 
24 		Program to test the in-memory API to the XMill (de)compression routines
25 
26 History:
27 
28       10/11/2002  - created by Hedzer Westra <hedzer@adlibsoft.com>
29 
30 */
31 
32 #include "stdafx.h"
33 
34 #define MAXEXPRS 1024
35 
36 #ifdef _DEBUG
37 	/* undefine to skip storing of XMI files */
38 	#define SAVE_OUTPUT
39 #endif
40 
41 /* global err msg */
42 char *errstr = NULL;
43 
44 /* compress and decompress 'buffer' using type 'lossy',
45  * save it to 'filename'.xmi and 'filename'.xml
46  * and then check consistency with the original XML iff
47  * compression was lossless.
48  */
compdecomp(char * buffer,int buflen,char * filename,int targetsize,clock_t * t2t,clock_t * t3t,int * xmibuflenp,bool isFirst)49 int testsettings::compdecomp(char *buffer, int buflen, char *filename, int targetsize,
50                              clock_t *t2t, clock_t *t3t, int *xmibuflenp, bool isFirst)
51 {
52 	char *xmibuf = NULL;
53 	char *xmlbuf = NULL;
54 	int xmibuflen = 0, xmlbuflen = 0;
55 	char *compr = NULL;
56 #ifdef SAVE_OUTPUT
57 	char dumstr[BUFLEN];
58 #endif
59 	clock_t t1 = clock();
60 	int stat = 0, cstat = 0;
61 	clock_t t2, t3;
62 	int bytesread = 0, endmarker = 0, len = 0;
63 
64    try {
65 	   /* compress */
66 	   if (blocksize > 0) {
67 		   /* read XML data per block */
68 
69 		   /* init */
70 		   xmill->InitCompress(&xmibuf, &xmibuflen, &bytesread);
71 		   do {
72 			   /* must we signal end-of-data ? */
73 			   if ((len = min(blocksize, buflen-bytesread)) == buflen-bytesread) {
74 				   endmarker = XMILL_END_DATA;
75 			   } else {
76 				   endmarker = XMILL_END_NONE;
77 			   }
78 			   /* compress this block */
79 			   xmill->CompressBlock(
80 					   &buffer[bytesread],
81 					   len,
82 					   &endmarker);
83 		   } while (bytesread < buflen);
84 		   /* check endmarker */
85 		   if (endmarker != XMILL_END_DATA) {
86 			   /* XML file not valid! */
87 			   //throw new XMillException(XMILL_ERR_PARSE, "There are unclosed XML tags!");
88 			   stat = XMILL_ERR_PARSE;
89 			   goto cleanup;
90 		   }
91 		   /* end the compression */
92 		   xmill->EndCompress();
93 	   } else {
94 		   /* compress a whole XML file at once */
95          xmill->Compress(buffer, buflen, &xmibuf, &xmibuflen, &bytesread);
96    	}
97    } catch (XMillException *e) {
98       stat = e->code;
99       errstr = str_save(e->GetErrorMsg());
100       delete e;
101 		t3 = t2 = clock();
102 		goto cleanup;
103 	}
104 
105 	t2 = clock();
106 
107 #ifdef SAVE_OUTPUT
108 	/* write to file */
109 	if (filename) {
110 		sprintf(dumstr, "%s.%s", filename, XMILL_EXT_XMI);
111 		FILE *f1 = fopen(dumstr, "wb");
112 		if (f1) {
113 			fwrite(xmibuf, 1, xmibuflen, f1);
114 			fclose(f1);
115 		}
116 	}
117 #endif
118 
119    try {
120 	   /* decompress */
121 	   if (blocksize > 0) {
122 		   /* read XMI data per block */
123 
124 		   /* init */
125 		   xmill->InitDecompress(&xmlbuf, &xmlbuflen, &bytesread);
126 		   do {
127 			   /* decompress this block */
128 			   xmill->DecompressBlock(
129 					   &xmibuf[bytesread],
130 					   min(blocksize, xmibuflen-bytesread),
131 					   &endmarker);
132 		   } while (bytesread < xmibuflen);
133 		   /* check endmarker */
134 		   if (endmarker != XMILL_END_DATA) {
135 			   /* XMI file not valid! */
136 			   stat = XMILL_ERR_PARSE;
137 			   goto cleanup;
138 		   }
139 		   /* end the decompression */
140 		   xmill->EndDecompress();
141 	   } else {
142 		   /* decompress in one go */
143 		   xmill->Decompress(xmibuf, xmibuflen,
144 			   &xmlbuf, &xmlbuflen, &bytesread);
145 	   }
146    } catch (XMillException *e) {
147       stat = e->code;
148       errstr = str_save(e->GetErrorMsg());
149       delete e;
150 		t3 = clock();
151 		goto cleanup;
152 	}
153 
154 	/* get timings */
155 	t3 = clock();
156 	t3 -= t2;
157 	t2 -= t1;
158    *t2t += t2;
159    *t3t += t3;
160 
161    *xmibuflenp = xmibuflen;
162 
163 	/* free XMI data */
164 	free (xmibuf);
165 
166 	/* check targetsize */
167 	if (  targetsize > 0
168 		&& targetsize != xmibuflen
169 		&& stats >= TEST_STATS_ERR) {
170 		if (!mustfail) {
171 			printf("Targetsize not matched!\n");
172 		}
173 		stat = TEST_ERROR_TARGETSIZE;
174 	}
175 
176 #ifdef SAVE_OUTPUT
177 	/* write output to file */
178 	if (filename) {
179 		sprintf(dumstr, "%s.xml", filename);
180 		FILE *f1 = fopen(dumstr, "wb");
181 		if (f1) {
182 			fwrite(xmlbuf, xmlbuflen, 1, f1);
183 			fclose(f1);
184 		}
185 	}
186 #endif
187 
188 	cstat = checkintegrity(buffer, buflen, xmlbuf, xmlbuflen);
189 	if (stat == 0) {
190 		stat = cstat;
191 	}
192 
193 cleanup:
194 	/* print stats */
195 	switch (bzip) {
196 		case XMILL_GPC_BZIP:
197 			compr = "bzip2";
198 			break;
199 		case XMILL_GPC_GZIP:
200 			compr = "gzip";
201 			break;
202 		case XMILL_GPC_NONE:
203 			compr = "nozip";
204 			break;
205 		case XMILL_GPC_PPMDI:
206 			compr = "ppmdi";
207 			break;
208 		default:
209 			compr = "unknown";
210 			break;
211 	}
212 	if (  (stats >= TEST_STATS_BPCTIME && isFirst)
213 		|| (stat != 0 && stats >= TEST_STATS_ERR && !mustfail)) {
214       /* print stats */
215 		printf ("stats:\txml: %ld Bytes, xmi: %ld Bytes, target: %ld Bytes\n"
216                "\tratio: %6.2lf%%, bpc: %4.2lf\n"
217                "\ttype: %s, compressor: %s, idx: %ld, paths: %s\n",
218 			buflen, xmibuflen, targetsize,
219 			(double)xmibuflen * 100 / (double)buflen,
220          (double)xmibuflen * 8 / (double)buflen,
221 			lossy ? "lossy" : "lossless",
222 			compr, gpcidx,
223 			exprs ? "yes" : "no");
224 	}
225 
226 	/* free decompressed XML data */
227 	tryfree (xmlbuf);
228 
229 	return stat;
230 }
231 
checkintegrity(char * buffer,int buflen,char * xmlbuf,int xmlbuflen)232 int testsettings::checkintegrity(char *buffer, int buflen, char *xmlbuf, int xmlbuflen)
233 {
234 	int i = 0, j = 0, stat = 0;
235 	bool different = false;
236 
237 	/* check that input==output */
238 	if (ignorewhite || lossy) {
239 		/* text should be the same except whitespace */
240 		while(i < buflen && j < xmlbuflen) {
241 			while (isspace(buffer[i])) i++;
242 			while (isspace(xmlbuf[j])) j++;
243 			if (buffer[i] != xmlbuf[j]) {
244 				different = true;
245 				break;
246 			}
247 			i++;
248 			j++;
249 		}
250 		if (different) {
251 			if (stats >= TEST_STATS_ERR && !mustfail) {
252 				printf("uncompressed data differs in pos %ld/%ld! ('%c' != '%c')\n",
253 					i, j, buffer[i], xmlbuf[j]);
254 			}
255 			stat = TEST_ERROR_NOIGNMATCH;
256 		}
257 	} else {
258 		/* text should be exactly the same */
259 		if (  buflen != xmlbuflen
260 			&& stats >= TEST_STATS_ERR
261 			&& !mustfail) {
262 			printf("uncompressed data size differs: %ld != %ld!\n", buflen, xmlbuflen);
263 		}
264 		int thebuflen = min(xmlbuflen, buflen);
265 		if (memcmp(buffer, xmlbuf, thebuflen)) {
266 			while(i < thebuflen && buffer[i]==xmlbuf[i]) i++;
267 			stat = TEST_ERROR_NOEXACTMATCH;
268 			if (stats >= TEST_STATS_ERR && !mustfail) {
269 				printf("uncompressed data differs in pos %ld! ('%c' != '%c')\n",
270 					i, buffer[i], xmlbuf[i]);
271 			}
272 		}
273 	}
274 
275 cleanup:
276 	return stat;
277 }
278 
279 /* decompress the xmifile and check consistency with xmlfile */
rundecomp(char * xmlfile,char * xmifile,int times)280 int testsettings::rundecomp(char *xmlfile, char *xmifile, int times)
281 {
282 	int stat = 0, i = 0;
283 	char *xmlbuf = NULL;
284 	char *xmibuf = NULL;
285 	char *xmlbuf2 = NULL;
286 	int xmlbuflen = 0;
287 	int xmibuflen = 0;
288 	int xmlbuflen2 = 0;
289 	clock_t t1, t2;
290 	int bytesread = 0;
291 
292 	/* read XML and XMI file */
293 	if ((stat = readfile(xmlfile, &xmlbuf, &xmlbuflen)) != 0) {
294 		goto cleanup;
295 	}
296 	if ((stat = readfile(xmifile, &xmibuf, &xmibuflen)) != 0) {
297 		goto cleanup;
298 	}
299 
300 	/* decompress it! */
301 	t1 = clock();
302 	for (i=0; i<times; i++) {
303       try {
304 		   xmill->Decompress(xmibuf,
305 				   blocksize > 0 ? min(blocksize, xmibuflen) : xmibuflen,
306 				   &xmlbuf2, &xmlbuflen2,
307 				   &bytesread);
308       } catch (XMillException *e) {
309          stat = e->code;
310          errstr = e->GetErrorMsg();
311          delete e;
312          goto cleanup;
313 	   }
314 		/* check that input==output */
315 		stat = checkintegrity(xmlbuf, xmlbuflen, xmlbuf2, xmlbuflen2);
316    }
317 
318    t2 = clock() - t1;
319 	if (stats >= TEST_STATS_TIMING
320 	   || (stat != 0 && stats >= TEST_STATS_ERR && !mustfail)) {
321 		printf("Done uncompressing %s %ld times.\n", xmifile, times);
322 	}
323 	if (stat < 0) {
324 		stat = 0;
325 	}
326 
327 	if (stats >= TEST_STATS_TIMING && !mustfail) {
328    	/* print stats */
329 		printf ("xml: %ld Bytes, xmi: %ld Bytes\n", xmlbuflen, xmibuflen);
330    	/* print timings */
331 		printf ("total clocks: %ld\naverage throughput: %lf KiB XML/sec, %lf KiB XMI/sec\n",
332          t2,
333 			(double)xmlbuflen * (double)CLOCKS_PER_SEC * (double)times / (1024.0 * (double)t2),
334 			(double)xmibuflen * (double)CLOCKS_PER_SEC * (double)times / (1024.0 * (double)t2));
335 	}
336 
337 cleanup:
338 	/* free some data */
339 	tryfree (xmlbuf);
340 	tryfree (xmibuf);
341 	tryfree (xmlbuf2);
342 
343 	return stat;
344 }
345 
346 /* compress XML file 'filename' 'times' times, using type 'lossy' */
runcompdecomp(char * filename,int targetsize)347 int testsettings::runcompdecomp(char *filename, int targetsize)
348 {
349 	int i = 0, numexprs = 0;
350 	char *buffer = NULL;
351 	int buflen = 0;
352 	int stat = 0, thestat = 0;
353 	char **pathexprs = NULL;
354 	bool exprsnow = exprs;
355    clock_t t2 = 0, t3 = 0;
356    int xmibuflen;
357 
358 	/* read the file to memory */
359 	if ((stat = readfile(filename, &buffer, &buflen)) != 0) {
360 		goto cleanup;
361 	}
362 
363 	if (exprsnow) {
364 		exprsnow = false;
365 		pathexprs = (char**)malloc(MAXEXPRS*sizeof(char*));
366 		/* read .xmill file to memory */
367 		if ((stat = XMill::readExprsFromFile(filename, pathexprs, MAXEXPRS, &numexprs)) == 0) {
368 			/* set these path exprs */
369          try {
370 			   xmill->Init (XMILL_OUT_STRING_OR_FILE, XMILL_INIT_USERINIT, lossy, xmill->GetCompressionMode(), pathexprs,
371                          false, 'n', true, -1, 1, gpcidx);
372          } catch (XMillException *e) {
373             stat = e->code;
374             errstr = e->GetErrorMsg();
375             delete e;
376             goto cleanup;
377 	      }
378 			exprsnow = true;
379 		}
380 		stat = 0;
381 	}
382 
383 	for (i=0; i<times; i++) {
384 		if (stats >= TEST_STATS_ALL) {
385 			printf("(de)compressing %s run %ld/%ld\n", filename, i+1, times);
386       }
387 		/* compress and decompress the file, then check consistency */
388 		if ((stat = compdecomp(buffer, buflen, filename, targetsize, &t2, &t3, &xmibuflen, i==0)) != 0) {
389 			goto prematureexit;
390 		}
391 	}
392 
393 prematureexit:
394 	/* cleanup pathexprs */
395 	if (exprsnow) {
396       try {
397 		   xmill->Init (XMILL_OUT_STRING_OR_FILE, XMILL_INIT_USERINIT, lossy, xmill->GetCompressionMode(), NULL,
398                       false, 'n', true, -1, 1, gpcidx);
399       } catch (XMillException *e) {
400          stat = e->code;
401          errstr = e->GetErrorMsg();
402          delete e;
403          goto cleanup;
404 	   }
405 	}
406 
407 	if (stat != 0) {
408 		if (stats >= TEST_STATS_ERR && !mustfail) {
409 			printf("Error while compressing & decompressing %s in run %ld/%ld.\n",
410 				filename, i+1, times);
411 			if (times > i+1) {
412 				printf("Skipped next %ld run(s).\n", times-i-1);
413 			}
414 			printf("\n");
415 		}
416 	} else if (stats >= TEST_STATS_TIMING && !mustfail) {
417       /* print timings */
418       printf ("timing for %s:\n"
419    			   "\ttotal compress clocks: %ld\n\taverage throughput: %6.1lf KiB XML/s, %6.1lf KiB XMI/s\n"
420 					"\ttotal decompress clocks: %ld\n\taverage throughput: %6.1lf KiB XML/s, %6.1lf KiB XMI/s\n",
421          filename,
422 			t2, (double)buflen * (double)CLOCKS_PER_SEC * (double)times / (1024.0 * (double)t2),
423 			(double)xmibuflen * (double)CLOCKS_PER_SEC * (double)times / (1024.0 * (double)t2),
424 			t3, (double)buflen * (double)CLOCKS_PER_SEC * (double)times / (1024.0 * (double)t3),
425 			(double)xmibuflen * (double)CLOCKS_PER_SEC * (double)times / (1024.0 * (double)t3));
426 		if (stats >= TEST_STATS_ALL) {
427 		   printf("Done compressing & decompressing %s %ld times.\n",
428 			   filename, times);
429       }
430 	}
431 
432 cleanup:
433 	/* free XML data */
434 	tryfree(buffer);
435 	if (exprsnow) {
436 		i = 0;
437 		while (pathexprs && pathexprs[i]) {
438 			tryfree(pathexprs[i]);
439 			i++;
440 		}
441 	}
442 	tryfree(pathexprs);
443 
444 	return stat;
445 }
446 
testsettings()447 testsettings::testsettings()
448 {
449    xmill = new XMill();
450 	times = 1;
451 	lossy = true;
452 	bzip = XMILL_GPC_BZIP;
453    gpcidx = XMILL_GZIP_IDX;
454 	mode = TEST_COMPDECOMP;
455 	exprs = false;
456 	stats = TEST_STATS_WARN;
457 	ignorewhite = false;
458 	blocksize = 0;
459 	mustfail = false;
460 }
461 
~testsettings()462 testsettings::~testsettings()
463 {
464 	delete xmill;
465 }
466 
setstats(char s)467 void testsettings::setstats(char s)
468 {
469 	stats = s;
470 }
471 
parsesetting(char * s,char * s1,bool * usedboth)472 int testsettings::parsesetting(char *s, char *s1, bool *usedboth)
473 {
474 	if (usedboth) {
475 		*usedboth = false;
476 	}
477 
478 		    if (!stricmp(s, "gzip")) {
479 		bzip = XMILL_GPC_GZIP;
480       gpcidx = XMILL_GZIP_IDX;
481 	} else if (!stricmp(s, "nozip")) {
482 		bzip = XMILL_GPC_NONE;
483       gpcidx = -1;
484 	} else if (!stricmp(s, "bzip2")) {
485 		bzip = XMILL_GPC_BZIP;
486       gpcidx = -1;
487 	} else if (!stricmp(s, "ppmdi")) {
488 		bzip = XMILL_GPC_PPMDI;
489       gpcidx = XMILL_PPMDI_IDX;
490 	} else if (!stricmp(s, "lossless")) {
491 		lossy = false;
492 	} else if (!stricmp(s, "lossy")) {
493 		lossy = true;
494 	} else if (!stricmp(s, "compdecomp")) {
495 		mode = TEST_COMPDECOMP;
496 	} else if (!stricmp(s, "decomp")) {
497 		mode = TEST_DECOMP;
498 	} else if (!stricmp(s, "targetsize")) {
499 		mode = TEST_TARGETSIZE;
500 	} else if (!stricmp(s, "exprs")) {
501 		exprs = true;
502 	} else if (!stricmp(s, "plain")) {
503 		exprs = false;
504 	} else if (!stricmp(s, "gpcidx") && s1 && usedboth) {
505 		gpcidx = atoi(s1);
506 		*usedboth = true;
507 	} else if (!stricmp(s, "verbose") && s1 && usedboth) {
508 		xmill->SetVerbose(atoi(s1));
509 		*usedboth = true;
510 	} else if (!stricmp(s, "stats") && s1 && usedboth) {
511 		setstats(atoi(s1));
512 		*usedboth = true;
513 	} else if (!stricmp(s, "silent")) {
514 		xmill->SetVerbose(XMILL_VERBOSE_SILENT);
515 	} else if (!stricmp(s, "noinc")) {
516 		xmill->SetNoIncrease();
517 	} else if (!stricmp(s, "allowinc")) {
518 		xmill->SetNoIncrease(false);
519 	} else if (!stricmp(s, "blocks") && s1 && usedboth) {
520 		blocksize = atoi(s1);
521 		*usedboth = true;
522 	} else if (!stricmp(s, "ignorewhite")) {
523 		ignorewhite = true;
524 	} else if (!stricmp(s, "exact")) {
525 		ignorewhite = false;
526 	} else if (!stricmp(s, "mustfail")) {
527 		mustfail = true;
528 	} else if (!stricmp(s, "mustnotfail")) {
529 		mustfail = false;
530 	} else if (!stricmp(s, "quit")) {
531 		return 1;
532 	}
533 	return 0;
534 }
535 
run(char ** files,int numfiles)536 int testsettings::run(char **files, int numfiles)
537 {
538   	int i = 0, stat = 0;
539 	bool mustreinit = true;
540 	int lasterrstat = 0;
541 
542 	switch (mode) {
543 		case TEST_COMPDECOMP:
544 	 		for (i=0; i<numfiles; i++) {
545 				if (mustreinit) {
546                try {
547 					   xmill->Init (XMILL_OUT_STRING_OR_FILE, XMILL_INIT_USERINIT, lossy, bzip, NULL, false,
548                                'n', true, -1, 1, gpcidx);
549                } catch (XMillException *e) {
550                   stat = e->code;
551                   errstr = e->GetErrorMsg();
552                   delete e;
553 						if (stats >= TEST_STATS_ERR && !mustfail) {
554 							printf("error initializing: code %ld, text '%s'\n\n",
555 								stat, errstr ? errstr : "");
556 						}
557 						goto cleanup;
558 					}
559 					mustreinit = false;
560 				}
561 				/* compress and decompress all files a few times */
562 				if ((stat = runcompdecomp(files[i])) != 0) {
563 					if (stats >= TEST_STATS_ERR && !mustfail) {
564 						printf("error (de)compressing %s: code %ld, text '%s'\n\n",
565 							files[i], stat, stat > 0 && errstr ? errstr : "");
566 					}
567 					/* we *must* reinitialize after a failure */
568 					mustreinit = true;
569 					lasterrstat = stat;
570 				} else if (stats >= TEST_STATS_TIMING) {
571 					printf("\n");
572 				}
573 			}
574 			break;
575 
576 		case TEST_DECOMP:
577 			for (i=0; i<numfiles-1; i+=2) {
578 				if (mustreinit) {
579                try {
580 					   xmill->Init (XMILL_OUT_STRING_OR_FILE, XMILL_INIT_USERINIT, lossy, bzip, NULL, false
581                               , 'n', true, -1, 1, gpcidx);
582                } catch (XMillException *e) {
583                   stat = e->code;
584                   errstr = e->GetErrorMsg();
585                   delete e;
586 						if (stats >= TEST_STATS_ERR && !mustfail) {
587 							printf("error initializing: code %ld, text '%s'\n\n",
588 								stat, errstr ? errstr : "");
589 						}
590 						goto cleanup;
591 					}
592 					mustreinit = false;
593 				}
594 				/* decompress all files a few times and check consistency */
595 				if ((stat = rundecomp(files[i], files[i+1], times)) != 0) {
596 				   if (stats >= TEST_STATS_ERR && !mustfail) {
597 						printf("error in %s / %s: code %ld, text '%s'\n\n",
598 						files[i], files[i+1], stat, stat > 0 && errstr ? errstr : "");
599 					}
600 					/* we *must* reinitialize after a failure */
601 					mustreinit = true;
602 					lasterrstat = stat;
603 				} else if (stats >= TEST_STATS_TIMING) {
604 					printf("\n");
605 				}
606 			}
607 			break;
608 
609 		case TEST_TARGETSIZE:
610 	 		for (i=1; i<numfiles; i++) {
611 				if (mustreinit) {
612                try {
613 					   xmill->Init (XMILL_OUT_STRING_OR_FILE, XMILL_INIT_USERINIT, lossy, bzip, NULL, false
614                               , 'n', true, -1, 1, gpcidx);
615                } catch (XMillException *e) {
616                   stat = e->code;
617                   errstr = e->GetErrorMsg();
618                   delete e;
619 						if (stats >= TEST_STATS_ERR && !mustfail) {
620 							printf("error initializing: code %ld, text '%s'\n\n",
621 								stat, errstr ? errstr : "");
622 						}
623 						goto cleanup;
624 					}
625 					mustreinit = false;
626 				}
627 				/* compress and decompress all files a few times */
628 				if ((stat = runcompdecomp(files[i], atoi(files[0]))) != 0) {
629 					if (stats >= TEST_STATS_ERR && !mustfail) {
630 						printf("error (de)compressing %s: code %ld, text '%s'\n\n",
631 							files[i], stat, stat > 0 && errstr ? errstr : "");
632 					}
633 					/* we *must* reinitialize after a failure */
634 					mustreinit = true;
635 					lasterrstat = stat;
636 				} else if (stats >= TEST_STATS_TIMING) {
637 					printf("\n");
638 				}
639 			}
640 			break;
641 
642 		default:
643 			stat = TEST_ERROR_MODE;
644 			break;
645 	}
646 
647 cleanup:
648 	if (stat == 0 && lasterrstat != 0) {
649 		stat = lasterrstat;
650 	}
651 
652 	return stat;
653 }
654 
trim(char * s)655 static char *trim(char *s)
656 {
657 	int i=0, j=strlen(s)-1, k=0;
658 	while(s[i] && isspace(s[i])) i++;
659 	while(j>=i && isspace(s[j])) j--;
660 	while (i<=j) {
661 		s[k++] = s[i++];
662 	}
663 	s[k] = '\0';
664 	return s;
665 }
666 
run(FILE * script)667 int testsettings::run(FILE *script)
668 {
669 	char line[STRLEN+1], *str = NULL, *str1 = NULL;
670 	int numfiles = 0, stat = 0;
671 	char *files[MAXFILES];
672 	bool usedboth;
673 	bool founderrors = false;
674 
675 	while (!feof(script)) {
676 		/* get a line from the script & trim whitespaces */
677 		fgets(line, STRLEN, script);
678 		trim(line);
679 		if (strlen(line) > 0) {
680 			/* take an action based on the first character */
681 			switch (line[0]) {
682 				case '*':
683 					/* setting */
684 					str = strtok(&line[1], " ");
685 					do {
686 						/* parse all settings */
687 						str1 = strtok(NULL, " ");
688 						if (parsesetting(str, str1, &usedboth) == 1) {
689 							/* 'quit' setting */
690 							goto cleanup;
691 						}
692 						if (usedboth) {
693 							/* skip setting argument */
694 							str = strtok(NULL, " ");
695 						} else {
696 							str = str1;
697 						}
698 					} while (str);
699 					break;
700 
701 				case '#':
702 					/* comment */
703 					break;
704 
705 				default:
706 					/* command */
707 					str = strtok(line, " ");
708 					times = atoi(str);
709 					numfiles = -1;
710 					while (files[++numfiles] = strtok(NULL, " "));
711 					if ((stat = run(files, numfiles)) != 0) {
712 						/* ignore error, continue */
713 						if (!mustfail) {
714 							founderrors = true;
715 						}
716 						stat = 0;
717 					} else if (mustfail) {
718 						printf("Previous test should fail but succeeded!\n");
719 						founderrors = true;
720 					}
721 			}
722 		}
723 	}
724 
725 cleanup:
726 	if (stat == 0 && founderrors) {
727 		stat = TEST_ERROR_FOUND;
728 	}
729 
730 	return stat;
731 }
732