summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Troan <ewt@src.gnome.org>1998-09-27 14:57:05 +0000
committerErik Troan <ewt@src.gnome.org>1998-09-27 14:57:05 +0000
commit0083afca97ed3a007488c9b63bcd93c778334022 (patch)
tree28c7588b4a0fbd53a8a714ced3c6e0761ec29106
parentb853105f398bf04a77d92faaca984d976c46603c (diff)
downloadgnome-common-0083afca97ed3a007488c9b63bcd93c778334022.tar.gz
1) added included tables
2) added option callbacks 3) added automatic help/usage messages svn path=/trunk/; revision=409
-rw-r--r--support/popt-gnome.h21
-rw-r--r--support/popt.c311
-rw-r--r--support/popt.h21
3 files changed, 95 insertions, 258 deletions
diff --git a/support/popt-gnome.h b/support/popt-gnome.h
index 850a8cd..50580f7 100644
--- a/support/popt-gnome.h
+++ b/support/popt-gnome.h
@@ -1,12 +1,19 @@
#ifndef H_POPT
#define H_POPT
+#include <stdio.h> /* for FILE * */
+
#define POPT_OPTION_DEPTH 10
#define POPT_ARG_NONE 0
#define POPT_ARG_STRING 1
#define POPT_ARG_INT 2
#define POPT_ARG_LONG 3
+#define POPT_ARG_INCLUDE_TABLE 4 /* arg points to table */
+#define POPT_ARG_CALLBACK 5 /* table-wide callback... must be
+ set first in table; arg points
+ to callback, descrip points to
+ callback data to pass */
#define POPT_ERROR_NOARG -10
#define POPT_ERROR_BADOPT -11
@@ -22,6 +29,7 @@
/* poptGetContext() flags */
#define POPT_CONTEXT_NO_EXEC (1 << 0) /* ignore exec expansions */
#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /* pay attention to argv[0] */
+#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /* options can't follow args */
struct poptOption {
const char * longName; /* may be NULL */
@@ -29,6 +37,8 @@ struct poptOption {
int argInfo;
void * arg; /* depends on argInfo */
int val; /* 0 means don't return, just update flag */
+ char * descrip; /* description for autohelp -- may be NULL */
+ char * argDescrip; /* argument description for autohelp */
};
struct poptAlias {
@@ -38,7 +48,15 @@ struct poptAlias {
char ** argv; /* must be free()able */
};
+extern struct poptOption poptHelpOptions[];
+#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
+ 0, "Help options", NULL },
+
typedef struct poptContext_s * poptContext;
+typedef struct poptOption * poptOption;
+
+typedef void (*poptCallbackType)(poptContext con, int key, const char * arg,
+ void * data);
poptContext poptGetContext(char * name, int argc, char ** argv,
const struct poptOption * options, int flags);
@@ -66,5 +84,8 @@ int poptReadDefaultConfig(poptContext con, int useEnv);
int poptParseArgvString(char * s, int * argcPtr, char *** argvPtr);
const char * poptStrerror(const int error);
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute);
+void poptPrintHelp(poptContext con, FILE * f, int flags);
+void poptPrintUsage(poptContext con, FILE * f, int flags);
+void poptSetOtherOptionHelp(poptContext con, const char * text);
#endif
diff --git a/support/popt.c b/support/popt.c
index fbe5a95..58b4a60 100644
--- a/support/popt.c
+++ b/support/popt.c
@@ -13,43 +13,7 @@
#include "findme.h"
#include "popt.h"
-
-struct optionStackEntry {
- int argc;
- char ** argv;
- int next;
- char * nextArg;
- char * nextCharArg;
- struct poptAlias * currAlias;
- int stuffed;
-};
-
-struct execEntry {
- char * longName;
- char shortName;
- char * script;
-};
-
-struct poptContext_s {
- struct optionStackEntry optionStack[POPT_OPTION_DEPTH], * os;
- char ** leftovers;
- int numLeftovers;
- int nextLeftover;
- const struct poptOption * options;
- int restLeftover;
- char * appName;
- struct poptAlias * aliases;
- int numAliases;
- int flags;
- struct execEntry * execs;
- int numExecs;
- char ** finalArgv;
- int finalArgvCount;
- int finalArgvAlloced;
- struct execEntry * doExec;
- char * execPath;
- int execAbsolute;
-};
+#include "poptint.h"
#ifndef HAVE_STRERROR
static char * strerror(int errno) {
@@ -87,6 +51,9 @@ poptContext poptGetContext(char * name, int argc, char ** argv,
con->finalArgv = malloc(sizeof(*con->finalArgv) * (argc * 2));
con->finalArgvAlloced = argc * 2;
con->flags = flags;
+
+ if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
+ con->flags |= POPT_CONTEXT_POSIXMEHARDER;
if (name)
con->appName = strcpy(malloc(strlen(name) + 1), name);
@@ -231,6 +198,42 @@ static void execCommand(poptContext con) {
execvp(argv[0], argv);
}
+static const struct poptOption * findOption(const struct poptOption * table,
+ const char * longName,
+ const char shortName,
+ poptCallbackType * callback,
+ void ** callbackData) {
+ const struct poptOption * opt = table;
+ const struct poptOption * opt2;
+ const struct poptOption * cb = NULL;
+
+ while (opt->longName || opt->shortName || opt->arg) {
+ if (opt->argInfo == POPT_ARG_INCLUDE_TABLE) {
+ opt2 = findOption(opt->arg, longName, shortName, callback,
+ callbackData);
+ if (opt2) return opt2;
+ } else if (opt->argInfo == POPT_ARG_CALLBACK) {
+ cb = opt;
+ } else if (longName && opt->longName &&
+ !strcmp(longName, opt->longName)) {
+ break;
+ } else if (shortName && shortName == opt->shortName) {
+ break;
+ }
+ opt++;
+ }
+
+ if (!opt->longName && !opt->shortName) return NULL;
+ if (cb) {
+ *callback = cb->arg;
+ *callbackData = cb->descrip;
+ } else {
+ *callback = NULL;
+ }
+
+ return opt;
+}
+
/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
int poptGetNextOpt(poptContext con) {
char * optString, * chptr, * localOptString;
@@ -241,6 +244,8 @@ int poptGetNextOpt(poptContext con) {
const struct poptOption * opt = NULL;
int done = 0;
int i;
+ poptCallbackType cb;
+ void * cbData;
while (!done) {
while (!con->os->nextCharArg && con->os->next == con->os->argc
@@ -257,6 +262,8 @@ int poptGetNextOpt(poptContext con) {
if (con->restLeftover || *origOptString != '-') {
con->leftovers[con->numLeftovers++] = origOptString;
+ if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
+ con->restLeftover = 1;
continue;
}
@@ -286,14 +293,8 @@ int poptGetNextOpt(poptContext con) {
*chptr = '\0';
}
- opt = con->options;
- while (opt->longName || opt->shortName) {
- if (opt->longName && !strcmp(optString, opt->longName))
- break;
- opt++;
- }
-
- if (!opt->longName && !opt->shortName) return POPT_ERROR_BADOPT;
+ opt = findOption(con->options, optString, '\0', &cb, &cbData);
+ if (!opt) return POPT_ERROR_BADOPT;
} else
con->os->nextCharArg = origOptString + 1;
}
@@ -311,10 +312,8 @@ int poptGetNextOpt(poptContext con) {
if (handleExec(con, NULL, *origOptString))
continue;
- opt = con->options;
- while ((opt->longName || opt->shortName) &&
- *origOptString != opt->shortName) opt++;
- if (!opt->longName && !opt->shortName) return POPT_ERROR_BADOPT;
+ opt = findOption(con->options, NULL, *origOptString, &cb, &cbData);
+ if (!opt) return POPT_ERROR_BADOPT;
origOptString++;
if (*origOptString)
@@ -369,7 +368,10 @@ int poptGetNextOpt(poptContext con) {
}
}
- if (opt->val) done = 1;
+ if (cb)
+ cb(con, opt->val, con->os->nextArg, cbData);
+ else if (opt->val)
+ done = 1;
if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
@@ -437,6 +439,7 @@ void poptFreeContext(poptContext con) {
free(con->finalArgv);
if (con->appName) free(con->appName);
if (con->aliases) free(con->aliases);
+ if (con->otherHelp) free(con->otherHelp);
free(con);
}
@@ -462,214 +465,6 @@ int poptAddAlias(poptContext con, struct poptAlias newAlias, int flags) {
return 0;
}
-int poptParseArgvString(char * s, int * argcPtr, char *** argvPtr) {
- char * buf = strcpy(alloca(strlen(s) + 1), s);
- char * bufStart = buf;
- char * src, * dst;
- char quote = '\0';
- int argvAlloced = 5;
- char ** argv = malloc(sizeof(*argv) * argvAlloced);
- char ** argv2;
- int argc = 0;
- int i;
-
- src = s;
- dst = buf;
- argv[argc] = buf;
-
- memset(buf, '\0', strlen(s) + 1);
-
- while (*src) {
- if (quote == *src) {
- quote = '\0';
- } else if (quote) {
- if (*src == '\\') {
- src++;
- if (!*src) {
- free(argv);
- return POPT_ERROR_BADQUOTE;
- }
- if (*src != quote) *buf++ = '\\';
- }
- *buf++ = *src;
- } else if (isspace(*src)) {
- if (*argv[argc]) {
- buf++, argc++;
- if (argc == argvAlloced) {
- argvAlloced += 5;
- argv = realloc(argv, sizeof(*argv) * argvAlloced);
- }
- argv[argc] = buf;
- }
- } else switch (*src) {
- case '"':
- case '\'':
- quote = *src;
- break;
- case '\\':
- src++;
- if (!*src) {
- free(argv);
- return POPT_ERROR_BADQUOTE;
- }
- /* fallthrough */
- default:
- *buf++ = *src;
- }
-
- src++;
- }
-
- if (strlen(argv[argc])) {
- argc++, buf++;
- }
-
- dst = malloc(argc * sizeof(*argv) + (buf - bufStart));
- argv2 = (void *) dst;
- dst += argc * sizeof(*argv);
- memcpy(argv2, argv, argc * sizeof(*argv));
- memcpy(dst, bufStart, buf - bufStart);
-
- for (i = 0; i < argc; i++) {
- argv2[i] = dst + (argv[i] - bufStart);
- }
-
- free(argv);
-
- *argvPtr = argv2;
- *argcPtr = argc;
-
- return 0;
-}
-
-static void configLine(poptContext con, char * line) {
- int nameLength = strlen(con->appName);
- char * opt;
- struct poptAlias alias;
- char * entryType;
- char * longName = NULL;
- char shortName = '\0';
-
- if (strncmp(line, con->appName, nameLength)) return;
- line += nameLength;
- if (!*line || !isspace(*line)) return;
- while (*line && isspace(*line)) line++;
- entryType = line;
-
- while (!*line || !isspace(*line)) line++;
- *line++ = '\0';
- while (*line && isspace(*line)) line++;
- if (!*line) return;
- opt = line;
-
- while (!*line || !isspace(*line)) line++;
- *line++ = '\0';
- while (*line && isspace(*line)) line++;
- if (!*line) return;
-
- if (opt[0] == '-' && opt[1] == '-')
- longName = opt + 2;
- else if (opt[0] == '-' && !opt[2])
- shortName = opt[1];
-
- if (!strcmp(entryType, "alias")) {
- if (poptParseArgvString(line, &alias.argc, &alias.argv)) return;
- alias.longName = longName, alias.shortName = shortName;
- poptAddAlias(con, alias, 0);
- } else if (!strcmp(entryType, "exec")) {
- con->execs = realloc(con->execs,
- sizeof(*con->execs) * (con->numExecs + 1));
- if (longName)
- con->execs[con->numExecs].longName = strdup(longName);
- else
- con->execs[con->numExecs].longName = NULL;
-
- con->execs[con->numExecs].shortName = shortName;
- con->execs[con->numExecs].script = strdup(line);
-
- con->numExecs++;
- }
-}
-
-int poptReadConfigFile(poptContext con, char * fn) {
- char * file, * chptr, * end;
- char * buf, * dst;
- int fd, rc;
- int fileLength;
-
- fd = open(fn, O_RDONLY);
- if (fd < 0) {
- if (errno == ENOENT)
- return 0;
- else
- return POPT_ERROR_ERRNO;
- }
-
- fileLength = lseek(fd, 0, SEEK_END);
- lseek(fd, 0, 0);
-
- file = alloca(fileLength + 1);
- if ((fd = read(fd, file, fileLength)) != fileLength) {
- rc = errno;
- close(fd);
- errno = rc;
- return POPT_ERROR_ERRNO;
- }
- close(fd);
-
- dst = buf = alloca(fileLength + 1);
-
- chptr = file;
- end = (file + fileLength);
- while (chptr < end) {
- switch (*chptr) {
- case '\n':
- *dst = '\0';
- dst = buf;
- while (*dst && isspace(*dst)) dst++;
- if (*dst && *dst != '#') {
- configLine(con, dst);
- }
- chptr++;
- break;
- case '\\':
- *dst++ = *chptr++;
- if (chptr < end) {
- if (*chptr == '\n')
- dst--, chptr++;
- /* \ at the end of a line does not insert a \n */
- else
- *dst++ = *chptr++;
- }
- break;
- default:
- *dst++ = *chptr++;
- }
- }
-
- return 0;
-}
-
-int poptReadDefaultConfig(poptContext con, int useEnv) {
- char * fn, * home;
- int rc;
-
- if (!con->appName) return 0;
-
- rc = poptReadConfigFile(con, "/etc/popt");
- if (rc) return rc;
- if (getuid() != geteuid()) return 0;
-
- if ((home = getenv("HOME"))) {
- fn = alloca(strlen(home) + 20);
- sprintf(fn, "%s/.popt", home);
- rc = poptReadConfigFile(con, fn);
- if (rc) return rc;
- }
-
- return 0;
-}
-
char * poptBadOption(poptContext con, int flags) {
struct optionStackEntry * os;
diff --git a/support/popt.h b/support/popt.h
index 850a8cd..50580f7 100644
--- a/support/popt.h
+++ b/support/popt.h
@@ -1,12 +1,19 @@
#ifndef H_POPT
#define H_POPT
+#include <stdio.h> /* for FILE * */
+
#define POPT_OPTION_DEPTH 10
#define POPT_ARG_NONE 0
#define POPT_ARG_STRING 1
#define POPT_ARG_INT 2
#define POPT_ARG_LONG 3
+#define POPT_ARG_INCLUDE_TABLE 4 /* arg points to table */
+#define POPT_ARG_CALLBACK 5 /* table-wide callback... must be
+ set first in table; arg points
+ to callback, descrip points to
+ callback data to pass */
#define POPT_ERROR_NOARG -10
#define POPT_ERROR_BADOPT -11
@@ -22,6 +29,7 @@
/* poptGetContext() flags */
#define POPT_CONTEXT_NO_EXEC (1 << 0) /* ignore exec expansions */
#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /* pay attention to argv[0] */
+#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /* options can't follow args */
struct poptOption {
const char * longName; /* may be NULL */
@@ -29,6 +37,8 @@ struct poptOption {
int argInfo;
void * arg; /* depends on argInfo */
int val; /* 0 means don't return, just update flag */
+ char * descrip; /* description for autohelp -- may be NULL */
+ char * argDescrip; /* argument description for autohelp */
};
struct poptAlias {
@@ -38,7 +48,15 @@ struct poptAlias {
char ** argv; /* must be free()able */
};
+extern struct poptOption poptHelpOptions[];
+#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
+ 0, "Help options", NULL },
+
typedef struct poptContext_s * poptContext;
+typedef struct poptOption * poptOption;
+
+typedef void (*poptCallbackType)(poptContext con, int key, const char * arg,
+ void * data);
poptContext poptGetContext(char * name, int argc, char ** argv,
const struct poptOption * options, int flags);
@@ -66,5 +84,8 @@ int poptReadDefaultConfig(poptContext con, int useEnv);
int poptParseArgvString(char * s, int * argcPtr, char *** argvPtr);
const char * poptStrerror(const int error);
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute);
+void poptPrintHelp(poptContext con, FILE * f, int flags);
+void poptPrintUsage(poptContext con, FILE * f, int flags);
+void poptSetOtherOptionHelp(poptContext con, const char * text);
#endif