Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. | |
3 | * | |
4 | * All Rights Reserved. | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining | |
7 | * a copy of this software and associated documentation files (the | |
8 | * "Software"), to deal in the Software without restriction, including | |
9 | * without limitation on the rights to use, copy, modify, merge, | |
10 | * publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, | |
12 | * subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice (including the | |
15 | * next paragraph) shall be included in all copies or substantial | |
16 | * portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
21 | * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS | |
22 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
23 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
25 | * SOFTWARE. | |
26 | */ | |
27 | ||
28 | /* | |
29 | * Authors: | |
30 | * Rickard E. (Rik) Faith <faith@redhat.com> | |
31 | * | |
32 | */ | |
33 | ||
34 | /** \file | |
35 | * Generic comma-delimited argument processing. */ | |
36 | ||
37 | #ifdef HAVE_DMX_CONFIG_H | |
38 | #include <dmx-config.h> | |
39 | #endif | |
40 | ||
41 | #define DMX_ARG_TEST 0 | |
42 | ||
43 | #include "dmx.h" | |
44 | #include "dmxarg.h" | |
45 | #include <stdio.h> | |
46 | #include <string.h> | |
47 | ||
48 | #if DMX_ARG_TEST | |
49 | #include <stdlib.h> | |
50 | #endif | |
51 | ||
52 | /** Stores the parsed argument list. */ | |
53 | struct _dmxArg { | |
54 | int argc; /**< Number of arguments in argv */ | |
55 | int argm; /**< Maximum number of arguments store-able in argv */ | |
56 | const char **argv; /**< Arguments */ | |
57 | }; | |
58 | ||
59 | /** Create an (externally opaque) \a dmxArg object. */ | |
60 | dmxArg | |
61 | dmxArgCreate(void) | |
62 | { | |
63 | dmxArg a = malloc(sizeof(*a)); | |
64 | ||
65 | a->argc = 0; | |
66 | a->argm = 2; | |
67 | a->argv = malloc(a->argm * sizeof(*a->argv)); | |
68 | a->argv[0] = NULL; | |
69 | return a; | |
70 | } | |
71 | ||
72 | /** Free the specified \a dmxArg object. */ | |
73 | void | |
74 | dmxArgFree(dmxArg a) | |
75 | { | |
76 | int i; | |
77 | ||
78 | for (i = 0; i < a->argc; i++) | |
79 | free((char *) a->argv[i]); | |
80 | free(a->argv); | |
81 | free(a); | |
82 | } | |
83 | ||
84 | /** Add the \a string as the next argument in the \a dmxArg object. */ | |
85 | void | |
86 | dmxArgAdd(dmxArg a, const char *string) | |
87 | { | |
88 | if (a->argm <= a->argc + 2) | |
89 | a->argv = realloc(a->argv, sizeof(*a->argv) * (a->argm *= 2)); | |
90 | a->argv[a->argc++] = strdup(string); | |
91 | a->argv[a->argc] = NULL; | |
92 | } | |
93 | ||
94 | /** Return the argument number \a item in the \a dmxArg object. | |
95 | * Arguments are 0 based. NULL will be returned for values less than 0 | |
96 | * or equal to or greater than the number of arguments in the object. */ | |
97 | const char * | |
98 | dmxArgV(dmxArg a, int item) | |
99 | { | |
100 | if (item < 0 || item >= a->argc) | |
101 | return NULL; | |
102 | return a->argv[item]; | |
103 | } | |
104 | ||
105 | /** Return the number of arguments in the \a dmxArg object. */ | |
106 | int | |
107 | dmxArgC(dmxArg a) | |
108 | { | |
109 | return a->argc; | |
110 | } | |
111 | ||
112 | /** Parse a string into arguments delimited by commas. Return a new \a | |
113 | * dmxArg object containing the arguments. */ | |
114 | dmxArg | |
115 | dmxArgParse(const char *string) | |
116 | { | |
117 | char *tmp; | |
118 | char *start, *pt; | |
119 | dmxArg a = dmxArgCreate(); | |
120 | int done; | |
121 | int len; | |
122 | ||
123 | if (!string) | |
124 | return a; | |
125 | ||
126 | len = strlen(string) + 2; | |
127 | tmp = malloc(len); | |
128 | strncpy(tmp, string, len); | |
129 | ||
130 | for (start = pt = tmp, done = 0; !done && *pt; start = ++pt) { | |
131 | for (; *pt && *pt != ','; pt++); | |
132 | if (!*pt) | |
133 | done = 1; | |
134 | *pt = '\0'; | |
135 | dmxArgAdd(a, start); | |
136 | } | |
137 | if (!done) | |
138 | dmxArgAdd(a, ""); /* Final comma */ | |
139 | ||
140 | free(tmp); | |
141 | return a; | |
142 | } | |
143 | ||
144 | #if DMX_ARG_TEST | |
145 | static void | |
146 | dmxArgPrint(dmxArg a) | |
147 | { | |
148 | int i; | |
149 | ||
150 | printf(" argc = %d\n", dmxArgC(a)); | |
151 | for (i = 0; i < dmxArgC(a); i++) | |
152 | printf(" argv[%d] = \"%s\"\n", i, dmxArgV(a, i)); | |
153 | } | |
154 | ||
155 | static void | |
156 | dmxArgTest(const char *string) | |
157 | { | |
158 | dmxArg a; | |
159 | ||
160 | if (!string) | |
161 | printf("Testing NULL\n"); | |
162 | else if (!strlen(string)) | |
163 | printf("Testing (empty)\n"); | |
164 | else | |
165 | printf("Testing \"%s\"\n", string); | |
166 | ||
167 | a = dmxArgParse(string); | |
168 | dmxArgPrint(a); | |
169 | dmxArgFree(a); | |
170 | } | |
171 | ||
172 | int | |
173 | main(void) | |
174 | { | |
175 | dmxArgTest(NULL); | |
176 | dmxArgTest(""); | |
177 | dmxArgTest(","); | |
178 | ||
179 | dmxArgTest("a"); | |
180 | dmxArgTest("a,"); | |
181 | dmxArgTest(",a"); | |
182 | ||
183 | dmxArgTest("a,b"); | |
184 | dmxArgTest("a,b,"); | |
185 | dmxArgTest("a,b,,"); | |
186 | dmxArgTest("a,b,,c"); | |
187 | ||
188 | return 0; | |
189 | } | |
190 | #endif |