【ArgParse】一个开源的入参解析库

发布时间 2023-09-14 11:38:05作者: 壹点灵异

项目地址argtable3

 

本地验证:

  • 编译构建

  • 新增验证

// examples/skull.c
#include "argtable3.h"

int main(int argc, char **argv)
{
    const char* progname = "skull";
    struct arg_lit *help = arg_lit0("h", "help", "this is help info");
    struct arg_lit *litn = arg_litn("l", "literal", 0, 5, "./progname -l --literal");
    struct arg_int *intn = arg_intn("i", "integer", "<int>", 0, 5, "./program -i 10 -i 20 -i 30");
    struct arg_dbl *dbln = arg_dbln("d", "double", "<double>", 0, 5, "./program -d 3.14 -d 2.718 -d 1.414");
    struct arg_str *strn = arg_strn("s", "string", "<string>", 0, 5, "./program -s hello -s world");
    struct arg_rex *rexn = arg_rexn("r", "regular", "^[A-Za-z0-9]+$", "<regex>", 0, 5, ARG_REX_ICASE, "./program -r [digit] -r [letters]");
    struct arg_file *filen = arg_filen("f", "file", "<file>", 0, 5, "./program file1.txt file2.txt file3.txt");
    struct arg_date *daten  = arg_daten("a", "date", "%Y-%m-%d", "<date>", 0, 5, "./program -a 2023-09-01 -a 2023-09-02 -a 2023-09-03");
    struct arg_end *end   = arg_end(20);
    void* argtable[] = {help, litn, intn, dbln, strn, rexn, filen, daten, end};
    int nerrors;
    int exitcode=0;

    /* verify the argtable[] entries were allocated sucessfully */
    if (arg_nullcheck(argtable) != 0) {
        /* NULL entries were detected, some allocations must have failed */
        printf("%s: insufficient memory\n", progname);
        exitcode=1;
        goto exit;
    }

    /* Parse the command line as defined by argtable[] */
    nerrors = arg_parse(argc, argv, argtable);

    /* If the parser returned any errors then display them and exit */
    if (nerrors > 0) {
        /* Display the error details contained in the arg_end struct.*/
        arg_print_errors(stdout,end,progname);
        printf("Try '%s --help' for more information.\n", progname);
        exitcode=1;
        goto exit;
    }

    /* special case: '--help' takes precedence over error reporting */
    if (help->count > 0) {
        printf("Usage: %s", progname);
        arg_print_syntax(stdout, argtable, "\n");
        printf("Print certain system information.  With no options, same as -s.\n\n");
        arg_print_glossary(stdout, argtable,"  %-25s %s\n");
        printf("\nReport bugs to <foo@bar>.\n");
        exitcode=0;
        goto exit;
    }

    /* special case: '--version' takes precedence error reporting */
    if (litn->count > 0) {
        printf("'%s'  count: %d.\n", litn->hdr.glossary, litn->count);
        exitcode=0;
        goto exit;
    }

    if (intn->count > 0) {
        printf("'%s'  count: %d.\n", intn->hdr.glossary, intn->count);
        for (int i = 0; i < intn->count; i++) {
            printf("Integer %d: %d\n", i+1, intn->ival[i]);
        }
        exitcode=0;
        goto exit;
    }

    if (dbln->count > 0) {
        printf("'%s'  count: %d.\n", dbln->hdr.glossary, dbln->count);
        for (int i = 0; i < dbln->count; i++) {
            printf("Double %d: %lf\n", i+1, dbln->dval[i]);
        }
        exitcode=0;
        goto exit;
    }

    if (strn->count > 0) {
        printf("'%s'  count: %d.\n", strn->hdr.glossary, strn->count);
        for (int i = 0; i < strn->count; i++) {
            printf("String %d: %s\n", i+1, strn->sval[i]);
        }
        exitcode=0;
        goto exit;
    }

    if (rexn->count > 0) {
        printf("'%s'  count: %d.\n", rexn->hdr.glossary, rexn->count);
        for (int i = 0; i < rexn->count; i++) {
            printf("Regular %d: %s\n", i+1, rexn->sval[i]);
        }
        exitcode=0;
        goto exit;
    }

    if (filen->count > 0) {
        printf("'%s'  count: %d.\n", filen->hdr.glossary, filen->count);
        for (int i = 0; i < filen->count; i++) {
            printf("File %d: %s\n", i+1, filen->filename[i]);
        }
        exitcode=0;
        goto exit;
    }

    if (daten->count > 0) {
        printf("'%s'  count: %d.\n", daten->hdr.glossary, daten->count);
        for (int i = 0; i < daten->count; i++) {
            printf("Date %d: %04d-%02d-%02d\n", i+1, daten->tmval[i].tm_year, daten->tmval[i].tm_mon, daten->tmval[i].tm_mday);
        }
        exitcode=0;
        goto exit;
    }

exit:
    /* deallocate each non-null entry in argtable[] */
    arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));

    return exitcode;
}
  • 源码修改

 实测月份少1,年份是基于1900

// src/arg_date.c
char* arg_strptime(const char* buf, const char* fmt, struct tm* tm) {
    while ((c = *fmt) != '\0') {
        /* Clear `alternate' modifier prior to new conversion. */
        alt_format = 0;

        /* Eat up white-space. */
        if (isspace(c)) {
            while (isspace((int)(*bp)))
                bp++;

            fmt++;
            continue;
        }

        if ((c = *fmt++) != '%')
            goto literal;

    again:
        switch (c = *fmt++) {
            case 'm': /* The month. */
                LEGAL_ALT(ALT_O);
                if (!(conv_num(&bp, &i, 1, 12)))
                    return (0);
                /* tm->tm_mon = i- 1; @skull #2023-9-14 10:18:34 */
                tm->tm_mon = i;
                break;

            case 'Y': /* The year. */
                LEGAL_ALT(ALT_E);
                if (!(conv_num(&bp, &i, 0, 9999)))
                    return (0);
                /* tm->tm_year = i - TM_YEAR_BASE; @skull #2023-9-14 10:19:59 */
                tm->tm_year = i;
                break;