Annotation of embedaddon/ntp/sntp/libopts/sort.c, revision 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>