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

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

Refactor zzcat for clarity.

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