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

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

More zzcat stuff.

  • Property svn:keywords set to Id
File size: 11.6 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 4030 2009-11-25 00:42:17Z 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, int64_t);
42static int zzcat_fread_fseek(char const *, unsigned char *, int64_t, int64_t);
43static int zzcat_fseek_fread(char const *, unsigned char *, int64_t, int64_t);
44#if defined HAVE_GETLINE
45static int zzcat_getline_getc(char const *, unsigned char *, int64_t, int);
46#endif
47static int zzcat_fseek_getc(char const *, unsigned char *,
48                            int64_t, int64_t, int);
49static int zzcat_fread_getc(char const *, unsigned char *, int64_t,
50                            int64_t, int);
51static int zzcat_random_socket(char const *, unsigned char *, int64_t);
52static int zzcat_random_stream(char const *, unsigned char *, int64_t);
53#if defined HAVE_MMAP
54static int zzcat_random_mmap(char const *, unsigned char *, int64_t);
55#endif
56
57static inline unsigned int myrand(void)
58{
59    static int seed = 1;
60    int x, y;
61    x = (seed + 0x12345678) << 11;
62    y = (seed + 0xfedcba98) >> 21;
63    seed = x * 1010101 + y * 343434;
64    return seed;
65}
66
67static inline int mygetc(FILE *stream, int getc_method)
68{
69    switch (getc_method)
70    {
71#if defined HAVE_GETC_UNLOCKED
72        case 3: return fgetc_unlocked(stream);
73        case 2: return getc_unlocked(stream);
74#endif
75        case 1: return fgetc(stream);
76        default: return getc(stream);
77    }
78}
79
80int main(int argc, char *argv[])
81{
82    int64_t len;
83    unsigned char *data;
84    char const *name;
85    int ret, cmd, fd;
86
87    if(argc != 3)
88        return EXIT_FAILURE;
89
90    name = argv[2];
91
92    /* Read the whole file */
93    fd = open(name, O_RDONLY);
94    if(fd < 0)
95        return EXIT_FAILURE;
96    len = lseek(fd, 0, SEEK_END);
97    if(len < 0)
98        return EXIT_FAILURE;
99    data = malloc(len + 16); /* 16 safety bytes */
100    lseek(fd, 0, SEEK_SET);
101    read(fd, data, len);
102    close(fd);
103
104    /* Read shit here and there, using different methods */
105    switch((cmd = atoi(argv[1])))
106    {
107        /* Simple socket calls */
108        case 100: ret = zzcat_read(name, data, len, 1); break;
109        case 101: ret = zzcat_read(name, data, len, 3); break;
110        case 102: ret = zzcat_read(name, data, len, len); break;
111        /* Simple stream calls */
112        case 200: ret = zzcat_fread(name, data, len, 1); break;
113        case 201: ret = zzcat_fread(name, data, len, 2); break;
114        case 202: ret = zzcat_fread(name, data, len, len); break;
115        case 203: ret = zzcat_fseek_getc(name, data, len, 0, 0); break;
116        case 204: ret = zzcat_fseek_getc(name, data, len, 0, 1); break;
117        case 205: ret = zzcat_fseek_getc(name, data, len, 2, 0); break;
118        case 206: ret = zzcat_fseek_getc(name, data, len, 2, 1); break;
119        case 207: ret = zzcat_fseek_getc(name, data, len, len / 2, 0); break;
120        case 208: ret = zzcat_fseek_getc(name, data, len, len / 2, 1); break;
121        case 209: ret = zzcat_fread_getc(name, data, len, 2, 0); break;
122        case 210: ret = zzcat_fread_getc(name, data, len, 2, 1); break;
123        case 211: ret = zzcat_fread_getc(name, data, len, len / 2, 0); break;
124        case 212: ret = zzcat_fread_getc(name, data, len, len / 2, 1); break;
125#if defined HAVE_GETLINE
126        case 213: ret = zzcat_getline_getc(name, data, len, 0); break;
127        case 214: ret = zzcat_getline_getc(name, data, len, 1); break;
128#endif
129        /* Simple unlocked stream calls */
130#if defined HAVE_GETC_UNLOCKED
131        case 300: ret = zzcat_fseek_getc(name, data, len, 0, 2); break;
132        case 301: ret = zzcat_fseek_getc(name, data, len, 0, 3); break;
133        case 302: ret = zzcat_fseek_getc(name, data, len, 2, 2); break;
134        case 303: ret = zzcat_fseek_getc(name, data, len, 2, 3); break;
135        case 304: ret = zzcat_fseek_getc(name, data, len, len / 2, 2); break;
136        case 305: ret = zzcat_fseek_getc(name, data, len, len / 2, 3); break;
137        case 306: ret = zzcat_fread_getc(name, data, len, 2, 2); break;
138        case 307: ret = zzcat_fread_getc(name, data, len, 2, 3); break;
139        case 308: ret = zzcat_fread_getc(name, data, len, len / 2, 2); break;
140        case 309: ret = zzcat_fread_getc(name, data, len, len / 2, 3); break;
141#   if defined HAVE_GETLINE
142        case 310: ret = zzcat_getline_getc(name, data, len, 2); break;
143        case 311: ret = zzcat_getline_getc(name, data, len, 3); break;
144#   endif
145#endif
146        /* Incomplete calls (but still OK since data is pre-filled) */
147        case 400: ret = zzcat_fread_fseek(name, data, len, 1); break;
148        case 401: ret = zzcat_fread_fseek(name, data, len, 2); break;
149        case 402: ret = zzcat_fread_fseek(name, data, len, 4000); break;
150        case 403: ret = zzcat_fseek_fread(name, data, len, 1); break;
151        case 404: ret = zzcat_fseek_fread(name, data, len, 2); break;
152        case 405: ret = zzcat_fseek_fread(name, data, len, 4000); break;
153        case 406: ret = zzcat_random_socket(name, data, len); break;
154        case 407: ret = zzcat_random_stream(name, data, len); break;
155        /* Misc */
156#if defined HAVE_MMAP
157        case 500: ret = zzcat_random_mmap(name, data, len); break;
158#endif
159        default: ret = EXIT_SUCCESS;
160    }
161
162    /* Write what we have read */
163    fwrite(data, len, 1, stdout);
164    free(data);
165
166    return ret;
167}
168
169/* Only read() calls */
170static int zzcat_read(char const *name, unsigned char *data, int64_t len,
171                      int64_t chunk)
172{
173    int i, fd = open(name, O_RDONLY);
174    if(fd < 0)
175        return EXIT_FAILURE;
176    for(i = 0; i < len; i += chunk)
177        read(fd, data + i, chunk);
178    close(fd);
179    return EXIT_SUCCESS;
180}
181
182/* Only fread() calls */
183static int zzcat_fread(char const *name, unsigned char *data, int64_t len,
184                       int64_t chunk)
185{
186    FILE *stream = fopen(name, "r");
187    int i;
188    if(!stream)
189        return EXIT_FAILURE;
190    for(i = 0; i < len; i += chunk)
191        fread(data + i, chunk, 1, stream);
192    fclose(stream);
193    return EXIT_SUCCESS;
194}
195
196/* Only fread() and fseek() calls */
197static int zzcat_fread_fseek(char const *name, unsigned char *data,
198                             int64_t len, int64_t chunk)
199{
200    FILE *stream = fopen(name, "r");
201    int i;
202    if(!stream)
203        return EXIT_FAILURE;
204    for(i = 0; i < len; )
205    {
206        fread(data + i, chunk, 1, stream);
207        i += chunk;
208        if (i >= len)
209            break;
210        fseek(stream, chunk, SEEK_CUR);
211        i += chunk;
212    }
213    fclose(stream);
214    return EXIT_SUCCESS;
215}
216
217/* Only fseek() and fread() calls */
218static int zzcat_fseek_fread(char const *name, unsigned char *data,
219                             int64_t len, int64_t chunk)
220{
221    FILE *stream = fopen(name, "r");
222    int i;
223    if(!stream)
224        return EXIT_FAILURE;
225    for(i = 0; i < len; )
226    {
227        fseek(stream, chunk, SEEK_CUR);
228        i += chunk;
229        if (i >= len)
230            break;
231        fread(data + i, chunk, 1, stream);
232        i += chunk;
233    }
234    fclose(stream);
235    return EXIT_SUCCESS;
236}
237
238#if defined HAVE_GETLINE
239/* getdelim() and getc() calls */
240static int zzcat_getline_getc(char const *name, unsigned char *data,
241                              int64_t len, int getc_method)
242{
243    FILE *stream = fopen(name, "r");
244    int i = 0, j;
245    char c;
246    if(!stream)
247        return EXIT_FAILURE;
248    (void)len;
249    while ((c = mygetc(stream, getc_method)) != EOF)
250    {
251        char *line;
252        ssize_t ret;
253        size_t n;
254
255        ungetc(c, stream);
256        line = NULL;
257        ret = getline(&line, &n, stream);
258        for (j = 0; j < ret; i++, j++)
259            data[i] = line[j];
260    }
261    fclose(stream);
262    return EXIT_SUCCESS;
263}
264#endif
265
266/* One fseek(), then only getc() or fgetc() calls */
267static int zzcat_fseek_getc(char const *name, unsigned char *data,
268                            int64_t len, int64_t chunk, int getc_method)
269{
270    FILE *stream = fopen(name, "r");
271    int i;
272    if(!stream)
273        return EXIT_FAILURE;
274    if (chunk)
275        fseek(stream, chunk, SEEK_CUR);
276    for(i = chunk; i < len; i++)
277        data[i] = mygetc(stream, getc_method);
278    fclose(stream);
279    return EXIT_SUCCESS;
280}
281
282/* One fread(), then only getc() or fgetc() calls */
283static int zzcat_fread_getc(char const *name, unsigned char *data,
284                            int64_t len, int64_t chunk, int getc_method)
285{
286    FILE *stream = fopen(name, "r");
287    int i;
288    if(!stream)
289        return EXIT_FAILURE;
290    if (chunk)
291        fread(data, 1, chunk, stream);
292    for(i = chunk; i < len; i++)
293        data[i] = mygetc(stream, getc_method);
294    fclose(stream);
295    return EXIT_SUCCESS;
296}
297
298/* Socket seeks and reads */
299static int zzcat_random_socket(char const *name, unsigned char *data,
300                               int64_t len)
301{
302    int i, j, fd = open(name, O_RDONLY);
303    if(fd < 0)
304        return EXIT_FAILURE;
305    for(i = 0; i < 128; i++)
306    {
307        lseek(fd, myrand() % len, SEEK_SET);
308        for(j = 0; j < 4; j++)
309            read(fd, data + lseek(fd, 0, SEEK_CUR), myrand() % 4096);
310#ifdef HAVE_LSEEK64
311        lseek64(fd, myrand() % len, SEEK_SET);
312        for(j = 0; j < 4; j++)
313            read(fd, data + lseek(fd, 0, SEEK_CUR), myrand() % 4096);
314#endif
315    }
316    close(fd);
317    return EXIT_SUCCESS;
318}
319
320/* Standard stream seeks and reads */
321static int zzcat_random_stream(char const *name, unsigned char *data,
322                               int64_t len)
323{
324    FILE *stream = fopen(name, "r");
325    int i, j;
326    if(!stream)
327        return EXIT_FAILURE;
328    for(i = 0; i < 128; i++)
329    {
330        long int now;
331        fseek(stream, myrand() % len, SEEK_SET);
332        for(j = 0; j < 4; j++)
333            fread(data + ftell(stream),
334                  myrand() % (len - ftell(stream)), 1, stream);
335        fseek(stream, myrand() % len, SEEK_SET);
336        now = ftell(stream);
337        for(j = 0; j < 16; j++)
338            data[now + j] = getc(stream);
339        now = ftell(stream);
340        for(j = 0; j < 16; j++)
341            data[now + j] = fgetc(stream);
342    }
343    fclose(stream);
344    return EXIT_SUCCESS;
345}
346
347#ifdef HAVE_MMAP
348/* mmap() followed by random memory reads */
349static int zzcat_random_mmap(char const *name, unsigned char *data,
350                               int64_t len)
351{
352    int i, j, fd = open(name, O_RDONLY);
353    if(fd < 0)
354        return EXIT_FAILURE;
355    for(i = 0; i < 128; i++)
356    {
357        char *map;
358        int moff, mlen, pgsz = len + 1;
359#ifdef HAVE_GETPAGESIZE
360        pgsz = getpagesize();
361#endif
362        moff = len < pgsz ? 0 : (myrand() % (len / pgsz)) * pgsz;
363        mlen = 1 + (myrand() % (len - moff));
364        map = mmap(NULL, mlen, PROT_READ, MAP_PRIVATE, fd, moff);
365        if(map == MAP_FAILED)
366            return EXIT_FAILURE;
367        for(j = 0; j < 128; j++)
368        {
369            int x = myrand() % mlen;
370            data[moff + x] = map[x];
371        }
372        munmap(map, mlen);
373    }
374    close(fd);
375    return EXIT_SUCCESS;
376}
377#endif
378
Note: See TracBrowser for help on using the repository browser.