--- /dev/null
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+
+#include "popt.h"
+#include "poptint.h"
+
+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);
+ strcpy(fn, home);
+ strcat(fn, "/.popt");
+ rc = poptReadConfigFile(con, fn);
+ if (rc) return rc;
+ }
+
+ return 0;
+}
+
--- /dev/null
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "popt.h"
+#include "poptint.h"
+
+static void displayArgs(poptContext con, int key, const char * arg,
+ void * data) {
+ if (key == '?')
+ poptPrintHelp(con, stderr, 0);
+ else
+ poptPrintUsage(con, stderr, 0);
+ exit(0);
+}
+
+struct poptOption poptHelpOptions[] = {
+ { NULL, '\0', POPT_ARG_CALLBACK, &displayArgs, '\0', NULL },
+ { "help", '?', 0, NULL, '?', "Show this help message" },
+ { "usage", '\0', 0, NULL, 'u', "Display brief usage message" },
+ { NULL, '\0', 0, NULL, 0 }
+} ;
+
+static void singleOptionHelp(FILE * f, int maxLeftCol,
+ const struct poptOption * opt) {
+ int indentLength = maxLeftCol + 5;
+ int lineLength = 79 - indentLength;
+ const char * help = opt->descrip;
+ int helpLength;
+ const char * ch;
+ char format[10];
+ char * left = alloca(maxLeftCol + 1);
+
+ *left = '\0';
+ if (opt->longName && opt->shortName)
+ sprintf(left, "-%c, --%s", opt->shortName, opt->longName);
+ else if (opt->shortName)
+ sprintf(left, "-%c", opt->shortName);
+ else if (opt->longName)
+ sprintf(left, "--%s", opt->longName);
+ if (!*left) return ;
+ if (opt->argDescrip) {
+ strcat(left, "=");
+ strcat(left, opt->argDescrip);
+ }
+
+ if (help)
+ fprintf(f," %-*s ", maxLeftCol, left);
+ else {
+ fprintf(f," %s\n", left);
+ return;
+ }
+
+ helpLength = strlen(help);
+ while (helpLength > lineLength) {
+ ch = help + lineLength - 1;
+ while (ch > help && !isspace(*ch)) ch--;
+ if (ch == help) break; /* give up */
+ while (ch > (help + 1) && isspace(*ch)) ch--;
+ ch++;
+
+ sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
+ fprintf(f, format, help, " ");
+ help = ch;
+ while (isspace(*help) && *help) help++;
+ helpLength = strlen(help);
+ }
+
+ if (helpLength) fprintf(f, "%s\n", help);
+}
+
+static int maxArgWidth(const struct poptOption * opt) {
+ int max = 0;
+ int this;
+
+ while (opt->longName || opt->shortName || opt->arg) {
+ if (opt->argInfo == POPT_ARG_INCLUDE_TABLE) {
+ this = maxArgWidth(opt->arg);
+ } else {
+ this = opt->shortName ? 2 : 0;
+ if (opt->longName) {
+ if (this) this += 2;
+ this += strlen(opt->longName) + 2;
+ }
+
+ if (opt->argDescrip)
+ this += strlen(opt->argDescrip) + 1;
+ }
+
+ if (this > max) max = this;
+
+ opt++;
+ }
+
+ return max;
+}
+
+static void singleTableHelp(FILE * f, const struct poptOption * table,
+ int left) {
+ const struct poptOption * opt;
+
+ opt = table;
+ while (opt->longName || opt->shortName || opt->arg) {
+ if (opt->longName || opt->shortName)
+ singleOptionHelp(f, left, opt);
+ opt++;
+ }
+
+ opt = table;
+ while (opt->longName || opt->shortName || opt->arg) {
+ if (opt->argInfo == POPT_ARG_INCLUDE_TABLE) {
+ if (opt->descrip)
+ fprintf(f, "\n%s\n", opt->descrip);
+ singleTableHelp(f, opt->arg, left);
+ }
+ opt++;
+ }
+}
+
+static int showHelpIntro(poptContext con, FILE * f) {
+ int len = 6;
+ char * fn;
+
+ fprintf(f, "Usage:");
+ if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
+ fn = con->optionStack->argv[0];
+ if (strchr(fn, '/')) fn = strchr(fn, '/') + 1;
+ fprintf(f, " %s", fn);
+ len += strlen(fn) + 1;
+ }
+
+ return len;
+}
+
+void poptPrintHelp(poptContext con, FILE * f, int flags) {
+ int leftColWidth;
+
+ showHelpIntro(con, f);
+ if (con->otherHelp)
+ fprintf(f, " %s\n", con->otherHelp);
+ else
+ fprintf(f, " [OPTION...]\n");
+
+ leftColWidth = maxArgWidth(con->options);
+ singleTableHelp(f, con->options, leftColWidth);
+}
+
+static int singleOptionUsage(FILE * f, int cursor,
+ const struct poptOption * opt) {
+ int len = 3;
+ char shortStr[2];
+ const char * item = shortStr;
+
+ if (opt->shortName) {
+ if (!opt->argInfo) return cursor; /* we did these already */
+ len++;
+ *shortStr = opt->shortName;
+ shortStr[1] = '\0';
+ } else if (opt->longName) {
+ len += 1 + strlen(opt->longName);
+ item = opt->longName;
+ }
+
+ if (len == 3) return cursor;
+
+ if (opt->argDescrip)
+ len += strlen(opt->argDescrip) + 1;
+
+ if ((cursor + len) > 79) {
+ fprintf(f, "\n ");
+ cursor = 7;
+ }
+
+ fprintf(f, " [-%s%s%s%s]", opt->shortName ? "" : "-", item,
+ opt->argDescrip ? "=" : "",
+ opt->argDescrip ? opt->argDescrip : "");
+
+ return cursor + len + 1;
+}
+
+int singleTableUsage(FILE * f, int cursor, const struct poptOption * table) {
+ const struct poptOption * opt;
+
+ opt = table;
+ while (opt->longName || opt->shortName || opt->arg) {
+ if (opt->longName || opt->shortName)
+ cursor = singleOptionUsage(f, cursor, opt);
+ else if (opt->argInfo == POPT_ARG_INCLUDE_TABLE)
+ cursor = singleTableUsage(f, cursor, opt->arg);
+ opt++;
+ }
+
+ return cursor;
+}
+
+static int showShortOptions(const struct poptOption * opt, FILE * f,
+ char * str) {
+ char s[300]; /* this is larger then the ascii set, so
+ it should do just fine */
+
+ if (!str) {
+ str = s;
+ memset(str, 0, sizeof(str));
+ }
+
+ while (opt->longName || opt->shortName || opt->arg) {
+ if (opt->shortName && !opt->argInfo)
+ str[strlen(str)] = opt->shortName;
+ else if (opt->argInfo == POPT_ARG_INCLUDE_TABLE)
+ showShortOptions(opt->arg, f, str);
+
+ opt++;
+ }
+
+ if (s != str || !*s)
+ return 0;
+
+ fprintf(f, " [-%s]", s);
+ return strlen(s) + 4;
+}
+
+void poptPrintUsage(poptContext con, FILE * f, int flags) {
+ int cursor;
+
+ cursor = showHelpIntro(con, f);
+ cursor += showShortOptions(con->options, f, NULL);
+ singleTableUsage(f, cursor, con->options);
+
+ if (con->otherHelp) {
+ cursor += strlen(con->otherHelp) + 1;
+ if (cursor > 79) fprintf(f, "\n ");
+ fprintf(f, " %s", con->otherHelp);
+ }
+
+ fprintf(f, "\n");
+}
+
+void poptSetOtherOptionHelp(poptContext con, const char * text) {
+ if (con->otherHelp) free(con->otherHelp);
+ con->otherHelp = strdup(text);
+}