home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / mc454src.zip / mc-4.5.4.src / mc-4.5.4 / src / popt.c < prev    next >
C/C++ Source or Header  |  1999-01-04  |  15KB  |  578 lines

  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 */
  4.  
  5. #ifdef HAVE_CONFIG_H
  6. #include "config.h"
  7. #endif
  8.  
  9. #include <errno.h>
  10. #include <ctype.h>
  11. #include <fcntl.h>
  12. #include <limits.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <unistd.h>
  17.  
  18. #if HAVE_ALLOCA_H
  19. # include <alloca.h>
  20. #endif
  21.  
  22. #include "findme.h"
  23. #include "popt.h"
  24. #include "poptint.h"
  25.  
  26. #ifndef HAVE_STRERROR
  27. static char * strerror(int errno) {
  28.     extern int sys_nerr;
  29.     extern char * sys_errlist[];
  30.  
  31.     if ((0 <= errno) && (errno < sys_nerr))
  32.     return sys_errlist[errno];
  33.     else
  34.     return POPT_("unknown errno");
  35. }
  36. #endif
  37.  
  38. void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
  39.     if (con->execPath) free(con->execPath);
  40.     con->execPath = strdup(path);
  41.     con->execAbsolute = allowAbsolute;
  42. }
  43.  
  44. static void invokeCallbacks(poptContext con,
  45.                 enum poptCallbackReason reason,
  46.                 const struct poptOption * table,
  47.                 int post) {
  48.     const struct poptOption * opt = table;
  49.     poptCallbackType cb;
  50.     
  51.     while (opt->longName || opt->shortName || opt->arg) {
  52.     if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
  53.         invokeCallbacks(con, 0, opt->arg, post);
  54.     } else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
  55.            ((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
  56.             ( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
  57.         cb = opt->arg;
  58.         cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
  59.            NULL, NULL, opt->descrip);
  60.     }
  61.     opt++;
  62.     }
  63. }
  64.  
  65. poptContext poptGetContext(char * name, int argc, char ** argv, 
  66.                const struct poptOption * options, int flags) {
  67.     poptContext con = malloc(sizeof(*con));
  68.  
  69.     memset(con, 0, sizeof(*con));
  70.  
  71.     con->os = con->optionStack;
  72.     con->os->argc = argc;
  73.     con->os->argv = argv;
  74.  
  75.     if (!(flags & POPT_CONTEXT_KEEP_FIRST))
  76.     con->os->next = 1;            /* skip argv[0] */
  77.  
  78.     con->leftovers = malloc(sizeof(char *) * (argc + 1));
  79.     con->options = options;
  80.     con->finalArgv = malloc(sizeof(*con->finalArgv) * (argc * 2));
  81.     con->finalArgvAlloced = argc * 2;
  82.     con->flags = flags;
  83.     con->execAbsolute = 1;
  84.  
  85.     if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
  86.     con->flags |= POPT_CONTEXT_POSIXMEHARDER;
  87.     
  88.     if (name)
  89.     con->appName = strcpy(malloc(strlen(name) + 1), name);
  90.  
  91.     invokeCallbacks(con, 0, con->options, 0);
  92.  
  93.     return con;
  94. }
  95.  
  96. void poptResetContext(poptContext con) {
  97.     con->os = con->optionStack;
  98.     con->os->currAlias = NULL;
  99.     con->os->nextCharArg = NULL;
  100.     con->os->nextArg = NULL;
  101.     con->os->next = 1;            /* skip argv[0] */
  102.  
  103.     con->numLeftovers = 0;
  104.     con->nextLeftover = 0;
  105.     con->restLeftover = 0;
  106.     con->doExec = NULL;
  107.     con->finalArgvCount = 0;
  108. }
  109.  
  110. /* Only one of longName, shortName may be set at a time */
  111. static int handleExec(poptContext con, char * longName, char shortName) {
  112.     int i;
  113.  
  114.     i = con->numExecs - 1;
  115.     if (longName) {
  116.     while (i >= 0 && (!con->execs[i].longName ||
  117.         strcmp(con->execs[i].longName, longName))) i--;
  118.     } else {
  119.     while (i >= 0 &&
  120.         con->execs[i].shortName != shortName) i--;
  121.     }
  122.  
  123.     if (i < 0) return 0;
  124.  
  125.     if (con->flags & POPT_CONTEXT_NO_EXEC)
  126.     return 1;
  127.  
  128.     if (!con->doExec) {
  129.     con->doExec = con->execs + i;
  130.     return 1;
  131.     }
  132.  
  133.     /* We already have an exec to do; remember this option for next
  134.        time 'round */
  135.     if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
  136.     con->finalArgvAlloced += 10;
  137.     con->finalArgv = realloc(con->finalArgv,
  138.             sizeof(*con->finalArgv) * con->finalArgvAlloced);
  139.     }
  140.  
  141.     i = con->finalArgvCount++;
  142.     con->finalArgv[i] = malloc((longName ? strlen(longName) : 0) + 3);
  143.     if (longName)
  144.     sprintf(con->finalArgv[i], "--%s", longName);
  145.     else 
  146.     sprintf(con->finalArgv[i], "-%c", shortName);
  147.  
  148.     return 1;
  149. }
  150.  
  151. /* Only one of longName, shortName may be set at a time */
  152. static int handleAlias(poptContext con, char * longName, char shortName,
  153.                char * nextCharArg) {
  154.     int i;
  155.  
  156.     if (con->os->currAlias && con->os->currAlias->longName && longName &&
  157.     !strcmp(con->os->currAlias->longName, longName)) 
  158.     return 0;
  159.     if (con->os->currAlias && shortName == con->os->currAlias->shortName)
  160.     return 0;
  161.  
  162.     i = con->numAliases - 1;
  163.     if (longName) {
  164.     while (i >= 0 && (!con->aliases[i].longName ||
  165.         strcmp(con->aliases[i].longName, longName))) i--;
  166.     } else {
  167.     while (i >= 0 &&
  168.         con->aliases[i].shortName != shortName) i--;
  169.     }
  170.  
  171.     if (i < 0) return 0;
  172.  
  173.     if ((con->os - con->optionStack + 1) 
  174.         == POPT_OPTION_DEPTH)
  175.     return POPT_ERROR_OPTSTOODEEP;
  176.  
  177.     if (nextCharArg && *nextCharArg)
  178.     con->os->nextCharArg = nextCharArg;
  179.  
  180.     con->os++;
  181.     con->os->next = 0;
  182.     con->os->stuffed = 0;
  183.     con->os->nextArg = con->os->nextCharArg = NULL;
  184.     con->os->currAlias = con->aliases + i;
  185.     con->os->argc = con->os->currAlias->argc;
  186.     con->os->argv = con->os->currAlias->argv;
  187.  
  188.     return 1;
  189. }
  190.  
  191. static void execCommand(poptContext con) {
  192.     char ** argv;
  193.     int pos = 0;
  194.     char * script = con->doExec->script;
  195.  
  196.     argv = malloc(sizeof(*argv) * 
  197.             (6 + con->numLeftovers + con->finalArgvCount));
  198.  
  199.     if (!con->execAbsolute && strchr(script, '/')) return;
  200.  
  201.     if (!strchr(script, '/') && con->execPath) {
  202.     argv[pos] = alloca(strlen(con->execPath) + strlen(script) + 2);
  203.     sprintf(argv[pos], "%s/%s", con->execPath, script);
  204.     } else {
  205.     argv[pos] = script;
  206.     }
  207.     pos++;
  208.  
  209.     argv[pos] = findProgramPath(con->os->argv[0]);
  210.     if (argv[pos]) pos++;
  211.     argv[pos++] = ";";
  212.  
  213.     memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
  214.     pos += con->finalArgvCount;
  215.  
  216.     if (con->numLeftovers) {
  217.     argv[pos++] = "--";
  218.     memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
  219.     pos += con->numLeftovers;
  220.     }
  221.  
  222.     argv[pos++] = NULL;
  223.  
  224. #ifdef __hpux
  225.     setresuid(getuid(), getuid(),-1);
  226. #else
  227.     setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
  228. #endif
  229.  
  230.     execvp(argv[0], argv);
  231. }
  232.  
  233. static const struct poptOption * findOption(const struct poptOption * table,
  234.                         const char * longName,
  235.                         const char shortName,
  236.                         poptCallbackType * callback,
  237.                         void ** callbackData,
  238.                         int singleDash) {
  239.     const struct poptOption * opt = table;
  240.     const struct poptOption * opt2;
  241.     const struct poptOption * cb = NULL;
  242.  
  243.     while (opt->longName || opt->shortName || opt->arg) {
  244.     if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
  245.         opt2 = findOption(opt->arg, longName, shortName, callback, 
  246.                   callbackData, singleDash);
  247.         if (opt2) {
  248.         if (*callback && !*callbackData)
  249.             *callbackData = opt->descrip;
  250.         return opt2;
  251.         }
  252.     } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
  253.         cb = opt;
  254.     } else if (longName && opt->longName && 
  255.            (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
  256.            !strcmp(longName, opt->longName)) {
  257.         break;
  258.     } else if (shortName && shortName == opt->shortName) {
  259.         break;
  260.     }
  261.     opt++;
  262.     }
  263.  
  264.     if (!opt->longName && !opt->shortName) return NULL;
  265.     *callbackData = NULL;
  266.     *callback = NULL;
  267.     if (cb) {
  268.     *callback = cb->arg;
  269.     if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
  270.         *callbackData = cb->descrip;
  271.     }
  272.  
  273.     return opt;
  274. }
  275.  
  276. /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
  277. int poptGetNextOpt(poptContext con) {
  278.     char * optString, * chptr, * localOptString;
  279.     char * longArg = NULL;
  280.     char * origOptString;
  281.     long aLong;
  282.     char * end;
  283.     const struct poptOption * opt = NULL;
  284.     int done = 0;
  285.     int i;
  286.     poptCallbackType cb;
  287.     void * cbData;
  288.     int singleDash;
  289.  
  290.     while (!done) {
  291.     while (!con->os->nextCharArg && con->os->next == con->os->argc 
  292.         && con->os > con->optionStack)
  293.         con->os--;
  294.     if (!con->os->nextCharArg && con->os->next == con->os->argc) {
  295.         invokeCallbacks(con, 0, con->options, 1);
  296.         if (con->doExec) execCommand(con);
  297.         return -1;
  298.     }
  299.  
  300.     if (!con->os->nextCharArg) {
  301.         
  302.         origOptString = con->os->argv[con->os->next++];
  303.  
  304.         if (con->restLeftover || *origOptString != '-') {
  305.         con->leftovers[con->numLeftovers++] = origOptString;
  306.         if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
  307.             con->restLeftover = 1;
  308.         continue;
  309.         }
  310.  
  311.         /* Make a copy we can hack at */
  312.         localOptString = optString = 
  313.             strcpy(alloca(strlen(origOptString) + 1), 
  314.             origOptString);
  315.  
  316.         if (!optString[0])
  317.         return POPT_ERROR_BADOPT;
  318.  
  319.         if (optString[1] == '-' && !optString[2]) {
  320.         con->restLeftover = 1;
  321.         continue;
  322.         } else {
  323.         optString++;
  324.         if (*optString == '-')
  325.             singleDash = 0, optString++;
  326.         else
  327.             singleDash = 1;
  328.  
  329.         if (handleAlias(con, optString, '\0', NULL))
  330.             continue;
  331.         if (handleExec(con, optString, '\0'))
  332.             continue;
  333.  
  334.         chptr = optString;
  335.         while (*chptr && *chptr != '=') chptr++;
  336.         if (*chptr == '=') {
  337.             longArg = origOptString + (chptr - localOptString) + 1;
  338.             *chptr = '\0';
  339.         }
  340.  
  341.         opt = findOption(con->options, optString, '\0', &cb, &cbData,
  342.                  singleDash);
  343.         if (!opt && !singleDash) return POPT_ERROR_BADOPT;
  344.         }
  345.  
  346.         if (!opt)
  347.         con->os->nextCharArg = origOptString + 1;
  348.     }
  349.  
  350.     if (con->os->nextCharArg) {
  351.         origOptString = con->os->nextCharArg;
  352.  
  353.         con->os->nextCharArg = NULL;
  354.  
  355.         if (handleAlias(con, NULL, *origOptString,
  356.                 origOptString + 1)) {
  357.         origOptString++;
  358.         continue;
  359.         }
  360.         if (handleExec(con, NULL, *origOptString))
  361.         continue;
  362.  
  363.         opt = findOption(con->options, NULL, *origOptString, &cb, 
  364.                  &cbData, 0);
  365.         if (!opt) return POPT_ERROR_BADOPT;
  366.  
  367.         origOptString++;
  368.         if (*origOptString)
  369.         con->os->nextCharArg = origOptString;
  370.     }
  371.  
  372.     if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) 
  373.         *((int *)opt->arg) = 1;
  374.     else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
  375.         if (longArg) {
  376.         con->os->nextArg = longArg;
  377.         } else if (con->os->nextCharArg) {
  378.         con->os->nextArg = con->os->nextCharArg;
  379.         con->os->nextCharArg = NULL;
  380.         } else { 
  381.         while (con->os->next == con->os->argc && 
  382.                con->os > con->optionStack)
  383.             con->os--;
  384.         if (con->os->next == con->os->argc)
  385.             return POPT_ERROR_NOARG;
  386.  
  387.         con->os->nextArg = con->os->argv[con->os->next++];
  388.         }
  389.  
  390.         if (opt->arg) {
  391.         switch (opt->argInfo & POPT_ARG_MASK) {
  392.           case POPT_ARG_STRING:
  393.             *((char **) opt->arg) = con->os->nextArg;
  394.             break;
  395.  
  396.           case POPT_ARG_INT:
  397.           case POPT_ARG_LONG:
  398.             aLong = strtol(con->os->nextArg, &end, 0);
  399.             if (*end) 
  400.             return POPT_ERROR_BADNUMBER;
  401.  
  402.             if (aLong == LONG_MIN || aLong == LONG_MAX)
  403.             return POPT_ERROR_OVERFLOW;
  404.             if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
  405.             *((long *) opt->arg) = aLong;
  406.             } else {
  407.             if (aLong > INT_MAX || aLong < INT_MIN)
  408.                 return POPT_ERROR_OVERFLOW;
  409.             *((int *) opt->arg) =aLong;
  410.             }
  411.             break;
  412.  
  413.           default:
  414.             fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
  415.               opt->argInfo & POPT_ARG_MASK);
  416.             exit(1);
  417.         }
  418.         }
  419.     }
  420.  
  421.     if (cb)
  422.         cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
  423.     else if (opt->val) 
  424.         done = 1;
  425.  
  426.     if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
  427.         con->finalArgvAlloced += 10;
  428.         con->finalArgv = realloc(con->finalArgv,
  429.                 sizeof(*con->finalArgv) * con->finalArgvAlloced);
  430.     }
  431.  
  432.     i = con->finalArgvCount++;
  433.     con->finalArgv[i] = 
  434.         malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
  435.     if (opt->longName)
  436.         sprintf(con->finalArgv[i], "--%s", opt->longName);
  437.     else 
  438.         sprintf(con->finalArgv[i], "-%c", opt->shortName);
  439.  
  440.     if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) 
  441.         con->finalArgv[con->finalArgvCount++] = strdup(con->os->nextArg);
  442.     }
  443.  
  444.     return opt->val;
  445. }
  446.  
  447. char * poptGetOptArg(poptContext con) {
  448.     char * ret = con->os->nextArg;
  449.     con->os->nextArg = NULL;
  450.     return ret;
  451. }
  452.  
  453. char * poptGetArg(poptContext con) {
  454.     if (con->numLeftovers == con->nextLeftover) return NULL;
  455.     return (con->leftovers[con->nextLeftover++]);
  456. }
  457.  
  458. char * poptPeekArg(poptContext con) {
  459.     if (con->numLeftovers == con->nextLeftover) return NULL;
  460.     return (con->leftovers[con->nextLeftover]);
  461. }
  462.  
  463. char ** poptGetArgs(poptContext con) {
  464.     if (con->numLeftovers == con->nextLeftover) return NULL;
  465.  
  466.     /* some apps like [like RPM ;-) ] need this NULL terminated */
  467.     con->leftovers[con->numLeftovers] = NULL;
  468.  
  469.     return (con->leftovers + con->nextLeftover);
  470. }
  471.  
  472. void poptFreeContext(poptContext con) {
  473.     int i;
  474.  
  475.     for (i = 0; i < con->numAliases; i++) {
  476.     if (con->aliases[i].longName) free(con->aliases[i].longName);
  477.     free(con->aliases[i].argv);
  478.     }
  479.  
  480.     for (i = 0; i < con->numExecs; i++) {
  481.     if (con->execs[i].longName) free(con->execs[i].longName);
  482.     free(con->execs[i].script);
  483.     }
  484.  
  485.     for (i = 0; i < con->finalArgvCount; i++)
  486.     free(con->finalArgv[i]);
  487.  
  488.     free(con->leftovers);
  489.     free(con->finalArgv);
  490.     if (con->appName) free(con->appName);
  491.     if (con->aliases) free(con->aliases);
  492.     if (con->otherHelp) free(con->otherHelp);
  493.     free(con);
  494. }
  495.  
  496. int poptAddAlias(poptContext con, struct poptAlias newAlias, int flags) {
  497.     int aliasNum = con->numAliases++;
  498.     struct poptAlias * alias;
  499.  
  500.     /* SunOS won't realloc(NULL, ...) */
  501.     if (!con->aliases)
  502.     con->aliases = malloc(sizeof(newAlias) * con->numAliases);
  503.     else
  504.     con->aliases = realloc(con->aliases, 
  505.                    sizeof(newAlias) * con->numAliases);
  506.     alias = con->aliases + aliasNum;
  507.     
  508.     *alias = newAlias;
  509.     if (alias->longName)
  510.     alias->longName = strcpy(malloc(strlen(alias->longName) + 1), 
  511.                     alias->longName);
  512.     else
  513.     alias->longName = NULL;
  514.  
  515.     return 0;
  516. }
  517.  
  518. char * poptBadOption(poptContext con, int flags) {
  519.     struct optionStackEntry * os;
  520.  
  521.     if (flags & POPT_BADOPTION_NOALIAS)
  522.     os = con->optionStack;
  523.     else
  524.     os = con->os;
  525.  
  526.     return os->argv[os->next - 1];
  527. }
  528.  
  529. #define POPT_ERROR_NOARG    -10
  530. #define POPT_ERROR_BADOPT    -11
  531. #define POPT_ERROR_OPTSTOODEEP    -13
  532. #define POPT_ERROR_BADQUOTE    -15    /* only from poptParseArgString() */
  533. #define POPT_ERROR_ERRNO    -16    /* only from poptParseArgString() */
  534.  
  535. const char * poptStrerror(const int error) {
  536.     switch (error) {
  537.       case POPT_ERROR_NOARG:
  538.     return POPT_("missing argument");
  539.       case POPT_ERROR_BADOPT:
  540.     return POPT_("unknown option");
  541.       case POPT_ERROR_OPTSTOODEEP:
  542.     return POPT_("aliases nested too deeply");
  543.       case POPT_ERROR_BADQUOTE:
  544.     return POPT_("error in paramter quoting");
  545.       case POPT_ERROR_BADNUMBER:
  546.     return POPT_("invalid numeric value");
  547.       case POPT_ERROR_OVERFLOW:
  548.     return POPT_("number too large or too small");
  549.       case POPT_ERROR_ERRNO:
  550.     return strerror(errno);
  551.       default:
  552.     return POPT_("unknown error");
  553.     }
  554. }
  555.  
  556. int poptStuffArgs(poptContext con, char ** argv) {
  557.     int i;
  558.  
  559.     if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
  560.     return POPT_ERROR_OPTSTOODEEP;
  561.  
  562.     for (i = 0; argv[i]; i++);
  563.  
  564.     con->os++;
  565.     con->os->next = 0;
  566.     con->os->nextArg = con->os->nextCharArg = NULL;
  567.     con->os->currAlias = NULL;
  568.     con->os->argc = i;
  569.     con->os->argv = argv;
  570.     con->os->stuffed = 1;
  571.  
  572.     return 0;
  573. }
  574.  
  575. const char * poptGetInvocationName(poptContext con) {
  576.     return con->os->argv[0];
  577. }
  578.