Ignore:
Timestamp:
Jan 13, 2010, 12:53:18 AM (11 years ago)
Author:
Sam Hocevar
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.