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

Last change on this file since 4010 was 4010, checked in by Sam Hocevar, 13 years ago

Minor refactoring in zzcat.

  • Property svn:keywords set to Id
File size: 9.8 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 4010 2009-11-23 00:26:59Z 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, int64_t);
41static int zzcat_fread(char const *, unsigned char *, int64_t);
42#if defined HAVE_GETLINE
43static int zzcat_getline_getc(char const *, unsigned char *, int64_t, int);
44#endif
45static int zzcat_fseek_getc(char const *, unsigned char *,
46                            int64_t, int64_t, int);
47static int zzcat_fread_getc(char const *, unsigned char *, int64_t,
48                            int64_t, int);
49static int zzcat_random_socket(char const *, unsigned char *, int64_t);
50static int zzcat_random_stream(char const *, unsigned char *, int64_t);
51#if defined HAVE_MMAP
52static int zzcat_random_mmap(char const *, unsigned char *, int64_t);
53#endif
54
55static inline unsigned int myrand(void)
56{
57    static int seed = 1;
58    int x, y;
59    x = (seed + 0x12345678) << 11;
60    y = (seed + 0xfedcba98) >> 21;
61    seed = x * 1010101 + y * 343434;
62    return seed;
63}
64
65static inline int mygetc(FILE *stream, int getc_method)
66{
67    switch (getc_method)
68    {
69#if defined HAVE_GETC_UNLOCKED
70        case 3: return fgetc_unlocked(stream);
71        case 2: return getc_unlocked(stream);
72#endif
73        case 1: return fgetc(stream);
74        default: return getc(stream);
75    }
76}
77
78int main(int argc, char *argv[])
79{
80    int64_t len;
81    unsigned char *data;
82    char const *name;
83    int ret, cmd, fd;
84
85    if(argc != 3)
86        return EXIT_FAILURE;
87
88    name = argv[2];
89
90    /* Read the whole file */
91    fd = open(name, O_RDONLY);
92    if(fd < 0)
93        return EXIT_FAILURE;
94    len = lseek(fd, 0, SEEK_END);
95    if(len < 0)
96        return EXIT_FAILURE;
97    data = malloc(len + 16); /* 16 safety bytes */
98    lseek(fd, 0, SEEK_SET);
99    read(fd, data, len);
100    close(fd);
101
102    /* Read shit here and there, using different methods */
103    switch((cmd = atoi(argv[1])))
104    {
105        /* Simple socket calls */
106        case 100: ret = zzcat_read(name, data, len, 1); break;
107        case 101: ret = zzcat_read(name, data, len, 3); break;
108        case 102: ret = zzcat_read(name, data, len, len); break;
109        /* Simple stream calls */
110        case 200: ret = zzcat_fread(name, data, len); break;
111        case 201: ret = zzcat_fseek_getc(name, data, len, 0, 0); break;
112        case 202: ret = zzcat_fseek_getc(name, data, len, 0, 1); break;
113        case 203: ret = zzcat_fseek_getc(name, data, len, 2, 0); break;
114        case 204: ret = zzcat_fseek_getc(name, data, len, 2, 1); break;
115        case 205: ret = zzcat_fseek_getc(name, data, len, len / 2, 0); break;
116        case 206: ret = zzcat_fseek_getc(name, data, len, len / 2, 1); break;
117        case 207: ret = zzcat_fread_getc(name, data, len, 2, 0); break;
118        case 208: ret = zzcat_fread_getc(name, data, len, 2, 1); break;
119        case 209: ret = zzcat_fread_getc(name, data, len, len / 2, 0); break;
120        case 210: ret = zzcat_fread_getc(name, data, len, len / 2, 1); break;
121#if defined HAVE_GETLINE
122        case 211: ret = zzcat_getline_getc(name, data, len, 0); break;
123        case 212: ret = zzcat_getline_getc(name, data, len, 1); break;
124#endif
125        /* Simple unlocked stream calls */
126#if defined HAVE_GETC_UNLOCKED
127        case 300: ret = zzcat_fseek_getc(name, data, len, 0, 2); break;
128        case 301: ret = zzcat_fseek_getc(name, data, len, 0, 3); break;
129        case 302: ret = zzcat_fseek_getc(name, data, len, 2, 2); break;
130        case 303: ret = zzcat_fseek_getc(name, data, len, 2, 3); break;
131        case 304: ret = zzcat_fseek_getc(name, data, len, len / 2, 2); break;
132        case 305: ret = zzcat_fseek_getc(name, data, len, len / 2, 3); break;
133        case 306: ret = zzcat_fread_getc(name, data, len, 2, 2); break;
134        case 307: ret = zzcat_fread_getc(name, data, len, 2, 3); break;
135        case 308: ret = zzcat_fread_getc(name, data, len, len / 2, 2); break;
136        case 309: ret = zzcat_fread_getc(name, data, len, len / 2, 3); break;
137#   if defined HAVE_GETLINE
138        case 310: ret = zzcat_getline_getc(name, data, len, 2); break;
139        case 311: ret = zzcat_getline_getc(name, data, len, 3); break;
140#   endif
141#endif
142        /* Complex socket calls */
143        case 400: ret = zzcat_random_socket(name, data, len); break;
144        /* Complex stream calls */
145        case 500: ret = zzcat_random_stream(name, data, len); break;
146        /* Misc */
147#if defined HAVE_MMAP
148        case 600: ret = zzcat_random_mmap(name, data, len); break;
149#endif
150        default: ret = EXIT_SUCCESS;
151    }
152
153    /* Write what we have read */
154    fwrite(data, len, 1, stdout);
155    free(data);
156
157    return ret;
158}
159
160/* Only read() calls */
161static int zzcat_read(char const *name, unsigned char *data, int64_t len,
162                      int64_t chunk)
163{
164    int i, fd = open(name, O_RDONLY);
165    if(fd < 0)
166        return EXIT_FAILURE;
167    for(i = 0; i < len; i += chunk)
168        read(fd, data + i, chunk);
169    close(fd);
170    return EXIT_SUCCESS;
171}
172
173/* Only fread() calls */
174static int zzcat_fread(char const *name, unsigned char *data, int64_t len)
175{
176    FILE *stream = fopen(name, "r");
177    int i;
178    if(!stream)
179        return EXIT_FAILURE;
180    for(i = 0; i < len; i++)
181        fread(data + i, 1, 1, stream);
182    fclose(stream);
183    return EXIT_SUCCESS;
184}
185
186#if defined HAVE_GETLINE
187/* getdelim() and getc() calls */
188static int zzcat_getline_getc(char const *name, unsigned char *data,
189                              int64_t len, int getc_method)
190{
191    FILE *stream = fopen(name, "r");
192    int i = 0, j;
193    char c;
194    if(!stream)
195        return EXIT_FAILURE;
196    (void)len;
197    while ((c = mygetc(stream, getc_method)) != EOF)
198    {
199        char *line;
200        ssize_t ret;
201        size_t n;
202
203        ungetc(c, stream);
204        line = NULL;
205        ret = getline(&line, &n, stream);
206        for (j = 0; j < ret; i++, j++)
207            data[i] = line[j];
208    }
209    fclose(stream);
210    return EXIT_SUCCESS;
211}
212#endif
213
214/* One fseek(), then only getc() or fgetc() calls */
215static int zzcat_fseek_getc(char const *name, unsigned char *data,
216                            int64_t len, int64_t chunk, int getc_method)
217{
218    FILE *stream = fopen(name, "r");
219    int i;
220    if(!stream)
221        return EXIT_FAILURE;
222    if (chunk)
223        fseek(stream, chunk, SEEK_CUR);
224    for(i = chunk; i < len; i++)
225        data[i] = mygetc(stream, getc_method);
226    fclose(stream);
227    return EXIT_SUCCESS;
228}
229
230/* One fread(), then only getc() or fgetc() calls */
231static int zzcat_fread_getc(char const *name, unsigned char *data,
232                            int64_t len, int64_t chunk, int getc_method)
233{
234    FILE *stream = fopen(name, "r");
235    int i;
236    if(!stream)
237        return EXIT_FAILURE;
238    if (chunk)
239        fread(data, 1, chunk, stream);
240    for(i = chunk; 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.