4 * @brief read command line options from a file
9 * Copyright (C) 1998, 1999 Henry Spencer.
11 * This library is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Library General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
16 * This library is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
19 * License for more details.
26 #include <utils/lexparser.h>
28 #include "optionsfrom.h"
30 #define MAX_USES 100 /* loop-detection limit */
31 #define SOME_ARGS 10 /* first guess at how many arguments we'll need */
34 * parse the options from a file
35 * does not alter the existing arguments, but does relocate and alter
36 * the argv pointer vector.
38 static err_t
parse_options_file(const char *filename
, int *argcp
, char **argvp
[], int optind
)
42 int next
; /* place for next argument */
43 int room
; /* how many more new arguments we can hold */
45 chunk_t chunk
, src
, line
, token
;
48 FILE *fd
= fopen(filename
, "r");
52 return "unable to open file";
55 /* determine the file size */
56 fseek(fd
, 0, SEEK_END
);
57 chunk
.len
= ftell(fd
);
60 /* allocate one byte more just in case of a missing final newline */
61 chunk
.ptr
= malloc(chunk
.len
+ 1);
63 /* read the whole file into a chunk */
64 bytes
= fread(chunk
.ptr
, 1, chunk
.len
, fd
);
67 newargc
= *argcp
+ SOME_ARGS
;
68 newargv
= malloc((newargc
+ 1) * sizeof(char *));
69 memcpy(newargv
, *argvp
, optind
* sizeof(char *));
74 /* we keep the chunk pointer so that we can still free it */
77 while (fetchline(&src
, &line
) && ugh
== NULL
)
79 while (eat_whitespace(&line
))
81 if (*line
.ptr
== '"'|| *line
.ptr
== '\'')
83 char delimiter
= *line
.ptr
;
87 if (!extract_token(&token
, delimiter
, &line
))
89 ugh
= "missing terminating delimiter";
95 if (!extract_token(&token
, ' ', &line
))
97 /* last token in a line */
103 /* do we have to allocate more memory for additional arguments? */
106 newargc
+= SOME_ARGS
;
107 newargv
= realloc(newargv
, (newargc
+1) * sizeof(char *));
111 /* terminate the token by replacing the delimiter with a null character */
112 *(token
.ptr
+ token
.len
) = '\0';
114 /* assign the token to the next argument */
115 newargv
[next
] = token
.ptr
;
121 if (ugh
) /* error of some kind */
128 memcpy(newargv
+ next
, *argvp
+ optind
, (*argcp
+ 1 - optind
) * sizeof(char *));
129 *argcp
+= next
- optind
;
137 err_t
optionsfrom(const char *filename
, int *argcp
, char **argvp
[], int optind
, FILE *errfile
)
139 static int nuses
= 0;
142 /* avoid endless loops with recursive --optionsfrom arguments */
146 if (nuses
>= MAX_USES
)
148 fprintf(errfile
, "%s: optionsfrom called %d times - looping?\n",
158 ugh
= parse_options_file(filename
, argcp
, argvp
, optind
);
160 if (ugh
!= NULL
&& errfile
!= NULL
)
162 fprintf(errfile
, "%s: optionsfrom failed: %s\n", (*argvp
)[0], ugh
);