updated the .TP cleanup for coherency in the key description pages.
[midnight-commander.git] / src / popt.c
blob5260e58223d08737b7be9f567dc35d97312d0a72
1 /* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
2 file accompanying popt source distributions, available from
3 ftp://ftp.redhat.com/pub/code/popt */
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif
9 #include "poptalloca.h"
10 #include <errno.h>
11 #include <ctype.h>
12 #include <limits.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #ifdef HAVE_UNISTD_H
17 # include <unistd.h>
18 #endif
20 #include "findme.h"
21 #include "popt.h"
22 #include "poptint.h"
24 #ifndef HAVE_STRERROR
25 static char * strerror(int errno) {
26 extern int sys_nerr;
27 extern char * sys_errlist[];
29 if ((0 <= errno) && (errno < sys_nerr))
30 return sys_errlist[errno];
31 else
32 return POPT_("unknown errno");
34 #endif
36 void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
37 if (con->execPath) free(con->execPath);
38 con->execPath = strdup(path);
39 con->execAbsolute = allowAbsolute;
42 static void invokeCallbacks(poptContext con, const struct poptOption * table,
43 int post) {
44 const struct poptOption * opt = table;
45 poptCallbackType cb;
47 while (opt->longName || opt->shortName || opt->arg) {
48 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
49 invokeCallbacks(con, opt->arg, post);
50 } else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
51 ((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
52 ( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
53 cb = (poptCallbackType)opt->arg;
54 cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
55 NULL, NULL, opt->descrip);
57 opt++;
61 poptContext poptGetContext(char * name, int argc, char ** argv,
62 const struct poptOption * options, int flags) {
63 poptContext con = malloc(sizeof(*con));
65 memset(con, 0, sizeof(*con));
67 con->os = con->optionStack;
68 con->os->argc = argc;
69 con->os->argv = argv;
71 if (!(flags & POPT_CONTEXT_KEEP_FIRST))
72 con->os->next = 1; /* skip argv[0] */
74 con->leftovers = malloc(sizeof(char *) * (argc + 1));
75 con->options = options;
76 con->finalArgv = malloc(sizeof(*con->finalArgv) * (argc * 2));
77 con->finalArgvAlloced = argc * 2;
78 con->flags = flags;
79 con->execAbsolute = 1;
81 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
82 con->flags |= POPT_CONTEXT_POSIXMEHARDER;
84 if (name)
85 con->appName = strcpy(malloc(strlen(name) + 1), name);
87 invokeCallbacks(con, con->options, 0);
89 return con;
92 void poptResetContext(poptContext con) {
93 int i;
95 con->os = con->optionStack;
96 con->os->currAlias = NULL;
97 con->os->nextCharArg = NULL;
98 con->os->nextArg = NULL;
99 con->os->next = 1; /* skip argv[0] */
101 con->numLeftovers = 0;
102 con->nextLeftover = 0;
103 con->restLeftover = 0;
104 con->doExec = NULL;
106 for (i = 0; i < con->finalArgvCount; i++)
107 free(con->finalArgv[i]);
109 con->finalArgvCount = 0;
112 /* Only one of longName, shortName may be set at a time */
113 static int handleExec(poptContext con, char * longName, char shortName) {
114 int i;
116 i = con->numExecs - 1;
117 if (longName) {
118 while (i >= 0 && (!con->execs[i].longName ||
119 strcmp(con->execs[i].longName, longName))) i--;
120 } else {
121 while (i >= 0 &&
122 con->execs[i].shortName != shortName) i--;
125 if (i < 0) return 0;
127 if (con->flags & POPT_CONTEXT_NO_EXEC)
128 return 1;
130 if (!con->doExec) {
131 con->doExec = con->execs + i;
132 return 1;
135 /* We already have an exec to do; remember this option for next
136 time 'round */
137 if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
138 con->finalArgvAlloced += 10;
139 con->finalArgv = realloc(con->finalArgv,
140 sizeof(*con->finalArgv) * con->finalArgvAlloced);
143 i = con->finalArgvCount++;
144 con->finalArgv[i] = malloc((longName ? strlen(longName) : 0) + 3);
145 if (longName)
146 sprintf(con->finalArgv[i], "--%s", longName);
147 else
148 sprintf(con->finalArgv[i], "-%c", shortName);
150 return 1;
153 /* Only one of longName, shortName may be set at a time */
154 static int handleAlias(poptContext con, char * longName, char shortName,
155 char * nextCharArg) {
156 int i;
158 if (con->os->currAlias && con->os->currAlias->longName && longName &&
159 !strcmp(con->os->currAlias->longName, longName))
160 return 0;
161 if (con->os->currAlias && shortName &&
162 shortName == con->os->currAlias->shortName)
163 return 0;
165 i = con->numAliases - 1;
166 if (longName) {
167 while (i >= 0 && (!con->aliases[i].longName ||
168 strcmp(con->aliases[i].longName, longName))) i--;
169 } else {
170 while (i >= 0 &&
171 con->aliases[i].shortName != shortName) i--;
174 if (i < 0) return 0;
176 if ((con->os - con->optionStack + 1)
177 == POPT_OPTION_DEPTH)
178 return POPT_ERROR_OPTSTOODEEP;
180 if (nextCharArg && *nextCharArg)
181 con->os->nextCharArg = nextCharArg;
183 con->os++;
184 con->os->next = 0;
185 con->os->stuffed = 0;
186 con->os->nextArg = con->os->nextCharArg = NULL;
187 con->os->currAlias = con->aliases + i;
188 con->os->argc = con->os->currAlias->argc;
189 con->os->argv = con->os->currAlias->argv;
191 return 1;
194 static void execCommand(poptContext con) {
195 #if 0
196 char ** argv;
197 int pos = 0;
198 char * script = con->doExec->script;
200 argv = malloc(sizeof(*argv) *
201 (6 + con->numLeftovers + con->finalArgvCount));
203 if (!con->execAbsolute && strchr(script, '/')) return;
205 if (!strchr(script, '/') && con->execPath) {
206 argv[pos] = alloca(strlen(con->execPath) + strlen(script) + 2);
207 sprintf(argv[pos], "%s/%s", con->execPath, script);
208 } else {
209 argv[pos] = script;
211 pos++;
213 argv[pos] = findProgramPath(con->os->argv[0]);
214 if (argv[pos]) pos++;
215 argv[pos++] = ";";
217 memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
218 pos += con->finalArgvCount;
220 if (con->numLeftovers) {
221 argv[pos++] = "--";
222 memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
223 pos += con->numLeftovers;
226 argv[pos++] = NULL;
228 execvp(argv[0], argv);
229 #else
230 abort();
231 #endif
234 static const struct poptOption * findOption(const struct poptOption * table,
235 const char * longName,
236 char shortName,
237 poptCallbackType * callback,
238 void ** callbackData,
239 int singleDash) {
240 const struct poptOption * opt = table;
241 const struct poptOption * opt2;
242 const struct poptOption * cb = NULL;
244 /* This happens when a single - is given */
245 if (singleDash && !shortName && !*longName)
246 shortName = '-';
248 while (opt->longName || opt->shortName || opt->arg) {
249 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
250 opt2 = findOption(opt->arg, longName, shortName, callback,
251 callbackData, singleDash);
252 if (opt2) {
253 if (*callback && !*callbackData)
254 *callbackData = opt->descrip;
255 return opt2;
257 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
258 cb = opt;
259 } else if (longName && opt->longName &&
260 (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
261 !strcmp(longName, opt->longName)) {
262 break;
263 } else if (shortName && shortName == opt->shortName) {
264 break;
266 opt++;
269 if (!opt->longName && !opt->shortName) return NULL;
270 *callbackData = NULL;
271 *callback = NULL;
272 if (cb) {
273 *callback = (poptCallbackType)cb->arg;
274 if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
275 *callbackData = cb->descrip;
278 return opt;
281 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
282 int poptGetNextOpt(poptContext con) {
283 char * optString, * chptr, * localOptString;
284 char * longArg = NULL;
285 char * origOptString;
286 long aLong;
287 char * end;
288 const struct poptOption * opt = NULL;
289 int done = 0;
290 int i;
291 poptCallbackType cb;
292 void * cbData;
293 int singleDash;
295 while (!done) {
296 while (!con->os->nextCharArg && con->os->next == con->os->argc
297 && con->os > con->optionStack)
298 con->os--;
299 if (!con->os->nextCharArg && con->os->next == con->os->argc) {
300 invokeCallbacks(con, con->options, 1);
301 if (con->doExec) execCommand(con);
302 return -1;
305 if (!con->os->nextCharArg) {
307 origOptString = con->os->argv[con->os->next++];
309 if (con->restLeftover || *origOptString != '-') {
310 con->leftovers[con->numLeftovers++] = origOptString;
311 if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
312 con->restLeftover = 1;
313 continue;
316 /* Make a copy we can hack at */
317 localOptString = optString =
318 strcpy(alloca(strlen(origOptString) + 1),
319 origOptString);
321 if (!optString[0])
322 return POPT_ERROR_BADOPT;
324 if (optString[1] == '-' && !optString[2]) {
325 con->restLeftover = 1;
326 continue;
327 } else {
328 optString++;
329 if (*optString == '-')
330 singleDash = 0, optString++;
331 else
332 singleDash = 1;
334 if (handleAlias(con, optString, '\0', NULL))
335 continue;
336 if (handleExec(con, optString, '\0'))
337 continue;
339 chptr = optString;
340 while (*chptr && *chptr != '=') chptr++;
341 if (*chptr == '=') {
342 longArg = origOptString + (chptr - localOptString) + 1;
343 *chptr = '\0';
346 opt = findOption(con->options, optString, '\0', &cb, &cbData,
347 singleDash);
348 if (!opt && !singleDash) return POPT_ERROR_BADOPT;
351 if (!opt)
352 con->os->nextCharArg = origOptString + 1;
355 if (con->os->nextCharArg) {
356 origOptString = con->os->nextCharArg;
358 con->os->nextCharArg = NULL;
360 if (handleAlias(con, NULL, *origOptString,
361 origOptString + 1)) {
362 origOptString++;
363 continue;
365 if (handleExec(con, NULL, *origOptString))
366 continue;
368 opt = findOption(con->options, NULL, *origOptString, &cb,
369 &cbData, 0);
370 if (!opt) return POPT_ERROR_BADOPT;
372 origOptString++;
373 if (*origOptString)
374 con->os->nextCharArg = origOptString;
377 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
378 *((int *)opt->arg) = 1;
379 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
380 if (opt->arg) *((int *) opt->arg) = opt->val;
381 } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
382 if (longArg) {
383 con->os->nextArg = longArg;
384 } else if (con->os->nextCharArg) {
385 con->os->nextArg = con->os->nextCharArg;
386 con->os->nextCharArg = NULL;
387 } else {
388 while (con->os->next == con->os->argc &&
389 con->os > con->optionStack)
390 con->os--;
391 if (con->os->next == con->os->argc)
392 return POPT_ERROR_NOARG;
394 con->os->nextArg = con->os->argv[con->os->next++];
397 if (opt->arg) {
398 switch (opt->argInfo & POPT_ARG_MASK) {
399 case POPT_ARG_STRING:
400 *((char **) opt->arg) = con->os->nextArg;
401 break;
403 case POPT_ARG_INT:
404 case POPT_ARG_LONG:
405 aLong = strtol(con->os->nextArg, &end, 0);
406 if (!(end && *end == '\0'))
407 return POPT_ERROR_BADNUMBER;
409 if (aLong == LONG_MIN || aLong == LONG_MAX)
410 return POPT_ERROR_OVERFLOW;
411 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
412 *((long *) opt->arg) = aLong;
413 } else {
414 if (aLong > INT_MAX || aLong < INT_MIN)
415 return POPT_ERROR_OVERFLOW;
416 *((int *) opt->arg) =aLong;
418 break;
420 default:
421 fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
422 opt->argInfo & POPT_ARG_MASK);
423 exit(1);
428 if (cb)
429 cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
430 else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
431 done = 1;
433 if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
434 con->finalArgvAlloced += 10;
435 con->finalArgv = realloc(con->finalArgv,
436 sizeof(*con->finalArgv) * con->finalArgvAlloced);
439 i = con->finalArgvCount++;
440 con->finalArgv[i] =
441 malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
442 if (opt->longName)
443 sprintf(con->finalArgv[i], "--%s", opt->longName);
444 else
445 sprintf(con->finalArgv[i], "-%c", opt->shortName);
447 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
448 && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
449 con->finalArgv[con->finalArgvCount++] = strdup(con->os->nextArg);
452 return opt->val;
455 char * poptGetOptArg(poptContext con) {
456 char * ret = con->os->nextArg;
457 con->os->nextArg = NULL;
458 return ret;
461 char * poptGetArg(poptContext con) {
462 if (con->numLeftovers == con->nextLeftover) return NULL;
463 return (con->leftovers[con->nextLeftover++]);
466 char * poptPeekArg(poptContext con) {
467 if (con->numLeftovers == con->nextLeftover) return NULL;
468 return (con->leftovers[con->nextLeftover]);
471 char ** poptGetArgs(poptContext con) {
472 if (con->numLeftovers == con->nextLeftover) return NULL;
474 /* some apps like [like RPM ;-) ] need this NULL terminated */
475 con->leftovers[con->numLeftovers] = NULL;
477 return (con->leftovers + con->nextLeftover);
480 void poptFreeContext(poptContext con) {
481 int i;
483 for (i = 0; i < con->numAliases; i++) {
484 if (con->aliases[i].longName) free(con->aliases[i].longName);
485 free(con->aliases[i].argv);
488 for (i = 0; i < con->numExecs; i++) {
489 if (con->execs[i].longName) free(con->execs[i].longName);
490 free(con->execs[i].script);
493 for (i = 0; i < con->finalArgvCount; i++)
494 free(con->finalArgv[i]);
496 free(con->leftovers);
497 free(con->finalArgv);
498 if (con->appName) free(con->appName);
499 if (con->aliases) free(con->aliases);
500 if (con->otherHelp) free(con->otherHelp);
501 if (con->execPath) free(con->execPath);
502 free(con);
505 int poptAddAlias(poptContext con, struct poptAlias newAlias, int flags) {
506 int aliasNum = con->numAliases++;
507 struct poptAlias * alias;
509 /* SunOS won't realloc(NULL, ...) */
510 if (!con->aliases)
511 con->aliases = malloc(sizeof(newAlias) * con->numAliases);
512 else
513 con->aliases = realloc(con->aliases,
514 sizeof(newAlias) * con->numAliases);
515 alias = con->aliases + aliasNum;
517 *alias = newAlias;
518 if (alias->longName)
519 alias->longName = strcpy(malloc(strlen(alias->longName) + 1),
520 alias->longName);
521 else
522 alias->longName = NULL;
524 return 0;
527 char * poptBadOption(poptContext con, int flags) {
528 struct optionStackEntry * os;
530 if (flags & POPT_BADOPTION_NOALIAS)
531 os = con->optionStack;
532 else
533 os = con->os;
535 return os->argv[os->next - 1];
538 #define POPT_ERROR_NOARG -10
539 #define POPT_ERROR_BADOPT -11
540 #define POPT_ERROR_OPTSTOODEEP -13
541 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
542 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
544 const char * poptStrerror(const int error) {
545 switch (error) {
546 case POPT_ERROR_NOARG:
547 return _("missing argument");
548 case POPT_ERROR_BADOPT:
549 return _("unknown option");
550 case POPT_ERROR_OPTSTOODEEP:
551 return POPT_("aliases nested too deeply");
552 case POPT_ERROR_BADQUOTE:
553 return POPT_("error in parameter quoting");
554 case POPT_ERROR_BADNUMBER:
555 return _("invalid numeric value");
556 case POPT_ERROR_OVERFLOW:
557 return POPT_("number too large or too small");
558 case POPT_ERROR_ERRNO:
559 return strerror(errno);
560 default:
561 return POPT_("unknown error");
565 int poptStuffArgs(poptContext con, char ** argv) {
566 int i;
568 if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
569 return POPT_ERROR_OPTSTOODEEP;
571 for (i = 0; argv[i]; i++);
573 con->os++;
574 con->os->next = 0;
575 con->os->nextArg = con->os->nextCharArg = NULL;
576 con->os->currAlias = NULL;
577 con->os->argc = i;
578 con->os->argv = argv;
579 con->os->stuffed = 1;
581 return 0;
584 const char * poptGetInvocationName(poptContext con) {
585 return con->os->argv[0];