Annotation of embedaddon/ntp/sntp/libopts/sort.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * \file sort.c
                      4:  *
                      5:  * Time-stamp:      "2010-07-17 10:34:15 bkorb"
                      6:  *
                      7:  *  This module implements argument sorting.
                      8:  *
                      9:  *  This file is part of AutoOpts, a companion to AutoGen.
                     10:  *  AutoOpts is free software.
                     11:  *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
                     12:  *
                     13:  *  AutoOpts is available under any one of two licenses.  The license
                     14:  *  in use must be one of these two and the choice is under the control
                     15:  *  of the user of the license.
                     16:  *
                     17:  *   The GNU Lesser General Public License, version 3 or later
                     18:  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
                     19:  *
                     20:  *   The Modified Berkeley Software Distribution License
                     21:  *      See the file "COPYING.mbsd"
                     22:  *
                     23:  *  These files have the following md5sums:
                     24:  *
                     25:  *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
                     26:  *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
                     27:  *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
                     28:  */
                     29: 
                     30: /* = = = START-STATIC-FORWARD = = = */
                     31: static tSuccess
                     32: mustHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
                     33:               char** ppzOpts, int* pOptsIdx);
                     34: 
                     35: static tSuccess
                     36: mayHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
                     37:              char** ppzOpts, int* pOptsIdx);
                     38: 
                     39: static tSuccess
                     40: checkShortOpts(tOptions* pOpts, char* pzArg, tOptState* pOS,
                     41:                char** ppzOpts, int* pOptsIdx);
                     42: /* = = = END-STATIC-FORWARD = = = */
                     43: 
                     44: /*
                     45:  *  "mustHandleArg" and "mayHandleArg" are really similar.  The biggest
                     46:  *  difference is that "may" will consume the next argument only if it
                     47:  *  does not start with a hyphen and "must" will consume it, hyphen or not.
                     48:  */
                     49: static tSuccess
                     50: mustHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
                     51:               char** ppzOpts, int* pOptsIdx)
                     52: {
                     53:     /*
                     54:      *  An option argument is required.  Long options can either have
                     55:      *  a separate command line argument, or an argument attached by
                     56:      *  the '=' character.  Figure out which.
                     57:      */
                     58:     switch (pOS->optType) {
                     59:     case TOPT_SHORT:
                     60:         /*
                     61:          *  See if an arg string follows the flag character.  If not,
                     62:          *  the next arg must be the option argument.
                     63:          */
                     64:         if (*pzArg != NUL)
                     65:             return SUCCESS;
                     66:         break;
                     67: 
                     68:     case TOPT_LONG:
                     69:         /*
                     70:          *  See if an arg string has already been assigned (glued on
                     71:          *  with an `=' character).  If not, the next is the opt arg.
                     72:          */
                     73:         if (pOS->pzOptArg != NULL)
                     74:             return SUCCESS;
                     75:         break;
                     76: 
                     77:     default:
                     78:         return FAILURE;
                     79:     }
                     80:     if (pOpts->curOptIdx >= pOpts->origArgCt)
                     81:         return FAILURE;
                     82: 
                     83:     ppzOpts[ (*pOptsIdx)++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                     84:     return SUCCESS;
                     85: }
                     86: 
                     87: static tSuccess
                     88: mayHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
                     89:              char** ppzOpts, int* pOptsIdx)
                     90: {
                     91:     /*
                     92:      *  An option argument is optional.
                     93:      */
                     94:     switch (pOS->optType) {
                     95:     case TOPT_SHORT:
                     96:         /*
                     97:          *  IF nothing is glued on after the current flag character,
                     98:          *  THEN see if there is another argument.  If so and if it
                     99:          *  does *NOT* start with a hyphen, then it is the option arg.
                    100:          */
                    101:         if (*pzArg != NUL)
                    102:             return SUCCESS;
                    103:         break;
                    104: 
                    105:     case TOPT_LONG:
                    106:         /*
                    107:          *  Look for an argument if we don't already have one (glued on
                    108:          *  with a `=' character)
                    109:          */
                    110:         if (pOS->pzOptArg != NULL)
                    111:             return SUCCESS;
                    112:         break;
                    113: 
                    114:     default:
                    115:         return FAILURE;
                    116:     }
                    117:     if (pOpts->curOptIdx >= pOpts->origArgCt)
                    118:         return PROBLEM;
                    119: 
                    120:     pzArg = pOpts->origArgVect[ pOpts->curOptIdx ];
                    121:     if (*pzArg != '-')
                    122:         ppzOpts[ (*pOptsIdx)++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    123:     return SUCCESS;
                    124: }
                    125: 
                    126: /*
                    127:  *  Process a string of short options glued together.  If the last one
                    128:  *  does or may take an argument, the do the argument processing and leave.
                    129:  */
                    130: static tSuccess
                    131: checkShortOpts(tOptions* pOpts, char* pzArg, tOptState* pOS,
                    132:                char** ppzOpts, int* pOptsIdx)
                    133: {
                    134:     while (*pzArg != NUL) {
                    135:         if (FAILED(shortOptionFind(pOpts, (tAoUC)*pzArg, pOS)))
                    136:             return FAILURE;
                    137: 
                    138:         /*
                    139:          *  See if we can have an arg.
                    140:          */
                    141:         if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) {
                    142:             pzArg++;
                    143: 
                    144:         } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) {
                    145:             /*
                    146:              *  Take an argument if it is not attached and it does not
                    147:              *  start with a hyphen.
                    148:              */
                    149:             if (pzArg[1] != NUL)
                    150:                 return SUCCESS;
                    151: 
                    152:             pzArg = pOpts->origArgVect[ pOpts->curOptIdx ];
                    153:             if (*pzArg != '-')
                    154:                 ppzOpts[ (*pOptsIdx)++ ] =
                    155:                     pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    156:             return SUCCESS;
                    157: 
                    158:         } else {
                    159:             /*
                    160:              *  IF we need another argument, be sure it is there and
                    161:              *  take it.
                    162:              */
                    163:             if (pzArg[1] == NUL) {
                    164:                 if (pOpts->curOptIdx >= pOpts->origArgCt)
                    165:                     return FAILURE;
                    166:                 ppzOpts[ (*pOptsIdx)++ ] =
                    167:                     pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    168:             }
                    169:             return SUCCESS;
                    170:         }
                    171:     }
                    172:     return SUCCESS;
                    173: }
                    174: 
                    175: /*
                    176:  *  If the program wants sorted options (separated operands and options),
                    177:  *  then this routine will to the trick.
                    178:  */
                    179: LOCAL void
                    180: optionSort(tOptions* pOpts)
                    181: {
                    182:     char** ppzOpts;
                    183:     char** ppzOpds;
                    184:     int    optsIdx = 0;
                    185:     int    opdsIdx = 0;
                    186: 
                    187:     tOptState os = OPTSTATE_INITIALIZER(DEFINED);
                    188: 
                    189:     /*
                    190:      *  Disable for POSIX conformance, or if there are no operands.
                    191:      */
                    192:     if (  (getenv("POSIXLY_CORRECT") != NULL)
                    193:        || NAMED_OPTS(pOpts))
                    194:         return;
                    195: 
                    196:     /*
                    197:      *  Make sure we can allocate two full-sized arg vectors.
                    198:      */
                    199:     ppzOpts = malloc(pOpts->origArgCt * sizeof(char*));
                    200:     if (ppzOpts == NULL)
                    201:         goto exit_no_mem;
                    202: 
                    203:     ppzOpds = malloc(pOpts->origArgCt * sizeof(char*));
                    204:     if (ppzOpds == NULL) {
                    205:         free(ppzOpts);
                    206:         goto exit_no_mem;
                    207:     }
                    208: 
                    209:     pOpts->curOptIdx = 1;
                    210:     pOpts->pzCurOpt  = NULL;
                    211: 
                    212:     /*
                    213:      *  Now, process all the options from our current position onward.
                    214:      *  (This allows interspersed options and arguments for the few
                    215:      *  non-standard programs that require it.)
                    216:      */
                    217:     for (;;) {
                    218:         char* pzArg;
                    219:         tSuccess res;
                    220: 
                    221:         /*
                    222:          *  If we're out of arguments, we're done.  Join the option and
                    223:          *  operand lists into the original argument vector.
                    224:          */
                    225:         if (pOpts->curOptIdx >= pOpts->origArgCt) {
                    226:             errno = 0;
                    227:             goto joinLists;
                    228:         }
                    229: 
                    230:         pzArg = pOpts->origArgVect[ pOpts->curOptIdx ];
                    231:         if (*pzArg != '-') {
                    232:             ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    233:             continue;
                    234:         }
                    235: 
                    236:         switch (pzArg[1]) {
                    237:         case NUL:
                    238:             /*
                    239:              *  A single hyphen is an operand.
                    240:              */
                    241:             ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    242:             continue;
                    243: 
                    244:         case '-':
                    245:             /*
                    246:              *  Two consecutive hypens.  Put them on the options list and then
                    247:              *  _always_ force the remainder of the arguments to be operands.
                    248:              */
                    249:             if (pzArg[2] == NUL) {
                    250:                 ppzOpts[ optsIdx++ ] =
                    251:                     pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    252:                 goto restOperands;
                    253:             }
                    254:             res = longOptionFind(pOpts, pzArg+2, &os);
                    255:             break;
                    256: 
                    257:         default:
                    258:             /*
                    259:              *  If short options are not allowed, then do long
                    260:              *  option processing.  Otherwise the character must be a
                    261:              *  short (i.e. single character) option.
                    262:              */
                    263:             if ((pOpts->fOptSet & OPTPROC_SHORTOPT) == 0) {
                    264:                 res = longOptionFind(pOpts, pzArg+1, &os);
                    265:             } else {
                    266:                 res = shortOptionFind(pOpts, (tAoUC)pzArg[1], &os);
                    267:             }
                    268:             break;
                    269:         }
                    270:         if (FAILED(res)) {
                    271:             errno = EINVAL;
                    272:             goto freeTemps;
                    273:         }
                    274: 
                    275:         /*
                    276:          *  We've found an option.  Add the argument to the option list.
                    277:          *  Next, we have to see if we need to pull another argument to be
                    278:          *  used as the option argument.
                    279:          */
                    280:         ppzOpts[ optsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    281: 
                    282:         if (OPTST_GET_ARGTYPE(os.pOD->fOptState) == OPARG_TYPE_NONE) {
                    283:             /*
                    284:              *  No option argument.  If we have a short option here,
                    285:              *  then scan for short options until we get to the end
                    286:              *  of the argument string.
                    287:              */
                    288:             if (  (os.optType == TOPT_SHORT)
                    289:                && FAILED(checkShortOpts(pOpts, pzArg+2, &os, ppzOpts,
                    290:                                         &optsIdx)) )  {
                    291:                 errno = EINVAL;
                    292:                 goto freeTemps;
                    293:             }
                    294: 
                    295:         } else if (os.pOD->fOptState & OPTST_ARG_OPTIONAL) {
                    296:             switch (mayHandleArg(pOpts, pzArg+2, &os, ppzOpts, &optsIdx)) {
                    297:             case FAILURE: errno = EIO; goto freeTemps;
                    298:             case PROBLEM: errno = 0;   goto joinLists;
                    299:             }
                    300: 
                    301:         } else {
                    302:             switch (mustHandleArg(pOpts, pzArg+2, &os, ppzOpts, &optsIdx)) {
                    303:             case PROBLEM:
                    304:             case FAILURE: errno = EIO; goto freeTemps;
                    305:             }
                    306:         }
                    307:     } /* for (;;) */
                    308: 
                    309:  restOperands:
                    310:     while (pOpts->curOptIdx < pOpts->origArgCt)
                    311:         ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                    312: 
                    313:  joinLists:
                    314:     if (optsIdx > 0)
                    315:         memcpy(pOpts->origArgVect + 1, ppzOpts, optsIdx * sizeof(char*));
                    316:     if (opdsIdx > 0)
                    317:         memcpy(pOpts->origArgVect + 1 + optsIdx, ppzOpds,
                    318:                opdsIdx * sizeof(char*));
                    319: 
                    320:  freeTemps:
                    321:     free(ppzOpts);
                    322:     free(ppzOpds);
                    323:     return;
                    324: 
                    325:  exit_no_mem:
                    326:     errno = ENOMEM;
                    327:     return;
                    328: }
                    329: 
                    330: /*
                    331:  * Local Variables:
                    332:  * mode: C
                    333:  * c-file-style: "stroustrup"
                    334:  * indent-tabs-mode: nil
                    335:  * End:
                    336:  * end of autoopts/sort.c */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>