"Fossies" - the Fresh Open Source Software Archive

Member "lzip-1.22-rc2/arg_parser.cc" (30 Apr 2020, 5804 Bytes) of package /linux/misc/lzip-1.22-rc2.tar.lz:


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 "arg_parser.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.21_vs_1.22-rc1.

    1 /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
    2    Copyright (C) 2006-2020 Antonio Diaz Diaz.
    3 
    4    This library is free software. Redistribution and use in source and
    5    binary forms, with or without modification, are permitted provided
    6    that the following conditions are met:
    7 
    8    1. Redistributions of source code must retain the above copyright
    9    notice, this list of conditions, and the following disclaimer.
   10 
   11    2. Redistributions in binary form must reproduce the above copyright
   12    notice, this list of conditions, and the following disclaimer in the
   13    documentation and/or other materials provided with the distribution.
   14 
   15    This library is distributed in the hope that it will be useful,
   16    but WITHOUT ANY WARRANTY; without even the implied warranty of
   17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   18 */
   19 
   20 #include <cstring>
   21 #include <string>
   22 #include <vector>
   23 
   24 #include "arg_parser.h"
   25 
   26 
   27 bool Arg_parser::parse_long_option( const char * const opt, const char * const arg,
   28                                     const Option options[], int & argind )
   29   {
   30   unsigned len;
   31   int index = -1;
   32   bool exact = false, ambig = false;
   33 
   34   for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ;
   35 
   36   // Test all long options for either exact match or abbreviated matches.
   37   for( int i = 0; options[i].code != 0; ++i )
   38     if( options[i].name && std::strncmp( options[i].name, &opt[2], len ) == 0 )
   39       {
   40       if( std::strlen( options[i].name ) == len )   // Exact match found
   41         { index = i; exact = true; break; }
   42       else if( index < 0 ) index = i;       // First nonexact match found
   43       else if( options[index].code != options[i].code ||
   44                options[index].has_arg != options[i].has_arg )
   45         ambig = true;       // Second or later nonexact match found
   46       }
   47 
   48   if( ambig && !exact )
   49     {
   50     error_ = "option '"; error_ += opt; error_ += "' is ambiguous";
   51     return false;
   52     }
   53 
   54   if( index < 0 )       // nothing found
   55     {
   56     error_ = "unrecognized option '"; error_ += opt; error_ += '\'';
   57     return false;
   58     }
   59 
   60   ++argind;
   61   data.push_back( Record( options[index].code ) );
   62 
   63   if( opt[len+2] )      // '--<long_option>=<argument>' syntax
   64     {
   65     if( options[index].has_arg == no )
   66       {
   67       error_ = "option '--"; error_ += options[index].name;
   68       error_ += "' doesn't allow an argument";
   69       return false;
   70       }
   71     if( options[index].has_arg == yes && !opt[len+3] )
   72       {
   73       error_ = "option '--"; error_ += options[index].name;
   74       error_ += "' requires an argument";
   75       return false;
   76       }
   77     data.back().argument = &opt[len+3];
   78     return true;
   79     }
   80 
   81   if( options[index].has_arg == yes )
   82     {
   83     if( !arg || !arg[0] )
   84       {
   85       error_ = "option '--"; error_ += options[index].name;
   86       error_ += "' requires an argument";
   87       return false;
   88       }
   89     ++argind; data.back().argument = arg;
   90     return true;
   91     }
   92 
   93   return true;
   94   }
   95 
   96 
   97 bool Arg_parser::parse_short_option( const char * const opt, const char * const arg,
   98                                      const Option options[], int & argind )
   99   {
  100   int cind = 1;         // character index in opt
  101 
  102   while( cind > 0 )
  103     {
  104     int index = -1;
  105     const unsigned char c = opt[cind];
  106 
  107     if( c != 0 )
  108       for( int i = 0; options[i].code; ++i )
  109         if( c == options[i].code )
  110           { index = i; break; }
  111 
  112     if( index < 0 )
  113       {
  114       error_ = "invalid option -- '"; error_ += c; error_ += '\'';
  115       return false;
  116       }
  117 
  118     data.push_back( Record( c ) );
  119     if( opt[++cind] == 0 ) { ++argind; cind = 0; }  // opt finished
  120 
  121     if( options[index].has_arg != no && cind > 0 && opt[cind] )
  122       {
  123       data.back().argument = &opt[cind]; ++argind; cind = 0;
  124       }
  125     else if( options[index].has_arg == yes )
  126       {
  127       if( !arg || !arg[0] )
  128         {
  129         error_ = "option requires an argument -- '"; error_ += c;
  130         error_ += '\'';
  131         return false;
  132         }
  133       data.back().argument = arg; ++argind; cind = 0;
  134       }
  135     }
  136   return true;
  137   }
  138 
  139 
  140 Arg_parser::Arg_parser( const int argc, const char * const argv[],
  141                         const Option options[], const bool in_order )
  142   {
  143   if( argc < 2 || !argv || !options ) return;
  144 
  145   std::vector< const char * > non_options;  // skipped non-options
  146   int argind = 1;               // index in argv
  147 
  148   while( argind < argc )
  149     {
  150     const unsigned char ch1 = argv[argind][0];
  151     const unsigned char ch2 = ch1 ? argv[argind][1] : 0;
  152 
  153     if( ch1 == '-' && ch2 )     // we found an option
  154       {
  155       const char * const opt = argv[argind];
  156       const char * const arg = ( argind + 1 < argc ) ? argv[argind+1] : 0;
  157       if( ch2 == '-' )
  158         {
  159         if( !argv[argind][2] ) { ++argind; break; } // we found "--"
  160         else if( !parse_long_option( opt, arg, options, argind ) ) break;
  161         }
  162       else if( !parse_short_option( opt, arg, options, argind ) ) break;
  163       }
  164     else
  165       {
  166       if( in_order ) data.push_back( Record( argv[argind++] ) );
  167       else non_options.push_back( argv[argind++] );
  168       }
  169     }
  170   if( !error_.empty() ) data.clear();
  171   else
  172     {
  173     for( unsigned i = 0; i < non_options.size(); ++i )
  174       data.push_back( Record( non_options[i] ) );
  175     while( argind < argc )
  176       data.push_back( Record( argv[argind++] ) );
  177     }
  178   }
  179 
  180 
  181 Arg_parser::Arg_parser( const char * const opt, const char * const arg,
  182                         const Option options[] )
  183   {
  184   if( !opt || !opt[0] || !options ) return;
  185 
  186   if( opt[0] == '-' && opt[1] )     // we found an option
  187     {
  188     int argind = 1;         // dummy
  189     if( opt[1] == '-' )
  190       { if( opt[2] ) parse_long_option( opt, arg, options, argind ); }
  191     else
  192       parse_short_option( opt, arg, options, argind );
  193     if( !error_.empty() ) data.clear();
  194     }
  195   else data.push_back( Record( opt ) );
  196   }