Changeset 4246


Ignore:
Timestamp:
Jan 13, 2010, 12:53:18 AM (7 years ago)
Author:
sam
Message:

Improve zzcat documentation and add commandline flags, including --help
and --version.

Location:
zzuf/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • zzuf/trunk/doc/zzcat.1.in

    r4244 r4246  
    33zzcat \- debugging tool for zzuf
    44.SH SYNOPSIS
    5 \fBzzcat\fR PROGRAM FILE
     5\fBzzcat\fR [\fB\-x\fR \fIsequence\fR] [\fIFILE\fR]...
     6.br
     7\fBzzcat \-l\fR | \fB\-\-list\fR
     8.br
     9\fBzzcat \-h\fR | \fB\-\-help\fR
     10.br
     11\fBzzcat \-V\fR | \fB\-\-version\fR
    612.SH DESCRIPTION
    713.PP
    8 \fBzzcat\fR is a tool to read files using various strategies. It is
    9 primarily used as a debugging tool for \fBzzuf\fR.
     14The \fBzzcat\fR utility reads files sequentially, writing them to the
     15standard output. The user can decide which sequence of library calls is
     16used to seek and read data.
     17
     18\fBzzcat\fR is primarily used as a debugging tool for \fBzzuf\fR.
    1019.SH USAGE
    1120.PP
    12 \fB    zzcat "fread(1,10000)" /dev/zero\fR
     21\fB    zzcat -x "fread(1,10000)" /dev/zero\fR
     22.SH OPTIONS
     23.TP
     24\fB\-x\fR, \fB\-\-execute\fR=\fIsequence\fR
     25Read a file or a stream using the instruction sequence specified in
     26\fIsequence\fR.
     27
     28If no sequence is specified, the following default sequence is used:
     29
     30\fB    repeat(\-1, fgetc(), feof(1))
     31.TP
     32\fB\-l\fR, \fB\-\-list\fR
     33Display the list of supported keywords and functions and exit.
     34.TP
     35\fB\-h\fR, \fB\-\-help\fR
     36Display a short help message and exit.
     37.TP
     38\fB\-V\fR, \fB\-\-version\fR
     39Output version information and exit.
    1340.SH EXAMPLES
    1441.PP
     
    1946.SH AUTHOR
    2047.PP
    21 Copyright \(co 2002, 2007\-2010 Sam Hocevar <sam@hocevar.net>.
     48Copyright \(co 2002\-2010 Sam Hocevar <sam@hocevar.net>.
    2249.PP
    2350\fBzzcat\fR and this manual page are free software. They come without any
  • zzuf/trunk/src/zzcat.c

    r4245 r4246  
    4444#include <string.h>
    4545
    46 static inline unsigned int myrand(void)
    47 {
    48     static int seed = 1;
    49     int x, y;
    50     x = (seed + 0x12345678) << 11;
    51     y = (seed + 0xfedcba98) >> 21;
    52     seed = x * 1010101 + y * 343434;
    53     return seed;
    54 }
     46#if !defined HAVE_GETOPT_LONG
     47#   include "mygetopt.h"
     48#elif defined HAVE_GETOPT_H
     49#   include <getopt.h>
     50#endif
     51
     52#if defined HAVE_GETOPT_LONG
     53#   define mygetopt getopt_long
     54#   define myoptind optind
     55#   define myoptarg optarg
     56#   define myoption option
     57#endif
     58
     59static int run(char const *sequence, char const *file);
     60
     61static void syntax(void);
     62static void version(void);
     63static void usage(void);
     64
     65/*
     66 * Main program.
     67 */
     68
     69int main(int argc, char *argv[])
     70{
     71    char const *sequence = "repeat(-1, fgetc(), feof(1))";
     72    int i;
     73
     74    for (;;)
     75    {
     76#define OPTSTR "+x:lhV"
     77#define MOREINFO "Try `%s --help' for more information.\n"
     78        int option_index = 0;
     79        static struct myoption long_options[] =
     80        {
     81            { "execute",     1, NULL, 'x' },
     82            { "list",        0, NULL, 'l' },
     83            { "help",        0, NULL, 'h' },
     84            { "version",     0, NULL, 'V' },
     85            { NULL,          0, NULL,  0  }
     86        };
     87        int c = mygetopt(argc, argv, OPTSTR, long_options, &option_index);
     88
     89        if (c == -1)
     90            break;
     91
     92        switch (c)
     93        {
     94        case 'x': /* --execute */
     95            if (myoptarg[0] == '=')
     96                myoptarg++;
     97            sequence = myoptarg;
     98            break;
     99        case 'l': /* --list */
     100            syntax();
     101            return 0;
     102        case 'h': /* --help */
     103            usage();
     104            return 0;
     105        case 'V': /* --version */
     106            version();
     107            return 0;
     108        default:
     109            fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c);
     110            printf(MOREINFO, argv[0]);
     111            return EXIT_FAILURE;
     112        }
     113    }
     114
     115    if (myoptind >= argc)
     116    {
     117        fprintf(stderr, "E: zzcat: too few arguments\n");
     118        return EXIT_FAILURE;
     119    }
     120
     121    for (i = myoptind; i < argc; i++)
     122    {
     123        int ret = run(sequence, argv[i]);
     124        if (ret)
     125            return ret;
     126    }
     127
     128    return EXIT_SUCCESS;
     129}
     130
     131/*
     132 * Command intepreter
     133 */
    55134
    56135#define MY_FOPEN(cmd) \
     
    63142        } \
    64143        retoff = 0; \
    65         p = strchr(p, ')') + 1; \
     144        sequence = strchr(sequence, ')') + 1; \
    66145    } while(0)
    67146
     
    70149        cmd; \
    71150        f = NULL; \
    72         p = strchr(p, ')') + 1; \
     151        sequence = strchr(sequence, ')') + 1; \
    73152    } while(0)
    74153
     
    100179            } \
    101180        } \
     181        /* fprintf(stderr, "debug: %s\n", #cmd); */ \
    102182        cmd; \
    103183        MERGE(buf, cnt, off); \
    104         p = strchr(p, ')') + 1; \
     184        sequence = strchr(sequence, ')') + 1; \
    105185    } while(0)
    106186
     
    120200        if (feofs >= l1) \
    121201            finish = 1; \
    122         p = strchr(p, ')') + 1; \
     202        sequence = strchr(sequence, ')') + 1; \
    123203    } while(0)
    124204
     
    157237
    158238#define PARSECMD(fmt, arg...) \
    159     make_fmt(&parser, fmt) == sscanf(p, parser.tmpfmt, ##arg, &parser.ch) \
    160         && parser.ch == parser.lastch
     239    (make_fmt(&parser, fmt) == sscanf(sequence, parser.tmpfmt, \
     240                                      ##arg, &parser.ch) \
     241         && parser.ch == parser.lastch)
    161242
    162243/*
     
    165246 */
    166247
    167 static int cat_file(char const *p, char const *file)
     248static int run(char const *sequence, char const *file)
    168249{
    169250    struct { char const *p; int count; } loops[128];
     
    176257    tmp = malloc(32 * 1024 * 1024);
    177258
    178     while (*p)
     259    while (*sequence)
    179260    {
    180261        struct parser parser;
     
    189270
    190271        /* Ignore punctuation */
    191         if (strchr(" \t,;\r\n", *p))
    192             p++;
     272        if (strchr(" \t,;\r\n", *sequence))
     273            sequence++;
    193274
    194275        /* Loop handling */
    195276        else if (PARSECMD("repeat ( %li ,", &l1))
    196277        {
    197             p = strchr(p, ',') + 1;
    198             loops[nloops].p = p;
     278            sequence = strchr(sequence, ',') + 1;
     279            loops[nloops].p = sequence;
    199280            loops[nloops].count = l1;
    200281            nloops++;
     
    207288                return EXIT_FAILURE;
    208289            }
    209             loops[nloops - 1].count--;
    210             if (loops[nloops - 1].count <= 0 || finish)
     290            if (loops[nloops - 1].count == 1 || finish)
    211291            {
    212292                nloops--;
    213                 p = strchr(p, ')') + 1;
     293                sequence = strchr(sequence, ')') + 1;
    214294            }
    215295            else
    216296            {
    217                 p = loops[nloops - 1].p;
     297                loops[nloops - 1].count--;
     298                sequence = loops[nloops - 1].p;
    218299            }
    219300
     
    352433        {
    353434            char buf[16];
    354             snprintf(buf, 16, strlen(p) < 16 ? "%s" : "%.12s...", p);
     435            snprintf(buf, 16, strlen(sequence) < 16 ? "%s" : "%.12s...",
     436                     sequence);
    355437            fprintf(stderr, "E: zzcat: syntax error near `%s'\n", buf);
    356438            return EXIT_FAILURE;
     
    375457    free(retbuf);
    376458    free(tmp);
    377 
    378     return EXIT_SUCCESS;
    379 }
    380 
    381 /*
    382  * Main program.
    383  */
    384 
    385 int main(int argc, char *argv[])
    386 {
    387     int i;
    388 
    389     if (argc < 2)
    390     {
    391         fprintf(stderr, "E: zzcat: too few arguments\n");
    392         return EXIT_FAILURE;
    393     }
    394 
    395     if (argc == 2)
    396         return cat_file("fread(1,33554432)", argv[1]);
    397 
    398     for (i = 2; i < argc; i++)
    399     {
    400         int ret = cat_file(argv[1], argv[i]);
    401         if (ret)
    402             return ret;
    403     }
    404459
    405460    return EXIT_SUCCESS;
     
    502557#endif
    503558
     559static char const *keyword_list[] =
     560{
     561    "repeat", "(<int>,<sequence>)", "loop <int> times through <sequence>",
     562    "feof", "(<int>)", "break out of loop or sequence after <int> EOFs",
     563    NULL
     564};
     565
     566static char const *function_list[] =
     567{
     568    "fopen", "()", "open file",
     569#if defined HAVE_FOPEN64
     570    "fopen64", "()", "same as fopen()",
     571#endif
     572#if defined HAVE___FOPEN64
     573    "__fopen64", "()", "same as fopen()",
     574#endif
     575    "freopen", "()", "reopen file",
     576#if defined HAVE_FREOPEN64
     577    "freopen64", "()", "same as reopen()",
     578#endif
     579#if defined HAVE___FREOPEN64
     580    "__freopen64", "()", "same as reopen()",
     581#endif
     582    "fclose", "()", "close file",
     583    "fread", "(<inta>,<intb>)", "read <intb> chunks of <inta> bytes",
     584    "getc", "()", "get one character (can be a macro)",
     585    "fgetc", "()", "get one character",
     586    "fgets", "(<int>)", "read one line no longer than <int> bytes",
     587#if defined HAVE__IO_GETC
     588    "_IO_getc", "()", "get one character",
     589#endif
     590#if defined HAVE_FREAD_UNLOCKED
     591    "fread_unlocked", "(<inta>,<intb>)", "same as fread(), unlocked I/O version",
     592#endif
     593#if defined HAVE_FGETS_UNLOCKED
     594    "fgets_unlocked", "(<int>)", "same as fgets(), unlocked I/O version",
     595#endif
     596#if defined HAVE_GETC_UNLOCKED
     597    "getc_unlocked", "()", "same as getc(), unlocked I/O version",
     598#endif
     599#if defined HAVE_FGETC_UNLOCKED
     600    "fgetc_unlocked", "()", "same as fgetc(), unlocked I/O version",
     601#endif
     602#if defined HAVE_GETLINE
     603    "getline", "()", "read one complete line of text",
     604#endif
     605#if defined HAVE_GETDELIM
     606    "getdelim", "('<char>')", "read all data until delimiter character <char>",
     607    "getdelim", "(<int>)", "read all data until delimiter character <int>",
     608#endif
     609#if defined HAVE___GETDELIM
     610    "__getdelim", "('<char>')", "same as getdelim()",
     611    "__getdelim", "(<int>)", "same as getdelim()",
     612#endif
     613    "fseek", "(<int>,<whence>)", "seek using SEEK_CUR, SEEK_SET or SEEK_END",
     614#if defined HAVE_FSEEKO
     615    "fseeko", "(<int>,<whence>)", "same as fseek()",
     616#endif
     617#if defined HAVE_FSEEKO64
     618    "fseeko64", "(<int>,<whence>)", "same as fseek()",
     619#endif
     620#if defined HAVE___FSEEKO64
     621    "__fseeko64", "(<int>,<whence>)", "same as fseek()",
     622#endif
     623    "rewind", "()", "rewind to the beginning of the stream",
     624    "ungetc", "()", "put one byte back in the stream",
     625    NULL
     626};
     627
     628static void print_list(char const **list)
     629{
     630    static char const spaces[] = "                                ";
     631
     632    while (*list)
     633    {
     634        size_t len = printf("  %s%s", list[0], list[1]);
     635        if (len < strlen(spaces))
     636            printf("%s", spaces + len);
     637        printf("%s\n", list[2]);
     638        list += 3;
     639    }
     640}
     641
     642static void syntax(void)
     643{
     644    printf("Available control keywords:\n");
     645    print_list(keyword_list);
     646    printf("\n");
     647    printf("Available functions:\n");
     648    print_list(function_list);
     649}
     650
     651static void version(void)
     652{
     653    printf("zzcat %s\n", PACKAGE_VERSION);
     654    printf("Copyright (C) 2002-2010 Sam Hocevar <sam@hocevar.net>\n");
     655    printf("This program is free software. It comes without any warranty, to the extent\n");
     656    printf("permitted by applicable law. You can redistribute it and/or modify it under\n");
     657    printf("the terms of the Do What The Fuck You Want To Public License, Version 2, as\n");
     658    printf("published by Sam Hocevar. See <http://sam.zoy.org/wtfpl/> for more details.\n");
     659    printf("\n");
     660    printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n");
     661}
     662
     663static void usage(void)
     664{
     665    printf("Usage: zzcat [-x sequence] [FILE...]\n");
     666    printf("       zzcat -l | --list\n");
     667    printf("       zzcat -h | --help\n");
     668    printf("       zzcat -V | --version\n");
     669    printf("Read FILE using a sequence of various I/O methods.\n");
     670    printf("\n");
     671    printf("Mandatory arguments to long options are mandatory for short options too.\n");
     672    printf("  -x, --execute <sequence>  execute commands in <sequence>\n");
     673    printf("  -l, --list                list available program functions\n");
     674    printf("  -h, --help                display this help and exit\n");
     675    printf("  -V, --version             output version information and exit\n");
     676    printf("\n");
     677    printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n");
     678}
     679
  • zzuf/trunk/test/check-utils

    r4240 r4246  
    5555        esac
    5656        # Regression tests for stuff that used to break
    57         check "$ZZOPTS" "$ZZCAT \"fread(1,33000) fseek(1,SEEK_SET) fread(1,1) fseek(4093,SEEK_CUR) fread(1,1) fseek(1,SEEK_CUR) fread(1,1)\" $file" \
     57        check "$ZZOPTS" "$ZZCAT -x \"fread(1,33000) fseek(1,SEEK_SET) fread(1,1) fseek(4093,SEEK_CUR) fread(1,1) fseek(1,SEEK_CUR) fread(1,1)\" $file" \
    5858              "eglibc (2.9-21) bug regression"
    59         check "$ZZOPTS" "$ZZCAT \"repeat(33000,getc_unlocked() ungetc() getline() feof(10))\" $file" \
     59        check "$ZZOPTS" "$ZZCAT -x \"repeat(33000,getc_unlocked() ungetc() getline() feof(10))\" $file" \
    6060              "sed getc_unlocked() bug regression"
    6161        # Misc tests
     
    9696          "fread(1,33000) fseek(1000,SEEK_CUR) repeat(10000,getc_unlocked(),feof(10))" \
    9797          ; do
    98             check "$ZZOPTS" "$ZZCAT \"$n\" $file" "$n"
     98            check "$ZZOPTS" "$ZZCAT -x \"$n\" $file" "$n"
    9999        done
    100100    done
Note: See TracChangeset for help on using the changeset viewer.