getopts.c

来自「国外网站上的一些精典的C程序」· C语言 代码 · 共 945 行 · 第 1/3 页

C
945
字号
/************************************************************************/
/*                                                                      */
/*  GETOPTS.C - Universal command line options parser                   */
/*                                                                      */
/*  Original Copyright 1990-96 by Robert B. Stout as part of            */
/*  the MicroFirm Function Library (MFL)                                */
/*                                                                      */
/*  The user is granted a free limited license to use this source file  */
/*  to create royalty-free programs, subject to the terms of the        */
/*  license restrictions specified in the LICENSE.MFL file.             */
/*                                                                      */
/************************************************************************/

/*
**  Modified 02-Aug-2001 for Win/Solaris by rbs
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include "snipmath.h"
#include "sniptype.h"
#include "snip_str.h"
#include "filnames.h"
#include "errors.h"
#include "minmax.h"
#include "getopts.h"
#include "numcnvrt.h"
#include "dirport.h"

int         xargc = 0;
char       *xargv[MAX_XARGS]        = {NULL};
Boolean_T   getopts_range_err       = False_;

#if defined(__unix__)
 Boolean_T  xargs_on = False_;
#else
 Boolean_T  xargs_on = True_;
#endif

static FILE       *rspfile = NULL;
static int         count = 0, argidx = 0;
static Boolean_T   string_pending = False_;
static Boolean_T   additive_pending = False_;
static char       *pending_buf = NULL;

enum proc_stat { PSerror = -1, PSok, PSliteral};

static Boolean_T      bounds(struct Option_Tag *);
static enum proc_stat swProc(char *swStr);
static enum proc_stat VoProc(char *swStr);
static void           argProc(char *argStr);

/*
**  getopts()
**
**  Parameters: 1 - argc from main()
**              2 - argv from main()
**              3 - your program's options[] array
**
**  Returns: Number of options specified or Error_
**
**  Notes: 1. Your program should declare the global options[] array which
**            specifies all options recognized by getopts().
**
**         2. Out of range data are coerced into range and getopts_range_err
**            is set True_.
*/

int getopts(int argc, char *argv[])
{
      int i;
      Boolean_T scanning = True_;
      struct Option_Tag *ptr;
      char rspfname[FILENAME_MAX];
      char newarg[256];
      enum proc_stat ps;

      xargc = argc;
      xargv[argidx++] = argv[0];
      for (i = 1, count = 0; i < argc; )
      {
            /*
            ** Get the next argument - first see if we're looking for a string
            */

            if (string_pending)
            {
                  if (additive_pending)
                        strcat(pending_buf, argv[i]);
                  else  strcpy(pending_buf, argv[i]);
                  string_pending = additive_pending = False_;
                  pending_buf = NULL;
                  --xargc;
                  ++i;
                  continue;
            }

            /*
            ** Next try a response file
            */

            if (rspfile && !feof(rspfile))
            {
                  if (NULL == fgets(newarg, 256, rspfile))
                  {
                        fclose(rspfile);
                        rspfile = NULL;
                        ++i;
                        continue;
                  }
                  else  strdelch(newarg, "\r\n");
            }
            /*
            **  Next, see if we're supposed to open a response file
            */
            else  if (scanning && !rspfile && '@' == argv[i][0])
            {
                  /*
                  ** If necessary, open a response file
                  */
                  rspfile = cant(&argv[i][1], "r");
                  --xargc;
                  continue;
            }
            /*
            **  None of the above, copy the argument verbatim
            */
            else
            {
                  strcpy(newarg, argv[i++]);
            }

            /*
            ** Per Unix tradition, back-to-back switch characters signify
            ** the end of the switches
            */

            if ('-' ==  newarg[0] && '-' == newarg[1])
            {
                  printf("Found %s\n", newarg);
                  if (2 == strlen(newarg))
                  {
                        scanning = False_;
                        if (!rspfile)
                              --xargc;
                        continue;
                  }
                  else                    /* Process a verbose option   */
                  {
                        VoProc(&newarg[2]);
                        continue;
                  }
            }

            /*
            **  If we got here, we're still processing switches
            */

            if (scanning && (strchr("-", newarg[0])))
            {
                  ps = swProc(newarg);

                  if (PSerror == ps)
                        return Error_;

                  if (PSok == ps)
                        continue;
            }

            /*
            ** If we got here, newarg must be an argument or filename
            */

            else  argProc(newarg);
      }
      return count;
}

