view th_args.c @ 161:a765a51cbd5c

Make th_print_wrap() function public and move the code to th_util.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 09 Feb 2015 18:41:00 +0200
parents fdea1c3acc53
children 503f0cb98775
line wrap: on
line source

/*
 * Simple commandline argument processing
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2002-2015 Tecnic Software productions (TNSP)
 *
 * Please read file 'COPYING' for information on license and distribution.
 */
#ifndef TH_EXTERNAL
#include "th_util.h"
#include "th_args.h"
#include "th_string.h"
#endif


/* Parse long and short options
 */
static BOOL th_args_process_opt(
    char *currArg, int *argIndex,
    int argc, char *argv[],
    const th_optarg_t opts[], int numOpts,
    BOOL (*handleOptionCB)(int, char *, char *),
    BOOL doProcess, BOOL isLong)
{
    const th_optarg_t *opt = NULL;
    char *optArg = NULL;
    int optIndex;

    for (optIndex = 0; optIndex < numOpts; optIndex++)
    {
        const th_optarg_t *node = &opts[optIndex];
        if (isLong && node->optLong != NULL)
        {
            if (strcmp(currArg, node->optLong) == 0)
            {
                opt = node;
                optArg = NULL;
                break;
            }

            size_t len = strlen(node->optLong);
            if (strncmp(currArg, node->optLong, len) == 0 &&
                currArg[len] == '=')
            {
                opt = node;
                optArg = (&currArg[len+1] != 0) ? &currArg[len+1] : NULL;
                break;
            }
        }
        else
        if (!isLong && node->optShort != 0)
        {
            if (*currArg == node->optShort)
            {
                opt = node;
                optArg = (currArg[1] != 0) ? &currArg[1] : NULL;
            }
        }
    }

    if (opt != NULL)
    {
        // Check for the possible option argument
        if ((opt->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL)
        {
            if (*argIndex < argc)
            {
                (*argIndex)++;
                optArg = argv[*argIndex];
            }
            else
            {
                THERR("Option '%s%s' requires an argument.\n",
                    isLong ? "--" : "-",
                    currArg);
                return FALSE;
            }
        }
        
        // Option was given succesfully, try to process it
        if (doProcess && !handleOptionCB(opt->id, optArg, currArg))
            return FALSE;
    }
    else
    {
        THERR("Unknown %s option '%s%s'\n",
            isLong ? "long" : "short",
            isLong ? "--" : "-",
            currArg);

        return FALSE;
    }

    return TRUE;
}


/* Process arguments, handling short and long options by
 * calling the given callback functions.
 */
BOOL th_args_process(int argc, char *argv[],
     const th_optarg_t *opts, const int numOpts,
     BOOL(*handleOptionCB) (int, char *, char *),
     BOOL(*handleOther) (char *), const int flags)
{
    int argIndex, handleFlags = flags & OPTH_ONLY_MASK;
    BOOL optionsOK = TRUE, endOfOptions = FALSE;

    for (argIndex = 1; argIndex < argc; argIndex++)
    {
        char *str = argv[argIndex];
        if (*str == '-' && !endOfOptions)
        {
            // Should we process options?
            BOOL doProcess = (handleFlags & OPTH_ONLY_OPTS) || handleFlags == 0;
            BOOL isLong;

            str++;
            if (*str == '-')
            {
                // Check for "--", which ends the options-list
                str++;
                if (*str == 0)
                {
                    endOfOptions = TRUE;
                    continue;
                }

                // We have a long option
                isLong = TRUE;
            }
            else
                isLong = FALSE;

            if (!th_args_process_opt(str, &argIndex, argc, argv,
                opts, numOpts, handleOptionCB, doProcess, isLong))
                optionsOK = FALSE;
        }
        else
        if (handleFlags == OPTH_ONLY_OTHER || handleFlags == 0)
        {
            // Was not option argument
            if (handleOther == NULL ||
                (handleOther != NULL && !handleOther(str)))
            {
                THERR("Invalid argument '%s'\n", str);
                optionsOK = FALSE;
            }
        }

        // Check if we bail out on invalid argument
        if (!optionsOK && (flags & OPTH_BAILOUT))
            return FALSE;
    }

    return optionsOK;
}


/* Print help for commandline arguments/options
 */
void th_args_help(FILE *fh,
    const th_optarg_t *opts, const int numOpts,
    const int flags)
{
    int index;
    (void) flags;

    // Print out option list
    for (index = 0; index < numOpts; index++)
    {
        const th_optarg_t *opt = &opts[index];
        char tmpStr[128];

        // Print short option
        if (opt->optShort != 0)
        {
            snprintf(tmpStr, sizeof(tmpStr),
                "-%c,", opt->optShort);
        }
        else
            tmpStr[0] = 0;

        fprintf(fh, " %-5s", tmpStr);

        // Print long option
        if (opt->optLong != NULL)
        {
            snprintf(tmpStr, sizeof(tmpStr), "--%s%s",
                opt->optLong,
                (opt->flags & OPT_ARGREQ) ? "=ARG" : "");
        }
        else
            tmpStr[0] = 0;

        fprintf(fh, "%-20s", tmpStr);

        th_print_wrap(fh, opt->desc, 26, 26, th_term_width() - 2);
    }
}