1706f2543Smrg/*
2706f2543Smrg * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
3706f2543Smrg *
4706f2543Smrg * All Rights Reserved.
5706f2543Smrg *
6706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining
7706f2543Smrg * a copy of this software and associated documentation files (the
8706f2543Smrg * "Software"), to deal in the Software without restriction, including
9706f2543Smrg * without limitation on the rights to use, copy, modify, merge,
10706f2543Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
11706f2543Smrg * and to permit persons to whom the Software is furnished to do so,
12706f2543Smrg * subject to the following conditions:
13706f2543Smrg *
14706f2543Smrg * The above copyright notice and this permission notice (including the
15706f2543Smrg * next paragraph) shall be included in all copies or substantial
16706f2543Smrg * portions of the Software.
17706f2543Smrg *
18706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19706f2543Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20706f2543Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21706f2543Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22706f2543Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23706f2543Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24706f2543Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25706f2543Smrg * SOFTWARE.
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Authors:
30706f2543Smrg *   Rickard E. (Rik) Faith <faith@redhat.com>
31706f2543Smrg *
32706f2543Smrg */
33706f2543Smrg
34706f2543Smrg/** \file
35706f2543Smrg * Generic comma-delimited argument processing. */
36706f2543Smrg
37706f2543Smrg#ifdef HAVE_DMX_CONFIG_H
38706f2543Smrg#include <dmx-config.h>
39706f2543Smrg#endif
40706f2543Smrg
41706f2543Smrg#define DMX_ARG_TEST 0
42706f2543Smrg
43706f2543Smrg#include "dmx.h"
44706f2543Smrg#include "dmxarg.h"
45706f2543Smrg#include <stdio.h>
46706f2543Smrg#include <string.h>
47706f2543Smrg
48706f2543Smrg#if DMX_ARG_TEST
49706f2543Smrg#include <stdlib.h>
50706f2543Smrg#endif
51706f2543Smrg
52706f2543Smrg/** Stores the parsed argument list. */
53706f2543Smrgstruct _dmxArg {
54706f2543Smrg    int        argc;   /**< Number of arguments in argv */
55706f2543Smrg    int        argm;   /**< Maximum number of arguments store-able in argv */
56706f2543Smrg    const char **argv; /**< Arguments */
57706f2543Smrg};
58706f2543Smrg
59706f2543Smrg/** Create an (externally opaque) \a dmxArg object. */
60706f2543SmrgdmxArg dmxArgCreate(void)
61706f2543Smrg{
62706f2543Smrg    dmxArg a   = malloc(sizeof(*a));
63706f2543Smrg    a->argc    = 0;
64706f2543Smrg    a->argm    = 2;
65706f2543Smrg    a->argv    = malloc(a->argm * sizeof(*a->argv));
66706f2543Smrg    a->argv[0] = NULL;
67706f2543Smrg    return a;
68706f2543Smrg}
69706f2543Smrg
70706f2543Smrg/** Free the specified \a dmxArg object. */
71706f2543Smrgvoid dmxArgFree(dmxArg a)
72706f2543Smrg{
73706f2543Smrg    int i;
74706f2543Smrg
75706f2543Smrg    for (i = 0; i < a->argc; i++) free((char *)a->argv[i]);
76706f2543Smrg    free(a->argv);
77706f2543Smrg    free(a);
78706f2543Smrg}
79706f2543Smrg
80706f2543Smrg/** Add the \a string as the next argument in the \a dmxArg object. */
81706f2543Smrgvoid dmxArgAdd(dmxArg a, const char *string)
82706f2543Smrg{
83706f2543Smrg    if (a->argm <= a->argc + 2)
84706f2543Smrg        a->argv = realloc(a->argv, sizeof(*a->argv) * (a->argm *= 2));
85706f2543Smrg    a->argv[a->argc++] = strdup(string);
86706f2543Smrg    a->argv[a->argc]   = NULL;
87706f2543Smrg}
88706f2543Smrg
89706f2543Smrg/** Return the argument number \a item in the \a dmxArg object.
90706f2543Smrg * Arguments are 0 based.  NULL will be returned for values less than 0
91706f2543Smrg * or equal to or greater than the number of arguments in the object. */
92706f2543Smrgconst char *dmxArgV(dmxArg a, int item)
93706f2543Smrg{
94706f2543Smrg    if (item < 0 || item >= a->argc) return NULL;
95706f2543Smrg    return a->argv[item];
96706f2543Smrg}
97706f2543Smrg
98706f2543Smrg/** Return the number of arguments in the \a dmxArg object. */
99706f2543Smrgint dmxArgC(dmxArg a)
100706f2543Smrg{
101706f2543Smrg    return a->argc;
102706f2543Smrg}
103706f2543Smrg
104706f2543Smrg/** Parse a string into arguments delimited by commas.  Return a new \a
105706f2543Smrg * dmxArg object containing the arguments. */
106706f2543SmrgdmxArg dmxArgParse(const char *string)
107706f2543Smrg{
108706f2543Smrg    char   *tmp;
109706f2543Smrg    char   *start, *pt;
110706f2543Smrg    dmxArg a = dmxArgCreate();
111706f2543Smrg    int    done;
112706f2543Smrg    int    len;
113706f2543Smrg
114706f2543Smrg    if (!string) return a;
115706f2543Smrg
116706f2543Smrg    len = strlen(string) + 2;
117706f2543Smrg    tmp = malloc(len);
118706f2543Smrg    strncpy(tmp, string, len);
119706f2543Smrg
120706f2543Smrg    for (start = pt = tmp, done = 0; !done && *pt; start = ++pt) {
121706f2543Smrg        for (;*pt && *pt != ','; pt++);
122706f2543Smrg        if (!*pt) done = 1;
123706f2543Smrg        *pt = '\0';
124706f2543Smrg        dmxArgAdd(a, start);
125706f2543Smrg    }
126706f2543Smrg    if (!done) dmxArgAdd(a, ""); /* Final comma */
127706f2543Smrg
128706f2543Smrg    free(tmp);
129706f2543Smrg    return a;
130706f2543Smrg}
131706f2543Smrg
132706f2543Smrg#if DMX_ARG_TEST
133706f2543Smrgstatic void dmxArgPrint(dmxArg a)
134706f2543Smrg{
135706f2543Smrg    int i;
136706f2543Smrg
137706f2543Smrg    printf("   argc = %d\n", dmxArgC(a));
138706f2543Smrg    for (i = 0; i < dmxArgC(a); i++)
139706f2543Smrg        printf("   argv[%d] = \"%s\"\n", i, dmxArgV(a, i));
140706f2543Smrg}
141706f2543Smrg
142706f2543Smrgstatic void dmxArgTest(const char *string)
143706f2543Smrg{
144706f2543Smrg    dmxArg a;
145706f2543Smrg
146706f2543Smrg    if (!string)
147706f2543Smrg        printf("Testing NULL\n");
148706f2543Smrg    else if (!strlen(string))
149706f2543Smrg        printf("Testing (empty)\n");
150706f2543Smrg    else
151706f2543Smrg        printf("Testing \"%s\"\n", string);
152706f2543Smrg
153706f2543Smrg    a = dmxArgParse(string);
154706f2543Smrg    dmxArgPrint(a);
155706f2543Smrg    dmxArgFree(a);
156706f2543Smrg}
157706f2543Smrg
158706f2543Smrgint main(void)
159706f2543Smrg{
160706f2543Smrg    dmxArgTest(NULL);
161706f2543Smrg    dmxArgTest("");
162706f2543Smrg    dmxArgTest(",");
163706f2543Smrg
164706f2543Smrg    dmxArgTest("a");
165706f2543Smrg    dmxArgTest("a,");
166706f2543Smrg    dmxArgTest(",a");
167706f2543Smrg
168706f2543Smrg    dmxArgTest("a,b");
169706f2543Smrg    dmxArgTest("a,b,");
170706f2543Smrg    dmxArgTest("a,b,,");
171706f2543Smrg    dmxArgTest("a,b,,c");
172706f2543Smrg
173706f2543Smrg    return 0;
174706f2543Smrg}
175706f2543Smrg#endif
176