/*
**  Static function to process switch statements
**
**  Parameters: 1 - argv[i] containing the switch
**
**  Returns: PSok      if switch successful
**           PSerror   if invalid
**           PSliteral if literal (non-switch) argument
*/

static enum proc_stat swProc(char *swStr)
{
      struct Option_Tag *ptr;
      Boolean_T searching;
      char *arg_ptr;
      unsigned char     byte_var;
      int               int_var;
      short             short_var;
      unsigned short    word_var;
      long              long_var;
      unsigned long     dword_var, bitfield_var;
      double            double_var;

      /*
      ** Found a switch - If the 2nd character is also a switch
      ** character. If so, then it's a literal and is skipped
      */

      if (strchr("-@", swStr[1]))
            return PSliteral;

      for (ptr = options, searching = True_; searching; ++ptr)
      {
            if (!ptr->case_sense)
            {
                  ptr->letter = toupper(ptr->letter);
                  swStr[1]    = toupper(swStr[1]);
            }
            if ((int)swStr[1] == ptr->letter) switch (ptr->type)
            {
            case Boolean_Tag:
                  if ('-' == swStr[2])
                        *((Boolean_T *)(ptr->buf)) = False_;
                  else  *((Boolean_T *)(ptr->buf)) = True_;
                  searching = False_;
                  break;

            case Bitfield_Tag:
                  if (!swStr[2])
                  {
                        if (ptr->Default)
                              arg_ptr = ptr->Default;
                        else  return PSerror;
                  }
                  else  arg_ptr = &swStr[2];

                  sscanf(arg_ptr, "%lx", (unsigned long *)(bitfield_var));
                  *((unsigned long *)(ptr->buf)) |= (unsigned long)bitfield_var;
                  bounds(ptr);
                  searching = False_;
                  break;

            case Byte_Tag:
                  if (!swStr[2])
                  {
                        if (ptr->Default)
                              arg_ptr = ptr->Default;
                        else  return PSerror;
                  }
                  else  arg_ptr = &swStr[2];

                  sscanf(arg_ptr, "%lx", &long_var);
                  byte_var = (unsigned char)(long_var & 0xffL);
                  if (ptr->additive)
                        *((char *)(ptr->buf)) += byte_var;
                  else  *((char *)(ptr->buf))  = byte_var;
                  bounds(ptr);
                  searching = False_;
                  break;

            case Int_Tag:
                  if (!swStr[2])
                  {
                        if (ptr->Default)
                              arg_ptr = ptr->Default;
                        else  return PSerror;
                  }
                  else  arg_ptr = &swStr[2];

                  int_var = (int)(dround(getopts_eval(arg_ptr)));
                  if (ptr->additive)
                        *((int *)(ptr->buf)) += (int)(dround(getopts_eval(arg_ptr)));
                  else  *((int *)(ptr->buf))  = (int)(dround(getopts_eval(arg_ptr)));
                  bounds(ptr);
                  searching = False_;
                  break;

            case Short_Tag:
                  if (!swStr[2])
                  {
                        if (ptr->Default)
                              arg_ptr = ptr->Default;
                        else  return PSerror;
                  }
                  else  arg_ptr = &swStr[2];

                  short_var = (short)dround(getopts_eval(arg_ptr));
                  if (ptr->additive)
                        *((short *)(ptr->buf)) += short_var;
                  else  *((short *)(ptr->buf))  = short_var;
                  bounds(ptr);
                  searching = False_;
                  break;

            case Word_Tag:
                  if (!swStr[2])
                  {
                        if (ptr->Default)
                              arg_ptr = ptr->Default;
                        else  return PSerror;
                  }
                  else  arg_ptr = &swStr[2];

                  sscanf(arg_ptr, "%hx", (unsigned short *)(&word_var));
                  if (ptr->additive)
                        *((unsigned short *)(ptr->buf)) += word_var;
                  else  *((unsigned short *)(ptr->buf))  = word_var;
                  bounds(ptr);
                  searching = False_;
                  break;

            case Long_Tag:
                  if (!swStr[2])
                  {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?