"Fossies" - the Fresh Open Source Software Archive

Member "ponyc-0.33.2/src/libponyrt/options/options.c" (3 Feb 2020, 5229 Bytes) of package /linux/misc/ponyc-0.33.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "options.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.33.1_vs_0.33.2.

    1 #include "options.h"
    2 
    3 #include "ponyassert.h"
    4 #include <string.h>
    5 #include <stdio.h>
    6 #include <stdbool.h>
    7 
    8 #define MATCH_LONG  1
    9 #define MATCH_SHORT 2
   10 #define MATCH_NONE  3
   11 #define PARSE_ARG (OPT_ARG_REQUIRED | OPT_ARG_OPTIONAL)
   12 
   13 static bool end_reached(const opt_arg_t* arg)
   14 {
   15   return (arg->long_opt == 0) && (arg->short_opt == 0) &&
   16     (arg->id == UINT32_MAX) && (arg->flag == UINT32_MAX);
   17 }
   18 
   19 static bool has_argument(opt_state_t* s)
   20 {
   21   bool short_arg = ((s->match_type == MATCH_SHORT) &&
   22     (*(s->opt_start + 1) || s->idx < (*s->argc)-1));
   23 
   24   bool long_arg = ((s->match_type == MATCH_LONG) &&
   25     ((*s->opt_end == '=') || s->idx < (*s->argc)-1));
   26 
   27   return (short_arg | long_arg);
   28 }
   29 
   30 static void parse_option_name(opt_state_t* s)
   31 {
   32   bool is_long_opt = s->argv[s->idx][1] == '-';
   33 
   34   s->match_type = is_long_opt ? MATCH_LONG : MATCH_SHORT;
   35   s->opt_start = (s->argv[s->idx] + 1 + is_long_opt);
   36 
   37   for(s->opt_end = s->opt_start; *s->opt_end && *s->opt_end != '=';
   38     s->opt_end++);
   39 }
   40 
   41 static const opt_arg_t* find_match(opt_state_t* s)
   42 {
   43   size_t match_length;
   44 
   45   const char* match_name;
   46   const opt_arg_t* match = NULL;
   47 
   48   parse_option_name(s);
   49 
   50   for(const opt_arg_t* p = s->args; !end_reached(p); ++p)
   51   {
   52     if(s->match_type == MATCH_LONG)
   53     {
   54       match_name = p->long_opt;
   55       match_length = (size_t)(s->opt_end - s->opt_start);
   56     }
   57     else
   58     {
   59       match_name = &p->short_opt;
   60       match_length = 1;
   61     }
   62 
   63     if(!strncmp(match_name, s->opt_start, match_length))
   64     {
   65       if(s->match_type == MATCH_SHORT || match_length == strlen(match_name))
   66       {
   67         // Exact match found. It is necessary to check for
   68         // the length of p->long_opt since there might be
   69         // options that are prefixes of another (strncmp),
   70         // and short options might be grouped.
   71         if((match != NULL) && (match->id != p->id))
   72           return (opt_arg_t*)1;
   73         
   74         match = p;
   75       }
   76     }
   77   }
   78 
   79   return match;
   80 }
   81 
   82 static bool is_positional(const opt_state_t* s)
   83 {
   84   return (s->argv[s->idx][0] != '-' || s->argv[s->idx][1] == '\0');
   85 }
   86 
   87 static bool skip_non_options(opt_state_t* s)
   88 {
   89   while(true)
   90   {
   91     if(s->idx == *s->argc)
   92       return false;
   93 
   94     if(!is_positional(s))
   95       return true;
   96 
   97     s->idx++;
   98   }
   99 }
  100 
  101 static void strip_accepted_opts(opt_state_t* s)
  102 {
  103   if(s->remove > 0)
  104   {
  105     *s->argc -= s->remove;
  106 
  107     pony_assert(*s->argc >= s->idx);
  108     memmove(&s->argv[s->idx], &s->argv[s->idx + s->remove],
  109       (unsigned int)(*s->argc - s->idx) * sizeof(char*));
  110 
  111     s->idx--;
  112 
  113     s->remove = 0;
  114   }
  115 }
  116 
  117 static void parse_long_opt_arg(opt_state_t* s)
  118 {
  119   if(*s->opt_end == '=')
  120   {
  121     s->arg_val = s->opt_end + 1;
  122     s->opt_start += strlen(s->opt_start);
  123   }
  124   else if(s->argv[s->idx + 1][0] != '-')
  125   {
  126     s->arg_val = s->argv[s->idx + 1];
  127     s->opt_start += strlen(s->opt_start);
  128 
  129     // Only remove if there actually was an argument
  130     if(s->argv[s->idx + 1][0])
  131       s->remove++;
  132   }
  133 }
  134 
  135 static void parse_short_opt_arg(opt_state_t* s)
  136 {
  137   if(*s->opt_end)
  138   {
  139     s->arg_val = s->opt_end;
  140     s->opt_start += strlen(s->opt_start);
  141   }
  142   else if(*(s->opt_start) != '-')
  143   {
  144     s->arg_val = s->argv[s->idx + 1];
  145   }
  146   else
  147   {
  148     s->arg_val = s->opt_start + 1;
  149     s->opt_start += strlen(s->opt_start);
  150   }
  151 
  152   s->remove++;
  153 }
  154 
  155 static void parse_short_opt(opt_state_t* s)
  156 {
  157   // Strip out the short option, as short options may be
  158   // grouped
  159   memmove(s->opt_start, s->opt_start + 1, strlen(s->opt_start));
  160 
  161   if(*s->opt_start)
  162     s->opt_start = s->argv[s->idx];
  163   else
  164     s->remove++;
  165 }
  166 
  167 static int missing_argument(opt_state_t* s)
  168 {
  169    printf("%s: '%s' option requires an argument!\n", s->argv[0],
  170       s->argv[s->idx]);
  171 
  172     return -2;
  173 }
  174 
  175 void ponyint_opt_init(const opt_arg_t* args, opt_state_t* s, int* argc,
  176   char** argv)
  177 {
  178   s->argc = argc;
  179   s->argv = argv;
  180   s->args = args;
  181   s->arg_val = NULL;
  182 
  183   s->opt_start = NULL;
  184   s->opt_end = NULL;
  185   s->match_type = 0;
  186   s->idx = 0;
  187   s->remove = 0;
  188 }
  189 
  190 int ponyint_opt_next(opt_state_t* s)
  191 {
  192   s->arg_val = NULL;
  193   
  194   if(s->opt_start == NULL || *s->opt_start == '\0')
  195   {
  196     // Parsing a new option
  197     s->idx++;
  198 
  199     if(!skip_non_options(s))
  200       return -1;
  201   }
  202 
  203   // Check for known exact match. If the option is known, process it,
  204   // otherwise ignore it.
  205   const opt_arg_t* m = find_match(s);
  206 
  207   if(m == NULL)
  208   {
  209     s->opt_start += strlen(s->opt_start);
  210     return ponyint_opt_next(s);
  211   }
  212   else if(m == (opt_arg_t*)1)
  213   {
  214     printf("%s: '%s' option is ambiguous!\n", s->argv[0], s->argv[s->idx]);
  215     return -2;
  216   }
  217 
  218   if ((m->flag == OPT_ARG_REQUIRED) && !has_argument(s))
  219     return missing_argument(s);
  220   
  221   if(s->match_type == MATCH_LONG)
  222   {
  223     s->remove++;
  224 
  225     if((m->flag & PARSE_ARG) && has_argument(s))
  226     {
  227       parse_long_opt_arg(s);
  228 
  229       if(s->arg_val == NULL && (m->flag & OPT_ARG_REQUIRED))
  230         return missing_argument(s);
  231     }
  232 
  233     s->opt_start = NULL;
  234   }
  235   else if(s->match_type == MATCH_SHORT)
  236   {
  237     parse_short_opt(s);
  238 
  239     if((m->flag & PARSE_ARG) && has_argument(s))
  240     {
  241       parse_short_opt_arg(s);
  242       
  243       if(s->arg_val == NULL && (m->flag & OPT_ARG_REQUIRED))
  244         return missing_argument(s);
  245     }
  246   }
  247 
  248   strip_accepted_opts(s);
  249 
  250   return (int)m->id;
  251 }