1 /*****************************************************************************/
5 /* Helper functions for command line parsing */
9 /* (C) 2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
48 /*****************************************************************************/
50 /*****************************************************************************/
54 /* Program name - is set after call to InitCmdLine */
57 /* The program argument vector */
59 unsigned ArgCount = 0;
61 /* Struct to pass the command line */
63 char** Vec; /* The argument vector */
64 unsigned Count; /* Actual number of arguments */
65 unsigned Size; /* Number of argument allocated */
70 /*****************************************************************************/
71 /* Helper functions */
72 /*****************************************************************************/
76 static void NewCmdLine (CmdLine* L)
77 /* Initialize a CmdLine struct */
81 /* Initialize the struct */
84 L->Vec = xmalloc (L->Size * sizeof (L->Vec[0]));
86 /* Copy the arguments. We have to allocate them on free store, otherwise
87 * we would have to keep track which one is on free store and which not,
88 * which is a lot more overhead.
90 for (I = 0; I < L->Count; ++I) {
91 L->Vec[I] = xstrdup (ArgVec[I]);
97 static void AddArg (CmdLine* L, const char* Arg)
98 /* Add one argument to the list */
100 if (L->Size <= L->Count) {
101 /* No space left, reallocate */
102 unsigned NewSize = L->Size * 2;
103 char** NewVec = xmalloc (NewSize * sizeof (L->Vec[0]));
104 memcpy (NewVec, L->Vec, L->Count * sizeof (L->Vec[0]));
110 /* We have space left, add a copy of the argument */
111 L->Vec [L->Count++] = xstrdup (Arg);
116 static void ExpandFile (CmdLine* L, const char* Name)
117 /* Add the contents of a file to the command line. Each line is a separate
118 * argument with leading and trailing whitespace removed.
123 /* Try to open the file for reading */
124 FILE* F = fopen (Name, "r");
126 AbEnd ("Cannot open \"%s\": %s", Name, strerror (errno));
129 /* File is open, read all lines */
130 while (fgets (Buf, sizeof (Buf), F) != 0) {
132 /* Get a pointer to the buffer */
135 /* Skip trailing whitespace (this will also kill the newline that is
136 * appended by fgets().
138 unsigned Len = strlen (Buf);
139 while (Len > 0 && IsSpace (Buf [Len-1])) {
144 /* Skip leading spaces */
145 while (IsSpace (*B)) {
149 /* Skip empty lines to work around problems with some editors */
154 /* Add anything not empty to the command line */
159 /* Close the file, ignore errors here since we had the file open for
167 /*****************************************************************************/
169 /*****************************************************************************/
173 void InitCmdLine (int* aArgCount, char** aArgVec[], const char* aProgName)
174 /* Initialize command line parsing. aArgVec is the argument array terminated by
175 * a NULL pointer (as usual), ArgCount is the number of valid arguments in the
176 * array. Both arguments are remembered in static storage.
182 /* Get the program name from argv[0] but strip a path */
183 if (*(aArgVec)[0] == 0) {
184 /* Use the default name given */
185 ProgName = aProgName;
188 const char* FirstArg = (*aArgVec)[0];
189 ProgName = strchr (FirstArg, '\0');
190 while (ProgName > FirstArg) {
192 if (*ProgName == '/' || *ProgName == '\\') {
197 if (ProgName[0] == '\0') {
198 /* Use the default */
199 ProgName = aProgName;
203 /* Make a CmdLine struct */
206 /* Walk over the parameters and add them to the CmdLine struct. Add a
207 * special handling for arguments preceeded by the '@' sign - these are
208 * actually files containing arguments.
210 for (I = 0; I < *aArgCount; ++I) {
212 /* Get the next argument */
213 char* Arg = (*aArgVec)[I];
215 /* Is this a file argument? */
216 if (Arg && Arg[0] == '@') {
218 /* Expand the file */
219 ExpandFile (&L, Arg+1);
223 /* No file, just add a copy */
229 /* Store the new argument list in a safe place... */
233 /* ...and pass back the changed data also */
234 *aArgCount = L.Count;
240 void UnknownOption (const char* Opt)
241 /* Print an error about an unknown option and die. */
243 AbEnd ("Unknown option: %s\n", Opt);
248 void NeedArg (const char* Opt)
249 /* Print an error about a missing option argument and exit. */
251 AbEnd ("Option requires an argument: %s\n", Opt);
256 void InvDef (const char* Def)
257 /* Print an error about an invalid definition and die */
259 AbEnd ("Invalid definition: `%s'\n", Def);
264 const char* GetArg (int* ArgNum, unsigned Len)
265 /* Get an argument for a short option. The argument may be appended to the
266 * option itself or may be separate. Len is the length of the option string.
269 const char* Arg = ArgVec[*ArgNum];
270 if (Arg[Len] != '\0') {
271 /* Argument appended */
274 /* Separate argument */
275 Arg = ArgVec[*ArgNum + 1];
277 /* End of arguments */
278 NeedArg (ArgVec[*ArgNum]);
287 void LongOption (int* ArgNum, const LongOpt* OptTab, unsigned OptCount)
288 /* Handle a long command line option */
290 /* Get the option and the argument (which may be zero) */
291 const char* Opt = ArgVec[*ArgNum];
293 /* Search the table for a match */
295 if (strcmp (Opt, OptTab->Option) == 0) {
296 /* Found, call the function */
297 if (OptTab->ArgCount > 0) {
298 /* We need an argument, check if we have one */
299 const char* Arg = ArgVec[++(*ArgNum)];
303 OptTab->Func (Opt, Arg);
305 OptTab->Func (Opt, 0);
311 /* Next table entry */