5 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
6 file accompanying popt source distributions, available from
7 ftp://ftp.rpm.org/pub/rpm/dist. */
16 #if defined(HAVE_FNMATCH_H)
21 #if defined(HAVE_GLOB_H)
24 #if !defined(HAVE_GLOB_PATTERN_P)
25 /* Return nonzero if PATTERN contains any metacharacters.
26 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
28 glob_pattern_p (const char * pattern
, int quote
)
33 for (p
= pattern
; *p
!= '\0'; ++p
)
40 if (quote
&& p
[1] != '\0')
53 #endif /* !defined(__GLIBC__) */
55 static int poptGlobFlags
= 0;
57 static int poptGlob_error(UNUSED(const char * epath
),
62 #endif /* HAVE_GLOB_H */
65 * Return path(s) from a glob pattern.
67 * @param pattern glob pattern
68 * @retval *acp no. of paths
69 * @retval *avp array of paths
70 * @return 0 on success
72 static int poptGlob(UNUSED(poptContext con
), const char * pattern
,
73 int * acp
, const char *** avp
)
75 const char * pat
= pattern
;
76 int rc
= 0; /* assume success */
78 #if defined(HAVE_GLOB_H)
79 if (glob_pattern_p(pat
, 0)) {
80 glob_t _g
, *pglob
= &_g
;
82 if (!(rc
= glob(pat
, poptGlobFlags
, poptGlob_error
, pglob
))) {
84 *acp
= (int) pglob
->gl_pathc
;
88 *avp
= (const char **) pglob
->gl_pathv
;
89 pglob
->gl_pathv
= NULL
;
92 } else if (rc
== GLOB_NOMATCH
) {
97 rc
= POPT_ERROR_ERRNO
;
99 #endif /* HAVE_GLOB_H */
103 if (avp
&& (*avp
= calloc((size_t)(1 + 1), sizeof (**avp
))) != NULL
)
104 (*avp
)[0] = xstrdup(pat
);
111 int poptSaneFile(const char * fn
)
115 if (fn
== NULL
|| strstr(fn
, ".rpmnew") || strstr(fn
, ".rpmsave"))
117 if (stat(fn
, &sb
) == -1)
119 if (!S_ISREG(sb
.st_mode
))
121 if (sb
.st_mode
& (S_IXUSR
|S_IXGRP
|S_IXOTH
))
126 int poptReadFile(const char * fn
, char ** bp
, size_t * nbp
, int flags
)
132 int rc
= POPT_ERROR_ERRNO
; /* assume failure */
134 fdno
= open(fn
, O_RDONLY
);
138 if ((nb
= lseek(fdno
, 0, SEEK_END
)) == (off_t
)-1
139 || (uintmax_t)nb
>= SIZE_MAX
140 || lseek(fdno
, 0, SEEK_SET
) == (off_t
)-1
141 || (b
= calloc(sizeof(*b
), (size_t)nb
+ 1)) == NULL
142 || read(fdno
, (char *)b
, (size_t)nb
) != (ssize_t
)nb
)
146 if (nb
!= (off_t
)-1 && (uintmax_t)nb
>= SIZE_MAX
)
152 if (close(fdno
) == -1)
155 rc
= POPT_ERROR_MALLOC
;
160 /* Trim out escaped newlines. */
161 if (flags
& POPT_READFILE_TRIMNEWLINES
)
163 for (t
= b
, s
= b
, se
= b
+ nb
; *s
&& s
< se
; s
++) {
197 * Check for application match.
199 * @param s config application name
200 * return 0 if config application matches
202 static int configAppMatch(poptContext con
, const char * s
)
206 if (con
->appName
== NULL
) /* XXX can't happen. */
209 #if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
210 if (glob_pattern_p(s
, 1)) {
211 static int flags
= FNM_PATHNAME
| FNM_PERIOD
;
213 flags
|= FNM_EXTMATCH
;
215 rc
= fnmatch(s
, con
->appName
, flags
);
218 rc
= strcmp(s
, con
->appName
);
222 static int poptConfigLine(poptContext con
, char * line
)
227 const char * appName
;
228 const char * entryType
;
230 struct poptItem_s item_buf
;
231 poptItem item
= &item_buf
;
233 int rc
= POPT_ERROR_BADCONFIG
;
235 if (con
->appName
== NULL
)
238 memset(item
, 0, sizeof(*item
));
241 while (*se
!= '\0' && !_isspaceptr(se
)) se
++;
247 if (configAppMatch(con
, appName
)) goto exit
;
249 while (*se
!= '\0' && _isspaceptr(se
)) se
++;
251 while (*se
!= '\0' && !_isspaceptr(se
)) se
++;
252 if (*se
!= '\0') *se
++ = '\0';
254 while (*se
!= '\0' && _isspaceptr(se
)) se
++;
255 if (*se
== '\0') goto exit
;
257 while (*se
!= '\0' && !_isspaceptr(se
)) se
++;
258 if (opt
[0] == '-' && *se
== '\0') goto exit
;
259 if (*se
!= '\0') *se
++ = '\0';
261 while (*se
!= '\0' && _isspaceptr(se
)) se
++;
262 if (opt
[0] == '-' && *se
== '\0') goto exit
;
264 if (opt
[0] == '-' && opt
[1] == '-')
265 item
->option
.longName
= opt
+ 2;
266 else if (opt
[0] == '-' && opt
[2] == '\0')
267 item
->option
.shortName
= opt
[1];
269 const char * fn
= opt
;
271 /* XXX handle globs and directories in fn? */
272 if ((rc
= poptReadFile(fn
, &b
, &nb
, POPT_READFILE_TRIMNEWLINES
)) != 0)
274 if (b
== NULL
|| nb
== 0)
277 /* Append remaining text to the interpolated file option text. */
279 size_t nse
= strlen(se
) + 1;
280 if ((b
= realloc(b
, (nb
+ nse
))) == NULL
) /* XXX can't happen */
282 (void) stpcpy( stpcpy(&b
[nb
-1], " "), se
);
287 /* Use the basename of the path as the long option name. */
288 { const char * longName
= strrchr(fn
, '/');
289 if (longName
!= NULL
)
293 if (longName
== NULL
) /* XXX can't happen. */
295 /* Single character basenames are treated as short options. */
296 if (longName
[1] != '\0')
297 item
->option
.longName
= longName
;
299 item
->option
.shortName
= longName
[0];
303 if (poptParseArgvString(se
, &item
->argc
, &item
->argv
)) goto exit
;
305 item
->option
.argInfo
= POPT_ARGFLAG_DOC_HIDDEN
;
306 for (i
= 0, j
= 0; i
< item
->argc
; i
++, j
++) {
308 if (!strncmp(item
->argv
[i
], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
309 f
= item
->argv
[i
] + sizeof("--POPTdesc=");
310 if (f
[0] == '$' && f
[1] == '"') f
++;
311 item
->option
.descrip
= f
;
312 item
->option
.argInfo
&= ~POPT_ARGFLAG_DOC_HIDDEN
;
315 if (!strncmp(item
->argv
[i
], "--POPTargs=", sizeof("--POPTargs=")-1)) {
316 f
= item
->argv
[i
] + sizeof("--POPTargs=");
317 if (f
[0] == '$' && f
[1] == '"') f
++;
318 item
->option
.argDescrip
= f
;
319 item
->option
.argInfo
&= ~POPT_ARGFLAG_DOC_HIDDEN
;
320 item
->option
.argInfo
|= POPT_ARG_STRING
;
324 item
->argv
[j
] = item
->argv
[i
];
327 item
->argv
[j
] = NULL
;
331 if (!strcmp(entryType
, "alias"))
332 rc
= poptAddItem(con
, item
, 0);
333 else if (!strcmp(entryType
, "exec"))
334 rc
= poptAddItem(con
, item
, 1);
336 rc
= 0; /* XXX for now, always return success */
342 int poptReadConfigFile(poptContext con
, const char * fn
)
344 char * b
= NULL
, *be
;
350 if ((rc
= poptReadFile(fn
, &b
, &nb
, POPT_READFILE_TRIMNEWLINES
)) != 0)
351 return (errno
== ENOENT
? 0 : rc
);
352 if (b
== NULL
|| nb
== 0) {
353 rc
= POPT_ERROR_BADCONFIG
;
357 if ((t
= malloc(nb
+ 1)) == NULL
)
362 for (se
= b
; se
< be
; se
++) {
367 while (*te
&& _isspaceptr(te
)) te
++;
368 if (*te
&& *te
!= '#')
369 if ((rc
= poptConfigLine(con
, te
)) != 0)
374 /* \ at the end of a line does not insert a \n */
375 if (se
< be
&& *se
!= '\n') {
394 int poptReadConfigFiles(poptContext con
, const char * paths
)
396 char * buf
= (paths
? xstrdup(paths
) : NULL
);
399 int rc
= 0; /* assume success */
401 for (p
= buf
; p
!= NULL
&& *p
!= '\0'; p
= pe
) {
402 const char ** av
= NULL
;
407 /* locate start of next path element */
409 if (pe
!= NULL
&& *pe
== ':')
412 pe
= (char *) (p
+ strlen(p
));
414 xx
= poptGlob(con
, p
, &ac
, &av
);
416 /* work-off each resulting file from the path element */
417 for (i
= 0; i
< ac
; i
++) {
418 const char * fn
= av
[i
];
419 if (!poptSaneFile(fn
))
421 xx
= poptReadConfigFile(con
, fn
);
437 int poptReadDefaultConfig(poptContext con
, UNUSED(int useEnv
))
441 int rc
= 0; /* assume success */
443 if (con
->appName
== NULL
) goto exit
;
445 rc
= poptReadConfigFile(con
, POPT_SYSCONFDIR
"/popt");
448 #if defined(HAVE_GLOB_H)
449 if (!stat(POPT_SYSCONFDIR
"/popt.d", &sb
) && S_ISDIR(sb
.st_mode
)) {
450 const char ** av
= NULL
;
454 if ((rc
= poptGlob(con
, POPT_SYSCONFDIR
"/popt.d/*", &ac
, &av
)) == 0) {
455 for (i
= 0; rc
== 0 && i
< ac
; i
++) {
456 const char * fn
= av
[i
];
457 if (!poptSaneFile(fn
))
459 rc
= poptReadConfigFile(con
, fn
);
470 if ((home
= getenv("HOME"))) {
471 char * fn
= malloc(strlen(home
) + 20);
473 (void) stpcpy(stpcpy(fn
, home
), "/.popt");
474 rc
= poptReadConfigFile(con
, fn
);
477 rc
= POPT_ERROR_ERRNO
;
486 poptFini(poptContext con
)
488 return poptFreeContext(con
);
492 poptInit(int argc
, const char ** argv
,
493 const struct poptOption
* options
, const char * configPaths
)
495 poptContext con
= NULL
;
498 if (argv
== NULL
|| argv
[0] == NULL
|| options
== NULL
)
501 if ((argv0
= strrchr(argv
[0], '/')) != NULL
) argv0
++;
502 else argv0
= argv
[0];
504 con
= poptGetContext(argv0
, argc
, (const char **)argv
, options
, 0);
505 if (con
!= NULL
&& poptReadConfigFiles(con
, configPaths
))