source: zzuf/trunk/test/zzcat.c @ 4007

Last change on this file since 4007 was 4007, checked in by Sam Hocevar, 11 years ago

Improve the zzcat test suite with more unlocked IO functions.

  • Property svn:keywords set to Id
File size: 9.3 KB
Line 
1/*
2 *  zzcat - various cat reimplementations for testing purposes
3 *  Copyright (c) 2006-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id: zzcat.c 4007 2009-11-22 18:54:49Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15#include "config.h"
16
17/* Needed for lseek64() */
18#define _LARGEFILE64_SOURCE
19/* Needed for O_RDONLY on HP-UX */
20#define _INCLUDE_POSIX_SOURCE
21
22#if defined HAVE_STDINT_H
23#   include <stdint.h>
24#elif defined HAVE_INTTYPES_H
25#   include <inttypes.h>
26#endif
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#if defined HAVE_UNISTD_H
31#   include <unistd.h>
32#endif
33#if defined HAVE_SYS_MMAN_H
34#   include <sys/mman.h>
35#endif
36#include <stdlib.h>
37#include <stdio.h>
38#include <string.h>
39
40static int zzcat_read(char const *, unsigned char *, int64_t);
41static int zzcat_fread(char const *, unsigned char *, int64_t);
42static int zzcat_getc(char const *, unsigned char *, int64_t, int);
43#if defined HAVE_GETLINE
44static int zzcat_getdelim_getc(char const *, unsigned char *, int64_t, int);
45#endif
46static int zzcat_fseek_getc(char const *, unsigned char *, int64_t, int);
47static int zzcat_fread_getc(char const *, unsigned char *, int64_t, int);
48static int zzcat_random_socket(char const *, unsigned char *, int64_t);
49static int zzcat_random_stream(char const *, unsigned char *, int64_t);
50#if defined HAVE_MMAP
51static int zzcat_random_mmap(char const *, unsigned char *, int64_t);
52#endif
53
54static inline unsigned int myrand(void)
55{
56    static int seed = 1;
57    int x, y;
58    x = (seed + 0x12345678) << 11;
59    y = (seed + 0xfedcba98) >> 21;
60    seed = x * 1010101 + y * 343434;
61    return seed;
62}
63
64static inline int mygetc(FILE *stream, int getc_method)
65{
66    switch (getc_method)
67    {
68#if defined HAVE_GETC_UNLOCKED
69        case 3: return fgetc_unlocked(stream);
70        case 2: return getc_unlocked(stream);
71#endif
72        case 1: return fgetc(stream);
73        default: return getc(stream);
74    }
75}
76
77int main(int argc, char *argv[])
78{
79    int64_t len;
80    unsigned char *data;
81    char const *name;
82    int ret, cmd, fd;
83
84    if(argc != 3)
85        return EXIT_FAILURE;
86
87    name = argv[2];
88
89    /* Read the whole file */
90    fd = open(name, O_RDONLY);
91    if(fd < 0)
92        return EXIT_FAILURE;
93    len = lseek(fd, 0, SEEK_END);
94    if(len < 0)
95        return EXIT_FAILURE;
96    data = malloc(len + 16); /* 16 safety bytes */
97    lseek(fd, 0, SEEK_SET);
98    read(fd, data, len);
99    close(fd);
100
101    /* Read shit here and there, using different methods */
102    switch((cmd = atoi(argv[1])))
103    {
104        /* Simple socket calls */
105        case 100: ret = zzcat_read(name, data, len); break;
106        /* Simple stream calls */
107        case 200: ret = zzcat_fread(name, data, len); break;
108        case 201: ret = zzcat_getc(name, data, len, 0); break;
109        case 202: ret = zzcat_getc(name, data, len, 1); break;
110        case 203: ret = zzcat_fseek_getc(name, data, len, 0); break;
111        case 204: ret = zzcat_fseek_getc(name, data, len, 1); break;
112        case 205: ret = zzcat_fread_getc(name, data, len, 0); break;
113        case 206: ret = zzcat_fread_getc(name, data, len, 1); break;
114#if defined HAVE_GETLINE
115        case 207: ret = zzcat_getdelim_getc(name, data, len, 0); break;
116        case 208: ret = zzcat_getdelim_getc(name, data, len, 1); break;
117#endif
118        /* Simple unlocked stream calls */
119#if defined HAVE_GETC_UNLOCKED
120        case 300: ret = zzcat_getc(name, data, len, 2); break;
121        case 301: ret = zzcat_getc(name, data, len, 3); break;
122        case 302: ret = zzcat_fseek_getc(name, data, len, 2); break;
123        case 303: ret = zzcat_fseek_getc(name, data, len, 3); break;
124        case 304: ret = zzcat_fread_getc(name, data, len, 2); break;
125        case 305: ret = zzcat_fread_getc(name, data, len, 3); break;
126#   if defined HAVE_GETLINE
127        case 306: ret = zzcat_getdelim_getc(name, data, len, 2); break;
128        case 307: ret = zzcat_getdelim_getc(name, data, len, 3); break;
129#   endif
130#endif
131        /* Complex socket calls */
132        case 400: ret = zzcat_random_socket(name, data, len); break;
133        /* Complex stream calls */
134        case 500: ret = zzcat_random_stream(name, data, len); break;
135        /* Misc */
136#if defined HAVE_MMAP
137        case 600: ret = zzcat_random_mmap(name, data, len); break;
138#endif
139        default: ret = EXIT_SUCCESS;
140    }
141
142    /* Write what we have read */
143    fwrite(data, len, 1, stdout);
144    free(data);
145
146    return ret;
147}
148
149/* Only read(1) calls */
150static int zzcat_read(char const *name, unsigned char *data, int64_t len)
151{
152    int i, fd = open(name, O_RDONLY);
153    if(fd < 0)
154        return EXIT_FAILURE;
155    for(i = 0; i < len; i++)
156        read(fd, data + i, 1);
157    close(fd);
158    return EXIT_SUCCESS;
159}
160
161/* Only fread() calls */
162static int zzcat_fread(char const *name, unsigned char *data, int64_t len)
163{
164    FILE *stream = fopen(name, "r");
165    int i;
166    if(!stream)
167        return EXIT_FAILURE;
168    for(i = 0; i < len; i++)
169        fread(data + i, 1, 1, stream);
170    fclose(stream);
171    return EXIT_SUCCESS;
172}
173
174/* Only getc() or fgetc() calls */
175static int zzcat_getc(char const *name, unsigned char *data, int64_t len,
176                      int getc_method)
177{
178    FILE *stream = fopen(name, "r");
179    int i;
180    if(!stream)
181        return EXIT_FAILURE;
182    for(i = 0; i < len; i++)
183        data[i] = mygetc(stream, getc_method);
184    fclose(stream);
185    return EXIT_SUCCESS;
186}
187
188#if defined HAVE_GETLINE
189/* getdelim() and getc() calls */
190static int zzcat_getdelim_getc(char const *name, unsigned char *data,
191                               int64_t len, int getc_method)
192{
193    FILE *stream = fopen(name, "r");
194    int i = 0, j;
195    char c;
196    if(!stream)
197        return EXIT_FAILURE;
198    (void)len;
199    while ((c = mygetc(stream, getc_method)) != EOF)
200    {
201        char *line;
202        ssize_t ret;
203        size_t n;
204
205        ungetc(c, stream);
206        line = NULL;
207        ret = getline(&line, &n, stream);
208        for (j = 0; j < ret; i++, j++)
209            data[i] = line[j];
210    }
211    fclose(stream);
212    return EXIT_SUCCESS;
213}
214#endif
215
216/* One fseek(), then only getc() or fgetc() calls */
217static int zzcat_fseek_getc(char const *name, unsigned char *data,
218                            int64_t len, int getc_method)
219{
220    FILE *stream = fopen(name, "r");
221    int i;
222    if(!stream)
223        return EXIT_FAILURE;
224    fseek(stream, len / 2, SEEK_CUR);
225    for(i = len / 2; i < len; i++)
226        data[i] = mygetc(stream, getc_method);
227    fclose(stream);
228    return EXIT_SUCCESS;
229}
230
231/* One fread(), then only getc() or fgetc() calls */
232static int zzcat_fread_getc(char const *name, unsigned char *data,
233                            int64_t len, int getc_method)
234{
235    FILE *stream = fopen(name, "r");
236    int i;
237    if(!stream)
238        return EXIT_FAILURE;
239    fread(data, 1, len / 2, stream);
240    for(i = len / 2; i < len; i++)
241        data[i] = mygetc(stream, getc_method);
242    fclose(stream);
243    return EXIT_SUCCESS;
244}
245
246/* Socket seeks and reads */
247static int zzcat_random_socket(char const *name, unsigned char *data,
248                               int64_t len)
249{
250    int i, j, fd = open(name, O_RDONLY);
251    if(fd < 0)
252        return EXIT_FAILURE;
253    for(i = 0; i < 128; i++)
254    {
255        lseek(fd, myrand() % len, SEEK_SET);
256        for(j = 0; j < 4; j++)
257            read(fd, data + lseek(fd, 0, SEEK_CUR), myrand() % 4096);
258#ifdef HAVE_LSEEK64
259        lseek64(fd, myrand() % len, SEEK_SET);
260        for(j = 0; j < 4; j++)
261            read(fd, data + lseek(fd, 0, SEEK_CUR), myrand() % 4096);
262#endif
263    }
264    close(fd);
265    return EXIT_SUCCESS;
266}
267
268/* Standard stream seeks and reads */
269static int zzcat_random_stream(char const *name, unsigned char *data,
270                               int64_t len)
271{
272    FILE *stream = fopen(name, "r");
273    int i, j;
274    if(!stream)
275        return EXIT_FAILURE;
276    for(i = 0; i < 128; i++)
277    {
278        long int now;
279        fseek(stream, myrand() % len, SEEK_SET);
280        for(j = 0; j < 4; j++)
281            fread(data + ftell(stream),
282                  myrand() % (len - ftell(stream)), 1, stream);
283        fseek(stream, myrand() % len, SEEK_SET);
284        now = ftell(stream);
285        for(j = 0; j < 16; j++)
286            data[now + j] = getc(stream);
287        now = ftell(stream);
288        for(j = 0; j < 16; j++)
289            data[now + j] = fgetc(stream);
290    }
291    fclose(stream);
292    return EXIT_SUCCESS;
293}
294
295#ifdef HAVE_MMAP
296/* mmap() followed by random memory reads */
297static int zzcat_random_mmap(char const *name, unsigned char *data,
298                               int64_t len)
299{
300    int i, j, fd = open(name, O_RDONLY);
301    if(fd < 0)
302        return EXIT_FAILURE;
303    for(i = 0; i < 128; i++)
304    {
305        char *map;
306        int moff, mlen, pgsz = len + 1;
307#ifdef HAVE_GETPAGESIZE
308        pgsz = getpagesize();
309#endif
310        moff = len < pgsz ? 0 : (myrand() % (len / pgsz)) * pgsz;
311        mlen = 1 + (myrand() % (len - moff));
312        map = mmap(NULL, mlen, PROT_READ, MAP_PRIVATE, fd, moff);
313        if(map == MAP_FAILED)
314            return EXIT_FAILURE;
315        for(j = 0; j < 128; j++)
316        {
317            int x = myrand() % mlen;
318            data[moff + x] = map[x];
319        }
320        munmap(map, mlen);
321    }
322    close(fd);
323    return EXIT_SUCCESS;
324}
325#endif
326
Note: See TracBrowser for help on using the repository browser.