1/* lzotest.c -- very comprehensive test driver for the LZO library
2
3   This file is part of the LZO real-time data compression library.
4
5   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
6   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
7   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
8   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
9   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
10   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
11   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
12   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
13   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
14   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
15   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
16   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
17   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
18   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
19   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
20   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
21   All Rights Reserved.
22
23   The LZO library is free software; you can redistribute it and/or
24   modify it under the terms of the GNU General Public License as
25   published by the Free Software Foundation; either version 2 of
26   the License, or (at your option) any later version.
27
28   The LZO library is distributed in the hope that it will be useful,
29   but WITHOUT ANY WARRANTY; without even the implied warranty of
30   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31   GNU General Public License for more details.
32
33   You should have received a copy of the GNU General Public License
34   along with the LZO library; see the file COPYING.
35   If not, write to the Free Software Foundation, Inc.,
36   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
37
38   Markus F.X.J. Oberhumer
39   <markus@oberhumer.com>
40   http://www.oberhumer.com/opensource/lzo/
41 */
42
43
44#include "lzo/lzoconf.h"
45
46
47/*************************************************************************
48// util
49**************************************************************************/
50
51/* portability layer */
52#define WANT_LZO_MALLOC 1
53#define WANT_LZO_FREAD 1
54#define WANT_LZO_WILDARGV 1
55#define WANT_LZO_UCLOCK 1
56#define ACC_WANT_ACCLIB_GETOPT 1
57#include "examples/portab.h"
58
59#if defined(HAVE_STRNICMP) && !defined(HAVE_STRNCASECMP)
60#  define strncasecmp(a,b,c) strnicmp(a,b,c)
61#  define HAVE_STRNCASECMP 1
62#endif
63
64#if 0
65#  define is_digit(x)   (isdigit((unsigned char)(x)))
66#  define is_space(x)   (isspace((unsigned char)(x)))
67#else
68#  define is_digit(x)   ((unsigned)(x) - '0' <= 9)
69#  define is_space(x)   ((x)==' ' || (x)=='\t' || (x)=='\r' || (x)=='\n')
70#endif
71
72
73/*************************************************************************
74// compression include section
75**************************************************************************/
76
77#define HAVE_LZO1_H 1
78#define HAVE_LZO1A_H 1
79#define HAVE_LZO1B_H 1
80#define HAVE_LZO1C_H 1
81#define HAVE_LZO1F_H 1
82#define HAVE_LZO1X_H 1
83#define HAVE_LZO1Y_H 1
84#define HAVE_LZO1Z_H 1
85#define HAVE_LZO2A_H 1
86
87#if defined(NO_ZLIB_H) || (SIZEOF_INT < 4)
88#undef HAVE_ZLIB_H
89#endif
90#if defined(NO_BZLIB_H) || (SIZEOF_INT != 4)
91#undef HAVE_BZLIB_H
92#endif
93
94#if 0 && defined(LZO_OS_DOS16)
95/* don't make this test program too big */
96#undef HAVE_LZO1_H
97#undef HAVE_LZO1A_H
98#undef HAVE_LZO1C_H
99#undef HAVE_LZO1Z_H
100#undef HAVE_LZO2A_H
101#undef HAVE_LZO2B_H
102#undef HAVE_ZLIB_H
103#endif
104
105
106/* LZO algorithms */
107#if defined(HAVE_LZO1_H)
108#  include "lzo/lzo1.h"
109#endif
110#if defined(HAVE_LZO1A_H)
111#  include "lzo/lzo1a.h"
112#endif
113#if defined(HAVE_LZO1B_H)
114#  include "lzo/lzo1b.h"
115#endif
116#if defined(HAVE_LZO1C_H)
117#  include "lzo/lzo1c.h"
118#endif
119#if defined(HAVE_LZO1F_H)
120#  include "lzo/lzo1f.h"
121#endif
122#if defined(HAVE_LZO1X_H)
123#  include "lzo/lzo1x.h"
124#  if defined(__LZO_PROFESSIONAL__)
125#    include "lzo/lzopro/lzo1x.h"
126#  endif
127#endif
128#if defined(HAVE_LZO1Y_H)
129#  include "lzo/lzo1y.h"
130#  if defined(__LZO_PROFESSIONAL__)
131#    include "lzo/lzopro/lzo1y.h"
132#  endif
133#endif
134#if defined(HAVE_LZO1Z_H)
135#  include "lzo/lzo1z.h"
136#endif
137#if defined(HAVE_LZO2A_H)
138#  include "lzo/lzo2a.h"
139#endif
140#if defined(HAVE_LZO2B_H)
141#  include "lzo/lzo2b.h"
142#endif
143#if defined(__LZO_PROFESSIONAL__)
144#  include "lzopro/t_config.ch"
145#endif
146/* other compressors */
147#if defined(HAVE_ZLIB_H)
148#  include <zlib.h>
149#  define ALG_ZLIB 1
150#endif
151#if defined(HAVE_BZLIB_H)
152#  include <bzlib.h>
153#  define ALG_BZIP2 1
154#endif
155
156
157/*************************************************************************
158// enumerate all methods
159**************************************************************************/
160
161enum {
162/* compression algorithms */
163    M_LZO1B_1     =     1,
164    M_LZO1B_2, M_LZO1B_3, M_LZO1B_4, M_LZO1B_5,
165    M_LZO1B_6, M_LZO1B_7, M_LZO1B_8, M_LZO1B_9,
166
167    M_LZO1C_1     =    11,
168    M_LZO1C_2, M_LZO1C_3, M_LZO1C_4, M_LZO1C_5,
169    M_LZO1C_6, M_LZO1C_7, M_LZO1C_8, M_LZO1C_9,
170
171    M_LZO1        =    21,
172    M_LZO1A       =    31,
173
174    M_LZO1B_99    =   901,
175    M_LZO1B_999   =   902,
176    M_LZO1C_99    =   911,
177    M_LZO1C_999   =   912,
178    M_LZO1_99     =   921,
179    M_LZO1A_99    =   931,
180
181    M_LZO1F_1     =    61,
182    M_LZO1F_999   =   962,
183    M_LZO1X_1     =    71,
184    M_LZO1X_1_11  =   111,
185    M_LZO1X_1_12  =   112,
186    M_LZO1X_1_15  =   115,
187    M_LZO1X_999   =   972,
188    M_LZO1Y_1     =    81,
189    M_LZO1Y_999   =   982,
190    M_LZO1Z_999   =   992,
191
192    M_LZO2A_999   =   942,
193    M_LZO2B_999   =   952,
194
195    M_LAST_LZO_COMPRESSOR = 998,
196
197/* other compressors */
198#if defined(ALG_ZLIB)
199    M_ZLIB_8_1 =  1101,
200    M_ZLIB_8_2, M_ZLIB_8_3, M_ZLIB_8_4, M_ZLIB_8_5,
201    M_ZLIB_8_6, M_ZLIB_8_7, M_ZLIB_8_8, M_ZLIB_8_9,
202#endif
203#if defined(ALG_BZIP2)
204    M_BZIP2_1  =  1201,
205    M_BZIP2_2, M_BZIP2_3, M_BZIP2_4, M_BZIP2_5,
206    M_BZIP2_6, M_BZIP2_7, M_BZIP2_8, M_BZIP2_9,
207#endif
208
209/* dummy compressor - for benchmarking */
210    M_MEMCPY      =   999,
211
212    M_LAST_COMPRESSOR = 4999,
213
214/* dummy algorithms - for benchmarking */
215    M_MEMSET      =  5001,
216
217/* checksum algorithms - for benchmarking */
218    M_ADLER32     =  6001,
219    M_CRC32       =  6002,
220#if defined(ALG_ZLIB)
221    M_Z_ADLER32   =  6011,
222    M_Z_CRC32     =  6012,
223#endif
224
225#if defined(__LZO_PROFESSIONAL__)
226#  include "lzopro/m_enum.ch"
227#endif
228
229    M_UNUSED
230};
231
232
233/*************************************************************************
234// command line options
235**************************************************************************/
236
237int opt_verbose = 2;
238
239long opt_c_loops = 0;
240long opt_d_loops = 0;
241const char *opt_corpus_path = NULL;
242const char *opt_dump_compressed_data = NULL;
243
244lzo_bool opt_use_safe_decompressor = 0;
245lzo_bool opt_use_asm_decompressor = 0;
246lzo_bool opt_use_asm_fast_decompressor = 0;
247lzo_bool opt_optimize_compressed_data = 0;
248
249int opt_dict = 0;
250lzo_uint opt_max_dict_len = LZO_UINT_MAX;
251const char *opt_dictionary_file = NULL;
252
253lzo_bool opt_read_from_stdin = 0;
254
255/* set these to 1 to measure the speed impact of a checksum */
256lzo_bool opt_compute_adler32 = 0;
257lzo_bool opt_compute_crc32 = 0;
258static lzo_uint32 adler_in, adler_out;
259static lzo_uint32 crc_in, crc_out;
260
261lzo_bool opt_execution_time = 0;
262int opt_uclock = -1;
263lzo_bool opt_clear_wrkmem = 0;
264
265static const lzo_bool opt_try_to_compress_0_bytes = 1;
266
267
268/*************************************************************************
269// misc globals
270**************************************************************************/
271
272static const char *progname = "";
273static lzo_uclock_handle_t uch;
274
275/* for statistics and benchmark */
276int opt_totals = 0;
277static unsigned long total_n = 0;
278static unsigned long total_c_len = 0;
279static unsigned long total_d_len = 0;
280static unsigned long total_blocks = 0;
281static double total_perc = 0.0;
282static const char *total_method_name = NULL;
283static unsigned total_method_names = 0;
284/* Note: the average value of a rate (e.g. compression speed) is defined
285 * by the Harmonic Mean (and _not_ by the Arithmethic Mean ) */
286static unsigned long total_c_mbs_n = 0;
287static unsigned long total_d_mbs_n = 0;
288static double total_c_mbs_harmonic = 0.0;
289static double total_d_mbs_harmonic = 0.0;
290static double total_c_mbs_sum = 0.0;
291static double total_d_mbs_sum = 0.0;
292
293
294#if defined(HAVE_LZO1X_H)
295int default_method = M_LZO1X_1;
296#elif defined(HAVE_LZO1B_H)
297int default_method = M_LZO1B_1;
298#elif defined(HAVE_LZO1C_H)
299int default_method = M_LZO1C_1;
300#elif defined(HAVE_LZO1F_H)
301int default_method = M_LZO1F_1;
302#elif defined(HAVE_LZO1Y_H)
303int default_method = M_LZO1Y_1;
304#else
305int default_method = M_MEMCPY;
306#endif
307
308
309static const int benchmark_methods[] = {
310    M_LZO1B_1, M_LZO1B_9,
311    M_LZO1C_1, M_LZO1C_9,
312    M_LZO1F_1,
313    M_LZO1X_1,
314    0
315};
316
317static const int x1_methods[] = {
318    M_LZO1, M_LZO1A, M_LZO1B_1, M_LZO1C_1, M_LZO1F_1, M_LZO1X_1, M_LZO1Y_1,
319    0
320};
321
322static const int x99_methods[] = {
323    M_LZO1_99, M_LZO1A_99, M_LZO1B_99, M_LZO1C_99,
324    0
325};
326
327static const int x999_methods[] = {
328    M_LZO1B_999, M_LZO1C_999, M_LZO1F_999, M_LZO1X_999, M_LZO1Y_999,
329    M_LZO1Z_999,
330    M_LZO2A_999,
331    0
332};
333
334
335/* exit codes of this test program */
336#define EXIT_OK         0
337#define EXIT_USAGE      1
338#define EXIT_FILE       2
339#define EXIT_MEM        3
340#define EXIT_ADLER      4
341#define EXIT_LZO_ERROR  5
342#define EXIT_LZO_INIT   6
343#define EXIT_INTERNAL   7
344
345
346/*************************************************************************
347// memory setup
348**************************************************************************/
349
350static lzo_uint opt_block_size;
351static lzo_uint opt_max_data_len;
352
353typedef struct {
354    lzo_bytep   ptr;
355    lzo_uint    len;
356    lzo_uint32  adler;
357    lzo_uint32  crc;
358    lzo_bytep   alloc_ptr;
359    lzo_uint    alloc_len;
360    lzo_uint    saved_len;
361} mblock_t;
362
363static mblock_t file_data;      /* original uncompressed data */
364static mblock_t block_c;        /* compressed data */
365static mblock_t block_d;        /* decompressed data */
366static mblock_t block_w;        /* wrkmem */
367static mblock_t dict;
368
369
370static void mb_alloc_extra(mblock_t *mb, lzo_uint len, lzo_uint extra_bottom, lzo_uint extra_top)
371{
372    lzo_uint align = (lzo_uint) sizeof(lzo_align_t);
373
374    mb->alloc_ptr = mb->ptr = NULL;
375    mb->alloc_len = mb->len = 0;
376
377    mb->alloc_len = extra_bottom + len + extra_top;
378    if (mb->alloc_len == 0) mb->alloc_len = 1;
379    mb->alloc_ptr = (lzo_bytep) lzo_malloc(mb->alloc_len);
380
381    if (mb->alloc_ptr == NULL) {
382        fprintf(stderr, "%s: out of memory (wanted %lu bytes)\n", progname, (unsigned long)mb->alloc_len);
383        exit(EXIT_MEM);
384    }
385    if (mb->alloc_len >= align && __lzo_align_gap(mb->alloc_ptr, align) != 0) {
386        fprintf(stderr, "%s: C library problem: malloc() returned misaligned pointer!\n", progname);
387        exit(EXIT_MEM);
388    }
389
390    mb->ptr = mb->alloc_ptr + extra_bottom;
391    mb->len = mb->saved_len = len;
392    mb->adler = 1;
393    mb->crc = 0;
394}
395
396
397static void mb_alloc(mblock_t *mb, lzo_uint len)
398{
399    mb_alloc_extra(mb, len, 0, 0);
400}
401
402
403static void mb_free(mblock_t *mb)
404{
405    if (!mb) return;
406    if (mb->alloc_ptr) lzo_free(mb->alloc_ptr);
407    mb->alloc_ptr = mb->ptr = NULL;
408    mb->alloc_len = mb->len = 0;
409}
410
411
412static lzo_uint get_max_compression_expansion(int m, lzo_uint bl)
413{
414    if (m == M_MEMCPY || m >= M_LAST_COMPRESSOR)
415        return 0;
416    if (m == M_LZO2A_999 || m == M_LZO2B_999)
417        return bl / 8 + 256;
418    if (m > 0  && m < M_LAST_LZO_COMPRESSOR)
419        return bl / 16 +  64 + 3;
420    return bl / 8 + 256;
421}
422
423static lzo_uint get_max_decompression_overrun(int m, lzo_uint bl)
424{
425    LZO_UNUSED(m);
426    LZO_UNUSED(bl);
427    /* may overwrite 3 bytes past the end of the decompressed block */
428    if (opt_use_asm_fast_decompressor)
429        return  (lzo_uint) sizeof(lzo_voidp) - 1;
430    return 0;
431}
432
433
434/*************************************************************************
435// dictionary support
436**************************************************************************/
437
438static void dict_alloc(lzo_uint max_dict_len)
439{
440    lzo_uint l = 0xbfff;    /* MAX_DICT_LEN */
441    if (max_dict_len > 0 && l > max_dict_len)
442        l = max_dict_len;
443    mb_alloc(&dict, l);
444}
445
446
447/* this default dictionary does not provide good contexts... */
448static void dict_set_default(void)
449{
450    lzo_uint d = 0;
451    unsigned i, j;
452
453    dict.len = 16 * 256;
454    if (dict.len > dict.alloc_len)
455        dict.len = dict.alloc_len;
456
457    lzo_memset(dict.ptr, 0, dict.len);
458
459    for (i = 0; i < 256; i++)
460        for (j = 0; j < 16; j++) {
461            if (d >= dict.len)
462                goto done;
463            dict.ptr[d++] = (unsigned char) i;
464        }
465
466done:
467    dict.adler = lzo_adler32(1, dict.ptr, dict.len);
468}
469
470
471static void dict_load(const char *file_name)
472{
473    FILE *fp;
474
475    dict.len = 0;
476    fp = fopen(file_name, "rb");
477    if (fp)
478    {
479        dict.len = (lzo_uint) lzo_fread(fp, dict.ptr, dict.alloc_len);
480        (void) fclose(fp);
481        dict.adler = lzo_adler32(1, dict.ptr, dict.len);
482    }
483}
484
485
486/*************************************************************************
487// compression database
488**************************************************************************/
489
490typedef struct
491{
492    const char *            name;
493    int                     id;
494    lzo_uint32              mem_compress;
495    lzo_uint32              mem_decompress;
496    lzo_compress_t          compress;
497    lzo_optimize_t          optimize;
498    lzo_decompress_t        decompress;
499    lzo_decompress_t        decompress_safe;
500    lzo_decompress_t        decompress_asm;
501    lzo_decompress_t        decompress_asm_safe;
502    lzo_decompress_t        decompress_asm_fast;
503    lzo_decompress_t        decompress_asm_fast_safe;
504    lzo_compress_dict_t     compress_dict;
505    lzo_decompress_dict_t   decompress_dict_safe;
506}
507compress_t;
508
509#include "asm.h"
510
511#include "wrap.h"
512#define M_PRIVATE       LZO_PRIVATE
513#define m_uint          lzo_uint
514#define m_uint32        lzo_uint32
515#define m_voidp         lzo_voidp
516#define m_bytep         lzo_bytep
517#define m_uintp         lzo_uintp
518#include "wrapmisc.h"
519
520static const compress_t compress_database[] = {
521#include "db.h"
522{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
523};
524
525
526/*************************************************************************
527// method info
528**************************************************************************/
529
530static
531lzo_decompress_t get_decomp_info ( const compress_t *c, const char **nn )
532{
533    lzo_decompress_t d = 0;
534    const char *n = NULL;
535
536    /* safe has priority over asm/fast */
537    if (!d && opt_use_safe_decompressor && opt_use_asm_fast_decompressor)
538    {
539        d = c->decompress_asm_fast_safe;
540        n = " [fs]";
541    }
542    if (!d && opt_use_safe_decompressor && opt_use_asm_decompressor)
543    {
544        d = c->decompress_asm_safe;
545        n = " [as]";
546    }
547    if (!d && opt_use_safe_decompressor)
548    {
549        d = c->decompress_safe;
550        n = " [s]";
551    }
552    if (!d && opt_use_asm_fast_decompressor)
553    {
554        d = c->decompress_asm_fast;
555        n = " [f]";
556    }
557    if (!d && opt_use_asm_decompressor)
558    {
559        d = c->decompress_asm;
560        n = " [a]";
561    }
562    if (!d)
563    {
564        d = c->decompress;
565        n = "";
566    }
567    if (!d)
568        n = "(null)";
569
570    if (opt_dict && c->decompress_dict_safe)
571        n = "";
572
573    if (nn)
574        *nn = n;
575    return d;
576}
577
578
579static
580const compress_t *find_method_by_id ( int method )
581{
582    const compress_t *db;
583    size_t size = sizeof(compress_database) / sizeof(*(compress_database));
584    size_t i;
585
586    db = compress_database;
587    for (i = 0; i < size && db->name != NULL; i++, db++)
588    {
589        if (method == db->id)
590            return db;
591    }
592    return NULL;
593}
594
595
596static
597const compress_t *find_method_by_name ( const char *name )
598{
599    const compress_t *db;
600    size_t size = sizeof(compress_database) / sizeof(*(compress_database));
601    size_t i;
602
603    db = compress_database;
604    for (i = 0; i < size && db->name != NULL; i++, db++)
605    {
606        size_t n = strlen(db->name);
607
608#if defined(HAVE_STRNCASECMP)
609        if (strncasecmp(name,db->name,n) == 0 && (!name[n] || name[n] == ','))
610            return db;
611#else
612        if (strncmp(name,db->name,n) == 0 && (!name[n] || name[n] == ','))
613            return db;
614#endif
615    }
616    return NULL;
617}
618
619
620static
621lzo_bool is_compressor ( const compress_t *c )
622{
623    return (c->id <= M_LAST_COMPRESSOR || c->id >= 9721);
624}
625
626
627/*************************************************************************
628// check that memory gets accessed within bounds
629**************************************************************************/
630
631void memchecker_init ( mblock_t *mb, lzo_xint l, unsigned char random_byte )
632{
633    lzo_uint i;
634    lzo_uint len = (lzo_uint) l;
635    lzo_bytep p;
636
637    assert(len <= mb->len);
638
639    /* bottom */
640    p = mb->ptr;
641    for (i = 0; i < 16 && p > mb->alloc_ptr; i++)
642        *--p = random_byte++;
643    /* top */
644    p = mb->ptr + len;
645    for (i = 0; i < 16 && p < mb->alloc_ptr + mb->alloc_len; i++)
646        *p++ = random_byte++;
647#if 0 || defined(LZO_DEBUG)
648    /* fill in garbage */
649    p = mb->ptr;
650    random_byte |= 1;
651    for (i = 0; i < len; i++, random_byte += 2)
652        *p++ = random_byte;
653#endif
654}
655
656
657int memchecker_check ( mblock_t *mb, lzo_xint l, unsigned char random_byte )
658{
659    lzo_uint i;
660    lzo_uint len = (lzo_uint) l;
661    lzo_bytep p;
662
663    assert(len <= mb->len);
664
665    /* bottom */
666    p = mb->ptr;
667    for (i = 0; i < 16 && p > mb->alloc_ptr; i++)
668        if (*--p != random_byte++)
669            return -1;
670    /* top */
671    p = mb->ptr + len;
672    for (i = 0; i < 16 && p < mb->alloc_ptr + mb->alloc_len; i++)
673        if (*p++ != random_byte++)
674            return -1;
675    return 0;
676}
677
678
679/*************************************************************************
680// compress a block
681**************************************************************************/
682
683static
684int call_compressor   ( const compress_t *c,
685                        const lzo_bytep src, lzo_uint  src_len,
686                              lzo_bytep dst, lzo_uintp dst_len )
687{
688    int r = -100;
689
690    if (c && c->compress && block_w.len >= c->mem_compress)
691    {
692        unsigned char random_byte = (unsigned char) src_len;
693        memchecker_init(&block_w, c->mem_compress, random_byte);
694        if (opt_clear_wrkmem)
695            lzo_memset(block_w.ptr, 0, c->mem_compress);
696
697        if (opt_dict && c->compress_dict)
698            r = c->compress_dict(src,src_len,dst,dst_len,block_w.ptr,dict.ptr,dict.len);
699        else
700            r = c->compress(src,src_len,dst,dst_len,block_w.ptr);
701
702        if (memchecker_check(&block_w, c->mem_compress, random_byte) != 0)
703            printf("WARNING: wrkmem overwrite error (compress) !!!\n");
704    }
705
706    if (r == 0 && opt_compute_adler32)
707    {
708        lzo_uint32 adler;
709        adler = lzo_adler32(0, NULL, 0);
710        adler = lzo_adler32(adler, src, src_len);
711        adler_in = adler;
712    }
713    if (r == 0 && opt_compute_crc32)
714    {
715        lzo_uint32 crc;
716        crc = lzo_crc32(0, NULL, 0);
717        crc = lzo_crc32(crc, src, src_len);
718        crc_in = crc;
719    }
720
721    return r;
722}
723
724
725/*************************************************************************
726// decompress a block
727**************************************************************************/
728
729static
730int call_decompressor ( const compress_t *c, lzo_decompress_t d,
731                        const lzo_bytep src, lzo_uint  src_len,
732                              lzo_bytep dst, lzo_uintp dst_len )
733{
734    int r = -100;
735
736    if (c && d && block_w.len >= c->mem_decompress)
737    {
738        unsigned char random_byte = (unsigned char) src_len;
739        memchecker_init(&block_w, c->mem_decompress, random_byte);
740        if (opt_clear_wrkmem)
741            lzo_memset(block_w.ptr, 0, c->mem_decompress);
742
743        if (opt_dict && c->decompress_dict_safe)
744            r = c->decompress_dict_safe(src,src_len,dst,dst_len,block_w.ptr,dict.ptr,dict.len);
745        else
746            r = d(src,src_len,dst,dst_len,block_w.ptr);
747
748        if (memchecker_check(&block_w, c->mem_decompress, random_byte) != 0)
749            printf("WARNING: wrkmem overwrite error (decompress) !!!\n");
750    }
751
752    if (r == 0 && opt_compute_adler32)
753        adler_out = lzo_adler32(1, dst, *dst_len);
754    if (r == 0 && opt_compute_crc32)
755        crc_out = lzo_crc32(0, dst, *dst_len);
756
757    return r;
758}
759
760
761/*************************************************************************
762// optimize a block
763**************************************************************************/
764
765static
766int call_optimizer   ( const compress_t *c,
767                             lzo_bytep src, lzo_uint  src_len,
768                             lzo_bytep dst, lzo_uintp dst_len )
769{
770    if (c && c->optimize && block_w.len >= c->mem_decompress)
771        return c->optimize(src,src_len,dst,dst_len,block_w.ptr);
772    return 0;
773}
774
775
776/***********************************************************************
777// read a file
778************************************************************************/
779
780static int load_file(const char *file_name, lzo_uint max_data_len)
781{
782    FILE *fp;
783#if (HAVE_FTELLO)
784    off_t ll = -1;
785#else
786    long ll = -1;
787#endif
788    lzo_uint l;
789    int r;
790    mblock_t *mb = &file_data;
791
792    mb_free(mb);
793
794    fp = fopen(file_name, "rb");
795    if (fp == NULL)
796    {
797        fflush(stdout); fflush(stderr);
798        fprintf(stderr, "%s: ", file_name);
799        fflush(stderr);
800        perror("fopen");
801        fflush(stdout); fflush(stderr);
802        return EXIT_FILE;
803    }
804    r = fseek(fp, 0, SEEK_END);
805    if (r == 0)
806    {
807#if (HAVE_FTELLO)
808        ll = ftello(fp);
809#else
810        ll = ftell(fp);
811#endif
812        r = fseek(fp, 0, SEEK_SET);
813    }
814    if (r != 0 || ll < 0)
815    {
816        fflush(stdout); fflush(stderr);
817        fprintf(stderr, "%s: ", file_name);
818        fflush(stderr);
819        perror("fseek");
820        fflush(stdout); fflush(stderr);
821        (void) fclose(fp);
822        return EXIT_FILE;
823    }
824
825    l = (lzo_uint) ll;
826    if (l > max_data_len) l = max_data_len;
827#if (HAVE_FTELLO)
828    if ((off_t) l != ll) l = max_data_len;
829#else
830    if ((long) l != ll) l = max_data_len;
831#endif
832
833    mb_alloc(mb, l);
834    mb->len = (lzo_uint) lzo_fread(fp, mb->ptr, mb->len);
835
836    r = ferror(fp);
837    if (fclose(fp) != 0 || r != 0)
838    {
839        mb_free(mb);
840        fflush(stdout); fflush(stderr);
841        fprintf(stderr, "%s: ", file_name);
842        fflush(stderr);
843        perror("fclose");
844        fflush(stdout); fflush(stderr);
845        return EXIT_FILE;
846    }
847
848    return EXIT_OK;
849}
850
851
852/***********************************************************************
853// print some compression statistics
854************************************************************************/
855
856static double t_div(double a, double b)
857{
858    return b > 0.00001 ? a / b : 0;
859}
860
861static double set_perc_d(double perc, char *s)
862{
863    if (perc <= 0.0) {
864        strcpy(s, "0.0");
865        return 0;
866    }
867    if (perc <= 100 - 1.0 / 16) {
868        sprintf(s, "%4.1f", perc);
869    }
870    else {
871        long p = (long) (perc + 0.5);
872        if (p < 100)
873            strcpy(s, "???");
874        else if (p >= 9999)
875            strcpy(s, "9999");
876        else
877            sprintf(s, "%ld", p);
878    }
879    return perc;
880}
881
882static double set_perc(unsigned long c_len, unsigned long d_len, char *s)
883{
884    double perc = 0.0;
885    if (d_len > 0)
886        perc = c_len * 100.0 / d_len;
887    return set_perc_d(perc, s);
888}
889
890
891static
892void print_stats ( const char *method_name, const char *file_name,
893                   long t_loops, long c_loops, long d_loops,
894                   double t_secs, double c_secs, double d_secs,
895                   unsigned long c_len, unsigned long d_len,
896                   unsigned long blocks )
897{
898    unsigned long x_len = d_len;
899    unsigned long t_bytes, c_bytes, d_bytes;
900    double c_mbs, d_mbs, t_mbs;
901    double perc;
902    char perc_str[4+1];
903
904    perc = set_perc(c_len, d_len, perc_str);
905
906    c_bytes = x_len * c_loops * t_loops;
907    d_bytes = x_len * d_loops * t_loops;
908    t_bytes = c_bytes + d_bytes;
909
910    if (opt_uclock == 0)
911        c_secs = d_secs = t_secs = 0.0;
912
913    /* speed in uncompressed megabytes per second (1 megabyte = 1.000.000 bytes) */
914    c_mbs = (c_secs > 0.001) ? (c_bytes / c_secs) / 1000000.0 : 0;
915    d_mbs = (d_secs > 0.001) ? (d_bytes / d_secs) / 1000000.0 : 0;
916    t_mbs = (t_secs > 0.001) ? (t_bytes / t_secs) / 1000000.0 : 0;
917
918    total_n++;
919    total_c_len += c_len;
920    total_d_len += d_len;
921    total_blocks += blocks;
922    total_perc += perc;
923    if (c_mbs > 0) {
924        total_c_mbs_n += 1;
925        total_c_mbs_harmonic += 1.0 / c_mbs;
926        total_c_mbs_sum += c_mbs;
927    }
928    if (d_mbs > 0) {
929        total_d_mbs_n += 1;
930        total_d_mbs_harmonic += 1.0 / d_mbs;
931        total_d_mbs_sum += d_mbs;
932    }
933
934    if (opt_verbose >= 2)
935    {
936        printf("  compressed into %lu bytes,  %s%%  (%s%.3f bits/byte)\n",
937               c_len, perc_str, "", perc * 0.08);
938
939#if 0
940        printf("%-15s %5ld: ","overall", t_loops);
941        printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
942               t_bytes, t_secs, t_mbs);
943#else
944        LZO_UNUSED(t_mbs);
945#endif
946        printf("%-15s %5ld: ","compress", c_loops);
947        printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
948               c_bytes, c_secs, c_mbs);
949        printf("%-15s %5ld: ","decompress", d_loops);
950        printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
951               d_bytes, d_secs, d_mbs);
952        printf("\n");
953    }
954
955    /* create a line for util/table.pl */
956    if (opt_verbose >= 1)
957    {
958        /* get basename */
959        const char *n, *nn, *b;
960        for (nn = n = b = file_name; *nn; nn++)
961            if (*nn == '/' || *nn == '\\' || *nn == ':')
962                b = nn + 1;
963            else
964                n = b;
965
966        printf("%-13s| %-14s %8lu %4lu %9lu %4s %s%8.3f %8.3f |\n",
967               method_name, n, d_len, blocks, c_len, perc_str, "", c_mbs, d_mbs);
968    }
969
970    if (opt_verbose >= 2)
971        printf("\n");
972}
973
974
975static
976void print_totals ( void )
977{
978    char perc_str[4+1];
979
980    if ((opt_verbose >= 1 && total_n > 1) || (opt_totals >= 2))
981    {
982        unsigned long n = total_n > 0 ? total_n : 1;
983        const char *t1 = "-------";
984        const char *t2 = total_method_names == 1 ? total_method_name : "";
985#if 1 && defined(__ACCLIB_PCLOCK_CH_INCLUDED)
986        char uclock_mode[32+1];
987        sprintf(uclock_mode, "[clock=%d]", uch.mode);
988        t1 = uclock_mode;
989        if (opt_uclock == 0) t1 = t2;
990#endif
991
992#if 1
993        set_perc_d(total_perc / n, perc_str);
994        printf("%-13s  %-12s %10lu %4.1f %9lu %4s %8.3f %8.3f\n",
995               t1, "***AVG***",
996               total_d_len / n, total_blocks * 1.0 / n, total_c_len / n, perc_str,
997               t_div(total_c_mbs_n, total_c_mbs_harmonic),
998               t_div(total_d_mbs_n, total_d_mbs_harmonic));
999#endif
1000        set_perc(total_c_len, total_d_len, perc_str);
1001        printf("%-13s  %-12s %10lu %4lu %9lu %4s %s%8.3f %8.3f\n",
1002               t2, "***TOTALS***",
1003               total_d_len, total_blocks, total_c_len, perc_str, "",
1004               t_div(total_c_mbs_n, total_c_mbs_harmonic),
1005               t_div(total_d_mbs_n, total_d_mbs_harmonic));
1006    }
1007}
1008
1009
1010/*************************************************************************
1011// compress and decompress a file
1012**************************************************************************/
1013
1014static __lzo_noinline
1015int process_file ( const compress_t *c, lzo_decompress_t decompress,
1016                   const char *method_name,
1017                   const char *file_name,
1018                   long t_loops, long c_loops, long d_loops )
1019{
1020    long t_i;
1021    unsigned long blocks = 0;
1022    unsigned long compressed_len = 0;
1023    double t_time = 0, c_time = 0, d_time = 0;
1024    lzo_uclock_t t_start, t_stop, x_start, x_stop;
1025    FILE *fp_dump = NULL;
1026
1027    if (opt_dump_compressed_data)
1028        fp_dump = fopen(opt_dump_compressed_data,"wb");
1029
1030/* process the file */
1031
1032    lzo_uclock_flush_cpu_cache(&uch, 0);
1033    lzo_uclock_read(&uch, &t_start);
1034    for (t_i = 0; t_i < t_loops; t_i++)
1035    {
1036        lzo_uint len, c_len, c_len_max, d_len = 0;
1037        const lzo_bytep d = file_data.ptr;
1038
1039        len = file_data.len;
1040        c_len = 0;
1041        blocks = 0;
1042
1043        /* process blocks */
1044        if (len > 0 || opt_try_to_compress_0_bytes) do
1045        {
1046            lzo_uint bl;
1047            long c_i;
1048            int r;
1049            unsigned char random_byte = (unsigned char) file_data.len;
1050#if 1 && defined(CLOCKS_PER_SEC)
1051            random_byte = (unsigned char) (random_byte ^ clock());
1052#endif
1053            blocks++;
1054
1055            bl = len > opt_block_size ? opt_block_size : len;
1056            /* update lengths for memchecker_xxx() */
1057            block_c.len = bl + get_max_compression_expansion(c->id, bl);
1058            block_d.len = bl + get_max_decompression_overrun(c->id, bl);
1059#if defined(__LZO_CHECKER)
1060            /* malloc a block of the exact size to detect any overrun */
1061            assert(block_c.alloc_ptr == NULL);
1062            assert(block_d.alloc_ptr == NULL);
1063            mb_alloc(&block_c, block_c.len);
1064            mb_alloc(&block_d, block_d.len);
1065#endif
1066            assert(block_c.len <= block_c.saved_len);
1067            assert(block_d.len <= block_d.saved_len);
1068
1069            memchecker_init(&block_c, block_c.len, random_byte);
1070            memchecker_init(&block_d, block_d.len, random_byte);
1071
1072        /* compress the block */
1073            c_len = c_len_max = 0;
1074            lzo_uclock_flush_cpu_cache(&uch, 0);
1075            lzo_uclock_read(&uch, &x_start);
1076            for (r = 0, c_i = 0; c_i < c_loops; c_i++)
1077            {
1078                c_len = block_c.len;
1079                r = call_compressor(c, d, bl, block_c.ptr, &c_len);
1080                if (r != 0)
1081                    break;
1082                if (c_len > c_len_max)
1083                    c_len_max = c_len;
1084                if (c_len > block_c.len)
1085                    goto compress_overrun;
1086            }
1087            lzo_uclock_read(&uch, &x_stop);
1088            c_time += lzo_uclock_get_elapsed(&uch, &x_start, &x_stop);
1089            if (r != 0)
1090            {
1091                printf("  compression failed in block %lu (%d) (%lu %lu)\n",
1092                       blocks, r, (unsigned long)c_len, (unsigned long)bl);
1093                return EXIT_LZO_ERROR;
1094            }
1095            if (memchecker_check(&block_c, block_c.len, random_byte) != 0)
1096            {
1097compress_overrun:
1098                printf("  compression overwrite error in block %lu "
1099                       "(%lu %lu %lu %lu)\n",
1100                       blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl, (unsigned long)block_c.len);
1101                return EXIT_LZO_ERROR;
1102            }
1103
1104        /* optimize the compressed block */
1105            if (c_len < bl && opt_optimize_compressed_data)
1106            {
1107                d_len = bl;
1108                r = call_optimizer(c, block_c.ptr, c_len, block_d.ptr, &d_len);
1109                if (r != 0 || d_len != bl)
1110                {
1111                    printf("  optimization failed in block %lu (%d) "
1112                           "(%lu %lu %lu)\n", blocks, r,
1113                           (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1114                    return EXIT_LZO_ERROR;
1115                }
1116                if (memchecker_check(&block_c, block_c.len, random_byte) != 0 ||
1117                    memchecker_check(&block_d, block_d.len, random_byte) != 0)
1118                {
1119                    printf("  optimize overwrite error in block %lu "
1120                           "(%lu %lu %lu %lu)\n",
1121                           blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl, (unsigned long)block_c.len);
1122                    return EXIT_LZO_ERROR;
1123                }
1124            }
1125
1126            /* dump compressed data to disk */
1127            if (fp_dump)
1128            {
1129                lzo_uint l = (lzo_uint) lzo_fwrite(fp_dump, block_c.ptr, c_len);
1130                if (l != c_len || fflush(fp_dump) != 0) {
1131                    /* write error */
1132                    (void) fclose(fp_dump); fp_dump = NULL;
1133                }
1134            }
1135
1136        /* decompress the block and verify */
1137            lzo_uclock_flush_cpu_cache(&uch, 0);
1138            lzo_uclock_read(&uch, &x_start);
1139            for (r = 0, c_i = 0; c_i < d_loops; c_i++)
1140            {
1141                d_len = bl;
1142                r = call_decompressor(c, decompress, block_c.ptr, c_len, block_d.ptr, &d_len);
1143                if (r != 0 || d_len != bl)
1144                    break;
1145            }
1146            lzo_uclock_read(&uch, &x_stop);
1147            d_time += lzo_uclock_get_elapsed(&uch, &x_start, &x_stop);
1148            if (r != 0)
1149            {
1150                printf("  decompression failed in block %lu (%d) "
1151                       "(%lu %lu %lu)\n", blocks, r,
1152                       (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1153                return EXIT_LZO_ERROR;
1154            }
1155            if (d_len != bl)
1156            {
1157                printf("  decompression size error in block %lu (%lu %lu %lu)\n",
1158                       blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1159                return EXIT_LZO_ERROR;
1160            }
1161            if (is_compressor(c))
1162            {
1163                if (lzo_memcmp(d, block_d.ptr, bl) != 0)
1164                {
1165                    lzo_uint x = 0;
1166                    while (x < bl && block_d.ptr[x] == d[x])
1167                        x++;
1168                    printf("  decompression data error in block %lu at offset "
1169                           "%lu (%lu %lu)\n", blocks, (unsigned long)x,
1170                           (unsigned long)c_len, (unsigned long)d_len);
1171                    if (opt_compute_adler32)
1172                        printf("      checksum: 0x%08lx 0x%08lx\n",
1173                               (unsigned long)adler_in, (unsigned long)adler_out);
1174#if 0
1175                    printf("Orig:  ");
1176                    r = (x >= 10) ? -10 : 0 - (int) x;
1177                    for (j = r; j <= 10 && x + j < bl; j++)
1178                        printf(" %02x", (int)d[x+j]);
1179                    printf("\nDecomp:");
1180                    for (j = r; j <= 10 && x + j < bl; j++)
1181                        printf(" %02x", (int)block_d.ptr[x+j]);
1182                    printf("\n");
1183#endif
1184                    return EXIT_LZO_ERROR;
1185                }
1186                if ((opt_compute_adler32 && adler_in != adler_out) ||
1187                    (opt_compute_crc32 && crc_in != crc_out))
1188                {
1189                    printf("  checksum error in block %lu (%lu %lu)\n",
1190                           blocks, (unsigned long)c_len, (unsigned long)d_len);
1191                    printf("      adler32: 0x%08lx 0x%08lx\n",
1192                           (unsigned long)adler_in, (unsigned long)adler_out);
1193                    printf("      crc32: 0x%08lx 0x%08lx\n",
1194                           (unsigned long)crc_in, (unsigned long)crc_out);
1195                    return EXIT_LZO_ERROR;
1196                }
1197            }
1198
1199            if (memchecker_check(&block_d, block_d.len, random_byte) != 0)
1200            {
1201                printf("  decompression overwrite error in block %lu "
1202                       "(%lu %lu %lu %lu)\n",
1203                       blocks, (unsigned long)c_len, (unsigned long)d_len,
1204                       (unsigned long)bl, (unsigned long)block_d.len);
1205                return EXIT_LZO_ERROR;
1206            }
1207
1208#if defined(__LZO_CHECKER)
1209            /* free in reverse order of allocations */
1210            mb_free(&block_d);
1211            mb_free(&block_c);
1212#endif
1213
1214            d += bl;
1215            len -= bl;
1216            compressed_len += (unsigned long) c_len_max;
1217        }
1218        while (len > 0);
1219    }
1220    lzo_uclock_read(&uch, &t_stop);
1221    t_time += lzo_uclock_get_elapsed(&uch, &t_start, &t_stop);
1222
1223    if (fp_dump) {
1224        (void) fclose(fp_dump); fp_dump = NULL;
1225    }
1226    opt_dump_compressed_data = NULL;    /* only dump the first file */
1227
1228    print_stats(method_name, file_name,
1229                t_loops, c_loops, d_loops,
1230                t_time, c_time, d_time,
1231                compressed_len, (unsigned long) file_data.len, blocks);
1232    if (total_method_name != c->name) {
1233        total_method_name = c->name;
1234        total_method_names += 1;
1235    }
1236
1237    return EXIT_OK;
1238}
1239
1240
1241
1242static
1243int do_file ( int method, const char *file_name,
1244              long c_loops, long d_loops,
1245              lzo_uint32p p_adler, lzo_uint32p p_crc )
1246{
1247    int r;
1248    const compress_t *c;
1249    lzo_decompress_t decompress;
1250    lzo_uint32 adler, crc;
1251    char method_name[256+1];
1252    const char *n;
1253    const long t_loops = 1;
1254
1255    adler_in = adler_out = 0;
1256    crc_in = crc_out = 0;
1257    if (p_adler)
1258        *p_adler = 0;
1259    if (p_crc)
1260        *p_crc = 0;
1261
1262    c = find_method_by_id(method);
1263    if (c == NULL || c->name == NULL || c->compress == NULL)
1264        return EXIT_INTERNAL;
1265    decompress = get_decomp_info(c,&n);
1266    if (!decompress || n == NULL || block_w.len < c->mem_decompress)
1267        return EXIT_INTERNAL;
1268    strcpy(method_name,c->name);
1269    strcat(method_name,n);
1270
1271    if (c_loops < 1)  c_loops = 1;
1272    if (d_loops < 1)  d_loops = 1;
1273
1274    fflush(stdout); fflush(stderr);
1275
1276    /* read the whole file */
1277    r = load_file(file_name, opt_max_data_len);
1278    if (r != 0)
1279        return r;
1280
1281    /* compute some checksums */
1282    adler = lzo_adler32(0, NULL, 0);
1283    adler = lzo_adler32(adler, file_data.ptr, file_data.len);
1284    if (p_adler)
1285        *p_adler = adler;
1286    crc = lzo_crc32(0, NULL, 0);
1287    crc = lzo_crc32(crc, file_data.ptr, file_data.len);
1288    if (p_crc)
1289        *p_crc = crc;
1290
1291    if (opt_verbose >= 2)
1292    {
1293        printf("File %s: %lu bytes   (0x%08lx, 0x%08lx)\n",
1294               file_name, (unsigned long) file_data.len, (unsigned long) adler, (unsigned long) crc);
1295        printf("  compressing %lu bytes (%ld/%ld/%ld loops, %lu block-size)\n",
1296               (unsigned long) file_data.len, t_loops, c_loops, d_loops, (unsigned long) opt_block_size);
1297        printf("  %s\n", method_name);
1298    }
1299
1300    r = process_file(c, decompress, method_name, file_name,
1301                     t_loops, c_loops, d_loops);
1302
1303    return r;
1304}
1305
1306
1307/*************************************************************************
1308// Calgary Corpus and Silesia Corpus test suite driver
1309**************************************************************************/
1310
1311struct corpus_entry_t
1312{
1313    const char *name;
1314    long loops;
1315    lzo_uint32 adler;
1316    lzo_uint32 crc;
1317};
1318
1319const struct corpus_entry_t *opt_corpus = NULL;
1320
1321static const struct corpus_entry_t calgary_corpus[] =
1322{
1323    { "bib",       8,  0x4bd09e98L, 0xb856ebe8L },
1324    { "book1",     1,  0xd4d3613eL, 0x24e19972L },
1325    { "book2",     1,  0x6fe14cc3L, 0xba0f3f26L },
1326    { "geo",       6,  0xf3cc5be0L, 0x4d3a6ed0L },
1327    { "news",      2,  0x2ed405b8L, 0xcafac853L },
1328    { "obj1",     35,  0x3887dd2cL, 0xc7b0cd26L },
1329    { "obj2",      4,  0xf89407c4L, 0x3ae33007L },
1330    { "paper1",   17,  0xfe65ce62L, 0x2b6baca0L },
1331    { "paper2",   11,  0x1238b7c2L, 0xf76cba72L },
1332    { "pic",       4,  0xf61a5702L, 0x4b17e59cL },
1333    { "progc",    25,  0x4c00ba45L, 0x6fb16094L },
1334    { "progl",    20,  0x4cba738eL, 0xddbf6baaL },
1335    { "progp",    28,  0x7495b92bL, 0x493a1809L },
1336    { "trans",    15,  0x52a2cec8L, 0xcdec06a6L },
1337    { NULL,        0,  0x00000000L, 0x00000000L }
1338};
1339
1340static const struct corpus_entry_t silesia_corpus[] =
1341{
1342    { "dickens",   1,  0x170f606fL, 0xaf3a6b76L },
1343    { "mozilla",   1,  0x1188dd4eL, 0x7fb0ab7dL },
1344    { "mr",        1,  0xaea14b97L, 0xa341883fL },
1345    { "nci",       1,  0x0af16f1fL, 0x60ff63d3L },
1346    { "ooffice",   1,  0x83c8f689L, 0xa023e1faL },
1347    { "osdb",      1,  0xb825b790L, 0xa0ca388cL },
1348    { "reymont",   1,  0xce5c82caL, 0x50d35f03L },
1349    { "samba",     1,  0x19dbb9f5L, 0x2beac5f3L },
1350    { "sao",       1,  0x7edfc4a9L, 0xfda125bfL },
1351    { "webster",   1,  0xf2962fc6L, 0x01f5a2e9L },
1352    { "xml",       1,  0xeccd03d6L, 0xff8f3051L },
1353    { "x-ray",     1,  0xc95435a0L, 0xc86a35c6L },
1354    { NULL,        0,  0x00000000L, 0x00000000L }
1355};
1356
1357
1358static
1359int do_corpus ( const struct corpus_entry_t *corpus, int method, const char *path,
1360                long c_loops, long d_loops )
1361{
1362    size_t i, n;
1363    char name[256];
1364
1365    if (path == NULL || strlen(path) >= sizeof(name) - 12)
1366        return EXIT_USAGE;
1367
1368    strcpy(name,path);
1369    n = strlen(name);
1370    if (n > 0 && name[n-1] != '/' && name[n-1] != '\\' && name[n-1] != ':')
1371    {
1372        strcat(name,"/");
1373        n++;
1374    }
1375
1376    for (i = 0; corpus[i].name != NULL; i++)
1377    {
1378        lzo_uint32 adler, crc;
1379        long c = c_loops * corpus[i].loops;
1380        long d = d_loops * corpus[i].loops;
1381        int r;
1382
1383        strcpy(name+n,corpus[i].name);
1384        r = do_file(method, name, c, d, &adler, &crc);
1385        if (r != 0)
1386            return r;
1387        if (adler != corpus[i].adler)
1388        {
1389            printf("  invalid test suite\n");
1390            return EXIT_ADLER;
1391        }
1392        if (corpus[i].crc && crc != corpus[i].crc)
1393        {
1394            printf("  internal checksum error !!  (0x%08lx 0x%08lx)\n",
1395                    (unsigned long) crc, (unsigned long) corpus[i].crc);
1396            return EXIT_INTERNAL;
1397        }
1398    }
1399    return EXIT_OK;
1400}
1401
1402
1403/*************************************************************************
1404// usage
1405**************************************************************************/
1406
1407static
1408void usage ( const char *name, int exit_code, lzo_bool show_methods )
1409{
1410    FILE *fp;
1411    int i;
1412
1413    fp = stdout;
1414
1415    fflush(stdout); fflush(stderr);
1416
1417    fprintf(fp,"Usage: %s [option..] file...\n", name);
1418    fprintf(fp,"\n");
1419    fprintf(fp,"Options:\n");
1420    fprintf(fp,"  -m#     compression method\n");
1421    fprintf(fp,"  -b#     set input block size (default %lu, max %lu)\n",
1422            (unsigned long) opt_block_size, (unsigned long) opt_max_data_len);
1423    fprintf(fp,"  -n#     number of compression/decompression runs\n");
1424    fprintf(fp,"  -c#     number of compression runs\n");
1425    fprintf(fp,"  -d#     number of decompression runs\n");
1426    fprintf(fp,"  -S      use safe decompressor (if available)\n");
1427    fprintf(fp,"  -A      use assembler decompressor (if available)\n");
1428    fprintf(fp,"  -F      use fast assembler decompressor (if available)\n");
1429    fprintf(fp,"  -O      optimize compressed data (if available)\n");
1430    fprintf(fp,"  -s DIR  process Calgary Corpus test suite in directory `DIR'\n");
1431    fprintf(fp,"  -@      read list of files to compress from stdin\n");
1432    fprintf(fp,"  -q      be quiet\n");
1433    fprintf(fp,"  -Q      be very quiet\n");
1434    fprintf(fp,"  -v      be verbose\n");
1435    fprintf(fp,"  -L      display software license\n");
1436
1437    if (show_methods)
1438    {
1439#if defined(__ACCLIB_PCLOCK_CH_INCLUDED)
1440        lzo_uclock_t t_dummy;
1441        lzo_uclock_read(&uch, &t_dummy);
1442        (void) lzo_uclock_get_elapsed(&uch, &t_dummy, &t_dummy);
1443        fprintf(fp,"\nAll timings are recorded using uclock mode %d %s.\n", uch.mode, uch.name);
1444#endif
1445        fprintf(fp,"\n\n");
1446        fprintf(fp,"The following compression methods are available:\n");
1447        fprintf(fp,"\n");
1448        fprintf(fp,"  usage   name           memory          available extras\n");
1449        fprintf(fp,"  -----   ----           ------          ----------------\n");
1450
1451        for (i = 0; i <= M_LAST_COMPRESSOR; i++)
1452        {
1453            const compress_t *c;
1454            c = find_method_by_id(i);
1455            if (c)
1456            {
1457                char n[16];
1458                const char *sep = "          ";
1459                unsigned long m = c->mem_compress;
1460
1461                sprintf(n,"-m%d",i);
1462                fprintf(fp,"  %-6s  %-13s",n,c->name);
1463#if 1
1464                fprintf(fp,"%9lu", m);
1465#else
1466                m = (m + 1023) / 1024;
1467                fprintf(fp,"%6lu KiB", m);
1468#endif
1469
1470                if (c->decompress_safe)
1471                    { fprintf(fp, "%s%s", sep, "safe"); sep = ", "; }
1472                if (c->decompress_asm)
1473                    { fprintf(fp, "%s%s", sep, "asm"); sep = ", "; }
1474                if (c->decompress_asm_safe)
1475                    { fprintf(fp, "%s%s", sep, "asm+safe"); sep = ", "; }
1476                if (c->decompress_asm_fast)
1477                    { fprintf(fp, "%s%s", sep, "fastasm"); sep = ", "; }
1478                if (c->decompress_asm_fast_safe)
1479                    { fprintf(fp, "%s%s", sep, "fastasm+safe"); sep = ", "; }
1480                if (c->optimize)
1481                    { fprintf(fp, "%s%s", sep, "optimize"); sep = ", "; }
1482                fprintf(fp, "\n");
1483            }
1484        }
1485    }
1486    else
1487    {
1488        fprintf(fp,"\n");
1489        fprintf(fp,"Type '%s -m' to list all available methods.\n", name);
1490    }
1491
1492    fflush(fp);
1493    if (exit_code < 0)
1494        exit_code = EXIT_USAGE;
1495    exit(exit_code);
1496}
1497
1498
1499static
1500void license(void)
1501{
1502    FILE *fp;
1503
1504    fp = stdout;
1505    fflush(stdout); fflush(stderr);
1506
1507#if defined(__LZO_PROFESSIONAL__)
1508#  include "lzopro/license.ch"
1509#else
1510fprintf(fp,
1511"   The LZO library is free software; you can redistribute it and/or\n"
1512"   modify it under the terms of the GNU General Public License as\n"
1513"   published by the Free Software Foundation; either version 2 of\n"
1514"   the License, or (at your option) any later version.\n"
1515"\n"
1516"   The LZO library is distributed in the hope that it will be useful,\n"
1517"   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1518"   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1519"   GNU General Public License for more details.\n"
1520    );
1521fprintf(fp,
1522"\n"
1523"   You should have received a copy of the GNU General Public License\n"
1524"   along with the LZO library; see the file COPYING.\n"
1525"   If not, write to the Free Software Foundation, Inc.,\n"
1526"   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
1527"\n"
1528"   Markus F.X.J. Oberhumer\n"
1529"   <markus@oberhumer.com>\n"
1530"   http://www.oberhumer.com/opensource/lzo/\n"
1531"\n"
1532    );
1533#endif
1534
1535    fflush(fp);
1536    exit(EXIT_OK);
1537}
1538
1539
1540/*************************************************************************
1541// parse method option '-m'
1542**************************************************************************/
1543
1544static int methods[256+1];
1545static int methods_n = 0;
1546
1547static void add_method(int m)
1548{
1549    int i;
1550
1551    if (m > 0)
1552    {
1553        if (!find_method_by_id(m)) {
1554            fprintf(stdout,"%s: invalid method %d\n",progname,m);
1555            exit(EXIT_USAGE);
1556        }
1557
1558        for (i = 0; i < methods_n; i++)
1559            if (methods[i] == m)
1560                return;
1561
1562        if (methods_n >= 256)
1563        {
1564            fprintf(stderr,"%s: too many methods\n",progname);
1565            exit(EXIT_USAGE);
1566        }
1567
1568        methods[methods_n++] = m;
1569        methods[methods_n] = 0;
1570    }
1571}
1572
1573
1574static void add_methods(const int *ml)
1575{
1576    while (*ml != 0)
1577        add_method(*ml++);
1578}
1579
1580
1581static void add_all_methods(int first, int last)
1582{
1583    int m;
1584
1585    for (m = first; m <= last; m++)
1586        if (find_method_by_id(m) != NULL)
1587            add_method(m);
1588}
1589
1590
1591static int m_strcmp(const char *a, const char *b)
1592{
1593    size_t n;
1594
1595    if (a[0] == 0 || b[0] == 0)
1596        return 1;
1597    n = strlen(b);
1598    if (strncmp(a,b,n) == 0 && (a[n] == 0 || a[n] == ','))
1599        return 0;
1600    return 1;
1601}
1602
1603
1604static lzo_bool m_strisdigit(const char *s)
1605{
1606    for (;;)
1607    {
1608        if (!is_digit(*s))
1609            return 0;
1610        s++;
1611        if (*s == 0 || *s == ',')
1612            break;
1613    }
1614    return 1;
1615}
1616
1617
1618static void parse_methods(const char *p)
1619{
1620    const compress_t *c;
1621
1622    for (;;)
1623    {
1624        if (p == NULL || p[0] == 0)
1625            usage(progname,-1,1);
1626        else if ((c = find_method_by_name(p)) != NULL)
1627            add_method(c->id);
1628        else if (m_strcmp(p,"all") == 0 || m_strcmp(p,"avail") == 0)
1629            add_all_methods(1,M_LAST_COMPRESSOR);
1630        else if (m_strcmp(p,"ALL") == 0)
1631        {
1632            add_all_methods(1,M_LAST_COMPRESSOR);
1633            add_all_methods(9721,9729);
1634            add_all_methods(9781,9789);
1635        }
1636        else if (m_strcmp(p,"lzo") == 0)
1637            add_all_methods(1,M_MEMCPY);
1638        else if (m_strcmp(p,"bench") == 0)
1639            add_methods(benchmark_methods);
1640        else if (m_strcmp(p,"m1") == 0)
1641            add_methods(x1_methods);
1642        else if (m_strcmp(p,"m99") == 0)
1643            add_methods(x99_methods);
1644        else if (m_strcmp(p,"m999") == 0)
1645            add_methods(x999_methods);
1646        else if (m_strcmp(p,"1x999") == 0)
1647            add_all_methods(9721,9729);
1648        else if (m_strcmp(p,"1y999") == 0)
1649            add_all_methods(9821,9829);
1650#if defined(ALG_ZLIB)
1651        else if (m_strcmp(p,"zlib") == 0)
1652            add_all_methods(M_ZLIB_8_1,M_ZLIB_8_9);
1653#endif
1654#if defined(ALG_BZIP2)
1655        else if (m_strcmp(p,"bzip2") == 0)
1656            add_all_methods(M_BZIP2_1,M_BZIP2_9);
1657#endif
1658#if defined(__LZO_PROFESSIONAL__)
1659#  include "lzopro/t_opt_m.ch"
1660#endif
1661        else if (m_strisdigit(p))
1662            add_method(atoi(p));
1663        else
1664        {
1665            printf("%s: invalid method '%s'\n\n",progname,p);
1666            exit(EXIT_USAGE);
1667        }
1668
1669        while (*p && *p != ',')
1670            p++;
1671        while (*p == ',')
1672            p++;
1673        if (*p == 0)
1674            return;
1675    }
1676}
1677
1678
1679/*************************************************************************
1680// options
1681**************************************************************************/
1682
1683enum {
1684    OPT_LONGOPT_ONLY = 512,
1685    OPT_ADLER32,
1686    OPT_CALGARY_CORPUS,
1687    OPT_CLEAR_WRKMEM,
1688    OPT_CRC32,
1689    OPT_DICT,
1690    OPT_DUMP,
1691    OPT_EXECUTION_TIME,
1692    OPT_MAX_DATA_LEN,
1693    OPT_MAX_DICT_LEN,
1694    OPT_SILESIA_CORPUS,
1695    OPT_UCLOCK,
1696    OPT_UNUSED
1697};
1698
1699static const struct acc_getopt_longopt_t longopts[] =
1700{
1701 /* { name  has_arg  *flag  val } */
1702    {"help",             0, 0, 'h'+256}, /* give help */
1703    {"license",          0, 0, 'L'},     /* display software license */
1704    {"quiet",            0, 0, 'q'},     /* quiet mode */
1705    {"verbose",          0, 0, 'v'},     /* verbose mode */
1706    {"version",          0, 0, 'V'+256}, /* display version number */
1707
1708    {"adler32",          0, 0, OPT_ADLER32},
1709    {"calgary-corpus",   1, 0, OPT_CALGARY_CORPUS},
1710    {"clear-wrkmem",     0, 0, OPT_CLEAR_WRKMEM},
1711    {"clock",            1, 0, OPT_UCLOCK},
1712    {"corpus",           1, 0, OPT_CALGARY_CORPUS},
1713    {"crc32",            0, 0, OPT_CRC32},
1714    {"dict",             1, 0, OPT_DICT},
1715    {"dump-compressed",  1, 0, OPT_DUMP},
1716    {"execution-time",   0, 0, OPT_EXECUTION_TIME},
1717    {"max-data-length",  1, 0, OPT_MAX_DATA_LEN},
1718    {"max-dict-length",  1, 0, OPT_MAX_DICT_LEN},
1719    {"silesia-corpus",   1, 0, OPT_SILESIA_CORPUS},
1720    {"uclock",           1, 0, OPT_UCLOCK},
1721    {"methods",          1, 0, 'm'},
1722    {"totals",           0, 0, 'T'},
1723
1724    { 0, 0, 0, 0 }
1725};
1726
1727
1728static int do_option(acc_getopt_p g, int optc)
1729{
1730#define mfx_optarg      g->optarg
1731    switch (optc)
1732    {
1733    case 'A':
1734        opt_use_asm_decompressor = 1;
1735        break;
1736    case 'b':
1737        opt_block_size = 0; /* set to opt_max_data_len later */
1738        if (mfx_optarg)
1739        {
1740            if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1741                return optc;
1742            opt_block_size = atol(mfx_optarg);
1743        }
1744        break;
1745    case 'c':
1746    case 'C':
1747        if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1748            return optc;
1749        opt_c_loops = atol(mfx_optarg);
1750        break;
1751    case 'd':
1752    case 'D':
1753        if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1754            return optc;
1755        opt_d_loops = atol(mfx_optarg);
1756        break;
1757    case 'F':
1758        opt_use_asm_fast_decompressor = 1;
1759        break;
1760    case 'h':
1761    case 'H':
1762    case '?':
1763    case 'h'+256:
1764        usage(progname,EXIT_OK,0);
1765        break;
1766    case 'L':
1767        license();
1768        break;
1769    case 'm':
1770        parse_methods(mfx_optarg);
1771        break;
1772    case 'n':
1773        if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1774            return optc;
1775        opt_c_loops = opt_d_loops = atol(mfx_optarg);
1776        break;
1777    case 'O':
1778        opt_optimize_compressed_data = 1;
1779        break;
1780    case 'q':
1781        opt_verbose -= 1;
1782        break;
1783    case 'Q':
1784        opt_verbose = 0;
1785        break;
1786    case 's':
1787    case OPT_CALGARY_CORPUS:
1788        if (!mfx_optarg || !mfx_optarg[0])
1789            return optc;
1790        opt_corpus_path = mfx_optarg;
1791        opt_corpus = calgary_corpus;
1792        break;
1793    case OPT_SILESIA_CORPUS:
1794        if (!mfx_optarg || !mfx_optarg[0])
1795            return optc;
1796        opt_corpus_path = mfx_optarg;
1797        opt_corpus = silesia_corpus;
1798        break;
1799    case 'S':
1800        opt_use_safe_decompressor = 1;
1801        break;
1802    case 'T':
1803        opt_totals += 1;
1804        break;
1805    case 'v':
1806        opt_verbose += 1;
1807        break;
1808    case 'V':
1809    case 'V'+256:
1810        exit(EXIT_OK);
1811        break;
1812    case '@':
1813        opt_read_from_stdin = 1;
1814        break;
1815
1816    case '1': case '2': case '3': case '4': case '5':
1817    case '6': case '7': case '8': case '9':
1818        /* this is a dirty hack... */
1819        if (g->shortpos == 0) {
1820            char m[2]; m[0] = (char) optc; m[1] = 0;
1821            parse_methods(m);
1822        } else {
1823            const char *m = &g->argv[g->optind][g->shortpos-1];
1824            parse_methods(m);
1825            ++g->optind; g->shortpos = 0;
1826        }
1827        break;
1828
1829    case OPT_ADLER32:
1830        opt_compute_adler32 = 1;
1831        break;
1832    case OPT_CLEAR_WRKMEM:
1833        opt_clear_wrkmem = 1;
1834        break;
1835    case OPT_CRC32:
1836        opt_compute_crc32 = 1;
1837        break;
1838    case OPT_DICT:
1839        opt_dict = 1;
1840        opt_dictionary_file = mfx_optarg;
1841        break;
1842    case OPT_EXECUTION_TIME:
1843        opt_execution_time = 1;
1844        break;
1845    case OPT_DUMP:
1846        opt_dump_compressed_data = mfx_optarg;
1847        break;
1848    case OPT_MAX_DATA_LEN:
1849        if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1850            return optc;
1851        opt_max_data_len = atol(mfx_optarg);
1852        break;
1853    case OPT_MAX_DICT_LEN:
1854        if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1855            return optc;
1856        opt_max_dict_len = atol(mfx_optarg);
1857        break;
1858    case OPT_UCLOCK:
1859        if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1860            return optc;
1861        opt_uclock = atoi(mfx_optarg);
1862#if defined(__ACCLIB_PCLOCK_CH_INCLUDED)
1863        if (opt_uclock > 0)
1864            uch.mode = opt_uclock;
1865#endif
1866        break;
1867
1868    case '\0':
1869        return -1;
1870    case ':':
1871        return -2;
1872    default:
1873        fprintf(stderr,"%s: internal error in getopt (%d)\n",progname,optc);
1874        return -3;
1875    }
1876    return 0;
1877#undef mfx_optarg
1878}
1879
1880
1881static void handle_opterr(acc_getopt_p g, const char *f, void *v)
1882{
1883    struct A { va_list ap; };
1884    struct A *a = (struct A *) v;
1885    fprintf( stderr, "%s: ", g->progname);
1886    if (a)
1887        vfprintf(stderr, f, a->ap);
1888    else
1889        fprintf( stderr, "UNKNOWN GETOPT ERROR");
1890    fprintf( stderr, "\n");
1891}
1892
1893
1894static int get_options(int argc, char **argv)
1895{
1896    acc_getopt_t mfx_getopt;
1897    int optc;
1898    static const char shortopts[] =
1899        "Ab::c:C:d:D:FhHLm::n:OqQs:STvV@123456789";
1900
1901    acc_getopt_init(&mfx_getopt, 1, argc, argv);
1902    mfx_getopt.progname = progname;
1903    mfx_getopt.opterr = handle_opterr;
1904    while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, NULL)) >= 0)
1905    {
1906        if (do_option(&mfx_getopt, optc) != 0)
1907            exit(EXIT_USAGE);
1908    }
1909
1910    return mfx_getopt.optind;
1911}
1912
1913
1914/*************************************************************************
1915// main
1916**************************************************************************/
1917
1918int __lzo_cdecl_main main(int argc, char *argv[])
1919{
1920    int r = EXIT_OK;
1921    int i, ii;
1922    int m;
1923    time_t t_total;
1924    const char *s;
1925
1926    lzo_wildargv(&argc, &argv);
1927    lzo_uclock_open(&uch);
1928
1929    progname = argv[0];
1930    for (s = progname; *s; s++)
1931        if ((*s == '/' || *s == '\\') && s[1])
1932            progname = s + 1;
1933
1934#if defined(__LZO_PROFESSIONAL__)
1935    printf("\nLZO Professional real-time data compression library (v%s, %s).\n",
1936           lzo_version_string(), lzo_version_date());
1937    printf("Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\nAll Rights Reserved.\n\n");
1938#else
1939    printf("\nLZO real-time data compression library (v%s, %s).\n",
1940           lzo_version_string(), lzo_version_date());
1941    printf("Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\nAll Rights Reserved.\n\n");
1942#endif
1943
1944
1945/*
1946 * Step 1: initialize the LZO library
1947 */
1948
1949    if (lzo_init() != LZO_E_OK)
1950    {
1951        printf("internal error - lzo_init() failed !!!\n");
1952        printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable `-DLZO_DEBUG' for diagnostics)\n");
1953        exit(1);
1954    }
1955
1956
1957/*
1958 * Step 2: setup default options
1959 */
1960
1961    opt_max_data_len = 64 * 1024L * 1024L;
1962    opt_block_size = 256 * 1024L;
1963
1964#if defined(LZO_ARCH_I086) && defined(ACC_MM_AHSHIFT)
1965#  if 1 && defined(LZO_ARCH_I086PM) && defined(BLX286)
1966    opt_max_data_len = 32 * 1024L * 1024L;
1967#  else
1968    opt_max_data_len = 14 * 1024L * 1024L;
1969#  endif
1970    /* reduce memory requirements for ancient 16-bit DOS 640kB real-mode */
1971    if (ACC_MM_AHSHIFT != 3) {
1972        opt_max_data_len = 16 * 1024L;
1973    }
1974#elif defined(LZO_OS_TOS)
1975    /* reduce memory requirements for 14 MB machines */
1976    opt_max_data_len = 8 * 1024L * 1024L;
1977#endif
1978
1979
1980
1981/*
1982 * Step 3: parse options
1983 */
1984
1985    if (argc < 2)
1986        usage(progname,-1,0);
1987    i = get_options(argc,argv);
1988
1989    if (methods_n == 0)
1990        add_method(default_method);
1991    if (methods_n > 1 && opt_read_from_stdin)
1992    {
1993        printf("%s: cannot use multiple methods and '-@'\n", progname);
1994        exit(EXIT_USAGE);
1995    }
1996
1997    if (opt_block_size == 0)
1998        opt_block_size = opt_max_data_len;
1999    if (opt_block_size > opt_max_data_len)
2000        opt_block_size = opt_max_data_len;
2001
2002    if (opt_c_loops < 1)
2003        opt_c_loops = 1;
2004    if (opt_d_loops < 1)
2005        opt_d_loops = 1;
2006
2007
2008/*
2009 * Step 4: start work
2010 */
2011
2012    block_w.len = 0;
2013    for (ii = 0; ii < methods_n; ii++) {
2014        const compress_t *c = find_method_by_id(methods[ii]);
2015        assert(c != NULL);
2016        if (c->mem_compress > block_w.len)
2017            block_w.len = c->mem_compress;
2018        if (c->mem_decompress > block_w.len)
2019            block_w.len = c->mem_decompress;
2020    }
2021
2022    mb_alloc(&block_w, block_w.len);
2023    lzo_memset(block_w.ptr, 0, block_w.len);
2024
2025#if !defined(__LZO_CHECKER)
2026    mb_alloc_extra(&block_c, opt_block_size + get_max_compression_expansion(-1, opt_block_size), 16, 16);
2027    mb_alloc_extra(&block_d, opt_block_size + get_max_decompression_overrun(-1, opt_block_size), 16, 16);
2028#endif
2029
2030    if (opt_dict)
2031    {
2032        opt_optimize_compressed_data = 0;
2033        dict_alloc(opt_max_dict_len);
2034        if (opt_dictionary_file)
2035        {
2036            dict_load(opt_dictionary_file);
2037            if (dict.len > 0)
2038                printf("Using dictionary '%s', %lu bytes, ID 0x%08lx.\n",
2039                       opt_dictionary_file,
2040                       (unsigned long) dict.len, (unsigned long) dict.adler);
2041        }
2042        if (dict.len == 0)
2043        {
2044            dict_set_default();
2045            printf("Using default dictionary, %lu bytes, ID 0x%08lx.\n",
2046                   (unsigned long) dict.len, (unsigned long) dict.adler);
2047        }
2048    }
2049
2050    t_total = time(NULL);
2051    ii = i;
2052    for (m = 0; m < methods_n && r == EXIT_OK; m++)
2053    {
2054        int method = methods[m];
2055
2056        i = ii;
2057        if (i >= argc && opt_corpus_path == NULL && !opt_read_from_stdin)
2058            usage(progname,-1,0);
2059        if (m == 0 && opt_verbose >= 1)
2060            printf("%lu block-size\n\n", (unsigned long) opt_block_size);
2061
2062        assert(find_method_by_id(method) != NULL);
2063
2064        if (opt_corpus_path != NULL)
2065            r = do_corpus(opt_corpus, method, opt_corpus_path,
2066                          opt_c_loops, opt_d_loops);
2067        else
2068        {
2069            for ( ; i < argc && r == EXIT_OK; i++)
2070            {
2071                r = do_file(method,argv[i],opt_c_loops,opt_d_loops,NULL,NULL);
2072                if (r == EXIT_FILE)     /* ignore file errors */
2073                    r = EXIT_OK;
2074            }
2075            if (opt_read_from_stdin)
2076            {
2077                char buf[512], *p;
2078
2079                while (r == EXIT_OK && fgets(buf,sizeof(buf)-1,stdin) != NULL)
2080                {
2081                    buf[sizeof(buf)-1] = 0;
2082                    p = buf + strlen(buf);
2083                    while (p > buf && is_space(p[-1]))
2084                            *--p = 0;
2085                    p = buf;
2086                    while (*p && is_space(*p))
2087                        p++;
2088                    if (*p)
2089                        r = do_file(method,p,opt_c_loops,opt_d_loops,NULL,NULL);
2090                    if (r == EXIT_FILE)     /* ignore file errors */
2091                        r = EXIT_OK;
2092                }
2093                opt_read_from_stdin = 0;
2094            }
2095        }
2096    }
2097    t_total = time(NULL) - t_total;
2098
2099    if (opt_totals)
2100        print_totals();
2101    if (opt_execution_time || (methods_n > 1 && opt_verbose >= 1))
2102        printf("\n%s: execution time: %lu seconds\n", progname, (unsigned long) t_total);
2103    if (r != EXIT_OK)
2104        printf("\n%s: exit code: %d\n", progname, r);
2105
2106    lzo_uclock_close(&uch);
2107    return r;
2108}
2109
2110
2111/*
2112vi:ts=4:et
2113*/
2114
2115