2 * libdpkg - Debian packaging suite library routines
3 * options.c - option parsing functions
5 * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2000,2002 Wichert Akkerman <wichert@deephackmode.org>
7 * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
33 #include <dpkg/i18n.h>
34 #include <dpkg/c-ctype.h>
35 #include <dpkg/dpkg.h>
36 #include <dpkg/string.h>
37 #include <dpkg/options.h>
39 static const char *printforhelp
;
42 badusage(const char *fmt
, ...)
48 m_vasprintf(&buf
, fmt
, args
);
51 ohshit("%s\n\n%s", buf
, gettext(printforhelp
));
54 static void DPKG_ATTR_NORET
DPKG_ATTR_PRINTF(3)
55 config_error(const char *file_name
, int line_num
, const char *fmt
, ...)
61 m_vasprintf(&buf
, fmt
, args
);
64 ohshit(_("configuration error: %s:%d: %s"), file_name
, line_num
, buf
);
68 dpkg_options_load_file(const char *fn
, const struct cmdinfo
*cmdinfos
)
72 char linebuf
[MAX_CONFIG_LINE
];
78 warning(_("failed to open configuration file '%.255s' for reading: %s"),
83 while (fgets(linebuf
, sizeof(linebuf
), file
)) {
85 const struct cmdinfo
*cip
;
89 str_rtrim_spaces(linebuf
, linebuf
+ strlen(linebuf
));
91 if ((linebuf
[0] == '#') || (linebuf
[0] == '\0'))
93 for (opt
= linebuf
; c_isalnum(*opt
) || *opt
== '-'; opt
++) ;
99 while (c_isspace(*opt
))
102 opt
= str_strip_quotes(opt
);
104 config_error(fn
, line_num
, _("unbalanced quotes in '%s'"), linebuf
);
107 for (cip
=cmdinfos
; cip
->olong
|| cip
->oshort
; cip
++) {
110 if (!cip
->olong
) continue;
111 if (strcmp(cip
->olong
, linebuf
) == 0)
113 l
=strlen(cip
->olong
);
114 if ((cip
->takesvalue
==2) && (linebuf
[l
]=='-') &&
115 !opt
&& strncmp(linebuf
, cip
->olong
, l
) == 0) {
122 config_error(fn
, line_num
, _("unknown option '%s'"), linebuf
);
124 if (cip
->takesvalue
) {
126 config_error(fn
, line_num
, _("'%s' needs a value"), linebuf
);
127 if (cip
->call
) cip
->call(cip
,opt
);
129 *cip
->sassignto
= m_strdup(opt
);
132 config_error(fn
, line_num
, _("'%s' does not take a value"), linebuf
);
133 if (cip
->call
) cip
->call(cip
,NULL
);
135 *cip
->iassignto
= cip
->arg_int
;
139 ohshite(_("read error in configuration file '%.255s'"), fn
);
141 ohshite(_("error closing configuration file '%.255s'"), fn
);
145 valid_config_filename(const struct dirent
*dent
)
149 if (dent
->d_name
[0] == '.')
152 for (c
= dent
->d_name
; *c
; c
++)
153 if (!c_isalnum(*c
) && *c
!= '_' && *c
!= '-')
163 dpkg_options_load_dir(const char *prog
, const struct cmdinfo
*cmdinfos
)
166 struct dirent
**dlist
;
169 dirname
= str_fmt("%s/%s.cfg.d", CONFIGDIR
, prog
);
171 dlist_n
= scandir(dirname
, &dlist
, valid_config_filename
, alphasort
);
173 if (errno
== ENOENT
) {
177 ohshite(_("error opening configuration directory '%s'"), dirname
);
180 for (i
= 0; i
< dlist_n
; i
++) {
183 filename
= str_fmt("%s/%s", dirname
, dlist
[i
]->d_name
);
184 dpkg_options_load_file(filename
, cmdinfos
);
195 dpkg_options_load(const char *prog
, const struct cmdinfo
*cmdinfos
)
199 dpkg_options_load_dir(prog
, cmdinfos
);
201 file
= str_fmt("%s/%s.cfg", CONFIGDIR
, prog
);
202 dpkg_options_load_file(file
, cmdinfos
);
205 home
= getenv("HOME");
207 file
= str_fmt("%s/.%s.cfg", home
, prog
);
208 dpkg_options_load_file(file
, cmdinfos
);
214 dpkg_options_parse(const char *const **argvp
, const struct cmdinfo
*cmdinfos
,
215 const char *help_str
)
217 const struct cmdinfo
*cip
;
218 const char *p
, *value
;
222 badusage(_("missing program name in argv[0]"));
224 printforhelp
= help_str
;
227 while ((p
= **argvp
) && p
[0] == '-' && p
[1] != '\0') {
229 if (strcmp(p
, "--") == 0)
234 cip
->olong
|| cip
->oshort
;
236 if (!cip
->olong
) continue;
237 if (strcmp(p
, cip
->olong
) == 0)
239 l
= strlen(cip
->olong
);
240 if (strncmp(p
, cip
->olong
, l
) == 0 &&
241 (p
[l
]== ((cip
->takesvalue
==2) ? '-' : '='))) { value
=p
+l
+1; break; }
243 if (!cip
->olong
) badusage(_("unknown option --%s"),p
);
244 if (cip
->takesvalue
) {
247 if (!value
) badusage(_("--%s option takes a value"),cip
->olong
);
249 if (cip
->call
) cip
->call(cip
,value
);
250 else *cip
->sassignto
= value
;
252 if (value
) badusage(_("--%s option does not take a value"),cip
->olong
);
253 if (cip
->call
) cip
->call(cip
,NULL
);
255 *cip
->iassignto
= cip
->arg_int
;
259 for (cip
= cmdinfos
; (cip
->olong
|| cip
->oshort
) && *p
!= cip
->oshort
; cip
++);
260 if (!cip
->oshort
) badusage(_("unknown option -%c"),*p
);
262 if (cip
->takesvalue
) {
265 if (!value
) badusage(_("-%c option takes a value"),cip
->oshort
);
268 if (*value
== '=') value
++;
270 if (cip
->call
) cip
->call(cip
,value
);
271 else *cip
->sassignto
= value
;
273 if (*p
== '=') badusage(_("-%c option does not take a value"),cip
->oshort
);
274 if (cip
->call
) cip
->call(cip
,NULL
);
276 *cip
->iassignto
= cip
->arg_int
;
284 dpkg_options_parse_arg_int(const struct cmdinfo
*cmd
, const char *str
)
290 value
= strtol(str
, &end
, 0);
291 if (str
== end
|| *end
|| value
< 0 || value
> INT_MAX
|| errno
!= 0) {
293 badusage(_("invalid integer for --%s: '%.250s'"), cmd
->olong
, str
);
295 badusage(_("invalid integer for -%c: '%.250s'"), cmd
->oshort
, str
);
302 setobsolete(const struct cmdinfo
*cip
, const char *value
)
304 warning(_("obsolete option '--%s'"), cip
->olong
);
307 const struct cmdinfo
*cipaction
= NULL
;
309 /* XXX: This function is a hack. */
317 setaction(const struct cmdinfo
*cip
, const char *value
)
319 if (cipaction
&& cip
)
320 badusage(_("conflicting actions -%c (--%s) and -%c (--%s)"),
321 option_short(cip
->oshort
), cip
->olong
,
322 option_short(cipaction
->oshort
), cipaction
->olong
);
324 if (cip
&& cip
->takesvalue
== 2 && cip
->sassignto
)
325 *cipaction
->sassignto
= value
;