optparser.cpp (3512B)
1 // Copyright (c) 2020 Morel BĂ©renger 2 // 3 // This software is provided 'as-is', without any express or implied 4 // warranty. In no event will the authors be held liable for any damages 5 // arising from the use of this software. 6 // 7 // Permission is granted to anyone to use this software for any purpose, 8 // including commercial applications, and to alter it and redistribute it 9 // freely, subject to the following restrictions: 10 // 11 // 1. The origin of this software must not be misrepresented; you must not 12 // claim that you wrote the original software. If you use this software 13 // in a product, an acknowledgment in the product documentation would be 14 // appreciated but is not required. 15 // 2. Altered source versions must be plainly marked as such, and must not be 16 // misrepresented as being the original software. 17 // 3. This notice may not be removed or altered from any source distribution. 18 19 // option parser: implementation 20 21 #include <string.h> 22 #include <assert.h> 23 #include <stdlib.h> 24 #include <stdio.h> 25 #include <stdint.h> 26 #include <errno.h> 27 #include <limits.h> 28 29 #include "optparser.hpp" 30 #include "utils.hpp" 31 32 // those strings must be defined in same order than the enum 33 // Trick: use vim's block insertion to check them 34 char const *parse_error_msgs[] = 35 { 36 /*NONE */"no error", 37 /*IGNORED */"not an option", 38 /*MAX_COUNT */"count overflow", 39 /*SET_NO_VAL */"this option needs a value", 40 /*SET_VAL_IGN*/"this option does not needs a value", 41 /*SET_FAIL */"failed to parse the value", 42 /*BAD_ARGS */"application bug: bad arguments to call", 43 /*BAD_SETTER */"application bug: bad values in option", 44 }; 45 46 parse_error_t parse_cmd_opt( char * arg, opt_desc_t* start, opt_desc_t const* end ) 47 { 48 BUG_CHECK( !( arg && start && end && end > start ), BAD_ARGS ); 49 50 if( arg[0] != '-' || arg[1] == 0 ) 51 { 52 return IGNORED; 53 } 54 55 opt_desc_t* opt = start; 56 char* argv = arg + 2; 57 58 //search for option (stores in opt) 59 if( arg[1] == '-' ) //long 60 { 61 char* name = argv; 62 size_t name_sz; 63 argv = strchr( name, '=' ); 64 if( argv ) 65 { 66 assert( argv > name ); 67 name_sz = static_cast<size_t>( argv - name ); 68 ++argv; 69 } 70 else 71 { 72 name_sz = strlen( name ); 73 } 74 75 for( ; true 76 && opt != end 77 && 0 != strncmp( name, opt->option, name_sz ) 78 && name_sz != strlen( opt->option ); ++opt ) 79 { 80 } 81 } 82 else //short 83 { 84 uint32_t name = static_cast<uint8_t>( arg[1] ); 85 if( name & 0x80 ) 86 { 87 assert( !( name & 0x80 ) && "TODO: utf-8 support" ); 88 abort(); 89 } 90 for( ; opt != end && opt->short_option != name; ++opt ) 91 { 92 } 93 } 94 95 //BUG_CHECK( ( opt->set && !opt->value ) || ( !opt->set && opt->value ), BAD_SETTER ); 96 97 if( opt == end ) 98 { 99 return IGNORED; 100 } 101 102 if( opt->value && empty_array( argv ) ) 103 { 104 return SET_NO_VAL; 105 } 106 107 if( !opt->value && !empty_array( argv ) ) 108 { 109 return SET_VAL_IGN; 110 } 111 112 if( opt->set && opt->set( opt->value, argv ) ) 113 { 114 return SET_FAIL; 115 } 116 117 if( opt->count < UINT32_MAX ) 118 { 119 ++opt->count; 120 } 121 return opt->count == UINT32_MAX ? MAX_COUNT : NONE; 122 } 123 124 void print_opts( FILE_PTR target, opt_desc_t const* start, opt_desc_t const* end ) 125 { 126 char short_name[] = ",-????"; 127 for( ; start != end; ++start ) 128 { 129 memcpy( short_name + 2, &start->short_option, sizeof( start->short_option ) ); 130 fprintf( target, "\t* --%s%s: %s", 131 start->option, 132 start->short_option ? short_name : "", 133 start->description 134 ); 135 //fail to show current val 136 if( start->show && start->show( start->value, target ) ) 137 { 138 abort(); 139 } 140 fputc( '\n', target ); 141 } 142 }